#include "avformat.h"
#include "swscale.h"
#include "framehook.h"
-#include "dsputil.h"
#include "opt.h"
#include "fifo.h"
#define INFINITY HUGE_VAL
#endif
+#undef exit
+
/* select an input stream for an output stream */
typedef struct AVStreamMap {
int file_index;
static int do_hex_dump = 0;
static int do_pkt_dump = 0;
static int do_psnr = 0;
-static int do_vstats = 0;
static int do_pass = 0;
static char *pass_logfilename = NULL;
static int audio_stream_copy = 0;
static int copy_ts= 0;
static int opt_shortest = 0; //
static int video_global_header = 0;
+static char *vstats_filename;
+static FILE *fvstats;
static int rate_emu = 0;
static int nb_frames_dup = 0;
static int nb_frames_drop = 0;
static int input_sync;
-static int limit_filesize = 0; //
+static uint64_t limit_filesize = 0; //
static int pgmyuv_compatibility_hack=0;
static int dts_delta_threshold = 10;
int opt_name_count=0;
AVCodecContext *avctx_opts[CODEC_TYPE_NB];
AVFormatContext *avformat_opts;
+static int64_t timer_start = 0;
static AVBitStreamFilterContext *video_bitstream_filters=NULL;
static AVBitStreamFilterContext *audio_bitstream_filters=NULL;
picture2 = picture;
}
- frame_hook_process(picture2, dec->pix_fmt, dec->width, dec->height);
+ frame_hook_process(picture2, dec->pix_fmt, dec->width, dec->height,
+ 1000000 * ist->pts / AV_TIME_BASE);
if (picture != picture2)
*picture = *picture2;
static void do_video_stats(AVFormatContext *os, AVOutputStream *ost,
int frame_size)
{
- static FILE *fvstats=NULL;
- char filename[40];
- time_t today2;
- struct tm *today;
AVCodecContext *enc;
int frame_number;
int64_t ti;
double ti1, bitrate, avg_bitrate;
+ /* this is executed just the first time do_video_stats is called */
if (!fvstats) {
- today2 = time(NULL);
- today = localtime(&today2);
- snprintf(filename, sizeof(filename), "vstats_%02d%02d%02d.log", today->tm_hour,
- today->tm_min,
- today->tm_sec);
- fvstats = fopen(filename,"w");
+ fvstats = fopen(vstats_filename, "w");
if (!fvstats) {
perror("fopen");
exit(1);
oc = output_files[0];
- total_size = url_ftell(&oc->pb);
+ total_size = url_fsize(&oc->pb);
+ if(total_size<0) // FIXME improve url_fsize() so it works with non seekable output too
+ total_size= url_ftell(&oc->pb);
buf[0] = '\0';
ti1 = 1e10;
enc->coded_frame->quality/(float)FF_QP2LAMBDA);
}
if (!vid && enc->codec_type == CODEC_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 q=%3.1f ",
- frame_number, enc->coded_frame ? enc->coded_frame->quality/(float)FF_QP2LAMBDA : -1);
+ 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,
+ enc->coded_frame ? enc->coded_frame->quality/(float)FF_QP2LAMBDA : -1);
if(is_last_report)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "L");
if(qp_hist && enc->coded_frame){
switch(ist->st->codec->codec_type) {
case CODEC_TYPE_AUDIO:{
if(pkt)
- samples= av_fast_realloc(samples, &samples_size, FFMAX(pkt->size, AVCODEC_MAX_AUDIO_FRAME_SIZE));
+ samples= av_fast_realloc(samples, &samples_size, FFMAX(pkt->size*sizeof(*samples), AVCODEC_MAX_AUDIO_FRAME_SIZE));
data_size= samples_size;
/* XXX: could avoid copy if PCM 16 bits with same
endianness as CPU */
goto fail_decode;
}
} else {
- switch(ist->st->codec->codec_type) {
- case CODEC_TYPE_AUDIO:
- ist->next_pts += ((int64_t)AV_TIME_BASE * ist->st->codec->frame_size) /
- (ist->st->codec->sample_rate * ist->st->codec->channels);
- break;
- case CODEC_TYPE_VIDEO:
- if (ist->st->codec->time_base.num != 0) {
- ist->next_pts += ((int64_t)AV_TIME_BASE *
- ist->st->codec->time_base.num) /
- ist->st->codec->time_base.den;
- }
- break;
+ switch(ist->st->codec->codec_type) {
+ case CODEC_TYPE_AUDIO:
+ ist->next_pts += ((int64_t)AV_TIME_BASE * ist->st->codec->frame_size) /
+ (ist->st->codec->sample_rate * ist->st->codec->channels);
+ break;
+ case CODEC_TYPE_VIDEO:
+ if (ist->st->codec->time_base.num != 0) {
+ ist->next_pts += ((int64_t)AV_TIME_BASE *
+ ist->st->codec->time_base.num) /
+ ist->st->codec->time_base.den;
}
- data_buf = ptr;
- data_size = len;
- ret = len;
- len = 0;
- }
-
- buffer_to_free = NULL;
- if (ist->st->codec->codec_type == CODEC_TYPE_VIDEO) {
- pre_process_video_frame(ist, (AVPicture *)&picture,
- &buffer_to_free);
+ break;
}
-
- // preprocess audio (volume)
- if (ist->st->codec->codec_type == CODEC_TYPE_AUDIO) {
- if (audio_volume != 256) {
- short *volp;
- volp = samples;
- for(i=0;i<(data_size / sizeof(short));i++) {
- int v = ((*volp) * audio_volume + 128) >> 8;
- if (v < -32768) v = -32768;
- if (v > 32767) v = 32767;
- *volp++ = v;
- }
+ data_buf = ptr;
+ data_size = len;
+ ret = len;
+ len = 0;
+ }
+
+ buffer_to_free = NULL;
+ if (ist->st->codec->codec_type == CODEC_TYPE_VIDEO) {
+ pre_process_video_frame(ist, (AVPicture *)&picture,
+ &buffer_to_free);
+ }
+
+ // preprocess audio (volume)
+ if (ist->st->codec->codec_type == CODEC_TYPE_AUDIO) {
+ if (audio_volume != 256) {
+ short *volp;
+ volp = samples;
+ for(i=0;i<(data_size / sizeof(short));i++) {
+ int v = ((*volp) * audio_volume + 128) >> 8;
+ if (v < -32768) v = -32768;
+ if (v > 32767) v = 32767;
+ *volp++ = v;
}
}
+ }
- /* frame rate emulation */
- if (ist->st->codec->rate_emu) {
- int64_t pts = av_rescale((int64_t) ist->frame * ist->st->codec->time_base.num, 1000000, ist->st->codec->time_base.den);
- int64_t now = av_gettime() - ist->start;
- if (pts > now)
- usleep(pts - now);
+ /* frame rate emulation */
+ if (ist->st->codec->rate_emu) {
+ int64_t pts = av_rescale((int64_t) ist->frame * ist->st->codec->time_base.num, 1000000, ist->st->codec->time_base.den);
+ int64_t now = av_gettime() - ist->start;
+ if (pts > now)
+ usleep(pts - now);
- ist->frame++;
- }
+ ist->frame++;
+ }
#if 0
- /* mpeg PTS deordering : if it is a P or I frame, the PTS
- is the one of the next displayed one */
- /* XXX: add mpeg4 too ? */
- if (ist->st->codec->codec_id == CODEC_ID_MPEG1VIDEO) {
- if (ist->st->codec->pict_type != B_TYPE) {
- int64_t tmp;
- tmp = ist->last_ip_pts;
- ist->last_ip_pts = ist->frac_pts.val;
- ist->frac_pts.val = tmp;
- }
+ /* mpeg PTS deordering : if it is a P or I frame, the PTS
+ is the one of the next displayed one */
+ /* XXX: add mpeg4 too ? */
+ if (ist->st->codec->codec_id == CODEC_ID_MPEG1VIDEO) {
+ if (ist->st->codec->pict_type != B_TYPE) {
+ int64_t tmp;
+ tmp = ist->last_ip_pts;
+ ist->last_ip_pts = ist->frac_pts.val;
+ ist->frac_pts.val = tmp;
}
+ }
#endif
- /* if output time reached then transcode raw format,
- encode packets and output them */
- if (start_time == 0 || ist->pts >= start_time)
- for(i=0;i<nb_ostreams;i++) {
- int frame_size;
+ /* if output time reached then transcode raw format,
+ encode packets and output them */
+ if (start_time == 0 || ist->pts >= start_time)
+ for(i=0;i<nb_ostreams;i++) {
+ int frame_size;
- ost = ost_table[i];
- if (ost->source_index == ist_index) {
- os = output_files[ost->file_index];
+ ost = ost_table[i];
+ if (ost->source_index == ist_index) {
+ os = output_files[ost->file_index];
#if 0
- printf("%d: got pts=%0.3f %0.3f\n", i,
- (double)pkt->pts / AV_TIME_BASE,
- ((double)ist->pts / AV_TIME_BASE) -
- ((double)ost->st->pts.val * ost->st->time_base.num / ost->st->time_base.den));
+ printf("%d: got pts=%0.3f %0.3f\n", i,
+ (double)pkt->pts / AV_TIME_BASE,
+ ((double)ist->pts / AV_TIME_BASE) -
+ ((double)ost->st->pts.val * ost->st->time_base.num / ost->st->time_base.den));
#endif
- /* set the input output pts pairs */
- //ost->sync_ipts = (double)(ist->pts + input_files_ts_offset[ist->file_index] - start_time)/ AV_TIME_BASE;
-
- if (ost->encoding_needed) {
- switch(ost->st->codec->codec_type) {
- case CODEC_TYPE_AUDIO:
- do_audio_out(os, ost, ist, data_buf, data_size);
- break;
- case CODEC_TYPE_VIDEO:
- do_video_out(os, ost, ist, &picture, &frame_size);
- video_size += frame_size;
- if (do_vstats && frame_size)
- do_video_stats(os, ost, frame_size);
- break;
- case CODEC_TYPE_SUBTITLE:
- do_subtitle_out(os, ost, ist, &subtitle,
- pkt->pts);
- break;
- default:
- av_abort();
- }
- } else {
- AVFrame avframe; //FIXME/XXX remove this
- AVPacket opkt;
- av_init_packet(&opkt);
-
- /* no reencoding needed : output the packet directly */
- /* force the input stream PTS */
-
- avcodec_get_frame_defaults(&avframe);
- ost->st->codec->coded_frame= &avframe;
- avframe.key_frame = pkt->flags & PKT_FLAG_KEY;
-
- if(ost->st->codec->codec_type == CODEC_TYPE_AUDIO)
- audio_size += data_size;
- else if (ost->st->codec->codec_type == CODEC_TYPE_VIDEO) {
- video_size += data_size;
- ost->sync_opts++;
- }
+ /* set the input output pts pairs */
+ //ost->sync_ipts = (double)(ist->pts + input_files_ts_offset[ist->file_index] - start_time)/ AV_TIME_BASE;
- opkt.stream_index= ost->index;
- if(pkt->pts != AV_NOPTS_VALUE)
- opkt.pts= av_rescale_q(av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q) + input_files_ts_offset[ist->file_index], AV_TIME_BASE_Q, ost->st->time_base);
- else
- opkt.pts= AV_NOPTS_VALUE;
-
- {
- int64_t dts;
- if (pkt->dts == AV_NOPTS_VALUE)
- dts = ist->next_pts;
- else
- dts= av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
- opkt.dts= av_rescale_q(dts + input_files_ts_offset[ist->file_index], AV_TIME_BASE_Q, ost->st->time_base);
- }
- opkt.flags= pkt->flags;
+ if (ost->encoding_needed) {
+ switch(ost->st->codec->codec_type) {
+ case CODEC_TYPE_AUDIO:
+ do_audio_out(os, ost, ist, data_buf, data_size);
+ break;
+ case CODEC_TYPE_VIDEO:
+ do_video_out(os, ost, ist, &picture, &frame_size);
+ video_size += frame_size;
+ if (vstats_filename && frame_size)
+ do_video_stats(os, ost, frame_size);
+ break;
+ case CODEC_TYPE_SUBTITLE:
+ do_subtitle_out(os, ost, ist, &subtitle,
+ pkt->pts);
+ break;
+ default:
+ av_abort();
+ }
+ } else {
+ AVFrame avframe; //FIXME/XXX remove this
+ AVPacket opkt;
+ av_init_packet(&opkt);
+
+ /* no reencoding needed : output the packet directly */
+ /* force the input stream PTS */
+
+ avcodec_get_frame_defaults(&avframe);
+ ost->st->codec->coded_frame= &avframe;
+ avframe.key_frame = pkt->flags & PKT_FLAG_KEY;
+
+ if(ost->st->codec->codec_type == CODEC_TYPE_AUDIO)
+ audio_size += data_size;
+ else if (ost->st->codec->codec_type == CODEC_TYPE_VIDEO) {
+ video_size += data_size;
+ ost->sync_opts++;
+ }
- //FIXME remove the following 2 lines they shall be replaced by the bitstream filters
- if(av_parser_change(ist->st->parser, ost->st->codec, &opkt.data, &opkt.size, data_buf, data_size, pkt->flags & PKT_FLAG_KEY))
- opkt.destruct= av_destruct_packet;
+ opkt.stream_index= ost->index;
+ if(pkt->pts != AV_NOPTS_VALUE)
+ opkt.pts= av_rescale_q(av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q) + input_files_ts_offset[ist->file_index], AV_TIME_BASE_Q, ost->st->time_base);
+ else
+ opkt.pts= AV_NOPTS_VALUE;
- write_frame(os, &opkt, ost->st->codec, bitstream_filters[ost->file_index][pkt->stream_index]);
- ost->st->codec->frame_number++;
- ost->frame_number++;
- av_free_packet(&opkt);
+ {
+ int64_t dts;
+ if (pkt->dts == AV_NOPTS_VALUE)
+ dts = ist->next_pts;
+ else
+ dts= av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
+ opkt.dts= av_rescale_q(dts + input_files_ts_offset[ist->file_index], AV_TIME_BASE_Q, ost->st->time_base);
}
+ opkt.flags= pkt->flags;
+
+ //FIXME remove the following 2 lines they shall be replaced by the bitstream filters
+ if(av_parser_change(ist->st->parser, ost->st->codec, &opkt.data, &opkt.size, data_buf, data_size, pkt->flags & PKT_FLAG_KEY))
+ opkt.destruct= av_destruct_packet;
+
+ write_frame(os, &opkt, ost->st->codec, bitstream_filters[ost->file_index][pkt->stream_index]);
+ ost->st->codec->frame_number++;
+ ost->frame_number++;
+ av_free_packet(&opkt);
}
}
- av_free(buffer_to_free);
- /* XXX: allocate the subtitles in the codec ? */
- if (subtitle_to_free) {
- if (subtitle_to_free->rects != NULL) {
- for (i = 0; i < subtitle_to_free->num_rects; i++) {
- av_free(subtitle_to_free->rects[i].bitmap);
- av_free(subtitle_to_free->rects[i].rgba_palette);
- }
- av_freep(&subtitle_to_free->rects);
+ }
+ av_free(buffer_to_free);
+ /* XXX: allocate the subtitles in the codec ? */
+ if (subtitle_to_free) {
+ if (subtitle_to_free->rects != NULL) {
+ for (i = 0; i < subtitle_to_free->num_rects; i++) {
+ av_free(subtitle_to_free->rects[i].bitmap);
+ av_free(subtitle_to_free->rects[i].rgba_palette);
}
- subtitle_to_free->num_rects = 0;
- subtitle_to_free = NULL;
+ av_freep(&subtitle_to_free->rects);
}
+ subtitle_to_free->num_rects = 0;
+ subtitle_to_free = NULL;
}
+ }
discard_packet:
if (pkt == NULL) {
/* EOF handling */
AVOutputStream *ost, **ost_table = NULL;
AVInputStream *ist, **ist_table = NULL;
AVInputFile *file_table;
- AVFormatContext *stream_no_data;
int key;
file_table= (AVInputFile*) av_mallocz(nb_input_files * sizeof(AVInputFile));
if (ost->video_resample) {
avcodec_get_frame_defaults(&ost->pict_tmp);
if( avpicture_alloc( (AVPicture*)&ost->pict_tmp, codec->pix_fmt,
- codec->width, codec->height ) )
+ codec->width, codec->height ) ) {
+ fprintf(stderr, "Cannot allocate temp picture, check pix fmt\n");
exit(1);
-
+ }
ost->img_resample_ctx = sws_getContext(
icodec->width - (frame_leftBand + frame_rightBand),
icodec->height - (frame_topBand + frame_bottomBand),
}
term_init();
- stream_no_data = 0;
key = -1;
+ timer_start = av_gettime();
for(; received_sigterm == 0;) {
int file_index, ist_index;
break;
/* finish if limit size exhausted */
- if (limit_filesize != 0 && (limit_filesize * 1024) < url_ftell(&output_files[0]->pb))
+ if (limit_filesize != 0 && limit_filesize < url_ftell(&output_files[0]->pb))
break;
/* read a frame from it and output it in the fifo */
if (opt_shortest) break; else continue; //
}
- if (!pkt.size) {
- stream_no_data = is;
- } else {
- stream_no_data = 0;
- }
if (do_pkt_dump) {
- av_pkt_dump(stdout, &pkt, do_hex_dump);
+ av_pkt_dump_log(NULL, AV_LOG_DEBUG, &pkt, do_hex_dump);
}
/* the following test is needed in case new streams appear
dynamically in stream : we ignore them */
pgmyuv_compatibility_hack=1;
// opt_image_format(arg);
arg = "image2";
+ fprintf(stderr, "pgmyuv format is deprecated, use image2\n");
}
file_iformat = av_find_input_format(arg);
for(i=0;i<ic->nb_streams;i++) {
int j;
AVCodecContext *enc = ic->streams[i]->codec;
-#if defined(HAVE_THREADS)
if(thread_count>1)
avcodec_thread_init(enc, thread_count);
-#endif
enc->thread_count= thread_count;
switch(enc->codec_type) {
case CODEC_TYPE_AUDIO:
bitstream_filters[nb_output_files][oc->nb_streams - 1]= video_bitstream_filters;
video_bitstream_filters= NULL;
-#if defined(HAVE_THREADS)
if(thread_count>1)
avcodec_thread_init(st->codec, thread_count);
-#endif
video_enc = st->codec;
bitstream_filters[nb_output_files][oc->nb_streams - 1]= audio_bitstream_filters;
audio_bitstream_filters= NULL;
-#if defined(HAVE_THREADS)
if(thread_count>1)
avcodec_thread_init(st->codec, thread_count);
-#endif
audio_enc = st->codec;
audio_enc->codec_type = CODEC_TYPE_AUDIO;
}
}
+static void opt_vstats_file (const char *arg)
+{
+ av_free (vstats_filename);
+ vstats_filename=av_strdup (arg);
+}
+
+static void opt_vstats (void)
+{
+ char filename[40];
+ time_t today2 = time(NULL);
+ struct tm *today = localtime(&today2);
+
+ snprintf(filename, sizeof(filename), "vstats_%02d%02d%02d.log", today->tm_hour, today->tm_min,
+ today->tm_sec);
+ opt_vstats_file(filename);
+}
+
static void opt_video_bsf(const char *arg)
{
AVBitStreamFilterContext *bsfc= av_bitstream_filter_init(arg); //FIXME split name and args for filter at '='
{ "map", HAS_ARG | OPT_EXPERT, {(void*)opt_map}, "set input stream mapping", "file:stream[:syncfile:syncstream]" },
{ "map_meta_data", HAS_ARG | OPT_EXPERT, {(void*)opt_map_meta_data}, "set meta data information of outfile from infile", "outfile:infile" },
{ "t", HAS_ARG, {(void*)opt_recording_time}, "set the recording time", "duration" },
- { "fs", HAS_ARG | OPT_INT, {(void*)&limit_filesize}, "set the limit file size", "limit_size" }, //
+ { "fs", HAS_ARG | OPT_INT64, {(void*)&limit_filesize}, "set the limit file size in bytes", "limit_size" }, //
{ "ss", HAS_ARG, {(void*)opt_start_time}, "set the start time offset", "time_off" },
{ "itsoffset", HAS_ARG, {(void*)opt_input_ts_offset}, "set the input ts offset", "time_off" },
{ "title", HAS_ARG | OPT_STRING, {(void*)&str_title}, "set the title", "string" },
{ "deinterlace", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&do_deinterlace},
"deinterlace pictures" },
{ "psnr", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&do_psnr}, "calculate PSNR of compressed frames" },
- { "vstats", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&do_vstats}, "dump video coding statistics to file" },
+ { "vstats", OPT_EXPERT | OPT_VIDEO, {(void*)&opt_vstats}, "dump video coding statistics to file" },
+ { "vstats_file", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_vstats_file}, "dump video coding statistics to file", "file" },
{ "vhook", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)add_frame_hooker}, "insert video processing module", "module" },
{ "intra_matrix", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_intra_matrix}, "specify intra matrix coeffs", "matrix" },
{ "inter_matrix", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_inter_matrix}, "specify inter matrix coeffs", "matrix" },
exit(1);
}
+/**
+ * Trivial log callback.
+ * Only suitable for show_help and similar since it lacks prefix handling.
+ */
+static void log_callback_help(void* ptr, int level, const char* fmt, va_list vl)
+{
+ vfprintf(stdout, fmt, vl);
+}
+
static void show_help(void)
{
+ av_log_set_callback(log_callback_help);
show_banner();
printf("usage: ffmpeg [[infile options] -i infile]... {[outfile options] outfile}...\n"
"Hyper fast Audio and Video encoder\n");
av_free(intra_matrix);
av_free(inter_matrix);
+
+ if (fvstats)
+ fclose(fvstats);
+ av_free(vstats_filename);
+
av_free(opt_names);
#ifdef CONFIG_POWERPC_PERF