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 "compat/android/binder.h"
85 #include "ffmpeg_sched.h"
86 #include "ffmpeg_utils.h"
87 #include "graph/graphprint.h"
89 const char program_name
[] = "ffmpeg";
90 const int program_birth_year
= 2000;
94 typedef struct BenchmarkTimeStamps
{
98 } BenchmarkTimeStamps
;
100 static BenchmarkTimeStamps
get_benchmark_time_stamps(void);
101 static int64_t getmaxrss(void);
103 atomic_uint nb_output_dumped
= 0;
105 static BenchmarkTimeStamps current_time
;
106 AVIOContext
*progress_avio
= NULL
;
108 InputFile
**input_files
= NULL
;
109 int nb_input_files
= 0;
111 OutputFile
**output_files
= NULL
;
112 int nb_output_files
= 0;
114 FilterGraph
**filtergraphs
;
122 /* init terminal so that we can grab keys */
123 static struct termios oldtty
;
124 static int restore_tty
;
127 static void term_exit_sigsafe(void)
131 tcsetattr (0, TCSANOW
, &oldtty
);
137 av_log(NULL
, AV_LOG_QUIET
, "%s", "");
141 static volatile int received_sigterm
= 0;
142 static volatile int received_nb_signals
= 0;
143 static atomic_int transcode_init_done
= 0;
144 static volatile int ffmpeg_exited
= 0;
145 static int64_t copy_ts_first_pts
= AV_NOPTS_VALUE
;
148 sigterm_handler(int sig
)
151 received_sigterm
= sig
;
152 received_nb_signals
++;
154 if(received_nb_signals
> 3) {
155 ret
= write(2/*STDERR_FILENO*/, "Received > 3 system signals, hard exiting\n",
156 strlen("Received > 3 system signals, hard exiting\n"));
157 if (ret
< 0) { /* Do nothing */ };
162 #if HAVE_SETCONSOLECTRLHANDLER
163 static BOOL WINAPI
CtrlHandler(DWORD fdwCtrlType
)
165 av_log(NULL
, AV_LOG_DEBUG
, "\nReceived windows signal %ld\n", fdwCtrlType
);
170 case CTRL_BREAK_EVENT
:
171 sigterm_handler(SIGINT
);
174 case CTRL_CLOSE_EVENT
:
175 case CTRL_LOGOFF_EVENT
:
176 case CTRL_SHUTDOWN_EVENT
:
177 sigterm_handler(SIGTERM
);
178 /* Basically, with these 3 events, when we return from this method the
179 process is hard terminated, so stall as long as we need to
180 to try and let the main thread(s) clean up and gracefully terminate
181 (we have at most 5 seconds, but should be done far before that). */
182 while (!ffmpeg_exited
) {
188 av_log(NULL
, AV_LOG_ERROR
, "Received unknown windows signal %ld\n", fdwCtrlType
);
195 #define SIGNAL(sig, func) \
197 action.sa_handler = func; \
198 sigaction(sig, &action, NULL); \
201 #define SIGNAL(sig, func) \
207 #if defined __linux__
208 struct sigaction action
= {0};
209 action
.sa_handler
= sigterm_handler
;
211 /* block other interrupts while processing this one */
212 sigfillset(&action
.sa_mask
);
214 /* restart interruptible functions (i.e. don't fail with EINTR) */
215 action
.sa_flags
= SA_RESTART
;
219 if (stdin_interaction
) {
221 if (tcgetattr (0, &tty
) == 0) {
225 tty
.c_iflag
&= ~(IGNBRK
|BRKINT
|PARMRK
|ISTRIP
226 |INLCR
|IGNCR
|ICRNL
|IXON
);
227 tty
.c_oflag
|= OPOST
;
228 tty
.c_lflag
&= ~(ECHO
|ECHONL
|ICANON
|IEXTEN
);
229 tty
.c_cflag
&= ~(CSIZE
|PARENB
);
234 tcsetattr (0, TCSANOW
, &tty
);
236 SIGNAL(SIGQUIT
, sigterm_handler
); /* Quit (POSIX). */
240 SIGNAL(SIGINT
, sigterm_handler
); /* Interrupt (ANSI). */
241 SIGNAL(SIGTERM
, sigterm_handler
); /* Termination (ANSI). */
243 SIGNAL(SIGXCPU
, sigterm_handler
);
246 signal(SIGPIPE
, SIG_IGN
); /* Broken pipe (POSIX). */
248 #if HAVE_SETCONSOLECTRLHANDLER
249 SetConsoleCtrlHandler((PHANDLER_ROUTINE
) CtrlHandler
, TRUE
);
253 /* read a key without blocking */
254 static int read_key(void)
256 unsigned char ch
= -1;
266 n
= select(1, &rfds
, NULL
, NULL
, &tv
);
275 # if HAVE_PEEKNAMEDPIPE && HAVE_GETSTDHANDLE
277 static HANDLE input_handle
;
280 input_handle
= GetStdHandle(STD_INPUT_HANDLE
);
281 is_pipe
= !GetConsoleMode(input_handle
, &dw
);
285 /* When running under a GUI, you will end here. */
286 if (!PeekNamedPipe(input_handle
, NULL
, 0, NULL
, &nchars
, NULL
)) {
287 // input pipe may have been closed by the program that ran ffmpeg
292 if (read(0, &ch
, 1) == 1)
306 static int decode_interrupt_cb(void *ctx
)
308 return received_nb_signals
> atomic_load(&transcode_init_done
);
311 const AVIOInterruptCB int_cb
= { decode_interrupt_cb
, NULL
};
313 static void ffmpeg_cleanup(int ret
)
315 if ((print_graphs
|| print_graphs_file
) && nb_output_files
> 0)
316 print_filtergraphs(filtergraphs
, nb_filtergraphs
, input_files
, nb_input_files
, output_files
, nb_output_files
);
319 int64_t maxrss
= getmaxrss() / 1024;
320 av_log(NULL
, AV_LOG_INFO
, "bench: maxrss=%"PRId64
"KiB\n", maxrss
);
323 for (int i
= 0; i
< nb_filtergraphs
; i
++)
324 fg_free(&filtergraphs
[i
]);
325 av_freep(&filtergraphs
);
327 for (int i
= 0; i
< nb_output_files
; i
++)
328 of_free(&output_files
[i
]);
330 for (int i
= 0; i
< nb_input_files
; i
++)
331 ifile_close(&input_files
[i
]);
333 for (int i
= 0; i
< nb_decoders
; i
++)
334 dec_free(&decoders
[i
]);
338 if (fclose(vstats_file
))
339 av_log(NULL
, AV_LOG_ERROR
,
340 "Error closing vstats file, loss of information possible: %s\n",
341 av_err2str(AVERROR(errno
)));
343 av_freep(&vstats_filename
);
344 of_enc_stats_close();
346 hw_device_free_all();
348 av_freep(&filter_nbthreads
);
350 av_freep(&print_graphs_file
);
351 av_freep(&print_graphs_format
);
353 av_freep(&input_files
);
354 av_freep(&output_files
);
358 avformat_network_deinit();
360 if (received_sigterm
) {
361 av_log(NULL
, AV_LOG_INFO
, "Exiting normally, received signal %d.\n",
362 (int) received_sigterm
);
363 } else if (ret
&& atomic_load(&transcode_init_done
)) {
364 av_log(NULL
, AV_LOG_INFO
, "Conversion failed!\n");
370 OutputStream
*ost_iter(OutputStream
*prev
)
372 int of_idx
= prev
? prev
->file
->index
: 0;
373 int ost_idx
= prev
? prev
->index
+ 1 : 0;
375 for (; of_idx
< nb_output_files
; of_idx
++) {
376 OutputFile
*of
= output_files
[of_idx
];
377 if (ost_idx
< of
->nb_streams
)
378 return of
->streams
[ost_idx
];
386 InputStream
*ist_iter(InputStream
*prev
)
388 int if_idx
= prev
? prev
->file
->index
: 0;
389 int ist_idx
= prev
? prev
->index
+ 1 : 0;
391 for (; if_idx
< nb_input_files
; if_idx
++) {
392 InputFile
*f
= input_files
[if_idx
];
393 if (ist_idx
< f
->nb_streams
)
394 return f
->streams
[ist_idx
];
402 static void frame_data_free(void *opaque
, uint8_t *data
)
404 FrameData
*fd
= (FrameData
*)data
;
406 av_frame_side_data_free(&fd
->side_data
, &fd
->nb_side_data
);
407 avcodec_parameters_free(&fd
->par_enc
);
412 static int frame_data_ensure(AVBufferRef
**dst
, int writable
)
414 AVBufferRef
*src
= *dst
;
416 if (!src
|| (writable
&& !av_buffer_is_writable(src
))) {
419 fd
= av_mallocz(sizeof(*fd
));
421 return AVERROR(ENOMEM
);
423 *dst
= av_buffer_create((uint8_t *)fd
, sizeof(*fd
),
424 frame_data_free
, NULL
, 0);
426 av_buffer_unref(&src
);
428 return AVERROR(ENOMEM
);
432 const FrameData
*fd_src
= (const FrameData
*)src
->data
;
434 memcpy(fd
, fd_src
, sizeof(*fd
));
436 fd
->side_data
= NULL
;
437 fd
->nb_side_data
= 0;
439 if (fd_src
->par_enc
) {
442 fd
->par_enc
= avcodec_parameters_alloc();
444 avcodec_parameters_copy(fd
->par_enc
, fd_src
->par_enc
) :
447 av_buffer_unref(dst
);
448 av_buffer_unref(&src
);
453 if (fd_src
->nb_side_data
) {
454 int ret
= clone_side_data(&fd
->side_data
, &fd
->nb_side_data
,
455 fd_src
->side_data
, fd_src
->nb_side_data
, 0);
457 av_buffer_unref(dst
);
458 av_buffer_unref(&src
);
463 av_buffer_unref(&src
);
465 fd
->dec
.frame_num
= UINT64_MAX
;
466 fd
->dec
.pts
= AV_NOPTS_VALUE
;
468 for (unsigned i
= 0; i
< FF_ARRAY_ELEMS(fd
->wallclock
); i
++)
469 fd
->wallclock
[i
] = INT64_MIN
;
476 FrameData
*frame_data(AVFrame
*frame
)
478 int ret
= frame_data_ensure(&frame
->opaque_ref
, 1);
479 return ret
< 0 ? NULL
: (FrameData
*)frame
->opaque_ref
->data
;
482 const FrameData
*frame_data_c(AVFrame
*frame
)
484 int ret
= frame_data_ensure(&frame
->opaque_ref
, 0);
485 return ret
< 0 ? NULL
: (const FrameData
*)frame
->opaque_ref
->data
;
488 FrameData
*packet_data(AVPacket
*pkt
)
490 int ret
= frame_data_ensure(&pkt
->opaque_ref
, 1);
491 return ret
< 0 ? NULL
: (FrameData
*)pkt
->opaque_ref
->data
;
494 const FrameData
*packet_data_c(AVPacket
*pkt
)
496 int ret
= frame_data_ensure(&pkt
->opaque_ref
, 0);
497 return ret
< 0 ? NULL
: (const FrameData
*)pkt
->opaque_ref
->data
;
500 int check_avoptions_used(const AVDictionary
*opts
, const AVDictionary
*opts_used
,
501 void *logctx
, int decode
)
503 const AVClass
*class = avcodec_get_class();
504 const AVClass
*fclass
= avformat_get_class();
506 const int flag
= decode
? AV_OPT_FLAG_DECODING_PARAM
:
507 AV_OPT_FLAG_ENCODING_PARAM
;
508 const AVDictionaryEntry
*e
= NULL
;
510 while ((e
= av_dict_iterate(opts
, e
))) {
511 const AVOption
*option
, *foption
;
514 if (av_dict_get(opts_used
, e
->key
, NULL
, 0))
517 optname
= av_strdup(e
->key
);
519 return AVERROR(ENOMEM
);
521 p
= strchr(optname
, ':');
525 option
= av_opt_find(&class, optname
, NULL
, 0,
526 AV_OPT_SEARCH_CHILDREN
| AV_OPT_SEARCH_FAKE_OBJ
);
527 foption
= av_opt_find(&fclass
, optname
, NULL
, 0,
528 AV_OPT_SEARCH_CHILDREN
| AV_OPT_SEARCH_FAKE_OBJ
);
530 if (!option
|| foption
)
533 if (!(option
->flags
& flag
)) {
534 av_log(logctx
, AV_LOG_ERROR
, "Codec AVOption %s (%s) is not a %s "
535 "option.\n", e
->key
, option
->help
? option
->help
: "",
536 decode
? "decoding" : "encoding");
537 return AVERROR(EINVAL
);
540 av_log(logctx
, AV_LOG_WARNING
, "Codec AVOption %s (%s) has not been used "
541 "for any stream. The most likely reason is either wrong type "
542 "(e.g. a video option with no video streams) or that it is a "
543 "private option of some decoder which was not actually used "
544 "for any stream.\n", e
->key
, option
->help
? option
->help
: "");
550 void update_benchmark(const char *fmt
, ...)
552 if (do_benchmark_all
) {
553 BenchmarkTimeStamps t
= get_benchmark_time_stamps();
559 vsnprintf(buf
, sizeof(buf
), fmt
, va
);
561 av_log(NULL
, AV_LOG_INFO
,
562 "bench: %8" PRIu64
" user %8" PRIu64
" sys %8" PRIu64
" real %s \n",
563 t
.user_usec
- current_time
.user_usec
,
564 t
.sys_usec
- current_time
.sys_usec
,
565 t
.real_usec
- current_time
.real_usec
, buf
);
571 static void print_report(int is_last_report
, int64_t timer_start
, int64_t cur_time
, int64_t pts
)
573 AVBPrint buf
, buf_script
;
574 int64_t total_size
= of_filesize(output_files
[0]);
578 static int64_t last_time
= -1;
579 static int first_report
= 1;
580 uint64_t nb_frames_dup
= 0, nb_frames_drop
= 0;
581 int mins
, secs
, ms
, us
;
583 const char *hours_sign
;
587 if (!print_stats
&& !is_last_report
&& !progress_avio
)
590 if (!is_last_report
) {
591 if (last_time
== -1) {
592 last_time
= cur_time
;
594 if (((cur_time
- last_time
) < stats_period
&& !first_report
) ||
595 (first_report
&& atomic_load(&nb_output_dumped
) < nb_output_files
))
597 last_time
= cur_time
;
600 t
= (cur_time
-timer_start
) / 1000000.0;
603 av_bprint_init(&buf
, 0, AV_BPRINT_SIZE_AUTOMATIC
);
604 av_bprint_init(&buf_script
, 0, AV_BPRINT_SIZE_AUTOMATIC
);
606 for (OutputStream
*ost
= ost_iter(NULL
); ost
; ost
= ost_iter(ost
)) {
607 const float q
= ost
->enc
? atomic_load(&ost
->quality
) / (float) FF_QP2LAMBDA
: -1;
609 if (vid
&& ost
->type
== AVMEDIA_TYPE_VIDEO
) {
610 av_bprintf(&buf
, "q=%2.1f ", q
);
611 av_bprintf(&buf_script
, "stream_%d_%d_q=%.1f\n",
612 ost
->file
->index
, ost
->index
, q
);
614 if (!vid
&& ost
->type
== AVMEDIA_TYPE_VIDEO
) {
616 uint64_t frame_number
= atomic_load(&ost
->packets_written
);
618 fps
= t
> 1 ? frame_number
/ t
: 0;
619 av_bprintf(&buf
, "frame=%5"PRId64
" fps=%3.*f q=%3.1f ",
620 frame_number
, fps
< 9.95, fps
, q
);
621 av_bprintf(&buf_script
, "frame=%"PRId64
"\n", frame_number
);
622 av_bprintf(&buf_script
, "fps=%.2f\n", fps
);
623 av_bprintf(&buf_script
, "stream_%d_%d_q=%.1f\n",
624 ost
->file
->index
, ost
->index
, q
);
626 av_bprintf(&buf
, "L");
629 nb_frames_dup
= atomic_load(&ost
->filter
->nb_frames_dup
);
630 nb_frames_drop
= atomic_load(&ost
->filter
->nb_frames_drop
);
638 if (copy_ts_first_pts
== AV_NOPTS_VALUE
&& pts
> 1)
639 copy_ts_first_pts
= pts
;
640 if (copy_ts_first_pts
!= AV_NOPTS_VALUE
)
641 pts
-= copy_ts_first_pts
;
644 us
= FFABS64U(pts
) % AV_TIME_BASE
;
645 secs
= FFABS64U(pts
) / AV_TIME_BASE
% 60;
646 mins
= FFABS64U(pts
) / AV_TIME_BASE
/ 60 % 60;
647 hours
= FFABS64U(pts
) / AV_TIME_BASE
/ 3600;
648 hours_sign
= (pts
< 0) ? "-" : "";
650 bitrate
= pts
!= AV_NOPTS_VALUE
&& pts
&& total_size
>= 0 ? total_size
* 8 / (pts
/ 1000.0) : -1;
651 speed
= pts
!= AV_NOPTS_VALUE
&& t
!= 0.0 ? (double)pts
/ AV_TIME_BASE
/ t
: -1;
653 if (total_size
< 0) av_bprintf(&buf
, "size=N/A time=");
654 else av_bprintf(&buf
, "size=%8.0fKiB time=", total_size
/ 1024.0);
655 if (pts
== AV_NOPTS_VALUE
) {
656 av_bprintf(&buf
, "N/A ");
658 av_bprintf(&buf
, "%s%02"PRId64
":%02d:%02d.%02d ",
659 hours_sign
, hours
, mins
, secs
, (100 * us
) / AV_TIME_BASE
);
663 av_bprintf(&buf
, "bitrate=N/A");
664 av_bprintf(&buf_script
, "bitrate=N/A\n");
666 av_bprintf(&buf
, "bitrate=%6.1fkbits/s", bitrate
);
667 av_bprintf(&buf_script
, "bitrate=%6.1fkbits/s\n", bitrate
);
670 if (total_size
< 0) av_bprintf(&buf_script
, "total_size=N/A\n");
671 else av_bprintf(&buf_script
, "total_size=%"PRId64
"\n", total_size
);
672 if (pts
== AV_NOPTS_VALUE
) {
673 av_bprintf(&buf_script
, "out_time_us=N/A\n");
674 av_bprintf(&buf_script
, "out_time_ms=N/A\n");
675 av_bprintf(&buf_script
, "out_time=N/A\n");
677 av_bprintf(&buf_script
, "out_time_us=%"PRId64
"\n", pts
);
678 av_bprintf(&buf_script
, "out_time_ms=%"PRId64
"\n", pts
);
679 av_bprintf(&buf_script
, "out_time=%s%02"PRId64
":%02d:%02d.%06d\n",
680 hours_sign
, hours
, mins
, secs
, us
);
683 if (nb_frames_dup
|| nb_frames_drop
)
684 av_bprintf(&buf
, " dup=%"PRId64
" drop=%"PRId64
, nb_frames_dup
, nb_frames_drop
);
685 av_bprintf(&buf_script
, "dup_frames=%"PRId64
"\n", nb_frames_dup
);
686 av_bprintf(&buf_script
, "drop_frames=%"PRId64
"\n", nb_frames_drop
);
689 av_bprintf(&buf
, " speed=N/A");
690 av_bprintf(&buf_script
, "speed=N/A\n");
692 av_bprintf(&buf
, " speed=%4.3gx", speed
);
693 av_bprintf(&buf_script
, "speed=%4.3gx\n", speed
);
697 ms
= (int)((t
- secs
) * 1000);
703 av_bprintf(&buf
, " elapsed=%"PRId64
":%02d:%02d.%02d", hours
, mins
, secs
, ms
/ 10);
705 if (print_stats
|| is_last_report
) {
706 const char end
= is_last_report
? '\n' : '\r';
707 if (print_stats
==1 && AV_LOG_INFO
> av_log_get_level()) {
708 fprintf(stderr
, "%s %c", buf
.str
, end
);
710 av_log(NULL
, AV_LOG_INFO
, "%s %c", buf
.str
, end
);
714 av_bprint_finalize(&buf
, NULL
);
717 av_bprintf(&buf_script
, "progress=%s\n",
718 is_last_report
? "end" : "continue");
719 avio_write(progress_avio
, buf_script
.str
,
720 FFMIN(buf_script
.len
, buf_script
.size
- 1));
721 avio_flush(progress_avio
);
722 av_bprint_finalize(&buf_script
, NULL
);
723 if (is_last_report
) {
724 if ((ret
= avio_closep(&progress_avio
)) < 0)
725 av_log(NULL
, AV_LOG_ERROR
,
726 "Error closing progress log, loss of information possible: %s\n", av_err2str(ret
));
733 static void print_stream_maps(void)
735 av_log(NULL
, AV_LOG_INFO
, "Stream mapping:\n");
736 for (InputStream
*ist
= ist_iter(NULL
); ist
; ist
= ist_iter(ist
)) {
737 for (int j
= 0; j
< ist
->nb_filters
; j
++) {
738 if (!filtergraph_is_simple(ist
->filters
[j
]->graph
)) {
739 av_log(NULL
, AV_LOG_INFO
, " Stream #%d:%d (%s) -> %s",
740 ist
->file
->index
, ist
->index
, ist
->dec
? ist
->dec
->name
: "?",
741 ist
->filters
[j
]->name
);
742 if (nb_filtergraphs
> 1)
743 av_log(NULL
, AV_LOG_INFO
, " (graph %d)", ist
->filters
[j
]->graph
->index
);
744 av_log(NULL
, AV_LOG_INFO
, "\n");
749 for (OutputStream
*ost
= ost_iter(NULL
); ost
; ost
= ost_iter(ost
)) {
750 if (ost
->attachment_filename
) {
751 /* an attached file */
752 av_log(NULL
, AV_LOG_INFO
, " File %s -> Stream #%d:%d\n",
753 ost
->attachment_filename
, ost
->file
->index
, ost
->index
);
757 if (ost
->filter
&& !filtergraph_is_simple(ost
->filter
->graph
)) {
758 /* output from a complex graph */
759 av_log(NULL
, AV_LOG_INFO
, " %s", ost
->filter
->name
);
760 if (nb_filtergraphs
> 1)
761 av_log(NULL
, AV_LOG_INFO
, " (graph %d)", ost
->filter
->graph
->index
);
763 av_log(NULL
, AV_LOG_INFO
, " -> Stream #%d:%d (%s)\n", ost
->file
->index
,
764 ost
->index
, ost
->enc
->enc_ctx
->codec
->name
);
768 av_log(NULL
, AV_LOG_INFO
, " Stream #%d:%d -> #%d:%d",
769 ost
->ist
->file
->index
,
774 const AVCodec
*in_codec
= ost
->ist
->dec
;
775 const AVCodec
*out_codec
= ost
->enc
->enc_ctx
->codec
;
776 const char *decoder_name
= "?";
777 const char *in_codec_name
= "?";
778 const char *encoder_name
= "?";
779 const char *out_codec_name
= "?";
780 const AVCodecDescriptor
*desc
;
783 decoder_name
= in_codec
->name
;
784 desc
= avcodec_descriptor_get(in_codec
->id
);
786 in_codec_name
= desc
->name
;
787 if (!strcmp(decoder_name
, in_codec_name
))
788 decoder_name
= "native";
792 encoder_name
= out_codec
->name
;
793 desc
= avcodec_descriptor_get(out_codec
->id
);
795 out_codec_name
= desc
->name
;
796 if (!strcmp(encoder_name
, out_codec_name
))
797 encoder_name
= "native";
800 av_log(NULL
, AV_LOG_INFO
, " (%s (%s) -> %s (%s))",
801 in_codec_name
, decoder_name
,
802 out_codec_name
, encoder_name
);
804 av_log(NULL
, AV_LOG_INFO
, " (copy)");
805 av_log(NULL
, AV_LOG_INFO
, "\n");
809 static void set_tty_echo(int on
)
813 if (tcgetattr(0, &tty
) == 0) {
814 if (on
) tty
.c_lflag
|= ECHO
;
815 else tty
.c_lflag
&= ~ECHO
;
816 tcsetattr(0, TCSANOW
, &tty
);
821 static int check_keyboard_interaction(int64_t cur_time
)
824 static int64_t last_time
;
825 /* read_key() returns 0 on EOF */
826 if (cur_time
- last_time
>= 100000) {
828 last_time
= cur_time
;
832 av_log(NULL
, AV_LOG_INFO
, "\n\n[q] command received. Exiting.\n\n");
835 if (key
== '+') av_log_set_level(av_log_get_level()+10);
836 if (key
== '-') av_log_set_level(av_log_get_level()-10);
837 if (key
== 'c' || key
== 'C'){
838 char buf
[4096], target
[64], command
[256], arg
[256] = {0};
841 fprintf(stderr
, "\nEnter command: <target>|all <time>|-1 <command>[ <argument>]\n");
844 while ((k
= read_key()) != '\n' && k
!= '\r' && i
< sizeof(buf
)-1)
849 fprintf(stderr
, "\n");
851 (n
= sscanf(buf
, "%63[^ ] %lf %255[^ ] %255[^\n]", target
, &time
, command
, arg
)) >= 3) {
852 av_log(NULL
, AV_LOG_DEBUG
, "Processing command target:%s time:%f command:%s arg:%s",
853 target
, time
, command
, arg
);
854 for (OutputStream
*ost
= ost_iter(NULL
); ost
; ost
= ost_iter(ost
)) {
856 fg_send_command(ost
->fg_simple
, time
, target
, command
, arg
,
859 for (i
= 0; i
< nb_filtergraphs
; i
++)
860 fg_send_command(filtergraphs
[i
], time
, target
, command
, arg
,
863 av_log(NULL
, AV_LOG_ERROR
,
864 "Parse error, at least 3 arguments were expected, "
865 "only %d given in string '%s'\n", n
, buf
);
869 fprintf(stderr
, "key function\n"
871 "+ increase verbosity\n"
872 "- decrease verbosity\n"
873 "c Send command to first matching filter supporting it\n"
874 "C Send/Queue command to all matching filters\n"
875 "h dump packets/hex press to cycle through the 3 states\n"
877 "s Show QP histogram\n"
884 * The following code is the main loop of the file converter
886 static int transcode(Scheduler
*sch
)
889 int64_t timer_start
, transcode_ts
= 0;
893 atomic_store(&transcode_init_done
, 1);
895 ret
= sch_start(sch
);
899 if (stdin_interaction
) {
900 av_log(NULL
, AV_LOG_INFO
, "Press [q] to stop, [?] for help\n");
903 timer_start
= av_gettime_relative();
905 while (!sch_wait(sch
, stats_period
, &transcode_ts
)) {
906 int64_t cur_time
= av_gettime_relative();
908 if (received_nb_signals
)
911 /* if 'q' pressed, exits */
912 if (stdin_interaction
)
913 if (check_keyboard_interaction(cur_time
) < 0)
916 /* dump report by using the output first video and audio streams */
917 print_report(0, timer_start
, cur_time
, transcode_ts
);
920 ret
= sch_stop(sch
, &transcode_ts
);
922 /* write the trailer if needed */
923 for (int i
= 0; i
< nb_output_files
; i
++) {
924 int err
= of_write_trailer(output_files
[i
]);
925 ret
= err_merge(ret
, err
);
930 /* dump report by using the first video and audio streams */
931 print_report(1, timer_start
, av_gettime_relative(), transcode_ts
);
936 static BenchmarkTimeStamps
get_benchmark_time_stamps(void)
938 BenchmarkTimeStamps time_stamps
= { av_gettime_relative() };
940 struct rusage rusage
;
942 getrusage(RUSAGE_SELF
, &rusage
);
943 time_stamps
.user_usec
=
944 (rusage
.ru_utime
.tv_sec
* 1000000LL) + rusage
.ru_utime
.tv_usec
;
945 time_stamps
.sys_usec
=
946 (rusage
.ru_stime
.tv_sec
* 1000000LL) + rusage
.ru_stime
.tv_usec
;
947 #elif HAVE_GETPROCESSTIMES
950 proc
= GetCurrentProcess();
951 GetProcessTimes(proc
, &c
, &e
, &k
, &u
);
952 time_stamps
.user_usec
=
953 ((int64_t)u
.dwHighDateTime
<< 32 | u
.dwLowDateTime
) / 10;
954 time_stamps
.sys_usec
=
955 ((int64_t)k
.dwHighDateTime
<< 32 | k
.dwLowDateTime
) / 10;
957 time_stamps
.user_usec
= time_stamps
.sys_usec
= 0;
962 static int64_t getmaxrss(void)
964 #if HAVE_GETRUSAGE && HAVE_STRUCT_RUSAGE_RU_MAXRSS
965 struct rusage rusage
;
966 getrusage(RUSAGE_SELF
, &rusage
);
967 return (int64_t)rusage
.ru_maxrss
* 1024;
968 #elif HAVE_GETPROCESSMEMORYINFO
970 PROCESS_MEMORY_COUNTERS memcounters
;
971 proc
= GetCurrentProcess();
972 memcounters
.cb
= sizeof(memcounters
);
973 GetProcessMemoryInfo(proc
, &memcounters
, sizeof(memcounters
));
974 return memcounters
.PeakPagefileUsage
;
980 int main(int argc
, char **argv
)
982 Scheduler
*sch
= NULL
;
985 BenchmarkTimeStamps ti
;
989 setvbuf(stderr
,NULL
,_IONBF
,0); /* win32 runtime needs this */
991 av_log_set_flags(AV_LOG_SKIP_REPEATED
);
992 parse_loglevel(argc
, argv
, options
);
995 avdevice_register_all();
997 avformat_network_init();
999 show_banner(argc
, argv
, options
);
1003 ret
= AVERROR(ENOMEM
);
1007 /* parse options and open all input/output files */
1008 ret
= ffmpeg_parse_options(argc
, argv
, sch
);
1012 if (nb_output_files
<= 0 && nb_input_files
== 0) {
1014 av_log(NULL
, AV_LOG_WARNING
, "Use -h to get full help or, even better, run 'man %s'\n", program_name
);
1019 if (nb_output_files
<= 0) {
1020 av_log(NULL
, AV_LOG_FATAL
, "At least one output file must be specified\n");
1025 #if CONFIG_MEDIACODEC
1026 android_binder_threadpool_init_if_required();
1029 current_time
= ti
= get_benchmark_time_stamps();
1030 ret
= transcode(sch
);
1031 if (ret
>= 0 && do_benchmark
) {
1032 int64_t utime
, stime
, rtime
;
1033 current_time
= get_benchmark_time_stamps();
1034 utime
= current_time
.user_usec
- ti
.user_usec
;
1035 stime
= current_time
.sys_usec
- ti
.sys_usec
;
1036 rtime
= current_time
.real_usec
- ti
.real_usec
;
1037 av_log(NULL
, AV_LOG_INFO
,
1038 "bench: utime=%0.3fs stime=%0.3fs rtime=%0.3fs\n",
1039 utime
/ 1000000.0, stime
/ 1000000.0, rtime
/ 1000000.0);
1042 ret
= received_nb_signals
? 255 :
1043 (ret
== FFMPEG_ERROR_RATE_EXCEEDED
) ? 69 : ret
;
1046 if (ret
== AVERROR_EXIT
)
1049 ffmpeg_cleanup(ret
);
1053 av_log(NULL
, AV_LOG_VERBOSE
, "\n");
1054 av_log(NULL
, AV_LOG_VERBOSE
, "Exiting with exit code %d\n", ret
);