aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2010-03-05 02:20:10 +0000
committerMichael Niedermayer <michaelni@gmx.at>2010-03-05 02:20:10 +0000
commit917d2bb348077079df64056a5dd6f4285aedcacb (patch)
tree3452265aaf511f2bbf52ffab1c905df242f7e230
parent4ef82b174a929c3cdce1c694810e8705dc51b320 (diff)
downloadffmpeg-917d2bb348077079df64056a5dd6f4285aedcacb.tar.gz
Libavfilter for ffplay support.
This still needs some minor work here and there but should be already functional. Note that the code pathes that are under "not avfilter" ifdefs as well as the ifdefs will be droped as soon as all major issues have been det with, aka could be real soon or not. Originally committed as revision 22216 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r--ffplay.c368
1 files changed, 338 insertions, 30 deletions
diff --git a/ffplay.c b/ffplay.c
index 36bbf15bb9..6ef0b25f28 100644
--- a/ffplay.c
+++ b/ffplay.c
@@ -32,6 +32,12 @@
#include "libavcodec/opt.h"
#include "libavcodec/dsputil.h"
+#if CONFIG_AVFILTER
+# include "libavfilter/avfilter.h"
+# include "libavfilter/avfiltergraph.h"
+# include "libavfilter/graphparser.h"
+#endif
+
#include "cmdutils.h"
#include <SDL.h>
@@ -72,7 +78,9 @@ const int program_birth_year = 2003;
/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
#define SAMPLE_ARRAY_SIZE (2*65536)
+#if !CONFIG_AVFILTER
static int sws_flags = SWS_BICUBIC;
+#endif
typedef struct PacketQueue {
AVPacketList *first_pkt, *last_pkt;
@@ -93,6 +101,11 @@ typedef struct VideoPicture {
int width, height; /* source height & width */
int allocated;
SDL_TimerID timer_id;
+ enum PixelFormat pix_fmt;
+
+#if CONFIG_AVFILTER
+ AVFilterPicRef *picref;
+#endif
} VideoPicture;
typedef struct SubPicture {
@@ -180,7 +193,9 @@ typedef struct VideoState {
int pictq_size, pictq_rindex, pictq_windex;
SDL_mutex *pictq_mutex;
SDL_cond *pictq_cond;
+#if !CONFIG_AVFILTER
struct SwsContext *img_convert_ctx;
+#endif
// QETimer *video_timer;
char filename[1024];
@@ -191,6 +206,9 @@ typedef struct VideoState {
int64_t last_dts_for_fault_detection;
int64_t last_pts_for_fault_detection;
+#if CONFIG_AVFILTER
+ AVFilterContext *out_video_filter; ///<the last filter in the video chain
+#endif
} VideoState;
static void show_help(void);
@@ -234,6 +252,9 @@ static int error_recognition = FF_ER_CAREFUL;
static int error_concealment = 3;
static int decoder_reorder_pts= -1;
static int autoexit;
+#if CONFIG_AVFILTER
+static char *vfilters = NULL;
+#endif
/* current context */
static int is_full_screen;
@@ -668,6 +689,13 @@ static void video_image_display(VideoState *is)
vp = &is->pictq[is->pictq_rindex];
if (vp->bmp) {
+#if CONFIG_AVFILTER
+ if (vp->picref->pixel_aspect.num == 0)
+ aspect_ratio = 0;
+ else
+ aspect_ratio = av_q2d(vp->picref->pixel_aspect);
+#else
+
/* XXX: use variable in the frame */
if (is->video_st->sample_aspect_ratio.num)
aspect_ratio = av_q2d(is->video_st->sample_aspect_ratio);
@@ -675,9 +703,10 @@ static void video_image_display(VideoState *is)
aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio);
else
aspect_ratio = 0;
+#endif
if (aspect_ratio <= 0.0)
aspect_ratio = 1.0;
- aspect_ratio *= (float)is->video_st->codec->width / is->video_st->codec->height;
+ aspect_ratio *= (float)vp->width / (float)vp->height;
/* if an active format is indicated, then it overrides the
mpeg format */
#if 0
@@ -927,9 +956,15 @@ static int video_open(VideoState *is){
} else if(!is_full_screen && screen_width){
w = screen_width;
h = screen_height;
+#if CONFIG_AVFILTER
+ }else if (is->out_video_filter && is->out_video_filter->inputs[0]){
+ w = is->out_video_filter->inputs[0]->w;
+ h = is->out_video_filter->inputs[0]->h;
+#else
}else if (is->video_st && is->video_st->codec->width){
w = is->video_st->codec->width;
h = is->video_st->codec->height;
+#endif
} else {
w = 640;
h = 480;
@@ -1241,12 +1276,23 @@ static void alloc_picture(void *opaque)
if (vp->bmp)
SDL_FreeYUVOverlay(vp->bmp);
- vp->bmp = SDL_CreateYUVOverlay(is->video_st->codec->width,
- is->video_st->codec->height,
+#if CONFIG_AVFILTER
+ if (vp->picref)
+ avfilter_unref_pic(vp->picref);
+ vp->picref = NULL;
+
+ vp->width = is->out_video_filter->inputs[0]->w;
+ vp->height = is->out_video_filter->inputs[0]->h;
+ vp->pix_fmt = is->out_video_filter->inputs[0]->format;
+#else
+ vp->width = is->video_st->codec->width;
+ vp->height = is->video_st->codec->height;
+ vp->pix_fmt = is->video_st->codec->pix_fmt;
+#endif
+
+ vp->bmp = SDL_CreateYUVOverlay(vp->width, vp->height,
SDL_YV12_OVERLAY,
screen);
- vp->width = is->video_st->codec->width;
- vp->height = is->video_st->codec->height;
SDL_LockMutex(is->pictq_mutex);
vp->allocated = 1;
@@ -1262,7 +1308,9 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t
{
VideoPicture *vp;
int dst_pix_fmt;
-
+#if CONFIG_AVFILTER
+ AVPicture pict_src;
+#endif
/* wait until we have space to put a new picture */
SDL_LockMutex(is->pictq_mutex);
while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE &&
@@ -1278,8 +1326,13 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t
/* alloc or resize hardware picture buffer */
if (!vp->bmp ||
+#if CONFIG_AVFILTER
+ vp->width != is->out_video_filter->inputs[0]->w ||
+ vp->height != is->out_video_filter->inputs[0]->h) {
+#else
vp->width != is->video_st->codec->width ||
vp->height != is->video_st->codec->height) {
+#endif
SDL_Event event;
vp->allocated = 0;
@@ -1304,6 +1357,11 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t
/* if the frame is not skipped, then display it */
if (vp->bmp) {
AVPicture pict;
+#if CONFIG_AVFILTER
+ if(vp->picref)
+ avfilter_unref_pic(vp->picref);
+ vp->picref = src_frame->opaque;
+#endif
/* get a pointer on the bitmap */
SDL_LockYUVOverlay (vp->bmp);
@@ -1317,18 +1375,31 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t
pict.linesize[0] = vp->bmp->pitches[0];
pict.linesize[1] = vp->bmp->pitches[2];
pict.linesize[2] = vp->bmp->pitches[1];
+
+#if CONFIG_AVFILTER
+ pict_src.data[0] = src_frame->data[0];
+ pict_src.data[1] = src_frame->data[1];
+ pict_src.data[2] = src_frame->data[2];
+
+ pict_src.linesize[0] = src_frame->linesize[0];
+ pict_src.linesize[1] = src_frame->linesize[1];
+ pict_src.linesize[2] = src_frame->linesize[2];
+
+ //FIXME use direct rendering
+ av_picture_copy(&pict, &pict_src,
+ vp->pix_fmt, vp->width, vp->height);
+#else
sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx,
- is->video_st->codec->width, is->video_st->codec->height,
- is->video_st->codec->pix_fmt,
- is->video_st->codec->width, is->video_st->codec->height,
+ vp->width, vp->height, vp->pix_fmt, vp->width, vp->height,
dst_pix_fmt, sws_flags, NULL, NULL, NULL);
if (is->img_convert_ctx == NULL) {
fprintf(stderr, "Cannot initialize the conversion context\n");
exit(1);
}
sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize,
- 0, is->video_st->codec->height, pict.data, pict.linesize);
+ 0, vp->height, pict.data, pict.linesize);
+#endif
/* update the bitmap content */
SDL_UnlockYUVOverlay(vp->bmp);
@@ -1386,20 +1457,12 @@ static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1, int6
return queue_picture(is, src_frame, pts, pos);
}
-static int video_thread(void *arg)
+static int get_video_frame(VideoState *is, AVFrame *frame, uint64_t *pts, AVPacket *pkt)
{
- VideoState *is = arg;
- AVPacket pkt1, *pkt = &pkt1;
int len1, got_picture, i;
- AVFrame *frame= avcodec_alloc_frame();
- double pts;
- for(;;) {
- while (is->paused && !is->videoq.abort_request) {
- SDL_Delay(10);
- }
if (packet_queue_get(&is->videoq, pkt, 1) < 0)
- break;
+ return -1;
if(pkt->data == flush_pkt.data){
avcodec_flush_buffers(is->video_st->codec);
@@ -1425,7 +1488,7 @@ static int video_thread(void *arg)
is->frame_last_delay = 0;
is->frame_timer = (double)av_gettime() / 1000000.0;
- continue;
+ return 0;
}
/* NOTE: ipts is the PTS of the _first_ picture beginning in
@@ -1450,25 +1513,251 @@ static int video_thread(void *arg)
|| (decoder_reorder_pts && is->faulty_pts<is->faulty_dts)
|| pkt->dts == AV_NOPTS_VALUE)
&& frame->reordered_opaque != AV_NOPTS_VALUE)
- pts= frame->reordered_opaque;
+ *pts= frame->reordered_opaque;
else if(pkt->dts != AV_NOPTS_VALUE)
- pts= pkt->dts;
+ *pts= pkt->dts;
else
- pts= 0;
- pts *= av_q2d(is->video_st->time_base);
+ *pts= 0;
+
+ /* put pts into units of 1/AV_TIME_BASE */
+ *pts = av_rescale_q(pts,is->video_st->time_base, AV_TIME_BASE_Q);
// if (len1 < 0)
// break;
- if (got_picture) {
- if (output_picture2(is, frame, pts, pkt->pos) < 0)
- goto the_end;
- }
- av_free_packet(pkt);
+ if (got_picture)
+ return 1;
+ 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;
+ uint64_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->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,
+ uint64_t *pts)
+{
+ 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;
+
+ 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();
+ uint64_t pts_int;
+ 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);
+#else
+ ret = get_video_frame(is, frame, &pts_int, &pkt);
+#endif
+
+ if (ret < 0) goto the_end;
+
+ if (!ret)
+ continue;
+
+ pts = pts_int;
+ pts /= AV_TIME_BASE;
+
+#if CONFIG_AVFILTER
+ ret = output_picture2(is, frame, pts, -1); /* fixme: unknown pos */
+#else
+ ret = output_picture2(is, frame, pts, pkt->pos);
+ av_free_packet(&pkt);
+#endif
+ if (ret < 0)
+ goto the_end;
+
if (step)
if (cur_stream)
stream_pause(cur_stream);
}
the_end:
+#if CONFIG_AVFILTER
+ avfilter_graph_destroy(graph);
+ av_freep(&graph);
+#endif
av_free(frame);
return 0;
}
@@ -2265,6 +2554,12 @@ static void stream_close(VideoState *is)
/* free all pictures */
for(i=0;i<VIDEO_PICTURE_QUEUE_SIZE; i++) {
vp = &is->pictq[i];
+#if CONFIG_AVFILTER
+ if (vp->picref) {
+ avfilter_unref_pic(vp->picref);
+ vp->picref = NULL;
+ }
+#endif
if (vp->bmp) {
SDL_FreeYUVOverlay(vp->bmp);
vp->bmp = NULL;
@@ -2274,8 +2569,10 @@ static void stream_close(VideoState *is)
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);
}
@@ -2367,6 +2664,9 @@ static void do_exit(void)
av_free(avcodec_opts[i]);
av_free(avformat_opts);
av_free(sws_opts);
+#if CONFIG_AVFILTER
+ avfilter_uninit();
+#endif
if (show_status)
printf("\n");
SDL_Quit();
@@ -2637,6 +2937,9 @@ static const OptionDef options[] = {
{ "sync", HAS_ARG | OPT_FUNC2 | OPT_EXPERT, {(void*)opt_sync}, "set audio-video sync. type (type=audio/video/ext)", "type" },
{ "threads", HAS_ARG | OPT_FUNC2 | OPT_EXPERT, {(void*)opt_thread_count}, "thread count", "count" },
{ "autoexit", OPT_BOOL | OPT_EXPERT, {(void*)&autoexit}, "exit at the end", "" },
+#if CONFIG_AVFILTER
+ { "vfilters", OPT_STRING | HAS_ARG, {(void*)&vfilters}, "video filters", "filter list" },
+#endif
{ "default", OPT_FUNC2 | HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {(void*)opt_default}, "generic catch all option", "" },
{ NULL, },
};
@@ -2689,13 +2992,18 @@ int main(int argc, char **argv)
/* register all codecs, demux and protocols */
avcodec_register_all();
avdevice_register_all();
+#if CONFIG_AVFILTER
+ avfilter_register_all();
+#endif
av_register_all();
for(i=0; i<CODEC_TYPE_NB; i++){
avcodec_opts[i]= avcodec_alloc_context2(i);
}
avformat_opts = avformat_alloc_context();
+#if !CONFIG_AVFILTER
sws_opts = sws_getContext(16,16,0, 16,16,0, sws_flags, NULL,NULL,NULL);
+#endif
show_banner();