]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_pp.c
Merge commit '218aefce4472dc02ee3f12830a9a894bf7916da9'
[ffmpeg] / libavfilter / vf_pp.c
1 /*
2  * Copyright (c) 2002 A'rpi
3  * Copyright (C) 2012 Clément Bœsch
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 /**
23  * @file
24  * libpostproc filter, ported from MPlayer.
25  */
26
27 #include "libavutil/avassert.h"
28 #include "libavutil/opt.h"
29 #include "internal.h"
30
31 #include "libpostproc/postprocess.h"
32
33 typedef struct {
34     int mode_id;
35     pp_mode *modes[PP_QUALITY_MAX + 1];
36     void *pp_ctx;
37 } PPFilterContext;
38
39 static av_cold int pp_init(AVFilterContext *ctx, const char *args)
40 {
41     int i;
42     PPFilterContext *pp = ctx->priv;
43
44     if (!args || !*args)
45         args = "de";
46
47     for (i = 0; i <= PP_QUALITY_MAX; i++) {
48         pp->modes[i] = pp_get_mode_by_name_and_quality(args, i);
49         if (!pp->modes[i])
50             return AVERROR_EXTERNAL;
51     }
52     pp->mode_id = PP_QUALITY_MAX;
53     return 0;
54 }
55
56 static int pp_process_command(AVFilterContext *ctx, const char *cmd, const char *args,
57                               char *res, int res_len, int flags)
58 {
59     PPFilterContext *pp = ctx->priv;
60
61     if (!strcmp(cmd, "quality")) {
62         pp->mode_id = av_clip(strtol(args, NULL, 10), 0, PP_QUALITY_MAX);
63         return 0;
64     }
65     return AVERROR(ENOSYS);
66 }
67
68 static int pp_query_formats(AVFilterContext *ctx)
69 {
70     static const enum PixelFormat pix_fmts[] = {
71         AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P,
72         AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVJ422P,
73         AV_PIX_FMT_YUV411P,
74         AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
75         AV_PIX_FMT_NONE
76     };
77     ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
78     return 0;
79 }
80
81 static int pp_config_props(AVFilterLink *inlink)
82 {
83     int flags = PP_CPU_CAPS_AUTO;
84     PPFilterContext *pp = inlink->dst->priv;
85
86     switch (inlink->format) {
87     case AV_PIX_FMT_YUVJ420P:
88     case AV_PIX_FMT_YUV420P: flags |= PP_FORMAT_420; break;
89     case AV_PIX_FMT_YUVJ422P:
90     case AV_PIX_FMT_YUV422P: flags |= PP_FORMAT_422; break;
91     case AV_PIX_FMT_YUV411P: flags |= PP_FORMAT_411; break;
92     case AV_PIX_FMT_YUVJ444P:
93     case AV_PIX_FMT_YUV444P: flags |= PP_FORMAT_444; break;
94     default: av_assert0(0);
95     }
96
97     pp->pp_ctx = pp_get_context(inlink->w, inlink->h, flags);
98     if (!pp->pp_ctx)
99         return AVERROR(ENOMEM);
100     return 0;
101 }
102
103 static int pp_filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inbuf)
104 {
105     AVFilterContext *ctx = inlink->dst;
106     PPFilterContext *pp = ctx->priv;
107     AVFilterLink *outlink = ctx->outputs[0];
108     const int aligned_w = FFALIGN(outlink->w, 8);
109     const int aligned_h = FFALIGN(outlink->h, 8);
110     AVFilterBufferRef *outbuf;
111
112     outbuf = ff_get_video_buffer(outlink, AV_PERM_WRITE, aligned_w, aligned_h);
113     if (!outbuf) {
114         avfilter_unref_buffer(inbuf);
115         return AVERROR(ENOMEM);
116     }
117     avfilter_copy_buffer_ref_props(outbuf, inbuf);
118
119     pp_postprocess((const uint8_t **)inbuf->data, inbuf->linesize,
120                    outbuf->data,                 outbuf->linesize,
121                    aligned_w, outlink->h,
122                    outbuf->video->qp_table,
123                    outbuf->video->qp_table_linesize,
124                    pp->modes[pp->mode_id],
125                    pp->pp_ctx,
126                    outbuf->video->pict_type);
127
128     avfilter_unref_buffer(inbuf);
129     return ff_filter_frame(outlink, outbuf);
130 }
131
132 static av_cold void pp_uninit(AVFilterContext *ctx)
133 {
134     int i;
135     PPFilterContext *pp = ctx->priv;
136
137     for (i = 0; i <= PP_QUALITY_MAX; i++)
138         pp_free_mode(pp->modes[i]);
139     if (pp->pp_ctx)
140         pp_free_context(pp->pp_ctx);
141 }
142
143 static const AVFilterPad pp_inputs[] = {
144     {
145         .name         = "default",
146         .type         = AVMEDIA_TYPE_VIDEO,
147         .config_props = pp_config_props,
148         .filter_frame = pp_filter_frame,
149         .min_perms    = AV_PERM_READ,
150     },
151     { NULL }
152 };
153
154 static const AVFilterPad pp_outputs[] = {
155     {
156         .name = "default",
157         .type = AVMEDIA_TYPE_VIDEO,
158     },
159     { NULL }
160 };
161
162 AVFilter avfilter_vf_pp = {
163     .name            = "pp",
164     .description     = NULL_IF_CONFIG_SMALL("Filter video using libpostproc."),
165     .priv_size       = sizeof(PPFilterContext),
166     .init            = pp_init,
167     .uninit          = pp_uninit,
168     .query_formats   = pp_query_formats,
169     .inputs          = pp_inputs,
170     .outputs         = pp_outputs,
171     .process_command = pp_process_command,
172 };