Newer
Older
av_free(async_buf);
allocated_async_buf_size = 0;
avfilter_uninit();
avformat_network_deinit();
if (received_sigterm) {
av_log(NULL, AV_LOG_INFO, "Received signal %d: terminating.\n",
(int) received_sigterm);
exit (255);
}
}
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)
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
break;
}
if (*p == -1) {
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];
}
}
}
/**
* 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;
int min_dec = -1, min_inc = -1;
/* 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);
}
/* 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;
}
}
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;
av_log(st->codec, AV_LOG_WARNING, "Requested sampling rate unsupported using closest supported (%d)\n", best);
}
}
}
static double
get_sync_ipts(const OutputStream *ost, int64_t pts)
OutputFile *of = output_files[ost->file_index];
return (double)(pts - of->start_time) / AV_TIME_BASE;
static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
AVCodecContext *avctx = ost->st->codec;
/*
* 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)) {
Justin Ruggles
committed
if (ost->frame_number >= ost->max_frames) {
av_free_packet(pkt);
Justin Ruggles
committed
}
ost->frame_number++;
}
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) {
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");
print_error("", a);
if (exit_on_error)
exit_program(1);
}
pkt->stream_index = ost->index;
ret = av_interleaved_write_frame(s, pkt);
if (ret < 0) {
print_error("av_interleaved_write_frame()", ret);
exit_program(1);
}
}
static int check_recording_time(OutputStream *ost)
{
OutputFile *of = output_files[ost->file_index];
if (of->recording_time != INT64_MAX &&
av_compare_ts(ost->sync_opts - ost->first_pts, ost->st->codec->time_base, of->recording_time,
AV_TIME_BASE_Q) >= 0) {
ost->is_past_recording_time = 1;
return 0;
}
return 1;
}
static void generate_silence(uint8_t* buf, enum AVSampleFormat sample_fmt, size_t size)
{
int fill_char = 0x00;
if (sample_fmt == AV_SAMPLE_FMT_U8)
fill_char = 0x80;
memset(buf, fill_char, size);
}
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
static int encode_audio_frame(AVFormatContext *s, OutputStream *ost,
const uint8_t *buf, int buf_size)
{
AVCodecContext *enc = ost->st->codec;
AVFrame *frame = NULL;
AVPacket pkt;
int ret, got_packet;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
if (buf) {
if (!ost->output_frame) {
ost->output_frame = avcodec_alloc_frame();
if (!ost->output_frame) {
av_log(NULL, AV_LOG_FATAL, "out-of-memory in encode_audio_frame()\n");
exit_program(1);
}
}
frame = ost->output_frame;
if (frame->extended_data != frame->data)
av_freep(&frame->extended_data);
avcodec_get_frame_defaults(frame);
frame->nb_samples = buf_size /
(enc->channels * av_get_bytes_per_sample(enc->sample_fmt));
if ((ret = avcodec_fill_audio_frame(frame, enc->channels, enc->sample_fmt,
buf, buf_size, 1)) < 0) {
av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
exit_program(1);
}
if (!check_recording_time(ost))
return 0;
frame->pts = ost->sync_opts;
ost->sync_opts += frame->nb_samples;
}
got_packet = 0;
if (avcodec_encode_audio2(enc, &pkt, frame, &got_packet) < 0) {
av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
exit_program(1);
}
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);
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;
}
return pkt.size;
}
static int alloc_audio_output_buf(AVCodecContext *dec, AVCodecContext *enc,
int nb_samples)
{
int64_t audio_buf_samples;
int audio_buf_size;
/* calculate required number of samples to allocate */
audio_buf_samples = ((int64_t)nb_samples * enc->sample_rate + dec->sample_rate) /
dec->sample_rate;
Justin Ruggles
committed
audio_buf_samples = 4 * audio_buf_samples + 16; // safety factors for resampling
audio_buf_samples = FFMAX(audio_buf_samples, enc->frame_size);
if (audio_buf_samples > INT_MAX)
return AVERROR(EINVAL);
audio_buf_size = av_samples_get_buffer_size(NULL, enc->channels,
audio_buf_samples,
if (audio_buf_size < 0)
return audio_buf_size;
av_fast_malloc(&audio_buf, &allocated_audio_buf_size, audio_buf_size);
if (!audio_buf)
return AVERROR(ENOMEM);
return 0;
}
static void do_audio_out(AVFormatContext *s, OutputStream *ost,
InputStream *ist, AVFrame *decoded_frame)
{
uint8_t *buftmp;
int size_out, frame_bytes, 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);
uint8_t *buf = decoded_frame->data[0];
int size = decoded_frame->nb_samples * dec->channels * isize;
if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples) < 0) {
av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n");
exit_program(1);
}
if (enc->channels != dec->channels || enc->sample_rate != dec->sample_rate)
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;
} else if (ost->audio_resample) {
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 > 0) {
double delta = get_sync_ipts(ost, ist->last_dts) * enc->sample_rate - ost->sync_opts -
av_fifo_size(ost->fifo) / (enc->channels * osize);
int idelta = delta * dec->sample_rate / enc->sample_rate;
int byte_delta = idelta * isize * 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",
-byte_delta / (isize * dec->channels));
av_fast_malloc(&async_buf, &allocated_async_buf_size,
byte_delta + size);
if (!async_buf) {
av_log(NULL, AV_LOG_FATAL, "Out of memory in do_audio_out\n");
exit_program(1);
}
if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples + idelta) < 0) {
av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n");
exit_program(1);
generate_silence(async_buf, dec->sample_fmt, byte_delta);
memcpy(async_buf + byte_delta, buf, size);
buf = async_buf;
av_log(NULL, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", idelta);
} 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);
// 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 if (audio_sync_method == 0)
ost->sync_opts = lrintf(get_sync_ipts(ost, ist->last_dts) * enc->sample_rate) -
av_fifo_size(ost->fifo) / (enc->channels * osize); // 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;
}
/* now encode as many frames as possible */
if (!(enc->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) {
/* 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) {
av_fifo_generic_read(ost->fifo, audio_buf, frame_bytes, NULL);
encode_audio_frame(s, ost, audio_buf, frame_bytes);
encode_audio_frame(s, ost, buftmp, size_out);
}
}
static void pre_process_video_frame(InputStream *ist, AVPicture *picture, void **bufp)
{
AVCodecContext *dec;
AVPicture *picture2;
AVPicture picture_tmp;
uint8_t *buf = 0;
dec = ist->st->codec;
/* deinterlace : must be done before any resize */
if (do_deinterlace) {
int size;
/* create temporary picture */
size = avpicture_get_size(dec->pix_fmt, dec->width, dec->height);
if (!buf)
return;
picture2 = &picture_tmp;
avpicture_fill(picture2, buf, dec->pix_fmt, dec->width, dec->height);
dec->pix_fmt, dec->width, dec->height) < 0) {
/* if error, do not deinterlace */
av_log(NULL, AV_LOG_WARNING, "Deinterlacing failed\n");
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
av_free(buf);
buf = NULL;
picture2 = picture;
}
} else {
picture2 = picture;
}
if (picture != picture2)
*picture = *picture2;
*bufp = buf;
}
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) {
av_log(NULL, AV_LOG_ERROR, "Subtitle packets must have a pts\n");
if (exit_on_error)
exit_program(1);
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 ? */
if (enc->codec_id == CODEC_ID_DVB_SUBTITLE)
nb = 2;
else
nb = 1;
ost->sync_opts = av_rescale_q(pts, ist->st->time_base, enc->time_base);
if (!check_recording_time(ost))
return;
sub->pts = av_rescale_q(pts, ist->st->time_base, AV_TIME_BASE_Q);
// start_display_time is required to be 0
sub->pts += av_rescale_q(sub->start_display_time, (AVRational){ 1, 1000 }, AV_TIME_BASE_Q);
sub->end_display_time -= sub->start_display_time;
sub->start_display_time = 0;
subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out,
subtitle_out_max_size, sub);
if (subtitle_out_size < 0) {
av_log(NULL, AV_LOG_FATAL, "Subtitle encoding failed\n");
exit_program(1);
}
av_init_packet(&pkt);
pkt.data = subtitle_out;
pkt.size = subtitle_out_size;
pkt.pts = av_rescale_q(sub->pts, AV_TIME_BASE_Q, ost->st->time_base);
if (enc->codec_id == CODEC_ID_DVB_SUBTITLE) {
/* 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;
}
write_frame(s, &pkt, ost);
static void do_video_out(AVFormatContext *s,
OutputStream *ost,
AVFrame *in_picture,
int *frame_size, float quality)
{
int nb_frames, i, ret, format_video_sync;
sync_ipts = get_sync_ipts(ost, in_picture->pts) / av_q2d(enc->time_base);
/* by default, we output a single frame */
nb_frames = 1;
*frame_size = 0;
format_video_sync = video_sync_method;
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;
switch (format_video_sync) {
case VSYNC_CFR:
// FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
else if (delta > 1.1)
nb_frames = lrintf(delta);
break;
case VSYNC_VFR:
if (delta <= -0.6)
nb_frames = 0;
else if (delta > 0.6)
ost->sync_opts = lrintf(sync_ipts);
break;
case VSYNC_PASSTHROUGH:
break;
default:
av_assert0(0);
}
nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number);
if (nb_frames == 0) {
nb_frames_drop++;
av_log(NULL, AV_LOG_VERBOSE, "*** drop!\n");
} else if (nb_frames > 1) {
nb_frames_dup += nb_frames - 1;
av_log(NULL, AV_LOG_VERBOSE, "*** %d dup!\n", nb_frames - 1);
}
if (!ost->frame_number)
ost->first_pts = ost->sync_opts;
/* duplicates frame if needed */
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
if (!check_recording_time(ost))
return;
if (s->oformat->flags & AVFMT_RAWPICTURE &&
enc->codec->id == CODEC_ID_RAWVIDEO) {
/* raw pictures are written as AVPicture structure to
avoid any copies. We support temporarily the older
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(ost->sync_opts, enc->time_base, ost->st->time_base);
pkt.flags |= AV_PKT_FLAG_KEY;
write_frame(s, &pkt, ost);
AVFrame big_picture;
/* better than nothing: use input picture interlaced
settings */
big_picture.interlaced_frame = in_picture->interlaced_frame;
if (ost->st->codec->flags & (CODEC_FLAG_INTERLACED_DCT|CODEC_FLAG_INTERLACED_ME)) {
if (ost->top_field_first == -1)
big_picture.top_field_first = in_picture->top_field_first;
else
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.pict_type = 0;
if (ost->forced_kf_index < ost->forced_kf_count &&
big_picture.pts >= ost->forced_kf_pts[ost->forced_kf_index]) {
big_picture.pict_type = AV_PICTURE_TYPE_I;
ost->forced_kf_index++;
}
ret = avcodec_encode_video2(enc, &pkt, &big_picture, &got_packet);
av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
exit_program(1);
}
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);
write_frame(s, &pkt, ost);
*frame_size = pkt.size;
video_size += pkt.size;
/* if two pass, output log */
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
}
}
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++;
static double psnr(double d)
{
return -10.0 * log(d) / log(10.0);
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
}
static void do_video_stats(AVFormatContext *os, OutputStream *ost,
int frame_size)
{
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");
exit_program(1);
}
}
enc = ost->st->codec;
if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
frame_number = ost->frame_number;
fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, enc->coded_frame->quality / (float)FF_QP2LAMBDA);
if (enc->flags&CODEC_FLAG_PSNR)
fprintf(vstats_file, "PSNR= %6.2f ", psnr(enc->coded_frame->error[0] / (enc->width * enc->height * 255.0 * 255.0)));
fprintf(vstats_file,"f_size= %6d ", frame_size);
/* compute pts value */
ti1 = ost->sync_opts * av_q2d(enc->time_base);
if (ti1 < 0.01)
ti1 = 0.01;
bitrate = (frame_size * 8) / av_q2d(enc->time_base) / 1000.0;
avg_bitrate = (double)(video_size * 8) / ti1 / 1000.0;
fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ",
(double)video_size / 1024, ti1, bitrate, avg_bitrate);
fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(enc->coded_frame->pict_type));
}
}
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
/* check for new output on any of the filtergraphs */
static int poll_filters(void)
{
AVFilterBufferRef *picref;
AVFrame *filtered_frame = NULL;
int i, frame_size, ret;
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = output_streams[i];
OutputFile *of = output_files[ost->file_index];
if (!ost->filter || ost->is_past_recording_time)
continue;
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;
while (avfilter_poll_frame(ost->filter->filter->inputs[0])) {
AVRational ist_pts_tb;
if ((ret = get_filtered_video_frame(ost->filter->filter,
filtered_frame, &picref,
&ist_pts_tb)) < 0)
return ret;
filtered_frame->pts = av_rescale_q(picref->pts, ist_pts_tb, AV_TIME_BASE_Q);
if (of->start_time && filtered_frame->pts < of->start_time)
return 0;
switch (ost->filter->filter->inputs[0]->type) {
case AVMEDIA_TYPE_VIDEO:
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);
if (vstats_filename && frame_size)
do_video_stats(of->ctx, ost, frame_size);
break;
default:
// TODO support audio/subtitle filters
av_assert0(0);
}
avfilter_unref_buffer(picref);
}
}
return 0;
}
static void print_report(int is_last_report, int64_t timer_start)
{
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];
if (!print_stats && !is_last_report)
return;
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;
}
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
total_size = avio_tell(oc->pb);
buf[0] = '\0';
ti1 = 1e10;
vid = 0;
for (i = 0; i < nb_output_streams; i++) {
ost = output_streams[i];
enc = ost->st->codec;
if (!ost->stream_copy && enc->coded_frame)
q = enc->coded_frame->quality / (float)FF_QP2LAMBDA;
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) {
float t = (av_gettime() - timer_start) / 1000000.0;
frame_number = ost->frame_number;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "frame=%5d fps=%3d q=%3.1f ",
frame_number, (t > 1) ? (int)(frame_number / t + 0.5) : 0, q);
if (is_last_report)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "L");
int j;
int qp = lrintf(q);
for (j = 0; j < 32; j++)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%X", (int)lrintf(log(qp_histogram[j] + 1) / log(2)));
double error, error_sum = 0;
double scale, scale_sum = 0;
char type[3] = { 'Y','U','V' };
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "PSNR=");
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;
error_sum += error;
scale_sum += scale;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%c:%2.2f ", type[j], psnr(error / scale));
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "*:%2.2f ", psnr(error_sum / scale_sum));
}
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;
bitrate = (double)(total_size * 8) / ti1 / 1000.0;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
"size=%8.0fkB time=%0.2f bitrate=%6.1fkbits/s",
(double)total_size / 1024, ti1, bitrate);
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);
av_log(NULL, AV_LOG_INFO, "%s \r", buf);
int64_t raw= audio_size + video_size + extra_size;
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",
video_size / 1024.0,
audio_size / 1024.0,
extra_size / 1024.0,
100.0 * (total_size - raw) / raw
);
}
}
static void flush_encoders(void)
{
int i, ret;
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = output_streams[i];
AVCodecContext *enc = ost->st->codec;
AVFormatContext *os = output_files[ost->file_index]->ctx;
if (!ost->encoding_needed)
continue;
if (ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <= 1)
if (ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO && (os->oformat->flags & AVFMT_RAWPICTURE) && enc->codec->id == CODEC_ID_RAWVIDEO)
continue;
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
switch (ost->st->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
fifo_bytes = av_fifo_size(ost->fifo);
if (fifo_bytes > 0) {
/* encode any samples remaining in fifo */
int frame_bytes = fifo_bytes;
av_fifo_generic_read(ost->fifo, audio_buf, fifo_bytes, NULL);
/* pad last frame with silence if needed */
if (!(enc->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME)) {
frame_bytes = enc->frame_size * enc->channels *
av_get_bytes_per_sample(enc->sample_fmt);
if (allocated_audio_buf_size < frame_bytes)
exit_program(1);
generate_silence(audio_buf+fifo_bytes, enc->sample_fmt, frame_bytes - fifo_bytes);
encode_audio_frame(os, ost, audio_buf, frame_bytes);
} else {
/* flush encoder with NULL frames until it is done
returning packets */
if (encode_audio_frame(os, ost, NULL, 0) == 0) {
stop_encoding = 1;
break;
}
}
break;
case AVMEDIA_TYPE_VIDEO:
ret = avcodec_encode_video2(enc, &pkt, NULL, &got_packet);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
exit_program(1);
}
video_size += ret;
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
stop_encoding = 1;
break;
}
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);
break;
default: