Newer
Older
is->audio_clock, pts);
last_clock = is->audio_clock;
/* free the current packet */
if (pkt->data)
memset(pkt_temp, 0, sizeof(*pkt_temp));
if (is->paused || is->audioq.abort_request) {
return -1;
}
if ((new_packet = packet_queue_get(&is->audioq, pkt, 1)) < 0)
if (pkt->data == flush_pkt.data) {
avcodec_flush_buffers(dec);
flush_complete = 0;
}
/* if update the audio clock with the pts */
if (pkt->pts != AV_NOPTS_VALUE) {
is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;
}
}
/* prepare a new audio buffer */
Diego Pettenò
committed
static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
{
VideoState *is = opaque;
int audio_size, len1;
double pts;
audio_callback_time = av_gettime();
while (len > 0) {
if (is->audio_buf_index >= is->audio_buf_size) {
audio_size = audio_decode_frame(is, &pts);
if (audio_size < 0) {
/* if error, just output silence */
is->audio_buf = is->silence_buf;
is->audio_buf_size = sizeof(is->silence_buf);
} else {
if (is->show_audio)
update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
audio_size = synchronize_audio(is, (int16_t *)is->audio_buf, audio_size,
pts);
is->audio_buf_size = audio_size;
}
is->audio_buf_index = 0;
}
len1 = is->audio_buf_size - is->audio_buf_index;
if (len1 > len)
len1 = len;
memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
len -= len1;
stream += len1;
is->audio_buf_index += len1;
}
}
/* open a given stream. Return 0 if OK */
static int stream_component_open(VideoState *is, int stream_index)
{
AVFormatContext *ic = is->ic;
AVCodecContext *avctx;
AVCodec *codec;
SDL_AudioSpec wanted_spec, spec;
AVDictionary *opts;
AVDictionaryEntry *t = NULL;
if (stream_index < 0 || stream_index >= ic->nb_streams)
return -1;
avctx = ic->streams[stream_index]->codec;
opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index]);
codec = avcodec_find_decoder(avctx->codec_id);
avctx->debug_mv = debug_mv;
avctx->debug = debug;
avctx->workaround_bugs = workaround_bugs;
avctx->idct_algo = idct;
avctx->skip_frame = skip_frame;
avctx->skip_idct = skip_idct;
avctx->skip_loop_filter = skip_loop_filter;
avctx->error_concealment = error_concealment;
if (fast) avctx->flags2 |= CODEC_FLAG2_FAST;
if (!av_dict_get(opts, "threads", NULL, 0))
av_dict_set(&opts, "threads", "auto", 0);
avcodec_open2(avctx, codec, &opts) < 0)
if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
return AVERROR_OPTION_NOT_FOUND;
}
/* prepare audio output */
if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
wanted_spec.freq = avctx->sample_rate;
wanted_spec.format = AUDIO_S16SYS;
if (!avctx->channel_layout)
avctx->channel_layout = av_get_default_channel_layout(avctx->channels);
if (!avctx->channel_layout) {
fprintf(stderr, "unable to guess channel layout\n");
return -1;
}
if (avctx->channels == 1)
is->sdl_channel_layout = AV_CH_LAYOUT_MONO;
else
is->sdl_channel_layout = AV_CH_LAYOUT_STEREO;
is->sdl_channels = av_get_channel_layout_nb_channels(is->sdl_channel_layout);
wanted_spec.channels = is->sdl_channels;
wanted_spec.silence = 0;
wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
wanted_spec.callback = sdl_audio_callback;
wanted_spec.userdata = is;
if (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
return -1;
}
is->audio_hw_buf_size = spec.size;
is->sdl_sample_fmt = AV_SAMPLE_FMT_S16;
is->resample_sample_fmt = is->sdl_sample_fmt;
is->resample_channel_layout = is->sdl_channel_layout;
}
Ronald S. Bultje
committed
ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
case AVMEDIA_TYPE_AUDIO:
is->audio_stream = stream_index;
is->audio_st = ic->streams[stream_index];
Fabrice Bellard
committed
/* init averaging filter */
is->audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
Fabrice Bellard
committed
is->audio_diff_avg_count = 0;
/* since we do not have a precise anough audio fifo fullness,
we correct audio sync only if larger than this threshold */
is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / avctx->sample_rate;
Fabrice Bellard
committed
memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
packet_queue_init(&is->audioq);
case AVMEDIA_TYPE_VIDEO:
is->video_stream = stream_index;
is->video_st = ic->streams[stream_index];
packet_queue_init(&is->videoq);
is->video_tid = SDL_CreateThread(video_thread, is);
break;
case AVMEDIA_TYPE_SUBTITLE:
is->subtitle_stream = stream_index;
is->subtitle_st = ic->streams[stream_index];
packet_queue_init(&is->subtitleq);
is->subtitle_tid = SDL_CreateThread(subtitle_thread, is);
break;
default:
break;
}
return 0;
}
static void stream_component_close(VideoState *is, int stream_index)
{
AVFormatContext *ic = is->ic;
AVCodecContext *avctx;
if (stream_index < 0 || stream_index >= ic->nb_streams)
return;
avctx = ic->streams[stream_index]->codec;
case AVMEDIA_TYPE_AUDIO:
packet_queue_abort(&is->audioq);
SDL_CloseAudio();
packet_queue_end(&is->audioq);
av_free_packet(&is->audio_pkt);
if (is->avr)
avresample_free(&is->avr);
av_freep(&is->audio_buf1);
is->audio_buf = NULL;
av_freep(&is->frame);
if (is->rdft) {
av_rdft_end(is->rdft);
av_freep(&is->rdft_data);
is->rdft = NULL;
is->rdft_bits = 0;
case AVMEDIA_TYPE_VIDEO:
packet_queue_abort(&is->videoq);
/* note: we also signal this mutex to make sure we deblock the
video thread in all cases */
SDL_LockMutex(is->pictq_mutex);
SDL_CondSignal(is->pictq_cond);
SDL_UnlockMutex(is->pictq_mutex);
SDL_WaitThread(is->video_tid, NULL);
packet_queue_end(&is->videoq);
break;
case AVMEDIA_TYPE_SUBTITLE:
packet_queue_abort(&is->subtitleq);
/* note: we also signal this mutex to make sure we deblock the
video thread in all cases */
SDL_LockMutex(is->subpq_mutex);
is->subtitle_stream_changed = 1;
SDL_CondSignal(is->subpq_cond);
SDL_UnlockMutex(is->subpq_mutex);
SDL_WaitThread(is->subtitle_tid, NULL);
packet_queue_end(&is->subtitleq);
break;
Ronald S. Bultje
committed
ic->streams[stream_index]->discard = AVDISCARD_ALL;
avcodec_close(avctx);
free_buffer_pool(&is->buffer_pool);
case AVMEDIA_TYPE_AUDIO:
is->audio_st = NULL;
is->audio_stream = -1;
break;
case AVMEDIA_TYPE_VIDEO:
is->video_st = NULL;
is->video_stream = -1;
break;
case AVMEDIA_TYPE_SUBTITLE:
is->subtitle_st = NULL;
is->subtitle_stream = -1;
break;
Fabrice Bellard
committed
/* since we have only one decoding thread, we can use a global
variable instead of a thread local variable */
static VideoState *global_video_state;
static int decode_interrupt_cb(void *ctx)
Fabrice Bellard
committed
{
return global_video_state && global_video_state->abort_request;
Fabrice Bellard
committed
}
/* this thread gets the stream from the disk or the network */
static int decode_thread(void *arg)
{
VideoState *is = arg;
int st_index[AVMEDIA_TYPE_NB];
AVDictionary **opts;
int orig_nb_streams;
memset(st_index, -1, sizeof(st_index));
is->video_stream = -1;
is->audio_stream = -1;
is->subtitle_stream = -1;
Fabrice Bellard
committed
global_video_state = is;
ic = avformat_alloc_context();
ic->interrupt_callback.callback = decode_interrupt_cb;
err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
Fabrice Bellard
committed
if (err < 0) {
print_error(is->filename, err);
ret = -1;
goto fail;
}
if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
ret = AVERROR_OPTION_NOT_FOUND;
goto fail;
}
ic->flags |= AVFMT_FLAG_GENPTS;
opts = setup_find_stream_info_opts(ic, codec_opts);
orig_nb_streams = ic->nb_streams;
err = avformat_find_stream_info(ic, opts);
if (err < 0) {
fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
ret = -1;
goto fail;
}
for (i = 0; i < orig_nb_streams; i++)
av_dict_free(&opts[i]);
av_freep(&opts);
if (ic->pb)
ic->pb->eof_reached = 0; // FIXME hack, avplay maybe should not use url_feof() to test for the end
if (seek_by_bytes < 0)
seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT);
Michael Niedermayer
committed
/* if seeking requested, we execute it */
if (start_time != AV_NOPTS_VALUE) {
int64_t timestamp;
timestamp = start_time;
/* add the stream start time */
if (ic->start_time != AV_NOPTS_VALUE)
timestamp += ic->start_time;
ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
fprintf(stderr, "%s: could not seek to position %0.3f\n",
is->filename, (double)timestamp / AV_TIME_BASE);
}
}
for (i = 0; i < ic->nb_streams; i++)
Ronald S. Bultje
committed
ic->streams[i]->discard = AVDISCARD_ALL;
if (!video_disable)
st_index[AVMEDIA_TYPE_VIDEO] =
av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,
wanted_stream[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);
if (!audio_disable)
st_index[AVMEDIA_TYPE_AUDIO] =
av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,
wanted_stream[AVMEDIA_TYPE_AUDIO],
st_index[AVMEDIA_TYPE_VIDEO],
NULL, 0);
if (!video_disable)
st_index[AVMEDIA_TYPE_SUBTITLE] =
av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE,
wanted_stream[AVMEDIA_TYPE_SUBTITLE],
(st_index[AVMEDIA_TYPE_AUDIO] >= 0 ?
st_index[AVMEDIA_TYPE_AUDIO] :
st_index[AVMEDIA_TYPE_VIDEO]),
NULL, 0);
av_dump_format(ic, 0, is->filename, 0);
if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);
if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);
is->refresh_tid = SDL_CreateThread(refresh_thread, is);
Michael Niedermayer
committed
is->show_audio = 2;
if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {
stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]);
if (is->video_stream < 0 && is->audio_stream < 0) {
Fabrice Bellard
committed
fprintf(stderr, "%s: could not open codecs\n", is->filename);
ret = -1;
Fabrice Bellard
committed
if (is->paused != is->last_paused) {
is->last_paused = is->paused;
Fabrice Bellard
committed
}
#if CONFIG_RTSP_DEMUXER
if (is->paused && !strcmp(ic->iformat->name, "rtsp")) {
Fabrice Bellard
committed
/* wait 10 ms to avoid trying to get another packet */
/* XXX: horrible */
SDL_Delay(10);
continue;
}
Michael Niedermayer
committed
#endif
int64_t seek_target = is->seek_pos;
int64_t seek_min = is->seek_rel > 0 ? seek_target - is->seek_rel + 2: INT64_MIN;
int64_t seek_max = is->seek_rel < 0 ? seek_target - is->seek_rel - 2: INT64_MAX;
// FIXME the +-2 is due to rounding being not done in the correct direction in generation
// of the seek_pos/seek_rel variables
Michael Niedermayer
committed
ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
if (ret < 0) {
fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
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 + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
|| ( (is->audioq .size > MIN_AUDIOQ_SIZE || is->audio_stream < 0)
&& (is->videoq .nb_packets > MIN_FRAMES || is->video_stream < 0)
&& (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0))) {
/* wait 10 ms */
SDL_Delay(10);
continue;
}
pkt->data = NULL;
pkt->size = 0;
pkt->stream_index = is->video_stream;
Michael Niedermayer
committed
}
if (is->audio_stream >= 0 &&
is->audio_st->codec->codec->capabilities & CODEC_CAP_DELAY) {
av_init_packet(pkt);
pkt->data = NULL;
pkt->size = 0;
pkt->stream_index = is->audio_stream;
packet_queue_put(&is->audioq, pkt);
}
if (is->audioq.size + is->videoq.size + is->subtitleq.size == 0) {
if (loop != 1 && (!loop || --loop)) {
stream_seek(cur_stream, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
Michael Niedermayer
committed
continue;
}
if (ret == AVERROR_EOF || (ic->pb && ic->pb->eof_reached))
SDL_Delay(100); /* wait for user event */
continue;
/* check if packet is in play range specified by user, then queue, otherwise discard */
pkt_in_play_range = duration == AV_NOPTS_VALUE ||
(pkt->pts - ic->streams[pkt->stream_index]->start_time) *
av_q2d(ic->streams[pkt->stream_index]->time_base) -
(double)(start_time != AV_NOPTS_VALUE ? start_time : 0) / 1000000
<= ((double)duration / 1000000);
if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
} else if (pkt->stream_index == is->video_stream && pkt_in_play_range) {
} else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
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) {
avformat_close_input(&is->ic);
Fabrice Bellard
committed
}
Fabrice Bellard
committed
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;
/* start video display */
is->pictq_mutex = SDL_CreateMutex();
is->subpq_mutex = SDL_CreateMutex();
Fabrice Bellard
committed
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;
}
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 == AVMEDIA_TYPE_VIDEO)
Fabrice Bellard
committed
start_index = is->video_stream;
else if (codec_type == AVMEDIA_TYPE_AUDIO)
Fabrice Bellard
committed
start_index = is->audio_stream;
else
start_index = is->subtitle_stream;
if (start_index < (codec_type == AVMEDIA_TYPE_SUBTITLE ? -1 : 0))
Fabrice Bellard
committed
return;
stream_index = start_index;
Fabrice Bellard
committed
if (++stream_index >= is->ic->nb_streams)
{
if (codec_type == AVMEDIA_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 */
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:
stream_component_close(is, start_index);
stream_component_open(is, stream_index);
}
Stefan Huehner
committed
static void toggle_full_screen(void)
#if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
/* OS X needs to empty the picture_queue */
int i;
for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
cur_stream->pictq[i].reallocate = 1;
#endif
is_full_screen = !is_full_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 the stream is paused unpause it, then step */
Wolfgang Hesseler
committed
if (cur_stream->paused)
stream_pause(cur_stream);
Wolfgang Hesseler
committed
}
step = 1;
Stefan Huehner
committed
static void toggle_audio_display(void)
int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
cur_stream->show_audio = (cur_stream->show_audio + 1) % 3;
cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height,
bgcolor);
SDL_UpdateRect(screen, cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height);
}
}
/* handle an event sent by the GUI */
Stefan Huehner
committed
static void event_loop(void)
Michel Bardiaux
committed
double incr, pos, frac;
if (exit_on_keydown) {
do_exit();
break;
}
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
step_to_next_frame();
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_t:
stream_cycle_channel(cur_stream, AVMEDIA_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 (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);
pos += incr;
Michael Niedermayer
committed
stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
Michel Bardiaux
committed
case SDL_MOUSEBUTTONDOWN:
if (exit_on_mousedown) {
do_exit();
break;
}
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);
fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
hh, mm, ss, thh, tmm, tss);
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(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;
}
}
}
static int opt_frame_size(const char *opt, const char *arg)
Limin Wang
committed
{
av_log(NULL, AV_LOG_ERROR,
"Option '%s' has been removed, use private format options instead\n", opt);
return AVERROR(EINVAL);
Limin Wang
committed
}
static int opt_width(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(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(const char *opt, const char *arg)
{
file_iformat = av_find_input_format(arg);
if (!file_iformat) {
fprintf(stderr, "Unknown input format: %s\n", arg);
Fabrice Bellard
committed
static int opt_frame_pix_fmt(const char *opt, const char *arg)
Limin Wang
committed
{
av_log(NULL, AV_LOG_ERROR,
"Option '%s' has been removed, use private format options instead\n", opt);
return AVERROR(EINVAL);
Limin Wang
committed
}
static int opt_sync(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;
fprintf(stderr, "Unknown value for %s: %s\n", opt, arg);
return 0;
Fabrice Bellard
committed
}
static int opt_seek(const char *opt, const char *arg)
start_time = parse_time_or_die(opt, arg, 1);
return 0;
static int opt_duration(const char *opt, const char *arg)
{
duration = parse_time_or_die(opt, arg, 1);
return 0;
}
static int opt_debug(const char *opt, const char *arg)
Wolfgang Hesseler
committed
{
debug = parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX);
return 0;
Wolfgang Hesseler
committed
}
static int opt_vismv(const char *opt, const char *arg)
Wolfgang Hesseler
committed
{
debug_mv = parse_number_or_die(opt, arg, OPT_INT64, INT_MIN, INT_MAX);
return 0;
Wolfgang Hesseler
committed
}
Diego Pettenò
committed
static const OptionDef options[] = {
#include "cmdutils_common_opts.h"
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
{ "x", HAS_ARG, { (void*)opt_width }, "force displayed width", "width" },
{ "y", HAS_ARG, { (void*)opt_height }, "force displayed height", "height" },
{ "s", HAS_ARG | OPT_VIDEO, { (void*)opt_frame_size }, "set frame size (WxH or abbreviation)", "size" },
{ "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_stream[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_number" },
{ "vst", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&wanted_stream[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_number" },
{ "sst", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&wanted_stream[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_number" },
{ "ss", HAS_ARG, { (void*)&opt_seek }, "seek to a given position in seconds", "pos" },
{ "t", HAS_ARG, { (void*)&opt_duration }, "play \"duration\" seconds of audio/video", "duration" },
{ "bytes", OPT_INT | HAS_ARG, { (void*)&seek_by_bytes }, "seek by bytes 0=off 1=on -1=auto", "val" },
{ "nodisp", OPT_BOOL, { (void*)&display_disable }, "disable graphical display" },
{ "f", HAS_ARG, { (void*)opt_format }, "force format", "fmt" },
{ "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", "" },
{ "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", "" },
{ "fast", OPT_BOOL | OPT_EXPERT, { (void*)&fast }, "non spec compliant optimizations", "" },
{ "genpts", OPT_BOOL | OPT_EXPERT, { (void*)&genpts }, "generate pts", "" },
{ "drp", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&decoder_reorder_pts }, "let decoder reorder pts 0=off 1=on -1=auto", ""},
{ "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" },
{ "ec", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&error_concealment }, "set error concealment options", "bit_mask" },
{ "sync", HAS_ARG | OPT_EXPERT, { (void*)opt_sync }, "set audio-video sync. type (type=audio/video/ext)", "type" },
{ "autoexit", OPT_BOOL | OPT_EXPERT, { (void*)&autoexit }, "exit at the end", "" },
{ "exitonkeydown", OPT_BOOL | OPT_EXPERT, { (void*)&exit_on_keydown }, "exit on key down", "" },
{ "exitonmousedown", OPT_BOOL | OPT_EXPERT, { (void*)&exit_on_mousedown }, "exit on mouse down", "" },
{ "loop", OPT_INT | HAS_ARG | OPT_EXPERT, { (void*)&loop }, "set number of times the playback shall be looped", "loop count" },
{ "framedrop", OPT_BOOL | OPT_EXPERT, { (void*)&framedrop }, "drop frames when cpu is too slow", "" },
{ "window_title", OPT_STRING | HAS_ARG, { (void*)&window_title }, "set window title", "window title" },
{ "vf", OPT_STRING | HAS_ARG, { (void*)&vfilters }, "video filters", "filter list" },
{ "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, { (void*)&rdftspeed }, "rdft speed", "msecs" },
{ "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { (void*)opt_default }, "generic catch all option", "" },
{ "i", 0, { NULL }, "avconv compatibility dummy option", ""},
printf("Simple media player\n");
printf("usage: %s [options] input_file\n", program_name);
}
static void show_help(void)
{
av_log_set_callback(log_callback_help);
show_help_options(options, "Main options:\n",
OPT_EXPERT, 0);
show_help_options(options, "\nAdvanced options:\n",
OPT_EXPERT, OPT_EXPERT);
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);
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"
"s activate frame-step mode\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"
static void opt_input_file(void *optctx, const char *filename)
if (input_filename) {
fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n",
filename, input_filename);
exit(1);
}
Michael Niedermayer
committed
if (!strcmp(filename, "-"))
input_filename = filename;
}
/* Called from the main */
int main(int argc, char **argv)
{
int flags;
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();
show_banner();
parse_options(NULL, argc, argv, options, opt_input_file);
if (!input_filename) {
fprintf(stderr, "An input file must be specified\n");
fprintf(stderr, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
if (display_disable) {
video_disable = 1;
}