#include "libswscale/swscale.h"
#include "libavresample/avresample.h"
#include "libavutil/opt.h"
-#include "libavutil/audioconvert.h"
+#include "libavutil/channel_layout.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/colorspace.h"
# include "libavfilter/buffersink.h"
#if HAVE_SYS_RESOURCE_H
+#include <sys/time.h>
#include <sys/types.h>
#include <sys/resource.h>
#elif HAVE_GETPROCESSTIMES
const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL };
-void exit_program(int ret)
+static void exit_program(void)
{
int i, j;
bsfc = next;
}
output_streams[i]->bitstream_filters = NULL;
+ avcodec_free_frame(&output_streams[i]->filtered_frame);
av_freep(&output_streams[i]->forced_keyframes);
av_freep(&output_streams[i]->avfilter);
av_freep(&output_streams[i]->logfile_prefix);
- av_freep(&output_streams[i]->filtered_frame);
av_freep(&output_streams[i]);
}
for (i = 0; i < nb_input_files; i++) {
av_freep(&input_files[i]);
}
for (i = 0; i < nb_input_streams; i++) {
- av_freep(&input_streams[i]->decoded_frame);
+ avcodec_free_frame(&input_streams[i]->decoded_frame);
av_dict_free(&input_streams[i]->opts);
free_buffer_pool(&input_streams[i]->buffer_pool);
av_freep(&input_streams[i]->filters);
(int) received_sigterm);
exit (255);
}
-
- exit(ret);
}
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);
+ exit(1);
}
}
-static void assert_codec_experimental(AVCodecContext *c, int encoder)
+static void abort_codec_experimental(AVCodec *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);
- }
+ 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->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);
+ exit(1);
}
-/**
+/*
* 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.
dec_codec->sample_fmts[0] != AV_SAMPLE_FMT_NONE &&
dec_codec->sample_fmts[1] != AV_SAMPLE_FMT_NONE) {
const enum AVSampleFormat *p;
- int min_dec = -1, min_inc = -1;
+ 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;
/* 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;
- } else if (*p > enc->sample_fmt) {
- min_inc = FFMIN(min_inc, *p - enc->sample_fmt);
- } else
- min_dec = FFMIN(min_dec, enc->sample_fmt - *p);
+ } 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;
+ }
+ }
+ }
}
/* if none match, provide the one that matches quality closest */
- dec->request_sample_fmt = min_inc > 0 ? enc->sample_fmt + min_inc :
- enc->sample_fmt - min_dec;
+ dec->request_sample_fmt = min_inc != INT_MAX ? inc_fmt : dec_fmt;
}
}
avctx->codec ? avctx->codec->name : "copy");
print_error("", a);
if (exit_on_error)
- exit_program(1);
+ exit(1);
}
*pkt = new_pkt;
ret = av_interleaved_write_frame(s, pkt);
if (ret < 0) {
print_error("av_interleaved_write_frame()", ret);
- exit_program(1);
+ exit(1);
}
}
if (avcodec_encode_audio2(enc, &pkt, frame, &got_packet) < 0) {
av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
- exit_program(1);
+ exit(1);
}
if (got_packet) {
if (pts == AV_NOPTS_VALUE) {
av_log(NULL, AV_LOG_ERROR, "Subtitle packets must have a pts\n");
if (exit_on_error)
- exit_program(1);
+ exit(1);
return;
}
subtitle_out_max_size, sub);
if (subtitle_out_size < 0) {
av_log(NULL, AV_LOG_FATAL, "Subtitle encoding failed\n");
- exit_program(1);
+ exit(1);
}
av_init_packet(&pkt);
static void do_video_out(AVFormatContext *s,
OutputStream *ost,
AVFrame *in_picture,
- int *frame_size, float quality)
+ int *frame_size)
{
int ret, format_video_sync;
AVPacket pkt;
big_picture.top_field_first = !!ost->top_field_first;
}
- /* handles same_quant here. This is not correct because it may
- not be a global option */
- big_picture.quality = quality;
+ big_picture.quality = ost->st->codec->global_quality;
if (!enc->me_threshold)
big_picture.pict_type = 0;
if (ost->forced_kf_index < ost->forced_kf_count &&
ret = avcodec_encode_video2(enc, &pkt, &big_picture, &got_packet);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
- exit_program(1);
+ exit(1);
}
if (got_packet) {
return -10.0 * log(d) / log(10.0);
}
-static void do_video_stats(AVFormatContext *os, OutputStream *ost,
- int frame_size)
+static void do_video_stats(OutputStream *ost, int frame_size)
{
AVCodecContext *enc;
int frame_number;
vstats_file = fopen(vstats_filename, "w");
if (!vstats_file) {
perror("fopen");
- exit_program(1);
+ exit(1);
}
}
}
}
-/**
+/*
* Read one frame for lavfi output for ost and encode it.
*/
static int poll_filter(OutputStream *ost)
if (!ost->frame_aspect_ratio)
ost->st->codec->sample_aspect_ratio = picref->video->pixel_aspect;
- do_video_out(of->ctx, ost, filtered_frame, &frame_size,
- same_quant ? ost->last_quality :
- ost->st->codec->global_quality);
+ do_video_out(of->ctx, ost, filtered_frame, &frame_size);
if (vstats_filename && frame_size)
- do_video_stats(of->ctx, ost, frame_size);
+ do_video_stats(ost, frame_size);
break;
case AVMEDIA_TYPE_AUDIO:
do_audio_out(of->ctx, ost, filtered_frame);
return 0;
}
-/**
+/*
* Read as many frames from possible from lavfi and encode them.
*
* Always read from the active stream with the lowest timestamp. If no frames
oc = output_files[0]->ctx;
total_size = avio_size(oc->pb);
- if (total_size < 0) // FIXME improve avio_size() so it works with non seekable output too
+ if (total_size <= 0) // FIXME improve avio_size() so it works with non seekable output too
total_size = avio_tell(oc->pb);
+ 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;
+ }
buf[0] = '\0';
ti1 = 1e10;
ret = encode(enc, &pkt, NULL, &got_packet);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "%s encoding failed\n", desc);
- exit_program(1);
+ exit(1);
}
*size += ret;
if (ost->logfile && enc->stats_out) {
pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts = av_rescale_q(pkt.dts, enc->time_base, ost->st->time_base);
+ if (pkt.duration > 0)
+ pkt.duration = av_rescale_q(pkt.duration, enc->time_base, ost->st->time_base);
write_frame(os, &pkt, ost);
}
write_frame(of->ctx, &opkt, ost);
ost->st->codec->frame_number++;
- av_free_packet(&opkt);
}
static void rate_emu_sleep(InputStream *ist)
{
AVFrame *decoded_frame;
AVCodecContext *avctx = ist->st->codec;
- int bps = av_get_bytes_per_sample(ist->st->codec->sample_fmt);
int i, ret, resample_changed;
if (!ist->decoded_frame && !(ist->decoded_frame = avcodec_alloc_frame()))
return AVERROR(ENOMEM);
- else
- avcodec_get_frame_defaults(ist->decoded_frame);
decoded_frame = ist->decoded_frame;
ret = avcodec_decode_audio4(avctx, decoded_frame, got_output, pkt);
pkt->pts = AV_NOPTS_VALUE;
}
- // preprocess audio (volume)
- if (audio_volume != 256) {
- int decoded_data_size = decoded_frame->nb_samples * avctx->channels * bps;
- void *samples = decoded_frame->data[0];
- switch (avctx->sample_fmt) {
- case AV_SAMPLE_FMT_U8:
- {
- uint8_t *volp = samples;
- for (i = 0; i < (decoded_data_size / sizeof(*volp)); i++) {
- int v = (((*volp - 128) * audio_volume + 128) >> 8) + 128;
- *volp++ = av_clip_uint8(v);
- }
- break;
- }
- case AV_SAMPLE_FMT_S16:
- {
- int16_t *volp = samples;
- for (i = 0; i < (decoded_data_size / sizeof(*volp)); i++) {
- int v = ((*volp) * audio_volume + 128) >> 8;
- *volp++ = av_clip_int16(v);
- }
- break;
- }
- case AV_SAMPLE_FMT_S32:
- {
- int32_t *volp = samples;
- for (i = 0; i < (decoded_data_size / sizeof(*volp)); i++) {
- int64_t v = (((int64_t)*volp * audio_volume + 128) >> 8);
- *volp++ = av_clipl_int32(v);
- }
- break;
- }
- case AV_SAMPLE_FMT_FLT:
- {
- float *volp = samples;
- float scale = audio_volume / 256.f;
- for (i = 0; i < (decoded_data_size / sizeof(*volp)); i++) {
- *volp++ *= scale;
- }
- break;
- }
- case AV_SAMPLE_FMT_DBL:
- {
- double *volp = samples;
- double scale = audio_volume / 256.;
- for (i = 0; i < (decoded_data_size / sizeof(*volp)); i++) {
- *volp++ *= scale;
- }
- break;
- }
- default:
- av_log(NULL, AV_LOG_FATAL,
- "Audio volume adjustment on sample format %s is not supported.\n",
- av_get_sample_fmt_name(ist->st->codec->sample_fmt));
- exit_program(1);
- }
- }
-
rate_emu_sleep(ist);
resample_changed = ist->resample_sample_fmt != decoded_frame->format ||
av_log(NULL, AV_LOG_FATAL, "Unable to find default channel "
"layout for Input Stream #%d.%d\n", ist->file_index,
ist->st->index);
- exit_program(1);
+ exit(1);
}
decoded_frame->channel_layout = avctx->channel_layout;
if (ist_in_filtergraph(filtergraphs[i], ist) &&
configure_filtergraph(filtergraphs[i]) < 0) {
av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n");
- exit_program(1);
+ exit(1);
}
}
AVFrame *decoded_frame;
void *buffer_to_free = NULL;
int i, ret = 0, resample_changed;
- float quality;
if (!ist->decoded_frame && !(ist->decoded_frame = avcodec_alloc_frame()))
return AVERROR(ENOMEM);
- else
- avcodec_get_frame_defaults(ist->decoded_frame);
decoded_frame = ist->decoded_frame;
ret = avcodec_decode_video2(ist->st->codec,
return ret;
}
- quality = same_quant ? decoded_frame->quality : 0;
decoded_frame->pts = guess_correct_pts(&ist->pts_ctx, decoded_frame->pkt_pts,
decoded_frame->pkt_dts);
pkt->size = 0;
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));
+ ret = poll_filters();
+ if (ret < 0 && (ret != AVERROR_EOF && ret != AVERROR(EAGAIN)))
+ av_log(NULL, AV_LOG_ERROR, "Error while filtering.\n");
+
ist->resample_width = decoded_frame->width;
ist->resample_height = decoded_frame->height;
ist->resample_pix_fmt = decoded_frame->format;
if (ist_in_filtergraph(filtergraphs[i], ist) &&
configure_filtergraph(filtergraphs[i]) < 0) {
av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n");
- exit_program(1);
+ exit(1);
}
}
for (i = 0; i < ist->nb_filters; i++) {
- // XXX what an ugly hack
- if (ist->filters[i]->graph->nb_outputs == 1)
- ist->filters[i]->graph->outputs[0]->ost->last_quality = quality;
-
if (ist->st->codec->codec->capabilities & CODEC_CAP_DR1) {
FrameBuffer *buf = decoded_frame->opaque;
AVFilterBufferRef *fb = avfilter_get_video_buffer_ref_from_arrays(
AVFormatContext **avc = av_malloc(sizeof(*avc) * nb_output_files);
if (!avc)
- exit_program(1);
+ exit(1);
for (i = 0; i < nb_output_files; i++)
avc[i] = output_files[i]->ctx;
static int init_input_stream(int ist_index, char *error, int error_len)
{
- int i;
+ int i, ret;
InputStream *ist = input_streams[ist_index];
if (ist->decoding_needed) {
AVCodec *codec = ist->dec;
if (!av_dict_get(ist->opts, "threads", NULL, 0))
av_dict_set(&ist->opts, "threads", "auto", 0);
- if (avcodec_open2(ist->st->codec, codec, &ist->opts) < 0) {
+ if ((ret = avcodec_open2(ist->st->codec, codec, &ist->opts)) < 0) {
+ if (ret == AVERROR_EXPERIMENTAL)
+ abort_codec_experimental(codec, 0);
snprintf(error, error_len, "Error while opening decoder for input stream #%d:%d",
ist->file_index, ist->st->index);
- return AVERROR(EINVAL);
+ return ret;
}
- assert_codec_experimental(ist->st->codec, 0);
assert_avoptions(ist->opts);
}
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");
- exit_program(1);
+ exit(1);
}
p = kf;
case AVMEDIA_TYPE_AUDIO:
if (audio_volume != 256) {
av_log(NULL, AV_LOG_FATAL, "-acodec copy and -vol are incompatible (frames are not decoded)\n");
- exit_program(1);
+ exit(1);
}
codec->channel_layout = icodec->channel_layout;
codec->sample_rate = icodec->sample_rate;
if (!f) {
av_log(NULL, AV_LOG_FATAL, "Cannot write log file '%s' for pass-1 encoding: %s\n",
logfilename, strerror(errno));
- exit_program(1);
+ exit(1);
}
ost->logfile = f;
} else {
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);
- exit_program(1);
+ exit(1);
}
codec->stats_in = logbuffer;
}
}
if (!av_dict_get(ost->opts, "threads", NULL, 0))
av_dict_set(&ost->opts, "threads", "auto", 0);
- if (avcodec_open2(ost->st->codec, codec, &ost->opts) < 0) {
+ if ((ret = avcodec_open2(ost->st->codec, codec, &ost->opts)) < 0) {
+ if (ret == AVERROR_EXPERIMENTAL)
+ abort_codec_experimental(codec, 1);
snprintf(error, sizeof(error), "Error while opening encoder for output stream #%d:%d - maybe incorrect parameters such as bit_rate, rate, width or height",
ost->file_index, ost->index);
- ret = AVERROR(EINVAL);
goto dump_format;
}
- assert_codec_experimental(ost->st->codec, 1);
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."
return 0;
}
-/**
- * @return 1 if there are still streams where more output is wanted,
- * 0 otherwise
- */
+/* Return 1 if there remain streams where more output is wanted, 0 otherwise. */
static int need_output(void)
{
int i;
input_files[i]->eagain = 0;
}
-/**
+/*
* Read one packet from an input file and send it for
* - decoding -> lavfi (audio/video)
* - decoding -> encoding -> muxing (subtitles)
* - muxing (streamcopy)
*
- * @return
+ * Return
* - 0 -- one packet was read and processed
* - AVERROR(EAGAIN) -- no packets were available for selected file,
* this function should be called again
if (ret != AVERROR_EOF) {
print_error(is->filename, ret);
if (exit_on_error)
- exit_program(1);
+ exit(1);
}
ifile->eof_reached = 1;
av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d\n",
ist->file_index, ist->st->index);
if (exit_on_error)
- exit_program(1);
+ exit(1);
}
discard_packet:
{
int idx = locate_option(argc, argv, options, "cpuflags");
if (idx && argv[idx + 1])
- opt_cpuflags("cpuflags", argv[idx + 1]);
+ opt_cpuflags(NULL, "cpuflags", argv[idx + 1]);
}
int main(int argc, char **argv)
OptionsContext o = { 0 };
int64_t ti;
+ atexit(exit_program);
+
reset_options(&o);
av_log_set_flags(AV_LOG_SKIP_REPEATED);
if (nb_output_files <= 0 && nb_input_files == 0) {
show_usage();
av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
- exit_program(1);
+ exit(1);
}
/* file converter / grab */
if (nb_output_files <= 0) {
fprintf(stderr, "At least one output file must be specified\n");
- exit_program(1);
+ exit(1);
}
ti = getutime();
if (transcode() < 0)
- exit_program(1);
+ exit(1);
ti = getutime() - ti;
if (do_benchmark) {
int maxrss = getmaxrss() / 1024;
printf("bench: utime=%0.3fs maxrss=%ikB\n", ti / 1000000.0, maxrss);
}
- exit_program(0);
+ exit(0);
return 0;
}