Merge pull request #22227 from danopdev:issue-22198

Fix issues: #22214 and #22198
This commit is contained in:
Alexander Smorkalov 2022-09-14 19:59:08 +03:00 committed by GitHub
commit e1272d73fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -48,15 +48,29 @@ class AndroidMediaNdkCapture : public IVideoCapture
public: public:
AndroidMediaNdkCapture(): AndroidMediaNdkCapture():
sawInputEOS(false), sawOutputEOS(false), sawInputEOS(false), sawOutputEOS(false),
frameWidth(0), frameHeight(0), colorFormat(0) {} frameStride(0), frameWidth(0), frameHeight(0), colorFormat(0),
videoWidth(0), videoHeight(0),
videoFrameCount(0),
videoRotation(0), videoRotationCode(-1),
videoOrientationAuto(false) {}
std::shared_ptr<AMediaExtractor> mediaExtractor; std::shared_ptr<AMediaExtractor> mediaExtractor;
std::shared_ptr<AMediaCodec> mediaCodec; std::shared_ptr<AMediaCodec> mediaCodec;
bool sawInputEOS; bool sawInputEOS;
bool sawOutputEOS; bool sawOutputEOS;
int32_t frameStride;
int32_t frameWidth; int32_t frameWidth;
int32_t frameHeight; int32_t frameHeight;
int32_t colorFormat; int32_t colorFormat;
int32_t videoWidth;
int32_t videoHeight;
float videoFrameRate;
int32_t videoFrameCount;
int32_t videoRotation;
int32_t videoRotationCode;
bool videoOrientationAuto;
std::vector<uint8_t> buffer; std::vector<uint8_t> buffer;
Mat frame;
~AndroidMediaNdkCapture() { cleanUp(); } ~AndroidMediaNdkCapture() { cleanUp(); }
@ -89,6 +103,7 @@ public:
size_t bufferSize = 0; size_t bufferSize = 0;
auto mediaFormat = std::shared_ptr<AMediaFormat>(AMediaCodec_getOutputFormat(mediaCodec.get()), deleter_AMediaFormat); auto mediaFormat = std::shared_ptr<AMediaFormat>(AMediaCodec_getOutputFormat(mediaCodec.get()), deleter_AMediaFormat);
AMediaFormat_getInt32(mediaFormat.get(), AMEDIAFORMAT_KEY_WIDTH, &frameWidth); AMediaFormat_getInt32(mediaFormat.get(), AMEDIAFORMAT_KEY_WIDTH, &frameWidth);
AMediaFormat_getInt32(mediaFormat.get(), AMEDIAFORMAT_KEY_STRIDE, &frameStride);
AMediaFormat_getInt32(mediaFormat.get(), AMEDIAFORMAT_KEY_HEIGHT, &frameHeight); AMediaFormat_getInt32(mediaFormat.get(), AMEDIAFORMAT_KEY_HEIGHT, &frameHeight);
AMediaFormat_getInt32(mediaFormat.get(), AMEDIAFORMAT_KEY_COLOR_FORMAT, &colorFormat); AMediaFormat_getInt32(mediaFormat.get(), AMEDIAFORMAT_KEY_COLOR_FORMAT, &colorFormat);
uint8_t* codecBuffer = AMediaCodec_getOutputBuffer(mediaCodec.get(), bufferIndex, &bufferSize); uint8_t* codecBuffer = AMediaCodec_getOutputBuffer(mediaCodec.get(), bufferIndex, &bufferSize);
@ -96,30 +111,14 @@ public:
LOGV("colorFormat: %d", colorFormat); LOGV("colorFormat: %d", colorFormat);
LOGV("buffer size: %zu", bufferSize); LOGV("buffer size: %zu", bufferSize);
LOGV("width (frame): %d", frameWidth); LOGV("width (frame): %d", frameWidth);
LOGV("stride (frame): %d", frameStride);
LOGV("height (frame): %d", frameHeight); LOGV("height (frame): %d", frameHeight);
if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM)
{ {
LOGV("output EOS"); LOGV("output EOS");
sawOutputEOS = true; sawOutputEOS = true;
} }
if ((size_t)frameWidth * frameHeight * 3 / 2 > bufferSize)
{
if (bufferSize == 3110400 && frameWidth == 1920 && frameHeight == 1088)
{
frameHeight = 1080;
LOGV("Buffer size is too small, force using height = %d", frameHeight);
}
else if(bufferSize == 3110400 && frameWidth == 1088 && frameHeight == 1920)
{
frameWidth = 1080;
LOGV("Buffer size is too small, force using width = %d", frameWidth);
}
else
{
LOGE("Buffer size is too small. Frame is ignored. Enable verbose logging to see actual values of parameters");
return false;
}
}
AMediaCodec_releaseOutputBuffer(mediaCodec.get(), bufferIndex, info.size != 0); AMediaCodec_releaseOutputBuffer(mediaCodec.get(), bufferIndex, info.size != 0);
return true; return true;
} else if (bufferIndex == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) { } else if (bufferIndex == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
@ -154,15 +153,25 @@ public:
if (buffer.empty()) { if (buffer.empty()) {
return false; return false;
} }
Mat yuv(frameHeight + frameHeight/2, frameWidth, CV_8UC1, buffer.data());
Mat yuv(frameHeight + frameHeight/2, frameStride, CV_8UC1, buffer.data());
if (colorFormat == COLOR_FormatYUV420Planar) { if (colorFormat == COLOR_FormatYUV420Planar) {
cv::cvtColor(yuv, out, cv::COLOR_YUV2BGR_YV12); cv::cvtColor(yuv, frame, cv::COLOR_YUV2BGR_YV12);
} else if (colorFormat == COLOR_FormatYUV420SemiPlanar) { } else if (colorFormat == COLOR_FormatYUV420SemiPlanar) {
cv::cvtColor(yuv, out, cv::COLOR_YUV2BGR_NV21); cv::cvtColor(yuv, frame, cv::COLOR_YUV2BGR_NV21);
} else { } else {
LOGE("Unsupported video format: %d", colorFormat); LOGE("Unsupported video format: %d", colorFormat);
return false; return false;
} }
Mat croppedFrame = frame(Rect(0, 0, videoWidth, videoHeight));
out.assign(croppedFrame);
if (videoOrientationAuto && -1 != videoRotationCode) {
cv::rotate(out, out, videoRotationCode);
}
return true; return true;
} }
@ -170,14 +179,32 @@ public:
{ {
switch (property_id) switch (property_id)
{ {
case CV_CAP_PROP_FRAME_WIDTH: return frameWidth; case CV_CAP_PROP_FRAME_WIDTH:
case CV_CAP_PROP_FRAME_HEIGHT: return frameHeight; return (( videoOrientationAuto &&
(cv::ROTATE_90_CLOCKWISE == videoRotationCode || cv::ROTATE_90_COUNTERCLOCKWISE == videoRotationCode))
? videoHeight : videoWidth);
case CV_CAP_PROP_FRAME_HEIGHT:
return (( videoOrientationAuto &&
(cv::ROTATE_90_CLOCKWISE == videoRotationCode || cv::ROTATE_90_COUNTERCLOCKWISE == videoRotationCode))
? videoWidth : videoHeight);
case CV_CAP_PROP_FPS: return videoFrameRate;
case CV_CAP_PROP_FRAME_COUNT: return videoFrameCount;
case CAP_PROP_ORIENTATION_META: return videoRotation;
case CAP_PROP_ORIENTATION_AUTO: return videoOrientationAuto ? 1 : 0;
} }
return 0; return 0;
} }
bool setProperty(int /* property_id */, double /* value */) CV_OVERRIDE bool setProperty(int property_id, double value) CV_OVERRIDE
{ {
switch (property_id)
{
case CAP_PROP_ORIENTATION_AUTO: {
videoOrientationAuto = value != 0 ? true : false;
return true;
}
}
return false; return false;
} }
@ -221,9 +248,20 @@ public:
if (!AMediaFormat_getString(format.get(), AMEDIAFORMAT_KEY_MIME, &mime)) { if (!AMediaFormat_getString(format.get(), AMEDIAFORMAT_KEY_MIME, &mime)) {
LOGV("no mime type"); LOGV("no mime type");
} else if (!strncmp(mime, "video/", 6)) { } else if (!strncmp(mime, "video/", 6)) {
int32_t trackWidth, trackHeight; int32_t trackWidth, trackHeight, fps, frameCount = 0, rotation = 0;
AMediaFormat_getInt32(format.get(), AMEDIAFORMAT_KEY_WIDTH, &trackWidth); AMediaFormat_getInt32(format.get(), AMEDIAFORMAT_KEY_WIDTH, &trackWidth);
AMediaFormat_getInt32(format.get(), AMEDIAFORMAT_KEY_HEIGHT, &trackHeight); AMediaFormat_getInt32(format.get(), AMEDIAFORMAT_KEY_HEIGHT, &trackHeight);
AMediaFormat_getInt32(format.get(), AMEDIAFORMAT_KEY_FRAME_RATE, &fps);
#if __ANDROID_API__ >= 28
AMediaFormat_getInt32(format.get(), AMEDIAFORMAT_KEY_ROTATION, &rotation);
LOGV("rotation (track): %d", rotation);
#endif
#if __ANDROID_API__ >= 29
AMediaFormat_getInt32(format.get(), AMEDIAFORMAT_KEY_FRAME_COUNT, &frameCount);
#endif
LOGV("width (track): %d", trackWidth); LOGV("width (track): %d", trackWidth);
LOGV("height (track): %d", trackHeight); LOGV("height (track): %d", trackHeight);
if (AMediaExtractor_selectTrack(mediaExtractor.get(), i) != AMEDIA_OK) { if (AMediaExtractor_selectTrack(mediaExtractor.get(), i) != AMEDIA_OK) {
@ -241,6 +279,31 @@ public:
if (AMediaCodec_start(mediaCodec.get()) != AMEDIA_OK) { if (AMediaCodec_start(mediaCodec.get()) != AMEDIA_OK) {
continue; continue;
} }
videoWidth = trackWidth;
videoHeight = trackHeight;
videoFrameRate = fps;
videoFrameCount = frameCount;
videoRotation = rotation;
switch(videoRotation) {
case 90:
videoRotationCode = cv::ROTATE_90_CLOCKWISE;
break;
case 180:
videoRotationCode = cv::ROTATE_180;
break;
case 270:
videoRotationCode = cv::ROTATE_90_COUNTERCLOCKWISE;
break;
default:
videoRotationCode = -1;
break;
}
return true; return true;
} }
} }
@ -251,9 +314,16 @@ public:
void cleanUp() { void cleanUp() {
sawInputEOS = true; sawInputEOS = true;
sawOutputEOS = true; sawOutputEOS = true;
frameStride = 0;
frameWidth = 0; frameWidth = 0;
frameHeight = 0; frameHeight = 0;
colorFormat = 0; colorFormat = 0;
videoWidth = 0;
videoHeight = 0;
videoFrameRate = 0;
videoFrameCount = 0;
videoRotation = 0;
videoRotationCode = -1;
} }
}; };