MediaSDK: fixed Linux build, improved BGR<->NV12 conversions
authorMaksim Shabunin <maksim.shabunin@gmail.com>
Thu, 26 Oct 2017 12:03:53 +0000 (15:03 +0300)
committerMaksim Shabunin <maksim.shabunin@gmail.com>
Wed, 1 Nov 2017 11:14:45 +0000 (14:14 +0300)
modules/imgproc/include/opencv2/imgproc/hal/hal.hpp
modules/imgproc/src/color.cpp
modules/videoio/src/cap_mfx_common.cpp
modules/videoio/src/cap_mfx_common.hpp
modules/videoio/src/cap_mfx_reader.cpp
modules/videoio/src/cap_mfx_writer.cpp

index 5523df2..a435fd6 100644 (file)
@@ -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,
index 370cf4d..7a28300 100644 (file)
@@ -9050,44 +9050,60 @@ inline void cvtYUV420p2RGBA(uchar * dst_data, size_t dst_step, int dst_width, in
 
 ///////////////////////////////////// RGB -> YUV420p /////////////////////////////////////
 
-template<int uIdx>
-inline void swapUV(uchar * &, uchar * &) {}
-template<>
-inline void swapUV<2>(uchar * & u, uchar * & v) { std::swap(u, v); }
-
-template<int bIdx, int uIdx>
 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<uIdx>(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<uchar>(u00 >> ITUR_BT_601_SHIFT);
-                v[k] = saturate_cast<uchar>(v00 >> ITUR_BT_601_SHIFT);
+                if (interleaved)
+                {
+                    u[k*2] = saturate_cast<uchar>(u00 >> ITUR_BT_601_SHIFT);
+                    v[k*2] = saturate_cast<uchar>(v00 >> ITUR_BT_601_SHIFT);
+                }
+                else
+                {
+                    u[k] = saturate_cast<uchar>(u00 >> ITUR_BT_601_SHIFT);
+                    v[k] = saturate_cast<uchar>(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<int bIdx, int uIdx>
-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<bIdx, uIdx> colorConverter(src_data, src_step, dst_data, dst_step, src_width, src_height, scn);
-    if( RGB888toYUV420pInvoker<bIdx, uIdx>::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<size_t>(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,
index 49fb847..bc790a0 100644 (file)
@@ -6,7 +6,6 @@
 
 // Linux specific
 #ifdef __linux__
-#include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
index f18eafe..b4d2d9a 100644 (file)
@@ -288,6 +288,7 @@ protected:
 // Linux specific
 #ifdef __linux__
 
+#include <unistd.h>
 #include <va/va_drm.h>
 
 class VAHandle : public DeviceHandler {
index c926611..f2ec1c4 100644 (file)
@@ -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;
 }
index ccbf8e4..a8e2406 100644 (file)
@@ -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)