+
+ }
+ return 0;
+}
+
+#if CONFIG_AVFILTER
+typedef struct {
+ VideoState *is;
+ AVFrame *frame;
+} FilterPriv;
+
+static int input_init(AVFilterContext *ctx, const char *args, void *opaque)
+{
+ FilterPriv *priv = ctx->priv;
+ if(!opaque) return -1;
+
+ priv->is = opaque;
+ 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;
+ AVFilterPicRef *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;
+
+ /* FIXME: until I figure out how to hook everything up to the codec
+ * right, we're just copying the entire frame. */
+ picref = avfilter_get_video_buffer(link, AV_PERM_WRITE, link->w, link->h);
+ av_picture_copy((AVPicture *)&picref->data, (AVPicture *)priv->frame,
+ picref->pic->format, link->w, link->h);
+ av_free_packet(&pkt);
+
+ picref->pts = pts;
+ picref->pos = pkt.pos;
+ picref->pixel_aspect = priv->is->video_st->codec->sample_aspect_ratio;
+ avfilter_start_frame(link, avfilter_ref_pic(picref, ~0));
+ avfilter_draw_slice(link, 0, link->h, 1);
+ avfilter_end_frame(link);
+ avfilter_unref_pic(picref);
+
+ 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;
+
+ return 0;
+}
+
+static AVFilter input_filter =
+{
+ .name = "ffplay_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 = CODEC_TYPE_VIDEO,
+ .request_frame = input_request_frame,
+ .config_props = input_config_props, },
+ { .name = NULL }},
+};
+
+static void output_end_frame(AVFilterLink *link)
+{
+}
+
+static int output_query_formats(AVFilterContext *ctx)
+{
+ enum PixelFormat pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE };
+
+ avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts));
+ return 0;
+}
+
+static int get_filtered_video_frame(AVFilterContext *ctx, AVFrame *frame,
+ int64_t *pts, int64_t *pos)
+{
+ AVFilterPicRef *pic;
+
+ if(avfilter_request_frame(ctx->inputs[0]))
+ return -1;
+ if(!(pic = ctx->inputs[0]->cur_pic))
+ return -1;
+ ctx->inputs[0]->cur_pic = NULL;
+
+ frame->opaque = pic;
+ *pts = pic->pts;
+ *pos = pic->pos;
+
+ memcpy(frame->data, pic->data, sizeof(frame->data));
+ memcpy(frame->linesize, pic->linesize, sizeof(frame->linesize));
+
+ return 1;
+}
+
+static AVFilter output_filter =
+{
+ .name = "ffplay_output",
+
+ .query_formats = output_query_formats,
+
+ .inputs = (AVFilterPad[]) {{ .name = "default",
+ .type = CODEC_TYPE_VIDEO,
+ .end_frame = output_end_frame,
+ .min_perms = AV_PERM_READ, },
+ { .name = NULL }},
+ .outputs = (AVFilterPad[]) {{ .name = NULL }},
+};
+#endif /* CONFIG_AVFILTER */
+
+static int video_thread(void *arg)
+{
+ VideoState *is = arg;
+ AVFrame *frame= avcodec_alloc_frame();
+ int64_t pts_int, pos;
+ double pts;
+ int ret;
+
+#if CONFIG_AVFILTER
+ AVFilterContext *filt_src = NULL, *filt_out = NULL;
+ AVFilterGraph *graph = av_mallocz(sizeof(AVFilterGraph));
+ graph->scale_sws_opts = av_strdup("sws_flags=bilinear");
+
+ if(!(filt_src = avfilter_open(&input_filter, "src"))) goto the_end;
+ if(!(filt_out = avfilter_open(&output_filter, "out"))) goto the_end;
+
+ if(avfilter_init_filter(filt_src, NULL, is)) goto the_end;
+ if(avfilter_init_filter(filt_out, NULL, frame)) goto the_end;
+
+
+ if(vfilters) {
+ AVFilterInOut *outputs = av_malloc(sizeof(AVFilterInOut));
+ AVFilterInOut *inputs = av_malloc(sizeof(AVFilterInOut));
+
+ outputs->name = av_strdup("in");
+ outputs->filter = filt_src;
+ outputs->pad_idx = 0;
+ outputs->next = NULL;
+
+ inputs->name = av_strdup("out");
+ inputs->filter = filt_out;
+ inputs->pad_idx = 0;
+ inputs->next = NULL;
+
+ if (avfilter_graph_parse(graph, vfilters, inputs, outputs, NULL) < 0)
+ goto the_end;
+ av_freep(&vfilters);
+ } else {
+ if(avfilter_link(filt_src, 0, filt_out, 0) < 0) goto the_end;
+ }
+ avfilter_graph_add_filter(graph, filt_src);
+ avfilter_graph_add_filter(graph, filt_out);
+
+ if(avfilter_graph_check_validity(graph, NULL)) goto the_end;
+ if(avfilter_graph_config_formats(graph, NULL)) goto the_end;
+ if(avfilter_graph_config_links(graph, NULL)) goto the_end;
+
+ is->out_video_filter = filt_out;
+#endif
+
+ for(;;) {
+#if !CONFIG_AVFILTER
+ AVPacket pkt;
+#endif
+ while (is->paused && !is->videoq.abort_request)
+ SDL_Delay(10);
+#if CONFIG_AVFILTER
+ ret = get_filtered_video_frame(filt_out, frame, &pts_int, &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;
+