1 /*
2 * Copyright (c) 2000-2003 Fabrice Bellard
3 *
4 * This file is part of FFmpeg.
5 *
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.
10 *
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.
15 *
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
19 */
20
21 /**
22 * @file
23 * multimedia converter based on the FFmpeg libraries
24 */
25
26 #include "config.h"
27
28 #include <errno.h>
30 #include <stdatomic.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <string.h>
35
36 #if HAVE_IO_H
37 #include <io.h>
38 #endif
39 #if HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 #if HAVE_SYS_RESOURCE_H
44 #include <sys/time.h>
45 #include <sys/types.h>
46 #include <sys/resource.h>
47 #elif HAVE_GETPROCESSTIMES
48 #include <windows.h>
49 #endif
50 #if HAVE_GETPROCESSMEMORYINFO
51 #include <windows.h>
52 #include <psapi.h>
53 #endif
54 #if HAVE_SETCONSOLECTRLHANDLER
55 #include <windows.h>
56 #endif
57
58 #if HAVE_SYS_SELECT_H
59 #include <sys/select.h>
60 #endif
61
62 #if HAVE_TERMIOS_H
63 #include <fcntl.h>
64 #include <sys/ioctl.h>
65 #include <sys/time.h>
66 #include <termios.h>
67 #elif HAVE_KBHIT
68 #include <conio.h>
69 #endif
70
75
77
79
84
87
89
95
98
100
103
106
109
112
115
116 #if HAVE_TERMIOS_H
117
118 /* init terminal so that we can grab keys */
119 static struct termios oldtty;
120 static int restore_tty;
121 #endif
122
124 {
125 #if HAVE_TERMIOS_H
126 if(restore_tty)
127 tcsetattr (0, TCSANOW, &oldtty);
128 #endif
129 }
130
132 {
135 }
136
142
143 static void
145 {
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 */ };
154 exit(123);
155 }
156 }
157
158 #if HAVE_SETCONSOLECTRLHANDLER
159 static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
160 {
162
163 switch (fdwCtrlType)
164 {
165 case CTRL_C_EVENT:
166 case CTRL_BREAK_EVENT:
168 return TRUE;
169
170 case CTRL_CLOSE_EVENT:
171 case CTRL_LOGOFF_EVENT:
172 case CTRL_SHUTDOWN_EVENT:
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). */
179 Sleep(0);
180 }
181 return TRUE;
182
183 default:
185 return FALSE;
186 }
187 }
188 #endif
189
190 #ifdef __linux__
191 #define SIGNAL(sig, func) \
192 do { \
193 action.sa_handler = func; \
194 sigaction(sig, &action, NULL); \
195 } while (0)
196 #else
197 #define SIGNAL(sig, func) \
198 signal(sig, func)
199 #endif
200
202 {
203 #if defined __linux__
204 struct sigaction action = {0};
206
207 /* block other interrupts while processing this one */
208 sigfillset(&action.sa_mask);
209
210 /* restart interruptible functions (i.e. don't fail with EINTR) */
211 action.sa_flags = SA_RESTART;
212 #endif
213
214 #if HAVE_TERMIOS_H
216 struct termios tty;
217 if (tcgetattr (0, &tty) == 0) {
218 oldtty = tty;
219 restore_tty = 1;
220
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);
226 tty.c_cflag |= CS8;
227 tty.c_cc[VMIN] = 1;
228 tty.c_cc[VTIME] = 0;
229
230 tcsetattr (0, TCSANOW, &tty);
231 }
233 }
234 #endif
235
238 #ifdef SIGXCPU
240 #endif
241 #ifdef SIGPIPE
242 signal(SIGPIPE, SIG_IGN); /* Broken pipe (POSIX). */
243 #endif
244 #if HAVE_SETCONSOLECTRLHANDLER
245 SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE);
246 #endif
247 }
248
249 /* read a key without blocking */
251 {
252 unsigned char ch;
253 #if HAVE_TERMIOS_H
254 int n = 1;
255 struct timeval tv;
256 fd_set rfds;
257
258 FD_ZERO(&rfds);
259 FD_SET(0, &rfds);
260 tv.tv_sec = 0;
261 tv.tv_usec = 0;
262 n = select(1, &rfds,
NULL,
NULL, &tv);
263 if (n > 0) {
265 if (n == 1)
266 return ch;
267
268 return n;
269 }
270 #elif HAVE_KBHIT
271 # if HAVE_PEEKNAMEDPIPE && HAVE_GETSTDHANDLE
272 static int is_pipe;
273 static HANDLE input_handle;
274 DWORD dw, nchars;
275 if(!input_handle){
276 input_handle = GetStdHandle(STD_INPUT_HANDLE);
277 is_pipe = !GetConsoleMode(input_handle, &dw);
278 }
279
280 if (is_pipe) {
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
284 return -1;
285 }
286 //Read it
287 if(nchars != 0) {
288 if (
read(0, &ch, 1) == 1)
289 return ch;
290 return 0;
291 }else{
292 return -1;
293 }
294 }
295 # endif
296 if(kbhit())
297 return(getch());
298 #endif
299 return -1;
300 }
301
303 {
305 }
306
308
310 {
314 }
315
319
322
325
329
333 "Error closing vstats file, loss of information possible: %s\n",
335 }
338
340
342
345
347
349
355 }
358 }
359
361 {
362 int of_idx = prev ? prev->
file->
index : 0;
363 int ost_idx = prev ? prev->
index + 1 : 0;
364
369
370 ost_idx = 0;
371 }
372
374 }
375
377 {
378 int if_idx = prev ? prev->
file->
index : 0;
379 int ist_idx = prev ? prev->
index + 1 : 0;
380
384 return f->streams[ist_idx];
385
386 ist_idx = 0;
387 }
388
390 }
391
393 {
395
397
399 }
400
402 {
404
407
409 if (!fd)
411
418 }
419
422
423 memcpy(fd, fd_src, sizeof(*fd));
425
428
437 }
438 }
439
441 } else {
442 fd->dec.frame_num = UINT64_MAX;
444
446 fd->wallclock[
i] = INT64_MIN;
447 }
448 }
449
450 return 0;
451 }
452
454 {
457 }
458
460 {
463 }
464
466 {
469 }
470
472 {
475 }
476
479 {
482
486
489 char *optname, *p;
490
492 continue;
493
495 if (!optname)
497
498 p = strchr(optname, ':');
499 if (p)
500 *p = 0;
501
508 continue;
509
513 decode ?
"decoding" :
"encoding");
515 }
516
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 "
522 }
523
524 return 0;
525 }
526
528 {
531 va_list va;
532 char buf[1024];
533
534 if (fmt) {
535 va_start(va, fmt);
537 va_end(va);
539 "bench: %8" PRIu64 " user %8" PRIu64 " sys %8" PRIu64 " real %s \n",
543 }
545 }
546 }
547
549 {
550 AVBPrint buf, buf_script;
552 int vid;
554 double speed;
556 static int first_report = 1;
557 uint64_t nb_frames_dup = 0, nb_frames_drop = 0;
560 const char *hours_sign;
562 float t;
563
565 return;
566
567 if (!is_last_report) {
568 if (last_time == -1) {
569 last_time = cur_time;
570 }
571 if (((cur_time - last_time) <
stats_period && !first_report) ||
573 return;
574 last_time = cur_time;
575 }
576
577 t = (cur_time-timer_start) / 1000000.0;
578
579 vid = 0;
584
587 av_bprintf(&buf_script,
"stream_%d_%d_q=%.1f\n",
589 }
591 float fps;
593
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);
599 av_bprintf(&buf_script,
"stream_%d_%d_q=%.1f\n",
601 if (is_last_report)
603
607 }
608
609 vid = 1;
610 }
611 }
612
618 }
619
624 hours_sign = (
pts < 0) ?
"-" :
"";
625
628
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);
633 } else {
634 av_bprintf(&buf,
"%s%02"PRId64
":%02d:%02d.%02d ",
636 }
637
641 }else{
644 }
645
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);
652 } else {
655 av_bprintf(&buf_script,
"out_time=%s%02"PRId64
":%02d:%02d.%06d\n",
656 hours_sign, hours, mins, secs,
us);
657 }
658
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);
663
664 if (speed < 0) {
667 } else {
669 av_bprintf(&buf_script,
"speed=%4.3gx\n", speed);
670 }
671
673 const char end = is_last_report ? '\n' : '\r';
675 fprintf(stderr, "%s %c", buf.str, end);
676 } else
678
679 fflush(stderr);
680 }
682
685 is_last_report ? "end" : "continue");
687 FFMIN(buf_script.len, buf_script.size - 1));
690 if (is_last_report) {
693 "Error closing progress log, loss of information possible: %s\n",
av_err2str(
ret));
694 }
695 }
696
697 first_report = 0;
698 }
699
701 {
704 for (int j = 0; j < ist->nb_filters; j++) {
707 ist->file->index, ist->index, ist->dec ? ist->dec->name : "?",
708 ist->filters[j]->name);
712 }
713 }
714 }
715
717 if (
ost->attachment_filename) {
718 /* an attached file */
721 continue;
722 }
723
725 /* output from a complex graph */
729
732 continue;
733 }
734
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 = "?";
748
749 if (in_codec) {
750 decoder_name = in_codec->
name;
753 in_codec_name =
desc->name;
754 if (!strcmp(decoder_name, in_codec_name))
755 decoder_name = "native";
756 }
757
758 if (out_codec) {
759 encoder_name = out_codec->
name;
762 out_codec_name =
desc->name;
763 if (!strcmp(encoder_name, out_codec_name))
764 encoder_name = "native";
765 }
766
768 in_codec_name, decoder_name,
769 out_codec_name, encoder_name);
770 } else
773 }
774 }
775
777 {
778 #if HAVE_TERMIOS_H
779 struct termios tty;
780 if (tcgetattr(0, &tty) == 0) {
781 if (
on) tty.c_lflag |=
ECHO;
782 else tty.c_lflag &= ~
ECHO;
783 tcsetattr(0, TCSANOW, &tty);
784 }
785 #endif
786 }
787
789 {
794 /* read_key() returns 0 on EOF */
795 if (cur_time - last_time >= 100000) {
797 last_time = cur_time;
798 }else
803 }
806 if (
key ==
'c' ||
key ==
'C'){
807 char buf[4096], target[64],
command[256],
arg[256] = {0};
808 double time;
809 int k, n = 0;
810 fprintf(stderr, "\nEnter command: <target>|all <time>|-1 <command>[ <argument>]\n");
813 while ((k =
read_key()) !=
'\n' && k !=
'\r' &&
i <
sizeof(buf)-1)
814 if (k > 0)
818 fprintf(stderr, "\n");
819 if (k > 0 &&
820 (n = sscanf(buf,
"%63[^ ] %lf %255[^ ] %255[^\n]", target, &time,
command,
arg)) >= 3) {
827 }
831 } else {
833 "Parse error, at least 3 arguments were expected, "
834 "only %d given in string '%s'\n", n, buf);
835 }
836 }
838 fprintf(stderr, "key function\n"
839 "? show this help\n"
840 "+ increase verbosity\n"
841 "- decrease verbosity\n"
842 "c Send command to first matching filter supporting it\n"
843 "C Send/Queue command to all matching filters\n"
844 "h dump packets/hex press to cycle through the 3 states\n"
845 "q quit\n"
846 "s Show QP histogram\n"
847 );
848 }
849 return 0;
850 }
851
852 /*
853 * The following code is the main loop of the file converter
854 */
856 {
858 int64_t timer_start, transcode_ts = 0;
859
861
863
867
870 }
871
873
876
877 /* if 'q' pressed, exits */
880 break;
881
882 /* dump report by using the output first video and audio streams */
884 }
885
887
888 /* write the trailer if needed */
892 }
893
895
896 /* dump report by using the first video and audio streams */
898
900 }
901
903 {
905 #if HAVE_GETRUSAGE
906 struct rusage rusage;
907
908 getrusage(RUSAGE_SELF, &rusage);
910 (rusage.ru_utime.tv_sec * 1000000LL) + rusage.ru_utime.tv_usec;
912 (rusage.ru_stime.tv_sec * 1000000LL) + rusage.ru_stime.tv_usec;
913 #elif HAVE_GETPROCESSTIMES
914 HANDLE proc;
916 proc = GetCurrentProcess();
917 GetProcessTimes(proc, &
c, &e, &k, &
u);
919 ((
int64_t)
u.dwHighDateTime << 32 |
u.dwLowDateTime) / 10;
921 ((
int64_t)k.dwHighDateTime << 32 | k.dwLowDateTime) / 10;
922 #else
924 #endif
925 return time_stamps;
926 }
927
929 {
930 #if HAVE_GETRUSAGE && HAVE_STRUCT_RUSAGE_RU_MAXRSS
931 struct rusage rusage;
932 getrusage(RUSAGE_SELF, &rusage);
933 return (
int64_t)rusage.ru_maxrss * 1024;
934 #elif HAVE_GETPROCESSMEMORYINFO
935 HANDLE proc;
936 PROCESS_MEMORY_COUNTERS memcounters;
937 proc = GetCurrentProcess();
938 memcounters.cb = sizeof(memcounters);
939 GetProcessMemoryInfo(proc, &memcounters, sizeof(memcounters));
940 return memcounters.PeakPagefileUsage;
941 #else
942 return 0;
943 #endif
944 }
945
946 int main(
int argc,
char **argv)
947 {
949
952
954
955 setvbuf(stderr,
NULL,_IONBF,0);
/* win32 runtime needs this */
956
959
960 #if CONFIG_AVDEVICE
962 #endif
964
966
968 if (!sch) {
971 }
972
973 /* parse options and open all input/output files */
977
983 }
984
989 }
990
1000 "bench: utime=%0.3fs stime=%0.3fs rtime=%0.3fs\n",
1001 utime / 1000000.0, stime / 1000000.0, rtime / 1000000.0);
1002 }
1003
1006
1010
1012
1014
1016 }