Newer
Older
* ffmpeg main
* Copyright (c) 2000-2003 Fabrice Bellard
* This file is part of FFmpeg.
* FFmpeg 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.
*
* FFmpeg 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 FFmpeg; 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 <unistd.h>
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavcodec/audioconvert.h"
#include "libavutil/audioconvert.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/colorspace.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"
#include "libavformat/os_support.h"
#include "libavformat/ffm.h" // not public API
# include "libavfilter/avcodec.h"
# include "libavfilter/avfilter.h"
# include "libavfilter/avfiltergraph.h"
Stefano Sabatini
committed
# include "libavfilter/buffersink.h"
# include "libavfilter/vsrc_buffer.h"
#endif
#if HAVE_SYS_RESOURCE_H
#include <sys/types.h>
#include <sys/time.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
#if HAVE_TERMIOS_H
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#elif HAVE_KBHIT
#include <conio.h>
#endif
#include <time.h>
#include "cmdutils.h"
#include "libavutil/avassert.h"
const char program_name[] = "avconv";
const int program_birth_year = 2000;
/* select an input stream for an output stream */
typedef struct StreamMap {
int disabled; /** 1 is this mapping is disabled by a negative map */
int file_index;
int stream_index;
int sync_file_index;
int sync_stream_index;
} StreamMap;
/**
* select an input file for an output file
*/
typedef struct MetadataMap {
int file; ///< file index
char type; ///< type of metadata to copy -- (g)lobal, (s)tream, (c)hapter or (p)rogram
int index; ///< stream/chapter/program number
} MetadataMap;
static const OptionDef options[];
#define MAX_STREAMS 1024 /* arbitrary sanity check value */
static int frame_bits_per_raw_sample = 0;
static int video_discard = 0;
static int do_deinterlace = 0;
static int intra_dc_precision = 8;
static int qp_hist = 0;
static int file_overwrite = 0;
static int do_benchmark = 0;
static int do_hex_dump = 0;
static int do_pkt_dump = 0;
static int do_pass = 0;
static const char *pass_logfilename_prefix;
static int video_sync_method= -1;
static int audio_sync_method= 0;
static float audio_drift_threshold= 0.1;
static int copy_ts= 0;
static int copy_tb= 0;
static int opt_shortest = 0;
static char *vstats_filename;
static FILE *vstats_file;
static int copy_initial_nonkeyframes = 0;
static int audio_volume = 256;
static int exit_on_error = 0;
static int using_stdin = 0;
static int run_as_daemon = 0;
static int q_pressed = 0;
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;
static int input_sync;
static float dts_delta_threshold = 10;
static int print_stats = 1;
static uint8_t *audio_buf;
static uint8_t *audio_out;
static unsigned int allocated_audio_out_size, allocated_audio_buf_size;
#define DEFAULT_PASS_LOGFILENAME_PREFIX "av2pass"
typedef struct InputStream {
int file_index;
AVStream *st;
int discard; /* true if stream data should be discarded */
int decoding_needed; /* true if the packets must be decoded in 'raw_fifo' */
AVCodec *dec;
int64_t start; /* time when read started */
int64_t next_pts; /* synthetic pts for cases where pkt.pts
is not defined */
int64_t pts; /* current pts */
double ts_scale;
int is_start; /* is 1 at the start and after a discontinuity */
int showed_multi_packet_warning;
AVDictionary *opts;
} InputStream;
typedef struct InputFile {
AVFormatContext *ctx;
int eof_reached; /* true if eof reached */
int ist_index; /* index of first stream in ist_table */
int buffer_size; /* current total buffer size */
int64_t ts_offset;
int nb_streams; /* number of stream that avconv is aware of; may be different
from ctx.nb_streams if new streams appear during av_read_frame() */
typedef struct OutputStream {
int file_index; /* file index */
int index; /* stream index in the output file */
int source_index; /* InputStream index */
AVStream *st; /* stream in the output file */
int encoding_needed; /* true if encoding needed for this stream */
int frame_number;
/* input pts and corresponding output pts
for A/V sync */
//double sync_ipts; /* dts from the AVPacket of the demuxer in second units */
struct InputStream *sync_ist; /* input stream to sync against */
int64_t sync_opts; /* output frame counter, could be changed to some true timestamp */ //FIXME look at frame_number
AVBitStreamFilterContext *bitstream_filters;
AVCodec *enc;
/* video only */
int video_resample;
AVFrame resample_frame; /* temporary frame for image resampling */
struct SwsContext *img_resample_ctx; /* for image resampling */
int resample_height;
int resample_width;
int resample_pix_fmt;
AVRational frame_rate;
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
float frame_aspect_ratio;
/* forced key frames */
int64_t *forced_kf_pts;
int forced_kf_count;
int forced_kf_index;
/* audio only */
int audio_resample;
ReSampleContext *resample; /* for audio resampling */
int resample_sample_fmt;
int resample_channels;
int resample_sample_rate;
int reformat_pair;
AVAudioConvert *reformat_ctx;
AVFifoBuffer *fifo; /* for compression: one audio fifo per codec */
FILE *logfile;
#if CONFIG_AVFILTER
AVFilterContext *output_video_filter;
AVFilterContext *input_video_filter;
AVFilterBufferRef *picref;
char *avfilter;
AVFilterGraph *graph;
#endif
int is_past_recording_time;
#if HAVE_TERMIOS_H
/* init terminal so that we can grab keys */
static struct termios oldtty;
#endif
Anton Khirnov
committed
typedef struct OutputFile {
AVFormatContext *ctx;
AVDictionary *opts;
int ost_index; /* index of the first stream in output_streams */
int64_t recording_time; /* desired length of the resulting file in microseconds */
int64_t start_time; /* start time in microseconds */
uint64_t limit_filesize;
Anton Khirnov
committed
} OutputFile;
static InputStream *input_streams = NULL;
static int nb_input_streams = 0;
static InputFile *input_files = NULL;
static int nb_input_files = 0;
static OutputStream *output_streams = NULL;
static int nb_output_streams = 0;
Anton Khirnov
committed
static OutputFile *output_files = NULL;
static int nb_output_files = 0;
Anton Khirnov
committed
/* input/output options */
int64_t start_time;
Anton Khirnov
committed
SpecifierOpt *codec_names;
int nb_codec_names;
SpecifierOpt *audio_channels;
int nb_audio_channels;
SpecifierOpt *audio_sample_rate;
int nb_audio_sample_rate;
SpecifierOpt *frame_rates;
int nb_frame_rates;
SpecifierOpt *frame_sizes;
int nb_frame_sizes;
SpecifierOpt *frame_pix_fmts;
int nb_frame_pix_fmts;
Anton Khirnov
committed
/* input options */
int64_t input_ts_offset;
Anton Khirnov
committed
SpecifierOpt *ts_scale;
int nb_ts_scale;
SpecifierOpt *dump_attachment;
int nb_dump_attachment;
Anton Khirnov
committed
/* output options */
StreamMap *stream_maps;
int nb_stream_maps;
/* first item specifies output metadata, second is input */
MetadataMap (*meta_data_maps)[2];
int nb_meta_data_maps;
int metadata_global_manual;
int metadata_streams_manual;
int metadata_chapters_manual;
const char **attachments;
int nb_attachments;
Anton Khirnov
committed
Anton Khirnov
committed
int64_t recording_time;
float mux_preload;
float mux_max_delay;
int video_disable;
int audio_disable;
int subtitle_disable;
int data_disable;
/* indexed by output file stream index */
int *streamid_map;
int nb_streamid_map;
SpecifierOpt *metadata;
int nb_metadata;
SpecifierOpt *max_frames;
int nb_max_frames;
SpecifierOpt *bitstream_filters;
int nb_bitstream_filters;
SpecifierOpt *codec_tags;
int nb_codec_tags;
SpecifierOpt *sample_fmts;
int nb_sample_fmts;
SpecifierOpt *qscale;
int nb_qscale;
SpecifierOpt *forced_key_frames;
int nb_forced_key_frames;
SpecifierOpt *force_fps;
int nb_force_fps;
SpecifierOpt *frame_aspect_ratios;
int nb_frame_aspect_ratios;
SpecifierOpt *rc_overrides;
int nb_rc_overrides;
SpecifierOpt *intra_matrices;
int nb_intra_matrices;
SpecifierOpt *inter_matrices;
int nb_inter_matrices;
SpecifierOpt *top_field_first;
int nb_top_field_first;
#if CONFIG_AVFILTER
SpecifierOpt *filters;
int nb_filters;
#endif
#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\
{\
int i, ret;\
for (i = 0; i < o->nb_ ## name; i++) {\
char *spec = o->name[i].specifier;\
if ((ret = check_stream_specifier(fmtctx, st, spec)) > 0)\
outvar = o->name[i].u.type;\
else if (ret < 0)\
exit_program(1);\
}\
}
static void reset_options(OptionsContext *o)
{
const OptionDef *po = options;
/* all OPT_SPEC and OPT_STRING can be freed in generic way */
while (po->name) {
void *dst = (uint8_t*)o + po->u.off;
if (po->flags & OPT_SPEC) {
SpecifierOpt **so = dst;
int i, *count = (int*)(so + 1);
for (i = 0; i < *count; i++) {
av_freep(&(*so)[i].specifier);
if (po->flags & OPT_STRING)
av_freep(&(*so)[i].u.str);
}
av_freep(so);
*count = 0;
} else if (po->flags & OPT_OFFSET && po->flags & OPT_STRING)
av_freep(dst);
po++;
}
av_freep(&o->stream_maps);
av_freep(&o->meta_data_maps);
av_freep(&o->streamid_map);
Anton Khirnov
committed
o->mux_max_delay = 0.7;
Anton Khirnov
committed
o->recording_time = INT64_MAX;
o->limit_filesize = UINT64_MAX;
o->chapters_input_file = INT_MAX;
Anton Khirnov
committed
uninit_opts();
init_opts();
}
#if CONFIG_AVFILTER
static int configure_video_filters(InputStream *ist, OutputStream *ost)
{
AVFilterContext *last_filter, *filter;
/** filter graph containing all filters including input & output */
AVCodecContext *codec = ost->st->codec;
AVCodecContext *icodec = ist->st->codec;
enum PixelFormat pix_fmts[] = { codec->pix_fmt, PIX_FMT_NONE };
AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc();
AVRational sample_aspect_ratio;
char args[255];
int ret;
ost->graph = avfilter_graph_alloc();
if (ist->st->sample_aspect_ratio.num){
sample_aspect_ratio = ist->st->sample_aspect_ratio;
}else
sample_aspect_ratio = ist->st->codec->sample_aspect_ratio;
snprintf(args, 255, "%d:%d:%d:%d:%d:%d:%d", ist->st->codec->width,
ist->st->codec->height, ist->st->codec->pix_fmt, 1, AV_TIME_BASE,
sample_aspect_ratio.num, sample_aspect_ratio.den);
ret = avfilter_graph_create_filter(&ost->input_video_filter, avfilter_get_by_name("buffer"),
"src", args, NULL, ost->graph);
if (ret < 0)
return ret;
#if FF_API_OLD_VSINK_API
ret = avfilter_graph_create_filter(&ost->output_video_filter, avfilter_get_by_name("buffersink"),
"out", NULL, pix_fmts, ost->graph);
#else
buffersink_params->pixel_fmts = pix_fmts;
ret = avfilter_graph_create_filter(&ost->output_video_filter, avfilter_get_by_name("buffersink"),
"out", NULL, buffersink_params, ost->graph);
#endif
av_freep(&buffersink_params);
if (ret < 0)
return ret;
last_filter = ost->input_video_filter;
if (codec->width != icodec->width || codec->height != icodec->height) {
snprintf(args, 255, "%d:%d:flags=0x%X",
codec->width,
codec->height,
if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
NULL, args, NULL, ost->graph)) < 0)
return ret;
if ((ret = avfilter_link(last_filter, 0, filter, 0)) < 0)
return ret;
last_filter = filter;
}
snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags);
ost->graph->scale_sws_opts = av_strdup(args);
if (ost->avfilter) {
AVFilterInOut *outputs = avfilter_inout_alloc();
AVFilterInOut *inputs = avfilter_inout_alloc();
outputs->name = av_strdup("in");
outputs->filter_ctx = last_filter;
outputs->pad_idx = 0;
outputs->next = NULL;
inputs->name = av_strdup("out");
inputs->filter_ctx = ost->output_video_filter;
inputs->pad_idx = 0;
inputs->next = NULL;
if ((ret = avfilter_graph_parse(ost->graph, ost->avfilter, &inputs, &outputs, NULL)) < 0)
return ret;
av_freep(&ost->avfilter);
} else {
if ((ret = avfilter_link(last_filter, 0, ost->output_video_filter, 0)) < 0)
return ret;
}
if ((ret = avfilter_graph_config(ost->graph, NULL)) < 0)
return ret;
codec->width = ost->output_video_filter->inputs[0]->w;
codec->height = ost->output_video_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->output_video_filter->inputs[0]->sample_aspect_ratio;
return 0;
}
#endif /* CONFIG_AVFILTER */
static void term_exit(void)
{
av_log(NULL, AV_LOG_QUIET, "%s", "");
#if HAVE_TERMIOS_H
if(!run_as_daemon)
tcsetattr (0, TCSANOW, &oldtty);
#endif
}
static volatile int received_sigterm = 0;
static void
sigterm_handler(int sig)
{
received_sigterm = sig;
q_pressed++;
term_exit();
}
static void term_init(void)
{
#if HAVE_TERMIOS_H
if(!run_as_daemon){
struct termios tty;
tcgetattr (0, &tty);
oldtty = tty;
atexit(term_exit);
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
|INLCR|IGNCR|ICRNL|IXON);
tty.c_oflag |= OPOST;
tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
tty.c_cflag &= ~(CSIZE|PARENB);
tty.c_cflag |= CS8;
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
tcsetattr (0, TCSANOW, &tty);
signal(SIGQUIT, sigterm_handler); /* Quit (POSIX). */
}
#endif
signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */
#ifdef SIGXCPU
signal(SIGXCPU, sigterm_handler);
#endif
}
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
/* read a key without blocking */
static int read_key(void)
{
#if HAVE_TERMIOS_H
int n = 1;
unsigned char ch;
struct timeval tv;
fd_set rfds;
if(run_as_daemon)
return -1;
FD_ZERO(&rfds);
FD_SET(0, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
n = select(1, &rfds, NULL, NULL, &tv);
if (n > 0) {
n = read(0, &ch, 1);
if (n == 1)
return ch;
return n;
}
#elif HAVE_KBHIT
if(kbhit())
return(getch());
#endif
return -1;
}
static int decode_interrupt_cb(void)
{
q_pressed += read_key() == 'q';
return q_pressed > 1;
void exit_program(int ret)
{
int i;
/* close files */
for(i=0;i<nb_output_files;i++) {
Anton Khirnov
committed
AVFormatContext *s = output_files[i].ctx;
if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
avio_close(s->pb);
avformat_free_context(s);
Anton Khirnov
committed
av_dict_free(&output_files[i].opts);
}
for(i=0;i<nb_input_files;i++) {
av_close_input_file(input_files[i].ctx);
}
for (i = 0; i < nb_input_streams; i++)
av_dict_free(&input_streams[i].opts);
if (vstats_file)
fclose(vstats_file);
av_free(vstats_filename);
av_freep(&input_streams);
av_freep(&input_files);
av_freep(&output_streams);
Anton Khirnov
committed
av_freep(&output_files);
uninit_opts();
av_free(audio_buf);
av_free(audio_out);
allocated_audio_buf_size= allocated_audio_out_size= 0;
av_free(samples);
#if CONFIG_AVFILTER
avfilter_uninit();
#endif
if (received_sigterm) {
av_log(NULL, AV_LOG_INFO, "Received signal %d: terminating.\n",
(int) received_sigterm);
exit (255);
}
exit(ret); /* not all OS-es handle main() return value */
}
static void assert_avoptions(AVDictionary *m)
{
AVDictionaryEntry *t;
if ((t = av_dict_get(m, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
av_log(NULL, AV_LOG_FATAL, "Option %s not found.\n", t->key);
exit_program(1);
}
}
static void assert_codec_experimental(AVCodecContext *c, int encoder)
{
const char *codec_string = encoder ? "encoder" : "decoder";
AVCodec *codec;
if (c->codec->capabilities & CODEC_CAP_EXPERIMENTAL &&
c->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
av_log(NULL, AV_LOG_FATAL, "%s '%s' is experimental and might produce bad "
"results.\nAdd '-strict experimental' if you want to use it.\n",
codec_string, c->codec->name);
codec = encoder ? avcodec_find_encoder(c->codec->id) : avcodec_find_decoder(c->codec->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);
exit_program(1);
}
}
static void choose_sample_fmt(AVStream *st, AVCodec *codec)
{
if(codec && codec->sample_fmts){
const enum AVSampleFormat *p= codec->sample_fmts;
for(; *p!=-1; p++){
if(*p == st->codec->sample_fmt)
break;
}
if (*p == -1) {
if((codec->capabilities & CODEC_CAP_LOSSLESS) && av_get_sample_fmt_name(st->codec->sample_fmt) > av_get_sample_fmt_name(codec->sample_fmts[0]))
av_log(NULL, AV_LOG_ERROR, "Convertion will not be lossless'\n");
if(av_get_sample_fmt_name(st->codec->sample_fmt))
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
av_log(NULL, AV_LOG_WARNING,
"Incompatible sample format '%s' for codec '%s', auto-selecting format '%s'\n",
av_get_sample_fmt_name(st->codec->sample_fmt),
codec->name,
av_get_sample_fmt_name(codec->sample_fmts[0]));
st->codec->sample_fmt = codec->sample_fmts[0];
}
}
}
static void choose_sample_rate(AVStream *st, AVCodec *codec)
{
if(codec && codec->supported_samplerates){
const int *p= codec->supported_samplerates;
int best=0;
int best_dist=INT_MAX;
for(; *p; p++){
int dist= abs(st->codec->sample_rate - *p);
if(dist < best_dist){
best_dist= dist;
best= *p;
}
}
if(best_dist){
av_log(st->codec, AV_LOG_WARNING, "Requested sampling rate unsupported using closest supported (%d)\n", best);
}
st->codec->sample_rate= best;
}
}
static void choose_pixel_fmt(AVStream *st, AVCodec *codec)
{
if(codec && codec->pix_fmts){
const enum PixelFormat *p= codec->pix_fmts;
if(st->codec->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL){
if(st->codec->codec_id==CODEC_ID_MJPEG){
p= (const enum PixelFormat[]){PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_NONE};
}else if(st->codec->codec_id==CODEC_ID_LJPEG){
p= (const enum PixelFormat[]){PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ444P, PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_YUV444P, PIX_FMT_BGRA, PIX_FMT_NONE};
}
}
for(; *p!=-1; p++){
if(*p == st->codec->pix_fmt)
break;
}
if (*p == -1) {
if(st->codec->pix_fmt != PIX_FMT_NONE)
av_log(NULL, AV_LOG_WARNING,
"Incompatible pixel format '%s' for codec '%s', auto-selecting format '%s'\n",
av_pix_fmt_descriptors[st->codec->pix_fmt].name,
codec->name,
av_pix_fmt_descriptors[codec->pix_fmts[0]].name);
st->codec->pix_fmt = codec->pix_fmts[0];
}
}
}
static double
get_sync_ipts(const OutputStream *ost)
{
const InputStream *ist = ost->sync_ist;
OutputFile *of = &output_files[ost->file_index];
return (double)(ist->pts - of->start_time)/AV_TIME_BASE;
}
static void write_frame(AVFormatContext *s, AVPacket *pkt, AVCodecContext *avctx, AVBitStreamFilterContext *bsfc){
int ret;
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){
av_free_packet(pkt);
new_pkt.destruct= av_destruct_packet;
} else if(a<0){
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");
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
print_error("", a);
if (exit_on_error)
exit_program(1);
}
*pkt= new_pkt;
bsfc= bsfc->next;
}
ret= av_interleaved_write_frame(s, pkt);
if(ret < 0){
print_error("av_interleaved_write_frame()", ret);
exit_program(1);
}
}
static void do_audio_out(AVFormatContext *s,
OutputStream *ost,
InputStream *ist,
unsigned char *buf, int size)
{
uint8_t *buftmp;
int64_t audio_out_size, audio_buf_size;
int64_t allocated_for_size= size;
int size_out, frame_bytes, ret, resample_changed;
AVCodecContext *enc= ost->st->codec;
AVCodecContext *dec= ist->st->codec;
int osize = av_get_bytes_per_sample(enc->sample_fmt);
int isize = av_get_bytes_per_sample(dec->sample_fmt);
const int coded_bps = av_get_bits_per_sample(enc->codec->id);
need_realloc:
audio_buf_size= (allocated_for_size + isize*dec->channels - 1) / (isize*dec->channels);
audio_buf_size= (audio_buf_size*enc->sample_rate + dec->sample_rate) / dec->sample_rate;
audio_buf_size= audio_buf_size*2 + 10000; //safety factors for the deprecated resampling API
audio_buf_size= FFMAX(audio_buf_size, enc->frame_size);
audio_buf_size*= osize*enc->channels;
audio_out_size= FFMAX(audio_buf_size, enc->frame_size * osize * enc->channels);
if(coded_bps > 8*osize)
audio_out_size= audio_out_size * coded_bps / (8*osize);
audio_out_size += FF_MIN_BUFFER_SIZE;
if(audio_out_size > INT_MAX || audio_buf_size > INT_MAX){
av_log(NULL, AV_LOG_FATAL, "Buffer sizes too large\n");
exit_program(1);
}
av_fast_malloc(&audio_buf, &allocated_audio_buf_size, audio_buf_size);
av_fast_malloc(&audio_out, &allocated_audio_out_size, audio_out_size);
if (!audio_buf || !audio_out){
av_log(NULL, AV_LOG_FATAL, "Out of memory in do_audio_out\n");
exit_program(1);
}
if (enc->channels != dec->channels)
ost->audio_resample = 1;
resample_changed = ost->resample_sample_fmt != dec->sample_fmt ||
ost->resample_channels != dec->channels ||
ost->resample_sample_rate != dec->sample_rate;
if ((ost->audio_resample && !ost->resample) || resample_changed) {
if (resample_changed) {
av_log(NULL, AV_LOG_INFO, "Input stream #%d.%d frame changed from rate:%d fmt:%s ch:%d to rate:%d fmt:%s ch:%d\n",
ist->file_index, ist->st->index,
ost->resample_sample_rate, av_get_sample_fmt_name(ost->resample_sample_fmt), ost->resample_channels,
dec->sample_rate, av_get_sample_fmt_name(dec->sample_fmt), dec->channels);
ost->resample_sample_fmt = dec->sample_fmt;
ost->resample_channels = dec->channels;
ost->resample_sample_rate = dec->sample_rate;
if (ost->resample)
audio_resample_close(ost->resample);
}
/* if audio_sync_method is >1 the resampler is needed for audio drift compensation */
if (audio_sync_method <= 1 &&
ost->resample_sample_fmt == enc->sample_fmt &&
ost->resample_channels == enc->channels &&
ost->resample_sample_rate == enc->sample_rate) {
ost->resample = NULL;
ost->audio_resample = 0;
if (dec->sample_fmt != AV_SAMPLE_FMT_S16)
av_log(NULL, AV_LOG_WARNING, "Using s16 intermediate sample format for resampling\n");
ost->resample = av_audio_resample_init(enc->channels, dec->channels,
enc->sample_rate, dec->sample_rate,
enc->sample_fmt, dec->sample_fmt,
16, 10, 0, 0.8);
if (!ost->resample) {
av_log(NULL, AV_LOG_FATAL, "Can not resample %d channels @ %d Hz to %d channels @ %d Hz\n",
dec->channels, dec->sample_rate,
enc->channels, enc->sample_rate);
exit_program(1);
}
}
}
#define MAKE_SFMT_PAIR(a,b) ((a)+AV_SAMPLE_FMT_NB*(b))
if (!ost->audio_resample && dec->sample_fmt!=enc->sample_fmt &&
MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt)!=ost->reformat_pair) {
if (ost->reformat_ctx)
av_audio_convert_free(ost->reformat_ctx);
ost->reformat_ctx = av_audio_convert_alloc(enc->sample_fmt, 1,
dec->sample_fmt, 1, NULL, 0);
if (!ost->reformat_ctx) {
av_log(NULL, AV_LOG_FATAL, "Cannot convert %s sample format to %s sample format\n",
av_get_sample_fmt_name(dec->sample_fmt),
av_get_sample_fmt_name(enc->sample_fmt));
exit_program(1);
}
ost->reformat_pair=MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt);
}
if(audio_sync_method){
double delta = get_sync_ipts(ost) * enc->sample_rate - ost->sync_opts
- av_fifo_size(ost->fifo)/(enc->channels * 2);
double idelta= delta*dec->sample_rate / enc->sample_rate;
int byte_delta= ((int)idelta)*2*dec->channels;
//FIXME resample delay
if(fabs(delta) > 50){
if(ist->is_start || fabs(delta) > audio_drift_threshold*enc->sample_rate){
if(byte_delta < 0){
byte_delta= FFMAX(byte_delta, -size);
size += byte_delta;
buf -= byte_delta;
av_log(NULL, AV_LOG_VERBOSE, "discarding %d audio samples\n", (int)-delta);
if(!size)
return;
ist->is_start=0;
}else{
static uint8_t *input_tmp= NULL;
input_tmp= av_realloc(input_tmp, byte_delta + size);
if(byte_delta > allocated_for_size - size){
allocated_for_size= byte_delta + (int64_t)size;
goto need_realloc;
}
ist->is_start=0;
memset(input_tmp, 0, byte_delta);
memcpy(input_tmp + byte_delta, buf, size);
buf= input_tmp;
size += byte_delta;
av_log(NULL, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", (int)delta);
}
}else if(audio_sync_method>1){
int comp= av_clip(delta, -audio_sync_method, audio_sync_method);
av_assert0(ost->audio_resample);
av_log(NULL, AV_LOG_VERBOSE, "compensating audio timestamp drift:%f compensation:%d in:%d\n",
delta, comp, enc->sample_rate);
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
// fprintf(stderr, "drift:%f len:%d opts:%"PRId64" ipts:%"PRId64" fifo:%d\n", delta, -1, ost->sync_opts, (int64_t)(get_sync_ipts(ost) * enc->sample_rate), av_fifo_size(ost->fifo)/(ost->st->codec->channels * 2));
av_resample_compensate(*(struct AVResampleContext**)ost->resample, comp, enc->sample_rate);
}
}
}else
ost->sync_opts= lrintf(get_sync_ipts(ost) * enc->sample_rate)
- av_fifo_size(ost->fifo)/(enc->channels * 2); //FIXME wrong
if (ost->audio_resample) {
buftmp = audio_buf;
size_out = audio_resample(ost->resample,
(short *)buftmp, (short *)buf,
size / (dec->channels * isize));
size_out = size_out * enc->channels * osize;
} else {
buftmp = buf;
size_out = size;
}
if (!ost->audio_resample && dec->sample_fmt!=enc->sample_fmt) {
const void *ibuf[6]= {buftmp};
void *obuf[6]= {audio_buf};
int istride[6]= {isize};
int ostride[6]= {osize};
int len= size_out/istride[0];
if (av_audio_convert(ost->reformat_ctx, obuf, ostride, ibuf, istride, len)<0) {
printf("av_audio_convert() failed\n");
if (exit_on_error)
exit_program(1);
return;
}
buftmp = audio_buf;
size_out = len*osize;
}
/* now encode as many frames as possible */
if (enc->frame_size > 1) {
/* output resampled raw samples */
if (av_fifo_realloc2(ost->fifo, av_fifo_size(ost->fifo) + size_out) < 0) {
av_log(NULL, AV_LOG_FATAL, "av_fifo_realloc2() failed\n");
exit_program(1);
}
av_fifo_generic_write(ost->fifo, buftmp, size_out, NULL);
frame_bytes = enc->frame_size * osize * enc->channels;
while (av_fifo_size(ost->fifo) >= frame_bytes) {
AVPacket pkt;
av_init_packet(&pkt);
av_fifo_generic_read(ost->fifo, audio_buf, frame_bytes, NULL);
//FIXME pass ost->sync_opts as AVFrame.pts in avcodec_encode_audio()
ret = avcodec_encode_audio(enc, audio_out, audio_out_size,
(short *)audio_buf);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
exit_program(1);
}
audio_size += ret;
pkt.stream_index= ost->index;
pkt.data= audio_out;
pkt.size= ret;
if(enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
pkt.pts= av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
pkt.flags |= AV_PKT_FLAG_KEY;
write_frame(s, &pkt, enc, ost->bitstream_filters);
ost->sync_opts += enc->frame_size;
}
} else {
AVPacket pkt;
av_init_packet(&pkt);
ost->sync_opts += size_out / (osize * enc->channels);
/* output a pcm frame */
/* determine the size of the coded buffer */
size_out /= osize;
if (coded_bps)
size_out = size_out*coded_bps/8;
if(size_out > audio_out_size){
av_log(NULL, AV_LOG_FATAL, "Internal error, buffer size too small\n");
exit_program(1);
}
//FIXME pass ost->sync_opts as AVFrame.pts in avcodec_encode_audio()