Newer
Older
}
is->ytop = 0;
is->xleft = 0;
/* start video display */
is->pictq_mutex = SDL_CreateMutex();
is->pictq_cond = SDL_CreateCond();
is->subpq_mutex = SDL_CreateMutex();
is->subpq_cond = SDL_CreateCond();
is->subtitle_decoder_mutex = SDL_CreateMutex();
is->audio_decoder_mutex = SDL_CreateMutex();
is->video_decoder_mutex = SDL_CreateMutex();
/* add the refresh timer to draw the picture */
schedule_refresh(is, 40);
Fabrice Bellard
committed
is->av_sync_type = av_sync_type;
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
is->parse_tid = SDL_CreateThread(decode_thread, is);
if (!is->parse_tid) {
av_free(is);
return NULL;
}
return is;
}
static void stream_close(VideoState *is)
{
VideoPicture *vp;
int i;
/* XXX: use a special url_shutdown call to abort parse cleanly */
is->abort_request = 1;
SDL_WaitThread(is->parse_tid, NULL);
/* free all pictures */
for(i=0;i<VIDEO_PICTURE_QUEUE_SIZE; i++) {
vp = &is->pictq[i];
if (vp->bmp) {
SDL_FreeYUVOverlay(vp->bmp);
vp->bmp = NULL;
}
}
SDL_DestroyMutex(is->pictq_mutex);
SDL_DestroyCond(is->pictq_cond);
SDL_DestroyMutex(is->subpq_mutex);
SDL_DestroyCond(is->subpq_cond);
SDL_DestroyMutex(is->subtitle_decoder_mutex);
SDL_DestroyMutex(is->audio_decoder_mutex);
SDL_DestroyMutex(is->video_decoder_mutex);
Fabrice Bellard
committed
void stream_cycle_channel(VideoState *is, int codec_type)
{
AVFormatContext *ic = is->ic;
int start_index, stream_index;
AVStream *st;
if (codec_type == CODEC_TYPE_VIDEO)
start_index = is->video_stream;
else if (codec_type == CODEC_TYPE_AUDIO)
Fabrice Bellard
committed
start_index = is->audio_stream;
else
start_index = is->subtitle_stream;
if (start_index < (codec_type == CODEC_TYPE_SUBTITLE ? -1 : 0))
Fabrice Bellard
committed
return;
stream_index = start_index;
for(;;) {
if (++stream_index >= is->ic->nb_streams)
{
if (codec_type == CODEC_TYPE_SUBTITLE)
{
stream_index = -1;
goto the_end;
} else
stream_index = 0;
}
Fabrice Bellard
committed
if (stream_index == start_index)
return;
st = ic->streams[stream_index];
Michael Niedermayer
committed
if (st->codec->codec_type == codec_type) {
Fabrice Bellard
committed
/* check that parameters are OK */
switch(codec_type) {
case CODEC_TYPE_AUDIO:
Michael Niedermayer
committed
if (st->codec->sample_rate != 0 &&
st->codec->channels != 0)
Fabrice Bellard
committed
goto the_end;
break;
case CODEC_TYPE_VIDEO:
case CODEC_TYPE_SUBTITLE:
Fabrice Bellard
committed
goto the_end;
default:
break;
}
}
}
the_end:
stream_component_close(is, start_index);
stream_component_open(is, stream_index);
}
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
void toggle_full_screen(void)
{
int w, h, flags;
is_full_screen = !is_full_screen;
if (!fs_screen_width) {
/* use default SDL method */
SDL_WM_ToggleFullScreen(screen);
} else {
/* use the recorded resolution */
flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
if (is_full_screen) {
w = fs_screen_width;
h = fs_screen_height;
flags |= SDL_FULLSCREEN;
} else {
w = screen_width;
h = screen_height;
flags |= SDL_RESIZABLE;
}
screen = SDL_SetVideoMode(w, h, 0, flags);
cur_stream->width = w;
cur_stream->height = h;
}
}
void toggle_pause(void)
{
if (cur_stream)
stream_pause(cur_stream);
Wolfgang Hesseler
committed
step = 0;
}
void step_to_next_frame(void)
{
if (cur_stream) {
if (cur_stream->paused)
cur_stream->paused=0;
cur_stream->video_current_pts = get_video_clock(cur_stream);
}
step = 1;
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
}
void do_exit(void)
{
if (cur_stream) {
stream_close(cur_stream);
cur_stream = NULL;
}
if (show_status)
printf("\n");
SDL_Quit();
exit(0);
}
void toggle_audio_display(void)
{
if (cur_stream) {
cur_stream->show_audio = !cur_stream->show_audio;
}
}
/* handle an event sent by the GUI */
void event_loop(void)
{
SDL_Event event;
Michel Bardiaux
committed
double incr, pos, frac;
for(;;) {
SDL_WaitEvent(&event);
switch(event.type) {
case SDL_KEYDOWN:
switch(event.key.keysym.sym) {
case SDLK_ESCAPE:
case SDLK_q:
do_exit();
break;
case SDLK_f:
toggle_full_screen();
break;
case SDLK_p:
case SDLK_SPACE:
toggle_pause();
break;
Wolfgang Hesseler
committed
case SDLK_s: //S: Step to next frame
step_to_next_frame();
break;
Fabrice Bellard
committed
stream_cycle_channel(cur_stream, CODEC_TYPE_AUDIO);
break;
case SDLK_v:
Fabrice Bellard
committed
stream_cycle_channel(cur_stream, CODEC_TYPE_VIDEO);
break;
case SDLK_t:
stream_cycle_channel(cur_stream, CODEC_TYPE_SUBTITLE);
break;
Fabrice Bellard
committed
case SDLK_w:
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) {
pos = get_master_clock(cur_stream);
pos += incr;
stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), incr);
Michel Bardiaux
committed
case SDL_MOUSEBUTTONDOWN:
if (cur_stream) {
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 = (double)event.button.x/(double)cur_stream->width;
ns = frac*tns;
hh = ns/3600;
mm = (ns%3600)/60;
ss = (ns%60);
fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
hh, mm, ss, thh, tmm, tss);
stream_seek(cur_stream, (int64_t)(cur_stream->ic->start_time+frac*cur_stream->ic->duration), 0);
}
break;
screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
cur_stream->width = event.resize.w;
cur_stream->height = event.resize.h;
}
break;
case SDL_QUIT:
Fabrice Bellard
committed
case FF_QUIT_EVENT:
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
do_exit();
break;
case FF_ALLOC_EVENT:
alloc_picture(event.user.data1);
break;
case FF_REFRESH_EVENT:
video_refresh_timer(event.user.data1);
break;
default:
break;
}
}
}
void opt_width(const char *arg)
{
screen_width = atoi(arg);
}
void opt_height(const char *arg)
{
screen_height = atoi(arg);
}
static void opt_format(const char *arg)
{
file_iformat = av_find_input_format(arg);
if (!file_iformat) {
fprintf(stderr, "Unknown input format: %s\n", arg);
exit(1);
}
}
Fabrice Bellard
committed
static void opt_image_format(const char *arg)
{
AVImageFormat *f;
Fabrice Bellard
committed
for(f = first_image_format; f != NULL; f = f->next) {
if (!strcmp(arg, f->name))
break;
}
if (!f) {
fprintf(stderr, "Unknown image format: '%s'\n", arg);
exit(1);
}
image_format = f;
}
Michael Niedermayer
committed
#ifdef CONFIG_NETWORK
Fabrice Bellard
committed
void opt_rtp_tcp(void)
{
/* only tcp protocol */
rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP);
}
Michael Niedermayer
committed
#endif
Fabrice Bellard
committed
Fabrice Bellard
committed
void opt_sync(const char *arg)
{
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;
else
show_help();
}
void opt_seek(const char *arg)
{
start_time = parse_date(arg, 1);
}
Wolfgang Hesseler
committed
static void opt_debug(const char *arg)
{
debug = atoi(arg);
}
Wolfgang Hesseler
committed
static void opt_vismv(const char *arg)
{
debug_mv = atoi(arg);
}
static void opt_thread_count(const char *arg)
{
thread_count= atoi(arg);
François Revol
committed
#if !defined(HAVE_THREADS)
fprintf(stderr, "Warning: not compiled with thread support, using thread emulation\n");
#endif
}
{ "h", 0, {(void*)show_help}, "show help" },
{ "x", HAS_ARG, {(void*)opt_width}, "force displayed width", "width" },
{ "y", HAS_ARG, {(void*)opt_height}, "force displayed height", "height" },
Fabrice Bellard
committed
#if 0
/* disabled as SDL/X11 does not support it correctly on application launch */
{ "fs", OPT_BOOL, {(void*)&is_full_screen}, "force full screen" },
#endif
{ "an", OPT_BOOL, {(void*)&audio_disable}, "disable audio" },
{ "vn", OPT_BOOL, {(void*)&video_disable}, "disable video" },
{ "ss", HAS_ARG, {(void*)&opt_seek}, "seek to a given position in seconds", "pos" },
{ "nodisp", OPT_BOOL, {(void*)&display_disable}, "disable graphical display" },
{ "f", HAS_ARG, {(void*)opt_format}, "force format", "fmt" },
Fabrice Bellard
committed
{ "img", HAS_ARG, {(void*)opt_image_format}, "force image format", "img_fmt" },
{ "stats", OPT_BOOL | OPT_EXPERT, {(void*)&show_status}, "show status", "" },
Wolfgang Hesseler
committed
{ "debug", HAS_ARG | OPT_EXPERT, {(void*)opt_debug}, "print specific debug info", "" },
{ "bug", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&workaround_bugs}, "workaround bugs", "" },
Wolfgang Hesseler
committed
{ "vismv", HAS_ARG | OPT_EXPERT, {(void*)opt_vismv}, "visualize motion vectors", "" },
{ "fast", OPT_BOOL | OPT_EXPERT, {(void*)&fast}, "non spec compliant optimizations", "" },
{ "genpts", OPT_BOOL | OPT_EXPERT, {(void*)&genpts}, "generate pts", "" },
{ "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&lowres}, "", "" },
{ "skiploop", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&skip_loop_filter}, "", "" },
{ "skipframe", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&skip_frame}, "", "" },
{ "skipidct", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&skip_idct}, "", "" },
{ "idct", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&idct}, "set idct algo", "algo" },
Michael Niedermayer
committed
{ "er", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&error_resilience}, "set error detection threshold (0-4)", "threshold" },
{ "ec", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&error_concealment}, "set error concealment options", "bit_mask" },
Michael Niedermayer
committed
#ifdef CONFIG_NETWORK
Fabrice Bellard
committed
{ "rtp_tcp", OPT_EXPERT, {(void*)&opt_rtp_tcp}, "force RTP/TCP protocol usage", "" },
Michael Niedermayer
committed
#endif
{ "sync", HAS_ARG | OPT_EXPERT, {(void*)opt_sync}, "set audio-video sync. type (type=audio/video/ext)", "type" },
{ "threads", HAS_ARG | OPT_EXPERT, {(void*)opt_thread_count}, "thread count", "count" },
{ NULL, },
};
void show_help(void)
{
printf("ffplay version " FFMPEG_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
"usage: ffplay [options] input_file\n"
show_help_options(options, "Main options:\n",
OPT_EXPERT, 0);
show_help_options(options, "\nAdvanced options:\n",
OPT_EXPERT, OPT_EXPERT);
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"
Fabrice Bellard
committed
"w show audio waves\n"
"left/right seek backward/forward 10 seconds\n"
"down/up seek backward/forward 1 minute\n"
Michel Bardiaux
committed
"mouse click seek to percentage in file corresponding to fraction of width\n"
);
exit(1);
}
void parse_arg_file(const char *filename)
{
Michael Niedermayer
committed
if (!strcmp(filename, "-"))
filename = "pipe:";
input_filename = filename;
}
/* Called from the main */
int main(int argc, char **argv)
{
Fabrice Bellard
committed
int flags, w, h;
/* register all codecs, demux and protocols */
av_register_all();
#ifdef CONFIG_OS2
MorphToPM(); // Morph the VIO application to a PM one to be able to use Win* functions
// Make stdout and stderr unbuffered
setbuf( stdout, NULL );
setbuf( stderr, NULL );
#endif
parse_options(argc, argv, options);
if (!input_filename)
show_help();
if (display_disable) {
video_disable = 1;
}
flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
#if !defined(CONFIG_WIN32) && !defined(CONFIG_DARWIN)
flags |= SDL_INIT_EVENTTHREAD; /* Not supported on win32 or darwin */
fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
exit(1);
}
if (!display_disable) {
#ifdef HAVE_X11
/* save the screen resolution... SDL should allow full screen
by resizing the window */
{
Display *dpy;
dpy = XOpenDisplay(NULL);
if (dpy) {
fs_screen_width = DisplayWidth(dpy, DefaultScreen(dpy));
fs_screen_height = DisplayHeight(dpy, DefaultScreen(dpy));
Fabrice Bellard
committed
flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
if (is_full_screen && fs_screen_width) {
w = fs_screen_width;
h = fs_screen_height;
flags |= SDL_FULLSCREEN;
} else {
w = screen_width;
h = screen_height;
flags |= SDL_RESIZABLE;
}
#ifndef CONFIG_DARWIN
Fabrice Bellard
committed
screen = SDL_SetVideoMode(w, h, 0, flags);
#else
/* setting bits_per_pixel = 0 or 32 causes blank video on OS X */
screen = SDL_SetVideoMode(w, h, 24, flags);
#endif
Fabrice Bellard
committed
if (!screen) {
fprintf(stderr, "SDL: could not set video mode - exiting\n");
exit(1);
}
SDL_WM_SetCaption("FFplay", "FFplay");
}
SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
Fabrice Bellard
committed
cur_stream = stream_open(input_filename, file_iformat);
event_loop();
/* never returns */
return 0;
}