diff options
author | Anton Khirnov <anton@khirnov.net> | 2012-05-30 08:53:08 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2012-06-05 09:36:10 +0200 |
commit | 67339f6eb41299096dd7de94f557b487ec3477ff (patch) | |
tree | e55eef1c40e8aa493d0a46291b0f113f6a43813d | |
parent | d55c2e05b5d07154ce374e159bbc1a6cf40e57d3 (diff) | |
download | ffmpeg-streaming-67339f6eb41299096dd7de94f557b487ec3477ff.zip ffmpeg-streaming-67339f6eb41299096dd7de94f557b487ec3477ff.tar.gz |
avplay: use buffersrc instead of custom input filter.
We do not allow user filters, so avtools shouldn't use them either.
It also allows to reuse buffer management code from avconv, thus
reducing duplication.
-rw-r--r-- | avplay.c | 297 |
1 files changed, 76 insertions, 221 deletions
@@ -42,6 +42,7 @@ # include "libavfilter/avfilter.h" # include "libavfilter/avfiltergraph.h" # include "libavfilter/buffersink.h" +# include "libavfilter/buffersrc.h" #endif #include "cmdutils.h" @@ -212,7 +213,10 @@ typedef struct VideoState { PtsCorrectionContext pts_ctx; #if CONFIG_AVFILTER + AVFilterContext *in_video_filter; ///< the first filter in the video chain AVFilterContext *out_video_filter; ///< the last filter in the video chain + int use_dr1; + FrameBuffer *buffer_pool; #endif float skip_frames; @@ -1517,206 +1521,27 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke } #if CONFIG_AVFILTER -typedef struct { - VideoState *is; - AVFrame *frame; - int use_dr1; -} FilterPriv; - -static int input_get_buffer(AVCodecContext *codec, AVFrame *pic) -{ - AVFilterContext *ctx = codec->opaque; - AVFilterBufferRef *ref; - int perms = AV_PERM_WRITE; - int i, w, h, stride[AV_NUM_DATA_POINTERS]; - unsigned edge; - int pixel_size; - - if (codec->codec->capabilities & CODEC_CAP_NEG_LINESIZES) - perms |= AV_PERM_NEG_LINESIZES; - - if (pic->buffer_hints & FF_BUFFER_HINTS_VALID) { - if (pic->buffer_hints & FF_BUFFER_HINTS_READABLE) perms |= AV_PERM_READ; - if (pic->buffer_hints & FF_BUFFER_HINTS_PRESERVE) perms |= AV_PERM_PRESERVE; - if (pic->buffer_hints & FF_BUFFER_HINTS_REUSABLE) perms |= AV_PERM_REUSE2; - } - if (pic->reference) perms |= AV_PERM_READ | AV_PERM_PRESERVE; - - w = codec->width; - h = codec->height; - avcodec_align_dimensions2(codec, &w, &h, stride); - edge = codec->flags & CODEC_FLAG_EMU_EDGE ? 0 : avcodec_get_edge_width(); - w += edge << 1; - h += edge << 1; - - if (!(ref = avfilter_get_video_buffer(ctx->outputs[0], perms, w, h))) - return -1; - - pixel_size = av_pix_fmt_descriptors[ref->format].comp[0].step_minus1 + 1; - ref->video->w = codec->width; - ref->video->h = codec->height; - for (i = 0; i < 4; i ++) { - unsigned hshift = (i == 1 || i == 2) ? av_pix_fmt_descriptors[ref->format].log2_chroma_w : 0; - unsigned vshift = (i == 1 || i == 2) ? av_pix_fmt_descriptors[ref->format].log2_chroma_h : 0; - - if (ref->data[i]) { - ref->data[i] += ((edge * pixel_size) >> hshift) + ((edge * ref->linesize[i]) >> vshift); - } - pic->data[i] = ref->data[i]; - pic->linesize[i] = ref->linesize[i]; - } - pic->opaque = ref; - pic->type = FF_BUFFER_TYPE_USER; - pic->reordered_opaque = codec->reordered_opaque; - pic->width = codec->width; - pic->height = codec->height; - pic->format = codec->pix_fmt; - pic->sample_aspect_ratio = codec->sample_aspect_ratio; - if (codec->pkt) pic->pkt_pts = codec->pkt->pts; - else pic->pkt_pts = AV_NOPTS_VALUE; - return 0; -} - -static void input_release_buffer(AVCodecContext *codec, AVFrame *pic) -{ - memset(pic->data, 0, sizeof(pic->data)); - avfilter_unref_buffer(pic->opaque); -} - -static int input_reget_buffer(AVCodecContext *codec, AVFrame *pic) -{ - AVFilterBufferRef *ref = pic->opaque; - - if (pic->data[0] == NULL) { - pic->buffer_hints |= FF_BUFFER_HINTS_READABLE; - return codec->get_buffer(codec, pic); - } - - if ((codec->width != ref->video->w) || (codec->height != ref->video->h) || - (codec->pix_fmt != ref->format)) { - av_log(codec, AV_LOG_ERROR, "Picture properties changed.\n"); - return -1; - } - - pic->reordered_opaque = codec->reordered_opaque; - if (codec->pkt) pic->pkt_pts = codec->pkt->pts; - else pic->pkt_pts = AV_NOPTS_VALUE; - return 0; -} - -static int input_init(AVFilterContext *ctx, const char *args, void *opaque) -{ - FilterPriv *priv = ctx->priv; - AVCodecContext *codec; - if (!opaque) return -1; - - priv->is = opaque; - codec = priv->is->video_st->codec; - codec->opaque = ctx; - if (codec->codec->capabilities & CODEC_CAP_DR1) { - priv->use_dr1 = 1; - codec->get_buffer = input_get_buffer; - codec->release_buffer = input_release_buffer; - codec->reget_buffer = input_reget_buffer; - codec->thread_safe_callbacks = 1; - } - - priv->frame = avcodec_alloc_frame(); - - return 0; -} - -static void input_uninit(AVFilterContext *ctx) -{ - FilterPriv *priv = ctx->priv; - av_free(priv->frame); -} - -static int input_request_frame(AVFilterLink *link) -{ - FilterPriv *priv = link->src->priv; - AVFilterBufferRef *picref; - int64_t pts = 0; - AVPacket pkt; - int ret; - - while (!(ret = get_video_frame(priv->is, priv->frame, &pts, &pkt))) - av_free_packet(&pkt); - if (ret < 0) - return -1; - - if (priv->use_dr1) { - picref = avfilter_ref_buffer(priv->frame->opaque, ~0); - } else { - picref = avfilter_get_video_buffer(link, AV_PERM_WRITE, link->w, link->h); - av_image_copy(picref->data, picref->linesize, - priv->frame->data, priv->frame->linesize, - picref->format, link->w, link->h); - } - av_free_packet(&pkt); - - avfilter_copy_frame_props(picref, priv->frame); - picref->pts = pts; - - avfilter_start_frame(link, picref); - avfilter_draw_slice(link, 0, link->h, 1); - avfilter_end_frame(link); - - return 0; -} - -static int input_query_formats(AVFilterContext *ctx) -{ - FilterPriv *priv = ctx->priv; - enum PixelFormat pix_fmts[] = { - priv->is->video_st->codec->pix_fmt, PIX_FMT_NONE - }; - - avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts)); - return 0; -} - -static int input_config_props(AVFilterLink *link) -{ - FilterPriv *priv = link->src->priv; - AVCodecContext *c = priv->is->video_st->codec; - - link->w = c->width; - link->h = c->height; - link->time_base = priv->is->video_st->time_base; - - return 0; -} - -static AVFilter input_filter = -{ - .name = "avplay_input", - - .priv_size = sizeof(FilterPriv), - - .init = input_init, - .uninit = input_uninit, - - .query_formats = input_query_formats, - - .inputs = (AVFilterPad[]) {{ .name = NULL }}, - .outputs = (AVFilterPad[]) {{ .name = "default", - .type = AVMEDIA_TYPE_VIDEO, - .request_frame = input_request_frame, - .config_props = input_config_props, }, - { .name = NULL }}, -}; - static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters) { char sws_flags_str[128]; + char buffersrc_args[256]; int ret; AVFilterContext *filt_src = NULL, *filt_out = NULL, *filt_format; + AVCodecContext *codec = is->video_st->codec; + 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) + snprintf(buffersrc_args, sizeof(buffersrc_args), "%d:%d:%d:%d:%d:%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, + graph)) < 0) return ret; if ((ret = avfilter_graph_create_filter(&filt_out, avfilter_get_by_name("buffersink"), @@ -1755,8 +1580,16 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c if ((ret = avfilter_graph_config(graph, NULL)) < 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; } @@ -1772,25 +1605,34 @@ static int video_thread(void *arg) #if CONFIG_AVFILTER AVFilterGraph *graph = avfilter_graph_alloc(); - AVFilterContext *filt_out = NULL; + AVFilterContext *filt_out = NULL, *filt_in = NULL; int64_t pos; int last_w = is->video_st->codec->width; int last_h = is->video_st->codec->height; if ((ret = configure_video_filters(graph, is, vfilters)) < 0) goto the_end; + filt_in = is->in_video_filter; filt_out = is->out_video_filter; #endif for (;;) { -#if !CONFIG_AVFILTER AVPacket pkt; -#else +#if CONFIG_AVFILTER AVFilterBufferRef *picref; AVRational tb; #endif while (is->paused && !is->videoq.abort_request) SDL_Delay(10); + + ret = get_video_frame(is, frame, &pts_int, &pkt); + if (ret < 0) + goto the_end; + av_free_packet(&pkt); + + if (!ret) + continue; + #if CONFIG_AVFILTER if ( last_w != is->video_st->codec->width || last_h != is->video_st->codec->height) { @@ -1804,8 +1646,33 @@ static int video_thread(void *arg) last_w = is->video_st->codec->width; last_h = is->video_st->codec->height; } - ret = av_buffersink_read(filt_out, &picref); - if (picref) { + + frame->pts = pts_int; + if (is->use_dr1) { + FrameBuffer *buf = frame->opaque; + AVFilterBufferRef *fb = avfilter_get_video_buffer_ref_from_arrays( + frame->data, frame->linesize, + AV_PERM_READ | AV_PERM_PRESERVE, + frame->width, frame->height, + frame->format); + + avfilter_copy_frame_props(fb, frame); + fb->buf->priv = buf; + fb->buf->free = filter_release_buffer; + + buf->refcount++; + av_buffersrc_buffer(filt_in, fb); + + } else + av_buffersrc_write_frame(filt_in, frame); + + while (ret >= 0) { + ret = av_buffersink_read(filt_out, &picref); + if (ret < 0) { + ret = 0; + break; + } + avfilter_copy_buf_props(frame, picref); pts_int = picref->pts; @@ -1813,35 +1680,22 @@ static int video_thread(void *arg) pos = picref->pos; frame->opaque = picref; - ret = 1; - } - - if (ret >= 0 && av_cmp_q(tb, is->video_st->time_base)) { - av_unused int64_t pts1 = pts_int; - pts_int = av_rescale_q(pts_int, tb, is->video_st->time_base); - av_dlog(NULL, "video_thread(): " - "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n", - tb.num, tb.den, pts1, - is->video_st->time_base.num, is->video_st->time_base.den, pts_int); + if (av_cmp_q(tb, is->video_st->time_base)) { + av_unused int64_t pts1 = pts_int; + pts_int = av_rescale_q(pts_int, tb, is->video_st->time_base); + av_dlog(NULL, "video_thread(): " + "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n", + tb.num, tb.den, pts1, + is->video_st->time_base.num, is->video_st->time_base.den, pts_int); + } + pts = pts_int * av_q2d(is->video_st->time_base); + ret = output_picture2(is, frame, pts, pos); } #else - ret = get_video_frame(is, frame, &pts_int, &pkt); -#endif - - if (ret < 0) - goto the_end; - - if (!ret) - continue; - pts = pts_int * av_q2d(is->video_st->time_base); - -#if CONFIG_AVFILTER - ret = output_picture2(is, frame, pts, pos); -#else ret = output_picture2(is, frame, pts, pkt.pos); - av_free_packet(&pkt); #endif + if (ret < 0) goto the_end; @@ -2386,6 +2240,7 @@ static void stream_component_close(VideoState *is, int stream_index) ic->streams[stream_index]->discard = AVDISCARD_ALL; avcodec_close(avctx); + free_buffer_pool(&is->buffer_pool); switch (avctx->codec_type) { case AVMEDIA_TYPE_AUDIO: is->audio_st = NULL; |