Merge pull request #26698 from warped-rudi:mediandk2

AndroidMediaNdkVideoWriter pixel format enhancement #26698

* videoio(Android): Add source pixel formats RGBA and GRAY to AndroidMediaNdkVideoWriter

Let AndroidMediaNdkVideoWriter::write() deduce source pixel format from matrix type:

CV_8UC3 -> BGR   (as before)
CV_8UC4 -> RGBA  (use in conjunction with CvCameraViewFrame)
CV_8UC1 -> GRAY

* samples/android/video-recorder: Send images to VideoWriter in RGBA format

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x ] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
Rüdiger Ihle 2025-01-03 15:53:00 +01:00 committed by GitHub
parent f65006eee1
commit a6f72f813d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 41 additions and 28 deletions

View File

@ -551,10 +551,12 @@ public:
}
Mat image = image_.getMat();
if (CV_8UC3 != image.type() || image.cols > width || image.rows > height) {
if (image.cols > width || image.rows > height ||
(CV_8UC1 != image.type() && CV_8UC3 != image.type() && CV_8UC4 != image.type())) {
LOGE(
"Expected input to be a mat of maximum %d x %d of type CV_8UC3 (%d), but received %d x %d of type: %d",
width, height, CV_8UC3,
"Expected input to be a mat of maximum %d x %d of type CV_8UC1, CV_8UC3 or CV_8UC4"
" (%d, %d, %d), but received %d x %d of type %d",
width, height, CV_8UC1, CV_8UC3, CV_8UC4,
image.cols, image.rows, image.type()
);
return;
@ -564,33 +566,45 @@ public:
ANativeWindow_Buffer buffer;
if (0 != ANativeWindow_lock(surface, &buffer, NULL)) {
LOGE("Failed to lock the surface");
} else {
if (AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM == buffer.format) {
Mat bufferMat(image.rows, image.cols, CV_8UC4, buffer.bits, buffer.stride * 4);
cvtColor(image, bufferMat, CV_BGR2RGBA);
} else {
LOGE("Unknow surface buffer format: %u", buffer.format);
}
ANativeWindow_unlockAndPost(surface);
return;
}
#else
LOGV("[write] image: %d x %d", image.cols, image.rows);
//OpenCV don't support RGB to NV12 so we need to connvert to YV12 and then manually changed it to NV12
if (AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM == buffer.format) {
Mat bufferMat(image.rows, image.cols, CV_8UC4, buffer.bits, buffer.stride * 4);
switch (image.type()) {
case CV_8UC4: image.copyTo(bufferMat); break;
case CV_8UC3: cvtColor(image, bufferMat, CV_BGR2RGBA); break;
case CV_8UC1: cvtColor(image, bufferMat, CV_GRAY2RGBA); break;
}
} else {
LOGE("Unknown surface buffer format: 0x%x", buffer.format);
}
ANativeWindow_unlockAndPost(surface);
#else
//OpenCV doesn't support RGB to NV12 so we need to convert to YV12 and then manually changed it to NV12
Mat imageYV12;
cvtColor(image, imageYV12, CV_BGR2YUV_YV12);
switch (image.type()) {
case CV_8UC4: cvtColor(image, imageYV12, CV_RGBA2YUV_YV12); break;
case CV_8UC3: cvtColor(image, imageYV12, CV_BGR2YUV_YV12); break;
case CV_8UC1: imageYV12.create(image.rows + image.rows/2, image.cols, CV_8UC1);
image.copyTo(imageYV12.rowRange(0, image.rows));
imageYV12.rowRange(image.rows, imageYV12.rows) = 128;
break;
}
//convert from YV12 to NV12
size_t yPlaneSize = width * height;
size_t vPlaneSize = yPlaneSize / 4;
if (image.type() != CV_8UC1) {
size_t yPlaneSize = width * height;
size_t vPlaneSize = yPlaneSize / 4;
Mat channels[2] = {
Mat( vPlaneSize, 1, CV_8UC1, imageYV12.ptr() + yPlaneSize + vPlaneSize ).clone(),
Mat( vPlaneSize, 1, CV_8UC1, imageYV12.ptr() + yPlaneSize ).clone()
};
Mat vuMat( vPlaneSize, 1, CV_8UC2, imageYV12.ptr() + yPlaneSize );
merge(channels, 2, vuMat);
Mat channels[2] = {
Mat( vPlaneSize, 1, CV_8UC1, imageYV12.ptr() + yPlaneSize + vPlaneSize ).clone(),
Mat( vPlaneSize, 1, CV_8UC1, imageYV12.ptr() + yPlaneSize ).clone()
};
Mat vuMat( vPlaneSize, 1, CV_8UC2, imageYV12.ptr() + yPlaneSize );
merge(channels, 2, vuMat);
}
writeBytes( imageYV12.ptr(), imageYV12.rows * imageYV12.cols );
#endif

View File

@ -164,16 +164,15 @@ public class RecorderActivity extends CameraActivity implements CvCameraViewList
{
Log.d(TAG, "Camera frame arrived");
Mat rgbMat = inputFrame.rgba();
mVideoFrame = inputFrame.rgba();
Log.d(TAG, "Size: " + rgbMat.width() + "x" + rgbMat.height());
Log.d(TAG, "Size: " + mVideoFrame.width() + "x" + mVideoFrame.height());
if (mVideoWriter != null && mVideoWriter.isOpened()) {
Imgproc.cvtColor(rgbMat, mVideoFrame, Imgproc.COLOR_RGBA2BGR);
mVideoWriter.write(mVideoFrame);
}
return rgbMat;
return mVideoFrame;
}
@Override