Vitaliy Zarubin
1 year ago
6 changed files with 405 additions and 369 deletions
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru> |
||||
* SPDX-License-Identifier: BSD-3-Clause |
||||
*/ |
||||
#ifndef FLUTTER_PLUGIN_CAMERA_AURORA_PLUGIN_YUV_H |
||||
#define FLUTTER_PLUGIN_CAMERA_AURORA_PLUGIN_YUV_H |
||||
|
||||
#include <libyuv/libyuv.h> |
||||
|
||||
#include <QBuffer> |
||||
#include <QImage> |
||||
#include <QtCore> |
||||
|
||||
namespace yuv { |
||||
|
||||
struct Result |
||||
{ |
||||
uint8_t *y; |
||||
int strideY; |
||||
uint8_t *u; |
||||
int strideU; |
||||
uint8_t *v; |
||||
int strideV; |
||||
int width; |
||||
int height; |
||||
std::shared_ptr<uint8_t> raw; |
||||
}; |
||||
|
||||
Result I420Scale(const uint8_t *srcY, |
||||
const uint8_t *srcU, |
||||
const uint8_t *srcV, |
||||
int srcWidth, |
||||
int srcHeight, |
||||
int outWidth, |
||||
int outHeight) |
||||
{ |
||||
auto bufSize = (((outWidth * outHeight) + ((outWidth + 1) / 2) * ((outHeight + 1) / 2))) * 2; |
||||
auto buf = std::shared_ptr<uint8_t>((uint8_t *) malloc(bufSize), free); |
||||
|
||||
auto y = buf.get(); |
||||
auto u = buf.get() + outWidth * outHeight; |
||||
auto v = buf.get() + outWidth * outHeight + (outWidth * outHeight + 3) / 4; |
||||
|
||||
auto srcStrideY = srcWidth; |
||||
auto srcStrideU = (srcWidth + 1) / 2; |
||||
auto srcStrideV = srcStrideU; |
||||
|
||||
auto outStrideY = outWidth; |
||||
auto outStrideU = (outWidth + 1) / 2; |
||||
auto outStrideV = outStrideU; |
||||
|
||||
libyuv::I420Scale(srcY, |
||||
srcStrideY, |
||||
srcU, |
||||
srcStrideU, |
||||
srcV, |
||||
srcStrideV, |
||||
srcWidth, |
||||
srcHeight, |
||||
y, |
||||
outStrideY, |
||||
u, |
||||
outStrideU, |
||||
v, |
||||
outStrideV, |
||||
outWidth, |
||||
outHeight, |
||||
libyuv::kFilterBilinear); |
||||
|
||||
return Result{y, outStrideY, u, outStrideU, v, outStrideV, outWidth, outHeight, buf}; |
||||
} |
||||
|
||||
Result I420Rotate(const uint8_t *srcY, |
||||
const uint8_t *srcU, |
||||
const uint8_t *srcV, |
||||
int srcWidth, |
||||
int srcHeight, |
||||
int degree) |
||||
{ |
||||
int d = degree; |
||||
|
||||
if (degree < 0) { |
||||
d = 360 - ((degree * -1) % 360); |
||||
} |
||||
|
||||
if (degree >= 360) { |
||||
d = degree % 360; |
||||
} |
||||
|
||||
int outWidth = srcWidth; |
||||
int outHeight = srcHeight; |
||||
|
||||
if (d == 90 || d == 270) { |
||||
outWidth = srcHeight; |
||||
outHeight = srcWidth; |
||||
} |
||||
|
||||
enum libyuv::RotationMode mode = (enum libyuv::RotationMode) d; |
||||
|
||||
auto bufSize = (((outWidth * outHeight) + ((outWidth + 1) / 2) * ((outHeight + 1) / 2))) * 2; |
||||
auto buf = std::shared_ptr<uint8_t>((uint8_t *) malloc(bufSize), free); |
||||
|
||||
auto y = buf.get(); |
||||
auto u = buf.get() + outWidth * outHeight; |
||||
auto v = buf.get() + outWidth * outHeight + (outWidth * outHeight + 3) / 4; |
||||
|
||||
auto srcStrideY = srcWidth; |
||||
auto srcStrideU = (srcWidth + 1) / 2; |
||||
auto srcStrideV = srcStrideU; |
||||
|
||||
auto outStrideY = outWidth; |
||||
auto outStrideU = (outWidth + 1) / 2; |
||||
auto outStrideV = outStrideU; |
||||
|
||||
libyuv::I420Rotate(srcY, |
||||
srcStrideY, |
||||
srcU, |
||||
srcStrideU, |
||||
srcV, |
||||
srcStrideV, |
||||
y, |
||||
outStrideY, |
||||
u, |
||||
outStrideU, |
||||
v, |
||||
outStrideV, |
||||
srcWidth, |
||||
srcHeight, |
||||
mode); |
||||
|
||||
return Result{y, outStrideY, u, outStrideU, v, outStrideV, outWidth, outHeight, buf}; |
||||
} |
||||
|
||||
std::shared_ptr<uint8_t> I420ToARGB( |
||||
const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV, int srcWidth, int srcHeight) |
||||
{ |
||||
auto srcStrideY = srcWidth; |
||||
auto srcStrideU = (srcWidth + 1) / 2; |
||||
auto srcStrideV = srcStrideU; |
||||
|
||||
auto bits = std::shared_ptr<uint8_t>((uint8_t *) malloc(srcWidth * srcHeight * 4), free); |
||||
|
||||
libyuv::I420ToARGB(srcY, |
||||
srcStrideY, |
||||
srcU, |
||||
srcStrideU, |
||||
srcV, |
||||
srcStrideV, |
||||
bits.get(), |
||||
srcWidth * 4, |
||||
srcWidth, |
||||
srcHeight); |
||||
|
||||
return bits; |
||||
} |
||||
|
||||
QImage I420ToQImage( |
||||
const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV, int srcWidth, int srcHeight) |
||||
{ |
||||
QSize size(srcWidth, srcHeight); |
||||
QImage image(size, QImage::Format_RGBA8888); |
||||
|
||||
auto srcStrideY = srcWidth; |
||||
auto srcStrideU = (srcWidth + 1) / 2; |
||||
auto srcStrideV = srcStrideU; |
||||
|
||||
libyuv::I420ToARGB(srcY, |
||||
srcStrideY, |
||||
srcU, |
||||
srcStrideU, |
||||
srcV, |
||||
srcStrideV, |
||||
reinterpret_cast<uint8_t *>(image.bits()), |
||||
srcWidth * 4, |
||||
srcWidth, |
||||
srcHeight); |
||||
|
||||
return image; |
||||
} |
||||
|
||||
std::string I420ToBase64(const uint8_t *srcY, |
||||
const uint8_t *srcU, |
||||
const uint8_t *srcV, |
||||
int srcWidth, |
||||
int srcHeight, |
||||
int orientationDisplay, |
||||
int orientationCamera, |
||||
int direction) |
||||
{ |
||||
auto angle = orientationCamera - orientationDisplay; |
||||
|
||||
if (direction < 0 && (orientationDisplay == 90 || orientationDisplay == 270)) { |
||||
angle -= 180; |
||||
} |
||||
|
||||
auto result = I420Rotate(srcY, srcU, srcV, srcWidth, srcHeight, angle); |
||||
|
||||
auto image = I420ToQImage(result.y, result.u, result.v, result.width, result.height); |
||||
|
||||
QBuffer qbuffer; |
||||
qbuffer.open(QIODevice::WriteOnly); |
||||
image.save(&qbuffer, "JPEG"); |
||||
|
||||
return qbuffer.data().toBase64().toStdString(); |
||||
} |
||||
|
||||
} // namespace yuv
|
||||
|
||||
#endif /* FLUTTER_PLUGIN_CAMERA_AURORA_PLUGIN_YUV_H */ |
Loading…
Reference in new issue