|
|
|
@ -21,14 +21,61 @@
|
|
|
|
|
#include "PhoneDevice.h"
|
|
|
|
|
#include "TermClient.h"
|
|
|
|
|
|
|
|
|
|
#include <opencv2/opencv.hpp>
|
|
|
|
|
#include <opencv2/core.hpp>
|
|
|
|
|
#include <opencv2/imgproc.hpp>
|
|
|
|
|
#include <opencv2/objdetect.hpp>
|
|
|
|
|
#include <opencv2/features2d.hpp>
|
|
|
|
|
|
|
|
|
|
#include <opencv2/core/types.hpp>
|
|
|
|
|
#include <opencv2/core/core.hpp>
|
|
|
|
|
#include <opencv2/imgproc/imgproc.hpp>
|
|
|
|
|
|
|
|
|
|
#include <android/log.h>
|
|
|
|
|
|
|
|
|
|
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
|
|
|
|
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
|
|
|
|
|
#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
|
|
|
|
#define ASSERT(cond, fmt, ...) \
|
|
|
|
|
if (!(cond)) { \
|
|
|
|
|
__android_log_assert(#cond, LOG_TAG, fmt, ##__VA_ARGS__); \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern bool GetJniEnv(JavaVM *vm, JNIEnv **env);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This value is 2 ^ 18 - 1, and is used to clamp the RGB values before their
|
|
|
|
|
// ranges
|
|
|
|
|
// are normalized to eight bits.
|
|
|
|
|
static const int kMaxChannelValue = 262143;
|
|
|
|
|
|
|
|
|
|
static inline uint32_t YUV2RGB(int nY, int nU, int nV) {
|
|
|
|
|
nY -= 16;
|
|
|
|
|
nU -= 128;
|
|
|
|
|
nV -= 128;
|
|
|
|
|
if (nY < 0) nY = 0;
|
|
|
|
|
|
|
|
|
|
// This is the floating point equivalent. We do the conversion in integer
|
|
|
|
|
// because some Android devices do not have floating point in hardware.
|
|
|
|
|
// nR = (int)(1.164 * nY + 1.596 * nV);
|
|
|
|
|
// nG = (int)(1.164 * nY - 0.813 * nV - 0.391 * nU);
|
|
|
|
|
// nB = (int)(1.164 * nY + 2.018 * nU);
|
|
|
|
|
|
|
|
|
|
int nR = (int)(1192 * nY + 1634 * nV);
|
|
|
|
|
int nG = (int)(1192 * nY - 833 * nV - 400 * nU);
|
|
|
|
|
int nB = (int)(1192 * nY + 2066 * nU);
|
|
|
|
|
|
|
|
|
|
nR = std::min(kMaxChannelValue, std::max(0, nR));
|
|
|
|
|
nG = std::min(kMaxChannelValue, std::max(0, nG));
|
|
|
|
|
nB = std::min(kMaxChannelValue, std::max(0, nB));
|
|
|
|
|
|
|
|
|
|
nR = (nR >> 10) & 0xff;
|
|
|
|
|
nG = (nG >> 10) & 0xff;
|
|
|
|
|
nB = (nB >> 10) & 0xff;
|
|
|
|
|
|
|
|
|
|
return 0xff000000 | (nR << 16) | (nG << 8) | nB;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CPhoneDevice::CPhoneDevice(JavaVM* vm, jobject service)
|
|
|
|
|
{
|
|
|
|
|
m_vm = vm;
|
|
|
|
@ -38,6 +85,7 @@ CPhoneDevice::CPhoneDevice(JavaVM* vm, jobject service)
|
|
|
|
|
|
|
|
|
|
jclass classService = env->GetObjectClass(m_javaService);
|
|
|
|
|
mRegisterTimerMid = env->GetMethodID(classService, "registerTimer", "(JI)Z");
|
|
|
|
|
mRegisterHeartbeatMid = env->GetMethodID(classService, "registerHeartbeatTimer", "(I)V");
|
|
|
|
|
mUnregisterTimerMid = env->GetMethodID(classService, "unregisterTimer", "(J)Z");
|
|
|
|
|
|
|
|
|
|
env->DeleteLocalRef(classService);
|
|
|
|
@ -48,6 +96,7 @@ CPhoneDevice::CPhoneDevice(JavaVM* vm, jobject service)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_timerUidFeed = time(NULL);
|
|
|
|
|
presentRotation_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CPhoneDevice::~CPhoneDevice()
|
|
|
|
@ -67,6 +116,11 @@ void CPhoneDevice::SetListener(IListener* listener)
|
|
|
|
|
m_listener = listener;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CPhoneDevice::Reboot()
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IDevice::timer_uid_t CPhoneDevice::registerTimer(unsigned int timerType, unsigned int timeout)
|
|
|
|
|
{
|
|
|
|
|
IDevice::timer_uid_t uid = m_timerUidFeed.fetch_add(1);
|
|
|
|
@ -140,7 +194,18 @@ bool CPhoneDevice::FireTimer(timer_uid_t uid)
|
|
|
|
|
|
|
|
|
|
IDevice::timer_uid_t CPhoneDevice::RegisterHeartbeat(unsigned int timerType, unsigned int timeout)
|
|
|
|
|
{
|
|
|
|
|
return registerTimer(timerType, timeout);
|
|
|
|
|
IDevice::timer_uid_t uid = m_timerUidFeed.fetch_add(1);
|
|
|
|
|
|
|
|
|
|
JNIEnv* env = NULL;
|
|
|
|
|
jboolean ret = JNI_FALSE;
|
|
|
|
|
bool attached = GetJniEnv(m_vm, &env);
|
|
|
|
|
if (attached)
|
|
|
|
|
{
|
|
|
|
|
env->CallVoidMethod(m_javaService, mRegisterHeartbeatMid, (jint)timeout);
|
|
|
|
|
m_vm->DetachCurrentThread();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return uid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CPhoneDevice::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const string& path)
|
|
|
|
@ -149,6 +214,10 @@ bool CPhoneDevice::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const string&
|
|
|
|
|
mPhotoInfo = photoInfo;
|
|
|
|
|
mPath = path;
|
|
|
|
|
|
|
|
|
|
LOGE("Image Buffer Size: %d", photoInfo.width * photoInfo.height * 4);
|
|
|
|
|
imageBuffer_ = (uint8_t*)malloc(photoInfo.width * photoInfo.height * 4);
|
|
|
|
|
ASSERT(imageBuffer_ != nullptr, "Failed to allocate imageBuffer_");
|
|
|
|
|
|
|
|
|
|
int cameraId = (int)photoInfo.channel - 1;
|
|
|
|
|
|
|
|
|
|
ACameraIdList *cameraIdList = NULL;
|
|
|
|
@ -199,7 +268,7 @@ bool CPhoneDevice::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const string&
|
|
|
|
|
LOGI("Failed to open camera device (id: %s)\n", selectedCameraId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
camera_status = ACameraDevice_createCaptureRequest(cameraDevice, TEMPLATE_PREVIEW,
|
|
|
|
|
camera_status = ACameraDevice_createCaptureRequest(cameraDevice, TEMPLATE_STILL_CAPTURE/*TEMPLATE_PREVIEW*/,
|
|
|
|
|
&captureRequest);
|
|
|
|
|
|
|
|
|
|
if (camera_status != ACAMERA_OK) {
|
|
|
|
@ -218,7 +287,7 @@ bool CPhoneDevice::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const string&
|
|
|
|
|
|
|
|
|
|
media_status_t status;
|
|
|
|
|
// status = AImageReader_new(1920, 1080, AIMAGE_FORMAT_YUV_420_888, 5, &mAImageReader);
|
|
|
|
|
status = AImageReader_new(1920, 1080, AIMAGE_FORMAT_JPEG, 5, &mAImageReader);
|
|
|
|
|
status = AImageReader_new(photoInfo.width, photoInfo.height, AIMAGE_FORMAT_YUV_420_888/*AIMAGE_FORMAT_JPEG*/, 5, &mAImageReader);
|
|
|
|
|
if (status != AMEDIA_OK)
|
|
|
|
|
{
|
|
|
|
|
LOGI("AImageReader_new error\n");
|
|
|
|
@ -273,11 +342,65 @@ ACameraCaptureSession_stateCallbacks* CPhoneDevice::GetSessionListener()
|
|
|
|
|
|
|
|
|
|
void CPhoneDevice::ImageCallback(AImageReader *reader)
|
|
|
|
|
{
|
|
|
|
|
bool res = false;
|
|
|
|
|
AImage *image = nullptr;
|
|
|
|
|
media_status_t status = AImageReader_acquireNextImage(reader, &image);
|
|
|
|
|
if (status == AMEDIA_OK && image)
|
|
|
|
|
{
|
|
|
|
|
bool res = WriteFile(image);
|
|
|
|
|
AImageCropRect srcRect;
|
|
|
|
|
AImage_getCropRect(image, &srcRect);
|
|
|
|
|
int32_t width = srcRect.right - srcRect.left;
|
|
|
|
|
int32_t height = srcRect.bottom - srcRect.top;
|
|
|
|
|
|
|
|
|
|
uint8_t *yPixel = nullptr;
|
|
|
|
|
uint8_t *uPixel = nullptr;
|
|
|
|
|
uint8_t *vPixel = nullptr;
|
|
|
|
|
|
|
|
|
|
int32_t yLen = 0;
|
|
|
|
|
int32_t uLen = 0;
|
|
|
|
|
int32_t vLen = 0;
|
|
|
|
|
|
|
|
|
|
cv::Mat _yuv_rgb_img, _yuv_gray_img;
|
|
|
|
|
|
|
|
|
|
AImage_getPlaneData(image, 0, &yPixel, &yLen);
|
|
|
|
|
AImage_getPlaneData(image, 1, &uPixel, &uLen);
|
|
|
|
|
AImage_getPlaneData(image, 2, &vPixel, &vLen);
|
|
|
|
|
|
|
|
|
|
uint8_t * data = new uint8_t[yLen + vLen + uLen];
|
|
|
|
|
memcpy(data, yPixel, yLen);
|
|
|
|
|
memcpy(data+yLen, vPixel, vLen);
|
|
|
|
|
memcpy(data+yLen+vLen, uPixel, uLen);
|
|
|
|
|
|
|
|
|
|
cv::Mat mYUV = cv::Mat(height * 1.5, width, CV_8UC1, data);
|
|
|
|
|
|
|
|
|
|
cv::cvtColor(mYUV, _yuv_rgb_img, cv::COLOR_YUV2RGB_NV21, 3);
|
|
|
|
|
|
|
|
|
|
// cv::Mat mYUV = cv::Mat(height, yStride, CV_8UC4, data);
|
|
|
|
|
|
|
|
|
|
cv::cvtColor(mYUV, _yuv_rgb_img, cv::COLOR_YUV2RGB_NV21, 3);
|
|
|
|
|
|
|
|
|
|
cv::rotate(_yuv_rgb_img, _yuv_rgb_img, cv::ROTATE_90_CLOCKWISE);
|
|
|
|
|
|
|
|
|
|
// cv::Mat mat = cv::Mat(buffer.height, buffer.stride, CV_8UC4, buffer.bits);
|
|
|
|
|
|
|
|
|
|
const char *str = "OSD";
|
|
|
|
|
putText(_yuv_rgb_img, str, cv::Point(50, 50), cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(0, 0, 0), 4,cv::LINE_AA);
|
|
|
|
|
putText(_yuv_rgb_img, str, cv::Point(50, 50), cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 2,cv::LINE_AA);
|
|
|
|
|
|
|
|
|
|
vector <int> compression_params;
|
|
|
|
|
compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
|
|
|
|
|
compression_params.push_back(75);
|
|
|
|
|
|
|
|
|
|
res = cv::imwrite(mPath.c_str(), _yuv_rgb_img, compression_params);
|
|
|
|
|
|
|
|
|
|
// ANativeWindow_unlockAndPost(theNativeWindow);
|
|
|
|
|
|
|
|
|
|
if (res)
|
|
|
|
|
{
|
|
|
|
|
int aa = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// bool res = WriteFile(image);
|
|
|
|
|
AImage_delete(image);
|
|
|
|
|
// delete pThis;
|
|
|
|
|
|
|
|
|
@ -319,7 +442,7 @@ bool CPhoneDevice::WriteFile(AImage *image)
|
|
|
|
|
fwrite(data, 1, len, file);
|
|
|
|
|
fclose(file);
|
|
|
|
|
|
|
|
|
|
LOGE("Capture: %s", path.c_str());
|
|
|
|
|
LOGI("Capture: %s", path.c_str());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
res = true;
|
|
|
|
@ -342,6 +465,220 @@ std::string CPhoneDevice::GetFileName() const
|
|
|
|
|
{
|
|
|
|
|
return mPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convert yuv image inside AImage into ANativeWindow_Buffer
|
|
|
|
|
* ANativeWindow_Buffer format is guaranteed to be
|
|
|
|
|
* WINDOW_FORMAT_RGBX_8888
|
|
|
|
|
* WINDOW_FORMAT_RGBA_8888
|
|
|
|
|
* @param buf a {@link ANativeWindow_Buffer } instance, destination of
|
|
|
|
|
* image conversion
|
|
|
|
|
* @param image a {@link AImage} instance, source of image conversion.
|
|
|
|
|
* it will be deleted via {@link AImage_delete}
|
|
|
|
|
*/
|
|
|
|
|
bool CPhoneDevice::DisplayImage(ANativeWindow_Buffer *buf, AImage *image) {
|
|
|
|
|
ASSERT(buf->format == WINDOW_FORMAT_RGBX_8888 ||
|
|
|
|
|
buf->format == WINDOW_FORMAT_RGBA_8888,
|
|
|
|
|
"Not supported buffer format");
|
|
|
|
|
|
|
|
|
|
int32_t srcFormat = -1;
|
|
|
|
|
AImage_getFormat(image, &srcFormat);
|
|
|
|
|
ASSERT(AIMAGE_FORMAT_YUV_420_888 == srcFormat, "Failed to get format");
|
|
|
|
|
int32_t srcPlanes = 0;
|
|
|
|
|
AImage_getNumberOfPlanes(image, &srcPlanes);
|
|
|
|
|
ASSERT(srcPlanes == 3, "Is not 3 planes");
|
|
|
|
|
|
|
|
|
|
switch (presentRotation_) {
|
|
|
|
|
case 0:
|
|
|
|
|
PresentImage(buf, image);
|
|
|
|
|
break;
|
|
|
|
|
case 90:
|
|
|
|
|
PresentImage90(buf, image);
|
|
|
|
|
break;
|
|
|
|
|
case 180:
|
|
|
|
|
PresentImage180(buf, image);
|
|
|
|
|
break;
|
|
|
|
|
case 270:
|
|
|
|
|
PresentImage270(buf, image);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ASSERT(0, "NOT recognized display rotation: %d", presentRotation_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AImage_delete(image);
|
|
|
|
|
image = nullptr;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* PresentImage()
|
|
|
|
|
* Converting yuv to RGB
|
|
|
|
|
* No rotation: (x,y) --> (x, y)
|
|
|
|
|
* Refer to:
|
|
|
|
|
* https://mathbits.com/MathBits/TISection/Geometry/Transformations2.htm
|
|
|
|
|
*/
|
|
|
|
|
void CPhoneDevice::PresentImage(ANativeWindow_Buffer *buf, AImage *image) {
|
|
|
|
|
AImageCropRect srcRect;
|
|
|
|
|
AImage_getCropRect(image, &srcRect);
|
|
|
|
|
|
|
|
|
|
AImage_getPlaneRowStride(image, 0, &yStride);
|
|
|
|
|
AImage_getPlaneRowStride(image, 1, &uvStride);
|
|
|
|
|
yPixel = imageBuffer_;
|
|
|
|
|
AImage_getPlaneData(image, 0, &yPixel, &yLen);
|
|
|
|
|
vPixel = imageBuffer_ + yLen;
|
|
|
|
|
AImage_getPlaneData(image, 1, &vPixel, &vLen);
|
|
|
|
|
uPixel = imageBuffer_ + yLen + vLen;
|
|
|
|
|
AImage_getPlaneData(image, 2, &uPixel, &uLen);
|
|
|
|
|
AImage_getPlanePixelStride(image, 1, &uvPixelStride);
|
|
|
|
|
|
|
|
|
|
int32_t height = std::min(buf->height, (srcRect.bottom - srcRect.top));
|
|
|
|
|
int32_t width = std::min(buf->width, (srcRect.right - srcRect.left));
|
|
|
|
|
|
|
|
|
|
uint32_t *out = static_cast<uint32_t *>(buf->bits);
|
|
|
|
|
|
|
|
|
|
for (int32_t y = 0; y < height; y++) {
|
|
|
|
|
const uint8_t *pY = yPixel + yStride * (y + srcRect.top) + srcRect.left;
|
|
|
|
|
|
|
|
|
|
int32_t uv_row_start = uvStride * ((y + srcRect.top) >> 1);
|
|
|
|
|
const uint8_t *pU = uPixel + uv_row_start + (srcRect.left >> 1);
|
|
|
|
|
const uint8_t *pV = vPixel + uv_row_start + (srcRect.left >> 1);
|
|
|
|
|
|
|
|
|
|
for (int32_t x = 0; x < width; x++) {
|
|
|
|
|
const int32_t uv_offset = (x >> 1) * uvPixelStride;
|
|
|
|
|
out[x] = YUV2RGB(pY[x], pU[uv_offset], pV[uv_offset]);
|
|
|
|
|
}
|
|
|
|
|
out += buf->stride;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* PresentImage90()
|
|
|
|
|
* Converting YUV to RGB
|
|
|
|
|
* Rotation image anti-clockwise 90 degree -- (x, y) --> (-y, x)
|
|
|
|
|
*/
|
|
|
|
|
void CPhoneDevice::PresentImage90(ANativeWindow_Buffer *buf, AImage *image) {
|
|
|
|
|
AImageCropRect srcRect;
|
|
|
|
|
AImage_getCropRect(image, &srcRect);
|
|
|
|
|
|
|
|
|
|
AImage_getPlaneRowStride(image, 0, &yStride);
|
|
|
|
|
AImage_getPlaneRowStride(image, 1, &uvStride);
|
|
|
|
|
yPixel = imageBuffer_;
|
|
|
|
|
AImage_getPlaneData(image, 0, &yPixel, &yLen);
|
|
|
|
|
vPixel = imageBuffer_ + yLen;
|
|
|
|
|
AImage_getPlaneData(image, 1, &vPixel, &vLen);
|
|
|
|
|
uPixel = imageBuffer_ + yLen + vLen;
|
|
|
|
|
AImage_getPlaneData(image, 2, &uPixel, &uLen);
|
|
|
|
|
AImage_getPlanePixelStride(image, 1, &uvPixelStride);
|
|
|
|
|
|
|
|
|
|
int32_t height = std::min(buf->width, (srcRect.bottom - srcRect.top));
|
|
|
|
|
int32_t width = std::min(buf->height, (srcRect.right - srcRect.left));
|
|
|
|
|
|
|
|
|
|
uint32_t *out = static_cast<uint32_t *>(buf->bits);
|
|
|
|
|
out += height - 1;
|
|
|
|
|
for (int32_t y = 0; y < height; y++) {
|
|
|
|
|
const uint8_t *pY = yPixel + yStride * (y + srcRect.top) + srcRect.left;
|
|
|
|
|
|
|
|
|
|
int32_t uv_row_start = uvStride * ((y + srcRect.top) >> 1);
|
|
|
|
|
const uint8_t *pU = uPixel + uv_row_start + (srcRect.left >> 1);
|
|
|
|
|
const uint8_t *pV = vPixel + uv_row_start + (srcRect.left >> 1);
|
|
|
|
|
|
|
|
|
|
for (int32_t x = 0; x < width; x++) {
|
|
|
|
|
const int32_t uv_offset = (x >> 1) * uvPixelStride;
|
|
|
|
|
// [x, y]--> [-y, x]
|
|
|
|
|
int testb = pU[uv_offset];
|
|
|
|
|
int testc = pV[uv_offset];
|
|
|
|
|
int testA = pY[x];
|
|
|
|
|
out[x * buf->stride] = YUV2RGB(testA, testb, testc);
|
|
|
|
|
}
|
|
|
|
|
out -= 1; // move to the next column
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* PresentImage180()
|
|
|
|
|
* Converting yuv to RGB
|
|
|
|
|
* Rotate image 180 degree: (x, y) --> (-x, -y)
|
|
|
|
|
*/
|
|
|
|
|
void CPhoneDevice::PresentImage180(ANativeWindow_Buffer *buf, AImage *image) {
|
|
|
|
|
AImageCropRect srcRect;
|
|
|
|
|
AImage_getCropRect(image, &srcRect);
|
|
|
|
|
|
|
|
|
|
AImage_getPlaneRowStride(image, 0, &yStride);
|
|
|
|
|
AImage_getPlaneRowStride(image, 1, &uvStride);
|
|
|
|
|
yPixel = imageBuffer_;
|
|
|
|
|
AImage_getPlaneData(image, 0, &yPixel, &yLen);
|
|
|
|
|
vPixel = imageBuffer_ + yLen;
|
|
|
|
|
AImage_getPlaneData(image, 1, &vPixel, &vLen);
|
|
|
|
|
uPixel = imageBuffer_ + yLen + vLen;
|
|
|
|
|
AImage_getPlaneData(image, 2, &uPixel, &uLen);
|
|
|
|
|
AImage_getPlanePixelStride(image, 1, &uvPixelStride);
|
|
|
|
|
|
|
|
|
|
int32_t height = std::min(buf->height, (srcRect.bottom - srcRect.top));
|
|
|
|
|
int32_t width = std::min(buf->width, (srcRect.right - srcRect.left));
|
|
|
|
|
|
|
|
|
|
uint32_t *out = static_cast<uint32_t *>(buf->bits);
|
|
|
|
|
out += (height - 1) * buf->stride;
|
|
|
|
|
for (int32_t y = 0; y < height; y++) {
|
|
|
|
|
const uint8_t *pY = yPixel + yStride * (y + srcRect.top) + srcRect.left;
|
|
|
|
|
|
|
|
|
|
int32_t uv_row_start = uvStride * ((y + srcRect.top) >> 1);
|
|
|
|
|
const uint8_t *pU = uPixel + uv_row_start + (srcRect.left >> 1);
|
|
|
|
|
const uint8_t *pV = vPixel + uv_row_start + (srcRect.left >> 1);
|
|
|
|
|
|
|
|
|
|
for (int32_t x = 0; x < width; x++) {
|
|
|
|
|
const int32_t uv_offset = (x >> 1) * uvPixelStride;
|
|
|
|
|
// mirror image since we are using front camera
|
|
|
|
|
out[width - 1 - x] = YUV2RGB(pY[x], pU[uv_offset], pV[uv_offset]);
|
|
|
|
|
// out[x] = YUV2RGB(pY[x], pU[uv_offset], pV[uv_offset]);
|
|
|
|
|
}
|
|
|
|
|
out -= buf->stride;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* PresentImage270()
|
|
|
|
|
* Converting image from YUV to RGB
|
|
|
|
|
* Rotate Image counter-clockwise 270 degree: (x, y) --> (y, x)
|
|
|
|
|
*/
|
|
|
|
|
void CPhoneDevice::PresentImage270(ANativeWindow_Buffer *buf, AImage *image) {
|
|
|
|
|
AImageCropRect srcRect;
|
|
|
|
|
AImage_getCropRect(image, &srcRect);
|
|
|
|
|
|
|
|
|
|
AImage_getPlaneRowStride(image, 0, &yStride);
|
|
|
|
|
AImage_getPlaneRowStride(image, 1, &uvStride);
|
|
|
|
|
yPixel = imageBuffer_;
|
|
|
|
|
AImage_getPlaneData(image, 0, &yPixel, &yLen);
|
|
|
|
|
vPixel = imageBuffer_ + yLen;
|
|
|
|
|
AImage_getPlaneData(image, 1, &vPixel, &vLen);
|
|
|
|
|
uPixel = imageBuffer_ + yLen + vLen;
|
|
|
|
|
AImage_getPlaneData(image, 2, &uPixel, &uLen);
|
|
|
|
|
AImage_getPlanePixelStride(image, 1, &uvPixelStride);
|
|
|
|
|
|
|
|
|
|
int32_t height = std::min(buf->width, (srcRect.bottom - srcRect.top));
|
|
|
|
|
int32_t width = std::min(buf->height, (srcRect.right - srcRect.left));
|
|
|
|
|
|
|
|
|
|
uint32_t *out = static_cast<uint32_t *>(buf->bits);
|
|
|
|
|
for (int32_t y = 0; y < height; y++) {
|
|
|
|
|
const uint8_t *pY = yPixel + yStride * (y + srcRect.top) + srcRect.left;
|
|
|
|
|
|
|
|
|
|
int32_t uv_row_start = uvStride * ((y + srcRect.top) >> 1);
|
|
|
|
|
const uint8_t *pU = uPixel + uv_row_start + (srcRect.left >> 1);
|
|
|
|
|
const uint8_t *pV = vPixel + uv_row_start + (srcRect.left >> 1);
|
|
|
|
|
|
|
|
|
|
for (int32_t x = 0; x < width; x++) {
|
|
|
|
|
const int32_t uv_offset = (x >> 1) * uvPixelStride;
|
|
|
|
|
int testb = pU[uv_offset];
|
|
|
|
|
int testc = pV[uv_offset];
|
|
|
|
|
int testA = pY[x];
|
|
|
|
|
out[(width - 1 - x) * buf->stride] =
|
|
|
|
|
YUV2RGB(testA, testb, testc);
|
|
|
|
|
}
|
|
|
|
|
out += 1; // move to the next column
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
bool CPhoneDevice::SendBroadcastMessage(String16 action, int value)
|
|
|
|
|
{
|
|
|
|
|