yading@10: /* yading@10: * Copyright (c) 2002 A'rpi yading@10: * Copyright (C) 2012 Clément Bœsch yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or modify yading@10: * it under the terms of the GNU General Public License as published by yading@10: * the Free Software Foundation; either version 2 of the License, or yading@10: * (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the yading@10: * GNU General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU General Public License along yading@10: * with FFmpeg; if not, write to the Free Software Foundation, Inc., yading@10: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. yading@10: */ yading@10: yading@10: /** yading@10: * @file yading@10: * libpostproc filter, ported from MPlayer. yading@10: */ yading@10: yading@10: #include "libavutil/avassert.h" yading@10: #include "libavutil/opt.h" yading@10: #include "internal.h" yading@10: yading@10: #include "libpostproc/postprocess.h" yading@10: yading@10: typedef struct { yading@10: const AVClass *class; yading@10: char *subfilters; yading@10: int mode_id; yading@10: pp_mode *modes[PP_QUALITY_MAX + 1]; yading@10: void *pp_ctx; yading@10: } PPFilterContext; yading@10: yading@10: #define OFFSET(x) offsetof(PPFilterContext, x) yading@10: #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM yading@10: static const AVOption pp_options[] = { yading@10: { "subfilters", "set postprocess subfilters", OFFSET(subfilters), AV_OPT_TYPE_STRING, {.str="de"}, .flags = FLAGS }, yading@10: { NULL } yading@10: }; yading@10: yading@10: AVFILTER_DEFINE_CLASS(pp); yading@10: yading@10: static av_cold int pp_init(AVFilterContext *ctx) yading@10: { yading@10: int i; yading@10: PPFilterContext *pp = ctx->priv; yading@10: yading@10: for (i = 0; i <= PP_QUALITY_MAX; i++) { yading@10: pp->modes[i] = pp_get_mode_by_name_and_quality(pp->subfilters, i); yading@10: if (!pp->modes[i]) yading@10: return AVERROR_EXTERNAL; yading@10: } yading@10: pp->mode_id = PP_QUALITY_MAX; yading@10: return 0; yading@10: } yading@10: yading@10: static int pp_process_command(AVFilterContext *ctx, const char *cmd, const char *args, yading@10: char *res, int res_len, int flags) yading@10: { yading@10: PPFilterContext *pp = ctx->priv; yading@10: yading@10: if (!strcmp(cmd, "quality")) { yading@10: pp->mode_id = av_clip(strtol(args, NULL, 10), 0, PP_QUALITY_MAX); yading@10: return 0; yading@10: } yading@10: return AVERROR(ENOSYS); yading@10: } yading@10: yading@10: static int pp_query_formats(AVFilterContext *ctx) yading@10: { yading@10: static const enum PixelFormat pix_fmts[] = { yading@10: AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P, yading@10: AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVJ422P, yading@10: AV_PIX_FMT_YUV411P, yading@10: AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, yading@10: AV_PIX_FMT_NONE yading@10: }; yading@10: ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); yading@10: return 0; yading@10: } yading@10: yading@10: static int pp_config_props(AVFilterLink *inlink) yading@10: { yading@10: int flags = PP_CPU_CAPS_AUTO; yading@10: PPFilterContext *pp = inlink->dst->priv; yading@10: yading@10: switch (inlink->format) { yading@10: case AV_PIX_FMT_YUVJ420P: yading@10: case AV_PIX_FMT_YUV420P: flags |= PP_FORMAT_420; break; yading@10: case AV_PIX_FMT_YUVJ422P: yading@10: case AV_PIX_FMT_YUV422P: flags |= PP_FORMAT_422; break; yading@10: case AV_PIX_FMT_YUV411P: flags |= PP_FORMAT_411; break; yading@10: case AV_PIX_FMT_YUVJ444P: yading@10: case AV_PIX_FMT_YUV444P: flags |= PP_FORMAT_444; break; yading@10: default: av_assert0(0); yading@10: } yading@10: yading@10: pp->pp_ctx = pp_get_context(inlink->w, inlink->h, flags); yading@10: if (!pp->pp_ctx) yading@10: return AVERROR(ENOMEM); yading@10: return 0; yading@10: } yading@10: yading@10: static int pp_filter_frame(AVFilterLink *inlink, AVFrame *inbuf) yading@10: { yading@10: AVFilterContext *ctx = inlink->dst; yading@10: PPFilterContext *pp = ctx->priv; yading@10: AVFilterLink *outlink = ctx->outputs[0]; yading@10: const int aligned_w = FFALIGN(outlink->w, 8); yading@10: const int aligned_h = FFALIGN(outlink->h, 8); yading@10: AVFrame *outbuf; yading@10: int qstride, qp_type; yading@10: int8_t *qp_table ; yading@10: yading@10: outbuf = ff_get_video_buffer(outlink, aligned_w, aligned_h); yading@10: if (!outbuf) { yading@10: av_frame_free(&inbuf); yading@10: return AVERROR(ENOMEM); yading@10: } yading@10: av_frame_copy_props(outbuf, inbuf); yading@10: qp_table = av_frame_get_qp_table(inbuf, &qstride, &qp_type); yading@10: yading@10: pp_postprocess((const uint8_t **)inbuf->data, inbuf->linesize, yading@10: outbuf->data, outbuf->linesize, yading@10: aligned_w, outlink->h, yading@10: qp_table, yading@10: qstride, yading@10: pp->modes[pp->mode_id], yading@10: pp->pp_ctx, yading@10: outbuf->pict_type | (qp_type ? PP_PICT_TYPE_QP2 : 0)); yading@10: yading@10: av_frame_free(&inbuf); yading@10: return ff_filter_frame(outlink, outbuf); yading@10: } yading@10: yading@10: static av_cold void pp_uninit(AVFilterContext *ctx) yading@10: { yading@10: int i; yading@10: PPFilterContext *pp = ctx->priv; yading@10: yading@10: for (i = 0; i <= PP_QUALITY_MAX; i++) yading@10: pp_free_mode(pp->modes[i]); yading@10: if (pp->pp_ctx) yading@10: pp_free_context(pp->pp_ctx); yading@10: } yading@10: yading@10: static const AVFilterPad pp_inputs[] = { yading@10: { yading@10: .name = "default", yading@10: .type = AVMEDIA_TYPE_VIDEO, yading@10: .config_props = pp_config_props, yading@10: .filter_frame = pp_filter_frame, yading@10: }, yading@10: { NULL } yading@10: }; yading@10: yading@10: static const AVFilterPad pp_outputs[] = { yading@10: { yading@10: .name = "default", yading@10: .type = AVMEDIA_TYPE_VIDEO, yading@10: }, yading@10: { NULL } yading@10: }; yading@10: yading@10: AVFilter avfilter_vf_pp = { yading@10: .name = "pp", yading@10: .description = NULL_IF_CONFIG_SMALL("Filter video using libpostproc."), yading@10: .priv_size = sizeof(PPFilterContext), yading@10: .init = pp_init, yading@10: .uninit = pp_uninit, yading@10: .query_formats = pp_query_formats, yading@10: .inputs = pp_inputs, yading@10: .outputs = pp_outputs, yading@10: .process_command = pp_process_command, yading@10: .priv_class = &pp_class, yading@10: yading@10: };