Newer
Older
Fabrice Bellard
committed
SDL_Delay(10);
continue;
}
Michael Niedermayer
committed
#endif
Michael Niedermayer
committed
int stream_index= -1;
int64_t seek_target= is->seek_pos;
if (is-> video_stream >= 0) stream_index= is-> video_stream;
else if(is-> audio_stream >= 0) stream_index= is-> audio_stream;
else if(is->subtitle_stream >= 0) stream_index= is->subtitle_stream;
if(stream_index>=0){
seek_target= av_rescale_q(seek_target, AV_TIME_BASE_Q, ic->streams[stream_index]->time_base);
}
ret = av_seek_frame(is->ic, stream_index, seek_target, is->seek_flags);
if (ret < 0) {
fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
}else{
if (is->audio_stream >= 0) {
packet_queue_flush(&is->audioq);
packet_queue_put(&is->audioq, &flush_pkt);
if (is->subtitle_stream >= 0) {
packet_queue_flush(&is->subtitleq);
packet_queue_put(&is->subtitleq, &flush_pkt);
}
if (is->video_stream >= 0) {
packet_queue_flush(&is->videoq);
packet_queue_put(&is->videoq, &flush_pkt);
Fabrice Bellard
committed
/* if the queue are full, no need to read more */
if (is->audioq.size > MAX_AUDIOQ_SIZE ||
is->videoq.size > MAX_VIDEOQ_SIZE ||
is->subtitleq.size > MAX_SUBTITLEQ_SIZE ||
Michael Niedermayer
committed
url_feof(&ic->pb)) {
/* wait 10 ms */
SDL_Delay(10);
continue;
}
if (url_ferror(&ic->pb) == 0) {
SDL_Delay(100); /* wait for user event */
continue;
} else
break;
}
if (pkt->stream_index == is->audio_stream) {
packet_queue_put(&is->audioq, pkt);
} else if (pkt->stream_index == is->video_stream) {
packet_queue_put(&is->videoq, pkt);
} else if (pkt->stream_index == is->subtitle_stream) {
packet_queue_put(&is->subtitleq, pkt);
} else {
av_free_packet(pkt);
}
}
/* wait until the end */
while (!is->abort_request) {
SDL_Delay(100);
}
Fabrice Bellard
committed
ret = 0;
Fabrice Bellard
committed
/* 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->subtitle_stream >= 0)
stream_component_close(is, is->subtitle_stream);
Fabrice Bellard
committed
if (is->ic) {
av_close_input_file(is->ic);
is->ic = NULL; /* safety */
}
Fabrice Bellard
committed
url_set_interrupt_cb(NULL);
Fabrice Bellard
committed
if (ret != 0) {
SDL_Event event;
Fabrice Bellard
committed
event.type = FF_QUIT_EVENT;
event.user.data1 = is;
SDL_PushEvent(&event);
}
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;
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();
/* add the refresh timer to draw the picture */
schedule_refresh(is, 40);
Fabrice Bellard
committed
is->av_sync_type = av_sync_type;
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
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);
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;
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);
}
Stefan Huehner
committed
static void toggle_full_screen(void)
if (!fs_screen_width) {
/* use default SDL method */
Michael Niedermayer
committed
// SDL_WM_ToggleFullScreen(screen);
Michael Niedermayer
committed
video_open(cur_stream);
Stefan Huehner
committed
static void toggle_pause(void)
{
if (cur_stream)
stream_pause(cur_stream);
Wolfgang Hesseler
committed
step = 0;
}
Stefan Huehner
committed
static void step_to_next_frame(void)
Wolfgang Hesseler
committed
{
if (cur_stream) {
if (cur_stream->paused)
cur_stream->paused=0;
cur_stream->video_current_pts = get_video_clock(cur_stream);
}
step = 1;
Stefan Huehner
committed
static void do_exit(void)
{
if (cur_stream) {
stream_close(cur_stream);
cur_stream = NULL;
}
if (show_status)
printf("\n");
SDL_Quit();
exit(0);
}
Stefan Huehner
committed
static void toggle_audio_display(void)
{
if (cur_stream) {
cur_stream->show_audio = !cur_stream->show_audio;
}
}
/* handle an event sent by the GUI */
Stefan Huehner
committed
static void event_loop(void)
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) {
if (seek_by_bytes) {
pos = url_ftell(&cur_stream->ic->pb);
if (cur_stream->ic->bit_rate)
incr *= cur_stream->ic->bit_rate / 60.0;
else
incr *= 180000.0;
pos += incr;
stream_seek(cur_stream, pos, incr);
} else {
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);
screen_width = cur_stream->width = event.resize.w;
screen_height= cur_stream->height= event.resize.h;
Fabrice Bellard
committed
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;
}
}
}
Limin Wang
committed
static void opt_frame_size(const char *arg)
{
if (av_parse_video_frame_size(&frame_width, &frame_height, arg) < 0) {
Limin Wang
committed
fprintf(stderr, "Incorrect frame size\n");
exit(1);
}
if ((frame_width % 2) != 0 || (frame_height % 2) != 0) {
fprintf(stderr, "Frame size must be a multiple of 2\n");
exit(1);
}
}
static void opt_width(const char *arg)
if(screen_width<=0){
fprintf(stderr, "invalid width\n");
exit(1);
}
static void opt_height(const char *arg)
if(screen_height<=0){
fprintf(stderr, "invalid height\n");
exit(1);
}
}
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
Limin Wang
committed
static void opt_frame_pix_fmt(const char *arg)
{
frame_pix_fmt = avcodec_get_pix_fmt(arg);
}
#ifdef CONFIG_RTSP_DEMUXER
static void opt_rtp_tcp(void)
Fabrice Bellard
committed
{
/* only tcp protocol */
rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP);
}
Michael Niedermayer
committed
#endif
Fabrice Bellard
committed
static void opt_sync(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;
Fabrice Bellard
committed
show_help();
Fabrice Bellard
committed
}
static void opt_seek(const char *arg)
{
start_time = parse_date(arg, 1);
}
Wolfgang Hesseler
committed
static void opt_debug(const char *arg)
{
av_log_level = 99;
Wolfgang Hesseler
committed
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
}
static void opt_show_help(void)
{
show_help();
exit(0);
}
{ "h", 0, {(void*)opt_show_help}, "show help" },
{ "x", HAS_ARG, {(void*)opt_width}, "force displayed width", "width" },
{ "y", HAS_ARG, {(void*)opt_height}, "force displayed height", "height" },
Limin Wang
committed
{ "s", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_size}, "set frame size (WxH or abbreviation)", "size" },
Fabrice Bellard
committed
{ "fs", OPT_BOOL, {(void*)&is_full_screen}, "force full screen" },
{ "an", OPT_BOOL, {(void*)&audio_disable}, "disable audio" },
{ "vn", OPT_BOOL, {(void*)&video_disable}, "disable video" },
{ "ast", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&wanted_audio_stream}, "", "" },
{ "vst", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&wanted_video_stream}, "", "" },
{ "ss", HAS_ARG, {(void*)&opt_seek}, "seek to a given position in seconds", "pos" },
{ "bytes", OPT_BOOL, {(void*)&seek_by_bytes}, "seek by bytes" },
{ "nodisp", OPT_BOOL, {(void*)&display_disable}, "disable graphical display" },
{ "f", HAS_ARG, {(void*)opt_format}, "force format", "fmt" },
Limin Wang
committed
{ "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_frame_pix_fmt}, "set pixel format", "format" },
{ "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", "" },
Michael Niedermayer
committed
{ "drp", OPT_BOOL |OPT_EXPERT, {(void*)&decoder_reorder_pts}, "let decoder reorder 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" },
#ifdef CONFIG_RTSP_DEMUXER
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-2007 Fabrice Bellard, et al.\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"
);
}
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)
{
/* register all codecs, demux and protocols */
av_register_all();
parse_options(argc, argv, options);
if (!input_filename) {
if (display_disable) {
video_disable = 1;
}
flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
#if !defined(__MINGW32__) && !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_SDL_VIDEO_SIZE
const SDL_VideoInfo *vi = SDL_GetVideoInfo();
fs_screen_width = vi->current_w;
fs_screen_height = vi->current_h;
#endif
}
SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
av_init_packet(&flush_pkt);
flush_pkt.data= "FLUSH";
Fabrice Bellard
committed
cur_stream = stream_open(input_filename, file_iformat);
event_loop();
/* never returns */
return 0;
}