Newer
Older
AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
AVCodecContext *avctx = ost->st->codec;
if ((avctx->codec_type == AVMEDIA_TYPE_VIDEO && video_sync_method == VSYNC_DROP) ||
(avctx->codec_type == AVMEDIA_TYPE_AUDIO && audio_sync_method < 0))
pkt->pts = pkt->dts = AV_NOPTS_VALUE;
/*
* 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) {
Michael Niedermayer
committed
av_free_packet(pkt);
new_pkt.destruct = av_destruct_packet;
} else if (a < 0) {
Stefano Sabatini
committed
av_log(NULL, AV_LOG_ERROR, "Failed to open bitstream filter %s for stream %d with codec %s",
bsfc->filter->name, pkt->stream_index,
avctx->codec ? avctx->codec->name : "copy");
if (exit_on_error)
Michael Niedermayer
committed
}
Michael Niedermayer
committed
Michael Niedermayer
committed
}
pkt->stream_index = ost->index;
ret = av_interleaved_write_frame(s, pkt);
if (ret < 0) {
print_error("av_interleaved_write_frame()", ret);
Michael Niedermayer
committed
}
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);
}
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);
Michael Niedermayer
committed
}
frame->pts = ost->sync_opts;
ost->sync_opts += frame->nb_samples;
Michael Niedermayer
committed
}
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);
Michael Niedermayer
committed
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;
av_free_packet(&pkt);
if (debug_ts) {
av_log(NULL, AV_LOG_INFO, "encoder -> type:audio "
"pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n",
av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base),
av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base));
}
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;
audio_buf_samples = 4 * audio_buf_samples + 10000; // 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,
enc->sample_fmt, 32);
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)
Sylvain Corré
committed
int frame_bytes, resample_changed;
AVCodecContext *enc = ost->st->codec;
AVCodecContext *dec = ist->st->codec;
Justin Ruggles
committed
int osize = av_get_bytes_per_sample(enc->sample_fmt);
int isize = av_get_bytes_per_sample(dec->sample_fmt);
uint8_t *buf[AV_NUM_DATA_POINTERS];
int size = decoded_frame->nb_samples * dec->channels * isize;
int planes = av_sample_fmt_is_planar(dec->sample_fmt) ? dec->channels : 1;
int i;
av_assert0(planes <= AV_NUM_DATA_POINTERS);
for(i=0; i<planes; i++)
buf[i]= decoded_frame->data[i];
Michael Niedermayer
committed
if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples) < 0) {
av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n");
Sylvain Corré
committed
|| enc->sample_fmt != dec->sample_fmt
|| 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->swr) || resample_changed || ost->audio_channels_mapped) {
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 audio_sync_method is >1 the resampler is needed for audio drift compensation */
if (audio_sync_method <= 1 && !ost->audio_channels_mapped &&
ost->resample_sample_fmt == enc->sample_fmt &&
ost->resample_channels == enc->channels &&
ost->resample_sample_rate == enc->sample_rate) {
ost->audio_resample = 0;
} else {
ost->swr = swr_alloc_set_opts(ost->swr,
enc->channel_layout, enc->sample_fmt, enc->sample_rate,
dec->channel_layout, dec->sample_fmt, dec->sample_rate,
0, NULL);
if (ost->audio_channels_mapped)
swr_set_channel_mapping(ost->swr, ost->audio_channels_map);
av_opt_set_double(ost->swr, "rmvol", ost->rematrix_volume, 0);
av_opt_set_int(ost->swr, "icl", av_get_default_channel_layout(ost->audio_channels_mapped), 0);
av_opt_set_int(ost->swr, "uch", ost->audio_channels_mapped, 0);
if (av_opt_set_int(ost->swr, "ich", dec->channels, 0) < 0) {
av_log(NULL, AV_LOG_FATAL, "Unsupported number of input channels\n");
exit_program(1);
}
if (av_opt_set_int(ost->swr, "och", enc->channels, 0) < 0) {
av_log(NULL, AV_LOG_FATAL, "Unsupported number of output channels\n");
exit_program(1);
}
if(audio_sync_method>1) av_opt_set_int(ost->swr, "flags", SWR_FLAG_RESAMPLE, 0);
av_log(NULL, AV_LOG_FATAL, "swr_init() failed\n");
swr_free(&ost->swr);
}
if (!ost->swr) {
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);
}
av_assert0(ost->audio_resample || dec->sample_fmt==enc->sample_fmt);
if (audio_sync_method > 0) {
double delta = get_sync_ipts(ost, ist->pts) * 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);
for (i=0; i<planes; i++)
buf[i] -= byte_delta/planes;
av_log(NULL, AV_LOG_VERBOSE, "discarding %d audio samples\n",
-byte_delta / (isize * dec->channels));
ist->is_start = 0;
} else {
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);
uint8_t *t = async_buf + i*((byte_delta + size)/planes);
generate_silence(t, dec->sample_fmt, byte_delta/planes);
memcpy(t + byte_delta/planes, buf[i], size/planes);
buf[i] = t;
}
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_log(NULL, AV_LOG_VERBOSE, "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));
Marton Balint
committed
swr_set_compensation(ost->swr, comp, enc->sample_rate);
ost->sync_opts = lrintf(get_sync_ipts(ost, ist->pts) * enc->sample_rate) -
av_fifo_size(ost->fifo) / (enc->channels * osize); // FIXME wrong
if (ost->audio_resample || ost->audio_channels_mapped) {
size_out = swr_convert(ost->swr, ( uint8_t*[]){buftmp}, allocated_audio_buf_size / (enc->channels * osize),
buf, size / (dec->channels * isize));
if (size_out < 0) {
av_log(NULL, AV_LOG_FATAL, "swr_convert failed\n");
exit_program(1);
}
size_out = size_out * enc->channels * osize;
av_assert0(ost->audio_resample || dec->sample_fmt==enc->sample_fmt);
if (!(enc->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) {
Michael Niedermayer
committed
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");
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) {
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;
Michael Niedermayer
committed
dec = ist->st->codec;
/* deinterlace : must be done before any resize */
int size;
/* create temporary picture */
size = avpicture_get_size(dec->pix_fmt, dec->width, dec->height);
buf = av_malloc(size);
if (!buf)
return;
picture2 = &picture_tmp;
avpicture_fill(picture2, buf, dec->pix_fmt, dec->width, dec->height);
if (avpicture_deinterlace(picture2, picture,
dec->pix_fmt, dec->width, dec->height) < 0) {
/* if error, do not deinterlace */
av_log(NULL, AV_LOG_WARNING, "Deinterlacing failed\n");
} else {
picture2 = picture;
}
if (picture != picture2)
*picture = *picture2;
*bufp = buf;
}
static void do_subtitle_out(AVFormatContext *s,
OutputStream *ost,
InputStream *ist,
Fabrice Bellard
committed
AVSubtitle *sub,
int64_t pts)
{
static uint8_t *subtitle_out = NULL;
int subtitle_out_max_size = 1024 * 1024;
Fabrice Bellard
committed
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)
Fabrice Bellard
committed
return;
}
Michael Niedermayer
committed
enc = ost->st->codec;
Fabrice Bellard
committed
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;
for (i = 0; i < nb; i++) {
ost->sync_opts = av_rescale_q(pts, ist->st->time_base, enc->time_base);
Reimar Döffinger
committed
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,
Fabrice Bellard
committed
subtitle_out_max_size, sub);
Reimar Döffinger
committed
if (subtitle_out_size < 0) {
av_log(NULL, AV_LOG_FATAL, "Subtitle encoding failed\n");
Reimar Döffinger
committed
}
Fabrice Bellard
committed
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);
Fabrice Bellard
committed
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);
Fabrice Bellard
committed
}
}
static void do_video_resample(OutputStream *ost,
InputStream *ist,
AVFrame *in_picture,
AVFrame **out_picture)
{
AVCodecContext *dec = ist->st->codec;
AVCodecContext *enc = ost->st->codec;
int resample_changed = ost->resample_width != in_picture->width ||
ost->resample_height != in_picture->height ||
ost->resample_pix_fmt != in_picture->format;
if (resample_changed) {
av_log(NULL, AV_LOG_INFO,
"Input stream #%d:%d frame changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s / frm size:%dx%d fmt:%s\n",
ist->file_index, ist->st->index,
ost->resample_width, ost->resample_height, av_get_pix_fmt_name(ost->resample_pix_fmt),
dec->width , dec->height , av_get_pix_fmt_name(dec->pix_fmt),
in_picture->width, in_picture->height, av_get_pix_fmt_name(in_picture->format));
ost->resample_width = in_picture->width;
ost->resample_height = in_picture->height;
ost->resample_pix_fmt = in_picture->format;
ost->video_resample = in_picture->width != enc->width ||
in_picture->height != enc->height ||
in_picture->format != enc->pix_fmt;
if (ost->video_resample) {
*out_picture = &ost->resample_frame;
if (!ost->img_resample_ctx || resample_changed) {
/* initialize the destination picture */
if (!ost->resample_frame.data[0]) {
avcodec_get_frame_defaults(&ost->resample_frame);
if (avpicture_alloc((AVPicture *)&ost->resample_frame, enc->pix_fmt,
enc->width, enc->height)) {
av_log(NULL, AV_LOG_FATAL, "Cannot allocate temp picture, check pix fmt\n");
exit_program(1);
}
}
/* initialize a new scaler context */
sws_freeContext(ost->img_resample_ctx);
ost->img_resample_ctx = sws_getContext(in_picture->width, in_picture->height, in_picture->format,
enc->width, enc->height, enc->pix_fmt,
ost->sws_flags, NULL, NULL, NULL);
if (ost->img_resample_ctx == NULL) {
av_log(NULL, AV_LOG_FATAL, "Cannot get resampling context\n");
exit_program(1);
}
}
sws_scale(ost->img_resample_ctx, in_picture->data, in_picture->linesize,
0, ost->resample_height, (*out_picture)->data, (*out_picture)->linesize);
}
#endif
}
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
static double psnr(double d)
{
return -10.0 * log(d) / log(10.0);
}
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));
}
}
static void do_video_out(AVFormatContext *s, OutputStream *ost,
InputStream *ist, AVFrame *in_picture)
int nb_frames, i, ret, format_video_sync;
AVCodecContext *enc;
Michael Niedermayer
committed
double duration = 0;
float quality = same_quant ? in_picture->quality
: ost->st->codec->global_quality;
Michael Niedermayer
committed
enc = ost->st->codec;
Michael Niedermayer
committed
if (ist->st->start_time != AV_NOPTS_VALUE && ist->st->first_dts != AV_NOPTS_VALUE) {
duration = FFMAX(av_q2d(ist->st->time_base), av_q2d(ist->st->codec->time_base));
if(ist->st->avg_frame_rate.num)
duration= FFMAX(duration, 1/av_q2d(ist->st->avg_frame_rate));
duration /= av_q2d(enc->time_base);
}
sync_ipts = get_sync_ipts(ost, in_picture->pts) / av_q2d(enc->time_base);
delta = sync_ipts - ost->sync_opts + duration;
Fabrice Bellard
committed
/* by default, we output a single frame */
nb_frames = 1;
format_video_sync = video_sync_method;
if (format_video_sync == VSYNC_AUTO)
format_video_sync = (s->oformat->flags & AVFMT_VARIABLE_FPS) ? ((s->oformat->flags & AVFMT_NOTIMESTAMPS) ? VSYNC_PASSTHROUGH : VSYNC_VFR) : 1;
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;
ost->sync_opts = lrintf(sync_ipts);
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);
}
do_video_resample(ost, ist, in_picture, &final_picture);
for (i = 0; i < nb_frames; i++) {
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
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
method. */
enc->coded_frame->interlaced_frame = in_picture->interlaced_frame;
enc->coded_frame->top_field_first = in_picture->top_field_first;
pkt.data = (uint8_t *)final_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);
} else {
Michael Niedermayer
committed
big_picture = *final_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
if (!enc->me_threshold)
Michael Niedermayer
committed
big_picture.pict_type = 0;
big_picture.pts = ost->sync_opts;
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");
if (pkt.pts == AV_NOPTS_VALUE && !(enc->codec->capabilities & CODEC_CAP_DELAY))
pkt.pts = ost->sync_opts;
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 (debug_ts) {
av_log(NULL, AV_LOG_INFO, "encoder -> type:video "
"pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n",
av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base),
av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &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);
}
/*
* 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.
*/
Fabrice Bellard
committed
ost->frame_number++;
if (vstats_filename && frame_size)
do_video_stats(output_files[ost->file_index].ctx, ost, frame_size);
Anton Khirnov
committed
static void print_report(OutputFile *output_files,
OutputStream *ost_table, int nb_ostreams,
Michael Niedermayer
committed
int is_last_report, int64_t timer_start, int64_t cur_time)
Fabrice Bellard
committed
{
char buf[1024];
AVFormatContext *oc;
Fabrice Bellard
committed
AVCodecContext *enc;
int frame_number, vid, i;
Baptiste Coudurier
committed
double bitrate;
int64_t pts = INT64_MAX;
static int qp_histogram[52];
int hours, mins, secs, us;
if (!print_stats && !is_last_report)
return;
Fabrice Bellard
committed
if (!is_last_report) {
if (last_time == -1) {
last_time = cur_time;
return;
Fabrice Bellard
committed
if ((cur_time - last_time) < 500000)
return;
last_time = cur_time;
}
Anton Khirnov
committed
oc = output_files[0].ctx;
Fabrice Bellard
committed
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)
total_size = 0;
}
Fabrice Bellard
committed
buf[0] = '\0';
vid = 0;
for (i = 0; i < nb_ostreams; i++) {
ost = &ost_table[i];
Michael Niedermayer
committed
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 fps, t = (cur_time-timer_start) / 1000000.0;
Fabrice Bellard
committed
frame_number = ost->frame_number;
fps = t > 1 ? frame_number / t : 0;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "frame=%5d fps=%3.*f q=%3.1f ",
frame_number, fps < 9.95, fps, q);
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "L");
if (qp >= 0 && qp < FF_ARRAY_ELEMS(qp_histogram))
for (j = 0; j < 32; j++)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%X", (int)lrintf(log(qp_histogram[j] + 1) / log(2)));
if (enc->flags&CODEC_FLAG_PSNR) {
Michael Niedermayer
committed
int j;
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;
Michael Niedermayer
committed
}
if (j)
scale /= 4;
Michael Niedermayer
committed
error_sum += error;
scale_sum += scale;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%c:%2.2f ", type[j], psnr(error / scale));
Michael Niedermayer
committed
}
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "*:%2.2f ", psnr(error_sum / scale_sum));
Michael Niedermayer
committed
}
Fabrice Bellard
committed
vid = 1;
}
/* compute min output value */
Baptiste Coudurier
committed
pts = FFMIN(pts, av_rescale_q(ost->st->pts.val,
ost->st->time_base, AV_TIME_BASE_Q));
Fabrice Bellard
committed
}
secs = pts / AV_TIME_BASE;
us = pts % AV_TIME_BASE;
mins = secs / 60;
secs %= 60;
hours = mins / 60;
mins %= 60;
bitrate = pts ? total_size * 8 / (pts / 1000.0) : 0;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
"size=%8.0fkB time=", total_size / 1024.0);
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
"%02d:%02d:%02d.%02d ", hours, mins, secs,
(100 * us) / AV_TIME_BASE);
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
"bitrate=%6.1fkbits/s", 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);
if (is_last_report) {
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
if(video_size + audio_size + extra_size == 0){
av_log(NULL, AV_LOG_WARNING, "Output file is empty, nothing was encoded (check -ss / -t / -frames parameters if used)\n");
}
static void flush_encoders(OutputStream *ost_table, int nb_ostreams)
{
int i, ret;
for (i = 0; i < nb_ostreams; i++) {
OutputStream *ost = &ost_table[i];
AVCodecContext *enc = ost->st->codec;
AVFormatContext *os = output_files[ost->file_index].ctx;
int stop_encoding = 0;
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;
Fabrice Bellard
committed
}
}
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 += pkt.size;
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);
write_frame(os, &pkt, ost);
break;
default:
}
}
}
/*
* Check whether a packet from ist should be written into ost at this time
*/
static int check_output_constraints(InputStream *ist, OutputStream *ost)
{
OutputFile *of = &output_files[ost->file_index];
int ist_index = ist - input_streams;
if (ost->source_index != ist_index)
return 0;
if (of->start_time && ist->pts < of->start_time)
return 0;
if (of->recording_time != INT64_MAX &&
av_compare_ts(ist->pts, AV_TIME_BASE_Q, of->recording_time + of->start_time,
(AVRational){ 1, 1000000 }) >= 0) {
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
ost->is_past_recording_time = 1;
return 0;
}
return 1;
}
static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *pkt)
{
OutputFile *of = &output_files[ost->file_index];
int64_t ost_tb_start_time = av_rescale_q(of->start_time, AV_TIME_BASE_Q, ost->st->time_base);
AVPicture pict;
AVPacket opkt;
av_init_packet(&opkt);
if ((!ost->frame_number && !(pkt->flags & AV_PKT_FLAG_KEY)) &&
!ost->copy_initial_nonkeyframes)
return;
/* force the input stream PTS */
if (ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
audio_size += pkt->size;
else if (ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
video_size += pkt->size;
ost->sync_opts++;
}
if (pkt->pts != AV_NOPTS_VALUE)
opkt.pts = av_rescale_q(pkt->pts, ist->st->time_base, ost->st->time_base) - ost_tb_start_time;
else
opkt.pts = AV_NOPTS_VALUE;
if (pkt->dts == AV_NOPTS_VALUE)
opkt.dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ost->st->time_base);
else
opkt.dts = av_rescale_q(pkt->dts, ist->st->time_base, ost->st->time_base);
opkt.dts -= ost_tb_start_time;
opkt.duration = av_rescale_q(pkt->duration, ist->st->time_base, ost->st->time_base);
opkt.flags = pkt->flags;
// FIXME remove the following 2 lines they shall be replaced by the bitstream filters
if ( ost->st->codec->codec_id != CODEC_ID_H264
&& ost->st->codec->codec_id != CODEC_ID_MPEG1VIDEO
&& ost->st->codec->codec_id != CODEC_ID_MPEG2VIDEO
&& ost->st->codec->codec_id != CODEC_ID_VC1
) {
if (av_parser_change(ist->st->parser, ost->st->codec, &opkt.data, &opkt.size, pkt->data, pkt->size, pkt->flags & AV_PKT_FLAG_KEY))
opkt.destruct = av_destruct_packet;
} else {
opkt.data = pkt->data;
opkt.size = pkt->size;
}
if (of->ctx->oformat->flags & AVFMT_RAWPICTURE) {
/* store AVPicture in AVPacket, as expected by the output format */
avpicture_fill(&pict, opkt.data, ost->st->codec->pix_fmt, ost->st->codec->width, ost->st->codec->height);
opkt.data = (uint8_t *)&pict;
opkt.size = sizeof(AVPicture);
opkt.flags |= AV_PKT_FLAG_KEY;
}
write_frame(of->ctx, &opkt, ost);