/* * Copyright (c) 2003 Fabrice Bellard * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * simple media player based on the FFmpeg libraries */ #include "config.h"#include "config_components.h"#include <math.h>#include <limits.h>#include <signal.h>#include <stdint.h> #include "libavutil/avstring.h"#include "libavutil/channel_layout.h"#include "libavutil/mathematics.h"#include "libavutil/mem.h"#include "libavutil/pixdesc.h"#include "libavutil/dict.h"#include "libavutil/fifo.h"#include "libavutil/samplefmt.h"#include "libavutil/time.h"#include "libavutil/bprint.h"#include "libavformat/avformat.h"#include "libavdevice/avdevice.h"#include "libswscale/swscale.h"#include "libavutil/opt.h"#include "libavutil/tx.h"#include "libswresample/swresample.h" #include "libavfilter/avfilter.h"#include "libavfilter/buffersink.h"#include "libavfilter/buffersrc.h" #include <SDL.h>#include <SDL_thread.h> #include "cmdutils.h"#include "ffplay_renderer.h"#include "opt_common.h" const char program_name[] = "ffplay";const int program_birth_year = 2003; #define MAX_QUEUE_SIZE (15 * 1024 * 1024)#define MIN_FRAMES 25#define EXTERNAL_CLOCK_MIN_FRAMES 2#define EXTERNAL_CLOCK_MAX_FRAMES 10 /* Minimum SDL audio buffer size, in samples. */#define SDL_AUDIO_MIN_BUFFER_SIZE 512/* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */#define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30 /* Step size for volume control in dB */#define SDL_VOLUME_STEP (0.75) /* no AV sync correction is done if below the minimum AV sync threshold */#define AV_SYNC_THRESHOLD_MIN 0.04/* AV sync correction is done if above the maximum AV sync threshold */#define AV_SYNC_THRESHOLD_MAX 0.1/* If a frame duration is longer than this, it will not be duplicated to compensate AV sync */#define AV_SYNC_FRAMEDUP_THRESHOLD 0.1/* no AV correction is done if too big error */#define AV_NOSYNC_THRESHOLD 10.0 /* maximum audio speed change to get correct sync */#define SAMPLE_CORRECTION_PERCENT_MAX 10 /* external clock speed adjustment constants for realtime sources based on buffer fullness */#define EXTERNAL_CLOCK_SPEED_MIN 0.900#define EXTERNAL_CLOCK_SPEED_MAX 1.010#define EXTERNAL_CLOCK_SPEED_STEP 0.001 /* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */#define AUDIO_DIFF_AVG_NB 20 /* polls for possible required screen refresh at least this often, should be less than 1/fps */#define REFRESH_RATE 0.01 /* NOTE: the size must be big enough to compensate the hardware audio buffersize size *//* TODO: We assume that a decoded and resampled frame fits into this buffer */#define SAMPLE_ARRAY_SIZE (8 * 65536) #define CURSOR_HIDE_DELAY 1000000 #define USE_ONEPASS_SUBTITLE_RENDER 1 typedef struct MyAVPacketList { AVPacket *pkt; int serial;} MyAVPacketList; typedef struct PacketQueue { AVFifo *pkt_list; int nb_packets; int size; int64_t duration; int abort_request; int serial; SDL_mutex *mutex; SDL_cond *cond;} PacketQueue; #define VIDEO_PICTURE_QUEUE_SIZE 3#define SUBPICTURE_QUEUE_SIZE 16#define SAMPLE_QUEUE_SIZE 9#define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE)) typedef struct AudioParams { int freq; AVChannelLayout ch_layout; enum AVSampleFormat fmt; int frame_size; int bytes_per_sec;} AudioParams; typedef struct Clock { double pts; /* clock base */ double pts_drift; /* clock base minus time at which we updated the clock */ double last_updated; double speed; int serial; /* clock is based on a packet with this serial */ int paused; int *queue_serial; /* pointer to the current packet queue serial, used for obsolete clock detection */} Clock; typedef struct FrameData { int64_t pkt_pos;} FrameData; /* Common struct for handling all types of decoded data and allocated render buffers. */typedef struct Frame { AVFrame *frame; AVSubtitle sub; int serial; double pts; /* presentation timestamp for the frame */ double duration; /* estimated duration of the frame */ int64_t pos; /* byte position of the frame in the input file */ int width; int height; int format; AVRational sar; int uploaded; int flip_v;} Frame; typedef struct FrameQueue { Frame queue[FRAME_QUEUE_SIZE]; int rindex; int windex; int size; int max_size; int keep_last; int rindex_shown; SDL_mutex *mutex; SDL_cond *cond; PacketQueue *pktq;} FrameQueue; enum { AV_SYNC_AUDIO_MASTER, /* default choice */ AV_SYNC_VIDEO_MASTER, AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */}; typedef struct Decoder { AVPacket *pkt; PacketQueue *queue; AVCodecContext *avctx; int pkt_serial; int finished; int packet_pending; SDL_cond *empty_queue_cond; int64_t start_pts; AVRational start_pts_tb; int64_t next_pts; AVRational next_pts_tb; SDL_Thread *decoder_tid;} Decoder; typedef struct VideoState { SDL_Thread *read_tid; const AVInputFormat *iformat; int abort_request; int force_refresh; int paused; int last_paused; int queue_attachments_req; int seek_req; int seek_flags; int64_t seek_pos; int64_t seek_rel; int read_pause_return; AVFormatContext *ic; int realtime; Clock audclk; Clock vidclk; Clock extclk; FrameQueue pictq; FrameQueue subpq; FrameQueue sampq; Decoder auddec; Decoder viddec; Decoder subdec; int audio_stream; int av_sync_type; double audio_clock; int audio_clock_serial; double audio_diff_cum; /* used for AV difference average computation */ double audio_diff_avg_coef; double audio_diff_threshold; int audio_diff_avg_count; AVStream *audio_st; PacketQueue audioq; int audio_hw_buf_size; uint8_t *audio_buf; uint8_t *audio_buf1; unsigned int audio_buf_size; /* in bytes */ unsigned int audio_buf1_size; int audio_buf_index; /* in bytes */ int audio_write_buf_size; int audio_volume; int muted; struct AudioParams audio_src; struct AudioParams audio_filter_src; struct AudioParams audio_tgt; struct SwrContext *swr_ctx; int frame_drops_early; int frame_drops_late; enum ShowMode { SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB } show_mode; int16_t sample_array[SAMPLE_ARRAY_SIZE]; int sample_array_index; int last_i_start; AVTXContext *rdft; av_tx_fn rdft_fn; int rdft_bits; float *real_data; AVComplexFloat *rdft_data; int xpos; double last_vis_time; SDL_Texture *vis_texture; SDL_Texture *sub_texture; SDL_Texture *vid_texture; int subtitle_stream; AVStream *subtitle_st; PacketQueue subtitleq; double frame_timer; double frame_last_returned_time; double frame_last_filter_delay; int video_stream; AVStream *video_st; PacketQueue videoq; double max_frame_duration; // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity struct SwsContext *sub_convert_ctx; int eof; char *filename; int width, height, xleft, ytop; int step; int vfilter_idx; AVFilterContext *in_video_filter; // the first filter in the video chain AVFilterContext *out_video_filter; // the last filter in the video chain AVFilterContext *in_audio_filter; // the first filter in the audio chain AVFilterContext *out_audio_filter; // the last filter in the audio chain AVFilterGraph *agraph; // audio filter graph int last_video_stream, last_audio_stream, last_subtitle_stream; SDL_cond *continue_read_thread;} VideoState; /* options specified by the user */static const AVInputFormat *file_iformat;static const char *input_filename;static const char *window_title;static int default_width = 640;static int default_height = 480;static int screen_width = 0;static int screen_height = 0;static int screen_left = SDL_WINDOWPOS_CENTERED;static int screen_top = SDL_WINDOWPOS_CENTERED;static int audio_disable;static int video_disable;static int subtitle_disable;static const char* wanted_stream_spec[AVMEDIA_TYPE_NB] = {0};static int seek_by_bytes = -1;static float seek_interval = 10;static int display_disable;static int borderless;static int alwaysontop;static int startup_volume = 100;static int show_status = -1;static int av_sync_type = AV_SYNC_AUDIO_MASTER;static int64_t start_time = AV_NOPTS_VALUE;static int64_t duration = AV_NOPTS_VALUE;static int fast = 0;static int genpts = 0;static int lowres = 0;static int decoder_reorder_pts = -1;static int autoexit;static int exit_on_keydown;static int exit_on_mousedown;static int loop = 1;static int framedrop = -1;static int infinite_buffer = -1;static enum ShowMode show_mode = SHOW_MODE_NONE;static const char *audio_codec_name;static const char *subtitle_codec_name;static const char *video_codec_name;double rdftspeed = 0.02;static int64_t cursor_last_shown;static int cursor_hidden = 0;static const char **vfilters_list = NULL;static int nb_vfilters = 0;static char *afilters = NULL;static int autorotate = 1;static int find_stream_info = 1;static int filter_nbthreads = 0;static int enable_vulkan = 0;static char *vulkan_params = NULL;static const char *hwaccel = NULL; /* current context */static int is_full_screen;static int64_t audio_callback_time; #define FF_QUIT_EVENT (SDL_USEREVENT + 2) static SDL_Window *window;static SDL_Renderer *renderer;static SDL_RendererInfo renderer_info = {0};static SDL_AudioDeviceID audio_dev; static VkRenderer *vk_renderer; static const struct TextureFormatEntry { enum AVPixelFormat format; int texture_fmt;} sdl_texture_format_map[] = { { AV_PIX_FMT_RGB8, SDL_PIXELFORMAT_RGB332 }, { AV_PIX_FMT_RGB444, SDL_PIXELFORMAT_RGB444 }, { AV_PIX_FMT_RGB555, SDL_PIXELFORMAT_RGB555 }, { AV_PIX_FMT_BGR555, SDL_PIXELFORMAT_BGR555 }, { AV_PIX_FMT_RGB565, SDL_PIXELFORMAT_RGB565 }, { AV_PIX_FMT_BGR565, SDL_PIXELFORMAT_BGR565 }, { AV_PIX_FMT_RGB24, SDL_PIXELFORMAT_RGB24 }, { AV_PIX_FMT_BGR24, SDL_PIXELFORMAT_BGR24 }, { AV_PIX_FMT_0RGB32, SDL_PIXELFORMAT_RGB888 }, { AV_PIX_FMT_0BGR32, SDL_PIXELFORMAT_BGR888 }, { AV_PIX_FMT_NE(RGB0, 0BGR), SDL_PIXELFORMAT_RGBX8888 }, { AV_PIX_FMT_NE(BGR0, 0RGB), SDL_PIXELFORMAT_BGRX8888 }, { AV_PIX_FMT_RGB32, SDL_PIXELFORMAT_ARGB8888 }, { AV_PIX_FMT_RGB32_1, SDL_PIXELFORMAT_RGBA8888 }, { AV_PIX_FMT_BGR32, SDL_PIXELFORMAT_ABGR8888 }, { AV_PIX_FMT_BGR32_1, SDL_PIXELFORMAT_BGRA8888 }, { AV_PIX_FMT_YUV420P, SDL_PIXELFORMAT_IYUV }, { AV_PIX_FMT_YUYV422, SDL_PIXELFORMAT_YUY2 }, { AV_PIX_FMT_UYVY422, SDL_PIXELFORMAT_UYVY },}; static int opt_add_vfilter(void *optctx, const char *opt, const char *arg){ int ret = GROW_ARRAY(vfilters_list, nb_vfilters); if (ret < 0) return ret; vfilters_list[nb_vfilters - 1] = av_strdup(arg); if (!vfilters_list[nb_vfilters - 1]) return AVERROR(ENOMEM); return 0;} static inlineint cmp_audio_fmts(enum AVSampleFormat fmt1, int64_t channel_count1, enum AVSampleFormat fmt2, int64_t channel_count2){ /* If channel count == 1, planar and non-planar formats are the same */ if (channel_count1 == 1 && channel_count2 == 1) return av_get_packed_sample_fmt(fmt1) != av_get_packed_sample_fmt(fmt2); else return channel_count1 != channel_count2 || fmt1 != fmt2;} static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt){ MyAVPacketList pkt1; int ret; if (q->abort_request) return -1; pkt1.pkt = pkt; pkt1.serial = q->serial; ret = av_fifo_write(q->pkt_list, &pkt1, 1); if (ret < 0) return ret; q->nb_packets++; q->size += pkt1.pkt->size + sizeof(pkt1); q->duration += pkt1.pkt->duration; /* XXX: should duplicate packet data in DV case */ SDL_CondSignal(q->cond); return 0;} static int packet_queue_put(PacketQueue *q, AVPacket *pkt){ AVPacket *pkt1; int ret; pkt1 = av_packet_alloc(); if (!pkt1) { av_packet_unref(pkt); return -1; } av_packet_move_ref(pkt1, pkt); SDL_LockMutex(q->mutex); ret = packet_queue_put_private(q, pkt1); SDL_UnlockMutex(q->mutex); if (ret < 0) av_packet_free(&pkt1); return ret;} static int packet_queue_put_nullpacket(PacketQueue *q, AVPacket *pkt, int stream_index){ pkt->stream_index = stream_index; return packet_queue_put(q, pkt);} /* packet queue handling */static int packet_queue_init(PacketQueue *q){ memset(q, 0, sizeof(PacketQueue)); q->pkt_list = av_fifo_alloc2(1, sizeof(MyAVPacketList), AV_FIFO_FLAG_AUTO_GROW); if (!q->pkt_list) return AVERROR(ENOMEM); q->mutex = SDL_CreateMutex(); if (!q->mutex) { av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError()); return AVERROR(ENOMEM); } q->cond = SDL_CreateCond(); if (!q->cond) { av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError()); return AVERROR(ENOMEM); } q->abort_request = 1; return 0;} static void packet_queue_flush(PacketQueue *q){ MyAVPacketList pkt1; SDL_LockMutex(q->mutex); while (av_fifo_read(q->pkt_list, &pkt1, 1) >= 0) av_packet_free(&pkt1.pkt); q->nb_packets = 0; q->size = 0; q->duration = 0; q->serial++; SDL_UnlockMutex(q->mutex);Lines 1–500 of 3895. Load more
/* * Copyright (c) 2003 Fabrice Bellard * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * simple media player based on the FFmpeg libraries */ #include "config.h" #include "config_components.h" #include <math.h> #include <limits.h> #include <signal.h> #include <stdint.h> #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/mathematics.h" #include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/dict.h" #include "libavutil/fifo.h" #include "libavutil/samplefmt.h" #include "libavutil/time.h" #include "libavutil/bprint.h" #include "libavformat/avformat.h" #include "libavdevice/avdevice.h" #include "libswscale/swscale.h" #include "libavutil/opt.h" #include "libavutil/tx.h" #include "libswresample/swresample.h" #include "libavfilter/avfilter.h" #include "libavfilter/buffersink.h" #include "libavfilter/buffersrc.h" #include <SDL.h> #include <SDL_thread.h> #include "cmdutils.h" #include "ffplay_renderer.h" #include "opt_common.h" const char program_name[] = "ffplay"; const int program_birth_year = 2003; #define MAX_QUEUE_SIZE (15 * 1024 * 1024) #define MIN_FRAMES 25 #define EXTERNAL_CLOCK_MIN_FRAMES 2 #define EXTERNAL_CLOCK_MAX_FRAMES 10 /* Minimum SDL audio buffer size, in samples. */ #define SDL_AUDIO_MIN_BUFFER_SIZE 512 /* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */ #define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30 /* Step size for volume control in dB */ #define SDL_VOLUME_STEP (0.75) /* no AV sync correction is done if below the minimum AV sync threshold */ #define AV_SYNC_THRESHOLD_MIN 0.04 /* AV sync correction is done if above the maximum AV sync threshold */ #define AV_SYNC_THRESHOLD_MAX 0.1 /* If a frame duration is longer than this, it will not be duplicated to compensate AV sync */ #define AV_SYNC_FRAMEDUP_THRESHOLD 0.1 /* no AV correction is done if too big error */ #define AV_NOSYNC_THRESHOLD 10.0 /* maximum audio speed change to get correct sync */ #define SAMPLE_CORRECTION_PERCENT_MAX 10 /* external clock speed adjustment constants for realtime sources based on buffer fullness */ #define EXTERNAL_CLOCK_SPEED_MIN 0.900 #define EXTERNAL_CLOCK_SPEED_MAX 1.010 #define EXTERNAL_CLOCK_SPEED_STEP 0.001 /* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */ #define AUDIO_DIFF_AVG_NB 20 /* polls for possible required screen refresh at least this often, should be less than 1/fps */ #define REFRESH_RATE 0.01 /* NOTE: the size must be big enough to compensate the hardware audio buffersize size */ /* TODO: We assume that a decoded and resampled frame fits into this buffer */ #define SAMPLE_ARRAY_SIZE (8 * 65536) #define CURSOR_HIDE_DELAY 1000000 #define USE_ONEPASS_SUBTITLE_RENDER 1 typedef struct MyAVPacketList { AVPacket *pkt; int serial; } MyAVPacketList; typedef struct PacketQueue { AVFifo *pkt_list; int nb_packets; int size; int64_t duration; int abort_request; int serial; SDL_mutex *mutex; SDL_cond *cond; } PacketQueue; #define VIDEO_PICTURE_QUEUE_SIZE 3 #define SUBPICTURE_QUEUE_SIZE 16 #define SAMPLE_QUEUE_SIZE 9 #define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE)) typedef struct AudioParams { int freq; AVChannelLayout ch_layout; enum AVSampleFormat fmt; int frame_size; int bytes_per_sec; } AudioParams; typedef struct Clock { double pts; /* clock base */ double pts_drift; /* clock base minus time at which we updated the clock */ double last_updated; double speed; int serial; /* clock is based on a packet with this serial */ int paused; int *queue_serial; /* pointer to the current packet queue serial, used for obsolete clock detection */ } Clock; typedef struct FrameData { int64_t pkt_pos; } FrameData; /* Common struct for handling all types of decoded data and allocated render buffers. */ typedef struct Frame { AVFrame *frame; AVSubtitle sub; int serial; double pts; /* presentation timestamp for the frame */ double duration; /* estimated duration of the frame */ int64_t pos; /* byte position of the frame in the input file */ int width; int height; int format; AVRational sar; int uploaded; int flip_v; } Frame; typedef struct FrameQueue { Frame queue[FRAME_QUEUE_SIZE]; int rindex; int windex; int size; int max_size; int keep_last; int rindex_shown; SDL_mutex *mutex; SDL_cond *cond; PacketQueue *pktq; } FrameQueue; enum { AV_SYNC_AUDIO_MASTER, /* default choice */ AV_SYNC_VIDEO_MASTER, AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */ }; typedef struct Decoder { AVPacket *pkt; PacketQueue *queue; AVCodecContext *avctx; int pkt_serial; int finished; int packet_pending; SDL_cond *empty_queue_cond; int64_t start_pts; AVRational start_pts_tb; int64_t next_pts; AVRational next_pts_tb; SDL_Thread *decoder_tid; } Decoder; typedef struct VideoState { SDL_Thread *read_tid; const AVInputFormat *iformat; int abort_request; int force_refresh; int paused; int last_paused; int queue_attachments_req; int seek_req; int seek_flags; int64_t seek_pos; int64_t seek_rel; int read_pause_return; AVFormatContext *ic; int realtime; Clock audclk; Clock vidclk; Clock extclk; FrameQueue pictq; FrameQueue subpq; FrameQueue sampq; Decoder auddec; Decoder viddec; Decoder subdec; int audio_stream; int av_sync_type; double audio_clock; int audio_clock_serial; double audio_diff_cum; /* used for AV difference average computation */ double audio_diff_avg_coef; double audio_diff_threshold; int audio_diff_avg_count; AVStream *audio_st; PacketQueue audioq; int audio_hw_buf_size; uint8_t *audio_buf; uint8_t *audio_buf1; unsigned int audio_buf_size; /* in bytes */ unsigned int audio_buf1_size; int audio_buf_index; /* in bytes */ int audio_write_buf_size; int audio_volume; int muted; struct AudioParams audio_src; struct AudioParams audio_filter_src; struct AudioParams audio_tgt; struct SwrContext *swr_ctx; int frame_drops_early; int frame_drops_late; enum ShowMode { SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB } show_mode; int16_t sample_array[SAMPLE_ARRAY_SIZE]; int sample_array_index; int last_i_start; AVTXContext *rdft; av_tx_fn rdft_fn; int rdft_bits; float *real_data; AVComplexFloat *rdft_data; int xpos; double last_vis_time; SDL_Texture *vis_texture; SDL_Texture *sub_texture; SDL_Texture *vid_texture; int subtitle_stream; AVStream *subtitle_st; PacketQueue subtitleq; double frame_timer; double frame_last_returned_time; double frame_last_filter_delay; int video_stream; AVStream *video_st; PacketQueue videoq; double max_frame_duration; // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity struct SwsContext *sub_convert_ctx; int eof; char *filename; int width, height, xleft, ytop; int step; int vfilter_idx; AVFilterContext *in_video_filter; // the first filter in the video chain AVFilterContext *out_video_filter; // the last filter in the video chain AVFilterContext *in_audio_filter; // the first filter in the audio chain AVFilterContext *out_audio_filter; // the last filter in the audio chain AVFilterGraph *agraph; // audio filter graph int last_video_stream, last_audio_stream, last_subtitle_stream; SDL_cond *continue_read_thread; } VideoState; /* options specified by the user */ static const AVInputFormat *file_iformat; static const char *input_filename; static const char *window_title; static int default_width = 640; static int default_height = 480; static int screen_width = 0; static int screen_height = 0; static int screen_left = SDL_WINDOWPOS_CENTERED; static int screen_top = SDL_WINDOWPOS_CENTERED; static int audio_disable; static int video_disable; static int subtitle_disable; static const char* wanted_stream_spec[AVMEDIA_TYPE_NB] = {0}; static int seek_by_bytes = -1; static float seek_interval = 10; static int display_disable; static int borderless; static int alwaysontop; static int startup_volume = 100; static int show_status = -1; static int av_sync_type = AV_SYNC_AUDIO_MASTER; static int64_t start_time = AV_NOPTS_VALUE; static int64_t duration = AV_NOPTS_VALUE; static int fast = 0; static int genpts = 0; static int lowres = 0; static int decoder_reorder_pts = -1; static int autoexit; static int exit_on_keydown; static int exit_on_mousedown; static int loop = 1; static int framedrop = -1; static int infinite_buffer = -1; static enum ShowMode show_mode = SHOW_MODE_NONE; static const char *audio_codec_name; static const char *subtitle_codec_name; static const char *video_codec_name; double rdftspeed = 0.02; static int64_t cursor_last_shown; static int cursor_hidden = 0; static const char **vfilters_list = NULL; static int nb_vfilters = 0; static char *afilters = NULL; static int autorotate = 1; static int find_stream_info = 1; static int filter_nbthreads = 0; static int enable_vulkan = 0; static char *vulkan_params = NULL; static const char *hwaccel = NULL; /* current context */ static int is_full_screen; static int64_t audio_callback_time; #define FF_QUIT_EVENT (SDL_USEREVENT + 2) static SDL_Window *window; static SDL_Renderer *renderer; static SDL_RendererInfo renderer_info = {0}; static SDL_AudioDeviceID audio_dev; static VkRenderer *vk_renderer; static const struct TextureFormatEntry { enum AVPixelFormat format; int texture_fmt; } sdl_texture_format_map[] = { { AV_PIX_FMT_RGB8, SDL_PIXELFORMAT_RGB332 }, { AV_PIX_FMT_RGB444, SDL_PIXELFORMAT_RGB444 }, { AV_PIX_FMT_RGB555, SDL_PIXELFORMAT_RGB555 }, { AV_PIX_FMT_BGR555, SDL_PIXELFORMAT_BGR555 }, { AV_PIX_FMT_RGB565, SDL_PIXELFORMAT_RGB565 }, { AV_PIX_FMT_BGR565, SDL_PIXELFORMAT_BGR565 }, { AV_PIX_FMT_RGB24, SDL_PIXELFORMAT_RGB24 }, { AV_PIX_FMT_BGR24, SDL_PIXELFORMAT_BGR24 }, { AV_PIX_FMT_0RGB32, SDL_PIXELFORMAT_RGB888 }, { AV_PIX_FMT_0BGR32, SDL_PIXELFORMAT_BGR888 }, { AV_PIX_FMT_NE(RGB0, 0BGR), SDL_PIXELFORMAT_RGBX8888 }, { AV_PIX_FMT_NE(BGR0, 0RGB), SDL_PIXELFORMAT_BGRX8888 }, { AV_PIX_FMT_RGB32, SDL_PIXELFORMAT_ARGB8888 }, { AV_PIX_FMT_RGB32_1, SDL_PIXELFORMAT_RGBA8888 }, { AV_PIX_FMT_BGR32, SDL_PIXELFORMAT_ABGR8888 }, { AV_PIX_FMT_BGR32_1, SDL_PIXELFORMAT_BGRA8888 }, { AV_PIX_FMT_YUV420P, SDL_PIXELFORMAT_IYUV }, { AV_PIX_FMT_YUYV422, SDL_PIXELFORMAT_YUY2 }, { AV_PIX_FMT_UYVY422, SDL_PIXELFORMAT_UYVY }, }; static int opt_add_vfilter(void *optctx, const char *opt, const char *arg) { int ret = GROW_ARRAY(vfilters_list, nb_vfilters); if (ret < 0) return ret; vfilters_list[nb_vfilters - 1] = av_strdup(arg); if (!vfilters_list[nb_vfilters - 1]) return AVERROR(ENOMEM); return 0; } static inline int cmp_audio_fmts(enum AVSampleFormat fmt1, int64_t channel_count1, enum AVSampleFormat fmt2, int64_t channel_count2) { /* If channel count == 1, planar and non-planar formats are the same */ if (channel_count1 == 1 && channel_count2 == 1) return av_get_packed_sample_fmt(fmt1) != av_get_packed_sample_fmt(fmt2); else return channel_count1 != channel_count2 || fmt1 != fmt2; } static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt) { MyAVPacketList pkt1; int ret; if (q->abort_request) return -1; pkt1.pkt = pkt; pkt1.serial = q->serial; ret = av_fifo_write(q->pkt_list, &pkt1, 1); if (ret < 0) return ret; q->nb_packets++; q->size += pkt1.pkt->size + sizeof(pkt1); q->duration += pkt1.pkt->duration; /* XXX: should duplicate packet data in DV case */ SDL_CondSignal(q->cond); return 0; } static int packet_queue_put(PacketQueue *q, AVPacket *pkt) { AVPacket *pkt1; int ret; pkt1 = av_packet_alloc(); if (!pkt1) { av_packet_unref(pkt); return -1; } av_packet_move_ref(pkt1, pkt); SDL_LockMutex(q->mutex); ret = packet_queue_put_private(q, pkt1); SDL_UnlockMutex(q->mutex); if (ret < 0) av_packet_free(&pkt1); return ret; } static int packet_queue_put_nullpacket(PacketQueue *q, AVPacket *pkt, int stream_index) { pkt->stream_index = stream_index; return packet_queue_put(q, pkt); } /* packet queue handling */ static int packet_queue_init(PacketQueue *q) { memset(q, 0, sizeof(PacketQueue)); q->pkt_list = av_fifo_alloc2(1, sizeof(MyAVPacketList), AV_FIFO_FLAG_AUTO_GROW); if (!q->pkt_list) return AVERROR(ENOMEM); q->mutex = SDL_CreateMutex(); if (!q->mutex) { av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError()); return AVERROR(ENOMEM); } q->cond = SDL_CreateCond(); if (!q->cond) { av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError()); return AVERROR(ENOMEM); } q->abort_request = 1; return 0; } static void packet_queue_flush(PacketQueue *q) { MyAVPacketList pkt1; SDL_LockMutex(q->mutex); while (av_fifo_read(q->pkt_list, &pkt1, 1) >= 0) av_packet_free(&pkt1.pkt); q->nb_packets = 0; q->size = 0; q->duration = 0; q->serial++; SDL_UnlockMutex(q->mutex);