#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/avassert.h"
+#include "libavutil/time.h"
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "cmdutils.h"
-#include <unistd.h>
#include <assert.h>
const char program_name[] = "ffplay";
static int exit_on_mousedown;
static int loop = 1;
static int framedrop = -1;
+static int infinite_buffer = 0;
static enum ShowMode show_mode = SHOW_MODE_NONE;
static const char *audio_codec_name;
static const char *subtitle_codec_name;
for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
vp = &is->pictq[i];
#if CONFIG_AVFILTER
- if (vp->picref) {
- avfilter_unref_buffer(vp->picref);
- vp->picref = NULL;
- }
+ avfilter_unref_bufferp(&vp->picref);
#endif
if (vp->bmp) {
SDL_FreeYUVOverlay(vp->bmp);
SDL_PushEvent(&event);
}
//FIXME ideally we should wait the correct time but SDLs event passing is so slow it would be silly
- usleep(is->audio_st && is->show_mode != SHOW_MODE_VIDEO ? rdftspeed*1000 : 5000);
+ av_usleep(is->audio_st && is->show_mode != SHOW_MODE_VIDEO ? rdftspeed*1000 : 5000);
}
return 0;
}
SDL_FreeYUVOverlay(vp->bmp);
#if CONFIG_AVFILTER
- if (vp->picref)
- avfilter_unref_buffer(vp->picref);
- vp->picref = NULL;
+ avfilter_unref_bufferp(&vp->picref);
#endif
vp->width = frame->width;
if (vp->bmp) {
AVPicture pict = { { 0 } };
#if CONFIG_AVFILTER
- if (vp->picref)
- avfilter_unref_buffer(vp->picref);
+ avfilter_unref_bufferp(&vp->picref);
vp->picref = src_frame->opaque;
#endif
return 0;
}
- avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt);
+ if(avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt) < 0)
+ return 0;
if (got_picture) {
int ret = 1;
SDL_UnlockMutex(is->pictq_mutex);
}
- if (ret)
- is->frame_last_returned_time = av_gettime() / 1000000.0;
-
return ret;
}
return 0;
}
#if CONFIG_AVFILTER
+static int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph,
+ AVFilterContext *source_ctx, AVFilterContext *sink_ctx)
+{
+ int ret;
+ AVFilterInOut *outputs = NULL, *inputs = NULL;
+
+ if (filtergraph) {
+ outputs = avfilter_inout_alloc();
+ inputs = avfilter_inout_alloc();
+ if (!outputs || !inputs) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ outputs->name = av_strdup("in");
+ outputs->filter_ctx = source_ctx;
+ outputs->pad_idx = 0;
+ outputs->next = NULL;
+
+ inputs->name = av_strdup("out");
+ inputs->filter_ctx = sink_ctx;
+ inputs->pad_idx = 0;
+ inputs->next = NULL;
+
+ if ((ret = avfilter_graph_parse(graph, filtergraph, &inputs, &outputs, NULL)) < 0)
+ goto fail;
+ } else {
+ if ((ret = avfilter_link(source_ctx, 0, sink_ctx, 0)) < 0)
+ goto fail;
+ }
+
+ return avfilter_graph_config(graph, NULL);
+fail:
+ avfilter_inout_free(&outputs);
+ avfilter_inout_free(&inputs);
+ return ret;
+}
+
static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters)
{
static const enum PixelFormat pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE };
snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%d", sws_flags);
graph->scale_sws_opts = av_strdup(sws_flags_str);
- snprintf(buffersrc_args, sizeof(buffersrc_args), "%d:%d:%d:%d:%d:%d:%d",
+ snprintf(buffersrc_args, sizeof(buffersrc_args),
+ "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
codec->width, codec->height, codec->pix_fmt,
is->video_st->time_base.num, is->video_st->time_base.den,
codec->sample_aspect_ratio.num, codec->sample_aspect_ratio.den);
-
if ((ret = avfilter_graph_create_filter(&filt_src,
avfilter_get_by_name("buffer"),
- "src", buffersrc_args, NULL,
+ "ffplay_buffer", buffersrc_args, NULL,
graph)) < 0)
return ret;
-#if FF_API_OLD_VSINK_API
- ret = avfilter_graph_create_filter(&filt_out,
- avfilter_get_by_name("buffersink"),
- "out", NULL, pix_fmts, graph);
-#else
buffersink_params->pixel_fmts = pix_fmts;
ret = avfilter_graph_create_filter(&filt_out,
avfilter_get_by_name("buffersink"),
- "out", NULL, buffersink_params, graph);
-#endif
+ "ffplay_buffersink", NULL, buffersink_params, graph);
av_freep(&buffersink_params);
if (ret < 0)
return ret;
if ((ret = avfilter_link(filt_format, 0, filt_out, 0)) < 0)
return ret;
-
- if (vfilters) {
- AVFilterInOut *outputs = avfilter_inout_alloc();
- AVFilterInOut *inputs = avfilter_inout_alloc();
-
- outputs->name = av_strdup("in");
- outputs->filter_ctx = filt_src;
- outputs->pad_idx = 0;
- outputs->next = NULL;
-
- inputs->name = av_strdup("out");
- inputs->filter_ctx = filt_format;
- inputs->pad_idx = 0;
- inputs->next = NULL;
-
- if ((ret = avfilter_graph_parse(graph, vfilters, &inputs, &outputs, NULL)) < 0)
- return ret;
- } else {
- if ((ret = avfilter_link(filt_src, 0, filt_format, 0)) < 0)
- return ret;
- }
-
- if ((ret = avfilter_graph_config(graph, NULL)) < 0)
+ if ((ret = configure_filtergraph(graph, vfilters, filt_src, filt_format)) < 0)
return ret;
is->in_video_filter = filt_src;
is->out_video_filter = filt_out;
- if (codec->codec->capabilities & CODEC_CAP_DR1) {
- is->use_dr1 = 1;
- codec->get_buffer = codec_get_buffer;
- codec->release_buffer = codec_release_buffer;
- codec->opaque = &is->buffer_pool;
- }
-
return ret;
}
static int video_thread(void *arg)
{
+ AVPacket pkt = { 0 };
VideoState *is = arg;
AVFrame *frame = avcodec_alloc_frame();
int64_t pts_int = AV_NOPTS_VALUE, pos = -1;
int ret;
#if CONFIG_AVFILTER
+ AVCodecContext *codec = is->video_st->codec;
AVFilterGraph *graph = avfilter_graph_alloc();
AVFilterContext *filt_out = NULL, *filt_in = NULL;
- int last_w = is->video_st->codec->width;
- int last_h = is->video_st->codec->height;
+ int last_w = 0;
+ int last_h = 0;
+ enum PixelFormat last_format = -2;
- if ((ret = configure_video_filters(graph, is, vfilters)) < 0) {
- SDL_Event event;
- event.type = FF_QUIT_EVENT;
- event.user.data1 = is;
- SDL_PushEvent(&event);
- goto the_end;
+ if (codec->codec->capabilities & CODEC_CAP_DR1) {
+ is->use_dr1 = 1;
+ codec->get_buffer = codec_get_buffer;
+ codec->release_buffer = codec_release_buffer;
+ codec->opaque = &is->buffer_pool;
}
- filt_in = is->in_video_filter;
- filt_out = is->out_video_filter;
#endif
for (;;) {
- AVPacket pkt;
#if CONFIG_AVFILTER
AVFilterBufferRef *picref;
- AVRational tb = filt_out->inputs[0]->time_base;
+ AVRational tb;
#endif
while (is->paused && !is->videoq.abort_request)
SDL_Delay(10);
+ avcodec_get_frame_defaults(frame);
+ av_free_packet(&pkt);
+
ret = get_video_frame(is, frame, &pts_int, &pkt);
if (ret < 0)
goto the_end;
- av_free_packet(&pkt);
if (!ret)
continue;
- is->frame_last_filter_delay = av_gettime() / 1000000.0 - is->frame_last_returned_time;
- if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
- is->frame_last_filter_delay = 0;
-
#if CONFIG_AVFILTER
if ( last_w != is->video_st->codec->width
- || last_h != is->video_st->codec->height) {
+ || last_h != is->video_st->codec->height
+ || last_format != is->video_st->codec->pix_fmt) {
av_log(NULL, AV_LOG_INFO, "Frame changed from size:%dx%d to size:%dx%d\n",
last_w, last_h, is->video_st->codec->width, is->video_st->codec->height);
avfilter_graph_free(&graph);
graph = avfilter_graph_alloc();
- if ((ret = configure_video_filters(graph, is, vfilters)) < 0)
+ if ((ret = configure_video_filters(graph, is, vfilters)) < 0) {
+ SDL_Event event;
+ event.type = FF_QUIT_EVENT;
+ event.user.data1 = is;
+ SDL_PushEvent(&event);
+ av_free_packet(&pkt);
goto the_end;
+ }
+ filt_in = is->in_video_filter;
filt_out = is->out_video_filter;
last_w = is->video_st->codec->width;
last_h = is->video_st->codec->height;
+ last_format = is->video_st->codec->pix_fmt;
}
frame->pts = pts_int;
- if (is->use_dr1) {
+ frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame);
+ if (is->use_dr1 && frame->opaque) {
FrameBuffer *buf = frame->opaque;
AVFilterBufferRef *fb = avfilter_get_video_buffer_ref_from_arrays(
frame->data, frame->linesize,
fb->buf->free = filter_release_buffer;
buf->refcount++;
- av_buffersrc_buffer(filt_in, fb);
+ av_buffersrc_add_ref(filt_in, fb, AV_BUFFERSRC_FLAG_NO_COPY);
} else
av_buffersrc_write_frame(filt_in, frame);
+ av_free_packet(&pkt);
+
while (ret >= 0) {
+ is->frame_last_returned_time = av_gettime() / 1000000.0;
+
ret = av_buffersink_get_buffer_ref(filt_out, &picref, 0);
if (ret < 0) {
ret = 0;
break;
}
- avfilter_fill_frame_from_video_buffer_ref(frame, picref);
+ is->frame_last_filter_delay = av_gettime() / 1000000.0 - is->frame_last_returned_time;
+ if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
+ is->frame_last_filter_delay = 0;
+
+ avfilter_copy_buf_props(frame, picref);
pts_int = picref->pts;
tb = filt_out->inputs[0]->time_base;
av_freep(&vfilters);
avfilter_graph_free(&graph);
#endif
+ av_free_packet(&pkt);
av_free(frame);
return 0;
}
is->frame->nb_samples,
dec->sample_fmt, 1);
- dec_channel_layout = (dec->channel_layout && dec->channels == av_get_channel_layout_nb_channels(dec->channel_layout)) ? dec->channel_layout : av_get_default_channel_layout(dec->channels);
+ dec_channel_layout =
+ (dec->channel_layout && dec->channels == av_get_channel_layout_nb_channels(dec->channel_layout)) ?
+ dec->channel_layout : av_get_default_channel_layout(dec->channels);
wanted_nb_samples = synchronize_audio(is, is->frame->nb_samples);
- if (dec->sample_fmt != is->audio_src.fmt ||
+ if (dec->sample_fmt != is->audio_src.fmt ||
dec_channel_layout != is->audio_src.channel_layout ||
- dec->sample_rate != is->audio_src.freq ||
+ dec->sample_rate != is->audio_src.freq ||
(wanted_nb_samples != is->frame->nb_samples && !is->swr_ctx)) {
- if (is->swr_ctx)
- swr_free(&is->swr_ctx);
+ swr_free(&is->swr_ctx);
is->swr_ctx = swr_alloc_set_opts(NULL,
is->audio_tgt.channel_layout, is->audio_tgt.fmt, is->audio_tgt.freq,
dec_channel_layout, dec->sample_fmt, dec->sample_rate,
0, NULL);
if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {
fprintf(stderr, "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
- dec->sample_rate,
- av_get_sample_fmt_name(dec->sample_fmt),
- dec->channels,
- is->audio_tgt.freq,
- av_get_sample_fmt_name(is->audio_tgt.fmt),
- is->audio_tgt.channels);
+ dec->sample_rate, av_get_sample_fmt_name(dec->sample_fmt), dec->channels,
+ is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels);
break;
}
is->audio_src.channel_layout = dec_channel_layout;
is->audio_src.fmt = dec->sample_fmt;
}
- resampled_data_size = data_size;
if (is->swr_ctx) {
- const uint8_t *in[] = { is->frame->data[0] };
+ const uint8_t **in = (const uint8_t **)is->frame->extended_data;
uint8_t *out[] = {is->audio_buf2};
+ int out_count = sizeof(is->audio_buf2) / is->audio_tgt.channels / av_get_bytes_per_sample(is->audio_tgt.fmt);
if (wanted_nb_samples != is->frame->nb_samples) {
if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - is->frame->nb_samples) * is->audio_tgt.freq / dec->sample_rate,
wanted_nb_samples * is->audio_tgt.freq / dec->sample_rate) < 0) {
break;
}
}
- len2 = swr_convert(is->swr_ctx, out, sizeof(is->audio_buf2) / is->audio_tgt.channels / av_get_bytes_per_sample(is->audio_tgt.fmt),
- in, is->frame->nb_samples);
+ len2 = swr_convert(is->swr_ctx, out, out_count, in, is->frame->nb_samples);
if (len2 < 0) {
- fprintf(stderr, "audio_resample() failed\n");
+ fprintf(stderr, "swr_convert() failed\n");
break;
}
- if (len2 == sizeof(is->audio_buf2) / is->audio_tgt.channels / av_get_bytes_per_sample(is->audio_tgt.fmt)) {
+ if (len2 == out_count) {
fprintf(stderr, "warning: audio buffer is probably too small\n");
swr_init(is->swr_ctx);
}
resampled_data_size = len2 * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
} else {
is->audio_buf = is->frame->data[0];
+ resampled_data_size = data_size;
}
/* if no pts, then compute it */
avctx = ic->streams[stream_index]->codec;
codec = avcodec_find_decoder(avctx->codec_id);
- opts = filter_codec_opts(codec_opts, codec, ic, ic->streams[stream_index]);
+ opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec);
switch(avctx->codec_type){
case AVMEDIA_TYPE_AUDIO : is->last_audio_stream = stream_index; if(audio_codec_name ) codec= avcodec_find_decoder_by_name( audio_codec_name); break;
packet_queue_flush(&is->audioq);
av_free_packet(&is->audio_pkt);
- if (is->swr_ctx)
- swr_free(&is->swr_ctx);
+ swr_free(&is->swr_ctx);
av_freep(&is->audio_buf1);
is->audio_buf = NULL;
av_freep(&is->frame);
ic->streams[stream_index]->discard = AVDISCARD_ALL;
avcodec_close(avctx);
+#if CONFIG_AVFILTER
free_buffer_pool(&is->buffer_pool);
+#endif
switch (avctx->codec_type) {
case AVMEDIA_TYPE_AUDIO:
is->audio_st = NULL;
}
/* if the queue are full, no need to read more */
- if ( is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
+ if (!infinite_buffer &&
+ (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
|| ( (is->audioq .nb_packets > MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request)
&& (is->videoq .nb_packets > MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request)
- && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0 || is->subtitleq.abort_request))) {
+ && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0 || is->subtitleq.abort_request)))) {
/* wait 10 ms */
SDL_Delay(10);
continue;
static void toggle_full_screen(VideoState *is)
{
- av_unused int i;
- is_full_screen = !is_full_screen;
#if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
/* OS X needs to reallocate the SDL overlays */
- for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
+ int i;
+ for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
is->pictq[i].reallocate = 1;
- }
#endif
+ is_full_screen = !is_full_screen;
video_open(is, 1);
}
{ "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", "" },
+ { "infbuf", OPT_BOOL | OPT_EXPERT, { (void*)&infinite_buffer }, "don't limit the input buffer size (useful with realtime streams)", "" },
{ "window_title", OPT_STRING | HAS_ARG, { (void*)&window_title }, "set window title", "window title" },
#if CONFIG_AVFILTER
{ "vf", OPT_STRING | HAS_ARG, { (void*)&vfilters }, "video filters", "filter list" },
{
int flags;
VideoState *is;
+ char dummy_videodriver[] = "SDL_VIDEODRIVER=dummy";
av_log_set_flags(AV_LOG_SKIP_REPEATED);
parse_loglevel(argc, argv, options);
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 */
#endif