2001-07-22 14:37:44 +00:00
/*
2003-06-07 18:34:02 +00:00
* Copyright (c) 2000-2003 Fabrice Bellard
2001-07-22 14:37:44 +00:00
*
2006-10-07 15:30:46 +00:00
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
2002-05-25 22:25:13 +00:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
2006-10-07 15:30:46 +00:00
* version 2.1 of the License, or (at your option) any later version.
2001-07-22 14:37:44 +00:00
*
2006-10-07 15:30:46 +00:00
* FFmpeg is distributed in the hope that it will be useful,
2001-07-22 14:37:44 +00:00
* but WITHOUT ANY WARRANTY; without even the implied warranty of
2002-05-25 22:25:13 +00:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
2001-07-22 14:37:44 +00:00
*
2002-05-25 22:25:13 +00:00
* You should have received a copy of the GNU Lesser General Public
2006-10-07 15:30:46 +00:00
* License along with FFmpeg; if not, write to the Free Software
2006-01-12 22:43:26 +00:00
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2001-07-22 14:37:44 +00:00
*/
2007-06-10 14:34:56 +00:00
2011-12-22 10:23:22 +01:00
/**
* @file
* multimedia converter based on the FFmpeg libraries
*/
2007-07-02 07:43:23 +00:00
#include "config.h"
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <errno.h>
2004-05-12 16:51:39 +00:00
#include <limits.h>
2012-06-22 22:34:02 +02:00
#if HAVE_ISATTY
2012-09-11 15:54:09 -04:00
#if HAVE_IO_H
#include <io.h>
#endif
#if HAVE_UNISTD_H
2008-08-14 22:01:59 +00:00
#include <unistd.h>
2012-06-22 22:34:02 +02:00
#endif
2012-09-11 15:54:09 -04:00
#endif
2008-05-09 11:56:36 +00:00
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
2012-05-19 12:05:02 +02:00
#include "libswresample/swresample.h"
2011-02-03 14:58:59 +01:00
#include "libavutil/opt.h"
2012-11-10 10:00:00 -05:00
#include "libavutil/channel_layout.h"
2011-02-07 14:37:08 +01:00
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
2010-07-01 18:49:44 +00:00
#include "libavutil/colorspace.h"
2008-05-09 11:56:36 +00:00
#include "libavutil/fifo.h"
2010-10-31 22:48:44 +00:00
#include "libavutil/intreadwrite.h"
2011-05-22 12:46:29 +02:00
#include "libavutil/dict.h"
2011-06-04 12:58:23 +01:00
#include "libavutil/mathematics.h"
2010-01-30 19:10:26 +00:00
#include "libavutil/pixdesc.h"
2008-05-09 11:56:36 +00:00
#include "libavutil/avstring.h"
2010-03-09 15:10:23 +00:00
#include "libavutil/libm.h"
2011-12-26 03:35:54 +01:00
#include "libavutil/imgutils.h"
2012-01-20 17:06:26 +01:00
#include "libavutil/timestamp.h"
2012-05-17 19:31:35 +02:00
#include "libavutil/bprint.h"
2012-06-21 20:31:44 +01:00
#include "libavutil/time.h"
2008-05-09 11:56:36 +00:00
#include "libavformat/os_support.h"
2001-08-15 22:29:44 +00:00
2011-04-09 03:09:49 +02:00
#include "libavformat/ffm.h" // not public API
2011-05-01 14:47:05 +02:00
# include "libavfilter/avcodec.h"
2010-05-07 09:43:21 +00:00
# include "libavfilter/avfilter.h"
# include "libavfilter/avfiltergraph.h"
2011-12-26 03:35:54 +01:00
# include "libavfilter/buffersrc.h"
2012-05-19 12:05:02 +02:00
# include "libavfilter/buffersink.h"
2010-05-07 09:43:21 +00:00
2009-01-13 23:44:16 +00:00
#if HAVE_SYS_RESOURCE_H
2012-10-14 00:27:26 +01:00
#include <sys/time.h>
2008-05-11 11:17:23 +00:00
#include <sys/types.h>
2008-05-08 00:44:42 +00:00
#include <sys/resource.h>
2009-01-13 23:44:16 +00:00
#elif HAVE_GETPROCESSTIMES
2007-07-13 16:11:36 +00:00
#include <windows.h>
#endif
2010-02-22 22:21:58 +00:00
#if HAVE_GETPROCESSMEMORYINFO
#include <windows.h>
#include <psapi.h>
#endif
2007-07-13 16:11:36 +00:00
2009-01-13 23:44:16 +00:00
#if HAVE_SYS_SELECT_H
2008-09-26 02:13:38 +00:00
#include <sys/select.h>
#endif
2011-03-30 20:58:13 +02:00
#if HAVE_TERMIOS_H
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#elif HAVE_KBHIT
2007-07-11 14:07:55 +00:00
#include <conio.h>
2001-08-13 21:43:02 +00:00
#endif
2012-06-10 21:34:15 +02:00
2012-06-02 07:26:41 +02:00
#if HAVE_PTHREADS
#include <pthread.h>
#endif
2002-05-25 22:25:13 +00:00
#include <time.h>
2001-07-22 14:37:44 +00:00
2012-08-09 00:26:38 +02:00
#include "ffmpeg.h"
2003-06-07 18:34:02 +00:00
#include "cmdutils.h"
2010-10-01 13:55:13 +00:00
#include "libavutil/avassert.h"
2004-09-22 17:50:53 +00:00
2011-04-23 15:19:17 +02:00
const char program_name [] = "ffmpeg" ;
2008-05-29 08:48:51 +00:00
const int program_birth_year = 2000 ;
2007-09-27 06:38:40 +00:00
2007-09-06 20:11:02 +00:00
static FILE * vstats_file ;
2002-10-10 17:09:01 +00:00
2012-12-09 18:40:22 +01:00
const char * const forced_keyframes_const_names [] = {
"n" ,
"n_forced" ,
"prev_forced_n" ,
"prev_forced_t" ,
"t" ,
NULL
};
2012-10-30 13:45:44 +01:00
static void do_video_stats ( OutputStream * ost , int frame_size );
2012-08-09 00:26:38 +02:00
static int64_t getutime ( void );
2013-03-02 16:04:49 +01:00
static int64_t getmaxrss ( void );
2003-01-22 22:40:52 +00:00
2011-04-22 18:49:44 +02:00
static int run_as_daemon = 0 ;
2004-04-15 13:57:55 +00:00
static int64_t video_size = 0 ;
static int64_t audio_size = 0 ;
2012-06-17 19:50:36 +02:00
static int64_t subtitle_size = 0 ;
2004-04-15 13:57:55 +00:00
static int64_t extra_size = 0 ;
2004-06-11 22:03:16 +00:00
static int nb_frames_dup = 0 ;
static int nb_frames_drop = 0 ;
2003-08-29 20:51:10 +00:00
2012-04-11 19:26:09 +02:00
static int current_time ;
2012-08-09 00:26:38 +02:00
AVIOContext * progress_avio = NULL ;
2005-09-11 11:10:25 +00:00
2012-06-22 22:15:24 +02:00
static uint8_t * subtitle_out ;
2012-06-11 15:34:12 +02:00
#if HAVE_PTHREADS
2012-06-02 07:26:41 +02:00
/* signal to input threads that they should exit; set by the main thread */
static int transcoding_finished ;
#endif
2008-12-26 19:25:24 +00:00
#define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass"
2001-07-22 14:37:44 +00:00
2012-08-01 18:23:12 +02:00
InputStream ** input_streams = NULL ;
int nb_input_streams = 0 ;
InputFile ** input_files = NULL ;
int nb_input_files = 0 ;
2012-03-29 08:51:17 +02:00
2012-08-01 18:23:12 +02:00
OutputStream ** output_streams = NULL ;
int nb_output_streams = 0 ;
OutputFile ** output_files = NULL ;
int nb_output_files = 0 ;
2001-07-22 14:37:44 +00:00
2012-08-01 18:23:12 +02:00
FilterGraph ** filtergraphs ;
int nb_filtergraphs ;
2001-07-22 14:37:44 +00:00
2011-03-30 20:58:13 +02:00
#if HAVE_TERMIOS_H
/* init terminal so that we can grab keys */
static struct termios oldtty ;
2012-01-17 00:10:17 +01:00
static int restore_tty ;
2011-03-30 20:58:13 +02:00
#endif
2012-04-11 19:26:09 +02:00
2012-07-26 19:29:27 +02:00
/* sub2video hack:
Convert subtitles to video with alpha to insert them in filter graphs.
This is a temporary solution until libavfilter gets real subtitles support.
*/
2013-03-10 11:51:02 +01:00
static int sub2video_get_blank_frame ( InputStream * ist )
{
int ret ;
AVFrame * frame = ist -> sub2video . frame ;
2012-07-26 19:29:27 +02:00
2013-03-10 11:51:02 +01:00
av_frame_unref ( frame );
ist -> sub2video . frame -> width = ist -> sub2video . w ;
ist -> sub2video . frame -> height = ist -> sub2video . h ;
ist -> sub2video . frame -> format = AV_PIX_FMT_RGB32 ;
if (( ret = av_frame_get_buffer ( frame , 32 )) < 0 )
return ret ;
memset ( frame -> data [ 0 ], 0 , frame -> height * frame -> linesize [ 0 ]);
return 0 ;
}
2012-07-26 19:29:27 +02:00
static void sub2video_copy_rect ( uint8_t * dst , int dst_linesize , int w , int h ,
AVSubtitleRect * r )
{
uint32_t * pal , * dst2 ;
uint8_t * src , * src2 ;
int x , y ;
if ( r -> type != SUBTITLE_BITMAP ) {
av_log ( NULL , AV_LOG_WARNING , "sub2video: non-bitmap subtitle \n " );
return ;
}
if ( r -> x < 0 || r -> x + r -> w > w || r -> y < 0 || r -> y + r -> h > h ) {
av_log ( NULL , AV_LOG_WARNING , "sub2video: rectangle overflowing \n " );
return ;
}
dst += r -> y * dst_linesize + r -> x * 4 ;
src = r -> pict . data [ 0 ];
pal = ( uint32_t * ) r -> pict . data [ 1 ];
for ( y = 0 ; y < r -> h ; y ++ ) {
dst2 = ( uint32_t * ) dst ;
src2 = src ;
for ( x = 0 ; x < r -> w ; x ++ )
* ( dst2 ++ ) = pal [ * ( src2 ++ )];
dst += dst_linesize ;
src += r -> pict . linesize [ 0 ];
}
}
static void sub2video_push_ref ( InputStream * ist , int64_t pts )
{
2013-03-10 11:51:02 +01:00
AVFrame * frame = ist -> sub2video . frame ;
2012-07-26 19:29:27 +02:00
int i ;
2013-03-10 11:51:02 +01:00
av_assert1 ( frame -> data [ 0 ]);
ist -> sub2video . last_pts = frame -> pts = pts ;
2012-07-26 19:29:27 +02:00
for ( i = 0 ; i < ist -> nb_filters ; i ++ )
2013-03-10 14:07:29 +01:00
av_buffersrc_add_frame_flags ( ist -> filters [ i ] -> filter , frame ,
AV_BUFFERSRC_FLAG_KEEP_REF |
AV_BUFFERSRC_FLAG_PUSH );
2012-07-26 19:29:27 +02:00
}
2012-09-09 16:37:45 +02:00
static void sub2video_update ( InputStream * ist , AVSubtitle * sub )
2012-07-26 19:29:27 +02:00
{
int w = ist -> sub2video . w , h = ist -> sub2video . h ;
2013-03-10 11:51:02 +01:00
AVFrame * frame = ist -> sub2video . frame ;
2012-07-26 19:29:27 +02:00
int8_t * dst ;
int dst_linesize ;
2012-11-29 20:25:37 +01:00
int num_rects , i ;
int64_t pts , end_pts ;
2012-07-26 19:29:27 +02:00
2013-03-10 11:51:02 +01:00
if ( ! frame )
2012-07-26 19:29:27 +02:00
return ;
2012-11-29 20:25:37 +01:00
if ( sub ) {
pts = av_rescale_q ( sub -> pts + sub -> start_display_time * 1000 ,
AV_TIME_BASE_Q , ist -> st -> time_base );
end_pts = av_rescale_q ( sub -> pts + sub -> end_display_time * 1000 ,
AV_TIME_BASE_Q , ist -> st -> time_base );
num_rects = sub -> num_rects ;
} else {
pts = ist -> sub2video . end_pts ;
end_pts = INT64_MAX ;
num_rects = 0 ;
}
2013-03-10 11:51:02 +01:00
if ( sub2video_get_blank_frame ( ist ) < 0 ) {
av_log ( ist -> st -> codec , AV_LOG_ERROR ,
"Impossible to get a blank canvas. \n " );
return ;
}
dst = frame -> data [ 0 ];
dst_linesize = frame -> linesize [ 0 ];
2012-11-29 20:25:37 +01:00
for ( i = 0 ; i < num_rects ; i ++ )
2012-07-26 19:29:27 +02:00
sub2video_copy_rect ( dst , dst_linesize , w , h , sub -> rects [ i ]);
sub2video_push_ref ( ist , pts );
2012-11-29 20:25:37 +01:00
ist -> sub2video . end_pts = end_pts ;
2012-07-26 19:29:27 +02:00
}
static void sub2video_heartbeat ( InputStream * ist , int64_t pts )
{
InputFile * infile = input_files [ ist -> file_index ];
int i , j , nb_reqs ;
int64_t pts2 ;
/* When a frame is read from a file, examine all sub2video streams in
the same file and send the sub2video frame again. Otherwise, decoded
video frames could be accumulating in the filter graph while a filter
(possibly overlay) is desperately waiting for a subtitle frame. */
for ( i = 0 ; i < infile -> nb_streams ; i ++ ) {
InputStream * ist2 = input_streams [ infile -> ist_index + i ];
2013-03-10 11:51:02 +01:00
if ( ! ist2 -> sub2video . frame )
2012-07-26 19:29:27 +02:00
continue ;
/* subtitles seem to be usually muxed ahead of other streams;
if not, substracting a larger time here is necessary */
pts2 = av_rescale_q ( pts , ist -> st -> time_base , ist2 -> st -> time_base ) - 1 ;
/* do not send the heartbeat frame if the subtitle is already ahead */
if ( pts2 <= ist2 -> sub2video . last_pts )
continue ;
2013-03-10 11:51:02 +01:00
if ( pts2 >= ist2 -> sub2video . end_pts || ! ist2 -> sub2video . frame -> data [ 0 ])
2012-11-29 20:25:37 +01:00
sub2video_update ( ist2 , NULL );
2012-07-26 19:29:27 +02:00
for ( j = 0 , nb_reqs = 0 ; j < ist2 -> nb_filters ; j ++ )
nb_reqs += av_buffersrc_get_nb_failed_requests ( ist2 -> filters [ j ] -> filter );
if ( nb_reqs )
sub2video_push_ref ( ist2 , pts2 );
}
}
static void sub2video_flush ( InputStream * ist )
{
int i ;
for ( i = 0 ; i < ist -> nb_filters ; i ++ )
av_buffersrc_add_ref ( ist -> filters [ i ] -> filter , NULL , 0 );
}
/* end of sub2video hack */
2012-08-09 00:26:38 +02:00
void term_exit ( void )
2001-07-22 14:37:44 +00:00
{
2011-06-15 11:24:00 +02:00
av_log ( NULL , AV_LOG_QUIET , "%s" , "" );
2011-03-30 20:58:13 +02:00
#if HAVE_TERMIOS_H
2012-01-17 00:10:17 +01:00
if ( restore_tty )
2011-04-18 13:10:52 +02:00
tcsetattr ( 0 , TCSANOW , & oldtty );
2011-03-30 20:58:13 +02:00
#endif
2010-03-20 01:02:45 +00:00
}
2001-07-22 14:37:44 +00:00
2009-07-27 13:01:44 +00:00
static volatile int received_sigterm = 0 ;
2012-08-09 04:12:50 +02:00
static volatile int received_nb_signals = 0 ;
2003-04-10 18:21:06 +00:00
2012-08-09 04:12:50 +02:00
static void
sigterm_handler ( int sig )
2003-04-10 18:21:06 +00:00
{
received_sigterm = sig ;
2011-10-08 17:21:25 +02:00
received_nb_signals ++ ;
2003-04-10 18:21:06 +00:00
term_exit ();
2011-12-16 19:37:32 +01:00
if ( received_nb_signals > 3 )
exit ( 123 );
2003-04-10 18:21:06 +00:00
}
2012-08-09 00:26:38 +02:00
void term_init ( void )
2001-07-22 14:37:44 +00:00
{
2011-03-30 20:58:13 +02:00
#if HAVE_TERMIOS_H
2011-04-22 18:49:44 +02:00
if ( ! run_as_daemon ){
2012-05-04 19:21:31 +02:00
struct termios tty ;
2012-06-06 12:39:07 +02:00
int istty = 1 ;
2012-06-05 19:58:03 +02:00
#if HAVE_ISATTY
2012-06-06 12:39:07 +02:00
istty = isatty ( 0 ) && isatty ( 2 );
2012-06-05 19:58:03 +02:00
#endif
2012-06-06 12:39:07 +02:00
if ( istty && tcgetattr ( 0 , & tty ) == 0 ) {
2012-05-04 19:21:31 +02:00
oldtty = tty ;
restore_tty = 1 ;
atexit ( term_exit );
2011-03-30 20:58:13 +02:00
2012-05-04 19:21:31 +02:00
tty . c_iflag &= ~ ( IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON );
tty . c_oflag |= OPOST ;
tty . c_lflag &= ~ ( ECHO | ECHONL | ICANON | IEXTEN );
tty . c_cflag &= ~ ( CSIZE | PARENB );
tty . c_cflag |= CS8 ;
tty . c_cc [ VMIN ] = 1 ;
tty . c_cc [ VTIME ] = 0 ;
2011-03-30 20:58:13 +02:00
2012-05-04 19:21:31 +02:00
tcsetattr ( 0 , TCSANOW , & tty );
}
signal ( SIGQUIT , sigterm_handler ); /* Quit (POSIX). */
2011-04-18 13:10:52 +02:00
}
2011-03-30 20:58:13 +02:00
#endif
2011-11-07 02:41:01 +01:00
avformat_network_deinit ();
2011-03-30 20:58:13 +02:00
2011-12-30 03:46:24 +01:00
signal ( SIGINT , sigterm_handler ); /* Interrupt (ANSI). */
2003-04-10 18:21:06 +00:00
signal ( SIGTERM , sigterm_handler ); /* Termination (ANSI). */
2010-01-20 06:42:39 +00:00
#ifdef SIGXCPU
signal ( SIGXCPU , sigterm_handler );
#endif
2001-07-22 14:37:44 +00:00
}
/* read a key without blocking */
static int read_key ( void )
{
2011-09-04 00:24:06 +02:00
unsigned char ch ;
2011-03-30 20:58:13 +02:00
#if HAVE_TERMIOS_H
int n = 1 ;
struct timeval tv ;
fd_set rfds ;
FD_ZERO ( & rfds );
FD_SET ( 0 , & rfds );
tv . tv_sec = 0 ;
tv . tv_usec = 0 ;
n = select ( 1 , & rfds , NULL , NULL , & tv );
if ( n > 0 ) {
n = read ( 0 , & ch , 1 );
if ( n == 1 )
return ch ;
return n ;
}
#elif HAVE_KBHIT
2011-09-04 00:24:06 +02:00
# if HAVE_PEEKNAMEDPIPE
static int is_pipe ;
static HANDLE input_handle ;
DWORD dw , nchars ;
if ( ! input_handle ){
input_handle = GetStdHandle ( STD_INPUT_HANDLE );
is_pipe = ! GetConsoleMode ( input_handle , & dw );
}
if ( stdin -> _cnt > 0 ) {
read ( 0 , & ch , 1 );
return ch ;
}
if ( is_pipe ) {
/* When running under a GUI, you will end here. */
2012-12-26 12:21:15 -07:00
if ( ! PeekNamedPipe ( input_handle , NULL , 0 , NULL , & nchars , NULL )) {
// input pipe may have been closed by the program that ran ffmpeg
2011-09-04 00:24:06 +02:00
return - 1 ;
2012-12-26 12:21:15 -07:00
}
2011-09-04 00:24:06 +02:00
//Read it
if ( nchars != 0 ) {
read ( 0 , & ch , 1 );
return ch ;
} else {
return - 1 ;
}
}
# endif
2007-07-11 14:07:55 +00:00
if ( kbhit ())
return ( getch ());
2006-11-22 12:15:58 +00:00
#endif
2001-07-22 14:37:44 +00:00
return - 1 ;
}
2011-11-19 01:55:55 +01:00
static int decode_interrupt_cb ( void * ctx )
2004-03-14 19:40:43 +00:00
{
2011-10-08 17:21:25 +02:00
return received_nb_signals > 1 ;
2004-03-14 19:40:43 +00:00
}
2012-08-01 18:23:12 +02:00
const AVIOInterruptCB int_cb = { decode_interrupt_cb , NULL };
2011-11-19 01:55:55 +01:00
2012-10-02 21:55:17 +02:00
static void exit_program ( void )
2008-04-14 22:31:49 +00:00
{
2012-03-29 08:51:17 +02:00
int i , j ;
2013-03-02 16:04:49 +01:00
if ( do_benchmark ) {
int maxrss = getmaxrss () / 1024 ;
printf ( "bench: maxrss=%ikB \n " , maxrss );
}
2012-03-29 08:51:17 +02:00
for ( i = 0 ; i < nb_filtergraphs ; i ++ ) {
avfilter_graph_free ( & filtergraphs [ i ] -> graph );
2012-05-26 13:31:54 +02:00
for ( j = 0 ; j < filtergraphs [ i ] -> nb_inputs ; j ++ ) {
av_freep ( & filtergraphs [ i ] -> inputs [ j ] -> name );
2012-03-29 08:51:17 +02:00
av_freep ( & filtergraphs [ i ] -> inputs [ j ]);
2012-05-26 13:31:54 +02:00
}
2012-03-29 08:51:17 +02:00
av_freep ( & filtergraphs [ i ] -> inputs );
2012-05-26 13:31:54 +02:00
for ( j = 0 ; j < filtergraphs [ i ] -> nb_outputs ; j ++ ) {
av_freep ( & filtergraphs [ i ] -> outputs [ j ] -> name );
2012-03-29 08:51:17 +02:00
av_freep ( & filtergraphs [ i ] -> outputs [ j ]);
2012-05-26 13:31:54 +02:00
}
2012-03-29 08:51:17 +02:00
av_freep ( & filtergraphs [ i ] -> outputs );
av_freep ( & filtergraphs [ i ]);
}
av_freep ( & filtergraphs );
2008-04-14 22:31:49 +00:00
2012-06-22 22:15:24 +02:00
av_freep ( & subtitle_out );
2008-04-14 22:31:49 +00:00
/* close files */
2011-12-30 03:46:24 +01:00
for ( i = 0 ; i < nb_output_files ; i ++ ) {
2012-04-15 15:28:30 +02:00
AVFormatContext * s = output_files [ i ] -> ctx ;
2008-04-21 01:22:25 +00:00
if ( ! ( s -> oformat -> flags & AVFMT_NOFILE ) && s -> pb )
2011-02-21 22:45:20 +01:00
avio_close ( s -> pb );
2011-02-04 12:04:18 +02:00
avformat_free_context ( s );
2012-04-15 15:28:30 +02:00
av_dict_free ( & output_files [ i ] -> opts );
av_freep ( & output_files [ i ]);
2008-04-14 22:31:49 +00:00
}
2012-01-02 02:48:34 +01:00
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
AVBitStreamFilterContext * bsfc = output_streams [ i ] -> bitstream_filters ;
2012-01-02 02:48:34 +01:00
while ( bsfc ) {
AVBitStreamFilterContext * next = bsfc -> next ;
av_bitstream_filter_close ( bsfc );
bsfc = next ;
}
2012-04-15 15:28:30 +02:00
output_streams [ i ] -> bitstream_filters = NULL ;
2012-09-21 09:10:23 +02:00
avcodec_free_frame ( & output_streams [ i ] -> filtered_frame );
2008-04-14 22:31:49 +00:00
2012-06-22 14:36:27 +02:00
av_freep ( & output_streams [ i ] -> forced_keyframes );
2012-12-09 18:40:22 +01:00
av_expr_free ( output_streams [ i ] -> forced_keyframes_pexpr );
2012-06-01 12:31:13 +02:00
av_freep ( & output_streams [ i ] -> avfilter );
2012-08-19 09:15:48 +02:00
av_freep ( & output_streams [ i ] -> logfile_prefix );
2012-04-15 15:28:30 +02:00
av_freep ( & output_streams [ i ]);
2010-10-01 21:36:13 +00:00
}
2011-12-30 03:46:24 +01:00
for ( i = 0 ; i < nb_input_files ; i ++ ) {
2012-04-15 15:28:30 +02:00
avformat_close_input ( & input_files [ i ] -> ctx );
av_freep ( & input_files [ i ]);
2010-10-01 21:36:13 +00:00
}
2011-12-06 01:37:27 +01:00
for ( i = 0 ; i < nb_input_streams ; i ++ ) {
2013-01-21 21:10:18 +01:00
av_frame_free ( & input_streams [ i ] -> decoded_frame );
av_frame_free ( & input_streams [ i ] -> filter_frame );
2012-04-15 15:28:30 +02:00
av_dict_free ( & input_streams [ i ] -> opts );
2013-02-06 15:00:38 +01:00
avsubtitle_free ( & input_streams [ i ] -> prev_sub . subtitle );
2013-03-20 11:12:20 +01:00
av_frame_free ( & input_streams [ i ] -> sub2video . frame );
2012-03-29 08:51:17 +02:00
av_freep ( & input_streams [ i ] -> filters );
2012-04-15 15:28:30 +02:00
av_freep ( & input_streams [ i ]);
2011-12-06 01:37:27 +01:00
}
2008-04-14 22:31:49 +00:00
if ( vstats_file )
fclose ( vstats_file );
av_free ( vstats_filename );
2011-05-22 22:12:35 +02:00
av_freep ( & input_streams );
av_freep ( & input_files );
2011-08-30 15:03:53 +02:00
av_freep ( & output_streams );
2011-08-30 14:19:39 +02:00
av_freep ( & output_files );
2011-05-22 22:12:35 +02:00
2010-10-02 08:44:33 +00:00
uninit_opts ();
2009-04-13 03:47:12 +00:00
2010-05-07 09:43:21 +00:00
avfilter_uninit ();
2011-11-06 02:47:48 +02:00
avformat_network_deinit ();
2010-05-07 09:43:21 +00:00
2008-04-14 22:31:49 +00:00
if ( received_sigterm ) {
2011-09-27 02:14:37 +02:00
av_log ( NULL , AV_LOG_INFO , "Received signal %d: terminating. \n " ,
( int ) received_sigterm );
2008-04-14 22:31:49 +00:00
}
2010-10-01 21:29:37 +00:00
}
2012-08-01 18:23:12 +02:00
void assert_avoptions ( AVDictionary * m )
2011-06-09 10:58:23 +02:00
{
AVDictionaryEntry * t ;
if (( t = av_dict_get ( m , "" , NULL , AV_DICT_IGNORE_SUFFIX ))) {
2011-09-27 02:14:37 +02:00
av_log ( NULL , AV_LOG_FATAL , "Option %s not found. \n " , t -> key );
2012-09-05 07:03:56 +00:00
exit ( 1 );
2011-06-09 10:58:23 +02:00
}
}
2012-10-18 22:58:25 -06:00
static void abort_codec_experimental ( AVCodec * c , int encoder )
2011-07-12 17:18:42 +02:00
{
2012-10-18 22:58:25 -06:00
exit ( 1 );
2011-07-12 17:18:42 +02:00
}
2012-08-09 00:26:38 +02:00
static void update_benchmark ( const char * fmt , ...)
2010-03-30 19:37:07 +00:00
{
2012-08-09 00:26:38 +02:00
if ( do_benchmark_all ) {
int64_t t = getutime ();
va_list va ;
char buf [ 1024 ];
2011-07-27 20:56:59 +02:00
2012-08-09 00:26:38 +02:00
if ( fmt ) {
va_start ( va , fmt );
vsnprintf ( buf , sizeof ( buf ), fmt , va );
va_end ( va );
printf ( "bench: %8" PRIu64 " %s \n " , t - current_time , buf );
2011-01-14 15:50:55 +01:00
}
2012-08-09 00:26:38 +02:00
current_time = t ;
2010-03-30 19:37:07 +00:00
}
}
2012-01-02 02:48:34 +01:00
static void write_frame ( AVFormatContext * s , AVPacket * pkt , OutputStream * ost )
2011-09-12 11:44:14 +02:00
{
2012-01-02 02:48:34 +01:00
AVBitStreamFilterContext * bsfc = ost -> bitstream_filters ;
AVCodecContext * avctx = ost -> st -> codec ;
2007-11-01 01:59:22 +00:00
int ret ;
2012-03-22 20:17:42 +01:00
if (( avctx -> codec_type == AVMEDIA_TYPE_VIDEO && video_sync_method == VSYNC_DROP ) ||
( avctx -> codec_type == AVMEDIA_TYPE_AUDIO && audio_sync_method < 0 ))
pkt -> pts = pkt -> dts = AV_NOPTS_VALUE ;
2012-08-19 02:42:53 +02:00
if (( avctx -> codec_type == AVMEDIA_TYPE_AUDIO || avctx -> codec_type == AVMEDIA_TYPE_VIDEO ) && pkt -> dts != AV_NOPTS_VALUE ) {
2012-05-17 04:07:16 +02:00
int64_t max = ost -> st -> cur_dts + ! ( s -> oformat -> flags & AVFMT_TS_NONSTRICT );
if ( ost -> st -> cur_dts && ost -> st -> cur_dts != AV_NOPTS_VALUE && max > pkt -> dts ) {
2012-08-19 02:42:53 +02:00
av_log ( s , max - pkt -> dts > 2 || avctx -> codec_type == AVMEDIA_TYPE_VIDEO ? AV_LOG_WARNING : AV_LOG_DEBUG ,
2012-08-19 08:58:49 -06:00
"st:%d PTS: %" PRId64 " DTS: %" PRId64 " < %" PRId64 " invalid, clipping \n " , pkt -> stream_index , pkt -> pts , pkt -> dts , max );
2012-08-19 02:42:53 +02:00
if ( pkt -> pts >= pkt -> dts )
pkt -> pts = FFMAX ( pkt -> pts , max );
pkt -> dts = max ;
2012-05-17 04:07:16 +02:00
}
}
2012-01-18 02:07:42 +01:00
/*
* Audio encoders may split the packets -- #frames in != #packets out.
* But there is no reordering, so we can limit the number of output packets
* by simply dropping them here.
* Counting encoded video frames needs to be done separately because of
* reordering, see do_video_out()
*/
if ( ! ( avctx -> codec_type == AVMEDIA_TYPE_VIDEO && avctx -> codec )) {
2012-03-20 15:36:28 -04:00
if ( ost -> frame_number >= ost -> max_frames ) {
av_free_packet ( pkt );
2012-01-18 02:07:42 +01:00
return ;
2012-03-20 15:36:28 -04:00
}
2012-01-18 02:07:42 +01:00
ost -> frame_number ++ ;
}
2011-12-30 03:46:24 +01:00
while ( bsfc ) {
AVPacket new_pkt = * pkt ;
int a = av_bitstream_filter_filter ( bsfc , avctx , NULL ,
& new_pkt . data , & new_pkt . size ,
pkt -> data , pkt -> size ,
pkt -> flags & AV_PKT_FLAG_KEY );
2012-08-10 04:33:42 +02:00
if ( a == 0 && new_pkt . data != pkt -> data && new_pkt . destruct ) {
uint8_t * t = av_malloc ( new_pkt . size + FF_INPUT_BUFFER_PADDING_SIZE ); //the new should be a subset of the old so cannot overflow
if ( t ) {
memcpy ( t , new_pkt . data , new_pkt . size );
memset ( t + new_pkt . size , 0 , FF_INPUT_BUFFER_PADDING_SIZE );
new_pkt . data = t ;
2013-03-08 17:28:42 +01:00
new_pkt . buf = NULL ;
2012-08-10 04:33:42 +02:00
a = 1 ;
} else
a = AVERROR ( ENOMEM );
}
2011-12-30 03:46:24 +01:00
if ( a > 0 ) {
2006-07-06 15:04:46 +00:00
av_free_packet ( pkt );
2013-01-21 21:10:18 +01:00
new_pkt . buf = av_buffer_create ( new_pkt . data , new_pkt . size ,
av_buffer_default_free , NULL , 0 );
if ( ! new_pkt . buf )
exit ( 1 );
2011-12-30 03:46:24 +01:00
} else if ( a < 0 ) {
2012-01-12 23:56:58 +01:00
av_log ( NULL , AV_LOG_ERROR , "Failed to open bitstream filter %s for stream %d with codec %s" ,
2011-09-27 02:14:37 +02:00
bsfc -> filter -> name , pkt -> stream_index ,
avctx -> codec ? avctx -> codec -> name : "copy" );
2008-01-21 13:36:20 +00:00
print_error ( "" , a );
2008-09-04 23:23:44 +00:00
if ( exit_on_error )
2012-09-05 07:03:56 +00:00
exit ( 1 );
2006-07-06 15:04:46 +00:00
}
2011-12-30 03:46:24 +01:00
* pkt = new_pkt ;
2006-07-06 15:04:46 +00:00
2011-12-30 03:46:24 +01:00
bsfc = bsfc -> next ;
2006-07-06 15:04:46 +00:00
}
2012-02-01 10:23:28 +01:00
pkt -> stream_index = ost -> index ;
2012-09-26 21:56:01 +02:00
if ( debug_ts ) {
av_log ( NULL , AV_LOG_INFO , "muxer <- type:%s "
2012-10-02 02:14:02 +02:00
"pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s size:%d \n " ,
2012-09-26 21:56:01 +02:00
av_get_media_type_string ( ost -> st -> codec -> codec_type ),
av_ts2str ( pkt -> pts ), av_ts2timestr ( pkt -> pts , & ost -> st -> time_base ),
2012-10-02 02:14:02 +02:00
av_ts2str ( pkt -> dts ), av_ts2timestr ( pkt -> dts , & ost -> st -> time_base ),
pkt -> size
2012-09-26 21:56:01 +02:00
);
}
2011-12-30 03:46:24 +01:00
ret = av_interleaved_write_frame ( s , pkt );
if ( ret < 0 ) {
2007-11-01 01:59:22 +00:00
print_error ( "av_interleaved_write_frame()" , ret );
2012-09-05 07:03:56 +00:00
exit ( 1 );
2007-11-01 01:59:22 +00:00
}
2006-07-06 15:04:46 +00:00
}
2012-08-20 10:57:18 +02:00
static void close_output_stream ( OutputStream * ost )
{
OutputFile * of = output_files [ ost -> file_index ];
ost -> finished = 1 ;
if ( of -> shortest ) {
2012-12-19 00:08:37 +01:00
int64_t end = av_rescale_q ( ost -> sync_opts - ost -> first_pts , ost -> st -> codec -> time_base , AV_TIME_BASE_Q );
of -> recording_time = FFMIN ( of -> recording_time , end );
2012-08-20 10:57:18 +02:00
}
}
2012-05-20 10:28:41 +02:00
static int check_recording_time ( OutputStream * ost )
{
OutputFile * of = output_files [ ost -> file_index ];
if ( of -> recording_time != INT64_MAX &&
av_compare_ts ( ost -> sync_opts - ost -> first_pts , ost -> st -> codec -> time_base , of -> recording_time ,
AV_TIME_BASE_Q ) >= 0 ) {
2012-08-20 11:08:34 +02:00
close_output_stream ( ost );
2012-05-20 10:28:41 +02:00
return 0 ;
}
return 1 ;
}
2012-04-17 13:30:00 -04:00
2012-05-05 18:22:46 +02:00
static void do_audio_out ( AVFormatContext * s , OutputStream * ost ,
AVFrame * frame )
2012-01-17 01:40:45 +01:00
{
AVCodecContext * enc = ost -> st -> codec ;
AVPacket pkt ;
2012-05-05 18:22:46 +02:00
int got_packet = 0 ;
2012-01-17 01:40:45 +01:00
av_init_packet ( & pkt );
pkt . data = NULL ;
pkt . size = 0 ;
2012-07-03 20:34:27 +02:00
2012-05-05 18:22:46 +02:00
if ( ! check_recording_time ( ost ))
return ;
2012-07-03 20:34:27 +02:00
2012-05-05 18:22:46 +02:00
if ( frame -> pts == AV_NOPTS_VALUE || audio_sync_method < 0 )
2012-03-01 13:02:49 -05:00
frame -> pts = ost -> sync_opts ;
2012-05-05 18:22:46 +02:00
ost -> sync_opts = frame -> pts + frame -> nb_samples ;
2012-01-17 01:40:45 +01:00
2012-05-05 18:22:46 +02:00
av_assert0 ( pkt . size || ! pkt . data );
2012-04-11 19:26:09 +02:00
update_benchmark ( NULL );
2012-01-17 01:40:45 +01:00
if ( avcodec_encode_audio2 ( enc , & pkt , frame , & got_packet ) < 0 ) {
2012-03-27 02:30:08 +02:00
av_log ( NULL , AV_LOG_FATAL , "Audio encoding failed (avcodec_encode_audio2) \n " );
2012-09-05 07:03:56 +00:00
exit ( 1 );
2012-01-17 01:40:45 +01:00
}
2012-04-11 19:26:09 +02:00
update_benchmark ( "encode_audio %d.%d" , ost -> file_index , ost -> index );
2012-01-17 01:40:45 +01:00
if ( got_packet ) {
if ( pkt . pts != AV_NOPTS_VALUE )
pkt . pts = av_rescale_q ( pkt . pts , enc -> time_base , ost -> st -> time_base );
2012-05-19 12:05:02 +02:00
if ( pkt . dts != AV_NOPTS_VALUE )
2012-02-06 19:08:32 -05:00
pkt . dts = av_rescale_q ( pkt . dts , enc -> time_base , ost -> st -> time_base );
2012-01-17 01:40:45 +01:00
if ( pkt . duration > 0 )
pkt . duration = av_rescale_q ( pkt . duration , enc -> time_base , ost -> st -> time_base );
2012-05-05 18:22:46 +02:00
if ( debug_ts ) {
av_log ( NULL , AV_LOG_INFO , "encoder -> type:audio "
"pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s \n " ,
av_ts2str ( pkt . pts ), av_ts2timestr ( pkt . pts , & ost -> st -> time_base ),
av_ts2str ( pkt . dts ), av_ts2timestr ( pkt . dts , & ost -> st -> time_base ));
}
2012-09-10 20:51:27 +02:00
audio_size += pkt . size ;
2012-01-17 01:40:45 +01:00
write_frame ( s , & pkt , ost );
2012-01-17 20:55:54 +01:00
av_free_packet ( & pkt );
2012-01-17 01:40:45 +01:00
}
2001-07-22 14:37:44 +00:00
}
2005-12-17 18:14:38 +00:00
static void do_subtitle_out ( AVFormatContext * s ,
2011-06-23 19:14:08 +02:00
OutputStream * ost ,
InputStream * ist ,
2012-09-09 16:28:30 +02:00
AVSubtitle * sub )
2005-06-03 14:31:45 +00:00
{
2009-08-26 10:22:27 +00:00
int subtitle_out_max_size = 1024 * 1024 ;
2005-06-03 14:31:45 +00:00
int subtitle_out_size , nb , i ;
AVCodecContext * enc ;
AVPacket pkt ;
2012-09-09 16:28:30 +02:00
int64_t pts ;
2005-06-03 14:31:45 +00:00
2012-09-09 16:28:30 +02:00
if ( sub -> pts == AV_NOPTS_VALUE ) {
2011-09-27 02:14:37 +02:00
av_log ( NULL , AV_LOG_ERROR , "Subtitle packets must have a pts \n " );
2008-09-04 23:23:44 +00:00
if ( exit_on_error )
2012-09-05 07:03:56 +00:00
exit ( 1 );
2005-06-03 14:31:45 +00:00
return ;
}
2005-07-17 22:24:36 +00:00
enc = ost -> st -> codec ;
2005-06-03 14:31:45 +00:00
if ( ! subtitle_out ) {
subtitle_out = av_malloc ( subtitle_out_max_size );
}
/* Note: DVB subtitle need one packet to draw them and one other
packet to clear them */
/* XXX: signal it in the codec context ? */
2012-08-05 11:11:04 +02:00
if ( enc -> codec_id == AV_CODEC_ID_DVB_SUBTITLE )
2005-06-03 14:31:45 +00:00
nb = 2 ;
else
nb = 1 ;
2012-08-01 18:39:46 +02:00
/* shift timestamp to honor -ss and make check_recording_time() work with -t */
2012-09-09 16:28:30 +02:00
pts = sub -> pts - output_files [ ost -> file_index ] -> start_time ;
2011-12-30 03:46:24 +01:00
for ( i = 0 ; i < nb ; i ++ ) {
2012-08-01 18:39:46 +02:00
ost -> sync_opts = av_rescale_q ( pts , AV_TIME_BASE_Q , enc -> time_base );
2012-07-03 20:34:27 +02:00
if ( ! check_recording_time ( ost ))
return ;
2012-02-08 23:14:28 +01:00
2012-08-01 18:39:46 +02:00
sub -> pts = pts ;
2009-08-26 08:43:11 +00:00
// start_display_time is required to be 0
2011-12-30 03:46:24 +01:00
sub -> pts += av_rescale_q ( sub -> start_display_time , ( AVRational ){ 1 , 1000 }, AV_TIME_BASE_Q );
sub -> end_display_time -= sub -> start_display_time ;
2009-08-26 08:43:11 +00:00
sub -> start_display_time = 0 ;
2012-07-25 19:45:16 +02:00
if ( i == 1 )
sub -> num_rects = 0 ;
2005-12-17 18:14:38 +00:00
subtitle_out_size = avcodec_encode_subtitle ( enc , subtitle_out ,
2005-06-03 14:31:45 +00:00
subtitle_out_max_size , sub );
2009-08-15 00:37:31 +00:00
if ( subtitle_out_size < 0 ) {
2011-09-27 02:14:37 +02:00
av_log ( NULL , AV_LOG_FATAL , "Subtitle encoding failed \n " );
2012-09-05 07:03:56 +00:00
exit ( 1 );
2009-08-15 00:37:31 +00:00
}
2005-12-17 18:14:38 +00:00
2005-06-03 14:31:45 +00:00
av_init_packet ( & pkt );
pkt . data = subtitle_out ;
pkt . size = subtitle_out_size ;
2011-12-30 03:46:24 +01:00
pkt . pts = av_rescale_q ( sub -> pts , AV_TIME_BASE_Q , ost -> st -> time_base );
2012-05-30 21:08:01 -07:00
pkt . duration = av_rescale_q ( sub -> end_display_time , ( AVRational ){ 1 , 1000 }, ost -> st -> time_base );
2012-08-05 11:11:04 +02:00
if ( enc -> codec_id == AV_CODEC_ID_DVB_SUBTITLE ) {
2005-06-03 14:31:45 +00:00
/* XXX: the pts correction is handled here. Maybe handling
it in the codec would be better */
if ( i == 0 )
pkt . pts += 90 * sub -> start_display_time ;
else
pkt . pts += 90 * sub -> end_display_time ;
}
2012-06-17 19:50:36 +02:00
subtitle_size += pkt . size ;
2012-09-10 20:51:27 +02:00
write_frame ( s , & pkt , ost );
2005-06-03 14:31:45 +00:00
}
}
2012-05-20 12:24:49 +02:00
static void do_video_out ( AVFormatContext * s ,
OutputStream * ost ,
2012-10-10 13:51:07 +02:00
AVFrame * in_picture )
2001-07-22 14:37:44 +00:00
{
2012-05-20 12:24:49 +02:00
int ret , format_video_sync ;
2012-05-20 12:04:09 +02:00
AVPacket pkt ;
2012-05-20 12:24:49 +02:00
AVCodecContext * enc = ost -> st -> codec ;
2012-07-18 16:35:01 +02:00
int nb_frames , i ;
2012-02-06 21:47:41 +01:00
double sync_ipts , delta ;
2011-09-13 05:13:34 +02:00
double duration = 0 ;
2012-02-07 13:22:20 +01:00
int frame_size = 0 ;
2012-04-17 04:01:17 +02:00
InputStream * ist = NULL ;
if ( ost -> source_index >= 0 )
ist = input_streams [ ost -> source_index ];
2005-12-17 18:14:38 +00:00
2012-05-09 18:15:03 +02:00
if ( ist && ist -> st -> start_time != AV_NOPTS_VALUE && ist -> st -> first_dts != AV_NOPTS_VALUE && ost -> frame_rate . num )
duration = 1 / ( av_q2d ( ost -> frame_rate ) * av_q2d ( enc -> time_base ));
2011-09-13 05:13:34 +02:00
2012-05-20 14:12:48 +02:00
sync_ipts = in_picture -> pts ;
2012-02-27 02:33:48 +01:00
delta = sync_ipts - ost -> sync_opts + duration ;
2010-03-15 02:32:21 +00:00
2002-10-21 17:42:47 +00:00
/* by default, we output a single frame */
nb_frames = 1 ;
2011-08-30 13:42:27 +02:00
format_video_sync = video_sync_method ;
2012-01-05 02:03:12 +01:00
if ( format_video_sync == VSYNC_AUTO )
2012-12-14 23:31:41 +11:00
format_video_sync = ( s -> oformat -> flags & AVFMT_VARIABLE_FPS ) ? (( s -> oformat -> flags & AVFMT_NOTIMESTAMPS ) ? VSYNC_PASSTHROUGH : VSYNC_VFR ) : VSYNC_CFR ;
2011-08-30 13:42:27 +02:00
2012-02-06 21:47:41 +01:00
switch ( format_video_sync ) {
case VSYNC_CFR :
2011-12-30 03:46:24 +01:00
// FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
2012-02-06 21:47:41 +01:00
if ( delta < - 1.1 )
2004-05-29 02:06:32 +00:00
nb_frames = 0 ;
2012-02-06 21:47:41 +01:00
else if ( delta > 1.1 )
nb_frames = lrintf ( delta );
break ;
case VSYNC_VFR :
if ( delta <= - 0.6 )
nb_frames = 0 ;
else if ( delta > 0.6 )
2012-05-11 20:43:41 +02:00
ost -> sync_opts = lrint ( sync_ipts );
2012-02-06 21:47:41 +01:00
break ;
2012-02-27 02:33:48 +01:00
case VSYNC_DROP :
2012-02-06 21:47:41 +01:00
case VSYNC_PASSTHROUGH :
2012-05-11 20:43:41 +02:00
ost -> sync_opts = lrint ( sync_ipts );
2012-02-06 21:47:41 +01:00
break ;
default :
av_assert0 ( 0 );
}
2003-07-12 07:37:05 +00:00
2011-09-05 22:10:26 +02:00
nb_frames = FFMIN ( nb_frames , ost -> max_frames - ost -> frame_number );
2012-02-06 21:47:41 +01:00
if ( nb_frames == 0 ) {
nb_frames_drop ++ ;
av_log ( NULL , AV_LOG_VERBOSE , "*** drop! \n " );
2001-07-22 14:37:44 +00:00
return ;
2012-02-06 21:47:41 +01:00
} else if ( nb_frames > 1 ) {
2012-07-04 03:48:36 +02:00
if ( nb_frames > dts_error_threshold * 30 ) {
2012-09-25 07:42:32 +02:00
av_log ( NULL , AV_LOG_ERROR , "%d frame duplication too large, skipping \n " , nb_frames - 1 );
2012-07-04 03:48:36 +02:00
nb_frames_drop ++ ;
return ;
}
2012-02-06 21:47:41 +01:00
nb_frames_dup += nb_frames - 1 ;
av_log ( NULL , AV_LOG_VERBOSE , "*** %d dup! \n " , nb_frames - 1 );
}
2002-03-19 06:30:41 +00:00
2012-07-18 16:35:01 +02:00
/* duplicates frame if needed */
for ( i = 0 ; i < nb_frames ; i ++ ) {
2012-05-20 12:04:09 +02:00
av_init_packet ( & pkt );
pkt . data = NULL ;
pkt . size = 0 ;
2012-05-20 14:11:48 +02:00
in_picture -> pts = ost -> sync_opts ;
2012-07-03 20:34:27 +02:00
if ( ! check_recording_time ( ost ))
return ;
2012-05-20 12:04:09 +02:00
if ( s -> oformat -> flags & AVFMT_RAWPICTURE &&
2012-08-05 11:11:04 +02:00
enc -> codec -> id == AV_CODEC_ID_RAWVIDEO ) {
2012-05-20 12:04:09 +02:00
/* raw pictures are written as AVPicture structure to
avoid any copies. We support temporarily the older
method. */
enc -> coded_frame -> interlaced_frame = in_picture -> interlaced_frame ;
enc -> coded_frame -> top_field_first = in_picture -> top_field_first ;
2012-11-02 13:09:48 +00:00
if ( enc -> coded_frame -> interlaced_frame )
enc -> field_order = enc -> coded_frame -> top_field_first ? AV_FIELD_TB : AV_FIELD_BT ;
else
enc -> field_order = AV_FIELD_PROGRESSIVE ;
2012-05-20 12:04:09 +02:00
pkt . data = ( uint8_t * ) in_picture ;
pkt . size = sizeof ( AVPicture );
2012-05-20 12:29:33 +02:00
pkt . pts = av_rescale_q ( in_picture -> pts , enc -> time_base , ost -> st -> time_base );
2012-05-20 12:04:09 +02:00
pkt . flags |= AV_PKT_FLAG_KEY ;
2012-06-08 10:24:09 -04:00
video_size += pkt . size ;
2012-09-10 20:51:27 +02:00
write_frame ( s , & pkt , ost );
2012-05-20 12:04:09 +02:00
} else {
2012-12-09 18:40:22 +01:00
int got_packet , forced_keyframe = 0 ;
double pts_time ;
2012-05-20 12:04:09 +02:00
2013-01-21 21:10:18 +01:00
if ( ost -> st -> codec -> flags & ( CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME ) &&
ost -> top_field_first >= 0 )
in_picture -> top_field_first = !! ost -> top_field_first ;
2012-05-20 12:04:09 +02:00
2013-03-12 13:40:42 +01:00
if ( in_picture -> interlaced_frame ) {
2012-11-02 13:09:48 +00:00
if ( enc -> codec -> id == AV_CODEC_ID_MJPEG )
2013-03-12 13:40:42 +01:00
enc -> field_order = in_picture -> top_field_first ? AV_FIELD_TT : AV_FIELD_BB ;
2012-11-02 13:09:48 +00:00
else
2013-03-12 13:40:42 +01:00
enc -> field_order = in_picture -> top_field_first ? AV_FIELD_TB : AV_FIELD_BT ;
2012-11-02 13:09:48 +00:00
} else
enc -> field_order = AV_FIELD_PROGRESSIVE ;
2013-01-21 21:10:18 +01:00
in_picture -> quality = ost -> st -> codec -> global_quality ;
2012-05-20 12:04:09 +02:00
if ( ! enc -> me_threshold )
2013-01-21 21:10:18 +01:00
in_picture -> pict_type = 0 ;
2012-12-09 18:40:22 +01:00
2013-03-12 13:40:42 +01:00
pts_time = in_picture -> pts != AV_NOPTS_VALUE ?
in_picture -> pts * av_q2d ( enc -> time_base ) : NAN ;
2012-05-20 12:04:09 +02:00
if ( ost -> forced_kf_index < ost -> forced_kf_count &&
2013-01-21 21:10:18 +01:00
in_picture -> pts >= ost -> forced_kf_pts [ ost -> forced_kf_index ]) {
2012-05-20 12:04:09 +02:00
ost -> forced_kf_index ++ ;
2012-12-09 18:40:22 +01:00
forced_keyframe = 1 ;
} else if ( ost -> forced_keyframes_pexpr ) {
double res ;
ost -> forced_keyframes_expr_const_values [ FKF_T ] = pts_time ;
res = av_expr_eval ( ost -> forced_keyframes_pexpr ,
ost -> forced_keyframes_expr_const_values , NULL );
av_dlog ( NULL , "force_key_frame: n:%f n_forced:%f prev_forced_n:%f t:%f prev_forced_t:%f -> res:%f \n " ,
ost -> forced_keyframes_expr_const_values [ FKF_N ],
ost -> forced_keyframes_expr_const_values [ FKF_N_FORCED ],
ost -> forced_keyframes_expr_const_values [ FKF_PREV_FORCED_N ],
ost -> forced_keyframes_expr_const_values [ FKF_T ],
ost -> forced_keyframes_expr_const_values [ FKF_PREV_FORCED_T ],
res );
if ( res ) {
forced_keyframe = 1 ;
ost -> forced_keyframes_expr_const_values [ FKF_PREV_FORCED_N ] =
ost -> forced_keyframes_expr_const_values [ FKF_N ];
ost -> forced_keyframes_expr_const_values [ FKF_PREV_FORCED_T ] =
ost -> forced_keyframes_expr_const_values [ FKF_T ];
ost -> forced_keyframes_expr_const_values [ FKF_N_FORCED ] += 1 ;
}
ost -> forced_keyframes_expr_const_values [ FKF_N ] += 1 ;
2012-05-20 12:04:09 +02:00
}
2012-12-09 18:40:22 +01:00
if ( forced_keyframe ) {
2013-03-12 13:40:42 +01:00
in_picture -> pict_type = AV_PICTURE_TYPE_I ;
2012-12-09 18:40:22 +01:00
av_log ( NULL , AV_LOG_DEBUG , "Forced keyframe at time %f \n " , pts_time );
}
2012-05-20 12:04:09 +02:00
update_benchmark ( NULL );
2013-01-21 21:10:18 +01:00
ret = avcodec_encode_video2 ( enc , & pkt , in_picture , & got_packet );
2012-05-20 12:04:09 +02:00
update_benchmark ( "encode_video %d.%d" , ost -> file_index , ost -> index );
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_FATAL , "Video encoding failed \n " );
2012-09-05 07:03:56 +00:00
exit ( 1 );
2012-05-20 12:04:09 +02:00
}
if ( got_packet ) {
if ( pkt . pts == AV_NOPTS_VALUE && ! ( enc -> codec -> capabilities & CODEC_CAP_DELAY ))
pkt . pts = ost -> sync_opts ;
if ( pkt . pts != AV_NOPTS_VALUE )
pkt . pts = av_rescale_q ( pkt . pts , enc -> time_base , ost -> st -> time_base );
if ( pkt . dts != AV_NOPTS_VALUE )
pkt . dts = av_rescale_q ( pkt . dts , enc -> time_base , ost -> st -> time_base );
if ( debug_ts ) {
av_log ( NULL , AV_LOG_INFO , "encoder -> type:video "
"pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s \n " ,
av_ts2str ( pkt . pts ), av_ts2timestr ( pkt . pts , & ost -> st -> time_base ),
av_ts2str ( pkt . dts ), av_ts2timestr ( pkt . dts , & ost -> st -> time_base ));
}
2004-05-29 02:06:32 +00:00
2012-05-20 12:04:09 +02:00
frame_size = pkt . size ;
video_size += pkt . size ;
2012-09-10 20:51:27 +02:00
write_frame ( s , & pkt , ost );
2012-05-20 12:04:09 +02:00
av_free_packet ( & pkt );
2004-04-17 19:41:49 +00:00
2012-05-20 12:04:09 +02:00
/* if two pass, output log */
if ( ost -> logfile && enc -> stats_out ) {
fprintf ( ost -> logfile , "%s" , enc -> stats_out );
2002-10-10 17:09:01 +00:00
}
2001-07-22 14:37:44 +00:00
}
}
2012-05-20 12:04:09 +02:00
ost -> sync_opts ++ ;
/*
* For video, number of frames in == number of packets out.
* But there may be reordering, so we can't throw away frames on encoder
* flush, we need to limit them here, before they go into encoder.
*/
ost -> frame_number ++ ;
2012-02-07 13:22:20 +01:00
if ( vstats_filename && frame_size )
2012-10-30 13:45:44 +01:00
do_video_stats ( ost , frame_size );
2013-03-22 22:47:30 -07:00
}
2001-07-22 14:37:44 +00:00
}
2012-05-20 12:06:56 +02:00
static double psnr ( double d )
{
return - 10.0 * log ( d ) / log ( 10.0 );
}
2012-10-24 19:18:12 +02:00
static void do_video_stats ( OutputStream * ost , int frame_size )
2012-05-20 12:06:56 +02:00
{
AVCodecContext * enc ;
int frame_number ;
double ti1 , bitrate , avg_bitrate ;
/* this is executed just the first time do_video_stats is called */
if ( ! vstats_file ) {
vstats_file = fopen ( vstats_filename , "w" );
if ( ! vstats_file ) {
perror ( "fopen" );
2012-09-05 07:03:56 +00:00
exit ( 1 );
2012-05-20 12:06:56 +02:00
}
}
enc = ost -> st -> codec ;
if ( enc -> codec_type == AVMEDIA_TYPE_VIDEO ) {
2012-12-04 16:25:21 +01:00
frame_number = ost -> st -> nb_frames ;
2012-05-20 12:06:56 +02:00
fprintf ( vstats_file , "frame= %5d q= %2.1f " , frame_number , enc -> coded_frame -> quality / ( float ) FF_QP2LAMBDA );
if ( enc -> flags & CODEC_FLAG_PSNR )
fprintf ( vstats_file , "PSNR= %6.2f " , psnr ( enc -> coded_frame -> error [ 0 ] / ( enc -> width * enc -> height * 255.0 * 255.0 )));
fprintf ( vstats_file , "f_size= %6d " , frame_size );
/* compute pts value */
2012-12-04 16:25:21 +01:00
ti1 = ost -> st -> pts . val * av_q2d ( enc -> time_base );
2012-05-20 12:06:56 +02:00
if ( ti1 < 0.01 )
ti1 = 0.01 ;
bitrate = ( frame_size * 8 ) / av_q2d ( enc -> time_base ) / 1000.0 ;
avg_bitrate = ( double )( video_size * 8 ) / ti1 / 1000.0 ;
fprintf ( vstats_file , "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s " ,
( double ) video_size / 1024 , ti1 , bitrate , avg_bitrate );
fprintf ( vstats_file , "type= %c \n " , av_get_picture_type_char ( enc -> coded_frame -> pict_type ));
}
}
2012-11-21 19:53:08 +11:00
/**
2012-08-17 13:50:16 +02:00
* Get and encode new output from any of the filtergraphs, without causing
* activity.
*
* @return 0 for success, <0 for severe errors
*/
static int reap_filters ( void )
2012-03-29 08:51:17 +02:00
{
AVFrame * filtered_frame = NULL ;
2012-08-17 13:50:16 +02:00
int i ;
2012-05-14 15:10:23 +02:00
int64_t frame_pts ;
2012-03-29 08:51:17 +02:00
2012-08-19 11:23:59 +02:00
/* Reap all buffers present in the buffer sinks */
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
OutputStream * ost = output_streams [ i ];
OutputFile * of = output_files [ ost -> file_index ];
int ret = 0 ;
2012-03-29 08:51:17 +02:00
2012-08-19 11:23:59 +02:00
if ( ! ost -> filter )
continue ;
2012-03-29 08:51:17 +02:00
2012-08-19 11:23:59 +02:00
if ( ! ost -> filtered_frame && ! ( ost -> filtered_frame = avcodec_alloc_frame ())) {
return AVERROR ( ENOMEM );
} else
avcodec_get_frame_defaults ( ost -> filtered_frame );
filtered_frame = ost -> filtered_frame ;
2012-03-29 08:51:17 +02:00
2012-08-19 11:23:59 +02:00
while ( 1 ) {
2013-03-12 13:40:42 +01:00
ret = av_buffersink_get_frame_flags ( ost -> filter -> filter , filtered_frame ,
2012-08-19 11:23:59 +02:00
AV_BUFFERSINK_FLAG_NO_REQUEST );
if ( ret < 0 ) {
if ( ret != AVERROR ( EAGAIN ) && ret != AVERROR_EOF ) {
char buf [ 256 ];
av_strerror ( ret , buf , sizeof ( buf ));
av_log ( NULL , AV_LOG_WARNING ,
"Error in av_buffersink_get_buffer_ref(): %s \n " , buf );
2012-04-19 18:44:55 +02:00
}
2012-08-19 11:23:59 +02:00
break ;
2012-04-17 04:01:17 +02:00
}
2012-08-19 11:23:59 +02:00
frame_pts = AV_NOPTS_VALUE ;
2013-03-12 13:40:42 +01:00
if ( filtered_frame -> pts != AV_NOPTS_VALUE ) {
filtered_frame -> pts = frame_pts = av_rescale_q ( filtered_frame -> pts ,
2012-08-19 11:23:59 +02:00
ost -> filter -> filter -> inputs [ 0 ] -> time_base ,
ost -> st -> codec -> time_base ) -
av_rescale_q ( of -> start_time ,
AV_TIME_BASE_Q ,
ost -> st -> codec -> time_base );
if ( of -> start_time && filtered_frame -> pts < 0 ) {
2013-03-12 13:40:42 +01:00
av_frame_unref ( filtered_frame );
2012-08-19 11:23:59 +02:00
continue ;
}
}
//if (ost->source_index >= 0)
// *filtered_frame= *input_streams[ost->source_index]->decoded_frame; //for me_threshold
switch ( ost -> filter -> filter -> inputs [ 0 ] -> type ) {
case AVMEDIA_TYPE_VIDEO :
filtered_frame -> pts = frame_pts ;
if ( ! ost -> frame_aspect_ratio )
2013-03-12 13:40:42 +01:00
ost -> st -> codec -> sample_aspect_ratio = filtered_frame -> sample_aspect_ratio ;
2012-08-19 11:23:59 +02:00
2012-10-10 13:51:07 +02:00
do_video_out ( of -> ctx , ost , filtered_frame );
2012-08-19 11:23:59 +02:00
break ;
case AVMEDIA_TYPE_AUDIO :
filtered_frame -> pts = frame_pts ;
2013-02-14 23:43:34 +01:00
if ( ! ( ost -> st -> codec -> codec -> capabilities & CODEC_CAP_PARAM_CHANGE ) &&
ost -> st -> codec -> channels != av_frame_get_channels ( filtered_frame )) {
av_log ( NULL , AV_LOG_ERROR ,
"Audio filter graph output is not normalized and encoder does not support parameter changes \n " );
break ;
}
2012-08-19 11:23:59 +02:00
do_audio_out ( of -> ctx , ost , filtered_frame );
break ;
default :
// TODO support subtitle filters
av_assert0 ( 0 );
}
2013-01-21 21:10:18 +01:00
av_frame_unref ( filtered_frame );
2012-03-29 08:51:17 +02:00
}
2012-08-19 11:23:59 +02:00
}
2012-08-17 13:50:16 +02:00
return 0 ;
2012-03-29 08:51:17 +02:00
}
2012-04-17 04:01:17 +02:00
static void print_report ( int is_last_report , int64_t timer_start , int64_t cur_time )
2002-10-21 17:42:47 +00:00
{
char buf [ 1024 ];
2012-07-08 13:03:39 +02:00
AVBPrint buf_script ;
2011-06-23 19:14:08 +02:00
OutputStream * ost ;
2009-04-17 15:15:25 +00:00
AVFormatContext * oc ;
2003-02-11 16:35:48 +00:00
int64_t total_size ;
2002-10-21 17:42:47 +00:00
AVCodecContext * enc ;
int frame_number , vid , i ;
2011-06-03 00:28:52 +02:00
double bitrate ;
2012-08-20 21:06:39 +02:00
int64_t pts = INT64_MIN ;
2003-02-11 16:35:48 +00:00
static int64_t last_time = - 1 ;
2005-12-18 20:01:02 +00:00
static int qp_histogram [ 52 ];
2011-09-27 02:14:37 +02:00
int hours , mins , secs , us ;
2005-12-17 18:14:38 +00:00
2012-07-08 13:03:39 +02:00
if ( ! print_stats && ! is_last_report && ! progress_avio )
2011-10-10 03:41:49 +02:00
return ;
2005-12-17 18:14:38 +00:00
2002-10-21 17:42:47 +00:00
if ( ! is_last_report ) {
if ( last_time == - 1 ) {
last_time = cur_time ;
return ;
2005-12-17 18:14:38 +00:00
}
2002-10-21 17:42:47 +00:00
if (( cur_time - last_time ) < 500000 )
return ;
last_time = cur_time ;
}
2012-04-15 15:28:30 +02:00
oc = output_files [ 0 ] -> ctx ;
2002-10-21 17:42:47 +00:00
2011-03-04 19:57:36 +01:00
total_size = avio_size ( oc -> pb );
2012-10-09 23:22:49 +02:00
if ( total_size <= 0 ) // FIXME improve avio_size() so it works with non seekable output too
2011-12-30 03:46:24 +01:00
total_size = avio_tell ( oc -> pb );
2005-12-17 18:14:38 +00:00
2002-10-21 17:42:47 +00:00
buf [ 0 ] = '\0' ;
vid = 0 ;
2012-07-08 13:03:39 +02:00
av_bprint_init ( & buf_script , 0 , 1 );
2012-04-15 15:03:07 +02:00
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
2011-04-06 21:17:32 +02:00
float q = - 1 ;
2012-04-15 15:28:30 +02:00
ost = output_streams [ i ];
2005-07-17 22:24:36 +00:00
enc = ost -> st -> codec ;
2011-10-26 02:09:31 +02:00
if ( ! ost -> stream_copy && enc -> coded_frame )
2011-12-30 03:46:24 +01:00
q = enc -> coded_frame -> quality / ( float ) FF_QP2LAMBDA ;
2010-03-30 23:30:55 +00:00
if ( vid && enc -> codec_type == AVMEDIA_TYPE_VIDEO ) {
2011-04-06 21:17:32 +02:00
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ), "q=%2.1f " , q );
2012-07-08 13:03:39 +02:00
av_bprintf ( & buf_script , "stream_%d_%d_q=%.1f \n " ,
ost -> file_index , ost -> index , q );
2002-11-20 03:06:12 +00:00
}
2010-03-30 23:30:55 +00:00
if ( ! vid && enc -> codec_type == AVMEDIA_TYPE_VIDEO ) {
2012-03-07 23:26:29 +01:00
float fps , t = ( cur_time - timer_start ) / 1000000.0 ;
2007-03-16 16:13:54 +00:00
2002-10-21 17:42:47 +00:00
frame_number = ost -> frame_number ;
2012-03-07 23:26:29 +01:00
fps = t > 1 ? frame_number / t : 0 ;
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ), "frame=%5d fps=%3.*f q=%3.1f " ,
frame_number , fps < 9.95 , fps , q );
2012-07-08 13:03:39 +02:00
av_bprintf ( & buf_script , "frame=%d \n " , frame_number );
av_bprintf ( & buf_script , "fps=%.1f \n " , fps );
av_bprintf ( & buf_script , "stream_%d_%d_q=%.1f \n " ,
ost -> file_index , ost -> index , q );
2011-12-30 03:46:24 +01:00
if ( is_last_report )
2005-01-12 00:16:25 +00:00
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ), "L" );
2011-12-30 03:46:24 +01:00
if ( qp_hist ) {
2005-12-18 20:01:02 +00:00
int j ;
2011-04-06 21:17:32 +02:00
int qp = lrintf ( q );
2011-12-30 03:46:24 +01:00
if ( qp >= 0 && qp < FF_ARRAY_ELEMS ( qp_histogram ))
2005-12-18 20:01:02 +00:00
qp_histogram [ qp ] ++ ;
2011-12-30 03:46:24 +01:00
for ( j = 0 ; j < 32 ; j ++ )
2012-08-05 22:22:10 +01:00
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ), "%X" , ( int ) lrintf ( log2 ( qp_histogram [ j ] + 1 )));
2005-12-18 20:01:02 +00:00
}
2012-10-25 01:16:34 +02:00
if (( enc -> flags & CODEC_FLAG_PSNR ) && ( enc -> coded_frame || is_last_report )) {
2003-12-29 23:08:30 +00:00
int j ;
2011-12-30 03:46:24 +01:00
double error , error_sum = 0 ;
double scale , scale_sum = 0 ;
2012-07-08 13:03:39 +02:00
double p ;
2011-12-30 03:46:24 +01:00
char type [ 3 ] = { 'Y' , 'U' , 'V' };
2005-01-12 00:16:25 +00:00
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ), "PSNR=" );
2011-12-30 03:46:24 +01:00
for ( j = 0 ; j < 3 ; j ++ ) {
if ( is_last_report ) {
error = enc -> error [ j ];
scale = enc -> width * enc -> height * 255.0 * 255.0 * frame_number ;
} else {
error = enc -> coded_frame -> error [ j ];
scale = enc -> width * enc -> height * 255.0 * 255.0 ;
2003-12-29 23:08:30 +00:00
}
2011-12-30 03:46:24 +01:00
if ( j )
scale /= 4 ;
2003-12-29 23:08:30 +00:00
error_sum += error ;
scale_sum += scale ;
2012-07-08 13:03:39 +02:00
p = psnr ( error / scale );
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ), "%c:%2.2f " , type [ j ], p );
av_bprintf ( & buf_script , "stream_%d_%d_psnr_%c=%2.2f \n " ,
2013-03-01 00:25:03 +01:00
ost -> file_index , ost -> index , type [ j ] | 32 , p );
2003-12-29 23:08:30 +00:00
}
2012-07-08 13:03:39 +02:00
p = psnr ( error_sum / scale_sum );
2011-12-30 03:46:24 +01:00
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ), "*:%2.2f " , psnr ( error_sum / scale_sum ));
2012-07-08 13:03:39 +02:00
av_bprintf ( & buf_script , "stream_%d_%d_psnr_all=%2.2f \n " ,
ost -> file_index , ost -> index , p );
2003-12-29 23:08:30 +00:00
}
2002-10-21 17:42:47 +00:00
vid = 1 ;
}
/* compute min output value */
2012-08-28 23:19:33 +02:00
if (( is_last_report || ! ost -> finished ) && ost -> st -> pts . val != AV_NOPTS_VALUE )
2012-08-20 21:06:39 +02:00
pts = FFMAX ( pts , av_rescale_q ( ost -> st -> pts . val ,
ost -> st -> time_base , AV_TIME_BASE_Q ));
2002-10-21 17:42:47 +00:00
}
2005-12-17 18:14:38 +00:00
2011-09-27 02:14:37 +02:00
secs = pts / AV_TIME_BASE ;
us = pts % AV_TIME_BASE ;
mins = secs / 60 ;
secs %= 60 ;
hours = mins / 60 ;
mins %= 60 ;
2011-06-03 00:29:36 +02:00
2012-12-23 00:19:11 +01:00
bitrate = pts && total_size >= 0 ? total_size * 8 / ( pts / 1000.0 ) : - 1 ;
2005-12-17 18:14:38 +00:00
2012-12-23 00:19:11 +01:00
if ( total_size < 0 ) snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ),
"size=N/A time=" );
else snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ),
"size=%8.0fkB time=" , total_size / 1024.0 );
2011-09-27 02:14:37 +02:00
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ),
"%02d:%02d:%02d.%02d " , hours , mins , secs ,
( 100 * us ) / AV_TIME_BASE );
2012-12-23 00:19:11 +01:00
if ( bitrate < 0 ) snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ),
"bitrate=N/A" );
else snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ),
"bitrate=%6.1fkbits/s" , bitrate );
if ( total_size < 0 ) av_bprintf ( & buf_script , "total_size=N/A \n " );
else av_bprintf ( & buf_script , "total_size=%" PRId64 " \n " , total_size );
2012-07-08 13:03:39 +02:00
av_bprintf ( & buf_script , "out_time_ms=%" PRId64 " \n " , pts );
av_bprintf ( & buf_script , "out_time=%02d:%02d:%02d.%06d \n " ,
hours , mins , secs , us );
2004-06-11 22:03:16 +00:00
2011-09-27 02:14:37 +02:00
if ( nb_frames_dup || nb_frames_drop )
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ), " dup=%d drop=%d" ,
nb_frames_dup , nb_frames_drop );
2012-07-08 13:03:39 +02:00
av_bprintf ( & buf_script , "dup_frames=%d \n " , nb_frames_dup );
av_bprintf ( & buf_script , "drop_frames=%d \n " , nb_frames_drop );
2005-12-17 18:14:38 +00:00
2012-07-08 13:03:39 +02:00
if ( print_stats || is_last_report ) {
2013-03-03 19:33:37 +01:00
if ( print_stats == 1 && AV_LOG_INFO > av_log_get_level ()) {
fprintf ( stderr , "%s \r " , buf );
} else
av_log ( NULL , AV_LOG_INFO , "%s \r " , buf );
2004-04-11 13:50:42 +00:00
2011-09-27 02:14:37 +02:00
fflush ( stderr );
2012-07-08 13:03:39 +02:00
}
if ( progress_avio ) {
av_bprintf ( & buf_script , "progress=%s \n " ,
is_last_report ? "end" : "continue" );
avio_write ( progress_avio , buf_script . str ,
FFMIN ( buf_script . len , buf_script . size - 1 ));
avio_flush ( progress_avio );
av_bprint_finalize ( & buf_script , NULL );
if ( is_last_report ) {
avio_close ( progress_avio );
progress_avio = NULL ;
}
}
2005-12-17 18:14:38 +00:00
2011-09-27 02:14:37 +02:00
if ( is_last_report ) {
2012-06-17 19:50:36 +02:00
int64_t raw = audio_size + video_size + subtitle_size + extra_size ;
2011-09-27 02:14:37 +02:00
av_log ( NULL , AV_LOG_INFO , " \n " );
2012-06-17 19:50:36 +02:00
av_log ( NULL , AV_LOG_INFO , "video:%1.0fkB audio:%1.0fkB subtitle:%1.0f global headers:%1.0fkB muxing overhead %f%% \n " ,
2011-12-30 03:46:24 +01:00
video_size / 1024.0 ,
audio_size / 1024.0 ,
2012-06-17 19:50:36 +02:00
subtitle_size / 1024.0 ,
2011-12-30 03:46:24 +01:00
extra_size / 1024.0 ,
100.0 * ( total_size - raw ) / raw
2004-04-15 13:57:55 +00:00
);
2012-06-17 19:50:36 +02:00
if ( video_size + audio_size + subtitle_size + extra_size == 0 ){
2011-11-25 16:17:06 +01:00
av_log ( NULL , AV_LOG_WARNING , "Output file is empty, nothing was encoded (check -ss / -t / -frames parameters if used) \n " );
}
2004-04-15 13:57:55 +00:00
}
2002-03-19 06:30:41 +00:00
}
2012-04-15 15:03:07 +02:00
static void flush_encoders ( void )
2011-08-30 15:55:25 +02:00
{
int i , ret ;
2012-04-15 15:03:07 +02:00
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
OutputStream * ost = output_streams [ i ];
2011-08-30 15:56:03 +02:00
AVCodecContext * enc = ost -> st -> codec ;
2012-04-15 15:28:30 +02:00
AVFormatContext * os = output_files [ ost -> file_index ] -> ctx ;
2012-01-17 01:40:45 +01:00
int stop_encoding = 0 ;
2011-08-30 15:55:25 +02:00
2011-08-30 16:00:47 +02:00
if ( ! ost -> encoding_needed )
2011-08-30 15:56:03 +02:00
continue ;
2011-08-30 15:55:25 +02:00
2011-12-30 03:46:24 +01:00
if ( ost -> st -> codec -> codec_type == AVMEDIA_TYPE_AUDIO && enc -> frame_size <= 1 )
2011-08-30 15:56:03 +02:00
continue ;
2012-08-05 11:11:04 +02:00
if ( ost -> st -> codec -> codec_type == AVMEDIA_TYPE_VIDEO && ( os -> oformat -> flags & AVFMT_RAWPICTURE ) && enc -> codec -> id == AV_CODEC_ID_RAWVIDEO )
2011-08-30 15:56:03 +02:00
continue ;
2011-08-30 15:55:25 +02:00
2011-12-30 03:46:24 +01:00
for (;;) {
2012-05-05 18:22:46 +02:00
int ( * encode )( AVCodecContext * , AVPacket * , const AVFrame * , int * ) = NULL ;
const char * desc ;
int64_t * size ;
2011-08-30 15:55:25 +02:00
2011-08-30 15:56:03 +02:00
switch ( ost -> st -> codec -> codec_type ) {
case AVMEDIA_TYPE_AUDIO :
2012-05-05 18:22:46 +02:00
encode = avcodec_encode_audio2 ;
desc = "Audio" ;
size = & audio_size ;
2011-08-30 15:56:03 +02:00
break ;
case AVMEDIA_TYPE_VIDEO :
2012-05-05 18:22:46 +02:00
encode = avcodec_encode_video2 ;
desc = "Video" ;
size = & video_size ;
break ;
default :
stop_encoding = 1 ;
}
if ( encode ) {
AVPacket pkt ;
int got_packet ;
av_init_packet ( & pkt );
pkt . data = NULL ;
pkt . size = 0 ;
2012-04-11 19:26:09 +02:00
update_benchmark ( NULL );
2012-05-05 18:22:46 +02:00
ret = encode ( enc , & pkt , NULL , & got_packet );
update_benchmark ( "flush %s %d.%d" , desc , ost -> file_index , ost -> index );
2011-08-30 15:56:03 +02:00
if ( ret < 0 ) {
2012-05-05 18:22:46 +02:00
av_log ( NULL , AV_LOG_FATAL , "%s encoding failed \n " , desc );
2012-09-05 07:03:56 +00:00
exit ( 1 );
2011-08-30 15:56:03 +02:00
}
2012-05-05 18:22:46 +02:00
* size += pkt . size ;
2011-08-30 15:56:03 +02:00
if ( ost -> logfile && enc -> stats_out ) {
fprintf ( ost -> logfile , "%s" , enc -> stats_out );
}
2012-02-01 10:51:36 +01:00
if ( ! got_packet ) {
2012-01-17 01:40:45 +01:00
stop_encoding = 1 ;
break ;
}
2012-02-01 10:51:36 +01:00
if ( pkt . pts != AV_NOPTS_VALUE )
pkt . pts = av_rescale_q ( pkt . pts , enc -> time_base , ost -> st -> time_base );
if ( pkt . dts != AV_NOPTS_VALUE )
pkt . dts = av_rescale_q ( pkt . dts , enc -> time_base , ost -> st -> time_base );
2012-11-07 11:33:41 -08:00
if ( pkt . duration > 0 )
pkt . duration = av_rescale_q ( pkt . duration , enc -> time_base , ost -> st -> time_base );
2012-01-17 01:40:45 +01:00
write_frame ( os , & pkt , ost );
2012-12-03 22:01:38 -08:00
if ( ost -> st -> codec -> codec_type == AVMEDIA_TYPE_VIDEO && vstats_filename ) {
2012-12-04 16:40:11 +01:00
do_video_stats ( ost , pkt . size );
2012-12-03 22:01:38 -08:00
}
2011-08-30 15:55:25 +02:00
}
2012-05-05 18:22:46 +02:00
2012-01-17 01:40:45 +01:00
if ( stop_encoding )
2011-08-30 15:56:03 +02:00
break ;
2011-08-30 15:55:25 +02:00
}
}
}
2011-11-23 04:02:17 +01:00
/*
* Check whether a packet from ist should be written into ost at this time
*/
static int check_output_constraints ( InputStream * ist , OutputStream * ost )
{
2012-04-15 15:28:30 +02:00
OutputFile * of = output_files [ ost -> file_index ];
int ist_index = input_files [ ist -> file_index ] -> ist_index + ist -> st -> index ;
2011-11-23 04:02:17 +01:00
if ( ost -> source_index != ist_index )
return 0 ;
if ( of -> start_time && ist -> pts < of -> start_time )
return 0 ;
return 1 ;
}
static void do_streamcopy ( InputStream * ist , OutputStream * ost , const AVPacket * pkt )
{
2012-04-15 15:28:30 +02:00
OutputFile * of = output_files [ ost -> file_index ];
2011-11-23 04:02:17 +01:00
int64_t ost_tb_start_time = av_rescale_q ( of -> start_time , AV_TIME_BASE_Q , ost -> st -> time_base );
AVPicture pict ;
AVPacket opkt ;
av_init_packet ( & opkt );
if (( ! ost -> frame_number && ! ( pkt -> flags & AV_PKT_FLAG_KEY )) &&
! ost -> copy_initial_nonkeyframes )
return ;
2012-09-27 03:37:27 +02:00
if ( ! ost -> frame_number && ist -> pts < of -> start_time &&
! ost -> copy_prior_start )
return ;
2012-07-03 20:34:27 +02:00
if ( of -> recording_time != INT64_MAX &&
ist -> pts >= of -> recording_time + of -> start_time ) {
2012-08-20 11:08:34 +02:00
close_output_stream ( ost );
2012-07-03 20:34:27 +02:00
return ;
}
2011-11-23 04:02:17 +01:00
/* force the input stream PTS */
if ( ost -> st -> codec -> codec_type == AVMEDIA_TYPE_AUDIO )
audio_size += pkt -> size ;
else if ( ost -> st -> codec -> codec_type == AVMEDIA_TYPE_VIDEO ) {
video_size += pkt -> size ;
ost -> sync_opts ++ ;
2012-06-17 19:50:36 +02:00
} else if ( ost -> st -> codec -> codec_type == AVMEDIA_TYPE_SUBTITLE ) {
subtitle_size += pkt -> size ;
2011-11-23 04:02:17 +01:00
}
if ( pkt -> pts != AV_NOPTS_VALUE )
opkt . pts = av_rescale_q ( pkt -> pts , ist -> st -> time_base , ost -> st -> time_base ) - ost_tb_start_time ;
else
opkt . pts = AV_NOPTS_VALUE ;
if ( pkt -> dts == AV_NOPTS_VALUE )
2012-02-08 17:25:01 +01:00
opkt . dts = av_rescale_q ( ist -> dts , AV_TIME_BASE_Q , ost -> st -> time_base );
2011-11-23 04:02:17 +01:00
else
opkt . dts = av_rescale_q ( pkt -> dts , ist -> st -> time_base , ost -> st -> time_base );
opkt . dts -= ost_tb_start_time ;
2012-10-27 03:18:09 +02:00
if ( ost -> st -> codec -> codec_type == AVMEDIA_TYPE_AUDIO && pkt -> dts != AV_NOPTS_VALUE ) {
int duration = av_get_audio_frame_duration ( ist -> st -> codec , pkt -> size );
if ( ! duration )
duration = ist -> st -> codec -> frame_size ;
opkt . dts = opkt . pts = av_rescale_delta ( ist -> st -> time_base , pkt -> dts ,
( AVRational ){ 1 , ist -> st -> codec -> sample_rate }, duration , & ist -> filter_in_rescale_delta_last ,
2012-11-14 02:06:50 +01:00
ost -> st -> time_base ) - ost_tb_start_time ;
2012-10-27 03:18:09 +02:00
}
2011-11-23 04:02:17 +01:00
opkt . duration = av_rescale_q ( pkt -> duration , ist -> st -> time_base , ost -> st -> time_base );
opkt . flags = pkt -> flags ;
2011-12-30 03:46:24 +01:00
// FIXME remove the following 2 lines they shall be replaced by the bitstream filters
2012-08-05 11:11:04 +02:00
if ( ost -> st -> codec -> codec_id != AV_CODEC_ID_H264
&& ost -> st -> codec -> codec_id != AV_CODEC_ID_MPEG1VIDEO
&& ost -> st -> codec -> codec_id != AV_CODEC_ID_MPEG2VIDEO
&& ost -> st -> codec -> codec_id != AV_CODEC_ID_VC1
2011-11-23 04:02:17 +01:00
) {
2013-01-21 21:10:18 +01:00
if ( av_parser_change ( ist -> st -> parser , ost -> st -> codec , & opkt . data , & opkt . size , pkt -> data , pkt -> size , pkt -> flags & AV_PKT_FLAG_KEY )) {
opkt . buf = av_buffer_create ( opkt . data , opkt . size , av_buffer_default_free , NULL , 0 );
if ( ! opkt . buf )
exit ( 1 );
}
2011-11-23 04:02:17 +01:00
} else {
opkt . data = pkt -> data ;
opkt . size = pkt -> size ;
}
2012-08-01 01:47:51 +02:00
if ( ost -> st -> codec -> codec_type == AVMEDIA_TYPE_VIDEO && ( of -> ctx -> oformat -> flags & AVFMT_RAWPICTURE )) {
2011-11-23 04:02:17 +01:00
/* store AVPicture in AVPacket, as expected by the output format */
avpicture_fill ( & pict , opkt . data , ost -> st -> codec -> pix_fmt , ost -> st -> codec -> width , ost -> st -> codec -> height );
opkt . data = ( uint8_t * ) & pict ;
opkt . size = sizeof ( AVPicture );
opkt . flags |= AV_PKT_FLAG_KEY ;
}
2012-01-02 02:48:34 +01:00
write_frame ( of -> ctx , & opkt , ost );
2011-11-23 04:02:17 +01:00
ost -> st -> codec -> frame_number ++ ;
}
static void rate_emu_sleep ( InputStream * ist )
{
2012-04-15 15:28:30 +02:00
if ( input_files [ ist -> file_index ] -> rate_emu ) {
2012-02-08 17:25:40 +01:00
int64_t pts = av_rescale ( ist -> dts , 1000000 , AV_TIME_BASE );
2011-11-23 04:02:17 +01:00
int64_t now = av_gettime () - ist -> start ;
if ( pts > now )
2012-06-21 20:31:44 +01:00
av_usleep ( pts - now );
2011-11-23 04:02:17 +01:00
}
}
2012-08-01 18:23:12 +02:00
int guess_input_channel_layout ( InputStream * ist )
2012-05-05 18:22:46 +02:00
{
AVCodecContext * dec = ist -> st -> codec ;
if ( ! dec -> channel_layout ) {
char layout_name [ 256 ];
2012-12-31 15:20:25 +01:00
if ( dec -> channels > ist -> guess_layout_max )
return 0 ;
2012-05-05 18:22:46 +02:00
dec -> channel_layout = av_get_default_channel_layout ( dec -> channels );
if ( ! dec -> channel_layout )
return 0 ;
av_get_channel_layout_string ( layout_name , sizeof ( layout_name ),
dec -> channels , dec -> channel_layout );
av_log ( NULL , AV_LOG_WARNING , "Guessed Channel Layout for Input Stream "
"#%d.%d : %s \n " , ist -> file_index , ist -> st -> index , layout_name );
}
return 1 ;
}
2012-05-18 12:46:11 +02:00
static int decode_audio ( InputStream * ist , AVPacket * pkt , int * got_output )
2011-11-23 04:02:17 +01:00
{
2013-01-21 21:10:18 +01:00
AVFrame * decoded_frame , * f ;
2011-12-06 01:37:27 +01:00
AVCodecContext * avctx = ist -> st -> codec ;
2013-01-21 21:10:18 +01:00
int i , ret , err = 0 , resample_changed ;
2012-07-26 17:56:52 +02:00
AVRational decoded_frame_tb ;
2011-11-23 04:02:17 +01:00
2011-12-06 01:37:27 +01:00
if ( ! ist -> decoded_frame && ! ( ist -> decoded_frame = avcodec_alloc_frame ()))
return AVERROR ( ENOMEM );
2013-01-21 21:10:18 +01:00
if ( ! ist -> filter_frame && ! ( ist -> filter_frame = av_frame_alloc ()))
return AVERROR ( ENOMEM );
2011-12-06 01:37:27 +01:00
decoded_frame = ist -> decoded_frame ;
2011-11-23 04:02:17 +01:00
2012-04-11 19:26:09 +02:00
update_benchmark ( NULL );
2011-12-06 01:37:27 +01:00
ret = avcodec_decode_audio4 ( avctx , decoded_frame , got_output , pkt );
2012-04-11 19:26:09 +02:00
update_benchmark ( "decode_audio %d.%d" , ist -> file_index , ist -> st -> index );
2012-08-09 15:14:57 +02:00
if ( ret >= 0 && avctx -> sample_rate <= 0 ) {
2012-03-23 10:59:03 +01:00
av_log ( avctx , AV_LOG_ERROR , "Sample rate %d invalid \n " , avctx -> sample_rate );
2012-08-17 13:50:16 +02:00
ret = AVERROR_INVALIDDATA ;
2012-03-23 10:59:03 +01:00
}
2011-11-23 04:02:17 +01:00
2012-08-08 12:27:50 +02:00
if ( !* got_output || ret < 0 ) {
if ( ! pkt -> size ) {
2012-05-05 18:22:46 +02:00
for ( i = 0 ; i < ist -> nb_filters ; i ++ )
2013-03-12 13:40:42 +01:00
#if 1
2012-08-19 19:02:31 +02:00
av_buffersrc_add_ref ( ist -> filters [ i ] -> filter , NULL , 0 );
2013-03-12 13:40:42 +01:00
#else
2013-01-21 21:10:18 +01:00
av_buffersrc_add_frame ( ist -> filters [ i ] -> filter , NULL );
2013-03-12 13:40:42 +01:00
#endif
2012-08-08 12:27:50 +02:00
}
2011-11-24 02:08:21 +01:00
return ret ;
2011-11-23 04:02:17 +01:00
}
2012-05-05 18:22:46 +02:00
#if 1
2012-02-08 16:28:56 +01:00
/* increment next_dts to use for the case where the input stream does not
2011-12-06 01:37:27 +01:00
have timestamps or there are multiple frames in the packet */
ist -> next_pts += (( int64_t ) AV_TIME_BASE * decoded_frame -> nb_samples ) /
avctx -> sample_rate ;
2012-02-08 16:28:56 +01:00
ist -> next_dts += (( int64_t ) AV_TIME_BASE * decoded_frame -> nb_samples ) /
avctx -> sample_rate ;
2012-05-05 18:22:46 +02:00
#endif
2011-11-23 04:02:17 +01:00
rate_emu_sleep ( ist );
2012-05-05 18:22:46 +02:00
resample_changed = ist -> resample_sample_fmt != decoded_frame -> format ||
ist -> resample_channels != avctx -> channels ||
ist -> resample_channel_layout != decoded_frame -> channel_layout ||
ist -> resample_sample_rate != decoded_frame -> sample_rate ;
if ( resample_changed ) {
char layout1 [ 64 ], layout2 [ 64 ];
2011-11-23 04:02:17 +01:00
2012-05-05 18:22:46 +02:00
if ( ! guess_input_channel_layout ( ist )) {
av_log ( NULL , AV_LOG_FATAL , "Unable to find default channel "
"layout for Input Stream #%d.%d \n " , ist -> file_index ,
ist -> st -> index );
2012-09-05 07:03:56 +00:00
exit ( 1 );
2012-05-05 18:22:46 +02:00
}
decoded_frame -> channel_layout = avctx -> channel_layout ;
av_get_channel_layout_string ( layout1 , sizeof ( layout1 ), ist -> resample_channels ,
ist -> resample_channel_layout );
av_get_channel_layout_string ( layout2 , sizeof ( layout2 ), avctx -> channels ,
decoded_frame -> channel_layout );
av_log ( NULL , AV_LOG_INFO ,
"Input stream #%d:%d frame changed from rate:%d fmt:%s ch:%d chl:%s to rate:%d fmt:%s ch:%d chl:%s \n " ,
ist -> file_index , ist -> st -> index ,
ist -> resample_sample_rate , av_get_sample_fmt_name ( ist -> resample_sample_fmt ),
ist -> resample_channels , layout1 ,
decoded_frame -> sample_rate , av_get_sample_fmt_name ( decoded_frame -> format ),
avctx -> channels , layout2 );
ist -> resample_sample_fmt = decoded_frame -> format ;
ist -> resample_sample_rate = decoded_frame -> sample_rate ;
ist -> resample_channel_layout = decoded_frame -> channel_layout ;
ist -> resample_channels = avctx -> channels ;
for ( i = 0 ; i < nb_filtergraphs ; i ++ )
2012-06-30 21:33:48 +02:00
if ( ist_in_filtergraph ( filtergraphs [ i ], ist )) {
FilterGraph * fg = filtergraphs [ i ];
int j ;
if ( configure_filtergraph ( fg ) < 0 ) {
av_log ( NULL , AV_LOG_FATAL , "Error reinitializing filters! \n " );
2012-10-02 19:43:01 +02:00
exit ( 1 );
2012-06-30 21:33:48 +02:00
}
for ( j = 0 ; j < fg -> nb_outputs ; j ++ ) {
OutputStream * ost = fg -> outputs [ j ] -> ost ;
if ( ost -> enc -> type == AVMEDIA_TYPE_AUDIO &&
! ( ost -> enc -> capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE ))
av_buffersink_set_frame_size ( ost -> filter -> filter ,
ost -> st -> codec -> frame_size );
}
2012-05-05 18:22:46 +02:00
}
}
2012-07-26 17:57:36 +02:00
/* if the decoder provides a pts, use it instead of the last packet pts.
the decoder could be delaying output by a packet or more. */
if ( decoded_frame -> pts != AV_NOPTS_VALUE ) {
ist -> dts = ist -> next_dts = ist -> pts = ist -> next_pts = av_rescale_q ( decoded_frame -> pts , avctx -> time_base , AV_TIME_BASE_Q );
decoded_frame_tb = avctx -> time_base ;
} else if ( decoded_frame -> pkt_pts != AV_NOPTS_VALUE ) {
decoded_frame -> pts = decoded_frame -> pkt_pts ;
pkt -> pts = AV_NOPTS_VALUE ;
decoded_frame_tb = ist -> st -> time_base ;
} else if ( pkt -> pts != AV_NOPTS_VALUE ) {
decoded_frame -> pts = pkt -> pts ;
pkt -> pts = AV_NOPTS_VALUE ;
decoded_frame_tb = ist -> st -> time_base ;
} else {
decoded_frame -> pts = ist -> dts ;
decoded_frame_tb = AV_TIME_BASE_Q ;
}
2012-06-30 11:26:11 +03:00
if ( decoded_frame -> pts != AV_NOPTS_VALUE )
2012-10-26 21:55:37 +02:00
decoded_frame -> pts = av_rescale_delta ( decoded_frame_tb , decoded_frame -> pts ,
( AVRational ){ 1 , ist -> st -> codec -> sample_rate }, decoded_frame -> nb_samples , & ist -> filter_in_rescale_delta_last ,
( AVRational ){ 1 , ist -> st -> codec -> sample_rate });
2013-01-21 21:10:18 +01:00
for ( i = 0 ; i < ist -> nb_filters ; i ++ ) {
if ( i < ist -> nb_filters - 1 ) {
f = ist -> filter_frame ;
err = av_frame_ref ( f , decoded_frame );
if ( err < 0 )
break ;
} else
f = decoded_frame ;
2013-03-12 13:40:42 +01:00
err = av_buffersrc_add_frame_flags ( ist -> filters [ i ] -> filter , f ,
2013-03-10 14:07:29 +01:00
AV_BUFFERSRC_FLAG_PUSH );
2013-01-21 21:10:18 +01:00
if ( err < 0 )
break ;
}
2012-07-26 17:51:56 +02:00
decoded_frame -> pts = AV_NOPTS_VALUE ;
2013-01-21 21:10:18 +01:00
av_frame_unref ( ist -> filter_frame );
av_frame_unref ( decoded_frame );
return err < 0 ? err : ret ;
2011-11-23 04:02:17 +01:00
}
2012-05-18 12:46:11 +02:00
static int decode_video ( InputStream * ist , AVPacket * pkt , int * got_output )
2011-11-23 04:02:17 +01:00
{
2013-01-21 21:10:18 +01:00
AVFrame * decoded_frame , * f ;
2011-11-23 04:02:17 +01:00
void * buffer_to_free = NULL ;
2013-01-21 21:10:18 +01:00
int i , ret = 0 , err = 0 , resample_changed ;
2012-04-29 11:16:03 +02:00
int64_t best_effort_timestamp ;
2011-12-03 21:20:50 +01:00
AVRational * frame_sample_aspect ;
2011-11-23 04:02:17 +01:00
2013-01-21 21:10:18 +01:00
if ( ! ist -> decoded_frame && ! ( ist -> decoded_frame = av_frame_alloc ()))
return AVERROR ( ENOMEM );
if ( ! ist -> filter_frame && ! ( ist -> filter_frame = av_frame_alloc ()))
2011-11-23 04:02:17 +01:00
return AVERROR ( ENOMEM );
2011-12-06 01:37:27 +01:00
decoded_frame = ist -> decoded_frame ;
2012-05-20 10:57:23 +02:00
pkt -> dts = av_rescale_q ( ist -> dts , AV_TIME_BASE_Q , ist -> st -> time_base );
2011-11-23 04:02:17 +01:00
2012-04-11 19:26:09 +02:00
update_benchmark ( NULL );
2011-11-23 04:02:17 +01:00
ret = avcodec_decode_video2 ( ist -> st -> codec ,
decoded_frame , got_output , pkt );
2012-04-11 19:26:09 +02:00
update_benchmark ( "decode_video %d.%d" , ist -> file_index , ist -> st -> index );
2012-08-08 12:27:50 +02:00
if ( !* got_output || ret < 0 ) {
if ( ! pkt -> size ) {
2012-04-01 19:01:37 +02:00
for ( i = 0 ; i < ist -> nb_filters ; i ++ )
2013-03-12 13:40:42 +01:00
#if 1
2012-08-19 19:02:31 +02:00
av_buffersrc_add_ref ( ist -> filters [ i ] -> filter , NULL , 0 );
2013-03-12 13:40:42 +01:00
#else
2013-01-21 21:10:18 +01:00
av_buffersrc_add_frame ( ist -> filters [ i ] -> filter , NULL );
2013-03-12 13:40:42 +01:00
#endif
2012-08-08 12:27:50 +02:00
}
2011-11-24 02:08:21 +01:00
return ret ;
2011-11-23 04:02:17 +01:00
}
2012-05-31 12:29:07 +02:00
if ( ist -> top_field_first >= 0 )
decoded_frame -> top_field_first = ist -> top_field_first ;
2012-04-29 11:16:03 +02:00
best_effort_timestamp = av_frame_get_best_effort_timestamp ( decoded_frame );
if ( best_effort_timestamp != AV_NOPTS_VALUE )
2012-05-20 10:57:23 +02:00
ist -> next_pts = ist -> pts = av_rescale_q ( decoded_frame -> pts = best_effort_timestamp , ist -> st -> time_base , AV_TIME_BASE_Q );
2011-11-23 04:02:17 +01:00
2012-07-12 10:24:59 +02:00
if ( debug_ts ) {
av_log ( NULL , AV_LOG_INFO , "decoder -> ist_index:%d type:video "
2012-07-13 16:24:32 +02:00
"frame_pts:%s frame_pts_time:%s best_effort_ts:%" PRId64 " best_effort_ts_time:%s keyframe:%d frame_type:%d \n " ,
2012-07-12 10:24:59 +02:00
ist -> st -> index , av_ts2str ( decoded_frame -> pts ),
av_ts2timestr ( decoded_frame -> pts , & ist -> st -> time_base ),
best_effort_timestamp ,
av_ts2timestr ( best_effort_timestamp , & ist -> st -> time_base ),
decoded_frame -> key_frame , decoded_frame -> pict_type );
}
2011-11-23 04:02:17 +01:00
pkt -> size = 0 ;
rate_emu_sleep ( ist );
2012-03-22 09:37:33 +01:00
if ( ist -> st -> sample_aspect_ratio . num )
decoded_frame -> sample_aspect_ratio = ist -> st -> sample_aspect_ratio ;
2012-03-29 07:40:26 +02:00
resample_changed = ist -> resample_width != decoded_frame -> width ||
ist -> resample_height != decoded_frame -> height ||
ist -> resample_pix_fmt != decoded_frame -> format ;
if ( resample_changed ) {
av_log ( NULL , AV_LOG_INFO ,
"Input stream #%d:%d frame changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s \n " ,
ist -> file_index , ist -> st -> index ,
ist -> resample_width , ist -> resample_height , av_get_pix_fmt_name ( ist -> resample_pix_fmt ),
decoded_frame -> width , decoded_frame -> height , av_get_pix_fmt_name ( decoded_frame -> format ));
2011-11-23 04:02:17 +01:00
2012-03-29 07:40:26 +02:00
ist -> resample_width = decoded_frame -> width ;
ist -> resample_height = decoded_frame -> height ;
ist -> resample_pix_fmt = decoded_frame -> format ;
2011-11-23 04:02:17 +01:00
2012-10-16 23:50:06 +02:00
for ( i = 0 ; i < nb_filtergraphs ; i ++ ) {
if ( ist_in_filtergraph ( filtergraphs [ i ], ist ) && ist -> reinit_filters &&
2012-04-01 15:08:33 +02:00
configure_filtergraph ( filtergraphs [ i ]) < 0 ) {
av_log ( NULL , AV_LOG_FATAL , "Error reinitializing filters! \n " );
2012-09-05 07:03:56 +00:00
exit ( 1 );
2012-02-07 11:51:06 +01:00
}
2012-10-16 23:50:06 +02:00
}
2011-11-23 04:02:17 +01:00
}
2012-04-17 04:01:17 +02:00
frame_sample_aspect = av_opt_ptr ( avcodec_get_frame_class (), decoded_frame , "sample_aspect_ratio" );
2012-03-29 08:51:17 +02:00
for ( i = 0 ; i < ist -> nb_filters ; i ++ ) {
2012-04-17 04:01:17 +02:00
if ( ! frame_sample_aspect -> num )
* frame_sample_aspect = ist -> st -> sample_aspect_ratio ;
2011-12-21 21:04:05 +01:00
2013-01-21 21:10:18 +01:00
if ( i < ist -> nb_filters - 1 ) {
f = ist -> filter_frame ;
err = av_frame_ref ( f , decoded_frame );
if ( err < 0 )
break ;
2011-12-21 21:04:05 +01:00
} else
2013-01-21 21:10:18 +01:00
f = decoded_frame ;
2013-03-12 13:40:42 +01:00
if ( av_buffersrc_add_frame_flags ( ist -> filters [ i ] -> filter , f ,
2013-03-10 14:07:29 +01:00
AV_BUFFERSRC_FLAG_PUSH ) < 0 ) {
2012-04-17 04:01:17 +02:00
av_log ( NULL , AV_LOG_FATAL , "Failed to inject frame into filter network \n " );
2012-10-02 19:43:01 +02:00
exit ( 1 );
2012-04-17 04:01:17 +02:00
}
2011-11-21 14:39:22 +01:00
}
2013-01-21 21:10:18 +01:00
av_frame_unref ( ist -> filter_frame );
av_frame_unref ( decoded_frame );
2011-11-23 04:02:17 +01:00
av_free ( buffer_to_free );
2013-01-21 21:10:18 +01:00
return err < 0 ? err : ret ;
2011-11-23 04:02:17 +01:00
}
static int transcode_subtitles ( InputStream * ist , AVPacket * pkt , int * got_output )
{
AVSubtitle subtitle ;
int i , ret = avcodec_decode_subtitle2 ( ist -> st -> codec ,
& subtitle , got_output , pkt );
2012-07-26 19:29:27 +02:00
if ( ret < 0 || !* got_output ) {
if ( ! pkt -> size )
sub2video_flush ( ist );
2011-11-24 02:08:21 +01:00
return ret ;
2012-07-26 19:29:27 +02:00
}
2011-11-23 04:02:17 +01:00
2012-08-09 11:44:17 +02:00
if ( ist -> fix_sub_duration ) {
if ( ist -> prev_sub . got_output ) {
2012-09-09 16:28:30 +02:00
int end = av_rescale ( subtitle . pts - ist -> prev_sub . subtitle . pts ,
1000 , AV_TIME_BASE );
2012-08-09 11:44:17 +02:00
if ( end < ist -> prev_sub . subtitle . end_display_time ) {
av_log ( ist -> st -> codec , AV_LOG_DEBUG ,
"Subtitle duration reduced from %d to %d \n " ,
ist -> prev_sub . subtitle . end_display_time , end );
ist -> prev_sub . subtitle . end_display_time = end ;
}
}
FFSWAP ( int , * got_output , ist -> prev_sub . got_output );
FFSWAP ( int , ret , ist -> prev_sub . ret );
FFSWAP ( AVSubtitle , subtitle , ist -> prev_sub . subtitle );
}
2012-09-09 16:37:45 +02:00
sub2video_update ( ist , & subtitle );
2012-09-09 15:53:21 +02:00
2012-08-09 11:44:17 +02:00
if ( !* got_output || ! subtitle . num_rects )
return ret ;
2011-11-23 04:02:17 +01:00
rate_emu_sleep ( ist );
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
OutputStream * ost = output_streams [ i ];
2011-11-23 04:02:17 +01:00
if ( ! check_output_constraints ( ist , ost ) || ! ost -> encoding_needed )
continue ;
2012-09-09 16:28:30 +02:00
do_subtitle_out ( output_files [ ost -> file_index ] -> ctx , ost , ist , & subtitle );
2011-11-23 04:02:17 +01:00
}
avsubtitle_free ( & subtitle );
2011-11-24 02:08:21 +01:00
return ret ;
2011-11-23 04:02:17 +01:00
}
2003-12-15 14:43:44 +00:00
/* pkt = NULL means EOF (needed to flush decoder buffers) */
2012-04-15 15:03:07 +02:00
static int output_packet ( InputStream * ist , const AVPacket * pkt )
2003-12-15 14:43:44 +00:00
{
2011-09-29 01:03:02 +02:00
int ret = 0 , i ;
2011-05-10 01:53:46 -04:00
int got_output ;
2010-05-07 09:43:21 +00:00
2009-04-10 12:53:22 +00:00
AVPacket avpkt ;
2012-04-24 18:44:51 +02:00
if ( ! ist -> saw_first_ts ) {
ist -> dts = ist -> st -> avg_frame_rate . num ? - ist -> st -> codec -> has_b_frames * AV_TIME_BASE / av_q2d ( ist -> st -> avg_frame_rate ) : 0 ;
ist -> pts = 0 ;
if ( pkt != NULL && pkt -> pts != AV_NOPTS_VALUE && ! ist -> decoding_needed ) {
ist -> dts += av_rescale_q ( pkt -> pts , ist -> st -> time_base , AV_TIME_BASE_Q );
ist -> pts = ist -> dts ; //unused but better to set it to a value thats not totally wrong
}
ist -> saw_first_ts = 1 ;
}
2009-04-10 12:53:22 +00:00
2012-02-08 06:19:43 +01:00
if ( ist -> next_dts == AV_NOPTS_VALUE )
ist -> next_dts = ist -> dts ;
2011-11-24 02:08:21 +01:00
if ( ist -> next_pts == AV_NOPTS_VALUE )
ist -> next_pts = ist -> pts ;
2008-02-17 19:08:15 +00:00
2003-12-15 14:43:44 +00:00
if ( pkt == NULL ) {
/* EOF handling */
2009-04-11 22:04:52 +00:00
av_init_packet ( & avpkt );
2009-04-10 12:53:22 +00:00
avpkt . data = NULL ;
avpkt . size = 0 ;
2003-12-15 14:43:44 +00:00
goto handle_eof ;
2009-04-11 22:04:52 +00:00
} else {
avpkt = * pkt ;
2003-12-15 14:43:44 +00:00
}
2011-12-30 03:46:24 +01:00
if ( pkt -> dts != AV_NOPTS_VALUE ) {
2012-02-08 06:19:43 +01:00
ist -> next_dts = ist -> dts = av_rescale_q ( pkt -> dts , ist -> st -> time_base , AV_TIME_BASE_Q );
2011-12-30 03:46:24 +01:00
if ( ist -> st -> codec -> codec_type != AVMEDIA_TYPE_VIDEO || ! ist -> decoding_needed )
2012-10-26 21:21:29 +02:00
ist -> next_pts = ist -> pts = ist -> dts ;
2011-11-10 14:59:00 +01:00
}
2008-02-17 17:55:53 +00:00
2011-12-30 03:46:24 +01:00
// while we have more to decode or while the decoder did output something on EOF
2011-11-23 04:02:17 +01:00
while ( ist -> decoding_needed && ( avpkt . size > 0 || ( ! pkt && got_output ))) {
2012-02-08 16:16:42 +01:00
int duration ;
2003-12-15 14:43:44 +00:00
handle_eof :
2008-02-15 21:45:12 +00:00
2011-11-24 02:08:21 +01:00
ist -> pts = ist -> next_pts ;
2012-02-08 06:19:43 +01:00
ist -> dts = ist -> next_dts ;
2011-11-24 02:08:21 +01:00
if ( avpkt . size && avpkt . size != pkt -> size ) {
2011-09-27 02:14:37 +02:00
av_log ( NULL , ist -> showed_multi_packet_warning ? AV_LOG_VERBOSE : AV_LOG_WARNING ,
"Multiple frames in a packet from stream %d \n " , pkt -> stream_index );
2011-11-24 02:08:21 +01:00
ist -> showed_multi_packet_warning = 1 ;
2010-01-27 13:27:18 +00:00
}
2008-02-17 19:38:47 +00:00
2011-12-30 03:46:24 +01:00
switch ( ist -> st -> codec -> codec_type ) {
2011-11-23 04:02:17 +01:00
case AVMEDIA_TYPE_AUDIO :
2012-05-18 12:46:11 +02:00
ret = decode_audio ( ist , & avpkt , & got_output );
2011-11-23 04:02:17 +01:00
break ;
case AVMEDIA_TYPE_VIDEO :
2012-05-18 12:46:11 +02:00
ret = decode_video ( ist , & avpkt , & got_output );
2012-02-08 16:16:42 +01:00
if ( avpkt . duration ) {
duration = av_rescale_q ( avpkt . duration , ist -> st -> time_base , AV_TIME_BASE_Q );
2012-02-28 18:41:01 +01:00
} else if ( ist -> st -> codec -> time_base . num != 0 && ist -> st -> codec -> time_base . den != 0 ) {
2012-02-08 16:16:42 +01:00
int ticks = ist -> st -> parser ? ist -> st -> parser -> repeat_pict + 1 : ist -> st -> codec -> ticks_per_frame ;
duration = (( int64_t ) AV_TIME_BASE *
ist -> st -> codec -> time_base . num * ticks ) /
ist -> st -> codec -> time_base . den ;
} else
duration = 0 ;
if ( ist -> dts != AV_NOPTS_VALUE && duration ) {
ist -> next_dts += duration ;
} else
ist -> next_dts = AV_NOPTS_VALUE ;
if ( got_output )
ist -> next_pts += duration ; //FIXME the duration is not correct in some cases
2011-11-23 04:02:17 +01:00
break ;
case AVMEDIA_TYPE_SUBTITLE :
ret = transcode_subtitles ( ist , & avpkt , & got_output );
break ;
default :
return - 1 ;
2007-03-12 14:35:36 +00:00
}
2003-12-15 14:43:44 +00:00
2011-09-28 01:31:38 +02:00
if ( ret < 0 )
return ret ;
2011-12-13 19:46:29 +01:00
avpkt . dts =
avpkt . pts = AV_NOPTS_VALUE ;
2011-11-24 02:08:21 +01:00
// touch data and size only if not EOF
if ( pkt ) {
if ( ist -> st -> codec -> codec_type != AVMEDIA_TYPE_AUDIO )
ret = avpkt . size ;
avpkt . data += ret ;
avpkt . size -= ret ;
2010-05-07 09:43:21 +00:00
}
2011-11-23 04:02:17 +01:00
if ( ! got_output ) {
2011-11-24 02:08:21 +01:00
continue ;
2007-03-12 14:35:36 +00:00
}
}
2005-12-17 18:14:38 +00:00
2011-11-23 04:02:17 +01:00
/* handle stream copy */
if ( ! ist -> decoding_needed ) {
rate_emu_sleep ( ist );
2012-02-08 07:56:53 +01:00
ist -> dts = ist -> next_dts ;
2011-11-23 04:02:17 +01:00
switch ( ist -> st -> codec -> codec_type ) {
case AVMEDIA_TYPE_AUDIO :
2012-02-08 07:56:53 +01:00
ist -> next_dts += (( int64_t ) AV_TIME_BASE * ist -> st -> codec -> frame_size ) /
2011-11-23 04:02:17 +01:00
ist -> st -> codec -> sample_rate ;
break ;
case AVMEDIA_TYPE_VIDEO :
2011-12-03 15:03:49 +01:00
if ( pkt -> duration ) {
2012-02-08 07:56:53 +01:00
ist -> next_dts += av_rescale_q ( pkt -> duration , ist -> st -> time_base , AV_TIME_BASE_Q );
2011-12-03 15:03:49 +01:00
} else if ( ist -> st -> codec -> time_base . num != 0 ) {
2011-12-30 03:46:24 +01:00
int ticks = ist -> st -> parser ? ist -> st -> parser -> repeat_pict + 1 : ist -> st -> codec -> ticks_per_frame ;
2012-02-08 07:56:53 +01:00
ist -> next_dts += (( int64_t ) AV_TIME_BASE *
2011-11-23 04:02:17 +01:00
ist -> st -> codec -> time_base . num * ticks ) /
ist -> st -> codec -> time_base . den ;
2004-06-22 21:14:01 +00:00
}
2011-11-23 04:02:17 +01:00
break ;
2004-06-22 21:14:01 +00:00
}
2012-02-08 17:26:06 +01:00
ist -> pts = ist -> dts ;
ist -> next_pts = ist -> next_dts ;
2004-06-22 21:14:01 +00:00
}
2012-04-15 15:03:07 +02:00
for ( i = 0 ; pkt && i < nb_output_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
OutputStream * ost = output_streams [ i ];
2011-11-23 04:02:17 +01:00
if ( ! check_output_constraints ( ist , ost ) || ost -> encoding_needed )
continue ;
do_streamcopy ( ist , ost , pkt );
}
2005-12-17 18:14:38 +00:00
2003-12-15 14:43:44 +00:00
return 0 ;
}
2012-04-15 15:03:07 +02:00
static void print_sdp ( void )
2007-08-20 08:12:08 +00:00
{
2013-01-17 15:34:25 +02:00
char sdp [ 16384 ];
2011-08-30 14:19:39 +02:00
int i ;
2012-04-15 15:03:07 +02:00
AVFormatContext ** avc = av_malloc ( sizeof ( * avc ) * nb_output_files );
2011-08-30 14:19:39 +02:00
if ( ! avc )
2012-09-05 07:03:56 +00:00
exit ( 1 );
2012-04-15 15:03:07 +02:00
for ( i = 0 ; i < nb_output_files ; i ++ )
2012-04-15 15:28:30 +02:00
avc [ i ] = output_files [ i ] -> ctx ;
2007-08-20 08:12:08 +00:00
2012-04-15 15:03:07 +02:00
av_sdp_create ( avc , nb_output_files , sdp , sizeof ( sdp ));
2007-08-20 08:12:08 +00:00
printf ( "SDP: \n %s \n " , sdp );
2008-11-15 12:32:38 +00:00
fflush ( stdout );
2011-08-30 14:19:39 +02:00
av_freep ( & avc );
2007-08-20 08:12:08 +00:00
}
2003-12-15 14:43:44 +00:00
2012-04-15 15:03:07 +02:00
static int init_input_stream ( int ist_index , char * error , int error_len )
2011-08-30 15:53:55 +02:00
{
2012-10-22 14:39:12 +02:00
int ret ;
2012-04-15 15:28:30 +02:00
InputStream * ist = input_streams [ ist_index ];
2012-04-10 22:06:53 +02:00
2011-08-30 15:53:55 +02:00
if ( ist -> decoding_needed ) {
AVCodec * codec = ist -> dec ;
if ( ! codec ) {
2011-11-07 02:41:01 +01:00
snprintf ( error , error_len , "Decoder (codec %s) not found for input stream #%d:%d" ,
2011-08-30 15:53:55 +02:00
avcodec_get_name ( ist -> st -> codec -> codec_id ), ist -> file_index , ist -> st -> index );
return AVERROR ( EINVAL );
}
2011-12-26 05:50:25 +01:00
2013-01-21 21:10:18 +01:00
av_opt_set_int ( ist -> st -> codec , "refcounted_frames" , 1 , 0 );
2011-12-26 05:50:25 +01:00
2012-01-21 23:23:23 +01:00
if ( ! av_dict_get ( ist -> opts , "threads" , NULL , 0 ))
av_dict_set ( & ist -> opts , "threads" , "auto" , 0 );
2012-10-18 22:58:25 -06:00
if (( ret = avcodec_open2 ( ist -> st -> codec , codec , & ist -> opts )) < 0 ) {
if ( ret == AVERROR_EXPERIMENTAL )
abort_codec_experimental ( codec , 0 );
2011-11-07 02:41:01 +01:00
snprintf ( error , error_len , "Error while opening decoder for input stream #%d:%d" ,
2011-08-30 15:53:55 +02:00
ist -> file_index , ist -> st -> index );
2012-10-18 22:58:25 -06:00
return ret ;
2011-08-30 15:53:55 +02:00
}
assert_avoptions ( ist -> opts );
}
ist -> next_pts = AV_NOPTS_VALUE ;
2012-02-08 07:56:17 +01:00
ist -> next_dts = AV_NOPTS_VALUE ;
2011-08-30 15:53:55 +02:00
ist -> is_start = 1 ;
return 0 ;
}
2012-04-01 15:08:33 +02:00
static InputStream * get_input_stream ( OutputStream * ost )
{
if ( ost -> source_index >= 0 )
return input_streams [ ost -> source_index ];
return NULL ;
}
2013-01-02 19:08:08 +01:00
static int compare_int64 ( const void * a , const void * b )
{
int64_t va = * ( int64_t * ) a , vb = * ( int64_t * ) b ;
return va < vb ? - 1 : va > vb ? + 1 : 0 ;
}
2012-06-22 14:36:27 +02:00
static void parse_forced_key_frames ( char * kf , OutputStream * ost ,
AVCodecContext * avctx )
{
char * p ;
2013-01-02 19:08:08 +01:00
int n = 1 , i , size , index = 0 ;
int64_t t , * pts ;
2012-06-22 14:36:27 +02:00
for ( p = kf ; * p ; p ++ )
if ( * p == ',' )
n ++ ;
2013-01-02 19:08:08 +01:00
size = n ;
pts = av_malloc ( sizeof ( * pts ) * size );
if ( ! pts ) {
2012-06-22 14:36:27 +02:00
av_log ( NULL , AV_LOG_FATAL , "Could not allocate forced key frames array. \n " );
2012-09-05 07:03:56 +00:00
exit ( 1 );
2012-06-22 14:36:27 +02:00
}
2012-04-30 22:48:42 +02:00
2012-06-30 12:09:24 +02:00
p = kf ;
2012-06-22 14:36:27 +02:00
for ( i = 0 ; i < n ; i ++ ) {
2012-06-30 12:09:24 +02:00
char * next = strchr ( p , ',' );
2012-04-30 22:48:42 +02:00
if ( next )
* next ++ = 0 ;
2013-01-02 19:08:08 +01:00
if ( ! memcmp ( p , "chapters" , 8 )) {
AVFormatContext * avf = output_files [ ost -> file_index ] -> ctx ;
int j ;
if ( avf -> nb_chapters > INT_MAX - size ||
! ( pts = av_realloc_f ( pts , size += avf -> nb_chapters - 1 ,
sizeof ( * pts )))) {
av_log ( NULL , AV_LOG_FATAL ,
"Could not allocate forced key frames array. \n " );
exit ( 1 );
}
t = p [ 8 ] ? parse_time_or_die ( "force_key_frames" , p + 8 , 1 ) : 0 ;
t = av_rescale_q ( t , AV_TIME_BASE_Q , avctx -> time_base );
for ( j = 0 ; j < avf -> nb_chapters ; j ++ ) {
AVChapter * c = avf -> chapters [ j ];
av_assert1 ( index < size );
pts [ index ++ ] = av_rescale_q ( c -> start , c -> time_base ,
avctx -> time_base ) + t ;
}
} else {
t = parse_time_or_die ( "force_key_frames" , p , 1 );
av_assert1 ( index < size );
pts [ index ++ ] = av_rescale_q ( t , AV_TIME_BASE_Q , avctx -> time_base );
}
2012-04-30 22:48:42 +02:00
2012-06-30 12:09:24 +02:00
p = next ;
2012-06-22 14:36:27 +02:00
}
2013-01-02 19:08:08 +01:00
av_assert0 ( index == size );
qsort ( pts , size , sizeof ( * pts ), compare_int64 );
ost -> forced_kf_count = size ;
ost -> forced_kf_pts = pts ;
2012-06-22 14:36:27 +02:00
}
2012-07-25 17:46:00 +02:00
static void report_new_stream ( int input_index , AVPacket * pkt )
{
InputFile * file = input_files [ input_index ];
AVStream * st = file -> ctx -> streams [ pkt -> stream_index ];
if ( pkt -> stream_index < file -> nb_streams_warn )
return ;
av_log ( file -> ctx , AV_LOG_WARNING ,
"New %s stream %d:%d at pos:%" PRId64 " and DTS:%ss \n " ,
av_get_media_type_string ( st -> codec -> codec_type ),
input_index , pkt -> stream_index ,
pkt -> pos , av_ts2timestr ( pkt -> dts , & st -> time_base ));
file -> nb_streams_warn = pkt -> stream_index + 1 ;
}
2012-04-15 15:03:07 +02:00
static int transcode_init ( void )
2001-07-22 14:37:44 +00:00
{
2011-09-11 23:35:35 +02:00
int ret = 0 , i , j , k ;
2011-11-22 02:54:50 +01:00
AVFormatContext * oc ;
2012-08-05 08:30:24 +02:00
AVCodecContext * codec ;
2011-08-30 15:03:53 +02:00
OutputStream * ost ;
2011-06-23 19:14:08 +02:00
InputStream * ist ;
2009-03-11 06:06:18 +00:00
char error [ 1024 ];
2007-08-20 08:12:08 +00:00
int want_sdp = 1 ;
2011-08-30 15:08:02 +02:00
2011-09-05 22:10:26 +02:00
/* init framerate emulation */
for ( i = 0 ; i < nb_input_files ; i ++ ) {
2012-04-15 15:28:30 +02:00
InputFile * ifile = input_files [ i ];
2011-09-05 22:10:26 +02:00
if ( ifile -> rate_emu )
for ( j = 0 ; j < ifile -> nb_streams ; j ++ )
2012-04-15 15:28:30 +02:00
input_streams [ j + ifile -> ist_index ] -> start = av_gettime ();
2011-09-05 22:10:26 +02:00
}
2001-07-22 14:37:44 +00:00
/* output stream init */
2011-11-22 02:54:50 +01:00
for ( i = 0 ; i < nb_output_files ; i ++ ) {
2012-04-15 15:28:30 +02:00
oc = output_files [ i ] -> ctx ;
2011-11-22 02:54:50 +01:00
if ( ! oc -> nb_streams && ! ( oc -> oformat -> flags & AVFMT_NOSTREAMS )) {
av_dump_format ( oc , i , oc -> filename , 1 );
2011-09-27 02:14:37 +02:00
av_log ( NULL , AV_LOG_ERROR , "Output file #%d does not contain any stream \n " , i );
2011-08-30 16:03:51 +02:00
return AVERROR ( EINVAL );
2006-11-05 20:08:26 +00:00
}
2001-07-22 14:37:44 +00:00
}
2012-04-01 15:08:33 +02:00
/* init complex filtergraphs */
for ( i = 0 ; i < nb_filtergraphs ; i ++ )
if (( ret = avfilter_graph_config ( filtergraphs [ i ] -> graph , NULL )) < 0 )
return ret ;
2001-07-22 14:37:44 +00:00
/* for each output stream, we compute the right encoding parameters */
2011-08-30 15:03:53 +02:00
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
2012-08-05 08:30:24 +02:00
AVCodecContext * icodec = NULL ;
2012-04-15 15:28:30 +02:00
ost = output_streams [ i ];
oc = output_files [ ost -> file_index ] -> ctx ;
2012-04-01 15:08:33 +02:00
ist = get_input_stream ( ost );
2001-07-22 14:37:44 +00:00
2011-11-04 01:44:06 +01:00
if ( ost -> attachment_filename )
continue ;
2011-11-22 02:54:50 +01:00
codec = ost -> st -> codec ;
2001-07-22 14:37:44 +00:00
2012-04-01 15:08:33 +02:00
if ( ist ) {
icodec = ist -> st -> codec ;
ost -> st -> disposition = ist -> st -> disposition ;
codec -> bits_per_raw_sample = icodec -> bits_per_raw_sample ;
codec -> chroma_sample_location = icodec -> chroma_sample_location ;
}
2008-03-07 19:25:09 +00:00
2011-10-26 02:09:31 +02:00
if ( ost -> stream_copy ) {
2012-04-21 07:03:06 +02:00
uint64_t extra_size ;
av_assert0 ( ist && ! ost -> filter );
extra_size = ( uint64_t ) icodec -> extradata_size + FF_INPUT_BUFFER_PADDING_SIZE ;
2010-06-08 19:27:29 +00:00
2011-08-30 15:57:50 +02:00
if ( extra_size > INT_MAX ) {
2011-08-30 16:03:51 +02:00
return AVERROR ( EINVAL );
2011-08-30 15:57:50 +02:00
}
2010-06-08 19:27:29 +00:00
2002-10-11 09:19:34 +00:00
/* if stream_copy is selected, no need to decode or encode */
2011-11-22 02:54:50 +01:00
codec -> codec_id = icodec -> codec_id ;
2002-10-11 09:19:34 +00:00
codec -> codec_type = icodec -> codec_type ;
2007-08-04 16:03:39 +00:00
2011-11-22 02:54:50 +01:00
if ( ! codec -> codec_tag ) {
2013-01-17 20:46:21 +01:00
unsigned int codec_tag ;
2011-11-22 02:54:50 +01:00
if ( ! oc -> oformat -> codec_tag ||
av_codec_get_id ( oc -> oformat -> codec_tag , icodec -> codec_tag ) == codec -> codec_id ||
2013-01-17 20:46:21 +01:00
! av_codec_get_tag2 ( oc -> oformat -> codec_tag , icodec -> codec_id , & codec_tag ))
2007-08-04 16:03:39 +00:00
codec -> codec_tag = icodec -> codec_tag ;
}
2011-11-22 02:54:50 +01:00
codec -> bit_rate = icodec -> bit_rate ;
2010-10-07 01:57:35 +00:00
codec -> rc_max_rate = icodec -> rc_max_rate ;
codec -> rc_buffer_size = icodec -> rc_buffer_size ;
2011-12-23 03:00:12 +01:00
codec -> field_order = icodec -> field_order ;
2011-11-22 02:54:50 +01:00
codec -> extradata = av_mallocz ( extra_size );
2011-08-30 15:57:50 +02:00
if ( ! codec -> extradata ) {
2011-08-30 16:03:51 +02:00
return AVERROR ( ENOMEM );
2011-08-30 15:57:50 +02:00
}
2010-06-08 19:27:29 +00:00
memcpy ( codec -> extradata , icodec -> extradata , icodec -> extradata_size );
2005-03-24 01:47:45 +00:00
codec -> extradata_size = icodec -> extradata_size ;
2012-05-12 21:09:32 +02:00
codec -> bits_per_coded_sample = icodec -> bits_per_coded_sample ;
2011-07-25 20:48:55 +02:00
codec -> time_base = ist -> st -> time_base ;
2012-02-05 05:14:26 +01:00
/*
* Avi is a special case here because it supports variable fps but
* having the fps and timebase differe significantly adds quite some
* overhead
*/
2011-11-22 02:54:50 +01:00
if ( ! strcmp ( oc -> oformat -> name , "avi" )) {
2012-07-28 17:43:14 +02:00
if ( copy_tb < 0 && av_q2d ( ist -> st -> r_frame_rate ) >= av_q2d ( ist -> st -> avg_frame_rate )
&& 0.5 / av_q2d ( ist -> st -> r_frame_rate ) > av_q2d ( ist -> st -> time_base )
&& 0.5 / av_q2d ( ist -> st -> r_frame_rate ) > av_q2d ( icodec -> time_base )
&& av_q2d ( ist -> st -> time_base ) < 1.0 / 500 && av_q2d ( icodec -> time_base ) < 1.0 / 500
|| copy_tb == 2 ){
codec -> time_base . num = ist -> st -> r_frame_rate . den ;
codec -> time_base . den = 2 * ist -> st -> r_frame_rate . num ;
codec -> ticks_per_frame = 2 ;
} else if ( copy_tb < 0 && av_q2d ( icodec -> time_base ) * icodec -> ticks_per_frame > 2 * av_q2d ( ist -> st -> time_base )
2011-12-01 03:06:16 +01:00
&& av_q2d ( ist -> st -> time_base ) < 1.0 / 500
|| copy_tb == 0 ){
2011-07-25 20:48:55 +02:00
codec -> time_base = icodec -> time_base ;
codec -> time_base . num *= icodec -> ticks_per_frame ;
codec -> time_base . den *= 2 ;
2012-04-12 12:57:22 +02:00
codec -> ticks_per_frame = 2 ;
2011-07-25 20:48:55 +02:00
}
2011-12-05 03:19:28 +01:00
} else if ( ! ( oc -> oformat -> flags & AVFMT_VARIABLE_FPS )
&& strcmp ( oc -> oformat -> name , "mov" ) && strcmp ( oc -> oformat -> name , "mp4" ) && strcmp ( oc -> oformat -> name , "3gp" )
&& strcmp ( oc -> oformat -> name , "3g2" ) && strcmp ( oc -> oformat -> name , "psp" ) && strcmp ( oc -> oformat -> name , "ipod" )
2012-09-21 15:57:09 +02:00
&& strcmp ( oc -> oformat -> name , "f4v" )
2011-12-05 03:19:28 +01:00
) {
2012-09-10 20:52:40 +02:00
if ( copy_tb < 0 && icodec -> time_base . den
&& av_q2d ( icodec -> time_base ) * icodec -> ticks_per_frame > av_q2d ( ist -> st -> time_base )
2011-12-01 03:06:16 +01:00
&& av_q2d ( ist -> st -> time_base ) < 1.0 / 500
|| copy_tb == 0 ){
2011-07-25 20:48:55 +02:00
codec -> time_base = icodec -> time_base ;
codec -> time_base . num *= icodec -> ticks_per_frame ;
}
}
2013-01-17 18:49:46 +01:00
if ( codec -> codec_tag == AV_RL32 ( "tmcd" )
&& icodec -> time_base . num < icodec -> time_base . den
&& icodec -> time_base . num > 0
&& 121LL * icodec -> time_base . num > icodec -> time_base . den ) {
codec -> time_base = icodec -> time_base ;
}
2012-06-11 03:00:28 +02:00
if ( ost -> frame_rate . num )
2012-08-05 23:25:27 +02:00
codec -> time_base = av_inv_q ( ost -> frame_rate );
2012-06-11 03:00:28 +02:00
2011-07-25 20:48:55 +02:00
av_reduce ( & codec -> time_base . num , & codec -> time_base . den ,
codec -> time_base . num , codec -> time_base . den , INT_MAX );
2011-12-30 03:46:24 +01:00
switch ( codec -> codec_type ) {
2010-03-30 23:30:55 +00:00
case AVMEDIA_TYPE_AUDIO :
2011-12-30 03:46:24 +01:00
if ( audio_volume != 256 ) {
2011-09-27 02:14:37 +02:00
av_log ( NULL , AV_LOG_FATAL , "-acodec copy and -vol are incompatible (frames are not decoded) \n " );
2012-09-05 07:03:56 +00:00
exit ( 1 );
2008-07-12 11:43:21 +00:00
}
2011-11-22 02:54:50 +01:00
codec -> channel_layout = icodec -> channel_layout ;
codec -> sample_rate = icodec -> sample_rate ;
codec -> channels = icodec -> channels ;
codec -> frame_size = icodec -> frame_size ;
2011-03-24 12:00:21 -04:00
codec -> audio_service_type = icodec -> audio_service_type ;
2011-11-22 02:54:50 +01:00
codec -> block_align = icodec -> block_align ;
2013-02-12 00:32:16 +01:00
if (( codec -> block_align == 1 || codec -> block_align == 1152 || codec -> block_align == 576 ) && codec -> codec_id == AV_CODEC_ID_MP3 )
2012-05-14 15:15:11 +02:00
codec -> block_align = 0 ;
2012-08-07 22:45:46 +02:00
if ( codec -> codec_id == AV_CODEC_ID_AC3 )
2012-05-14 15:15:11 +02:00
codec -> block_align = 0 ;
2002-10-11 09:19:34 +00:00
break ;
2010-03-30 23:30:55 +00:00
case AVMEDIA_TYPE_VIDEO :
2011-11-22 02:54:50 +01:00
codec -> pix_fmt = icodec -> pix_fmt ;
codec -> width = icodec -> width ;
codec -> height = icodec -> height ;
codec -> has_b_frames = icodec -> has_b_frames ;
2011-04-16 16:47:24 -07:00
if ( ! codec -> sample_aspect_ratio . num ) {
2011-11-22 02:54:50 +01:00
codec -> sample_aspect_ratio =
2011-04-16 16:47:24 -07:00
ost -> st -> sample_aspect_ratio =
ist -> st -> sample_aspect_ratio . num ? ist -> st -> sample_aspect_ratio :
ist -> st -> codec -> sample_aspect_ratio . num ?
ist -> st -> codec -> sample_aspect_ratio : ( AVRational ){ 0 , 1 };
}
2011-11-05 23:43:01 +01:00
ost -> st -> avg_frame_rate = ist -> st -> avg_frame_rate ;
2002-10-11 09:19:34 +00:00
break ;
2010-03-30 23:30:55 +00:00
case AVMEDIA_TYPE_SUBTITLE :
2011-11-22 02:54:50 +01:00
codec -> width = icodec -> width ;
2009-01-17 23:54:27 +00:00
codec -> height = icodec -> height ;
2005-06-03 14:31:45 +00:00
break ;
2011-04-14 13:32:36 +02:00
case AVMEDIA_TYPE_DATA :
2011-09-28 01:31:38 +02:00
case AVMEDIA_TYPE_ATTACHMENT :
2011-04-14 13:32:36 +02:00
break ;
2002-10-11 09:19:34 +00:00
default :
2007-07-02 07:43:23 +00:00
abort ();
2002-10-11 09:19:34 +00:00
}
} else {
2011-06-16 06:24:54 +02:00
if ( ! ost -> enc )
2012-02-12 11:50:01 +01:00
ost -> enc = avcodec_find_encoder ( codec -> codec_id );
2012-04-20 15:17:38 +02:00
if ( ! ost -> enc ) {
2012-04-18 06:53:11 +02:00
/* should only happen when a default codec is not present. */
2012-04-20 15:17:38 +02:00
snprintf ( error , sizeof ( error ), "Encoder (codec %s) not found for output stream #%d:%d" ,
avcodec_get_name ( ost -> st -> codec -> codec_id ), ost -> file_index , ost -> index );
ret = AVERROR ( EINVAL );
goto dump_format ;
}
2011-11-22 02:54:50 +01:00
2012-04-01 15:08:33 +02:00
if ( ist )
2012-08-19 23:59:41 +02:00
ist -> decoding_needed ++ ;
2011-10-10 03:41:49 +02:00
ost -> encoding_needed = 1 ;
2011-11-22 02:54:50 +01:00
2012-07-30 05:15:10 +02:00
if ( ! ost -> filter &&
( codec -> codec_type == AVMEDIA_TYPE_VIDEO ||
codec -> codec_type == AVMEDIA_TYPE_AUDIO )) {
FilterGraph * fg ;
fg = init_simple_filtergraph ( ist , ost );
if ( configure_filtergraph ( fg )) {
av_log ( NULL , AV_LOG_FATAL , "Error opening filters! \n " );
exit ( 1 );
}
}
2012-05-20 11:55:25 +02:00
if ( codec -> codec_type == AVMEDIA_TYPE_VIDEO ) {
2012-06-05 12:43:33 +02:00
if ( ost -> filter && ! ost -> frame_rate . num )
ost -> frame_rate = av_buffersink_get_frame_rate ( ost -> filter -> filter );
2012-08-26 22:36:13 +02:00
if ( ist && ! ost -> frame_rate . num )
ost -> frame_rate = ist -> framerate ;
2012-05-20 11:55:25 +02:00
if ( ist && ! ost -> frame_rate . num )
ost -> frame_rate = ist -> st -> r_frame_rate . num ? ist -> st -> r_frame_rate : ( AVRational ){ 25 , 1 };
2012-07-30 00:56:33 +02:00
// ost->frame_rate = ist->st->avg_frame_rate.num ? ist->st->avg_frame_rate : (AVRational){25, 1};
2012-05-20 11:55:25 +02:00
if ( ost -> enc && ost -> enc -> supported_framerates && ! ost -> force_fps ) {
int idx = av_find_nearest_q_idx ( ost -> frame_rate , ost -> enc -> supported_framerates );
ost -> frame_rate = ost -> enc -> supported_framerates [ idx ];
}
}
2012-05-05 18:22:46 +02:00
switch ( codec -> codec_type ) {
case AVMEDIA_TYPE_AUDIO :
codec -> sample_fmt = ost -> filter -> filter -> inputs [ 0 ] -> format ;
codec -> sample_rate = ost -> filter -> filter -> inputs [ 0 ] -> sample_rate ;
codec -> channel_layout = ost -> filter -> filter -> inputs [ 0 ] -> channel_layout ;
2012-12-26 16:53:02 +01:00
codec -> channels = avfilter_link_get_channels ( ost -> filter -> filter -> inputs [ 0 ]);
2012-05-05 18:22:46 +02:00
codec -> time_base = ( AVRational ){ 1 , codec -> sample_rate };
break ;
case AVMEDIA_TYPE_VIDEO :
2012-08-05 23:25:27 +02:00
codec -> time_base = av_inv_q ( ost -> frame_rate );
2012-05-23 14:31:30 +02:00
if ( ost -> filter && ! ( codec -> time_base . num && codec -> time_base . den ))
codec -> time_base = ost -> filter -> filter -> inputs [ 0 ] -> time_base ;
2012-01-28 19:48:17 +01:00
if ( av_q2d ( codec -> time_base ) < 0.001 && video_sync_method != VSYNC_PASSTHROUGH
&& ( video_sync_method == VSYNC_CFR || ( video_sync_method == VSYNC_AUTO && ! ( oc -> oformat -> flags & AVFMT_VARIABLE_FPS )))){
2012-04-04 11:50:16 +02:00
av_log ( oc , AV_LOG_WARNING , "Frame rate very high for a muxer not efficiently supporting it. \n "
"Please consider specifying a lower framerate, a different muxer or -vsync 2 \n " );
2011-06-20 20:13:26 +02:00
}
2011-10-05 14:01:46 +02:00
for ( j = 0 ; j < ost -> forced_kf_count ; j ++ )
ost -> forced_kf_pts [ j ] = av_rescale_q ( ost -> forced_kf_pts [ j ],
AV_TIME_BASE_Q ,
codec -> time_base );
2011-06-15 08:00:03 +02:00
2012-04-01 15:08:33 +02:00
codec -> width = ost -> filter -> filter -> inputs [ 0 ] -> w ;
codec -> height = ost -> filter -> filter -> inputs [ 0 ] -> h ;
codec -> sample_aspect_ratio = ost -> st -> sample_aspect_ratio =
ost -> frame_aspect_ratio ? // overridden by the -aspect cli option
av_d2q ( ost -> frame_aspect_ratio * codec -> height / codec -> width , 255 ) :
ost -> filter -> filter -> inputs [ 0 ] -> sample_aspect_ratio ;
2013-03-19 00:43:01 +01:00
if ( ! strncmp ( ost -> enc -> name , "libx264" , 7 ) &&
codec -> pix_fmt == AV_PIX_FMT_NONE &&
ost -> filter -> filter -> inputs [ 0 ] -> format != AV_PIX_FMT_YUV420P )
av_log ( NULL , AV_LOG_INFO ,
"No pixel format specified, %s for H.264 encoding chosen. \n "
"Use -pix_fmt yuv420p for compatibility with outdated media players. \n " ,
av_get_pix_fmt_name ( ost -> filter -> filter -> inputs [ 0 ] -> format ));
2012-04-01 15:08:33 +02:00
codec -> pix_fmt = ost -> filter -> filter -> inputs [ 0 ] -> format ;
2012-03-23 15:46:30 +01:00
2012-05-23 21:19:16 +02:00
if ( ! icodec ||
codec -> width != icodec -> width ||
2012-03-23 20:59:09 +01:00
codec -> height != icodec -> height ||
codec -> pix_fmt != icodec -> pix_fmt ) {
2012-04-17 04:01:17 +02:00
codec -> bits_per_raw_sample = frame_bits_per_raw_sample ;
2010-05-07 09:43:21 +00:00
}
2012-03-23 15:46:30 +01:00
2012-12-09 18:40:22 +01:00
if ( ost -> forced_keyframes ) {
if ( ! strncmp ( ost -> forced_keyframes , "expr:" , 5 )) {
ret = av_expr_parse ( & ost -> forced_keyframes_pexpr , ost -> forced_keyframes + 5 ,
forced_keyframes_const_names , NULL , NULL , NULL , NULL , 0 , NULL );
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_ERROR ,
"Invalid force_key_frames expression '%s' \n " , ost -> forced_keyframes + 5 );
return ret ;
}
ost -> forced_keyframes_expr_const_values [ FKF_N ] = 0 ;
ost -> forced_keyframes_expr_const_values [ FKF_N_FORCED ] = 0 ;
ost -> forced_keyframes_expr_const_values [ FKF_PREV_FORCED_N ] = NAN ;
ost -> forced_keyframes_expr_const_values [ FKF_PREV_FORCED_T ] = NAN ;
} else {
parse_forced_key_frames ( ost -> forced_keyframes , ost , ost -> st -> codec );
}
}
2002-10-11 09:19:34 +00:00
break ;
2010-03-30 23:30:55 +00:00
case AVMEDIA_TYPE_SUBTITLE :
2012-02-05 14:28:19 +01:00
codec -> time_base = ( AVRational ){ 1 , 1000 };
2012-08-09 11:55:22 +02:00
if ( ! codec -> width ) {
codec -> width = input_streams [ ost -> source_index ] -> st -> codec -> width ;
codec -> height = input_streams [ ost -> source_index ] -> st -> codec -> height ;
}
2005-06-03 14:31:45 +00:00
break ;
2002-10-11 09:19:34 +00:00
default :
2007-07-02 07:43:23 +00:00
abort ();
2005-06-03 14:31:45 +00:00
break ;
2001-07-22 14:37:44 +00:00
}
2002-10-11 09:19:34 +00:00
/* two pass mode */
2012-03-14 02:04:18 +01:00
if ( codec -> flags & ( CODEC_FLAG_PASS1 | CODEC_FLAG_PASS2 )) {
2002-10-11 09:19:34 +00:00
char logfilename [ 1024 ];
FILE * f ;
2005-12-17 18:14:38 +00:00
snprintf ( logfilename , sizeof ( logfilename ), "%s-%d.log" ,
2012-08-19 09:15:48 +02:00
ost -> logfile_prefix ? ost -> logfile_prefix :
DEFAULT_PASS_LOGFILENAME_PREFIX ,
2008-12-26 19:28:42 +00:00
i );
2012-03-12 17:42:57 +01:00
if ( ! strcmp ( ost -> enc -> name , "libx264" )) {
av_dict_set ( & ost -> opts , "stats" , logfilename , AV_DICT_DONT_OVERWRITE );
} else {
2012-03-14 02:04:18 +01:00
if ( codec -> flags & CODEC_FLAG_PASS2 ) {
2012-03-12 17:43:48 +01:00
char * logbuffer ;
size_t logbuffer_size ;
if ( cmdutils_read_file ( logfilename , & logbuffer , & logbuffer_size ) < 0 ) {
av_log ( NULL , AV_LOG_FATAL , "Error reading log file '%s' for pass-2 encoding \n " ,
2012-05-19 12:05:02 +02:00
logfilename );
2012-09-05 07:03:56 +00:00
exit ( 1 );
2012-03-12 17:43:48 +01:00
}
codec -> stats_in = logbuffer ;
2002-10-11 09:19:34 +00:00
}
2012-03-14 02:04:18 +01:00
if ( codec -> flags & CODEC_FLAG_PASS1 ) {
f = fopen ( logfilename , "wb" );
if ( ! f ) {
av_log ( NULL , AV_LOG_FATAL , "Cannot write log file '%s' for pass-1 encoding: %s \n " ,
logfilename , strerror ( errno ));
2012-10-02 19:43:01 +02:00
exit ( 1 );
2012-03-14 02:04:18 +01:00
}
ost -> logfile = f ;
2011-10-30 02:26:48 +01:00
}
}
2002-10-10 17:09:01 +00:00
}
}
2002-10-11 09:19:34 +00:00
}
2001-07-22 14:37:44 +00:00
/* open each encoder */
2011-08-30 15:03:53 +02:00
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
ost = output_streams [ i ];
2001-07-22 14:37:44 +00:00
if ( ost -> encoding_needed ) {
2011-11-22 02:54:50 +01:00
AVCodec * codec = ost -> enc ;
2012-04-01 15:08:33 +02:00
AVCodecContext * dec = NULL ;
if (( ist = get_input_stream ( ost )))
dec = ist -> st -> codec ;
if ( dec && dec -> subtitle_header ) {
2012-08-05 08:57:20 -07:00
/* ASS code assumes this buffer is null terminated so add extra byte. */
ost -> st -> codec -> subtitle_header = av_mallocz ( dec -> subtitle_header_size + 1 );
2010-11-13 13:57:49 +00:00
if ( ! ost -> st -> codec -> subtitle_header ) {
ret = AVERROR ( ENOMEM );
goto dump_format ;
}
memcpy ( ost -> st -> codec -> subtitle_header , dec -> subtitle_header , dec -> subtitle_header_size );
ost -> st -> codec -> subtitle_header_size = dec -> subtitle_header_size ;
}
2012-01-21 23:23:23 +01:00
if ( ! av_dict_get ( ost -> opts , "threads" , NULL , 0 ))
av_dict_set ( & ost -> opts , "threads" , "auto" , 0 );
2012-10-18 22:58:25 -06:00
if (( ret = avcodec_open2 ( ost -> st -> codec , codec , & ost -> opts )) < 0 ) {
if ( ret == AVERROR_EXPERIMENTAL )
abort_codec_experimental ( codec , 1 );
2011-11-07 02:41:01 +01:00
snprintf ( error , sizeof ( error ), "Error while opening encoder for output stream #%d:%d - maybe incorrect parameters such as bit_rate, rate, width or height" ,
2001-07-22 14:37:44 +00:00
ost -> file_index , ost -> index );
2009-03-11 06:06:18 +00:00
goto dump_format ;
2001-07-22 14:37:44 +00:00
}
2012-06-25 00:32:49 +02:00
if ( ost -> enc -> type == AVMEDIA_TYPE_AUDIO &&
! ( ost -> enc -> capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE ))
av_buffersink_set_frame_size ( ost -> filter -> filter ,
ost -> st -> codec -> frame_size );
2011-05-25 17:29:25 +02:00
assert_avoptions ( ost -> opts );
2011-07-14 09:38:36 +02:00
if ( ost -> st -> codec -> bit_rate && ost -> st -> codec -> bit_rate < 1000 )
av_log ( NULL , AV_LOG_WARNING , "The bitrate parameter is set too low."
2011-10-08 21:39:36 +02:00
" It takes bits/s as argument, not kbits/s \n " );
2005-07-17 22:24:36 +00:00
extra_size += ost -> st -> codec -> extradata_size ;
2011-09-11 23:35:35 +02:00
if ( ost -> st -> codec -> me_threshold )
2012-04-15 15:28:30 +02:00
input_streams [ ost -> source_index ] -> st -> codec -> debug |= FF_DEBUG_MV ;
2013-02-27 23:22:39 +02:00
} else {
av_opt_set_dict ( ost -> st -> codec , & ost -> opts );
2001-07-22 14:37:44 +00:00
}
}
2011-08-30 15:53:55 +02:00
/* init input streams */
for ( i = 0 ; i < nb_input_streams ; i ++ )
2013-03-08 02:46:46 +01:00
if (( ret = init_input_stream ( i , error , sizeof ( error ))) < 0 ) {
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
ost = output_streams [ i ];
avcodec_close ( ost -> st -> codec );
}
2011-08-30 15:53:55 +02:00
goto dump_format ;
2013-03-08 02:46:46 +01:00
}
2010-02-02 22:23:09 +00:00
2011-09-11 23:35:35 +02:00
/* discard unused programs */
for ( i = 0 ; i < nb_input_files ; i ++ ) {
2012-04-15 15:28:30 +02:00
InputFile * ifile = input_files [ i ];
2011-09-11 23:35:35 +02:00
for ( j = 0 ; j < ifile -> ctx -> nb_programs ; j ++ ) {
AVProgram * p = ifile -> ctx -> programs [ j ];
int discard = AVDISCARD_ALL ;
for ( k = 0 ; k < p -> nb_stream_indexes ; k ++ )
2012-04-15 15:28:30 +02:00
if ( ! input_streams [ ifile -> ist_index + p -> stream_index [ k ]] -> discard ) {
2011-09-11 23:35:35 +02:00
discard = AVDISCARD_DEFAULT ;
2011-04-24 16:48:42 -04:00
break ;
}
2011-09-11 23:35:35 +02:00
p -> discard = discard ;
2001-07-22 14:37:44 +00:00
}
}
/* open files and write file headers */
2011-08-30 14:19:39 +02:00
for ( i = 0 ; i < nb_output_files ; i ++ ) {
2012-04-15 15:28:30 +02:00
oc = output_files [ i ] -> ctx ;
2011-11-22 02:54:50 +01:00
oc -> interrupt_callback = int_cb ;
2012-05-26 00:55:56 +03:00
if (( ret = avformat_write_header ( oc , & output_files [ i ] -> opts )) < 0 ) {
char errbuf [ 128 ];
const char * errbuf_ptr = errbuf ;
if ( av_strerror ( ret , errbuf , sizeof ( errbuf )) < 0 )
errbuf_ptr = strerror ( AVUNERROR ( ret ));
snprintf ( error , sizeof ( error ), "Could not write header for output file #%d (incorrect codec parameters ?): %s" , i , errbuf_ptr );
2007-02-13 18:26:14 +00:00
ret = AVERROR ( EINVAL );
2009-03-11 06:06:18 +00:00
goto dump_format ;
2001-09-24 23:22:25 +00:00
}
2012-04-17 04:01:17 +02:00
// assert_avoptions(output_files[i]->opts);
2011-11-22 02:54:50 +01:00
if ( strcmp ( oc -> oformat -> name , "rtp" )) {
2007-08-20 08:12:08 +00:00
want_sdp = 0 ;
}
}
2009-03-11 06:06:18 +00:00
dump_format :
/* dump the file output parameters - cannot be done before in case
of stream copy */
2011-11-22 02:54:50 +01:00
for ( i = 0 ; i < nb_output_files ; i ++ ) {
2012-04-15 15:28:30 +02:00
av_dump_format ( output_files [ i ] -> ctx , i , output_files [ i ] -> ctx -> filename , 1 );
2009-03-11 06:06:18 +00:00
}
/* dump the stream mapping */
2011-09-27 02:14:37 +02:00
av_log ( NULL , AV_LOG_INFO , "Stream mapping: \n " );
2012-04-01 15:08:33 +02:00
for ( i = 0 ; i < nb_input_streams ; i ++ ) {
ist = input_streams [ i ];
for ( j = 0 ; j < ist -> nb_filters ; j ++ ) {
if ( ist -> filters [ j ] -> graph -> graph_desc ) {
av_log ( NULL , AV_LOG_INFO , " Stream #%d:%d (%s) -> %s" ,
ist -> file_index , ist -> st -> index , ist -> dec ? ist -> dec -> name : "?" ,
2012-05-26 13:31:54 +02:00
ist -> filters [ j ] -> name );
2012-04-01 15:08:33 +02:00
if ( nb_filtergraphs > 1 )
av_log ( NULL , AV_LOG_INFO , " (graph %d)" , ist -> filters [ j ] -> graph -> index );
av_log ( NULL , AV_LOG_INFO , " \n " );
}
}
}
2011-09-27 02:14:37 +02:00
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
ost = output_streams [ i ];
2011-11-04 01:44:06 +01:00
if ( ost -> attachment_filename ) {
/* an attached file */
av_log ( NULL , AV_LOG_INFO , " File %s -> Stream #%d:%d \n " ,
ost -> attachment_filename , ost -> file_index , ost -> index );
continue ;
2009-03-11 06:06:18 +00:00
}
2012-04-01 15:08:33 +02:00
if ( ost -> filter && ost -> filter -> graph -> graph_desc ) {
/* output from a complex graph */
2012-05-26 13:31:54 +02:00
av_log ( NULL , AV_LOG_INFO , " %s" , ost -> filter -> name );
2012-04-01 15:08:33 +02:00
if ( nb_filtergraphs > 1 )
av_log ( NULL , AV_LOG_INFO , " (graph %d)" , ost -> filter -> graph -> index );
av_log ( NULL , AV_LOG_INFO , " -> Stream #%d:%d (%s) \n " , ost -> file_index ,
ost -> index , ost -> enc ? ost -> enc -> name : "?" );
continue ;
}
2011-11-07 02:41:01 +01:00
av_log ( NULL , AV_LOG_INFO , " Stream #%d:%d -> #%d:%d" ,
2012-04-15 15:28:30 +02:00
input_streams [ ost -> source_index ] -> file_index ,
input_streams [ ost -> source_index ] -> st -> index ,
2011-09-27 02:14:37 +02:00
ost -> file_index ,
ost -> index );
2012-04-15 15:28:30 +02:00
if ( ost -> sync_ist != input_streams [ ost -> source_index ])
2011-11-07 02:41:01 +01:00
av_log ( NULL , AV_LOG_INFO , " [sync #%d:%d]" ,
2011-09-27 02:14:37 +02:00
ost -> sync_ist -> file_index ,
ost -> sync_ist -> st -> index );
2011-10-26 02:09:31 +02:00
if ( ost -> stream_copy )
2011-09-27 02:14:37 +02:00
av_log ( NULL , AV_LOG_INFO , " (copy)" );
else
2012-04-15 15:28:30 +02:00
av_log ( NULL , AV_LOG_INFO , " (%s -> %s)" , input_streams [ ost -> source_index ] -> dec ?
input_streams [ ost -> source_index ] -> dec -> name : "?" ,
2011-09-27 02:14:37 +02:00
ost -> enc ? ost -> enc -> name : "?" );
av_log ( NULL , AV_LOG_INFO , " \n " );
2009-03-11 06:06:18 +00:00
}
if ( ret ) {
2011-09-27 02:14:37 +02:00
av_log ( NULL , AV_LOG_ERROR , "%s \n " , error );
2011-08-30 16:03:51 +02:00
return ret ;
2009-03-11 06:06:18 +00:00
}
2007-08-20 08:12:08 +00:00
if ( want_sdp ) {
2012-04-15 15:03:07 +02:00
print_sdp ();
2001-07-22 14:37:44 +00:00
}
2011-08-30 16:03:51 +02:00
return 0 ;
}
2012-08-24 13:31:50 +02:00
/* Return 1 if there remain streams where more output is wanted, 0 otherwise. */
2012-06-01 10:44:11 +02:00
static int need_output ( void )
{
int i ;
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
OutputStream * ost = output_streams [ i ];
OutputFile * of = output_files [ ost -> file_index ];
AVFormatContext * os = output_files [ ost -> file_index ] -> ctx ;
2012-08-08 12:04:53 +02:00
if ( ost -> finished ||
2012-06-01 10:44:11 +02:00
( os -> pb && avio_tell ( os -> pb ) >= of -> limit_filesize ))
continue ;
2012-06-04 22:54:15 +02:00
if ( ost -> frame_number >= ost -> max_frames ) {
2012-06-01 10:44:11 +02:00
int j ;
for ( j = 0 ; j < of -> ctx -> nb_streams ; j ++ )
2012-08-20 11:08:34 +02:00
close_output_stream ( output_streams [ of -> ost_index + j ]);
2012-06-01 10:44:11 +02:00
continue ;
}
return 1 ;
}
return 0 ;
}
2012-07-21 22:54:08 +02:00
/**
2012-08-17 13:50:16 +02:00
* Select the output stream to process.
2012-07-21 22:54:08 +02:00
*
2012-08-17 13:50:16 +02:00
* @return selected output stream, or NULL if none available
2012-07-21 22:54:08 +02:00
*/
2012-08-17 13:50:16 +02:00
static OutputStream * choose_output ( void )
2012-07-21 22:54:08 +02:00
{
2012-08-17 13:50:16 +02:00
int i ;
int64_t opts_min = INT64_MAX ;
OutputStream * ost_min = NULL ;
2012-07-21 22:54:08 +02:00
2012-08-17 13:50:16 +02:00
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
OutputStream * ost = output_streams [ i ];
int64_t opts = av_rescale_q ( ost -> st -> cur_dts , ost -> st -> time_base ,
AV_TIME_BASE_Q );
if ( ! ost -> unavailable && ! ost -> finished && opts < opts_min ) {
opts_min = opts ;
ost_min = ost ;
2012-07-21 22:54:08 +02:00
}
}
2012-08-17 13:50:16 +02:00
return ost_min ;
2012-07-21 22:54:08 +02:00
}
2012-06-06 15:56:34 +02:00
static int check_keyboard_interaction ( int64_t cur_time )
{
int i , ret , key ;
static int64_t last_time ;
if ( received_nb_signals )
return AVERROR_EXIT ;
/* read_key() returns 0 on EOF */
if ( cur_time - last_time >= 100000 && ! run_as_daemon ){
key = read_key ();
last_time = cur_time ;
} else
key = - 1 ;
if ( key == 'q' )
return AVERROR_EXIT ;
if ( key == '+' ) av_log_set_level ( av_log_get_level () + 10 );
if ( key == '-' ) av_log_set_level ( av_log_get_level () - 10 );
if ( key == 's' ) qp_hist ^= 1 ;
if ( key == 'h' ){
if ( do_hex_dump ){
do_hex_dump = do_pkt_dump = 0 ;
} else if ( do_pkt_dump ){
do_hex_dump = 1 ;
} else
do_pkt_dump = 1 ;
av_log_set_level ( AV_LOG_DEBUG );
}
if ( key == 'c' || key == 'C' ){
char buf [ 4096 ], target [ 64 ], command [ 256 ], arg [ 256 ] = { 0 };
double time ;
int k , n = 0 ;
fprintf ( stderr , " \n Enter command: <target> <time> <command>[ <argument>] \n " );
i = 0 ;
while (( k = read_key ()) != '\n' && k != '\r' && i < sizeof ( buf ) - 1 )
if ( k > 0 )
buf [ i ++ ] = k ;
buf [ i ] = 0 ;
if ( k > 0 &&
( n = sscanf ( buf , "%63[^ ] %lf %255[^ ] %255[^ \n ]" , target , & time , command , arg )) >= 3 ) {
av_log ( NULL , AV_LOG_DEBUG , "Processing command target:%s time:%f command:%s arg:%s" ,
target , time , command , arg );
for ( i = 0 ; i < nb_filtergraphs ; i ++ ) {
FilterGraph * fg = filtergraphs [ i ];
if ( fg -> graph ) {
if ( time < 0 ) {
ret = avfilter_graph_send_command ( fg -> graph , target , command , arg , buf , sizeof ( buf ),
key == 'c' ? AVFILTER_CMD_FLAG_ONE : 0 );
fprintf ( stderr , "Command reply for stream %d: ret:%d res:%s \n " , i , ret , buf );
} else {
ret = avfilter_graph_queue_command ( fg -> graph , target , command , arg , 0 , time );
}
}
}
} else {
av_log ( NULL , AV_LOG_ERROR ,
"Parse error, at least 3 arguments were expected, "
"only %d given in string '%s' \n " , n , buf );
}
}
if ( key == 'd' || key == 'D' ){
int debug = 0 ;
if ( key == 'D' ) {
debug = input_streams [ 0 ] -> st -> codec -> debug << 1 ;
if ( ! debug ) debug = 1 ;
while ( debug & ( FF_DEBUG_DCT_COEFF | FF_DEBUG_VIS_QP | FF_DEBUG_VIS_MB_TYPE )) //unsupported, would just crash
debug += debug ;
} else
if ( scanf ( "%d" , & debug ) != 1 )
fprintf ( stderr , "error parsing debug value \n " );
for ( i = 0 ; i < nb_input_streams ; i ++ ) {
input_streams [ i ] -> st -> codec -> debug = debug ;
}
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
OutputStream * ost = output_streams [ i ];
ost -> st -> codec -> debug = debug ;
}
if ( debug ) av_log_set_level ( AV_LOG_DEBUG );
fprintf ( stderr , "debug=%d \n " , debug );
}
if ( key == '?' ){
fprintf ( stderr , "key function \n "
"? show this help \n "
"+ increase verbosity \n "
"- decrease verbosity \n "
"c Send command to filtergraph \n "
"D cycle through available debug modes \n "
"h dump packets/hex press to cycle through the 3 states \n "
"q quit \n "
"s Show QP histogram \n "
);
}
return 0 ;
}
2012-06-11 15:34:12 +02:00
#if HAVE_PTHREADS
2012-06-02 07:26:41 +02:00
static void * input_thread ( void * arg )
{
InputFile * f = arg ;
int ret = 0 ;
while ( ! transcoding_finished && ret >= 0 ) {
AVPacket pkt ;
ret = av_read_frame ( f -> ctx , & pkt );
if ( ret == AVERROR ( EAGAIN )) {
2012-06-21 20:31:44 +01:00
av_usleep ( 10000 );
2012-06-02 07:26:41 +02:00
ret = 0 ;
continue ;
} else if ( ret < 0 )
break ;
pthread_mutex_lock ( & f -> fifo_lock );
while ( ! av_fifo_space ( f -> fifo ))
pthread_cond_wait ( & f -> fifo_cond , & f -> fifo_lock );
av_dup_packet ( & pkt );
av_fifo_generic_write ( f -> fifo , & pkt , sizeof ( pkt ), NULL );
pthread_mutex_unlock ( & f -> fifo_lock );
}
f -> finished = 1 ;
return NULL ;
}
static void free_input_threads ( void )
{
int i ;
if ( nb_input_files == 1 )
return ;
transcoding_finished = 1 ;
for ( i = 0 ; i < nb_input_files ; i ++ ) {
InputFile * f = input_files [ i ];
AVPacket pkt ;
2012-06-13 13:33:42 +02:00
if ( ! f -> fifo || f -> joined )
2012-06-02 07:26:41 +02:00
continue ;
pthread_mutex_lock ( & f -> fifo_lock );
while ( av_fifo_size ( f -> fifo )) {
av_fifo_generic_read ( f -> fifo , & pkt , sizeof ( pkt ), NULL );
av_free_packet ( & pkt );
}
pthread_cond_signal ( & f -> fifo_cond );
pthread_mutex_unlock ( & f -> fifo_lock );
pthread_join ( f -> thread , NULL );
f -> joined = 1 ;
while ( av_fifo_size ( f -> fifo )) {
av_fifo_generic_read ( f -> fifo , & pkt , sizeof ( pkt ), NULL );
av_free_packet ( & pkt );
}
av_fifo_free ( f -> fifo );
}
}
static int init_input_threads ( void )
{
int i , ret ;
if ( nb_input_files == 1 )
return 0 ;
for ( i = 0 ; i < nb_input_files ; i ++ ) {
InputFile * f = input_files [ i ];
if ( ! ( f -> fifo = av_fifo_alloc ( 8 * sizeof ( AVPacket ))))
return AVERROR ( ENOMEM );
pthread_mutex_init ( & f -> fifo_lock , NULL );
pthread_cond_init ( & f -> fifo_cond , NULL );
if (( ret = pthread_create ( & f -> thread , NULL , input_thread , f )))
return AVERROR ( ret );
}
return 0 ;
}
static int get_input_packet_mt ( InputFile * f , AVPacket * pkt )
{
int ret = 0 ;
pthread_mutex_lock ( & f -> fifo_lock );
if ( av_fifo_size ( f -> fifo )) {
av_fifo_generic_read ( f -> fifo , pkt , sizeof ( * pkt ), NULL );
pthread_cond_signal ( & f -> fifo_cond );
} else {
if ( f -> finished )
ret = AVERROR_EOF ;
else
ret = AVERROR ( EAGAIN );
}
pthread_mutex_unlock ( & f -> fifo_lock );
return ret ;
}
#endif
static int get_input_packet ( InputFile * f , AVPacket * pkt )
{
2012-06-11 15:34:12 +02:00
#if HAVE_PTHREADS
2012-06-02 07:26:41 +02:00
if ( nb_input_files > 1 )
return get_input_packet_mt ( f , pkt );
#endif
return av_read_frame ( f -> ctx , pkt );
}
2012-08-04 12:04:02 +02:00
static int got_eagain ( void )
{
int i ;
2012-08-17 13:50:16 +02:00
for ( i = 0 ; i < nb_output_streams ; i ++ )
if ( output_streams [ i ] -> unavailable )
2012-08-04 12:04:02 +02:00
return 1 ;
return 0 ;
}
static void reset_eagain ( void )
{
int i ;
for ( i = 0 ; i < nb_input_files ; i ++ )
input_files [ i ] -> eagain = 0 ;
2012-08-17 13:50:16 +02:00
for ( i = 0 ; i < nb_output_streams ; i ++ )
output_streams [ i ] -> unavailable = 0 ;
}
2012-08-24 13:31:50 +02:00
/*
* Return
2012-08-09 18:04:17 +02:00
* - 0 -- one packet was read and processed
* - AVERROR(EAGAIN) -- no packets were available for selected file,
* this function should be called again
* - AVERROR_EOF -- this function should not be called again
*/
2012-08-17 13:50:16 +02:00
static int process_input ( int file_index )
2012-08-09 18:04:17 +02:00
{
2012-08-17 13:50:16 +02:00
InputFile * ifile = input_files [ file_index ];
2012-08-09 18:04:17 +02:00
AVFormatContext * is ;
InputStream * ist ;
AVPacket pkt ;
int ret , i , j ;
is = ifile -> ctx ;
ret = get_input_packet ( ifile , & pkt );
if ( ret == AVERROR ( EAGAIN )) {
ifile -> eagain = 1 ;
return ret ;
}
if ( ret < 0 ) {
if ( ret != AVERROR_EOF ) {
print_error ( is -> filename , ret );
if ( exit_on_error )
2012-09-05 07:03:56 +00:00
exit ( 1 );
2012-08-09 18:04:17 +02:00
}
ifile -> eof_reached = 1 ;
for ( i = 0 ; i < ifile -> nb_streams ; i ++ ) {
ist = input_streams [ ifile -> ist_index + i ];
if ( ist -> decoding_needed )
output_packet ( ist , NULL );
2012-08-17 13:50:16 +02:00
/* mark all outputs that don't go through lavfi as finished */
for ( j = 0 ; j < nb_output_streams ; j ++ ) {
OutputStream * ost = output_streams [ j ];
2012-08-04 18:35:27 +02:00
2012-08-17 13:50:16 +02:00
if ( ost -> source_index == ifile -> ist_index + i &&
( ost -> stream_copy || ost -> enc -> type == AVMEDIA_TYPE_SUBTITLE ))
close_output_stream ( ost );
2012-08-04 18:35:27 +02:00
}
}
2012-08-11 11:50:32 +02:00
return AVERROR ( EAGAIN );
2012-08-09 18:04:17 +02:00
}
reset_eagain ();
if ( do_pkt_dump ) {
av_pkt_dump_log2 ( NULL , AV_LOG_DEBUG , & pkt , do_hex_dump ,
is -> streams [ pkt . stream_index ]);
}
/* the following test is needed in case new streams appear
dynamically in stream : we ignore them */
if ( pkt . stream_index >= ifile -> nb_streams ) {
report_new_stream ( file_index , & pkt );
goto discard_packet ;
}
ist = input_streams [ ifile -> ist_index + pkt . stream_index ];
if ( ist -> discard )
goto discard_packet ;
2012-11-17 11:12:04 +01:00
if ( debug_ts ) {
av_log ( NULL , AV_LOG_INFO , "demuxer -> ist_index:%d type:%s "
2012-11-22 00:12:18 +01:00
"next_dts:%s next_dts_time:%s next_pts:%s next_pts_time:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s off:%s off_time:%s \n " ,
ifile -> ist_index + pkt . stream_index , av_get_media_type_string ( ist -> st -> codec -> codec_type ),
av_ts2str ( ist -> next_dts ), av_ts2timestr ( ist -> next_dts , & AV_TIME_BASE_Q ),
av_ts2str ( ist -> next_pts ), av_ts2timestr ( ist -> next_pts , & AV_TIME_BASE_Q ),
av_ts2str ( pkt . pts ), av_ts2timestr ( pkt . pts , & ist -> st -> time_base ),
av_ts2str ( pkt . dts ), av_ts2timestr ( pkt . dts , & ist -> st -> time_base ),
av_ts2str ( input_files [ ist -> file_index ] -> ts_offset ),
av_ts2timestr ( input_files [ ist -> file_index ] -> ts_offset , & AV_TIME_BASE_Q ));
2012-11-17 11:12:04 +01:00
}
2012-11-24 01:34:26 +01:00
if ( ! ist -> wrap_correction_done && is -> start_time != AV_NOPTS_VALUE && ist -> st -> pts_wrap_bits < 64 ){
2012-11-24 03:02:11 +01:00
int64_t stime , stime2 ;
2012-11-24 01:34:52 +01:00
// Correcting starttime based on the enabled streams
// FIXME this ideally should be done before the first use of starttime but we do not know which are the enabled streams at that point.
// so we instead do it here as part of discontinuity handling
if ( ist -> next_dts == AV_NOPTS_VALUE
&& ifile -> ts_offset == - is -> start_time
&& ( is -> iformat -> flags & AVFMT_TS_DISCONT )) {
int64_t new_start_time = INT64_MAX ;
for ( i = 0 ; i < is -> nb_streams ; i ++ ) {
AVStream * st = is -> streams [ i ];
if ( st -> discard == AVDISCARD_ALL || st -> start_time == AV_NOPTS_VALUE )
continue ;
new_start_time = FFMIN ( new_start_time , av_rescale_q ( st -> start_time , st -> time_base , AV_TIME_BASE_Q ));
}
if ( new_start_time > is -> start_time ) {
av_log ( is , AV_LOG_VERBOSE , "Correcting start time by %" PRId64 " \n " , new_start_time - is -> start_time );
ifile -> ts_offset = - new_start_time ;
}
}
2012-11-24 03:02:11 +01:00
stime = av_rescale_q ( is -> start_time , AV_TIME_BASE_Q , ist -> st -> time_base );
stime2 = stime + ( 1ULL << ist -> st -> pts_wrap_bits );
2012-08-09 18:04:17 +02:00
ist -> wrap_correction_done = 1 ;
2012-08-24 01:39:32 +02:00
if ( stime2 > stime && pkt . dts != AV_NOPTS_VALUE && pkt . dts > stime + ( 1LL << ( ist -> st -> pts_wrap_bits - 1 ))) {
pkt . dts -= 1ULL << ist -> st -> pts_wrap_bits ;
2012-08-09 18:04:17 +02:00
ist -> wrap_correction_done = 0 ;
}
2012-08-24 01:39:32 +02:00
if ( stime2 > stime && pkt . pts != AV_NOPTS_VALUE && pkt . pts > stime + ( 1LL << ( ist -> st -> pts_wrap_bits - 1 ))) {
pkt . pts -= 1ULL << ist -> st -> pts_wrap_bits ;
2012-08-09 18:04:17 +02:00
ist -> wrap_correction_done = 0 ;
}
}
if ( pkt . dts != AV_NOPTS_VALUE )
pkt . dts += av_rescale_q ( ifile -> ts_offset , AV_TIME_BASE_Q , ist -> st -> time_base );
if ( pkt . pts != AV_NOPTS_VALUE )
pkt . pts += av_rescale_q ( ifile -> ts_offset , AV_TIME_BASE_Q , ist -> st -> time_base );
if ( pkt . pts != AV_NOPTS_VALUE )
pkt . pts *= ist -> ts_scale ;
if ( pkt . dts != AV_NOPTS_VALUE )
pkt . dts *= ist -> ts_scale ;
2013-03-23 04:30:19 +01:00
if ( pkt . dts != AV_NOPTS_VALUE && ist -> next_dts == AV_NOPTS_VALUE && ! copy_ts
&& ( is -> iformat -> flags & AVFMT_TS_DISCONT ) && ifile -> last_ts != AV_NOPTS_VALUE ) {
int64_t pkt_dts = av_rescale_q ( pkt . dts , ist -> st -> time_base , AV_TIME_BASE_Q );
int64_t delta = pkt_dts - ifile -> last_ts ;
if ( delta < - 1LL * dts_delta_threshold * AV_TIME_BASE ||
( delta > 1LL * dts_delta_threshold * AV_TIME_BASE &&
ist -> st -> codec -> codec_type != AVMEDIA_TYPE_SUBTITLE )){
ifile -> ts_offset -= delta ;
av_log ( NULL , AV_LOG_DEBUG ,
"Inter stream timestamp discontinuity %" PRId64 ", new offset= %" PRId64 " \n " ,
delta , ifile -> ts_offset );
pkt . dts -= av_rescale_q ( delta , AV_TIME_BASE_Q , ist -> st -> time_base );
if ( pkt . pts != AV_NOPTS_VALUE )
pkt . pts -= av_rescale_q ( delta , AV_TIME_BASE_Q , ist -> st -> time_base );
}
}
2012-08-09 18:04:17 +02:00
if ( pkt . dts != AV_NOPTS_VALUE && ist -> next_dts != AV_NOPTS_VALUE &&
! copy_ts ) {
int64_t pkt_dts = av_rescale_q ( pkt . dts , ist -> st -> time_base , AV_TIME_BASE_Q );
int64_t delta = pkt_dts - ist -> next_dts ;
if ( is -> iformat -> flags & AVFMT_TS_DISCONT ) {
if ( delta < - 1LL * dts_delta_threshold * AV_TIME_BASE ||
( delta > 1LL * dts_delta_threshold * AV_TIME_BASE &&
ist -> st -> codec -> codec_type != AVMEDIA_TYPE_SUBTITLE ) ||
pkt_dts + 1 < ist -> pts ){
ifile -> ts_offset -= delta ;
av_log ( NULL , AV_LOG_DEBUG ,
"timestamp discontinuity %" PRId64 ", new offset= %" PRId64 " \n " ,
delta , ifile -> ts_offset );
pkt . dts -= av_rescale_q ( delta , AV_TIME_BASE_Q , ist -> st -> time_base );
if ( pkt . pts != AV_NOPTS_VALUE )
pkt . pts -= av_rescale_q ( delta , AV_TIME_BASE_Q , ist -> st -> time_base );
}
} else {
if ( delta < - 1LL * dts_error_threshold * AV_TIME_BASE ||
2012-08-11 23:38:48 +02:00
( delta > 1LL * dts_error_threshold * AV_TIME_BASE && ist -> st -> codec -> codec_type != AVMEDIA_TYPE_SUBTITLE )
) {
2012-08-09 18:04:17 +02:00
av_log ( NULL , AV_LOG_WARNING , "DTS %" PRId64 ", next:%" PRId64 " st:%d invalid dropping \n " , pkt . dts , ist -> next_dts , pkt . stream_index );
pkt . dts = AV_NOPTS_VALUE ;
}
if ( pkt . pts != AV_NOPTS_VALUE ){
int64_t pkt_pts = av_rescale_q ( pkt . pts , ist -> st -> time_base , AV_TIME_BASE_Q );
delta = pkt_pts - ist -> next_dts ;
if ( delta < - 1LL * dts_error_threshold * AV_TIME_BASE ||
2012-08-11 23:38:48 +02:00
( delta > 1LL * dts_error_threshold * AV_TIME_BASE && ist -> st -> codec -> codec_type != AVMEDIA_TYPE_SUBTITLE )
) {
2012-08-09 18:04:17 +02:00
av_log ( NULL , AV_LOG_WARNING , "PTS %" PRId64 ", next:%" PRId64 " invalid dropping st:%d \n " , pkt . pts , ist -> next_dts , pkt . stream_index );
pkt . pts = AV_NOPTS_VALUE ;
}
}
}
}
2013-03-23 04:30:19 +01:00
if ( pkt . dts != AV_NOPTS_VALUE )
ifile -> last_ts = av_rescale_q ( pkt . dts , ist -> st -> time_base , AV_TIME_BASE_Q );
2012-11-17 11:12:04 +01:00
if ( debug_ts ) {
2012-11-21 23:19:32 +01:00
av_log ( NULL , AV_LOG_INFO , "demuxer+ffmpeg -> ist_index:%d type:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s off:%s off_time:%s \n " ,
2012-11-22 00:12:18 +01:00
ifile -> ist_index + pkt . stream_index , av_get_media_type_string ( ist -> st -> codec -> codec_type ),
av_ts2str ( pkt . pts ), av_ts2timestr ( pkt . pts , & ist -> st -> time_base ),
av_ts2str ( pkt . dts ), av_ts2timestr ( pkt . dts , & ist -> st -> time_base ),
av_ts2str ( input_files [ ist -> file_index ] -> ts_offset ),
av_ts2timestr ( input_files [ ist -> file_index ] -> ts_offset , & AV_TIME_BASE_Q ));
2012-11-17 11:12:04 +01:00
}
2012-08-09 18:04:17 +02:00
sub2video_heartbeat ( ist , pkt . pts );
2012-08-17 13:50:16 +02:00
ret = output_packet ( ist , & pkt );
if ( ret < 0 ) {
2012-08-09 18:04:17 +02:00
char buf [ 128 ];
av_strerror ( ret , buf , sizeof ( buf ));
av_log ( NULL , AV_LOG_ERROR , "Error while decoding stream #%d:%d: %s \n " ,
ist -> file_index , ist -> st -> index , buf );
if ( exit_on_error )
2012-09-05 07:03:56 +00:00
exit ( 1 );
2012-08-09 18:04:17 +02:00
}
discard_packet :
av_free_packet ( & pkt );
return 0 ;
}
2012-08-17 13:50:16 +02:00
/**
* Perform a step of transcoding for the specified filter graph.
*
* @param[in] graph filter graph to consider
* @param[out] best_ist input stream where a frame would allow to continue
* @return 0 for success, <0 for error
*/
static int transcode_from_filter ( FilterGraph * graph , InputStream ** best_ist )
{
int i , ret ;
int nb_requests , nb_requests_max = 0 ;
InputFilter * ifilter ;
InputStream * ist ;
* best_ist = NULL ;
ret = avfilter_graph_request_oldest ( graph -> graph );
if ( ret >= 0 )
return reap_filters ();
if ( ret == AVERROR_EOF ) {
ret = reap_filters ();
for ( i = 0 ; i < graph -> nb_outputs ; i ++ )
close_output_stream ( graph -> outputs [ i ] -> ost );
return ret ;
}
if ( ret != AVERROR ( EAGAIN ))
return ret ;
for ( i = 0 ; i < graph -> nb_inputs ; i ++ ) {
ifilter = graph -> inputs [ i ];
ist = ifilter -> ist ;
if ( input_files [ ist -> file_index ] -> eagain ||
input_files [ ist -> file_index ] -> eof_reached )
continue ;
nb_requests = av_buffersrc_get_nb_failed_requests ( ifilter -> filter );
if ( nb_requests > nb_requests_max ) {
nb_requests_max = nb_requests ;
* best_ist = ist ;
}
}
if ( !* best_ist )
for ( i = 0 ; i < graph -> nb_outputs ; i ++ )
graph -> outputs [ i ] -> ost -> unavailable = 1 ;
return 0 ;
}
/**
* Run a single step of transcoding.
*
* @return 0 for success, <0 for error
*/
static int transcode_step ( void )
{
OutputStream * ost ;
InputStream * ist ;
int ret ;
ost = choose_output ();
if ( ! ost ) {
if ( got_eagain ()) {
reset_eagain ();
av_usleep ( 10000 );
return 0 ;
}
av_log ( NULL , AV_LOG_VERBOSE , "No more inputs to read from, finishing. \n " );
return AVERROR_EOF ;
}
if ( ost -> filter ) {
if (( ret = transcode_from_filter ( ost -> filter -> graph , & ist )) < 0 )
return ret ;
if ( ! ist )
return 0 ;
} else {
av_assert0 ( ost -> source_index >= 0 );
ist = input_streams [ ost -> source_index ];
}
ret = process_input ( ist -> file_index );
if ( ret == AVERROR ( EAGAIN )) {
if ( input_files [ ist -> file_index ] -> eagain )
ost -> unavailable = 1 ;
return 0 ;
}
if ( ret < 0 )
return ret == AVERROR_EOF ? 0 : ret ;
return reap_filters ();
}
2011-08-30 16:03:51 +02:00
/*
* The following code is the main loop of the file converter
*/
2012-04-15 15:03:07 +02:00
static int transcode ( void )
2011-08-30 16:03:51 +02:00
{
int ret , i ;
2012-08-09 18:04:17 +02:00
AVFormatContext * os ;
2011-08-30 16:03:51 +02:00
OutputStream * ost ;
InputStream * ist ;
int64_t timer_start ;
2012-04-15 15:03:07 +02:00
ret = transcode_init ();
2011-08-30 16:03:51 +02:00
if ( ret < 0 )
goto fail ;
2012-07-14 17:52:51 +02:00
if ( stdin_interaction ) {
2011-09-27 02:14:37 +02:00
av_log ( NULL , AV_LOG_INFO , "Press [q] to stop, [?] for help \n " );
2004-03-14 19:40:43 +00:00
}
2001-09-24 23:22:25 +00:00
2007-03-16 16:13:54 +00:00
timer_start = av_gettime ();
2002-05-09 01:06:59 +00:00
2012-06-11 15:34:12 +02:00
#if HAVE_PTHREADS
2012-06-02 07:26:41 +02:00
if (( ret = init_input_threads ()) < 0 )
goto fail ;
#endif
2012-08-04 12:06:30 +02:00
while ( ! received_sigterm ) {
2011-10-08 17:32:06 +02:00
int64_t cur_time = av_gettime ();
2004-06-29 22:56:54 +00:00
2001-09-24 23:22:25 +00:00
/* if 'q' pressed, exits */
2012-07-14 17:52:51 +02:00
if ( stdin_interaction )
2012-06-06 15:56:34 +02:00
if ( check_keyboard_interaction ( cur_time ) < 0 )
2004-03-14 19:40:43 +00:00
break ;
2001-09-24 23:22:25 +00:00
2012-04-01 15:08:33 +02:00
/* check if there's any stream where output is still needed */
2012-06-01 10:44:11 +02:00
if ( ! need_output ()) {
av_log ( NULL , AV_LOG_VERBOSE , "No more output streams to write to, finishing. \n " );
2012-04-01 15:08:33 +02:00
break ;
2001-07-22 14:37:44 +00:00
}
2012-04-01 15:08:33 +02:00
2012-08-17 13:50:16 +02:00
ret = transcode_step ();
2012-08-09 18:04:17 +02:00
if ( ret < 0 ) {
2012-08-17 13:50:16 +02:00
if ( ret == AVERROR_EOF || ret == AVERROR ( EAGAIN ))
2009-03-03 19:50:04 +00:00
continue ;
2012-08-17 13:50:16 +02:00
2012-08-09 18:04:17 +02:00
av_log ( NULL , AV_LOG_ERROR , "Error while filtering. \n " );
2002-10-21 17:42:47 +00:00
break ;
}
2005-12-17 18:14:38 +00:00
2002-10-21 17:42:47 +00:00
/* dump report by using the output first video and audio streams */
2012-04-17 04:01:17 +02:00
print_report ( 0 , timer_start , cur_time );
2001-07-22 14:37:44 +00:00
}
2012-06-11 15:34:12 +02:00
#if HAVE_PTHREADS
2012-06-02 07:26:41 +02:00
free_input_threads ();
#endif
2003-12-15 14:43:44 +00:00
/* at the end of stream, we must flush the decoder buffers */
2011-05-22 22:12:35 +02:00
for ( i = 0 ; i < nb_input_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
ist = input_streams [ i ];
2012-04-02 20:13:29 +02:00
if ( ! input_files [ ist -> file_index ] -> eof_reached && ist -> decoding_needed ) {
2012-04-15 15:03:07 +02:00
output_packet ( ist , NULL );
2003-12-15 14:43:44 +00:00
}
}
2012-04-15 15:03:07 +02:00
flush_encoders ();
2003-12-15 14:43:44 +00:00
2001-09-24 23:22:25 +00:00
term_exit ();
2001-07-22 14:37:44 +00:00
2004-03-05 22:51:22 +00:00
/* write the trailer if needed and close file */
2011-12-30 03:46:24 +01:00
for ( i = 0 ; i < nb_output_files ; i ++ ) {
2012-04-15 15:28:30 +02:00
os = output_files [ i ] -> ctx ;
2004-03-05 22:51:22 +00:00
av_write_trailer ( os );
}
2004-04-15 16:34:38 +00:00
/* dump report by using the first video and audio streams */
2012-04-17 04:01:17 +02:00
print_report ( 1 , timer_start , av_gettime ());
2004-04-15 16:34:38 +00:00
2001-07-22 14:37:44 +00:00
/* close each encoder */
2011-08-30 15:03:53 +02:00
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
ost = output_streams [ i ];
2001-07-22 14:37:44 +00:00
if ( ost -> encoding_needed ) {
2005-07-17 22:24:36 +00:00
av_freep ( & ost -> st -> codec -> stats_in );
avcodec_close ( ost -> st -> codec );
2001-07-22 14:37:44 +00:00
}
}
2005-12-17 18:14:38 +00:00
2001-07-22 14:37:44 +00:00
/* close each decoder */
2011-05-22 22:12:35 +02:00
for ( i = 0 ; i < nb_input_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
ist = input_streams [ i ];
2001-07-22 14:37:44 +00:00
if ( ist -> decoding_needed ) {
2005-07-17 22:24:36 +00:00
avcodec_close ( ist -> st -> codec );
2001-07-22 14:37:44 +00:00
}
}
/* finished ! */
2009-03-11 06:13:14 +00:00
ret = 0 ;
2005-12-17 18:14:38 +00:00
2009-03-11 06:06:18 +00:00
fail :
2012-06-11 15:34:12 +02:00
#if HAVE_PTHREADS
2012-06-02 07:26:41 +02:00
free_input_threads ();
#endif
2001-08-13 21:43:02 +00:00
2011-08-30 15:03:53 +02:00
if ( output_streams ) {
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
ost = output_streams [ i ];
2001-07-22 14:37:44 +00:00
if ( ost ) {
2011-10-26 02:09:31 +02:00
if ( ost -> stream_copy )
2010-06-08 19:27:29 +00:00
av_freep ( & ost -> st -> codec -> extradata );
2002-10-10 17:09:01 +00:00
if ( ost -> logfile ) {
fclose ( ost -> logfile );
ost -> logfile = NULL ;
}
2010-11-13 13:57:49 +00:00
av_freep ( & ost -> st -> codec -> subtitle_header );
2010-10-18 21:47:15 +00:00
av_free ( ost -> forced_kf_pts );
2011-05-25 17:29:25 +02:00
av_dict_free ( & ost -> opts );
2013-02-24 19:07:42 +01:00
av_dict_free ( & ost -> swr_opts );
2012-12-18 21:47:28 -05:00
av_dict_free ( & ost -> resample_opts );
2001-07-22 14:37:44 +00:00
}
}
}
return ret ;
}
2012-08-09 00:26:38 +02:00
2011-07-27 20:56:59 +02:00
static int64_t getutime ( void )
2002-09-01 07:19:38 +00:00
{
2011-07-27 20:56:59 +02:00
#if HAVE_GETRUSAGE
struct rusage rusage ;
getrusage ( RUSAGE_SELF , & rusage );
return ( rusage . ru_utime . tv_sec * 1000000LL ) + rusage . ru_utime . tv_usec ;
#elif HAVE_GETPROCESSTIMES
HANDLE proc ;
FILETIME c , e , k , u ;
proc = GetCurrentProcess ();
GetProcessTimes ( proc , & c , & e , & k , & u );
return (( int64_t ) u . dwHighDateTime << 32 | u . dwLowDateTime ) / 10 ;
#else
return av_gettime ();
#endif
2002-10-10 17:09:01 +00:00
}
2001-09-24 23:22:25 +00:00
2010-02-22 22:21:58 +00:00
static int64_t getmaxrss ( void )
{
#if HAVE_GETRUSAGE && HAVE_STRUCT_RUSAGE_RU_MAXRSS
struct rusage rusage ;
getrusage ( RUSAGE_SELF , & rusage );
return ( int64_t ) rusage . ru_maxrss * 1024 ;
#elif HAVE_GETPROCESSMEMORYINFO
HANDLE proc ;
PROCESS_MEMORY_COUNTERS memcounters ;
proc = GetCurrentProcess ();
memcounters . cb = sizeof ( memcounters );
GetProcessMemoryInfo ( proc , & memcounters , sizeof ( memcounters ));
return memcounters . PeakPagefileUsage ;
#else
return 0 ;
#endif
}
2011-09-12 11:44:14 +02:00
static void log_callback_null ( void * ptr , int level , const char * fmt , va_list vl )
2011-04-18 13:10:52 +02:00
{
}
2007-09-16 18:08:51 +00:00
int main ( int argc , char ** argv )
{
2012-06-08 21:35:16 +02:00
int ret ;
2007-09-16 18:08:51 +00:00
int64_t ti ;
2012-09-05 07:03:56 +00:00
atexit ( exit_program );
2012-09-30 15:02:03 +02:00
setvbuf ( stderr , NULL , _IONBF , 0 ); /* win32 runtime needs this */
2010-09-24 15:39:10 +00:00
av_log_set_flags ( AV_LOG_SKIP_REPEATED );
2011-09-26 08:15:37 +02:00
parse_loglevel ( argc , argv , options );
2010-09-24 15:39:10 +00:00
2011-04-18 13:10:52 +02:00
if ( argc > 1 && ! strcmp ( argv [ 1 ], "-d" )){
2011-04-22 18:49:44 +02:00
run_as_daemon = 1 ;
2011-04-18 13:10:52 +02:00
av_log_set_callback ( log_callback_null );
argc -- ;
argv ++ ;
}
2007-11-22 16:10:02 +00:00
avcodec_register_all ();
2010-04-22 08:55:23 +00:00
#if CONFIG_AVDEVICE
2007-11-22 16:10:02 +00:00
avdevice_register_all ();
2010-05-07 09:43:21 +00:00
#endif
avfilter_register_all ();
2007-09-16 18:08:51 +00:00
av_register_all ();
2011-11-06 02:47:48 +02:00
avformat_network_init ();
2007-09-16 18:08:51 +00:00
2011-12-20 22:03:25 +01:00
show_banner ( argc , argv , options );
2007-09-16 18:08:51 +00:00
2011-10-08 17:20:52 +02:00
term_init ();
2012-06-08 21:35:16 +02:00
/* parse options and open all input/output files */
2012-12-20 02:38:02 +01:00
ret = ffmpeg_parse_options ( argc , argv );
2012-06-08 21:35:16 +02:00
if ( ret < 0 )
exit ( 1 );
2007-09-16 18:08:51 +00:00
2011-12-30 03:46:24 +01:00
if ( nb_output_files <= 0 && nb_input_files == 0 ) {
2009-12-21 02:15:46 +00:00
show_usage ();
2011-09-27 02:14:37 +02:00
av_log ( NULL , AV_LOG_WARNING , "Use -h to get full help or, even better, run 'man %s' \n " , program_name );
2012-09-05 07:03:56 +00:00
exit ( 1 );
2009-12-21 02:15:46 +00:00
}
2009-12-13 13:49:14 +00:00
2007-09-16 18:08:51 +00:00
/* file converter / grab */
if ( nb_output_files <= 0 ) {
2011-09-27 02:14:37 +02:00
av_log ( NULL , AV_LOG_FATAL , "At least one output file must be specified \n " );
2012-09-05 07:03:56 +00:00
exit ( 1 );
2007-09-16 18:08:51 +00:00
}
2012-08-09 19:09:39 +02:00
// if (nb_input_files == 0) {
// av_log(NULL, AV_LOG_FATAL, "At least one input file must be specified\n");
2012-10-02 19:43:01 +02:00
// exit(1);
2012-08-09 19:09:39 +02:00
// }
2007-09-16 18:08:51 +00:00
2012-04-11 19:26:09 +02:00
current_time = ti = getutime ();
2012-04-15 15:03:07 +02:00
if ( transcode () < 0 )
2012-09-05 07:03:56 +00:00
exit ( 1 );
2007-09-16 18:08:51 +00:00
ti = getutime () - ti ;
if ( do_benchmark ) {
2013-03-02 16:04:49 +01:00
printf ( "bench: utime=%0.3fs \n " , ti / 1000000.0 );
2007-09-16 18:08:51 +00:00
}
2013-02-06 04:03:52 +01:00
exit ( received_nb_signals ? 255 : 0 );
2011-08-29 07:03:24 +02:00
return 0 ;
2007-09-16 18:08:51 +00:00
}