Newer
Older
Diego Biurrun
committed
* 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
Diego Biurrun
committed
* version 2.1 of the License, or (at your option) any later version.
Diego Biurrun
committed
* FFmpeg is distributed in the hope that it will be useful,
* 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
Diego Biurrun
committed
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Diego Biurrun
committed
Aurelien Jacobs
committed
/* needed for usleep() */
Aurelien Jacobs
committed
#include "config.h"
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <errno.h>
Aurelien Jacobs
committed
#include <unistd.h>
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavcodec/opt.h"
#include "libavcodec/audioconvert.h"
#include "libavcore/parseutils.h"
#include "libavutil/colorspace.h"
#include "libavutil/fifo.h"
#include "libavutil/pixdesc.h"
#include "libavutil/avstring.h"
#include "libavformat/os_support.h"
#if CONFIG_AVFILTER
# include "libavfilter/avfilter.h"
# include "libavfilter/avfiltergraph.h"
# include "libavfilter/graphparser.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
#include <sys/select.h>
#endif
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
Michael Niedermayer
committed
const char program_name[] = "FFmpeg";
const int program_birth_year = 2000;
/* select an input stream for an output stream */
typedef struct AVStreamMap {
int file_index;
int stream_index;
int sync_file_index;
int sync_stream_index;
/**
* select an input file for an output file
*/
Patrice Bensoussan
committed
typedef struct AVMetaDataMap {
int out_file;
int in_file;
} AVMetaDataMap;
Diego Pettenò
committed
static const OptionDef options[];
#define MAX_FILES 100
static const char *last_asked_format = NULL;
static int64_t input_files_ts_offset[MAX_FILES];
static double input_files_ts_scale[MAX_FILES][MAX_STREAMS];
static AVCodec *input_codecs[MAX_FILES*MAX_STREAMS];
static AVCodec *output_codecs[MAX_FILES*MAX_STREAMS];
static AVStreamMap stream_maps[MAX_FILES*MAX_STREAMS];
Patrice Bensoussan
committed
static AVMetaDataMap meta_data_maps[MAX_FILES];
static int nb_meta_data_maps;
/* indexed by output file stream index */
static int streamid_map[MAX_STREAMS];
static int frame_width = 0;
static int frame_height = 0;
static float frame_aspect_ratio = 0;
static enum PixelFormat frame_pix_fmt = PIX_FMT_NONE;
static enum SampleFormat audio_sample_fmt = SAMPLE_FMT_NONE;
Michael Niedermayer
committed
static int frame_topBand = 0;
static int frame_bottomBand = 0;
static int frame_leftBand = 0;
static int frame_rightBand = 0;
Fabrice Bellard
committed
static int max_frames[4] = {INT_MAX, INT_MAX, INT_MAX, INT_MAX};
Michael Niedermayer
committed
static float video_qscale = 0;
Vidar Madsen
committed
static uint16_t *intra_matrix = NULL;
static uint16_t *inter_matrix = NULL;
static const char *video_rc_override_string=NULL;
static int video_discard = 0;
static char *video_codec_name = NULL;
static unsigned int video_codec_tag = 0;
static char *video_language = NULL;
static int do_deinterlace = 0;
Michael Niedermayer
committed
static int me_threshold = 0;
static int loop_input = 0;
static int loop_output = AVFMT_NOOUTPUTLOOP;
#if CONFIG_AVFILTER
static char *vfilters = NULL;
AVFilterGraph *graph = NULL;
static int intra_only = 0;
static int audio_sample_rate = 44100;
static int64_t channel_layout = 0;
#define QSCALE_NONE -99999
static float audio_qscale = QSCALE_NONE;
static int audio_disable = 0;
static int audio_channels = 1;
static char *audio_codec_name = NULL;
static unsigned int audio_codec_tag = 0;
Fabrice Bellard
committed
static char *audio_language = NULL;
static int subtitle_disable = 0;
static char *subtitle_codec_name = NULL;
Fabrice Bellard
committed
static char *subtitle_language = NULL;
static unsigned int subtitle_codec_tag = 0;
static float mux_preload= 0.5;
static float mux_max_delay= 0.7;
static int64_t recording_time = INT64_MAX;
static int64_t start_time = 0;
static int64_t recording_timestamp = 0;
static int metadata_count;
static AVMetadataTag *metadata;
static int do_hex_dump = 0;
static int do_pkt_dump = 0;
static int do_psnr = 0;
static int do_pass = 0;
static int audio_stream_copy = 0;
static int video_stream_copy = 0;
Fabrice Bellard
committed
static int subtitle_stream_copy = 0;
static int video_sync_method= -1;
static int audio_sync_method= 0;
Michael Niedermayer
committed
static int video_global_header = 0;
static FILE *vstats_file;
Nico Sabbi
committed
static int opt_programid = 0;
Wolfram Gloger
committed
static int copy_initial_nonkeyframes = 0;
Max Krasnyansky
committed
static int rate_emu = 0;
Fabrice Bellard
committed
static int video_channel = 0;
static char *video_standard;
Fabrice Bellard
committed
Michael Niedermayer
committed
static int audio_volume = 256;
static int exit_on_error = 0;
static int using_stdin = 0;
static int verbose = 1;
Leon van Stuivenberg
committed
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 uint64_t limit_filesize = 0;
static int force_fps = 0;
static int pgmyuv_compatibility_hack=0;
static float dts_delta_threshold = 10;
static unsigned int sws_flags = SWS_BICUBIC;
static uint8_t *audio_buf;
static uint8_t *audio_out;
Michael Niedermayer
committed
unsigned int allocated_audio_out_size, allocated_audio_buf_size;
static short *samples;
Michael Niedermayer
committed
static AVBitStreamFilterContext *video_bitstream_filters=NULL;
static AVBitStreamFilterContext *audio_bitstream_filters=NULL;
static AVBitStreamFilterContext *subtitle_bitstream_filters=NULL;
Michael Niedermayer
committed
static AVBitStreamFilterContext *bitstream_filters[MAX_FILES][MAX_STREAMS];
#define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass"
struct AVInputStream;
typedef struct AVOutputStream {
int file_index; /* file index */
int index; /* stream index in the output file */
int source_index; /* AVInputStream index */
AVStream *st; /* stream in the output file */
Fabrice Bellard
committed
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 AVInputStream *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
int video_resample;
Michael Niedermayer
committed
AVFrame pict_tmp; /* temporary image for resampling */
struct SwsContext *img_resample_ctx; /* for image resampling */
int resample_height;
Jason Garrett-Glaser
committed
int resample_pix_fmt;
/* full frame size of first frame */
int original_height;
int original_width;
/* cropping area sizes */
int video_crop;
int topBand;
int bottomBand;
int leftBand;
int rightBand;
/* cropping area of first frame */
int original_topBand;
int original_bottomBand;
int original_leftBand;
int original_rightBand;
/* audio only */
int audio_resample;
ReSampleContext *resample; /* for audio resampling */
int reformat_pair;
AVAudioConvert *reformat_ctx;
Michael Niedermayer
committed
AVFifoBuffer *fifo; /* for compression: one audio fifo per codec */
} AVOutputStream;
typedef struct AVInputStream {
int file_index;
int 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' */
int64_t sample_index; /* current sample */
Max Krasnyansky
committed
int64_t start; /* time when read started */
int64_t next_pts; /* synthetic pts for cases where pkt.pts
is not defined */
int is_start; /* is 1 at the start and after a discontinuity */
Michael Niedermayer
committed
int showed_multi_packet_warning;
int is_past_recording_time;
AVFilterContext *output_video_filter;
AVFilterContext *input_video_filter;
AVFrame *filter_frame;
int has_filter_frame;
AVFilterBufferRef *picref;
} AVInputStream;
typedef struct AVInputFile {
int eof_reached; /* true if eof reached */
int ist_index; /* index of first stream in ist_table */
int buffer_size; /* current total buffer size */
int nb_streams; /* nb streams we are aware of */
/* init terminal so that we can grab keys */
static struct termios oldtty;
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
#if CONFIG_AVFILTER
typedef struct {
int pix_fmt;
} FilterOutPriv;
static int output_init(AVFilterContext *ctx, const char *args, void *opaque)
{
FilterOutPriv *priv = ctx->priv;
if(!opaque) return -1;
priv->pix_fmt = *((int *)opaque);
return 0;
}
static void output_end_frame(AVFilterLink *link)
{
}
static int output_query_formats(AVFilterContext *ctx)
{
FilterOutPriv *priv = ctx->priv;
enum PixelFormat pix_fmts[] = { priv->pix_fmt, PIX_FMT_NONE };
avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts));
return 0;
}
static int get_filtered_video_pic(AVFilterContext *ctx,
AVFilterBufferRef **picref, AVFrame *pic2,
AVFilterBufferRef *pic;
if(avfilter_request_frame(ctx->inputs[0]))
return -1;
*pts = pic->pts;
memcpy(pic2->data, pic->data, sizeof(pic->data));
memcpy(pic2->linesize, pic->linesize, sizeof(pic->linesize));
S.N. Hemanth Meenakshisundaram
committed
pic2->interlaced_frame = pic->video->interlaced;
pic2->top_field_first = pic->video->top_field_first;
return 1;
}
static AVFilter output_filter =
{
.name = "ffmpeg_output",
.priv_size = sizeof(FilterOutPriv),
.init = output_init,
.query_formats = output_query_formats,
.inputs = (AVFilterPad[]) {{ .name = "default",
.type = AVMEDIA_TYPE_VIDEO,
.end_frame = output_end_frame,
.min_perms = AV_PERM_READ, },
{ .name = NULL }},
.outputs = (AVFilterPad[]) {{ .name = NULL }},
};
static int configure_filters(AVInputStream *ist, AVOutputStream *ost)
{
AVFilterContext *last_filter, *filter;
/** filter graph containing all filters including input & output */
AVCodecContext *codec = ost->st->codec;
AVCodecContext *icodec = ist->st->codec;
char args[255];
int ret;
graph = av_mallocz(sizeof(AVFilterGraph));
if ((ret = avfilter_open(&ist->input_video_filter, avfilter_get_by_name("buffer"), "src")) < 0)
return ret;
if ((ret = avfilter_open(&ist->output_video_filter, &output_filter, "out")) < 0)
return ret;
snprintf(args, 255, "%d:%d:%d", ist->st->codec->width,
ist->st->codec->height, ist->st->codec->pix_fmt);
if ((ret = avfilter_init_filter(ist->input_video_filter, args, NULL)) < 0)
return ret;
if ((ret = avfilter_init_filter(ist->output_video_filter, NULL, &codec->pix_fmt)) < 0)
return ret;
/* add input and output filters to the overall graph */
avfilter_graph_add_filter(graph, ist->input_video_filter);
avfilter_graph_add_filter(graph, ist->output_video_filter);
last_filter = ist->input_video_filter;
snprintf(args, 255, "%d:%d:%d:%d",
codec->width, codec->height,
ost->leftBand, ost->topBand);
if ((ret = avfilter_open(&filter, avfilter_get_by_name("crop"), NULL)) < 0)
return ret;
if ((ret = avfilter_init_filter(filter, args, NULL)) < 0)
return ret;
if ((ret = avfilter_link(last_filter, 0, filter, 0)) < 0)
return ret;
last_filter = filter;
avfilter_graph_add_filter(graph, last_filter);
icodec->width - (frame_leftBand + frame_rightBand)) ||
(codec->height != icodec->height - (frame_topBand + frame_bottomBand))) {
snprintf(args, 255, "%d:%d:flags=0x%X",
codec->width,
codec->height,
(int)av_get_int(sws_opts, "sws_flags", NULL));
if ((ret = avfilter_open(&filter, avfilter_get_by_name("scale"), NULL)) < 0)
return ret;
if ((ret = avfilter_init_filter(filter, args, NULL)) < 0)
return ret;
if ((ret = avfilter_link(last_filter, 0, filter, 0)) < 0)
return ret;
last_filter = filter;
avfilter_graph_add_filter(graph, last_filter);
snprintf(args, sizeof(args), "flags=0x%X", (int)av_get_int(sws_opts, "sws_flags", NULL));
graph->scale_sws_opts = av_strdup(args);
AVFilterInOut *outputs = av_malloc(sizeof(AVFilterInOut));
AVFilterInOut *inputs = av_malloc(sizeof(AVFilterInOut));
outputs->name = av_strdup("in");
outputs->filter = last_filter;
outputs->pad_idx = 0;
outputs->next = NULL;
inputs->name = av_strdup("out");
inputs->filter = ist->output_video_filter;
inputs->pad_idx = 0;
inputs->next = NULL;
if ((ret = avfilter_graph_parse(graph, vfilters, inputs, outputs, NULL)) < 0)
return ret;
if ((ret = avfilter_link(last_filter, 0, ist->output_video_filter, 0)) < 0)
return ret;
}
/* configure all the filter links */
if ((ret = avfilter_graph_check_validity(graph, NULL)) < 0)
return ret;
if ((ret = avfilter_graph_config_formats(graph, NULL)) < 0)
return ret;
if ((ret = avfilter_graph_config_links(graph, NULL)) < 0)
return ret;
codec->width = ist->output_video_filter->inputs[0]->w;
codec->height = ist->output_video_filter->inputs[0]->h;
return 0;
}
#endif /* CONFIG_AVFILTER */
av_log(NULL, AV_LOG_QUIET, "");
static volatile int received_sigterm = 0;
Roumen Petrov
committed
static void
sigterm_handler(int sig)
{
received_sigterm = sig;
term_exit();
}
struct termios tty;
tcgetattr (0, &tty);
oldtty = tty;
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;
signal(SIGQUIT, sigterm_handler); /* Quit (POSIX). */
#endif
Roumen Petrov
committed
signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */
#ifdef SIGXCPU
signal(SIGXCPU, sigterm_handler);
#endif
}
/* read a key without blocking */
static int read_key(void)
{
int n = 1;
struct timeval tv;
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(0, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
n = select(1, &rfds, NULL, NULL, &tv);
if (n > 0) {
n = read(0, &ch, 1);
if (n == 1)
return n;
Leon van Stuivenberg
committed
static int decode_interrupt_cb(void)
{
return q_pressed || (q_pressed = read_key() == 'q');
}
{
int i;
/* close files */
for(i=0;i<nb_output_files;i++) {
/* maybe av_close_output_file ??? */
AVFormatContext *s = output_files[i];
int j;
if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
url_fclose(s->pb);
for(j=0;j<s->nb_streams;j++) {
av_metadata_free(&s->streams[j]->metadata);
av_free(s->streams[j]->codec);
av_free(s->streams[j]);
}
for(j=0;j<s->nb_programs;j++) {
av_metadata_free(&s->programs[j]->metadata);
}
for(j=0;j<s->nb_chapters;j++) {
av_metadata_free(&s->chapters[j]->metadata);
}
av_metadata_free(&s->metadata);
av_free(s);
}
for(i=0;i<nb_input_files;i++)
av_close_input_file(input_files[i]);
av_free(intra_matrix);
av_free(inter_matrix);
if (vstats_file)
fclose(vstats_file);
av_free(vstats_filename);
av_free(opt_names);
av_free(video_codec_name);
av_free(audio_codec_name);
av_free(subtitle_codec_name);
av_free(video_standard);
for (i=0;i<AVMEDIA_TYPE_NB;i++)
av_free(avcodec_opts[i]);
av_free(avformat_opts);
av_free(sws_opts);
av_free(audio_buf);
av_free(audio_out);
Michael Niedermayer
committed
allocated_audio_buf_size= allocated_audio_out_size= 0;
av_free(samples);
#if CONFIG_AVFILTER
avfilter_uninit();
#endif
if (received_sigterm) {
fprintf(stderr,
"Received signal %d: terminating.\n",
(int) received_sigterm);
exit (255);
}
exit(ret); /* not all OS-es handle main() return value */
return ret;
Ronald S. Bultje
committed
static void choose_sample_fmt(AVStream *st, AVCodec *codec)
{
if(codec && codec->sample_fmts){
const enum SampleFormat *p= codec->sample_fmts;
for(; *p!=-1; p++){
if(*p == st->codec->sample_fmt)
break;
}
if(*p == -1)
st->codec->sample_fmt = codec->sample_fmts[0];
}
}
Michael Niedermayer
committed
static void choose_sample_rate(AVStream *st, AVCodec *codec)
{
if(codec && codec->supported_samplerates){
const int *p= codec->supported_samplerates;
Michael Niedermayer
committed
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);
}
Michael Niedermayer
committed
st->codec->sample_rate= best;
}
}
Ronald S. Bultje
committed
static void choose_pixel_fmt(AVStream *st, AVCodec *codec)
{
if(codec && codec->pix_fmts){
const enum PixelFormat *p= codec->pix_fmts;
for(; *p!=-1; p++){
if(*p == st->codec->pix_fmt)
break;
}
if(*p == -1
&& !( st->codec->codec_id==CODEC_ID_MJPEG
&& st->codec->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL
Ronald S. Bultje
committed
&& ( st->codec->pix_fmt == PIX_FMT_YUV420P
|| st->codec->pix_fmt == PIX_FMT_YUV422P)))
st->codec->pix_fmt = codec->pix_fmts[0];
}
}
static int read_ffserver_streams(AVFormatContext *s, const char *filename)
int i, err;
int nopts = 0;
err = av_open_input_file(&ic, filename, NULL, FFM_PACKET_SIZE, NULL);
if (err < 0)
return err;
/* copy stream format */
s->nb_streams = ic->nb_streams;
for(i=0;i<ic->nb_streams;i++) {
AVStream *st;
Ronald S. Bultje
committed
AVCodec *codec;
Alex Beregszaszi
committed
// FIXME: a more elegant solution is needed
st = av_mallocz(sizeof(AVStream));
Alex Beregszaszi
committed
st->codec = avcodec_alloc_context();
if (!st->codec) {
print_error(filename, AVERROR(ENOMEM));
Ronald S. Bultje
committed
avcodec_copy_context(st->codec, ic->streams[i]->codec);
Ronald S. Bultje
committed
codec = avcodec_find_encoder(st->codec->codec_id);
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
if (audio_stream_copy) {
st->stream_copy = 1;
} else
choose_sample_fmt(st, codec);
} else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
if (video_stream_copy) {
st->stream_copy = 1;
} else
choose_pixel_fmt(st, codec);
}
if(!st->codec->thread_count)
st->codec->thread_count = 1;
if(st->codec->thread_count>1)
avcodec_thread_init(st->codec, st->codec->thread_count);
if(st->codec->flags & CODEC_FLAG_BITEXACT)
nopts = 1;
if (!nopts)
s->timestamp = av_gettime();
static double
get_sync_ipts(const AVOutputStream *ost)
{
const AVInputStream *ist = ost->sync_ist;
Michael Niedermayer
committed
return (double)(ist->pts - start_time)/AV_TIME_BASE;
}
Michael Niedermayer
committed
static void write_frame(AVFormatContext *s, AVPacket *pkt, AVCodecContext *avctx, AVBitStreamFilterContext *bsfc){
Michael Niedermayer
committed
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);
Michael Niedermayer
committed
av_free_packet(pkt);
new_pkt.destruct= av_destruct_packet;
fprintf(stderr, "%s failed for stream %d, codec %s",
bsfc->filter->name, pkt->stream_index,
avctx->codec ? avctx->codec->name : "copy");
if (exit_on_error)
Michael Niedermayer
committed
}
*pkt= new_pkt;
bsfc= bsfc->next;
}
ret= av_interleaved_write_frame(s, pkt);
if(ret < 0){
print_error("av_interleaved_write_frame()", ret);
Michael Niedermayer
committed
}
Fabrice Bellard
committed
#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
static void do_audio_out(AVFormatContext *s,
AVOutputStream *ost,
Michael Niedermayer
committed
int64_t audio_out_size, audio_buf_size;
Sylvain Corré
committed
Michael Niedermayer
committed
AVCodecContext *enc= ost->st->codec;
AVCodecContext *dec= ist->st->codec;
int osize= av_get_bits_per_sample_format(enc->sample_fmt)/8;
int isize= av_get_bits_per_sample_format(dec->sample_fmt)/8;
Michael Niedermayer
committed
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);
Michael Niedermayer
committed
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);
Michael Niedermayer
committed
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){
fprintf(stderr, "Buffer sizes too large\n");
Michael Niedermayer
committed
}
Michael Niedermayer
committed
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){
fprintf(stderr, "Out of memory in do_audio_out\n");
Sylvain Corré
committed
if (enc->channels != dec->channels)
ost->audio_resample = 1;
if (ost->audio_resample && !ost->resample) {
if (dec->sample_fmt != SAMPLE_FMT_S16)
fprintf(stderr, "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) {
fprintf(stderr, "Can not resample %d channels @ %d Hz to %d channels @ %d Hz\n",
dec->channels, dec->sample_rate,
enc->channels, enc->sample_rate);
}
}
#define MAKE_SFMT_PAIR(a,b) ((a)+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) {
fprintf(stderr, "Cannot convert %s sample format to %s sample format\n",
avcodec_get_sample_fmt_name(dec->sample_fmt),
avcodec_get_sample_fmt_name(enc->sample_fmt));
}
ost->reformat_pair=MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt);
}
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){
Michael Niedermayer
committed
byte_delta= FFMAX(byte_delta, -size);
size += byte_delta;
buf -= byte_delta;
if(verbose > 2)
fprintf(stderr, "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;
if(verbose > 2)
fprintf(stderr, "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);
if(verbose > 2)
fprintf(stderr, "compensating audio timestamp drift:%f compensation:%d in:%d\n", delta, comp, enc->sample_rate);
Michael Niedermayer
committed
// 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);
}
ost->sync_opts= lrintf(get_sync_ipts(ost) * enc->sample_rate)
- av_fifo_size(ost->fifo)/(enc->channels * 2); //FIXME wrong
size_out = audio_resample(ost->resample,
size / (dec->channels * isize));
size_out = size_out * enc->channels * osize;
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)
return;
}
size_out = len*osize;
if (enc->frame_size > 1) {
Michael Niedermayer
committed
if (av_fifo_realloc2(ost->fifo, av_fifo_size(ost->fifo) + size_out) < 0) {
fprintf(stderr, "av_fifo_realloc2() failed\n");
Michael Niedermayer
committed
av_fifo_generic_write(ost->fifo, buftmp, size_out, NULL);
frame_bytes = enc->frame_size * osize * enc->channels;
Michael Niedermayer
committed
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) {
fprintf(stderr, "Audio encoding failed\n");
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, bitstream_filters[ost->file_index][pkt.stream_index]);
ost->sync_opts += enc->frame_size;
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;
Michael Niedermayer
committed
if(size_out > audio_out_size){
fprintf(stderr, "Internal error, buffer size too small\n");
Michael Niedermayer
committed
}
//FIXME pass ost->sync_opts as AVFrame.pts in avcodec_encode_audio()
ret = avcodec_encode_audio(enc, audio_out, size_out,