android/camera: Implement image flipping

We use libyuv's Mirror function to handle horizontal flip. Regarding the vertical flip, libyuv doc states that 'just set a negative height'
This commit is contained in:
zhupengfei 2020-04-12 15:10:14 +08:00 committed by bunnei
parent 232efb88d3
commit c0c8b16e43
4 changed files with 62 additions and 14 deletions

View File

@ -210,8 +210,13 @@ CaptureSession::CaptureSession(ACameraManager* manager, const std::string& id) {
#undef CAMERA_CALL
#undef CREATE
Interface::Interface(Factory& factory_, const std::string& id_, const Service::CAM::Flip& flip_)
: factory(factory_), id(id_), flip(flip_) {}
Interface::Interface(Factory& factory_, const std::string& id_, const Service::CAM::Flip& flip)
: factory(factory_), id(id_) {
mirror = base_mirror =
flip == Service::CAM::Flip::Horizontal || flip == Service::CAM::Flip::Reverse;
invert = base_invert =
flip == Service::CAM::Flip::Vertical || flip == Service::CAM::Flip::Reverse;
}
Interface::~Interface() = default;
@ -227,8 +232,11 @@ void Interface::SetResolution(const Service::CAM::Resolution& resolution_) {
resolution = resolution_;
}
void Interface::SetFlip(Service::CAM::Flip flip_) {
flip = flip_;
void Interface::SetFlip(Service::CAM::Flip flip) {
mirror = base_mirror ^
(flip == Service::CAM::Flip::Horizontal || flip == Service::CAM::Flip::Reverse);
invert =
base_invert ^ (flip == Service::CAM::Flip::Vertical || flip == Service::CAM::Flip::Reverse);
}
void Interface::SetFormat(Service::CAM::OutputFormat format_) {
@ -265,19 +273,32 @@ std::vector<u16> Interface::ReceiveFrame() {
scaled_y.data(), resolution.width, scaled_u.data(), resolution.width / 4,
scaled_v.data(), resolution.width / 4, resolution.width, resolution.height,
libyuv::kFilterBilinear);
// TODO: Record and apply flip
if (mirror) {
std::vector<u8> mirrored_y(scaled_y.size());
std::vector<u8> mirrored_u(scaled_u.size());
std::vector<u8> mirrored_v(scaled_v.size());
libyuv::I420Mirror(scaled_y.data(), resolution.width, scaled_u.data(), resolution.width / 4,
scaled_v.data(), resolution.width / 4, mirrored_y.data(),
resolution.width, mirrored_u.data(), resolution.width / 4,
mirrored_v.data(), resolution.width / 4, resolution.width,
resolution.height);
scaled_y.swap(mirrored_y);
scaled_u.swap(mirrored_u);
scaled_v.swap(mirrored_v);
}
std::vector<u16> output(resolution.width * resolution.height);
if (format == Service::CAM::OutputFormat::RGB565) {
libyuv::I420ToRGB565(scaled_y.data(), resolution.width, scaled_u.data(),
resolution.width / 4, scaled_v.data(), resolution.width / 4,
reinterpret_cast<u8*>(output.data()), resolution.width * 2,
resolution.width, resolution.height);
resolution.width, invert ? -resolution.height : resolution.height);
} else {
libyuv::I420ToYUY2(scaled_y.data(), resolution.width, scaled_u.data(), resolution.width / 4,
scaled_v.data(), resolution.width / 4,
reinterpret_cast<u8*>(output.data()), resolution.width * 2,
resolution.width, resolution.height);
resolution.width, invert ? -resolution.height : resolution.height);
}
return output;
}

View File

@ -37,7 +37,13 @@ private:
std::string id;
Service::CAM::Resolution resolution;
Service::CAM::Flip flip;
// Flipping parameters. mirror = horizontal, invert = vertical.
bool base_mirror{};
bool base_invert{};
bool mirror{};
bool invert{};
Service::CAM::OutputFormat format;
// std::vector<u16> image; // Data fetched from the frontend
// bool opened{}; // Whether the camera was successfully opened

View File

@ -29,7 +29,12 @@ void CleanupJNI(JNIEnv* env) {
env->DeleteGlobalRef(s_still_image_camera_helper_class);
}
Interface::Interface(jstring path_, const Service::CAM::Flip& flip_) : path(path_), flip(flip_) {}
Interface::Interface(jstring path_, const Service::CAM::Flip& flip) : path(path_) {
mirror = base_mirror =
flip == Service::CAM::Flip::Horizontal || flip == Service::CAM::Flip::Reverse;
invert = base_invert =
flip == Service::CAM::Flip::Vertical || flip == Service::CAM::Flip::Reverse;
}
Interface::~Interface() {
Factory::last_path = nullptr;
@ -70,13 +75,20 @@ void Interface::StartCapture() {
info.width, info.height);
BITMAP_CALL(unlockPixels(env, bitmap));
if (mirror) {
std::vector<u8> mirrored(data.size());
libyuv::ARGBMirror(data.data(), info.stride, mirrored.data(), info.stride, info.width,
info.height);
data.swap(mirrored);
}
image.resize(info.height * info.width);
if (format == Service::CAM::OutputFormat::RGB565) {
libyuv::ARGBToRGB565(data.data(), info.stride, reinterpret_cast<u8*>(image.data()),
info.width * 2, info.width, info.height);
info.width * 2, info.width, invert ? -info.height : info.height);
} else {
libyuv::ARGBToYUY2(data.data(), info.stride, reinterpret_cast<u8*>(image.data()),
info.width * 2, info.width, info.height);
info.width * 2, info.width, invert ? -info.height : info.height);
}
opened = true;
@ -87,8 +99,11 @@ void Interface::SetResolution(const Service::CAM::Resolution& resolution_) {
resolution = resolution_;
}
void Interface::SetFlip(Service::CAM::Flip flip_) {
flip = flip_;
void Interface::SetFlip(Service::CAM::Flip flip) {
mirror = base_mirror ^
(flip == Service::CAM::Flip::Horizontal || flip == Service::CAM::Flip::Reverse);
invert =
base_invert ^ (flip == Service::CAM::Flip::Vertical || flip == Service::CAM::Flip::Reverse);
}
void Interface::SetFormat(Service::CAM::OutputFormat format_) {

View File

@ -31,7 +31,13 @@ public:
private:
jstring path;
Service::CAM::Resolution resolution;
Service::CAM::Flip flip;
// Flipping parameters. mirror = horizontal, invert = vertical.
bool base_mirror{};
bool base_invert{};
bool mirror{};
bool invert{};
Service::CAM::OutputFormat format;
std::vector<u16> image; // Data fetched from the frontend
bool opened{}; // Whether the camera was successfully opened