📄 ffplay.c
字号:
ret = 0; fail: /* disable interrupting */ global_video_state = NULL; /* close each stream */ if (is->audio_stream >= 0) stream_component_close(is, is->audio_stream); if (is->video_stream >= 0) stream_component_close(is, is->video_stream); if (is->ic) { av_close_input_file(is->ic); is->ic = NULL; /* safety */ } url_set_interrupt_cb(NULL); if (ret != 0) { SDL_Event event; event.type = FF_QUIT_EVENT; event.user.data1 = is; SDL_PushEvent(&event); } return 0;}static VideoState *stream_open(const char *filename, AVInputFormat *iformat){ VideoState *is; is = av_mallocz(sizeof(VideoState)); if (!is) return NULL; pstrcpy(is->filename, sizeof(is->filename), filename); is->iformat = iformat; if (screen) { is->width = screen->w; is->height = screen->h; } is->ytop = 0; is->xleft = 0; /* start video display */ is->pictq_mutex = SDL_CreateMutex(); is->pictq_cond = SDL_CreateCond(); /* add the refresh timer to draw the picture */ schedule_refresh(is, 40); is->av_sync_type = av_sync_type; 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);}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 start_index = is->audio_stream; if (start_index < 0) return; stream_index = start_index; for(;;) { if (++stream_index >= is->ic->nb_streams) stream_index = 0; if (stream_index == start_index) return; st = ic->streams[stream_index]; if (st->codec.codec_type == codec_type) { /* check that parameters are OK */ switch(codec_type) { case CODEC_TYPE_AUDIO: if (st->codec.sample_rate != 0 && st->codec.channels != 0) goto the_end; break; case CODEC_TYPE_VIDEO: goto the_end; default: break; } } } the_end: stream_component_close(is, start_index); stream_component_open(is, stream_index);}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); 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;}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; 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; case SDLK_s: //S: Step to next frame step_to_next_frame(); break; case SDLK_a: if (cur_stream) stream_cycle_channel(cur_stream, CODEC_TYPE_AUDIO); break; case SDLK_v: if (cur_stream) stream_cycle_channel(cur_stream, CODEC_TYPE_VIDEO); break; case SDLK_w: toggle_audio_display(); break; 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)); } break; default: break; } break; 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)); } break; case SDL_VIDEORESIZE: if (cur_stream) { 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: case FF_QUIT_EVENT: 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); }}static void opt_image_format(const char *arg){ AVImageFormat *f; 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;}#ifdef CONFIG_NETWORKvoid opt_rtp_tcp(void){ /* only tcp protocol */ rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP);}#endifvoid 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);}static void opt_debug(const char *arg){ debug = atoi(arg);} static void opt_vismv(const char *arg){ debug_mv = atoi(arg);}static void opt_thread_count(const char *arg){ thread_count= atoi(arg);#if !defined(HAVE_PTHREADS) && !defined(HAVE_W32THREADS) fprintf(stderr, "Warning: not compiled with thread support, using thread emulation\n");#endif} const OptionDef options[] = { { "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" },#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" }, { "img", HAS_ARG, {(void*)opt_image_format}, "force image format", "img_fmt" }, { "stats", OPT_BOOL | OPT_EXPERT, {(void*)&show_status}, "show status", "" }, { "debug", HAS_ARG | OPT_EXPERT, {(void*)opt_debug}, "print specific debug info", "" }, { "bug", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&workaround_bugs}, "workaround bugs", "" }, { "vismv", HAS_ARG | OPT_EXPERT, {(void*)opt_vismv}, "visualize motion vectors", "" },#ifdef CONFIG_NETWORK { "rtp_tcp", OPT_EXPERT, {(void*)&opt_rtp_tcp}, "force RTP/TCP protocol usage", "" },#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" "Simple media player\n"); printf("\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" "a cycle audio channel\n" "v cycle video channel\n" "w show audio waves\n" "left/right seek backward/forward 10 seconds\n" "down/up seek backward/forward 1 minute\n" "mouse click seek to percentage in file corresponding to fraction of width\n" ); exit(1);}void parse_arg_file(const char *filename){ if (!strcmp(filename, "-")) filename = "pipe:"; input_filename = filename;}/* Called from the main */int main(int argc, char **argv){ int flags, w, h; /* register all codecs, demux and protocols */ av_register_all(); 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;#ifndef CONFIG_WIN32 flags |= SDL_INIT_EVENTTHREAD; /* Not supported on win32 */#endif if (SDL_Init (flags)) { 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)); XCloseDisplay(dpy); } }#endif 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; } screen = SDL_SetVideoMode(w, h, 0, flags); 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); cur_stream = stream_open(input_filename, file_iformat); event_loop(); /* never returns */ return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -