Newer
Older
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) {
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);
av_log(NULL, AV_LOG_FATAL, "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, ost->bitstream_filters);
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){
av_log(NULL, AV_LOG_FATAL, "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,
av_log(NULL, AV_LOG_FATAL, "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, ost->bitstream_filters);
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++) {
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.stream_index = ost->index;
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->st->codec, ost->bitstream_filters);
Fabrice Bellard
committed
}
}
static int bit_buffer_size= 1024*256;
static uint8_t *bit_buffer= NULL;
Todd Kirby
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 != dec->width ||
ost->resample_height != dec->height ||
ost->resample_pix_fmt != dec->pix_fmt;
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\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));
ost->resample_width = dec->width;
ost->resample_height = dec->height;
ost->resample_pix_fmt = dec->pix_fmt;
}
ost->video_resample = dec->width != enc->width ||
dec->height != enc->height ||
dec->pix_fmt != 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(dec->width, dec->height, dec->pix_fmt,
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
}
static void do_video_out(AVFormatContext *s,
OutputStream *ost,
InputStream *ist,
int nb_frames, i, ret, format_video_sync;
AVCodecContext *enc;
double sync_ipts;
Michael Niedermayer
committed
double duration = 0;
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) / av_q2d(enc->time_base);
Fabrice Bellard
committed
/* by default, we output a single frame */
nb_frames = 1;
Philip Gladstone
committed
*frame_size = 0;
format_video_sync = video_sync_method;
if (format_video_sync < 0)
format_video_sync = (s->oformat->flags & AVFMT_VARIABLE_FPS) ? ((s->oformat->flags & AVFMT_NOTIMESTAMPS) ? 0 : 2) : 1;
if (format_video_sync) {
Michael Niedermayer
committed
double vdelta = sync_ipts - ost->sync_opts + duration;
//FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
if (vdelta < -1.1)
nb_frames = 0;
else if (format_video_sync == 2) {
if(vdelta<=-0.6){
nb_frames=0;
}else if(vdelta>0.6)
}else if (vdelta > 1.1)
//fprintf(stderr, "vdelta:%f, ost->sync_opts:%"PRId64", ost->sync_ipts:%f nb_frames:%d\n", vdelta, ost->sync_opts, get_sync_ipts(ost), nb_frames);
if (nb_frames == 0){
++nb_frames_drop;
av_log(NULL, AV_LOG_VERBOSE, "*** drop!\n");
nb_frames_dup += nb_frames - 1;
av_log(NULL, AV_LOG_VERBOSE, "*** %d dup!\n", nb_frames-1);
ost->sync_opts= lrintf(sync_ipts);
nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number);
do_video_resample(ost, ist, in_picture, &final_picture);
Fabrice Bellard
committed
for(i=0;i<nb_frames;i++) {
AVPacket pkt;
av_init_packet(&pkt);
pkt.stream_index= ost->index;
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->st->codec, ost->bitstream_filters);
} 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 = AV_NOPTS_VALUE;
big_picture.pts= ost->sync_opts;
// big_picture.pts= av_rescale(ost->sync_opts, AV_TIME_BASE*(int64_t)enc->time_base.num, enc->time_base.den);
//av_log(NULL, AV_LOG_DEBUG, "%"PRId64" -> encoder\n", 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_video(enc,
bit_buffer, bit_buffer_size,
av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
pkt.data= bit_buffer;
if(enc->coded_frame->pts != AV_NOPTS_VALUE)
pkt.pts= av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
/*av_log(NULL, AV_LOG_DEBUG, "encoder -> %"PRId64"/%"PRId64"\n",
pkt.pts != AV_NOPTS_VALUE ? av_rescale(pkt.pts, enc->time_base.den, AV_TIME_BASE*(int64_t)enc->time_base.num) : -1,
pkt.dts != AV_NOPTS_VALUE ? av_rescale(pkt.dts, enc->time_base.den, AV_TIME_BASE*(int64_t)enc->time_base.num) : -1);*/
if(enc->coded_frame->key_frame)
pkt.flags |= AV_PKT_FLAG_KEY;
write_frame(s, &pkt, ost->st->codec, ost->bitstream_filters);
video_size += ret;
//fprintf(stderr,"\nFrame: %3d size: %5d type: %d",
// enc->frame_number-1, ret, enc->pict_type);
/* if two pass, output log */
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
Fabrice Bellard
committed
ost->frame_number++;
static double psnr(double d)
{
return -10.0*log(d)/log(10.0);
static void do_video_stats(AVFormatContext *os, OutputStream *ost,
Fabrice Bellard
committed
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) {
Benoit Fouet
committed
perror("fopen");
Benoit Fouet
committed
}
}
Michael Niedermayer
committed
enc = ost->st->codec;
if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
Fabrice Bellard
committed
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);
Fabrice Bellard
committed
/* 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);
Stefano Sabatini
committed
fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(enc->coded_frame->pict_type));
Fabrice Bellard
committed
}
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) {
Michael Niedermayer
committed
float t = (cur_time-timer_start) / 1000000.0;
Fabrice Bellard
committed
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);
Michael Niedermayer
committed
if(is_last_report)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "L");
if(qp>=0 && qp<FF_ARRAY_ELEMS(qp_histogram))
qp_histogram[qp]++;
for(j=0; j<32; j++)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%X", (int)lrintf(log(qp_histogram[j]+1)/log(2)));
}
Michael Niedermayer
committed
if (enc->flags&CODEC_FLAG_PSNR){
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=");
Michael Niedermayer
committed
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;
}
if(j) scale/=4;
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;
if (!ost->encoding_needed)
continue;
if (ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <=1)
continue;
if (ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO && (os->oformat->flags & AVFMT_RAWPICTURE) && enc->codec->id == CODEC_ID_RAWVIDEO)
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
continue;
for(;;) {
AVPacket pkt;
int fifo_bytes;
av_init_packet(&pkt);
pkt.stream_index= ost->index;
switch (ost->st->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
fifo_bytes = av_fifo_size(ost->fifo);
ret = 0;
/* encode any samples remaining in fifo */
if (fifo_bytes > 0) {
int osize = av_get_bytes_per_sample(enc->sample_fmt);
int fs_tmp = enc->frame_size;
av_fifo_generic_read(ost->fifo, audio_buf, fifo_bytes, NULL);
if (enc->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME) {
enc->frame_size = fifo_bytes / (osize * enc->channels);
} else { /* pad */
int frame_bytes = enc->frame_size*osize*enc->channels;
if (allocated_audio_buf_size < frame_bytes)
exit_program(1);
generate_silence(audio_buf+fifo_bytes, enc->sample_fmt, frame_bytes - fifo_bytes);
ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, (short *)audio_buf);
pkt.duration = av_rescale((int64_t)enc->frame_size*ost->st->time_base.den,
ost->st->time_base.num, enc->sample_rate);
enc->frame_size = fs_tmp;
}
if (ret <= 0) {
ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
exit_program(1);
}
audio_size += ret;
pkt.flags |= AV_PKT_FLAG_KEY;
break;
case AVMEDIA_TYPE_VIDEO:
ret = avcodec_encode_video(enc, bit_buffer, bit_buffer_size, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
exit_program(1);
}
video_size += ret;
if(enc->coded_frame && enc->coded_frame->key_frame)
pkt.flags |= AV_PKT_FLAG_KEY;
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
break;
default:
ret=-1;
if (ret <= 0)
break;
pkt.data = bit_buffer;
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);
write_frame(os, &pkt, ost->st->codec, ost->bitstream_filters);
}
}
}
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
/*
* 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) {
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++;
}
opkt.stream_index = ost->index;
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->pts, 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
) {
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->st->codec, ost->bitstream_filters);
ost->st->codec->frame_number++;
ost->frame_number++;
av_free_packet(&opkt);
}
static void rate_emu_sleep(InputStream *ist)
{
if (input_files[ist->file_index].rate_emu) {
int64_t pts = av_rescale(ist->pts, 1000000, AV_TIME_BASE);
int64_t now = av_gettime() - ist->start;
if (pts > now)
usleep(pts - now);
}
}
static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
{
static unsigned int samples_size = 0;
int bps = av_get_bytes_per_sample(ist->st->codec->sample_fmt);
uint8_t *decoded_data_buf = NULL;
int decoded_data_size = 0;
int i, ret;
if (pkt && samples_size < FFMAX(pkt->size * bps, AVCODEC_MAX_AUDIO_FRAME_SIZE)) {
av_free(samples);
samples_size = FFMAX(pkt->size * bps, AVCODEC_MAX_AUDIO_FRAME_SIZE);
samples = av_malloc(samples_size);
}
decoded_data_size = samples_size;
ret = avcodec_decode_audio3(ist->st->codec, samples, &decoded_data_size,
pkt);
if (ret < 0)
return ret;
*got_output = decoded_data_size > 0;
/* Some bug in mpeg audio decoder gives */
/* decoded_data_size < 0, it seems they are overflows */
if (!*got_output) {
/* no audio frame */
}
decoded_data_buf = (uint8_t *)samples;
ist->next_pts += ((int64_t)AV_TIME_BASE/bps * decoded_data_size) /
(ist->st->codec->sample_rate * ist->st->codec->channels);
// preprocess audio (volume)
if (audio_volume != 256) {
switch (ist->st->codec->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);
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);
}
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;
}
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
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);
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = &output_streams[i];
if (!check_output_constraints(ist, ost) || !ost->encoding_needed)
continue;
do_audio_out(output_files[ost->file_index].ctx, ost, ist,
decoded_data_buf, decoded_data_size);
}
}
static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_t *pkt_pts, int64_t *pkt_dts)
{
AVFrame *decoded_frame, *filtered_frame = NULL;
void *buffer_to_free = NULL;
int i, ret = 0;
float quality = 0;
int frame_available = 1;
int duration=0;
Michael Niedermayer
committed
int64_t *best_effort_timestamp;
AVRational *frame_sample_aspect;
if (!(decoded_frame = avcodec_alloc_frame()))
return AVERROR(ENOMEM);
pkt->pts = *pkt_pts;
pkt->dts = *pkt_dts;
*pkt_pts = AV_NOPTS_VALUE;
if (pkt->duration) {
duration = av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);
} else if(ist->st->codec->time_base.num != 0) {
int ticks= ist->st->parser ? ist->st->parser->repeat_pict+1 : ist->st->codec->ticks_per_frame;
duration = ((int64_t)AV_TIME_BASE *
ist->st->codec->time_base.num * ticks) /
ist->st->codec->time_base.den;
}
if(*pkt_dts != AV_NOPTS_VALUE && duration) {
*pkt_dts += duration;
}else
*pkt_dts = AV_NOPTS_VALUE;
ret = avcodec_decode_video2(ist->st->codec,
decoded_frame, got_output, pkt);
if (ret < 0)
goto fail;
quality = same_quant ? decoded_frame->quality : 0;
if (!*got_output) {
/* no picture yet */
av_freep(&decoded_frame);
Michael Niedermayer
committed
best_effort_timestamp= av_opt_ptr(avcodec_get_frame_class(), decoded_frame, "best_effort_timestamp");
if(*best_effort_timestamp != AV_NOPTS_VALUE)
ist->next_pts = ist->pts = *best_effort_timestamp;
ist->next_pts += duration;
pre_process_video_frame(ist, (AVPicture *)decoded_frame, &buffer_to_free);
#if CONFIG_AVFILTER
Michael Niedermayer
committed
frame_sample_aspect= av_opt_ptr(avcodec_get_frame_class(), decoded_frame, "sample_aspect_ratio");
for(i=0;i<nb_output_streams;i++) {
OutputStream *ost = ost = &output_streams[i];
if(check_output_constraints(ist, ost)){
Michael Niedermayer
committed
if (!frame_sample_aspect->num)
*frame_sample_aspect = ist->st->sample_aspect_ratio;
av_vsrc_buffer_add_frame(ost->input_video_filter, decoded_frame, AV_VSRC_BUF_FLAG_OVERWRITE);
}
}
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = &output_streams[i];
int frame_size;
if (!check_output_constraints(ist, ost) || !ost->encoding_needed)
continue;
#if CONFIG_AVFILTER
if (ost->input_video_filter) {
frame_available = avfilter_poll_frame(ost->output_video_filter->inputs[0]);
}
while (frame_available) {
if (ost->output_video_filter) {
AVRational ist_pts_tb = ost->output_video_filter->inputs[0]->time_base;
if (av_buffersink_get_buffer_ref(ost->output_video_filter, &ost->picref, 0) < 0)
goto cont;
if (!filtered_frame && !(filtered_frame = avcodec_alloc_frame())) {
ret = AVERROR(ENOMEM);
goto fail;
}
*filtered_frame= *decoded_frame; //for me_threshold
if (ost->picref) {
avfilter_fill_frame_from_video_buffer_ref(filtered_frame, ost->picref);
ist->pts = av_rescale_q(ost->picref->pts, ist_pts_tb, AV_TIME_BASE_Q);
if (ost->picref->video && !ost->frame_aspect_ratio)
ost->st->codec->sample_aspect_ratio = ost->picref->video->sample_aspect_ratio;
#else
filtered_frame = decoded_frame;
#endif
do_video_out(output_files[ost->file_index].ctx, ost, ist, filtered_frame, &frame_size,
same_quant ? quality : ost->st->codec->global_quality);
if (vstats_filename && frame_size)
do_video_stats(output_files[ost->file_index].ctx, ost, frame_size);
#if CONFIG_AVFILTER
cont:
frame_available = ost->output_video_filter && avfilter_poll_frame(ost->output_video_filter->inputs[0]);
avfilter_unref_buffer(ost->picref);
av_freep(&filtered_frame);
#endif
fail:
av_free(buffer_to_free);
av_freep(&decoded_frame);
return ret;
Fabrice Bellard
committed
}
static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output)
{
AVSubtitle subtitle;
int i, ret = avcodec_decode_subtitle2(ist->st->codec,
&subtitle, got_output, pkt);
if (ret < 0)
return ret;
if (!*got_output)
rate_emu_sleep(ist);
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = &output_streams[i];
if (!check_output_constraints(ist, ost) || !ost->encoding_needed)
continue;
do_subtitle_out(output_files[ost->file_index].ctx, ost, ist, &subtitle, pkt->pts);
}
avsubtitle_free(&subtitle);
}
Fabrice Bellard
committed
/* pkt = NULL means EOF (needed to flush decoder buffers) */
static int output_packet(InputStream *ist,
OutputStream *ost_table, int nb_ostreams,
Wolfram Gloger
committed
const AVPacket *pkt)
Fabrice Bellard
committed
{
int got_output;
int64_t pkt_dts = AV_NOPTS_VALUE;
int64_t pkt_pts = AV_NOPTS_VALUE;
if (ist->next_pts == AV_NOPTS_VALUE)
ist->next_pts = ist->pts;
Michael Niedermayer
committed
Fabrice Bellard
committed
if (pkt == NULL) {
/* EOF handling */
av_init_packet(&avpkt);
avpkt.data = NULL;
avpkt.size = 0;