1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Routines for encoding and decoding a small number of bits into an image
6 // in a way that is decodable even after scaling/encoding/cropping.
8 // The encoding is very simple:
10 // #### #### ######## #### #### ####
11 // #### #### ######## #### #### ####
12 // #### #### ######## #### #### ####
13 // #### #### ######## #### #### ####
14 // 1 2 3 4 5 6 7 8 9 10 11 12 13 14
15 // <-----start----><--one-bit-><-zero bit-><----stop---->
17 // We use a basic unit, depicted here as four characters wide.
18 // We start with 1u black 1u white 1u black 1u white. (1-4 above)
19 // From there on, a "one" bit is encoded as 2u black and 1u white,
20 // and a zero bit is encoded as 1u black and 2u white. After
21 // all the bits we end the pattern with the same pattern as the
22 // start of the pattern.
27 #include "base/logging.h"
28 #include "media/base/video_frame.h"
29 #include "media/cast/test/utility/barcode.h"
35 const int kBlackThreshold
= 256 * 2 / 3;
36 const int kWhiteThreshold
= 256 / 3;
38 bool EncodeBarcode(const std::vector
<bool>& bits
,
39 scoped_refptr
<VideoFrame
> output_frame
) {
40 DCHECK(output_frame
->format() == VideoFrame::YV12
||
41 output_frame
->format() == VideoFrame::YV16
||
42 output_frame
->format() == VideoFrame::I420
||
43 output_frame
->format() == VideoFrame::YV12J
);
44 int row_bytes
= output_frame
->row_bytes(VideoFrame::kYPlane
);
45 std::vector
<unsigned char> bytes(row_bytes
);
46 for (int i
= 0; i
< row_bytes
; i
++) {
49 size_t units
= bits
.size() * 3 + 7; // White or black bar where size matters.
50 // We only use 60% of the image to make sure it works even if
51 // the image gets cropped.
52 size_t unit_size
= row_bytes
* 6 / 10 / units
;
53 if (unit_size
< 1) return false;
54 size_t bytes_required
= unit_size
* units
;
55 size_t padding
= (row_bytes
- bytes_required
) / 2;
56 unsigned char *pos
= &bytes
[padding
];
57 // Two leading black bars.
58 memset(pos
, 0, unit_size
);
60 memset(pos
, 0, unit_size
);
62 for (size_t bit
= 0; bit
< bits
.size(); bit
++) {
63 memset(pos
, 0, bits
[bit
] ? unit_size
* 2: unit_size
);
66 memset(pos
, 0, unit_size
);
68 memset(pos
, 0, unit_size
);
70 DCHECK_LE(pos
- &bytes
.front(), row_bytes
);
72 // Now replicate this one row into all rows in kYPlane.
73 for (int row
= 0; row
< output_frame
->rows(VideoFrame::kYPlane
); row
++) {
74 memcpy(output_frame
->data(VideoFrame::kYPlane
) +
75 output_frame
->stride(VideoFrame::kYPlane
) * row
,
83 bool DecodeBarCodeRows(const scoped_refptr
<VideoFrame
>& frame
,
84 std::vector
<bool>* output
,
87 // Do a basic run-length encoding
91 for (int pos
= 0; pos
< frame
->row_bytes(VideoFrame::kYPlane
); pos
++) {
93 for (int row
= min_row
; row
< max_row
; row
++) {
94 value
+= frame
->data(VideoFrame::kYPlane
)[
95 frame
->stride(VideoFrame::kYPlane
) * row
+ pos
];
97 value
/= max_row
- min_row
;
98 if (is_black
? value
> kBlackThreshold
: value
< kWhiteThreshold
) {
100 runs
.push_back(length
);
106 runs
.push_back(length
);
108 // Try decoding starting at each white-black transition.
109 while (runs
.size() >= output
->size() * 2 + 7) {
110 std::deque
<int>::const_iterator i
= runs
.begin();
111 double unit_size
= (i
[1] + i
[2] + i
[3] + i
[4]) / 4;
113 if (i
[0] > unit_size
* 2 || i
[0] < unit_size
/ 2) valid
= false;
114 if (i
[1] > unit_size
* 2 || i
[1] < unit_size
/ 2) valid
= false;
115 if (i
[2] > unit_size
* 2 || i
[2] < unit_size
/ 2) valid
= false;
116 if (i
[3] > unit_size
* 2 || i
[3] < unit_size
/ 2) valid
= false;
118 for (size_t bit
= 0; valid
&& bit
< output
->size(); bit
++) {
119 if (i
[0] > unit_size
/ 2 && i
[0] <= unit_size
* 1.5 &&
120 i
[1] > unit_size
* 1.5 && i
[1] <= unit_size
* 3) {
121 (*output
)[bit
] = false;
122 } else if (i
[1] > unit_size
/ 2 && i
[1] <= unit_size
* 1.5 &&
123 i
[0] > unit_size
* 1.5 && i
[0] <= unit_size
* 3) {
124 (*output
)[bit
] = true;
131 if (i
[0] > unit_size
* 2 || i
[0] < unit_size
/ 2) valid
= false;
132 if (i
[1] > unit_size
* 2 || i
[1] < unit_size
/ 2) valid
= false;
133 if (i
[2] > unit_size
* 2 || i
[2] < unit_size
/ 2) valid
= false;
135 DCHECK(i
<= runs
.end());
137 // Decoding successful, return true
148 // Note that "output" is assumed to be the right size already. This
149 // could be inferred from the data, but the decoding is more robust
150 // if we can assume that we know how many bits we want.
151 bool DecodeBarcode(const scoped_refptr
<VideoFrame
>& frame
,
152 std::vector
<bool>* output
) {
153 DCHECK(frame
->format() == VideoFrame::YV12
||
154 frame
->format() == VideoFrame::YV16
||
155 frame
->format() == VideoFrame::I420
||
156 frame
->format() == VideoFrame::YV12J
);
157 int rows
= frame
->rows(VideoFrame::kYPlane
);
159 if (DecodeBarCodeRows(frame
,
161 std::max(0, rows
/ 2 - 5),
162 std::min(rows
, rows
/ 2 + 5))) {
167 if (DecodeBarCodeRows(frame
, output
, 0, std::min(5, rows
))) {