#include "libavutil/samplefmt.h"
#include "libavutil/avassert.h"
#include "libavutil/time.h"
+#include "libavutil/bprint.h"
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
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 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;
#endif
static int autorotate = 1;
static int find_stream_info = 1;
+static int filter_nbthreads = 0;
/* current context */
static int is_full_screen;
if (packet_queue_get(d->queue, &pkt, 1, &d->pkt_serial) < 0)
return -1;
}
- } while (d->queue->serial != d->pkt_serial);
+ if (d->queue->serial == d->pkt_serial)
+ break;
+ av_packet_unref(&pkt);
+ } while (1);
if (pkt.data == flush_pkt.data) {
avcodec_flush_buffers(d->avctx);
int scr_xleft, int scr_ytop, int scr_width, int scr_height,
int pic_width, int pic_height, AVRational pic_sar)
{
- float aspect_ratio;
- int width, height, x, y;
+ AVRational aspect_ratio = pic_sar;
+ int64_t width, height, x, y;
- if (pic_sar.num == 0)
- aspect_ratio = 0;
- else
- aspect_ratio = av_q2d(pic_sar);
+ if (av_cmp_q(aspect_ratio, av_make_q(0, 1)) <= 0)
+ aspect_ratio = av_make_q(1, 1);
- if (aspect_ratio <= 0.0)
- aspect_ratio = 1.0;
- aspect_ratio *= (float)pic_width / (float)pic_height;
+ aspect_ratio = av_mul_q(aspect_ratio, av_make_q(pic_width, pic_height));
/* XXX: we suppose the screen has a 1.0 pixel ratio */
height = scr_height;
- width = lrint(height * aspect_ratio) & ~1;
+ width = av_rescale(height, aspect_ratio.num, aspect_ratio.den) & ~1;
if (width > scr_width) {
width = scr_width;
- height = lrint(width / aspect_ratio) & ~1;
+ height = av_rescale(width, aspect_ratio.den, aspect_ratio.num) & ~1;
}
x = (scr_width - width) / 2;
y = (scr_height - height) / 2;
rect->x = scr_xleft + x;
rect->y = scr_ytop + y;
- rect->w = FFMAX(width, 1);
- rect->h = FFMAX(height, 1);
+ rect->w = FFMAX((int)width, 1);
+ rect->h = FFMAX((int)height, 1);
}
static void get_sdl_pix_fmt_and_blendmode(int format, Uint32 *sdl_pix_fmt, SDL_BlendMode *sdl_blendmode)
static void set_default_window_size(int width, int height, AVRational sar)
{
SDL_Rect rect;
- calculate_display_rect(&rect, 0, 0, INT_MAX, height, width, height, sar);
+ int max_width = screen_width ? screen_width : INT_MAX;
+ int max_height = screen_height ? screen_height : INT_MAX;
+ if (max_width == INT_MAX && max_height == INT_MAX)
+ max_height = height;
+ calculate_display_rect(&rect, 0, 0, max_width, max_height, width, height, sar);
default_width = rect.w;
default_height = rect.h;
}
{
int w,h;
- if (screen_width) {
- w = screen_width;
- h = screen_height;
- } else {
- w = default_width;
- h = default_height;
- }
+ w = screen_width ? screen_width : default_width;
+ h = screen_height ? screen_height : default_height;
if (!window_title)
window_title = input_filename;
SDL_SetWindowTitle(window, window_title);
SDL_SetWindowSize(window, w, h);
- SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
+ SDL_SetWindowPosition(window, screen_left, screen_top);
if (is_full_screen)
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
SDL_ShowWindow(window);
}
is->force_refresh = 0;
if (show_status) {
+ AVBPrint buf;
static int64_t last_time;
int64_t cur_time;
int aqsize, vqsize, sqsize;
av_diff = get_master_clock(is) - get_clock(&is->vidclk);
else if (is->audio_st)
av_diff = get_master_clock(is) - get_clock(&is->audclk);
- av_log(NULL, AV_LOG_INFO,
- "%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64" \r",
- get_master_clock(is),
- (is->audio_st && is->video_st) ? "A-V" : (is->video_st ? "M-V" : (is->audio_st ? "M-A" : " ")),
- av_diff,
- is->frame_drops_early + is->frame_drops_late,
- aqsize / 1024,
- vqsize / 1024,
- sqsize,
- is->video_st ? is->viddec.avctx->pts_correction_num_faulty_dts : 0,
- is->video_st ? is->viddec.avctx->pts_correction_num_faulty_pts : 0);
- fflush(stdout);
+
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
+ av_bprintf(&buf,
+ "%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64" \r",
+ get_master_clock(is),
+ (is->audio_st && is->video_st) ? "A-V" : (is->video_st ? "M-V" : (is->audio_st ? "M-A" : " ")),
+ av_diff,
+ is->frame_drops_early + is->frame_drops_late,
+ aqsize / 1024,
+ vqsize / 1024,
+ sqsize,
+ is->video_st ? is->viddec.avctx->pts_correction_num_faulty_dts : 0,
+ is->video_st ? is->viddec.avctx->pts_correction_num_faulty_pts : 0);
+
+ if (show_status == 1 && AV_LOG_INFO > av_log_get_level())
+ fprintf(stderr, "%s", buf.str);
+ else
+ av_log(NULL, AV_LOG_INFO, "%s", buf.str);
+
+ fflush(stderr);
+ av_bprint_finalize(&buf, NULL);
+
last_time = cur_time;
}
}
avfilter_graph_free(&is->agraph);
if (!(is->agraph = avfilter_graph_alloc()))
return AVERROR(ENOMEM);
+ is->agraph->nb_threads = filter_nbthreads;
while ((e = av_dict_get(swr_opts, "", e, AV_DICT_IGNORE_SUFFIX)))
av_strlcatf(aresample_swr_opts, sizeof(aresample_swr_opts), "%s=%s:", e->key, e->value);
if (force_output_format) {
channel_layouts[0] = is->audio_tgt.channel_layout;
- channels [0] = is->audio_tgt.channels;
+ channels [0] = is->audio_tgt.channel_layout ? -1 : is->audio_tgt.channels;
sample_rates [0] = is->audio_tgt.freq;
if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 0, AV_OPT_SEARCH_CHILDREN)) < 0)
goto end;
return ret;
}
-static int decoder_start(Decoder *d, int (*fn)(void *), void *arg)
+static int decoder_start(Decoder *d, int (*fn)(void *), const char *thread_name, void* arg)
{
packet_queue_start(d->queue);
- d->decoder_tid = SDL_CreateThread(fn, "decoder", arg);
+ d->decoder_tid = SDL_CreateThread(fn, thread_name, arg);
if (!d->decoder_tid) {
av_log(NULL, AV_LOG_ERROR, "SDL_CreateThread(): %s\n", SDL_GetError());
return AVERROR(ENOMEM);
AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL);
#if CONFIG_AVFILTER
- AVFilterGraph *graph = avfilter_graph_alloc();
+ AVFilterGraph *graph = NULL;
AVFilterContext *filt_out = NULL, *filt_in = NULL;
int last_w = 0;
int last_h = 0;
enum AVPixelFormat last_format = -2;
int last_serial = -1;
int last_vfilter_idx = 0;
- if (!graph) {
- av_frame_free(&frame);
- return AVERROR(ENOMEM);
- }
-
#endif
- if (!frame) {
-#if CONFIG_AVFILTER
- avfilter_graph_free(&graph);
-#endif
+ if (!frame)
return AVERROR(ENOMEM);
- }
for (;;) {
ret = get_video_frame(is, frame);
(const char *)av_x_if_null(av_get_pix_fmt_name(frame->format), "none"), is->viddec.pkt_serial);
avfilter_graph_free(&graph);
graph = avfilter_graph_alloc();
+ if (!graph) {
+ ret = AVERROR(ENOMEM);
+ goto the_end;
+ }
+ graph->nb_threads = filter_nbthreads;
if ((ret = configure_video_filters(graph, is, vfilters_list ? vfilters_list[is->vfilter_idx] : NULL, frame)) < 0) {
SDL_Event event;
event.type = FF_QUIT_EVENT;
is->auddec.start_pts = is->audio_st->start_time;
is->auddec.start_pts_tb = is->audio_st->time_base;
}
- if ((ret = decoder_start(&is->auddec, audio_thread, is)) < 0)
+ if ((ret = decoder_start(&is->auddec, audio_thread, "audio_decoder", is)) < 0)
goto out;
SDL_PauseAudioDevice(audio_dev, 0);
break;
is->video_st = ic->streams[stream_index];
decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread);
- if ((ret = decoder_start(&is->viddec, video_thread, is)) < 0)
+ if ((ret = decoder_start(&is->viddec, video_thread, "video_decoder", is)) < 0)
goto out;
is->queue_attachments_req = 1;
break;
is->subtitle_st = ic->streams[stream_index];
decoder_init(&is->subdec, avctx, &is->subtitleq, is->continue_read_thread);
- if ((ret = decoder_start(&is->subdec, subtitle_thread, is)) < 0)
+ if ((ret = decoder_start(&is->subdec, subtitle_thread, "subtitle_decoder", is)) < 0)
goto out;
break;
default:
}
memset(st_index, -1, sizeof(st_index));
- is->last_video_stream = is->video_stream = -1;
- is->last_audio_stream = is->audio_stream = -1;
- is->last_subtitle_stream = is->subtitle_stream = -1;
is->eof = 0;
ic = avformat_alloc_context();
}
if (is->queue_attachments_req) {
if (is->video_st && is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC) {
- AVPacket copy = { 0 };
+ AVPacket copy;
if ((ret = av_packet_ref(©, &is->video_st->attached_pic)) < 0)
goto fail;
packet_queue_put(&is->videoq, ©);
packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream);
is->eof = 1;
}
- if (ic->pb && ic->pb->error)
- break;
+ if (ic->pb && ic->pb->error) {
+ if (autoexit)
+ goto fail;
+ else
+ break;
+ }
SDL_LockMutex(wait_mutex);
SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
SDL_UnlockMutex(wait_mutex);
is = av_mallocz(sizeof(VideoState));
if (!is)
return NULL;
+ is->last_video_stream = is->video_stream = -1;
+ is->last_audio_stream = is->audio_stream = -1;
+ is->last_subtitle_stream = is->subtitle_stream = -1;
is->filename = av_strdup(filename);
if (!is->filename)
goto fail;
seek_chapter(cur_stream, -1);
break;
case SDLK_LEFT:
- incr = -10.0;
+ incr = seek_interval ? -seek_interval : -10.0;
goto do_seek;
case SDLK_RIGHT:
- incr = 10.0;
+ incr = seek_interval ? seek_interval : 10.0;
goto do_seek;
case SDLK_UP:
incr = 60.0;
break;
case SDL_WINDOWEVENT:
switch (event.window.event) {
- case SDL_WINDOWEVENT_RESIZED:
+ case SDL_WINDOWEVENT_SIZE_CHANGED:
screen_width = cur_stream->width = event.window.data1;
screen_height = cur_stream->height = event.window.data2;
if (cur_stream->vis_texture) {
{ "ss", HAS_ARG, { .func_arg = opt_seek }, "seek to a given position in seconds", "pos" },
{ "t", HAS_ARG, { .func_arg = opt_duration }, "play \"duration\" seconds of audio/video", "duration" },
{ "bytes", OPT_INT | HAS_ARG, { &seek_by_bytes }, "seek by bytes 0=off 1=on -1=auto", "val" },
+ { "seek_interval", OPT_FLOAT | HAS_ARG, { &seek_interval }, "set seek interval for left/right keys, in seconds", "seconds" },
{ "nodisp", OPT_BOOL, { &display_disable }, "disable graphical display" },
{ "noborder", OPT_BOOL, { &borderless }, "borderless window" },
+ { "alwaysontop", OPT_BOOL, { &alwaysontop }, "window always on top" },
{ "volume", OPT_INT | HAS_ARG, { &startup_volume}, "set startup volume 0=min 100=max", "volume" },
{ "f", HAS_ARG, { .func_arg = opt_format }, "force format", "fmt" },
{ "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_frame_pix_fmt }, "set pixel format", "format" },
{ "framedrop", OPT_BOOL | OPT_EXPERT, { &framedrop }, "drop frames when cpu is too slow", "" },
{ "infbuf", OPT_BOOL | OPT_EXPERT, { &infinite_buffer }, "don't limit the input buffer size (useful with realtime streams)", "" },
{ "window_title", OPT_STRING | HAS_ARG, { &window_title }, "set window title", "window title" },
+ { "left", OPT_INT | HAS_ARG | OPT_EXPERT, { &screen_left }, "set the x position for the left of the window", "x pos" },
+ { "top", OPT_INT | HAS_ARG | OPT_EXPERT, { &screen_top }, "set the y position for the top of the window", "y pos" },
#if CONFIG_AVFILTER
{ "vf", OPT_EXPERT | HAS_ARG, { .func_arg = opt_add_vfilter }, "set video filters", "filter_graph" },
{ "af", OPT_STRING | HAS_ARG, { &afilters }, "set audio filters", "filter_graph" },
{ "autorotate", OPT_BOOL, { &autorotate }, "automatically rotate video", "" },
{ "find_stream_info", OPT_BOOL | OPT_INPUT | OPT_EXPERT, { &find_stream_info },
"read and decode the streams to fill missing information with heuristics" },
+ { "filter_threads", HAS_ARG | OPT_INT | OPT_EXPERT, { &filter_nbthreads }, "number of filter threads per graph" },
{ NULL, },
};
"c cycle program\n"
"w cycle video filters or show modes\n"
"s activate frame-step mode\n"
- "left/right seek backward/forward 10 seconds\n"
+ "left/right seek backward/forward 10 seconds or to custom interval if -seek_interval is set\n"
"down/up seek backward/forward 1 minute\n"
"page down/page up seek backward/forward 10 minutes\n"
"right mouse click seek to percentage in file corresponding to fraction of width\n"
if (!display_disable) {
int flags = SDL_WINDOW_HIDDEN;
+ if (alwaysontop)
+#if SDL_VERSION_ATLEAST(2,0,5)
+ flags |= SDL_WINDOW_ALWAYS_ON_TOP;
+#else
+ av_log(NULL, AV_LOG_WARNING, "Your SDL version doesn't support SDL_WINDOW_ALWAYS_ON_TOP. Feature will be inactive.\n");
+#endif
if (borderless)
flags |= SDL_WINDOW_BORDERLESS;
else