7#include <QtCore/qjnitypes.h>
8#include <QtCore/QLoggingCategory>
26 auto planes =
frame.callMethod<QtJniTypes::AndroidImagePlaneArray>(
"getPlanes");
27 if (!planes.isValid())
30 int numberPlanes = jniEnv->GetArrayLength(planes.object<jarray>());
32 int pixelStrides[numberPlanes];
33 int rowStrides[numberPlanes];
34 int bufferSize[numberPlanes];
35 uint8_t *
buffer[numberPlanes];
37 auto resetPlane = [&](
int index) {
38 if (index < 0 || index > numberPlanes)
41 rowStrides[
index] = 0;
42 pixelStrides[
index] = 0;
43 bufferSize[
index] = 0;
48 QJniObject plane = jniEnv->GetObjectArrayElement(planes.object<jobjectArray>(),
index);
49 if (jniEnv.checkAndClearExceptions() || !plane.isValid()) {
54 rowStrides[
index] = plane.callMethod<jint>(
"getRowStride");
55 pixelStrides[
index] = plane.callMethod<jint>(
"getPixelStride");
57 auto byteBuffer = plane.callMethod<QtJniTypes::JavaByteBuffer>(
"getBuffer");
58 if (!byteBuffer.isValid()) {
65 buffer[
index] =
static_cast<uint8_t *
>(jniEnv->GetDirectBufferAddress(byteBuffer.object()));
66 bufferSize[
index] = byteBuffer.callMethod<jint>(
"remaining");
75 AndroidImageFormat imageFormat = AndroidImageFormat(
format);
77 switch (imageFormat) {
78 case AndroidImageFormat::JPEG:
81 case AndroidImageFormat::YUV_420_888:
82 if (numberPlanes < 3) {
87 if (pixelStrides[1] == 1)
89 else if (pixelStrides[1] == 2 && abs(
buffer[1] -
buffer[2]) == 1)
93 case AndroidImageFormat::HEIC:
97 case AndroidImageFormat::RAW_PRIVATE:
98 case AndroidImageFormat::RAW_SENSOR:
102 case AndroidImageFormat::FLEX_RGBA_8888:
103 case AndroidImageFormat::FLEX_RGB_888:
108 case AndroidImageFormat::YUV_422_888:
109 case AndroidImageFormat::YUV_444_888:
110 case AndroidImageFormat::YCBCR_P010:
120 qCWarning(qLCAndroidCameraFrame) <<
"Cannot determine image format!";
124 auto copyPlane = [&](
int mapIndex,
int arrayIndex) {
125 if (arrayIndex >= numberPlanes)
128 m_planes[mapIndex].rowStride = rowStrides[arrayIndex];
129 m_planes[mapIndex].size = bufferSize[arrayIndex];
130 m_planes[mapIndex].data =
buffer[arrayIndex];
133 switch (calculedPixelFormat) {
149 <<
"FFmpeg HW Mediacodec does not encode other than YCbCr formats";
152 m_planes[0].rowStride = m_image.bytesPerLine();
153 m_planes[0].size = m_image.sizeInBytes();
154 m_planes[0].data = m_image.bits();
161 long timestamp =
frame.callMethod<jlong>(
"getTimestamp");
162 m_timestamp = timestamp / 1000;
164 int width =
frame.callMethod<jint>(
"getWidth");
177 m_frame = jniEnv->NewGlobalRef(
frame.object());
178 jniEnv.checkAndClearExceptions();
179 }
else if (
frame.isValid()) {
180 frame.callMethod<
void>(
"close");
190 if (qFrame.isValid())
191 qFrame.callMethod<
void>(
"close");
195 jniEnv->DeleteGlobalRef(m_frame);
Q_DECLARE_JNI_TYPE(StringArray, "[Ljava/lang/String;")
QAndroidCameraFrame(QJniObject frame)
static QImage fromData(QByteArrayView data, const char *format=nullptr)
Combined button and popup list for selecting options.
Q_DECLARE_JNI_CLASS(AndroidImageFormat, "android/graphics/ImageFormat")
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
GLint GLsizei GLsizei height
GLint GLsizei GLsizei GLenum format