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 /**
20 * @file QR encoder source and filter.
21 *
22 * A QR code (quick-response code) is a type of two-dimensional matrix
23 * barcode, invented in 1994, by Japanese company Denso Wave for
24 * labelling automobile parts.
25 *
26 * This source uses the libqrencode library to generate QR code:
27 * https://fukuchi.org/works/qrencode/
28 */
29
30 //#define DEBUG
31
32 #include "config_components.h"
33
40
48
49 #include <qrencode.h>
50
67 };
68
70 "dar",
71 "duration",
72 "hsub", "vsub",
73 "main_h", "H", ///< height of the input video
74 "main_w", "W", ///< width of the input video
75 "n", ///< number of frame
76 "pict_type",
77 "qr_w", "w", ///< width of the QR code
78 "rendered_padded_qr_w", "Q", ///< width of the rendered QR code
79 "rendered_qr_w", "q", ///< width of the rendered QR code
80 "sar",
81 "t", ///< timestamp expressed in seconds
82 "x",
83 "y",
85 };
86
87 #define V(name_) qr->var_values[VAR_##name_]
88
92 };
93
96
101
105
108
112
115
118
122
123 /* these are only used when nothing must be encoded */
126
131
132 /* only used for filter to contain scaled image to blend on top of input */
135
138
140
144
149
150 #define OFFSET(x) offsetof(QREncodeContext, x)
151 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
152 #define TFLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
153
154 #define COMMON_OPTIONS \
155 { "qrcode_width", "set rendered QR code width expression", OFFSET(rendered_qrcode_width_expr), AV_OPT_TYPE_STRING, {.str = "64"}, 0, INT_MAX, FLAGS }, \
156 { "q", "set rendered QR code width expression", OFFSET(rendered_qrcode_width_expr), AV_OPT_TYPE_STRING, {.str = "64"}, 0, INT_MAX, FLAGS }, \
157 { "padded_qrcode_width", "set rendered padded QR code width expression", OFFSET(rendered_padded_qrcode_width_expr), AV_OPT_TYPE_STRING, {.str = "q"}, 0, INT_MAX, FLAGS }, \
158 { "Q", "set rendered padded QR code width expression", OFFSET(rendered_padded_qrcode_width_expr), AV_OPT_TYPE_STRING, {.str = "q"}, 0, INT_MAX, FLAGS }, \
159 { "case_sensitive", "generate code which is case sensitive", OFFSET(case_sensitive), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS }, \
160 { "cs", "generate code which is case sensitive", OFFSET(case_sensitive), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS }, \
161 \
162 { "level", "error correction level, lowest is L", OFFSET(level), AV_OPT_TYPE_INT, { .i64 = AVCOL_SPC_UNSPECIFIED }, 0, QR_ECLEVEL_H, .flags = FLAGS, .unit = "level"}, \
163 { "l", "error correction level, lowest is L", OFFSET(level), AV_OPT_TYPE_INT, { .i64 = AVCOL_SPC_UNSPECIFIED }, 0, QR_ECLEVEL_H, .flags = FLAGS, .unit = "level"}, \
164 { "L", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QR_ECLEVEL_L }, 0, 0, FLAGS, .unit = "level" }, \
165 { "M", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QR_ECLEVEL_M }, 0, 0, FLAGS, .unit = "level" }, \
166 { "Q", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QR_ECLEVEL_Q }, 0, 0, FLAGS, .unit = "level" }, \
167 { "H", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QR_ECLEVEL_H }, 0, 0, FLAGS, .unit = "level" }, \
168 \
169 {"expansion", "set the expansion mode", OFFSET(expansion), AV_OPT_TYPE_INT, {.i64=EXPANSION_NORMAL}, 0, 2, FLAGS, .unit = "expansion"}, \
170 {"none", "set no expansion", OFFSET(expansion), AV_OPT_TYPE_CONST, {.i64 = EXPANSION_NONE}, 0, 0, FLAGS, .unit = "expansion"}, \
171 {"normal", "set normal expansion", OFFSET(expansion), AV_OPT_TYPE_CONST, {.i64 = EXPANSION_NORMAL}, 0, 0, FLAGS, .unit = "expansion"}, \
172 \
173 { "foreground_color", "set QR foreground color", OFFSET(foreground_color), AV_OPT_TYPE_COLOR, {.str = "black"}, 0, 0, FLAGS }, \
174 { "fc", "set QR foreground color", OFFSET(foreground_color), AV_OPT_TYPE_COLOR, {.str = "black"}, 0, 0, FLAGS }, \
175 { "background_color", "set QR background color", OFFSET(background_color), AV_OPT_TYPE_COLOR, {.str = "white"}, 0, 0, FLAGS }, \
176 { "bc", "set QR background color", OFFSET(background_color), AV_OPT_TYPE_COLOR, {.str = "white"}, 0, 0, FLAGS }, \
177 \
178 {"text", "set text to encode", OFFSET(text), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS}, \
179 {"textfile", "set text file to encode", OFFSET(textfile), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS}, \
180
182 "rand"
183 };
184
186 {
188 }
189
190 static const ff_eval_func2
fun2[] = {
193 };
194
195 static int func_pts(
void *
ctx, AVBPrint *bp,
const char *function_name,
196 unsigned argc, char **argv)
197 {
199 const char *fmt;
200 const char *strftime_fmt =
NULL;
203
204 // argv: pts, FMT, [DELTA, strftime_fmt]
205
206 fmt = argc >= 1 ? argv[0] : "flt";
207 if (argc >= 2) {
209 }
210 if (argc >= 3) {
211 strftime_fmt = argv[2];
212 }
213
215 }
216
218 unsigned argc, char **argv)
219 {
221
223 return 0;
224 }
225
227 unsigned argc, char **argv)
228 {
229 const char *strftime_fmt = argc ? argv[0] :
NULL;
230
231 return ff_print_time(
ctx, bp, strftime_fmt, !strcmp(function_name,
"localtime"));
232 }
233
235 unsigned argc, char **argv)
236 {
239
242 else if (argc >= 2)
244
245 return 0;
246 }
247
249 unsigned argc, char **argv)
250 {
252
256 }
257
259 unsigned argc, char **argv)
260 {
264
265 /*
266 * argv[0] expression to be converted to `int`
267 * argv[1] format: 'x', 'X', 'd' or 'u'
268 * argv[2] positions printed (optional)
269 */
270
271 if (argc == 3) {
275 " to print: '%s'\n", argv[2]);
277 }
278 }
279
285 }
286
298 };
299
301 {
304
306
309
313 "Both text and text file provided. Please provide only one\n");
315 }
318 }
319
324 };
325
327
328 return 0;
329 }
330
332 {
334
337
339
343 }
344
345 #ifdef DEBUG
347 {
350 const char *p = qrcode->data;
351
353 return;
354 for (
i = 0;
i < qrcode->width;
i++) {
355 for (j = 0; j < qrcode->width; j++)
356 line[j] = (*p++)&1 ?
'@' :
' ';
359 }
361 }
362 #endif
363
365 {
368 QRcode *qrcode =
NULL;
370 char qrcode_width_changed;
373 uint8_t *srcp;
374 uint8_t *dstp0, *dstp;
375
377
381 break;
385 break;
386 }
387
393 }
394
395 return 0;
396 }
397
401 if (!qrcode) {
404 "Failed to encode string with error \'%s\'\n",
av_err2str(
ret));
405 goto end;
406 }
407
409 "Encoded QR with width:%d version:%d\n", qrcode->width, qrcode->version);
410 #ifdef DEBUG
412 #endif
413
414 qrcode_width_changed = qr->
qrcode_width != qrcode->width;
416
417 // realloc mask if needed
418 if (qrcode_width_changed) {
421 qrcode->width, qrcode->width,
425 "Failed to allocate image for QR code with width %d\n", qrcode->width);
426 goto end;
427 }
428 }
429
430 /* fill mask */
432 srcp = qrcode->data;
433
434 for (
i = 0;
i < qrcode->width;
i++) {
435 dstp = dstp0;
436 for (j = 0; j < qrcode->width; j++)
437 *dstp++ = (*srcp++ & 1) ? 255 : 0;
439 }
440
442 if (qrcode_width_changed) {
443 /* realloc padded image */
444
445 // compute virtual non-rendered padded size
446 // Q/q = W/w
449
456 "Failed to allocate image for QR code with width %d\n",
458 goto end;
459 }
460 }
461
462 /* fill padding */
466
467 /* blend mask */
474
475 /* scale padded QR over the frame */
477 if (!sws) {
479 goto end;
480 }
481
489
491 goto end;
492
497 } else {
498 #define EVAL_EXPR(name_) \
499 av_expr_eval(qr->name_##_pexpr, qr->var_values, &qr->lfg);
500
501 V(qr_w) =
V(
w) = qrcode->width;
502
503 V(rendered_qr_w) =
V(q) = EVAL_EXPR(rendered_qrcode_width);
504 V(rendered_padded_qr_w) =
V(
Q) = EVAL_EXPR(rendered_padded_qrcode_width);
505 /* It is necessary if q is expressed from Q */
506 V(rendered_qr_w) =
V(q) = EVAL_EXPR(rendered_qrcode_width);
507
510 /* It is necessary if x is expressed from y */
512
514 "Rendering QR code with values n:%d w:%d q:%d Q:%d x:%d y:%d t:%f\n",
515 (
int)
V(n), (
int)
V(
w), (
int)
V(q), (
int)
V(
Q), (
int)
V(x), (
int)
V(y),
V(t));
516
517 /* blend rectangle over the target */
521
525
531 "Failed to allocate image for rendered QR code with width %d\n",
533 goto end;
534 }
535 }
536
537 /* scale mask */
539 if (!sws) {
541 goto end;
542 }
543
551
553 goto end;
554
559
560 /* blend mask over the input frame */
567 }
568
569 end:
571 QRcode_free(qrcode);
572
574 }
575
576 #if CONFIG_QRENCODESRC_FILTER
577
583 };
584
586
588 {
593
596
597 #define PARSE_AND_EVAL_EXPR(var_name_, expr_name_) \
598 ret = av_expr_parse_and_eval(&qr->var_values[VAR_##var_name_], \
599 qr->expr_name_##_expr, \
600 var_names, qr->var_values, \
601 NULL, NULL, \
602 fun2_names, fun2, \
603 &qr->lfg, 0, ctx); \
604 if (ret < 0) { \
605 av_log(ctx, AV_LOG_ERROR, \
606 "Could not evaluate expression '%s'\n", \
607 qr->expr_name_##_expr); \
608 return ret; \
609 }
610
611 /* undefined for the source */
614 V(x) =
V(y) =
V(t) =
V(n) =
NAN;
615 V(dar) =
V(sar) = 1.0;
616
617 PARSE_AND_EVAL_EXPR(rendered_qr_w, rendered_qrcode_width);
618 V(q) =
V(rendered_qr_w);
619 PARSE_AND_EVAL_EXPR(rendered_padded_qr_w, rendered_padded_qrcode_width);
620 V(
Q) =
V(rendered_padded_qr_w);
621 PARSE_AND_EVAL_EXPR(rendered_qr_w, rendered_qrcode_width);
622 V(q) =
V(rendered_qr_w);
623
626
628 "q:%d Q:%d case_sensitive:%d level:%d\n",
631
634 "Resulting padded QR code width (%d) is lesser than the QR code width (%d)\n",
637 }
638
642
645
650
651 return 0;
652 }
653
655 {
659 ff_get_video_buffer(outlink, qr->rendered_padded_qrcode_width, qr->rendered_padded_qrcode_width);
661
665 V(n) =
frame->pts = qr->pts++;
667
670
672 }
673
675 {
680
681 // this is needed to support both the no-draw and draw cases
682 // for the no-draw case we use FFDrawContext to write on the input picture ref
688
690 }
691
693 {
698 }
699 };
700
702 .
name =
"qrencodesrc",
705 .priv_class = &qrencodesrc_class,
711 };
712
713 #endif // CONFIG_QRENCODESRC_FILTER
714
715 #if CONFIG_QRENCODE_FILTER
716
722 };
723
725
727 {
730 char *expr;
732
734
737
746
749
750 #define PARSE_EXPR(name_) \
751 ret = av_expr_parse(&qr->name_##_pexpr, expr = qr->name_##_expr, var_names, \
752 NULL, NULL, fun2_names, fun2, 0, ctx); \
753 if (ret < 0) { \
754 av_log(ctx, AV_LOG_ERROR, \
755 "Could not to parse expression '%s' for '%s'\n", \
756 expr, #name_); \
757 return AVERROR(EINVAL); \
758 }
759
764
769
771
772 return 0;
773 }
774
776 {
778 }
779
781 {
787
791 V(pict_type) =
frame->pict_type;
793
795
798
800 }
801
803 {
809 },
810 };
811
816 .priv_class = &qrencode_class,
823 };
824
825 #endif // CONFIG_QRENCODE_FILTER