This source file includes following definitions.
- EncodeBarcode
- DecodeBarcode
#include <deque>
#include <vector>
#include "base/logging.h"
#include "media/base/video_frame.h"
#include "media/cast/test/utility/barcode.h"
namespace media {
namespace cast {
namespace test {
const int kBlackThreshold = 256 * 2 / 3;
const int kWhiteThreshold = 256 / 3;
bool EncodeBarcode(const std::vector<bool>& bits,
scoped_refptr<VideoFrame> output_frame) {
DCHECK(output_frame->format() == VideoFrame::YV12 ||
output_frame->format() == VideoFrame::YV16 ||
output_frame->format() == VideoFrame::I420 ||
output_frame->format() == VideoFrame::YV12J);
int row_bytes = output_frame->row_bytes(VideoFrame::kYPlane);
std::vector<unsigned char> bytes(row_bytes);
for (int i = 0; i < row_bytes; i++) {
bytes[i] = 255;
}
size_t units = bits.size() * 3 + 7;
size_t unit_size = row_bytes * 6 / 10 / units;
if (unit_size < 1) return false;
size_t bytes_required = unit_size * units;
size_t padding = (row_bytes - bytes_required) / 2;
unsigned char *pos = &bytes[padding];
memset(pos, 0, unit_size);
pos += unit_size * 2;
memset(pos, 0, unit_size);
pos += unit_size * 2;
for (size_t bit = 0; bit < bits.size(); bit++) {
memset(pos, 0, bits[bit] ? unit_size * 2: unit_size);
pos += unit_size * 3;
}
memset(pos, 0, unit_size);
pos += unit_size * 2;
memset(pos, 0, unit_size);
pos += unit_size;
DCHECK_LE(pos - &bytes.front(), row_bytes);
for (int row = 0; row < output_frame->rows(VideoFrame::kYPlane); row++) {
memcpy(output_frame->data(VideoFrame::kYPlane) +
output_frame->stride(VideoFrame::kYPlane) * row,
&bytes.front(),
row_bytes);
}
return true;
}
bool DecodeBarcode(const scoped_refptr<VideoFrame>& frame,
std::vector<bool>* output) {
DCHECK(frame->format() == VideoFrame::YV12 ||
frame->format() == VideoFrame::YV16 ||
frame->format() == VideoFrame::I420 ||
frame->format() == VideoFrame::YV12J);
int min_row = std::max(0, frame->rows(VideoFrame::kYPlane) / 2 - 10);
int max_row = std::min(frame->rows(VideoFrame::kYPlane),
frame->rows(VideoFrame::kYPlane) / 2 + 10);
std::deque<int> runs;
bool is_black = true;
int length = 0;
for (int pos = 0; pos < frame->row_bytes(VideoFrame::kYPlane); pos++) {
float value = 0.0;
for (int row = min_row; row < max_row; row++) {
value += frame->data(VideoFrame::kYPlane)[
frame->stride(VideoFrame::kYPlane) * row + pos];
}
value /= max_row - min_row;
if (is_black ? value > kBlackThreshold : value < kWhiteThreshold) {
is_black = !is_black;
runs.push_back(length);
length = 1;
} else {
length++;
}
}
runs.push_back(length);
while (runs.size() >= output->size() * 2 + 7) {
std::deque<int>::const_iterator i = runs.begin();
double unit_size = (i[1] + i[2] + i[3] + i[4]) / 4;
bool valid = true;
if (i[0] > unit_size * 2 || i[0] < unit_size / 2) valid = false;
if (i[1] > unit_size * 2 || i[1] < unit_size / 2) valid = false;
if (i[2] > unit_size * 2 || i[2] < unit_size / 2) valid = false;
if (i[3] > unit_size * 2 || i[3] < unit_size / 2) valid = false;
i += 4;
for (size_t bit = 0; valid && bit < output->size(); bit++) {
if (i[0] > unit_size / 2 && i[0] <= unit_size * 1.5 &&
i[1] > unit_size * 1.5 && i[1] <= unit_size * 3) {
(*output)[bit] = false;
} else if (i[1] > unit_size / 2 && i[1] <= unit_size * 1.5 &&
i[0] > unit_size * 1.5 && i[0] <= unit_size * 3) {
(*output)[bit] = true;
} else {
valid = false;
}
i += 2;
}
if (i[0] > unit_size * 2 || i[0] < unit_size / 2) valid = false;
if (i[1] > unit_size * 2 || i[1] < unit_size / 2) valid = false;
if (i[2] > unit_size * 2 || i[2] < unit_size / 2) valid = false;
i += 3;
DCHECK(i <= runs.end());
if (valid) {
return true;
}
runs.pop_front();
runs.pop_front();
}
return false;
}
}
}
}