#include <limits.h>
#include "libavutil/avstring.h"
#include "libavutil/colorspace.h"
+#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
+#include "libavutil/dict.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/avassert.h"
# include "libavfilter/avcodec.h"
# include "libavfilter/avfilter.h"
# include "libavfilter/avfiltergraph.h"
+# include "libavfilter/vsink_buffer.h"
#endif
#include <SDL.h>
const char program_name[] = "ffplay";
const int program_birth_year = 2003;
-//#define DEBUG
-//#define DEBUG_SYNC
-
#define MAX_QUEUE_SIZE (15 * 1024 * 1024)
#define MIN_AUDIOQ_SIZE (20 * 16 * 1024)
#define MIN_FRAMES 5
typedef struct VideoPicture {
double pts; ///<presentation time stamp for this picture
double target_clock; ///<av_gettime() time at which this should be displayed ideally
+ double duration; ///<expected duration of the frame
int64_t pos; ///<byte position in file
SDL_Overlay *bmp;
int width, height; /* source height & width */
int refresh;
} VideoState;
-static void show_help(void);
+static int opt_help(const char *opt, const char *arg);
/* options specified by the user */
static AVInputFormat *file_iformat;
static int fs_screen_height;
static int screen_width = 0;
static int screen_height = 0;
-static int frame_width = 0;
-static int frame_height = 0;
-static enum PixelFormat frame_pix_fmt = PIX_FMT_NONE;
static int audio_disable;
static int video_disable;
static int wanted_stream[AVMEDIA_TYPE_NB]={
static int exit_on_keydown;
static int exit_on_mousedown;
static int loop=1;
-static int framedrop=1;
+static int framedrop=-1;
static enum ShowMode show_mode = SHOW_MODE_NONE;
static int rdftspeed=20;
}
}
+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->read_tid, NULL);
+ SDL_WaitThread(is->refresh_tid, NULL);
+
+ /* free all pictures */
+ 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;
+ }
+#endif
+ 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);
+#if !CONFIG_AVFILTER
+ if (is->img_convert_ctx)
+ sws_freeContext(is->img_convert_ctx);
+#endif
+ av_free(is);
+}
+
+static void do_exit(void)
+{
+ if (cur_stream) {
+ stream_close(cur_stream);
+ cur_stream = NULL;
+ }
+ uninit_opts();
+#if CONFIG_AVFILTER
+ avfilter_uninit();
+#endif
+ if (show_status)
+ printf("\n");
+ SDL_Quit();
+ av_log(NULL, AV_LOG_QUIET, "%s", "");
+ exit(0);
+}
+
static int video_open(VideoState *is){
int flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
int w,h;
#endif
if (!screen) {
fprintf(stderr, "SDL: could not set video mode - exiting\n");
- return -1;
+ do_exit();
}
if (!window_title)
window_title = input_filename;
}
}
is->frame_timer += delay;
-#if defined(DEBUG_SYNC)
- printf("video: delay=%0.3f actual_delay=%0.3f pts=%0.3f A-V=%f\n",
- delay, actual_delay, frame_current_pts, -diff);
-#endif
+
+ av_dlog(NULL, "video: delay=%0.3f pts=%0.3f A-V=%f\n",
+ delay, frame_current_pts, -diff);
return is->frame_timer;
}
assert(nextvp->target_clock >= vp->target_clock);
next_target= nextvp->target_clock;
}else{
- next_target= vp->target_clock + is->video_clock - vp->pts; //FIXME pass durations cleanly
+ next_target= vp->target_clock + vp->duration;
}
- if(framedrop && time > next_target){
+ if((framedrop>0 || (framedrop && is->audio_st)) && time > next_target){
is->skip_frames *= 1.0 + FRAME_SKIP_FACTOR;
if(is->pictq_size > 1 || time > next_target + 0.5){
/* update queue size and signal for next picture */
}
}
-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->read_tid, NULL);
- SDL_WaitThread(is->refresh_tid, NULL);
-
- /* free all pictures */
- 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;
- }
-#endif
- 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);
-#if !CONFIG_AVFILTER
- if (is->img_convert_ctx)
- sws_freeContext(is->img_convert_ctx);
-#endif
- av_free(is);
-}
-
-static void do_exit(void)
-{
- if (cur_stream) {
- stream_close(cur_stream);
- cur_stream = NULL;
- }
- uninit_opts();
-#if CONFIG_AVFILTER
- avfilter_uninit();
-#endif
- if (show_status)
- printf("\n");
- SDL_Quit();
- av_log(NULL, AV_LOG_QUIET, "");
- exit(0);
-}
-
/* allocate a picture (needs to do that in main thread to avoid
potential locking problems */
static void alloc_picture(void *opaque)
vp = &is->pictq[is->pictq_windex];
+ vp->duration = frame_delay;
+
/* alloc or resize hardware picture buffer */
if (!vp->bmp ||
#if CONFIG_AVFILTER
static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacket *pkt)
{
- int len1 av_unused, got_picture, i;
+ int got_picture, i;
if (packet_queue_get(&is->videoq, pkt, 1) < 0)
return -1;
return 0;
}
- len1 = avcodec_decode_video2(is->video_st->codec,
- frame, &got_picture,
- pkt);
+ avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt);
if (got_picture) {
if (decoder_reorder_pts == -1) {
priv->is->video_st->codec->pix_fmt, PIX_FMT_NONE
};
- avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts));
+ avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
return 0;
}
link->w = c->width;
link->h = c->height;
+ link->sample_aspect_ratio = priv->is->video_st->sample_aspect_ratio;
link->time_base = priv->is->video_st->time_base;
return 0;
{
char sws_flags_str[128];
int ret;
- FFSinkContext ffsink_ctx = { .pix_fmt = PIX_FMT_YUV420P };
+ enum PixelFormat pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE };
AVFilterContext *filt_src = NULL, *filt_out = NULL;
snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%d", sws_flags);
graph->scale_sws_opts = av_strdup(sws_flags_str);
if ((ret = avfilter_graph_create_filter(&filt_src, &input_filter, "src",
NULL, is, graph)) < 0)
- goto the_end;
- if ((ret = avfilter_graph_create_filter(&filt_out, &ffsink, "out",
- NULL, &ffsink_ctx, graph)) < 0)
- goto the_end;
+ return ret;
+ if ((ret = avfilter_graph_create_filter(&filt_out, avfilter_get_by_name("buffersink"), "out",
+ NULL, pix_fmts, graph)) < 0)
+ return ret;
if(vfilters) {
- AVFilterInOut *outputs = av_malloc(sizeof(AVFilterInOut));
- AVFilterInOut *inputs = av_malloc(sizeof(AVFilterInOut));
+ AVFilterInOut *outputs = avfilter_inout_alloc();
+ AVFilterInOut *inputs = avfilter_inout_alloc();
outputs->name = av_strdup("in");
outputs->filter_ctx = filt_src;
inputs->pad_idx = 0;
inputs->next = NULL;
- if ((ret = avfilter_graph_parse(graph, vfilters, inputs, outputs, NULL)) < 0)
- goto the_end;
+ if ((ret = avfilter_graph_parse(graph, vfilters, &inputs, &outputs, NULL)) < 0)
+ return ret;
av_freep(&vfilters);
} else {
if ((ret = avfilter_link(filt_src, 0, filt_out, 0)) < 0)
- goto the_end;
+ return ret;
}
if ((ret = avfilter_graph_config(graph, NULL)) < 0)
- goto the_end;
+ return ret;
is->out_video_filter = filt_out;
-the_end:
+
return ret;
}
AVPacket pkt;
#else
AVFilterBufferRef *picref;
- AVRational tb;
+ AVRational tb = filt_out->inputs[0]->time_base;
#endif
while (is->paused && !is->videoq.abort_request)
SDL_Delay(10);
#if CONFIG_AVFILTER
- ret = get_filtered_video_frame(filt_out, frame, &picref, &tb);
+ ret = av_vsink_buffer_get_video_buffer_ref(filt_out, &picref, 0);
if (picref) {
+ avfilter_fill_frame_from_video_buffer_ref(frame, picref);
pts_int = picref->pts;
pos = picref->pos;
frame->opaque = picref;
if (ret < 0) goto the_end;
- if (!ret)
+ if (!picref)
continue;
pts = pts_int*av_q2d(is->video_st->time_base);
VideoState *is = arg;
SubPicture *sp;
AVPacket pkt1, *pkt = &pkt1;
- int len1 av_unused, got_subtitle;
+ int got_subtitle;
double pts;
int i, j;
int r, g, b, y, u, v, a;
SDL_UnlockMutex(is->subpq_mutex);
if (is->subtitleq.abort_request)
- goto the_end;
+ return 0;
sp = &is->subpq[is->subpq_windex];
if (pkt->pts != AV_NOPTS_VALUE)
pts = av_q2d(is->subtitle_st->time_base)*pkt->pts;
- len1 = avcodec_decode_subtitle2(is->subtitle_st->codec,
- &sp->sub, &got_subtitle,
- pkt);
+ avcodec_decode_subtitle2(is->subtitle_st->codec, &sp->sub,
+ &got_subtitle, pkt);
+
if (got_subtitle && sp->sub.format == 0) {
sp->pts = pts;
}
av_free_packet(pkt);
}
- the_end:
return 0;
}
if (is->reformat_ctx) {
const void *ibuf[6]= {is->audio_buf1};
void *obuf[6]= {is->audio_buf2};
- int istride[6]= {av_get_bits_per_sample_fmt(dec->sample_fmt)/8};
+ int istride[6]= {av_get_bytes_per_sample(dec->sample_fmt)};
int ostride[6]= {2};
int len= data_size/istride[0];
if (av_audio_convert(is->reformat_ctx, obuf, ostride, ibuf, istride, len)<0) {
n = 2 * dec->channels;
is->audio_clock += (double)data_size /
(double)(n * dec->sample_rate);
-#if defined(DEBUG_SYNC)
+#ifdef DEBUG
{
static double last_clock;
printf("audio: delay=%0.3f clock=%0.3f pts=%0.3f\n",
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]);
+
/* prepare audio output */
if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
if (avctx->channels > 0) {
avctx->error_concealment= error_concealment;
avctx->thread_count= thread_count;
- set_context_opts(avctx, avcodec_opts[avctx->codec_type], 0, codec);
-
if(codec->capabilities & CODEC_CAP_DR1)
avctx->flags |= CODEC_FLAG_EMU_EDGE;
- if (avcodec_open(avctx, codec) < 0)
+ if (!codec ||
+ avcodec_open2(avctx, codec, &opts) < 0)
return -1;
+ 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) {
static int read_thread(void *arg)
{
VideoState *is = arg;
- AVFormatContext *ic;
+ AVFormatContext *ic = NULL;
int err, i, ret;
int st_index[AVMEDIA_TYPE_NB];
AVPacket pkt1, *pkt = &pkt1;
- AVFormatParameters params, *ap = ¶ms;
int eof=0;
int pkt_in_play_range = 0;
-
- ic = avformat_alloc_context();
+ AVDictionaryEntry *t;
+ AVDictionary **opts;
+ int orig_nb_streams;
memset(st_index, -1, sizeof(st_index));
is->video_stream = -1;
global_video_state = is;
avio_set_interrupt_cb(decode_interrupt_cb);
- memset(ap, 0, sizeof(*ap));
-
- ap->prealloced_context = 1;
- ap->width = frame_width;
- ap->height= frame_height;
- ap->time_base= (AVRational){1, 25};
- ap->pix_fmt = frame_pix_fmt;
- ic->flags |= AVFMT_FLAG_PRIV_OPT;
-
-
- err = av_open_input_file(&ic, is->filename, is->iformat, 0, ap);
- if (err >= 0) {
- set_context_opts(ic, avformat_opts, AV_OPT_FLAG_DECODING_PARAM, NULL);
- err = av_demuxer_open(ic, ap);
- if(err < 0){
- avformat_free_context(ic);
- ic= NULL;
- }
- }
+ err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
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;
+ }
is->ic = ic;
if(genpts)
ic->flags |= AVFMT_FLAG_GENPTS;
- err = av_find_stream_info(ic);
+ 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, ffplay maybe should not use url_feof() to test for the end
static int opt_frame_size(const char *opt, const char *arg)
{
- if (av_parse_video_size(&frame_width, &frame_height, arg) < 0) {
- fprintf(stderr, "Incorrect frame size\n");
- return AVERROR(EINVAL);
- }
- if ((frame_width % 2) != 0 || (frame_height % 2) != 0) {
- fprintf(stderr, "Frame size must be a multiple of 2\n");
- return AVERROR(EINVAL);
- }
- return 0;
+ av_log(NULL, AV_LOG_WARNING, "Option -s is deprecated, use -video_size.\n");
+ return opt_default("video_size", arg);
}
static int opt_width(const char *opt, const char *arg)
static int opt_frame_pix_fmt(const char *opt, const char *arg)
{
- frame_pix_fmt = av_get_pix_fmt(arg);
- return 0;
+ av_log(NULL, AV_LOG_WARNING, "Option -pix_fmt is deprecated, use -pixel_format.\n");
+ return opt_default("pixel_format", arg);
}
static int opt_sync(const char *opt, const char *arg)
static void show_usage(void)
{
printf("Simple media player\n");
- printf("usage: ffplay [options] input_file\n");
+ printf("usage: %s [options] input_file\n", program_name);
printf("\n");
}
-static void show_help(void)
+static int opt_help(const char *opt, const char *arg)
{
av_log_set_callback(log_callback_help);
show_usage();
"down/up seek backward/forward 1 minute\n"
"mouse click seek to percentage in file corresponding to fraction of width\n"
);
+ return 0;
}
/* Called from the main */
if (!input_filename) {
show_usage();
fprintf(stderr, "An input file must be specified\n");
- fprintf(stderr, "Use -h to get full help or, even better, run 'man ffplay'\n");
+ fprintf(stderr, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
exit(1);
}
video_disable = 1;
}
flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
+ if (audio_disable)
+ flags &= ~SDL_INIT_AUDIO;
#if !defined(__MINGW32__) && !defined(__APPLE__)
flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */
#endif
if (SDL_Init (flags)) {
fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
+ fprintf(stderr, "(Did you set the DISPLAY variable?)\n");
exit(1);
}