拍照功能实现
parent
2d8cb9f1e9
commit
09503b82d0
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2015 Rockchip Electronics Co. LTD
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __CAMERA2_HELPER_H__
|
||||
#define __CAMERA2_HELPER_H__
|
||||
|
||||
struct ImageFormat {
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
|
||||
int32_t format; // Through out this demo, the format is fixed to
|
||||
// YUV_420 format
|
||||
};
|
||||
|
||||
/**
|
||||
* A helper class to assist image size comparison, by comparing the absolute
|
||||
* size
|
||||
* regardless of the portrait or landscape mode.
|
||||
*/
|
||||
class DisplayDimension {
|
||||
public:
|
||||
DisplayDimension(int32_t w, int32_t h) : w_(w), h_(h), portrait_(false) {
|
||||
if (h > w) {
|
||||
// make it landscape
|
||||
w_ = h;
|
||||
h_ = w;
|
||||
portrait_ = true;
|
||||
}
|
||||
}
|
||||
DisplayDimension(const DisplayDimension& other) {
|
||||
w_ = other.w_;
|
||||
h_ = other.h_;
|
||||
portrait_ = other.portrait_;
|
||||
}
|
||||
|
||||
DisplayDimension(void) {
|
||||
w_ = 0;
|
||||
h_ = 0;
|
||||
portrait_ = false;
|
||||
}
|
||||
DisplayDimension& operator=(const DisplayDimension& other) {
|
||||
w_ = other.w_;
|
||||
h_ = other.h_;
|
||||
portrait_ = other.portrait_;
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
bool IsSameRatio(DisplayDimension& other) {
|
||||
return (w_ * other.h_ == h_ * other.w_);
|
||||
}
|
||||
bool operator>(DisplayDimension& other) {
|
||||
return (w_ >= other.w_ & h_ >= other.h_);
|
||||
}
|
||||
bool operator==(DisplayDimension& other) {
|
||||
return (w_ == other.w_ && h_ == other.h_ && portrait_ == other.portrait_);
|
||||
}
|
||||
DisplayDimension operator-(DisplayDimension& other) {
|
||||
DisplayDimension delta(w_ - other.w_, h_ - other.h_);
|
||||
return delta;
|
||||
}
|
||||
void Flip(void) { portrait_ = !portrait_; }
|
||||
bool IsPortrait(void) { return portrait_; }
|
||||
int32_t width(void) { return w_; }
|
||||
int32_t height(void) { return h_; }
|
||||
int32_t org_width(void) { return (portrait_ ? h_ : w_); }
|
||||
int32_t org_height(void) { return (portrait_ ? w_ : h_); }
|
||||
|
||||
private:
|
||||
int32_t w_, h_;
|
||||
bool portrait_;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __CAMERA2_HELPER_H__ */
|
@ -0,0 +1,418 @@
|
||||
// Tencent is pleased to support the open source community by making ncnn available.
|
||||
//
|
||||
// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// https://opensource.org/licenses/BSD-3-Clause
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "ndkcamera.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
|
||||
#include "mat.h"
|
||||
|
||||
static void onDisconnected(void* context, ACameraDevice* device)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_WARN, "NdkCamera", "onDisconnected %p", device);
|
||||
}
|
||||
|
||||
static void onError(void* context, ACameraDevice* device, int error)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_WARN, "NdkCamera", "onError %p %d", device, error);
|
||||
}
|
||||
|
||||
static void onImageAvailable(void* context, AImageReader* reader)
|
||||
{
|
||||
// __android_log_print(ANDROID_LOG_WARN, "NdkCamera", "onImageAvailable %p", reader);
|
||||
|
||||
AImage* image = 0;
|
||||
media_status_t status = AImageReader_acquireLatestImage(reader, &image);
|
||||
|
||||
if (status != AMEDIA_OK)
|
||||
{
|
||||
// error
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t format;
|
||||
AImage_getFormat(image, &format);
|
||||
|
||||
// assert format == AIMAGE_FORMAT_YUV_420_888
|
||||
|
||||
int32_t width = 0;
|
||||
int32_t height = 0;
|
||||
AImage_getWidth(image, &width);
|
||||
AImage_getHeight(image, &height);
|
||||
|
||||
int32_t y_pixelStride = 0;
|
||||
int32_t u_pixelStride = 0;
|
||||
int32_t v_pixelStride = 0;
|
||||
AImage_getPlanePixelStride(image, 0, &y_pixelStride);
|
||||
AImage_getPlanePixelStride(image, 1, &u_pixelStride);
|
||||
AImage_getPlanePixelStride(image, 2, &v_pixelStride);
|
||||
|
||||
int32_t y_rowStride = 0;
|
||||
int32_t u_rowStride = 0;
|
||||
int32_t v_rowStride = 0;
|
||||
AImage_getPlaneRowStride(image, 0, &y_rowStride);
|
||||
AImage_getPlaneRowStride(image, 1, &u_rowStride);
|
||||
AImage_getPlaneRowStride(image, 2, &v_rowStride);
|
||||
|
||||
uint8_t* y_data = 0;
|
||||
uint8_t* u_data = 0;
|
||||
uint8_t* v_data = 0;
|
||||
int y_len = 0;
|
||||
int u_len = 0;
|
||||
int v_len = 0;
|
||||
AImage_getPlaneData(image, 0, &y_data, &y_len);
|
||||
AImage_getPlaneData(image, 1, &u_data, &u_len);
|
||||
AImage_getPlaneData(image, 2, &v_data, &v_len);
|
||||
|
||||
if (u_data == v_data + 1 && v_data == y_data + width * height && y_pixelStride == 1 && u_pixelStride == 2 && v_pixelStride == 2 && y_rowStride == width && u_rowStride == width && v_rowStride == width)
|
||||
{
|
||||
// already nv21 :)
|
||||
((NdkCamera*)context)->on_image((unsigned char*)y_data, (int)width, (int)height);
|
||||
}
|
||||
else
|
||||
{
|
||||
// construct nv21
|
||||
unsigned char* nv21 = new unsigned char[width * height + width * height / 2];
|
||||
{
|
||||
// Y
|
||||
unsigned char* yptr = nv21;
|
||||
for (int y=0; y<height; y++)
|
||||
{
|
||||
const unsigned char* y_data_ptr = y_data + y_rowStride * y;
|
||||
for (int x=0; x<width; x++)
|
||||
{
|
||||
yptr[0] = y_data_ptr[0];
|
||||
yptr++;
|
||||
y_data_ptr += y_pixelStride;
|
||||
}
|
||||
}
|
||||
|
||||
// UV
|
||||
unsigned char* uvptr = nv21 + width * height;
|
||||
for (int y=0; y<height/2; y++)
|
||||
{
|
||||
const unsigned char* v_data_ptr = v_data + v_rowStride * y;
|
||||
const unsigned char* u_data_ptr = u_data + u_rowStride * y;
|
||||
for (int x=0; x<width/2; x++)
|
||||
{
|
||||
uvptr[0] = v_data_ptr[0];
|
||||
uvptr[1] = u_data_ptr[0];
|
||||
uvptr += 2;
|
||||
v_data_ptr += v_pixelStride;
|
||||
u_data_ptr += u_pixelStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
((NdkCamera*)context)->on_image((unsigned char*)nv21, (int)width, (int)height);
|
||||
|
||||
delete[] nv21;
|
||||
}
|
||||
|
||||
AImage_delete(image);
|
||||
}
|
||||
|
||||
static void onSessionActive(void* context, ACameraCaptureSession *session)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_WARN, "NdkCamera", "onSessionActive %p", session);
|
||||
}
|
||||
|
||||
static void onSessionReady(void* context, ACameraCaptureSession *session)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_WARN, "NdkCamera", "onSessionReady %p", session);
|
||||
}
|
||||
|
||||
static void onSessionClosed(void* context, ACameraCaptureSession *session)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_WARN, "NdkCamera", "onSessionClosed %p", session);
|
||||
}
|
||||
|
||||
void onCaptureFailed(void* context, ACameraCaptureSession* session, ACaptureRequest* request, ACameraCaptureFailure* failure)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_WARN, "NdkCamera", "onCaptureFailed %p %p %p", session, request, failure);
|
||||
}
|
||||
|
||||
void onCaptureSequenceCompleted(void* context, ACameraCaptureSession* session, int sequenceId, int64_t frameNumber)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_WARN, "NdkCamera", "onCaptureSequenceCompleted %p %d %ld", session, sequenceId, frameNumber);
|
||||
}
|
||||
|
||||
void onCaptureSequenceAborted(void* context, ACameraCaptureSession* session, int sequenceId)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_WARN, "NdkCamera", "onCaptureSequenceAborted %p %d", session, sequenceId);
|
||||
}
|
||||
|
||||
void onCaptureCompleted(void* context, ACameraCaptureSession* session, ACaptureRequest* request, const ACameraMetadata* result)
|
||||
{
|
||||
// __android_log_print(ANDROID_LOG_WARN, "NdkCamera", "onCaptureCompleted %p %p %p", session, request, result);
|
||||
}
|
||||
|
||||
NdkCamera::NdkCamera()
|
||||
{
|
||||
camera_facing = 0;
|
||||
camera_orientation = 0;
|
||||
|
||||
camera_manager = 0;
|
||||
camera_device = 0;
|
||||
image_reader = 0;
|
||||
image_reader_surface = 0;
|
||||
image_reader_target = 0;
|
||||
capture_request = 0;
|
||||
capture_session_output_container = 0;
|
||||
capture_session_output = 0;
|
||||
capture_session = 0;
|
||||
|
||||
|
||||
// setup imagereader and its surface
|
||||
{
|
||||
AImageReader_new(640, 480, AIMAGE_FORMAT_YUV_420_888, /*maxImages*/2, &image_reader);
|
||||
|
||||
AImageReader_ImageListener listener;
|
||||
listener.context = this;
|
||||
listener.onImageAvailable = onImageAvailable;
|
||||
|
||||
AImageReader_setImageListener(image_reader, &listener);
|
||||
|
||||
AImageReader_getWindow(image_reader, &image_reader_surface);
|
||||
|
||||
ANativeWindow_acquire(image_reader_surface);
|
||||
}
|
||||
}
|
||||
|
||||
NdkCamera::~NdkCamera()
|
||||
{
|
||||
close();
|
||||
|
||||
if (image_reader)
|
||||
{
|
||||
AImageReader_delete(image_reader);
|
||||
image_reader = 0;
|
||||
}
|
||||
|
||||
if (image_reader_surface)
|
||||
{
|
||||
ANativeWindow_release(image_reader_surface);
|
||||
image_reader_surface = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int NdkCamera::open(int _camera_facing)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_WARN, "NdkCamera", "open");
|
||||
|
||||
camera_facing = _camera_facing;
|
||||
|
||||
camera_manager = ACameraManager_create();
|
||||
|
||||
// find front camera
|
||||
std::string camera_id;
|
||||
{
|
||||
ACameraIdList* camera_id_list = 0;
|
||||
ACameraManager_getCameraIdList(camera_manager, &camera_id_list);
|
||||
|
||||
for (int i = 0; i < camera_id_list->numCameras; ++i)
|
||||
{
|
||||
const char* id = camera_id_list->cameraIds[i];
|
||||
ACameraMetadata* camera_metadata = 0;
|
||||
ACameraManager_getCameraCharacteristics(camera_manager, id, &camera_metadata);
|
||||
|
||||
// query faceing
|
||||
acamera_metadata_enum_android_lens_facing_t facing = ACAMERA_LENS_FACING_FRONT;
|
||||
{
|
||||
ACameraMetadata_const_entry e = { 0 };
|
||||
ACameraMetadata_getConstEntry(camera_metadata, ACAMERA_LENS_FACING, &e);
|
||||
facing = (acamera_metadata_enum_android_lens_facing_t)e.data.u8[0];
|
||||
}
|
||||
|
||||
if (camera_facing == 0 && facing != ACAMERA_LENS_FACING_FRONT)
|
||||
{
|
||||
ACameraMetadata_free(camera_metadata);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (camera_facing == 1 && facing != ACAMERA_LENS_FACING_BACK)
|
||||
{
|
||||
ACameraMetadata_free(camera_metadata);
|
||||
continue;
|
||||
}
|
||||
|
||||
camera_id = id;
|
||||
|
||||
// query orientation
|
||||
int orientation = 0;
|
||||
{
|
||||
ACameraMetadata_const_entry e = { 0 };
|
||||
ACameraMetadata_getConstEntry(camera_metadata, ACAMERA_SENSOR_ORIENTATION, &e);
|
||||
|
||||
orientation = (int)e.data.i32[0];
|
||||
}
|
||||
|
||||
camera_orientation = orientation;
|
||||
|
||||
ACameraMetadata_free(camera_metadata);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
ACameraManager_deleteCameraIdList(camera_id_list);
|
||||
}
|
||||
|
||||
__android_log_print(ANDROID_LOG_WARN, "NdkCamera", "open %s %d", camera_id.c_str(), camera_orientation);
|
||||
|
||||
// open camera
|
||||
{
|
||||
ACameraDevice_StateCallbacks camera_device_state_callbacks;
|
||||
camera_device_state_callbacks.context = this;
|
||||
camera_device_state_callbacks.onDisconnected = onDisconnected;
|
||||
camera_device_state_callbacks.onError = onError;
|
||||
|
||||
ACameraManager_openCamera(camera_manager, camera_id.c_str(), &camera_device_state_callbacks, &camera_device);
|
||||
}
|
||||
|
||||
// capture request
|
||||
{
|
||||
ACameraDevice_createCaptureRequest(camera_device, TEMPLATE_PREVIEW, &capture_request);
|
||||
|
||||
ACameraOutputTarget_create(image_reader_surface, &image_reader_target);
|
||||
ACaptureRequest_addTarget(capture_request, image_reader_target);
|
||||
}
|
||||
|
||||
// capture session
|
||||
{
|
||||
ACameraCaptureSession_stateCallbacks camera_capture_session_state_callbacks;
|
||||
camera_capture_session_state_callbacks.context = this;
|
||||
camera_capture_session_state_callbacks.onActive = onSessionActive;
|
||||
camera_capture_session_state_callbacks.onReady = onSessionReady;
|
||||
camera_capture_session_state_callbacks.onClosed = onSessionClosed;
|
||||
|
||||
ACaptureSessionOutputContainer_create(&capture_session_output_container);
|
||||
|
||||
ACaptureSessionOutput_create(image_reader_surface, &capture_session_output);
|
||||
|
||||
ACaptureSessionOutputContainer_add(capture_session_output_container, capture_session_output);
|
||||
|
||||
ACameraDevice_createCaptureSession(camera_device, capture_session_output_container, &camera_capture_session_state_callbacks, &capture_session);
|
||||
|
||||
ACameraCaptureSession_captureCallbacks camera_capture_session_capture_callbacks;
|
||||
camera_capture_session_capture_callbacks.context = this;
|
||||
camera_capture_session_capture_callbacks.onCaptureStarted = 0;
|
||||
camera_capture_session_capture_callbacks.onCaptureProgressed = 0;
|
||||
camera_capture_session_capture_callbacks.onCaptureCompleted = onCaptureCompleted;
|
||||
camera_capture_session_capture_callbacks.onCaptureFailed = onCaptureFailed;
|
||||
camera_capture_session_capture_callbacks.onCaptureSequenceCompleted = onCaptureSequenceCompleted;
|
||||
camera_capture_session_capture_callbacks.onCaptureSequenceAborted = onCaptureSequenceAborted;
|
||||
camera_capture_session_capture_callbacks.onCaptureBufferLost = 0;
|
||||
|
||||
ACameraCaptureSession_setRepeatingRequest(capture_session, &camera_capture_session_capture_callbacks, 1, &capture_request, nullptr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NdkCamera::close()
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_WARN, "NdkCamera", "close");
|
||||
|
||||
if (capture_session)
|
||||
{
|
||||
ACameraCaptureSession_stopRepeating(capture_session);
|
||||
ACameraCaptureSession_close(capture_session);
|
||||
capture_session = 0;
|
||||
}
|
||||
|
||||
if (camera_device)
|
||||
{
|
||||
ACameraDevice_close(camera_device);
|
||||
camera_device = 0;
|
||||
}
|
||||
|
||||
if (capture_session_output_container)
|
||||
{
|
||||
ACaptureSessionOutputContainer_free(capture_session_output_container);
|
||||
capture_session_output_container = 0;
|
||||
}
|
||||
|
||||
if (capture_session_output)
|
||||
{
|
||||
ACaptureSessionOutput_free(capture_session_output);
|
||||
capture_session_output = 0;
|
||||
}
|
||||
|
||||
if (capture_request)
|
||||
{
|
||||
ACaptureRequest_free(capture_request);
|
||||
capture_request = 0;
|
||||
}
|
||||
|
||||
if (image_reader_target)
|
||||
{
|
||||
ACameraOutputTarget_free(image_reader_target);
|
||||
image_reader_target = 0;
|
||||
}
|
||||
|
||||
if (camera_manager)
|
||||
{
|
||||
ACameraManager_delete(camera_manager);
|
||||
camera_manager = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void NdkCamera::on_image(const cv::Mat& rgb) const
|
||||
{
|
||||
}
|
||||
|
||||
void NdkCamera::on_image(const unsigned char* nv21, int nv21_width, int nv21_height) const
|
||||
{
|
||||
// rotate nv21
|
||||
int w = 0;
|
||||
int h = 0;
|
||||
int rotate_type = 0;
|
||||
if (camera_orientation == 0)
|
||||
{
|
||||
w = nv21_width;
|
||||
h = nv21_height;
|
||||
rotate_type = camera_facing == 0 ? 2 : 1;
|
||||
}
|
||||
if (camera_orientation == 90)
|
||||
{
|
||||
w = nv21_height;
|
||||
h = nv21_width;
|
||||
rotate_type = camera_facing == 0 ? 5 : 6;
|
||||
}
|
||||
if (camera_orientation == 180)
|
||||
{
|
||||
w = nv21_width;
|
||||
h = nv21_height;
|
||||
rotate_type = camera_facing == 0 ? 4 : 3;
|
||||
}
|
||||
if (camera_orientation == 270)
|
||||
{
|
||||
w = nv21_height;
|
||||
h = nv21_width;
|
||||
rotate_type = camera_facing == 0 ? 7 : 8;
|
||||
}
|
||||
|
||||
cv::Mat nv21_rotated(h + h / 2, w, CV_8UC1);
|
||||
ncnn::kanna_rotate_yuv420sp(nv21, nv21_width, nv21_height, nv21_rotated.data, w, h, rotate_type);
|
||||
|
||||
// nv21_rotated to rgb
|
||||
cv::Mat rgb(h, w, CV_8UC3);
|
||||
ncnn::yuv420sp2rgb(nv21_rotated.data, w, h, rgb.data);
|
||||
|
||||
on_image(rgb);
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
// Tencent is pleased to support the open source community by making ncnn available.
|
||||
//
|
||||
// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// https://opensource.org/licenses/BSD-3-Clause
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef NDKCAMERA_H
|
||||
#define NDKCAMERA_H
|
||||
|
||||
#include <camera/NdkCameraDevice.h>
|
||||
#include <camera/NdkCameraManager.h>
|
||||
#include <camera/NdkCameraMetadata.h>
|
||||
#include <media/NdkImageReader.h>
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
|
||||
class NdkCamera
|
||||
{
|
||||
public:
|
||||
NdkCamera();
|
||||
virtual ~NdkCamera();
|
||||
|
||||
// facing 0=front 1=back
|
||||
int open(int camera_facing = 0);
|
||||
void close();
|
||||
|
||||
virtual void on_image(const cv::Mat& rgb) const;
|
||||
|
||||
virtual void on_image(const unsigned char* nv21, int nv21_width, int nv21_height) const;
|
||||
|
||||
public:
|
||||
int camera_facing;
|
||||
int camera_orientation;
|
||||
|
||||
private:
|
||||
ACameraManager* camera_manager;
|
||||
ACameraDevice* camera_device;
|
||||
AImageReader* image_reader;
|
||||
ANativeWindow* image_reader_surface;
|
||||
ACameraOutputTarget* image_reader_target;
|
||||
ACaptureRequest* capture_request;
|
||||
ACaptureSessionOutputContainer* capture_session_output_container;
|
||||
ACaptureSessionOutput* capture_session_output;
|
||||
ACameraCaptureSession* capture_session;
|
||||
};
|
||||
|
||||
#endif // NDKCAMERA_H
|
Loading…
Reference in New Issue