vf_quirc.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * This file is part of FFmpeg.
  3. *
  4. * FFmpeg is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * FFmpeg is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with FFmpeg; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. /**
  19. * @file QR decoder video filter
  20. *
  21. * Use libquirc library to decode the content of QR codes, and put the decoded
  22. * content to metadata. See:
  23. * https://github.com/dlbeer/quirc
  24. */
  25. #include "libavutil/imgutils.h"
  26. #include "libavutil/opt.h"
  27. #include "avfilter.h"
  28. #include "filters.h"
  29. #include "formats.h"
  30. #include "video.h"
  31. #include <quirc.h>
  32. typedef struct QuircContext {
  33. const AVClass *class;
  34. struct quirc *quirc;
  35. } QuircContext;
  36. static av_cold int init(AVFilterContext *ctx)
  37. {
  38. QuircContext *quirc = ctx->priv;
  39. quirc->quirc = quirc_new();
  40. if (!quirc->quirc) {
  41. return AVERROR(ENOMEM);
  42. }
  43. return 0;
  44. }
  45. static av_cold void uninit(AVFilterContext *ctx)
  46. {
  47. QuircContext *quirc = ctx->priv;
  48. quirc_destroy(quirc->quirc);
  49. }
  50. static int config_input(AVFilterLink *inlink)
  51. {
  52. AVFilterContext *ctx = inlink->dst;
  53. QuircContext *quirc = ctx->priv;
  54. int err;
  55. err = quirc_resize(quirc->quirc, inlink->w, inlink->h);
  56. if (err == -1) {
  57. return AVERROR(ENOMEM);
  58. }
  59. return 0;
  60. }
  61. static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
  62. {
  63. FilterLink *inl = ff_filter_link(inlink);
  64. AVFilterContext *ctx = inlink->dst;
  65. AVFilterLink *outlink = ctx->outputs[0];
  66. QuircContext *quirc = ctx->priv;
  67. int codes_count;
  68. uint8_t *image;
  69. /* copy input image to quirc buffer */
  70. image = quirc_begin(quirc->quirc, NULL, NULL);
  71. av_image_copy_plane(image, inlink->w,
  72. frame->data[0], frame->linesize[0], inlink->w, inlink->h);
  73. quirc_end(quirc->quirc);
  74. codes_count = quirc_count(quirc->quirc);
  75. av_log(ctx, AV_LOG_VERBOSE,
  76. "Found count %d codes in image #%ld\n", codes_count, inl->frame_count_out);
  77. if (codes_count) {
  78. int i, j;
  79. AVDictionary **metadata = &frame->metadata;
  80. av_dict_set_int(metadata, "lavfi.quirc.count", codes_count, 0);
  81. for (i = 0; i < codes_count; i++) {
  82. struct quirc_code code;
  83. struct quirc_data data;
  84. quirc_decode_error_t err;
  85. char metadata_key[64];
  86. quirc_extract(quirc->quirc, i, &code);
  87. err = quirc_decode(&code, &data);
  88. if (err) {
  89. av_log(ctx, AV_LOG_WARNING,
  90. "Failed to decode image: %s\n", quirc_strerror(err));
  91. continue;
  92. }
  93. for (j = 0; j < 4; j++) {
  94. struct quirc_point corner = code.corners[j];
  95. #define SET_CORNER_METADATA(key_, value_) \
  96. snprintf(metadata_key, sizeof(metadata_key)-1, \
  97. "lavfi.quirc.%d.corner.%d." #key_, i, j); \
  98. av_dict_set_int(metadata, metadata_key, value_, 0)
  99. SET_CORNER_METADATA(x, corner.x);
  100. SET_CORNER_METADATA(y, corner.y);
  101. }
  102. snprintf(metadata_key, sizeof(metadata_key)-1, "lavfi.quirc.%d.payload", i); \
  103. av_dict_set(metadata, metadata_key, data.payload, 0);
  104. av_log(ctx, AV_LOG_INFO,
  105. "Found QR code at position %d,%d - %d,%d with payload: %s\n",
  106. code.corners[0].x, code.corners[0].y,
  107. code.corners[3].x, code.corners[3].y, data.payload);
  108. }
  109. }
  110. return ff_filter_frame(outlink, frame);
  111. }
  112. static const enum AVPixelFormat pix_fmts[] = {
  113. AV_PIX_FMT_GRAY8,
  114. AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
  115. AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
  116. AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
  117. AV_PIX_FMT_NV12, AV_PIX_FMT_NV21,
  118. AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
  119. AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
  120. AV_PIX_FMT_YUVJ440P,
  121. AV_PIX_FMT_NONE
  122. };
  123. static const AVClass quirc_class = {
  124. .class_name = "quirc",
  125. .version = LIBAVUTIL_VERSION_INT,
  126. .category = AV_CLASS_CATEGORY_FILTER
  127. };
  128. static const AVFilterPad inputs[] = {
  129. {
  130. .name = "default",
  131. .type = AVMEDIA_TYPE_VIDEO,
  132. .filter_frame = filter_frame,
  133. .config_props = config_input
  134. },
  135. };
  136. const FFFilter ff_vf_quirc = {
  137. .p.name = "quirc",
  138. .p.description = NULL_IF_CONFIG_SMALL("Decode and show QR codes content."),
  139. .p.priv_class = &quirc_class,
  140. .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC |
  141. AVFILTER_FLAG_METADATA_ONLY,
  142. .priv_size = sizeof(QuircContext),
  143. .init = init,
  144. .uninit = uninit,
  145. FILTER_INPUTS(inputs),
  146. FILTER_OUTPUTS(ff_video_default_filterpad),
  147. FILTER_PIXFMTS_ARRAY(pix_fmts),
  148. };