FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/fftools/ffplay.c
Date: 2026-10-29 17:07:12
Exec Total Coverage
Lines: 0 2725 0.0%
Functions: 0 121 0.0%
Branches: 0 1865 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 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 * simple media player based on the FFmpeg libraries
24 */
25
26 #include "config.h"
27 #include "config_components.h"
28 #include <math.h>
29 #include <limits.h>
30 #include <signal.h>
31 #include <stdint.h>
32
33 #include "libavutil/attributes.h"
34 #include "libavutil/avstring.h"
35 #include "libavutil/channel_layout.h"
36 #include "libavutil/mathematics.h"
37 #include "libavutil/mem.h"
38 #include "libavutil/pixdesc.h"
39 #include "libavutil/dict.h"
40 #include "libavutil/fifo.h"
41 #include "libavutil/parseutils.h"
42 #include "libavutil/samplefmt.h"
43 #include "libavutil/time.h"
44 #include "libavutil/bprint.h"
45 #include "libavcodec/bsf.h"
46 #include "libavformat/avformat.h"
47 #include "libavdevice/avdevice.h"
48 #include "libswscale/swscale.h"
49 #include "libavutil/opt.h"
50 #include "libavutil/tx.h"
51 #include "libswresample/swresample.h"
52
53 #include "libavfilter/avfilter.h"
54 #include "libavfilter/buffersink.h"
55 #include "libavfilter/buffersrc.h"
56
57 #include <SDL.h>
58 #include <SDL_thread.h>
59
60 #include "cmdutils.h"
61 #include "ffplay_dir.h"
62 #include "ffplay_list.h"
63 #include "ffplay_renderer.h"
64 #include "opt_common.h"
65
66 const char program_name[] = "ffplay";
67 const int program_birth_year = 2003;
68
69 #define MAX_QUEUE_SIZE (15 * 1024 * 1024)
70 #define MIN_FRAMES 25
71 #define EXTERNAL_CLOCK_MIN_FRAMES 2
72 #define EXTERNAL_CLOCK_MAX_FRAMES 10
73
74 /* Minimum SDL audio buffer size, in samples. */
75 #define SDL_AUDIO_MIN_BUFFER_SIZE 512
76 /* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */
77 #define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30
78
79 /* Step size for volume control in dB */
80 #define SDL_VOLUME_STEP (0.75)
81
82 /* no AV sync correction is done if below the minimum AV sync threshold */
83 #define AV_SYNC_THRESHOLD_MIN 0.04
84 /* AV sync correction is done if above the maximum AV sync threshold */
85 #define AV_SYNC_THRESHOLD_MAX 0.1
86 /* If a frame duration is longer than this, it will not be duplicated to compensate AV sync */
87 #define AV_SYNC_FRAMEDUP_THRESHOLD 0.1
88 /* no AV correction is done if too big error */
89 #define AV_NOSYNC_THRESHOLD 10.0
90
91 /* maximum audio speed change to get correct sync */
92 #define SAMPLE_CORRECTION_PERCENT_MAX 10
93
94 /* external clock speed adjustment constants for realtime sources based on buffer fullness */
95 #define EXTERNAL_CLOCK_SPEED_MIN 0.900
96 #define EXTERNAL_CLOCK_SPEED_MAX 1.010
97 #define EXTERNAL_CLOCK_SPEED_STEP 0.001
98
99 /* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */
100 #define AUDIO_DIFF_AVG_NB 20
101
102 /* polls for possible required screen refresh at least this often, should be less than 1/fps */
103 #define REFRESH_RATE 0.01
104
105 /* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
106 /* TODO: We assume that a decoded and resampled frame fits into this buffer */
107 #define SAMPLE_ARRAY_SIZE (8 * 65536)
108
109 #define CURSOR_HIDE_DELAY 1000000
110
111 #define USE_ONEPASS_SUBTITLE_RENDER 1
112
113 typedef struct MyAVPacketList {
114 AVPacket *pkt;
115 int serial;
116 } MyAVPacketList;
117
118 typedef struct PacketQueue {
119 AVFifo *pkt_list;
120 int nb_packets;
121 int size;
122 int64_t duration;
123 int abort_request;
124 int serial;
125 SDL_mutex *mutex;
126 SDL_cond *cond;
127 } PacketQueue;
128
129 #define VIDEO_PICTURE_QUEUE_SIZE 3
130 #define SUBPICTURE_QUEUE_SIZE 16
131 #define SAMPLE_QUEUE_SIZE 9
132 #define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE))
133
134 typedef struct AudioParams {
135 int freq;
136 AVChannelLayout ch_layout;
137 enum AVSampleFormat fmt;
138 int frame_size;
139 int bytes_per_sec;
140 } AudioParams;
141
142 typedef struct Clock {
143 double pts; /* clock base */
144 double pts_drift; /* clock base minus time at which we updated the clock */
145 double last_updated;
146 double speed;
147 int serial; /* clock is based on a packet with this serial */
148 int paused;
149 int *queue_serial; /* pointer to the current packet queue serial, used for obsolete clock detection */
150 } Clock;
151
152 typedef struct FrameData {
153 int64_t pkt_pos;
154 } FrameData;
155
156 /* Common struct for handling all types of decoded data and allocated render buffers. */
157 typedef struct Frame {
158 AVFrame *frame;
159 AVSubtitle sub;
160 int serial;
161 double pts; /* presentation timestamp for the frame */
162 double duration; /* estimated duration of the frame */
163 int64_t pos; /* byte position of the frame in the input file */
164 int width;
165 int height;
166 int format;
167 AVRational sar;
168 int uploaded;
169 int flip_v;
170 } Frame;
171
172 typedef struct FrameQueue {
173 Frame queue[FRAME_QUEUE_SIZE];
174 int rindex;
175 int windex;
176 int size;
177 int max_size;
178 int keep_last;
179 int rindex_shown;
180 SDL_mutex *mutex;
181 SDL_cond *cond;
182 PacketQueue *pktq;
183 } FrameQueue;
184
185 typedef struct StreamGroup {
186 AVStreamGroup *stg;
187 AVBitStreamFilterGraph *graph;
188 AVBitStreamFilterContext *sink;
189 } StreamGroup;
190
191 typedef struct Stream {
192 StreamGroup *group;
193 AVBitStreamFilterContext *filter;
194 } Stream;
195
196 typedef struct FormatContext {
197 Stream **streams;
198 int nb_streams;
199 StreamGroup **stream_groups;
200 int nb_stream_groups;
201 } FormatContext;
202
203 enum {
204 AV_SYNC_AUDIO_MASTER, /* default choice */
205 AV_SYNC_VIDEO_MASTER,
206 AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */
207 };
208
209 typedef struct Decoder {
210 AVPacket *pkt;
211 PacketQueue *queue;
212 AVCodecContext *avctx;
213 int pkt_serial;
214 int finished;
215 int packet_pending;
216 SDL_cond *empty_queue_cond;
217 int64_t start_pts;
218 AVRational start_pts_tb;
219 int64_t next_pts;
220 AVRational next_pts_tb;
221 SDL_Thread *decoder_tid;
222 } Decoder;
223
224 typedef struct VideoState {
225 SDL_Thread *read_tid;
226 const AVInputFormat *iformat;
227 int abort_request;
228 int force_refresh;
229 int paused;
230 int last_paused;
231 int queue_attachments_req;
232 int seek_req;
233 int seek_flags;
234 int64_t seek_pos;
235 int64_t seek_rel;
236 int read_pause_return;
237 AVFormatContext *ic;
238 int realtime;
239
240 Clock audclk;
241 Clock vidclk;
242 Clock extclk;
243
244 FrameQueue pictq;
245 FrameQueue subpq;
246 FrameQueue sampq;
247
248 Decoder auddec;
249 Decoder viddec;
250 Decoder subdec;
251
252 int audio_stream;
253
254 int av_sync_type;
255
256 double audio_clock;
257 int audio_clock_serial;
258 double audio_diff_cum; /* used for AV difference average computation */
259 double audio_diff_avg_coef;
260 double audio_diff_threshold;
261 int audio_diff_avg_count;
262 AVStream *audio_st;
263 PacketQueue audioq;
264 int audio_hw_buf_size;
265 uint8_t *audio_buf;
266 uint8_t *audio_buf1;
267 unsigned int audio_buf_size; /* in bytes */
268 unsigned int audio_buf1_size;
269 int audio_buf_index; /* in bytes */
270 int audio_write_buf_size;
271 int audio_volume;
272 int muted;
273 struct AudioParams audio_src;
274 struct AudioParams audio_filter_src;
275 struct AudioParams audio_tgt;
276 struct SwrContext *swr_ctx;
277 int frame_drops_early;
278 int frame_drops_late;
279
280 enum ShowMode {
281 SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_PHASE, SHOW_MODE_NB
282 } show_mode;
283 int16_t sample_array[SAMPLE_ARRAY_SIZE];
284 int sample_array_index;
285 int last_i_start;
286 AVTXContext *rdft;
287 av_tx_fn rdft_fn;
288 int rdft_bits;
289 float *real_data;
290 AVComplexFloat *rdft_data;
291 int xpos;
292 double last_vis_time;
293 RenderParams render_params;
294 SDL_Texture *vis_texture;
295 SDL_Texture *sub_texture;
296 SDL_Texture *vid_texture;
297 SDL_AudioDeviceID audio_dev;
298 int64_t audio_callback_time;
299
300 int subtitle_stream;
301 AVStream *subtitle_st;
302 PacketQueue subtitleq;
303
304 double frame_timer;
305 double frame_last_returned_time;
306 double frame_last_filter_delay;
307 int video_stream;
308 AVStream *video_st;
309 PacketQueue videoq;
310 double max_frame_duration; // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity
311 struct SwsContext *sub_convert_ctx;
312 int eof;
313
314 char *filename;
315 int id;
316 SDL_atomic_t replacement;
317 char *title;
318 int seek_by_bytes;
319 int infinite_buffer;
320 int loop;
321 int width, height, xleft, ytop;
322 int step;
323
324 int vfilter_idx;
325 AVFilterContext *in_video_filter; // the first filter in the video chain
326 AVFilterContext *out_video_filter; // the last filter in the video chain
327 AVFilterContext *in_audio_filter; // the first filter in the audio chain
328 AVFilterContext *out_audio_filter; // the last filter in the audio chain
329 AVFilterGraph *agraph; // audio filter graph
330
331 int last_video_stream, last_audio_stream, last_subtitle_stream;
332
333 SDL_cond *continue_read_thread;
334 } VideoState;
335
336 /* options specified by the user */
337 static const AVInputFormat *file_iformat;
338 static const char *input_filename;
339 static const char *window_title;
340 static int default_width = 640;
341 static int default_height = 480;
342 static int screen_width = 0;
343 static int screen_height = 0;
344 static int screen_left = SDL_WINDOWPOS_CENTERED;
345 static int screen_top = SDL_WINDOWPOS_CENTERED;
346 static int audio_disable;
347 static int video_disable;
348 static int subtitle_disable;
349 static const char* wanted_stream_spec[AVMEDIA_TYPE_NB] = {0};
350 static int seek_by_bytes = -1;
351 static float seek_interval = 10;
352 static int display_disable;
353 static int borderless;
354 static int alwaysontop;
355 static int startup_volume = 100;
356 static int show_status = -1;
357 static int av_sync_type = AV_SYNC_AUDIO_MASTER;
358 static int64_t start_time = AV_NOPTS_VALUE;
359 static int64_t duration = AV_NOPTS_VALUE;
360 static int fast = 0;
361 static int genpts = 0;
362 static int lowres = 0;
363 static int decoder_reorder_pts = -1;
364 static int autoexit;
365 static int exit_on_keydown;
366 static int exit_on_mousedown;
367 static int loop = 1;
368 static int framedrop = -1;
369 static int infinite_buffer = -1;
370 static enum ShowMode show_mode = SHOW_MODE_NONE;
371 static const char *audio_codec_name;
372 static const char *subtitle_codec_name;
373 static const char *video_codec_name;
374 double rdftspeed = 0.02;
375 static int64_t cursor_last_shown;
376 static int cursor_hidden = 0;
377 static ListView *list;
378 /* the key that pins the list when it is released, 0 for none */
379 static SDL_Keycode list_key;
380 /* whether the list shows the files of dir_list rather than the chapters of the stream playing */
381 static int list_shows_files;
382 static DirList *dir_list;
383 /* the directory dir_thread reads, taken over by the event loop once done is set */
384 static struct {
385 char *path;
386 AVDictionary *options;
387 int play_if_no_dir;
388 int cancelled;
389 SDL_atomic_t abort;
390 DirList *dl;
391 int ret;
392 SDL_atomic_t done;
393 } dir_request;
394 static SDL_Thread *dir_thread;
395 /* the stream chosen in the file list, paused until it can play and replace the one playing */
396 static VideoState *next_stream;
397 static const char **vfilters_list = NULL;
398 static int nb_vfilters = 0;
399 static char *afilters = NULL;
400 static int autorotate = 1;
401 static int find_stream_info = 1;
402 static int filter_nbthreads = 0;
403 static int enable_vulkan = 0;
404 static char *vulkan_params = NULL;
405 static char *video_background = NULL;
406 static const char *hwaccel = NULL;
407
408 /* current context */
409 static int is_full_screen;
410
411 #define FF_QUIT_EVENT (SDL_USEREVENT + 2)
412 /* a stream has a picture to show, has no video, no picture before the end of its video, or no room to buffer more */
413 #define FF_READY_EVENT (SDL_USEREVENT + 3)
414
415 static int last_stream_id;
416
417 static volatile sig_atomic_t received_sigterm = 0;
418 static volatile int received_nb_signals = 0;
419 static int exit_status = 0;
420
421 static SDL_Window *window;
422 static SDL_Renderer *renderer;
423 static int wait_for_events;
424 static SDL_RendererInfo renderer_info = {0};
425
426 static VkRenderer *vk_renderer;
427
428 static const struct TextureFormatEntry {
429 enum AVPixelFormat format;
430 int texture_fmt;
431 } sdl_texture_format_map[] = {
432 { AV_PIX_FMT_RGB8, SDL_PIXELFORMAT_RGB332 },
433 { AV_PIX_FMT_RGB444, SDL_PIXELFORMAT_RGB444 },
434 { AV_PIX_FMT_RGB555, SDL_PIXELFORMAT_RGB555 },
435 { AV_PIX_FMT_BGR555, SDL_PIXELFORMAT_BGR555 },
436 { AV_PIX_FMT_RGB565, SDL_PIXELFORMAT_RGB565 },
437 { AV_PIX_FMT_BGR565, SDL_PIXELFORMAT_BGR565 },
438 { AV_PIX_FMT_RGB24, SDL_PIXELFORMAT_RGB24 },
439 { AV_PIX_FMT_BGR24, SDL_PIXELFORMAT_BGR24 },
440 { AV_PIX_FMT_0RGB32, SDL_PIXELFORMAT_RGB888 },
441 { AV_PIX_FMT_0BGR32, SDL_PIXELFORMAT_BGR888 },
442 { AV_PIX_FMT_NE(RGB0, 0BGR), SDL_PIXELFORMAT_RGBX8888 },
443 { AV_PIX_FMT_NE(BGR0, 0RGB), SDL_PIXELFORMAT_BGRX8888 },
444 { AV_PIX_FMT_RGB32, SDL_PIXELFORMAT_ARGB8888 },
445 { AV_PIX_FMT_RGB32_1, SDL_PIXELFORMAT_RGBA8888 },
446 { AV_PIX_FMT_BGR32, SDL_PIXELFORMAT_ABGR8888 },
447 { AV_PIX_FMT_BGR32_1, SDL_PIXELFORMAT_BGRA8888 },
448 { AV_PIX_FMT_YUV420P, SDL_PIXELFORMAT_IYUV },
449 { AV_PIX_FMT_YUYV422, SDL_PIXELFORMAT_YUY2 },
450 { AV_PIX_FMT_UYVY422, SDL_PIXELFORMAT_UYVY },
451 };
452
453 ✗ static int opt_add_vfilter(void *optctx, const char *opt, const char *arg)
454 {
455 ✗ int ret = GROW_ARRAY(vfilters_list, nb_vfilters);
456 ✗ if (ret < 0)
457 ✗ return ret;
458
459 ✗ vfilters_list[nb_vfilters - 1] = av_strdup(arg);
460 ✗ if (!vfilters_list[nb_vfilters - 1])
461 ✗ return AVERROR(ENOMEM);
462
463 ✗ return 0;
464 }
465
466 static inline
467 ✗ int cmp_audio_fmts(enum AVSampleFormat fmt1, int64_t channel_count1,
468 enum AVSampleFormat fmt2, int64_t channel_count2)
469 {
470 /* If channel count == 1, planar and non-planar formats are the same */
471 ✗ if (channel_count1 == 1 && channel_count2 == 1)
472 ✗ return av_get_packed_sample_fmt(fmt1) != av_get_packed_sample_fmt(fmt2);
473 else
474 ✗ return channel_count1 != channel_count2 || fmt1 != fmt2;
475 }
476
477 ✗ static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
478 {
479 MyAVPacketList pkt1;
480 int ret;
481
482 ✗ if (q->abort_request)
483 ✗ return -1;
484
485
486 ✗ pkt1.pkt = pkt;
487 ✗ pkt1.serial = q->serial;
488
489 ✗ ret = av_fifo_write(q->pkt_list, &pkt1, 1);
490 ✗ if (ret < 0)
491 ✗ return ret;
492 ✗ q->nb_packets++;
493 ✗ q->size += pkt1.pkt->size + sizeof(pkt1);
494 ✗ q->duration += pkt1.pkt->duration;
495 /* XXX: should duplicate packet data in DV case */
496 ✗ SDL_CondSignal(q->cond);
497 ✗ return 0;
498 }
499
500 ✗ static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
501 {
502 AVPacket *pkt1;
503 int ret;
504
505 ✗ pkt1 = av_packet_alloc();
506 ✗ if (!pkt1) {
507 ✗ av_packet_unref(pkt);
508 ✗ return -1;
509 }
510 ✗ av_packet_move_ref(pkt1, pkt);
511
512 ✗ SDL_LockMutex(q->mutex);
513 ✗ ret = packet_queue_put_private(q, pkt1);
514 ✗ SDL_UnlockMutex(q->mutex);
515
516 ✗ if (ret < 0)
517 ✗ av_packet_free(&pkt1);
518
519 ✗ return ret;
520 }
521
522 ✗ static int packet_queue_put_nullpacket(PacketQueue *q, AVPacket *pkt, int stream_index)
523 {
524 ✗ pkt->stream_index = stream_index;
525 ✗ return packet_queue_put(q, pkt);
526 }
527
528 /* packet queue handling */
529 ✗ static int packet_queue_init(PacketQueue *q)
530 {
531 ✗ memset(q, 0, sizeof(PacketQueue));
532 ✗ q->pkt_list = av_fifo_alloc2(1, sizeof(MyAVPacketList), AV_FIFO_FLAG_AUTO_GROW);
533 ✗ if (!q->pkt_list)
534 ✗ return AVERROR(ENOMEM);
535 ✗ q->mutex = SDL_CreateMutex();
536 ✗ if (!q->mutex) {
537 ✗ av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
538 ✗ return AVERROR(ENOMEM);
539 }
540 ✗ q->cond = SDL_CreateCond();
541 ✗ if (!q->cond) {
542 ✗ av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
543 ✗ return AVERROR(ENOMEM);
544 }
545 ✗ q->abort_request = 1;
546 ✗ return 0;
547 }
548
549 ✗ static void packet_queue_flush(PacketQueue *q)
550 {
551 MyAVPacketList pkt1;
552
553 ✗ SDL_LockMutex(q->mutex);
554 ✗ while (av_fifo_read(q->pkt_list, &pkt1, 1) >= 0)
555 ✗ av_packet_free(&pkt1.pkt);
556 ✗ q->nb_packets = 0;
557 ✗ q->size = 0;
558 ✗ q->duration = 0;
559 ✗ q->serial++;
560 ✗ SDL_UnlockMutex(q->mutex);
561 ✗ }
562
563 ✗ static void packet_queue_destroy(PacketQueue *q)
564 {
565 ✗ packet_queue_flush(q);
566 ✗ av_fifo_freep2(&q->pkt_list);
567 ✗ SDL_DestroyMutex(q->mutex);
568 ✗ SDL_DestroyCond(q->cond);
569 ✗ }
570
571 ✗ static void packet_queue_abort(PacketQueue *q)
572 {
573 ✗ SDL_LockMutex(q->mutex);
574
575 ✗ q->abort_request = 1;
576
577 ✗ SDL_CondSignal(q->cond);
578
579 ✗ SDL_UnlockMutex(q->mutex);
580 ✗ }
581
582 ✗ static void packet_queue_start(PacketQueue *q)
583 {
584 ✗ SDL_LockMutex(q->mutex);
585 ✗ q->abort_request = 0;
586 ✗ q->serial++;
587 ✗ SDL_UnlockMutex(q->mutex);
588 ✗ }
589
590 /* return < 0 if aborted, 0 if no packet and > 0 if packet. */
591 ✗ static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)
592 {
593 MyAVPacketList pkt1;
594 int ret;
595
596 ✗ SDL_LockMutex(q->mutex);
597
598 for (;;) {
599 ✗ if (q->abort_request) {
600 ✗ ret = -1;
601 ✗ break;
602 }
603
604 ✗ if (av_fifo_read(q->pkt_list, &pkt1, 1) >= 0) {
605 ✗ q->nb_packets--;
606 ✗ q->size -= pkt1.pkt->size + sizeof(pkt1);
607 ✗ q->duration -= pkt1.pkt->duration;
608 ✗ av_packet_move_ref(pkt, pkt1.pkt);
609 ✗ if (serial)
610 ✗ *serial = pkt1.serial;
611 ✗ av_packet_free(&pkt1.pkt);
612 ✗ ret = 1;
613 ✗ break;
614 ✗ } else if (!block) {
615 ✗ ret = 0;
616 ✗ break;
617 } else {
618 ✗ SDL_CondWait(q->cond, q->mutex);
619 }
620 }
621 ✗ SDL_UnlockMutex(q->mutex);
622 ✗ return ret;
623 }
624
625 ✗ static int decoder_init(Decoder *d, AVCodecContext *avctx, PacketQueue *queue, SDL_cond *empty_queue_cond) {
626 ✗ memset(d, 0, sizeof(Decoder));
627 ✗ d->pkt = av_packet_alloc();
628 ✗ if (!d->pkt)
629 ✗ return AVERROR(ENOMEM);
630 ✗ d->avctx = avctx;
631 ✗ d->queue = queue;
632 ✗ d->empty_queue_cond = empty_queue_cond;
633 ✗ d->start_pts = AV_NOPTS_VALUE;
634 ✗ d->pkt_serial = -1;
635 ✗ packet_queue_start(d->queue);
636 ✗ return 0;
637 }
638
639 ✗ static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) {
640 ✗ int ret = AVERROR(EAGAIN);
641
642 for (;;) {
643 ✗ if (d->queue->serial == d->pkt_serial) {
644 do {
645 ✗ if (d->queue->abort_request)
646 ✗ return -1;
647
648 ✗ switch (d->avctx->codec_type) {
649 ✗ case AVMEDIA_TYPE_VIDEO:
650 ✗ ret = avcodec_receive_frame(d->avctx, frame);
651 ✗ if (ret >= 0) {
652 ✗ if (decoder_reorder_pts == -1) {
653 ✗ frame->pts = frame->best_effort_timestamp;
654 ✗ } else if (!decoder_reorder_pts) {
655 ✗ frame->pts = frame->pkt_dts;
656 }
657 }
658 ✗ break;
659 ✗ case AVMEDIA_TYPE_AUDIO:
660 ✗ ret = avcodec_receive_frame(d->avctx, frame);
661 ✗ if (ret >= 0) {
662 ✗ AVRational tb = (AVRational){1, frame->sample_rate};
663 ✗ if (frame->pts != AV_NOPTS_VALUE)
664 ✗ frame->pts = av_rescale_q(frame->pts, d->avctx->pkt_timebase, tb);
665 ✗ else if (d->next_pts != AV_NOPTS_VALUE)
666 ✗ frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb);
667 ✗ if (frame->pts != AV_NOPTS_VALUE) {
668 ✗ d->next_pts = frame->pts + frame->nb_samples;
669 ✗ d->next_pts_tb = tb;
670 }
671 }
672 ✗ break;
673 }
674 ✗ if (ret == AVERROR_EOF) {
675 ✗ d->finished = d->pkt_serial;
676 ✗ avcodec_flush_buffers(d->avctx);
677 ✗ return 0;
678 }
679 ✗ if (ret >= 0)
680 ✗ return 1;
681 ✗ } while (ret != AVERROR(EAGAIN));
682 }
683
684 do {
685 ✗ if (d->queue->nb_packets == 0)
686 ✗ SDL_CondSignal(d->empty_queue_cond);
687 ✗ if (d->packet_pending) {
688 ✗ d->packet_pending = 0;
689 } else {
690 ✗ int old_serial = d->pkt_serial;
691 ✗ if (packet_queue_get(d->queue, d->pkt, 1, &d->pkt_serial) < 0)
692 ✗ return -1;
693 ✗ if (old_serial != d->pkt_serial) {
694 ✗ avcodec_flush_buffers(d->avctx);
695 ✗ d->finished = 0;
696 ✗ d->next_pts = d->start_pts;
697 ✗ d->next_pts_tb = d->start_pts_tb;
698 }
699 }
700 ✗ if (d->queue->serial == d->pkt_serial)
701 ✗ break;
702 ✗ av_packet_unref(d->pkt);
703 } while (1);
704
705 ✗ if (d->avctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {
706 ✗ int got_frame = 0;
707 ✗ ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, d->pkt);
708 ✗ if (ret < 0) {
709 ✗ ret = AVERROR(EAGAIN);
710 } else {
711 ✗ if (got_frame && !d->pkt->data) {
712 ✗ d->packet_pending = 1;
713 }
714 ✗ ret = got_frame ? 0 : (d->pkt->data ? AVERROR(EAGAIN) : AVERROR_EOF);
715 }
716 ✗ av_packet_unref(d->pkt);
717 } else {
718 ✗ if (d->pkt->buf && !d->pkt->opaque_ref) {
719 FrameData *fd;
720
721 ✗ d->pkt->opaque_ref = av_buffer_allocz(sizeof(*fd));
722 ✗ if (!d->pkt->opaque_ref)
723 ✗ return AVERROR(ENOMEM);
724 ✗ fd = (FrameData*)d->pkt->opaque_ref->data;
725 ✗ fd->pkt_pos = d->pkt->pos;
726 }
727
728 ✗ if (avcodec_send_packet(d->avctx, d->pkt) == AVERROR(EAGAIN)) {
729 ✗ av_log(d->avctx, AV_LOG_ERROR, "Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
730 ✗ d->packet_pending = 1;
731 } else {
732 ✗ av_packet_unref(d->pkt);
733 }
734 }
735 }
736 }
737
738 ✗ static void decoder_destroy(Decoder *d) {
739 ✗ av_packet_free(&d->pkt);
740 ✗ avcodec_free_context(&d->avctx);
741 ✗ }
742
743 ✗ static void frame_queue_unref_item(Frame *vp)
744 {
745 ✗ av_frame_unref(vp->frame);
746 ✗ avsubtitle_free(&vp->sub);
747 ✗ }
748
749 ✗ static int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int keep_last)
750 {
751 int i;
752 ✗ memset(f, 0, sizeof(FrameQueue));
753 ✗ if (!(f->mutex = SDL_CreateMutex())) {
754 ✗ av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
755 ✗ return AVERROR(ENOMEM);
756 }
757 ✗ if (!(f->cond = SDL_CreateCond())) {
758 ✗ av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
759 ✗ return AVERROR(ENOMEM);
760 }
761 ✗ f->pktq = pktq;
762 ✗ f->max_size = FFMIN(max_size, FRAME_QUEUE_SIZE);
763 ✗ f->keep_last = !!keep_last;
764 ✗ for (i = 0; i < f->max_size; i++)
765 ✗ if (!(f->queue[i].frame = av_frame_alloc()))
766 ✗ return AVERROR(ENOMEM);
767 ✗ return 0;
768 }
769
770 ✗ static void frame_queue_destroy(FrameQueue *f)
771 {
772 int i;
773 ✗ for (i = 0; i < f->max_size; i++) {
774 ✗ Frame *vp = &f->queue[i];
775 ✗ frame_queue_unref_item(vp);
776 ✗ av_frame_free(&vp->frame);
777 }
778 ✗ SDL_DestroyMutex(f->mutex);
779 ✗ SDL_DestroyCond(f->cond);
780 ✗ }
781
782 ✗ static void frame_queue_signal(FrameQueue *f)
783 {
784 ✗ SDL_LockMutex(f->mutex);
785 ✗ SDL_CondSignal(f->cond);
786 ✗ SDL_UnlockMutex(f->mutex);
787 ✗ }
788
789 ✗ static Frame *frame_queue_peek(FrameQueue *f)
790 {
791 ✗ return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];
792 }
793
794 ✗ static Frame *frame_queue_peek_next(FrameQueue *f)
795 {
796 ✗ return &f->queue[(f->rindex + f->rindex_shown + 1) % f->max_size];
797 }
798
799 ✗ static Frame *frame_queue_peek_last(FrameQueue *f)
800 {
801 ✗ return &f->queue[f->rindex];
802 }
803
804 ✗ static Frame *frame_queue_peek_writable(FrameQueue *f)
805 {
806 /* wait until we have space to put a new frame */
807 ✗ SDL_LockMutex(f->mutex);
808 ✗ while (f->size >= f->max_size &&
809 ✗ !f->pktq->abort_request) {
810 ✗ SDL_CondWait(f->cond, f->mutex);
811 }
812 ✗ SDL_UnlockMutex(f->mutex);
813
814 ✗ if (f->pktq->abort_request)
815 ✗ return NULL;
816
817 ✗ return &f->queue[f->windex];
818 }
819
820 ✗ static Frame *frame_queue_peek_readable(FrameQueue *f)
821 {
822 /* wait until we have a readable a new frame */
823 ✗ SDL_LockMutex(f->mutex);
824 ✗ while (f->size - f->rindex_shown <= 0 &&
825 ✗ !f->pktq->abort_request) {
826 ✗ SDL_CondWait(f->cond, f->mutex);
827 }
828 ✗ SDL_UnlockMutex(f->mutex);
829
830 ✗ if (f->pktq->abort_request)
831 ✗ return NULL;
832
833 ✗ return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];
834 }
835
836 ✗ static void frame_queue_push(FrameQueue *f)
837 {
838 ✗ if (++f->windex == f->max_size)
839 ✗ f->windex = 0;
840 ✗ SDL_LockMutex(f->mutex);
841 ✗ f->size++;
842 ✗ SDL_CondSignal(f->cond);
843 ✗ SDL_UnlockMutex(f->mutex);
844 ✗ }
845
846 ✗ static void frame_queue_next(FrameQueue *f)
847 {
848 ✗ if (f->keep_last && !f->rindex_shown) {
849 ✗ f->rindex_shown = 1;
850 ✗ return;
851 }
852 ✗ frame_queue_unref_item(&f->queue[f->rindex]);
853 ✗ if (++f->rindex == f->max_size)
854 ✗ f->rindex = 0;
855 ✗ SDL_LockMutex(f->mutex);
856 ✗ f->size--;
857 ✗ SDL_CondSignal(f->cond);
858 ✗ SDL_UnlockMutex(f->mutex);
859 }
860
861 /* return the number of undisplayed frames in the queue */
862 ✗ static int frame_queue_nb_remaining(FrameQueue *f)
863 {
864 ✗ return f->size - f->rindex_shown;
865 }
866
867 /* return last shown position */
868 ✗ static int64_t frame_queue_last_pos(FrameQueue *f)
869 {
870 ✗ Frame *fp = &f->queue[f->rindex];
871 ✗ if (f->rindex_shown && fp->serial == f->pktq->serial)
872 ✗ return fp->pos;
873 else
874 ✗ return -1;
875 }
876
877 ✗ static void decoder_abort(Decoder *d, FrameQueue *fq)
878 {
879 ✗ packet_queue_abort(d->queue);
880 ✗ frame_queue_signal(fq);
881 ✗ SDL_WaitThread(d->decoder_tid, NULL);
882 ✗ d->decoder_tid = NULL;
883 ✗ packet_queue_flush(d->queue);
884 ✗ }
885
886 ✗ static inline void fill_rectangle(int x, int y, int w, int h)
887 {
888 SDL_Rect rect;
889 ✗ rect.x = x;
890 ✗ rect.y = y;
891 ✗ rect.w = w;
892 ✗ rect.h = h;
893 ✗ if (w && h)
894 ✗ SDL_RenderFillRect(renderer, &rect);
895 ✗ }
896
897 ✗ static int realloc_texture(SDL_Texture **texture, Uint32 new_format, int new_width, int new_height, SDL_BlendMode blendmode, int init_texture)
898 {
899 Uint32 format;
900 int access, w, h;
901 ✗ if (!*texture || SDL_QueryTexture(*texture, &format, &access, &w, &h) < 0 || new_width != w || new_height != h || new_format != format) {
902 void *pixels;
903 int pitch;
904 ✗ if (*texture)
905 ✗ SDL_DestroyTexture(*texture);
906 ✗ if (!(*texture = SDL_CreateTexture(renderer, new_format, SDL_TEXTUREACCESS_STREAMING, new_width, new_height)))
907 ✗ return -1;
908 ✗ if (SDL_SetTextureBlendMode(*texture, blendmode) < 0)
909 ✗ return -1;
910 ✗ if (init_texture) {
911 ✗ if (SDL_LockTexture(*texture, NULL, &pixels, &pitch) < 0)
912 ✗ return -1;
913 ✗ memset(pixels, 0, pitch * new_height);
914 ✗ SDL_UnlockTexture(*texture);
915 }
916 ✗ av_log(NULL, AV_LOG_VERBOSE, "Created %dx%d texture with %s.\n", new_width, new_height, SDL_GetPixelFormatName(new_format));
917 }
918 ✗ return 0;
919 }
920
921 ✗ static void calculate_display_rect(SDL_Rect *rect,
922 int scr_xleft, int scr_ytop, int scr_width, int scr_height,
923 int pic_width, int pic_height, AVRational pic_sar)
924 {
925 ✗ AVRational aspect_ratio = pic_sar;
926 int64_t width, height, x, y;
927
928 ✗ if (av_cmp_q(aspect_ratio, av_make_q(0, 1)) <= 0)
929 ✗ aspect_ratio = av_make_q(1, 1);
930
931 ✗ aspect_ratio = av_mul_q(aspect_ratio, av_make_q(pic_width, pic_height));
932
933 /* XXX: we suppose the screen has a 1.0 pixel ratio */
934 ✗ height = scr_height;
935 ✗ width = av_rescale(height, aspect_ratio.num, aspect_ratio.den) & ~1;
936 ✗ if (width > scr_width) {
937 ✗ width = scr_width;
938 ✗ height = av_rescale(width, aspect_ratio.den, aspect_ratio.num) & ~1;
939 }
940 ✗ x = (scr_width - width) / 2;
941 ✗ y = (scr_height - height) / 2;
942 ✗ rect->x = scr_xleft + x;
943 ✗ rect->y = scr_ytop + y;
944 ✗ rect->w = FFMAX((int)width, 1);
945 ✗ rect->h = FFMAX((int)height, 1);
946 ✗ }
947
948 ✗ static void get_sdl_pix_fmt_and_blendmode(int format, Uint32 *sdl_pix_fmt, SDL_BlendMode *sdl_blendmode)
949 {
950 int i;
951 ✗ *sdl_blendmode = SDL_BLENDMODE_NONE;
952 ✗ *sdl_pix_fmt = SDL_PIXELFORMAT_UNKNOWN;
953 ✗ if (format == AV_PIX_FMT_RGB32 ||
954 ✗ format == AV_PIX_FMT_RGB32_1 ||
955 ✗ format == AV_PIX_FMT_BGR32 ||
956 format == AV_PIX_FMT_BGR32_1)
957 ✗ *sdl_blendmode = SDL_BLENDMODE_BLEND;
958 ✗ for (i = 0; i < FF_ARRAY_ELEMS(sdl_texture_format_map); i++) {
959 ✗ if (format == sdl_texture_format_map[i].format) {
960 ✗ *sdl_pix_fmt = sdl_texture_format_map[i].texture_fmt;
961 ✗ return;
962 }
963 }
964 }
965
966 ✗ static int upload_texture(SDL_Texture **tex, AVFrame *frame)
967 {
968 ✗ int ret = 0;
969 Uint32 sdl_pix_fmt;
970 SDL_BlendMode sdl_blendmode;
971 ✗ get_sdl_pix_fmt_and_blendmode(frame->format, &sdl_pix_fmt, &sdl_blendmode);
972 ✗ if (realloc_texture(tex, sdl_pix_fmt == SDL_PIXELFORMAT_UNKNOWN ? SDL_PIXELFORMAT_ARGB8888 : sdl_pix_fmt, frame->width, frame->height, sdl_blendmode, 0) < 0)
973 ✗ return -1;
974 ✗ switch (sdl_pix_fmt) {
975 ✗ case SDL_PIXELFORMAT_IYUV:
976 ✗ if (frame->linesize[0] > 0 && frame->linesize[1] > 0 && frame->linesize[2] > 0) {
977 ✗ ret = SDL_UpdateYUVTexture(*tex, NULL, frame->data[0], frame->linesize[0],
978 ✗ frame->data[1], frame->linesize[1],
979 ✗ frame->data[2], frame->linesize[2]);
980 ✗ } else if (frame->linesize[0] < 0 && frame->linesize[1] < 0 && frame->linesize[2] < 0) {
981 ✗ ret = SDL_UpdateYUVTexture(*tex, NULL, frame->data[0] + frame->linesize[0] * (frame->height - 1), -frame->linesize[0],
982 ✗ frame->data[1] + frame->linesize[1] * (AV_CEIL_RSHIFT(frame->height, 1) - 1), -frame->linesize[1],
983 ✗ frame->data[2] + frame->linesize[2] * (AV_CEIL_RSHIFT(frame->height, 1) - 1), -frame->linesize[2]);
984 } else {
985 ✗ av_log(NULL, AV_LOG_ERROR, "Mixed negative and positive linesizes are not supported.\n");
986 ✗ return -1;
987 }
988 ✗ break;
989 ✗ default:
990 ✗ if (frame->linesize[0] < 0) {
991 ✗ ret = SDL_UpdateTexture(*tex, NULL, frame->data[0] + frame->linesize[0] * (frame->height - 1), -frame->linesize[0]);
992 } else {
993 ✗ ret = SDL_UpdateTexture(*tex, NULL, frame->data[0], frame->linesize[0]);
994 }
995 ✗ break;
996 }
997 ✗ return ret;
998 }
999
1000 static enum AVColorSpace sdl_supported_color_spaces[] = {
1001 AVCOL_SPC_BT709,
1002 AVCOL_SPC_BT470BG,
1003 AVCOL_SPC_SMPTE170M,
1004 };
1005
1006 static enum AVAlphaMode sdl_supported_alpha_modes[] = {
1007 AVALPHA_MODE_UNSPECIFIED,
1008 AVALPHA_MODE_STRAIGHT,
1009 };
1010
1011 ✗ static void set_sdl_yuv_conversion_mode(AVFrame *frame)
1012 {
1013 #if SDL_VERSION_ATLEAST(2,0,8)
1014 ✗ SDL_YUV_CONVERSION_MODE mode = SDL_YUV_CONVERSION_AUTOMATIC;
1015 ✗ if (frame && (frame->format == AV_PIX_FMT_YUV420P || frame->format == AV_PIX_FMT_YUYV422 || frame->format == AV_PIX_FMT_UYVY422)) {
1016 ✗ if (frame->color_range == AVCOL_RANGE_JPEG)
1017 ✗ mode = SDL_YUV_CONVERSION_JPEG;
1018 ✗ else if (frame->colorspace == AVCOL_SPC_BT709)
1019 ✗ mode = SDL_YUV_CONVERSION_BT709;
1020 ✗ else if (frame->colorspace == AVCOL_SPC_BT470BG || frame->colorspace == AVCOL_SPC_SMPTE170M)
1021 ✗ mode = SDL_YUV_CONVERSION_BT601;
1022 }
1023 ✗ SDL_SetYUVConversionMode(mode); /* FIXME: no support for linear transfer */
1024 #endif
1025 ✗ }
1026
1027 ✗ static void draw_video_background(VideoState *is)
1028 {
1029 ✗ const int tile_size = VIDEO_BACKGROUND_TILE_SIZE;
1030 ✗ SDL_Rect *rect = &is->render_params.target_rect;
1031 SDL_BlendMode blendMode;
1032
1033 ✗ if (!SDL_GetTextureBlendMode(is->vid_texture, &blendMode) && blendMode == SDL_BLENDMODE_BLEND) {
1034 ✗ switch (is->render_params.video_background_type) {
1035 ✗ case VIDEO_BACKGROUND_TILES:
1036 ✗ SDL_SetRenderDrawColor(renderer, 237, 237, 237, 255);
1037 ✗ fill_rectangle(rect->x, rect->y, rect->w, rect->h);
1038 ✗ SDL_SetRenderDrawColor(renderer, 222, 222, 222, 255);
1039 ✗ for (int x = 0; x < rect->w; x += tile_size * 2)
1040 ✗ fill_rectangle(rect->x + x, rect->y, FFMIN(tile_size, rect->w - x), rect->h);
1041 ✗ for (int y = 0; y < rect->h; y += tile_size * 2)
1042 ✗ fill_rectangle(rect->x, rect->y + y, rect->w, FFMIN(tile_size, rect->h - y));
1043 ✗ SDL_SetRenderDrawColor(renderer, 237, 237, 237, 255);
1044 ✗ for (int y = 0; y < rect->h; y += tile_size * 2) {
1045 ✗ int h = FFMIN(tile_size, rect->h - y);
1046 ✗ for (int x = 0; x < rect->w; x += tile_size * 2)
1047 ✗ fill_rectangle(x + rect->x, y + rect->y, FFMIN(tile_size, rect->w - x), h);
1048 }
1049 ✗ break;
1050 ✗ case VIDEO_BACKGROUND_COLOR: {
1051 ✗ const uint8_t *c = is->render_params.video_background_color;
1052 ✗ SDL_SetRenderDrawColor(renderer, c[0], c[1], c[2], c[3]);
1053 ✗ fill_rectangle(rect->x, rect->y, rect->w, rect->h);
1054 ✗ break;
1055 }
1056 ✗ case VIDEO_BACKGROUND_NONE:
1057 ✗ SDL_SetTextureBlendMode(is->vid_texture, SDL_BLENDMODE_NONE);
1058 ✗ break;
1059 }
1060 }
1061 ✗ }
1062
1063 static int current_chapter(VideoState *is);
1064 static void file_list_listed(VideoState *is);
1065 static void seek_chapter(VideoState *is, int i);
1066
1067 ✗ static const char *chapter_tag(const AVChapter *chapter, const char *key)
1068 {
1069 ✗ const AVDictionaryEntry *tag = av_dict_get(chapter->metadata, key, NULL, 0);
1070
1071 ✗ return tag ? tag->value : NULL;
1072 }
1073
1074 /* shows the chapter list with the chapter selected, or with the selection kept when no row shows it */
1075 ✗ static int chapter_list_show(VideoState *is, int chapter)
1076 {
1077 ✗ ListEntry *entries = av_calloc(is->ic->nb_chapters, sizeof(*entries));
1078 int ret;
1079
1080 ✗ if (!entries)
1081 ✗ return AVERROR(ENOMEM);
1082 ✗ for (int i = 0; i < is->ic->nb_chapters; i++) {
1083 ✗ const AVChapter *ch = is->ic->chapters[i];
1084
1085 ✗ entries[i] = (ListEntry){ chapter_tag(ch, "title"), chapter_tag(ch, "artist"), -1, ch->metadata };
1086 ✗ if (ch->end != AV_NOPTS_VALUE && ch->end > ch->start && (uint64_t)ch->end - ch->start <= INT64_MAX)
1087 ✗ entries[i].length = av_rescale_q(ch->end - ch->start, ch->time_base, AV_TIME_BASE_Q);
1088 }
1089 ✗ if (list_shows_files)
1090 ✗ list_view_clear(list);
1091 ✗ ret = list_view_show(list, entries, is->ic->nb_chapters, chapter);
1092 ✗ av_free(entries);
1093 ✗ if (ret >= 0)
1094 ✗ list_shows_files = 0;
1095 ✗ return ret;
1096 }
1097
1098 ✗ static void chapter_list_pin(VideoState *is)
1099 {
1100 ✗ if (chapter_list_show(is, current_chapter(is)) >= 0)
1101 ✗ list_view_pin(list, 1);
1102 ✗ }
1103
1104 ✗ static void video_image_display(VideoState *is)
1105 {
1106 Frame *vp;
1107 ✗ Frame *sp = NULL;
1108 ✗ SDL_Rect *rect = &is->render_params.target_rect;
1109
1110 ✗ vp = frame_queue_peek_last(&is->pictq);
1111 ✗ calculate_display_rect(rect, is->xleft, is->ytop, is->width, is->height, vp->width, vp->height, vp->sar);
1112 ✗ if (vk_renderer) {
1113 ✗ vk_renderer_display(vk_renderer, vp->frame, &is->render_params);
1114 ✗ return;
1115 }
1116
1117 ✗ if (is->subtitle_st) {
1118 ✗ if (frame_queue_nb_remaining(&is->subpq) > 0) {
1119 ✗ sp = frame_queue_peek(&is->subpq);
1120
1121 ✗ if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) {
1122 ✗ if (!sp->uploaded) {
1123 uint8_t* pixels[4];
1124 int pitch[4];
1125 int i;
1126 ✗ if (!sp->width || !sp->height) {
1127 ✗ sp->width = vp->width;
1128 ✗ sp->height = vp->height;
1129 }
1130 ✗ if (realloc_texture(&is->sub_texture, SDL_PIXELFORMAT_ARGB8888, sp->width, sp->height, SDL_BLENDMODE_BLEND, 1) < 0)
1131 ✗ return;
1132
1133 ✗ for (i = 0; i < sp->sub.num_rects; i++) {
1134 ✗ AVSubtitleRect *sub_rect = sp->sub.rects[i];
1135
1136 ✗ sub_rect->x = av_clip(sub_rect->x, 0, sp->width );
1137 ✗ sub_rect->y = av_clip(sub_rect->y, 0, sp->height);
1138 ✗ sub_rect->w = av_clip(sub_rect->w, 0, sp->width - sub_rect->x);
1139 ✗ sub_rect->h = av_clip(sub_rect->h, 0, sp->height - sub_rect->y);
1140
1141 ✗ is->sub_convert_ctx = sws_getCachedContext(is->sub_convert_ctx,
1142 sub_rect->w, sub_rect->h, AV_PIX_FMT_PAL8,
1143 sub_rect->w, sub_rect->h, AV_PIX_FMT_BGRA,
1144 0, NULL, NULL, NULL);
1145 ✗ if (!is->sub_convert_ctx) {
1146 ✗ av_log(NULL, AV_LOG_FATAL, "Cannot initialize the conversion context\n");
1147 ✗ return;
1148 }
1149 ✗ if (!SDL_LockTexture(is->sub_texture, (SDL_Rect *)sub_rect, (void **)pixels, pitch)) {
1150 ✗ sws_scale(is->sub_convert_ctx, (const uint8_t * const *)sub_rect->data, sub_rect->linesize,
1151 0, sub_rect->h, pixels, pitch);
1152 ✗ SDL_UnlockTexture(is->sub_texture);
1153 }
1154 }
1155 ✗ sp->uploaded = 1;
1156 }
1157 } else
1158 ✗ sp = NULL;
1159 }
1160 }
1161
1162 ✗ set_sdl_yuv_conversion_mode(vp->frame);
1163
1164 ✗ if (!vp->uploaded) {
1165 ✗ if (upload_texture(&is->vid_texture, vp->frame) < 0) {
1166 ✗ set_sdl_yuv_conversion_mode(NULL);
1167 ✗ return;
1168 }
1169 ✗ vp->uploaded = 1;
1170 ✗ vp->flip_v = vp->frame->linesize[0] < 0;
1171 }
1172
1173 ✗ draw_video_background(is);
1174 ✗ SDL_RenderCopyEx(renderer, is->vid_texture, NULL, rect, 0, NULL, vp->flip_v ? SDL_FLIP_VERTICAL : 0);
1175 ✗ set_sdl_yuv_conversion_mode(NULL);
1176 ✗ if (sp) {
1177 #if USE_ONEPASS_SUBTITLE_RENDER
1178 ✗ SDL_RenderCopy(renderer, is->sub_texture, NULL, rect);
1179 #else
1180 int i;
1181 double xratio = (double)rect->w / (double)sp->width;
1182 double yratio = (double)rect->h / (double)sp->height;
1183 for (i = 0; i < sp->sub.num_rects; i++) {
1184 SDL_Rect *sub_rect = (SDL_Rect*)sp->sub.rects[i];
1185 SDL_Rect target = {.x = rect.x + sub_rect->x * xratio,
1186 .y = rect.y + sub_rect->y * yratio,
1187 .w = sub_rect->w * xratio,
1188 .h = sub_rect->h * yratio};
1189 SDL_RenderCopy(renderer, is->sub_texture, sub_rect, &target);
1190 }
1191 #endif
1192 }
1193 }
1194
1195 ✗ static inline int compute_mod(int a, int b)
1196 {
1197 ✗ return a < 0 ? a%b + b : a%b;
1198 }
1199
1200 ✗ static void video_audio_display(VideoState *s)
1201 {
1202 int i, i_start, x, y1, y, ys, delay, n, nb_display_channels;
1203 int ch, channels, h, h2;
1204 int64_t time_diff;
1205 int rdft_bits, nb_freq;
1206
1207 ✗ for (rdft_bits = 1; (1 << rdft_bits) < 2 * s->height; rdft_bits++)
1208 ;
1209 ✗ nb_freq = 1 << (rdft_bits - 1);
1210
1211 /* compute display index : center on currently output samples */
1212 ✗ channels = s->audio_tgt.ch_layout.nb_channels;
1213 ✗ nb_display_channels = channels;
1214 ✗ if (!s->paused) {
1215 ✗ int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq);
1216 ✗ n = 2 * channels;
1217 ✗ delay = s->audio_write_buf_size;
1218 ✗ delay /= n;
1219
1220 /* to be more precise, we take into account the time spent since
1221 the last buffer computation */
1222 ✗ if (s->audio_callback_time) {
1223 ✗ time_diff = av_gettime_relative() - s->audio_callback_time;
1224 ✗ delay -= (time_diff * s->audio_tgt.freq) / 1000000;
1225 }
1226
1227 ✗ delay += 2 * data_used;
1228 ✗ if (delay < data_used)
1229 ✗ delay = data_used;
1230
1231 ✗ i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
1232 ✗ if (s->show_mode == SHOW_MODE_WAVES) {
1233 ✗ h = INT_MIN;
1234 ✗ for (i = 0; i < 1000; i += channels) {
1235 ✗ int idx = (SAMPLE_ARRAY_SIZE + x - i) % SAMPLE_ARRAY_SIZE;
1236 ✗ int a = s->sample_array[idx];
1237 ✗ int b = s->sample_array[(idx + 4 * channels) % SAMPLE_ARRAY_SIZE];
1238 ✗ int c = s->sample_array[(idx + 5 * channels) % SAMPLE_ARRAY_SIZE];
1239 ✗ int d = s->sample_array[(idx + 9 * channels) % SAMPLE_ARRAY_SIZE];
1240 ✗ int score = a - d;
1241 ✗ if (h < score && (b ^ c) < 0) {
1242 ✗ h = score;
1243 ✗ i_start = idx;
1244 }
1245 }
1246 }
1247
1248 ✗ s->last_i_start = i_start;
1249 } else {
1250 ✗ i_start = s->last_i_start;
1251 }
1252
1253 ✗ if (s->show_mode == SHOW_MODE_WAVES) {
1254 ✗ SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
1255
1256 /* total height for one channel */
1257 ✗ h = s->height / nb_display_channels;
1258 /* graph height / 2 */
1259 ✗ h2 = (h * 9) / 20;
1260 ✗ for (ch = 0; ch < nb_display_channels; ch++) {
1261 ✗ i = i_start + ch;
1262 ✗ y1 = s->ytop + ch * h + (h / 2); /* position of center line */
1263 ✗ for (x = 0; x < s->width; x++) {
1264 ✗ y = (s->sample_array[i] * h2) >> 15;
1265 ✗ if (y < 0) {
1266 ✗ y = -y;
1267 ✗ ys = y1 - y;
1268 } else {
1269 ✗ ys = y1;
1270 }
1271 ✗ fill_rectangle(s->xleft + x, ys, 1, y);
1272 ✗ i += channels;
1273 ✗ if (i >= SAMPLE_ARRAY_SIZE)
1274 ✗ i -= SAMPLE_ARRAY_SIZE;
1275 }
1276 }
1277
1278 ✗ SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
1279
1280 ✗ for (ch = 1; ch < nb_display_channels; ch++) {
1281 ✗ y = s->ytop + ch * h;
1282 ✗ fill_rectangle(s->xleft, y, s->width, 1);
1283 }
1284 } else {
1285 ✗ int err = 0;
1286 ✗ if (realloc_texture(&s->vis_texture, SDL_PIXELFORMAT_ARGB8888, s->width, s->height, SDL_BLENDMODE_NONE, 1) < 0)
1287 ✗ return;
1288
1289 ✗ if (s->xpos >= s->width)
1290 ✗ s->xpos = 0;
1291 ✗ nb_display_channels= FFMIN(nb_display_channels, 2);
1292 ✗ if (rdft_bits != s->rdft_bits) {
1293 ✗ const float rdft_scale = 1.0;
1294 ✗ av_tx_uninit(&s->rdft);
1295 ✗ av_freep(&s->real_data);
1296 ✗ av_freep(&s->rdft_data);
1297 ✗ s->rdft_bits = rdft_bits;
1298 ✗ s->real_data = av_malloc_array(nb_freq, 4 *sizeof(*s->real_data));
1299 ✗ s->rdft_data = av_malloc_array(nb_freq + 1, 2 *sizeof(*s->rdft_data));
1300 ✗ err = av_tx_init(&s->rdft, &s->rdft_fn, AV_TX_FLOAT_RDFT,
1301 0, 1 << rdft_bits, &rdft_scale, 0);
1302 }
1303 ✗ if (err < 0 || !s->rdft_data) {
1304 ✗ av_log(NULL, AV_LOG_ERROR, "Failed to allocate buffers for RDFT, switching to waves display\n");
1305 ✗ s->show_mode = SHOW_MODE_WAVES;
1306 } else {
1307 float *data_in[2];
1308 AVComplexFloat *data[2];
1309 ✗ SDL_Rect rect = {.x = s->xpos, .y = 0, .w = 1, .h = s->height};
1310 uint32_t *pixels;
1311 int pitch;
1312 ✗ for (ch = 0; ch < nb_display_channels; ch++) {
1313 ✗ data_in[ch] = s->real_data + 2 * nb_freq * ch;
1314 ✗ data[ch] = s->rdft_data + nb_freq * ch;
1315 ✗ i = i_start + ch;
1316 ✗ for (x = 0; x < 2 * nb_freq; x++) {
1317 ✗ double w = (x-nb_freq) * (1.0 / nb_freq);
1318 ✗ data_in[ch][x] = s->sample_array[i] * (1.0 - w * w);
1319 ✗ i += channels;
1320 ✗ if (i >= SAMPLE_ARRAY_SIZE)
1321 ✗ i -= SAMPLE_ARRAY_SIZE;
1322 }
1323 ✗ s->rdft_fn(s->rdft, data[ch], data_in[ch], sizeof(float));
1324 }
1325 /* Least efficient way to do this, we should of course
1326 * directly access it but it is more than fast enough. */
1327 ✗ if (!SDL_LockTexture(s->vis_texture, &rect, (void **)&pixels, &pitch)) {
1328 ✗ double w = 1 / sqrt(nb_freq);
1329 ✗ int show_phase = s->show_mode == SHOW_MODE_PHASE && nb_display_channels == 2;
1330 ✗ pitch >>= 2;
1331 ✗ pixels += pitch * s->height;
1332 ✗ for (y = 0; y < s->height; y++) {
1333 ✗ int a = sqrt(w * sqrt(data[0][y].re * data[0][y].re + data[0][y].im * data[0][y].im));
1334 ✗ int b = (nb_display_channels == 2 ) ? sqrt(w * hypot(data[1][y].re, data[1][y].im))
1335 : a;
1336 ✗ a = FFMIN(a, 255);
1337 ✗ b = FFMIN(b, 255);
1338 ✗ int blue = (a+b) >> 1;
1339 ✗ if (show_phase) {
1340 /* phase(left) - phase(right) in units of pi */
1341 ✗ double phase = atan2(data[0][y].im * data[1][y].re - data[0][y].re * data[1][y].im,
1342 ✗ data[0][y].re * data[1][y].re + data[0][y].im * data[1][y].im) / M_PI;
1343 ✗ int phase_shift = lrint(phase * FFMIN(a, b));
1344 ✗ a = FFMIN(a - phase_shift / 2, 255);
1345 ✗ b = FFMIN(b - phase_shift / 2, 255);
1346 ✗ blue = FFMIN(blue + phase_shift, 255);
1347 }
1348 ✗ pixels -= pitch;
1349 ✗ *pixels = (a << 16) + (b << 8) + blue;
1350 }
1351 ✗ SDL_UnlockTexture(s->vis_texture);
1352 }
1353 ✗ SDL_RenderCopy(renderer, s->vis_texture, NULL, NULL);
1354 }
1355 ✗ if (!s->paused)
1356 ✗ s->xpos++;
1357 }
1358 }
1359
1360 ✗ static void uninit_bsf_graph(AVFormatContext *ic, int stream_index)
1361 {
1362 ✗ FormatContext *ici = ic->opaque;
1363 Stream *sti;
1364 StreamGroup *stgi;
1365
1366 ✗ if (stream_index >= ici->nb_streams)
1367 ✗ return;
1368
1369 ✗ sti = ici->streams[stream_index];
1370 ✗ sti->filter = NULL;
1371
1372 ✗ stgi = sti->group;
1373 ✗ if (stgi) {
1374 ✗ av_bsf_graph_free(&stgi->graph);
1375 ✗ stgi->sink = NULL;
1376
1377 ✗ for (int i = 0; i < stgi->stg->nb_entries; i++) {
1378 ✗ ici->streams[stgi->stg->entries[i]->stream->index]->filter = NULL;
1379 ✗ ici->streams[stgi->stg->entries[i]->stream->index]->group = NULL;
1380 }
1381 }
1382 ✗ sti->group = stgi;
1383 }
1384
1385 ✗ static void stream_component_close(VideoState *is, int stream_index)
1386 {
1387 ✗ AVFormatContext *ic = is->ic;
1388
1389 AVCodecParameters *codecpar;
1390
1391 ✗ if (stream_index < 0 || stream_index >= ic->nb_streams)
1392 ✗ return;
1393 ✗ codecpar = ic->streams[stream_index]->codecpar;
1394
1395 ✗ uninit_bsf_graph(ic, stream_index);
1396
1397 ✗ switch (codecpar->codec_type) {
1398 ✗ case AVMEDIA_TYPE_AUDIO:
1399 ✗ decoder_abort(&is->auddec, &is->sampq);
1400 ✗ avfilter_graph_free(&is->agraph);
1401 ✗ SDL_CloseAudioDevice(is->audio_dev);
1402 ✗ is->audio_dev = 0;
1403 ✗ decoder_destroy(&is->auddec);
1404 ✗ swr_free(&is->swr_ctx);
1405 ✗ av_freep(&is->audio_buf1);
1406 ✗ is->audio_buf1_size = 0;
1407 ✗ is->audio_buf = NULL;
1408
1409 ✗ if (is->rdft) {
1410 ✗ av_tx_uninit(&is->rdft);
1411 ✗ av_freep(&is->real_data);
1412 ✗ av_freep(&is->rdft_data);
1413 ✗ is->rdft = NULL;
1414 ✗ is->rdft_bits = 0;
1415 }
1416 ✗ break;
1417 ✗ case AVMEDIA_TYPE_VIDEO:
1418 ✗ decoder_abort(&is->viddec, &is->pictq);
1419 ✗ decoder_destroy(&is->viddec);
1420 ✗ break;
1421 ✗ case AVMEDIA_TYPE_SUBTITLE:
1422 ✗ decoder_abort(&is->subdec, &is->subpq);
1423 ✗ decoder_destroy(&is->subdec);
1424 ✗ break;
1425 ✗ default:
1426 ✗ break;
1427 }
1428
1429 ✗ ic->streams[stream_index]->discard = AVDISCARD_ALL;
1430 ✗ switch (codecpar->codec_type) {
1431 ✗ case AVMEDIA_TYPE_AUDIO:
1432 ✗ is->audio_st = NULL;
1433 ✗ is->audio_stream = -1;
1434 ✗ break;
1435 ✗ case AVMEDIA_TYPE_VIDEO:
1436 ✗ is->video_st = NULL;
1437 ✗ is->video_stream = -1;
1438 ✗ break;
1439 ✗ case AVMEDIA_TYPE_SUBTITLE:
1440 ✗ is->subtitle_st = NULL;
1441 ✗ is->subtitle_stream = -1;
1442 ✗ break;
1443 ✗ default:
1444 ✗ break;
1445 }
1446 }
1447
1448 ✗ static void stream_close(VideoState *is)
1449 {
1450 /* XXX: use a special url_shutdown call to abort parse cleanly */
1451 ✗ is->abort_request = 1;
1452 ✗ SDL_WaitThread(is->read_tid, NULL);
1453
1454 /* close each stream */
1455 ✗ if (is->audio_stream >= 0)
1456 ✗ stream_component_close(is, is->audio_stream);
1457 ✗ if (is->video_stream >= 0)
1458 ✗ stream_component_close(is, is->video_stream);
1459 ✗ if (is->subtitle_stream >= 0)
1460 ✗ stream_component_close(is, is->subtitle_stream);
1461
1462 ✗ if (is->ic) {
1463 ✗ FormatContext *ici = is->ic->opaque;
1464 ✗ for (int i = 0; i < ici->nb_streams; i++)
1465 ✗ av_freep(&ici->streams[i]);
1466 ✗ av_freep(&ici->streams);
1467 ✗ for (int i = 0; i < ici->nb_stream_groups; i++)
1468 ✗ av_freep(&ici->stream_groups[i]);
1469 ✗ av_freep(&ici->stream_groups);
1470 ✗ av_freep(&is->ic->opaque);
1471 }
1472
1473 ✗ avformat_close_input(&is->ic);
1474
1475 ✗ packet_queue_destroy(&is->videoq);
1476 ✗ packet_queue_destroy(&is->audioq);
1477 ✗ packet_queue_destroy(&is->subtitleq);
1478
1479 /* free all pictures */
1480 ✗ frame_queue_destroy(&is->pictq);
1481 ✗ frame_queue_destroy(&is->sampq);
1482 ✗ frame_queue_destroy(&is->subpq);
1483 ✗ SDL_DestroyCond(is->continue_read_thread);
1484 ✗ sws_freeContext(is->sub_convert_ctx);
1485 ✗ av_free(is->filename);
1486 ✗ av_free(is->title);
1487 ✗ if (is->vis_texture)
1488 ✗ SDL_DestroyTexture(is->vis_texture);
1489 ✗ if (is->vid_texture)
1490 ✗ SDL_DestroyTexture(is->vid_texture);
1491 ✗ if (is->sub_texture)
1492 ✗ SDL_DestroyTexture(is->sub_texture);
1493 ✗ av_free(is);
1494 ✗ }
1495
1496 ✗ static void do_exit(VideoState *is)
1497 {
1498 ✗ if (is) {
1499 ✗ stream_close(is);
1500 }
1501 ✗ if (next_stream)
1502 ✗ stream_close(next_stream);
1503 ✗ SDL_AtomicSet(&dir_request.abort, 1);
1504 ✗ for (int waited = 0; dir_thread && !SDL_AtomicGet(&dir_request.done) && waited < 2000; waited += 10)
1505 ✗ SDL_Delay(10);
1506 ✗ if (dir_thread && !SDL_AtomicGet(&dir_request.done)) {
1507 /* a protocol that does not take the interrupt keeps the thread and its request until the process ends */
1508 ✗ SDL_DetachThread(dir_thread);
1509 } else {
1510 ✗ if (dir_thread)
1511 ✗ SDL_WaitThread(dir_thread, NULL);
1512 ✗ dir_list_free(&dir_request.dl);
1513 ✗ av_freep(&dir_request.path);
1514 ✗ av_dict_free(&dir_request.options);
1515 }
1516 ✗ list_view_free(&list);
1517 ✗ if (renderer)
1518 ✗ SDL_DestroyRenderer(renderer);
1519 ✗ if (vk_renderer)
1520 ✗ vk_renderer_destroy(vk_renderer);
1521 ✗ if (window)
1522 ✗ SDL_DestroyWindow(window);
1523 ✗ uninit_opts();
1524 ✗ for (int i = 0; i < nb_vfilters; i++)
1525 ✗ av_freep(&vfilters_list[i]);
1526 ✗ av_freep(&vfilters_list);
1527 ✗ av_freep(&video_codec_name);
1528 ✗ av_freep(&audio_codec_name);
1529 ✗ av_freep(&subtitle_codec_name);
1530 ✗ av_freep(&input_filename);
1531 ✗ dir_list_free(&dir_list);
1532 ✗ avformat_network_deinit();
1533 ✗ if (show_status)
1534 ✗ printf("\n");
1535 ✗ SDL_Quit();
1536 ✗ av_log(NULL, AV_LOG_QUIET, "%s", "");
1537 ✗ exit(exit_status);
1538 }
1539
1540 ✗ static void sigterm_handler(int sig)
1541 {
1542 ✗ received_sigterm = sig;
1543 ✗ if (++received_nb_signals > 3)
1544 ✗ exit(123);
1545 ✗ }
1546
1547 ✗ static void set_default_window_size(int width, int height, AVRational sar)
1548 {
1549 SDL_Rect rect;
1550 ✗ int max_width = screen_width ? screen_width : INT_MAX;
1551 ✗ int max_height = screen_height ? screen_height : INT_MAX;
1552 ✗ if (max_width == INT_MAX && max_height == INT_MAX)
1553 ✗ max_height = height;
1554 ✗ calculate_display_rect(&rect, 0, 0, max_width, max_height, width, height, sar);
1555 ✗ default_width = rect.w;
1556 ✗ default_height = rect.h;
1557 ✗ }
1558
1559 ✗ static int video_open(VideoState *is)
1560 {
1561 int w,h;
1562
1563 ✗ w = screen_width ? screen_width : default_width;
1564 ✗ h = screen_height ? screen_height : default_height;
1565
1566 ✗ SDL_SetWindowTitle(window, window_title ? window_title : is->title ? is->title : is->filename);
1567
1568 ✗ SDL_SetWindowSize(window, w, h);
1569 ✗ SDL_SetWindowPosition(window, screen_left, screen_top);
1570 ✗ if (is_full_screen)
1571 ✗ SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
1572 ✗ SDL_ShowWindow(window);
1573
1574 ✗ is->width = w;
1575 ✗ is->height = h;
1576 ✗ list_view_set_size(list, w, h);
1577
1578 ✗ return 0;
1579 }
1580
1581 /* display the current picture, if any */
1582 ✗ static void video_display(VideoState *is)
1583 {
1584 ✗ if (!is->width)
1585 ✗ video_open(is);
1586
1587 ✗ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
1588 ✗ SDL_RenderClear(renderer);
1589 ✗ if (is->audio_st && is->show_mode != SHOW_MODE_VIDEO)
1590 ✗ video_audio_display(is);
1591 ✗ else if (is->video_st && is->pictq.rindex_shown)
1592 ✗ video_image_display(is);
1593 ✗ list_view_draw(list);
1594 ✗ SDL_RenderPresent(renderer);
1595 ✗ }
1596
1597 ✗ static double get_clock(Clock *c)
1598 {
1599 ✗ if (*c->queue_serial != c->serial)
1600 ✗ return NAN;
1601 ✗ if (c->paused) {
1602 ✗ return c->pts;
1603 } else {
1604 ✗ double time = av_gettime_relative() / 1000000.0;
1605 ✗ return c->pts_drift + time - (time - c->last_updated) * (1.0 - c->speed);
1606 }
1607 }
1608
1609 ✗ static void set_clock_at(Clock *c, double pts, int serial, double time)
1610 {
1611 ✗ c->pts = pts;
1612 ✗ c->last_updated = time;
1613 ✗ c->pts_drift = c->pts - time;
1614 ✗ c->serial = serial;
1615 ✗ }
1616
1617 ✗ static void set_clock(Clock *c, double pts, int serial)
1618 {
1619 ✗ double time = av_gettime_relative() / 1000000.0;
1620 ✗ set_clock_at(c, pts, serial, time);
1621 ✗ }
1622
1623 ✗ static void set_clock_speed(Clock *c, double speed)
1624 {
1625 ✗ set_clock(c, get_clock(c), c->serial);
1626 ✗ c->speed = speed;
1627 ✗ }
1628
1629 ✗ static void init_clock(Clock *c, int *queue_serial)
1630 {
1631 ✗ c->speed = 1.0;
1632 ✗ c->paused = 0;
1633 ✗ c->queue_serial = queue_serial;
1634 ✗ set_clock(c, NAN, -1);
1635 ✗ }
1636
1637 ✗ static void sync_clock_to_slave(Clock *c, Clock *slave)
1638 {
1639 ✗ double clock = get_clock(c);
1640 ✗ double slave_clock = get_clock(slave);
1641 ✗ if (!isnan(slave_clock) && (isnan(clock) || fabs(clock - slave_clock) > AV_NOSYNC_THRESHOLD))
1642 ✗ set_clock(c, slave_clock, slave->serial);
1643 ✗ }
1644
1645 ✗ static int get_master_sync_type(VideoState *is) {
1646 ✗ if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) {
1647 ✗ if (is->video_st)
1648 ✗ return AV_SYNC_VIDEO_MASTER;
1649 else
1650 ✗ return AV_SYNC_AUDIO_MASTER;
1651 ✗ } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) {
1652 ✗ if (is->audio_st)
1653 ✗ return AV_SYNC_AUDIO_MASTER;
1654 else
1655 ✗ return AV_SYNC_EXTERNAL_CLOCK;
1656 } else {
1657 ✗ return AV_SYNC_EXTERNAL_CLOCK;
1658 }
1659 }
1660
1661 /* get the current master clock value */
1662 ✗ static double get_master_clock(VideoState *is)
1663 {
1664 double val;
1665
1666 ✗ switch (get_master_sync_type(is)) {
1667 ✗ case AV_SYNC_VIDEO_MASTER:
1668 ✗ val = get_clock(&is->vidclk);
1669 ✗ break;
1670 ✗ case AV_SYNC_AUDIO_MASTER:
1671 ✗ val = get_clock(&is->audclk);
1672 ✗ break;
1673 ✗ default:
1674 ✗ val = get_clock(&is->extclk);
1675 ✗ break;
1676 }
1677 ✗ return val;
1678 }
1679
1680 ✗ static void check_external_clock_speed(VideoState *is) {
1681 ✗ if (is->video_stream >= 0 && is->videoq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES ||
1682 ✗ is->audio_stream >= 0 && is->audioq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES) {
1683 ✗ set_clock_speed(&is->extclk, FFMAX(EXTERNAL_CLOCK_SPEED_MIN, is->extclk.speed - EXTERNAL_CLOCK_SPEED_STEP));
1684 ✗ } else if ((is->video_stream < 0 || is->videoq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES) &&
1685 ✗ (is->audio_stream < 0 || is->audioq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES)) {
1686 ✗ set_clock_speed(&is->extclk, FFMIN(EXTERNAL_CLOCK_SPEED_MAX, is->extclk.speed + EXTERNAL_CLOCK_SPEED_STEP));
1687 } else {
1688 ✗ double speed = is->extclk.speed;
1689 ✗ if (speed != 1.0)
1690 ✗ set_clock_speed(&is->extclk, speed + EXTERNAL_CLOCK_SPEED_STEP * (1.0 - speed) / fabs(1.0 - speed));
1691 }
1692 ✗ }
1693
1694 /* seek in the stream */
1695 ✗ static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int by_bytes)
1696 {
1697 ✗ if (!is->seek_req) {
1698 ✗ is->seek_pos = pos;
1699 ✗ is->seek_rel = rel;
1700 ✗ is->seek_flags &= ~AVSEEK_FLAG_BYTE;
1701 ✗ if (by_bytes)
1702 ✗ is->seek_flags |= AVSEEK_FLAG_BYTE;
1703 ✗ is->seek_req = 1;
1704 ✗ SDL_CondSignal(is->continue_read_thread);
1705 }
1706 ✗ }
1707
1708 /* pause or resume the video */
1709 ✗ static void stream_toggle_pause(VideoState *is)
1710 {
1711 ✗ if (is->paused) {
1712 ✗ is->frame_timer += av_gettime_relative() / 1000000.0 - is->vidclk.last_updated;
1713 ✗ if (is->read_pause_return != AVERROR(ENOSYS)) {
1714 ✗ is->vidclk.paused = 0;
1715 }
1716 ✗ set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial);
1717 }
1718 ✗ set_clock(&is->extclk, get_clock(&is->extclk), is->extclk.serial);
1719 ✗ is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused = !is->paused;
1720 ✗ }
1721
1722 ✗ static void toggle_pause(VideoState *is)
1723 {
1724 ✗ stream_toggle_pause(is);
1725 ✗ is->step = 0;
1726 ✗ }
1727
1728 ✗ static void toggle_mute(VideoState *is)
1729 {
1730 ✗ is->muted = !is->muted;
1731 ✗ }
1732
1733 ✗ static void update_volume(VideoState *is, int sign, double step)
1734 {
1735 ✗ double volume_level = is->audio_volume ? (20 * log(is->audio_volume / (double)SDL_MIX_MAXVOLUME) / log(10)) : -1000.0;
1736 ✗ int new_volume = lrint(SDL_MIX_MAXVOLUME * pow(10.0, (volume_level + sign * step) / 20.0));
1737 ✗ is->audio_volume = av_clip(is->audio_volume == new_volume ? (is->audio_volume + sign) : new_volume, 0, SDL_MIX_MAXVOLUME);
1738 ✗ }
1739
1740 ✗ static void step_to_next_frame(VideoState *is)
1741 {
1742 /* if the stream is paused unpause it, then step */
1743 ✗ if (is->paused)
1744 ✗ stream_toggle_pause(is);
1745 ✗ is->step = 1;
1746 ✗ }
1747
1748 ✗ static double compute_target_delay(double delay, VideoState *is)
1749 {
1750 ✗ double sync_threshold, diff = 0;
1751
1752 /* update delay to follow master synchronisation source */
1753 ✗ if (get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER) {
1754 /* if video is slave, we try to correct big delays by
1755 duplicating or deleting a frame */
1756 ✗ diff = get_clock(&is->vidclk) - get_master_clock(is);
1757
1758 /* skip or repeat frame. We take into account the
1759 delay to compute the threshold. I still don't know
1760 if it is the best guess */
1761 ✗ sync_threshold = FFMAX(AV_SYNC_THRESHOLD_MIN, FFMIN(AV_SYNC_THRESHOLD_MAX, delay));
1762 ✗ if (!isnan(diff) && fabs(diff) < is->max_frame_duration) {
1763 ✗ if (diff <= -sync_threshold)
1764 ✗ delay = FFMAX(0, delay + diff);
1765 ✗ else if (diff >= sync_threshold && delay > AV_SYNC_FRAMEDUP_THRESHOLD)
1766 ✗ delay = delay + diff;
1767 ✗ else if (diff >= sync_threshold)
1768 ✗ delay = 2 * delay;
1769 }
1770 }
1771
1772 ✗ av_log(NULL, AV_LOG_TRACE, "video: delay=%0.3f A-V=%f\n",
1773 delay, -diff);
1774
1775 ✗ return delay;
1776 }
1777
1778 ✗ static double vp_duration(VideoState *is, Frame *vp, Frame *nextvp) {
1779 ✗ if (vp->serial == nextvp->serial) {
1780 ✗ double duration = nextvp->pts - vp->pts;
1781 ✗ if (isnan(duration) || duration <= 0 || duration > is->max_frame_duration)
1782 ✗ return vp->duration;
1783 else
1784 ✗ return duration;
1785 } else {
1786 ✗ return 0.0;
1787 }
1788 }
1789
1790 ✗ static void update_video_pts(VideoState *is, double pts, int serial)
1791 {
1792 /* update current video pts */
1793 ✗ set_clock(&is->vidclk, pts, serial);
1794 ✗ sync_clock_to_slave(&is->extclk, &is->vidclk);
1795 ✗ }
1796
1797 /* called to display each frame */
1798 ✗ static void video_refresh(void *opaque, double *remaining_time)
1799 {
1800 ✗ VideoState *is = opaque;
1801 double time;
1802
1803 Frame *sp, *sp2;
1804
1805 ✗ if (!is->paused && get_master_sync_type(is) == AV_SYNC_EXTERNAL_CLOCK && is->realtime)
1806 ✗ check_external_clock_speed(is);
1807
1808 ✗ if (!display_disable && is->show_mode != SHOW_MODE_VIDEO && is->audio_st) {
1809 ✗ time = av_gettime_relative() / 1000000.0;
1810 ✗ if (is->force_refresh || is->last_vis_time + rdftspeed < time) {
1811 ✗ video_display(is);
1812 ✗ is->last_vis_time = time;
1813 }
1814 ✗ *remaining_time = FFMIN(*remaining_time, is->last_vis_time + rdftspeed - time);
1815 }
1816
1817 ✗ if (is->video_st) {
1818 ✗ retry:
1819 ✗ if (frame_queue_nb_remaining(&is->pictq) == 0) {
1820 // nothing to do, no picture to display in the queue
1821 } else {
1822 double last_duration, duration, delay;
1823 Frame *vp, *lastvp;
1824
1825 /* dequeue the picture */
1826 ✗ lastvp = frame_queue_peek_last(&is->pictq);
1827 ✗ vp = frame_queue_peek(&is->pictq);
1828
1829 ✗ if (vp->serial != is->videoq.serial) {
1830 ✗ frame_queue_next(&is->pictq);
1831 ✗ goto retry;
1832 }
1833
1834 ✗ if (lastvp->serial != vp->serial)
1835 ✗ is->frame_timer = av_gettime_relative() / 1000000.0;
1836
1837 ✗ if (is->paused)
1838 ✗ goto display;
1839
1840 /* compute nominal last_duration */
1841 ✗ last_duration = vp_duration(is, lastvp, vp);
1842 ✗ delay = compute_target_delay(last_duration, is);
1843
1844 ✗ time= av_gettime_relative()/1000000.0;
1845 ✗ if (time < is->frame_timer + delay) {
1846 ✗ *remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time);
1847 ✗ goto display;
1848 }
1849
1850 ✗ is->frame_timer += delay;
1851 ✗ if (delay > 0 && time - is->frame_timer > AV_SYNC_THRESHOLD_MAX)
1852 ✗ is->frame_timer = time;
1853
1854 ✗ SDL_LockMutex(is->pictq.mutex);
1855 ✗ if (!isnan(vp->pts))
1856 ✗ update_video_pts(is, vp->pts, vp->serial);
1857 ✗ SDL_UnlockMutex(is->pictq.mutex);
1858
1859 ✗ if (frame_queue_nb_remaining(&is->pictq) > 1) {
1860 ✗ Frame *nextvp = frame_queue_peek_next(&is->pictq);
1861 ✗ duration = vp_duration(is, vp, nextvp);
1862 ✗ if(!is->step && (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){
1863 ✗ is->frame_drops_late++;
1864 ✗ frame_queue_next(&is->pictq);
1865 ✗ goto retry;
1866 }
1867 }
1868
1869 ✗ if (is->subtitle_st) {
1870 ✗ while (frame_queue_nb_remaining(&is->subpq) > 0) {
1871 ✗ sp = frame_queue_peek(&is->subpq);
1872
1873 ✗ if (frame_queue_nb_remaining(&is->subpq) > 1)
1874 ✗ sp2 = frame_queue_peek_next(&is->subpq);
1875 else
1876 ✗ sp2 = NULL;
1877
1878 ✗ if (sp->serial != is->subtitleq.serial
1879 ✗ || (is->vidclk.pts > (sp->pts + ((float) sp->sub.end_display_time / 1000)))
1880 ✗ || (sp2 && is->vidclk.pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000))))
1881 {
1882 ✗ if (sp->uploaded) {
1883 int i;
1884 ✗ for (i = 0; i < sp->sub.num_rects; i++) {
1885 ✗ AVSubtitleRect *sub_rect = sp->sub.rects[i];
1886 uint8_t *pixels;
1887 int pitch, j;
1888
1889 ✗ if (!SDL_LockTexture(is->sub_texture, (SDL_Rect *)sub_rect, (void **)&pixels, &pitch)) {
1890 ✗ for (j = 0; j < sub_rect->h; j++, pixels += pitch)
1891 ✗ memset(pixels, 0, sub_rect->w << 2);
1892 ✗ SDL_UnlockTexture(is->sub_texture);
1893 }
1894 }
1895 }
1896 ✗ frame_queue_next(&is->subpq);
1897 } else {
1898 break;
1899 }
1900 }
1901 }
1902
1903 ✗ frame_queue_next(&is->pictq);
1904 ✗ is->force_refresh = 1;
1905
1906 ✗ if (is->step && !is->paused)
1907 ✗ stream_toggle_pause(is);
1908 }
1909 ✗ display:
1910 /* display picture */
1911 ✗ if (!display_disable && is->force_refresh && is->show_mode == SHOW_MODE_VIDEO)
1912 ✗ video_display(is);
1913 }
1914 ✗ is->force_refresh = 0;
1915 ✗ if (show_status) {
1916 AVBPrint buf;
1917 static int64_t last_time;
1918 int64_t cur_time;
1919 int aqsize, vqsize, sqsize;
1920 double av_diff;
1921
1922 ✗ cur_time = av_gettime_relative();
1923 ✗ if (!last_time || (cur_time - last_time) >= 30000) {
1924 ✗ aqsize = 0;
1925 ✗ vqsize = 0;
1926 ✗ sqsize = 0;
1927 ✗ if (is->audio_st)
1928 ✗ aqsize = is->audioq.size;
1929 ✗ if (is->video_st)
1930 ✗ vqsize = is->videoq.size;
1931 ✗ if (is->subtitle_st)
1932 ✗ sqsize = is->subtitleq.size;
1933 ✗ av_diff = 0;
1934 ✗ if (is->audio_st && is->video_st)
1935 ✗ av_diff = get_clock(&is->audclk) - get_clock(&is->vidclk);
1936 ✗ else if (is->video_st)
1937 ✗ av_diff = get_master_clock(is) - get_clock(&is->vidclk);
1938 ✗ else if (is->audio_st)
1939 ✗ av_diff = get_master_clock(is) - get_clock(&is->audclk);
1940
1941 ✗ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
1942 ✗ av_bprintf(&buf,
1943 "%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB \r",
1944 get_master_clock(is),
1945 ✗ (is->audio_st && is->video_st) ? "A-V" : (is->video_st ? "M-V" : (is->audio_st ? "M-A" : " ")),
1946 av_diff,
1947 ✗ is->frame_drops_early + is->frame_drops_late,
1948 aqsize / 1024,
1949 vqsize / 1024,
1950 sqsize);
1951
1952 ✗ if (show_status == 1 && AV_LOG_INFO > av_log_get_level())
1953 ✗ fprintf(stderr, "%s", buf.str);
1954 else
1955 ✗ av_log(NULL, AV_LOG_INFO, "%s", buf.str);
1956
1957 ✗ fflush(stderr);
1958 ✗ av_bprint_finalize(&buf, NULL);
1959
1960 ✗ last_time = cur_time;
1961 }
1962 }
1963 ✗ }
1964
1965 ✗ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial)
1966 {
1967 Frame *vp;
1968
1969 #if defined(DEBUG_SYNC)
1970 printf("frame_type=%c pts=%0.3f\n",
1971 av_get_picture_type_char(src_frame->pict_type), pts);
1972 #endif
1973
1974 ✗ if (!(vp = frame_queue_peek_writable(&is->pictq)))
1975 ✗ return -1;
1976
1977 ✗ vp->sar = src_frame->sample_aspect_ratio;
1978 ✗ vp->uploaded = 0;
1979
1980 ✗ vp->width = src_frame->width;
1981 ✗ vp->height = src_frame->height;
1982 ✗ vp->format = src_frame->format;
1983
1984 ✗ vp->pts = pts;
1985 ✗ vp->duration = duration;
1986 ✗ vp->pos = pos;
1987 ✗ vp->serial = serial;
1988
1989 ✗ set_default_window_size(vp->width, vp->height, vp->sar);
1990
1991 ✗ av_frame_move_ref(vp->frame, src_frame);
1992 ✗ frame_queue_push(&is->pictq);
1993 ✗ return 0;
1994 }
1995
1996 ✗ static int get_video_frame(VideoState *is, AVFrame *frame)
1997 {
1998 int got_picture;
1999
2000 ✗ if ((got_picture = decoder_decode_frame(&is->viddec, frame, NULL)) < 0)
2001 ✗ return -1;
2002
2003 ✗ if (got_picture) {
2004 ✗ double dpts = NAN;
2005
2006 ✗ if (frame->pts != AV_NOPTS_VALUE)
2007 ✗ dpts = av_q2d(is->video_st->time_base) * frame->pts;
2008
2009 ✗ frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame);
2010
2011 ✗ if (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) {
2012 ✗ if (frame->pts != AV_NOPTS_VALUE) {
2013 ✗ double diff = dpts - get_master_clock(is);
2014 ✗ if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD &&
2015 ✗ diff - is->frame_last_filter_delay < 0 &&
2016 ✗ is->viddec.pkt_serial == is->vidclk.serial &&
2017 ✗ is->videoq.nb_packets) {
2018 ✗ is->frame_drops_early++;
2019 ✗ av_frame_unref(frame);
2020 ✗ got_picture = 0;
2021 }
2022 }
2023 }
2024 }
2025
2026 ✗ return got_picture;
2027 }
2028
2029 ✗ static int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph,
2030 AVFilterContext *source_ctx, AVFilterContext *sink_ctx)
2031 {
2032 int ret, i;
2033 ✗ int nb_filters = graph->nb_filters;
2034 ✗ AVFilterInOut *outputs = NULL, *inputs = NULL;
2035
2036 ✗ if (filtergraph) {
2037 ✗ outputs = avfilter_inout_alloc();
2038 ✗ inputs = avfilter_inout_alloc();
2039 ✗ if (!outputs || !inputs) {
2040 ✗ ret = AVERROR(ENOMEM);
2041 ✗ goto fail;
2042 }
2043
2044 ✗ outputs->name = av_strdup("in");
2045 ✗ outputs->filter_ctx = source_ctx;
2046 ✗ outputs->pad_idx = 0;
2047 ✗ outputs->next = NULL;
2048
2049 ✗ inputs->name = av_strdup("out");
2050 ✗ inputs->filter_ctx = sink_ctx;
2051 ✗ inputs->pad_idx = 0;
2052 ✗ inputs->next = NULL;
2053
2054 ✗ if ((ret = avfilter_graph_parse_ptr(graph, filtergraph, &inputs, &outputs, NULL)) < 0)
2055 ✗ goto fail;
2056 } else {
2057 ✗ if ((ret = avfilter_link(source_ctx, 0, sink_ctx, 0)) < 0)
2058 ✗ goto fail;
2059 }
2060
2061 /* Reorder the filters to ensure that inputs of the custom filters are merged first */
2062 ✗ for (i = 0; i < graph->nb_filters - nb_filters; i++)
2063 ✗ FFSWAP(AVFilterContext*, graph->filters[i], graph->filters[i + nb_filters]);
2064
2065 ✗ ret = avfilter_graph_config(graph, NULL);
2066 ✗ fail:
2067 ✗ avfilter_inout_free(&outputs);
2068 ✗ avfilter_inout_free(&inputs);
2069 ✗ return ret;
2070 }
2071
2072 ✗ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters, AVFrame *frame)
2073 {
2074 enum AVPixelFormat pix_fmts[FF_ARRAY_ELEMS(sdl_texture_format_map)];
2075 ✗ char sws_flags_str[512] = "";
2076 int ret;
2077 ✗ AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter = NULL;
2078 ✗ AVCodecParameters *codecpar = is->video_st->codecpar;
2079 ✗ AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL);
2080 ✗ const AVDictionaryEntry *e = NULL;
2081 ✗ int nb_pix_fmts = 0;
2082 int i, j;
2083 ✗ AVBufferSrcParameters *par = av_buffersrc_parameters_alloc();
2084
2085 ✗ if (!par)
2086 ✗ return AVERROR(ENOMEM);
2087
2088 ✗ for (i = 0; i < renderer_info.num_texture_formats; i++) {
2089 ✗ for (j = 0; j < FF_ARRAY_ELEMS(sdl_texture_format_map); j++) {
2090 ✗ if (renderer_info.texture_formats[i] == sdl_texture_format_map[j].texture_fmt) {
2091 ✗ pix_fmts[nb_pix_fmts++] = sdl_texture_format_map[j].format;
2092 ✗ break;
2093 }
2094 }
2095 }
2096
2097 ✗ while ((e = av_dict_iterate(sws_dict, e))) {
2098 ✗ if (!strcmp(e->key, "sws_flags")) {
2099 ✗ av_strlcatf(sws_flags_str, sizeof(sws_flags_str), "%s=%s:", "flags", e->value);
2100 } else
2101 ✗ av_strlcatf(sws_flags_str, sizeof(sws_flags_str), "%s=%s:", e->key, e->value);
2102 }
2103 ✗ if (strlen(sws_flags_str))
2104 ✗ sws_flags_str[strlen(sws_flags_str)-1] = '\0';
2105
2106 ✗ graph->scale_sws_opts = av_strdup(sws_flags_str);
2107
2108
2109 ✗ filt_src = avfilter_graph_alloc_filter(graph, avfilter_get_by_name("buffer"),
2110 "ffplay_buffer");
2111 ✗ if (!filt_src) {
2112 ✗ ret = AVERROR(ENOMEM);
2113 ✗ goto fail;
2114 }
2115
2116 ✗ par->format = frame->format;
2117 ✗ par->time_base = is->video_st->time_base;
2118 ✗ par->width = frame->width;
2119 ✗ par->height = frame->height;
2120 ✗ par->sample_aspect_ratio = codecpar->sample_aspect_ratio;
2121 ✗ par->color_space = frame->colorspace;
2122 ✗ par->color_range = frame->color_range;
2123 ✗ par->alpha_mode = frame->alpha_mode;
2124 ✗ par->frame_rate = fr;
2125 ✗ par->hw_frames_ctx = frame->hw_frames_ctx;
2126 ✗ ret = av_buffersrc_parameters_set(filt_src, par);
2127 ✗ if (ret < 0)
2128 ✗ goto fail;
2129
2130 ✗ ret = avfilter_init_dict(filt_src, NULL);
2131 ✗ if (ret < 0)
2132 ✗ goto fail;
2133
2134 ✗ filt_out = avfilter_graph_alloc_filter(graph, avfilter_get_by_name("buffersink"),
2135 "ffplay_buffersink");
2136 ✗ if (!filt_out) {
2137 ✗ ret = AVERROR(ENOMEM);
2138 ✗ goto fail;
2139 }
2140
2141 ✗ if ((ret = av_opt_set_array(filt_out, "pixel_formats", AV_OPT_SEARCH_CHILDREN,
2142 0, nb_pix_fmts, AV_OPT_TYPE_PIXEL_FMT, pix_fmts)) < 0)
2143 ✗ goto fail;
2144 ✗ if (!vk_renderer &&
2145 ✗ (ret = av_opt_set_array(filt_out, "colorspaces", AV_OPT_SEARCH_CHILDREN,
2146 0, FF_ARRAY_ELEMS(sdl_supported_color_spaces),
2147 AV_OPT_TYPE_INT, sdl_supported_color_spaces)) < 0)
2148 ✗ goto fail;
2149
2150 ✗ if ((ret = av_opt_set_array(filt_out, "alphamodes", AV_OPT_SEARCH_CHILDREN,
2151 0, FF_ARRAY_ELEMS(sdl_supported_alpha_modes),
2152 AV_OPT_TYPE_INT, sdl_supported_alpha_modes)) < 0)
2153 ✗ goto fail;
2154
2155 ✗ ret = avfilter_init_dict(filt_out, NULL);
2156 ✗ if (ret < 0)
2157 ✗ goto fail;
2158
2159 ✗ last_filter = filt_out;
2160
2161 /* Note: this macro adds a filter before the lastly added filter, so the
2162 * processing order of the filters is in reverse */
2163 #define INSERT_FILT(name, arg) do { \
2164 AVFilterContext *filt_ctx; \
2165 \
2166 ret = avfilter_graph_create_filter(&filt_ctx, \
2167 avfilter_get_by_name(name), \
2168 "ffplay_" name, arg, NULL, graph); \
2169 if (ret < 0) \
2170 goto fail; \
2171 \
2172 ret = avfilter_link(filt_ctx, 0, last_filter, 0); \
2173 if (ret < 0) \
2174 goto fail; \
2175 \
2176 last_filter = filt_ctx; \
2177 } while (0)
2178
2179 ✗ if (autorotate) {
2180 ✗ double theta = 0.0;
2181 ✗ int32_t *displaymatrix = NULL;
2182 ✗ AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX);
2183 ✗ if (sd)
2184 ✗ displaymatrix = (int32_t *)sd->data;
2185 ✗ if (!displaymatrix) {
2186 ✗ const AVPacketSideData *psd = av_packet_side_data_get(is->video_st->codecpar->coded_side_data,
2187 ✗ is->video_st->codecpar->nb_coded_side_data,
2188 AV_PKT_DATA_DISPLAYMATRIX);
2189 ✗ if (psd)
2190 ✗ displaymatrix = (int32_t *)psd->data;
2191 }
2192 ✗ theta = get_rotation(displaymatrix);
2193
2194 ✗ if (fabs(theta - 90) < 1.0) {
2195 ✗ INSERT_FILT("transpose", displaymatrix[3] > 0 ? "cclock_flip" : "clock");
2196 ✗ } else if (fabs(theta - 180) < 1.0) {
2197 ✗ if (displaymatrix[0] < 0)
2198 ✗ INSERT_FILT("hflip", NULL);
2199 ✗ if (displaymatrix[4] < 0)
2200 ✗ INSERT_FILT("vflip", NULL);
2201 ✗ } else if (fabs(theta - 270) < 1.0) {
2202 ✗ INSERT_FILT("transpose", displaymatrix[3] < 0 ? "clock_flip" : "cclock");
2203 ✗ } else if (fabs(theta) > 1.0) {
2204 char rotate_buf[64];
2205 ✗ snprintf(rotate_buf, sizeof(rotate_buf), "%f*PI/180", theta);
2206 ✗ INSERT_FILT("rotate", rotate_buf);
2207 } else {
2208 ✗ if (displaymatrix && displaymatrix[4] < 0)
2209 ✗ INSERT_FILT("vflip", NULL);
2210 }
2211 }
2212
2213 ✗ if ((ret = configure_filtergraph(graph, vfilters, filt_src, last_filter)) < 0)
2214 ✗ goto fail;
2215
2216 ✗ is->in_video_filter = filt_src;
2217 ✗ is->out_video_filter = filt_out;
2218
2219 ✗ fail:
2220 ✗ av_freep(&par);
2221 ✗ return ret;
2222 }
2223
2224 ✗ static int configure_audio_filters(VideoState *is, const char *afilters, int force_output_format)
2225 {
2226 ✗ AVFilterContext *filt_asrc = NULL, *filt_asink = NULL;
2227 ✗ char aresample_swr_opts[512] = "";
2228 ✗ const AVDictionaryEntry *e = NULL;
2229 AVBPrint bp;
2230 char asrc_args[256];
2231 int ret;
2232
2233 ✗ avfilter_graph_free(&is->agraph);
2234 ✗ if (!(is->agraph = avfilter_graph_alloc()))
2235 ✗ return AVERROR(ENOMEM);
2236 ✗ is->agraph->nb_threads = filter_nbthreads;
2237
2238 ✗ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
2239
2240 ✗ while ((e = av_dict_iterate(swr_opts, e)))
2241 ✗ av_strlcatf(aresample_swr_opts, sizeof(aresample_swr_opts), "%s=%s:", e->key, e->value);
2242 ✗ if (strlen(aresample_swr_opts))
2243 ✗ aresample_swr_opts[strlen(aresample_swr_opts)-1] = '\0';
2244 ✗ av_opt_set(is->agraph, "aresample_swr_opts", aresample_swr_opts, 0);
2245
2246 ✗ av_channel_layout_describe_bprint(&is->audio_filter_src.ch_layout, &bp);
2247
2248 ✗ ret = snprintf(asrc_args, sizeof(asrc_args),
2249 "sample_rate=%d:sample_fmt=%s:time_base=%d/%d:channel_layout=%s",
2250 is->audio_filter_src.freq, av_get_sample_fmt_name(is->audio_filter_src.fmt),
2251 1, is->audio_filter_src.freq, bp.str);
2252
2253 ✗ ret = avfilter_graph_create_filter(&filt_asrc,
2254 avfilter_get_by_name("abuffer"), "ffplay_abuffer",
2255 asrc_args, NULL, is->agraph);
2256 ✗ if (ret < 0)
2257 ✗ goto end;
2258
2259 ✗ filt_asink = avfilter_graph_alloc_filter(is->agraph, avfilter_get_by_name("abuffersink"),
2260 "ffplay_abuffersink");
2261 ✗ if (!filt_asink) {
2262 ✗ ret = AVERROR(ENOMEM);
2263 ✗ goto end;
2264 }
2265
2266 ✗ if ((ret = av_opt_set(filt_asink, "sample_formats", "s16", AV_OPT_SEARCH_CHILDREN)) < 0)
2267 ✗ goto end;
2268
2269 ✗ if (force_output_format) {
2270 ✗ if ((ret = av_opt_set_array(filt_asink, "channel_layouts", AV_OPT_SEARCH_CHILDREN,
2271 ✗ 0, 1, AV_OPT_TYPE_CHLAYOUT, &is->audio_tgt.ch_layout)) < 0)
2272 ✗ goto end;
2273 ✗ if ((ret = av_opt_set_array(filt_asink, "samplerates", AV_OPT_SEARCH_CHILDREN,
2274 ✗ 0, 1, AV_OPT_TYPE_INT, &is->audio_tgt.freq)) < 0)
2275 ✗ goto end;
2276 }
2277
2278 ✗ ret = avfilter_init_dict(filt_asink, NULL);
2279 ✗ if (ret < 0)
2280 ✗ goto end;
2281
2282 ✗ if ((ret = configure_filtergraph(is->agraph, afilters, filt_asrc, filt_asink)) < 0)
2283 ✗ goto end;
2284
2285 ✗ is->in_audio_filter = filt_asrc;
2286 ✗ is->out_audio_filter = filt_asink;
2287
2288 ✗ end:
2289 ✗ if (ret < 0)
2290 ✗ avfilter_graph_free(&is->agraph);
2291 ✗ av_bprint_finalize(&bp, NULL);
2292
2293 ✗ return ret;
2294 }
2295
2296 ✗ static int audio_thread(void *arg)
2297 {
2298 ✗ VideoState *is = arg;
2299 ✗ AVFrame *frame = av_frame_alloc();
2300 Frame *af;
2301 ✗ int last_serial = -1;
2302 int reconfigure;
2303 ✗ int got_frame = 0;
2304 AVRational tb;
2305 ✗ int ret = 0;
2306
2307 ✗ if (!frame)
2308 ✗ return AVERROR(ENOMEM);
2309
2310 do {
2311 ✗ if ((got_frame = decoder_decode_frame(&is->auddec, frame, NULL)) < 0)
2312 ✗ goto the_end;
2313
2314 ✗ if (got_frame) {
2315 ✗ tb = (AVRational){1, frame->sample_rate};
2316
2317 ✗ reconfigure =
2318 ✗ cmp_audio_fmts(is->audio_filter_src.fmt, is->audio_filter_src.ch_layout.nb_channels,
2319 ✗ frame->format, frame->ch_layout.nb_channels) ||
2320 ✗ av_channel_layout_compare(&is->audio_filter_src.ch_layout, &frame->ch_layout) ||
2321 ✗ is->audio_filter_src.freq != frame->sample_rate ||
2322 ✗ is->auddec.pkt_serial != last_serial;
2323
2324 ✗ if (reconfigure) {
2325 char buf1[1024], buf2[1024];
2326 ✗ av_channel_layout_describe(&is->audio_filter_src.ch_layout, buf1, sizeof(buf1));
2327 ✗ av_channel_layout_describe(&frame->ch_layout, buf2, sizeof(buf2));
2328 ✗ av_log(NULL, AV_LOG_DEBUG,
2329 "Audio frame changed from rate:%d ch:%d fmt:%s layout:%s serial:%d to rate:%d ch:%d fmt:%s layout:%s serial:%d\n",
2330 is->audio_filter_src.freq, is->audio_filter_src.ch_layout.nb_channels, av_get_sample_fmt_name(is->audio_filter_src.fmt), buf1, last_serial,
2331 ✗ frame->sample_rate, frame->ch_layout.nb_channels, av_get_sample_fmt_name(frame->format), buf2, is->auddec.pkt_serial);
2332
2333 ✗ is->audio_filter_src.fmt = frame->format;
2334 ✗ ret = av_channel_layout_copy(&is->audio_filter_src.ch_layout, &frame->ch_layout);
2335 ✗ if (ret < 0)
2336 ✗ goto the_end;
2337 ✗ is->audio_filter_src.freq = frame->sample_rate;
2338 ✗ last_serial = is->auddec.pkt_serial;
2339
2340 ✗ if ((ret = configure_audio_filters(is, afilters, 1)) < 0)
2341 ✗ goto the_end;
2342 }
2343
2344 ✗ if ((ret = av_buffersrc_add_frame(is->in_audio_filter, frame)) < 0)
2345 ✗ goto the_end;
2346
2347 ✗ while ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, frame, 0)) >= 0) {
2348 ✗ FrameData *fd = frame->opaque_ref ? (FrameData*)frame->opaque_ref->data : NULL;
2349 ✗ tb = av_buffersink_get_time_base(is->out_audio_filter);
2350 ✗ if (!(af = frame_queue_peek_writable(&is->sampq)))
2351 ✗ goto the_end;
2352
2353 ✗ af->pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);
2354 ✗ af->pos = fd ? fd->pkt_pos : -1;
2355 ✗ af->serial = is->auddec.pkt_serial;
2356 ✗ af->duration = av_q2d((AVRational){frame->nb_samples, frame->sample_rate});
2357
2358 ✗ av_frame_move_ref(af->frame, frame);
2359 ✗ frame_queue_push(&is->sampq);
2360
2361 ✗ if (is->audioq.serial != is->auddec.pkt_serial)
2362 ✗ break;
2363 }
2364 ✗ if (ret == AVERROR_EOF)
2365 ✗ is->auddec.finished = is->auddec.pkt_serial;
2366 }
2367 ✗ } while (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF);
2368 ✗ the_end:
2369 ✗ avfilter_graph_free(&is->agraph);
2370 ✗ av_frame_free(&frame);
2371 ✗ return ret;
2372 }
2373
2374 ✗ static int decoder_start(Decoder *d, int (*fn)(void *), const char *thread_name, void* arg)
2375 {
2376 ✗ d->decoder_tid = SDL_CreateThread(fn, thread_name, arg);
2377 ✗ if (!d->decoder_tid) {
2378 ✗ av_log(NULL, AV_LOG_ERROR, "SDL_CreateThread(): %s\n", SDL_GetError());
2379 ✗ return AVERROR(ENOMEM);
2380 }
2381 ✗ return 0;
2382 }
2383
2384 /* pushes the event for the event loop, marked with the stream it comes from */
2385 ✗ static void push_stream_event(VideoState *is, Uint32 type)
2386 {
2387 ✗ SDL_Event event = { .user = { .type = type, .code = is->id } };
2388
2389 ✗ if (SDL_PushEvent(&event) < 0)
2390 ✗ av_log(NULL, AV_LOG_ERROR, "Could not push the event of '%s': %s\n", is->filename, SDL_GetError());
2391 ✗ }
2392
2393 ✗ static int video_thread(void *arg)
2394 {
2395 ✗ VideoState *is = arg;
2396 ✗ AVFrame *frame = av_frame_alloc();
2397 double pts;
2398 double duration;
2399 ✗ int ret, announced = 0;
2400 ✗ AVRational tb = is->video_st->time_base;
2401 ✗ AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL);
2402
2403 ✗ AVFilterGraph *graph = NULL;
2404 ✗ AVFilterContext *filt_out = NULL, *filt_in = NULL;
2405 ✗ int last_w = 0;
2406 ✗ int last_h = 0;
2407 ✗ enum AVPixelFormat last_format = -2;
2408 ✗ int last_serial = -1;
2409 ✗ int last_vfilter_idx = 0;
2410
2411 ✗ if (!frame)
2412 ✗ return AVERROR(ENOMEM);
2413
2414 for (;;) {
2415 ✗ ret = get_video_frame(is, frame);
2416 ✗ if (ret < 0)
2417 ✗ goto the_end;
2418 ✗ if (!ret) {
2419 ✗ if (is->viddec.finished == is->viddec.pkt_serial && !announced) {
2420 ✗ push_stream_event(is, FF_READY_EVENT);
2421 ✗ announced = 1;
2422 }
2423 ✗ continue;
2424 }
2425
2426 ✗ if ( last_w != frame->width
2427 ✗ || last_h != frame->height
2428 ✗ || last_format != frame->format
2429 ✗ || last_serial != is->viddec.pkt_serial
2430 ✗ || last_vfilter_idx != is->vfilter_idx) {
2431 ✗ av_log(NULL, AV_LOG_DEBUG,
2432 "Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\n",
2433 last_w, last_h,
2434 ✗ (const char *)av_x_if_null(av_get_pix_fmt_name(last_format), "none"), last_serial,
2435 ✗ frame->width, frame->height,
2436 ✗ (const char *)av_x_if_null(av_get_pix_fmt_name(frame->format), "none"), is->viddec.pkt_serial);
2437 ✗ avfilter_graph_free(&graph);
2438 ✗ graph = avfilter_graph_alloc();
2439 ✗ if (!graph) {
2440 ✗ ret = AVERROR(ENOMEM);
2441 ✗ goto the_end;
2442 }
2443 ✗ graph->nb_threads = filter_nbthreads;
2444 ✗ if ((ret = configure_video_filters(graph, is, vfilters_list ? vfilters_list[is->vfilter_idx] : NULL, frame)) < 0) {
2445 ✗ push_stream_event(is, FF_QUIT_EVENT);
2446 ✗ goto the_end;
2447 }
2448 ✗ filt_in = is->in_video_filter;
2449 ✗ filt_out = is->out_video_filter;
2450 ✗ last_w = frame->width;
2451 ✗ last_h = frame->height;
2452 ✗ last_format = frame->format;
2453 ✗ last_serial = is->viddec.pkt_serial;
2454 ✗ last_vfilter_idx = is->vfilter_idx;
2455 ✗ frame_rate = av_buffersink_get_frame_rate(filt_out);
2456 }
2457
2458 ✗ ret = av_buffersrc_add_frame(filt_in, frame);
2459 ✗ if (ret < 0)
2460 ✗ goto the_end;
2461
2462 ✗ while (ret >= 0) {
2463 FrameData *fd;
2464
2465 ✗ is->frame_last_returned_time = av_gettime_relative() / 1000000.0;
2466
2467 ✗ ret = av_buffersink_get_frame_flags(filt_out, frame, 0);
2468 ✗ if (ret < 0) {
2469 ✗ if (ret == AVERROR_EOF)
2470 ✗ is->viddec.finished = is->viddec.pkt_serial;
2471 ✗ ret = 0;
2472 ✗ break;
2473 }
2474
2475 ✗ fd = frame->opaque_ref ? (FrameData*)frame->opaque_ref->data : NULL;
2476
2477 ✗ is->frame_last_filter_delay = av_gettime_relative() / 1000000.0 - is->frame_last_returned_time;
2478 ✗ if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
2479 ✗ is->frame_last_filter_delay = 0;
2480 ✗ tb = av_buffersink_get_time_base(filt_out);
2481 ✗ duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0);
2482 ✗ pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);
2483 ✗ ret = queue_picture(is, frame, pts, duration, fd ? fd->pkt_pos : -1, is->viddec.pkt_serial);
2484 ✗ av_frame_unref(frame);
2485 ✗ if (ret >= 0 && !announced) {
2486 ✗ push_stream_event(is, FF_READY_EVENT);
2487 ✗ announced = 1;
2488 }
2489 ✗ if (is->videoq.serial != is->viddec.pkt_serial)
2490 ✗ break;
2491 }
2492
2493 ✗ if (ret < 0)
2494 ✗ goto the_end;
2495 }
2496 ✗ the_end:
2497 ✗ if (!announced && SDL_AtomicGet(&is->replacement))
2498 ✗ push_stream_event(is, FF_QUIT_EVENT);
2499 ✗ avfilter_graph_free(&graph);
2500 ✗ av_frame_free(&frame);
2501 ✗ return 0;
2502 }
2503
2504 ✗ static int subtitle_thread(void *arg)
2505 {
2506 ✗ VideoState *is = arg;
2507 Frame *sp;
2508 int got_subtitle;
2509 double pts;
2510
2511 for (;;) {
2512 ✗ if (!(sp = frame_queue_peek_writable(&is->subpq)))
2513 ✗ return 0;
2514
2515 ✗ if ((got_subtitle = decoder_decode_frame(&is->subdec, NULL, &sp->sub)) < 0)
2516 ✗ break;
2517
2518 ✗ pts = 0;
2519
2520 ✗ if (got_subtitle && sp->sub.format == 0) {
2521 ✗ if (sp->sub.pts != AV_NOPTS_VALUE)
2522 ✗ pts = sp->sub.pts / (double)AV_TIME_BASE;
2523 ✗ sp->pts = pts;
2524 ✗ sp->serial = is->subdec.pkt_serial;
2525 ✗ sp->width = is->subdec.avctx->width;
2526 ✗ sp->height = is->subdec.avctx->height;
2527 ✗ sp->uploaded = 0;
2528
2529 /* now we can update the picture count */
2530 ✗ frame_queue_push(&is->subpq);
2531 ✗ } else if (got_subtitle) {
2532 ✗ avsubtitle_free(&sp->sub);
2533 }
2534 }
2535 ✗ return 0;
2536 }
2537
2538 /* copy samples for viewing in editor window */
2539 ✗ static void update_sample_display(VideoState *is, short *samples, int samples_size)
2540 {
2541 int size, len;
2542
2543 ✗ size = samples_size / sizeof(short);
2544 ✗ while (size > 0) {
2545 ✗ len = SAMPLE_ARRAY_SIZE - is->sample_array_index;
2546 ✗ if (len > size)
2547 ✗ len = size;
2548 ✗ memcpy(is->sample_array + is->sample_array_index, samples, len * sizeof(short));
2549 ✗ samples += len;
2550 ✗ is->sample_array_index += len;
2551 ✗ if (is->sample_array_index >= SAMPLE_ARRAY_SIZE)
2552 ✗ is->sample_array_index = 0;
2553 ✗ size -= len;
2554 }
2555 ✗ }
2556
2557 /* return the wanted number of samples to get better sync if sync_type is video
2558 * or external master clock */
2559 ✗ static int synchronize_audio(VideoState *is, int nb_samples)
2560 {
2561 ✗ int wanted_nb_samples = nb_samples;
2562
2563 /* if not master, then we try to remove or add samples to correct the clock */
2564 ✗ if (get_master_sync_type(is) != AV_SYNC_AUDIO_MASTER) {
2565 double diff, avg_diff;
2566 int min_nb_samples, max_nb_samples;
2567
2568 ✗ diff = get_clock(&is->audclk) - get_master_clock(is);
2569
2570 ✗ if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) {
2571 ✗ is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum;
2572 ✗ if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) {
2573 /* not enough measures to have a correct estimate */
2574 ✗ is->audio_diff_avg_count++;
2575 } else {
2576 /* estimate the A-V difference */
2577 ✗ avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);
2578
2579 ✗ if (fabs(avg_diff) >= is->audio_diff_threshold) {
2580 ✗ wanted_nb_samples = nb_samples + (int)(diff * is->audio_src.freq);
2581 ✗ min_nb_samples = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100));
2582 ✗ max_nb_samples = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100));
2583 ✗ wanted_nb_samples = av_clip(wanted_nb_samples, min_nb_samples, max_nb_samples);
2584 }
2585 ✗ av_log(NULL, AV_LOG_TRACE, "diff=%f adiff=%f sample_diff=%d apts=%0.3f %f\n",
2586 diff, avg_diff, wanted_nb_samples - nb_samples,
2587 is->audio_clock, is->audio_diff_threshold);
2588 }
2589 } else {
2590 /* too big difference : may be initial PTS errors, so
2591 reset A-V filter */
2592 ✗ is->audio_diff_avg_count = 0;
2593 ✗ is->audio_diff_cum = 0;
2594 }
2595 }
2596
2597 ✗ return wanted_nb_samples;
2598 }
2599
2600 /**
2601 * Decode one audio frame and return its uncompressed size.
2602 *
2603 * The processed audio frame is decoded, converted if required, and
2604 * stored in is->audio_buf, with size in bytes given by the return
2605 * value.
2606 */
2607 ✗ static int audio_decode_frame(VideoState *is)
2608 {
2609 int data_size, resampled_data_size;
2610 av_unused double audio_clock0;
2611 int wanted_nb_samples;
2612 Frame *af;
2613
2614 ✗ if (is->paused)
2615 ✗ return -1;
2616
2617 do {
2618 #if defined(_WIN32)
2619 while (frame_queue_nb_remaining(&is->sampq) == 0) {
2620 if ((av_gettime_relative() - is->audio_callback_time) > 1000000LL * is->audio_hw_buf_size / is->audio_tgt.bytes_per_sec / 2)
2621 return -1;
2622 av_usleep (1000);
2623 }
2624 #endif
2625 ✗ if (!(af = frame_queue_peek_readable(&is->sampq)))
2626 ✗ return -1;
2627 ✗ frame_queue_next(&is->sampq);
2628 ✗ } while (af->serial != is->audioq.serial);
2629
2630 ✗ data_size = av_samples_get_buffer_size(NULL, af->frame->ch_layout.nb_channels,
2631 ✗ af->frame->nb_samples,
2632 ✗ af->frame->format, 1);
2633
2634 ✗ wanted_nb_samples = synchronize_audio(is, af->frame->nb_samples);
2635
2636 ✗ if (af->frame->format != is->audio_src.fmt ||
2637 ✗ av_channel_layout_compare(&af->frame->ch_layout, &is->audio_src.ch_layout) ||
2638 ✗ af->frame->sample_rate != is->audio_src.freq ||
2639 ✗ (wanted_nb_samples != af->frame->nb_samples && !is->swr_ctx)) {
2640 int ret;
2641 ✗ swr_free(&is->swr_ctx);
2642 ✗ ret = swr_alloc_set_opts2(&is->swr_ctx,
2643 ✗ &is->audio_tgt.ch_layout, is->audio_tgt.fmt, is->audio_tgt.freq,
2644 ✗ &af->frame->ch_layout, af->frame->format, af->frame->sample_rate,
2645 0, NULL);
2646 ✗ if (ret < 0 || swr_init(is->swr_ctx) < 0) {
2647 ✗ av_log(NULL, AV_LOG_ERROR,
2648 "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
2649 ✗ af->frame->sample_rate, av_get_sample_fmt_name(af->frame->format), af->frame->ch_layout.nb_channels,
2650 is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.ch_layout.nb_channels);
2651 ✗ swr_free(&is->swr_ctx);
2652 ✗ return -1;
2653 }
2654 ✗ if (av_channel_layout_copy(&is->audio_src.ch_layout, &af->frame->ch_layout) < 0)
2655 ✗ return -1;
2656 ✗ is->audio_src.freq = af->frame->sample_rate;
2657 ✗ is->audio_src.fmt = af->frame->format;
2658 }
2659
2660 ✗ if (is->swr_ctx) {
2661 ✗ const uint8_t **in = (const uint8_t **)af->frame->extended_data;
2662 ✗ uint8_t **out = &is->audio_buf1;
2663 ✗ int out_count = (int64_t)wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate + 256;
2664 ✗ int out_size = av_samples_get_buffer_size(NULL, is->audio_tgt.ch_layout.nb_channels, out_count, is->audio_tgt.fmt, 0);
2665 int len2;
2666 ✗ if (out_size < 0) {
2667 ✗ av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size() failed\n");
2668 ✗ return -1;
2669 }
2670 ✗ if (wanted_nb_samples != af->frame->nb_samples) {
2671 ✗ if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - af->frame->nb_samples) * is->audio_tgt.freq / af->frame->sample_rate,
2672 ✗ wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate) < 0) {
2673 ✗ av_log(NULL, AV_LOG_ERROR, "swr_set_compensation() failed\n");
2674 ✗ return -1;
2675 }
2676 }
2677 ✗ av_fast_malloc(&is->audio_buf1, &is->audio_buf1_size, out_size);
2678 ✗ if (!is->audio_buf1)
2679 ✗ return AVERROR(ENOMEM);
2680 ✗ len2 = swr_convert(is->swr_ctx, out, out_count, in, af->frame->nb_samples);
2681 ✗ if (len2 < 0) {
2682 ✗ av_log(NULL, AV_LOG_ERROR, "swr_convert() failed\n");
2683 ✗ return -1;
2684 }
2685 ✗ if (len2 == out_count) {
2686 ✗ av_log(NULL, AV_LOG_WARNING, "audio buffer is probably too small\n");
2687 ✗ if (swr_init(is->swr_ctx) < 0)
2688 ✗ swr_free(&is->swr_ctx);
2689 }
2690 ✗ is->audio_buf = is->audio_buf1;
2691 ✗ resampled_data_size = len2 * is->audio_tgt.ch_layout.nb_channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
2692 } else {
2693 ✗ is->audio_buf = af->frame->data[0];
2694 ✗ resampled_data_size = data_size;
2695 }
2696
2697 ✗ audio_clock0 = is->audio_clock;
2698 /* update the audio clock with the pts */
2699 ✗ if (!isnan(af->pts))
2700 ✗ is->audio_clock = af->pts + (double) af->frame->nb_samples / af->frame->sample_rate;
2701 else
2702 ✗ is->audio_clock = NAN;
2703 ✗ is->audio_clock_serial = af->serial;
2704 #ifdef DEBUG
2705 {
2706 static double last_clock;
2707 printf("audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n",
2708 is->audio_clock - last_clock,
2709 is->audio_clock, audio_clock0);
2710 last_clock = is->audio_clock;
2711 }
2712 #endif
2713 ✗ return resampled_data_size;
2714 }
2715
2716 /* prepare a new audio buffer */
2717 ✗ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
2718 {
2719 ✗ VideoState *is = opaque;
2720 int audio_size, len1;
2721
2722 ✗ is->audio_callback_time = av_gettime_relative();
2723
2724 ✗ while (len > 0) {
2725 ✗ if (is->audio_buf_index >= is->audio_buf_size) {
2726 ✗ audio_size = audio_decode_frame(is);
2727 ✗ if (audio_size < 0) {
2728 /* if error, just output silence */
2729 ✗ is->audio_buf = NULL;
2730 ✗ is->audio_buf_size = SDL_AUDIO_MIN_BUFFER_SIZE / is->audio_tgt.frame_size * is->audio_tgt.frame_size;
2731 } else {
2732 ✗ if (is->show_mode != SHOW_MODE_VIDEO)
2733 ✗ update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
2734 ✗ is->audio_buf_size = audio_size;
2735 }
2736 ✗ is->audio_buf_index = 0;
2737 }
2738 ✗ len1 = is->audio_buf_size - is->audio_buf_index;
2739 ✗ if (len1 > len)
2740 ✗ len1 = len;
2741 ✗ if (!is->muted && is->audio_buf && is->audio_volume == SDL_MIX_MAXVOLUME)
2742 ✗ memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
2743 else {
2744 ✗ memset(stream, 0, len1);
2745 ✗ if (!is->muted && is->audio_buf)
2746 ✗ SDL_MixAudioFormat(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, AUDIO_S16SYS, len1, is->audio_volume);
2747 }
2748 ✗ len -= len1;
2749 ✗ stream += len1;
2750 ✗ is->audio_buf_index += len1;
2751 }
2752 ✗ is->audio_write_buf_size = is->audio_buf_size - is->audio_buf_index;
2753 /* Let's assume the audio driver that is used by SDL has two periods. */
2754 ✗ if (!isnan(is->audio_clock)) {
2755 ✗ set_clock_at(&is->audclk, is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / is->audio_tgt.bytes_per_sec, is->audio_clock_serial, is->audio_callback_time / 1000000.0);
2756 ✗ sync_clock_to_slave(&is->extclk, &is->audclk);
2757 }
2758 ✗ }
2759
2760 ✗ static int audio_open(VideoState *is, AVChannelLayout *wanted_channel_layout, int wanted_sample_rate, struct AudioParams *audio_hw_params)
2761 {
2762 SDL_AudioSpec wanted_spec, spec;
2763 const char *env;
2764 static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};
2765 static const int next_sample_rates[] = {0, 44100, 48000, 96000, 192000};
2766 ✗ int next_sample_rate_idx = FF_ARRAY_ELEMS(next_sample_rates) - 1;
2767 ✗ int wanted_nb_channels = wanted_channel_layout->nb_channels;
2768
2769 ✗ env = SDL_getenv("SDL_AUDIO_CHANNELS");
2770 ✗ if (env) {
2771 ✗ wanted_nb_channels = atoi(env);
2772 ✗ av_channel_layout_uninit(wanted_channel_layout);
2773 ✗ av_channel_layout_default(wanted_channel_layout, wanted_nb_channels);
2774 }
2775 ✗ if (wanted_channel_layout->order != AV_CHANNEL_ORDER_NATIVE) {
2776 ✗ av_channel_layout_uninit(wanted_channel_layout);
2777 ✗ av_channel_layout_default(wanted_channel_layout, wanted_nb_channels);
2778 }
2779 ✗ wanted_nb_channels = wanted_channel_layout->nb_channels;
2780 ✗ wanted_spec.channels = wanted_nb_channels;
2781 ✗ wanted_spec.freq = wanted_sample_rate;
2782 ✗ if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
2783 ✗ av_log(NULL, AV_LOG_ERROR, "Invalid sample rate or channel count!\n");
2784 ✗ return -1;
2785 }
2786 ✗ while (next_sample_rate_idx && next_sample_rates[next_sample_rate_idx] >= wanted_spec.freq)
2787 ✗ next_sample_rate_idx--;
2788 ✗ wanted_spec.format = AUDIO_S16SYS;
2789 ✗ wanted_spec.silence = 0;
2790 ✗ wanted_spec.samples = FFMAX(SDL_AUDIO_MIN_BUFFER_SIZE, 2 << av_log2(wanted_spec.freq / SDL_AUDIO_MAX_CALLBACKS_PER_SEC));
2791 ✗ wanted_spec.callback = sdl_audio_callback;
2792 ✗ wanted_spec.userdata = is;
2793 ✗ while (!(is->audio_dev = SDL_OpenAudioDevice(NULL, 0, &wanted_spec, &spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE))) {
2794 ✗ av_log(NULL, AV_LOG_WARNING, "SDL_OpenAudio (%d channels, %d Hz): %s\n",
2795 ✗ wanted_spec.channels, wanted_spec.freq, SDL_GetError());
2796 ✗ wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];
2797 ✗ if (!wanted_spec.channels) {
2798 ✗ wanted_spec.freq = next_sample_rates[next_sample_rate_idx--];
2799 ✗ wanted_spec.channels = wanted_nb_channels;
2800 ✗ if (!wanted_spec.freq) {
2801 ✗ av_log(NULL, AV_LOG_ERROR,
2802 "No more combinations to try, audio open failed\n");
2803 ✗ return -1;
2804 }
2805 }
2806 ✗ av_channel_layout_default(wanted_channel_layout, wanted_spec.channels);
2807 }
2808 ✗ if (spec.format != AUDIO_S16SYS) {
2809 ✗ av_log(NULL, AV_LOG_ERROR,
2810 ✗ "SDL advised audio format %d is not supported!\n", spec.format);
2811 ✗ return -1;
2812 }
2813 ✗ if (spec.channels != wanted_spec.channels) {
2814 ✗ av_channel_layout_uninit(wanted_channel_layout);
2815 ✗ av_channel_layout_default(wanted_channel_layout, spec.channels);
2816 ✗ if (wanted_channel_layout->order != AV_CHANNEL_ORDER_NATIVE) {
2817 ✗ av_log(NULL, AV_LOG_ERROR,
2818 ✗ "SDL advised channel count %d is not supported!\n", spec.channels);
2819 ✗ return -1;
2820 }
2821 }
2822
2823 ✗ audio_hw_params->fmt = AV_SAMPLE_FMT_S16;
2824 ✗ audio_hw_params->freq = spec.freq;
2825 ✗ if (av_channel_layout_copy(&audio_hw_params->ch_layout, wanted_channel_layout) < 0)
2826 ✗ return -1;
2827 ✗ audio_hw_params->frame_size = av_samples_get_buffer_size(NULL, audio_hw_params->ch_layout.nb_channels, 1, audio_hw_params->fmt, 1);
2828 ✗ audio_hw_params->bytes_per_sec = av_samples_get_buffer_size(NULL, audio_hw_params->ch_layout.nb_channels, audio_hw_params->freq, audio_hw_params->fmt, 1);
2829 ✗ if (audio_hw_params->bytes_per_sec <= 0 || audio_hw_params->frame_size <= 0) {
2830 ✗ av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size failed\n");
2831 ✗ return -1;
2832 }
2833 ✗ return spec.size;
2834 }
2835
2836 ✗ static int create_hwaccel(AVBufferRef **device_ctx)
2837 {
2838 enum AVHWDeviceType type;
2839 int ret;
2840 AVBufferRef *vk_dev;
2841
2842 ✗ *device_ctx = NULL;
2843
2844 ✗ if (!hwaccel)
2845 ✗ return 0;
2846
2847 ✗ type = av_hwdevice_find_type_by_name(hwaccel);
2848 ✗ if (type == AV_HWDEVICE_TYPE_NONE)
2849 ✗ return AVERROR(ENOTSUP);
2850
2851 ✗ if (!vk_renderer) {
2852 ✗ av_log(NULL, AV_LOG_ERROR, "Vulkan renderer is not available\n");
2853 ✗ return AVERROR(ENOTSUP);
2854 }
2855
2856 ✗ ret = vk_renderer_get_hw_dev(vk_renderer, &vk_dev);
2857 ✗ if (ret < 0)
2858 ✗ return ret;
2859
2860 ✗ ret = av_hwdevice_ctx_create_derived(device_ctx, type, vk_dev, 0);
2861 ✗ if (!ret)
2862 ✗ return 0;
2863
2864 ✗ if (ret != AVERROR(ENOSYS))
2865 ✗ return ret;
2866
2867 ✗ av_log(NULL, AV_LOG_WARNING, "Derive %s from vulkan not supported.\n", hwaccel);
2868 ✗ ret = av_hwdevice_ctx_create(device_ctx, type, NULL, NULL, 0);
2869 ✗ return ret;
2870 }
2871
2872 ✗ static int init_lcevc_graph(AVFormatContext *ic, int stream_index)
2873 {
2874 ✗ FormatContext *ici = ic->opaque;
2875 ✗ StreamGroup *stgi = ici->streams[stream_index]->group;
2876 ✗ AVStreamGroup *stg = stgi->stg;
2877 ✗ const AVBitStreamFilter *filter, *lcevc_filter = av_bsf_get_by_name("lcevc_merge");
2878 AVBitStreamFilterContext *lcevc_merge;
2879 int ret;
2880
2881 ✗ stgi->graph = av_bsf_graph_alloc();
2882 ✗ if (!stgi->graph)
2883 ✗ return AVERROR(ENOMEM);
2884
2885 ✗ const AVStreamGroupLayeredVideo *lcevc = stg->params.layered_video;
2886 ✗ AVStream *base_st = ic->streams[stream_index];
2887 ✗ AVStream *lcevc_st = stg->entries[lcevc->el_index]->stream;
2888 ✗ Stream *lcevc_sti = ici->streams[lcevc_st->index];
2889 ✗ Stream *base_sti = ici->streams[stream_index];
2890
2891 ✗ filter = av_bsf_get_by_name("source");
2892 ✗ ret = av_bsf_graph_alloc_filter(&base_sti->filter, filter, "lcevc_merge_base", stgi->graph);
2893 ✗ if (ret < 0)
2894 ✗ return ret;
2895 ✗ av_opt_set_q(base_sti->filter->priv_data, "time_base", base_st->time_base, 0);
2896 ✗ ret = av_bsf_source_parameters_set(base_sti->filter, base_st->codecpar);
2897 ✗ if (ret < 0)
2898 ✗ return ret;
2899
2900 ✗ ret = av_bsf_graph_alloc_filter(&lcevc_sti->filter, filter, "lcevc_merge_enhancement", stgi->graph);
2901 ✗ if (ret < 0)
2902 ✗ return ret;
2903 ✗ av_opt_set_q(lcevc_sti->filter->priv_data, "time_base", lcevc_st->time_base, 0);
2904 ✗ ret = av_bsf_source_parameters_set(lcevc_sti->filter, lcevc_st->codecpar);
2905 ✗ if (ret < 0)
2906 ✗ return ret;
2907
2908 ✗ ret = av_bsf_graph_alloc_filter(&lcevc_merge, lcevc_filter, "lcevc_merge", stgi->graph);
2909 ✗ if (ret < 0)
2910 ✗ return ret;
2911
2912 ✗ filter = av_bsf_get_by_name("sink");
2913 ✗ ret = av_bsf_graph_alloc_filter(&stgi->sink, filter, "lcevc_merge_sink", stgi->graph);
2914 ✗ if (ret < 0)
2915 ✗ return ret;
2916
2917 ✗ ret = av_bsf_init_dict(base_sti->filter, NULL);
2918 ✗ if (ret < 0)
2919 ✗ return ret;
2920 ✗ ret = av_bsf_init_dict(lcevc_sti->filter, NULL);
2921 ✗ if (ret < 0)
2922 ✗ return ret;
2923 ✗ ret = av_bsf_init_dict(lcevc_merge, NULL);
2924 ✗ if (ret < 0)
2925 ✗ return ret;
2926 ✗ ret = av_bsf_init_dict(stgi->sink, NULL);
2927 ✗ if (ret < 0)
2928 ✗ return ret;
2929
2930 ✗ ret = av_bsf_link(base_sti->filter, 0, lcevc_merge, 0);
2931 ✗ if (ret < 0)
2932 ✗ return ret;
2933 ✗ ret = av_bsf_link(lcevc_sti->filter, 0, lcevc_merge, 1);
2934 ✗ if (ret < 0)
2935 ✗ return ret;
2936 ✗ ret = av_bsf_link(lcevc_merge, 0, stgi->sink, 0);
2937 ✗ if (ret < 0)
2938 ✗ return ret;
2939
2940 ✗ ret = av_bsf_graph_config(stgi->graph, NULL);
2941 ✗ if (ret < 0)
2942 ✗ return ret;
2943
2944 ✗ lcevc_st->discard = AVDISCARD_DEFAULT;
2945 ✗ lcevc_sti->group = stgi;
2946
2947 ✗ return 0;
2948 }
2949
2950 /* opens the audio device for the output of the audio filters and starts decoding and playing the audio */
2951 ✗ static int audio_start(VideoState *is)
2952 {
2953 ✗ AVChannelLayout ch_layout = { 0 };
2954 ✗ int ret = av_buffersink_get_ch_layout(is->out_audio_filter, &ch_layout);
2955
2956 ✗ if (ret >= 0)
2957 ✗ ret = audio_open(is, &ch_layout, av_buffersink_get_sample_rate(is->out_audio_filter), &is->audio_tgt);
2958 ✗ av_channel_layout_uninit(&ch_layout);
2959 ✗ if (ret < 0)
2960 ✗ return ret;
2961 ✗ is->audio_hw_buf_size = ret;
2962 ✗ is->audio_src = is->audio_tgt;
2963 ✗ is->audio_buf_size = 0;
2964 ✗ is->audio_buf_index = 0;
2965
2966 /* init averaging filter */
2967 ✗ is->audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
2968 ✗ is->audio_diff_avg_count = 0;
2969 /* since we do not have a precise anough audio FIFO fullness,
2970 we correct audio sync only if larger than this threshold */
2971 ✗ is->audio_diff_threshold = (double)(is->audio_hw_buf_size) / is->audio_tgt.bytes_per_sec;
2972
2973 ✗ if ((ret = decoder_start(&is->auddec, audio_thread, "audio_decoder", is)) < 0)
2974 ✗ return ret;
2975 ✗ SDL_PauseAudioDevice(is->audio_dev, 0);
2976 ✗ return 0;
2977 }
2978
2979 /* open a given stream. Return 0 if OK */
2980 ✗ static int stream_component_open(VideoState *is, int stream_index)
2981 {
2982 ✗ AVFormatContext *ic = is->ic;
2983 ✗ FormatContext *ici = ic->opaque;
2984 AVCodecContext *avctx;
2985 const AVCodec *codec;
2986 ✗ const char *forced_codec_name = NULL;
2987 ✗ AVDictionary *opts = NULL;
2988 ✗ int ret = 0;
2989 ✗ int stream_lowres = lowres;
2990
2991 ✗ if (stream_index < 0 || stream_index >= ic->nb_streams)
2992 ✗ return -1;
2993
2994 ✗ avctx = avcodec_alloc_context3(NULL);
2995 ✗ if (!avctx)
2996 ✗ return AVERROR(ENOMEM);
2997
2998 ✗ ret = avcodec_parameters_to_context(avctx, ic->streams[stream_index]->codecpar);
2999 ✗ if (ret < 0)
3000 ✗ goto fail;
3001 ✗ avctx->pkt_timebase = ic->streams[stream_index]->time_base;
3002
3003 ✗ codec = avcodec_find_decoder(avctx->codec_id);
3004
3005 ✗ switch(avctx->codec_type){
3006 ✗ case AVMEDIA_TYPE_AUDIO : is->last_audio_stream = stream_index; forced_codec_name = audio_codec_name; break;
3007 ✗ case AVMEDIA_TYPE_SUBTITLE: is->last_subtitle_stream = stream_index; forced_codec_name = subtitle_codec_name; break;
3008 ✗ case AVMEDIA_TYPE_VIDEO : is->last_video_stream = stream_index; forced_codec_name = video_codec_name; break;
3009 }
3010 ✗ if (forced_codec_name)
3011 ✗ codec = avcodec_find_decoder_by_name(forced_codec_name);
3012 ✗ if (!codec) {
3013 ✗ if (forced_codec_name) av_log(NULL, AV_LOG_WARNING,
3014 "No codec could be found with name '%s'\n", forced_codec_name);
3015 ✗ else av_log(NULL, AV_LOG_WARNING,
3016 ✗ "No decoder could be found for codec %s\n", avcodec_get_name(avctx->codec_id));
3017 ✗ ret = AVERROR(EINVAL);
3018 ✗ goto fail;
3019 }
3020
3021 ✗ avctx->codec_id = codec->id;
3022 ✗ if (stream_lowres > codec->max_lowres) {
3023 ✗ av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
3024 ✗ codec->max_lowres);
3025 ✗ stream_lowres = codec->max_lowres;
3026 }
3027 ✗ avctx->lowres = stream_lowres;
3028
3029 ✗ if (fast)
3030 ✗ avctx->flags2 |= AV_CODEC_FLAG2_FAST;
3031
3032 ✗ ret = filter_codec_opts(codec_opts, avctx->codec_id, ic,
3033 ✗ ic->streams[stream_index], codec, &opts, NULL);
3034 ✗ if (ret < 0)
3035 ✗ goto fail;
3036
3037 ✗ if (!av_dict_get(opts, "threads", NULL, 0))
3038 ✗ av_dict_set(&opts, "threads", "auto", 0);
3039 ✗ if (stream_lowres)
3040 ✗ av_dict_set_int(&opts, "lowres", stream_lowres, 0);
3041
3042 ✗ av_dict_set(&opts, "flags", "+copy_opaque", AV_DICT_MULTIKEY);
3043
3044 ✗ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
3045 ✗ ret = create_hwaccel(&avctx->hw_device_ctx);
3046 ✗ if (ret < 0)
3047 ✗ goto fail;
3048 }
3049
3050 ✗ if ((ret = avcodec_open2(avctx, codec, &opts)) < 0) {
3051 ✗ goto fail;
3052 }
3053 ✗ ret = check_avoptions(opts);
3054 ✗ if (ret < 0)
3055 ✗ goto fail;
3056
3057 ✗ is->eof = 0;
3058 ✗ ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
3059 ✗ switch (avctx->codec_type) {
3060 ✗ case AVMEDIA_TYPE_AUDIO:
3061 ✗ is->audio_filter_src.freq = avctx->sample_rate;
3062 ✗ ret = av_channel_layout_copy(&is->audio_filter_src.ch_layout, &avctx->ch_layout);
3063 ✗ if (ret < 0)
3064 ✗ goto fail;
3065 ✗ is->audio_filter_src.fmt = avctx->sample_fmt;
3066 ✗ if ((ret = configure_audio_filters(is, afilters, 0)) < 0)
3067 ✗ goto fail;
3068
3069 ✗ is->audio_stream = stream_index;
3070 ✗ is->audio_st = ic->streams[stream_index];
3071
3072 ✗ if ((ret = decoder_init(&is->auddec, avctx, &is->audioq, is->continue_read_thread)) < 0)
3073 ✗ goto fail;
3074 ✗ if (is->ic->iformat->flags & AVFMT_NOTIMESTAMPS) {
3075 ✗ is->auddec.start_pts = is->audio_st->start_time;
3076 ✗ is->auddec.start_pts_tb = is->audio_st->time_base;
3077 }
3078 ✗ if (!SDL_AtomicGet(&is->replacement) && (ret = audio_start(is)) < 0)
3079 ✗ stream_component_close(is, stream_index);
3080 ✗ break;
3081 ✗ case AVMEDIA_TYPE_VIDEO:
3082 ✗ is->video_stream = stream_index;
3083 ✗ is->video_st = ic->streams[stream_index];
3084
3085 ✗ if (ici->streams[stream_index]->group) {
3086 ✗ if ((ret = init_lcevc_graph(ic, stream_index)) < 0)
3087 ✗ goto fail;
3088 }
3089 ✗ if ((ret = decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread)) < 0)
3090 ✗ goto fail;
3091 ✗ if ((ret = decoder_start(&is->viddec, video_thread, "video_decoder", is)) < 0)
3092 ✗ goto out;
3093 ✗ is->queue_attachments_req = 1;
3094 ✗ break;
3095 ✗ case AVMEDIA_TYPE_SUBTITLE:
3096 ✗ is->subtitle_stream = stream_index;
3097 ✗ is->subtitle_st = ic->streams[stream_index];
3098
3099 ✗ if ((ret = decoder_init(&is->subdec, avctx, &is->subtitleq, is->continue_read_thread)) < 0)
3100 ✗ goto fail;
3101 ✗ if ((ret = decoder_start(&is->subdec, subtitle_thread, "subtitle_decoder", is)) < 0)
3102 ✗ goto out;
3103 ✗ break;
3104 ✗ default:
3105 ✗ break;
3106 }
3107 ✗ goto out;
3108
3109 ✗ fail:
3110 ✗ avcodec_free_context(&avctx);
3111 ✗ out:
3112 ✗ av_dict_free(&opts);
3113
3114 ✗ return ret;
3115 }
3116
3117 ✗ static int decode_interrupt_cb(void *ctx)
3118 {
3119 ✗ VideoState *is = ctx;
3120 ✗ return is->abort_request;
3121 }
3122
3123 ✗ static int stream_has_enough_packets(AVStream *st, int stream_id, PacketQueue *queue) {
3124 ✗ return stream_id < 0 ||
3125 ✗ queue->abort_request ||
3126 ✗ (st->disposition & AV_DISPOSITION_ATTACHED_PIC) ||
3127 ✗ queue->nb_packets > MIN_FRAMES && (!queue->duration || av_q2d(st->time_base) * queue->duration > 1.0);
3128 }
3129
3130 ✗ static int is_realtime(AVFormatContext *s)
3131 {
3132 ✗ if( !strcmp(s->iformat->name, "rtp")
3133 ✗ || !strcmp(s->iformat->name, "rtsp")
3134 ✗ || !strcmp(s->iformat->name, "sdp")
3135 )
3136 ✗ return 1;
3137
3138 ✗ if(s->pb && ( !strncmp(s->url, "rtp:", 4)
3139 ✗ || !strncmp(s->url, "udp:", 4)
3140 )
3141 )
3142 ✗ return 1;
3143 ✗ return 0;
3144 }
3145
3146 ✗ static int do_bsf_graph(AVFormatContext *ic, VideoState *is,
3147 Stream *sti, AVPacket *pkt)
3148 {
3149 ✗ StreamGroup *stgi = sti->group;
3150 ✗ AVBitStreamFilterContext *source = sti->filter;
3151 int ret;
3152
3153 ✗ ret = av_bsf_source_add_packet(source, pkt, AV_BSF_SOURCE_FLAG_PUSH);
3154 ✗ if (ret < 0) {
3155 ✗ if (pkt)
3156 ✗ av_packet_unref(pkt);
3157 ✗ av_log(NULL, AV_LOG_ERROR, "Error submitting a packet for filtering: %s\n",
3158 ✗ av_err2str(ret));
3159 ✗ return ret;
3160 }
3161
3162 while (1) {
3163 ✗ ret = av_bsf_sink_get_packet(stgi->sink, pkt, 0);
3164 ✗ if (ret == AVERROR(EAGAIN))
3165 ✗ return 0;
3166 ✗ else if (ret < 0) {
3167 ✗ if (ret != AVERROR_EOF)
3168 ✗ av_log(NULL, AV_LOG_ERROR,
3169 "Error applying bitstream filters to a packet: %s\n",
3170 ✗ av_err2str(ret));
3171 ✗ return ret;
3172 }
3173 ✗ pkt->time_base = av_bsf_sink_get_time_base(stgi->sink);
3174 ✗ packet_queue_put(&is->videoq, pkt);
3175 }
3176
3177 return 0;
3178 }
3179
3180 ✗ static int do_bsf_flush(AVFormatContext *ic, VideoState *is)
3181 {
3182 ✗ FormatContext *ici = ic->opaque;
3183 int ret;
3184
3185 ✗ for (unsigned i = 0; i < ic->nb_streams; i++) {
3186 ✗ Stream *sti = ici->streams[i];
3187 ✗ StreamGroup *stgi = sti->group;
3188
3189 ✗ if (!stgi || !stgi->graph)
3190 ✗ continue;
3191
3192 ✗ ret = do_bsf_graph(ic, is, sti, NULL);
3193 ✗ ret = (ret == AVERROR_EOF) ? 0 : (ret < 0) ? ret : AVERROR_BUG;
3194 ✗ if (ret < 0) {
3195 ✗ av_log(NULL, AV_LOG_ERROR, "Error flushing BSFs: %s\n",
3196 ✗ av_err2str(ret));
3197 ✗ return ret;
3198 }
3199 }
3200
3201 ✗ return 0;
3202 }
3203
3204 /* this thread gets the stream from the disk or the network */
3205 ✗ static int read_thread(void *arg)
3206 {
3207 ✗ VideoState *is = arg;
3208 ✗ AVFormatContext *ic = NULL;
3209 ✗ FormatContext *ici = NULL;
3210 int err, i, ret;
3211 int st_index[AVMEDIA_TYPE_NB];
3212 ✗ AVPacket *pkt = NULL;
3213 int64_t stream_start_time;
3214 char metadata_description[96];
3215 ✗ int pkt_in_play_range = 0;
3216 ✗ int announced = 0;
3217 const AVDictionaryEntry *t;
3218 ✗ SDL_mutex *wait_mutex = SDL_CreateMutex();
3219 ✗ AVDictionary *format_options = NULL;
3220 ✗ int scan_all_pmts_set = 0;
3221 int64_t pkt_ts;
3222
3223 ✗ if (!wait_mutex) {
3224 ✗ av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
3225 ✗ ret = AVERROR(ENOMEM);
3226 ✗ goto fail;
3227 }
3228
3229 ✗ memset(st_index, -1, sizeof(st_index));
3230 ✗ is->eof = 0;
3231
3232 ✗ pkt = av_packet_alloc();
3233 ✗ if (!pkt) {
3234 ✗ av_log(NULL, AV_LOG_FATAL, "Could not allocate packet.\n");
3235 ✗ ret = AVERROR(ENOMEM);
3236 ✗ goto fail;
3237 }
3238 ✗ ic = avformat_alloc_context();
3239 ✗ if (!ic) {
3240 ✗ av_log(NULL, AV_LOG_FATAL, "Could not allocate context.\n");
3241 ✗ ret = AVERROR(ENOMEM);
3242 ✗ goto fail;
3243 }
3244 ✗ ic->opaque = av_mallocz(sizeof(FormatContext));
3245 ✗ if (!ic->opaque) {
3246 ✗ av_log(NULL, AV_LOG_FATAL, "Could not allocate internal context.\n");
3247 ✗ ret = AVERROR(ENOMEM);
3248 ✗ goto fail;
3249 }
3250 ✗ ic->interrupt_callback.callback = decode_interrupt_cb;
3251 ✗ ic->interrupt_callback.opaque = is;
3252 ✗ if ((ret = av_dict_copy(&format_options, format_opts, 0)) < 0)
3253 ✗ goto fail;
3254 ✗ if (!av_dict_get(format_options, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
3255 ✗ av_dict_set(&format_options, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
3256 ✗ scan_all_pmts_set = 1;
3257 }
3258 ✗ err = avformat_open_input(&ic, is->filename, is->iformat, &format_options);
3259 ✗ if (err < 0) {
3260 ✗ print_error(is->filename, err);
3261 ✗ ret = -1;
3262 ✗ goto fail;
3263 }
3264 ✗ if (scan_all_pmts_set)
3265 ✗ av_dict_set(&format_options, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);
3266 ✗ remove_avoptions(&format_options, codec_opts);
3267
3268 ✗ ret = check_avoptions(format_options);
3269 ✗ if (ret < 0)
3270 ✗ goto fail;
3271 ✗ is->ic = ic;
3272
3273 ✗ if (genpts)
3274 ✗ ic->flags |= AVFMT_FLAG_GENPTS;
3275
3276 ✗ if (find_stream_info) {
3277 AVDictionary **opts;
3278 ✗ int orig_nb_streams = ic->nb_streams;
3279
3280 ✗ err = setup_find_stream_info_opts(ic, codec_opts, &opts);
3281 ✗ if (err < 0) {
3282 ✗ av_log(NULL, AV_LOG_ERROR,
3283 "Error setting up avformat_find_stream_info() options\n");
3284 ✗ ret = err;
3285 ✗ goto fail;
3286 }
3287
3288 ✗ err = avformat_find_stream_info(ic, opts);
3289
3290 ✗ for (i = 0; i < orig_nb_streams; i++)
3291 ✗ av_dict_free(&opts[i]);
3292 ✗ av_freep(&opts);
3293
3294 ✗ if (err < 0) {
3295 ✗ av_log(NULL, AV_LOG_WARNING,
3296 "%s: could not find codec parameters\n", is->filename);
3297 ✗ ret = -1;
3298 ✗ goto fail;
3299 }
3300 }
3301
3302 ✗ if (ic->pb)
3303 ✗ ic->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use avio_feof() to test for the end
3304
3305 ✗ if (is->seek_by_bytes < 0)
3306 ✗ is->seek_by_bytes = !(ic->iformat->flags & AVFMT_NO_BYTE_SEEK) &&
3307 ✗ !!(ic->iformat->flags & AVFMT_TS_DISCONT) &&
3308 ✗ strcmp("ogg", ic->iformat->name);
3309
3310 ✗ is->max_frame_duration = (ic->iformat->flags & AVFMT_TS_DISCONT) ? 10.0 : 3600.0;
3311
3312 ✗ if (!window_title && (t = av_dict_get(ic->metadata, "title", NULL, 0)))
3313 ✗ is->title = av_asprintf("%s - %s", t->value, is->filename);
3314
3315 /* if seeking requested, we execute it */
3316 ✗ if (start_time != AV_NOPTS_VALUE) {
3317 int64_t timestamp;
3318
3319 ✗ timestamp = start_time;
3320 /* add the stream start time */
3321 ✗ if (ic->start_time != AV_NOPTS_VALUE)
3322 ✗ timestamp += ic->start_time;
3323 ✗ ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
3324 ✗ if (ret < 0) {
3325 ✗ av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
3326 ✗ is->filename, (double)timestamp / AV_TIME_BASE);
3327 }
3328 }
3329
3330 ✗ is->realtime = is_realtime(ic);
3331
3332 ✗ if (show_status) {
3333 ✗ fprintf(stderr, "\x1b[2K\r");
3334 ✗ av_dump_format(ic, 0, is->filename, 0);
3335 }
3336
3337 ✗ ici = ic->opaque;
3338 ✗ ici->streams = av_calloc(ic->nb_streams, sizeof(*ici->streams));
3339 ✗ if (!ici->streams) {
3340 ✗ av_log(NULL, AV_LOG_FATAL, "Could not allocate internal streams context.\n");
3341 ✗ ret = AVERROR(ENOMEM);
3342 ✗ goto fail;
3343 }
3344 ✗ ici->nb_streams = ic->nb_streams;
3345 ✗ for (i = 0; i < ic->nb_streams; i++) {
3346 ✗ AVStream *st = ic->streams[i];
3347 ✗ enum AVMediaType type = st->codecpar->codec_type;
3348 ✗ ici->streams[i] = av_mallocz(sizeof(Stream));
3349 ✗ if (!ici->streams[i]) {
3350 ✗ av_log(NULL, AV_LOG_FATAL, "Could not allocate internal stream context.\n");
3351 ✗ ret = AVERROR(ENOMEM);
3352 ✗ goto fail;
3353 }
3354 ✗ st->discard = AVDISCARD_ALL;
3355 ✗ if (type >= 0 && wanted_stream_spec[type] && st_index[type] == -1)
3356 ✗ if (avformat_match_stream_specifier(ic, st, wanted_stream_spec[type]) > 0)
3357 ✗ st_index[type] = i;
3358 // Clear all pre-existing metadata update flags to avoid printing
3359 // initial metadata as update.
3360 ✗ st->event_flags &= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED;
3361 }
3362 ✗ ici->stream_groups = av_calloc(ic->nb_stream_groups, sizeof(*ici->stream_groups));
3363 ✗ if (!ici->stream_groups) {
3364 ✗ av_log(NULL, AV_LOG_FATAL, "Could not allocate internal stream groups context.\n");
3365 ✗ ret = AVERROR(ENOMEM);
3366 ✗ goto fail;
3367 }
3368 ✗ ici->nb_stream_groups = ic->nb_stream_groups;
3369 ✗ for (i = 0; i < ic->nb_stream_groups; i++) {
3370 ✗ AVStreamGroup *stg = ic->stream_groups[i];
3371
3372 ✗ ici->stream_groups[i] = av_mallocz(sizeof(*ici->stream_groups[i]));
3373 ✗ if (!ici->stream_groups[i]) {
3374 ✗ av_log(NULL, AV_LOG_FATAL, "Could not allocate internal stream group.\n");
3375 ✗ ret = AVERROR(ENOMEM);
3376 ✗ goto fail;
3377 }
3378 ✗ ici->stream_groups[i]->stg = stg;
3379
3380 ✗ if (stg->type != AV_STREAM_GROUP_PARAMS_LCEVC)
3381 ✗ continue;
3382 ✗ if (!av_bsf_get_by_name("lcevc_merge") || stg->nb_entries != 2)
3383 ✗ continue;
3384 ✗ for (int j = 0; j < stg->nb_entries; j++) {
3385 ✗ AVStreamGroupEntry *entry = stg->entries[j];
3386 ✗ if (entry->type != AV_STREAM_GROUP_ENTRY_STREAM) {
3387 ✗ ret = AVERROR_BUG;
3388 ✗ goto fail;
3389 }
3390 }
3391
3392 ✗ const AVStreamGroupLayeredVideo *lcevc = stg->params.layered_video;
3393 ✗ const AVStream *base_st = ic->streams[stg->entries[!lcevc->el_index]->stream->index];
3394 ✗ Stream *base_sti = ici->streams[base_st->index];
3395
3396 ✗ base_sti->group = ici->stream_groups[i];
3397 }
3398 ✗ ic->event_flags &= ~AVFMT_EVENT_FLAG_METADATA_UPDATED;
3399 ✗ for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
3400 ✗ if (wanted_stream_spec[i] && st_index[i] == -1) {
3401 ✗ av_log(NULL, AV_LOG_ERROR, "Stream specifier %s does not match any %s stream\n", wanted_stream_spec[i], av_get_media_type_string(i));
3402 ✗ st_index[i] = INT_MAX;
3403 }
3404 }
3405
3406 ✗ if (!video_disable)
3407 ✗ st_index[AVMEDIA_TYPE_VIDEO] =
3408 ✗ av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,
3409 st_index[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);
3410 ✗ if (!audio_disable)
3411 ✗ st_index[AVMEDIA_TYPE_AUDIO] =
3412 ✗ av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,
3413 st_index[AVMEDIA_TYPE_AUDIO],
3414 st_index[AVMEDIA_TYPE_VIDEO],
3415 NULL, 0);
3416 ✗ if (!video_disable && !subtitle_disable)
3417 ✗ st_index[AVMEDIA_TYPE_SUBTITLE] =
3418 ✗ av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE,
3419 st_index[AVMEDIA_TYPE_SUBTITLE],
3420 ✗ (st_index[AVMEDIA_TYPE_AUDIO] >= 0 ?
3421 st_index[AVMEDIA_TYPE_AUDIO] :
3422 st_index[AVMEDIA_TYPE_VIDEO]),
3423 NULL, 0);
3424
3425 ✗ is->show_mode = show_mode;
3426 ✗ if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
3427 ✗ AVStream *st = ic->streams[st_index[AVMEDIA_TYPE_VIDEO]];
3428 ✗ AVCodecParameters *codecpar = st->codecpar;
3429 ✗ AVRational sar = av_guess_sample_aspect_ratio(ic, st, NULL);
3430 ✗ if (codecpar->width)
3431 ✗ set_default_window_size(codecpar->width, codecpar->height, sar);
3432 }
3433
3434 /* open the streams */
3435 ✗ if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
3436 ✗ stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);
3437 }
3438
3439 ✗ ret = -1;
3440 ✗ if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
3441 ✗ ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);
3442 }
3443 ✗ if (is->show_mode == SHOW_MODE_NONE)
3444 ✗ is->show_mode = ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;
3445
3446 ✗ if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {
3447 ✗ stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]);
3448 }
3449
3450 ✗ if (is->video_stream < 0 && is->audio_stream < 0) {
3451 ✗ av_log(NULL, AV_LOG_FATAL, "Failed to open file '%s' or configure filtergraph\n",
3452 is->filename);
3453 ✗ ret = -1;
3454 ✗ goto fail;
3455 }
3456 ✗ if (is->video_stream < 0)
3457 ✗ push_stream_event(is, FF_READY_EVENT);
3458
3459 ✗ if (is->infinite_buffer < 0 && is->realtime)
3460 ✗ is->infinite_buffer = 1;
3461
3462 for (;;) {
3463 ✗ if (is->abort_request)
3464 ✗ break;
3465 ✗ if (is->paused != is->last_paused) {
3466 ✗ is->last_paused = is->paused;
3467 ✗ if (is->paused)
3468 ✗ is->read_pause_return = av_read_pause(ic);
3469 else
3470 ✗ av_read_play(ic);
3471 }
3472 #if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
3473 ✗ if (is->paused &&
3474 ✗ (!strcmp(ic->iformat->name, "rtsp") ||
3475 ✗ (ic->pb && !strncmp(is->filename, "mmsh:", 5)))) {
3476 /* wait 10 ms to avoid trying to get another packet */
3477 /* XXX: horrible */
3478 ✗ SDL_Delay(10);
3479 ✗ continue;
3480 }
3481 #endif
3482 ✗ if (is->seek_req) {
3483 ✗ int64_t seek_target = is->seek_pos;
3484 ✗ int64_t seek_min = is->seek_rel > 0 ? seek_target - is->seek_rel + 2: INT64_MIN;
3485 ✗ int64_t seek_max = is->seek_rel < 0 ? seek_target - is->seek_rel - 2: INT64_MAX;
3486 // FIXME the +-2 is due to rounding being not done in the correct direction in generation
3487 // of the seek_pos/seek_rel variables
3488
3489 ✗ ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
3490 ✗ if (ret < 0) {
3491 ✗ av_log(NULL, AV_LOG_ERROR,
3492 ✗ "%s: error while seeking\n", is->ic->url);
3493 } else {
3494 ✗ if (is->audio_stream >= 0)
3495 ✗ packet_queue_flush(&is->audioq);
3496 ✗ if (is->subtitle_stream >= 0)
3497 ✗ packet_queue_flush(&is->subtitleq);
3498 ✗ if (is->video_stream >= 0) {
3499 ✗ packet_queue_flush(&is->videoq);
3500 ✗ uninit_bsf_graph(is->ic, is->video_stream);
3501 ✗ if (ici->streams[is->video_stream]->group) {
3502 ✗ if ((ret = init_lcevc_graph(is->ic, is->video_stream)) < 0)
3503 ✗ goto fail;
3504 }
3505 }
3506 ✗ if (is->seek_flags & AVSEEK_FLAG_BYTE) {
3507 ✗ set_clock(&is->extclk, NAN, 0);
3508 } else {
3509 ✗ set_clock(&is->extclk, seek_target / (double)AV_TIME_BASE, 0);
3510 }
3511 }
3512 ✗ is->seek_req = 0;
3513 ✗ is->queue_attachments_req = 1;
3514 ✗ is->eof = 0;
3515 ✗ if (is->paused)
3516 ✗ step_to_next_frame(is);
3517 }
3518 ✗ if (is->queue_attachments_req) {
3519 ✗ if (is->video_st && is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC) {
3520 ✗ if ((ret = av_packet_ref(pkt, &is->video_st->attached_pic)) < 0)
3521 ✗ goto fail;
3522 ✗ packet_queue_put(&is->videoq, pkt);
3523 ✗ packet_queue_put_nullpacket(&is->videoq, pkt, is->video_stream);
3524 }
3525 ✗ is->queue_attachments_req = 0;
3526 }
3527
3528 /* if the queue are full, no need to read more */
3529 ✗ if (is->infinite_buffer < 1 &&
3530 ✗ (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
3531 ✗ || (stream_has_enough_packets(is->audio_st, is->audio_stream, &is->audioq) &&
3532 ✗ stream_has_enough_packets(is->video_st, is->video_stream, &is->videoq) &&
3533 ✗ stream_has_enough_packets(is->subtitle_st, is->subtitle_stream, &is->subtitleq)))) {
3534 ✗ if (!announced && SDL_AtomicGet(&is->replacement) && is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE) {
3535 ✗ push_stream_event(is, FF_READY_EVENT);
3536 ✗ announced = 1;
3537 }
3538 /* wait 10 ms */
3539 ✗ SDL_LockMutex(wait_mutex);
3540 ✗ SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
3541 ✗ SDL_UnlockMutex(wait_mutex);
3542 ✗ continue;
3543 }
3544 ✗ if (!is->paused &&
3545 ✗ (!is->audio_st || (is->auddec.finished == is->audioq.serial && frame_queue_nb_remaining(&is->sampq) == 0)) &&
3546 ✗ (!is->video_st || (is->viddec.finished == is->videoq.serial && frame_queue_nb_remaining(&is->pictq) == 0))) {
3547 ✗ if (is->loop != 1 && (!is->loop || --is->loop)) {
3548 ✗ stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
3549 ✗ } else if (autoexit) {
3550 ✗ ret = AVERROR_EOF;
3551 ✗ goto fail;
3552 }
3553 }
3554 ✗ ret = av_read_frame(ic, pkt);
3555 ✗ if (ret < 0) {
3556 ✗ if ((ret == AVERROR_EOF || avio_feof(ic->pb)) && !is->eof) {
3557 ✗ if (is->video_stream >= 0) {
3558 ✗ ret = do_bsf_flush(ic, is);
3559 ✗ if (ret < 0)
3560 ✗ goto fail;
3561 ✗ packet_queue_put_nullpacket(&is->videoq, pkt, is->video_stream);
3562 }
3563 ✗ if (is->audio_stream >= 0)
3564 ✗ packet_queue_put_nullpacket(&is->audioq, pkt, is->audio_stream);
3565 ✗ if (is->subtitle_stream >= 0)
3566 ✗ packet_queue_put_nullpacket(&is->subtitleq, pkt, is->subtitle_stream);
3567 ✗ is->eof = 1;
3568 }
3569 ✗ if (ic->pb && ic->pb->error) {
3570 ✗ if (autoexit)
3571 ✗ goto fail;
3572 else
3573 ✗ break;
3574 }
3575 ✗ SDL_LockMutex(wait_mutex);
3576 ✗ SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
3577 ✗ SDL_UnlockMutex(wait_mutex);
3578 ✗ continue;
3579 } else {
3580 ✗ is->eof = 0;
3581 }
3582
3583 ✗ if (show_status) {
3584 ✗ if (ic->event_flags & AVFMT_EVENT_FLAG_METADATA_UPDATED) {
3585 ✗ fprintf(stderr, "\x1b[2K\r");
3586 ✗ dump_dictionary(NULL, ic->metadata,
3587 "\r New metadata", " ", AV_LOG_INFO);
3588 }
3589 ✗ if (ic->streams[pkt->stream_index]->event_flags &
3590 AVSTREAM_EVENT_FLAG_METADATA_UPDATED) {
3591 ✗ fprintf(stderr, "\x1b[2K\r");
3592 ✗ snprintf(metadata_description,
3593 sizeof(metadata_description),
3594 "\r New metadata for stream %d",
3595 ✗ pkt->stream_index);
3596 ✗ dump_dictionary(NULL, ic->streams[pkt->stream_index]->metadata,
3597 metadata_description, " ", AV_LOG_INFO);
3598 }
3599 }
3600 ✗ ic->event_flags &= ~AVFMT_EVENT_FLAG_METADATA_UPDATED;
3601 ✗ ic->streams[pkt->stream_index]->event_flags &= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED;
3602
3603 /* check if packet is in play range specified by user, then queue, otherwise discard */
3604 ✗ stream_start_time = ic->streams[pkt->stream_index]->start_time;
3605 ✗ pkt_ts = pkt->pts == AV_NOPTS_VALUE ? pkt->dts : pkt->pts;
3606 ✗ pkt_in_play_range = duration == AV_NOPTS_VALUE ||
3607 ✗ (pkt_ts - (stream_start_time != AV_NOPTS_VALUE ? stream_start_time : 0)) *
3608 ✗ av_q2d(ic->streams[pkt->stream_index]->time_base) -
3609 ✗ (double)(start_time != AV_NOPTS_VALUE ? start_time : 0) / 1000000
3610 ✗ <= ((double)duration / 1000000);
3611 ✗ if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
3612 ✗ packet_queue_put(&is->audioq, pkt);
3613 ✗ } else if (pkt->stream_index == is->video_stream && pkt_in_play_range
3614 ✗ && !(is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC)) {
3615 ✗ Stream *sti = ici->streams[is->video_stream];
3616 ✗ StreamGroup *stgi = sti->group;
3617 ✗ if (stgi && stgi->graph) {
3618 ✗ ret = do_bsf_graph(ic, is, sti, pkt);
3619 ✗ if (ret < 0)
3620 ✗ goto fail;
3621 } else
3622 ✗ packet_queue_put(&is->videoq, pkt);
3623 ✗ } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
3624 ✗ packet_queue_put(&is->subtitleq, pkt);
3625 } else {
3626 ✗ Stream *sti = ici->streams[pkt->stream_index];
3627 ✗ StreamGroup *stgi = sti->group;
3628 ✗ if (stgi && stgi->graph) {
3629 ✗ ret = do_bsf_graph(ic, is, sti, pkt);
3630 ✗ if (ret < 0)
3631 ✗ goto fail;
3632 }
3633 ✗ av_packet_unref(pkt);
3634 }
3635 }
3636
3637 ✗ ret = 0;
3638 ✗ fail:
3639 ✗ if (ic && !is->ic) {
3640 ✗ av_freep(&ic->opaque);
3641 ✗ avformat_close_input(&ic);
3642 }
3643 ✗ av_dict_free(&format_options);
3644
3645 ✗ av_packet_free(&pkt);
3646 ✗ if (ret != 0)
3647 ✗ push_stream_event(is, FF_QUIT_EVENT);
3648 ✗ SDL_DestroyMutex(wait_mutex);
3649 ✗ return 0;
3650 }
3651
3652 /* replaced is the stream playing which the new one is to replace, NULL for none; the replacement starts paused with
3653 * the volume of the stream it replaces, and opens no audio device before stream_replace() */
3654 ✗ static VideoState *stream_open(const char *filename,
3655 const AVInputFormat *iformat, const VideoState *replaced)
3656 {
3657 VideoState *is;
3658
3659 ✗ is = av_mallocz(sizeof(VideoState));
3660 ✗ if (!is)
3661 ✗ return NULL;
3662 ✗ is->last_video_stream = is->video_stream = -1;
3663 ✗ is->last_audio_stream = is->audio_stream = -1;
3664 ✗ is->last_subtitle_stream = is->subtitle_stream = -1;
3665 ✗ is->filename = av_strdup(filename);
3666 ✗ is->id = ++last_stream_id;
3667 ✗ if (!is->filename)
3668 ✗ goto fail;
3669 ✗ is->iformat = iformat;
3670 ✗ is->seek_by_bytes = seek_by_bytes;
3671 ✗ is->infinite_buffer = infinite_buffer;
3672 ✗ is->loop = loop;
3673 ✗ is->ytop = 0;
3674 ✗ is->xleft = 0;
3675
3676 /* start video display */
3677 ✗ if (frame_queue_init(&is->pictq, &is->videoq, VIDEO_PICTURE_QUEUE_SIZE, 1) < 0)
3678 ✗ goto fail;
3679 ✗ if (frame_queue_init(&is->subpq, &is->subtitleq, SUBPICTURE_QUEUE_SIZE, 0) < 0)
3680 ✗ goto fail;
3681 ✗ if (frame_queue_init(&is->sampq, &is->audioq, SAMPLE_QUEUE_SIZE, 1) < 0)
3682 ✗ goto fail;
3683
3684 ✗ if (packet_queue_init(&is->videoq) < 0 ||
3685 ✗ packet_queue_init(&is->audioq) < 0 ||
3686 ✗ packet_queue_init(&is->subtitleq) < 0)
3687 ✗ goto fail;
3688
3689 ✗ if (!(is->continue_read_thread = SDL_CreateCond())) {
3690 ✗ av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
3691 ✗ goto fail;
3692 }
3693
3694 ✗ init_clock(&is->vidclk, &is->videoq.serial);
3695 ✗ init_clock(&is->audclk, &is->audioq.serial);
3696 ✗ init_clock(&is->extclk, &is->extclk.serial);
3697 ✗ is->audio_clock_serial = -1;
3698 ✗ if (startup_volume < 0)
3699 ✗ av_log(NULL, AV_LOG_WARNING, "-volume=%d < 0, setting to 0\n", startup_volume);
3700 ✗ if (startup_volume > 100)
3701 ✗ av_log(NULL, AV_LOG_WARNING, "-volume=%d > 100, setting to 100\n", startup_volume);
3702 ✗ if (video_background) {
3703 ✗ if (!strcmp(video_background, "none")) {
3704 ✗ is->render_params.video_background_type = VIDEO_BACKGROUND_NONE;
3705 ✗ } else if (strcmp(video_background, "tiles")) {
3706 ✗ if (av_parse_color(is->render_params.video_background_color, video_background, -1, NULL) >= 0)
3707 ✗ is->render_params.video_background_type = VIDEO_BACKGROUND_COLOR;
3708 else
3709 ✗ goto fail;
3710 }
3711 }
3712 ✗ is->audio_volume = SDL_MIX_MAXVOLUME * av_clip(startup_volume, 0, 100) / 100;
3713 ✗ is->muted = 0;
3714 ✗ if (replaced) {
3715 ✗ SDL_AtomicSet(&is->replacement, 1);
3716 ✗ is->audio_volume = replaced->audio_volume;
3717 ✗ is->muted = replaced->muted;
3718 ✗ is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused = 1;
3719 }
3720 ✗ is->av_sync_type = av_sync_type;
3721 ✗ is->read_tid = SDL_CreateThread(read_thread, "read_thread", is);
3722 ✗ if (!is->read_tid) {
3723 ✗ av_log(NULL, AV_LOG_FATAL, "SDL_CreateThread(): %s\n", SDL_GetError());
3724 ✗ fail:
3725 ✗ stream_close(is);
3726 ✗ return NULL;
3727 }
3728 ✗ return is;
3729 }
3730
3731 ✗ static void stream_cycle_channel(VideoState *is, int codec_type)
3732 {
3733 ✗ AVFormatContext *ic = is->ic;
3734 int start_index, stream_index;
3735 int old_index;
3736 AVStream *st;
3737 ✗ AVProgram *p = NULL;
3738 ✗ int nb_streams = is->ic->nb_streams;
3739
3740 ✗ if (codec_type == AVMEDIA_TYPE_VIDEO) {
3741 ✗ start_index = is->last_video_stream;
3742 ✗ old_index = is->video_stream;
3743 ✗ } else if (codec_type == AVMEDIA_TYPE_AUDIO) {
3744 ✗ start_index = is->last_audio_stream;
3745 ✗ old_index = is->audio_stream;
3746 } else {
3747 ✗ start_index = is->last_subtitle_stream;
3748 ✗ old_index = is->subtitle_stream;
3749 }
3750 ✗ stream_index = start_index;
3751
3752 ✗ if (codec_type != AVMEDIA_TYPE_VIDEO && is->video_stream != -1) {
3753 ✗ p = av_find_program_from_stream(ic, NULL, is->video_stream);
3754 ✗ if (p) {
3755 ✗ nb_streams = p->nb_stream_indexes;
3756 ✗ for (start_index = 0; start_index < nb_streams; start_index++)
3757 ✗ if (p->stream_index[start_index] == stream_index)
3758 ✗ break;
3759 ✗ if (start_index == nb_streams)
3760 ✗ start_index = -1;
3761 ✗ stream_index = start_index;
3762 }
3763 }
3764
3765 for (;;) {
3766 ✗ if (++stream_index >= nb_streams)
3767 {
3768 ✗ if (codec_type == AVMEDIA_TYPE_SUBTITLE)
3769 {
3770 ✗ stream_index = -1;
3771 ✗ is->last_subtitle_stream = -1;
3772 ✗ goto the_end;
3773 }
3774 ✗ if (start_index == -1)
3775 ✗ return;
3776 ✗ stream_index = 0;
3777 }
3778 ✗ if (stream_index == start_index)
3779 ✗ return;
3780 ✗ st = is->ic->streams[p ? p->stream_index[stream_index] : stream_index];
3781 ✗ if (st->codecpar->codec_type == codec_type) {
3782 /* check that parameters are OK */
3783 ✗ switch (codec_type) {
3784 ✗ case AVMEDIA_TYPE_AUDIO:
3785 ✗ if (st->codecpar->sample_rate != 0 &&
3786 ✗ st->codecpar->ch_layout.nb_channels != 0)
3787 ✗ goto the_end;
3788 ✗ break;
3789 ✗ case AVMEDIA_TYPE_VIDEO:
3790 case AVMEDIA_TYPE_SUBTITLE:
3791 ✗ goto the_end;
3792 ✗ default:
3793 ✗ break;
3794 }
3795 }
3796 }
3797 ✗ the_end:
3798 ✗ if (p && stream_index != -1)
3799 ✗ stream_index = p->stream_index[stream_index];
3800 ✗ av_log(NULL, AV_LOG_INFO, "Switch %s stream from #%d to #%d\n",
3801 av_get_media_type_string(codec_type),
3802 old_index,
3803 stream_index);
3804
3805 ✗ stream_component_close(is, old_index);
3806 ✗ stream_component_open(is, stream_index);
3807 }
3808
3809
3810 ✗ static void toggle_full_screen(VideoState *is)
3811 {
3812 ✗ is_full_screen = !is_full_screen;
3813 ✗ SDL_SetWindowFullscreen(window, is_full_screen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
3814 ✗ }
3815
3816 ✗ static void toggle_audio_display(VideoState *is)
3817 {
3818 ✗ int next = is->show_mode;
3819 do {
3820 ✗ next = (next + 1) % SHOW_MODE_NB;
3821 ✗ } while (next != is->show_mode && (next == SHOW_MODE_VIDEO && !is->video_st || next != SHOW_MODE_VIDEO && !is->audio_st));
3822 ✗ if (is->show_mode != next) {
3823 ✗ is->force_refresh = 1;
3824 ✗ is->show_mode = next;
3825 }
3826 ✗ }
3827
3828 ✗ static void refresh_loop_wait_event(VideoState *is, SDL_Event *event) {
3829 ✗ double remaining_time = 0.0;
3830 ✗ SDL_PumpEvents();
3831 ✗ while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
3832 ✗ if (received_sigterm) {
3833 ✗ exit_status = 123;
3834 ✗ do_exit(is);
3835 }
3836 ✗ if (!cursor_hidden && av_gettime_relative() - cursor_last_shown > CURSOR_HIDE_DELAY) {
3837 ✗ SDL_ShowCursor(0);
3838 ✗ cursor_hidden = 1;
3839 }
3840 ✗ if (remaining_time > 0.0) {
3841 ✗ if (!wait_for_events)
3842 ✗ av_usleep((int64_t)(remaining_time * 1000000.0));
3843 ✗ else if (SDL_WaitEventTimeout(NULL, ceil(remaining_time * 1000)))
3844 ✗ continue;
3845 }
3846 ✗ remaining_time = REFRESH_RATE;
3847 ✗ if (list_view_visible(list))
3848 ✗ list_view_set_playing(list, list_shows_files ? -1 : current_chapter(is));
3849 ✗ if (dir_thread && SDL_AtomicGet(&dir_request.done))
3850 ✗ file_list_listed(is);
3851 ✗ if (list_view_update(list))
3852 ✗ is->force_refresh = 1;
3853 ✗ if (is->show_mode != SHOW_MODE_NONE && (!is->paused || is->force_refresh))
3854 ✗ video_refresh(is, &remaining_time);
3855 ✗ SDL_PumpEvents();
3856 }
3857 ✗ }
3858
3859 /* index of the chapter containing the current playback position, -1 before the first one */
3860 ✗ static int current_chapter(VideoState *is)
3861 {
3862 ✗ int64_t pos = get_master_clock(is) * AV_TIME_BASE;
3863 int i;
3864
3865 ✗ for (i = 0; i < is->ic->nb_chapters; i++) {
3866 ✗ AVChapter *ch = is->ic->chapters[i];
3867 ✗ if (av_compare_ts(pos, AV_TIME_BASE_Q, ch->start, ch->time_base) < 0)
3868 ✗ break;
3869 }
3870 ✗ return i - 1;
3871 }
3872
3873 ✗ static void seek_chapter(VideoState *is, int i)
3874 {
3875 ✗ i = FFMAX(i, 0);
3876 ✗ chapter_list_show(is, FFMIN(i, is->ic->nb_chapters - 1));
3877 ✗ if (i >= is->ic->nb_chapters)
3878 ✗ return;
3879
3880 ✗ av_log(NULL, AV_LOG_VERBOSE, "Seeking to chapter %d.\n", i);
3881 ✗ stream_seek(is, av_rescale_q(is->ic->chapters[i]->start, is->ic->chapters[i]->time_base,
3882 ✗ AV_TIME_BASE_Q), 0, 0);
3883 }
3884
3885 /* shows the files of the directory with the entry selected */
3886 ✗ static int file_list_show(DirList *dl, int selected)
3887 {
3888 int ret;
3889
3890 ✗ if (!list_shows_files)
3891 ✗ list_view_clear(list);
3892 ✗ ret = list_view_show(list, dl->entries, dl->nb_entries, selected);
3893 ✗ if (ret >= 0)
3894 ✗ list_shows_files = 1;
3895 ✗ return ret;
3896 }
3897
3898 /* opens the file to replace the stream playing once it can play */
3899 ✗ static void file_play(VideoState *is, const char *path)
3900 {
3901 ✗ if (next_stream)
3902 ✗ stream_close(next_stream);
3903 ✗ if (!(next_stream = stream_open(path, file_iformat, is)))
3904 ✗ av_log(NULL, AV_LOG_ERROR, "Could not open '%s'\n", path);
3905 ✗ }
3906
3907 ✗ static int dir_interrupt_cb(void *ctx)
3908 {
3909 ✗ return SDL_AtomicGet(&dir_request.abort);
3910 }
3911
3912 ✗ static int dir_thread_func(void *arg)
3913 {
3914 ✗ const AVIOInterruptCB int_cb = { dir_interrupt_cb };
3915
3916 ✗ dir_request.ret = dir_list_read(&dir_request.dl, dir_request.path, &int_cb, &dir_request.options);
3917 ✗ SDL_AtomicSet(&dir_request.done, 1);
3918 ✗ return 0;
3919 }
3920
3921 /* starts reading the directory on dir_thread, unless it is busy; with play_if_no_dir the path is played when it is no
3922 * directory */
3923 ✗ static void file_list_read(const char *path, int play_if_no_dir)
3924 {
3925 ✗ int ret = 0;
3926
3927 ✗ if (dir_thread) {
3928 ✗ av_log(NULL, AV_LOG_VERBOSE, "Not listing '%s' while '%s' is being read\n", path, dir_request.path);
3929 ✗ return;
3930 }
3931 ✗ dir_request.play_if_no_dir = play_if_no_dir;
3932 ✗ dir_request.cancelled = 0;
3933 ✗ SDL_AtomicSet(&dir_request.abort, 0);
3934 ✗ SDL_AtomicSet(&dir_request.done, 0);
3935 ✗ if (!(dir_request.path = av_strdup(path)))
3936 ✗ ret = AVERROR(ENOMEM);
3937 else
3938 ✗ ret = av_dict_copy(&dir_request.options, format_opts, 0);
3939 ✗ if (ret < 0 || !(dir_thread = SDL_CreateThread(dir_thread_func, "dir_reader", NULL))) {
3940 ✗ av_log(NULL, AV_LOG_ERROR, "Could not list the directory '%s': %s\n", path, ret < 0 ? av_err2str(ret) : SDL_GetError());
3941 ✗ av_freep(&dir_request.path);
3942 ✗ av_dict_free(&dir_request.options);
3943 }
3944 }
3945
3946 /* takes over what dir_thread read: shows the directory, plays the path when it is no directory, or drops the result of
3947 * a cancelled request */
3948 ✗ static void file_list_listed(VideoState *is)
3949 {
3950 int ret;
3951
3952 ✗ SDL_WaitThread(dir_thread, NULL);
3953 ✗ dir_thread = NULL;
3954 ✗ av_dict_free(&dir_request.options);
3955 ✗ if (dir_request.cancelled) {
3956 ✗ dir_list_free(&dir_request.dl);
3957 ✗ } else if (dir_request.ret < 0) {
3958 ✗ av_log(NULL, dir_request.play_if_no_dir ? AV_LOG_VERBOSE : AV_LOG_ERROR, "Could not list the directory '%s': %s\n",
3959 ✗ dir_request.path, av_err2str(dir_request.ret));
3960 ✗ if (dir_request.play_if_no_dir)
3961 ✗ file_play(is, dir_request.path);
3962 ✗ } else if ((ret = file_list_show(dir_request.dl, 0)) < 0) {
3963 ✗ av_log(NULL, AV_LOG_ERROR, "Could not show the list: %s\n", av_err2str(ret));
3964 ✗ dir_list_free(&dir_request.dl);
3965 } else {
3966 ✗ dir_list_free(&dir_list);
3967 ✗ dir_list = dir_request.dl;
3968 ✗ dir_request.dl = NULL;
3969 ✗ list_view_clear_search(list);
3970 ✗ list_view_pin(list, 1);
3971 }
3972 ✗ av_freep(&dir_request.path);
3973 ✗ }
3974
3975 /* pins the file list, showing the directory listed last or else the directory of the input */
3976 ✗ static void file_list_open(VideoState *is)
3977 {
3978 ✗ const char *name = is->filename, *dir;
3979 char *path;
3980
3981 ✗ if (dir_list) {
3982 ✗ if (file_list_show(dir_list, -1) >= 0)
3983 ✗ list_view_pin(list, 1);
3984 ✗ return;
3985 }
3986 ✗ av_strstart(name, "file:", &name);
3987 ✗ if (!(path = av_strdup(name)))
3988 ✗ return;
3989 ✗ dir = av_dirname(path);
3990 ✗ file_list_read(*dir ? dir : "/", 0);
3991 ✗ av_free(path);
3992 }
3993
3994 /* lists the chosen directory, or plays the chosen file */
3995 ✗ static void file_list_choose(VideoState *is, int entry)
3996 {
3997 ✗ char *path = dir_list_path(dir_list, entry);
3998
3999 ✗ if (!path)
4000 ✗ return;
4001 ✗ if (entry < dir_list->nb_dirs + dir_list->nb_maybe_dirs)
4002 ✗ file_list_read(path, entry >= dir_list->nb_dirs);
4003 else
4004 ✗ file_play(is, path);
4005 ✗ av_free(path);
4006 }
4007
4008 ✗ static void list_choose(VideoState *is, int entry)
4009 {
4010 ✗ if (list_shows_files)
4011 ✗ file_list_choose(is, entry);
4012 else
4013 ✗ seek_chapter(is, entry);
4014 ✗ }
4015
4016 /* plays next_stream instead of the stream playing, which goes on from its position when next_stream has no video and
4017 * its audio cannot play */
4018 ✗ static VideoState *stream_replace(VideoState *is)
4019 {
4020 ✗ int audio_stream = is->audio_stream;
4021 ✗ double pos = get_master_clock(is);
4022
4023 ✗ stream_component_close(is, audio_stream);
4024 ✗ SDL_AtomicSet(&next_stream->replacement, 0);
4025 ✗ if (next_stream->audio_stream >= 0 && audio_start(next_stream) < 0) {
4026 ✗ stream_component_close(next_stream, next_stream->audio_stream);
4027 ✗ if (next_stream->video_stream < 0) {
4028 ✗ av_log(NULL, AV_LOG_ERROR, "Could not play '%s'\n", next_stream->filename);
4029 ✗ stream_close(next_stream);
4030 ✗ next_stream = NULL;
4031 ✗ if (audio_stream >= 0 && stream_component_open(is, audio_stream) < 0)
4032 ✗ av_log(NULL, AV_LOG_ERROR, "Could not reopen the audio of '%s'\n", is->filename);
4033 ✗ if (!is->seek_by_bytes && !isnan(pos))
4034 ✗ stream_seek(is, (int64_t)(pos * AV_TIME_BASE), 0, 0);
4035 ✗ return is;
4036 }
4037 }
4038 /* the chapter entries belong to the stream closed */
4039 ✗ if (!list_shows_files)
4040 ✗ list_view_clear(list);
4041 ✗ list_view_pin(list, 0);
4042 ✗ next_stream->width = is->width;
4043 ✗ next_stream->height = is->height;
4044 ✗ stream_close(is);
4045 ✗ is = next_stream;
4046 ✗ next_stream = NULL;
4047 ✗ SDL_SetWindowTitle(window, window_title ? window_title : is->title ? is->title : is->filename);
4048 ✗ toggle_pause(is);
4049 ✗ return is;
4050 }
4051
4052 /* handle an event sent by the GUI */
4053 ✗ static void event_loop(VideoState *cur_stream)
4054 {
4055 SDL_Event event;
4056 double incr, pos, frac;
4057 int chosen;
4058
4059 ✗ for (;;) {
4060 double x;
4061 ✗ refresh_loop_wait_event(cur_stream, &event);
4062 ✗ switch (event.type) {
4063 ✗ case SDL_KEYDOWN:
4064 ✗ if (exit_on_keydown || (!list_view_pinned(list) &&
4065 ✗ (event.key.keysym.sym == SDLK_ESCAPE || event.key.keysym.sym == SDLK_q))) {
4066 ✗ do_exit(cur_stream);
4067 ✗ break;
4068 }
4069 // If we don't yet have a window, skip all key events, because read_thread might still be initializing...
4070 ✗ if (!cur_stream->width)
4071 ✗ continue;
4072 ✗ if (list_view_pinned(list)) {
4073 ✗ if (!list_shows_files && (event.key.keysym.sym == SDLK_PAGEUP || event.key.keysym.sym == SDLK_PAGEDOWN))
4074 ✗ seek_chapter(cur_stream, current_chapter(cur_stream) + (event.key.keysym.sym == SDLK_PAGEUP ? 1 : -1));
4075 ✗ else if ((chosen = list_view_key(list, event.key.keysym.sym)) >= 0)
4076 ✗ list_choose(cur_stream, chosen);
4077 /* escape while a directory is being read for the list */
4078 ✗ if (dir_thread && !list_view_pinned(list)) {
4079 ✗ dir_request.cancelled = 1;
4080 ✗ SDL_AtomicSet(&dir_request.abort, 1);
4081 }
4082 ✗ break;
4083 }
4084 ✗ switch (event.key.keysym.sym) {
4085 ✗ case SDLK_f:
4086 ✗ toggle_full_screen(cur_stream);
4087 ✗ cur_stream->force_refresh = 1;
4088 ✗ break;
4089 ✗ case SDLK_p:
4090 case SDLK_SPACE:
4091 ✗ toggle_pause(cur_stream);
4092 ✗ break;
4093 ✗ case SDLK_m:
4094 ✗ toggle_mute(cur_stream);
4095 ✗ break;
4096 ✗ case SDLK_KP_MULTIPLY:
4097 case SDLK_0:
4098 ✗ update_volume(cur_stream, 1, SDL_VOLUME_STEP);
4099 ✗ break;
4100 ✗ case SDLK_KP_DIVIDE:
4101 case SDLK_9:
4102 ✗ update_volume(cur_stream, -1, SDL_VOLUME_STEP);
4103 ✗ break;
4104 ✗ case SDLK_s: // S: Step to next frame
4105 ✗ step_to_next_frame(cur_stream);
4106 ✗ break;
4107 ✗ case SDLK_a:
4108 ✗ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
4109 ✗ break;
4110 ✗ case SDLK_v:
4111 ✗ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
4112 ✗ break;
4113 ✗ case SDLK_c:
4114 ✗ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
4115 ✗ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
4116 ✗ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
4117 ✗ break;
4118 ✗ case SDLK_t:
4119 ✗ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
4120 ✗ break;
4121 ✗ case SDLK_l:
4122 ✗ list_key = cur_stream->ic->nb_chapters > 0 ? SDLK_l : 0;
4123 ✗ break;
4124 ✗ case SDLK_o:
4125 ✗ list_key = SDLK_o;
4126 ✗ break;
4127 ✗ case SDLK_RETURN:
4128 case SDLK_KP_ENTER:
4129 ✗ if (list_view_visible(list) && (chosen = list_view_selected(list)) >= 0)
4130 ✗ list_choose(cur_stream, chosen);
4131 ✗ break;
4132 ✗ case SDLK_w:
4133 ✗ if (cur_stream->show_mode == SHOW_MODE_VIDEO && cur_stream->vfilter_idx < nb_vfilters - 1) {
4134 ✗ if (++cur_stream->vfilter_idx >= nb_vfilters)
4135 ✗ cur_stream->vfilter_idx = 0;
4136 } else {
4137 ✗ cur_stream->vfilter_idx = 0;
4138 ✗ toggle_audio_display(cur_stream);
4139 }
4140 ✗ break;
4141 ✗ case SDLK_PAGEUP:
4142 ✗ if (cur_stream->ic->nb_chapters <= 1) {
4143 ✗ incr = 600.0;
4144 ✗ goto do_seek;
4145 }
4146 ✗ seek_chapter(cur_stream, current_chapter(cur_stream) + 1);
4147 ✗ break;
4148 ✗ case SDLK_PAGEDOWN:
4149 ✗ if (cur_stream->ic->nb_chapters <= 1) {
4150 ✗ incr = -600.0;
4151 ✗ goto do_seek;
4152 }
4153 ✗ seek_chapter(cur_stream, current_chapter(cur_stream) - 1);
4154 ✗ break;
4155 ✗ case SDLK_LEFT:
4156 ✗ incr = seek_interval ? -seek_interval : -10.0;
4157 ✗ goto do_seek;
4158 ✗ case SDLK_RIGHT:
4159 ✗ incr = seek_interval ? seek_interval : 10.0;
4160 ✗ goto do_seek;
4161 ✗ case SDLK_UP:
4162 ✗ incr = 60.0;
4163 ✗ goto do_seek;
4164 ✗ case SDLK_DOWN:
4165 ✗ incr = -60.0;
4166 ✗ do_seek:
4167 ✗ if (cur_stream->seek_by_bytes) {
4168 ✗ pos = -1;
4169 ✗ if (pos < 0 && cur_stream->video_stream >= 0)
4170 ✗ pos = frame_queue_last_pos(&cur_stream->pictq);
4171 ✗ if (pos < 0 && cur_stream->audio_stream >= 0)
4172 ✗ pos = frame_queue_last_pos(&cur_stream->sampq);
4173 ✗ if (pos < 0)
4174 ✗ pos = avio_tell(cur_stream->ic->pb);
4175 ✗ if (cur_stream->ic->bit_rate)
4176 ✗ incr *= cur_stream->ic->bit_rate / 8.0;
4177 else
4178 ✗ incr *= 180000.0;
4179 ✗ pos += incr;
4180 ✗ stream_seek(cur_stream, pos, incr, 1);
4181 } else {
4182 ✗ pos = get_master_clock(cur_stream);
4183 ✗ if (isnan(pos))
4184 ✗ pos = (double)cur_stream->seek_pos / AV_TIME_BASE;
4185 ✗ pos += incr;
4186 ✗ if (cur_stream->ic->start_time != AV_NOPTS_VALUE && pos < cur_stream->ic->start_time / (double)AV_TIME_BASE)
4187 ✗ pos = cur_stream->ic->start_time / (double)AV_TIME_BASE;
4188 ✗ stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
4189 }
4190 ✗ break;
4191 ✗ default:
4192 ✗ break;
4193 }
4194 ✗ break;
4195 ✗ case SDL_KEYUP:
4196 /* on the release of a press made while unpinned, so that the key's own text input does not start the search */
4197 ✗ if (list_key && event.key.keysym.sym == list_key) {
4198 ✗ if (list_key == SDLK_o)
4199 ✗ file_list_open(cur_stream);
4200 else
4201 ✗ chapter_list_pin(cur_stream);
4202 }
4203 ✗ list_key = 0;
4204 ✗ break;
4205 ✗ case SDL_TEXTINPUT:
4206 ✗ if (list_view_pinned(list))
4207 ✗ list_view_text(list, event.text.text);
4208 ✗ break;
4209 ✗ case SDL_MOUSEWHEEL:
4210 ✗ if (list_view_visible(list))
4211 ✗ list_view_move(list, -event.wheel.y);
4212 ✗ break;
4213 ✗ case SDL_MOUSEBUTTONDOWN:
4214 ✗ if (exit_on_mousedown) {
4215 ✗ do_exit(cur_stream);
4216 ✗ break;
4217 }
4218 ✗ if (event.button.button == SDL_BUTTON_LEFT && list_view_visible(list) &&
4219 ✗ list_view_click(list, event.button.x, event.button.y, &chosen)) {
4220 ✗ if (chosen >= 0)
4221 ✗ list_choose(cur_stream, chosen);
4222 ✗ break;
4223 }
4224 ✗ if (event.button.button == SDL_BUTTON_LEFT) {
4225 static int64_t last_mouse_left_click = 0;
4226 ✗ if (av_gettime_relative() - last_mouse_left_click <= 500000) {
4227 ✗ toggle_full_screen(cur_stream);
4228 ✗ cur_stream->force_refresh = 1;
4229 ✗ last_mouse_left_click = 0;
4230 } else {
4231 ✗ last_mouse_left_click = av_gettime_relative();
4232 }
4233 }
4234 av_fallthrough;
4235 case SDL_MOUSEMOTION:
4236 ✗ if (cursor_hidden) {
4237 ✗ SDL_ShowCursor(1);
4238 ✗ cursor_hidden = 0;
4239 }
4240 ✗ cursor_last_shown = av_gettime_relative();
4241 ✗ if (event.type == SDL_MOUSEMOTION)
4242 ✗ list_view_hover(list, event.motion.x, event.motion.y);
4243 ✗ if (event.type == SDL_MOUSEBUTTONDOWN) {
4244 ✗ if (event.button.button != SDL_BUTTON_RIGHT)
4245 ✗ break;
4246 ✗ x = event.button.x;
4247 } else {
4248 ✗ if (!(event.motion.state & SDL_BUTTON_RMASK))
4249 ✗ break;
4250 ✗ x = event.motion.x;
4251 }
4252 ✗ if (cur_stream->seek_by_bytes || cur_stream->ic->duration <= 0) {
4253 ✗ uint64_t size = avio_size(cur_stream->ic->pb);
4254 ✗ stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);
4255 } else {
4256 int64_t ts;
4257 int ns, hh, mm, ss;
4258 int tns, thh, tmm, tss;
4259 ✗ tns = cur_stream->ic->duration / 1000000LL;
4260 ✗ thh = tns / 3600;
4261 ✗ tmm = (tns % 3600) / 60;
4262 ✗ tss = (tns % 60);
4263 ✗ frac = x / cur_stream->width;
4264 ✗ ns = frac * tns;
4265 ✗ hh = ns / 3600;
4266 ✗ mm = (ns % 3600) / 60;
4267 ✗ ss = (ns % 60);
4268 ✗ av_log(NULL, AV_LOG_INFO,
4269 "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
4270 hh, mm, ss, thh, tmm, tss);
4271 ✗ ts = frac * cur_stream->ic->duration;
4272 ✗ if (cur_stream->ic->start_time != AV_NOPTS_VALUE)
4273 ✗ ts += cur_stream->ic->start_time;
4274 ✗ stream_seek(cur_stream, ts, 0, 0);
4275 }
4276 ✗ break;
4277 ✗ case SDL_WINDOWEVENT:
4278 ✗ switch (event.window.event) {
4279 ✗ case SDL_WINDOWEVENT_LEAVE:
4280 ✗ list_view_hover(list, -1, -1);
4281 ✗ break;
4282 ✗ case SDL_WINDOWEVENT_SIZE_CHANGED:
4283 ✗ screen_width = cur_stream->width = event.window.data1;
4284 ✗ screen_height = cur_stream->height = event.window.data2;
4285 ✗ if (cur_stream->vis_texture) {
4286 ✗ SDL_DestroyTexture(cur_stream->vis_texture);
4287 ✗ cur_stream->vis_texture = NULL;
4288 }
4289 ✗ list_view_set_size(list, screen_width, screen_height);
4290 ✗ if (vk_renderer)
4291 ✗ vk_renderer_resize(vk_renderer, screen_width, screen_height);
4292 av_fallthrough;
4293 case SDL_WINDOWEVENT_EXPOSED:
4294 ✗ cur_stream->force_refresh = 1;
4295 }
4296 ✗ break;
4297 ✗ case FF_READY_EVENT:
4298 ✗ if (next_stream && event.user.code == next_stream->id)
4299 ✗ cur_stream = stream_replace(cur_stream);
4300 ✗ break;
4301 ✗ case FF_QUIT_EVENT:
4302 ✗ if (next_stream && event.user.code == next_stream->id) {
4303 ✗ av_log(NULL, AV_LOG_ERROR, "Could not play '%s'\n", next_stream->filename);
4304 ✗ stream_close(next_stream);
4305 ✗ next_stream = NULL;
4306 }
4307 ✗ if (event.user.code != cur_stream->id)
4308 ✗ break;
4309 av_fallthrough;
4310 case SDL_QUIT:
4311 ✗ do_exit(cur_stream);
4312 ✗ break;
4313 ✗ default:
4314 ✗ break;
4315 }
4316 }
4317 }
4318
4319 ✗ static int opt_width(void *optctx, const char *opt, const char *arg)
4320 {
4321 double num;
4322 ✗ int ret = parse_number(opt, arg, OPT_TYPE_INT64, 1, INT_MAX, &num);
4323 ✗ if (ret < 0)
4324 ✗ return ret;
4325
4326 ✗ screen_width = num;
4327 ✗ return 0;
4328 }
4329
4330 ✗ static int opt_height(void *optctx, const char *opt, const char *arg)
4331 {
4332 double num;
4333 ✗ int ret = parse_number(opt, arg, OPT_TYPE_INT64, 1, INT_MAX, &num);
4334 ✗ if (ret < 0)
4335 ✗ return ret;
4336
4337 ✗ screen_height = num;
4338 ✗ return 0;
4339 }
4340
4341 ✗ static int opt_format(void *optctx, const char *opt, const char *arg)
4342 {
4343 ✗ file_iformat = av_find_input_format(arg);
4344 ✗ if (!file_iformat) {
4345 ✗ av_log(NULL, AV_LOG_FATAL, "Unknown input format: %s\n", arg);
4346 ✗ return AVERROR(EINVAL);
4347 }
4348 ✗ return 0;
4349 }
4350
4351 ✗ static int opt_sync(void *optctx, const char *opt, const char *arg)
4352 {
4353 ✗ if (!strcmp(arg, "audio"))
4354 ✗ av_sync_type = AV_SYNC_AUDIO_MASTER;
4355 ✗ else if (!strcmp(arg, "video"))
4356 ✗ av_sync_type = AV_SYNC_VIDEO_MASTER;
4357 ✗ else if (!strcmp(arg, "ext"))
4358 ✗ av_sync_type = AV_SYNC_EXTERNAL_CLOCK;
4359 else {
4360 ✗ av_log(NULL, AV_LOG_ERROR, "Unknown value for %s: %s\n", opt, arg);
4361 ✗ exit(1);
4362 }
4363 ✗ return 0;
4364 }
4365
4366 ✗ static int opt_show_mode(void *optctx, const char *opt, const char *arg)
4367 {
4368 ✗ show_mode = !strcmp(arg, "video") ? SHOW_MODE_VIDEO :
4369 ✗ !strcmp(arg, "waves") ? SHOW_MODE_WAVES :
4370 ✗ !strcmp(arg, "rdft" ) ? SHOW_MODE_RDFT :
4371 ✗ !strcmp(arg, "phase") ? SHOW_MODE_PHASE : SHOW_MODE_NONE;
4372
4373 ✗ if (show_mode == SHOW_MODE_NONE) {
4374 double num;
4375 ✗ int ret = parse_number(opt, arg, OPT_TYPE_INT, 0, SHOW_MODE_NB-1, &num);
4376 ✗ if (ret < 0)
4377 ✗ return ret;
4378 ✗ show_mode = num;
4379 }
4380 ✗ return 0;
4381 }
4382
4383 ✗ static int opt_input_file(void *optctx, const char *filename)
4384 {
4385 ✗ if (input_filename) {
4386 ✗ av_log(NULL, AV_LOG_FATAL,
4387 "Argument '%s' provided as input filename, but '%s' was already specified.\n",
4388 filename, input_filename);
4389 ✗ return AVERROR(EINVAL);
4390 }
4391 ✗ if (!strcmp(filename, "-"))
4392 ✗ filename = "fd:";
4393 ✗ input_filename = av_strdup(filename);
4394 ✗ if (!input_filename)
4395 ✗ return AVERROR(ENOMEM);
4396
4397 ✗ return 0;
4398 }
4399
4400 ✗ static int opt_codec(void *optctx, const char *opt, const char *arg)
4401 {
4402 ✗ const char *spec = strchr(opt, ':');
4403 const char **name;
4404 ✗ if (!spec) {
4405 ✗ av_log(NULL, AV_LOG_ERROR,
4406 "No media specifier was specified in '%s' in option '%s'\n",
4407 arg, opt);
4408 ✗ return AVERROR(EINVAL);
4409 }
4410 ✗ spec++;
4411
4412 ✗ switch (spec[0]) {
4413 ✗ case 'a' : name = &audio_codec_name; break;
4414 ✗ case 's' : name = &subtitle_codec_name; break;
4415 ✗ case 'v' : name = &video_codec_name; break;
4416 ✗ default:
4417 ✗ av_log(NULL, AV_LOG_ERROR,
4418 "Invalid media specifier '%s' in option '%s'\n", spec, opt);
4419 ✗ return AVERROR(EINVAL);
4420 }
4421
4422 ✗ av_freep(name);
4423 ✗ *name = av_strdup(arg);
4424 ✗ return *name ? 0 : AVERROR(ENOMEM);
4425 }
4426
4427 static int dummy;
4428
4429 static const OptionDef options[] = {
4430 CMDUTILS_COMMON_OPTIONS
4431 { "x", OPT_TYPE_FUNC, OPT_FUNC_ARG, { .func_arg = opt_width }, "force displayed width", "width" },
4432 { "y", OPT_TYPE_FUNC, OPT_FUNC_ARG, { .func_arg = opt_height }, "force displayed height", "height" },
4433 { "fs", OPT_TYPE_BOOL, 0, { &is_full_screen }, "force full screen" },
4434 { "an", OPT_TYPE_BOOL, 0, { &audio_disable }, "disable audio" },
4435 { "vn", OPT_TYPE_BOOL, 0, { &video_disable }, "disable video" },
4436 { "sn", OPT_TYPE_BOOL, 0, { &subtitle_disable }, "disable subtitling" },
4437 { "ast", OPT_TYPE_STRING, OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_specifier" },
4438 { "vst", OPT_TYPE_STRING, OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_specifier" },
4439 { "sst", OPT_TYPE_STRING, OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_specifier" },
4440 { "ss", OPT_TYPE_TIME, 0, { &start_time }, "seek to a given position in seconds", "pos" },
4441 { "t", OPT_TYPE_TIME, 0, { &duration }, "play \"duration\" seconds of audio/video", "duration" },
4442 { "bytes", OPT_TYPE_INT, 0, { &seek_by_bytes }, "seek by bytes 0=off 1=on -1=auto", "val" },
4443 { "seek_interval", OPT_TYPE_FLOAT, 0, { &seek_interval }, "set seek interval for left/right keys, in seconds", "seconds" },
4444 { "nodisp", OPT_TYPE_BOOL, 0, { &display_disable }, "disable graphical display" },
4445 { "noborder", OPT_TYPE_BOOL, 0, { &borderless }, "borderless window" },
4446 { "alwaysontop", OPT_TYPE_BOOL, 0, { &alwaysontop }, "window always on top" },
4447 { "volume", OPT_TYPE_INT, 0, { &startup_volume}, "set startup volume 0=min 100=max", "volume" },
4448 { "f", OPT_TYPE_FUNC, OPT_FUNC_ARG, { .func_arg = opt_format }, "force format", "fmt" },
4449 { "stats", OPT_TYPE_BOOL, OPT_EXPERT, { &show_status }, "show status", "" },
4450 { "fast", OPT_TYPE_BOOL, OPT_EXPERT, { &fast }, "non spec compliant optimizations", "" },
4451 { "genpts", OPT_TYPE_BOOL, OPT_EXPERT, { &genpts }, "generate pts", "" },
4452 { "drp", OPT_TYPE_INT, OPT_EXPERT, { &decoder_reorder_pts }, "let decoder reorder pts 0=off 1=on -1=auto", ""},
4453 { "lowres", OPT_TYPE_INT, OPT_EXPERT, { &lowres }, "", "" },
4454 { "sync", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT, { .func_arg = opt_sync }, "set audio-video sync. type (type=audio/video/ext)", "type" },
4455 { "autoexit", OPT_TYPE_BOOL, OPT_EXPERT, { &autoexit }, "exit at the end", "" },
4456 { "exitonkeydown", OPT_TYPE_BOOL, OPT_EXPERT, { &exit_on_keydown }, "exit on key down", "" },
4457 { "exitonmousedown", OPT_TYPE_BOOL, OPT_EXPERT, { &exit_on_mousedown }, "exit on mouse down", "" },
4458 { "loop", OPT_TYPE_INT, OPT_EXPERT, { &loop }, "set number of times the playback shall be looped", "loop count" },
4459 { "framedrop", OPT_TYPE_BOOL, OPT_EXPERT, { &framedrop }, "drop frames when cpu is too slow", "" },
4460 { "infbuf", OPT_TYPE_BOOL, OPT_EXPERT, { &infinite_buffer }, "don't limit the input buffer size (useful with realtime streams)", "" },
4461 { "window_title", OPT_TYPE_STRING, 0, { &window_title }, "set window title", "window title" },
4462 { "left", OPT_TYPE_INT, OPT_EXPERT, { &screen_left }, "set the x position for the left of the window", "x pos" },
4463 { "top", OPT_TYPE_INT, OPT_EXPERT, { &screen_top }, "set the y position for the top of the window", "y pos" },
4464 { "vf", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT, { .func_arg = opt_add_vfilter }, "set video filters", "filter_graph" },
4465 { "af", OPT_TYPE_STRING, 0, { &afilters }, "set audio filters", "filter_graph" },
4466 { "rdftspeed", OPT_TYPE_INT, OPT_AUDIO | OPT_EXPERT, { &rdftspeed }, "rdft speed", "msecs" },
4467 { "showmode", OPT_TYPE_FUNC, OPT_FUNC_ARG, { .func_arg = opt_show_mode}, "select show mode (0 = video, 1 = waves, 2 = RDFT, 3 = phase)", "mode" },
4468 { "i", OPT_TYPE_BOOL, 0, { &dummy}, "read specified file", "input_file"},
4469 { "codec", OPT_TYPE_FUNC, OPT_FUNC_ARG, { .func_arg = opt_codec}, "force decoder", "decoder_name" },
4470 { "acodec", OPT_TYPE_STRING, OPT_EXPERT, { &audio_codec_name }, "force audio decoder", "decoder_name" },
4471 { "scodec", OPT_TYPE_STRING, OPT_EXPERT, { &subtitle_codec_name }, "force subtitle decoder", "decoder_name" },
4472 { "vcodec", OPT_TYPE_STRING, OPT_EXPERT, { &video_codec_name }, "force video decoder", "decoder_name" },
4473 { "autorotate", OPT_TYPE_BOOL, 0, { &autorotate }, "automatically rotate video", "" },
4474 { "find_stream_info", OPT_TYPE_BOOL, OPT_INPUT | OPT_EXPERT, { &find_stream_info },
4475 "read and decode the streams to fill missing information with heuristics" },
4476 { "filter_threads", OPT_TYPE_INT, OPT_EXPERT, { &filter_nbthreads }, "number of filter threads per graph" },
4477 { "enable_vulkan", OPT_TYPE_BOOL, 0, { &enable_vulkan }, "enable vulkan renderer" },
4478 { "vulkan_params", OPT_TYPE_STRING, OPT_EXPERT, { &vulkan_params }, "vulkan configuration using a list of key=value pairs separated by ':'" },
4479 { "video_bg", OPT_TYPE_STRING, OPT_EXPERT, { &video_background }, "set video background for transparent videos" },
4480 { "hwaccel", OPT_TYPE_STRING, OPT_EXPERT, { &hwaccel }, "use HW accelerated decoding" },
4481 { NULL, },
4482 };
4483
4484 ✗ static void show_usage(void)
4485 {
4486 ✗ av_log(NULL, AV_LOG_INFO, "Simple media player\n");
4487 ✗ av_log(NULL, AV_LOG_INFO, "usage: %s [options] input_file\n", program_name);
4488 ✗ av_log(NULL, AV_LOG_INFO, "\n");
4489 ✗ }
4490
4491 ✗ void show_help_default(const char *opt, const char *arg)
4492 {
4493 ✗ av_log_set_callback(log_callback_help);
4494 ✗ show_usage();
4495 ✗ show_help_options(options, "Main options:", 0, OPT_EXPERT);
4496 ✗ show_help_options(options, "Advanced options:", OPT_EXPERT, 0);
4497 ✗ printf("\n");
4498 ✗ show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
4499 ✗ show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
4500 ✗ show_help_children(avfilter_get_class(), AV_OPT_FLAG_FILTERING_PARAM);
4501 ✗ printf("\nWhile playing:\n"
4502 "q, ESC quit\n"
4503 "f toggle full screen\n"
4504 "p, SPC pause\n"
4505 "m toggle mute\n"
4506 "9, 0 decrease and increase volume respectively\n"
4507 "/, * decrease and increase volume respectively\n"
4508 "a cycle audio channel in the current program\n"
4509 "v cycle video channel\n"
4510 "t cycle subtitle channel in the current program\n"
4511 "c cycle program\n"
4512 "w cycle video filters or show modes\n"
4513 "s activate frame-step mode\n"
4514 "left/right seek backward/forward by 10 seconds or a custom interval if -seek_interval is set\n"
4515 "down/up seek backward/forward 1 minute\n"
4516 "page down/page up seek to previous/next chapter or backward/forward 10 minutes if no chapters\n"
4517 "l keep the chapter list on screen; typing then filters it, down/up move its selection and escape closes it\n"
4518 "o list the directory of the input; enter or a click opens a directory or plays a file, escape closes the list\n"
4519 "enter seek to the chapter selected in the chapter list while it is shown\n"
4520 "mouse wheel move the chapter list selection while it is shown\n"
4521 "left click seek to the clicked chapter list entry, or sort the list by the clicked column, again to flip it;\n"
4522 " the left half of the shuffle button lowers its seed, the right half raises it\n"
4523 "mouse over (i) show the metadata of that chapter list entry\n"
4524 "right mouse click seek to percentage in file corresponding to fraction of width\n"
4525 "left double-click toggle full screen\n"
4526 );
4527 ✗ }
4528
4529 /* Called from the main */
4530 ✗ int main(int argc, char **argv)
4531 {
4532 int flags, ret;
4533 VideoState *is;
4534
4535 ✗ init_dynload();
4536
4537 ✗ av_log_set_flags(AV_LOG_SKIP_REPEATED);
4538 ✗ parse_loglevel(argc, argv, options);
4539
4540 /* register all codecs, demux and protocols */
4541 #if CONFIG_AVDEVICE
4542 ✗ avdevice_register_all();
4543 #endif
4544 ✗ avformat_network_init();
4545
4546 ✗ signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
4547 ✗ signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */
4548
4549 ✗ show_banner(argc, argv, options);
4550
4551 ✗ ret = parse_options(NULL, argc, argv, options, opt_input_file);
4552 ✗ if (ret < 0)
4553 ✗ exit(ret == AVERROR_EXIT ? 0 : 1);
4554
4555 ✗ if (!input_filename) {
4556 ✗ show_usage();
4557 ✗ av_log(NULL, AV_LOG_FATAL, "An input file must be specified\n");
4558 ✗ av_log(NULL, AV_LOG_FATAL,
4559 "Use -h to get full help or, even better, run 'man %s'\n", program_name);
4560 ✗ exit(1);
4561 }
4562
4563 ✗ if (display_disable) {
4564 ✗ video_disable = 1;
4565 }
4566 ✗ flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
4567 ✗ if (audio_disable)
4568 ✗ flags &= ~SDL_INIT_AUDIO;
4569 ✗ if (display_disable)
4570 ✗ flags &= ~SDL_INIT_VIDEO;
4571 ✗ if (SDL_Init (flags)) {
4572 ✗ av_log(NULL, AV_LOG_FATAL, "Could not initialize SDL - %s\n", SDL_GetError());
4573 ✗ av_log(NULL, AV_LOG_FATAL, "(Did you set the DISPLAY variable?)\n");
4574 ✗ exit(1);
4575 }
4576
4577 ✗ SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
4578 ✗ SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
4579
4580 ✗ if (!display_disable) {
4581 ✗ int flags = SDL_WINDOW_HIDDEN;
4582 ✗ if (alwaysontop)
4583 #if SDL_VERSION_ATLEAST(2,0,5)
4584 ✗ flags |= SDL_WINDOW_ALWAYS_ON_TOP;
4585 #else
4586 av_log(NULL, AV_LOG_WARNING, "Your SDL version doesn't support SDL_WINDOW_ALWAYS_ON_TOP. Feature will be inactive.\n");
4587 #endif
4588 ✗ if (borderless)
4589 ✗ flags |= SDL_WINDOW_BORDERLESS;
4590 else
4591 ✗ flags |= SDL_WINDOW_RESIZABLE;
4592
4593 #ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR
4594 ✗ SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
4595 #endif
4596 ✗ if (hwaccel && !enable_vulkan) {
4597 ✗ av_log(NULL, AV_LOG_INFO, "Enable vulkan renderer to support hwaccel %s\n", hwaccel);
4598 ✗ enable_vulkan = 1;
4599 }
4600 ✗ if (enable_vulkan) {
4601 ✗ vk_renderer = vk_get_renderer();
4602 ✗ if (vk_renderer) {
4603 #if SDL_VERSION_ATLEAST(2, 0, 6)
4604 ✗ flags |= SDL_WINDOW_VULKAN;
4605 #endif
4606 } else {
4607 ✗ av_log(NULL, AV_LOG_WARNING, "Doesn't support vulkan renderer, fallback to SDL renderer\n");
4608 ✗ enable_vulkan = 0;
4609 }
4610 }
4611 ✗ window = SDL_CreateWindow(program_name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, default_width, default_height, flags);
4612 ✗ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
4613 ✗ if (!window) {
4614 ✗ av_log(NULL, AV_LOG_FATAL, "Failed to create window: %s", SDL_GetError());
4615 ✗ do_exit(NULL);
4616 }
4617 SDL_version version;
4618 ✗ SDL_GetVersion(&version);
4619 /* SDL before 2.0.16 waits for events by polling */
4620 ✗ wait_for_events = SDL_VERSIONNUM(version.major, version.minor, version.patch) >= SDL_VERSIONNUM(2, 0, 16);
4621
4622 ✗ if (vk_renderer) {
4623 ✗ AVDictionary *dict = NULL;
4624
4625 ✗ if (vulkan_params) {
4626 ✗ int ret = av_dict_parse_string(&dict, vulkan_params, "=", ":", 0);
4627 ✗ if (ret < 0) {
4628 ✗ av_log(NULL, AV_LOG_FATAL, "Failed to parse, %s\n", vulkan_params);
4629 ✗ do_exit(NULL);
4630 }
4631 }
4632 ✗ ret = vk_renderer_create(vk_renderer, window, dict);
4633 ✗ av_dict_free(&dict);
4634 ✗ if (ret < 0) {
4635 ✗ av_log(NULL, AV_LOG_FATAL, "Failed to create vulkan renderer, %s\n", av_err2str(ret));
4636 ✗ do_exit(NULL);
4637 }
4638 } else {
4639 ✗ renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
4640 ✗ if (!renderer) {
4641 ✗ av_log(NULL, AV_LOG_WARNING, "Failed to initialize a hardware accelerated renderer: %s\n", SDL_GetError());
4642 ✗ renderer = SDL_CreateRenderer(window, -1, 0);
4643 }
4644 ✗ if (renderer) {
4645 ✗ if (!SDL_GetRendererInfo(renderer, &renderer_info))
4646 ✗ av_log(NULL, AV_LOG_VERBOSE, "Initialized %s renderer.\n", renderer_info.name);
4647 }
4648 ✗ if (!renderer || !renderer_info.num_texture_formats) {
4649 ✗ av_log(NULL, AV_LOG_FATAL, "Failed to create window or renderer: %s", SDL_GetError());
4650 ✗ do_exit(NULL);
4651 }
4652 }
4653 }
4654
4655 ✗ list = list_view_alloc(renderer);
4656 ✗ if (!list) {
4657 ✗ av_log(NULL, AV_LOG_FATAL, "Could not allocate the list\n");
4658 ✗ do_exit(NULL);
4659 }
4660 ✗ is = stream_open(input_filename, file_iformat, NULL);
4661 ✗ if (!is) {
4662 ✗ av_log(NULL, AV_LOG_FATAL, "Failed to initialize VideoState!\n");
4663 ✗ do_exit(NULL);
4664 }
4665
4666 ✗ event_loop(is);
4667
4668 /* never returns */
4669
4670 ✗ return 0;
4671 }
4672