1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm
#include "movingCheckerReader.hpp"
#include "libvideostitch/logging.hpp"
#include <cmath>
static const int CHECKER_SIZE = 32;
static const int MAX_CHROMA = 24;
namespace VideoStitch {
namespace Input {
MovingCheckerReader::MovingCheckerReader(readerid_t id, int64_t targetWidth, int64_t targetHeight)
: Reader(id),
VideoReader(targetWidth, targetHeight, (targetWidth * targetHeight * 3) / 2, VideoStitch::YV12, Host,
{60, 1} /*fps*/, 0, NO_LAST_FRAME, true /* procedural */, NULL),
curFrame(0) {
getSpec().setDisplayName("Procedural: MovingChecker");
}
MovingCheckerReader::~MovingCheckerReader() {}
void movingCheckerBoard(unsigned char* dst, int64_t width, int64_t height, int checkerOffset) {
// checkerboard pattern in Y
for (int64_t y = 0; y < height; y++) {
unsigned evenCol = (((y + 2 * checkerOffset) / CHECKER_SIZE) & 1);
for (int64_t x = 0; x < width; x++) {
unsigned evenRow = (((x + 4 * checkerOffset) / CHECKER_SIZE) & 1);
dst[y * width + x] = (evenRow ^ evenCol) ? 64 : 196;
}
}
// slowly changing color scheme
auto uval = (unsigned char)((sin(checkerOffset / 10. * M_PI)) * MAX_CHROMA + 128);
auto vval = (unsigned char)((cos(checkerOffset / 51. * M_PI)) * MAX_CHROMA + 128);
unsigned char* uv = &dst[width * height];
// U
for (int64_t y = 0; y < height / 4; y++) {
for (int64_t x = 0; x < width; x++) {
uv[y * width + x] = uval;
}
}
unsigned char* v = &uv[width * height / 4];
// V
for (int64_t y = 0; y < height / 4; y++) {
for (int64_t x = 0; x < width; x++) {
v[y * width + x] = vval;
}
}
}
Status MovingCheckerReader::seekFrame(frameid_t frame) {
curFrame = frame;
return Status::OK();
}
ReadStatus MovingCheckerReader::readFrame(mtime_t& date, unsigned char* videoFrame) {
// XXX TODO FIXME procedurals with a frame rate please
date =
(mtime_t)round(1000000.0 * (double)curFrame * (double)getSpec().frameRate.den / (double)getSpec().frameRate.num);
// can't simulate realistic usage, but at the very least the decoder has to write all the data once
// memcpy(videoFrame, inputFrame, getSpec().frameDataSize);
movingCheckerBoard(videoFrame, getSpec().width, getSpec().height, curFrame);
curFrame++;
return ReadStatus::OK();
}
} // namespace Input
} // namespace VideoStitch