2 * Copyright (c) 2000-2003 Fabrice Bellard
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * multimedia converter based on the FFmpeg libraries
30 #include <stdatomic.h>
43 #if HAVE_SYS_RESOURCE_H
45 #include <sys/types.h>
46 #include <sys/resource.h>
47 #elif HAVE_GETPROCESSTIMES
50 #if HAVE_GETPROCESSMEMORYINFO
54 #if HAVE_SETCONSOLECTRLHANDLER
59 #include <sys/select.h>
64 #include <sys/ioctl.h>
71 #include "libavutil/bprint.h"
72 #include "libavutil/dict.h"
73 #include "libavutil/mem.h"
74 #include "libavutil/time.h"
76 #include "libavformat/avformat.h"
78 #include "libavdevice/avdevice.h"
82 #include "ffmpeg_sched.h"
83 #include "ffmpeg_utils.h"
85 const char program_name
[] = "ffmpeg";
86 const int program_birth_year
= 2000;
90 typedef struct BenchmarkTimeStamps
{
94 } BenchmarkTimeStamps
;
96 static BenchmarkTimeStamps
get_benchmark_time_stamps(void);
97 static int64_t getmaxrss(void);
99 atomic_uint nb_output_dumped
= 0;
101 static BenchmarkTimeStamps current_time
;
102 AVIOContext
*progress_avio
= NULL
;
104 InputFile
**input_files
= NULL
;
105 int nb_input_files
= 0;
107 OutputFile
**output_files
= NULL
;
108 int nb_output_files
= 0;
110 FilterGraph
**filtergraphs
;
118 /* init terminal so that we can grab keys */
119 static struct termios oldtty
;
120 static int restore_tty
;
123 static void term_exit_sigsafe(void)
127 tcsetattr (0, TCSANOW
, &oldtty
);
133 av_log(NULL
, AV_LOG_QUIET
, "%s", "");
137 static volatile int received_sigterm
= 0;
138 static volatile int received_nb_signals
= 0;
139 static atomic_int transcode_init_done
= 0;
140 static volatile int ffmpeg_exited
= 0;
141 static int64_t copy_ts_first_pts
= AV_NOPTS_VALUE
;
144 sigterm_handler(int sig
)
147 received_sigterm
= sig
;
148 received_nb_signals
++;
150 if(received_nb_signals
> 3) {
151 ret
= write(2/*STDERR_FILENO*/, "Received > 3 system signals, hard exiting\n",
152 strlen("Received > 3 system signals, hard exiting\n"));
153 if (ret
< 0) { /* Do nothing */ };
158 #if HAVE_SETCONSOLECTRLHANDLER
159 static BOOL WINAPI
CtrlHandler(DWORD fdwCtrlType
)
161 av_log(NULL
, AV_LOG_DEBUG
, "\nReceived windows signal %ld\n", fdwCtrlType
);
166 case CTRL_BREAK_EVENT
:
167 sigterm_handler(SIGINT
);
170 case CTRL_CLOSE_EVENT
:
171 case CTRL_LOGOFF_EVENT
:
172 case CTRL_SHUTDOWN_EVENT
:
173 sigterm_handler(SIGTERM
);
174 /* Basically, with these 3 events, when we return from this method the
175 process is hard terminated, so stall as long as we need to
176 to try and let the main thread(s) clean up and gracefully terminate
177 (we have at most 5 seconds, but should be done far before that). */
178 while (!ffmpeg_exited
) {
184 av_log(NULL
, AV_LOG_ERROR
, "Received unknown windows signal %ld\n", fdwCtrlType
);
191 #define SIGNAL(sig, func) \
193 action.sa_handler = func; \
194 sigaction(sig, &action, NULL); \
197 #define SIGNAL(sig, func) \
203 #if defined __linux__
204 struct sigaction action
= {0};
205 action
.sa_handler
= sigterm_handler
;
207 /* block other interrupts while processing this one */
208 sigfillset(&action
.sa_mask
);
210 /* restart interruptible functions (i.e. don't fail with EINTR) */
211 action
.sa_flags
= SA_RESTART
;
215 if (stdin_interaction
) {
217 if (tcgetattr (0, &tty
) == 0) {
221 tty
.c_iflag
&= ~(IGNBRK
|BRKINT
|PARMRK
|ISTRIP
222 |INLCR
|IGNCR
|ICRNL
|IXON
);
223 tty
.c_oflag
|= OPOST
;
224 tty
.c_lflag
&= ~(ECHO
|ECHONL
|ICANON
|IEXTEN
);
225 tty
.c_cflag
&= ~(CSIZE
|PARENB
);
230 tcsetattr (0, TCSANOW
, &tty
);
232 SIGNAL(SIGQUIT
, sigterm_handler
); /* Quit (POSIX). */
236 SIGNAL(SIGINT
, sigterm_handler
); /* Interrupt (ANSI). */
237 SIGNAL(SIGTERM
, sigterm_handler
); /* Termination (ANSI). */
239 SIGNAL(SIGXCPU
, sigterm_handler
);
242 signal(SIGPIPE
, SIG_IGN
); /* Broken pipe (POSIX). */
244 #if HAVE_SETCONSOLECTRLHANDLER
245 SetConsoleCtrlHandler((PHANDLER_ROUTINE
) CtrlHandler
, TRUE
);
249 /* read a key without blocking */
250 static int read_key(void)
262 n
= select(1, &rfds
, NULL
, NULL
, &tv
);
271 # if HAVE_PEEKNAMEDPIPE && HAVE_GETSTDHANDLE
273 static HANDLE input_handle
;
276 input_handle
= GetStdHandle(STD_INPUT_HANDLE
);
277 is_pipe
= !GetConsoleMode(input_handle
, &dw
);
281 /* When running under a GUI, you will end here. */
282 if (!PeekNamedPipe(input_handle
, NULL
, 0, NULL
, &nchars
, NULL
)) {
283 // input pipe may have been closed by the program that ran ffmpeg
288 if (read(0, &ch
, 1) == 1)
302 static int decode_interrupt_cb(void *ctx
)
304 return received_nb_signals
> atomic_load(&transcode_init_done
);
307 const AVIOInterruptCB int_cb
= { decode_interrupt_cb
, NULL
};
309 static void ffmpeg_cleanup(int ret
)
312 int64_t maxrss
= getmaxrss() / 1024;
313 av_log(NULL
, AV_LOG_INFO
, "bench: maxrss=%"PRId64
"KiB\n", maxrss
);
316 for (int i
= 0; i
< nb_filtergraphs
; i
++)
317 fg_free(&filtergraphs
[i
]);
318 av_freep(&filtergraphs
);
320 for (int i
= 0; i
< nb_output_files
; i
++)
321 of_free(&output_files
[i
]);
323 for (int i
= 0; i
< nb_input_files
; i
++)
324 ifile_close(&input_files
[i
]);
326 for (int i
= 0; i
< nb_decoders
; i
++)
327 dec_free(&decoders
[i
]);
331 if (fclose(vstats_file
))
332 av_log(NULL
, AV_LOG_ERROR
,
333 "Error closing vstats file, loss of information possible: %s\n",
334 av_err2str(AVERROR(errno
)));
336 av_freep(&vstats_filename
);
337 of_enc_stats_close();
339 hw_device_free_all();
341 av_freep(&filter_nbthreads
);
343 av_freep(&input_files
);
344 av_freep(&output_files
);
348 avformat_network_deinit();
350 if (received_sigterm
) {
351 av_log(NULL
, AV_LOG_INFO
, "Exiting normally, received signal %d.\n",
352 (int) received_sigterm
);
353 } else if (ret
&& atomic_load(&transcode_init_done
)) {
354 av_log(NULL
, AV_LOG_INFO
, "Conversion failed!\n");
360 OutputStream
*ost_iter(OutputStream
*prev
)
362 int of_idx
= prev
? prev
->file
->index
: 0;
363 int ost_idx
= prev
? prev
->index
+ 1 : 0;
365 for (; of_idx
< nb_output_files
; of_idx
++) {
366 OutputFile
*of
= output_files
[of_idx
];
367 if (ost_idx
< of
->nb_streams
)
368 return of
->streams
[ost_idx
];
376 InputStream
*ist_iter(InputStream
*prev
)
378 int if_idx
= prev
? prev
->file
->index
: 0;
379 int ist_idx
= prev
? prev
->index
+ 1 : 0;
381 for (; if_idx
< nb_input_files
; if_idx
++) {
382 InputFile
*f
= input_files
[if_idx
];
383 if (ist_idx
< f
->nb_streams
)
384 return f
->streams
[ist_idx
];
392 static void frame_data_free(void *opaque
, uint8_t *data
)
394 FrameData
*fd
= (FrameData
*)data
;
396 avcodec_parameters_free(&fd
->par_enc
);
401 static int frame_data_ensure(AVBufferRef
**dst
, int writable
)
403 AVBufferRef
*src
= *dst
;
405 if (!src
|| (writable
&& !av_buffer_is_writable(src
))) {
408 fd
= av_mallocz(sizeof(*fd
));
410 return AVERROR(ENOMEM
);
412 *dst
= av_buffer_create((uint8_t *)fd
, sizeof(*fd
),
413 frame_data_free
, NULL
, 0);
415 av_buffer_unref(&src
);
417 return AVERROR(ENOMEM
);
421 const FrameData
*fd_src
= (const FrameData
*)src
->data
;
423 memcpy(fd
, fd_src
, sizeof(*fd
));
426 if (fd_src
->par_enc
) {
429 fd
->par_enc
= avcodec_parameters_alloc();
431 avcodec_parameters_copy(fd
->par_enc
, fd_src
->par_enc
) :
434 av_buffer_unref(dst
);
435 av_buffer_unref(&src
);
440 av_buffer_unref(&src
);
442 fd
->dec
.frame_num
= UINT64_MAX
;
443 fd
->dec
.pts
= AV_NOPTS_VALUE
;
445 for (unsigned i
= 0; i
< FF_ARRAY_ELEMS(fd
->wallclock
); i
++)
446 fd
->wallclock
[i
] = INT64_MIN
;
453 FrameData
*frame_data(AVFrame
*frame
)
455 int ret
= frame_data_ensure(&frame
->opaque_ref
, 1);
456 return ret
< 0 ? NULL
: (FrameData
*)frame
->opaque_ref
->data
;
459 const FrameData
*frame_data_c(AVFrame
*frame
)
461 int ret
= frame_data_ensure(&frame
->opaque_ref
, 0);
462 return ret
< 0 ? NULL
: (const FrameData
*)frame
->opaque_ref
->data
;
465 FrameData
*packet_data(AVPacket
*pkt
)
467 int ret
= frame_data_ensure(&pkt
->opaque_ref
, 1);
468 return ret
< 0 ? NULL
: (FrameData
*)pkt
->opaque_ref
->data
;
471 const FrameData
*packet_data_c(AVPacket
*pkt
)
473 int ret
= frame_data_ensure(&pkt
->opaque_ref
, 0);
474 return ret
< 0 ? NULL
: (const FrameData
*)pkt
->opaque_ref
->data
;
477 int check_avoptions_used(const AVDictionary
*opts
, const AVDictionary
*opts_used
,
478 void *logctx
, int decode
)
480 const AVClass
*class = avcodec_get_class();
481 const AVClass
*fclass
= avformat_get_class();
483 const int flag
= decode
? AV_OPT_FLAG_DECODING_PARAM
:
484 AV_OPT_FLAG_ENCODING_PARAM
;
485 const AVDictionaryEntry
*e
= NULL
;
487 while ((e
= av_dict_iterate(opts
, e
))) {
488 const AVOption
*option
, *foption
;
491 if (av_dict_get(opts_used
, e
->key
, NULL
, 0))
494 optname
= av_strdup(e
->key
);
496 return AVERROR(ENOMEM
);
498 p
= strchr(optname
, ':');
502 option
= av_opt_find(&class, optname
, NULL
, 0,
503 AV_OPT_SEARCH_CHILDREN
| AV_OPT_SEARCH_FAKE_OBJ
);
504 foption
= av_opt_find(&fclass
, optname
, NULL
, 0,
505 AV_OPT_SEARCH_CHILDREN
| AV_OPT_SEARCH_FAKE_OBJ
);
507 if (!option
|| foption
)
510 if (!(option
->flags
& flag
)) {
511 av_log(logctx
, AV_LOG_ERROR
, "Codec AVOption %s (%s) is not a %s "
512 "option.\n", e
->key
, option
->help
? option
->help
: "",
513 decode
? "decoding" : "encoding");
514 return AVERROR(EINVAL
);
517 av_log(logctx
, AV_LOG_WARNING
, "Codec AVOption %s (%s) has not been used "
518 "for any stream. The most likely reason is either wrong type "
519 "(e.g. a video option with no video streams) or that it is a "
520 "private option of some decoder which was not actually used "
521 "for any stream.\n", e
->key
, option
->help
? option
->help
: "");
527 void update_benchmark(const char *fmt
, ...)
529 if (do_benchmark_all
) {
530 BenchmarkTimeStamps t
= get_benchmark_time_stamps();
536 vsnprintf(buf
, sizeof(buf
), fmt
, va
);
538 av_log(NULL
, AV_LOG_INFO
,
539 "bench: %8" PRIu64
" user %8" PRIu64
" sys %8" PRIu64
" real %s \n",
540 t
.user_usec
- current_time
.user_usec
,
541 t
.sys_usec
- current_time
.sys_usec
,
542 t
.real_usec
- current_time
.real_usec
, buf
);
548 static void print_report(int is_last_report
, int64_t timer_start
, int64_t cur_time
, int64_t pts
)
550 AVBPrint buf
, buf_script
;
551 int64_t total_size
= of_filesize(output_files
[0]);
555 static int64_t last_time
= -1;
556 static int first_report
= 1;
557 uint64_t nb_frames_dup
= 0, nb_frames_drop
= 0;
560 const char *hours_sign
;
564 if (!print_stats
&& !is_last_report
&& !progress_avio
)
567 if (!is_last_report
) {
568 if (last_time
== -1) {
569 last_time
= cur_time
;
571 if (((cur_time
- last_time
) < stats_period
&& !first_report
) ||
572 (first_report
&& atomic_load(&nb_output_dumped
) < nb_output_files
))
574 last_time
= cur_time
;
577 t
= (cur_time
-timer_start
) / 1000000.0;
580 av_bprint_init(&buf
, 0, AV_BPRINT_SIZE_AUTOMATIC
);
581 av_bprint_init(&buf_script
, 0, AV_BPRINT_SIZE_AUTOMATIC
);
582 for (OutputStream
*ost
= ost_iter(NULL
); ost
; ost
= ost_iter(ost
)) {
583 const float q
= ost
->enc
? atomic_load(&ost
->quality
) / (float) FF_QP2LAMBDA
: -1;
585 if (vid
&& ost
->type
== AVMEDIA_TYPE_VIDEO
) {
586 av_bprintf(&buf
, "q=%2.1f ", q
);
587 av_bprintf(&buf_script
, "stream_%d_%d_q=%.1f\n",
588 ost
->file
->index
, ost
->index
, q
);
590 if (!vid
&& ost
->type
== AVMEDIA_TYPE_VIDEO
) {
592 uint64_t frame_number
= atomic_load(&ost
->packets_written
);
594 fps
= t
> 1 ? frame_number
/ t
: 0;
595 av_bprintf(&buf
, "frame=%5"PRId64
" fps=%3.*f q=%3.1f ",
596 frame_number
, fps
< 9.95, fps
, q
);
597 av_bprintf(&buf_script
, "frame=%"PRId64
"\n", frame_number
);
598 av_bprintf(&buf_script
, "fps=%.2f\n", fps
);
599 av_bprintf(&buf_script
, "stream_%d_%d_q=%.1f\n",
600 ost
->file
->index
, ost
->index
, q
);
602 av_bprintf(&buf
, "L");
605 nb_frames_dup
= atomic_load(&ost
->filter
->nb_frames_dup
);
606 nb_frames_drop
= atomic_load(&ost
->filter
->nb_frames_drop
);
614 if (copy_ts_first_pts
== AV_NOPTS_VALUE
&& pts
> 1)
615 copy_ts_first_pts
= pts
;
616 if (copy_ts_first_pts
!= AV_NOPTS_VALUE
)
617 pts
-= copy_ts_first_pts
;
620 us
= FFABS64U(pts
) % AV_TIME_BASE
;
621 secs
= FFABS64U(pts
) / AV_TIME_BASE
% 60;
622 mins
= FFABS64U(pts
) / AV_TIME_BASE
/ 60 % 60;
623 hours
= FFABS64U(pts
) / AV_TIME_BASE
/ 3600;
624 hours_sign
= (pts
< 0) ? "-" : "";
626 bitrate
= pts
!= AV_NOPTS_VALUE
&& pts
&& total_size
>= 0 ? total_size
* 8 / (pts
/ 1000.0) : -1;
627 speed
= pts
!= AV_NOPTS_VALUE
&& t
!= 0.0 ? (double)pts
/ AV_TIME_BASE
/ t
: -1;
629 if (total_size
< 0) av_bprintf(&buf
, "size=N/A time=");
630 else av_bprintf(&buf
, "size=%8.0fKiB time=", total_size
/ 1024.0);
631 if (pts
== AV_NOPTS_VALUE
) {
632 av_bprintf(&buf
, "N/A ");
634 av_bprintf(&buf
, "%s%02"PRId64
":%02d:%02d.%02d ",
635 hours_sign
, hours
, mins
, secs
, (100 * us
) / AV_TIME_BASE
);
639 av_bprintf(&buf
, "bitrate=N/A");
640 av_bprintf(&buf_script
, "bitrate=N/A\n");
642 av_bprintf(&buf
, "bitrate=%6.1fkbits/s", bitrate
);
643 av_bprintf(&buf_script
, "bitrate=%6.1fkbits/s\n", bitrate
);
646 if (total_size
< 0) av_bprintf(&buf_script
, "total_size=N/A\n");
647 else av_bprintf(&buf_script
, "total_size=%"PRId64
"\n", total_size
);
648 if (pts
== AV_NOPTS_VALUE
) {
649 av_bprintf(&buf_script
, "out_time_us=N/A\n");
650 av_bprintf(&buf_script
, "out_time_ms=N/A\n");
651 av_bprintf(&buf_script
, "out_time=N/A\n");
653 av_bprintf(&buf_script
, "out_time_us=%"PRId64
"\n", pts
);
654 av_bprintf(&buf_script
, "out_time_ms=%"PRId64
"\n", pts
);
655 av_bprintf(&buf_script
, "out_time=%s%02"PRId64
":%02d:%02d.%06d\n",
656 hours_sign
, hours
, mins
, secs
, us
);
659 if (nb_frames_dup
|| nb_frames_drop
)
660 av_bprintf(&buf
, " dup=%"PRId64
" drop=%"PRId64
, nb_frames_dup
, nb_frames_drop
);
661 av_bprintf(&buf_script
, "dup_frames=%"PRId64
"\n", nb_frames_dup
);
662 av_bprintf(&buf_script
, "drop_frames=%"PRId64
"\n", nb_frames_drop
);
665 av_bprintf(&buf
, " speed=N/A");
666 av_bprintf(&buf_script
, "speed=N/A\n");
668 av_bprintf(&buf
, " speed=%4.3gx", speed
);
669 av_bprintf(&buf_script
, "speed=%4.3gx\n", speed
);
672 if (print_stats
|| is_last_report
) {
673 const char end
= is_last_report
? '\n' : '\r';
674 if (print_stats
==1 && AV_LOG_INFO
> av_log_get_level()) {
675 fprintf(stderr
, "%s %c", buf
.str
, end
);
677 av_log(NULL
, AV_LOG_INFO
, "%s %c", buf
.str
, end
);
681 av_bprint_finalize(&buf
, NULL
);
684 av_bprintf(&buf_script
, "progress=%s\n",
685 is_last_report
? "end" : "continue");
686 avio_write(progress_avio
, buf_script
.str
,
687 FFMIN(buf_script
.len
, buf_script
.size
- 1));
688 avio_flush(progress_avio
);
689 av_bprint_finalize(&buf_script
, NULL
);
690 if (is_last_report
) {
691 if ((ret
= avio_closep(&progress_avio
)) < 0)
692 av_log(NULL
, AV_LOG_ERROR
,
693 "Error closing progress log, loss of information possible: %s\n", av_err2str(ret
));
700 static void print_stream_maps(void)
702 av_log(NULL
, AV_LOG_INFO
, "Stream mapping:\n");
703 for (InputStream
*ist
= ist_iter(NULL
); ist
; ist
= ist_iter(ist
)) {
704 for (int j
= 0; j
< ist
->nb_filters
; j
++) {
705 if (!filtergraph_is_simple(ist
->filters
[j
]->graph
)) {
706 av_log(NULL
, AV_LOG_INFO
, " Stream #%d:%d (%s) -> %s",
707 ist
->file
->index
, ist
->index
, ist
->dec
? ist
->dec
->name
: "?",
708 ist
->filters
[j
]->name
);
709 if (nb_filtergraphs
> 1)
710 av_log(NULL
, AV_LOG_INFO
, " (graph %d)", ist
->filters
[j
]->graph
->index
);
711 av_log(NULL
, AV_LOG_INFO
, "\n");
716 for (OutputStream
*ost
= ost_iter(NULL
); ost
; ost
= ost_iter(ost
)) {
717 if (ost
->attachment_filename
) {
718 /* an attached file */
719 av_log(NULL
, AV_LOG_INFO
, " File %s -> Stream #%d:%d\n",
720 ost
->attachment_filename
, ost
->file
->index
, ost
->index
);
724 if (ost
->filter
&& !filtergraph_is_simple(ost
->filter
->graph
)) {
725 /* output from a complex graph */
726 av_log(NULL
, AV_LOG_INFO
, " %s", ost
->filter
->name
);
727 if (nb_filtergraphs
> 1)
728 av_log(NULL
, AV_LOG_INFO
, " (graph %d)", ost
->filter
->graph
->index
);
730 av_log(NULL
, AV_LOG_INFO
, " -> Stream #%d:%d (%s)\n", ost
->file
->index
,
731 ost
->index
, ost
->enc_ctx
->codec
->name
);
735 av_log(NULL
, AV_LOG_INFO
, " Stream #%d:%d -> #%d:%d",
736 ost
->ist
->file
->index
,
741 const AVCodec
*in_codec
= ost
->ist
->dec
;
742 const AVCodec
*out_codec
= ost
->enc_ctx
->codec
;
743 const char *decoder_name
= "?";
744 const char *in_codec_name
= "?";
745 const char *encoder_name
= "?";
746 const char *out_codec_name
= "?";
747 const AVCodecDescriptor
*desc
;
750 decoder_name
= in_codec
->name
;
751 desc
= avcodec_descriptor_get(in_codec
->id
);
753 in_codec_name
= desc
->name
;
754 if (!strcmp(decoder_name
, in_codec_name
))
755 decoder_name
= "native";
759 encoder_name
= out_codec
->name
;
760 desc
= avcodec_descriptor_get(out_codec
->id
);
762 out_codec_name
= desc
->name
;
763 if (!strcmp(encoder_name
, out_codec_name
))
764 encoder_name
= "native";
767 av_log(NULL
, AV_LOG_INFO
, " (%s (%s) -> %s (%s))",
768 in_codec_name
, decoder_name
,
769 out_codec_name
, encoder_name
);
771 av_log(NULL
, AV_LOG_INFO
, " (copy)");
772 av_log(NULL
, AV_LOG_INFO
, "\n");
776 static void set_tty_echo(int on
)
780 if (tcgetattr(0, &tty
) == 0) {
781 if (on
) tty
.c_lflag
|= ECHO
;
782 else tty
.c_lflag
&= ~ECHO
;
783 tcsetattr(0, TCSANOW
, &tty
);
788 static int check_keyboard_interaction(int64_t cur_time
)
791 static int64_t last_time
;
792 /* read_key() returns 0 on EOF */
793 if (cur_time
- last_time
>= 100000) {
795 last_time
= cur_time
;
799 av_log(NULL
, AV_LOG_INFO
, "\n\n[q] command received. Exiting.\n\n");
802 if (key
== '+') av_log_set_level(av_log_get_level()+10);
803 if (key
== '-') av_log_set_level(av_log_get_level()-10);
804 if (key
== 'c' || key
== 'C'){
805 char buf
[4096], target
[64], command
[256], arg
[256] = {0};
808 fprintf(stderr
, "\nEnter command: <target>|all <time>|-1 <command>[ <argument>]\n");
811 while ((k
= read_key()) != '\n' && k
!= '\r' && i
< sizeof(buf
)-1)
816 fprintf(stderr
, "\n");
818 (n
= sscanf(buf
, "%63[^ ] %lf %255[^ ] %255[^\n]", target
, &time
, command
, arg
)) >= 3) {
819 av_log(NULL
, AV_LOG_DEBUG
, "Processing command target:%s time:%f command:%s arg:%s",
820 target
, time
, command
, arg
);
821 for (OutputStream
*ost
= ost_iter(NULL
); ost
; ost
= ost_iter(ost
)) {
823 fg_send_command(ost
->fg_simple
, time
, target
, command
, arg
,
826 for (i
= 0; i
< nb_filtergraphs
; i
++)
827 fg_send_command(filtergraphs
[i
], time
, target
, command
, arg
,
830 av_log(NULL
, AV_LOG_ERROR
,
831 "Parse error, at least 3 arguments were expected, "
832 "only %d given in string '%s'\n", n
, buf
);
836 fprintf(stderr
, "key function\n"
838 "+ increase verbosity\n"
839 "- decrease verbosity\n"
840 "c Send command to first matching filter supporting it\n"
841 "C Send/Queue command to all matching filters\n"
842 "h dump packets/hex press to cycle through the 3 states\n"
844 "s Show QP histogram\n"
851 * The following code is the main loop of the file converter
853 static int transcode(Scheduler
*sch
)
856 int64_t timer_start
, transcode_ts
= 0;
860 atomic_store(&transcode_init_done
, 1);
862 ret
= sch_start(sch
);
866 if (stdin_interaction
) {
867 av_log(NULL
, AV_LOG_INFO
, "Press [q] to stop, [?] for help\n");
870 timer_start
= av_gettime_relative();
872 while (!sch_wait(sch
, stats_period
, &transcode_ts
)) {
873 int64_t cur_time
= av_gettime_relative();
875 if (received_nb_signals
)
878 /* if 'q' pressed, exits */
879 if (stdin_interaction
)
880 if (check_keyboard_interaction(cur_time
) < 0)
883 /* dump report by using the output first video and audio streams */
884 print_report(0, timer_start
, cur_time
, transcode_ts
);
887 ret
= sch_stop(sch
, &transcode_ts
);
889 /* write the trailer if needed */
890 for (int i
= 0; i
< nb_output_files
; i
++) {
891 int err
= of_write_trailer(output_files
[i
]);
892 ret
= err_merge(ret
, err
);
897 /* dump report by using the first video and audio streams */
898 print_report(1, timer_start
, av_gettime_relative(), transcode_ts
);
903 static BenchmarkTimeStamps
get_benchmark_time_stamps(void)
905 BenchmarkTimeStamps time_stamps
= { av_gettime_relative() };
907 struct rusage rusage
;
909 getrusage(RUSAGE_SELF
, &rusage
);
910 time_stamps
.user_usec
=
911 (rusage
.ru_utime
.tv_sec
* 1000000LL) + rusage
.ru_utime
.tv_usec
;
912 time_stamps
.sys_usec
=
913 (rusage
.ru_stime
.tv_sec
* 1000000LL) + rusage
.ru_stime
.tv_usec
;
914 #elif HAVE_GETPROCESSTIMES
917 proc
= GetCurrentProcess();
918 GetProcessTimes(proc
, &c
, &e
, &k
, &u
);
919 time_stamps
.user_usec
=
920 ((int64_t)u
.dwHighDateTime
<< 32 | u
.dwLowDateTime
) / 10;
921 time_stamps
.sys_usec
=
922 ((int64_t)k
.dwHighDateTime
<< 32 | k
.dwLowDateTime
) / 10;
924 time_stamps
.user_usec
= time_stamps
.sys_usec
= 0;
929 static int64_t getmaxrss(void)
931 #if HAVE_GETRUSAGE && HAVE_STRUCT_RUSAGE_RU_MAXRSS
932 struct rusage rusage
;
933 getrusage(RUSAGE_SELF
, &rusage
);
934 return (int64_t)rusage
.ru_maxrss
* 1024;
935 #elif HAVE_GETPROCESSMEMORYINFO
937 PROCESS_MEMORY_COUNTERS memcounters
;
938 proc
= GetCurrentProcess();
939 memcounters
.cb
= sizeof(memcounters
);
940 GetProcessMemoryInfo(proc
, &memcounters
, sizeof(memcounters
));
941 return memcounters
.PeakPagefileUsage
;
947 int main(int argc
, char **argv
)
949 Scheduler
*sch
= NULL
;
952 BenchmarkTimeStamps ti
;
956 setvbuf(stderr
,NULL
,_IONBF
,0); /* win32 runtime needs this */
958 av_log_set_flags(AV_LOG_SKIP_REPEATED
);
959 parse_loglevel(argc
, argv
, options
);
962 avdevice_register_all();
964 avformat_network_init();
966 show_banner(argc
, argv
, options
);
970 ret
= AVERROR(ENOMEM
);
974 /* parse options and open all input/output files */
975 ret
= ffmpeg_parse_options(argc
, argv
, sch
);
979 if (nb_output_files
<= 0 && nb_input_files
== 0) {
981 av_log(NULL
, AV_LOG_WARNING
, "Use -h to get full help or, even better, run 'man %s'\n", program_name
);
986 if (nb_output_files
<= 0) {
987 av_log(NULL
, AV_LOG_FATAL
, "At least one output file must be specified\n");
992 current_time
= ti
= get_benchmark_time_stamps();
993 ret
= transcode(sch
);
994 if (ret
>= 0 && do_benchmark
) {
995 int64_t utime
, stime
, rtime
;
996 current_time
= get_benchmark_time_stamps();
997 utime
= current_time
.user_usec
- ti
.user_usec
;
998 stime
= current_time
.sys_usec
- ti
.sys_usec
;
999 rtime
= current_time
.real_usec
- ti
.real_usec
;
1000 av_log(NULL
, AV_LOG_INFO
,
1001 "bench: utime=%0.3fs stime=%0.3fs rtime=%0.3fs\n",
1002 utime
/ 1000000.0, stime
/ 1000000.0, rtime
/ 1000000.0);
1005 ret
= received_nb_signals
? 255 :
1006 (ret
== FFMPEG_ERROR_RATE_EXCEEDED
) ? 69 : ret
;
1009 if (ret
== AVERROR_EXIT
)
1012 ffmpeg_cleanup(ret
);