Newer
Older
Fabrice Bellard
committed
static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
{
VideoState *is;
is = av_mallocz(sizeof(VideoState));
if (!is)
return NULL;
av_strlcpy(is->filename, filename, sizeof(is->filename));
Fabrice Bellard
committed
is->iformat = iformat;
/* start video display */
is->pictq_mutex = SDL_CreateMutex();
is->subpq_mutex = SDL_CreateMutex();
packet_queue_init(&is->videoq);
packet_queue_init(&is->audioq);
packet_queue_init(&is->subtitleq);
is->continue_read_thread = SDL_CreateCond();
init_clock(&is->vidclk, &is->videoq.serial);
init_clock(&is->audclk, &is->audioq.serial);
init_clock(&is->extclk, &is->extclk.serial);
is->audio_clock_serial = -1;
Fabrice Bellard
committed
is->av_sync_type = av_sync_type;
is->read_tid = SDL_CreateThread(read_thread, is);
if (!is->read_tid) {
av_free(is);
return NULL;
}
return is;
}
Stefan Huehner
committed
static void stream_cycle_channel(VideoState *is, int codec_type)
Fabrice Bellard
committed
{
AVFormatContext *ic = is->ic;
int start_index, stream_index;
Fabrice Bellard
committed
AVStream *st;
Marton Balint
committed
AVProgram *p = NULL;
int nb_streams = is->ic->nb_streams;
Fabrice Bellard
committed
if (codec_type == AVMEDIA_TYPE_VIDEO) {
start_index = is->last_video_stream;
old_index = is->video_stream;
} else if (codec_type == AVMEDIA_TYPE_AUDIO) {
start_index = is->last_audio_stream;
old_index = is->audio_stream;
} else {
start_index = is->last_subtitle_stream;
old_index = is->subtitle_stream;
}
Fabrice Bellard
committed
stream_index = start_index;
Marton Balint
committed
if (codec_type != AVMEDIA_TYPE_VIDEO && is->video_stream != -1) {
p = av_find_program_from_stream(ic, NULL, is->video_stream);
if (p) {
nb_streams = p->nb_stream_indexes;
for (start_index = 0; start_index < nb_streams; start_index++)
if (p->stream_index[start_index] == stream_index)
break;
if (start_index == nb_streams)
start_index = -1;
stream_index = start_index;
}
}
Marton Balint
committed
if (++stream_index >= nb_streams)
{
if (codec_type == AVMEDIA_TYPE_SUBTITLE)
{
stream_index = -1;
is->last_subtitle_stream = -1;
goto the_end;
}
if (start_index == -1)
return;
stream_index = 0;
}
Fabrice Bellard
committed
if (stream_index == start_index)
return;
Marton Balint
committed
st = is->ic->streams[p ? p->stream_index[stream_index] : stream_index];
Michael Niedermayer
committed
if (st->codec->codec_type == codec_type) {
Fabrice Bellard
committed
/* check that parameters are OK */
case AVMEDIA_TYPE_AUDIO:
Michael Niedermayer
committed
if (st->codec->sample_rate != 0 &&
st->codec->channels != 0)
Fabrice Bellard
committed
goto the_end;
break;
case AVMEDIA_TYPE_VIDEO:
case AVMEDIA_TYPE_SUBTITLE:
Fabrice Bellard
committed
goto the_end;
default:
break;
}
}
}
the_end:
Marton Balint
committed
if (p && stream_index != -1)
stream_index = p->stream_index[stream_index];
stream_component_close(is, old_index);
Fabrice Bellard
committed
stream_component_open(is, stream_index);
}
static void toggle_full_screen(VideoState *is)
#if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
Hanspeter Niederstrasser
committed
/* OS X needs to reallocate the SDL overlays */
int i;
for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
is->pictq[i].reallocate = 1;
#endif
is_full_screen = !is_full_screen;
static void toggle_audio_display(VideoState *is)
int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
int next = is->show_mode;
do {
next = (next + 1) % SHOW_MODE_NB;
} while (next != is->show_mode && (next == SHOW_MODE_VIDEO && !is->video_st || next != SHOW_MODE_VIDEO && !is->audio_st));
if (is->show_mode != next) {
fill_rectangle(screen,
is->xleft, is->ytop, is->width, is->height,
bgcolor, 1);
is->force_refresh = 1;
is->show_mode = next;
}
static void refresh_loop_wait_event(VideoState *is, SDL_Event *event) {
double remaining_time = 0.0;
SDL_PumpEvents();
while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS)) {
if (!cursor_hidden && av_gettime() - cursor_last_shown > CURSOR_HIDE_DELAY) {
SDL_ShowCursor(0);
cursor_hidden = 1;
}
if (remaining_time > 0.0)
av_usleep((int64_t)(remaining_time * 1000000.0));
remaining_time = REFRESH_RATE;
if (is->show_mode != SHOW_MODE_NONE && (!is->paused || is->force_refresh))
video_refresh(is, &remaining_time);
SDL_PumpEvents();
}
static void event_loop(VideoState *cur_stream)
Michel Bardiaux
committed
double incr, pos, frac;
refresh_loop_wait_event(cur_stream, &event);
if (exit_on_keydown) {
break;
}
toggle_full_screen(cur_stream);
cur_stream->force_refresh = 1;
toggle_pause(cur_stream);
step_to_next_frame(cur_stream);
Wolfgang Hesseler
committed
break;
stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
Fabrice Bellard
committed
break;
case SDLK_v:
stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
Fabrice Bellard
committed
break;
case SDLK_c:
stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
break;
case SDLK_t:
stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
break;
Fabrice Bellard
committed
case SDLK_w:
toggle_audio_display(cur_stream);
case SDLK_PAGEUP:
incr = 600.0;
goto do_seek;
case SDLK_PAGEDOWN:
incr = -600.0;
goto do_seek;
case SDLK_LEFT:
incr = -10.0;
goto do_seek;
case SDLK_RIGHT:
incr = 10.0;
goto do_seek;
case SDLK_UP:
incr = 60.0;
goto do_seek;
case SDLK_DOWN:
incr = -60.0;
do_seek:
if (cur_stream->video_stream >= 0 && cur_stream->video_current_pos >= 0) {
pos = cur_stream->video_current_pos;
} else if (cur_stream->audio_stream >= 0 && cur_stream->audio_pkt.pos >= 0) {
pos = cur_stream->audio_pkt.pos;
} else
pos = avio_tell(cur_stream->ic->pb);
incr *= cur_stream->ic->bit_rate / 8.0;
else
incr *= 180000.0;
pos += incr;
Michael Niedermayer
committed
stream_seek(cur_stream, pos, incr, 1);
} else {
pos = get_master_clock(cur_stream);
if (isnan(pos))
pos = (double)cur_stream->seek_pos / AV_TIME_BASE;
if (cur_stream->ic->start_time != AV_NOPTS_VALUE && pos < cur_stream->ic->start_time / (double)AV_TIME_BASE)
pos = cur_stream->ic->start_time / (double)AV_TIME_BASE;
Michael Niedermayer
committed
stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
case SDL_VIDEOEXPOSE:
cur_stream->force_refresh = 1;
break;
Michel Bardiaux
committed
case SDL_MOUSEBUTTONDOWN:
if (exit_on_mousedown) {
break;
}
if (cursor_hidden) {
SDL_ShowCursor(1);
cursor_hidden = 0;
}
cursor_last_shown = av_gettime();
if (event.type == SDL_MOUSEBUTTONDOWN) {
x = event.button.x;
} else {
if (event.motion.state != SDL_PRESSED)
if (seek_by_bytes || cur_stream->ic->duration <= 0) {
uint64_t size = avio_size(cur_stream->ic->pb);
stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);
int64_t ts;
int ns, hh, mm, ss;
int tns, thh, tmm, tss;
tns = cur_stream->ic->duration / 1000000LL;
thh = tns / 3600;
tmm = (tns % 3600) / 60;
tss = (tns % 60);
frac = x / cur_stream->width;
ns = frac * tns;
hh = ns / 3600;
mm = (ns % 3600) / 60;
ss = (ns % 60);
av_log(NULL, AV_LOG_INFO,
"Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
if (cur_stream->ic->start_time != AV_NOPTS_VALUE)
ts += cur_stream->ic->start_time;
stream_seek(cur_stream, ts, 0, 0);
Michael Niedermayer
committed
}
screen = SDL_SetVideoMode(FFMIN(16383, event.resize.w), event.resize.h, 0,
SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
av_log(NULL, AV_LOG_FATAL, "Failed to set video mode\n");
do_exit(cur_stream);
}
screen_width = cur_stream->width = screen->w;
screen_height = cur_stream->height = screen->h;
cur_stream->force_refresh = 1;
Fabrice Bellard
committed
case FF_QUIT_EVENT:
break;
case FF_ALLOC_EVENT:
alloc_picture(event.user.data1);
break;
default:
break;
}
}
}
static int opt_frame_size(void *optctx, const char *opt, const char *arg)
Limin Wang
committed
{
av_log(NULL, AV_LOG_WARNING, "Option -s is deprecated, use -video_size.\n");
return opt_default(NULL, "video_size", arg);
Limin Wang
committed
}
static int opt_width(void *optctx, const char *opt, const char *arg)
screen_width = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
return 0;
static int opt_height(void *optctx, const char *opt, const char *arg)
screen_height = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
return 0;
static int opt_format(void *optctx, const char *opt, const char *arg)
{
file_iformat = av_find_input_format(arg);
if (!file_iformat) {
av_log(NULL, AV_LOG_FATAL, "Unknown input format: %s\n", arg);
Fabrice Bellard
committed
static int opt_frame_pix_fmt(void *optctx, const char *opt, const char *arg)
Limin Wang
committed
{
av_log(NULL, AV_LOG_WARNING, "Option -pix_fmt is deprecated, use -pixel_format.\n");
return opt_default(NULL, "pixel_format", arg);
Limin Wang
committed
}
static int opt_sync(void *optctx, const char *opt, const char *arg)
Fabrice Bellard
committed
{
if (!strcmp(arg, "audio"))
av_sync_type = AV_SYNC_AUDIO_MASTER;
else if (!strcmp(arg, "video"))
av_sync_type = AV_SYNC_VIDEO_MASTER;
else if (!strcmp(arg, "ext"))
av_sync_type = AV_SYNC_EXTERNAL_CLOCK;
av_log(NULL, AV_LOG_ERROR, "Unknown value for %s: %s\n", opt, arg);
return 0;
Fabrice Bellard
committed
}
static int opt_seek(void *optctx, const char *opt, const char *arg)
start_time = parse_time_or_die(opt, arg, 1);
return 0;
static int opt_duration(void *optctx, const char *opt, const char *arg)
{
duration = parse_time_or_die(opt, arg, 1);
return 0;
}
static int opt_show_mode(void *optctx, const char *opt, const char *arg)
{
show_mode = !strcmp(arg, "video") ? SHOW_MODE_VIDEO :
!strcmp(arg, "waves") ? SHOW_MODE_WAVES :
!strcmp(arg, "rdft" ) ? SHOW_MODE_RDFT :
parse_number_or_die(opt, arg, OPT_INT, 0, SHOW_MODE_NB-1);
return 0;
}
static void opt_input_file(void *optctx, const char *filename)
{
if (input_filename) {
av_log(NULL, AV_LOG_FATAL,
"Argument '%s' provided as input filename, but '%s' was already specified.\n",
filename, input_filename);
}
if (!strcmp(filename, "-"))
filename = "pipe:";
input_filename = filename;
}
Stefano Sabatini
committed
static int opt_codec(void *optctx, const char *opt, const char *arg)
{
Stefano Sabatini
committed
const char *spec = strchr(opt, ':');
if (!spec) {
av_log(NULL, AV_LOG_ERROR,
"No media specifier was specified in '%s' in option '%s'\n",
Stefano Sabatini
committed
arg, opt);
return AVERROR(EINVAL);
}
spec++;
switch (spec[0]) {
case 'a' : audio_codec_name = arg; break;
case 's' : subtitle_codec_name = arg; break;
case 'v' : video_codec_name = arg; break;
default:
av_log(NULL, AV_LOG_ERROR,
"Invalid media specifier '%s' in option '%s'\n", spec, opt);
Stefano Sabatini
committed
return AVERROR(EINVAL);
}
return 0;
}
static int dummy;
Diego Pettenò
committed
static const OptionDef options[] = {
#include "cmdutils_common_opts.h"
{ "x", HAS_ARG, { .func_arg = opt_width }, "force displayed width", "width" },
{ "y", HAS_ARG, { .func_arg = opt_height }, "force displayed height", "height" },
{ "s", HAS_ARG | OPT_VIDEO, { .func_arg = opt_frame_size }, "set frame size (WxH or abbreviation)", "size" },
{ "fs", OPT_BOOL, { &is_full_screen }, "force full screen" },
{ "an", OPT_BOOL, { &audio_disable }, "disable audio" },
{ "vn", OPT_BOOL, { &video_disable }, "disable video" },
{ "sn", OPT_BOOL, { &subtitle_disable }, "disable subtitling" },
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
{ "ast", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_number" },
{ "vst", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_number" },
{ "sst", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_number" },
{ "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" },
{ "nodisp", OPT_BOOL, { &display_disable }, "disable graphical display" },
{ "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" },
{ "stats", OPT_BOOL | OPT_EXPERT, { &show_status }, "show status", "" },
{ "bug", OPT_INT | HAS_ARG | OPT_EXPERT, { &workaround_bugs }, "workaround bugs", "" },
{ "fast", OPT_BOOL | OPT_EXPERT, { &fast }, "non spec compliant optimizations", "" },
{ "genpts", OPT_BOOL | OPT_EXPERT, { &genpts }, "generate pts", "" },
{ "drp", OPT_INT | HAS_ARG | OPT_EXPERT, { &decoder_reorder_pts }, "let decoder reorder pts 0=off 1=on -1=auto", ""},
{ "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, { &lowres }, "", "" },
{ "ec", OPT_INT | HAS_ARG | OPT_EXPERT, { &error_concealment }, "set error concealment options", "bit_mask" },
{ "sync", HAS_ARG | OPT_EXPERT, { .func_arg = opt_sync }, "set audio-video sync. type (type=audio/video/ext)", "type" },
{ "autoexit", OPT_BOOL | OPT_EXPERT, { &autoexit }, "exit at the end", "" },
{ "exitonkeydown", OPT_BOOL | OPT_EXPERT, { &exit_on_keydown }, "exit on key down", "" },
{ "exitonmousedown", OPT_BOOL | OPT_EXPERT, { &exit_on_mousedown }, "exit on mouse down", "" },
{ "loop", OPT_INT | HAS_ARG | OPT_EXPERT, { &loop }, "set number of times the playback shall be looped", "loop count" },
{ "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" },
{ "vf", OPT_STRING | HAS_ARG, { &vfilters }, "set video filters", "filter_graph" },
{ "af", OPT_STRING | HAS_ARG, { &afilters }, "set audio filters", "filter_graph" },
{ "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, { &rdftspeed }, "rdft speed", "msecs" },
{ "showmode", HAS_ARG, { .func_arg = opt_show_mode}, "select show mode (0 = video, 1 = waves, 2 = RDFT)", "mode" },
{ "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { .func_arg = opt_default }, "generic catch all option", "" },
{ "i", OPT_BOOL, { &dummy}, "read specified file", "input_file"},
Stefano Sabatini
committed
{ "codec", HAS_ARG, { .func_arg = opt_codec}, "force decoder", "decoder_name" },
{ "acodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &audio_codec_name }, "force audio decoder", "decoder_name" },
{ "scodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &subtitle_codec_name }, "force subtitle decoder", "decoder_name" },
{ "vcodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &video_codec_name }, "force video decoder", "decoder_name" },
av_log(NULL, AV_LOG_INFO, "Simple media player\n");
av_log(NULL, AV_LOG_INFO, "usage: %s [options] input_file\n", program_name);
av_log(NULL, AV_LOG_INFO, "\n");
void show_help_default(const char *opt, const char *arg)
av_log_set_callback(log_callback_help);
show_help_options(options, "Main options:", 0, OPT_EXPERT, 0);
show_help_options(options, "Advanced options:", OPT_EXPERT, 0, 0);
show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
show_help_children(sws_get_class(), AV_OPT_FLAG_ENCODING_PARAM);
#else
show_help_children(avfilter_get_class(), AV_OPT_FLAG_FILTERING_PARAM);
printf("\nWhile playing:\n"
"q, ESC quit\n"
"f toggle full screen\n"
"p, SPC pause\n"
Fabrice Bellard
committed
"a cycle audio channel\n"
"v cycle video channel\n"
"t cycle subtitle channel\n"
"c cycle program\n"
Fabrice Bellard
committed
"w show audio waves\n"
"s activate frame-step mode\n"
"left/right seek backward/forward 10 seconds\n"
"down/up seek backward/forward 1 minute\n"
"page down/page up seek backward/forward 10 minutes\n"
Michel Bardiaux
committed
"mouse click seek to percentage in file corresponding to fraction of width\n"
static int lockmgr(void **mtx, enum AVLockOp op)
{
switch(op) {
case AV_LOCK_CREATE:
*mtx = SDL_CreateMutex();
if(!*mtx)
return 1;
return 0;
case AV_LOCK_OBTAIN:
return !!SDL_LockMutex(*mtx);
case AV_LOCK_RELEASE:
return !!SDL_UnlockMutex(*mtx);
case AV_LOCK_DESTROY:
SDL_DestroyMutex(*mtx);
return 0;
}
return 1;
}
/* Called from the main */
int main(int argc, char **argv)
{
int flags;
char dummy_videodriver[] = "SDL_VIDEODRIVER=dummy";
av_log_set_flags(AV_LOG_SKIP_REPEATED);
parse_loglevel(argc, argv, options);
#if CONFIG_AVDEVICE
#endif
#if CONFIG_AVFILTER
avfilter_register_all();
#endif
avformat_network_init();
init_opts();
signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */
show_banner(argc, argv, options);
parse_options(NULL, argc, argv, options, opt_input_file);
if (!input_filename) {
av_log(NULL, AV_LOG_FATAL, "An input file must be specified\n");
av_log(NULL, AV_LOG_FATAL,
"Use -h to get full help or, even better, run 'man %s'\n", program_name);
if (display_disable) {
video_disable = 1;
}
flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
if (audio_disable)
flags &= ~SDL_INIT_AUDIO;
if (display_disable)
SDL_putenv(dummy_videodriver); /* For the event queue, we always need a video driver. */
#if !defined(__MINGW32__) && !defined(__APPLE__)
flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */
av_log(NULL, AV_LOG_FATAL, "Could not initialize SDL - %s\n", SDL_GetError());
av_log(NULL, AV_LOG_FATAL, "(Did you set the DISPLAY variable?)\n");
exit(1);
}
if (!display_disable) {
const SDL_VideoInfo *vi = SDL_GetVideoInfo();
fs_screen_width = vi->current_w;
fs_screen_height = vi->current_h;
}
SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
if (av_lockmgr_register(lockmgr)) {
av_log(NULL, AV_LOG_FATAL, "Could not initialize lock manager!\n");
do_exit(NULL);
}
is = stream_open(input_filename, file_iformat);
if (!is) {
av_log(NULL, AV_LOG_FATAL, "Failed to initialize VideoState!\n");
do_exit(NULL);
}
/* never returns */
return 0;
}