From 0c79f4a00f8043a3e824067c24c6bf371114e468 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Thu, 26 Oct 2017 15:03:53 +0300 Subject: [PATCH] MediaSDK: fixed Linux build, improved BGR<->NV12 conversions --- .../include/opencv2/imgproc/hal/hal.hpp | 12 ++ modules/imgproc/src/color.cpp | 152 +++++++++++------- modules/videoio/src/cap_mfx_common.cpp | 1 - modules/videoio/src/cap_mfx_common.hpp | 1 + modules/videoio/src/cap_mfx_reader.cpp | 13 +- modules/videoio/src/cap_mfx_writer.cpp | 33 +--- 6 files changed, 116 insertions(+), 96 deletions(-) diff --git a/modules/imgproc/include/opencv2/imgproc/hal/hal.hpp b/modules/imgproc/include/opencv2/imgproc/hal/hal.hpp index 5523df27d9..a435fd6b85 100644 --- a/modules/imgproc/include/opencv2/imgproc/hal/hal.hpp +++ b/modules/imgproc/include/opencv2/imgproc/hal/hal.hpp @@ -192,6 +192,12 @@ CV_EXPORTS void cvtTwoPlaneYUVtoBGR(const uchar * src_data, size_t src_step, int dst_width, int dst_height, int dcn, bool swapBlue, int uIdx); +//! Separate Y and UV planes +CV_EXPORTS void cvtTwoPlaneYUVtoBGR(const uchar * y_data, const uchar * uv_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int dst_width, int dst_height, + int dcn, bool swapBlue, int uIdx); + CV_EXPORTS void cvtThreePlaneYUVtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int dst_width, int dst_height, @@ -202,6 +208,12 @@ CV_EXPORTS void cvtBGRtoThreePlaneYUV(const uchar * src_data, size_t src_step, int width, int height, int scn, bool swapBlue, int uIdx); +//! Separate Y and UV planes +CV_EXPORTS void cvtBGRtoTwoPlaneYUV(const uchar * src_data, size_t src_step, + uchar * y_data, uchar * uv_data, size_t dst_step, + int width, int height, + int scn, bool swapBlue, int uIdx); + CV_EXPORTS void cvtOnePlaneYUVtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, diff --git a/modules/imgproc/src/color.cpp b/modules/imgproc/src/color.cpp index 370cf4d1f8..7a28300f77 100644 --- a/modules/imgproc/src/color.cpp +++ b/modules/imgproc/src/color.cpp @@ -9050,44 +9050,60 @@ inline void cvtYUV420p2RGBA(uchar * dst_data, size_t dst_step, int dst_width, in ///////////////////////////////////// RGB -> YUV420p ///////////////////////////////////// -template -inline void swapUV(uchar * &, uchar * &) {} -template<> -inline void swapUV<2>(uchar * & u, uchar * & v) { std::swap(u, v); } - -template struct RGB888toYUV420pInvoker: public ParallelLoopBody { - RGB888toYUV420pInvoker(const uchar * _src_data, size_t _src_step, uchar * _dst_data, size_t _dst_step, - int _src_width, int _src_height, int _scn) + RGB888toYUV420pInvoker(const uchar * _src_data, size_t _src_step, + uchar * _y_data, uchar * _uv_data, size_t _dst_step, + int _src_width, int _src_height, int _scn, bool swapBlue_, bool swapUV_, bool interleaved_) : src_data(_src_data), src_step(_src_step), - dst_data(_dst_data), dst_step(_dst_step), + y_data(_y_data), uv_data(_uv_data), dst_step(_dst_step), src_width(_src_width), src_height(_src_height), - scn(_scn) { } + scn(_scn), swapBlue(swapBlue_), swapUV(swapUV_), interleaved(interleaved_) { } void operator()(const Range& rowRange) const { const int w = src_width; const int h = src_height; - const int cn = scn; for( int i = rowRange.start; i < rowRange.end; i++ ) { - const uchar* row0 = src_data + src_step * (2 * i); - const uchar* row1 = src_data + src_step * (2 * i + 1); + const uchar* brow0 = src_data + src_step * (2 * i); + const uchar* grow0 = brow0 + 1; + const uchar* rrow0 = brow0 + 2; + const uchar* brow1 = src_data + src_step * (2 * i + 1); + const uchar* grow1 = brow1 + 1; + const uchar* rrow1 = brow1 + 2; + if (swapBlue) + { + std::swap(brow0, rrow0); + std::swap(brow1, rrow1); + } - uchar* y = dst_data + dst_step * (2*i); - uchar* u = dst_data + dst_step * (h + i/2) + (i % 2) * (w/2); - uchar* v = dst_data + dst_step * (h + (i + h/2)/2) + ((i + h/2) % 2) * (w/2); + uchar* y = y_data + dst_step * (2*i); + uchar* u; + uchar* v; + if (interleaved) + { + u = uv_data + dst_step * i; + v = uv_data + dst_step * i + 1; + } + else + { + u = uv_data + dst_step * (i/2) + (i % 2) * (w/2); + v = uv_data + dst_step * ((i + h/2)/2) + ((i + h/2) % 2) * (w/2); + } - swapUV(u, v); + if (swapUV) + { + std::swap(u, v); + } for( int j = 0, k = 0; j < w * cn; j += 2 * cn, k++ ) { - int r00 = row0[2-bIdx + j]; int g00 = row0[1 + j]; int b00 = row0[bIdx + j]; - int r01 = row0[2-bIdx + cn + j]; int g01 = row0[1 + cn + j]; int b01 = row0[bIdx + cn + j]; - int r10 = row1[2-bIdx + j]; int g10 = row1[1 + j]; int b10 = row1[bIdx + j]; - int r11 = row1[2-bIdx + cn + j]; int g11 = row1[1 + cn + j]; int b11 = row1[bIdx + cn + j]; + int r00 = rrow0[j]; int g00 = grow0[j]; int b00 = brow0[j]; + int r01 = rrow0[cn + j]; int g01 = grow0[cn + j]; int b01 = brow0[cn + j]; + int r10 = rrow1[j]; int g10 = grow1[j]; int b10 = brow1[j]; + int r11 = rrow1[cn + j]; int g11 = grow1[cn + j]; int b11 = brow1[cn + j]; const int shifted16 = (16 << ITUR_BT_601_SHIFT); const int halfShift = (1 << (ITUR_BT_601_SHIFT - 1)); @@ -9105,15 +9121,26 @@ struct RGB888toYUV420pInvoker: public ParallelLoopBody int u00 = ITUR_BT_601_CRU * r00 + ITUR_BT_601_CGU * g00 + ITUR_BT_601_CBU * b00 + halfShift + shifted128; int v00 = ITUR_BT_601_CBU * r00 + ITUR_BT_601_CGV * g00 + ITUR_BT_601_CBV * b00 + halfShift + shifted128; - u[k] = saturate_cast(u00 >> ITUR_BT_601_SHIFT); - v[k] = saturate_cast(v00 >> ITUR_BT_601_SHIFT); + if (interleaved) + { + u[k*2] = saturate_cast(u00 >> ITUR_BT_601_SHIFT); + v[k*2] = saturate_cast(v00 >> ITUR_BT_601_SHIFT); + } + else + { + u[k] = saturate_cast(u00 >> ITUR_BT_601_SHIFT); + v[k] = saturate_cast(v00 >> ITUR_BT_601_SHIFT); + } } } } - static bool isFit( int src_width, int src_height ) + void convert() const { - return (src_width * src_height >= 320*240); + if( src_width * src_height >= 320*240 ) + parallel_for_(Range(0, src_height/2), *this); + else + operator()(Range(0, src_height/2)); } private: @@ -9121,24 +9148,16 @@ private: const uchar * src_data; size_t src_step; - uchar * dst_data; + uchar *y_data, *uv_data; size_t dst_step; int src_width; int src_height; const int scn; + bool swapBlue; + bool swapUV; + bool interleaved; }; -template -static void cvtRGBtoYUV420p(const uchar * src_data, size_t src_step, - uchar * dst_data, size_t dst_step, - int src_width, int src_height, int scn) -{ - RGB888toYUV420pInvoker colorConverter(src_data, src_step, dst_data, dst_step, src_width, src_height, scn); - if( RGB888toYUV420pInvoker::isFit(src_width, src_height) ) - parallel_for_(Range(0, src_height/2), colorConverter); - else - colorConverter(Range(0, src_height/2)); -} ///////////////////////////////////// YUV422 -> RGB ///////////////////////////////////// @@ -10777,25 +10796,36 @@ void cvtLabtoBGR(const uchar * src_data, size_t src_step, } void cvtTwoPlaneYUVtoBGR(const uchar * src_data, size_t src_step, - uchar * dst_data, size_t dst_step, - int dst_width, int dst_height, - int dcn, bool swapBlue, int uIdx) + uchar * dst_data, size_t dst_step, + int dst_width, int dst_height, + int dcn, bool swapBlue, int uIdx) { - CV_INSTRUMENT_REGION() + CV_INSTRUMENT_REGION(); CALL_HAL(cvtTwoPlaneYUVtoBGR, cv_hal_cvtTwoPlaneYUVtoBGR, src_data, src_step, dst_data, dst_step, dst_width, dst_height, dcn, swapBlue, uIdx); - int blueIdx = swapBlue ? 2 : 0; const uchar* uv = src_data + src_step * static_cast(dst_height); + cvtTwoPlaneYUVtoBGR(src_data, uv, src_step, dst_data, dst_step, dst_width, dst_height, dcn, swapBlue, uIdx); +} + +void cvtTwoPlaneYUVtoBGR(const uchar * y_data, const uchar * uv_data, size_t src_step, + uchar * dst_data, size_t dst_step, + int dst_width, int dst_height, + int dcn, bool swapBlue, int uIdx) +{ + CV_INSTRUMENT_REGION(); + + // TODO: add hal replacement method + int blueIdx = swapBlue ? 2 : 0; switch(dcn*100 + blueIdx * 10 + uIdx) { - case 300: cvtYUV420sp2RGB<0, 0> (dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break; - case 301: cvtYUV420sp2RGB<0, 1> (dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break; - case 320: cvtYUV420sp2RGB<2, 0> (dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break; - case 321: cvtYUV420sp2RGB<2, 1> (dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break; - case 400: cvtYUV420sp2RGBA<0, 0>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break; - case 401: cvtYUV420sp2RGBA<0, 1>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break; - case 420: cvtYUV420sp2RGBA<2, 0>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break; - case 421: cvtYUV420sp2RGBA<2, 1>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break; + case 300: cvtYUV420sp2RGB<0, 0> (dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break; + case 301: cvtYUV420sp2RGB<0, 1> (dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break; + case 320: cvtYUV420sp2RGB<2, 0> (dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break; + case 321: cvtYUV420sp2RGB<2, 1> (dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break; + case 400: cvtYUV420sp2RGBA<0, 0>(dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break; + case 401: cvtYUV420sp2RGBA<0, 1>(dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break; + case 420: cvtYUV420sp2RGBA<2, 0>(dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break; + case 421: cvtYUV420sp2RGBA<2, 1>(dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break; default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break; }; } @@ -10835,15 +10865,19 @@ void cvtBGRtoThreePlaneYUV(const uchar * src_data, size_t src_step, CV_INSTRUMENT_REGION() CALL_HAL(cvtBGRtoThreePlaneYUV, cv_hal_cvtBGRtoThreePlaneYUV, src_data, src_step, dst_data, dst_step, width, height, scn, swapBlue, uIdx); - int blueIdx = swapBlue ? 2 : 0; - switch(blueIdx + uIdx*10) - { - case 10: cvtRGBtoYUV420p<0, 1>(src_data, src_step, dst_data, dst_step, width, height, scn); break; - case 12: cvtRGBtoYUV420p<2, 1>(src_data, src_step, dst_data, dst_step, width, height, scn); break; - case 20: cvtRGBtoYUV420p<0, 2>(src_data, src_step, dst_data, dst_step, width, height, scn); break; - case 22: cvtRGBtoYUV420p<2, 2>(src_data, src_step, dst_data, dst_step, width, height, scn); break; - default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break; - }; + uchar * uv_data = dst_data + dst_step * height; + RGB888toYUV420pInvoker(src_data, src_step, dst_data, uv_data, dst_step, width, height, scn, swapBlue, uIdx == 2, false).convert(); +} + +void cvtBGRtoTwoPlaneYUV(const uchar * src_data, size_t src_step, + uchar * y_data, uchar * uv_data, size_t dst_step, + int width, int height, + int scn, bool swapBlue, int uIdx) +{ + CV_INSTRUMENT_REGION(); + + // TODO: add hal replacement method + RGB888toYUV420pInvoker(src_data, src_step, y_data, uv_data, dst_step, width, height, scn, swapBlue, uIdx == 2, true).convert(); } void cvtOnePlaneYUVtoBGR(const uchar * src_data, size_t src_step, diff --git a/modules/videoio/src/cap_mfx_common.cpp b/modules/videoio/src/cap_mfx_common.cpp index 49fb847c3f..bc790a0e55 100644 --- a/modules/videoio/src/cap_mfx_common.cpp +++ b/modules/videoio/src/cap_mfx_common.cpp @@ -6,7 +6,6 @@ // Linux specific #ifdef __linux__ -#include #include #include #include diff --git a/modules/videoio/src/cap_mfx_common.hpp b/modules/videoio/src/cap_mfx_common.hpp index f18eafe92f..b4d2d9a2b6 100644 --- a/modules/videoio/src/cap_mfx_common.hpp +++ b/modules/videoio/src/cap_mfx_common.hpp @@ -288,6 +288,7 @@ protected: // Linux specific #ifdef __linux__ +#include #include class VAHandle : public DeviceHandler { diff --git a/modules/videoio/src/cap_mfx_reader.cpp b/modules/videoio/src/cap_mfx_reader.cpp index c926611940..f2ec1c42d4 100644 --- a/modules/videoio/src/cap_mfx_reader.cpp +++ b/modules/videoio/src/cap_mfx_reader.cpp @@ -5,6 +5,7 @@ #include "cap_mfx_reader.hpp" #include "opencv2/core/base.hpp" #include "cap_mfx_common.hpp" +#include "opencv2/imgproc/hal/hal.hpp" using namespace cv; using namespace std; @@ -243,17 +244,11 @@ bool VideoCapture_IntelMFX::retrieveFrame(int, OutputArray out) const int cols = info.CropW; const int rows = info.CropH; - Mat nv12(rows * 3 / 2, cols, CV_8UC1); - Mat Y(rows, cols, CV_8UC1, data.Y, data.Pitch); - Mat UV(rows / 2, cols, CV_8UC1, data.UV, data.Pitch); + out.create(rows, cols, CV_8UC3); + Mat res = out.getMat(); - Y.copyTo(Mat(nv12, Rect(0, 0, cols, rows))); - UV.copyTo(Mat(nv12, Rect(0, rows, cols, rows / 2))); - - Mat u_and_v[2]; - split(UV.reshape(2), u_and_v); - cvtColor(nv12, out, COLOR_YUV2BGR_NV12); + hal::cvtTwoPlaneYUVtoBGR(data.Y, data.UV, data.Pitch, res.data, res.step, cols, rows, 3, false, 0); return true; } diff --git a/modules/videoio/src/cap_mfx_writer.cpp b/modules/videoio/src/cap_mfx_writer.cpp index ccbf8e4a94..a8e2406156 100644 --- a/modules/videoio/src/cap_mfx_writer.cpp +++ b/modules/videoio/src/cap_mfx_writer.cpp @@ -5,6 +5,7 @@ #include "cap_mfx_writer.hpp" #include "opencv2/core/base.hpp" #include "cap_mfx_common.hpp" +#include "opencv2/imgproc/hal/hal.hpp" using namespace std; using namespace cv; @@ -166,26 +167,6 @@ void VideoWriter_IntelMFX::write(cv::InputArray input) write_one(input); } -inline static void to_nv12(cv::InputArray bgr, cv::Mat & Y, cv::Mat & UV) -{ - const int height = bgr.rows(); - const int width = bgr.cols(); - Mat yuv; - cvtColor(bgr, yuv, CV_BGR2YUV_I420); - CV_Assert(yuv.isContinuous()); - Mat Y_(Y, Rect(0, 0, width, height)); - yuv.rowRange(0, height).copyTo(Y_); - Mat UV_planar(height, width / 2, CV_8UC1, yuv.ptr(height)); - Mat u_and_v[2] = { - UV_planar.rowRange(0, height / 2), - UV_planar.rowRange(height / 2, height), - }; - Mat uv; - cv::merge(u_and_v, 2, uv); - Mat UV_(UV, Rect(0, 0, width, height / 2)); - uv.reshape(1).copyTo(UV_); -} - bool VideoWriter_IntelMFX::write_one(cv::InputArray bgr) { mfxStatus res; @@ -209,13 +190,11 @@ bool VideoWriter_IntelMFX::write_one(cv::InputArray bgr) MSG(cerr << "MFX: Failed to get free surface" << endl); return false; } - const int rows = workSurface->Info.Height; - const int cols = workSurface->Info.Width; - Mat Y(rows, cols, CV_8UC1, workSurface->Data.Y, workSurface->Data.Pitch); - Mat UV(rows / 2, cols, CV_8UC1, workSurface->Data.UV, workSurface->Data.Pitch); - to_nv12(bgr, Y, UV); - CV_Assert(Y.ptr() == workSurface->Data.Y); - CV_Assert(UV.ptr() == workSurface->Data.UV); + Mat src = bgr.getMat(); + hal::cvtBGRtoTwoPlaneYUV(src.data, src.step, + workSurface->Data.Y, workSurface->Data.UV, workSurface->Data.Pitch, + workSurface->Info.CropW, workSurface->Info.CropH, + 3, false, 1); } while (true)