Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2010 Stefano Sabatini
  3.  *
  4.  * This file is part of FFmpeg.
  5.  *
  6.  * FFmpeg is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2.1 of the License, or (at your option) any later version.
  10.  *
  11.  * FFmpeg is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with FFmpeg; if not, write to the Free Software
  18.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19.  */
  20.  
  21. /**
  22.  * @file
  23.  * libopencv wrapper functions
  24.  */
  25.  
  26. #include <opencv/cv.h>
  27. #include <opencv/cxcore.h>
  28. #include "libavutil/avstring.h"
  29. #include "libavutil/common.h"
  30. #include "libavutil/file.h"
  31. #include "libavutil/opt.h"
  32. #include "avfilter.h"
  33. #include "formats.h"
  34. #include "internal.h"
  35. #include "video.h"
  36.  
  37. static void fill_iplimage_from_frame(IplImage *img, const AVFrame *frame, enum AVPixelFormat pixfmt)
  38. {
  39.     IplImage *tmpimg;
  40.     int depth, channels_nb;
  41.  
  42.     if      (pixfmt == AV_PIX_FMT_GRAY8) { depth = IPL_DEPTH_8U;  channels_nb = 1; }
  43.     else if (pixfmt == AV_PIX_FMT_BGRA)  { depth = IPL_DEPTH_8U;  channels_nb = 4; }
  44.     else if (pixfmt == AV_PIX_FMT_BGR24) { depth = IPL_DEPTH_8U;  channels_nb = 3; }
  45.     else return;
  46.  
  47.     tmpimg = cvCreateImageHeader((CvSize){frame->width, frame->height}, depth, channels_nb);
  48.     *img = *tmpimg;
  49.     img->imageData = img->imageDataOrigin = frame->data[0];
  50.     img->dataOrder = IPL_DATA_ORDER_PIXEL;
  51.     img->origin    = IPL_ORIGIN_TL;
  52.     img->widthStep = frame->linesize[0];
  53. }
  54.  
  55. static void fill_frame_from_iplimage(AVFrame *frame, const IplImage *img, enum AVPixelFormat pixfmt)
  56. {
  57.     frame->linesize[0] = img->widthStep;
  58.     frame->data[0]     = img->imageData;
  59. }
  60.  
  61. static int query_formats(AVFilterContext *ctx)
  62. {
  63.     static const enum AVPixelFormat pix_fmts[] = {
  64.         AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
  65.     };
  66.  
  67.     ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
  68.     return 0;
  69. }
  70.  
  71. typedef struct {
  72.     const AVClass *class;
  73.     char *name;
  74.     char *params;
  75.     int (*init)(AVFilterContext *ctx, const char *args);
  76.     void (*uninit)(AVFilterContext *ctx);
  77.     void (*end_frame_filter)(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg);
  78.     void *priv;
  79. } OCVContext;
  80.  
  81. typedef struct {
  82.     int type;
  83.     int    param1, param2;
  84.     double param3, param4;
  85. } SmoothContext;
  86.  
  87. static av_cold int smooth_init(AVFilterContext *ctx, const char *args)
  88. {
  89.     OCVContext *s = ctx->priv;
  90.     SmoothContext *smooth = s->priv;
  91.     char type_str[128] = "gaussian";
  92.  
  93.     smooth->param1 = 3;
  94.     smooth->param2 = 0;
  95.     smooth->param3 = 0.0;
  96.     smooth->param4 = 0.0;
  97.  
  98.     if (args)
  99.         sscanf(args, "%127[^|]|%d|%d|%lf|%lf", type_str, &smooth->param1, &smooth->param2, &smooth->param3, &smooth->param4);
  100.  
  101.     if      (!strcmp(type_str, "blur"         )) smooth->type = CV_BLUR;
  102.     else if (!strcmp(type_str, "blur_no_scale")) smooth->type = CV_BLUR_NO_SCALE;
  103.     else if (!strcmp(type_str, "median"       )) smooth->type = CV_MEDIAN;
  104.     else if (!strcmp(type_str, "gaussian"     )) smooth->type = CV_GAUSSIAN;
  105.     else if (!strcmp(type_str, "bilateral"    )) smooth->type = CV_BILATERAL;
  106.     else {
  107.         av_log(ctx, AV_LOG_ERROR, "Smoothing type '%s' unknown.\n", type_str);
  108.         return AVERROR(EINVAL);
  109.     }
  110.  
  111.     if (smooth->param1 < 0 || !(smooth->param1%2)) {
  112.         av_log(ctx, AV_LOG_ERROR,
  113.                "Invalid value '%d' for param1, it has to be a positive odd number\n",
  114.                smooth->param1);
  115.         return AVERROR(EINVAL);
  116.     }
  117.     if ((smooth->type == CV_BLUR || smooth->type == CV_BLUR_NO_SCALE || smooth->type == CV_GAUSSIAN) &&
  118.         (smooth->param2 < 0 || (smooth->param2 && !(smooth->param2%2)))) {
  119.         av_log(ctx, AV_LOG_ERROR,
  120.                "Invalid value '%d' for param2, it has to be zero or a positive odd number\n",
  121.                smooth->param2);
  122.         return AVERROR(EINVAL);
  123.     }
  124.  
  125.     av_log(ctx, AV_LOG_VERBOSE, "type:%s param1:%d param2:%d param3:%f param4:%f\n",
  126.            type_str, smooth->param1, smooth->param2, smooth->param3, smooth->param4);
  127.     return 0;
  128. }
  129.  
  130. static void smooth_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
  131. {
  132.     OCVContext *s = ctx->priv;
  133.     SmoothContext *smooth = s->priv;
  134.     cvSmooth(inimg, outimg, smooth->type, smooth->param1, smooth->param2, smooth->param3, smooth->param4);
  135. }
  136.  
  137. static int read_shape_from_file(int *cols, int *rows, int **values, const char *filename,
  138.                                 void *log_ctx)
  139. {
  140.     uint8_t *buf, *p, *pend;
  141.     size_t size;
  142.     int ret, i, j, w;
  143.  
  144.     if ((ret = av_file_map(filename, &buf, &size, 0, log_ctx)) < 0)
  145.         return ret;
  146.  
  147.     /* prescan file to get the number of lines and the maximum width */
  148.     w = 0;
  149.     for (i = 0; i < size; i++) {
  150.         if (buf[i] == '\n') {
  151.             if (*rows == INT_MAX) {
  152.                 av_log(log_ctx, AV_LOG_ERROR, "Overflow on the number of rows in the file\n");
  153.                 return AVERROR_INVALIDDATA;
  154.             }
  155.             ++(*rows);
  156.             *cols = FFMAX(*cols, w);
  157.             w = 0;
  158.         } else if (w == INT_MAX) {
  159.             av_log(log_ctx, AV_LOG_ERROR, "Overflow on the number of columns in the file\n");
  160.             return AVERROR_INVALIDDATA;
  161.         }
  162.         w++;
  163.     }
  164.     if (*rows > (SIZE_MAX / sizeof(int) / *cols)) {
  165.         av_log(log_ctx, AV_LOG_ERROR, "File with size %dx%d is too big\n",
  166.                *rows, *cols);
  167.         return AVERROR_INVALIDDATA;
  168.     }
  169.     if (!(*values = av_mallocz(sizeof(int) * *rows * *cols)))
  170.         return AVERROR(ENOMEM);
  171.  
  172.     /* fill *values */
  173.     p    = buf;
  174.     pend = buf + size-1;
  175.     for (i = 0; i < *rows; i++) {
  176.         for (j = 0;; j++) {
  177.             if (p > pend || *p == '\n') {
  178.                 p++;
  179.                 break;
  180.             } else
  181.                 (*values)[*cols*i + j] = !!av_isgraph(*(p++));
  182.         }
  183.     }
  184.     av_file_unmap(buf, size);
  185.  
  186. #ifdef DEBUG
  187.     {
  188.         char *line;
  189.         if (!(line = av_malloc(*cols + 1)))
  190.             return AVERROR(ENOMEM);
  191.         for (i = 0; i < *rows; i++) {
  192.             for (j = 0; j < *cols; j++)
  193.                 line[j] = (*values)[i * *cols + j] ? '@' : ' ';
  194.             line[j] = 0;
  195.             av_log(log_ctx, AV_LOG_DEBUG, "%3d: %s\n", i, line);
  196.         }
  197.         av_free(line);
  198.     }
  199. #endif
  200.  
  201.     return 0;
  202. }
  203.  
  204. static int parse_iplconvkernel(IplConvKernel **kernel, char *buf, void *log_ctx)
  205. {
  206.     char shape_filename[128] = "", shape_str[32] = "rect";
  207.     int cols = 0, rows = 0, anchor_x = 0, anchor_y = 0, shape = CV_SHAPE_RECT;
  208.     int *values = NULL, ret;
  209.  
  210.     sscanf(buf, "%dx%d+%dx%d/%32[^=]=%127s", &cols, &rows, &anchor_x, &anchor_y, shape_str, shape_filename);
  211.  
  212.     if      (!strcmp(shape_str, "rect"   )) shape = CV_SHAPE_RECT;
  213.     else if (!strcmp(shape_str, "cross"  )) shape = CV_SHAPE_CROSS;
  214.     else if (!strcmp(shape_str, "ellipse")) shape = CV_SHAPE_ELLIPSE;
  215.     else if (!strcmp(shape_str, "custom" )) {
  216.         shape = CV_SHAPE_CUSTOM;
  217.         if ((ret = read_shape_from_file(&cols, &rows, &values, shape_filename, log_ctx)) < 0)
  218.             return ret;
  219.     } else {
  220.         av_log(log_ctx, AV_LOG_ERROR,
  221.                "Shape unspecified or type '%s' unknown.\n", shape_str);
  222.         return AVERROR(EINVAL);
  223.     }
  224.  
  225.     if (rows <= 0 || cols <= 0) {
  226.         av_log(log_ctx, AV_LOG_ERROR,
  227.                "Invalid non-positive values for shape size %dx%d\n", cols, rows);
  228.         return AVERROR(EINVAL);
  229.     }
  230.  
  231.     if (anchor_x < 0 || anchor_y < 0 || anchor_x >= cols || anchor_y >= rows) {
  232.         av_log(log_ctx, AV_LOG_ERROR,
  233.                "Shape anchor %dx%d is not inside the rectangle with size %dx%d.\n",
  234.                anchor_x, anchor_y, cols, rows);
  235.         return AVERROR(EINVAL);
  236.     }
  237.  
  238.     *kernel = cvCreateStructuringElementEx(cols, rows, anchor_x, anchor_y, shape, values);
  239.     av_freep(&values);
  240.     if (!*kernel)
  241.         return AVERROR(ENOMEM);
  242.  
  243.     av_log(log_ctx, AV_LOG_VERBOSE, "Structuring element: w:%d h:%d x:%d y:%d shape:%s\n",
  244.            rows, cols, anchor_x, anchor_y, shape_str);
  245.     return 0;
  246. }
  247.  
  248. typedef struct {
  249.     int nb_iterations;
  250.     IplConvKernel *kernel;
  251. } DilateContext;
  252.  
  253. static av_cold int dilate_init(AVFilterContext *ctx, const char *args)
  254. {
  255.     OCVContext *s = ctx->priv;
  256.     DilateContext *dilate = s->priv;
  257.     char default_kernel_str[] = "3x3+0x0/rect";
  258.     char *kernel_str;
  259.     const char *buf = args;
  260.     int ret;
  261.  
  262.     if (args)
  263.         kernel_str = av_get_token(&buf, "|");
  264.     else
  265.         kernel_str = av_strdup(default_kernel_str);
  266.     if (!kernel_str)
  267.         return AVERROR(ENOMEM);
  268.     if ((ret = parse_iplconvkernel(&dilate->kernel, kernel_str, ctx)) < 0)
  269.         return ret;
  270.     av_free(kernel_str);
  271.  
  272.     if (!buf || sscanf(buf, "|%d", &dilate->nb_iterations) != 1)
  273.         dilate->nb_iterations = 1;
  274.     av_log(ctx, AV_LOG_VERBOSE, "iterations_nb:%d\n", dilate->nb_iterations);
  275.     if (dilate->nb_iterations <= 0) {
  276.         av_log(ctx, AV_LOG_ERROR, "Invalid non-positive value '%d' for nb_iterations\n",
  277.                dilate->nb_iterations);
  278.         return AVERROR(EINVAL);
  279.     }
  280.     return 0;
  281. }
  282.  
  283. static av_cold void dilate_uninit(AVFilterContext *ctx)
  284. {
  285.     OCVContext *s = ctx->priv;
  286.     DilateContext *dilate = s->priv;
  287.  
  288.     cvReleaseStructuringElement(&dilate->kernel);
  289. }
  290.  
  291. static void dilate_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
  292. {
  293.     OCVContext *s = ctx->priv;
  294.     DilateContext *dilate = s->priv;
  295.     cvDilate(inimg, outimg, dilate->kernel, dilate->nb_iterations);
  296. }
  297.  
  298. static void erode_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
  299. {
  300.     OCVContext *s = ctx->priv;
  301.     DilateContext *dilate = s->priv;
  302.     cvErode(inimg, outimg, dilate->kernel, dilate->nb_iterations);
  303. }
  304.  
  305. typedef struct {
  306.     const char *name;
  307.     size_t priv_size;
  308.     int  (*init)(AVFilterContext *ctx, const char *args);
  309.     void (*uninit)(AVFilterContext *ctx);
  310.     void (*end_frame_filter)(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg);
  311. } OCVFilterEntry;
  312.  
  313. static OCVFilterEntry ocv_filter_entries[] = {
  314.     { "dilate", sizeof(DilateContext), dilate_init, dilate_uninit, dilate_end_frame_filter },
  315.     { "erode",  sizeof(DilateContext), dilate_init, dilate_uninit, erode_end_frame_filter  },
  316.     { "smooth", sizeof(SmoothContext), smooth_init, NULL, smooth_end_frame_filter },
  317. };
  318.  
  319. static av_cold int init(AVFilterContext *ctx)
  320. {
  321.     OCVContext *s = ctx->priv;
  322.     int i;
  323.  
  324.     if (!s->name) {
  325.         av_log(ctx, AV_LOG_ERROR, "No libopencv filter name specified\n");
  326.         return AVERROR(EINVAL);
  327.     }
  328.     for (i = 0; i < FF_ARRAY_ELEMS(ocv_filter_entries); i++) {
  329.         OCVFilterEntry *entry = &ocv_filter_entries[i];
  330.         if (!strcmp(s->name, entry->name)) {
  331.             s->init             = entry->init;
  332.             s->uninit           = entry->uninit;
  333.             s->end_frame_filter = entry->end_frame_filter;
  334.  
  335.             if (!(s->priv = av_mallocz(entry->priv_size)))
  336.                 return AVERROR(ENOMEM);
  337.             return s->init(ctx, s->params);
  338.         }
  339.     }
  340.  
  341.     av_log(ctx, AV_LOG_ERROR, "No libopencv filter named '%s'\n", s->name);
  342.     return AVERROR(EINVAL);
  343. }
  344.  
  345. static av_cold void uninit(AVFilterContext *ctx)
  346. {
  347.     OCVContext *s = ctx->priv;
  348.  
  349.     if (s->uninit)
  350.         s->uninit(ctx);
  351.     av_free(s->priv);
  352. }
  353.  
  354. static int filter_frame(AVFilterLink *inlink, AVFrame *in)
  355. {
  356.     AVFilterContext *ctx = inlink->dst;
  357.     OCVContext *s = ctx->priv;
  358.     AVFilterLink *outlink= inlink->dst->outputs[0];
  359.     AVFrame *out;
  360.     IplImage inimg, outimg;
  361.  
  362.     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  363.     if (!out) {
  364.         av_frame_free(&in);
  365.         return AVERROR(ENOMEM);
  366.     }
  367.     av_frame_copy_props(out, in);
  368.  
  369.     fill_iplimage_from_frame(&inimg , in , inlink->format);
  370.     fill_iplimage_from_frame(&outimg, out, inlink->format);
  371.     s->end_frame_filter(ctx, &inimg, &outimg);
  372.     fill_frame_from_iplimage(out, &outimg, inlink->format);
  373.  
  374.     av_frame_free(&in);
  375.  
  376.     return ff_filter_frame(outlink, out);
  377. }
  378.  
  379. #define OFFSET(x) offsetof(OCVContext, x)
  380. #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
  381. static const AVOption ocv_options[] = {
  382.     { "filter_name",   NULL, OFFSET(name),   AV_OPT_TYPE_STRING, .flags = FLAGS },
  383.     { "filter_params", NULL, OFFSET(params), AV_OPT_TYPE_STRING, .flags = FLAGS },
  384.     { NULL }
  385. };
  386.  
  387. AVFILTER_DEFINE_CLASS(ocv);
  388.  
  389. static const AVFilterPad avfilter_vf_ocv_inputs[] = {
  390.     {
  391.         .name         = "default",
  392.         .type         = AVMEDIA_TYPE_VIDEO,
  393.         .filter_frame = filter_frame,
  394.     },
  395.     { NULL }
  396. };
  397.  
  398. static const AVFilterPad avfilter_vf_ocv_outputs[] = {
  399.     {
  400.         .name = "default",
  401.         .type = AVMEDIA_TYPE_VIDEO,
  402.     },
  403.     { NULL }
  404. };
  405.  
  406. AVFilter avfilter_vf_ocv = {
  407.     .name          = "ocv",
  408.     .description   = NULL_IF_CONFIG_SMALL("Apply transform using libopencv."),
  409.     .priv_size     = sizeof(OCVContext),
  410.     .priv_class    = &ocv_class,
  411.     .query_formats = query_formats,
  412.     .init          = init,
  413.     .uninit        = uninit,
  414.     .inputs        = avfilter_vf_ocv_inputs,
  415.     .outputs       = avfilter_vf_ocv_outputs,
  416. };
  417.