2001-07-22 16:18:56 +02:00
/*
2008-01-16 23:14:26 +01:00
* various utility functions for use within FFmpeg
2002-05-26 00:34:32 +02:00
* Copyright ( c ) 2000 , 2001 , 2002 Fabrice Bellard
2001-07-22 16:18:56 +02:00
*
2006-10-07 17:30:46 +02:00
* This file is part of FFmpeg .
*
* FFmpeg is free software ; you can redistribute it and / or
2002-05-26 00:34:32 +02:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
2006-10-07 17:30:46 +02:00
* version 2.1 of the License , or ( at your option ) any later version .
2001-07-22 16:18:56 +02:00
*
2006-10-07 17:30:46 +02:00
* FFmpeg is distributed in the hope that it will be useful ,
2001-07-22 16:18:56 +02:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2002-05-26 00:34:32 +02:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
2001-07-22 16:18:56 +02:00
*
2002-05-26 00:34:32 +02:00
* You should have received a copy of the GNU Lesser General Public
2006-10-07 17:30:46 +02:00
* License along with FFmpeg ; if not , write to the Free Software
2006-01-12 23:43:26 +01:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2001-07-22 16:18:56 +02:00
*/
2011-03-15 13:11:57 +01:00
/* #define DEBUG */
2001-08-13 23:37:10 +02:00
# include "avformat.h"
2011-03-06 20:08:30 +01:00
# include "avio_internal.h"
2008-08-28 01:43:28 +02:00
# include "internal.h"
2010-05-18 21:16:40 +02:00
# include "libavcodec/internal.h"
2011-03-09 15:12:24 +01:00
# include "libavcodec/raw.h"
2011-12-16 11:48:09 +01:00
# include "libavcodec/bytestream.h"
2011-12-22 03:06:06 +01:00
# include "libavutil/avassert.h"
2010-09-26 16:25:22 +02:00
# include "libavutil/opt.h"
2011-05-22 12:46:29 +02:00
# include "libavutil/dict.h"
2011-06-04 17:36:30 +02:00
# include "libavutil/pixdesc.h"
2009-01-04 20:00:35 +01:00
# include "metadata.h"
2010-10-06 22:21:07 +02:00
# include "id3v2.h"
2012-01-05 10:14:07 +01:00
# include "libavutil/avassert.h"
2008-05-09 13:56:36 +02:00
# include "libavutil/avstring.h"
2011-06-04 13:58:23 +02:00
# include "libavutil/mathematics.h"
2011-11-07 22:32:21 +01:00
# include "libavutil/parseutils.h"
2012-05-13 22:22:35 +02:00
# include "libavutil/timestamp.h"
2007-07-11 14:45:14 +02:00
# include "riff.h"
2010-03-06 23:36:36 +01:00
# include "audiointerleave.h"
2011-04-04 20:40:38 +02:00
# include "url.h"
2010-03-05 23:31:45 +01:00
# include <stdarg.h>
# if CONFIG_NETWORK
# include "network.h"
# endif
2002-07-27 04:54:10 +02:00
2004-01-13 23:02:49 +01:00
# undef NDEBUG
# include <assert.h>
2005-06-28 14:55:08 +02:00
/**
2010-04-20 16:45:34 +02:00
* @ file
2008-01-16 23:14:26 +01:00
* various utility functions for use within FFmpeg
2005-06-28 14:55:08 +02:00
*/
2008-08-08 20:40:50 +02:00
unsigned avformat_version ( void )
{
2011-12-22 03:06:06 +01:00
av_assert0 ( LIBAVFORMAT_VERSION_MICRO > = 100 ) ;
2008-08-08 20:40:50 +02:00
return LIBAVFORMAT_VERSION_INT ;
}
2010-01-03 15:31:25 +01:00
const char * avformat_configuration ( void )
2009-11-18 18:15:17 +01:00
{
2011-03-17 17:01:10 +01:00
return FFMPEG_CONFIGURATION ;
2009-11-18 18:15:17 +01:00
}
2010-01-03 15:31:25 +01:00
const char * avformat_license ( void )
2009-11-18 18:15:17 +01:00
{
# define LICENSE_PREFIX "libavformat license: "
2011-03-17 16:57:37 +01:00
return LICENSE_PREFIX FFMPEG_LICENSE + sizeof ( LICENSE_PREFIX ) - 1 ;
2009-11-18 18:15:17 +01:00
}
2012-04-03 23:34:53 +02:00
# define RELATIVE_TS_BASE (INT64_MAX - (1LL<<48))
2012-03-07 22:13:39 +01:00
static int is_relative ( int64_t ts ) {
2012-04-03 23:34:53 +02:00
return ts > ( RELATIVE_TS_BASE - ( 1LL < < 48 ) ) ;
2012-03-07 22:13:39 +01:00
}
2008-08-10 02:28:56 +02:00
/* fraction handling */
/**
* f = val + ( num / den ) + 0.5 .
*
* ' num ' is normalized so that it is such as 0 < = num < den .
*
* @ param f fractional number
* @ param val integer value
* @ param num must be > = 0
* @ param den must be > = 1
*/
2011-07-15 20:27:43 +02:00
static void frac_init ( AVFrac * f , int64_t val , int64_t num , int64_t den )
2008-08-10 02:28:56 +02:00
{
num + = ( den > > 1 ) ;
if ( num > = den ) {
val + = num / den ;
num = num % den ;
}
f - > val = val ;
f - > num = num ;
f - > den = den ;
}
/**
* Fractional addition to f : f = f + ( incr / f - > den ) .
*
* @ param f fractional number
* @ param incr increment , can be positive or negative
*/
2011-07-15 20:27:43 +02:00
static void frac_add ( AVFrac * f , int64_t incr )
2008-08-10 02:28:56 +02:00
{
int64_t num , den ;
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 ;
}
2006-06-25 19:37:12 +02:00
2008-01-16 23:14:26 +01:00
/** head of registered input format linked list */
2011-02-03 12:47:18 +01:00
static AVInputFormat * first_iformat = NULL ;
2008-01-16 23:14:26 +01:00
/** head of registered output format linked list */
2011-02-03 12:47:18 +01:00
static AVOutputFormat * first_oformat = NULL ;
2001-07-22 16:18:56 +02:00
2007-12-12 20:01:58 +01: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 18:28:47 +02:00
void av_register_input_format ( AVInputFormat * format )
2001-07-22 16:18:56 +02:00
{
2002-05-20 18:28:47 +02: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 16:18:56 +02:00
while ( * p ! = NULL ) p = & ( * p ) - > next ;
* p = format ;
format - > next = NULL ;
}
2010-01-02 00:50:10 +01:00
int av_match_ext ( const char * filename , const char * extensions )
2001-07-22 16:18:56 +02:00
{
const char * ext , * p ;
char ext1 [ 32 ] , * q ;
2004-04-27 04:55:05 +02:00
if ( ! filename )
return 0 ;
2005-12-17 19:14:38 +01:00
2001-07-22 16:18:56 +02:00
ext = strrchr ( filename , ' . ' ) ;
if ( ext ) {
ext + + ;
p = extensions ;
for ( ; ; ) {
q = ext1 ;
2005-12-17 19:14:38 +01:00
while ( * p ! = ' \0 ' & & * p ! = ' , ' & & q - ext1 < sizeof ( ext1 ) - 1 )
2001-07-22 16:18:56 +02:00
* q + + = * p + + ;
* q = ' \0 ' ;
2011-11-02 20:17:25 +01:00
if ( ! av_strcasecmp ( ext1 , ext ) )
2001-07-22 16:18:56 +02:00
return 1 ;
2005-12-17 19:14:38 +01:00
if ( * p = = ' \0 ' )
2001-07-22 16:18:56 +02:00
break ;
p + + ;
}
}
return 0 ;
}
2009-01-17 22:40:27 +01:00
static int match_format ( const char * name , const char * names )
{
const char * p ;
int len , namelen ;
if ( ! name | | ! names )
return 0 ;
namelen = strlen ( name ) ;
while ( ( p = strchr ( names , ' , ' ) ) ) {
len = FFMAX ( p - names , namelen ) ;
2011-11-02 20:17:25 +01:00
if ( ! av_strncasecmp ( name , names , len ) )
2009-01-17 22:40:27 +01:00
return 1 ;
names = p + 1 ;
}
2011-11-02 20:17:25 +01:00
return ! av_strcasecmp ( name , names ) ;
2009-01-17 22:40:27 +01:00
}
2010-01-01 13:46:24 +01:00
AVOutputFormat * av_guess_format ( const char * short_name , const char * filename ,
const char * mime_type )
2001-07-22 16:18:56 +02:00
{
2010-11-13 09:55:15 +01:00
AVOutputFormat * fmt = NULL , * fmt_found ;
2001-07-22 16:18:56 +02:00
int score_max , score ;
2003-01-11 06:02:14 +01:00
/* specific test for image sequences */
2009-01-14 00:44:16 +01:00
# if CONFIG_IMAGE2_MUXER
2005-12-17 19:14:38 +01:00
if ( ! short_name & & filename & &
2006-09-04 11:57:47 +02:00
av_filename_number_test ( filename ) & &
2011-04-05 13:13:53 +02:00
ff_guess_image2_codec ( filename ) ! = CODEC_ID_NONE ) {
2010-01-01 13:58:03 +01:00
return av_guess_format ( " image2 " , NULL , NULL ) ;
2004-11-11 19:09:28 +01:00
}
2006-07-10 23:14:37 +02:00
# endif
2008-01-16 23:14:26 +01:00
/* Find the proper file type. */
2001-07-22 16:18:56 +02:00
fmt_found = NULL ;
score_max = 0 ;
2010-11-13 09:55:15 +01:00
while ( ( fmt = av_oformat_next ( fmt ) ) ) {
2001-07-22 16:18:56 +02:00
score = 0 ;
2012-01-13 11:09:43 +01:00
if ( fmt - > name & & short_name & & match_format ( short_name , fmt - > name ) )
2001-07-22 16:18:56 +02:00
score + = 100 ;
if ( fmt - > mime_type & & mime_type & & ! strcmp ( fmt - > mime_type , mime_type ) )
score + = 10 ;
2005-12-17 19:14:38 +01:00
if ( filename & & fmt - > extensions & &
2010-01-02 00:56:09 +01:00
av_match_ext ( filename , fmt - > extensions ) ) {
2001-07-22 16:18:56 +02:00
score + = 5 ;
}
if ( score > score_max ) {
score_max = score ;
fmt_found = fmt ;
}
}
return fmt_found ;
2005-12-17 19:14:38 +01:00
}
2001-07-22 16:18:56 +02:00
2005-12-17 19:14:38 +01:00
enum CodecID av_guess_codec ( AVOutputFormat * fmt , const char * short_name ,
2010-03-31 01:30:55 +02:00
const char * filename , const char * mime_type , enum AVMediaType type ) {
if ( type = = AVMEDIA_TYPE_VIDEO ) {
2004-11-11 19:09:28 +01:00
enum CodecID codec_id = CODEC_ID_NONE ;
2009-01-14 00:44:16 +01:00
# if CONFIG_IMAGE2_MUXER
2004-11-12 23:51:52 +01:00
if ( ! strcmp ( fmt - > name , " image2 " ) | | ! strcmp ( fmt - > name , " image2pipe " ) ) {
2011-04-05 13:13:53 +02:00
codec_id = ff_guess_image2_codec ( filename ) ;
2004-11-11 19:09:28 +01:00
}
2006-07-10 23:14:37 +02:00
# endif
2004-11-11 19:09:28 +01:00
if ( codec_id = = CODEC_ID_NONE )
codec_id = fmt - > video_codec ;
return codec_id ;
2010-03-31 01:30:55 +02:00
} else if ( type = = AVMEDIA_TYPE_AUDIO )
2004-11-11 19:09:28 +01:00
return fmt - > audio_codec ;
2010-12-04 15:46:13 +01:00
else if ( type = = AVMEDIA_TYPE_SUBTITLE )
return fmt - > subtitle_codec ;
2004-11-11 19:09:28 +01:00
else
return CODEC_ID_NONE ;
}
2002-05-20 18:28:47 +02:00
AVInputFormat * av_find_input_format ( const char * short_name )
{
2010-11-13 09:55:15 +01:00
AVInputFormat * fmt = NULL ;
while ( ( fmt = av_iformat_next ( fmt ) ) ) {
2009-01-17 22:40:27 +01:00
if ( match_format ( short_name , fmt - > name ) )
2002-05-20 18:28:47 +02:00
return fmt ;
}
return NULL ;
}
2011-12-19 11:46:34 +01:00
int ffio_limit ( AVIOContext * s , int size )
2005-05-26 22:17:12 +02:00
{
2011-12-16 15:40:21 +01:00
if ( s - > maxsize > = 0 ) {
2011-12-16 05:54:03 +01:00
int64_t remaining = s - > maxsize - avio_tell ( s ) ;
2011-12-16 15:40:21 +01:00
if ( remaining < size ) {
int64_t newsize = avio_size ( s ) ;
if ( ! s - > maxsize | | s - > maxsize < newsize )
2011-12-31 15:27:51 +01:00
s - > maxsize = newsize - ! newsize ;
2011-12-16 15:40:21 +01:00
remaining = s - > maxsize - avio_tell ( s ) ;
2011-12-25 04:48:26 +01:00
remaining = FFMAX ( remaining , 0 ) ;
2011-12-16 15:40:21 +01:00
}
2011-12-25 04:48:26 +01:00
if ( s - > maxsize > = 0 & & remaining + 1 < size ) {
2011-12-16 15:46:45 +01:00
av_log ( 0 , AV_LOG_ERROR , " Truncating packet of size %d to % " PRId64 " \n " , size , remaining + 1 ) ;
size = remaining + 1 ;
}
2011-12-16 05:54:03 +01:00
}
2011-12-19 11:46:34 +01:00
return size ;
}
int av_get_packet ( AVIOContext * s , AVPacket * pkt , int size )
{
int ret ;
2012-04-30 22:58:27 +02:00
int orig_size = size ;
2011-12-19 11:46:34 +01:00
size = ffio_limit ( s , size ) ;
2011-12-16 05:54:03 +01:00
ret = av_new_packet ( pkt , size ) ;
2005-05-26 22:17:12 +02:00
if ( ret < 0 )
return ret ;
2011-03-03 20:11:45 +01:00
pkt - > pos = avio_tell ( s ) ;
2005-05-26 22:17:12 +02:00
2011-02-21 16:43:01 +01:00
ret = avio_read ( s , pkt - > data , size ) ;
2005-05-26 22:17:12 +02:00
if ( ret < = 0 )
av_free_packet ( pkt ) ;
else
2009-04-08 22:19:12 +02:00
av_shrink_packet ( pkt , ret ) ;
2012-04-30 22:58:27 +02:00
if ( pkt - > size < orig_size )
pkt - > flags | = AV_PKT_FLAG_CORRUPT ;
2005-05-26 22:17:12 +02:00
return ret ;
}
2011-02-20 11:04:12 +01:00
int av_append_packet ( AVIOContext * s , AVPacket * pkt , int size )
2010-11-21 11:24:48 +01:00
{
int ret ;
int old_size ;
if ( ! pkt - > size )
return av_get_packet ( s , pkt , size ) ;
old_size = pkt - > size ;
ret = av_grow_packet ( pkt , size ) ;
if ( ret < 0 )
return ret ;
2011-02-21 16:43:01 +01:00
ret = avio_read ( s , pkt - > data + old_size , size ) ;
2010-11-21 11:24:48 +01:00
av_shrink_packet ( pkt , old_size + FFMAX ( ret , 0 ) ) ;
return ret ;
}
2003-11-10 19:37:55 +01:00
2006-09-04 11:57:47 +02:00
int av_filename_number_test ( const char * filename )
2002-05-20 18:28:47 +02:00
{
char buf [ 1024 ] ;
2006-09-04 11:57:47 +02:00
return filename & & ( av_get_frame_filename ( buf , sizeof ( buf ) , filename , 1 ) > = 0 ) ;
2002-05-20 18:28:47 +02:00
}
2011-03-04 01:12:17 +01:00
AVInputFormat * av_probe_input_format3 ( AVProbeData * pd , int is_opened , int * score_ret )
2002-05-20 18:28:47 +02:00
{
2010-10-06 22:21:07 +02:00
AVProbeData lpd = * pd ;
2010-11-13 09:55:15 +01:00
AVInputFormat * fmt1 = NULL , * fmt ;
2011-11-23 21:56:16 +01:00
int score , nodat = 0 , score_max = 0 ;
2002-05-20 18:28:47 +02:00
2010-10-06 22:21:07 +02:00
if ( lpd . buf_size > 10 & & ff_id3v2_match ( lpd . buf , ID3v2_DEFAULT_MAGIC ) ) {
int id3len = ff_id3v2_tag_len ( lpd . buf ) ;
if ( lpd . buf_size > id3len + 16 ) {
lpd . buf + = id3len ;
lpd . buf_size - = id3len ;
2011-11-23 21:56:16 +01:00
} else
nodat = 1 ;
2010-10-06 22:21:07 +02:00
}
2002-05-20 18:28:47 +02:00
fmt = NULL ;
2010-11-13 09:55:15 +01:00
while ( ( fmt1 = av_iformat_next ( fmt1 ) ) ) {
2007-01-19 23:52:59 +01:00
if ( ! is_opened = = ! ( fmt1 - > flags & AVFMT_NOFILE ) )
2002-05-20 18:28:47 +02:00
continue ;
score = 0 ;
2002-05-24 04:09:40 +02:00
if ( fmt1 - > read_probe ) {
2010-10-06 22:21:07 +02:00
score = fmt1 - > read_probe ( & lpd ) ;
2011-11-23 21:55:25 +01:00
if ( fmt1 - > extensions & & av_match_ext ( lpd . filename , fmt1 - > extensions ) )
2011-11-23 21:56:16 +01:00
score = FFMAX ( score , nodat ? AVPROBE_SCORE_MAX / 4 - 1 : 1 ) ;
2002-05-24 04:09:40 +02:00
} else if ( fmt1 - > extensions ) {
2010-10-06 22:21:07 +02:00
if ( av_match_ext ( lpd . filename , fmt1 - > extensions ) ) {
2002-05-20 18:28:47 +02:00
score = 50 ;
}
2005-12-17 19:14:38 +01:00
}
2011-03-04 01:12:17 +01:00
if ( score > score_max ) {
score_max = score ;
2002-05-20 18:28:47 +02:00
fmt = fmt1 ;
2011-03-04 01:12:17 +01:00
} else if ( score = = score_max )
2008-04-15 15:50:02 +02:00
fmt = NULL ;
2002-05-20 18:28:47 +02:00
}
2011-03-04 01:12:17 +01:00
* score_ret = score_max ;
2011-10-26 03:37:24 +02:00
2002-05-20 18:28:47 +02:00
return fmt ;
}
2011-03-04 01:12:17 +01:00
AVInputFormat * av_probe_input_format2 ( AVProbeData * pd , int is_opened , int * score_max )
{
int score_ret ;
AVInputFormat * fmt = av_probe_input_format3 ( pd , is_opened , & score_ret ) ;
if ( score_ret > * score_max ) {
* score_max = score_ret ;
return fmt ;
} else
return NULL ;
}
2007-03-27 21:28:40 +02:00
AVInputFormat * av_probe_input_format ( AVProbeData * pd , int is_opened ) {
int score = 0 ;
return av_probe_input_format2 ( pd , is_opened , & score ) ;
}
2011-03-04 01:12:17 +01:00
static int set_codec_from_probe_data ( AVFormatContext * s , AVStream * st , AVProbeData * pd )
2008-07-12 15:25:26 +02:00
{
2010-05-22 23:52:02 +02:00
static const struct {
const char * name ; enum CodecID id ; enum AVMediaType type ;
} fmt_id_type [ ] = {
{ " aac " , CODEC_ID_AAC , AVMEDIA_TYPE_AUDIO } ,
{ " ac3 " , CODEC_ID_AC3 , AVMEDIA_TYPE_AUDIO } ,
{ " dts " , CODEC_ID_DTS , AVMEDIA_TYPE_AUDIO } ,
{ " eac3 " , CODEC_ID_EAC3 , AVMEDIA_TYPE_AUDIO } ,
{ " h264 " , CODEC_ID_H264 , AVMEDIA_TYPE_VIDEO } ,
2011-08-20 00:27:54 +02:00
{ " loas " , CODEC_ID_AAC_LATM , AVMEDIA_TYPE_AUDIO } ,
2010-05-22 23:52:02 +02:00
{ " m4v " , CODEC_ID_MPEG4 , AVMEDIA_TYPE_VIDEO } ,
{ " mp3 " , CODEC_ID_MP3 , AVMEDIA_TYPE_AUDIO } ,
{ " mpegvideo " , CODEC_ID_MPEG2VIDEO , AVMEDIA_TYPE_VIDEO } ,
{ 0 }
} ;
2011-03-04 01:12:17 +01:00
int score ;
AVInputFormat * fmt = av_probe_input_format3 ( pd , 1 , & score ) ;
2008-07-12 15:25:26 +02:00
if ( fmt ) {
2010-05-22 23:52:02 +02:00
int i ;
2009-09-17 20:46:50 +02:00
av_log ( s , AV_LOG_DEBUG , " Probe with size=%d, packets=%d detected %s with score=%d \n " ,
pd - > buf_size , MAX_PROBE_PACKETS - st - > probe_packets , fmt - > name , score ) ;
2010-05-22 23:52:02 +02:00
for ( i = 0 ; fmt_id_type [ i ] . name ; i + + ) {
if ( ! strcmp ( fmt - > name , fmt_id_type [ i ] . name ) ) {
st - > codec - > codec_id = fmt_id_type [ i ] . id ;
st - > codec - > codec_type = fmt_id_type [ i ] . type ;
break ;
}
2008-08-25 17:39:43 +02:00
}
2008-07-12 15:25:26 +02:00
}
2011-03-04 01:12:17 +01:00
return score ;
2008-07-12 15:25:26 +02:00
}
2002-05-20 18:28:47 +02:00
/************************************************************/
/* input media file */
2001-09-25 01:25:28 +02:00
2012-01-28 04:23:26 +01:00
int av_demuxer_open ( AVFormatContext * ic ) {
2011-04-30 21:35:48 +02:00
int err ;
if ( ic - > iformat - > read_header ) {
2012-01-28 04:23:26 +01:00
err = ic - > iformat - > read_header ( ic ) ;
2011-04-30 21:35:48 +02:00
if ( err < 0 )
return err ;
}
if ( ic - > pb & & ! ic - > data_offset )
ic - > data_offset = avio_tell ( ic - > pb ) ;
return 0 ;
}
2008-01-16 23:14:26 +01:00
/** size of probe buffer, for guessing file type from file contents */
2006-02-02 12:27:35 +01:00
# define PROBE_BUF_MIN 2048
2006-06-13 13:10:55 +02:00
# define PROBE_BUF_MAX (1<<20)
2002-05-20 18:28:47 +02:00
2011-02-20 11:04:12 +01:00
int av_probe_input_buffer ( AVIOContext * pb , AVInputFormat * * fmt ,
2010-03-14 23:40:16 +01:00
const char * filename , void * logctx ,
unsigned int offset , unsigned int max_probe_size )
{
AVProbeData pd = { filename ? filename : " " , NULL , - offset } ;
unsigned char * buf = NULL ;
int ret = 0 , probe_size ;
if ( ! max_probe_size ) {
max_probe_size = PROBE_BUF_MAX ;
} else if ( max_probe_size > PROBE_BUF_MAX ) {
max_probe_size = PROBE_BUF_MAX ;
} else if ( max_probe_size < PROBE_BUF_MIN ) {
return AVERROR ( EINVAL ) ;
}
if ( offset > = max_probe_size ) {
return AVERROR ( EINVAL ) ;
}
2011-07-29 03:53:19 +02:00
for ( probe_size = PROBE_BUF_MIN ; probe_size < = max_probe_size & & ! * fmt ;
2010-03-26 02:12:14 +01:00
probe_size = FFMIN ( probe_size < < 1 , FFMAX ( max_probe_size , probe_size + 1 ) ) ) {
2011-07-29 03:53:19 +02:00
int score = probe_size < max_probe_size ? AVPROBE_SCORE_MAX / 4 : 0 ;
2010-03-14 23:40:16 +01:00
int buf_offset = ( probe_size = = PROBE_BUF_MIN ) ? 0 : probe_size > > 1 ;
2011-08-27 21:24:13 +02:00
void * buftmp ;
2010-03-14 23:40:16 +01:00
if ( probe_size < offset ) {
continue ;
}
/* read probe data */
2011-08-27 21:24:13 +02:00
buftmp = av_realloc ( buf , probe_size + AVPROBE_PADDING_SIZE ) ;
if ( ! buftmp ) {
av_free ( buf ) ;
return AVERROR ( ENOMEM ) ;
}
buf = buftmp ;
2011-02-21 16:43:01 +01:00
if ( ( ret = avio_read ( pb , buf + buf_offset , probe_size - buf_offset ) ) < 0 ) {
2010-03-14 23:40:16 +01:00
/* fail if error was not end of file, otherwise, lower score */
if ( ret ! = AVERROR_EOF ) {
av_free ( buf ) ;
return ret ;
}
score = 0 ;
2010-03-16 22:45:30 +01:00
ret = 0 ; /* error was end of file, nothing read */
2010-03-14 23:40:16 +01:00
}
pd . buf_size + = ret ;
pd . buf = & buf [ offset ] ;
memset ( pd . buf + pd . buf_size , 0 , AVPROBE_PADDING_SIZE ) ;
/* guess file format */
* fmt = av_probe_input_format2 ( & pd , 1 , & score ) ;
if ( * fmt ) {
if ( score < = AVPROBE_SCORE_MAX / 4 ) { //this can only be true in the last iteration
2011-04-19 11:50:27 +02:00
av_log ( logctx , AV_LOG_WARNING , " Format %s detected only with low score of %d, misdetection possible! \n " , ( * fmt ) - > name , score ) ;
2010-03-14 23:40:16 +01:00
} else
2011-04-19 11:50:27 +02:00
av_log ( logctx , AV_LOG_DEBUG , " Format %s probed with size=%d and score=%d \n " , ( * fmt ) - > name , probe_size , score ) ;
2010-03-14 23:40:16 +01:00
}
}
2010-03-26 02:12:14 +01:00
if ( ! * fmt ) {
2010-04-08 11:02:27 +02:00
av_free ( buf ) ;
2010-03-26 02:12:14 +01:00
return AVERROR_INVALIDDATA ;
}
2010-04-08 11:02:27 +02:00
/* rewind. reuse probe buffer to avoid seeking */
2011-03-06 20:08:30 +01:00
if ( ( ret = ffio_rewind_with_probe_data ( pb , buf , pd . buf_size ) ) < 0 )
2010-04-08 11:02:27 +02:00
av_free ( buf ) ;
2010-03-14 23:40:16 +01:00
2010-04-08 11:02:27 +02:00
return ret ;
2010-03-14 23:40:16 +01:00
}
2011-05-22 08:37:25 +02:00
/* open input file and probe the format if necessary */
2011-11-05 12:30:21 +01:00
static int init_input ( AVFormatContext * s , const char * filename , AVDictionary * * options )
2011-05-22 08:37:25 +02:00
{
int ret ;
AVProbeData pd = { filename , NULL , 0 } ;
if ( s - > pb ) {
s - > flags | = AVFMT_FLAG_CUSTOM_IO ;
if ( ! s - > iformat )
2012-03-19 13:24:04 +01:00
return av_probe_input_buffer ( s - > pb , & s - > iformat , filename , s , 0 , s - > probesize ) ;
2011-05-22 08:37:25 +02:00
else if ( s - > iformat - > flags & AVFMT_NOFILE )
2011-06-22 18:25:49 +02:00
av_log ( s , AV_LOG_WARNING , " Custom AVIOContext makes no sense and "
" will be ignored with AVFMT_NOFILE format. \n " ) ;
2011-05-22 08:37:25 +02:00
return 0 ;
2001-07-22 16:18:56 +02:00
}
2011-05-22 08:37:25 +02:00
if ( ( s - > iformat & & s - > iformat - > flags & AVFMT_NOFILE ) | |
( ! s - > iformat & & ( s - > iformat = av_probe_input_format ( & pd , 0 ) ) ) )
return 0 ;
2012-03-25 11:58:55 +02:00
if ( ( ret = avio_open2 ( & s - > pb , filename , AVIO_FLAG_READ | s - > avio_flags ,
2011-11-05 12:30:21 +01:00
& s - > interrupt_callback , options ) ) < 0 )
2011-08-23 03:47:24 +02:00
return ret ;
2011-05-22 08:37:25 +02:00
if ( s - > iformat )
return 0 ;
2012-03-19 13:24:04 +01:00
return av_probe_input_buffer ( s - > pb , & s - > iformat , filename , s , 0 , s - > probesize ) ;
2011-05-22 08:37:25 +02:00
}
2012-02-25 18:05:55 +01:00
static AVPacket * add_to_pktbuf ( AVPacketList * * packet_buffer , AVPacket * pkt ,
AVPacketList * * plast_pktl ) {
AVPacketList * pktl = av_mallocz ( sizeof ( AVPacketList ) ) ;
if ( ! pktl )
return NULL ;
if ( * packet_buffer )
( * plast_pktl ) - > next = pktl ;
else
* packet_buffer = pktl ;
/* add the packet in the buffered packet list */
* plast_pktl = pktl ;
pktl - > pkt = * pkt ;
return & pktl - > pkt ;
}
2012-03-18 17:34:14 +01:00
static void queue_attached_pictures ( AVFormatContext * s )
{
int i ;
for ( i = 0 ; i < s - > nb_streams ; i + + )
2012-03-18 17:35:49 +01:00
if ( s - > streams [ i ] - > disposition & AV_DISPOSITION_ATTACHED_PIC & &
s - > streams [ i ] - > discard < AVDISCARD_ALL ) {
2012-03-18 17:34:14 +01:00
AVPacket copy = s - > streams [ i ] - > attached_pic ;
copy . destruct = NULL ;
add_to_pktbuf ( & s - > raw_packet_buffer , & copy , & s - > raw_packet_buffer_end ) ;
}
}
2011-05-22 08:37:25 +02:00
int avformat_open_input ( AVFormatContext * * ps , const char * filename , AVInputFormat * fmt , AVDictionary * * options )
{
AVFormatContext * s = * ps ;
2012-03-18 17:34:14 +01:00
int ret = 0 ;
2011-05-22 08:37:25 +02:00
AVDictionary * tmp = NULL ;
2012-02-25 09:53:35 +01:00
ID3v2ExtraMeta * id3v2_extra_meta = NULL ;
2011-05-22 08:37:25 +02:00
if ( ! s & & ! ( s = avformat_alloc_context ( ) ) )
return AVERROR ( ENOMEM ) ;
2012-04-18 13:49:07 +02:00
if ( ! s - > av_class ) {
av_log ( 0 , AV_LOG_ERROR , " Input context has not been properly allocated by avformat_alloc_context() and is not NULL either \n " ) ;
return AVERROR ( EINVAL ) ;
}
2011-05-22 08:37:25 +02:00
if ( fmt )
s - > iformat = fmt ;
if ( options )
av_dict_copy ( & tmp , * options , 0 ) ;
if ( ( ret = av_opt_set_dict ( s , & tmp ) ) < 0 )
goto fail ;
2011-11-05 12:30:21 +01:00
if ( ( ret = init_input ( s , filename , & tmp ) ) < 0 )
2011-05-22 08:37:25 +02:00
goto fail ;
/* check filename in case an image number is expected */
if ( s - > iformat - > flags & AVFMT_NEEDNUMBER ) {
if ( ! av_filename_number_test ( filename ) ) {
ret = AVERROR ( EINVAL ) ;
2001-09-25 01:25:28 +02:00
goto fail ;
2002-05-20 18:28:47 +02:00
}
2011-05-22 08:37:25 +02:00
}
s - > duration = s - > start_time = AV_NOPTS_VALUE ;
2012-06-15 19:58:11 +02:00
av_strlcpy ( s - > filename , filename ? filename : " " , sizeof ( s - > filename ) ) ;
2011-05-22 08:37:25 +02:00
/* allocate private data */
if ( s - > iformat - > priv_data_size > 0 ) {
if ( ! ( s - > priv_data = av_mallocz ( s - > iformat - > priv_data_size ) ) ) {
ret = AVERROR ( ENOMEM ) ;
2010-03-14 23:40:16 +01:00
goto fail ;
2002-11-18 18:17:27 +01:00
}
2011-05-22 08:37:25 +02:00
if ( s - > iformat - > priv_class ) {
* ( const AVClass * * ) s - > priv_data = s - > iformat - > priv_class ;
av_opt_set_defaults ( s - > priv_data ) ;
if ( ( ret = av_opt_set_dict ( s - > priv_data , & tmp ) ) < 0 )
goto fail ;
}
2002-05-20 18:28:47 +02:00
}
2011-05-22 08:37:25 +02:00
/* e.g. AVFMT_NOFILE formats will not have a AVIOContext */
if ( s - > pb )
2012-02-25 09:53:59 +01:00
ff_id3v2_read ( s , ID3v2_DEFAULT_MAGIC , & id3v2_extra_meta ) ;
2005-12-17 19:14:38 +01:00
2011-06-18 04:40:18 +02:00
if ( ! ( s - > flags & AVFMT_FLAG_PRIV_OPT ) & & s - > iformat - > read_header )
2012-01-12 13:20:36 +01:00
if ( ( ret = s - > iformat - > read_header ( s ) ) < 0 )
2003-10-29 15:20:56 +01:00
goto fail ;
2011-05-22 08:37:25 +02:00
2012-02-25 09:53:35 +01:00
if ( id3v2_extra_meta & &
( ret = ff_id3v2_parse_apic ( s , & id3v2_extra_meta ) ) < 0 )
goto fail ;
ff_id3v2_free_extra_meta ( & id3v2_extra_meta ) ;
2012-03-18 17:34:14 +01:00
queue_attached_pictures ( s ) ;
2012-02-25 18:05:55 +01:00
2011-06-18 04:40:18 +02:00
if ( ! ( s - > flags & AVFMT_FLAG_PRIV_OPT ) & & s - > pb & & ! s - > data_offset )
2011-05-22 08:37:25 +02:00
s - > data_offset = avio_tell ( s - > pb ) ;
s - > raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE ;
if ( options ) {
av_dict_free ( options ) ;
* options = tmp ;
2003-01-11 06:02:14 +01:00
}
2011-05-22 08:37:25 +02:00
* ps = s ;
2002-05-20 18:28:47 +02:00
return 0 ;
2005-12-17 19:14:38 +01:00
2011-05-22 08:37:25 +02:00
fail :
2012-02-25 09:53:35 +01:00
ff_id3v2_free_extra_meta ( & id3v2_extra_meta ) ;
2011-05-22 08:37:25 +02:00
av_dict_free ( & tmp ) ;
if ( s - > pb & & ! ( s - > flags & AVFMT_FLAG_CUSTOM_IO ) )
avio_close ( s - > pb ) ;
avformat_free_context ( s ) ;
* ps = NULL ;
return ret ;
2001-07-22 16:18:56 +02:00
}
2003-10-29 15:20:56 +01:00
/*******************************************************/
2012-06-05 01:07:48 +02:00
static void probe_codec ( AVFormatContext * s , AVStream * st , const AVPacket * pkt )
{
2012-06-05 22:43:44 +02:00
if ( st - > request_probe > 0 ) {
2012-06-05 01:07:48 +02:00
AVProbeData * pd = & st - > probe_data ;
2012-06-05 22:43:44 +02:00
int end ;
av_log ( s , AV_LOG_DEBUG , " probing stream %d pp:%d \n " , st - > index , st - > probe_packets ) ;
2012-06-05 01:07:48 +02:00
- - st - > probe_packets ;
2012-06-05 01:58:48 +02:00
if ( pkt ) {
pd - > buf = av_realloc ( pd - > buf , pd - > buf_size + pkt - > size + AVPROBE_PADDING_SIZE ) ;
memcpy ( pd - > buf + pd - > buf_size , pkt - > data , pkt - > size ) ;
pd - > buf_size + = pkt - > size ;
memset ( pd - > buf + pd - > buf_size , 0 , AVPROBE_PADDING_SIZE ) ;
} else {
st - > probe_packets = 0 ;
}
2012-06-05 01:07:48 +02:00
2012-06-05 22:43:44 +02:00
end = s - > raw_packet_buffer_remaining_size < = 0
| | st - > probe_packets < = 0 ;
if ( end | | av_log2 ( pd - > buf_size ) ! = av_log2 ( pd - > buf_size - pkt - > size ) ) {
int score = set_codec_from_probe_data ( s , st , pd ) ;
if ( ( st - > codec - > codec_id ! = CODEC_ID_NONE & & score > AVPROBE_SCORE_MAX / 4 )
| | end ) {
2012-06-05 01:07:48 +02:00
pd - > buf_size = 0 ;
av_freep ( & pd - > buf ) ;
2012-06-05 22:43:44 +02:00
st - > request_probe = - 1 ;
if ( st - > codec - > codec_id ! = CODEC_ID_NONE ) {
av_log ( s , AV_LOG_DEBUG , " probed stream %d \n " , st - > index ) ;
} else
av_log ( s , AV_LOG_WARNING , " probed stream %d failed \n " , st - > index ) ;
2012-06-05 01:07:48 +02:00
}
}
}
}
2012-03-04 21:41:59 +01:00
int ff_read_packet ( AVFormatContext * s , AVPacket * pkt )
2003-11-10 19:37:55 +01:00
{
2009-05-31 02:24:06 +02:00
int ret , i ;
2007-12-19 11:56:17 +01:00
AVStream * st ;
2008-07-12 20:42:00 +02:00
for ( ; ; ) {
AVPacketList * pktl = s - > raw_packet_buffer ;
if ( pktl ) {
* pkt = pktl - > pkt ;
2012-06-05 01:58:48 +02:00
st = s - > streams [ pkt - > stream_index ] ;
2012-06-05 22:43:44 +02:00
if ( st - > request_probe < = 0 ) {
2008-07-12 20:42:00 +02:00
s - > raw_packet_buffer = pktl - > next ;
2009-06-25 20:48:57 +02:00
s - > raw_packet_buffer_remaining_size + = pkt - > size ;
2008-07-12 20:42:00 +02:00
av_free ( pktl ) ;
return 0 ;
}
}
2008-07-12 20:43:02 +02:00
av_init_packet ( pkt ) ;
ret = s - > iformat - > read_packet ( s , pkt ) ;
2009-05-31 02:24:06 +02:00
if ( ret < 0 ) {
if ( ! pktl | | ret = = AVERROR ( EAGAIN ) )
return ret ;
2012-06-05 01:58:48 +02:00
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
st = s - > streams [ i ] ;
if ( st - > probe_packets ) {
probe_codec ( s , st , NULL ) ;
}
2012-06-05 22:43:44 +02:00
av_assert0 ( st - > request_probe < = 0 ) ;
2012-06-05 01:58:48 +02:00
}
2009-05-31 02:24:06 +02:00
continue ;
}
2011-04-20 03:25:48 +02:00
2011-07-24 16:28:33 +02:00
if ( ( s - > flags & AVFMT_FLAG_DISCARD_CORRUPT ) & &
( pkt - > flags & AV_PKT_FLAG_CORRUPT ) ) {
av_log ( s , AV_LOG_WARNING ,
" Dropped corrupted packet (stream = %d) \n " ,
pkt - > stream_index ) ;
2011-10-18 12:00:48 +02:00
av_free_packet ( pkt ) ;
2011-07-24 16:28:33 +02:00
continue ;
}
2011-05-21 02:17:10 +02:00
if ( ! ( s - > flags & AVFMT_FLAG_KEEP_SIDE_DATA ) )
av_packet_merge_side_data ( pkt ) ;
2011-08-02 22:07:51 +02:00
2011-10-12 01:04:12 +02:00
if ( pkt - > stream_index > = ( unsigned ) s - > nb_streams ) {
av_log ( s , AV_LOG_ERROR , " Invalid stream index %d \n " , pkt - > stream_index ) ;
continue ;
}
2008-07-12 20:43:02 +02:00
st = s - > streams [ pkt - > stream_index ] ;
2007-12-19 11:56:17 +01:00
2008-07-12 20:43:02 +02:00
switch ( st - > codec - > codec_type ) {
2010-03-31 01:30:55 +02:00
case AVMEDIA_TYPE_VIDEO :
2008-07-12 20:43:02 +02:00
if ( s - > video_codec_id ) st - > codec - > codec_id = s - > video_codec_id ;
break ;
2010-03-31 01:30:55 +02:00
case AVMEDIA_TYPE_AUDIO :
2008-07-12 20:43:02 +02:00
if ( s - > audio_codec_id ) st - > codec - > codec_id = s - > audio_codec_id ;
break ;
2010-03-31 01:30:55 +02:00
case AVMEDIA_TYPE_SUBTITLE :
2008-07-12 20:43:02 +02:00
if ( s - > subtitle_codec_id ) st - > codec - > codec_id = s - > subtitle_codec_id ;
break ;
}
2007-12-19 11:56:17 +01:00
2011-03-04 01:12:17 +01:00
if ( ! pktl & & st - > request_probe < = 0 )
2008-07-14 22:31:17 +02:00
return ret ;
2008-08-07 00:17:38 +02:00
add_to_pktbuf ( & s - > raw_packet_buffer , pkt , & s - > raw_packet_buffer_end ) ;
2009-06-25 20:48:57 +02:00
s - > raw_packet_buffer_remaining_size - = pkt - > size ;
2008-07-14 22:31:17 +02:00
2012-06-05 01:07:48 +02:00
probe_codec ( s , st , pkt ) ;
2008-07-12 20:42:00 +02:00
}
2003-11-10 19:37:55 +01:00
}
2012-03-04 21:41:59 +01:00
# if FF_API_READ_PACKET
int av_read_packet ( AVFormatContext * s , AVPacket * pkt )
{
return ff_read_packet ( s , pkt ) ;
}
# endif
2003-11-10 19:37:55 +01:00
/**********************************************************/
2012-03-04 04:06:15 +01:00
static int determinable_frame_size ( AVCodecContext * avctx )
{
2012-04-04 18:21:37 +02:00
if ( /*avctx->codec_id == CODEC_ID_AAC ||*/
2012-03-04 04:06:15 +01:00
avctx - > codec_id = = CODEC_ID_MP1 | |
2012-04-04 18:21:37 +02:00
avctx - > codec_id = = CODEC_ID_MP2 | |
2012-03-06 03:56:25 +01:00
avctx - > codec_id = = CODEC_ID_MP3 /* ||
avctx - > codec_id = = CODEC_ID_CELT */ )
2012-03-04 04:06:15 +01:00
return 1 ;
return 0 ;
}
2005-06-28 14:55:08 +02:00
/**
2008-01-16 23:14:26 +01:00
* Get the number of samples of an audio frame . Return - 1 on error .
2005-06-28 14:55:08 +02:00
*/
2012-02-27 21:54:41 +01:00
static int get_audio_frame_size ( AVCodecContext * enc , int size , int mux )
2003-11-10 19:37:55 +01:00
{
int frame_size ;
2012-02-27 21:54:41 +01:00
/* give frame_size priority if demuxing */
if ( ! mux & & enc - > frame_size > 1 )
return enc - > frame_size ;
2006-07-07 19:50:09 +02:00
2012-02-27 21:54:41 +01:00
if ( ( frame_size = av_get_audio_frame_duration ( enc , size ) ) > 0 )
return frame_size ;
/* fallback to using frame_size if muxing */
if ( enc - > frame_size > 1 )
return enc - > frame_size ;
return - 1 ;
2003-11-10 19:37:55 +01:00
}
2005-06-28 14:55:08 +02:00
/**
2008-01-16 23:14:26 +01:00
* Return the frame duration in seconds . Return 0 if not available .
2005-06-28 14:55:08 +02:00
*/
2005-12-17 19:14:38 +01:00
static void compute_frame_duration ( int * pnum , int * pden , AVStream * st ,
2003-11-10 19:37:55 +01:00
AVCodecParserContext * pc , AVPacket * pkt )
{
int frame_size ;
* pnum = 0 ;
* pden = 0 ;
2005-07-18 00:24:36 +02:00
switch ( st - > codec - > codec_type ) {
2010-03-31 01:30:55 +02:00
case AVMEDIA_TYPE_VIDEO :
2011-12-01 02:44:19 +01:00
if ( st - > r_frame_rate . num & & ! pc ) {
2011-11-28 10:02:21 +01:00
* pnum = st - > r_frame_rate . den ;
* pden = st - > r_frame_rate . num ;
} else if ( st - > time_base . num * 1000LL > st - > time_base . den ) {
2005-04-30 23:43:59 +02:00
* pnum = st - > time_base . num ;
* pden = st - > time_base . den ;
2005-07-18 00:24:36 +02: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 22:26:50 +02:00
if ( pc & & pc - > repeat_pict ) {
2009-02-24 21:17:02 +01:00
* pnum = ( * pnum ) * ( 1 + pc - > repeat_pict ) ;
2005-05-06 22:26:50 +02:00
}
2010-04-10 00:39:39 +02:00
//If this codec can be interlaced or progressive then we need a parser to compute duration of a packet
//Thus if we have no parser in such case leave duration undefined.
if ( st - > codec - > ticks_per_frame > 1 & & ! pc ) {
* pnum = * pden = 0 ;
}
2003-11-10 19:37:55 +01:00
}
break ;
2010-03-31 01:30:55 +02:00
case AVMEDIA_TYPE_AUDIO :
2012-02-27 21:54:41 +01:00
frame_size = get_audio_frame_size ( st - > codec , pkt - > size , 0 ) ;
2011-01-06 04:30:19 +01:00
if ( frame_size < = 0 | | st - > codec - > sample_rate < = 0 )
2003-11-10 19:37:55 +01:00
break ;
* pnum = frame_size ;
2005-07-18 00:24:36 +02:00
* pden = st - > codec - > sample_rate ;
2003-11-10 19:37:55 +01:00
break ;
default :
break ;
}
}
2004-10-22 03:51:17 +02:00
static int is_intra_only ( AVCodecContext * enc ) {
2010-03-31 01:30:55 +02:00
if ( enc - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
2004-10-22 03:51:17 +02:00
return 1 ;
2010-03-31 01:30:55 +02:00
} else if ( enc - > codec_type = = AVMEDIA_TYPE_VIDEO ) {
2004-10-22 03:51:17 +02:00
switch ( enc - > codec_id ) {
case CODEC_ID_MJPEG :
case CODEC_ID_MJPEGB :
case CODEC_ID_LJPEG :
2011-09-23 00:10:29 +02:00
case CODEC_ID_PRORES :
2004-10-22 03:51:17 +02:00
case CODEC_ID_RAWVIDEO :
2012-02-28 15:16:41 +01:00
case CODEC_ID_V210 :
2004-10-22 03:51:17 +02:00
case CODEC_ID_DVVIDEO :
case CODEC_ID_HUFFYUV :
2004-11-28 19:29:38 +01:00
case CODEC_ID_FFVHUFF :
2004-10-22 03:51:17 +02:00
case CODEC_ID_ASV1 :
case CODEC_ID_ASV2 :
case CODEC_ID_VCR1 :
2008-10-23 19:30:36 +02:00
case CODEC_ID_DNXHD :
2009-01-18 01:47:46 +01:00
case CODEC_ID_JPEG2000 :
2012-05-15 12:51:12 +02:00
case CODEC_ID_MDEC :
2012-03-05 21:29:23 +01:00
case CODEC_ID_UTVIDEO :
2004-10-22 03:51:17 +02:00
return 1 ;
default : break ;
}
}
return 0 ;
}
2012-03-06 03:56:25 +01:00
static AVPacketList * get_next_pkt ( AVFormatContext * s , AVStream * st , AVPacketList * pktl )
{
if ( pktl - > next )
return pktl - > next ;
if ( pktl = = s - > parse_queue_end )
return s - > packet_buffer ;
return NULL ;
}
2007-09-03 09:56:26 +02:00
static void update_initial_timestamps ( AVFormatContext * s , int stream_index ,
int64_t dts , int64_t pts )
{
2007-08-05 00:46:13 +02:00
AVStream * st = s - > streams [ stream_index ] ;
2012-03-06 03:56:25 +01:00
AVPacketList * pktl = s - > parse_queue ? s - > parse_queue : s - > packet_buffer ;
2007-08-05 00:46:13 +02:00
2012-03-07 22:13:39 +01:00
if ( st - > first_dts ! = AV_NOPTS_VALUE | | dts = = AV_NOPTS_VALUE | | st - > cur_dts = = AV_NOPTS_VALUE | | is_relative ( dts ) )
2007-08-05 00:46:13 +02:00
return ;
2012-03-07 22:13:39 +01:00
st - > first_dts = dts - ( st - > cur_dts - RELATIVE_TS_BASE ) ;
2007-08-05 00:46:13 +02:00
st - > cur_dts = dts ;
2012-03-07 22:13:39 +01:00
if ( is_relative ( pts ) )
pts + = st - > first_dts - RELATIVE_TS_BASE ;
2012-03-06 03:56:25 +01:00
for ( ; pktl ; pktl = get_next_pkt ( s , st , pktl ) ) {
2007-08-05 00:46:13 +02:00
if ( pktl - > pkt . stream_index ! = stream_index )
continue ;
2012-03-07 22:13:39 +01:00
if ( is_relative ( pktl - > pkt . pts ) )
pktl - > pkt . pts + = st - > first_dts - RELATIVE_TS_BASE ;
2007-08-05 00:46:13 +02:00
2012-03-07 22:13:39 +01:00
if ( is_relative ( pktl - > pkt . dts ) )
pktl - > pkt . dts + = st - > first_dts - RELATIVE_TS_BASE ;
2007-08-05 00:54:46 +02:00
if ( st - > start_time = = AV_NOPTS_VALUE & & pktl - > pkt . pts ! = AV_NOPTS_VALUE )
st - > start_time = pktl - > pkt . pts ;
2007-08-05 00:46:13 +02:00
}
2007-09-03 09:56:26 +02:00
if ( st - > start_time = = AV_NOPTS_VALUE )
st - > start_time = pts ;
2007-08-05 00:46:13 +02:00
}
2012-02-28 00:07:07 +01:00
static void update_initial_durations ( AVFormatContext * s , AVStream * st ,
int stream_index , int duration )
2008-02-15 21:32:32 +01:00
{
2012-03-06 03:56:25 +01:00
AVPacketList * pktl = s - > parse_queue ? s - > parse_queue : s - > packet_buffer ;
2012-03-07 22:13:39 +01:00
int64_t cur_dts = RELATIVE_TS_BASE ;
2008-06-03 02:50:22 +02:00
if ( st - > first_dts ! = AV_NOPTS_VALUE ) {
cur_dts = st - > first_dts ;
2012-03-06 03:56:25 +01:00
for ( ; pktl ; pktl = get_next_pkt ( s , st , pktl ) ) {
2012-02-28 00:07:07 +01:00
if ( pktl - > pkt . stream_index = = stream_index ) {
2008-06-03 02:50:22 +02:00
if ( pktl - > pkt . pts ! = pktl - > pkt . dts | | pktl - > pkt . dts ! = AV_NOPTS_VALUE | | pktl - > pkt . duration )
break ;
2012-02-28 00:07:07 +01:00
cur_dts - = duration ;
2008-06-03 02:50:22 +02:00
}
}
2012-05-14 17:14:44 +02:00
if ( pktl & & pktl - > pkt . dts ! = st - > first_dts ) {
2012-05-14 17:51:05 +02:00
av_log ( s , AV_LOG_DEBUG , " first_dts %s not matching first dts %s in que \n " , av_ts2str ( st - > first_dts ) , av_ts2str ( pktl - > pkt . dts ) ) ;
2012-05-14 17:14:44 +02:00
return ;
}
if ( ! pktl ) {
2012-05-14 17:51:05 +02:00
av_log ( s , AV_LOG_DEBUG , " first_dts %s but no packet with dts in ques \n " , av_ts2str ( st - > first_dts ) ) ;
2012-05-14 17:14:44 +02:00
return ;
}
2012-03-06 03:56:25 +01:00
pktl = s - > parse_queue ? s - > parse_queue : s - > packet_buffer ;
2008-06-03 02:50:22 +02:00
st - > first_dts = cur_dts ;
2012-03-07 22:13:39 +01:00
} else if ( st - > cur_dts ! = RELATIVE_TS_BASE )
2008-06-03 02:50:22 +02:00
return ;
2008-02-15 21:32:32 +01:00
2012-03-06 03:56:25 +01:00
for ( ; pktl ; pktl = get_next_pkt ( s , st , pktl ) ) {
2012-02-28 00:07:07 +01:00
if ( pktl - > pkt . stream_index ! = stream_index )
2008-02-15 21:32:32 +01:00
continue ;
2012-03-02 06:22:20 +01:00
if ( pktl - > pkt . pts = = pktl - > pkt . dts & & ( pktl - > pkt . dts = = AV_NOPTS_VALUE | | pktl - > pkt . dts = = st - > first_dts )
2008-02-20 04:40:07 +01:00
& & ! pktl - > pkt . duration ) {
2008-06-03 02:50:22 +02:00
pktl - > pkt . dts = cur_dts ;
2008-06-03 02:43:56 +02:00
if ( ! st - > codec - > has_b_frames )
2008-06-03 02:50:22 +02:00
pktl - > pkt . pts = cur_dts ;
2012-03-06 03:56:25 +01:00
// if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO)
2012-02-28 00:07:07 +01:00
pktl - > pkt . duration = duration ;
2008-02-15 21:32:32 +01:00
} else
break ;
2012-03-02 06:22:20 +01:00
cur_dts = pktl - > pkt . dts + pktl - > pkt . duration ;
2008-02-15 21:32:32 +01:00
}
2012-03-02 06:22:20 +01:00
if ( ! pktl )
2008-06-03 02:50:22 +02:00
st - > cur_dts = cur_dts ;
2008-02-15 21:32:32 +01:00
}
2005-12-17 19:14:38 +01:00
static void compute_pkt_fields ( AVFormatContext * s , AVStream * st ,
2003-11-10 19:37:55 +01:00
AVCodecParserContext * pc , AVPacket * pkt )
{
2007-03-17 15:27:01 +01:00
int num , den , presentation_delayed , delay , i ;
2007-04-13 09:50:04 +02:00
int64_t offset ;
2005-12-17 19:14:38 +01:00
2010-03-31 14:55:16 +02:00
if ( s - > flags & AVFMT_FLAG_NOFILLIN )
return ;
2010-01-30 23:55:12 +01:00
if ( ( s - > flags & AVFMT_FLAG_IGNDTS ) & & pkt - > pts ! = AV_NOPTS_VALUE )
pkt - > dts = AV_NOPTS_VALUE ;
2011-04-28 01:40:44 +02:00
if ( st - > codec - > codec_id ! = CODEC_ID_H264 & & pc & & pc - > pict_type = = AV_PICTURE_TYPE_B )
2009-10-03 21:40:52 +02:00
//FIXME Set low_delay = 0 when has_b_frames = 1
2009-06-11 06:30:05 +02:00
st - > codec - > has_b_frames = 1 ;
2008-10-19 00:41:21 +02:00
/* do we have a video B-frame ? */
delay = st - > codec - > has_b_frames ;
presentation_delayed = 0 ;
2011-02-08 03:15:44 +01:00
2008-10-19 00:41:21 +02:00
/* XXX: need has_b_frame, but cannot get it if the codec is
not initialized */
if ( delay & &
2011-04-28 01:40:44 +02:00
pc & & pc - > pict_type ! = AV_PICTURE_TYPE_B )
2008-10-19 00:41:21 +02:00
presentation_delayed = 1 ;
2011-09-20 04:32:46 +02:00
if ( pkt - > pts ! = AV_NOPTS_VALUE & & pkt - > dts ! = AV_NOPTS_VALUE & & pkt - > dts - ( 1LL < < ( st - > pts_wrap_bits - 1 ) ) > pkt - > pts & & st - > pts_wrap_bits < 63 ) {
2007-07-31 17:06:27 +02:00
pkt - > dts - = 1LL < < st - > pts_wrap_bits ;
}
2008-10-19 03:02:48 +02:00
// some mpeg2 in mpeg-ps lack dts (issue171 / input_file.mpg)
// we take the conservative approach and discard both
// Note, if this is misbehaving for a H.264 file then possibly presentation_delayed is not set correctly.
if ( delay = = 1 & & pkt - > dts = = pkt - > pts & & pkt - > dts ! = AV_NOPTS_VALUE & & presentation_delayed ) {
2011-09-14 19:53:59 +02:00
av_log ( s , AV_LOG_DEBUG , " invalid dts/pts combination % " PRIi64 " \n " , pkt - > dts ) ;
2011-11-16 01:19:35 +01:00
pkt - > dts = AV_NOPTS_VALUE ;
2008-10-19 03:02:48 +02:00
}
2003-11-10 19:37:55 +01:00
if ( pkt - > duration = = 0 ) {
2004-05-29 20:50:31 +02:00
compute_frame_duration ( & num , & den , st , pc , pkt ) ;
2003-11-10 19:37:55 +01:00
if ( den & & num ) {
2010-04-05 00:19:42 +02:00
pkt - > duration = av_rescale_rnd ( 1 , num * ( int64_t ) st - > time_base . den , den * ( int64_t ) st - > time_base . num , AV_ROUND_DOWN ) ;
2003-11-10 19:37:55 +01:00
}
}
2012-03-06 03:56:25 +01:00
if ( pkt - > duration ! = 0 & & ( s - > packet_buffer | | s - > parse_queue ) )
update_initial_durations ( s , st , pkt - > stream_index , pkt - > duration ) ;
2003-11-10 19:37:55 +01:00
2008-01-16 23:14:26 +01:00
/* correct timestamps with byte offset if demuxers only have timestamps
on packet boundaries */
2007-04-13 09:50:04 +02: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 ;
}
2009-02-24 23:19:09 +01:00
if ( pc & & pc - > dts_sync_point > = 0 ) {
// we have synchronization info from the parser
int64_t den = st - > codec - > time_base . den * ( int64_t ) st - > time_base . num ;
if ( den > 0 ) {
int64_t num = st - > codec - > time_base . num * ( int64_t ) st - > time_base . den ;
if ( pkt - > dts ! = AV_NOPTS_VALUE ) {
// got DTS from the stream, update reference timestamp
st - > reference_dts = pkt - > dts - pc - > dts_ref_dts_delta * num / den ;
pkt - > pts = pkt - > dts + pc - > pts_dts_delta * num / den ;
} else if ( st - > reference_dts ! = AV_NOPTS_VALUE ) {
// compute DTS based on reference timestamp
pkt - > dts = st - > reference_dts + pc - > dts_ref_dts_delta * num / den ;
pkt - > pts = pkt - > dts + pc - > pts_dts_delta * num / den ;
}
if ( pc - > dts_sync_point > 0 )
st - > reference_dts = pkt - > dts ; // new reference
}
}
2007-06-12 11:29:25 +02:00
/* This may be redundant, but it should not hurt. */
2007-03-17 15:29:00 +01:00
if ( pkt - > dts ! = AV_NOPTS_VALUE & & pkt - > pts ! = AV_NOPTS_VALUE & & pkt - > pts > pkt - > dts )
presentation_delayed = 1 ;
2005-12-17 19:14:38 +01:00
2012-05-13 22:22:35 +02:00
// av_log(NULL, AV_LOG_DEBUG, "IN delayed:%d pts:%s, dts:%s cur_dts:%s st:%d pc:%p duration:%d\n",
// presentation_delayed, av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts), pkt->stream_index, pc, pkt->duration);
2003-11-10 19:37:55 +01:00
/* interpolate PTS and DTS if they are not present */
2009-03-01 04:17:24 +01:00
//We skip H264 currently because delay and has_b_frames are not reliably set
if ( ( delay = = 0 | | ( delay = = 1 & & pc ) ) & & st - > codec - > codec_id ! = CODEC_ID_H264 ) {
2007-03-17 15:29:00 +01:00
if ( presentation_delayed ) {
2008-01-16 23:14:26 +01:00
/* DTS = decompression timestamp */
/* PTS = presentation timestamp */
2007-03-17 15:29:00 +01:00
if ( pkt - > dts = = AV_NOPTS_VALUE )
2008-02-20 21:24:38 +01:00
pkt - > dts = st - > last_IP_pts ;
2007-09-03 09:56:26 +02:00
update_initial_timestamps ( s , pkt - > stream_index , pkt - > dts , pkt - > pts ) ;
2007-03-17 15:29:00 +01:00
if ( pkt - > dts = = AV_NOPTS_VALUE )
pkt - > dts = st - > cur_dts ;
/* this is tricky: the dts must be incremented by the duration
2008-01-16 23:14:26 +01:00
of the frame we are displaying , i . e . the last I - or P - frame */
2008-02-20 21:24:38 +01:00
if ( st - > last_IP_duration = = 0 )
st - > last_IP_duration = pkt - > duration ;
2008-07-09 01:25:01 +02:00
if ( pkt - > dts ! = AV_NOPTS_VALUE )
2008-07-09 01:26:26 +02:00
st - > cur_dts = pkt - > dts + st - > last_IP_duration ;
2008-02-20 21:24:38 +01:00
st - > last_IP_duration = pkt - > duration ;
st - > last_IP_pts = pkt - > pts ;
2007-03-17 15:29:00 +01:00
/* cannot compute PTS if not present (we can compute it only
2008-01-16 23:14:26 +01:00
by knowing the future */
2012-02-28 00:07:07 +01:00
} else if ( pkt - > pts ! = AV_NOPTS_VALUE | |
pkt - > dts ! = AV_NOPTS_VALUE | |
2012-03-06 03:56:25 +01:00
pkt - > duration ) {
2012-02-28 00:07:07 +01:00
int duration = pkt - > duration ;
if ( pkt - > pts ! = AV_NOPTS_VALUE & & duration ) {
int64_t old_diff = FFABS ( st - > cur_dts - duration - pkt - > pts ) ;
2007-03-17 15:29:00 +01:00
int64_t new_diff = FFABS ( st - > cur_dts - pkt - > pts ) ;
2012-04-12 10:13:11 +02:00
if ( old_diff < new_diff & & old_diff < ( duration > > 3 )
2012-07-08 22:18:34 +02:00
& & st - > codec - > codec_type = = AVMEDIA_TYPE_VIDEO
2012-04-12 10:13:11 +02:00
& & ( ! strcmp ( s - > iformat - > name , " mpeg " ) | |
! strcmp ( s - > iformat - > name , " mpegts " ) ) ) {
2012-02-28 00:07:07 +01:00
pkt - > pts + = duration ;
2012-04-12 10:13:11 +02:00
av_log ( s , AV_LOG_WARNING , " Adjusting PTS forward \n " ) ;
2012-05-13 22:22:35 +02:00
// av_log(NULL, AV_LOG_DEBUG, "id:%d old:%"PRId64" new:%"PRId64" dur:%d cur:%s size:%d\n",
// pkt->stream_index, old_diff, new_diff, pkt->duration, av_ts2str(st->cur_dts), pkt->size);
2007-03-17 15:29:00 +01:00
}
2004-12-15 03:36:03 +01:00
}
2005-12-17 19:14:38 +01:00
2007-03-17 15:29:00 +01:00
/* presentation is not delayed : PTS and DTS are the same */
2012-05-05 00:44:48 +02:00
if ( pkt - > pts = = AV_NOPTS_VALUE )
2007-03-17 15:29:00 +01:00
pkt - > pts = pkt - > dts ;
2012-05-05 00:44:48 +02:00
update_initial_timestamps ( s , pkt - > stream_index , pkt - > pts ,
pkt - > pts ) ;
if ( pkt - > pts = = AV_NOPTS_VALUE )
2007-03-17 15:29:00 +01:00
pkt - > pts = st - > cur_dts ;
pkt - > dts = pkt - > pts ;
2012-05-05 00:44:48 +02:00
if ( pkt - > pts ! = AV_NOPTS_VALUE )
2012-02-28 00:07:07 +01:00
st - > cur_dts = pkt - > pts + duration ;
2007-03-17 15:29:00 +01:00
}
2003-11-10 19:37:55 +01:00
}
2007-03-17 15:27:01 +01:00
2008-08-12 19:26:36 +02:00
if ( pkt - > pts ! = AV_NOPTS_VALUE & & delay < = MAX_REORDER_DELAY ) {
2007-03-17 15:27:01 +01:00
st - > pts_buffer [ 0 ] = pkt - > pts ;
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 ] ;
2011-10-05 14:12:42 +02:00
if ( st - > codec - > codec_id = = CODEC_ID_H264 ) { // we skipped it above so we try here
2007-09-03 09:56:26 +02:00
update_initial_timestamps ( s , pkt - > stream_index , pkt - > dts , pkt - > pts ) ; // this should happen on the first packet
2007-08-05 00:46:13 +02:00
}
2007-03-17 15:27:01 +01:00
if ( pkt - > dts > st - > cur_dts )
st - > cur_dts = pkt - > dts ;
}
2012-05-13 22:22:35 +02:00
// av_log(NULL, AV_LOG_ERROR, "OUTdelayed:%d/%d pts:%s, dts:%s cur_dts:%s\n",
// presentation_delayed, delay, av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts));
2005-12-17 19:14:38 +01:00
2003-11-10 19:37:55 +01:00
/* update flags */
2007-10-24 06:54:44 +02:00
if ( is_intra_only ( st - > codec ) )
2010-03-31 14:29:58 +02:00
pkt - > flags | = AV_PKT_FLAG_KEY ;
2009-02-20 00:35:59 +01:00
if ( pc )
pkt - > convergence_duration = pc - > convergence_duration ;
2003-11-10 19:37:55 +01:00
}
2012-03-03 09:43:14 +01:00
static void free_packet_buffer ( AVPacketList * * pkt_buf , AVPacketList * * pkt_buf_end )
{
while ( * pkt_buf ) {
AVPacketList * pktl = * pkt_buf ;
* pkt_buf = pktl - > next ;
av_free_packet ( & pktl - > pkt ) ;
av_freep ( & pktl ) ;
}
* pkt_buf_end = NULL ;
}
2003-11-10 19:37:55 +01:00
2012-03-04 15:49:26 +01:00
/**
* Parse a packet , add all split parts to parse_queue
*
* @ param pkt packet to parse , NULL when flushing the parser at end of stream
*/
static int parse_packet ( AVFormatContext * s , AVPacket * pkt , int stream_index )
2003-11-10 19:37:55 +01:00
{
2012-03-04 15:49:26 +01:00
AVPacket out_pkt = { 0 } , flush_pkt = { 0 } ;
AVStream * st = s - > streams [ stream_index ] ;
uint8_t * data = pkt ? pkt - > data : NULL ;
int size = pkt ? pkt - > size : 0 ;
int ret = 0 , got_output = 0 ;
2003-11-10 19:37:55 +01:00
2012-03-04 15:49:26 +01:00
if ( ! pkt ) {
av_init_packet ( & flush_pkt ) ;
pkt = & flush_pkt ;
got_output = 1 ;
2012-03-25 13:16:48 +02:00
} else if ( ! size & & st - > parser - > flags & PARSER_FLAG_COMPLETE_FRAMES ) {
// preserve 0-size sync packets
compute_pkt_fields ( s , st , st - > parser , pkt ) ;
2012-03-04 15:49:26 +01:00
}
2007-04-22 13:07:35 +02:00
2012-03-04 15:49:26 +01:00
while ( size > 0 | | ( pkt = = & flush_pkt & & got_output ) ) {
int len ;
2007-02-06 00:04:48 +01:00
2012-03-04 15:49:26 +01:00
av_init_packet ( & out_pkt ) ;
len = av_parser_parse2 ( st - > parser , st - > codec ,
& out_pkt . data , & out_pkt . size , data , size ,
pkt - > pts , pkt - > dts , pkt - > pos ) ;
2007-02-06 00:04:48 +01:00
2012-03-04 15:49:26 +01:00
pkt - > pts = pkt - > dts = AV_NOPTS_VALUE ;
/* increment read pointer */
data + = len ;
size - = len ;
got_output = ! ! out_pkt . size ;
if ( ! out_pkt . size )
continue ;
/* set the duration */
out_pkt . duration = 0 ;
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
if ( st - > codec - > sample_rate > 0 ) {
out_pkt . duration = av_rescale_q_rnd ( st - > parser - > duration ,
( AVRational ) { 1 , st - > codec - > sample_rate } ,
st - > time_base ,
AV_ROUND_DOWN ) ;
2003-11-10 19:37:55 +01:00
}
2012-03-04 15:49:26 +01:00
} else if ( st - > codec - > time_base . num ! = 0 & &
st - > codec - > time_base . den ! = 0 ) {
out_pkt . duration = av_rescale_q_rnd ( st - > parser - > duration ,
st - > codec - > time_base ,
st - > time_base ,
AV_ROUND_DOWN ) ;
}
out_pkt . stream_index = st - > index ;
out_pkt . pts = st - > parser - > pts ;
out_pkt . dts = st - > parser - > dts ;
out_pkt . pos = st - > parser - > pos ;
if ( st - > parser - > key_frame = = 1 | |
( st - > parser - > key_frame = = - 1 & &
st - > parser - > pict_type = = AV_PICTURE_TYPE_I ) )
out_pkt . flags | = AV_PKT_FLAG_KEY ;
2012-06-02 21:11:43 +02:00
if ( st - > parser - > key_frame = = - 1 & & st - > parser - > pict_type = = AV_PICTURE_TYPE_NONE & & ( pkt - > flags & AV_PKT_FLAG_KEY ) )
out_pkt . flags | = AV_PKT_FLAG_KEY ;
2012-03-04 15:49:26 +01:00
compute_pkt_fields ( s , st , st - > parser , & out_pkt ) ;
if ( ( s - > iformat - > flags & AVFMT_GENERIC_INDEX ) & &
out_pkt . flags & AV_PKT_FLAG_KEY ) {
2012-03-06 03:56:25 +01:00
int64_t pos = ( st - > parser - > flags & PARSER_FLAG_COMPLETE_FRAMES ) ? out_pkt . pos : st - > parser - > frame_offset ;
2012-03-04 15:49:26 +01:00
ff_reduce_index ( s , st - > index ) ;
2012-03-06 03:56:25 +01:00
av_add_index_entry ( st , pos , out_pkt . dts ,
2012-03-04 15:49:26 +01:00
0 , 0 , AVINDEX_KEYFRAME ) ;
}
if ( out_pkt . data = = pkt - > data & & out_pkt . size = = pkt - > size ) {
out_pkt . destruct = pkt - > destruct ;
pkt - > destruct = NULL ;
}
if ( ( ret = av_dup_packet ( & out_pkt ) ) < 0 )
goto fail ;
if ( ! add_to_pktbuf ( & s - > parse_queue , & out_pkt , & s - > parse_queue_end ) ) {
av_free_packet ( & out_pkt ) ;
ret = AVERROR ( ENOMEM ) ;
goto fail ;
}
}
/* end of the stream => close and free the parser */
if ( pkt = = & flush_pkt ) {
av_parser_close ( st - > parser ) ;
st - > parser = NULL ;
}
fail :
av_free_packet ( pkt ) ;
return ret ;
}
2012-03-03 16:28:32 +01:00
static int read_from_packet_buffer ( AVPacketList * * pkt_buffer ,
AVPacketList * * pkt_buffer_end ,
AVPacket * pkt )
{
AVPacketList * pktl ;
av_assert0 ( * pkt_buffer ) ;
pktl = * pkt_buffer ;
* pkt = pktl - > pkt ;
* pkt_buffer = pktl - > next ;
if ( ! pktl - > next )
* pkt_buffer_end = NULL ;
av_freep ( & pktl ) ;
return 0 ;
}
2011-07-15 20:27:43 +02:00
static int read_frame_internal ( AVFormatContext * s , AVPacket * pkt )
2003-11-10 19:37:55 +01:00
{
2012-03-04 15:49:26 +01:00
int ret = 0 , i , got_packet = 0 ;
2003-11-10 19:37:55 +01:00
2007-04-22 13:07:35 +02:00
av_init_packet ( pkt ) ;
2012-03-04 15:49:26 +01:00
while ( ! got_packet & & ! s - > parse_queue ) {
AVStream * st ;
AVPacket cur_pkt ;
2007-02-06 00:04:48 +01:00
2012-03-04 15:49:26 +01:00
/* read next packet */
2012-03-04 21:41:59 +01:00
ret = ff_read_packet ( s , & cur_pkt ) ;
2012-03-04 15:49:26 +01:00
if ( ret < 0 ) {
if ( ret = = AVERROR ( EAGAIN ) )
2003-11-10 19:37:55 +01:00
return ret ;
2012-03-04 15:49:26 +01:00
/* flush the parsers */
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
st = s - > streams [ i ] ;
if ( st - > parser & & st - > need_parsing )
parse_packet ( s , NULL , st - > index ) ;
2003-12-15 15:45:37 +01:00
}
2012-03-04 15:49:26 +01:00
/* all remaining packets are now in parse_queue =>
* really terminate parsing */
break ;
}
ret = 0 ;
st = s - > streams [ cur_pkt . stream_index ] ;
if ( cur_pkt . pts ! = AV_NOPTS_VALUE & &
cur_pkt . dts ! = AV_NOPTS_VALUE & &
cur_pkt . pts < cur_pkt . dts ) {
2012-05-13 22:22:35 +02:00
av_log ( s , AV_LOG_WARNING , " Invalid timestamps stream=%d, pts=%s, dts=%s, size=%d \n " ,
2012-03-04 15:49:26 +01:00
cur_pkt . stream_index ,
2012-05-13 22:22:35 +02:00
av_ts2str ( cur_pkt . pts ) ,
av_ts2str ( cur_pkt . dts ) ,
2012-03-04 15:49:26 +01:00
cur_pkt . size ) ;
}
if ( s - > debug & FF_FDEBUG_TS )
2012-05-13 22:22:35 +02:00
av_log ( s , AV_LOG_DEBUG , " ff_read_packet stream=%d, pts=%s, dts=%s, size=%d, duration=%d, flags=%d \n " ,
2012-03-04 15:49:26 +01:00
cur_pkt . stream_index ,
2012-05-13 22:22:35 +02:00
av_ts2str ( cur_pkt . pts ) ,
av_ts2str ( cur_pkt . dts ) ,
2012-03-04 15:49:26 +01:00
cur_pkt . size ,
cur_pkt . duration ,
cur_pkt . flags ) ;
if ( st - > need_parsing & & ! st - > parser & & ! ( s - > flags & AVFMT_FLAG_NOPARSE ) ) {
st - > parser = av_parser_init ( st - > codec - > codec_id ) ;
if ( ! st - > parser ) {
2012-03-06 03:56:25 +01:00
av_log ( s , AV_LOG_VERBOSE , " parser not found for codec "
" %s, packets or times may be invalid. \n " ,
avcodec_get_name ( st - > codec - > codec_id ) ) ;
2012-03-04 15:49:26 +01:00
/* no parser available: just output the raw packets */
st - > need_parsing = AVSTREAM_PARSE_NONE ;
} else if ( st - > need_parsing = = AVSTREAM_PARSE_HEADERS ) {
st - > parser - > flags | = PARSER_FLAG_COMPLETE_FRAMES ;
} else if ( st - > need_parsing = = AVSTREAM_PARSE_FULL_ONCE ) {
st - > parser - > flags | = PARSER_FLAG_ONCE ;
2012-05-21 14:32:24 +02:00
} else if ( st - > need_parsing = = AVSTREAM_PARSE_FULL_RAW ) {
st - > parser - > flags | = PARSER_FLAG_USE_CODEC_TS ;
2008-05-23 19:52:42 +02:00
}
2012-03-04 15:49:26 +01:00
}
2008-05-23 19:52:42 +02:00
2012-03-04 15:49:26 +01:00
if ( ! st - > need_parsing | | ! st - > parser ) {
/* no parsing needed: we just output the packet as is */
* pkt = cur_pkt ;
compute_pkt_fields ( s , st , NULL , pkt ) ;
if ( ( s - > iformat - > flags & AVFMT_GENERIC_INDEX ) & &
( pkt - > flags & AV_PKT_FLAG_KEY ) & & pkt - > dts ! = AV_NOPTS_VALUE ) {
ff_reduce_index ( s , st - > index ) ;
av_add_index_entry ( st , pkt - > pos , pkt - > dts , 0 , 0 , AVINDEX_KEYFRAME ) ;
2003-11-10 19:37:55 +01:00
}
2012-03-04 15:49:26 +01:00
got_packet = 1 ;
} else if ( st - > discard < AVDISCARD_ALL ) {
if ( ( ret = parse_packet ( s , & cur_pkt , cur_pkt . stream_index ) ) < 0 )
return ret ;
} else {
/* free packet */
av_free_packet ( & cur_pkt ) ;
2003-11-10 19:37:55 +01:00
}
2012-04-14 00:17:30 +02:00
if ( pkt - > flags & AV_PKT_FLAG_KEY )
st - > skip_to_keyframe = 0 ;
if ( st - > skip_to_keyframe ) {
av_free_packet ( & cur_pkt ) ;
got_packet = 0 ;
}
2003-11-10 19:37:55 +01:00
}
2012-03-04 15:49:26 +01:00
if ( ! got_packet & & s - > parse_queue )
ret = read_from_packet_buffer ( & s - > parse_queue , & s - > parse_queue_end , pkt ) ;
2008-06-09 15:38:56 +02:00
if ( s - > debug & FF_FDEBUG_TS )
2012-05-13 22:22:35 +02:00
av_log ( s , AV_LOG_DEBUG , " read_frame_internal stream=%d, pts=%s, dts=%s, size=%d, duration=%d, flags=%d \n " ,
2006-08-08 21:55:32 +02:00
pkt - > stream_index ,
2012-05-13 22:22:35 +02:00
av_ts2str ( pkt - > pts ) ,
av_ts2str ( pkt - > dts ) ,
2008-06-26 13:28:24 +02:00
pkt - > size ,
2009-10-30 19:17:16 +01:00
pkt - > duration ,
2008-06-26 13:28:24 +02:00
pkt - > flags ) ;
2006-08-08 21:55:32 +02:00
2012-03-04 15:49:26 +01:00
return ret ;
2012-01-05 10:14:07 +01:00
}
2003-11-10 19:37:55 +01:00
int av_read_frame ( AVFormatContext * s , AVPacket * pkt )
2001-07-22 16:18:56 +02:00
{
2012-01-05 10:16:41 +01:00
const int genpts = s - > flags & AVFMT_FLAG_GENPTS ;
int eof = 0 ;
2012-03-07 22:13:39 +01:00
int ret ;
2005-08-15 16:22:43 +02:00
2012-03-07 22:13:39 +01:00
if ( ! genpts ) {
ret = s - > packet_buffer ? read_from_packet_buffer ( & s - > packet_buffer ,
2012-03-03 16:28:32 +01:00
& s - > packet_buffer_end ,
pkt ) :
2012-01-05 10:14:07 +01:00
read_frame_internal ( s , pkt ) ;
2012-03-07 22:13:39 +01:00
goto return_packet ;
}
2012-01-05 10:14:07 +01:00
2012-01-05 10:16:41 +01:00
for ( ; ; ) {
AVPacketList * pktl = s - > packet_buffer ;
2005-08-15 16:22:43 +02:00
if ( pktl ) {
2012-01-05 10:16:41 +01:00
AVPacket * next_pkt = & pktl - > pkt ;
2005-08-15 16:22:43 +02:00
2012-01-05 10:14:07 +01:00
if ( next_pkt - > dts ! = AV_NOPTS_VALUE ) {
2010-06-22 10:48:28 +02:00
int wrap_bits = s - > streams [ next_pkt - > stream_index ] - > pts_wrap_bits ;
2012-04-04 21:01:04 +02:00
// last dts seen for this stream. if any of packets following
// current one had no dts, we will set this to AV_NOPTS_VALUE.
int64_t last_dts = next_pkt - > dts ;
2012-01-05 10:16:41 +01:00
while ( pktl & & next_pkt - > pts = = AV_NOPTS_VALUE ) {
if ( pktl - > pkt . stream_index = = next_pkt - > stream_index & &
2012-04-04 21:01:04 +02:00
( av_compare_mod ( next_pkt - > dts , pktl - > pkt . dts , 2LL < < ( wrap_bits - 1 ) ) < 0 ) ) {
if ( av_compare_mod ( pktl - > pkt . pts , pktl - > pkt . dts , 2LL < < ( wrap_bits - 1 ) ) ) { //not b frame
next_pkt - > pts = pktl - > pkt . dts ;
}
if ( last_dts ! = AV_NOPTS_VALUE ) {
// Once last dts was set to AV_NOPTS_VALUE, we don't change it.
last_dts = pktl - > pkt . dts ;
}
2005-08-15 16:22:43 +02:00
}
2012-01-05 10:16:41 +01:00
pktl = pktl - > next ;
2005-08-15 16:22:43 +02:00
}
2012-04-04 21:01:04 +02:00
if ( eof & & next_pkt - > pts = = AV_NOPTS_VALUE & & last_dts ! = AV_NOPTS_VALUE ) {
// Fixing the last reference frame had none pts issue (For MXF etc).
// We only do this when
// 1. eof.
// 2. we are not able to resolve a pts value for current packet.
// 3. the packets for this stream at the end of the files had valid dts.
next_pkt - > pts = last_dts + next_pkt - > duration ;
}
2005-08-15 16:22:43 +02:00
pktl = s - > packet_buffer ;
}
2005-12-17 19:14:38 +01:00
2012-01-05 10:14:07 +01:00
/* read packet from packet buffer, if there is data */
if ( ! ( next_pkt - > pts = = AV_NOPTS_VALUE & &
2012-03-07 22:13:39 +01:00
next_pkt - > dts ! = AV_NOPTS_VALUE & & ! eof ) ) {
ret = read_from_packet_buffer ( & s - > packet_buffer ,
2012-03-03 16:28:32 +01:00
& s - > packet_buffer_end , pkt ) ;
2012-03-07 22:13:39 +01:00
goto return_packet ;
}
2005-08-15 16:22:43 +02:00
}
2005-12-17 19:14:38 +01:00
2012-01-05 10:14:07 +01:00
ret = read_frame_internal ( s , pkt ) ;
if ( ret < 0 ) {
if ( pktl & & ret ! = AVERROR ( EAGAIN ) ) {
eof = 1 ;
continue ;
} else
return ret ;
2005-08-15 16:22:43 +02:00
}
2012-01-05 10:14:07 +01:00
if ( av_dup_packet ( add_to_pktbuf ( & s - > packet_buffer , pkt ,
& s - > packet_buffer_end ) ) < 0 )
return AVERROR ( ENOMEM ) ;
2003-11-10 19:37:55 +01:00
}
2012-03-07 22:13:39 +01:00
return_packet :
if ( is_relative ( pkt - > dts ) )
pkt - > dts - = RELATIVE_TS_BASE ;
if ( is_relative ( pkt - > pts ) )
pkt - > pts - = RELATIVE_TS_BASE ;
return ret ;
2003-11-10 19:37:55 +01:00
}
/* XXX: suppress the packet queue */
static void flush_packet_queue ( AVFormatContext * s )
{
2012-03-04 15:49:26 +01:00
free_packet_buffer ( & s - > parse_queue , & s - > parse_queue_end ) ;
2012-03-03 09:43:14 +01:00
free_packet_buffer ( & s - > packet_buffer , & s - > packet_buffer_end ) ;
free_packet_buffer ( & s - > raw_packet_buffer , & s - > raw_packet_buffer_end ) ;
2003-11-10 19:37:55 +01:00
2009-06-25 20:48:57 +02:00
s - > raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE ;
2002-05-20 18:28:47 +02:00
}
2003-11-10 19:37:55 +01:00
/*******************************************************/
/* seek support */
2004-01-13 23:02:49 +01:00
int av_find_default_stream_index ( AVFormatContext * s )
{
2008-06-03 17:19:43 +02:00
int first_audio_index = - 1 ;
2004-01-13 23:02:49 +01:00
int i ;
AVStream * st ;
if ( s - > nb_streams < = 0 )
return - 1 ;
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
st = s - > streams [ i ] ;
2012-03-15 09:04:41 +01:00
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_VIDEO & &
! ( st - > disposition & AV_DISPOSITION_ATTACHED_PIC ) ) {
2004-01-13 23:02:49 +01:00
return i ;
}
2010-03-31 01:30:55 +02:00
if ( first_audio_index < 0 & & st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO )
2008-06-03 17:19:43 +02:00
first_audio_index = i ;
2004-01-13 23:02:49 +01:00
}
2008-06-03 17:19:43 +02:00
return first_audio_index > = 0 ? first_audio_index : 0 ;
2004-01-13 23:02:49 +01:00
}
2005-06-28 14:55:08 +02:00
/**
* Flush the frame reader .
*/
2010-03-16 00:15:24 +01:00
void ff_read_frame_flush ( AVFormatContext * s )
2003-11-10 19:37:55 +01:00
{
AVStream * st ;
2009-12-12 16:26:33 +01:00
int i , j ;
2003-11-10 19:37:55 +01:00
flush_packet_queue ( s ) ;
/* for each stream, reset read state */
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
st = s - > streams [ i ] ;
2005-12-17 19:14:38 +01:00
2003-11-10 19:37:55 +01:00
if ( st - > parser ) {
av_parser_close ( st - > parser ) ;
st - > parser = NULL ;
}
2008-02-20 21:24:38 +01:00
st - > last_IP_pts = AV_NOPTS_VALUE ;
2012-03-07 22:13:39 +01:00
if ( st - > first_dts = = AV_NOPTS_VALUE ) st - > cur_dts = RELATIVE_TS_BASE ;
2011-11-03 14:31:01 +01:00
else st - > cur_dts = AV_NOPTS_VALUE ; /* we set the current DTS to an unspecified origin */
2009-02-24 23:19:09 +01:00
st - > reference_dts = AV_NOPTS_VALUE ;
2009-05-31 02:24:06 +02:00
st - > probe_packets = MAX_PROBE_PACKETS ;
2009-12-12 16:26:33 +01:00
for ( j = 0 ; j < MAX_REORDER_DELAY + 1 ; j + + )
st - > pts_buffer [ j ] = AV_NOPTS_VALUE ;
2003-11-10 19:37:55 +01:00
}
}
2011-10-16 15:03:30 +02:00
void ff_update_cur_dts ( AVFormatContext * s , AVStream * ref_st , int64_t timestamp )
{
2004-10-12 12:28:27 +02:00
int i ;
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
2004-10-22 15:15:18 +02:00
AVStream * st = s - > streams [ i ] ;
2004-10-12 12:28:27 +02:00
2005-12-17 19:14:38 +01:00
st - > cur_dts = av_rescale ( timestamp ,
2004-10-22 15:15:18 +02: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 12:28:27 +02:00
}
}
2008-01-13 14:33:37 +01: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 ;
}
}
2011-01-22 10:03:22 +01:00
int ff_add_index_entry ( AVIndexEntry * * index_entries ,
int * nb_index_entries ,
unsigned int * index_entries_allocated_size ,
int64_t pos , int64_t timestamp , int size , int distance , int flags )
2003-11-10 19:37:55 +01:00
{
AVIndexEntry * entries , * ie ;
2004-01-13 23:02:49 +01:00
int index ;
2005-12-17 19:14:38 +01:00
2011-01-22 10:03:22 +01:00
if ( ( unsigned ) * nb_index_entries + 1 > = UINT_MAX / sizeof ( AVIndexEntry ) )
2005-01-08 15:21:33 +01:00
return - 1 ;
2005-12-17 19:14:38 +01:00
2012-03-07 22:13:39 +01:00
if ( is_relative ( timestamp ) ) //FIXME this maintains previous behavior but we should shift by the correct offset once known
timestamp - = RELATIVE_TS_BASE ;
2011-01-22 10:03:22 +01:00
entries = av_fast_realloc ( * index_entries ,
index_entries_allocated_size ,
( * nb_index_entries + 1 ) *
2003-11-10 19:37:55 +01:00
sizeof ( AVIndexEntry ) ) ;
2005-01-08 15:21:33 +01:00
if ( ! entries )
return - 1 ;
2011-01-22 10:03:22 +01:00
* index_entries = entries ;
2004-01-13 23:02:49 +01:00
2011-01-22 10:03:22 +01:00
index = ff_index_search_timestamp ( * index_entries , * nb_index_entries , timestamp , AVSEEK_FLAG_ANY ) ;
2004-01-13 23:02:49 +01:00
2004-10-11 00:05:43 +02:00
if ( index < 0 ) {
2011-01-22 10:03:22 +01:00
index = ( * nb_index_entries ) + + ;
2004-01-17 19:06:52 +01:00
ie = & entries [ index ] ;
2004-10-11 00:05:43 +02:00
assert ( index = = 0 | | ie [ - 1 ] . timestamp < timestamp ) ;
} else {
ie = & entries [ index ] ;
if ( ie - > timestamp ! = timestamp ) {
2004-10-14 01:58:28 +02:00
if ( ie - > timestamp < = timestamp )
return - 1 ;
2011-01-22 10:03:22 +01:00
memmove ( entries + index + 1 , entries + index , sizeof ( AVIndexEntry ) * ( * nb_index_entries - index ) ) ;
( * nb_index_entries ) + + ;
2007-06-12 11:29:25 +02:00
} else if ( ie - > pos = = pos & & distance < ie - > min_distance ) //do not reduce the distance
2004-10-11 00:05:43 +02:00
distance = ie - > min_distance ;
2004-01-17 19:06:52 +01:00
}
2004-10-11 00:05:43 +02:00
2004-01-13 23:02:49 +01:00
ie - > pos = pos ;
ie - > timestamp = timestamp ;
2004-01-17 19:06:52 +01:00
ie - > min_distance = distance ;
2006-03-01 12:29:55 +01:00
ie - > size = size ;
2004-01-13 23:02:49 +01:00
ie - > flags = flags ;
2005-12-17 19:14:38 +01:00
2004-01-17 19:06:52 +01:00
return index ;
2003-11-10 19:37:55 +01:00
}
2011-01-22 10:03:22 +01:00
int av_add_index_entry ( AVStream * st ,
int64_t pos , int64_t timestamp , int size , int distance , int flags )
{
return ff_add_index_entry ( & st - > index_entries , & st - > nb_index_entries ,
& st - > index_entries_allocated_size , pos ,
timestamp , size , distance , flags ) ;
}
int ff_index_search_timestamp ( const AVIndexEntry * entries , int nb_entries ,
int64_t wanted_timestamp , int flags )
2003-11-10 19:37:55 +01:00
{
int a , b , m ;
int64_t timestamp ;
2004-10-11 00:05:43 +02:00
a = - 1 ;
b = nb_entries ;
2004-01-13 23:02:49 +01:00
2010-03-09 16:19:23 +01:00
//optimize appending index entries at the end
if ( b & & entries [ b - 1 ] . timestamp < wanted_timestamp )
a = b - 1 ;
2004-10-11 00:05:43 +02:00
while ( b - a > 1 ) {
m = ( a + b ) > > 1 ;
2003-11-10 19:37:55 +01:00
timestamp = entries [ m ] . timestamp ;
2004-10-11 00:05:43 +02:00
if ( timestamp > = wanted_timestamp )
b = m ;
if ( timestamp < = wanted_timestamp )
2004-01-13 23:02:49 +01:00
a = m ;
2003-11-10 19:37:55 +01:00
}
2005-03-13 01:13:01 +01:00
m = ( flags & AVSEEK_FLAG_BACKWARD ) ? a : b ;
2005-12-17 19:14:38 +01:00
2005-03-13 01:13:01 +01:00
if ( ! ( flags & AVSEEK_FLAG_ANY ) ) {
while ( m > = 0 & & m < nb_entries & & ! ( entries [ m ] . flags & AVINDEX_KEYFRAME ) ) {
m + = ( flags & AVSEEK_FLAG_BACKWARD ) ? - 1 : 1 ;
}
}
2004-10-11 00:05:43 +02:00
2005-12-17 19:14:38 +01:00
if ( m = = nb_entries )
2004-10-11 00:05:43 +02:00
return - 1 ;
return m ;
2003-11-10 19:37:55 +01:00
}
2011-01-22 10:03:22 +01:00
int av_index_search_timestamp ( AVStream * st , int64_t wanted_timestamp ,
int flags )
{
return ff_index_search_timestamp ( st - > index_entries , st - > nb_index_entries ,
wanted_timestamp , flags ) ;
}
2011-10-16 15:03:30 +02:00
int ff_seek_frame_binary ( AVFormatContext * s , int stream_index , int64_t target_ts , int flags )
{
2004-04-12 18:50:03 +02:00
AVInputFormat * avif = s - > iformat ;
2009-03-05 20:15:14 +01:00
int64_t av_uninit ( pos_min ) , av_uninit ( pos_max ) , pos , pos_limit ;
2004-04-12 18:50:03 +02:00
int64_t ts_min , ts_max , ts ;
2006-11-14 02:34:36 +01:00
int index ;
2009-12-06 01:03:53 +01:00
int64_t ret ;
2004-04-12 18:50:03 +02:00
AVStream * st ;
2004-05-23 18:26:12 +02:00
if ( stream_index < 0 )
return - 1 ;
2005-12-17 19:14:38 +01:00
2012-05-13 22:22:35 +02:00
av_dlog ( s , " read_seek: %d %s \n " , stream_index , av_ts2str ( target_ts ) ) ;
2004-04-12 18:50:03 +02:00
ts_max =
ts_min = AV_NOPTS_VALUE ;
2007-06-12 20:50:50 +02:00
pos_limit = - 1 ; //gcc falsely says it may be uninitialized
2004-04-12 18:50:03 +02:00
st = s - > streams [ stream_index ] ;
if ( st - > index_entries ) {
AVIndexEntry * e ;
2008-01-16 23:14:26 +01:00
index = av_index_search_timestamp ( st , target_ts , flags | AVSEEK_FLAG_BACKWARD ) ; //FIXME whole func must be checked for non-keyframe entries in index case, especially read_timestamp()
2004-10-11 00:05:43 +02:00
index = FFMAX ( index , 0 ) ;
2004-04-12 18:50:03 +02:00
e = & st - > index_entries [ index ] ;
if ( e - > timestamp < = target_ts | | e - > pos = = e - > min_distance ) {
pos_min = e - > pos ;
ts_min = e - > timestamp ;
2012-05-13 22:22:35 +02:00
av_dlog ( s , " using cached pos_min=0x% " PRIx64 " dts_min=%s \n " ,
pos_min , av_ts2str ( ts_min ) ) ;
2004-04-12 18:50:03 +02:00
} else {
assert ( index = = 0 ) ;
}
2005-12-17 19:14:38 +01:00
index = av_index_search_timestamp ( st , target_ts , flags & ~ AVSEEK_FLAG_BACKWARD ) ;
2005-03-13 01:13:01 +01:00
assert ( index < st - > nb_index_entries ) ;
if ( index > = 0 ) {
2004-04-12 18:50:03 +02: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 ;
2012-05-13 22:22:35 +02:00
av_dlog ( s , " using cached pos_max=0x% " PRIx64 " pos_limit=0x% " PRIx64 " dts_max=%s \n " ,
pos_max , pos_limit , av_ts2str ( ts_max ) ) ;
2004-04-12 18:50:03 +02:00
}
}
2011-10-16 15:03:30 +02:00
pos = ff_gen_search ( s , stream_index , target_ts , pos_min , pos_max , pos_limit , ts_min , ts_max , flags , & ts , avif - > read_timestamp ) ;
2006-11-14 02:34:36 +01:00
if ( pos < 0 )
return - 1 ;
/* do the seek */
2011-02-28 14:57:54 +01:00
if ( ( ret = avio_seek ( s - > pb , pos , SEEK_SET ) ) < 0 )
2009-12-06 01:03:53 +01:00
return ret ;
2006-11-14 02:34:36 +01:00
2011-10-21 22:26:13 +02:00
ff_read_frame_flush ( s ) ;
2011-10-16 15:03:30 +02:00
ff_update_cur_dts ( s , st , ts ) ;
2006-11-14 02:34:36 +01:00
return 0 ;
}
2011-10-16 15:03:30 +02:00
int64_t ff_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 ) )
{
2006-11-14 02:34:36 +01:00
int64_t pos , ts ;
int64_t start_pos , filesize ;
int no_change ;
2012-05-13 22:22:35 +02:00
av_dlog ( s , " gen_seek: %d %s \n " , stream_index , av_ts2str ( target_ts ) ) ;
2006-11-14 02:34:36 +01:00
2004-04-12 18:50:03 +02:00
if ( ts_min = = AV_NOPTS_VALUE ) {
pos_min = s - > data_offset ;
2006-11-14 02:34:36 +01:00
ts_min = read_timestamp ( s , stream_index , & pos_min , INT64_MAX ) ;
2004-04-12 18:50:03 +02:00
if ( ts_min = = AV_NOPTS_VALUE )
return - 1 ;
}
2011-10-21 20:45:00 +02:00
if ( ts_min > = target_ts ) {
* ts_ret = ts_min ;
return pos_min ;
}
2004-04-12 18:50:03 +02:00
if ( ts_max = = AV_NOPTS_VALUE ) {
int step = 1024 ;
2011-03-04 19:57:36 +01:00
filesize = avio_size ( s - > pb ) ;
2005-07-08 11:14:05 +02:00
pos_max = filesize - 1 ;
2004-04-12 18:50:03 +02:00
do {
pos_max - = step ;
2006-11-14 02:34:36 +01:00
ts_max = read_timestamp ( s , stream_index , & pos_max , pos_max + step ) ;
2004-04-12 18:50:03 +02:00
step + = step ;
} while ( ts_max = = AV_NOPTS_VALUE & & pos_max > = step ) ;
if ( ts_max = = AV_NOPTS_VALUE )
return - 1 ;
2005-12-17 19:14:38 +01:00
2004-04-12 18:50:03 +02:00
for ( ; ; ) {
int64_t tmp_pos = pos_max + 1 ;
2006-11-14 02:34:36 +01:00
int64_t tmp_ts = read_timestamp ( s , stream_index , & tmp_pos , INT64_MAX ) ;
2004-04-12 18:50:03 +02:00
if ( tmp_ts = = AV_NOPTS_VALUE )
break ;
ts_max = tmp_ts ;
pos_max = tmp_pos ;
2005-07-08 11:14:05 +02:00
if ( tmp_pos > = filesize )
break ;
2004-04-12 18:50:03 +02:00
}
pos_limit = pos_max ;
}
2011-10-21 20:45:00 +02:00
if ( ts_max < = target_ts ) {
* ts_ret = ts_max ;
return pos_max ;
}
2006-02-02 20:23:33 +01:00
if ( ts_min > ts_max ) {
return - 1 ;
} else if ( ts_min = = ts_max ) {
pos_limit = pos_min ;
}
2004-04-12 18:50:03 +02:00
no_change = 0 ;
while ( pos_min < pos_limit ) {
2012-05-13 22:22:35 +02:00
av_dlog ( s , " pos_min=0x% " PRIx64 " pos_max=0x% " PRIx64 " dts_min=%s dts_max=%s \n " ,
pos_min , pos_max , av_ts2str ( ts_min ) , av_ts2str ( ts_max ) ) ;
2004-04-12 18:50:03 +02:00
assert ( pos_limit < = pos_max ) ;
if ( no_change = = 0 ) {
int64_t approximate_keyframe_distance = pos_max - pos_limit ;
// interpolate position (better than dichotomy)
2004-10-11 00:05:43 +02:00
pos = av_rescale ( target_ts - ts_min , pos_max - pos_min , ts_max - ts_min )
+ pos_min - approximate_keyframe_distance ;
2004-04-12 18:50:03 +02: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 23:14:26 +01:00
/* linear search if bisection failed, can only happen if there
are very few or no keyframes between min / max */
2004-04-12 18:50:03 +02: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 02:34:36 +01:00
ts = read_timestamp ( s , stream_index , & pos , INT64_MAX ) ; //may pass pos_limit instead of -1
2004-04-12 18:50:03 +02:00
if ( pos = = pos_max )
no_change + + ;
else
no_change = 0 ;
2012-05-13 22:22:35 +02:00
av_dlog ( s , " % " PRId64 " % " PRId64 " % " PRId64 " / %s %s %s target:%s limit:% " PRId64 " start:% " PRId64 " noc:%d \n " ,
pos_min , pos , pos_max ,
av_ts2str ( ts_min ) , av_ts2str ( ts ) , av_ts2str ( ts_max ) , av_ts2str ( target_ts ) ,
2011-06-07 13:18:12 +02:00
pos_limit , start_pos , no_change ) ;
2007-04-22 20:48:07 +02:00
if ( ts = = AV_NOPTS_VALUE ) {
av_log ( s , AV_LOG_ERROR , " read_timestamp() failed in the middle \n " ) ;
return - 1 ;
}
2004-04-12 18:50:03 +02:00
assert ( ts ! = AV_NOPTS_VALUE ) ;
2004-10-11 00:05:43 +02:00
if ( target_ts < = ts ) {
2004-04-12 18:50:03 +02:00
pos_limit = start_pos - 1 ;
pos_max = pos ;
ts_max = ts ;
2004-10-11 00:05:43 +02:00
}
if ( target_ts > = ts ) {
2004-04-12 18:50:03 +02:00
pos_min = pos ;
ts_min = ts ;
}
}
2005-12-17 19:14:38 +01:00
2004-10-11 00:05:43 +02:00
pos = ( flags & AVSEEK_FLAG_BACKWARD ) ? pos_min : pos_max ;
ts = ( flags & AVSEEK_FLAG_BACKWARD ) ? ts_min : ts_max ;
2011-10-21 22:08:39 +02:00
#if 0
2004-04-12 18:50:03 +02:00
pos_min = pos ;
2006-11-14 02:34:36 +01:00
ts_min = read_timestamp ( s , stream_index , & pos_min , INT64_MAX ) ;
2004-04-12 18:50:03 +02:00
pos_min + + ;
2006-11-14 02:34:36 +01:00
ts_max = read_timestamp ( s , stream_index , & pos_min , INT64_MAX ) ;
2012-05-13 22:22:35 +02:00
av_dlog ( s , " pos=0x% " PRIx64 " %s<=%s<=%s \n " ,
pos , av_ts2str ( ts_min ) , av_ts2str ( target_ts ) , av_ts2str ( ts_max ) ) ;
2011-10-21 22:08:39 +02:00
# endif
2006-11-14 02:34:36 +01:00
* ts_ret = ts ;
return pos ;
2004-04-12 18:50:03 +02:00
}
2011-07-15 20:27:43 +02:00
static int seek_frame_byte ( AVFormatContext * s , int stream_index , int64_t pos , int flags ) {
2004-10-11 00:05:43 +02:00
int64_t pos_min , pos_max ;
pos_min = s - > data_offset ;
2011-03-04 19:57:36 +01:00
pos_max = avio_size ( s - > pb ) - 1 ;
2004-10-11 00:05:43 +02:00
if ( pos < pos_min ) pos = pos_min ;
else if ( pos > pos_max ) pos = pos_max ;
2011-02-28 14:57:54 +01:00
avio_seek ( s - > pb , pos , SEEK_SET ) ;
2004-10-11 00:05:43 +02:00
return 0 ;
}
2011-07-15 20:27:43 +02:00
static int seek_frame_generic ( AVFormatContext * s ,
2004-10-11 00:05:43 +02:00
int stream_index , int64_t timestamp , int flags )
2003-11-10 19:37:55 +01:00
{
2009-12-01 23:56:44 +01:00
int index ;
int64_t ret ;
2003-11-10 19:37:55 +01:00
AVStream * st ;
AVIndexEntry * ie ;
st = s - > streams [ stream_index ] ;
2007-02-06 00:04:48 +01:00
2005-03-13 01:13:01 +01:00
index = av_index_search_timestamp ( st , timestamp , flags ) ;
2007-02-06 00:04:48 +01:00
2010-02-04 00:59:48 +01:00
if ( index < 0 & & st - > nb_index_entries & & timestamp < st - > index_entries [ 0 ] . timestamp )
return - 1 ;
2007-04-22 18:23:44 +02:00
if ( index < 0 | | index = = st - > nb_index_entries - 1 ) {
2007-02-06 00:04:48 +01:00
AVPacket pkt ;
2011-10-05 18:23:47 +02:00
int nonkey = 0 ;
2007-02-06 00:04:48 +01:00
2008-05-27 23:44:42 +02:00
if ( st - > nb_index_entries ) {
assert ( st - > index_entries ) ;
2007-02-06 00:04:48 +01:00
ie = & st - > index_entries [ st - > nb_index_entries - 1 ] ;
2011-02-28 14:57:54 +01:00
if ( ( ret = avio_seek ( s - > pb , ie - > pos , SEEK_SET ) ) < 0 )
2008-07-31 20:02:55 +02:00
return ret ;
2011-10-16 15:03:30 +02:00
ff_update_cur_dts ( s , st , ie - > timestamp ) ;
2008-07-31 20:02:55 +02:00
} else {
2011-02-28 14:57:54 +01:00
if ( ( ret = avio_seek ( s - > pb , s - > data_offset , SEEK_SET ) ) < 0 )
2008-07-31 20:02:55 +02:00
return ret ;
}
2011-09-14 00:27:01 +02:00
for ( ; ; ) {
2011-09-14 00:26:25 +02:00
int read_status ;
2009-01-22 13:06:02 +01:00
do {
2011-09-14 00:26:25 +02:00
read_status = av_read_frame ( s , & pkt ) ;
} while ( read_status = = AVERROR ( EAGAIN ) ) ;
if ( read_status < 0 )
2007-02-06 00:04:48 +01:00
break ;
av_free_packet ( & pkt ) ;
2011-10-05 18:23:47 +02:00
if ( stream_index = = pkt . stream_index & & pkt . dts > timestamp ) {
if ( pkt . flags & AV_PKT_FLAG_KEY )
2007-02-06 00:04:48 +01:00
break ;
2011-11-19 01:15:40 +01:00
if ( nonkey + + > 1000 & & st - > codec - > codec_id ! = CODEC_ID_CDGRAPHICS ) {
2011-10-05 18:23:47 +02:00
av_log ( s , AV_LOG_ERROR , " seek_frame_generic failed as this stream seems to contain no keyframes after the target timestamp, %d non keyframes found \n " , nonkey ) ;
break ;
}
2007-02-06 00:04:48 +01:00
}
}
index = av_index_search_timestamp ( st , timestamp , flags ) ;
}
2003-11-10 19:37:55 +01:00
if ( index < 0 )
return - 1 ;
2010-03-16 00:15:24 +01:00
ff_read_frame_flush ( s ) ;
2011-09-14 19:48:59 +02:00
AV_NOWARN_DEPRECATED (
2007-02-06 00:04:48 +01:00
if ( s - > iformat - > read_seek ) {
if ( s - > iformat - > read_seek ( s , stream_index , timestamp , flags ) > = 0 )
return 0 ;
}
2011-09-14 19:48:59 +02:00
)
2007-02-06 00:04:48 +01:00
ie = & st - > index_entries [ index ] ;
2011-02-28 14:57:54 +01:00
if ( ( ret = avio_seek ( s - > pb , ie - > pos , SEEK_SET ) ) < 0 )
2008-07-31 20:02:55 +02:00
return ret ;
2011-10-16 15:03:30 +02:00
ff_update_cur_dts ( s , st , ie - > timestamp ) ;
2004-05-23 18:26:12 +02:00
2003-11-10 19:37:55 +01:00
return 0 ;
}
2012-03-18 17:34:14 +01:00
static int seek_frame_internal ( AVFormatContext * s , int stream_index ,
int64_t timestamp , int flags )
2003-11-10 19:37:55 +01:00
{
int ret ;
2004-05-23 18:26:12 +02:00
AVStream * st ;
2005-12-17 19:14:38 +01:00
2011-09-17 01:02:23 +02:00
if ( flags & AVSEEK_FLAG_BYTE ) {
2011-10-02 17:57:53 +02:00
if ( s - > iformat - > flags & AVFMT_NO_BYTE_SEEK )
return - 1 ;
2011-09-17 01:02:23 +02:00
ff_read_frame_flush ( s ) ;
2011-07-15 20:27:43 +02:00
return seek_frame_byte ( s , stream_index , timestamp , flags ) ;
2011-09-17 01:02:23 +02:00
}
2005-12-17 19:14:38 +01:00
2004-05-23 18:26:12 +02:00
if ( stream_index < 0 ) {
stream_index = av_find_default_stream_index ( s ) ;
if ( stream_index < 0 )
return - 1 ;
2005-12-17 19:14:38 +01:00
2004-10-11 00:05:43 +02:00
st = s - > streams [ stream_index ] ;
2011-08-23 03:47:24 +02:00
/* timestamp for default must be expressed in AV_TIME_BASE units */
2004-10-11 00:05:43 +02:00
timestamp = av_rescale ( timestamp , st - > time_base . den , AV_TIME_BASE * ( int64_t ) st - > time_base . num ) ;
2004-05-23 18:26:12 +02:00
}
2003-11-10 19:37:55 +01:00
/* first, we try the format specific seek */
2011-09-14 19:48:59 +02:00
AV_NOWARN_DEPRECATED (
2011-09-17 01:02:23 +02:00
if ( s - > iformat - > read_seek ) {
ff_read_frame_flush ( s ) ;
2004-10-11 00:05:43 +02:00
ret = s - > iformat - > read_seek ( s , stream_index , timestamp , flags ) ;
2011-09-17 01:02:23 +02:00
} else
2003-11-10 19:37:55 +01:00
ret = - 1 ;
2011-09-14 19:48:59 +02:00
)
2003-11-10 19:37:55 +01:00
if ( ret > = 0 ) {
return 0 ;
}
2004-04-12 18:50:03 +02:00
2011-09-17 01:02:23 +02:00
if ( s - > iformat - > read_timestamp & & ! ( s - > iformat - > flags & AVFMT_NOBINSEARCH ) ) {
ff_read_frame_flush ( s ) ;
2011-10-16 15:03:30 +02:00
return ff_seek_frame_binary ( s , stream_index , timestamp , flags ) ;
2011-09-17 01:02:23 +02:00
} else if ( ! ( s - > iformat - > flags & AVFMT_NOGENSEARCH ) ) {
ff_read_frame_flush ( s ) ;
2011-07-15 20:27:43 +02:00
return seek_frame_generic ( s , stream_index , timestamp , flags ) ;
2011-09-17 01:02:23 +02:00
}
2011-05-17 17:30:05 +02:00
else
return - 1 ;
2003-11-10 19:37:55 +01:00
}
2012-03-18 17:34:14 +01:00
int av_seek_frame ( AVFormatContext * s , int stream_index , int64_t timestamp , int flags )
{
int ret = seek_frame_internal ( s , stream_index , timestamp , flags ) ;
if ( ret > = 0 )
queue_attached_pictures ( s ) ;
return ret ;
}
2009-03-14 16:51:46 +01:00
int avformat_seek_file ( AVFormatContext * s , int stream_index , int64_t min_ts , int64_t ts , int64_t max_ts , int flags )
{
if ( min_ts > ts | | max_ts < ts )
return - 1 ;
2011-09-17 01:02:23 +02:00
if ( s - > iformat - > read_seek2 ) {
2012-03-18 17:34:14 +01:00
int ret ;
2011-09-17 01:02:23 +02:00
ff_read_frame_flush ( s ) ;
2012-03-18 17:34:14 +01:00
ret = s - > iformat - > read_seek2 ( s , stream_index , min_ts , ts , max_ts , flags ) ;
if ( ret > = 0 )
queue_attached_pictures ( s ) ;
return ret ;
2011-09-17 01:02:23 +02:00
}
2009-03-14 16:51:46 +01:00
if ( s - > iformat - > read_timestamp ) {
//try to seek via read_timestamp()
}
//Fallback to old API if new is not implemented but old is
//Note the old has somewat different sematics
2011-09-14 19:48:59 +02:00
AV_NOWARN_DEPRECATED (
2012-02-18 00:16:58 +01:00
if ( s - > iformat - > read_seek | | 1 ) {
int dir = ( ts - min_ts > ( uint64_t ) ( max_ts - ts ) ? AVSEEK_FLAG_BACKWARD : 0 ) ;
int ret = av_seek_frame ( s , stream_index , ts , flags | dir ) ;
if ( ret < 0 & & ts ! = min_ts & & max_ts ! = ts ) {
ret = av_seek_frame ( s , stream_index , dir ? max_ts : min_ts , flags | dir ) ;
if ( ret > = 0 )
ret = av_seek_frame ( s , stream_index , ts , flags | ( dir ^ AVSEEK_FLAG_BACKWARD ) ) ;
}
return ret ;
}
2011-09-14 19:48:59 +02:00
)
2009-03-14 16:51:46 +01:00
2011-07-15 20:27:43 +02:00
// try some generic seek like seek_frame_generic() but with new ts semantics
2009-03-14 16:51:46 +01:00
}
2003-10-29 15:20:56 +01:00
/*******************************************************/
2003-08-08 20:02:23 +02:00
2005-06-28 14:55:08 +02:00
/**
2010-06-30 17:38:06 +02:00
* Return TRUE if the stream has accurate duration in any stream .
2005-06-28 14:55:08 +02:00
*
2007-09-05 18:47:48 +02:00
* @ return TRUE if the stream has accurate duration for at least one component .
2005-06-28 14:55:08 +02:00
*/
2011-07-15 20:27:43 +02:00
static int has_duration ( AVFormatContext * ic )
2003-08-08 20:02:23 +02:00
{
int i ;
AVStream * st ;
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2007-09-05 18:47:48 +02:00
if ( st - > duration ! = AV_NOPTS_VALUE )
2003-08-08 20:02:23 +02:00
return 1 ;
}
2012-04-25 07:13:02 +02:00
if ( ic - > duration ! = AV_NOPTS_VALUE )
2012-04-13 07:00:57 +02:00
return 1 ;
2003-08-08 20:02:23 +02:00
return 0 ;
}
2005-06-28 14:55:08 +02:00
/**
* Estimate the stream timings from the one of each components .
*
* Also computes the global bitrate if possible .
*/
2011-07-15 20:27:43 +02:00
static void update_stream_timings ( AVFormatContext * ic )
2003-08-08 20:02:23 +02:00
{
2011-05-12 03:40:21 +02:00
int64_t start_time , start_time1 , start_time_text , end_time , end_time1 ;
2011-10-09 14:12:14 +02:00
int64_t duration , duration1 , filesize ;
2003-08-08 20:02:23 +02:00
int i ;
AVStream * st ;
2006-12-07 01:47:37 +01:00
start_time = INT64_MAX ;
2011-05-12 03:40:21 +02:00
start_time_text = INT64_MAX ;
2006-12-07 01:47:37 +01:00
end_time = INT64_MIN ;
2007-09-05 18:47:48 +02:00
duration = INT64_MIN ;
2003-08-08 20:02:23 +02:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2008-01-22 00:43:25 +01:00
if ( st - > start_time ! = AV_NOPTS_VALUE & & st - > time_base . den ) {
2005-04-30 23:43:59 +02:00
start_time1 = av_rescale_q ( st - > start_time , st - > time_base , AV_TIME_BASE_Q ) ;
2012-06-12 19:07:25 +02:00
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_SUBTITLE | | st - > codec - > codec_type = = AVMEDIA_TYPE_DATA ) {
2011-05-12 03:40:21 +02:00
if ( start_time1 < start_time_text )
start_time_text = start_time1 ;
} else
2012-06-14 18:54:09 +02:00
start_time = FFMIN ( start_time , start_time1 ) ;
2003-08-08 20:02:23 +02:00
if ( st - > duration ! = AV_NOPTS_VALUE ) {
2005-04-30 23:43:59 +02:00
end_time1 = start_time1
+ av_rescale_q ( st - > duration , st - > time_base , AV_TIME_BASE_Q ) ;
2011-10-18 09:17:12 +02:00
end_time = FFMAX ( end_time , end_time1 ) ;
2003-08-08 20:02:23 +02:00
}
}
2007-09-05 18:47:48 +02:00
if ( st - > duration ! = AV_NOPTS_VALUE ) {
duration1 = av_rescale_q ( st - > duration , st - > time_base , AV_TIME_BASE_Q ) ;
2011-10-18 09:17:12 +02:00
duration = FFMAX ( duration , duration1 ) ;
2007-09-05 18:47:48 +02:00
}
2003-08-08 20:02:23 +02:00
}
2011-05-12 03:40:21 +02:00
if ( start_time = = INT64_MAX | | ( start_time > start_time_text & & start_time - start_time_text < AV_TIME_BASE ) )
start_time = start_time_text ;
2012-06-12 19:28:08 +02:00
else if ( start_time > start_time_text )
av_log ( ic , AV_LOG_VERBOSE , " Ignoring outlier non primary stream starttime %f \n " , start_time_text / ( float ) AV_TIME_BASE ) ;
2006-12-07 01:47:37 +01:00
if ( start_time ! = INT64_MAX ) {
2003-08-08 20:02:23 +02:00
ic - > start_time = start_time ;
2011-10-18 09:17:12 +02:00
if ( end_time ! = INT64_MIN )
duration = FFMAX ( duration , end_time - start_time ) ;
2007-09-05 18:47:48 +02:00
}
2011-09-13 01:02:48 +02:00
if ( duration ! = INT64_MIN & & ic - > duration = = AV_NOPTS_VALUE ) {
2007-09-05 18:47:48 +02:00
ic - > duration = duration ;
2011-09-13 01:02:48 +02:00
}
2011-10-18 01:33:09 +02:00
if ( ic - > pb & & ( filesize = avio_size ( ic - > pb ) ) > 0 & & ic - > duration ! = AV_NOPTS_VALUE ) {
2008-01-16 23:14:26 +01:00
/* compute the bitrate */
2011-10-09 14:12:14 +02:00
ic - > bit_rate = ( double ) filesize * 8.0 * AV_TIME_BASE /
2007-09-05 18:47:48 +02:00
( double ) ic - > duration ;
2003-08-08 20:02:23 +02:00
}
}
static void fill_all_stream_timings ( AVFormatContext * ic )
{
int i ;
AVStream * st ;
2011-07-15 20:27:43 +02:00
update_stream_timings ( ic ) ;
2003-08-08 20:02:23 +02:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
if ( st - > start_time = = AV_NOPTS_VALUE ) {
2005-04-30 23:43:59 +02: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 20:02:23 +02:00
}
}
}
2011-07-15 20:27:43 +02:00
static void estimate_timings_from_bit_rate ( AVFormatContext * ic )
2003-08-08 20:02:23 +02:00
{
int64_t filesize , duration ;
int bit_rate , i ;
AVStream * st ;
/* if bit_rate is already set, we believe it */
2010-12-20 10:58:27 +01:00
if ( ic - > bit_rate < = 0 ) {
2003-08-08 20:02:23 +02:00
bit_rate = 0 ;
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2010-12-20 10:58:27 +01:00
if ( st - > codec - > bit_rate > 0 )
2005-07-18 00:24:36 +02:00
bit_rate + = st - > codec - > bit_rate ;
2003-08-08 20:02:23 +02:00
}
ic - > bit_rate = bit_rate ;
}
/* if duration is already set, we believe it */
2005-12-17 19:14:38 +01:00
if ( ic - > duration = = AV_NOPTS_VALUE & &
2011-10-09 14:12:14 +02:00
ic - > bit_rate ! = 0 ) {
filesize = ic - > pb ? avio_size ( ic - > pb ) : 0 ;
2003-08-08 20:02:23 +02:00
if ( filesize > 0 ) {
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2005-04-30 23:43:59 +02:00
duration = av_rescale ( 8 * filesize , st - > time_base . den , ic - > bit_rate * ( int64_t ) st - > time_base . num ) ;
2007-08-18 03:26:06 +02:00
if ( st - > duration = = AV_NOPTS_VALUE )
2003-08-08 20:02:23 +02:00
st - > duration = duration ;
}
}
}
}
# define DURATION_MAX_READ_SIZE 250000
2010-01-31 18:43:18 +01:00
# define DURATION_MAX_RETRY 3
2003-08-08 20:02:23 +02:00
/* only usable for MPEG-PS streams */
2011-07-15 20:27:43 +02:00
static void estimate_timings_from_pts ( AVFormatContext * ic , int64_t old_offset )
2003-08-08 20:02:23 +02:00
{
AVPacket pkt1 , * pkt = & pkt1 ;
AVStream * st ;
int read_size , i , ret ;
2010-10-07 21:05:31 +02:00
int64_t end_time ;
2003-08-08 20:02:23 +02:00
int64_t filesize , offset , duration ;
2010-01-31 18:43:18 +01:00
int retry = 0 ;
2005-12-17 19:14:38 +01:00
2007-04-26 12:49:48 +02:00
/* flush packet queue */
flush_packet_queue ( ic ) ;
2010-10-07 21:10:51 +02:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
2007-04-26 12:49:48 +02:00
st = ic - > streams [ i ] ;
2010-10-07 21:05:31 +02:00
if ( st - > start_time = = AV_NOPTS_VALUE & & st - > first_dts = = AV_NOPTS_VALUE )
2011-07-15 20:27:43 +02:00
av_log ( st - > codec , AV_LOG_WARNING , " start time is not set in estimate_timings_from_pts \n " ) ;
2009-12-13 23:56:59 +01:00
2007-04-26 12:49:48 +02:00
if ( st - > parser ) {
av_parser_close ( st - > parser ) ;
st - > parser = NULL ;
}
}
2005-12-17 19:14:38 +01:00
2003-08-08 20:02:23 +02:00
/* estimate the end time (duration) */
/* XXX: may need to support wrapping */
2011-10-09 14:12:14 +02:00
filesize = ic - > pb ? avio_size ( ic - > pb ) : 0 ;
2010-01-31 18:43:18 +01:00
end_time = AV_NOPTS_VALUE ;
do {
2011-08-23 03:47:24 +02:00
offset = filesize - ( DURATION_MAX_READ_SIZE < < retry ) ;
if ( offset < 0 )
offset = 0 ;
2003-08-08 20:02:23 +02:00
2011-08-23 03:47:24 +02:00
avio_seek ( ic - > pb , offset , SEEK_SET ) ;
read_size = 0 ;
for ( ; ; ) {
if ( read_size > = DURATION_MAX_READ_SIZE < < ( FFMAX ( retry - 1 , 0 ) ) )
break ;
2005-12-17 19:14:38 +01:00
2011-08-23 03:47:24 +02:00
do {
2012-03-04 21:41:59 +01:00
ret = ff_read_packet ( ic , pkt ) ;
2011-08-23 03:47:24 +02:00
} while ( ret = = AVERROR ( EAGAIN ) ) ;
if ( ret ! = 0 )
break ;
read_size + = pkt - > size ;
st = ic - > streams [ pkt - > stream_index ] ;
if ( pkt - > pts ! = AV_NOPTS_VALUE & &
( st - > start_time ! = AV_NOPTS_VALUE | |
st - > first_dts ! = AV_NOPTS_VALUE ) ) {
duration = end_time = pkt - > pts ;
if ( st - > start_time ! = AV_NOPTS_VALUE )
duration - = st - > start_time ;
else
duration - = st - > first_dts ;
if ( duration < 0 )
duration + = 1LL < < st - > pts_wrap_bits ;
if ( duration > 0 ) {
if ( st - > duration = = AV_NOPTS_VALUE | | st - > duration < duration )
st - > duration = duration ;
}
2003-08-08 20:02:23 +02:00
}
2011-08-23 03:47:24 +02:00
av_free_packet ( pkt ) ;
2003-08-08 20:02:23 +02:00
}
2010-01-31 18:43:18 +01:00
} while ( end_time = = AV_NOPTS_VALUE
& & filesize > ( DURATION_MAX_READ_SIZE < < retry )
& & + + retry < = DURATION_MAX_RETRY ) ;
2005-12-17 19:14:38 +01:00
2005-04-30 23:43:59 +02:00
fill_all_stream_timings ( ic ) ;
2003-08-08 20:02:23 +02:00
2011-02-28 14:57:54 +01:00
avio_seek ( ic - > pb , old_offset , SEEK_SET ) ;
2010-10-07 21:10:51 +02:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
2007-08-18 02:44:14 +02:00
st = ic - > streams [ i ] ;
st - > cur_dts = st - > first_dts ;
2008-02-20 21:24:38 +01:00
st - > last_IP_pts = AV_NOPTS_VALUE ;
2011-03-08 22:39:14 +01:00
st - > reference_dts = AV_NOPTS_VALUE ;
2007-08-18 02:44:14 +02:00
}
2003-08-08 20:02:23 +02:00
}
2011-07-15 20:27:43 +02:00
static void estimate_timings ( AVFormatContext * ic , int64_t old_offset )
2003-08-08 20:02:23 +02:00
{
int64_t file_size ;
/* get the file size, if possible */
if ( ic - > iformat - > flags & AVFMT_NOFILE ) {
file_size = 0 ;
} else {
2011-03-04 19:57:36 +01:00
file_size = avio_size ( ic - > pb ) ;
2011-10-18 09:17:12 +02:00
file_size = FFMAX ( 0 , file_size ) ;
2003-08-08 20:02:23 +02:00
}
2006-07-10 23:14:37 +02:00
if ( ( ! strcmp ( ic - > iformat - > name , " mpeg " ) | |
! strcmp ( ic - > iformat - > name , " mpegts " ) ) & &
2011-03-05 21:06:46 +01:00
file_size & & ic - > pb - > seekable ) {
2003-08-08 20:02:23 +02:00
/* get accurate estimate from the PTSes */
2011-07-15 20:27:43 +02:00
estimate_timings_from_pts ( ic , old_offset ) ;
2012-06-18 07:20:09 +02:00
ic - > duration_estimation_method = AVFMT_DURATION_FROM_PTS ;
2011-07-15 20:27:43 +02:00
} else if ( has_duration ( ic ) ) {
2008-01-16 23:14:26 +01:00
/* at least one component has timings - we use them for all
2003-08-08 20:02:23 +02:00
the components */
fill_all_stream_timings ( ic ) ;
2012-06-18 07:20:09 +02:00
ic - > duration_estimation_method = AVFMT_DURATION_FROM_STREAM ;
2003-08-08 20:02:23 +02:00
} else {
2009-11-30 23:08:22 +01:00
av_log ( ic , AV_LOG_WARNING , " Estimating duration from bitrate, this may be inaccurate \n " ) ;
2008-01-16 23:14:26 +01:00
/* less precise: use bitrate info */
2011-07-15 20:27:43 +02:00
estimate_timings_from_bit_rate ( ic ) ;
2012-06-18 07:20:09 +02:00
ic - > duration_estimation_method = AVFMT_DURATION_FROM_BITRATE ;
2003-08-08 20:02:23 +02:00
}
2011-07-15 20:27:43 +02:00
update_stream_timings ( ic ) ;
2003-08-08 20:02:23 +02:00
{
int i ;
2011-06-03 13:52:29 +02:00
AVStream av_unused * st ;
2003-08-08 20:02:23 +02:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2011-04-29 17:27:01 +02:00
av_dlog ( ic , " %d: start_time: %0.3f duration: %0.3f \n " , i ,
( double ) st - > start_time / AV_TIME_BASE ,
( double ) st - > duration / AV_TIME_BASE ) ;
2003-08-08 20:02:23 +02:00
}
2011-04-29 17:27:01 +02:00
av_dlog ( ic , " stream: start_time: %0.3f duration: %0.3f bitrate=%d kb/s \n " ,
( double ) ic - > start_time / AV_TIME_BASE ,
( double ) ic - > duration / AV_TIME_BASE ,
ic - > bit_rate / 1000 ) ;
2003-08-08 20:02:23 +02:00
}
}
2012-02-28 00:02:10 +01:00
static int has_codec_parameters ( AVStream * st )
2002-05-20 18:28:47 +02:00
{
2012-02-28 00:02:10 +01:00
AVCodecContext * avctx = st - > codec ;
2002-05-20 18:28:47 +02:00
int val ;
2011-07-16 23:08:29 +02:00
switch ( avctx - > codec_type ) {
2010-03-31 01:30:55 +02:00
case AVMEDIA_TYPE_AUDIO :
2012-02-28 00:02:10 +01:00
val = avctx - > sample_rate & & avctx - > channels ;
2012-03-04 04:06:15 +01:00
if ( ! avctx - > frame_size & & determinable_frame_size ( avctx ) )
2008-06-25 20:36:41 +02:00
return 0 ;
2012-02-28 00:02:10 +01:00
if ( st - > info - > found_decoder > = 0 & & avctx - > sample_fmt = = AV_SAMPLE_FMT_NONE )
return 0 ;
2002-05-20 18:28:47 +02:00
break ;
2010-03-31 01:30:55 +02:00
case AVMEDIA_TYPE_VIDEO :
2012-02-28 00:02:10 +01:00
val = avctx - > width ;
if ( st - > info - > found_decoder > = 0 & & avctx - > pix_fmt = = PIX_FMT_NONE )
return 0 ;
2002-05-20 18:28:47 +02:00
break ;
2011-08-27 02:39:11 +02:00
case AVMEDIA_TYPE_DATA :
if ( avctx - > codec_id = = CODEC_ID_NONE ) return 1 ;
2002-05-20 18:28:47 +02:00
default :
val = 1 ;
break ;
}
2011-07-16 23:08:29 +02:00
return avctx - > codec_id ! = CODEC_ID_NONE & & val ! = 0 ;
2002-05-20 18:28:47 +02:00
}
2010-07-03 05:07:33 +02:00
static int has_decode_delay_been_guessed ( AVStream * st )
{
2012-07-02 22:59:42 +02:00
if ( st - > codec - > codec_id ! = CODEC_ID_H264 ) return 1 ;
2012-07-02 23:18:32 +02:00
# if CONFIG_H264_DECODER
if ( st - > codec - > has_b_frames & &
avpriv_h264_has_num_reorder_frames ( st - > codec ) = = st - > codec - > has_b_frames )
return 1 ;
# endif
2012-07-02 22:59:42 +02:00
if ( st - > codec - > has_b_frames < 3 )
return st - > info - > nb_decoded_frames > = 6 ;
2012-07-02 23:23:33 +02:00
else if ( st - > codec - > has_b_frames < 4 )
return st - > info - > nb_decoded_frames > = 18 ;
else
return st - > info - > nb_decoded_frames > = 20 ;
2010-07-03 05:07:33 +02:00
}
2012-01-18 10:59:32 +01:00
/* returns 1 or 0 if or if not decoded data was returned, or a negative error */
2011-05-22 19:24:59 +02:00
static int try_decode_frame ( AVStream * st , AVPacket * avpkt , AVDictionary * * options )
2003-11-10 19:37:55 +01:00
{
AVCodec * codec ;
2012-01-02 09:01:02 +01:00
int got_picture = 1 , ret = 0 ;
2003-11-10 19:37:55 +01:00
AVFrame picture ;
2011-11-02 19:35:36 +01:00
AVPacket pkt = * avpkt ;
2005-12-17 19:14:38 +01:00
2012-02-28 00:02:10 +01:00
if ( ! avcodec_is_open ( st - > codec ) & & ! st - > info - > found_decoder ) {
2012-01-18 20:32:32 +01:00
AVDictionary * thread_opt = NULL ;
2012-01-28 19:15:15 +01:00
codec = st - > codec - > codec ? st - > codec - > codec :
avcodec_find_decoder ( st - > codec - > codec_id ) ;
2012-02-28 00:02:10 +01:00
if ( ! codec ) {
st - > info - > found_decoder = - 1 ;
2009-04-13 05:32:02 +02:00
return - 1 ;
2012-02-28 00:02:10 +01:00
}
2012-01-18 20:32:32 +01:00
/* force thread count to 1 since the h264 decoder will not extract SPS
* and PPS to extradata during multi - threaded decoding */
av_dict_set ( options ? options : & thread_opt , " threads " , " 1 " , 0 ) ;
ret = avcodec_open2 ( st - > codec , codec , options ? options : & thread_opt ) ;
if ( ! options )
av_dict_free ( & thread_opt ) ;
2012-02-28 00:02:10 +01:00
if ( ret < 0 ) {
st - > info - > found_decoder = - 1 ;
2009-04-13 05:32:02 +02:00
return ret ;
2012-02-28 00:02:10 +01:00
}
st - > info - > found_decoder = 1 ;
} else if ( ! st - > info - > found_decoder )
st - > info - > found_decoder = 1 ;
if ( st - > info - > found_decoder < 0 )
return - 1 ;
2005-04-25 20:29:06 +02:00
2012-01-02 09:01:02 +01:00
while ( ( pkt . size > 0 | | ( ! pkt . data & & got_picture ) ) & &
ret > = 0 & &
2012-02-28 00:02:10 +01:00
( ! has_codec_parameters ( st ) | |
2011-11-02 19:35:36 +01:00
! has_decode_delay_been_guessed ( st ) | |
( ! st - > codec_info_nb_frames & & st - > codec - > codec - > capabilities & CODEC_CAP_CHANNEL_CONF ) ) ) {
got_picture = 0 ;
avcodec_get_frame_defaults ( & picture ) ;
2009-04-13 05:32:02 +02:00
switch ( st - > codec - > codec_type ) {
2010-03-31 01:30:55 +02:00
case AVMEDIA_TYPE_VIDEO :
2009-04-13 05:32:02 +02:00
ret = avcodec_decode_video2 ( st - > codec , & picture ,
2011-11-02 19:35:36 +01:00
& got_picture , & pkt ) ;
2009-04-13 05:32:02 +02:00
break ;
2010-03-31 01:30:55 +02:00
case AVMEDIA_TYPE_AUDIO :
2011-11-02 19:35:36 +01:00
ret = avcodec_decode_audio4 ( st - > codec , & picture , & got_picture , & pkt ) ;
2009-04-13 05:32:02 +02:00
break ;
default :
break ;
}
2011-11-02 19:35:36 +01:00
if ( ret > = 0 ) {
if ( got_picture )
st - > info - > nb_decoded_frames + + ;
pkt . data + = ret ;
pkt . size - = ret ;
2012-01-18 10:59:32 +01:00
ret = got_picture ;
2011-11-02 19:35:36 +01:00
}
2003-11-10 19:37:55 +01:00
}
2012-01-04 04:08:46 +01:00
if ( ! pkt . data & & ! got_picture )
return - 1 ;
2003-11-10 19:37:55 +01:00
return ret ;
}
2010-05-22 17:56:49 +02:00
unsigned int ff_codec_get_tag ( const AVCodecTag * tags , enum CodecID id )
2007-07-11 14:45:14 +02:00
{
while ( tags - > id ! = CODEC_ID_NONE ) {
if ( tags - > id = = id )
return tags - > tag ;
tags + + ;
}
return 0 ;
}
2009-06-23 01:09:34 +02:00
enum CodecID ff_codec_get_id ( const AVCodecTag * tags , unsigned int tag )
2007-07-11 14:45:14 +02:00
{
2007-07-27 13:36:17 +02: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 + + ) {
2011-10-17 10:12:51 +02:00
if ( avpriv_toupper4 ( tag ) = = avpriv_toupper4 ( tags [ i ] . tag ) )
2007-07-27 13:36:17 +02:00
return tags [ i ] . id ;
2007-07-11 14:45:14 +02:00
}
return CODEC_ID_NONE ;
}
2008-11-08 19:37:03 +01:00
unsigned int av_codec_get_tag ( const AVCodecTag * const * tags , enum CodecID id )
2007-07-11 14:45:14 +02:00
{
int i ;
for ( i = 0 ; tags & & tags [ i ] ; i + + ) {
2009-06-23 01:09:34 +02:00
int tag = ff_codec_get_tag ( tags [ i ] , id ) ;
2007-07-11 14:45:14 +02:00
if ( tag ) return tag ;
}
return 0 ;
}
2008-11-08 19:37:03 +01:00
enum CodecID av_codec_get_id ( const AVCodecTag * const * tags , unsigned int tag )
2007-07-11 14:45:14 +02:00
{
int i ;
for ( i = 0 ; tags & & tags [ i ] ; i + + ) {
2009-06-23 01:09:34 +02:00
enum CodecID id = ff_codec_get_id ( tags [ i ] , tag ) ;
2007-07-11 14:45:14 +02:00
if ( id ! = CODEC_ID_NONE ) return id ;
}
return CODEC_ID_NONE ;
}
2008-05-24 23:44:29 +02:00
static void compute_chapters_end ( AVFormatContext * s )
{
2011-04-01 03:02:02 +02:00
unsigned int i , j ;
2011-05-25 09:43:55 +02:00
int64_t max_time = s - > duration + ( ( s - > start_time = = AV_NOPTS_VALUE ) ? 0 : s - > start_time ) ;
2008-05-24 23:44:29 +02:00
2011-04-01 03:02:02 +02:00
for ( i = 0 ; i < s - > nb_chapters ; i + + )
2008-05-24 23:44:29 +02:00
if ( s - > chapters [ i ] - > end = = AV_NOPTS_VALUE ) {
2011-04-01 03:02:02 +02:00
AVChapter * ch = s - > chapters [ i ] ;
int64_t end = max_time ? av_rescale_q ( max_time , AV_TIME_BASE_Q , ch - > time_base )
: INT64_MAX ;
for ( j = 0 ; j < s - > nb_chapters ; j + + ) {
AVChapter * ch1 = s - > chapters [ j ] ;
int64_t next_start = av_rescale_q ( ch1 - > start , ch1 - > time_base , ch - > time_base ) ;
if ( j ! = i & & next_start > ch - > start & & next_start < end )
end = next_start ;
}
ch - > end = ( end = = INT64_MAX ) ? ch - > start : end ;
2008-05-24 23:44:29 +02:00
}
}
2006-12-11 17:59:10 +01:00
static int get_std_framerate ( int i ) {
2012-04-09 18:54:42 +02:00
if ( i < 60 * 12 ) return ( i + 1 ) * 1001 ;
2012-04-09 18:56:46 +02:00
else return ( ( const int [ ] ) { 24 , 30 , 60 , 12 , 15 , 48 } ) [ i - 60 * 12 ] * 1000 * 12 ;
2006-12-11 17:59:10 +01:00
}
2007-12-27 01:16:48 +01: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 23:14:26 +01:00
* Old DivX and Xvid often have nonsense timebases like 1f ps or 2f ps .
* MPEG - 2 commonly misuses field repeat flags to store different framerates .
2007-12-27 01:16:48 +01: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
2009-01-17 13:21:01 +01:00
/* || c->codec_tag == AV_RL32("DIVX")
| | c - > codec_tag = = AV_RL32 ( " XVID " ) */
2009-02-24 14:35:54 +01:00
| | c - > codec_id = = CODEC_ID_MPEG2VIDEO
| | c - > codec_id = = CODEC_ID_H264
)
2007-12-27 01:16:48 +01:00
return 1 ;
return 0 ;
}
2012-02-06 17:26:38 +01:00
# if FF_API_FORMAT_PARAMETERS
int av_find_stream_info ( AVFormatContext * ic )
{
return avformat_find_stream_info ( ic , NULL ) ;
}
# endif
2011-05-22 19:24:59 +02:00
int avformat_find_stream_info ( AVFormatContext * ic , AVDictionary * * options )
2002-05-20 18:28:47 +02:00
{
2006-02-02 21:54:41 +01:00
int i , count , ret , read_size , j ;
2002-05-20 18:28:47 +02:00
AVStream * st ;
2003-11-10 19:37:55 +01:00
AVPacket pkt1 , * pkt ;
2011-03-03 20:11:45 +01:00
int64_t old_offset = avio_tell ( ic - > pb ) ;
2011-05-22 19:24:59 +02:00
int orig_nb_streams = ic - > nb_streams ; // new streams might appear, no options for those
2012-01-06 11:51:12 +01:00
int flush_codecs = 1 ;
2007-03-02 14:23:06 +01:00
2012-04-14 10:43:35 +02:00
if ( ic - > pb )
av_log ( ic , AV_LOG_DEBUG , " File position before avformat_find_stream_info() is % " PRId64 " \n " , avio_tell ( ic - > pb ) ) ;
2005-04-30 23:43:59 +02:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
2010-10-03 00:18:02 +02:00
AVCodec * codec ;
2012-01-18 20:32:32 +01:00
AVDictionary * thread_opt = NULL ;
2005-04-30 23:43:59 +02:00
st = ic - > streams [ i ] ;
2011-06-28 08:39:12 +02:00
2010-11-17 00:50:18 +01:00
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_VIDEO | |
st - > codec - > codec_type = = AVMEDIA_TYPE_SUBTITLE ) {
2005-04-30 23:43:59 +02:00
/* if(!st->time_base.num)
st - > time_base = */
2005-07-18 00:24:36 +02:00
if ( ! st - > codec - > time_base . num )
st - > codec - > time_base = st - > time_base ;
2005-04-30 23:43:59 +02:00
}
2005-06-27 02:04:03 +02:00
//only for the split stuff
2010-03-31 14:55:16 +02:00
if ( ! st - > parser & & ! ( ic - > flags & AVFMT_FLAG_NOPARSE ) ) {
2005-07-18 00:24:36 +02:00
st - > parser = av_parser_init ( st - > codec - > codec_id ) ;
2012-05-21 14:32:24 +02:00
if ( st - > parser ) {
if ( st - > need_parsing = = AVSTREAM_PARSE_HEADERS ) {
st - > parser - > flags | = PARSER_FLAG_COMPLETE_FRAMES ;
} else if ( st - > need_parsing = = AVSTREAM_PARSE_FULL_RAW ) {
st - > parser - > flags | = PARSER_FLAG_USE_CODEC_TS ;
}
2012-06-07 19:02:32 +02:00
} else if ( st - > need_parsing ) {
av_log ( ic , AV_LOG_VERBOSE , " parser not found for codec "
" %s, packets or times may be invalid. \n " ,
avcodec_get_name ( st - > codec - > codec_id ) ) ;
2005-08-15 17:58:21 +02:00
}
2005-06-27 02:04:03 +02:00
}
2012-01-28 19:15:15 +01:00
codec = st - > codec - > codec ? st - > codec - > codec :
avcodec_find_decoder ( st - > codec - > codec_id ) ;
2010-10-03 00:18:02 +02:00
2012-01-18 20:32:32 +01:00
/* force thread count to 1 since the h264 decoder will not extract SPS
* and PPS to extradata during multi - threaded decoding */
av_dict_set ( options ? & options [ i ] : & thread_opt , " threads " , " 1 " , 0 ) ;
2012-01-07 15:36:44 +01:00
2010-11-13 14:57:49 +01:00
/* Ensure that subtitle_header is properly set. */
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_SUBTITLE
& & codec & & ! st - > codec - > codec )
2012-01-18 20:32:32 +01:00
avcodec_open2 ( st - > codec , codec , options ? & options [ i ]
: & thread_opt ) ;
2010-11-13 14:57:49 +01:00
2010-02-04 00:05:58 +01:00
//try to just open decoders, in case this is enough to get parameters
2012-02-28 00:02:10 +01:00
if ( ! has_codec_parameters ( st ) ) {
2010-11-13 14:57:49 +01:00
if ( codec & & ! st - > codec - > codec )
2012-01-07 15:36:44 +01:00
avcodec_open2 ( st - > codec , codec , options ? & options [ i ]
2012-01-18 20:32:32 +01:00
: & thread_opt ) ;
2010-02-04 00:05:58 +01:00
}
2012-01-18 20:32:32 +01:00
if ( ! options )
av_dict_free ( & thread_opt ) ;
2005-04-30 23:43:59 +02:00
}
2010-10-06 22:52:26 +02:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
2010-10-09 00:01:19 +02:00
ic - > streams [ i ] - > info - > last_dts = AV_NOPTS_VALUE ;
2004-12-19 02:23:22 +01:00
}
2005-12-17 19:14:38 +01:00
2002-05-20 18:28:47 +02:00
count = 0 ;
read_size = 0 ;
for ( ; ; ) {
2011-11-06 21:34:24 +01:00
if ( ff_check_interrupt ( & ic - > interrupt_callback ) ) {
2011-03-13 00:42:27 +01:00
ret = AVERROR_EXIT ;
2009-06-18 02:22:08 +02:00
av_log ( ic , AV_LOG_DEBUG , " interrupted \n " ) ;
2009-02-23 03:38:45 +01:00
break ;
}
2002-05-20 18:28:47 +02:00
/* check if one codec still needs to be handled */
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
2011-02-28 01:20:56 +01:00
int fps_analyze_framecount = 20 ;
2002-05-20 18:28:47 +02:00
st = ic - > streams [ i ] ;
2012-02-28 00:02:10 +01:00
if ( ! has_codec_parameters ( st ) )
2002-05-20 18:28:47 +02:00
break ;
2011-02-28 01:20:56 +01:00
/* if the timebase is coarse (like the usual millisecond precision
of mkv ) , we need to analyze more frames to reliably arrive at
the correct fps */
if ( av_q2d ( st - > time_base ) > 0.0005 )
fps_analyze_framecount * = 2 ;
2011-05-09 23:34:23 +02:00
if ( ic - > fps_probe_size > = 0 )
fps_analyze_framecount = ic - > fps_probe_size ;
2004-12-21 03:16:11 +01:00
/* variable fps and no guess at the real fps */
2010-02-22 11:19:46 +01:00
if ( tb_unreliable ( st - > codec ) & & ! ( st - > r_frame_rate . num & & st - > avg_frame_rate . num )
2011-02-28 01:20:56 +01:00
& & st - > info - > duration_count < fps_analyze_framecount
& & st - > codec - > codec_type = = AVMEDIA_TYPE_VIDEO )
2004-12-21 03:16:11 +01:00
break ;
2005-07-18 00:24:36 +02:00
if ( st - > parser & & st - > parser - > parser - > split & & ! st - > codec - > extradata )
2005-06-27 02:04:03 +02:00
break ;
2011-09-11 00:33:20 +02:00
if ( st - > first_dts = = AV_NOPTS_VALUE & &
( st - > codec - > codec_type = = AVMEDIA_TYPE_VIDEO | |
st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) )
2007-08-05 00:46:13 +02:00
break ;
2002-05-20 18:28:47 +02: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 19:37:55 +01:00
if ( ! ( ic - > ctx_flags & AVFMTCTX_NOHEADER ) ) {
2002-05-20 18:28:47 +02:00
/* if we found the info for all the codecs, we can stop */
ret = count ;
2009-06-18 02:22:08 +02:00
av_log ( ic , AV_LOG_DEBUG , " All info found \n " ) ;
2012-01-06 11:51:12 +01:00
flush_codecs = 0 ;
2002-05-20 18:28:47 +02:00
break ;
}
2006-09-26 19:25:28 +02:00
}
2006-09-26 19:27:08 +02:00
/* we did not get all the codec info, but we read too much data */
2009-06-25 21:10:27 +02:00
if ( read_size > = ic - > probesize ) {
2006-09-26 19:27:08 +02:00
ret = count ;
2010-05-24 18:42:16 +02:00
av_log ( ic , AV_LOG_DEBUG , " Probe buffer size limit %d reached \n " , ic - > probesize ) ;
2012-04-21 12:05:23 +02:00
for ( i = 0 ; i < ic - > nb_streams ; i + + )
if ( ! ic - > streams [ i ] - > r_frame_rate . num & &
ic - > streams [ i ] - > info - > duration_count < = 1 )
av_log ( ic , AV_LOG_WARNING ,
" Stream #%d: not enough frames to estimate rate; "
" consider increasing probesize \n " , i ) ;
2006-09-26 19:27:08 +02:00
break ;
}
2002-05-20 18:28:47 +02:00
2003-11-10 19:37:55 +01:00
/* NOTE: a new stream can be added there if no header in file
( AVFMTCTX_NOHEADER ) */
2011-07-15 20:27:43 +02:00
ret = read_frame_internal ( ic , & pkt1 ) ;
2011-06-29 22:50:21 +02:00
if ( ret = = AVERROR ( EAGAIN ) )
continue ;
if ( ret < 0 ) {
2012-01-02 09:01:02 +01:00
/* EOF or error*/
2003-11-10 19:37:55 +01:00
break ;
}
2008-08-07 00:17:38 +02:00
pkt = add_to_pktbuf ( & ic - > packet_buffer , & pkt1 , & ic - > packet_buffer_end ) ;
2010-10-09 00:01:19 +02:00
if ( ( ret = av_dup_packet ( pkt ) ) < 0 )
goto find_stream_info_err ;
2002-05-20 18:28:47 +02:00
2003-11-10 19:37:55 +01:00
read_size + = pkt - > size ;
2002-05-20 18:28:47 +02:00
st = ic - > streams [ pkt - > stream_index ] ;
2010-10-09 00:01:19 +02:00
if ( st - > codec_info_nb_frames > 1 ) {
2012-01-05 00:49:02 +01:00
int64_t t = 0 ;
if ( st - > time_base . den > 0 )
t = av_rescale_q ( st - > info - > codec_info_duration , st - > time_base , AV_TIME_BASE_Q ) ;
if ( st - > avg_frame_rate . num > 0 )
t = FFMAX ( t , av_rescale_q ( st - > codec_info_nb_frames , ( AVRational ) { st - > avg_frame_rate . den , st - > avg_frame_rate . num } , AV_TIME_BASE_Q ) ) ;
if ( t > = ic - > max_analyze_duration ) {
2011-05-29 21:07:35 +02:00
av_log ( ic , AV_LOG_WARNING , " max_analyze_duration %d reached at % " PRId64 " \n " , ic - > max_analyze_duration , t ) ;
2009-03-19 22:54:34 +01:00
break ;
2009-06-18 02:22:08 +02:00
}
2010-10-09 00:01:19 +02:00
st - > info - > codec_info_duration + = pkt - > duration ;
2009-03-19 22:54:34 +01:00
}
2005-05-22 10:47:09 +02:00
{
2010-10-09 00:01:19 +02:00
int64_t last = st - > info - > last_dts ;
2005-05-07 01:41:47 +02:00
2011-10-08 03:06:26 +02:00
if ( pkt - > dts ! = AV_NOPTS_VALUE & & last ! = AV_NOPTS_VALUE & & pkt - > dts > last ) {
2012-03-07 22:13:39 +01:00
double dts = ( is_relative ( pkt - > dts ) ? pkt - > dts - RELATIVE_TS_BASE : pkt - > dts ) * av_q2d ( st - > time_base ) ;
2011-10-08 03:06:26 +02:00
int64_t duration = pkt - > dts - last ;
2006-12-11 17:59:10 +01:00
2011-12-15 21:28:24 +01:00
// if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
// av_log(NULL, AV_LOG_ERROR, "%f\n", dts);
2012-04-09 18:54:42 +02:00
for ( i = 0 ; i < FF_ARRAY_ELEMS ( st - > info - > duration_error [ 0 ] [ 0 ] ) ; i + + ) {
2007-01-02 21:35:46 +01:00
int framerate = get_std_framerate ( i ) ;
2011-09-16 20:40:08 +02:00
double sdts = dts * framerate / ( 1001 * 12 ) ;
for ( j = 0 ; j < 2 ; j + + ) {
int ticks = lrintf ( sdts + j * 0.5 ) ;
double error = sdts - ticks + j * 0.5 ;
st - > info - > duration_error [ j ] [ 0 ] [ i ] + = error ;
st - > info - > duration_error [ j ] [ 1 ] [ i ] + = error * error ;
}
2007-01-02 21:35:46 +01:00
}
2010-10-09 00:01:19 +02:00
st - > info - > duration_count + + ;
2009-02-27 08:56:24 +01:00
// ignore the first 4 values, they might have some random jitter
2010-10-09 00:01:19 +02:00
if ( st - > info - > duration_count > 3 )
st - > info - > duration_gcd = av_gcd ( st - > info - > duration_gcd , duration ) ;
2004-12-19 02:23:22 +01:00
}
2010-10-09 00:01:19 +02:00
if ( last = = AV_NOPTS_VALUE | | st - > info - > duration_count < = 1 )
st - > info - > last_dts = pkt - > dts ;
2004-12-19 02:23:22 +01:00
}
2005-07-18 00:24:36 +02:00
if ( st - > parser & & st - > parser - > parser - > split & & ! st - > codec - > extradata ) {
int i = st - > parser - > parser - > split ( st - > codec , pkt - > data , pkt - > size ) ;
2012-01-12 20:12:24 +01:00
if ( i > 0 & & i < FF_MAX_EXTRADATA_SIZE ) {
2005-07-18 00:24:36 +02:00
st - > codec - > extradata_size = i ;
2006-06-29 21:42:34 +02:00
st - > codec - > extradata = av_malloc ( st - > codec - > extradata_size + FF_INPUT_BUFFER_PADDING_SIZE ) ;
2012-01-12 20:12:24 +01:00
if ( ! st - > codec - > extradata )
return AVERROR ( ENOMEM ) ;
2005-07-18 00:24:36 +02:00
memcpy ( st - > codec - > extradata , pkt - > data , st - > codec - > extradata_size ) ;
2006-06-29 21:42:34 +02:00
memset ( st - > codec - > extradata + i , 0 , FF_INPUT_BUFFER_PADDING_SIZE ) ;
2005-06-27 02:04:03 +02:00
}
}
2005-12-17 19:14:38 +01:00
2003-11-10 19:37:55 +01: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 23:14:26 +01:00
it takes longer and uses more memory . For MPEG - 4 , we need to
2011-06-28 08:39:12 +02:00
decompress for QuickTime .
If CODEC_CAP_CHANNEL_CONF is set this will force decoding of at
least one frame of codec data , this makes sure the codec initializes
the channel configuration and does not only trust the values from the container .
*/
2012-01-02 09:01:02 +01:00
try_decode_frame ( st , pkt , ( options & & i < orig_nb_streams ) ? & options [ i ] : NULL ) ;
2005-12-17 19:14:38 +01:00
2010-07-03 05:15:37 +02:00
st - > codec_info_nb_frames + + ;
2002-05-20 18:28:47 +02:00
count + + ;
}
2012-01-06 11:51:12 +01:00
if ( flush_codecs ) {
AVPacket empty_pkt = { 0 } ;
2012-03-06 03:56:25 +01:00
int err = 0 ;
2012-01-06 11:51:12 +01:00
av_init_packet ( & empty_pkt ) ;
ret = - 1 ; /* we could not have all the codec parameters before EOF */
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
/* flush the decoders */
2012-03-06 03:56:25 +01:00
if ( st - > info - > found_decoder = = 1 ) {
do {
err = try_decode_frame ( st , & empty_pkt ,
( options & & i < orig_nb_streams ) ?
& options [ i ] : NULL ) ;
} while ( err > 0 & & ! has_codec_parameters ( st ) ) ;
if ( err < 0 ) {
av_log ( ic , AV_LOG_INFO ,
" decoding for stream %d failed \n " , st - > index ) ;
}
2012-01-27 01:42:53 +01:00
}
2012-03-06 03:56:25 +01:00
if ( ! has_codec_parameters ( st ) ) {
2012-01-06 11:51:12 +01:00
char buf [ 256 ] ;
avcodec_string ( buf , sizeof ( buf ) , st - > codec , 0 ) ;
2012-01-27 01:42:53 +01:00
av_log ( ic , AV_LOG_WARNING ,
" Could not find codec parameters (%s) \n " , buf ) ;
2012-01-06 11:51:12 +01:00
} else {
ret = 0 ;
}
}
}
2008-03-15 17:15:47 +01:00
// close codecs which were opened in try_decode_frame()
2005-06-27 22:54:36 +02:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2011-12-08 06:57:44 +01:00
avcodec_close ( st - > codec ) ;
2005-06-27 22:54:36 +02:00
}
2002-05-20 18:28:47 +02:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
st = ic - > streams [ i ] ;
2010-03-31 01:30:55 +02:00
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_VIDEO ) {
2011-03-09 15:12:24 +01:00
if ( st - > codec - > codec_id = = CODEC_ID_RAWVIDEO & & ! st - > codec - > codec_tag & & ! st - > codec - > bits_per_coded_sample ) {
uint32_t tag = avcodec_pix_fmt_to_codec_tag ( st - > codec - > pix_fmt ) ;
if ( ff_find_pix_fmt ( ff_raw_pix_fmt_tags , tag ) = = st - > codec - > pix_fmt )
st - > codec - > codec_tag = tag ;
}
2004-12-19 02:23:22 +01:00
2012-03-13 21:45:05 +01:00
if ( st - > codec_info_nb_frames > 2 & & ! st - > avg_frame_rate . num & & st - > info - > codec_info_duration )
av_reduce ( & st - > avg_frame_rate . num , & st - > avg_frame_rate . den ,
( st - > codec_info_nb_frames - 2 ) * ( int64_t ) st - > time_base . den ,
st - > info - > codec_info_duration * ( int64_t ) st - > time_base . num , 60000 ) ;
2009-02-27 08:56:24 +01:00
// the check for tb_unreliable() is not completely correct, since this is not about handling
// a unreliable/inexact time base, but a time base that is finer than necessary, as e.g.
// ipmovie.c produces.
2011-02-15 04:14:53 +01:00
if ( tb_unreliable ( st - > codec ) & & st - > info - > duration_count > 15 & & st - > info - > duration_gcd > FFMAX ( 1 , st - > time_base . den / ( 500LL * st - > time_base . num ) ) & & ! st - > r_frame_rate . num )
2010-10-09 00:01:19 +02:00
av_reduce ( & st - > r_frame_rate . num , & st - > r_frame_rate . den , st - > time_base . den , st - > time_base . num * st - > info - > duration_gcd , INT_MAX ) ;
if ( st - > info - > duration_count & & ! st - > r_frame_rate . num
2007-12-27 01:16:48 +01:00
& & tb_unreliable ( st - > codec ) /*&&
2008-01-16 23:14:26 +01:00
//FIXME we should not special-case MPEG-2, but this needs testing with non-MPEG-2 ...
2010-10-09 00:01:19 +02:00
st - > time_base . num * duration_sum [ i ] / st - > info - > duration_count * 101LL > st - > time_base . den */ ) {
2009-02-27 15:13:15 +01:00
int num = 0 ;
2011-09-16 20:40:08 +02:00
double best_error = 0.01 ;
2012-04-09 18:54:42 +02:00
for ( j = 0 ; j < FF_ARRAY_ELEMS ( st - > info - > duration_error [ 0 ] [ 0 ] ) ; j + + ) {
2011-09-16 20:40:08 +02:00
int k ;
if ( st - > info - > codec_info_duration & & st - > info - > codec_info_duration * av_q2d ( st - > time_base ) < ( 1001 * 12.0 ) / get_std_framerate ( j ) )
continue ;
2011-12-15 21:26:50 +01:00
if ( ! st - > info - > codec_info_duration & & 1.0 < ( 1001 * 12.0 ) / get_std_framerate ( j ) )
continue ;
2011-09-16 20:40:08 +02:00
for ( k = 0 ; k < 2 ; k + + ) {
int n = st - > info - > duration_count ;
double a = st - > info - > duration_error [ k ] [ 0 ] [ j ] / n ;
double error = st - > info - > duration_error [ k ] [ 1 ] [ j ] / n - a * a ;
if ( error < best_error & & best_error > 0.000000001 ) {
best_error = error ;
num = get_std_framerate ( j ) ;
}
if ( error < 0.02 )
av_log ( NULL , AV_LOG_DEBUG , " rfps: %f %f \n " , get_std_framerate ( j ) / 12.0 / 1001 , error ) ;
2006-02-02 21:54:41 +01:00
}
2005-05-07 01:41:47 +02:00
}
2009-02-27 15:13:15 +01:00
// do not increase frame rate by more than 1 % in order to match a standard rate.
if ( num & & ( ! st - > r_frame_rate . num | | ( double ) num / ( 12 * 1001 ) < 1.01 * av_q2d ( st - > r_frame_rate ) ) )
av_reduce ( & st - > r_frame_rate . num , & st - > r_frame_rate . den , num , 12 * 1001 , INT_MAX ) ;
2004-12-19 02:23:22 +01:00
}
2005-04-30 23:43:59 +02:00
if ( ! st - > r_frame_rate . num ) {
2006-10-03 21:13:27 +02:00
if ( st - > codec - > time_base . den * ( int64_t ) st - > time_base . num
2009-02-27 00:47:32 +01:00
< = st - > codec - > time_base . num * st - > codec - > ticks_per_frame * ( int64_t ) st - > time_base . den ) {
2006-10-03 21:13:27 +02:00
st - > r_frame_rate . num = st - > codec - > time_base . den ;
2009-02-27 00:47:32 +01:00
st - > r_frame_rate . den = st - > codec - > time_base . num * st - > codec - > ticks_per_frame ;
2006-10-03 21:13:27 +02:00
} else {
st - > r_frame_rate . num = st - > time_base . den ;
st - > r_frame_rate . den = st - > time_base . num ;
}
2003-03-12 16:16:19 +01:00
}
2010-03-31 01:30:55 +02:00
} else if ( st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
2008-09-08 16:24:59 +02:00
if ( ! st - > codec - > bits_per_coded_sample )
st - > codec - > bits_per_coded_sample = av_get_bits_per_sample ( st - > codec - > codec_id ) ;
2011-03-24 17:09:02 +01:00
// set stream disposition based on audio service type
switch ( st - > codec - > audio_service_type ) {
case AV_AUDIO_SERVICE_TYPE_EFFECTS :
st - > disposition = AV_DISPOSITION_CLEAN_EFFECTS ; break ;
case AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED :
st - > disposition = AV_DISPOSITION_VISUAL_IMPAIRED ; break ;
case AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED :
st - > disposition = AV_DISPOSITION_HEARING_IMPAIRED ; break ;
case AV_AUDIO_SERVICE_TYPE_COMMENTARY :
st - > disposition = AV_DISPOSITION_COMMENT ; break ;
case AV_AUDIO_SERVICE_TYPE_KARAOKE :
st - > disposition = AV_DISPOSITION_KARAOKE ; break ;
}
2002-05-20 18:28:47 +02:00
}
2001-07-22 16:18:56 +02:00
}
2002-05-20 18:28:47 +02:00
2011-07-15 20:27:43 +02:00
estimate_timings ( ic , old_offset ) ;
2007-04-12 10:11:33 +02:00
2008-05-24 23:44:29 +02:00
compute_chapters_end ( ic ) ;
2010-10-09 00:01:19 +02:00
find_stream_info_err :
2011-12-25 11:45:05 +01:00
for ( i = 0 ; i < ic - > nb_streams ; i + + ) {
if ( ic - > streams [ i ] - > codec )
ic - > streams [ i ] - > codec - > thread_count = 0 ;
2010-10-09 00:01:19 +02:00
av_freep ( & ic - > streams [ i ] - > info ) ;
2011-12-25 11:45:05 +01:00
}
2012-04-14 10:43:35 +02:00
if ( ic - > pb )
av_log ( ic , AV_LOG_DEBUG , " File position after avformat_find_stream_info() is % " PRId64 " \n " , avio_tell ( ic - > pb ) ) ;
2002-05-20 18:28:47 +02:00
return ret ;
2001-07-22 16:18:56 +02:00
}
2011-08-22 23:42:19 +02:00
AVProgram * av_find_program_from_stream ( AVFormatContext * ic , AVProgram * last , int s )
2010-12-27 10:08:20 +01:00
{
int i , j ;
2011-08-22 23:42:19 +02:00
for ( i = 0 ; i < ic - > nb_programs ; i + + ) {
if ( ic - > programs [ i ] = = last ) {
last = NULL ;
} else {
if ( ! last )
for ( j = 0 ; j < ic - > programs [ i ] - > nb_stream_indexes ; j + + )
if ( ic - > programs [ i ] - > stream_index [ j ] = = s )
return ic - > programs [ i ] ;
}
}
2010-12-27 10:08:20 +01:00
return NULL ;
}
int av_find_best_stream ( AVFormatContext * ic ,
enum AVMediaType type ,
int wanted_stream_nb ,
int related_stream ,
AVCodec * * decoder_ret ,
int flags )
{
2011-02-20 01:18:30 +01:00
int i , nb_streams = ic - > nb_streams ;
2010-12-27 10:08:20 +01:00
int ret = AVERROR_STREAM_NOT_FOUND , best_count = - 1 ;
unsigned * program = NULL ;
AVCodec * decoder = NULL , * best_decoder = NULL ;
if ( related_stream > = 0 & & wanted_stream_nb < 0 ) {
2011-08-22 23:42:19 +02:00
AVProgram * p = av_find_program_from_stream ( ic , NULL , related_stream ) ;
2010-12-27 10:08:20 +01:00
if ( p ) {
program = p - > stream_index ;
nb_streams = p - > nb_stream_indexes ;
}
}
for ( i = 0 ; i < nb_streams ; i + + ) {
2011-02-20 01:18:30 +01:00
int real_stream_index = program ? program [ i ] : i ;
AVStream * st = ic - > streams [ real_stream_index ] ;
2010-12-27 10:08:20 +01:00
AVCodecContext * avctx = st - > codec ;
if ( avctx - > codec_type ! = type )
continue ;
2011-02-20 01:18:30 +01:00
if ( wanted_stream_nb > = 0 & & real_stream_index ! = wanted_stream_nb )
2010-12-27 10:08:20 +01:00
continue ;
2011-02-10 07:25:40 +01:00
if ( st - > disposition & ( AV_DISPOSITION_HEARING_IMPAIRED | AV_DISPOSITION_VISUAL_IMPAIRED ) )
continue ;
2010-12-27 10:08:20 +01:00
if ( decoder_ret ) {
2011-02-20 01:18:49 +01:00
decoder = avcodec_find_decoder ( st - > codec - > codec_id ) ;
2010-12-27 10:08:20 +01:00
if ( ! decoder ) {
if ( ret < 0 )
ret = AVERROR_DECODER_NOT_FOUND ;
continue ;
}
}
if ( best_count > = st - > codec_info_nb_frames )
continue ;
best_count = st - > codec_info_nb_frames ;
2011-02-20 01:18:30 +01:00
ret = real_stream_index ;
2010-12-27 10:08:20 +01:00
best_decoder = decoder ;
if ( program & & i = = nb_streams - 1 & & ret < 0 ) {
program = NULL ;
nb_streams = ic - > nb_streams ;
i = 0 ; /* no related stream found, try again with everything */
}
}
if ( decoder_ret )
* decoder_ret = best_decoder ;
return ret ;
}
2003-11-10 19:37:55 +01:00
/*******************************************************/
int av_read_play ( AVFormatContext * s )
{
2007-12-17 10:28:46 +01:00
if ( s - > iformat - > read_play )
return s - > iformat - > read_play ( s ) ;
2007-12-20 01:25:18 +01:00
if ( s - > pb )
2011-04-12 09:37:10 +02:00
return avio_pause ( s - > pb , 0 ) ;
2007-12-17 10:28:46 +01:00
return AVERROR ( ENOSYS ) ;
2003-11-10 19:37:55 +01:00
}
int av_read_pause ( AVFormatContext * s )
{
2007-12-17 10:28:46 +01:00
if ( s - > iformat - > read_pause )
return s - > iformat - > read_pause ( s ) ;
2007-12-20 01:25:18 +01:00
if ( s - > pb )
2011-04-12 09:37:10 +02:00
return avio_pause ( s - > pb , 1 ) ;
2007-12-17 10:28:46 +01:00
return AVERROR ( ENOSYS ) ;
2003-11-10 19:37:55 +01:00
}
2011-02-04 11:04:16 +01:00
void avformat_free_context ( AVFormatContext * s )
{
int i ;
AVStream * st ;
2011-06-05 13:18:17 +02:00
av_opt_free ( s ) ;
2011-06-06 13:14:05 +02:00
if ( s - > iformat & & s - > iformat - > priv_class & & s - > priv_data )
2011-06-05 13:18:17 +02:00
av_opt_free ( s - > priv_data ) ;
2001-07-22 16:18:56 +02:00
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
2003-10-29 15:20:56 +01:00
/* free all data in a stream component */
st = s - > streams [ i ] ;
2003-11-10 19:37:55 +01:00
if ( st - > parser ) {
av_parser_close ( st - > parser ) ;
2001-07-22 16:18:56 +02:00
}
2012-02-25 18:05:55 +01:00
if ( st - > attached_pic . data )
av_free_packet ( & st - > attached_pic ) ;
2011-05-22 12:46:29 +02:00
av_dict_free ( & st - > metadata ) ;
2011-10-01 01:29:30 +02:00
av_freep ( & st - > index_entries ) ;
av_freep ( & st - > codec - > extradata ) ;
av_freep ( & st - > codec - > subtitle_header ) ;
av_freep ( & st - > codec ) ;
av_freep ( & st - > priv_data ) ;
av_freep ( & st - > info ) ;
av_freep ( & st ) ;
2001-07-22 16:18:56 +02:00
}
2007-09-25 22:45:46 +02:00
for ( i = s - > nb_programs - 1 ; i > = 0 ; i - - ) {
2011-05-22 12:46:29 +02:00
av_dict_free ( & s - > programs [ i ] - > metadata ) ;
2007-10-20 10:25:13 +02:00
av_freep ( & s - > programs [ i ] - > stream_index ) ;
2007-09-25 22:45:46 +02:00
av_freep ( & s - > programs [ i ] ) ;
}
2008-04-25 01:09:28 +02:00
av_freep ( & s - > programs ) ;
2002-05-24 04:09:40 +02:00
av_freep ( & s - > priv_data ) ;
2008-05-23 15:07:58 +02:00
while ( s - > nb_chapters - - ) {
2011-05-22 12:46:29 +02:00
av_dict_free ( & s - > chapters [ s - > nb_chapters ] - > metadata ) ;
2011-10-01 01:29:30 +02:00
av_freep ( & s - > chapters [ s - > nb_chapters ] ) ;
2008-05-23 00:00:21 +02:00
}
av_freep ( & s - > chapters ) ;
2011-05-22 12:46:29 +02:00
av_dict_free ( & s - > metadata ) ;
2011-04-20 11:03:55 +02:00
av_freep ( & s - > streams ) ;
2002-05-19 01:11:09 +02:00
av_free ( s ) ;
2001-07-22 16:18:56 +02:00
}
2011-12-11 10:34:08 +01:00
# if FF_API_CLOSE_INPUT_FILE
2007-12-19 15:07:13 +01:00
void av_close_input_file ( AVFormatContext * s )
{
2011-12-11 10:34:08 +01:00
avformat_close_input ( & s ) ;
}
# endif
void avformat_close_input ( AVFormatContext * * ps )
{
AVFormatContext * s = * ps ;
2011-12-14 17:15:53 +01:00
AVIOContext * pb = ( s - > iformat & & ( s - > iformat - > flags & AVFMT_NOFILE ) ) | | ( s - > flags & AVFMT_FLAG_CUSTOM_IO ) ?
2011-05-22 08:37:25 +02:00
NULL : s - > pb ;
2011-12-11 10:01:46 +01:00
flush_packet_queue ( s ) ;
2011-12-14 17:15:53 +01:00
if ( s - > iformat & & ( s - > iformat - > read_close ) )
2011-12-11 10:01:46 +01:00
s - > iformat - > read_close ( s ) ;
avformat_free_context ( s ) ;
2011-12-11 10:34:08 +01:00
* ps = NULL ;
2007-12-19 15:07:13 +01:00
if ( pb )
2011-02-21 22:45:20 +01:00
avio_close ( pb ) ;
2007-12-19 15:07:13 +01:00
}
2012-02-06 17:21:46 +01:00
# if FF_API_NEW_STREAM
AVStream * av_new_stream ( AVFormatContext * s , int id )
{
AVStream * st = avformat_new_stream ( s , NULL ) ;
if ( st )
st - > id = id ;
return st ;
}
# endif
2011-06-18 11:19:27 +02:00
AVStream * avformat_new_stream ( AVFormatContext * s , AVCodec * c )
2002-05-20 18:28:47 +02:00
{
AVStream * st ;
2006-08-30 23:18:17 +02:00
int i ;
2010-10-06 22:56:14 +02:00
AVStream * * streams ;
2002-05-20 18:28:47 +02:00
2010-10-06 22:56:14 +02:00
if ( s - > nb_streams > = INT_MAX / sizeof ( * streams ) )
return NULL ;
streams = av_realloc ( s - > streams , ( s - > nb_streams + 1 ) * sizeof ( * streams ) ) ;
if ( ! streams )
return NULL ;
s - > streams = streams ;
2002-05-20 18:28:47 +02:00
st = av_mallocz ( sizeof ( AVStream ) ) ;
if ( ! st )
return NULL ;
2010-10-09 00:01:19 +02:00
if ( ! ( st - > info = av_mallocz ( sizeof ( * st - > info ) ) ) ) {
av_free ( st ) ;
return NULL ;
}
2012-03-07 21:41:54 +01:00
st - > info - > last_dts = AV_NOPTS_VALUE ;
2005-12-17 19:14:38 +01:00
2011-06-18 11:19:27 +02:00
st - > codec = avcodec_alloc_context3 ( c ) ;
2003-08-08 20:13:43 +02:00
if ( s - > iformat ) {
/* no default bitrate if decoding */
2005-07-18 00:24:36 +02:00
st - > codec - > bit_rate = 0 ;
2003-08-08 20:13:43 +02:00
}
2002-05-20 18:28:47 +02:00
st - > index = s - > nb_streams ;
2003-08-08 20:02:23 +02:00
st - > start_time = AV_NOPTS_VALUE ;
st - > duration = AV_NOPTS_VALUE ;
2008-07-08 16:07:37 +02:00
/* we set the current DTS to 0 so that formats without any timestamps
but durations get some timestamps , formats with some unknown
timestamps have their first few packets buffered and the
timestamps corrected before they are returned to the user */
2012-03-07 22:13:39 +01:00
st - > cur_dts = s - > iformat ? RELATIVE_TS_BASE : 0 ;
2007-08-05 00:46:13 +02:00
st - > first_dts = AV_NOPTS_VALUE ;
2009-05-31 02:24:06 +02:00
st - > probe_packets = MAX_PROBE_PACKETS ;
2004-05-21 22:43:21 +02:00
2008-01-16 23:14:26 +01:00
/* default pts setting is MPEG-like */
2011-11-29 19:28:15 +01:00
avpriv_set_pts_info ( st , 33 , 1 , 90000 ) ;
2008-02-20 21:24:38 +01:00
st - > last_IP_pts = AV_NOPTS_VALUE ;
2006-08-30 23:18:17 +02:00
for ( i = 0 ; i < MAX_REORDER_DELAY + 1 ; i + + )
st - > pts_buffer [ i ] = AV_NOPTS_VALUE ;
2009-02-24 23:19:09 +01:00
st - > reference_dts = AV_NOPTS_VALUE ;
2004-05-21 22:43:21 +02:00
2008-08-24 01:13:58 +02:00
st - > sample_aspect_ratio = ( AVRational ) { 0 , 1 } ;
2002-05-20 18:28:47 +02:00
s - > streams [ s - > nb_streams + + ] = st ;
return st ;
}
2007-09-25 22:45:46 +02:00
AVProgram * av_new_program ( AVFormatContext * ac , int id )
{
AVProgram * program = NULL ;
int i ;
2011-06-07 13:18:12 +02:00
av_dlog ( ac , " new_program: id=0x%04x \n " , id ) ;
2007-09-25 22:45:46 +02:00
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 ;
}
2011-10-17 08:58:50 +02:00
AVChapter * avpriv_new_chapter ( AVFormatContext * s , int id , AVRational time_base , int64_t start , int64_t end , const char * title )
2008-05-23 00:00:21 +02:00
{
2008-05-23 15:02:27 +02:00
AVChapter * chapter = NULL ;
int i ;
2008-05-23 15:07:58 +02:00
for ( i = 0 ; i < s - > nb_chapters ; i + + )
2008-05-23 15:02:27 +02:00
if ( s - > chapters [ i ] - > id = = id )
chapter = s - > chapters [ i ] ;
if ( ! chapter ) {
chapter = av_mallocz ( sizeof ( AVChapter ) ) ;
2008-05-23 15:03:04 +02:00
if ( ! chapter )
2008-05-23 15:14:11 +02:00
return NULL ;
2008-05-23 15:07:58 +02:00
dynarray_add ( & s - > chapters , & s - > nb_chapters , chapter ) ;
2008-05-23 15:02:27 +02:00
}
2011-05-22 12:46:29 +02:00
av_dict_set ( & chapter - > metadata , " title " , title , 0 ) ;
2008-05-23 15:02:27 +02:00
chapter - > id = id ;
2008-05-23 20:15:13 +02:00
chapter - > time_base = time_base ;
2008-05-23 00:00:21 +02:00
chapter - > start = start ;
2008-05-23 15:04:12 +02:00
chapter - > end = end ;
2008-05-23 00:00:21 +02:00
2008-05-23 15:14:11 +02:00
return chapter ;
2008-05-23 00:00:21 +02:00
}
2007-09-25 22:45:46 +02:00
2002-05-20 18:28:47 +02:00
/************************************************************/
/* output media file */
2001-07-22 16:18:56 +02:00
2011-05-19 22:09:34 +02:00
int avformat_alloc_output_context2 ( AVFormatContext * * avctx , AVOutputFormat * oformat ,
const char * format , const char * filename )
{
2011-05-19 22:12:37 +02:00
AVFormatContext * s = avformat_alloc_context ( ) ;
2011-05-19 22:09:34 +02:00
int ret = 0 ;
* avctx = NULL ;
2011-05-19 22:12:37 +02:00
if ( ! s )
2011-04-30 20:43:16 +02:00
goto nomem ;
2011-05-19 22:12:37 +02:00
if ( ! oformat ) {
2011-04-30 20:43:16 +02:00
if ( format ) {
oformat = av_guess_format ( format , NULL , NULL ) ;
if ( ! oformat ) {
av_log ( s , AV_LOG_ERROR , " Requested output format '%s' is not a suitable output format \n " , format ) ;
2011-05-19 22:09:34 +02:00
ret = AVERROR ( EINVAL ) ;
2011-04-30 20:43:16 +02:00
goto error ;
}
} else {
oformat = av_guess_format ( NULL , filename , NULL ) ;
if ( ! oformat ) {
2011-05-19 22:09:34 +02:00
ret = AVERROR ( EINVAL ) ;
2011-04-30 20:43:16 +02:00
av_log ( s , AV_LOG_ERROR , " Unable to find a suitable output format for '%s' \n " ,
2011-05-19 22:12:37 +02:00
filename ) ;
2011-04-30 20:43:16 +02:00
goto error ;
}
}
}
2011-05-19 22:12:37 +02:00
s - > oformat = oformat ;
2011-04-30 20:43:16 +02:00
if ( s - > oformat - > priv_data_size > 0 ) {
s - > priv_data = av_mallocz ( s - > oformat - > priv_data_size ) ;
if ( ! s - > priv_data )
goto nomem ;
if ( s - > oformat - > priv_class ) {
* ( const AVClass * * ) s - > priv_data = s - > oformat - > priv_class ;
av_opt_set_defaults ( s - > priv_data ) ;
}
} else
s - > priv_data = NULL ;
2011-05-19 22:12:37 +02:00
if ( filename )
2011-04-30 20:43:16 +02:00
av_strlcpy ( s - > filename , filename , sizeof ( s - > filename ) ) ;
2011-05-19 22:09:34 +02:00
* avctx = s ;
return 0 ;
2011-04-30 20:43:16 +02:00
nomem :
av_log ( s , AV_LOG_ERROR , " Out of memory \n " ) ;
2011-05-19 22:09:34 +02:00
ret = AVERROR ( ENOMEM ) ;
2011-04-30 20:43:16 +02:00
error :
avformat_free_context ( s ) ;
2011-05-19 22:09:34 +02:00
return ret ;
2011-04-30 20:43:16 +02:00
}
2011-05-19 22:09:34 +02:00
# if FF_API_ALLOC_OUTPUT_CONTEXT
AVFormatContext * avformat_alloc_output_context ( const char * format ,
AVOutputFormat * oformat , const char * filename )
{
AVFormatContext * avctx ;
int ret = avformat_alloc_output_context2 ( & avctx , oformat , format , filename ) ;
return ret < 0 ? NULL : avctx ;
}
# endif
2010-05-18 21:23:29 +02:00
static int validate_codec_tag ( AVFormatContext * s , AVStream * st )
{
const AVCodecTag * avctag ;
int n ;
enum CodecID id = CODEC_ID_NONE ;
unsigned int tag = 0 ;
/**
* Check that tag + id is in the table
* If neither is in the table - > OK
* If tag is in the table with another id - > FAIL
* If id is in the table with another tag - > FAIL unless strict < normal
*/
for ( n = 0 ; s - > oformat - > codec_tag [ n ] ; n + + ) {
avctag = s - > oformat - > codec_tag [ n ] ;
while ( avctag - > id ! = CODEC_ID_NONE ) {
2011-10-17 10:12:51 +02:00
if ( avpriv_toupper4 ( avctag - > tag ) = = avpriv_toupper4 ( st - > codec - > codec_tag ) ) {
2010-05-18 21:23:29 +02:00
id = avctag - > id ;
if ( id = = st - > codec - > codec_id )
return 1 ;
}
if ( avctag - > id = = st - > codec - > codec_id )
tag = avctag - > tag ;
avctag + + ;
}
}
if ( id ! = CODEC_ID_NONE )
return 0 ;
if ( tag & & ( st - > codec - > strict_std_compliance > = FF_COMPLIANCE_NORMAL ) )
return 0 ;
return 1 ;
}
2011-05-22 13:53:33 +02:00
int avformat_write_header ( AVFormatContext * s , AVDictionary * * options )
{
int ret = 0 , i ;
2002-10-21 19:40:23 +02:00
AVStream * st ;
2011-05-22 13:53:33 +02:00
AVDictionary * tmp = NULL ;
if ( options )
av_dict_copy ( & tmp , * options , 0 ) ;
if ( ( ret = av_opt_set_dict ( s , & tmp ) ) < 0 )
goto fail ;
2011-07-25 22:25:24 +02:00
if ( s - > priv_data & & s - > oformat - > priv_class & & * ( const AVClass * * ) s - > priv_data = = s - > oformat - > priv_class & &
( ret = av_opt_set_dict ( s - > priv_data , & tmp ) ) < 0 )
goto fail ;
2002-10-21 19:40:23 +02:00
2005-08-14 18:19:20 +02:00
// some sanity checks
2010-12-27 08:46:44 +01:00
if ( s - > nb_streams = = 0 & & ! ( s - > oformat - > flags & AVFMT_NOSTREAMS ) ) {
2010-01-13 15:32:48 +01:00
av_log ( s , AV_LOG_ERROR , " no streams \n " ) ;
2011-05-22 13:53:33 +02:00
ret = AVERROR ( EINVAL ) ;
goto fail ;
2010-01-13 15:32:48 +01:00
}
2005-08-14 18:19:20 +02:00
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
st = s - > streams [ i ] ;
switch ( st - > codec - > codec_type ) {
2010-03-31 01:30:55 +02:00
case AVMEDIA_TYPE_AUDIO :
2005-08-14 18:19:20 +02:00
if ( st - > codec - > sample_rate < = 0 ) {
av_log ( s , AV_LOG_ERROR , " sample rate not set \n " ) ;
2011-05-22 13:53:33 +02:00
ret = AVERROR ( EINVAL ) ;
goto fail ;
2005-08-14 18:19:20 +02:00
}
2008-09-08 21:37:22 +02:00
if ( ! st - > codec - > block_align )
st - > codec - > block_align = st - > codec - > channels *
av_get_bits_per_sample ( st - > codec - > codec_id ) > > 3 ;
2005-08-14 18:19:20 +02:00
break ;
2010-03-31 01:30:55 +02:00
case AVMEDIA_TYPE_VIDEO :
2005-08-14 18:19:20 +02:00
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 " ) ;
2011-05-22 13:53:33 +02:00
ret = AVERROR ( EINVAL ) ;
goto fail ;
2005-08-14 18:19:20 +02:00
}
2010-02-12 21:35:29 +01:00
if ( ( st - > codec - > width < = 0 | | st - > codec - > height < = 0 ) & & ! ( s - > oformat - > flags & AVFMT_NODIMENSIONS ) ) {
2005-08-14 18:19:20 +02:00
av_log ( s , AV_LOG_ERROR , " dimensions not set \n " ) ;
2011-05-22 13:53:33 +02:00
ret = AVERROR ( EINVAL ) ;
goto fail ;
2005-08-14 18:19:20 +02:00
}
2011-09-22 18:17:28 +02:00
if ( av_cmp_q ( st - > sample_aspect_ratio , st - > codec - > sample_aspect_ratio )
2011-10-03 16:32:17 +02:00
& & FFABS ( av_q2d ( st - > sample_aspect_ratio ) - av_q2d ( st - > codec - > sample_aspect_ratio ) ) > 0.004 * av_q2d ( st - > sample_aspect_ratio )
2011-09-22 18:17:28 +02:00
) {
2012-02-12 15:47:31 +01:00
av_log ( s , AV_LOG_ERROR , " Aspect ratio mismatch between muxer "
" (%d/%d) and encoder layer (%d/%d) \n " ,
2012-01-29 05:29:26 +01:00
st - > sample_aspect_ratio . num , st - > sample_aspect_ratio . den ,
st - > codec - > sample_aspect_ratio . num ,
st - > codec - > sample_aspect_ratio . den ) ;
2011-05-22 13:53:33 +02:00
ret = AVERROR ( EINVAL ) ;
goto fail ;
2008-09-19 14:37:38 +02:00
}
2005-08-14 18:19:20 +02:00
break ;
}
2007-01-21 13:31:58 +01:00
if ( s - > oformat - > codec_tag ) {
2012-05-11 16:53:22 +02:00
if ( st - > codec - > codec_tag
& & st - > codec - > codec_id = = CODEC_ID_RAWVIDEO
& & ( av_codec_get_tag ( s - > oformat - > codec_tag , st - > codec - > codec_id ) = = 0 | | av_codec_get_tag ( s - > oformat - > codec_tag , st - > codec - > codec_id ) = = MKTAG ( ' r ' , ' a ' , ' w ' , ' ' ) )
& & ! validate_codec_tag ( s , st ) ) {
//the current rawvideo encoding system ends up setting the wrong codec_tag for avi/mov, we override it here
2010-06-06 01:13:52 +02:00
st - > codec - > codec_tag = 0 ;
}
2007-01-21 13:31:58 +01:00
if ( st - > codec - > codec_tag ) {
2010-05-18 21:23:29 +02:00
if ( ! validate_codec_tag ( s , st ) ) {
2012-05-11 16:52:47 +02:00
char tagbuf [ 32 ] , cortag [ 32 ] ;
2010-06-02 12:54:53 +02:00
av_get_codec_tag_string ( tagbuf , sizeof ( tagbuf ) , st - > codec - > codec_tag ) ;
2012-05-11 16:52:47 +02:00
av_get_codec_tag_string ( cortag , sizeof ( cortag ) , av_codec_get_tag ( s - > oformat - > codec_tag , st - > codec - > codec_id ) ) ;
2010-05-18 21:23:29 +02:00
av_log ( s , AV_LOG_ERROR ,
2012-05-11 16:52:47 +02:00
" Tag %s/0x%08x incompatible with output codec id '%d' (%s) \n " ,
tagbuf , st - > codec - > codec_tag , st - > codec - > codec_id , cortag ) ;
2011-05-22 13:53:33 +02:00
ret = AVERROR_INVALIDDATA ;
goto fail ;
2010-05-18 21:23:29 +02:00
}
2007-01-21 13:31:58 +01:00
} else
st - > codec - > codec_tag = av_codec_get_tag ( s - > oformat - > codec_tag , st - > codec - > codec_id ) ;
}
2009-02-12 09:10:43 +01:00
if ( s - > oformat - > flags & AVFMT_GLOBALHEADER & &
! ( st - > codec - > flags & CODEC_FLAG_GLOBAL_HEADER ) )
av_log ( s , AV_LOG_WARNING , " Codec for stream %d does not use global headers but container format requires global headers \n " , i ) ;
2005-08-14 18:19:20 +02:00
}
2007-01-08 15:22:00 +01:00
if ( ! s - > priv_data & & s - > oformat - > priv_data_size > 0 ) {
2007-01-08 13:57:08 +01:00
s - > priv_data = av_mallocz ( s - > oformat - > priv_data_size ) ;
2011-05-22 13:53:33 +02:00
if ( ! s - > priv_data ) {
ret = AVERROR ( ENOMEM ) ;
goto fail ;
}
if ( s - > oformat - > priv_class ) {
* ( const AVClass * * ) s - > priv_data = s - > oformat - > priv_class ;
av_opt_set_defaults ( s - > priv_data ) ;
if ( ( ret = av_opt_set_dict ( s - > priv_data , & tmp ) ) < 0 )
goto fail ;
}
2007-01-08 15:22:00 +01:00
}
2007-01-08 13:57:08 +01:00
2010-02-16 17:32:25 +01:00
/* set muxer identification string */
2010-12-27 08:46:44 +01:00
if ( s - > nb_streams & & ! ( s - > streams [ 0 ] - > codec - > flags & CODEC_FLAG_BITEXACT ) ) {
2011-05-22 12:46:29 +02:00
av_dict_set ( & s - > metadata , " encoder " , LIBAVFORMAT_IDENT , 0 ) ;
2010-02-16 17:32:25 +01:00
}
2005-11-05 00:50:11 +01:00
if ( s - > oformat - > write_header ) {
ret = s - > oformat - > write_header ( s ) ;
if ( ret < 0 )
2011-05-22 13:53:33 +02:00
goto fail ;
2005-11-05 00:50:11 +01:00
}
2002-10-21 19:40:23 +02:00
/* init PTS generation */
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
2005-08-14 18:37:29 +02:00
int64_t den = AV_NOPTS_VALUE ;
2002-10-21 19:40:23 +02:00
st = s - > streams [ i ] ;
2005-07-18 00:24:36 +02:00
switch ( st - > codec - > codec_type ) {
2010-03-31 01:30:55 +02:00
case AVMEDIA_TYPE_AUDIO :
2005-08-14 18:37:29 +02:00
den = ( int64_t ) st - > time_base . num * st - > codec - > sample_rate ;
2002-10-21 19:40:23 +02:00
break ;
2010-03-31 01:30:55 +02:00
case AVMEDIA_TYPE_VIDEO :
2005-08-14 18:37:29 +02:00
den = ( int64_t ) st - > time_base . num * st - > codec - > time_base . den ;
2002-10-21 19:40:23 +02:00
break ;
default :
break ;
}
2005-08-14 18:37:29 +02:00
if ( den ! = AV_NOPTS_VALUE ) {
2011-05-22 13:53:33 +02:00
if ( den < = 0 ) {
ret = AVERROR_INVALIDDATA ;
goto fail ;
}
2011-07-15 20:27:43 +02:00
frac_init ( & st - > pts , 0 , 0 , den ) ;
2005-08-14 18:37:29 +02:00
}
2002-10-21 19:40:23 +02:00
}
2011-05-22 13:53:33 +02:00
if ( options ) {
av_dict_free ( options ) ;
* options = tmp ;
}
2002-10-21 19:40:23 +02:00
return 0 ;
2011-05-22 13:53:33 +02:00
fail :
av_dict_free ( & tmp ) ;
return ret ;
2002-05-20 18:28:47 +02:00
}
2004-05-29 20:50:31 +02:00
//FIXME merge with compute_pkt_fields
2009-12-01 21:15:05 +01:00
static int compute_pkt_fields2 ( AVFormatContext * s , AVStream * st , AVPacket * pkt ) {
2006-08-30 23:18:17 +02:00
int delay = FFMAX ( st - > codec - > has_b_frames , ! ! st - > codec - > max_b_frames ) ;
int num , den , frame_size , i ;
2004-04-04 20:33:07 +02:00
2012-05-13 22:22:35 +02:00
av_dlog ( s , " compute_pkt_fields2: pts:%s dts:%s cur_dts:%s b:%d size:%d st:%d \n " ,
av_ts2str ( pkt - > pts ) , av_ts2str ( pkt - > dts ) , av_ts2str ( st - > cur_dts ) , delay , pkt - > size , pkt - > stream_index ) ;
2005-12-17 19:14:38 +01:00
2004-05-29 04:06:32 +02:00
/* duration field */
2004-05-29 20:50:31 +02:00
if ( pkt - > duration = = 0 ) {
compute_frame_duration ( & num , & den , st , NULL , pkt ) ;
if ( den & & num ) {
2009-02-27 00:47:32 +01:00
pkt - > duration = av_rescale ( 1 , num * ( int64_t ) st - > time_base . den * st - > codec - > ticks_per_frame , den * ( int64_t ) st - > time_base . num ) ;
2004-05-29 20:50:31 +02:00
}
}
2004-05-29 04:06:32 +02:00
2008-06-25 20:31:48 +02:00
if ( pkt - > pts = = AV_NOPTS_VALUE & & pkt - > dts ! = AV_NOPTS_VALUE & & delay = = 0 )
pkt - > pts = pkt - > dts ;
2004-05-29 04:06:32 +02:00
//XXX/FIXME this is a temporary hack until all encoders output pts
2006-08-30 23:18:17 +02:00
if ( ( pkt - > pts = = 0 | | pkt - > pts = = AV_NOPTS_VALUE ) & & pkt - > dts = = AV_NOPTS_VALUE & & ! delay ) {
2012-01-22 14:12:22 +01:00
static int warned ;
if ( ! warned ) {
av_log ( s , AV_LOG_WARNING , " Encoder did not produce proper pts, making some up. \n " ) ;
warned = 1 ;
}
2004-05-29 04:06:32 +02:00
pkt - > dts =
// pkt->pts= st->cur_dts;
pkt - > pts = st - > pts . val ;
}
2005-12-17 19:14:38 +01:00
//calculate dts from pts
2008-08-12 19:26:36 +02:00
if ( pkt - > pts ! = AV_NOPTS_VALUE & & pkt - > dts = = AV_NOPTS_VALUE & & delay < = MAX_REORDER_DELAY ) {
2006-08-30 23:18:17 +02:00
st - > pts_buffer [ 0 ] = pkt - > pts ;
for ( i = 1 ; i < delay + 1 & & st - > pts_buffer [ i ] = = AV_NOPTS_VALUE ; i + + )
2010-03-08 00:10:18 +01:00
st - > pts_buffer [ i ] = pkt - > pts + ( i - delay - 1 ) * pkt - > duration ;
2006-08-30 23:18:17 +02:00
for ( i = 0 ; i < delay & & st - > pts_buffer [ i ] > st - > pts_buffer [ i + 1 ] ; i + + )
2006-11-01 22:28:36 +01:00
FFSWAP ( int64_t , st - > pts_buffer [ i ] , st - > pts_buffer [ i + 1 ] ) ;
2006-08-30 23:18:17 +02:00
pkt - > dts = st - > pts_buffer [ 0 ] ;
2004-05-29 04:06:32 +02:00
}
2005-12-17 19:14:38 +01:00
2011-05-26 20:19:04 +02:00
if ( st - > cur_dts & & st - > cur_dts ! = AV_NOPTS_VALUE & &
( ( ! ( s - > oformat - > flags & AVFMT_TS_NONSTRICT ) & &
st - > cur_dts > = pkt - > dts ) | | st - > cur_dts > pkt - > dts ) ) {
2009-12-01 21:15:05 +01:00
av_log ( s , AV_LOG_ERROR ,
2012-05-13 22:22:35 +02:00
" Application provided invalid, non monotonically increasing dts to muxer in stream %d: %s >= %s \n " ,
st - > index , av_ts2str ( st - > cur_dts ) , av_ts2str ( pkt - > dts ) ) ;
2011-03-15 12:34:55 +01:00
return AVERROR ( EINVAL ) ;
2004-12-14 17:19:26 +01:00
}
if ( pkt - > dts ! = AV_NOPTS_VALUE & & pkt - > pts ! = AV_NOPTS_VALUE & & pkt - > pts < pkt - > dts ) {
2012-05-13 22:22:35 +02:00
av_log ( s , AV_LOG_ERROR , " pts (%s) < dts (%s) in stream %d \n " ,
av_ts2str ( pkt - > pts ) , av_ts2str ( pkt - > dts ) , st - > index ) ;
2011-03-15 12:34:55 +01:00
return AVERROR ( EINVAL ) ;
2004-12-14 17:19:26 +01:00
}
2012-05-13 22:22:35 +02:00
// av_log(s, AV_LOG_DEBUG, "av_write_frame: pts2:%s dts2:%s\n", av_ts2str(pkt->pts), av_ts2str(pkt->dts));
2004-05-29 04:06:32 +02:00
st - > cur_dts = pkt - > dts ;
st - > pts . val = pkt - > dts ;
2002-10-21 19:40:23 +02:00
/* update pts */
2005-07-18 00:24:36 +02:00
switch ( st - > codec - > codec_type ) {
2010-03-31 01:30:55 +02:00
case AVMEDIA_TYPE_AUDIO :
2012-02-27 21:54:41 +01:00
frame_size = get_audio_frame_size ( st - > codec , pkt - > size , 1 ) ;
2004-04-04 16:39:20 +02:00
2008-01-16 23:14:26 +01: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 04:06:32 +02:00
if ( frame_size > = 0 & & ( pkt - > size | | st - > pts . num ! = st - > pts . den > > 1 | | st - > pts . val ) ) {
2011-07-15 20:27:43 +02:00
frac_add ( & st - > pts , ( int64_t ) st - > time_base . den * frame_size ) ;
2002-11-19 19:30:03 +01:00
}
2002-10-21 19:40:23 +02:00
break ;
2010-03-31 01:30:55 +02:00
case AVMEDIA_TYPE_VIDEO :
2011-07-15 20:27:43 +02:00
frac_add ( & st - > pts , ( int64_t ) st - > time_base . den * st - > codec - > time_base . num ) ;
2002-10-21 19:40:23 +02:00
break ;
default :
break ;
}
2004-12-14 17:19:26 +01:00
return 0 ;
2004-05-29 20:50:31 +02:00
}
int av_write_frame ( AVFormatContext * s , AVPacket * pkt )
{
2012-01-20 18:27:33 +01:00
int ret ;
if ( ! pkt ) {
if ( s - > oformat - > flags & AVFMT_ALLOW_FLUSH )
return s - > oformat - > write_packet ( s , pkt ) ;
return 1 ;
}
ret = compute_pkt_fields2 ( s , s - > streams [ pkt - > stream_index ] , pkt ) ;
2004-10-08 22:09:52 +02:00
2006-08-08 22:31:19 +02:00
if ( ret < 0 & & ! ( s - > oformat - > flags & AVFMT_NOTIMESTAMPS ) )
2004-12-14 17:19:26 +01:00
return ret ;
2005-12-17 19:14:38 +01:00
2004-10-08 22:09:52 +02:00
ret = s - > oformat - > write_packet ( s , pkt ) ;
2011-03-16 08:45:14 +01:00
if ( ret > = 0 )
s - > streams [ pkt - > stream_index ] - > nb_frames + + ;
2004-10-08 22:09:52 +02:00
return ret ;
2004-05-29 20:50:31 +02:00
}
2011-11-30 00:21:00 +01:00
# define CHUNK_START 0x1000
2011-11-08 10:35:14 +01:00
int ff_interleave_add_packet ( AVFormatContext * s , AVPacket * pkt ,
2009-01-31 07:01:58 +01:00
int ( * compare ) ( AVFormatContext * , AVPacket * , AVPacket * ) )
{
AVPacketList * * next_point , * this_pktl ;
2011-11-30 00:21:00 +01:00
AVStream * st = s - > streams [ pkt - > stream_index ] ;
int chunked = s - > max_chunk_size | | s - > max_chunk_duration ;
2009-01-31 07:01:58 +01:00
this_pktl = av_mallocz ( sizeof ( AVPacketList ) ) ;
2011-11-08 10:35:14 +01:00
if ( ! this_pktl )
return AVERROR ( ENOMEM ) ;
2009-01-31 07:01:58 +01:00
this_pktl - > pkt = * pkt ;
2009-04-12 00:38:00 +02:00
pkt - > destruct = NULL ; // do not free original but only the copy
av_dup_packet ( & this_pktl - > pkt ) ; // duplicate the packet if it uses non-alloced memory
2009-01-31 07:01:58 +01:00
2009-09-16 22:04:04 +02:00
if ( s - > streams [ pkt - > stream_index ] - > last_in_packet_buffer ) {
2011-11-30 00:21:00 +01:00
next_point = & ( st - > last_in_packet_buffer - > next ) ;
} else {
2009-09-16 03:17:39 +02:00
next_point = & s - > packet_buffer ;
2011-11-30 00:21:00 +01:00
}
2009-09-16 22:04:04 +02:00
if ( * next_point ) {
2011-11-30 00:21:00 +01:00
if ( chunked ) {
uint64_t max = av_rescale_q ( s - > max_chunk_duration , AV_TIME_BASE_Q , st - > time_base ) ;
if ( st - > interleaver_chunk_size + pkt - > size < = s - > max_chunk_size - 1U
& & st - > interleaver_chunk_duration + pkt - > duration < = max - 1U ) {
st - > interleaver_chunk_size + = pkt - > size ;
st - > interleaver_chunk_duration + = pkt - > duration ;
goto next_non_null ;
} else {
st - > interleaver_chunk_size =
st - > interleaver_chunk_duration = 0 ;
this_pktl - > pkt . flags | = CHUNK_START ;
}
}
2009-09-16 22:04:04 +02:00
if ( compare ( s , & s - > packet_buffer_end - > pkt , pkt ) ) {
2011-11-30 00:21:00 +01:00
while ( * next_point
& & ( ( chunked & & ! ( ( * next_point ) - > pkt . flags & CHUNK_START ) )
| | ! compare ( s , & ( * next_point ) - > pkt , pkt ) ) ) {
2009-09-16 22:06:48 +02:00
next_point = & ( * next_point ) - > next ;
}
2011-11-30 00:21:00 +01:00
if ( * next_point )
goto next_non_null ;
2009-09-16 22:06:48 +02:00
} else {
next_point = & ( s - > packet_buffer_end - > next ) ;
2009-09-16 22:04:04 +02:00
}
2009-09-16 02:59:15 +02:00
}
2009-09-16 22:06:48 +02:00
assert ( ! * next_point ) ;
2009-09-16 02:59:15 +02:00
2009-09-16 22:06:48 +02:00
s - > packet_buffer_end = this_pktl ;
2009-09-16 22:04:04 +02:00
next_non_null :
2009-09-16 02:59:15 +02:00
2009-09-16 22:04:04 +02:00
this_pktl - > next = * next_point ;
2009-09-16 02:59:15 +02:00
2009-09-16 22:04:04 +02:00
s - > streams [ pkt - > stream_index ] - > last_in_packet_buffer =
* next_point = this_pktl ;
2011-11-08 10:35:14 +01:00
return 0 ;
2009-01-31 07:01:58 +01:00
}
2011-01-25 02:29:36 +01:00
static int ff_interleave_compare_dts ( AVFormatContext * s , AVPacket * next , AVPacket * pkt )
2009-01-31 07:01:58 +01:00
{
AVStream * st = s - > streams [ pkt - > stream_index ] ;
AVStream * st2 = s - > streams [ next - > stream_index ] ;
2011-05-07 22:48:29 +02:00
int comp = av_compare_ts ( next - > dts , st2 - > time_base , pkt - > dts ,
st - > time_base ) ;
2011-10-26 22:17:08 +02:00
if ( s - > audio_preload & & ( ( st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) ! = ( st2 - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) ) ) {
int64_t ts = av_rescale_q ( pkt - > dts , st - > time_base , AV_TIME_BASE_Q ) - s - > audio_preload * ( st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) ;
int64_t ts2 = av_rescale_q ( next - > dts , st2 - > time_base , AV_TIME_BASE_Q ) - s - > audio_preload * ( st2 - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) ;
if ( ts = = ts2 ) {
ts = ( pkt - > dts * st - > time_base . num * AV_TIME_BASE - s - > audio_preload * ( int64_t ) ( st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) * st - > time_base . den ) * st2 - > time_base . den
- ( next - > dts * st2 - > time_base . num * AV_TIME_BASE - s - > audio_preload * ( int64_t ) ( st2 - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO ) * st2 - > time_base . den ) * st - > time_base . den ;
ts2 = 0 ;
}
comp = ( ts > ts2 ) - ( ts < ts2 ) ;
}
2011-05-07 22:48:29 +02:00
if ( comp = = 0 )
2011-04-11 22:20:36 +02:00
return pkt - > stream_index < next - > stream_index ;
2011-05-07 22:48:29 +02:00
return comp > 0 ;
2009-01-31 07:01:58 +01:00
}
2012-03-15 13:37:43 +01:00
int ff_interleave_packet_per_dts ( AVFormatContext * s , AVPacket * out ,
AVPacket * pkt , int flush )
{
2009-01-31 07:01:58 +01:00
AVPacketList * pktl ;
2011-09-07 00:10:44 +02:00
int stream_count = 0 , noninterleaved_count = 0 ;
2011-09-09 17:15:08 +02:00
int64_t delta_dts_max = 0 ;
2011-11-08 10:35:14 +01:00
int i , ret ;
2004-09-30 01:25:01 +02:00
if ( pkt ) {
2011-11-08 10:35:14 +01:00
ret = ff_interleave_add_packet ( s , pkt , ff_interleave_compare_dts ) ;
if ( ret < 0 )
return ret ;
2004-09-30 01:25:01 +02:00
}
2005-12-17 19:14:38 +01:00
2011-09-07 00:10:44 +02:00
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
if ( s - > streams [ i ] - > last_in_packet_buffer ) {
+ + stream_count ;
2011-09-07 00:23:18 +02:00
} else if ( s - > streams [ i ] - > codec - > codec_type = = AVMEDIA_TYPE_SUBTITLE ) {
+ + noninterleaved_count ;
2011-09-07 00:10:44 +02:00
}
}
2005-12-17 19:14:38 +01:00
2011-09-07 00:10:44 +02:00
if ( s - > nb_streams = = stream_count ) {
flush = 1 ;
2011-09-07 00:23:18 +02:00
} else if ( ! flush ) {
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
if ( s - > streams [ i ] - > last_in_packet_buffer ) {
int64_t delta_dts =
av_rescale_q ( s - > streams [ i ] - > last_in_packet_buffer - > pkt . dts ,
s - > streams [ i ] - > time_base ,
AV_TIME_BASE_Q ) -
av_rescale_q ( s - > packet_buffer - > pkt . dts ,
s - > streams [ s - > packet_buffer - > pkt . stream_index ] - > time_base ,
AV_TIME_BASE_Q ) ;
2011-09-09 17:15:08 +02:00
delta_dts_max = FFMAX ( delta_dts_max , delta_dts ) ;
2011-09-07 00:23:18 +02:00
}
}
if ( s - > nb_streams = = stream_count + noninterleaved_count & &
2011-09-09 17:15:08 +02:00
delta_dts_max > 20 * AV_TIME_BASE ) {
2011-09-07 00:23:18 +02:00
av_log ( s , AV_LOG_DEBUG , " flushing with %d noninterleaved \n " , noninterleaved_count ) ;
flush = 1 ;
}
2011-09-07 00:10:44 +02:00
}
if ( stream_count & & flush ) {
2004-09-30 01:25:01 +02:00
pktl = s - > packet_buffer ;
* out = pktl - > pkt ;
2005-12-17 19:14:38 +01:00
s - > packet_buffer = pktl - > next ;
2009-09-16 02:59:15 +02:00
if ( ! s - > packet_buffer )
s - > packet_buffer_end = NULL ;
2009-09-16 22:04:04 +02:00
if ( s - > streams [ out - > stream_index ] - > last_in_packet_buffer = = pktl )
s - > streams [ out - > stream_index ] - > last_in_packet_buffer = NULL ;
2004-09-30 01:25:01 +02:00
av_freep ( & pktl ) ;
return 1 ;
} else {
av_init_packet ( out ) ;
return 0 ;
}
}
2012-03-15 13:37:43 +01:00
# if FF_API_INTERLEAVE_PACKET
int av_interleave_packet_per_dts ( AVFormatContext * s , AVPacket * out ,
AVPacket * pkt , int flush )
{
return ff_interleave_packet_per_dts ( s , out , pkt , flush ) ;
}
# endif
2004-09-30 01:25:01 +02:00
/**
2010-06-30 17:38:06 +02:00
* Interleave an AVPacket correctly so it can be muxed .
2004-09-30 01:25:01 +02: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 19:14:38 +01:00
* @ return 1 if a packet was output , 0 if no packet could be output ,
2008-03-22 02:06:57 +01:00
* < 0 if an error occurred
2004-09-30 01:25:01 +02:00
*/
2011-07-15 20:27:43 +02:00
static int interleave_packet ( AVFormatContext * s , AVPacket * out , AVPacket * in , int flush ) {
2012-01-18 08:07:40 +01:00
if ( s - > oformat - > interleave_packet ) {
int ret = s - > oformat - > interleave_packet ( s , out , in , flush ) ;
if ( in )
av_free_packet ( in ) ;
return ret ;
} else
2012-03-15 13:37:43 +01:00
return ff_interleave_packet_per_dts ( s , out , in , flush ) ;
2004-09-30 01:25:01 +02:00
}
2004-05-29 20:50:31 +02:00
int av_interleaved_write_frame ( AVFormatContext * s , AVPacket * pkt ) {
2012-03-21 11:42:32 +01:00
int ret , flush = 0 ;
2004-05-29 20:50:31 +02:00
2012-03-21 11:42:32 +01:00
if ( pkt ) {
AVStream * st = s - > streams [ pkt - > stream_index ] ;
2005-03-24 02:51:57 +01:00
2012-03-21 11:42:32 +01:00
//FIXME/XXX/HACK drop zero sized packets
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO & & pkt - > size = = 0 )
return 0 ;
2005-12-17 19:14:38 +01:00
2012-05-13 22:22:35 +02:00
av_dlog ( s , " av_interleaved_write_frame size:%d dts:%s pts:%s \n " ,
pkt - > size , av_ts2str ( pkt - > dts ) , av_ts2str ( pkt - > pts ) ) ;
2012-03-21 11:42:32 +01:00
if ( ( ret = compute_pkt_fields2 ( s , st , pkt ) ) < 0 & & ! ( s - > oformat - > flags & AVFMT_NOTIMESTAMPS ) )
return ret ;
if ( pkt - > dts = = AV_NOPTS_VALUE & & ! ( s - > oformat - > flags & AVFMT_NOTIMESTAMPS ) )
return AVERROR ( EINVAL ) ;
} else {
av_dlog ( s , " av_interleaved_write_frame FLUSH \n " ) ;
flush = 1 ;
}
2004-05-29 20:50:31 +02:00
2004-09-30 01:25:01 +02:00
for ( ; ; ) {
AVPacket opkt ;
2012-03-21 11:42:32 +01:00
int ret = interleave_packet ( s , & opkt , pkt , flush ) ;
2004-09-30 01:25:01 +02:00
if ( ret < = 0 ) //FIXME cleanup needed for ret<0 ?
return ret ;
2005-12-17 19:14:38 +01:00
2004-09-30 01:25:01 +02:00
ret = s - > oformat - > write_packet ( s , & opkt ) ;
2011-03-16 08:45:14 +01:00
if ( ret > = 0 )
s - > streams [ opkt . stream_index ] - > nb_frames + + ;
2005-12-17 19:14:38 +01:00
2004-09-30 01:25:01 +02:00
av_free_packet ( & opkt ) ;
pkt = NULL ;
2005-12-17 19:14:38 +01:00
2004-05-29 20:50:31 +02:00
if ( ret < 0 )
return ret ;
2011-09-14 19:54:48 +02:00
if ( s - > pb & & s - > pb - > error )
return s - > pb - > error ;
2004-05-29 20:50:31 +02:00
}
2002-05-20 18:28:47 +02:00
}
int av_write_trailer ( AVFormatContext * s )
{
2004-10-01 18:30:15 +02:00
int ret , i ;
2005-12-17 19:14:38 +01:00
2004-09-30 01:25:01 +02:00
for ( ; ; ) {
AVPacket pkt ;
2011-07-15 20:27:43 +02:00
ret = interleave_packet ( s , & pkt , NULL , 1 ) ;
2004-09-30 01:25:01 +02:00
if ( ret < 0 ) //FIXME cleanup needed for ret<0 ?
2004-10-01 18:30:15 +02:00
goto fail ;
2004-09-30 01:25:01 +02:00
if ( ! ret )
break ;
2005-12-17 19:14:38 +01:00
2004-09-30 01:25:01 +02:00
ret = s - > oformat - > write_packet ( s , & pkt ) ;
2011-03-16 08:45:14 +01:00
if ( ret > = 0 )
s - > streams [ pkt . stream_index ] - > nb_frames + + ;
2005-12-17 19:14:38 +01:00
2004-09-30 01:25:01 +02:00
av_free_packet ( & pkt ) ;
2005-12-17 19:14:38 +01:00
2004-05-29 20:50:31 +02:00
if ( ret < 0 )
2004-10-01 18:30:15 +02:00
goto fail ;
2011-09-14 19:54:48 +02:00
if ( s - > pb & & s - > pb - > error )
2004-10-08 22:09:52 +02:00
goto fail ;
2004-05-29 20:50:31 +02:00
}
2005-11-05 00:50:11 +01:00
if ( s - > oformat - > write_trailer )
ret = s - > oformat - > write_trailer ( s ) ;
2004-10-01 18:30:15 +02:00
fail :
2012-04-10 21:36:30 +02:00
if ( s - > pb )
avio_flush ( s - > pb ) ;
2004-10-08 22:09:52 +02:00
if ( ret = = 0 )
2011-09-14 19:54:48 +02:00
ret = s - > pb ? s - > pb - > error : 0 ;
2010-03-05 18:26:34 +01:00
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
2004-10-01 18:30:15 +02:00
av_freep ( & s - > streams [ i ] - > priv_data ) ;
2010-03-05 18:26:34 +01:00
av_freep ( & s - > streams [ i ] - > index_entries ) ;
}
2011-12-12 18:22:22 +01:00
if ( s - > oformat - > priv_class )
2011-06-05 13:18:17 +02:00
av_opt_free ( s - > priv_data ) ;
2002-05-20 18:28:47 +02:00
av_freep ( & s - > priv_data ) ;
return ret ;
2001-07-22 16:18:56 +02:00
}
2011-06-30 19:45:22 +02:00
int av_get_output_timestamp ( struct AVFormatContext * s , int stream ,
int64_t * dts , int64_t * wall )
{
if ( ! s - > oformat | | ! s - > oformat - > get_output_timestamp )
return AVERROR ( ENOSYS ) ;
s - > oformat - > get_output_timestamp ( s , stream , dts , wall ) ;
return 0 ;
}
2010-03-16 00:14:07 +01:00
void ff_program_add_stream_index ( AVFormatContext * ac , int progid , unsigned int idx )
2007-10-20 10:25:13 +02:00
{
int i , j ;
AVProgram * program = NULL ;
void * tmp ;
2009-10-19 20:55:27 +02:00
if ( idx > = ac - > nb_streams ) {
av_log ( ac , AV_LOG_ERROR , " stream index %d is not valid \n " , idx ) ;
return ;
}
2007-10-20 10:25:13 +02:00
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 ;
}
}
2009-02-22 00:00:07 +01:00
static void print_fps ( double d , const char * postfix ) {
uint64_t v = lrintf ( d * 100 ) ;
if ( v % 100 ) av_log ( NULL , AV_LOG_INFO , " , %3.2f %s " , d , postfix ) ;
else if ( v % ( 100 * 1000 ) ) av_log ( NULL , AV_LOG_INFO , " , %1.0f %s " , d , postfix ) ;
else av_log ( NULL , AV_LOG_INFO , " , %1.0fk %s " , d / 1000 , postfix ) ;
}
2011-05-22 12:46:29 +02:00
static void dump_metadata ( void * ctx , AVDictionary * m , const char * indent )
2009-12-14 00:19:24 +01:00
{
2011-05-22 12:46:29 +02:00
if ( m & & ! ( m - > count = = 1 & & av_dict_get ( m , " language " , NULL , 0 ) ) ) {
AVDictionaryEntry * tag = NULL ;
2009-12-14 00:19:24 +01:00
av_log ( ctx , AV_LOG_INFO , " %sMetadata: \n " , indent ) ;
2011-05-22 12:46:29 +02:00
while ( ( tag = av_dict_get ( m , " " , tag , AV_DICT_IGNORE_SUFFIX ) ) ) {
2011-06-19 20:32:37 +02:00
if ( strcmp ( " language " , tag - > key ) ) {
2012-02-10 02:39:14 +01:00
const char * p = tag - > value ;
av_log ( ctx , AV_LOG_INFO , " %s %-16s: " , indent , tag - > key ) ;
while ( * p ) {
char tmp [ 256 ] ;
size_t len = strcspn ( p , " \ xd \ xa " ) ;
av_strlcpy ( tmp , p , FFMIN ( sizeof ( tmp ) , len + 1 ) ) ;
av_log ( ctx , AV_LOG_INFO , " %s " , tmp ) ;
p + = len ;
if ( * p = = 0xd ) av_log ( ctx , AV_LOG_INFO , " " ) ;
if ( * p = = 0xa ) av_log ( ctx , AV_LOG_INFO , " \n %s %-16s: " , indent , " " ) ;
if ( * p ) p + + ;
}
av_log ( ctx , AV_LOG_INFO , " \n " ) ;
2011-06-19 20:32:37 +02:00
}
2009-12-14 00:19:24 +01:00
}
}
}
2001-07-22 16:18:56 +02:00
/* "user interface" functions */
2007-10-22 01:10:15 +02:00
static void dump_stream_format ( AVFormatContext * ic , int i , int index , int is_output )
2007-10-20 10:17:01 +02:00
{
2007-10-22 01:10:15 +02:00
char buf [ 256 ] ;
2007-10-20 10:17:01 +02:00
int flags = ( is_output ? ic - > oformat - > flags : ic - > iformat - > flags ) ;
AVStream * st = ic - > streams [ i ] ;
2009-01-17 12:13:33 +01:00
int g = av_gcd ( st - > time_base . num , st - > time_base . den ) ;
2011-05-22 12:46:29 +02:00
AVDictionaryEntry * lang = av_dict_get ( st - > metadata , " language " , NULL , 0 ) ;
2007-10-20 10:17:01 +02:00
avcodec_string ( buf , sizeof ( buf ) , st - > codec , is_output ) ;
2011-09-23 10:16:36 +02:00
av_log ( NULL , AV_LOG_INFO , " Stream #%d:%d " , index , i ) ;
2007-10-20 10:17:01 +02:00
/* 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 ) ;
2009-03-01 16:38:06 +01:00
if ( lang )
av_log ( NULL , AV_LOG_INFO , " (%s) " , lang - > value ) ;
2010-02-23 16:07:18 +01:00
av_log ( NULL , AV_LOG_DEBUG , " , %d, %d/%d " , st - > codec_info_nb_frames , st - > time_base . num / g , st - > time_base . den / g ) ;
2007-10-20 10:17:01 +02:00
av_log ( NULL , AV_LOG_INFO , " : %s " , buf ) ;
2009-01-22 20:45:53 +01:00
if ( st - > sample_aspect_ratio . num & & // default
av_cmp_q ( st - > sample_aspect_ratio , st - > codec - > sample_aspect_ratio ) ) {
AVRational display_aspect_ratio ;
av_reduce ( & display_aspect_ratio . num , & display_aspect_ratio . den ,
st - > codec - > width * st - > sample_aspect_ratio . num ,
st - > codec - > height * st - > sample_aspect_ratio . den ,
1024 * 1024 ) ;
2011-07-27 10:35:08 +02:00
av_log ( NULL , AV_LOG_INFO , " , SAR %d:%d DAR %d:%d " ,
2009-01-22 20:45:53 +01:00
st - > sample_aspect_ratio . num , st - > sample_aspect_ratio . den ,
display_aspect_ratio . num , display_aspect_ratio . den ) ;
}
2010-03-31 01:30:55 +02:00
if ( st - > codec - > codec_type = = AVMEDIA_TYPE_VIDEO ) {
2009-12-13 16:52:11 +01:00
if ( st - > avg_frame_rate . den & & st - > avg_frame_rate . num )
print_fps ( av_q2d ( st - > avg_frame_rate ) , " fps " ) ;
2007-10-20 10:17:01 +02:00
if ( st - > r_frame_rate . den & & st - > r_frame_rate . num )
2009-02-22 00:00:07 +01:00
print_fps ( av_q2d ( st - > r_frame_rate ) , " tbr " ) ;
2009-02-21 22:30:44 +01:00
if ( st - > time_base . den & & st - > time_base . num )
2009-02-22 00:00:07 +01:00
print_fps ( 1 / av_q2d ( st - > time_base ) , " tbn " ) ;
2009-02-21 22:30:44 +01:00
if ( st - > codec - > time_base . den & & st - > codec - > time_base . num )
2009-02-22 00:00:07 +01:00
print_fps ( 1 / av_q2d ( st - > codec - > time_base ) , " tbc " ) ;
2007-10-20 10:17:01 +02:00
}
2011-02-12 19:11:11 +01:00
if ( st - > disposition & AV_DISPOSITION_DEFAULT )
av_log ( NULL , AV_LOG_INFO , " (default) " ) ;
if ( st - > disposition & AV_DISPOSITION_DUB )
av_log ( NULL , AV_LOG_INFO , " (dub) " ) ;
if ( st - > disposition & AV_DISPOSITION_ORIGINAL )
av_log ( NULL , AV_LOG_INFO , " (original) " ) ;
if ( st - > disposition & AV_DISPOSITION_COMMENT )
av_log ( NULL , AV_LOG_INFO , " (comment) " ) ;
if ( st - > disposition & AV_DISPOSITION_LYRICS )
av_log ( NULL , AV_LOG_INFO , " (lyrics) " ) ;
if ( st - > disposition & AV_DISPOSITION_KARAOKE )
av_log ( NULL , AV_LOG_INFO , " (karaoke) " ) ;
if ( st - > disposition & AV_DISPOSITION_FORCED )
av_log ( NULL , AV_LOG_INFO , " (forced) " ) ;
if ( st - > disposition & AV_DISPOSITION_HEARING_IMPAIRED )
av_log ( NULL , AV_LOG_INFO , " (hearing impaired) " ) ;
if ( st - > disposition & AV_DISPOSITION_VISUAL_IMPAIRED )
av_log ( NULL , AV_LOG_INFO , " (visual impaired) " ) ;
2011-02-14 19:43:38 +01:00
if ( st - > disposition & AV_DISPOSITION_CLEAN_EFFECTS )
av_log ( NULL , AV_LOG_INFO , " (clean effects) " ) ;
2007-10-20 10:17:01 +02:00
av_log ( NULL , AV_LOG_INFO , " \n " ) ;
2009-12-14 00:27:43 +01:00
dump_metadata ( NULL , st - > metadata , " " ) ;
2007-10-20 10:17:01 +02:00
}
2001-07-22 16:18:56 +02:00
2011-02-16 09:52:35 +01:00
void av_dump_format ( AVFormatContext * ic ,
int index ,
const char * url ,
int is_output )
2001-07-22 16:18:56 +02:00
{
2007-10-25 12:11:15 +02:00
int i ;
2011-09-30 19:30:35 +02:00
uint8_t * printed = ic - > nb_streams ? av_mallocz ( ic - > nb_streams ) : NULL ;
2009-10-19 04:12:10 +02:00
if ( ic - > nb_streams & & ! printed )
return ;
2001-07-22 16:18:56 +02:00
2005-12-17 19:14:38 +01:00
av_log ( NULL , AV_LOG_INFO , " %s #%d, %s, %s '%s': \n " ,
2001-07-22 16:18:56 +02:00
is_output ? " Output " : " Input " ,
2005-12-17 19:14:38 +01:00
index ,
is_output ? ic - > oformat - > name : ic - > iformat - > name ,
2001-07-22 16:18:56 +02:00
is_output ? " to " : " from " , url ) ;
2009-12-14 00:34:46 +01:00
dump_metadata ( NULL , ic - > metadata , " " ) ;
2003-08-08 20:02:23 +02:00
if ( ! is_output ) {
2005-05-29 13:44:21 +02:00
av_log ( NULL , AV_LOG_INFO , " Duration: " ) ;
2003-08-08 20:02:23 +02: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 08:46:54 +02:00
av_log ( NULL , AV_LOG_INFO , " %02d:%02d:%02d.%02d " , hours , mins , secs ,
( 100 * us ) / AV_TIME_BASE ) ;
2003-08-08 20:02:23 +02:00
} else {
2005-05-29 13:44:21 +02:00
av_log ( NULL , AV_LOG_INFO , " N/A " ) ;
2003-08-08 20:02:23 +02:00
}
2004-10-11 19:12:52 +02:00
if ( ic - > start_time ! = AV_NOPTS_VALUE ) {
int secs , us ;
2005-05-29 13:44:21 +02:00
av_log ( NULL , AV_LOG_INFO , " , start: " ) ;
2004-10-11 19:12:52 +02:00
secs = ic - > start_time / AV_TIME_BASE ;
2010-09-07 23:06:21 +02:00
us = abs ( ic - > start_time % AV_TIME_BASE ) ;
2005-05-29 13:44:21 +02:00
av_log ( NULL , AV_LOG_INFO , " %d.%06d " ,
2004-10-11 19:12:52 +02:00
secs , ( int ) av_rescale ( us , 1000000 , AV_TIME_BASE ) ) ;
}
2005-05-29 13:44:21 +02:00
av_log ( NULL , AV_LOG_INFO , " , bitrate: " ) ;
2003-08-08 20:02:23 +02:00
if ( ic - > bit_rate ) {
2005-05-29 13:44:21 +02:00
av_log ( NULL , AV_LOG_INFO , " %d kb/s " , ic - > bit_rate / 1000 ) ;
2003-08-08 20:02:23 +02:00
} else {
2005-05-29 13:44:21 +02:00
av_log ( NULL , AV_LOG_INFO , " N/A " ) ;
2003-08-08 20:02:23 +02:00
}
2005-05-29 13:44:21 +02:00
av_log ( NULL , AV_LOG_INFO , " \n " ) ;
2003-08-08 20:02:23 +02:00
}
2010-02-28 19:37:09 +01:00
for ( i = 0 ; i < ic - > nb_chapters ; i + + ) {
AVChapter * ch = ic - > chapters [ i ] ;
av_log ( NULL , AV_LOG_INFO , " Chapter #%d.%d: " , index , i ) ;
av_log ( NULL , AV_LOG_INFO , " start %f, " , ch - > start * av_q2d ( ch - > time_base ) ) ;
av_log ( NULL , AV_LOG_INFO , " end %f \n " , ch - > end * av_q2d ( ch - > time_base ) ) ;
dump_metadata ( NULL , ch - > metadata , " " ) ;
}
2007-10-20 10:25:13 +02:00
if ( ic - > nb_programs ) {
2009-10-19 04:12:10 +02:00
int j , k , total = 0 ;
2007-10-20 10:25:13 +02:00
for ( j = 0 ; j < ic - > nb_programs ; j + + ) {
2011-05-22 12:46:29 +02:00
AVDictionaryEntry * name = av_dict_get ( ic - > programs [ j ] - > metadata ,
2009-03-01 16:38:06 +01:00
" name " , NULL , 0 ) ;
2007-10-26 22:02:11 +02:00
av_log ( NULL , AV_LOG_INFO , " Program %d %s \n " , ic - > programs [ j ] - > id ,
2009-03-01 16:38:06 +01:00
name ? name - > value : " " ) ;
2009-12-14 00:27:43 +01:00
dump_metadata ( NULL , ic - > programs [ j ] - > metadata , " " ) ;
2009-10-19 04:12:10 +02:00
for ( k = 0 ; k < ic - > programs [ j ] - > nb_stream_indexes ; k + + ) {
2007-10-22 01:10:15 +02:00
dump_stream_format ( ic , ic - > programs [ j ] - > stream_index [ k ] , index , is_output ) ;
2009-10-19 04:12:10 +02:00
printed [ ic - > programs [ j ] - > stream_index [ k ] ] = 1 ;
}
total + = ic - > programs [ j ] - > nb_stream_indexes ;
}
if ( total < ic - > nb_streams )
av_log ( NULL , AV_LOG_INFO , " No Program \n " ) ;
}
2009-10-19 04:20:08 +02:00
for ( i = 0 ; i < ic - > nb_streams ; i + + )
if ( ! printed [ i ] )
2009-10-18 22:25:48 +02:00
dump_stream_format ( ic , i , index , is_output ) ;
2009-10-19 04:12:10 +02:00
av_free ( printed ) ;
2001-07-22 16:18:56 +02:00
}
2012-06-20 02:24:39 +02:00
# if FF_API_AV_GETTIME && CONFIG_SHARED && HAVE_SYMVER
FF_SYMVER ( int64_t , av_gettime , ( void ) , " LIBAVFORMAT_54 " )
2007-07-16 22:28:43 +02:00
{
2012-06-20 02:24:39 +02:00
return av_gettime ( ) ;
2007-07-16 22:28:43 +02:00
}
2012-06-20 02:24:39 +02:00
# endif
2007-07-16 22:28:43 +02:00
2010-03-10 23:21:39 +01:00
uint64_t ff_ntp_time ( void )
{
return ( av_gettime ( ) / 1000 ) * 1000 + NTP_OFFSET_US ;
}
2006-09-04 11:57:47 +02:00
int av_get_frame_filename ( char * buf , int buf_size ,
const char * path , int number )
2001-09-16 23:50:48 +02:00
{
const char * p ;
2003-10-26 11:49:49 +01:00
char * q , buf1 [ 20 ] , c ;
int nd , len , percentd_found ;
2001-09-16 23:50:48 +02:00
q = buf ;
p = path ;
percentd_found = 0 ;
for ( ; ; ) {
c = * p + + ;
if ( c = = ' \0 ' )
break ;
if ( c = = ' % ' ) {
2002-12-11 04:20:05 +01:00
do {
nd = 0 ;
while ( isdigit ( * p ) ) {
nd = nd * 10 + * p + + - ' 0 ' ;
}
c = * p + + ;
} while ( isdigit ( c ) ) ;
2001-09-16 23:50:48 +02: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 15:17:26 +01:00
static void hex_dump_internal ( void * avcl , FILE * f , int level , uint8_t * buf , int size )
2002-05-20 18:28:47 +02:00
{
int len , i , j , c ;
2009-11-11 22:57:50 +01:00
# undef fprintf
2007-03-12 15:17:26 +01:00
# define PRINT(...) do { if (!f) av_log(avcl, level, __VA_ARGS__); else fprintf(f, __VA_ARGS__); } while(0)
2002-05-20 18:28:47 +02:00
for ( i = 0 ; i < size ; i + = 16 ) {
len = size - i ;
if ( len > 16 )
len = 16 ;
2007-03-12 15:17:26 +01:00
PRINT ( " %08x " , i ) ;
2002-05-20 18:28:47 +02:00
for ( j = 0 ; j < 16 ; j + + ) {
if ( j < len )
2007-03-12 15:17:26 +01:00
PRINT ( " %02x " , buf [ i + j ] ) ;
2002-05-20 18:28:47 +02:00
else
2007-03-12 15:17:26 +01:00
PRINT ( " " ) ;
2002-05-20 18:28:47 +02:00
}
2007-03-12 15:17:26 +01:00
PRINT ( " " ) ;
2002-05-20 18:28:47 +02:00
for ( j = 0 ; j < len ; j + + ) {
c = buf [ i + j ] ;
if ( c < ' ' | | c > ' ~ ' )
c = ' . ' ;
2007-03-12 15:17:26 +01:00
PRINT ( " %c " , c ) ;
2002-05-20 18:28:47 +02:00
}
2007-03-12 15:17:26 +01:00
PRINT ( " \n " ) ;
2002-05-20 18:28:47 +02:00
}
2007-03-12 15:17:26 +01: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 18:28:47 +02:00
}
2011-02-24 09:08:06 +01:00
static void pkt_dump_internal ( void * avcl , FILE * f , int level , AVPacket * pkt , int dump_payload , AVRational time_base )
2003-11-10 19:37:55 +01:00
{
2009-11-11 22:57:50 +01:00
# undef fprintf
2007-03-12 15:17:26 +01: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 ) ;
2010-03-31 14:29:58 +02:00
PRINT ( " keyframe=%d \n " , ( ( pkt - > flags & AV_PKT_FLAG_KEY ) ! = 0 ) ) ;
2011-02-24 09:08:06 +01:00
PRINT ( " duration=%0.3f \n " , pkt - > duration * av_q2d ( time_base ) ) ;
2003-12-15 15:45:37 +01:00
/* DTS is _always_ valid after av_read_frame() */
2007-03-12 15:17:26 +01:00
PRINT ( " dts= " ) ;
2003-12-15 15:45:37 +01:00
if ( pkt - > dts = = AV_NOPTS_VALUE )
2007-03-12 15:17:26 +01:00
PRINT ( " N/A " ) ;
2003-12-15 15:45:37 +01:00
else
2011-02-24 09:08:06 +01:00
PRINT ( " %0.3f " , pkt - > dts * av_q2d ( time_base ) ) ;
2008-01-16 23:14:26 +01:00
/* PTS may not be known if B-frames are present. */
2007-03-12 15:17:26 +01:00
PRINT ( " pts= " ) ;
2003-11-10 19:37:55 +01:00
if ( pkt - > pts = = AV_NOPTS_VALUE )
2007-03-12 15:17:26 +01:00
PRINT ( " N/A " ) ;
2003-11-10 19:37:55 +01:00
else
2011-02-24 09:08:06 +01:00
PRINT ( " %0.3f " , pkt - > pts * av_q2d ( time_base ) ) ;
2007-03-12 15:17:26 +01:00
PRINT ( " \n " ) ;
PRINT ( " size=%d \n " , pkt - > size ) ;
# undef PRINT
2003-11-10 19:37:55 +01:00
if ( dump_payload )
av_hex_dump ( f , pkt - > data , pkt - > size ) ;
}
2011-04-05 12:59:27 +02:00
# if FF_API_PKT_DUMP
2007-03-12 15:17:26 +01:00
void av_pkt_dump ( FILE * f , AVPacket * pkt , int dump_payload )
{
2011-02-24 09:08:06 +01:00
AVRational tb = { 1 , AV_TIME_BASE } ;
pkt_dump_internal ( NULL , f , 0 , pkt , dump_payload , tb ) ;
}
2011-04-05 12:59:27 +02:00
# endif
2011-02-24 09:08:06 +01:00
void av_pkt_dump2 ( FILE * f , AVPacket * pkt , int dump_payload , AVStream * st )
{
pkt_dump_internal ( NULL , f , 0 , pkt , dump_payload , st - > time_base ) ;
2007-03-12 15:17:26 +01:00
}
2011-04-05 12:59:27 +02:00
# if FF_API_PKT_DUMP
2007-03-12 15:17:26 +01:00
void av_pkt_dump_log ( void * avcl , int level , AVPacket * pkt , int dump_payload )
{
2011-02-24 09:08:06 +01:00
AVRational tb = { 1 , AV_TIME_BASE } ;
pkt_dump_internal ( avcl , NULL , level , pkt , dump_payload , tb ) ;
}
2011-04-05 12:59:27 +02:00
# endif
2011-02-24 09:08:06 +01:00
void av_pkt_dump_log2 ( void * avcl , int level , AVPacket * pkt , int dump_payload ,
AVStream * st )
{
pkt_dump_internal ( avcl , NULL , level , pkt , dump_payload , st - > time_base ) ;
2007-03-12 15:17:26 +01:00
}
2010-06-27 16:16:46 +02:00
void av_url_split ( char * proto , int proto_size ,
char * authorization , int authorization_size ,
char * hostname , int hostname_size ,
int * port_ptr ,
char * path , int path_size ,
const char * url )
2002-07-24 20:04:50 +02:00
{
2007-12-29 17:13:03 +01:00
const char * p , * ls , * at , * col , * brk ;
2007-09-27 21:18:07 +02:00
if ( port_ptr ) * port_ptr = - 1 ;
if ( proto_size > 0 ) proto [ 0 ] = 0 ;
if ( authorization_size > 0 ) authorization [ 0 ] = 0 ;
if ( hostname_size > 0 ) hostname [ 0 ] = 0 ;
if ( path_size > 0 ) path [ 0 ] = 0 ;
/* parse protocol */
if ( ( p = strchr ( url , ' : ' ) ) ) {
av_strlcpy ( proto , url , FFMIN ( proto_size , p + 1 - url ) ) ;
p + + ; /* skip ':' */
if ( * p = = ' / ' ) p + + ;
if ( * p = = ' / ' ) p + + ;
2002-07-24 20:04:50 +02:00
} else {
2007-09-27 21:18:07 +02:00
/* no protocol means plain filename */
av_strlcpy ( path , url , path_size ) ;
return ;
}
2004-08-12 02:09:32 +02:00
2007-09-27 21:18:07 +02:00
/* separate path from hostname */
2007-12-29 17:13:03 +01:00
ls = strchr ( p , ' / ' ) ;
if ( ! ls )
ls = strchr ( p , ' ? ' ) ;
if ( ls )
2007-12-29 17:34:51 +01:00
av_strlcpy ( path , ls , path_size ) ;
2007-12-29 17:13:03 +01:00
else
2007-09-27 21:18:07 +02:00
ls = & p [ strlen ( p ) ] ; // XXX
/* the rest is hostname, use that to parse auth/port */
if ( ls ! = p ) {
/* authorization (user[:pass]@hostname) */
if ( ( at = strchr ( p , ' @ ' ) ) & & at < ls ) {
av_strlcpy ( authorization , p ,
FFMIN ( authorization_size , at + 1 - p ) ) ;
p = at + 1 ; /* skip '@' */
2002-07-24 20:04:50 +02:00
}
2007-09-27 21:18:07 +02:00
2007-09-29 16:35:52 +02: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 20:04:50 +02:00
}
}
2010-03-25 08:13:20 +01:00
char * ff_data_to_hex ( char * buff , const uint8_t * src , int s , int lowercase )
2008-08-28 01:43:28 +02:00
{
int i ;
2010-03-25 08:13:20 +01:00
static const char hex_table_uc [ 16 ] = { ' 0 ' , ' 1 ' , ' 2 ' , ' 3 ' ,
2010-03-25 08:14:41 +01:00
' 4 ' , ' 5 ' , ' 6 ' , ' 7 ' ,
' 8 ' , ' 9 ' , ' A ' , ' B ' ,
' C ' , ' D ' , ' E ' , ' F ' } ;
2010-03-25 08:13:20 +01:00
static const char hex_table_lc [ 16 ] = { ' 0 ' , ' 1 ' , ' 2 ' , ' 3 ' ,
' 4 ' , ' 5 ' , ' 6 ' , ' 7 ' ,
' 8 ' , ' 9 ' , ' a ' , ' b ' ,
' c ' , ' d ' , ' e ' , ' f ' } ;
const char * hex_table = lowercase ? hex_table_lc : hex_table_uc ;
2008-08-28 01:43:28 +02:00
for ( i = 0 ; i < s ; i + + ) {
2008-08-28 14:00:58 +02:00
buff [ i * 2 ] = hex_table [ src [ i ] > > 4 ] ;
buff [ i * 2 + 1 ] = hex_table [ src [ i ] & 0xF ] ;
2008-08-28 01:43:28 +02:00
}
return buff ;
}
2010-08-09 12:05:33 +02:00
int ff_hex_to_data ( uint8_t * data , const char * p )
{
int c , len , v ;
len = 0 ;
v = 1 ;
for ( ; ; ) {
p + = strspn ( p , SPACE_CHARS ) ;
if ( * p = = ' \0 ' )
break ;
c = toupper ( ( unsigned char ) * p + + ) ;
if ( c > = ' 0 ' & & c < = ' 9 ' )
c = c - ' 0 ' ;
else if ( c > = ' A ' & & c < = ' F ' )
c = c - ' A ' + 10 ;
else
break ;
v = ( v < < 4 ) | c ;
if ( v & 0x100 ) {
if ( data )
data [ len ] = v ;
len + + ;
v = 1 ;
}
}
return len ;
}
2011-11-29 19:28:15 +01:00
# if FF_API_SET_PTS_INFO
2004-05-21 22:43:21 +02:00
void av_set_pts_info ( AVStream * s , int pts_wrap_bits ,
2009-07-01 20:50:31 +02:00
unsigned int pts_num , unsigned int pts_den )
2011-11-29 19:28:15 +01:00
{
avpriv_set_pts_info ( s , pts_wrap_bits , pts_num , pts_den ) ;
}
# endif
void avpriv_set_pts_info ( AVStream * s , int pts_wrap_bits ,
unsigned int pts_num , unsigned int pts_den )
2002-10-21 17:54:49 +02:00
{
2011-02-06 15:27:30 +01:00
AVRational new_tb ;
if ( av_reduce ( & new_tb . num , & new_tb . den , pts_num , pts_den , INT_MAX ) ) {
if ( new_tb . num ! = pts_num )
av_log ( NULL , AV_LOG_DEBUG , " st:%d removing common factor %d from timebase \n " , s - > index , pts_num / new_tb . num ) ;
2009-07-01 22:52:48 +02:00
} else
av_log ( NULL , AV_LOG_WARNING , " st:%d has too large timebase, reducing \n " , s - > index ) ;
2009-07-02 14:47:58 +02:00
2011-02-06 15:27:30 +01:00
if ( new_tb . num < = 0 | | new_tb . den < = 0 ) {
2012-05-23 16:46:39 +02:00
av_log ( NULL , AV_LOG_ERROR , " Ignoring attempt to set invalid timebase %d/%d for st:%d \n " , new_tb . num , new_tb . den , s - > index ) ;
2011-02-06 15:27:30 +01:00
return ;
}
s - > time_base = new_tb ;
s - > pts_wrap_bits = pts_wrap_bits ;
2002-10-21 17:54:49 +02:00
}
2010-03-05 23:31:45 +01:00
int ff_url_join ( char * str , int size , const char * proto ,
const char * authorization , const char * hostname ,
int port , const char * fmt , . . . )
{
# if CONFIG_NETWORK
2011-06-06 14:13:02 +02:00
struct addrinfo hints = { 0 } , * ai ;
2010-03-05 23:31:45 +01:00
# endif
str [ 0 ] = ' \0 ' ;
if ( proto )
av_strlcatf ( str , size , " %s:// " , proto ) ;
2010-06-19 23:56:50 +02:00
if ( authorization & & authorization [ 0 ] )
2010-03-05 23:31:45 +01:00
av_strlcatf ( str , size , " %s@ " , authorization ) ;
# if CONFIG_NETWORK && defined(AF_INET6)
/* Determine if hostname is a numerical IPv6 address,
* properly escape it within [ ] in that case . */
hints . ai_flags = AI_NUMERICHOST ;
if ( ! getaddrinfo ( hostname , NULL , & hints , & ai ) ) {
if ( ai - > ai_family = = AF_INET6 ) {
av_strlcat ( str , " [ " , size ) ;
av_strlcat ( str , hostname , size ) ;
av_strlcat ( str , " ] " , size ) ;
} else {
av_strlcat ( str , hostname , size ) ;
}
freeaddrinfo ( ai ) ;
} else
# endif
/* Not an IPv6 address, just output the plain string. */
av_strlcat ( str , hostname , size ) ;
if ( port > = 0 )
av_strlcatf ( str , size , " :%d " , port ) ;
if ( fmt ) {
va_list vl ;
int len = strlen ( str ) ;
va_start ( vl , fmt ) ;
vsnprintf ( str + len , size > len ? size - len : 0 , fmt , vl ) ;
va_end ( vl ) ;
}
return strlen ( str ) ;
}
2010-05-21 09:07:57 +02:00
int ff_write_chained ( AVFormatContext * dst , int dst_stream , AVPacket * pkt ,
AVFormatContext * src )
{
AVPacket local_pkt ;
local_pkt = * pkt ;
local_pkt . stream_index = dst_stream ;
if ( pkt - > pts ! = AV_NOPTS_VALUE )
local_pkt . pts = av_rescale_q ( pkt - > pts ,
src - > streams [ pkt - > stream_index ] - > time_base ,
dst - > streams [ dst_stream ] - > time_base ) ;
if ( pkt - > dts ! = AV_NOPTS_VALUE )
local_pkt . dts = av_rescale_q ( pkt - > dts ,
src - > streams [ pkt - > stream_index ] - > time_base ,
dst - > streams [ dst_stream ] - > time_base ) ;
return av_write_frame ( dst , & local_pkt ) ;
}
2010-08-19 16:49:53 +02:00
void ff_parse_key_value ( const char * str , ff_parse_key_val_cb callback_get_buf ,
void * context )
{
const char * ptr = str ;
/* Parse key=value pairs. */
for ( ; ; ) {
const char * key ;
char * dest = NULL , * dest_end ;
int key_len , dest_len = 0 ;
/* Skip whitespace and potential commas. */
while ( * ptr & & ( isspace ( * ptr ) | | * ptr = = ' , ' ) )
ptr + + ;
if ( ! * ptr )
break ;
key = ptr ;
if ( ! ( ptr = strchr ( key , ' = ' ) ) )
break ;
ptr + + ;
key_len = ptr - key ;
callback_get_buf ( context , key , key_len , & dest , & dest_len ) ;
dest_end = dest + dest_len - 1 ;
if ( * ptr = = ' \" ' ) {
ptr + + ;
while ( * ptr & & * ptr ! = ' \" ' ) {
if ( * ptr = = ' \\ ' ) {
if ( ! ptr [ 1 ] )
break ;
if ( dest & & dest < dest_end )
* dest + + = ptr [ 1 ] ;
ptr + = 2 ;
} else {
if ( dest & & dest < dest_end )
* dest + + = * ptr ;
ptr + + ;
}
}
if ( * ptr = = ' \" ' )
ptr + + ;
} else {
for ( ; * ptr & & ! ( isspace ( * ptr ) | | * ptr = = ' , ' ) ; ptr + + )
if ( dest & & dest < dest_end )
* dest + + = * ptr ;
}
if ( dest )
* dest = 0 ;
}
}
2010-12-26 02:24:51 +01:00
int ff_find_stream_index ( AVFormatContext * s , int id )
{
int i ;
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
if ( s - > streams [ i ] - > id = = id )
return i ;
}
return - 1 ;
}
2011-03-17 11:24:23 +01:00
void ff_make_absolute_url ( char * buf , int size , const char * base ,
const char * rel )
{
char * sep ;
/* Absolute path, relative to the current server */
if ( base & & strstr ( base , " :// " ) & & rel [ 0 ] = = ' / ' ) {
if ( base ! = buf )
av_strlcpy ( buf , base , size ) ;
sep = strstr ( buf , " :// " ) ;
if ( sep ) {
sep + = 3 ;
sep = strchr ( sep , ' / ' ) ;
if ( sep )
* sep = ' \0 ' ;
}
av_strlcat ( buf , rel , size ) ;
return ;
}
/* If rel actually is an absolute url, just copy it */
if ( ! base | | strstr ( rel , " :// " ) | | rel [ 0 ] = = ' / ' ) {
av_strlcpy ( buf , rel , size ) ;
return ;
}
if ( base ! = buf )
av_strlcpy ( buf , base , size ) ;
/* Remove the file name from the base url */
sep = strrchr ( buf , ' / ' ) ;
if ( sep )
sep [ 1 ] = ' \0 ' ;
else
buf [ 0 ] = ' \0 ' ;
while ( av_strstart ( rel , " ../ " , NULL ) & & sep ) {
/* Remove the path delimiter at the end */
sep [ 0 ] = ' \0 ' ;
sep = strrchr ( buf , ' / ' ) ;
/* If the next directory name to pop off is "..", break here */
if ( ! strcmp ( sep ? & sep [ 1 ] : buf , " .. " ) ) {
/* Readd the slash we just removed */
av_strlcat ( buf , " / " , size ) ;
break ;
}
/* Cut off the directory name */
if ( sep )
sep [ 1 ] = ' \0 ' ;
else
buf [ 0 ] = ' \0 ' ;
rel + = 3 ;
}
av_strlcat ( buf , rel , size ) ;
}
2011-07-13 11:45:17 +02:00
int64_t ff_iso8601_to_unix_time ( const char * datestr )
{
2011-07-13 09:30:06 +02:00
# if HAVE_STRPTIME
2011-11-07 23:12:09 +01:00
struct tm time1 = { 0 } , time2 = { 0 } ;
char * ret1 , * ret2 ;
ret1 = strptime ( datestr , " %Y - %m - %d %T " , & time1 ) ;
ret2 = strptime ( datestr , " %Y - %m - %dT%T " , & time2 ) ;
if ( ret2 & & ! ret1 )
return av_timegm ( & time2 ) ;
else
return av_timegm ( & time1 ) ;
2011-07-13 09:30:06 +02:00
# else
av_log ( NULL , AV_LOG_WARNING , " strptime() unavailable on this system, cannot convert "
" the date string. \n " ) ;
return 0 ;
# endif
2011-07-13 11:45:17 +02:00
}
2011-08-11 20:34:45 +02:00
int avformat_query_codec ( AVOutputFormat * ofmt , enum CodecID codec_id , int std_compliance )
{
if ( ofmt ) {
if ( ofmt - > query_codec )
return ofmt - > query_codec ( codec_id , std_compliance ) ;
else if ( ofmt - > codec_tag )
return ! ! av_codec_get_tag ( ofmt - > codec_tag , codec_id ) ;
else if ( codec_id = = ofmt - > video_codec | | codec_id = = ofmt - > audio_codec | |
codec_id = = ofmt - > subtitle_codec )
2011-08-23 03:47:24 +02:00
return 1 ;
2011-08-11 20:34:45 +02:00
}
return AVERROR_PATCHWELCOME ;
}
2011-11-01 12:40:04 +01:00
int avformat_network_init ( void )
{
# if CONFIG_NETWORK
int ret ;
2011-11-07 22:07:39 +01:00
ff_network_inited_globally = 1 ;
2011-11-01 12:40:04 +01:00
if ( ( ret = ff_network_init ( ) ) < 0 )
return ret ;
ff_tls_init ( ) ;
# endif
return 0 ;
}
int avformat_network_deinit ( void )
{
# if CONFIG_NETWORK
ff_network_close ( ) ;
ff_tls_deinit ( ) ;
# endif
return 0 ;
}
2011-12-16 11:48:09 +01:00
int ff_add_param_change ( AVPacket * pkt , int32_t channels ,
uint64_t channel_layout , int32_t sample_rate ,
int32_t width , int32_t height )
{
uint32_t flags = 0 ;
int size = 4 ;
uint8_t * data ;
if ( ! pkt )
return AVERROR ( EINVAL ) ;
if ( channels ) {
size + = 4 ;
flags | = AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT ;
}
if ( channel_layout ) {
size + = 8 ;
flags | = AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT ;
}
if ( sample_rate ) {
size + = 4 ;
flags | = AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE ;
}
if ( width | | height ) {
size + = 8 ;
flags | = AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS ;
}
data = av_packet_new_side_data ( pkt , AV_PKT_DATA_PARAM_CHANGE , size ) ;
if ( ! data )
return AVERROR ( ENOMEM ) ;
bytestream_put_le32 ( & data , flags ) ;
if ( channels )
bytestream_put_le32 ( & data , channels ) ;
if ( channel_layout )
bytestream_put_le64 ( & data , channel_layout ) ;
if ( sample_rate )
bytestream_put_le32 ( & data , sample_rate ) ;
if ( width | | height ) {
bytestream_put_le32 ( & data , width ) ;
bytestream_put_le32 ( & data , height ) ;
}
return 0 ;
}
2012-01-27 13:33:09 +01:00
const struct AVCodecTag * avformat_get_riff_video_tags ( void )
{
return ff_codec_bmp_tags ;
}
const struct AVCodecTag * avformat_get_riff_audio_tags ( void )
{
return ff_codec_wav_tags ;
}
2012-05-07 20:27:08 +02:00
AVRational av_guess_sample_aspect_ratio ( AVFormatContext * format , AVStream * stream , AVFrame * frame )
{
AVRational undef = { 0 , 1 } ;
AVRational stream_sample_aspect_ratio = stream ? stream - > sample_aspect_ratio : undef ;
2012-05-20 15:53:02 +02:00
AVRational codec_sample_aspect_ratio = stream & & stream - > codec ? stream - > codec - > sample_aspect_ratio : undef ;
AVRational frame_sample_aspect_ratio = frame ? frame - > sample_aspect_ratio : codec_sample_aspect_ratio ;
2012-05-07 20:27:08 +02:00
av_reduce ( & stream_sample_aspect_ratio . num , & stream_sample_aspect_ratio . den ,
stream_sample_aspect_ratio . num , stream_sample_aspect_ratio . den , INT_MAX ) ;
if ( stream_sample_aspect_ratio . num < = 0 | | stream_sample_aspect_ratio . den < = 0 )
stream_sample_aspect_ratio = undef ;
av_reduce ( & frame_sample_aspect_ratio . num , & frame_sample_aspect_ratio . den ,
frame_sample_aspect_ratio . num , frame_sample_aspect_ratio . den , INT_MAX ) ;
if ( frame_sample_aspect_ratio . num < = 0 | | frame_sample_aspect_ratio . den < = 0 )
frame_sample_aspect_ratio = undef ;
if ( stream_sample_aspect_ratio . num )
return stream_sample_aspect_ratio ;
else
return frame_sample_aspect_ratio ;
}