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
85
88
90
96
99
101
104
107
110
113
116
117 #if HAVE_TERMIOS_H
118
119 /* init terminal so that we can grab keys */
120 static struct termios oldtty;
121 static int restore_tty;
122 #endif
123
125 {
126 #if HAVE_TERMIOS_H
127 if(restore_tty)
128 tcsetattr (0, TCSANOW, &oldtty);
129 #endif
130 }
131
133 {
136 }
137
143
144 static void
146 {
152 ret = write(2
/*STDERR_FILENO*/,
"Received > 3 system signals, hard exiting\n",
153 strlen("Received > 3 system signals, hard exiting\n"));
154 if (
ret < 0) {
/* Do nothing */ };
155 exit(123);
156 }
157 }
158
159 #if HAVE_SETCONSOLECTRLHANDLER
160 static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
161 {
163
164 switch (fdwCtrlType)
165 {
166 case CTRL_C_EVENT:
167 case CTRL_BREAK_EVENT:
169 return TRUE;
170
171 case CTRL_CLOSE_EVENT:
172 case CTRL_LOGOFF_EVENT:
173 case CTRL_SHUTDOWN_EVENT:
175 /* Basically, with these 3 events, when we return from this method the
176 process is hard terminated, so stall as long as we need to
177 to try and let the main thread(s) clean up and gracefully terminate
178 (we have at most 5 seconds, but should be done far before that). */
180 Sleep(0);
181 }
182 return TRUE;
183
184 default:
186 return FALSE;
187 }
188 }
189 #endif
190
191 #ifdef __linux__
192 #define SIGNAL(sig, func) \
193 do { \
194 action.sa_handler = func; \
195 sigaction(sig, &action, NULL); \
196 } while (0)
197 #else
198 #define SIGNAL(sig, func) \
199 signal(sig, func)
200 #endif
201
203 {
204 #if defined __linux__
205 struct sigaction action = {0};
207
208 /* block other interrupts while processing this one */
209 sigfillset(&action.sa_mask);
210
211 /* restart interruptible functions (i.e. don't fail with EINTR) */
212 action.sa_flags = SA_RESTART;
213 #endif
214
215 #if HAVE_TERMIOS_H
217 struct termios tty;
218 if (tcgetattr (0, &tty) == 0) {
219 oldtty = tty;
220 restore_tty = 1;
221
222 tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
223 |INLCR|IGNCR|ICRNL|IXON);
224 tty.c_oflag |= OPOST;
225 tty.c_lflag &= ~(
ECHO|ECHONL|ICANON|IEXTEN);
226 tty.c_cflag &= ~(CSIZE|PARENB);
227 tty.c_cflag |= CS8;
228 tty.c_cc[VMIN] = 1;
229 tty.c_cc[VTIME] = 0;
230
231 tcsetattr (0, TCSANOW, &tty);
232 }
234 }
235 #endif
236
239 #ifdef SIGXCPU
241 #endif
242 #ifdef SIGPIPE
243 signal(SIGPIPE, SIG_IGN); /* Broken pipe (POSIX). */
244 #endif
245 #if HAVE_SETCONSOLECTRLHANDLER
246 SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE);
247 #endif
248 }
249
250 /* read a key without blocking */
252 {
253 unsigned char ch = -1;
254 #if HAVE_TERMIOS_H
255 int n = 1;
256 struct timeval tv;
257 fd_set rfds;
258
259 FD_ZERO(&rfds);
260 FD_SET(0, &rfds);
261 tv.tv_sec = 0;
262 tv.tv_usec = 0;
263 n = select(1, &rfds,
NULL,
NULL, &tv);
264 if (n > 0) {
266 if (n == 1)
267 return ch;
268
269 return n;
270 }
271 #elif HAVE_KBHIT
272 # if HAVE_PEEKNAMEDPIPE && HAVE_GETSTDHANDLE
273 static int is_pipe;
274 static HANDLE input_handle;
275 DWORD dw, nchars;
276 if(!input_handle){
277 input_handle = GetStdHandle(STD_INPUT_HANDLE);
278 is_pipe = !GetConsoleMode(input_handle, &dw);
279 }
280
281 if (is_pipe) {
282 /* When running under a GUI, you will end here. */
283 if (!PeekNamedPipe(input_handle,
NULL, 0,
NULL, &nchars,
NULL)) {
284 // input pipe may have been closed by the program that ran ffmpeg
285 return -1;
286 }
287 //Read it
288 if(nchars != 0) {
289 if (
read(0, &ch, 1) == 1)
290 return ch;
291 return 0;
292 }else{
293 return -1;
294 }
295 }
296 # endif
297 if(kbhit())
298 return(getch());
299 #endif
300 return ch;
301 }
302
304 {
306 }
307
309
311 {
314
318 }
319
323
326
329
333
337 "Error closing vstats file, loss of information possible: %s\n",
339 }
342
344
346
349
352
354
356
362 }
365 }
366
368 {
369 int of_idx = prev ? prev->
file->
index : 0;
370 int ost_idx = prev ? prev->
index + 1 : 0;
371
376
377 ost_idx = 0;
378 }
379
381 }
382
384 {
385 int if_idx = prev ? prev->
file->
index : 0;
386 int ist_idx = prev ? prev->
index + 1 : 0;
387
391 return f->streams[ist_idx];
392
393 ist_idx = 0;
394 }
395
397 }
398
400 {
402
405
407 }
408
410 {
412
415
417 if (!fd)
419
426 }
427
430
431 memcpy(fd, fd_src, sizeof(*fd));
433 fd->side_data =
NULL;
434 fd->nb_side_data = 0;
435
438
447 }
448 }
449
457 }
458 }
459
461 } else {
462 fd->dec.frame_num = UINT64_MAX;
464
466 fd->wallclock[
i] = INT64_MIN;
467 }
468 }
469
470 return 0;
471 }
472
474 {
477 }
478
480 {
483 }
484
486 {
489 }
490
492 {
495 }
496
499 {
502
506
510
512 continue;
513
515 if (!optname)
517
518 p = strchr(optname,
':');
521
528 continue;
529
533 decode ?
"decoding" :
"encoding");
535 }
536
538 "for any stream. The most likely reason is either wrong type "
539 "(e.g. a video option with no video streams) or that it is a "
540 "private option of some decoder which was not actually used "
542 }
543
544 return 0;
545 }
546
548 {
551 va_list va;
552 char buf[1024];
553
554 if (fmt) {
555 va_start(va, fmt);
557 va_end(va);
559 "bench: %8" PRIu64 " user %8" PRIu64 " sys %8" PRIu64 " real %s \n",
563 }
565 }
566 }
567
569 {
570 AVBPrint buf, buf_script;
572 int vid;
574 double speed;
576 static int first_report = 1;
577 uint64_t nb_frames_dup = 0, nb_frames_drop = 0;
578 int mins, secs, ms,
us;
580 const char *hours_sign;
582 float t;
583
585 return;
586
587 if (!is_last_report) {
588 if (last_time == -1) {
589 last_time = cur_time;
590 }
591 if (((cur_time - last_time) <
stats_period && !first_report) ||
593 return;
594 last_time = cur_time;
595 }
596
597 t = (cur_time-timer_start) / 1000000.0;
598
599 vid = 0;
602
605
608 av_bprintf(&buf_script,
"stream_%d_%d_q=%.1f\n",
610 }
612 float fps;
614
615 fps = t > 1 ? frame_number / t : 0;
616 av_bprintf(&buf,
"frame=%5"PRId64
" fps=%3.*f q=%3.1f ",
617 frame_number, fps < 9.95, fps, q);
618 av_bprintf(&buf_script,
"frame=%"PRId64
"\n", frame_number);
620 av_bprintf(&buf_script,
"stream_%d_%d_q=%.1f\n",
622 if (is_last_report)
624
628 }
629
630 vid = 1;
631 }
632 }
633
639 }
640
645 hours_sign = (
pts < 0) ?
"-" :
"";
646
649
650 if (total_size < 0)
av_bprintf(&buf,
"size=N/A time=");
651 else av_bprintf(&buf,
"size=%8.0fKiB time=", total_size / 1024.0);
654 } else {
655 av_bprintf(&buf,
"%s%02"PRId64
":%02d:%02d.%02d ",
657 }
658
662 }else{
665 }
666
667 if (total_size < 0)
av_bprintf(&buf_script,
"total_size=N/A\n");
668 else av_bprintf(&buf_script,
"total_size=%"PRId64
"\n", total_size);
673 } else {
676 av_bprintf(&buf_script,
"out_time=%s%02"PRId64
":%02d:%02d.%06d\n",
677 hours_sign, hours, mins, secs,
us);
678 }
679
680 if (nb_frames_dup || nb_frames_drop)
681 av_bprintf(&buf,
" dup=%"PRId64
" drop=%"PRId64, nb_frames_dup, nb_frames_drop);
682 av_bprintf(&buf_script,
"dup_frames=%"PRId64
"\n", nb_frames_dup);
683 av_bprintf(&buf_script,
"drop_frames=%"PRId64
"\n", nb_frames_drop);
684
685 if (speed < 0) {
688 } else {
690 av_bprintf(&buf_script,
"speed=%4.3gx\n", speed);
691 }
692
693 secs = (int)t;
694 ms = (int)((t - secs) * 1000);
695 mins = secs / 60;
696 secs %= 60;
697 hours = mins / 60;
698 mins %= 60;
699
700 av_bprintf(&buf,
" elapsed=%"PRId64
":%02d:%02d.%02d", hours, mins, secs, ms / 10);
701
703 const char end = is_last_report ? '\n' : '\r';
705 fprintf(stderr, "%s %c", buf.str, end);
706 } else
708
709 fflush(stderr);
710 }
712
715 is_last_report ? "end" : "continue");
717 FFMIN(buf_script.len, buf_script.size - 1));
720 if (is_last_report) {
723 "Error closing progress log, loss of information possible: %s\n",
av_err2str(
ret));
724 }
725 }
726
727 first_report = 0;
728 }
729
731 {
734 for (int j = 0; j < ist->nb_filters; j++) {
737 ist->file->index, ist->index, ist->dec ? ist->dec->name : "?",
738 ist->filters[j]->name);
742 }
743 }
744 }
745
747 if (
ost->attachment_filename) {
748 /* an attached file */
751 continue;
752 }
753
755 /* output from a complex graph */
759
762 continue;
763 }
764
772 const AVCodec *out_codec =
ost->enc->enc_ctx->codec;
773 const char *decoder_name = "?";
774 const char *in_codec_name = "?";
775 const char *encoder_name = "?";
776 const char *out_codec_name = "?";
778
779 if (in_codec) {
780 decoder_name = in_codec->
name;
783 in_codec_name =
desc->name;
784 if (!strcmp(decoder_name, in_codec_name))
785 decoder_name = "native";
786 }
787
788 if (out_codec) {
789 encoder_name = out_codec->
name;
792 out_codec_name =
desc->name;
793 if (!strcmp(encoder_name, out_codec_name))
794 encoder_name = "native";
795 }
796
798 in_codec_name, decoder_name,
799 out_codec_name, encoder_name);
800 } else
803 }
804 }
805
807 {
808 #if HAVE_TERMIOS_H
809 struct termios tty;
810 if (tcgetattr(0, &tty) == 0) {
811 if (
on) tty.c_lflag |=
ECHO;
812 else tty.c_lflag &= ~
ECHO;
813 tcsetattr(0, TCSANOW, &tty);
814 }
815 #endif
816 }
817
819 {
822 /* read_key() returns 0 on EOF */
823 if (cur_time - last_time >= 100000) {
825 last_time = cur_time;
826 }else
831 }
834 if (
key ==
'c' ||
key ==
'C'){
835 char buf[4096], target[64],
command[256],
arg[256] = {0};
836 double time;
837 int k, n = 0;
838 fprintf(stderr, "\nEnter command: <target>|all <time>|-1 <command>[ <argument>]\n");
841 while ((k =
read_key()) !=
'\n' && k !=
'\r' &&
i <
sizeof(buf)-1)
842 if (k > 0)
846 fprintf(stderr, "\n");
847 if (k > 0 &&
848 (n = sscanf(buf,
"%63[^ ] %lf %255[^ ] %255[^\n]", target, &time,
command,
arg)) >= 3) {
855 }
859 } else {
861 "Parse error, at least 3 arguments were expected, "
862 "only %d given in string '%s'\n", n, buf);
863 }
864 }
866 fprintf(stderr, "key function\n"
867 "? show this help\n"
868 "+ increase verbosity\n"
869 "- decrease verbosity\n"
870 "c Send command to first matching filter supporting it\n"
871 "C Send/Queue command to all matching filters\n"
872 "h dump packets/hex press to cycle through the 3 states\n"
873 "q quit\n"
874 "s Show QP histogram\n"
875 );
876 }
877 return 0;
878 }
879
880 /*
881 * The following code is the main loop of the file converter
882 */
884 {
886 int64_t timer_start, transcode_ts = 0;
887
889
891
895
898 }
899
901
904
906 break;
907
908 /* if 'q' pressed, exits */
911 break;
912
913 /* dump report by using the output first video and audio streams */
915 }
916
918
919 /* write the trailer if needed */
923 }
924
926
927 /* dump report by using the first video and audio streams */
929
931 }
932
934 {
936 #if HAVE_GETRUSAGE
937 struct rusage rusage;
938
939 getrusage(RUSAGE_SELF, &rusage);
941 (rusage.ru_utime.tv_sec * 1000000LL) + rusage.ru_utime.tv_usec;
943 (rusage.ru_stime.tv_sec * 1000000LL) + rusage.ru_stime.tv_usec;
944 #elif HAVE_GETPROCESSTIMES
945 HANDLE proc;
947 proc = GetCurrentProcess();
948 GetProcessTimes(proc, &
c, &e, &k, &
u);
950 ((
int64_t)
u.dwHighDateTime << 32 |
u.dwLowDateTime) / 10;
952 ((
int64_t)k.dwHighDateTime << 32 | k.dwLowDateTime) / 10;
953 #else
955 #endif
956 return time_stamps;
957 }
958
960 {
961 #if HAVE_GETRUSAGE && HAVE_STRUCT_RUSAGE_RU_MAXRSS
962 struct rusage rusage;
963 getrusage(RUSAGE_SELF, &rusage);
964 return (
int64_t)rusage.ru_maxrss * 1024;
965 #elif HAVE_GETPROCESSMEMORYINFO
966 HANDLE proc;
967 PROCESS_MEMORY_COUNTERS memcounters;
968 proc = GetCurrentProcess();
969 memcounters.cb = sizeof(memcounters);
970 GetProcessMemoryInfo(proc, &memcounters, sizeof(memcounters));
971 return memcounters.PeakPagefileUsage;
972 #else
973 return 0;
974 #endif
975 }
976
977 int main(
int argc,
char **argv)
978 {
980
983
985
986 setvbuf(stderr,
NULL,_IONBF,0);
/* win32 runtime needs this */
987
990
991 #if CONFIG_AVDEVICE
993 #endif
995
997
999 if (!sch) {
1002 }
1003
1004 /* parse options and open all input/output files */
1008
1014 }
1015
1020 }
1021
1031 "bench: utime=%0.3fs stime=%0.3fs rtime=%0.3fs\n",
1032 utime / 1000000.0, stime / 1000000.0, rtime / 1000000.0);
1033 }
1034
1037
1041
1043
1045
1048
1050 }