]> git.sesse.net Git - ffmpeg/blobdiff - ffplay.c
av_url_split: dont let '/' char whallop '?' char
[ffmpeg] / ffplay.c
index 86444a822bf7a5d7fcbcb3e431a6c1d3bb781cb7..598ce749d5d5a84c59f346b03505f0dd14e4f630 100644 (file)
--- a/ffplay.c
+++ b/ffplay.c
@@ -37,6 +37,7 @@
 #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"
@@ -57,7 +58,6 @@
 
 #include "cmdutils.h"
 
-#include <unistd.h>
 #include <assert.h>
 
 const char program_name[] = "ffplay";
@@ -281,6 +281,7 @@ static int exit_on_keydown;
 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;
@@ -908,10 +909,7 @@ static void stream_close(VideoState *is)
     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);
@@ -1015,7 +1013,7 @@ static int refresh_thread(void *opaque)
             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;
 }
@@ -1317,9 +1315,7 @@ static void alloc_picture(AllocEventProps *event_props)
         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;
@@ -1425,8 +1421,7 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts1, int64_
     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
 
@@ -1504,7 +1499,8 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke
         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;
@@ -1540,15 +1536,50 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke
             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 };
@@ -1562,28 +1593,22 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c
     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;
@@ -1595,41 +1620,12 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c
     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;
 }
 
@@ -1637,6 +1633,7 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c
 
 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;
@@ -1644,59 +1641,65 @@ static int video_thread(void *arg)
     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,
@@ -1709,19 +1712,27 @@ static int video_thread(void *arg)
             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;
@@ -1756,6 +1767,7 @@ static int video_thread(void *arg)
     av_freep(&vfilters);
     avfilter_graph_free(&graph);
 #endif
+    av_free_packet(&pkt);
     av_free(frame);
     return 0;
 }
@@ -1941,27 +1953,24 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
                                                    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;
@@ -1970,10 +1979,10 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
                 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) {
@@ -1981,13 +1990,12 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
                         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);
                 }
@@ -1995,6 +2003,7 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
                 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 */
@@ -2149,7 +2158,7 @@ static int stream_component_open(VideoState *is, int stream_index)
     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;
@@ -2253,8 +2262,7 @@ static void stream_component_close(VideoState *is, int stream_index)
 
         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);
@@ -2300,7 +2308,9 @@ static void stream_component_close(VideoState *is, int stream_index)
 
     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;
@@ -2495,10 +2505,11 @@ static int read_thread(void *arg)
         }
 
         /* 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;
@@ -2674,14 +2685,13 @@ static void stream_cycle_channel(VideoState *is, int codec_type)
 
 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);
 }
 
@@ -2986,6 +2996,7 @@ static const OptionDef options[] = {
     { "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" },
@@ -3060,6 +3071,7 @@ int main(int argc, char **argv)
 {
     int flags;
     VideoState *is;
+    char dummy_videodriver[] = "SDL_VIDEODRIVER=dummy";
 
     av_log_set_flags(AV_LOG_SKIP_REPEATED);
     parse_loglevel(argc, argv, options);
@@ -3097,6 +3109,8 @@ int main(int argc, char **argv)
     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