2011-07-27 20:56:59 +02:00
/*
* avconv main
* Copyright (c) 2000-2011 The libav developers.
*
* This file is part of Libav.
*
* Libav is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Libav is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <limits.h>
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
2012-04-05 14:06:28 -04:00
#include "libavresample/avresample.h"
2011-07-27 20:56:59 +02:00
#include "libavutil/opt.h"
2012-11-10 10:00:00 -05:00
#include "libavutil/channel_layout.h"
2011-07-27 20:56:59 +02:00
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/fifo.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/avstring.h"
#include "libavutil/libm.h"
2011-12-19 15:44:58 +01:00
#include "libavutil/imgutils.h"
2012-06-21 20:31:44 +01:00
#include "libavutil/time.h"
2011-07-27 20:56:59 +02:00
#include "libavformat/os_support.h"
# include "libavfilter/avfilter.h"
2011-12-21 21:04:05 +01:00
# include "libavfilter/buffersrc.h"
2012-04-27 06:56:56 +02:00
# include "libavfilter/buffersink.h"
2011-07-27 20:56:59 +02:00
#if HAVE_SYS_RESOURCE_H
2012-10-14 00:27:26 +01:00
#include <sys/time.h>
2011-07-27 20:56:59 +02:00
#include <sys/types.h>
#include <sys/resource.h>
#elif HAVE_GETPROCESSTIMES
#include <windows.h>
#endif
#if HAVE_GETPROCESSMEMORYINFO
#include <windows.h>
#include <psapi.h>
#endif
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
2012-06-02 07:26:41 +02:00
#if HAVE_PTHREADS
#include <pthread.h>
#endif
2011-07-27 20:56:59 +02:00
#include <time.h>
2012-08-01 18:23:12 +02:00
#include "avconv.h"
2011-07-27 20:56:59 +02:00
#include "cmdutils.h"
#include "libavutil/avassert.h"
const char program_name [] = "avconv" ;
const int program_birth_year = 2000 ;
static FILE * vstats_file ;
static int64_t video_size = 0 ;
static int64_t audio_size = 0 ;
static int64_t extra_size = 0 ;
static int nb_frames_dup = 0 ;
static int nb_frames_drop = 0 ;
2011-10-09 15:57:30 +02:00
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
2011-07-27 20:56:59 +02:00
#define DEFAULT_PASS_LOGFILENAME_PREFIX "av2pass"
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 ;
2012-04-01 15:08:33 +02:00
2012-08-01 18:23:12 +02:00
FilterGraph ** filtergraphs ;
int nb_filtergraphs ;
2011-08-28 17:21:56 +02:00
2011-07-27 20:56:59 +02:00
static void term_exit ( void )
{
av_log ( NULL , AV_LOG_QUIET , "" );
}
static volatile int received_sigterm = 0 ;
static volatile int received_nb_signals = 0 ;
static void
sigterm_handler ( int sig )
{
received_sigterm = sig ;
received_nb_signals ++ ;
term_exit ();
}
static void term_init ( void )
{
2011-12-30 01:58:29 +05:30
signal ( SIGINT , sigterm_handler ); /* Interrupt (ANSI). */
2011-07-27 20:56:59 +02:00
signal ( SIGTERM , sigterm_handler ); /* Termination (ANSI). */
#ifdef SIGXCPU
signal ( SIGXCPU , sigterm_handler );
#endif
}
2011-11-06 23:22:04 +02:00
static int decode_interrupt_cb ( void * ctx )
2011-07-27 20:56:59 +02:00
{
return received_nb_signals > 1 ;
}
2012-08-01 18:23:12 +02:00
const AVIOInterruptCB int_cb = { decode_interrupt_cb , NULL };
2011-11-06 23:22:04 +02:00
2013-07-07 01:52:51 +02:00
static void avconv_cleanup ( int ret )
2011-07-27 20:56:59 +02:00
{
2012-03-29 08:51:17 +02:00
int i , j ;
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 );
2013-03-13 14:24:45 +01:00
av_freep ( & filtergraphs [ i ] -> graph_desc );
2012-03-29 08:51:17 +02:00
av_freep ( & filtergraphs [ i ]);
}
av_freep ( & filtergraphs );
2011-07-27 20:56:59 +02:00
/* close files */
2011-12-30 01:58:29 +05:30
for ( i = 0 ; i < nb_output_files ; i ++ ) {
2012-04-15 15:28:30 +02:00
AVFormatContext * s = output_files [ i ] -> ctx ;
2013-05-29 15:38:21 +02:00
if ( s && s -> oformat && ! ( s -> oformat -> flags & AVFMT_NOFILE ) && s -> pb )
2011-07-27 20:56:59 +02:00
avio_close ( s -> pb );
avformat_free_context ( s );
2012-04-15 15:28:30 +02:00
av_dict_free ( & output_files [ i ] -> opts );
av_freep ( & output_files [ i ]);
2011-07-27 20:56:59 +02:00
}
2012-01-01 17:56:28 +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-01 17:56:28 +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 );
2012-01-02 15:02:46 +01:00
2012-06-22 14:36:27 +02:00
av_freep ( & output_streams [ i ] -> forced_keyframes );
2012-04-15 15:28:30 +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 ]);
2012-01-01 17:56:28 +01:00
}
2011-12-30 01:58:29 +05:30
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 ]);
2011-07-27 20:56:59 +02:00
}
2011-12-05 11:49:38 -05: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 );
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-05 11:49:38 -05:00
}
2011-07-27 20:56:59 +02:00
if ( vstats_file )
fclose ( vstats_file );
av_free ( vstats_filename );
av_freep ( & input_streams );
av_freep ( & input_files );
2011-08-17 10:21:37 +02:00
av_freep ( & output_streams );
2011-08-17 09:56:08 +02:00
av_freep ( & output_files );
2011-07-27 20:56:59 +02:00
uninit_opts ();
2011-11-06 02:47:48 +02:00
avformat_network_deinit ();
2011-07-27 20:56:59 +02:00
if ( received_sigterm ) {
2011-09-13 07:31:21 +02:00
av_log ( NULL , AV_LOG_INFO , "Received signal %d: terminating. \n " ,
( int ) received_sigterm );
2011-07-27 20:56:59 +02:00
exit ( 255 );
}
}
2012-08-01 18:23:12 +02:00
void assert_avoptions ( AVDictionary * m )
2011-07-27 20:56:59 +02:00
{
AVDictionaryEntry * t ;
if (( t = av_dict_get ( m , "" , NULL , AV_DICT_IGNORE_SUFFIX ))) {
2011-09-12 21:51:02 +02:00
av_log ( NULL , AV_LOG_FATAL , "Option %s not found. \n " , t -> key );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2011-07-27 20:56:59 +02:00
}
}
2012-10-18 22:58:25 -06:00
static void abort_codec_experimental ( AVCodec * c , int encoder )
2011-07-27 20:56:59 +02:00
{
const char * codec_string = encoder ? "encoder" : "decoder" ;
AVCodec * codec ;
2012-10-18 22:58:25 -06:00
av_log ( NULL , AV_LOG_FATAL , "%s '%s' is experimental and might produce bad "
"results. \n Add '-strict experimental' if you want to use it. \n " ,
codec_string , c -> name );
codec = encoder ? avcodec_find_encoder ( c -> id ) : avcodec_find_decoder ( c -> id );
if ( ! ( codec -> capabilities & CODEC_CAP_EXPERIMENTAL ))
av_log ( NULL , AV_LOG_FATAL , "Or use the non experimental %s '%s'. \n " ,
codec_string , codec -> name );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2011-07-27 20:56:59 +02:00
}
2012-08-24 13:31:50 +02:00
/*
2011-07-27 20:56:59 +02:00
* Update the requested input sample format based on the output sample format.
* This is currently only used to request float output from decoders which
* support multiple sample formats, one of which is AV_SAMPLE_FMT_FLT.
* Ideally this will be removed in the future when decoders do not do format
* conversion and only output in their native format.
*/
static void update_sample_fmt ( AVCodecContext * dec , AVCodec * dec_codec ,
AVCodecContext * enc )
{
/* if sample formats match or a decoder sample format has already been
requested, just return */
if ( enc -> sample_fmt == dec -> sample_fmt ||
dec -> request_sample_fmt > AV_SAMPLE_FMT_NONE )
return ;
/* if decoder supports more than one output format */
if ( dec_codec && dec_codec -> sample_fmts &&
dec_codec -> sample_fmts [ 0 ] != AV_SAMPLE_FMT_NONE &&
dec_codec -> sample_fmts [ 1 ] != AV_SAMPLE_FMT_NONE ) {
const enum AVSampleFormat * p ;
2012-08-25 16:32:12 -04:00
int min_dec = INT_MAX , min_inc = INT_MAX ;
enum AVSampleFormat dec_fmt = AV_SAMPLE_FMT_NONE ;
enum AVSampleFormat inc_fmt = AV_SAMPLE_FMT_NONE ;
2011-07-27 20:56:59 +02:00
/* find a matching sample format in the encoder */
for ( p = dec_codec -> sample_fmts ; * p != AV_SAMPLE_FMT_NONE ; p ++ ) {
if ( * p == enc -> sample_fmt ) {
dec -> request_sample_fmt = * p ;
return ;
2012-08-25 16:32:12 -04:00
} else {
enum AVSampleFormat dfmt = av_get_packed_sample_fmt ( * p );
enum AVSampleFormat efmt = av_get_packed_sample_fmt ( enc -> sample_fmt );
int fmt_diff = 32 * abs ( dfmt - efmt );
if ( av_sample_fmt_is_planar ( * p ) !=
av_sample_fmt_is_planar ( enc -> sample_fmt ))
fmt_diff ++ ;
if ( dfmt == efmt ) {
min_inc = fmt_diff ;
inc_fmt = * p ;
} else if ( dfmt > efmt ) {
if ( fmt_diff < min_inc ) {
min_inc = fmt_diff ;
inc_fmt = * p ;
}
} else {
if ( fmt_diff < min_dec ) {
min_dec = fmt_diff ;
dec_fmt = * p ;
}
}
}
2011-07-27 20:56:59 +02:00
}
/* if none match, provide the one that matches quality closest */
2012-08-25 16:32:12 -04:00
dec -> request_sample_fmt = min_inc != INT_MAX ? inc_fmt : dec_fmt ;
2011-07-27 20:56:59 +02:00
}
}
2012-01-01 21:51:26 +01:00
static void write_frame ( AVFormatContext * s , AVPacket * pkt , OutputStream * ost )
2011-12-30 01:58:29 +05:30
{
2012-01-01 21:51:26 +01:00
AVBitStreamFilterContext * bsfc = ost -> bitstream_filters ;
AVCodecContext * avctx = ost -> st -> codec ;
2011-07-27 20:56:59 +02:00
int ret ;
2012-01-02 09:22:41 +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-02 09:22:41 +01:00
return ;
2012-03-20 15:36:28 -04:00
}
2012-01-02 09:22:41 +01:00
ost -> frame_number ++ ;
}
2011-12-30 01:58:29 +05:30
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 );
if ( a > 0 ) {
2011-07-27 20:56:59 +02: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 )
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2011-12-30 01:58:29 +05:30
} else if ( a < 0 ) {
2011-09-13 07:31:21 +02:00
av_log ( NULL , AV_LOG_ERROR , "%s failed for stream %d, codec %s" ,
bsfc -> filter -> name , pkt -> stream_index ,
avctx -> codec ? avctx -> codec -> name : "copy" );
2011-07-27 20:56:59 +02:00
print_error ( "" , a );
if ( exit_on_error )
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2011-07-27 20:56:59 +02:00
}
2011-12-30 01:58:29 +05:30
* pkt = new_pkt ;
2011-07-27 20:56:59 +02:00
2011-12-30 01:58:29 +05:30
bsfc = bsfc -> next ;
2011-07-27 20:56:59 +02:00
}
2013-04-24 08:34:44 +02:00
if ( ! ( s -> oformat -> flags & AVFMT_NOTIMESTAMPS ) &&
ost -> last_mux_dts != AV_NOPTS_VALUE &&
pkt -> dts < ost -> last_mux_dts + ! ( s -> oformat -> flags & AVFMT_TS_NONSTRICT )) {
av_log ( NULL , AV_LOG_WARNING , "Non-monotonous DTS in output stream "
"%d:%d; previous: %" PRId64 ", current: %" PRId64 "; " ,
ost -> file_index , ost -> st -> index , ost -> last_mux_dts , pkt -> dts );
if ( exit_on_error ) {
av_log ( NULL , AV_LOG_FATAL , "aborting. \n " );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2013-04-24 08:34:44 +02:00
}
av_log ( NULL , AV_LOG_WARNING , "changing to %" PRId64 ". This may result "
"in incorrect timestamps in the output file. \n " ,
ost -> last_mux_dts + 1 );
pkt -> dts = ost -> last_mux_dts + 1 ;
if ( pkt -> pts != AV_NOPTS_VALUE )
pkt -> pts = FFMAX ( pkt -> pts , pkt -> dts );
}
ost -> last_mux_dts = pkt -> dts ;
2012-02-01 10:23:28 +01:00
pkt -> stream_index = ost -> index ;
2011-12-30 01:58:29 +05:30
ret = av_interleaved_write_frame ( s , pkt );
if ( ret < 0 ) {
2011-07-27 20:56:59 +02:00
print_error ( "av_interleaved_write_frame()" , ret );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2011-07-27 20:56:59 +02:00
}
}
2012-02-05 14:32:10 +01:00
static int check_recording_time ( OutputStream * ost )
{
2012-04-15 15:28:30 +02:00
OutputFile * of = output_files [ ost -> file_index ];
2012-02-05 14:32:10 +01:00
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-08 12:04:53 +02:00
ost -> finished = 1 ;
2012-02-05 14:32:10 +01:00
return 0 ;
}
return 1 ;
}
2012-05-05 18:22:46 +02:00
static void do_audio_out ( AVFormatContext * s , OutputStream * ost ,
AVFrame * frame )
2011-12-31 09:36:25 -05:00
{
AVCodecContext * enc = ost -> st -> codec ;
AVPacket pkt ;
2012-05-05 18:22:46 +02:00
int got_packet = 0 ;
2011-12-31 09:36:25 -05:00
av_init_packet ( & pkt );
pkt . data = NULL ;
pkt . size = 0 ;
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 ;
2011-12-31 09:36:25 -05:00
if ( avcodec_encode_audio2 ( enc , & pkt , frame , & got_packet ) < 0 ) {
av_log ( NULL , AV_LOG_FATAL , "Audio encoding failed \n " );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2011-12-31 09:36:25 -05: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-02-06 19:08:32 -05:00
if ( pkt . dts != AV_NOPTS_VALUE )
pkt . dts = av_rescale_q ( pkt . dts , enc -> time_base , ost -> st -> time_base );
2011-12-31 09:36:25 -05:00
if ( pkt . duration > 0 )
pkt . duration = av_rescale_q ( pkt . duration , enc -> time_base , ost -> st -> time_base );
write_frame ( s , & pkt , ost );
audio_size += pkt . size ;
}
2011-07-27 20:56:59 +02:00
}
static void do_subtitle_out ( AVFormatContext * s ,
OutputStream * ost ,
InputStream * ist ,
AVSubtitle * sub ,
int64_t pts )
{
static uint8_t * subtitle_out = NULL ;
int subtitle_out_max_size = 1024 * 1024 ;
int subtitle_out_size , nb , i ;
AVCodecContext * enc ;
AVPacket pkt ;
if ( pts == AV_NOPTS_VALUE ) {
2011-09-13 07:31:21 +02:00
av_log ( NULL , AV_LOG_ERROR , "Subtitle packets must have a pts \n " );
2011-07-27 20:56:59 +02:00
if ( exit_on_error )
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2011-07-27 20:56:59 +02:00
return ;
}
enc = ost -> st -> codec ;
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 )
2011-07-27 20:56:59 +02:00
nb = 2 ;
else
nb = 1 ;
2011-12-30 01:58:29 +05:30
for ( i = 0 ; i < nb ; i ++ ) {
2012-02-05 14:32:10 +01:00
ost -> sync_opts = av_rescale_q ( pts , ist -> st -> time_base , enc -> time_base );
if ( ! check_recording_time ( ost ))
return ;
2011-07-27 20:56:59 +02:00
sub -> pts = av_rescale_q ( pts , ist -> st -> time_base , AV_TIME_BASE_Q );
// start_display_time is required to be 0
2011-12-30 01:58:29 +05:30
sub -> pts += av_rescale_q ( sub -> start_display_time , ( AVRational ){ 1 , 1000 }, AV_TIME_BASE_Q );
sub -> end_display_time -= sub -> start_display_time ;
2011-07-27 20:56:59 +02:00
sub -> start_display_time = 0 ;
subtitle_out_size = avcodec_encode_subtitle ( enc , subtitle_out ,
subtitle_out_max_size , sub );
if ( subtitle_out_size < 0 ) {
2011-09-13 07:31:21 +02:00
av_log ( NULL , AV_LOG_FATAL , "Subtitle encoding failed \n " );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2011-07-27 20:56:59 +02:00
}
av_init_packet ( & pkt );
pkt . data = subtitle_out ;
pkt . size = subtitle_out_size ;
2011-12-30 01:58:29 +05:30
pkt . pts = av_rescale_q ( sub -> pts , AV_TIME_BASE_Q , ost -> st -> time_base );
2012-08-05 11:11:04 +02:00
if ( enc -> codec_id == AV_CODEC_ID_DVB_SUBTITLE ) {
2011-07-27 20:56:59 +02: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-01-01 21:51:26 +01:00
write_frame ( s , & pkt , ost );
2011-07-27 20:56:59 +02:00
}
}
static void do_video_out ( AVFormatContext * s ,
OutputStream * ost ,
AVFrame * in_picture ,
2012-10-09 17:40:20 +02:00
int * frame_size )
2011-07-27 20:56:59 +02:00
{
2012-05-09 16:25:02 +02:00
int ret , format_video_sync ;
AVPacket pkt ;
AVCodecContext * enc = ost -> st -> codec ;
2011-07-27 20:56:59 +02:00
* frame_size = 0 ;
2011-08-16 19:06:46 -07:00
format_video_sync = video_sync_method ;
2011-11-26 11:01:33 +01:00
if ( format_video_sync == VSYNC_AUTO )
format_video_sync = ( s -> oformat -> flags & AVFMT_NOTIMESTAMPS ) ? VSYNC_PASSTHROUGH :
( s -> oformat -> flags & AVFMT_VARIABLE_FPS ) ? VSYNC_VFR : VSYNC_CFR ;
2012-05-09 16:25:02 +02:00
if ( format_video_sync != VSYNC_PASSTHROUGH &&
ost -> frame_number &&
in_picture -> pts != AV_NOPTS_VALUE &&
in_picture -> pts < ost -> sync_opts ) {
2012-02-06 21:47:41 +01:00
nb_frames_drop ++ ;
av_log ( NULL , AV_LOG_VERBOSE , "*** drop! \n " );
2011-07-27 20:56:59 +02:00
return ;
2012-02-06 21:47:41 +01:00
}
2011-07-27 20:56:59 +02:00
2012-05-09 16:25:02 +02:00
if ( in_picture -> pts == AV_NOPTS_VALUE )
in_picture -> pts = ost -> sync_opts ;
ost -> sync_opts = in_picture -> pts ;
2012-02-05 14:32:10 +01:00
if ( ! ost -> frame_number )
2012-05-09 16:25:02 +02:00
ost -> first_pts = in_picture -> pts ;
2012-02-05 14:32:10 +01:00
2012-05-18 12:18:49 +02:00
av_init_packet ( & pkt );
pkt . data = NULL ;
pkt . size = 0 ;
2011-07-27 20:56:59 +02:00
2013-04-10 15:02:01 +02:00
if ( ost -> frame_number >= ost -> max_frames )
2012-05-18 12:18:49 +02:00
return ;
2012-02-05 14:32:10 +01:00
2012-05-18 12:18:49 +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-18 12:18:49 +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 ;
pkt . data = ( uint8_t * ) in_picture ;
pkt . size = sizeof ( AVPicture );
pkt . pts = av_rescale_q ( in_picture -> pts , enc -> time_base , ost -> st -> time_base );
pkt . flags |= AV_PKT_FLAG_KEY ;
write_frame ( s , & pkt , ost );
} else {
int got_packet ;
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-18 12:18:49 +02:00
2013-01-21 21:10:18 +01:00
in_picture -> quality = ost -> st -> codec -> global_quality ;
2012-05-18 12:18:49 +02:00
if ( ! enc -> me_threshold )
2013-01-21 21:10:18 +01:00
in_picture -> pict_type = 0 ;
2012-05-18 12:18:49 +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 ]) {
in_picture -> pict_type = AV_PICTURE_TYPE_I ;
2012-05-18 12:18:49 +02:00
ost -> forced_kf_index ++ ;
}
2013-01-21 21:10:18 +01:00
ret = avcodec_encode_video2 ( enc , & pkt , in_picture , & got_packet );
2012-05-18 12:18:49 +02:00
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_FATAL , "Video encoding failed \n " );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2012-05-18 12:18:49 +02:00
}
if ( got_packet ) {
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 );
2011-07-27 20:56:59 +02:00
2012-01-01 21:51:26 +01:00
write_frame ( s , & pkt , ost );
2012-05-18 12:18:49 +02:00
* frame_size = pkt . size ;
video_size += pkt . size ;
2011-07-27 20:56:59 +02:00
2012-05-18 12:18:49 +02:00
/* if two pass, output log */
if ( ost -> logfile && enc -> stats_out ) {
fprintf ( ost -> logfile , "%s" , enc -> stats_out );
2011-07-27 20:56:59 +02:00
}
}
2012-05-18 12:18:49 +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 ++ ;
2011-07-27 20:56:59 +02:00
}
2011-12-30 01:58:29 +05:30
static double psnr ( double d )
{
return - 10.0 * log ( d ) / log ( 10.0 );
2011-07-27 20:56:59 +02:00
}
2012-10-24 19:18:12 +02:00
static void do_video_stats ( OutputStream * ost , int frame_size )
2011-07-27 20:56:59 +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" );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2011-07-27 20:56:59 +02:00
}
}
enc = ost -> st -> codec ;
if ( enc -> codec_type == AVMEDIA_TYPE_VIDEO ) {
frame_number = ost -> frame_number ;
2011-12-30 01:58:29 +05:30
fprintf ( vstats_file , "frame= %5d q= %2.1f " , frame_number , enc -> coded_frame -> quality / ( float ) FF_QP2LAMBDA );
2011-07-27 20:56:59 +02:00
if ( enc -> flags & CODEC_FLAG_PSNR )
2011-12-30 01:58:29 +05:30
fprintf ( vstats_file , "PSNR= %6.2f " , psnr ( enc -> coded_frame -> error [ 0 ] / ( enc -> width * enc -> height * 255.0 * 255.0 )));
2011-07-27 20:56:59 +02:00
fprintf ( vstats_file , "f_size= %6d " , frame_size );
/* compute pts value */
ti1 = ost -> sync_opts * av_q2d ( enc -> time_base );
if ( ti1 < 0.01 )
ti1 = 0.01 ;
2011-12-30 01:58:29 +05:30
bitrate = ( frame_size * 8 ) / av_q2d ( enc -> time_base ) / 1000.0 ;
2011-07-27 20:56:59 +02:00
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 " ,
2011-12-30 01:58:29 +05:30
( double ) video_size / 1024 , ti1 , bitrate , avg_bitrate );
2011-07-27 20:56:59 +02:00
fprintf ( vstats_file , "type= %c \n " , av_get_picture_type_char ( enc -> coded_frame -> pict_type ));
}
}
2012-08-24 13:31:50 +02:00
/*
2012-08-03 22:09:58 +02:00
* Read one frame for lavfi output for ost and encode it.
*/
static int poll_filter ( OutputStream * ost )
2012-03-29 08:51:17 +02:00
{
2012-08-03 22:09:58 +02:00
OutputFile * of = output_files [ ost -> file_index ];
2012-03-29 08:51:17 +02:00
AVFrame * filtered_frame = NULL ;
2012-08-03 22:09:58 +02:00
int frame_size , ret ;
2012-03-29 08:51:17 +02:00
2012-08-03 22:09:58 +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-03 22:09:58 +02:00
if ( ost -> enc -> type == AVMEDIA_TYPE_AUDIO &&
! ( ost -> enc -> capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE ))
2013-01-21 21:10:18 +01:00
ret = av_buffersink_get_samples ( ost -> filter -> filter , filtered_frame ,
2012-08-03 22:09:58 +02:00
ost -> st -> codec -> frame_size );
else
2013-01-21 21:10:18 +01:00
ret = av_buffersink_get_frame ( ost -> filter -> filter , filtered_frame );
2012-03-29 08:51:17 +02:00
2012-08-03 22:09:58 +02:00
if ( ret < 0 )
return ret ;
2012-03-29 08:51:17 +02:00
2013-01-21 21:10:18 +01:00
if ( filtered_frame -> pts != AV_NOPTS_VALUE ) {
2013-06-15 09:35:10 +02:00
int64_t start_time = ( of -> start_time == AV_NOPTS_VALUE ) ? 0 : of -> start_time ;
2013-01-21 21:10:18 +01:00
filtered_frame -> pts = av_rescale_q ( filtered_frame -> pts ,
2012-08-03 22:09:58 +02:00
ost -> filter -> filter -> inputs [ 0 ] -> time_base ,
ost -> st -> codec -> time_base ) -
2013-06-15 09:35:10 +02:00
av_rescale_q ( start_time ,
2012-08-03 22:09:58 +02:00
AV_TIME_BASE_Q ,
ost -> st -> codec -> time_base );
2012-03-29 08:51:17 +02:00
}
2012-08-03 22:09:58 +02:00
switch ( ost -> filter -> filter -> inputs [ 0 ] -> type ) {
case AVMEDIA_TYPE_VIDEO :
if ( ! ost -> frame_aspect_ratio )
2013-01-21 21:10:18 +01:00
ost -> st -> codec -> sample_aspect_ratio = filtered_frame -> sample_aspect_ratio ;
2012-08-03 22:09:58 +02:00
2012-10-09 17:40:20 +02:00
do_video_out ( of -> ctx , ost , filtered_frame , & frame_size );
2012-08-03 22:09:58 +02:00
if ( vstats_filename && frame_size )
2012-10-24 19:18:12 +02:00
do_video_stats ( ost , frame_size );
2012-08-03 22:09:58 +02:00
break ;
case AVMEDIA_TYPE_AUDIO :
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-08-03 22:09:58 +02:00
2012-03-29 08:51:17 +02:00
return 0 ;
}
2012-08-24 13:31:50 +02:00
/*
2012-08-03 22:09:58 +02:00
* Read as many frames from possible from lavfi and encode them.
*
* Always read from the active stream with the lowest timestamp. If no frames
* are available for it then return EAGAIN and wait for more input. This way we
* can use lavfi sources that generate unlimited amount of frames without memory
* usage exploding.
*/
static int poll_filters ( void )
{
2012-08-11 11:50:32 +02:00
int i , j , ret = 0 ;
2012-08-03 22:09:58 +02:00
while ( ret >= 0 && ! received_sigterm ) {
OutputStream * ost = NULL ;
int64_t min_pts = INT64_MAX ;
/* choose output stream with the lowest timestamp */
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
int64_t pts = output_streams [ i ] -> sync_opts ;
2012-08-08 12:04:53 +02:00
if ( ! output_streams [ i ] -> filter || output_streams [ i ] -> finished )
2012-08-03 22:09:58 +02:00
continue ;
pts = av_rescale_q ( pts , output_streams [ i ] -> st -> codec -> time_base ,
AV_TIME_BASE_Q );
if ( pts < min_pts ) {
min_pts = pts ;
ost = output_streams [ i ];
}
}
if ( ! ost )
break ;
ret = poll_filter ( ost );
if ( ret == AVERROR_EOF ) {
2012-08-11 11:50:32 +02:00
OutputFile * of = output_files [ ost -> file_index ];
2012-08-08 12:04:53 +02:00
ost -> finished = 1 ;
2012-08-03 22:09:58 +02:00
2012-08-11 11:50:32 +02:00
if ( of -> shortest ) {
for ( j = 0 ; j < of -> ctx -> nb_streams ; j ++ )
output_streams [ of -> ost_index + j ] -> finished = 1 ;
}
2012-08-03 22:09:58 +02:00
ret = 0 ;
} else if ( ret == AVERROR ( EAGAIN ))
return 0 ;
}
return ret ;
}
2012-04-15 15:03:07 +02:00
static void print_report ( int is_last_report , int64_t timer_start )
2011-07-27 20:56:59 +02:00
{
char buf [ 1024 ];
OutputStream * ost ;
AVFormatContext * oc ;
int64_t total_size ;
AVCodecContext * enc ;
int frame_number , vid , i ;
double bitrate , ti1 , pts ;
static int64_t last_time = - 1 ;
static int qp_histogram [ 52 ];
2011-10-09 15:57:30 +02:00
if ( ! print_stats && ! is_last_report )
return ;
2011-07-27 20:56:59 +02:00
if ( ! is_last_report ) {
int64_t cur_time ;
/* display the report every 0.5 seconds */
cur_time = av_gettime ();
if ( last_time == - 1 ) {
last_time = cur_time ;
return ;
}
if (( cur_time - last_time ) < 500000 )
return ;
last_time = cur_time ;
}
2012-04-15 15:28:30 +02:00
oc = output_files [ 0 ] -> ctx ;
2011-07-27 20:56:59 +02: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 01:58:29 +05:30
total_size = avio_tell ( oc -> pb );
2012-10-09 23:22:49 +02:00
if ( total_size < 0 ) {
char errbuf [ 128 ];
av_strerror ( total_size , errbuf , sizeof ( errbuf ));
av_log ( NULL , AV_LOG_VERBOSE , "Bitrate not available, "
"avio_tell() failed: %s \n " , errbuf );
total_size = 0 ;
}
2011-07-27 20:56:59 +02:00
buf [ 0 ] = '\0' ;
ti1 = 1e10 ;
vid = 0 ;
2012-04-15 15:03:07 +02:00
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
2011-07-27 20:56:59 +02:00
float q = - 1 ;
2012-04-15 15:28:30 +02:00
ost = output_streams [ i ];
2011-07-27 20:56:59 +02:00
enc = ost -> st -> codec ;
2011-10-23 11:22:33 +02:00
if ( ! ost -> stream_copy && enc -> coded_frame )
2011-12-30 01:58:29 +05:30
q = enc -> coded_frame -> quality / ( float ) FF_QP2LAMBDA ;
2011-07-27 20:56:59 +02:00
if ( vid && enc -> codec_type == AVMEDIA_TYPE_VIDEO ) {
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ), "q=%2.1f " , q );
}
if ( ! vid && enc -> codec_type == AVMEDIA_TYPE_VIDEO ) {
2011-12-30 01:58:29 +05:30
float t = ( av_gettime () - timer_start ) / 1000000.0 ;
2011-07-27 20:56:59 +02:00
frame_number = ost -> frame_number ;
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ), "frame=%5d fps=%3d q=%3.1f " ,
2011-12-30 01:58:29 +05:30
frame_number , ( t > 1 ) ? ( int )( frame_number / t + 0.5 ) : 0 , q );
if ( is_last_report )
2011-07-27 20:56:59 +02:00
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ), "L" );
2011-12-30 01:58:29 +05:30
if ( qp_hist ) {
2011-07-27 20:56:59 +02:00
int j ;
int qp = lrintf ( q );
2011-12-30 01:58:29 +05:30
if ( qp >= 0 && qp < FF_ARRAY_ELEMS ( qp_histogram ))
2011-07-27 20:56:59 +02:00
qp_histogram [ qp ] ++ ;
2011-12-30 01:58:29 +05:30
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 )));
2011-07-27 20:56:59 +02:00
}
2011-12-30 01:58:29 +05:30
if ( enc -> flags & CODEC_FLAG_PSNR ) {
2011-07-27 20:56:59 +02:00
int j ;
2011-12-30 01:58:29 +05:30
double error , error_sum = 0 ;
double scale , scale_sum = 0 ;
char type [ 3 ] = { 'Y' , 'U' , 'V' };
2011-07-27 20:56:59 +02:00
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ), "PSNR=" );
2011-12-30 01:58:29 +05:30
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 ;
2011-07-27 20:56:59 +02:00
}
2011-12-30 01:58:29 +05:30
if ( j )
scale /= 4 ;
2011-07-27 20:56:59 +02:00
error_sum += error ;
scale_sum += scale ;
2011-12-30 01:58:29 +05:30
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ), "%c:%2.2f " , type [ j ], psnr ( error / scale ));
2011-07-27 20:56:59 +02:00
}
2011-12-30 01:58:29 +05:30
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ), "*:%2.2f " , psnr ( error_sum / scale_sum ));
2011-07-27 20:56:59 +02:00
}
vid = 1 ;
}
/* compute min output value */
pts = ( double ) ost -> st -> pts . val * av_q2d ( ost -> st -> time_base );
if (( pts < ti1 ) && ( pts > 0 ))
ti1 = pts ;
}
if ( ti1 < 0.01 )
ti1 = 0.01 ;
2011-09-13 07:31:21 +02:00
bitrate = ( double )( total_size * 8 ) / ti1 / 1000.0 ;
2011-07-27 20:56:59 +02:00
2011-09-13 07:31:21 +02:00
snprintf ( buf + strlen ( buf ), sizeof ( buf ) - strlen ( buf ),
2011-07-27 20:56:59 +02:00
"size=%8.0fkB time=%0.2f bitrate=%6.1fkbits/s" ,
( double ) total_size / 1024 , ti1 , bitrate );
2011-09-13 07:31:21 +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 );
2011-07-27 20:56:59 +02:00
2011-10-09 16:32:54 +02:00
av_log ( NULL , AV_LOG_INFO , "%s \r " , buf );
2011-07-27 20:56:59 +02:00
2011-09-13 07:31:21 +02:00
fflush ( stderr );
2011-07-27 20:56:59 +02:00
2011-09-13 07:31:21 +02:00
if ( is_last_report ) {
2011-07-27 20:56:59 +02:00
int64_t raw = audio_size + video_size + extra_size ;
2011-09-13 07:31:21 +02:00
av_log ( NULL , AV_LOG_INFO , " \n " );
av_log ( NULL , AV_LOG_INFO , "video:%1.0fkB audio:%1.0fkB global headers:%1.0fkB muxing overhead %f%% \n " ,
2011-12-30 01:58:29 +05:30
video_size / 1024.0 ,
audio_size / 1024.0 ,
extra_size / 1024.0 ,
100.0 * ( total_size - raw ) / raw
2011-07-27 20:56:59 +02:00
);
}
}
2012-04-15 15:03:07 +02:00
static void flush_encoders ( void )
2011-08-18 08:55:29 +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-16 11:19:20 +02:00
AVCodecContext * enc = ost -> st -> codec ;
2012-04-15 15:28:30 +02:00
AVFormatContext * os = output_files [ ost -> file_index ] -> ctx ;
2011-12-31 09:36:25 -05:00
int stop_encoding = 0 ;
2011-08-18 08:55:29 +02:00
2011-08-19 17:52:46 +02:00
if ( ! ost -> encoding_needed )
2011-08-16 11:19:20 +02:00
continue ;
2011-08-18 08:55:29 +02:00
2011-12-30 01:58:29 +05:30
if ( ost -> st -> codec -> codec_type == AVMEDIA_TYPE_AUDIO && enc -> frame_size <= 1 )
2011-08-16 11:19:20 +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-16 11:19:20 +02:00
continue ;
2011-08-18 08:55:29 +02:00
2011-12-30 01:58:29 +05:30
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-18 08:55:29 +02:00
2011-08-16 11:19:20 +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-16 11:19:20 +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 ;
ret = encode ( enc , & pkt , NULL , & got_packet );
2011-08-16 11:19:20 +02:00
if ( ret < 0 ) {
2012-05-05 18:22:46 +02:00
av_log ( NULL , AV_LOG_FATAL , "%s encoding failed \n " , desc );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2011-08-16 11:19:20 +02:00
}
2012-05-05 18:22:46 +02:00
* size += ret ;
2011-08-16 11:19:20 +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 ) {
2011-12-31 09:36:25 -05: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-06 14:24:31 -05:00
if ( pkt . duration > 0 )
pkt . duration = av_rescale_q ( pkt . duration , enc -> time_base , ost -> st -> time_base );
2011-12-31 09:36:25 -05:00
write_frame ( os , & pkt , ost );
2011-08-18 08:55:29 +02:00
}
2012-05-05 18:22:46 +02:00
2011-12-31 09:36:25 -05:00
if ( stop_encoding )
2011-08-16 11:19:20 +02:00
break ;
2011-08-18 08:55:29 +02:00
}
}
}
2011-11-21 13:48:45 +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-21 13:48:45 +01:00
if ( ost -> source_index != ist_index )
return 0 ;
2013-06-15 09:35:10 +02:00
if ( of -> start_time != AV_NOPTS_VALUE && ist -> last_dts < of -> start_time )
2011-11-21 13:48:45 +01:00
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 ];
2013-06-18 11:12:09 +02:00
InputFile * f = input_files [ ist -> file_index ];
2013-06-15 09:35:10 +02:00
int64_t start_time = ( of -> start_time == AV_NOPTS_VALUE ) ? 0 : of -> start_time ;
int64_t ost_tb_start_time = av_rescale_q ( start_time , AV_TIME_BASE_Q , ost -> st -> time_base );
2011-11-21 13:48:45 +01:00
AVPacket opkt ;
av_init_packet ( & opkt );
if (( ! ost -> frame_number && ! ( pkt -> flags & AV_PKT_FLAG_KEY )) &&
! ost -> copy_initial_nonkeyframes )
return ;
2012-02-05 14:32:10 +01:00
if ( of -> recording_time != INT64_MAX &&
2013-06-15 09:35:10 +02:00
ist -> last_dts >= of -> recording_time + start_time ) {
2012-08-08 12:04:53 +02:00
ost -> finished = 1 ;
2012-02-05 14:32:10 +01:00
return ;
}
2013-06-18 11:12:09 +02:00
if ( f -> recording_time != INT64_MAX ) {
start_time = f -> ctx -> start_time ;
if ( f -> start_time != AV_NOPTS_VALUE )
start_time += f -> start_time ;
if ( ist -> last_dts >= f -> recording_time + start_time ) {
ost -> finished = 1 ;
return ;
}
}
2011-11-21 13:48:45 +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 ++ ;
}
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-05 21:12:43 +01:00
opkt . dts = av_rescale_q ( ist -> last_dts , AV_TIME_BASE_Q , ost -> st -> time_base );
2011-11-21 13:48:45 +01:00
else
opkt . dts = av_rescale_q ( pkt -> dts , ist -> st -> time_base , ost -> st -> time_base );
opkt . dts -= ost_tb_start_time ;
opkt . duration = av_rescale_q ( pkt -> duration , ist -> st -> time_base , ost -> st -> time_base );
opkt . flags = pkt -> flags ;
2011-12-30 01:58:29 +05:30
// 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-21 13:48:45 +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 )
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2013-01-21 21:10:18 +01:00
}
2011-11-21 13:48:45 +01:00
} else {
opkt . data = pkt -> data ;
opkt . size = pkt -> size ;
}
2012-01-01 21:51:26 +01:00
write_frame ( of -> ctx , & opkt , ost );
2011-11-21 13:48:45 +01:00
ost -> st -> codec -> frame_number ++ ;
}
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 ];
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-21 14:39:22 +01:00
{
2013-01-21 21:10:18 +01:00
AVFrame * decoded_frame , * f ;
2011-11-21 17:41:49 -05:00
AVCodecContext * avctx = ist -> st -> codec ;
2013-01-21 21:10:18 +01:00
int i , ret , err = 0 , resample_changed ;
2011-11-21 14:39:22 +01:00
2011-12-05 11:49:38 -05:00
if ( ! ist -> decoded_frame && ! ( ist -> decoded_frame = avcodec_alloc_frame ()))
2011-11-21 17:41:49 -05:00
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-05 11:49:38 -05:00
decoded_frame = ist -> decoded_frame ;
2011-11-21 14:39:22 +01:00
2011-11-21 17:41:49 -05:00
ret = avcodec_decode_audio4 ( avctx , decoded_frame , got_output , pkt );
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-01-21 21:10:18 +01:00
av_buffersrc_add_frame ( ist -> filters [ i ] -> filter , NULL );
2012-08-08 12:27:50 +02:00
}
2011-11-21 21:30:23 +01:00
return ret ;
2011-11-21 14:39:22 +01:00
}
2011-11-21 17:41:49 -05: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 )
2012-02-03 15:32:51 +01:00
ist -> next_dts = decoded_frame -> pts ;
2012-05-05 18:22:46 +02:00
else if ( pkt -> pts != AV_NOPTS_VALUE ) {
decoded_frame -> pts = pkt -> pts ;
pkt -> pts = AV_NOPTS_VALUE ;
}
2011-11-21 14:39:22 +01:00
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-21 14:39:22 +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 );
2013-07-07 01:52:51 +02:00
exit_program ( 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 ++ )
if ( ist_in_filtergraph ( filtergraphs [ i ], ist ) &&
configure_filtergraph ( filtergraphs [ i ]) < 0 ) {
av_log ( NULL , AV_LOG_FATAL , "Error reinitializing filters! \n " );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2012-05-05 18:22:46 +02:00
}
2011-11-21 14:39:22 +01:00
}
2011-12-05 10:36:54 -05:00
2012-06-30 11:26:11 +03:00
if ( decoded_frame -> pts != AV_NOPTS_VALUE )
decoded_frame -> pts = av_rescale_q ( decoded_frame -> pts ,
ist -> st -> time_base ,
( 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 ;
2012-05-05 18:22:46 +02:00
2013-01-21 21:10:18 +01:00
err = av_buffersrc_add_frame ( ist -> filters [ i ] -> filter , f );
if ( err < 0 )
break ;
}
av_frame_unref ( ist -> filter_frame );
av_frame_unref ( decoded_frame );
return err < 0 ? err : ret ;
2011-11-21 14:39:22 +01:00
}
2012-05-18 12:46:11 +02:00
static int decode_video ( InputStream * ist , AVPacket * pkt , int * got_output )
2011-11-21 14:39:22 +01:00
{
2013-01-21 21:10:18 +01:00
AVFrame * decoded_frame , * f ;
2011-11-21 14:39:22 +01:00
void * buffer_to_free = NULL ;
2013-01-21 21:10:18 +01:00
int i , ret = 0 , err = 0 , resample_changed ;
2011-11-21 14:39:22 +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-21 14:39:22 +01:00
return AVERROR ( ENOMEM );
2011-12-05 11:49:38 -05:00
decoded_frame = ist -> decoded_frame ;
2011-11-21 14:39:22 +01:00
ret = avcodec_decode_video2 ( ist -> st -> codec ,
decoded_frame , got_output , pkt );
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-01-21 21:10:18 +01:00
av_buffersrc_add_frame ( ist -> filters [ i ] -> filter , NULL );
2012-08-08 12:27:50 +02:00
}
2011-11-21 21:30:23 +01:00
return ret ;
2011-11-21 14:39:22 +01:00
}
2012-08-08 12:27:50 +02:00
2012-02-02 12:21:37 +01:00
decoded_frame -> pts = guess_correct_pts ( & ist -> pts_ctx , decoded_frame -> pkt_pts ,
decoded_frame -> pkt_dts );
2011-11-21 14:39:22 +01:00
pkt -> size = 0 ;
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 ));
2012-09-06 21:51:31 +02:00
ret = poll_filters ();
if ( ret < 0 && ( ret != AVERROR_EOF && ret != AVERROR ( EAGAIN )))
av_log ( NULL , AV_LOG_ERROR , "Error while filtering. \n " );
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 ;
2012-04-01 15:08:33 +02:00
for ( i = 0 ; i < nb_filtergraphs ; i ++ )
if ( ist_in_filtergraph ( filtergraphs [ i ], ist ) &&
configure_filtergraph ( filtergraphs [ i ]) < 0 ) {
av_log ( NULL , AV_LOG_FATAL , "Error reinitializing filters! \n " );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2012-04-01 15:08:33 +02:00
}
2012-03-29 07:40:26 +02:00
}
2012-03-29 08:51:17 +02:00
for ( i = 0 ; i < ist -> nb_filters ; i ++ ) {
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 ;
err = av_buffersrc_add_frame ( ist -> filters [ i ] -> filter , f );
if ( err < 0 )
break ;
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-21 14:39:22 +01:00
av_free ( buffer_to_free );
2013-01-21 21:10:18 +01:00
return err < 0 ? err : ret ;
2011-11-21 14:39:22 +01:00
}
2011-11-21 14:39:22 +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 );
if ( ret < 0 )
return ret ;
if ( !* got_output )
2011-11-21 21:30:23 +01:00
return ret ;
2011-11-21 14:39:22 +01:00
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
OutputStream * ost = output_streams [ i ];
2011-11-21 14:39:22 +01:00
if ( ! check_output_constraints ( ist , ost ) || ! ost -> encoding_needed )
continue ;
2012-04-15 15:28:30 +02:00
do_subtitle_out ( output_files [ ost -> file_index ] -> ctx , ost , ist , & subtitle , pkt -> pts );
2011-11-21 14:39:22 +01:00
}
avsubtitle_free ( & subtitle );
2011-11-21 21:30:23 +01:00
return ret ;
2011-11-21 14:39:22 +01:00
}
2011-07-27 20:56:59 +02: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 )
2011-07-27 20:56:59 +02:00
{
2011-11-22 07:13:29 +01:00
int i ;
2011-07-27 20:56:59 +02:00
int got_output ;
AVPacket avpkt ;
2012-02-03 15:32:51 +01:00
if ( ist -> next_dts == AV_NOPTS_VALUE )
2012-02-05 21:12:43 +01:00
ist -> next_dts = ist -> last_dts ;
2011-07-27 20:56:59 +02:00
if ( pkt == NULL ) {
/* EOF handling */
av_init_packet ( & avpkt );
avpkt . data = NULL ;
avpkt . size = 0 ;
goto handle_eof ;
} else {
avpkt = * pkt ;
}
2011-12-30 01:58:29 +05:30
if ( pkt -> dts != AV_NOPTS_VALUE )
2012-02-05 21:12:43 +01:00
ist -> next_dts = ist -> last_dts = av_rescale_q ( pkt -> dts , ist -> st -> time_base , AV_TIME_BASE_Q );
2011-07-27 20:56:59 +02:00
2011-12-30 01:58:29 +05:30
// while we have more to decode or while the decoder did output something on EOF
2011-11-21 14:05:38 +01:00
while ( ist -> decoding_needed && ( avpkt . size > 0 || ( ! pkt && got_output ))) {
2011-11-22 07:13:29 +01:00
int ret = 0 ;
2011-07-27 20:56:59 +02:00
handle_eof :
2012-02-05 21:12:43 +01:00
ist -> last_dts = ist -> next_dts ;
2011-11-22 07:16:23 +01:00
if ( avpkt . size && avpkt . size != pkt -> size ) {
2011-09-13 07:31:21 +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-22 07:16:23 +01:00
ist -> showed_multi_packet_warning = 1 ;
}
2011-07-27 20:56:59 +02:00
2011-12-30 01:58:29 +05:30
switch ( ist -> st -> codec -> codec_type ) {
2011-11-21 15:37:40 +01:00
case AVMEDIA_TYPE_AUDIO :
2012-05-18 12:46:11 +02:00
ret = decode_audio ( ist , & avpkt , & got_output );
2011-11-21 15:37:40 +01:00
break ;
case AVMEDIA_TYPE_VIDEO :
2012-05-18 12:46:11 +02:00
ret = decode_video ( ist , & avpkt , & got_output );
2012-02-02 12:21:37 +01:00
if ( avpkt . duration )
ist -> next_dts += av_rescale_q ( avpkt . duration , ist -> st -> time_base , AV_TIME_BASE_Q );
2012-06-26 13:10:01 +02:00
else if ( ist -> st -> avg_frame_rate . num )
2012-07-29 14:58:53 +01:00
ist -> next_dts += av_rescale_q ( 1 , av_inv_q ( ist -> st -> avg_frame_rate ),
2012-02-02 13:18:49 +01:00
AV_TIME_BASE_Q );
2012-02-02 12:21:37 +01:00
else if ( ist -> st -> codec -> time_base . num != 0 ) {
int ticks = ist -> st -> parser ? ist -> st -> parser -> repeat_pict + 1 :
ist -> st -> codec -> ticks_per_frame ;
ist -> next_dts += av_rescale_q ( ticks , ist -> st -> codec -> time_base , AV_TIME_BASE_Q );
}
2011-11-21 15:37:40 +01:00
break ;
case AVMEDIA_TYPE_SUBTITLE :
ret = transcode_subtitles ( ist , & avpkt , & got_output );
break ;
2011-11-21 14:06:25 +01:00
default :
return - 1 ;
}
2011-07-27 20:56:59 +02:00
2011-09-23 16:17:42 +02:00
if ( ret < 0 )
return ret ;
2011-11-24 00:18:33 +01:00
// touch data and size only if not EOF
if ( pkt ) {
avpkt . data += ret ;
avpkt . size -= ret ;
}
2011-11-21 15:37:40 +01:00
if ( ! got_output ) {
2011-11-21 21:30:23 +01:00
continue ;
2011-11-21 15:37:40 +01:00
}
2011-07-27 20:56:59 +02:00
}
2011-11-21 13:48:45 +01:00
/* handle stream copy */
2011-11-21 14:05:38 +01:00
if ( ! ist -> decoding_needed ) {
2012-02-05 21:12:43 +01:00
ist -> last_dts = ist -> next_dts ;
2011-11-21 14:05:38 +01:00
switch ( ist -> st -> codec -> codec_type ) {
case AVMEDIA_TYPE_AUDIO :
2012-02-03 15:32:51 +01:00
ist -> next_dts += (( int64_t ) AV_TIME_BASE * ist -> st -> codec -> frame_size ) /
2011-11-21 14:05:38 +01:00
ist -> st -> codec -> sample_rate ;
break ;
case AVMEDIA_TYPE_VIDEO :
if ( ist -> st -> codec -> time_base . num != 0 ) {
2011-12-30 01:58:29 +05:30
int ticks = ist -> st -> parser ? ist -> st -> parser -> repeat_pict + 1 : ist -> st -> codec -> ticks_per_frame ;
2012-02-03 15:32:51 +01:00
ist -> next_dts += (( int64_t ) AV_TIME_BASE *
2011-11-21 14:05:38 +01:00
ist -> st -> codec -> time_base . num * ticks ) /
ist -> st -> codec -> time_base . den ;
}
break ;
}
}
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-21 13:48:45 +01:00
if ( ! check_output_constraints ( ist , ost ) || ost -> encoding_needed )
continue ;
do_streamcopy ( ist , ost , pkt );
}
2011-07-27 20:56:59 +02:00
return 0 ;
}
2012-04-15 15:03:07 +02:00
static void print_sdp ( void )
2011-07-27 20:56:59 +02:00
{
2013-01-17 15:34:25 +02:00
char sdp [ 16384 ];
2011-08-17 09:56:08 +02:00
int i ;
2012-04-15 15:03:07 +02:00
AVFormatContext ** avc = av_malloc ( sizeof ( * avc ) * nb_output_files );
2011-08-17 09:56:08 +02:00
if ( ! avc )
2013-07-07 01:52:51 +02:00
exit_program ( 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 ;
2011-07-27 20:56:59 +02:00
2012-04-15 15:03:07 +02:00
av_sdp_create ( avc , nb_output_files , sdp , sizeof ( sdp ));
2011-07-27 20:56:59 +02:00
printf ( "SDP: \n %s \n " , sdp );
fflush ( stdout );
2011-08-17 09:56:08 +02:00
av_freep ( & avc );
2011-07-27 20:56:59 +02:00
}
2012-04-15 15:03:07 +02:00
static int init_input_stream ( int ist_index , char * error , int error_len )
2011-07-06 08:49:07 +02:00
{
2012-10-18 22:58:25 -06:00
int i , ret ;
2012-04-15 15:28:30 +02:00
InputStream * ist = input_streams [ ist_index ];
2011-07-06 08:49:07 +02:00
if ( ist -> decoding_needed ) {
AVCodec * codec = ist -> dec ;
if ( ! codec ) {
2011-11-06 13:00:13 +01:00
snprintf ( error , error_len , "Decoder (codec id %d) not found for input stream #%d:%d" ,
2011-07-06 08:49:07 +02:00
ist -> st -> codec -> codec_id , ist -> file_index , ist -> st -> index );
return AVERROR ( EINVAL );
}
/* update requested sample format for the decoder based on the
corresponding encoder sample format */
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
OutputStream * ost = output_streams [ i ];
2011-07-06 08:49:07 +02:00
if ( ost -> source_index == ist_index ) {
update_sample_fmt ( ist -> st -> codec , codec , ost -> st -> codec );
break ;
}
}
2013-01-21 21:10:18 +01:00
av_opt_set_int ( ist -> st -> codec , "refcounted_frames" , 1 , 0 );
2011-12-19 15:44:58 +01:00
2012-01-18 10:53:41 +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 ) {
2013-06-20 00:06:08 +02:00
char errbuf [ 128 ];
2012-10-18 22:58:25 -06:00
if ( ret == AVERROR_EXPERIMENTAL )
abort_codec_experimental ( codec , 0 );
2013-06-20 00:06:08 +02:00
av_strerror ( ret , errbuf , sizeof ( errbuf ));
snprintf ( error , error_len ,
"Error while opening decoder for input stream "
"#%d:%d : %s" ,
ist -> file_index , ist -> st -> index , errbuf );
2012-10-18 22:58:25 -06:00
return ret ;
2011-07-06 08:49:07 +02:00
}
assert_avoptions ( ist -> opts );
}
2012-02-05 21:12:43 +01:00
ist -> last_dts = ist -> st -> avg_frame_rate . num ? - ist -> st -> codec -> has_b_frames * AV_TIME_BASE / av_q2d ( ist -> st -> avg_frame_rate ) : 0 ;
2012-02-03 15:32:51 +01:00
ist -> next_dts = AV_NOPTS_VALUE ;
2011-07-06 08:49:07 +02:00
init_pts_correction ( & ist -> pts_ctx );
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 ];
if ( ost -> filter ) {
FilterGraph * fg = ost -> filter -> graph ;
int i ;
for ( i = 0 ; i < fg -> nb_inputs ; i ++ )
if ( fg -> inputs [ i ] -> ist -> st -> codec -> codec_type == ost -> st -> codec -> codec_type )
return fg -> inputs [ i ] -> ist ;
}
return NULL ;
}
2012-06-22 14:36:27 +02:00
static void parse_forced_key_frames ( char * kf , OutputStream * ost ,
AVCodecContext * avctx )
{
char * p ;
int n = 1 , i ;
int64_t t ;
for ( p = kf ; * p ; p ++ )
if ( * p == ',' )
n ++ ;
ost -> forced_kf_count = n ;
ost -> forced_kf_pts = av_malloc ( sizeof ( * ost -> forced_kf_pts ) * n );
if ( ! ost -> forced_kf_pts ) {
av_log ( NULL , AV_LOG_FATAL , "Could not allocate forced key frames array. \n " );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2012-06-22 14:36:27 +02:00
}
2012-04-30 22:48:42 +02:00
p = kf ;
2012-06-22 14:36:27 +02:00
for ( i = 0 ; i < n ; i ++ ) {
2012-04-30 22:48:42 +02:00
char * next = strchr ( p , ',' );
if ( next )
* next ++ = 0 ;
2012-06-22 14:36:27 +02:00
t = parse_time_or_die ( "force_key_frames" , p , 1 );
ost -> forced_kf_pts [ i ] = av_rescale_q ( t , AV_TIME_BASE_Q , avctx -> time_base );
2012-04-30 22:48:42 +02:00
p = next ;
2012-06-22 14:36:27 +02:00
}
}
2012-04-15 15:03:07 +02:00
static int transcode_init ( void )
2011-07-27 20:56:59 +02:00
{
2011-08-31 22:24:06 +02:00
int ret = 0 , i , j , k ;
2011-11-20 12:23:55 +01:00
AVFormatContext * oc ;
2012-08-05 08:30:24 +02:00
AVCodecContext * codec ;
2011-08-17 10:21:37 +02:00
OutputStream * ost ;
2011-07-27 20:56:59 +02:00
InputStream * ist ;
char error [ 1024 ];
int want_sdp = 1 ;
2011-08-17 10:27:17 +02:00
2011-08-29 09:16:42 +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-08-29 09:16:42 +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-08-29 09:16:42 +02:00
}
2011-07-27 20:56:59 +02:00
/* output stream init */
2011-11-20 12:32:27 +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-20 12:23:55 +01:00
if ( ! oc -> nb_streams && ! ( oc -> oformat -> flags & AVFMT_NOSTREAMS )) {
av_dump_format ( oc , i , oc -> filename , 1 );
2011-09-13 07:31:21 +02:00
av_log ( NULL , AV_LOG_ERROR , "Output file #%d does not contain any stream \n " , i );
2011-08-19 14:45:02 -07:00
return AVERROR ( EINVAL );
2011-07-27 20:56:59 +02: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 ;
2011-07-27 20:56:59 +02:00
/* for each output stream, we compute the right encoding parameters */
2011-08-17 10:21:37 +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 );
2011-07-27 20:56:59 +02:00
2011-10-30 07:10:08 +01:00
if ( ost -> attachment_filename )
continue ;
2011-11-20 12:32:27 +01:00
codec = ost -> st -> codec ;
2011-07-27 20:56:59 +02: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 ;
}
2011-07-27 20:56:59 +02:00
2011-10-23 11:22:33 +02:00
if ( ost -> stream_copy ) {
2013-05-26 15:31:09 +02:00
AVRational sar ;
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 ;
2011-07-27 20:56:59 +02:00
2011-08-19 11:26:21 -07:00
if ( extra_size > INT_MAX ) {
2011-08-19 14:45:02 -07:00
return AVERROR ( EINVAL );
2011-08-19 11:26:21 -07:00
}
2011-07-27 20:56:59 +02:00
/* if stream_copy is selected, no need to decode or encode */
2011-11-20 12:32:27 +01:00
codec -> codec_id = icodec -> codec_id ;
2011-07-27 20:56:59 +02:00
codec -> codec_type = icodec -> codec_type ;
2011-11-20 12:32:27 +01:00
if ( ! codec -> codec_tag ) {
if ( ! oc -> oformat -> codec_tag ||
av_codec_get_id ( oc -> oformat -> codec_tag , icodec -> codec_tag ) == codec -> codec_id ||
av_codec_get_tag ( oc -> oformat -> codec_tag , icodec -> codec_id ) <= 0 )
2011-07-27 20:56:59 +02:00
codec -> codec_tag = icodec -> codec_tag ;
}
2011-11-20 12:32:27 +01:00
codec -> bit_rate = icodec -> bit_rate ;
2011-07-27 20:56:59 +02:00
codec -> rc_max_rate = icodec -> rc_max_rate ;
codec -> rc_buffer_size = icodec -> rc_buffer_size ;
2011-12-13 18:49:06 -08:00
codec -> field_order = icodec -> field_order ;
2011-11-20 12:32:27 +01:00
codec -> extradata = av_mallocz ( extra_size );
2011-08-19 11:26:21 -07:00
if ( ! codec -> extradata ) {
2011-08-19 14:45:02 -07:00
return AVERROR ( ENOMEM );
2011-08-19 11:26:21 -07:00
}
2011-07-27 20:56:59 +02:00
memcpy ( codec -> extradata , icodec -> extradata , icodec -> extradata_size );
2011-11-20 12:32:27 +01:00
codec -> extradata_size = icodec -> extradata_size ;
2011-11-29 11:10:31 +01:00
if ( ! copy_tb ) {
2011-11-20 12:32:27 +01:00
codec -> time_base = icodec -> time_base ;
2011-07-27 20:56:59 +02:00
codec -> time_base . num *= icodec -> ticks_per_frame ;
av_reduce ( & codec -> time_base . num , & codec -> time_base . den ,
codec -> time_base . num , codec -> time_base . den , INT_MAX );
2011-11-20 12:32:27 +01:00
} else
2011-07-27 20:56:59 +02:00
codec -> time_base = ist -> st -> time_base ;
2011-11-20 12:32:27 +01:00
2011-12-30 01:58:29 +05:30
switch ( codec -> codec_type ) {
2011-07-27 20:56:59 +02:00
case AVMEDIA_TYPE_AUDIO :
2011-12-30 01:58:29 +05:30
if ( audio_volume != 256 ) {
2011-09-13 07:31:21 +02:00
av_log ( NULL , AV_LOG_FATAL , "-acodec copy and -vol are incompatible (frames are not decoded) \n " );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2011-07-27 20:56:59 +02:00
}
2011-11-20 12:32:27 +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-07-27 20:56:59 +02:00
codec -> audio_service_type = icodec -> audio_service_type ;
2011-11-20 12:32:27 +01:00
codec -> block_align = icodec -> block_align ;
2011-07-27 20:56:59 +02:00
break ;
case AVMEDIA_TYPE_VIDEO :
2011-11-20 12:32:27 +01:00
codec -> pix_fmt = icodec -> pix_fmt ;
codec -> width = icodec -> width ;
codec -> height = icodec -> height ;
codec -> has_b_frames = icodec -> has_b_frames ;
2013-05-26 15:31:09 +02:00
if ( ost -> frame_aspect_ratio )
sar = av_d2q ( ost -> frame_aspect_ratio * codec -> height / codec -> width , 255 );
else if ( ist -> st -> sample_aspect_ratio . num )
sar = ist -> st -> sample_aspect_ratio ;
else
sar = icodec -> sample_aspect_ratio ;
ost -> st -> sample_aspect_ratio = codec -> sample_aspect_ratio = sar ;
2011-07-27 20:56:59 +02:00
break ;
case AVMEDIA_TYPE_SUBTITLE :
2011-11-20 12:32:27 +01:00
codec -> width = icodec -> width ;
2011-07-27 20:56:59 +02:00
codec -> height = icodec -> height ;
break ;
case AVMEDIA_TYPE_DATA :
2011-09-27 10:37:22 +02:00
case AVMEDIA_TYPE_ATTACHMENT :
2011-07-27 20:56:59 +02:00
break ;
default :
abort ();
}
} else {
2012-04-18 06:53:11 +02:00
if ( ! ost -> enc ) {
/* should only happen when a default codec is not present. */
snprintf ( error , sizeof ( error ), "Automatic encoder selection "
"failed for output stream #%d:%d. Default encoder for "
"format %s is probably disabled. Please choose an "
"encoder manually. \n " , ost -> file_index , ost -> index ,
oc -> oformat -> name );
ret = AVERROR ( EINVAL );
goto dump_format ;
}
2011-11-20 12:32:27 +01:00
2012-04-01 15:08:33 +02:00
if ( ist )
ist -> decoding_needed = 1 ;
2011-09-27 08:16:26 +02:00
ost -> encoding_needed = 1 ;
2011-11-20 12:32:27 +01:00
2012-05-09 16:25:02 +02:00
/*
* We want CFR output if and only if one of those is true:
* 1) user specified output framerate with -r
* 2) user specified -vsync cfr
* 3) output format is CFR and the user didn't force vsync to
* something else than CFR
*
* in such a case, set ost->frame_rate
*/
if ( codec -> codec_type == AVMEDIA_TYPE_VIDEO &&
! ost -> frame_rate . num && ist &&
( video_sync_method == VSYNC_CFR ||
( video_sync_method == VSYNC_AUTO &&
! ( oc -> oformat -> flags & ( AVFMT_NOTIMESTAMPS | AVFMT_VARIABLE_FPS ))))) {
2012-08-24 17:42:46 +02:00
ost -> frame_rate = ist -> framerate . num ? ist -> framerate :
ist -> st -> avg_frame_rate . num ?
ist -> st -> avg_frame_rate :
( AVRational ){ 25 , 1 };
2012-05-09 16:25:02 +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
if ( ! ost -> filter &&
( codec -> codec_type == AVMEDIA_TYPE_VIDEO ||
codec -> codec_type == AVMEDIA_TYPE_AUDIO )) {
2012-04-01 15:08:33 +02:00
FilterGraph * fg ;
fg = init_simple_filtergraph ( ist , ost );
2012-05-26 12:47:47 +02:00
if ( configure_filtergraph ( fg )) {
2012-04-01 15:08:33 +02:00
av_log ( NULL , AV_LOG_FATAL , "Error opening filters! \n " );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2012-04-01 15:08:33 +02:00
}
2012-05-05 18:22:46 +02:00
}
2012-04-01 15:08:33 +02:00
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 ;
codec -> channels = av_get_channel_layout_nb_channels ( codec -> channel_layout );
codec -> time_base = ( AVRational ){ 1 , codec -> sample_rate };
break ;
case AVMEDIA_TYPE_VIDEO :
2012-05-09 16:25:02 +02:00
codec -> time_base = ost -> filter -> filter -> inputs [ 0 ] -> time_base ;
2011-07-27 20:56:59 +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 ;
codec -> pix_fmt = ost -> filter -> filter -> inputs [ 0 ] -> format ;
2012-03-23 15:46:30 +01:00
2012-08-05 08:30:24 +02:00
if ( icodec &&
( codec -> width != icodec -> width ||
codec -> height != icodec -> height ||
codec -> pix_fmt != icodec -> pix_fmt )) {
2012-03-23 15:46:30 +01:00
codec -> bits_per_raw_sample = 0 ;
}
2012-06-22 14:36:27 +02:00
if ( ost -> forced_keyframes )
parse_forced_key_frames ( ost -> forced_keyframes , ost ,
ost -> st -> codec );
2011-07-27 20:56:59 +02:00
break ;
case AVMEDIA_TYPE_SUBTITLE :
2012-02-05 14:28:19 +01:00
codec -> time_base = ( AVRational ){ 1 , 1000 };
2011-07-27 20:56:59 +02:00
break ;
default :
abort ();
break ;
}
/* two pass mode */
2011-09-27 08:21:48 +02:00
if (( codec -> flags & ( CODEC_FLAG_PASS1 | CODEC_FLAG_PASS2 ))) {
2011-07-27 20:56:59 +02:00
char logfilename [ 1024 ];
FILE * f ;
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 ,
2011-07-27 20:56:59 +02: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-12 17:43:48 +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 ));
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2012-03-12 17:43:48 +01:00
}
ost -> logfile = f ;
} else {
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 " ,
logfilename );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2012-03-12 17:43:48 +01:00
}
codec -> stats_in = logbuffer ;
2011-07-27 20:56:59 +02:00
}
2012-03-12 17:42:57 +01:00
}
2011-07-27 20:56:59 +02:00
}
}
}
/* open each encoder */
2011-08-17 10:21:37 +02:00
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
ost = output_streams [ i ];
2011-07-27 20:56:59 +02:00
if ( ost -> encoding_needed ) {
2011-11-20 12:32:27 +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 ) {
2011-07-27 20:56:59 +02:00
ost -> st -> codec -> subtitle_header = av_malloc ( dec -> subtitle_header_size );
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-18 10:53:41 +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-06 13:00:13 +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" ,
2011-07-27 20:56:59 +02:00
ost -> file_index , ost -> index );
goto dump_format ;
}
assert_avoptions ( ost -> opts );
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."
"It takes bits/s as argument, not kbits/s \n " );
extra_size += ost -> st -> codec -> extradata_size ;
2011-09-02 17:06:30 +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 );
2011-07-27 20:56:59 +02:00
}
}
2011-07-06 08:49:07 +02:00
/* init input streams */
for ( i = 0 ; i < nb_input_streams ; i ++ )
2012-04-15 15:03:07 +02:00
if (( ret = init_input_stream ( i , error , sizeof ( error ))) < 0 )
2011-07-06 08:49:07 +02:00
goto dump_format ;
2011-07-27 20:56:59 +02:00
2011-08-31 22:24:06 +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-08-31 22:24:06 +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-08-31 22:24:06 +02:00
discard = AVDISCARD_DEFAULT ;
break ;
}
p -> discard = discard ;
}
}
2011-07-27 20:56:59 +02:00
/* open files and write file headers */
2011-08-17 09:56:08 +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-20 12:23:55 +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 ];
2013-06-21 12:47:01 +02:00
av_strerror ( ret , errbuf , sizeof ( errbuf ));
snprintf ( error , sizeof ( error ),
"Could not write header for output file #%d "
"(incorrect codec parameters ?): %s" ,
i , errbuf );
2011-07-27 20:56:59 +02:00
ret = AVERROR ( EINVAL );
goto dump_format ;
}
2012-04-15 15:28:30 +02:00
assert_avoptions ( output_files [ i ] -> opts );
2011-11-20 12:23:55 +01:00
if ( strcmp ( oc -> oformat -> name , "rtp" )) {
2011-07-27 20:56:59 +02:00
want_sdp = 0 ;
}
}
dump_format :
/* dump the file output parameters - cannot be done before in case
of stream copy */
2011-11-20 12:32:27 +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 );
2011-07-27 20:56:59 +02:00
}
/* dump the stream mapping */
2011-09-13 07:31:21 +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-13 07:31:21 +02:00
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
ost = output_streams [ i ];
2011-10-30 07:10:08 +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 ;
}
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-06 13:00:13 +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-13 07:31:21 +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-06 13:00:13 +01:00
av_log ( NULL , AV_LOG_INFO , " [sync #%d:%d]" ,
2011-09-13 07:31:21 +02:00
ost -> sync_ist -> file_index ,
ost -> sync_ist -> st -> index );
2011-10-23 11:22:33 +02:00
if ( ost -> stream_copy )
2011-09-13 07:31:21 +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-13 07:31:21 +02:00
ost -> enc ? ost -> enc -> name : "?" );
av_log ( NULL , AV_LOG_INFO , " \n " );
2011-07-27 20:56:59 +02:00
}
if ( ret ) {
2011-09-13 07:31:21 +02:00
av_log ( NULL , AV_LOG_ERROR , "%s \n " , error );
2011-08-19 14:45:02 -07:00
return ret ;
2011-07-27 20:56:59 +02:00
}
if ( want_sdp ) {
2012-04-15 15:03:07 +02:00
print_sdp ();
2011-07-27 20:56:59 +02:00
}
2011-08-19 14:45:02 -07: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 20:01:55 +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-08 12:04:53 +02:00
output_streams [ of -> ost_index + j ] -> finished = 1 ;
2012-06-01 10:44:11 +02:00
continue ;
}
return 1 ;
}
return 0 ;
}
2012-08-04 12:12:50 +02:00
static InputFile * select_input_file ( void )
2012-06-01 11:00:27 +02:00
{
2012-08-04 12:12:50 +02:00
InputFile * ifile = NULL ;
2012-06-01 11:00:27 +02:00
int64_t ipts_min = INT64_MAX ;
2012-08-04 12:12:50 +02:00
int i ;
2012-06-01 11:00:27 +02:00
for ( i = 0 ; i < nb_input_streams ; i ++ ) {
InputStream * ist = input_streams [ i ];
int64_t ipts = ist -> last_dts ;
2012-08-04 12:04:02 +02:00
if ( ist -> discard || input_files [ ist -> file_index ] -> eagain )
2012-06-01 11:00:27 +02:00
continue ;
if ( ! input_files [ ist -> file_index ] -> eof_reached ) {
if ( ipts < ipts_min ) {
ipts_min = ipts ;
2012-08-04 12:12:50 +02:00
ifile = input_files [ ist -> file_index ];
2012-06-01 11:00:27 +02:00
}
}
}
2012-08-04 12:12:50 +02:00
return ifile ;
2012-06-01 11:00:27 +02:00
}
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 )
{
2013-04-23 20:34:59 +02:00
if ( f -> rate_emu ) {
int i ;
for ( i = 0 ; i < f -> nb_streams ; i ++ ) {
InputStream * ist = input_streams [ f -> ist_index + i ];
int64_t pts = av_rescale ( ist -> last_dts , 1000000 , AV_TIME_BASE );
int64_t now = av_gettime () - ist -> start ;
if ( pts > now )
return AVERROR ( EAGAIN );
}
}
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 ;
for ( i = 0 ; i < nb_input_files ; i ++ )
if ( input_files [ i ] -> eagain )
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-24 13:31:50 +02:00
/*
2012-08-04 18:35:27 +02:00
* Read one packet from an input file and send it for
* - decoding -> lavfi (audio/video)
* - decoding -> encoding -> muxing (subtitles)
* - muxing (streamcopy)
*
2012-08-24 13:31:50 +02:00
* Return
2012-08-04 18:35:27 +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
*/
static int process_input ( void )
{
InputFile * ifile ;
AVFormatContext * is ;
InputStream * ist ;
AVPacket pkt ;
int ret , i , j ;
/* select the stream that we must read now */
ifile = select_input_file ();
/* if none, if is finished */
if ( ! ifile ) {
if ( got_eagain ()) {
reset_eagain ();
av_usleep ( 10000 );
return AVERROR ( EAGAIN );
}
av_log ( NULL , AV_LOG_VERBOSE , "No more inputs to read from. \n " );
return AVERROR_EOF ;
}
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 )
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2012-08-04 18:35:27 +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 );
/* mark all outputs that don't go through lavfi as finished */
for ( j = 0 ; j < nb_output_streams ; j ++ ) {
OutputStream * ost = output_streams [ j ];
if ( ost -> source_index == ifile -> ist_index + i &&
( ost -> stream_copy || ost -> enc -> type == AVMEDIA_TYPE_SUBTITLE ))
2012-08-08 12:04:53 +02:00
ost -> finished = 1 ;
2012-08-04 18:35:27 +02:00
}
}
2012-08-11 11:50:32 +02:00
return AVERROR ( EAGAIN );
2012-08-04 18:35:27 +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 )
goto discard_packet ;
ist = input_streams [ ifile -> ist_index + pkt . stream_index ];
if ( ist -> discard )
goto discard_packet ;
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 ;
if ( pkt . dts != AV_NOPTS_VALUE && ist -> next_dts != AV_NOPTS_VALUE &&
( is -> iformat -> flags & AVFMT_TS_DISCONT )) {
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 (( FFABS ( delta ) > 1LL * dts_delta_threshold * AV_TIME_BASE || pkt_dts + 1 < ist -> last_dts ) && ! copy_ts ) {
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 );
}
}
ret = output_packet ( ist , & pkt );
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_ERROR , "Error while decoding stream #%d:%d \n " ,
ist -> file_index , ist -> st -> index );
if ( exit_on_error )
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2012-08-04 18:35:27 +02:00
}
discard_packet :
av_free_packet ( & pkt );
return 0 ;
}
2011-08-19 14:45:02 -07: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-19 14:45:02 -07:00
{
2012-08-04 18:35:27 +02:00
int ret , i , need_input = 1 ;
AVFormatContext * os ;
2011-08-19 14:45:02 -07:00
OutputStream * ost ;
InputStream * ist ;
int64_t timer_start ;
2012-04-15 15:03:07 +02:00
ret = transcode_init ();
2011-08-19 14:45:02 -07:00
if ( ret < 0 )
goto fail ;
2011-09-13 07:31:21 +02:00
av_log ( NULL , AV_LOG_INFO , "Press ctrl-c to stop encoding \n " );
2011-07-27 20:56:59 +02:00
term_init ();
timer_start = av_gettime ();
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 ) {
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 ;
2012-06-01 10:44:11 +02:00
}
2012-04-01 15:08:33 +02:00
2012-08-04 18:35:27 +02:00
/* read and process one input packet if needed */
if ( need_input ) {
ret = process_input ();
if ( ret == AVERROR_EOF )
need_input = 0 ;
}
ret = poll_filters ();
if ( ret < 0 ) {
if ( ret == AVERROR_EOF || ret == AVERROR ( EAGAIN ))
2011-07-27 20:56:59 +02:00
continue ;
2012-08-04 18:35:27 +02:00
av_log ( NULL , AV_LOG_ERROR , "Error while filtering. \n " );
2011-07-27 20:56:59 +02:00
break ;
}
/* dump report by using the output first video and audio streams */
2012-04-15 15:03:07 +02:00
print_report ( 0 , timer_start );
2011-07-27 20:56:59 +02:00
}
2012-06-11 15:34:12 +02:00
#if HAVE_PTHREADS
2012-06-02 07:26:41 +02:00
free_input_threads ();
#endif
2011-07-27 20:56:59 +02:00
/* at the end of stream, we must flush the decoder buffers */
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 );
2011-07-27 20:56:59 +02:00
}
}
2012-03-29 08:51:17 +02:00
poll_filters ();
2012-04-15 15:03:07 +02:00
flush_encoders ();
2011-07-27 20:56:59 +02:00
term_exit ();
/* write the trailer if needed and close file */
2011-12-30 01:58:29 +05:30
for ( i = 0 ; i < nb_output_files ; i ++ ) {
2012-04-15 15:28:30 +02:00
os = output_files [ i ] -> ctx ;
2011-07-27 20:56:59 +02:00
av_write_trailer ( os );
}
/* dump report by using the first video and audio streams */
2012-04-15 15:03:07 +02:00
print_report ( 1 , timer_start );
2011-07-27 20:56:59 +02:00
/* close each encoder */
2011-08-17 10:21:37 +02:00
for ( i = 0 ; i < nb_output_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
ost = output_streams [ i ];
2011-07-27 20:56:59 +02:00
if ( ost -> encoding_needed ) {
av_freep ( & ost -> st -> codec -> stats_in );
avcodec_close ( ost -> st -> codec );
}
}
/* close each decoder */
for ( i = 0 ; i < nb_input_streams ; i ++ ) {
2012-04-15 15:28:30 +02:00
ist = input_streams [ i ];
2011-07-27 20:56:59 +02:00
if ( ist -> decoding_needed ) {
avcodec_close ( ist -> st -> codec );
}
}
/* finished ! */
ret = 0 ;
fail :
2012-06-11 15:34:12 +02:00
#if HAVE_PTHREADS
2012-06-02 07:26:41 +02:00
free_input_threads ();
#endif
2011-07-27 20:56:59 +02:00
2011-08-17 10:21:37 +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 ];
2011-07-27 20:56:59 +02:00
if ( ost ) {
2011-10-23 11:22:33 +02:00
if ( ost -> stream_copy )
2011-07-27 20:56:59 +02:00
av_freep ( & ost -> st -> codec -> extradata );
if ( ost -> logfile ) {
fclose ( ost -> logfile );
ost -> logfile = NULL ;
}
av_freep ( & ost -> st -> codec -> subtitle_header );
av_free ( ost -> forced_kf_pts );
av_dict_free ( & ost -> opts );
2012-12-18 21:47:28 -05:00
av_dict_free ( & ost -> resample_opts );
2011-07-27 20:56:59 +02:00
}
}
}
return ret ;
}
static int64_t getutime ( void )
{
#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
}
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
}
int main ( int argc , char ** argv )
{
2012-06-08 21:35:16 +02:00
int ret ;
2011-07-27 20:56:59 +02:00
int64_t ti ;
2013-07-07 01:52:51 +02:00
register_exit ( avconv_cleanup );
2012-09-05 07:03:56 +00:00
2011-07-27 20:56:59 +02:00
av_log_set_flags ( AV_LOG_SKIP_REPEATED );
2011-09-26 08:15:37 +02:00
parse_loglevel ( argc , argv , options );
2011-07-27 20:56:59 +02:00
avcodec_register_all ();
#if CONFIG_AVDEVICE
avdevice_register_all ();
#endif
avfilter_register_all ();
av_register_all ();
2011-11-06 02:47:48 +02:00
avformat_network_init ();
2011-07-27 20:56:59 +02:00
show_banner ();
2012-06-08 21:35:16 +02:00
/* parse options and open all input/output files */
ret = avconv_parse_options ( argc , argv );
if ( ret < 0 )
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2011-07-27 20:56:59 +02:00
2011-12-30 01:58:29 +05:30
if ( nb_output_files <= 0 && nb_input_files == 0 ) {
2011-07-27 20:56:59 +02:00
show_usage ();
2011-09-13 07:31:21 +02:00
av_log ( NULL , AV_LOG_WARNING , "Use -h to get full help or, even better, run 'man %s' \n " , program_name );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2011-07-27 20:56:59 +02:00
}
/* file converter / grab */
if ( nb_output_files <= 0 ) {
fprintf ( stderr , "At least one output file must be specified \n " );
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2011-07-27 20:56:59 +02:00
}
ti = getutime ();
2012-04-15 15:03:07 +02:00
if ( transcode () < 0 )
2013-07-07 01:52:51 +02:00
exit_program ( 1 );
2011-07-27 20:56:59 +02:00
ti = getutime () - ti ;
if ( do_benchmark ) {
int maxrss = getmaxrss () / 1024 ;
printf ( "bench: utime=%0.3fs maxrss=%ikB \n " , ti / 1000000.0 , maxrss );
}
2013-07-07 01:52:51 +02:00
exit_program ( 0 );
2011-08-29 07:03:24 +02:00
return 0 ;
2011-07-27 20:56:59 +02:00
}