Ignore title parameter for navigator.registerProtocolHandler
[chromium-blink-merge.git] / media / cast / test / utility / barcode.cc
blob2e5978411223ebb8a30be0e1a9876816bfc0577e
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.
7 //
8 // The encoding is very simple:
9 //
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.
24 #include <deque>
25 #include <vector>
27 #include "base/logging.h"
28 #include "media/base/video_frame.h"
29 #include "media/cast/test/utility/barcode.h"
31 namespace media {
32 namespace cast {
33 namespace test {
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++) {
47 bytes[i] = 255;
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);
59 pos += unit_size * 2;
60 memset(pos, 0, unit_size);
61 pos += unit_size * 2;
62 for (size_t bit = 0; bit < bits.size(); bit++) {
63 memset(pos, 0, bits[bit] ? unit_size * 2: unit_size);
64 pos += unit_size * 3;
66 memset(pos, 0, unit_size);
67 pos += unit_size * 2;
68 memset(pos, 0, unit_size);
69 pos += 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,
76 &bytes.front(),
77 row_bytes);
79 return true;
82 namespace {
83 bool DecodeBarCodeRows(const scoped_refptr<VideoFrame>& frame,
84 std::vector<bool>* output,
85 int min_row,
86 int max_row) {
87 // Do a basic run-length encoding
88 std::deque<int> runs;
89 bool is_black = true;
90 int length = 0;
91 for (int pos = 0; pos < frame->row_bytes(VideoFrame::kYPlane); pos++) {
92 float value = 0.0;
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) {
99 is_black = !is_black;
100 runs.push_back(length);
101 length = 1;
102 } else {
103 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;
112 bool valid = true;
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;
117 i += 4;
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;
125 } else {
126 // Not a valid code
127 valid = false;
129 i += 2;
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;
134 i += 3;
135 DCHECK(i <= runs.end());
136 if (valid) {
137 // Decoding successful, return true
138 return true;
140 runs.pop_front();
141 runs.pop_front();
143 return false;
146 } // namespace
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);
158 // Middle 10 lines
159 if (DecodeBarCodeRows(frame,
160 output,
161 std::max(0, rows / 2 - 5),
162 std::min(rows, rows / 2 + 5))) {
163 return true;
166 // Top 5 lines
167 if (DecodeBarCodeRows(frame, output, 0, std::min(5, rows))) {
168 return true;
171 return false;
174 } // namespace test
175 } // namespace cast
176 } // namespace media