added VideoWriter_GPU
authorVladislav Vinogradov <no@email>
Tue, 17 Apr 2012 07:12:16 +0000 (07:12 +0000)
committerVladislav Vinogradov <no@email>
Tue, 17 Apr 2012 07:12:16 +0000 (07:12 +0000)
12 files changed:
3rdparty/ffmpeg/opencv_ffmpeg.dll
3rdparty/ffmpeg/opencv_ffmpeg_64.dll
modules/gpu/CMakeLists.txt
modules/gpu/include/opencv2/gpu/gpu.hpp
modules/gpu/src/cuda/rgb_to_yv12.cu [new file with mode: 0644]
modules/gpu/src/precomp.hpp
modules/gpu/src/video_writer.cpp [new file with mode: 0644]
modules/gpu/test/test_video.cpp
modules/highgui/src/cap_ffmpeg_api.hpp
modules/highgui/src/cap_ffmpeg_impl.hpp
modules/highgui/src/cap_ffmpeg_impl_v2.hpp
samples/gpu/video_writer.cpp [new file with mode: 0644]

index f2691ac..eb02a95 100644 (file)
Binary files a/3rdparty/ffmpeg/opencv_ffmpeg.dll and b/3rdparty/ffmpeg/opencv_ffmpeg.dll differ
index 7407c05..cd3c499 100644 (file)
Binary files a/3rdparty/ffmpeg/opencv_ffmpeg_64.dll and b/3rdparty/ffmpeg/opencv_ffmpeg_64.dll differ
index bc16c5b..2a4e6e3 100644 (file)
@@ -7,6 +7,8 @@ ocv_add_module(gpu opencv_imgproc opencv_calib3d opencv_objdetect opencv_video o
 
 ocv_module_include_directories("${CMAKE_CURRENT_SOURCE_DIR}/src/cuda")
 
+ocv_module_include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../highgui/src")
+
 file(GLOB lib_hdrs               "include/opencv2/${name}/*.hpp" "include/opencv2/${name}/*.h")
 file(GLOB lib_int_hdrs           "src/*.hpp" "src/*.h")
 file(GLOB lib_cuda_hdrs          "src/cuda/*.hpp" "src/cuda/*.h")
@@ -48,7 +50,19 @@ if (HAVE_CUDA)
   OCV_CUDA_COMPILE(cuda_objs ${lib_cuda} ${ncv_cuda})
   #CUDA_BUILD_CLEAN_TARGET()
   
-  set(cuda_link_libs ${CUDA_LIBRARIES} ${CUDA_npp_LIBRARY})
+  unset(CUDA_nvcuvid_LIBRARY CACHE)
+  find_cuda_helper_libs(nvcuvid)
+
+  if (WIN32)
+    unset(CUDA_nvcuvenc_LIBRARY CACHE)
+    find_cuda_helper_libs(nvcuvenc)
+  endif()
+  
+  set(cuda_link_libs ${CUDA_LIBRARIES} ${CUDA_npp_LIBRARY} ${CUDA_nvcuvid_LIBRARY})
+
+  if (WIN32)
+    set(cuda_link_libs ${cuda_link_libs} ${CUDA_nvcuvenc_LIBRARY})
+  endif()
 else()
   set(lib_cuda "")
   set(cuda_objs "")
@@ -61,7 +75,7 @@ ocv_set_module_sources(
   SOURCES ${lib_int_hdrs} ${lib_cuda_hdrs} ${lib_device_hdrs} ${lib_device_hdrs_detail} ${lib_srcs} ${lib_cuda} ${ncv_files} ${cuda_objs}
   )
   
-ocv_create_module(${cuda_link_libs})
+ocv_create_module(${cuda_link_libs} ${HIGHGUI_LIBRARIES})
   
 if(HAVE_CUDA)
   if(HAVE_CUFFT)
index b1b63b0..6c60958 100644 (file)
@@ -45,6 +45,7 @@
 \r
 #ifndef SKIP_INCLUDES\r
 #include <vector>\r
+#include <memory>\r
 #endif\r
 \r
 #include "opencv2/core/gpumat.hpp"\r
@@ -1884,6 +1885,100 @@ CV_EXPORTS void interpolateFrames(const GpuMat& frame0, const GpuMat& frame1,
 \r
 CV_EXPORTS void createOpticalFlowNeedleMap(const GpuMat& u, const GpuMat& v, GpuMat& vertex, GpuMat& colors);\r
 \r
+\r
+////////////////////////////////// Video Encoding //////////////////////////////////////////\r
+\r
+// Works only under Windows\r
+// Supports olny H264 video codec and AVI files\r
+class CV_EXPORTS VideoWriter_GPU\r
+{\r
+public:\r
+    struct EncoderParams;\r
+\r
+    // Callbacks for video encoder, use it if you want to work with raw video stream\r
+    class EncoderCallBack;\r
+\r
+    VideoWriter_GPU();\r
+    VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps);\r
+    VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params);\r
+    VideoWriter_GPU(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps);\r
+    VideoWriter_GPU(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params);\r
+    ~VideoWriter_GPU();\r
+\r
+    // all methods throws cv::Exception if error occurs\r
+    void open(const std::string& fileName, cv::Size frameSize, double fps);\r
+    void open(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params);\r
+    void open(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps);\r
+    void open(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params);\r
+\r
+    bool isOpened() const;\r
+    void close();\r
+\r
+    void write(const cv::gpu::GpuMat& image, bool lastFrame = false);\r
+\r
+    struct EncoderParams\r
+    {\r
+        int       P_Interval;      //    NVVE_P_INTERVAL,\r
+        int       IDR_Period;      //    NVVE_IDR_PERIOD,\r
+        int       DynamicGOP;      //    NVVE_DYNAMIC_GOP,\r
+        int       RCType;          //    NVVE_RC_TYPE,\r
+        int       AvgBitrate;      //    NVVE_AVG_BITRATE,\r
+        int       PeakBitrate;     //    NVVE_PEAK_BITRATE,\r
+        int       QP_Level_Intra;  //    NVVE_QP_LEVEL_INTRA,\r
+        int       QP_Level_InterP; //    NVVE_QP_LEVEL_INTER_P,\r
+        int       QP_Level_InterB; //    NVVE_QP_LEVEL_INTER_B,\r
+        int       DeblockMode;     //    NVVE_DEBLOCK_MODE,\r
+        int       ProfileLevel;    //    NVVE_PROFILE_LEVEL,\r
+        int       ForceIntra;      //    NVVE_FORCE_INTRA,\r
+        int       ForceIDR;        //    NVVE_FORCE_IDR,\r
+        int       ClearStat;       //    NVVE_CLEAR_STAT,\r
+        int       DIMode;          //    NVVE_SET_DEINTERLACE,\r
+        int       Presets;         //    NVVE_PRESETS,\r
+        int       DisableCabac;    //    NVVE_DISABLE_CABAC,\r
+        int       NaluFramingType; //    NVVE_CONFIGURE_NALU_FRAMING_TYPE\r
+        int       DisableSPSPPS;   //    NVVE_DISABLE_SPS_PPS\r
+\r
+        EncoderParams();\r
+        explicit EncoderParams(const std::string& configFile);\r
+\r
+        void load(const std::string& configFile);\r
+        void save(const std::string& configFile) const;\r
+    };\r
+\r
+    class EncoderCallBack\r
+    {\r
+    public:\r
+        enum PicType\r
+        {\r
+            IFRAME = 1,\r
+            PFRAME = 2,\r
+            BFRAME = 3\r
+        };\r
+\r
+        virtual ~EncoderCallBack() {}\r
+\r
+        // callback function to signal the start of bitstream that is to be encoded\r
+        // must return pointer to buffer\r
+        virtual unsigned char* acquireBitStream(int* bufferSize) = 0;\r
+\r
+        // callback function to signal that the encoded bitstream is ready to be written to file\r
+        virtual void releaseBitStream(unsigned char* data, int size) = 0;\r
+\r
+        // callback function to signal that the encoding operation on the frame has started\r
+        virtual void onBeginFrame(int frameNumber, PicType picType) = 0;\r
+\r
+        // callback function signals that the encoding operation on the frame has finished\r
+        virtual void onEndFrame(int frameNumber, PicType picType) = 0;\r
+    };\r
+\r
+private:\r
+    VideoWriter_GPU(const VideoWriter_GPU&);\r
+    VideoWriter_GPU& operator=(const VideoWriter_GPU&);\r
+\r
+    class Impl;\r
+    std::auto_ptr<Impl> impl_;\r
+};\r
+\r
 } // namespace gpu\r
 \r
 } // namespace cv\r
diff --git a/modules/gpu/src/cuda/rgb_to_yv12.cu b/modules/gpu/src/cuda/rgb_to_yv12.cu
new file mode 100644 (file)
index 0000000..abf5949
--- /dev/null
@@ -0,0 +1,171 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////\r
+//\r
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.\r
+//\r
+//  By downloading, copying, installing or using the software you agree to this license.\r
+//  If you do not agree to this license, do not download, install,\r
+//  copy or use the software.\r
+//\r
+//\r
+//                           License Agreement\r
+//                For Open Source Computer Vision Library\r
+//\r
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.\r
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.\r
+// Third party copyrights are property of their respective owners.\r
+//\r
+// Redistribution and use in source and binary forms, with or without modification,\r
+// are permitted provided that the following conditions are met:\r
+//\r
+//   * Redistribution's of source code must retain the above copyright notice,\r
+//     this list of conditions and the following disclaimer.\r
+//\r
+//   * Redistribution's in binary form must reproduce the above copyright notice,\r
+//     this list of conditions and the following disclaimer in the documentation\r
+//     and/or other materials provided with the distribution.\r
+//\r
+//   * The name of the copyright holders may not be used to endorse or promote products\r
+//     derived from this software without specific prior written permission.\r
+//\r
+// This software is provided by the copyright holders and contributors "as is" and\r
+// any express or bpied warranties, including, but not limited to, the bpied\r
+// warranties of merchantability and fitness for a particular purpose are disclaimed.\r
+// In no event shall the Intel Corporation or contributors be liable for any direct,\r
+// indirect, incidental, special, exemplary, or consequential damages\r
+// (including, but not limited to, procurement of substitute goods or services;\r
+// loss of use, data, or profits; or business interruption) however caused\r
+// and on any theory of liability, whether in contract, strict liability,\r
+// or tort (including negligence or otherwise) arising in any way out of\r
+// the use of this software, even if advised of the possibility of such damage.\r
+//\r
+//M*/\r
+\r
+#include "opencv2/gpu/device/common.hpp"\r
+#include "opencv2/gpu/device/vec_traits.hpp"\r
+\r
+namespace cv { namespace gpu { namespace device \r
+{\r
+    namespace video_encoding\r
+    {\r
+        __device__ __forceinline__ void rgbtoy(const uchar b, const uchar g, const uchar r, uchar& y)\r
+        {\r
+            y = static_cast<uchar>(((int)(30 * r) + (int)(59 * g) + (int)(11 * b)) / 100);\r
+        }\r
+\r
+        __device__ __forceinline__ void rgbtoyuv(const uchar b, const uchar g, const uchar r, uchar& y, uchar& u, uchar& v)\r
+        {\r
+            rgbtoy(b, g, r, y);\r
+            u = static_cast<uchar>(((int)(-17 * r) - (int)(33 * g) + (int)(50 * b) + 12800) / 100);\r
+            v = static_cast<uchar>(((int)(50 * r) - (int)(42 * g) - (int)(8 * b) + 12800) / 100);\r
+        }\r
+\r
+        __global__ void Gray_to_YV12(const DevMem2Db src, PtrStepb dst)\r
+        {\r
+            const int x = (blockIdx.x * blockDim.x + threadIdx.x) * 2;\r
+            const int y = (blockIdx.y * blockDim.y + threadIdx.y) * 2;\r
+\r
+            if (x + 1 >= src.cols || y + 1 >= src.rows)\r
+                return;\r
+\r
+            // get pointers to the data\r
+            const size_t planeSize = src.rows * dst.step;\r
+            PtrStepb y_plane(dst.data, dst.step);\r
+            PtrStepb u_plane(y_plane.data + planeSize, dst.step / 2);\r
+            PtrStepb v_plane(u_plane.data + (planeSize / 4), dst.step / 2);\r
+\r
+            uchar pix;\r
+            uchar y_val, u_val, v_val;\r
+\r
+            pix = src(y, x);\r
+            rgbtoy(pix, pix, pix, y_val);\r
+            y_plane(y, x) = y_val;\r
+\r
+            pix = src(y, x + 1);\r
+            rgbtoy(pix, pix, pix, y_val);\r
+            y_plane(y, x + 1) = y_val;\r
+\r
+            pix = src(y + 1, x);\r
+            rgbtoy(pix, pix, pix, y_val);\r
+            y_plane(y + 1, x) = y_val;\r
+\r
+            pix = src(y + 1, x + 1);\r
+            rgbtoyuv(pix, pix, pix, y_val, u_val, v_val);\r
+            y_plane(y + 1, x + 1) = y_val;\r
+            u_plane(y / 2, x / 2) = u_val;\r
+            v_plane(y / 2, x / 2) = v_val;\r
+        }\r
+\r
+        template <typename T>\r
+        __global__ void BGR_to_YV12(const DevMem2D_<T> src, PtrStepb dst)\r
+        {\r
+            const int x = (blockIdx.x * blockDim.x + threadIdx.x) * 2;\r
+            const int y = (blockIdx.y * blockDim.y + threadIdx.y) * 2;\r
+\r
+            if (x + 1 >= src.cols || y + 1 >= src.rows)\r
+                return;\r
+\r
+            // get pointers to the data\r
+            const size_t planeSize = src.rows * dst.step;\r
+            PtrStepb y_plane(dst.data, dst.step);\r
+            PtrStepb u_plane(y_plane.data + planeSize, dst.step / 2);\r
+            PtrStepb v_plane(u_plane.data + (planeSize / 4), dst.step / 2);\r
+\r
+            T pix;\r
+            uchar y_val, u_val, v_val;\r
+\r
+            pix = src(y, x);\r
+            rgbtoy(pix.z, pix.y, pix.x, y_val);\r
+            y_plane(y, x) = y_val;\r
+\r
+            pix = src(y, x + 1);\r
+            rgbtoy(pix.z, pix.y, pix.x, y_val);\r
+            y_plane(y, x + 1) = y_val;\r
+\r
+            pix = src(y + 1, x);\r
+            rgbtoy(pix.z, pix.y, pix.x, y_val);\r
+            y_plane(y + 1, x) = y_val;\r
+\r
+            pix = src(y + 1, x + 1);\r
+            rgbtoyuv(pix.z, pix.y, pix.x, y_val, u_val, v_val);\r
+            y_plane(y + 1, x + 1) = y_val;\r
+            u_plane(y / 2, x / 2) = u_val;\r
+            v_plane(y / 2, x / 2) = v_val;\r
+        }\r
+\r
+        void Gray_to_YV12_caller(const DevMem2Db src, PtrStepb dst)\r
+        {\r
+            dim3 block(32, 8);\r
+            dim3 grid(divUp(src.cols, block.x * 2), divUp(src.rows, block.y * 2));\r
+\r
+            Gray_to_YV12<<<grid, block>>>(src, dst);\r
+            cudaSafeCall( cudaGetLastError() );\r
+\r
+            cudaSafeCall( cudaDeviceSynchronize() );\r
+        }\r
+        template <int cn>\r
+        void BGR_to_YV12_caller(const DevMem2Db src, PtrStepb dst)\r
+        {\r
+            typedef typename TypeVec<uchar, cn>::vec_type src_t;\r
+\r
+            dim3 block(32, 8);\r
+            dim3 grid(divUp(src.cols, block.x * 2), divUp(src.rows, block.y * 2));\r
+\r
+            BGR_to_YV12<<<grid, block>>>(static_cast< DevMem2D_<src_t> >(src), dst);\r
+            cudaSafeCall( cudaGetLastError() );\r
+\r
+            cudaSafeCall( cudaDeviceSynchronize() );\r
+        }\r
+\r
+        void YV12_gpu(const DevMem2Db src, int cn, DevMem2Db dst)\r
+        {\r
+            typedef void (*func_t)(const DevMem2Db src, PtrStepb dst);\r
+            \r
+            static const func_t funcs[] = \r
+            {\r
+                0, Gray_to_YV12_caller, 0, BGR_to_YV12_caller<3>, BGR_to_YV12_caller<4>\r
+            };\r
+            \r
+            funcs[cn](src, dst);\r
+        }\r
+    }\r
+}}}\r
index 6ee54cd..b95ea61 100644 (file)
 \r
 #ifdef HAVE_CUDA\r
 \r
-    #include "cuda.h"\r
-    #include "cuda_runtime_api.h"\r
-    #include "npp.h"\r
+    #include <cuda.h>\r
+    #include <cuda_runtime.h>\r
+    #include <npp.h>\r
 \r
     #ifdef HAVE_CUFFT\r
-        #include "cufft.h"\r
+        #include <cufft.h>\r
     #endif\r
 \r
     #ifdef HAVE_CUBLAS\r
-        #include "cublas.h"\r
+        #include <cublas.h>\r
+    #endif\r
+\r
+    #include <nvcuvid.h>\r
+\r
+    #ifdef WIN32\r
+        #include <NVEncoderAPI.h>\r
     #endif\r
 \r
     #include "internal_shared.hpp"\r
diff --git a/modules/gpu/src/video_writer.cpp b/modules/gpu/src/video_writer.cpp
new file mode 100644 (file)
index 0000000..4bacc0b
--- /dev/null
@@ -0,0 +1,724 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////\r
+//\r
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.\r
+//\r
+//  By downloading, copying, installing or using the software you agree to this license.\r
+//  If you do not agree to this license, do not download, install,\r
+//  copy or use the software.\r
+//\r
+//\r
+//                           License Agreement\r
+//                For Open Source Computer Vision Library\r
+//\r
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.\r
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.\r
+// Third party copyrights are property of their respective owners.\r
+//\r
+// Redistribution and use in source and binary forms, with or without modification,\r
+// are permitted provided that the following conditions are met:\r
+//\r
+//   * Redistribution's of source code must retain the above copyright notice,\r
+//     this list of conditions and the following disclaimer.\r
+//\r
+//   * Redistribution's in binary form must reproduce the above copyright notice,\r
+//     this list of conditions and the following disclaimer in the documentation\r
+//     and/or other materials provided with the distribution.\r
+//\r
+//   * The name of the copyright holders may not be used to endorse or promote products\r
+//     derived from this software without specific prior written permission.\r
+//\r
+// This software is provided by the copyright holders and contributors "as is" and\r
+// any express or implied warranties, including, but not limited to, the implied\r
+// warranties of merchantability and fitness for a particular purpose are disclaimed.\r
+// In no event shall the Intel Corporation or contributors be liable for any direct,\r
+// indirect, incidental, special, exemplary, or consequential damages\r
+// (including, but not limited to, procurement of substitute goods or services;\r
+// loss of use, data, or profits; or business interruption) however caused\r
+// and on any theory of liability, whether in contract, strict liability,\r
+// or tort (including negligence or otherwise) arising in any way out of\r
+// the use of this software, even if advised of the possibility of such damage.\r
+//\r
+//M*/\r
+\r
+#include "precomp.hpp"\r
+\r
+#if !defined HAVE_CUDA || !defined WIN32\r
+\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU() { throw_nogpu(); }\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string&, cv::Size, double) { throw_nogpu(); }\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string&, cv::Size, double, const EncoderParams&) { throw_nogpu(); }\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>&, cv::Size, double) { throw_nogpu(); }\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>&, cv::Size, double, const EncoderParams&) { throw_nogpu(); }\r
+cv::gpu::VideoWriter_GPU::~VideoWriter_GPU() {}\r
+void cv::gpu::VideoWriter_GPU::open(const std::string&, cv::Size, double) { throw_nogpu(); }\r
+void cv::gpu::VideoWriter_GPU::open(const std::string&, cv::Size, double, const EncoderParams&) { throw_nogpu(); }\r
+void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>&, cv::Size, double) { throw_nogpu(); }\r
+void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>&, cv::Size, double, const EncoderParams&) { throw_nogpu(); }\r
+bool cv::gpu::VideoWriter_GPU::isOpened() const { return false; }\r
+void cv::gpu::VideoWriter_GPU::close() {}\r
+void cv::gpu::VideoWriter_GPU::write(const cv::gpu::GpuMat&, bool) { throw_nogpu(); }\r
+\r
+cv::gpu::VideoWriter_GPU::EncoderParams::EncoderParams() { throw_nogpu(); }\r
+cv::gpu::VideoWriter_GPU::EncoderParams::EncoderParams(const std::string&) { throw_nogpu(); }\r
+void cv::gpu::VideoWriter_GPU::EncoderParams::load(const std::string&) { throw_nogpu(); }\r
+void cv::gpu::VideoWriter_GPU::EncoderParams::save(const std::string&) const { throw_nogpu(); }\r
+\r
+#else // !defined HAVE_CUDA || !defined WIN32\r
+\r
+#ifdef HAVE_FFMPEG\r
+    #ifdef NEW_FFMPEG\r
+        #include "cap_ffmpeg_impl_v2.hpp"\r
+    #else\r
+        #include "cap_ffmpeg_impl.hpp"\r
+    #endif\r
+#else\r
+    #include "cap_ffmpeg_api.hpp"\r
+#endif\r
+\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+// VideoWriter_GPU::Impl\r
+\r
+namespace\r
+{\r
+    class NVEncoderWrapper\r
+    {\r
+    public:\r
+        NVEncoderWrapper() : encoder_(0)\r
+        {\r
+            int err;\r
+\r
+            err = NVGetHWEncodeCaps();\r
+            if (err)\r
+                CV_Error(CV_GpuNotSupported, "No CUDA capability present");\r
+\r
+            // Create the Encoder API Interface\r
+            err = NVCreateEncoder(&encoder_);\r
+            CV_Assert( err == 0 );\r
+        }\r
+\r
+        ~NVEncoderWrapper()\r
+        {\r
+            if (encoder_)\r
+                NVDestroyEncoder(encoder_);\r
+        }\r
+\r
+        operator NVEncoder() const\r
+        {\r
+            return encoder_;\r
+        }\r
+\r
+    private:\r
+        NVEncoder encoder_;\r
+    };\r
+\r
+    enum CodecType\r
+    {\r
+        MPEG1, //not supported yet\r
+        MPEG2, //not supported yet\r
+        MPEG4, //not supported yet\r
+        H264\r
+    };\r
+}\r
+\r
+class cv::gpu::VideoWriter_GPU::Impl\r
+{\r
+public:\r
+    Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, CodecType codec = H264);\r
+    Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, const EncoderParams& params, CodecType codec = H264);\r
+\r
+    void write(const cv::gpu::GpuMat& image, bool lastFrame);\r
+\r
+private:\r
+    Impl(const Impl&);\r
+    Impl& operator=(const Impl&);\r
+\r
+    void initEncoder(double fps);\r
+    void setEncodeParams(const EncoderParams& params);\r
+    void initGpuMemory();\r
+    void initCallBacks();\r
+    void createHWEncoder();\r
+    \r
+    cv::Ptr<EncoderCallBack> callback_;\r
+    cv::Size frameSize_;\r
+\r
+    CodecType codec_;\r
+    NVVE_SurfaceFormat surfaceFormat_;\r
+\r
+    NVEncoderWrapper encoder_;\r
+\r
+    cv::gpu::GpuMat videoFrame_;\r
+    CUvideoctxlock cuCtxLock_;\r
+\r
+    // CallBacks\r
+\r
+    static unsigned char* NVENCAPI HandleAcquireBitStream(int* pBufferSize, void* pUserdata);\r
+    static void NVENCAPI HandleReleaseBitStream(int nBytesInBuffer, unsigned char* cb, void* pUserdata);\r
+    static void NVENCAPI HandleOnBeginFrame(const NVVE_BeginFrameInfo* pbfi, void* pUserdata);\r
+    static void NVENCAPI HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata);\r
+};\r
+\r
+cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, CodecType codec) :\r
+    callback_(callback),\r
+    frameSize_(frameSize),\r
+    codec_(codec),\r
+    surfaceFormat_(YV12),\r
+    cuCtxLock_(0)\r
+{\r
+    initEncoder(fps);\r
+\r
+    initGpuMemory();\r
+\r
+    initCallBacks();\r
+\r
+    createHWEncoder();\r
+}\r
+\r
+cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, const EncoderParams& params, CodecType codec) :\r
+    callback_(callback),\r
+    frameSize_(frameSize),\r
+    codec_(codec),\r
+    surfaceFormat_(YV12),\r
+    cuCtxLock_(0)\r
+{\r
+    initEncoder(fps);\r
+\r
+    setEncodeParams(params);\r
+\r
+    initGpuMemory();\r
+\r
+    initCallBacks();\r
+\r
+    createHWEncoder();\r
+}\r
+\r
+void cv::gpu::VideoWriter_GPU::Impl::initEncoder(double fps)\r
+{\r
+    int err;\r
+\r
+    // Set codec\r
+\r
+    static const unsigned long codecs_id[] = \r
+    {\r
+        NV_CODEC_TYPE_MPEG1, NV_CODEC_TYPE_MPEG2, NV_CODEC_TYPE_MPEG4, NV_CODEC_TYPE_H264, NV_CODEC_TYPE_VC1\r
+    };\r
+    err = NVSetCodec(encoder_, codecs_id[codec_]);\r
+    if (err)\r
+        CV_Error(CV_StsNotImplemented, "Codec format is not supported");\r
+\r
+    // Set default params\r
+\r
+    err = NVSetDefaultParam(encoder_);\r
+    CV_Assert( err == 0 );\r
+\r
+    // Set some common params\r
+\r
+    int inputSize[] = { frameSize_.width, frameSize_.height };\r
+    err = NVSetParamValue(encoder_, NVVE_IN_SIZE, &inputSize);\r
+    CV_Assert( err == 0 );\r
+    err = NVSetParamValue(encoder_, NVVE_OUT_SIZE, &inputSize);\r
+    CV_Assert( err == 0 );\r
+\r
+    //int aspectRatio[] = { frameSize_.width, frameSize_.height, ASPECT_RATIO_DAR };\r
+    int aspectRatio[] = { 16, 9, ASPECT_RATIO_DAR };\r
+    err = NVSetParamValue(encoder_, NVVE_ASPECT_RATIO, &aspectRatio);\r
+    CV_Assert( err == 0 );\r
+\r
+    // FPS\r
+\r
+    int frame_rate = static_cast<int>(fps + 0.5);\r
+    int frame_rate_base = 1;\r
+    while (fabs(static_cast<double>(frame_rate) / frame_rate_base) - fps > 0.001)\r
+    {\r
+        frame_rate_base *= 10;\r
+        frame_rate = static_cast<int>(fps*frame_rate_base + 0.5);\r
+    }\r
+    int FrameRate[] = { frame_rate, frame_rate_base };\r
+    err = NVSetParamValue(encoder_, NVVE_FRAME_RATE, &FrameRate);\r
+    CV_Assert( err == 0 );\r
+\r
+    // Select device for encoding\r
+\r
+    int gpuID = cv::gpu::getDevice();\r
+    err = NVSetParamValue(encoder_, NVVE_FORCE_GPU_SELECTION, &gpuID);\r
+    CV_Assert( err == 0 );\r
+}\r
+\r
+void cv::gpu::VideoWriter_GPU::Impl::setEncodeParams(const EncoderParams& params)\r
+{\r
+    int err;\r
+\r
+    int P_Interval = params.P_Interval;\r
+    err = NVSetParamValue(encoder_, NVVE_P_INTERVAL, &P_Interval);\r
+    CV_Assert( err == 0 );\r
+\r
+    int IDR_Period = params.IDR_Period;\r
+    err = NVSetParamValue(encoder_, NVVE_IDR_PERIOD, &IDR_Period);\r
+    CV_Assert( err == 0 );\r
+\r
+    int DynamicGOP = params.DynamicGOP;\r
+    err = NVSetParamValue(encoder_, NVVE_DYNAMIC_GOP, &DynamicGOP);\r
+    CV_Assert( err == 0 );\r
+\r
+    NVVE_RateCtrlType RCType = static_cast<NVVE_RateCtrlType>(params.RCType);\r
+    err = NVSetParamValue(encoder_, NVVE_RC_TYPE, &RCType);\r
+    CV_Assert( err == 0 );\r
+\r
+    int AvgBitrate = params.AvgBitrate;\r
+    err = NVSetParamValue(encoder_, NVVE_AVG_BITRATE, &AvgBitrate);\r
+    CV_Assert( err == 0 );\r
+\r
+    int PeakBitrate = params.PeakBitrate;\r
+    err = NVSetParamValue(encoder_, NVVE_PEAK_BITRATE, &PeakBitrate);\r
+    CV_Assert( err == 0 );\r
+\r
+    int QP_Level_Intra = params.QP_Level_Intra;\r
+    err = NVSetParamValue(encoder_, NVVE_QP_LEVEL_INTRA, &QP_Level_Intra);\r
+    CV_Assert( err == 0 );\r
+\r
+    int QP_Level_InterP = params.QP_Level_InterP;\r
+    err = NVSetParamValue(encoder_, NVVE_QP_LEVEL_INTER_P, &QP_Level_InterP);\r
+    CV_Assert( err == 0 );\r
+\r
+    int QP_Level_InterB = params.QP_Level_InterB;\r
+    err = NVSetParamValue(encoder_, NVVE_QP_LEVEL_INTER_B, &QP_Level_InterB);\r
+    CV_Assert( err == 0 );\r
+\r
+    int DeblockMode = params.DeblockMode;\r
+    err = NVSetParamValue(encoder_, NVVE_DEBLOCK_MODE, &DeblockMode);\r
+    CV_Assert( err == 0 );\r
+\r
+    int ProfileLevel = params.ProfileLevel;\r
+    err = NVSetParamValue(encoder_, NVVE_PROFILE_LEVEL, &ProfileLevel);\r
+    CV_Assert( err == 0 );\r
+\r
+    int ForceIntra = params.ForceIntra;\r
+    err = NVSetParamValue(encoder_, NVVE_FORCE_INTRA, &ForceIntra);\r
+    CV_Assert( err == 0 );\r
+\r
+    int ForceIDR = params.ForceIDR;\r
+    err = NVSetParamValue(encoder_, NVVE_FORCE_IDR, &ForceIDR);\r
+    CV_Assert( err == 0 );\r
+\r
+    int ClearStat = params.ClearStat;\r
+    err = NVSetParamValue(encoder_, NVVE_CLEAR_STAT, &ClearStat);\r
+    CV_Assert( err == 0 );\r
+\r
+    NVVE_DI_MODE DIMode = static_cast<NVVE_DI_MODE>(params.DIMode);\r
+    err = NVSetParamValue(encoder_, NVVE_SET_DEINTERLACE, &DIMode);\r
+    CV_Assert( err == 0 );\r
+\r
+    if (params.Presets != -1)\r
+    {\r
+        NVVE_PRESETS_TARGET Presets = static_cast<NVVE_PRESETS_TARGET>(params.Presets);\r
+        err = NVSetParamValue(encoder_, NVVE_PRESETS, &Presets);\r
+        CV_Assert ( err == 0 );\r
+    }\r
+\r
+    int DisableCabac = params.DisableCabac;\r
+    err = NVSetParamValue(encoder_, NVVE_DISABLE_CABAC, &DisableCabac);\r
+    CV_Assert ( err == 0 );\r
+\r
+    int NaluFramingType = params.NaluFramingType;\r
+    err = NVSetParamValue(encoder_, NVVE_CONFIGURE_NALU_FRAMING_TYPE, &NaluFramingType);\r
+    CV_Assert ( err == 0 );\r
+\r
+    int DisableSPSPPS = params.DisableSPSPPS;\r
+    err = NVSetParamValue(encoder_, NVVE_DISABLE_SPS_PPS, &DisableSPSPPS);\r
+    CV_Assert ( err == 0 );\r
+}\r
+\r
+void cv::gpu::VideoWriter_GPU::Impl::initGpuMemory()\r
+{\r
+    int err;\r
+    CUresult cuRes;\r
+\r
+    // initialize context\r
+    cv::gpu::GpuMat temp(1, 1, CV_8U);\r
+    temp.release();\r
+\r
+    static const int bpp[] =\r
+    {\r
+        16, // UYVY, 4:2:2\r
+        16, // YUY2, 4:2:2\r
+        12, // YV12, 4:2:0\r
+        12, // NV12, 4:2:0\r
+        12, // IYUV, 4:2:0\r
+    };\r
+\r
+    CUcontext cuContext;\r
+    cuRes = cuCtxGetCurrent(&cuContext);\r
+    CV_Assert( cuRes == CUDA_SUCCESS );\r
+\r
+    // Allocate the CUDA memory Pitched Surface\r
+    if (surfaceFormat_ == UYVY || surfaceFormat_ == YUY2)\r
+        videoFrame_.create(frameSize_.height, (frameSize_.width * bpp[surfaceFormat_]) / 8, CV_8UC1);\r
+    else\r
+        videoFrame_.create((frameSize_.height * bpp[surfaceFormat_]) / 8, frameSize_.width, CV_8UC1);\r
+\r
+    // Create the Video Context Lock (used for synchronization)\r
+    cuRes = cuvidCtxLockCreate(&cuCtxLock_, cuContext);\r
+    CV_Assert( cuRes == CUDA_SUCCESS );\r
+\r
+    // If we are using GPU Device Memory with NVCUVENC, it is necessary to create a \r
+    // CUDA Context with a Context Lock cuvidCtxLock.  The Context Lock needs to be passed to NVCUVENC\r
+\r
+    int iUseDeviceMem = 1;\r
+    err = NVSetParamValue(encoder_, NVVE_DEVICE_MEMORY_INPUT, &iUseDeviceMem);\r
+    CV_Assert ( err == 0 );\r
+\r
+    err = NVSetParamValue(encoder_, NVVE_DEVICE_CTX_LOCK, &cuCtxLock_);\r
+    CV_Assert ( err == 0 );\r
+}\r
+\r
+void cv::gpu::VideoWriter_GPU::Impl::initCallBacks()\r
+{\r
+    NVVE_CallbackParams cb;\r
+    memset(&cb, 0, sizeof(NVVE_CallbackParams));\r
+\r
+    cb.pfnacquirebitstream = HandleAcquireBitStream;\r
+    cb.pfnonbeginframe     = HandleOnBeginFrame;\r
+    cb.pfnonendframe       = HandleOnEndFrame;\r
+    cb.pfnreleasebitstream = HandleReleaseBitStream;\r
+\r
+    NVRegisterCB(encoder_, cb, this);\r
+}\r
+\r
+void cv::gpu::VideoWriter_GPU::Impl::createHWEncoder()\r
+{\r
+    int err;\r
+\r
+    // Create the NVIDIA HW resources for Encoding on NVIDIA hardware\r
+    err = NVCreateHWEncoder(encoder_);\r
+    CV_Assert( err == 0 );\r
+}\r
+\r
+namespace cv { namespace gpu { namespace device \r
+{\r
+    namespace video_encoding\r
+    {\r
+        void YV12_gpu(const DevMem2Db src, int cn, DevMem2Db dst);\r
+    }\r
+}}}\r
+\r
+void cv::gpu::VideoWriter_GPU::Impl::write(const cv::gpu::GpuMat& frame, bool lastFrame)\r
+{\r
+    CV_Assert( frame.size() == frameSize_ );\r
+    CV_Assert( frame.type() == CV_8UC1 || frame.type() == CV_8UC3 || frame.type() == CV_8UC4 );\r
+\r
+    NVVE_EncodeFrameParams efparams;\r
+    efparams.Width = frameSize_.width;\r
+    efparams.Height = frameSize_.height;\r
+    efparams.Pitch = static_cast<int>(videoFrame_.step);\r
+    efparams.SurfFmt = surfaceFormat_;\r
+    efparams.PictureStruc = FRAME_PICTURE;\r
+    efparams.topfieldfirst =  0;\r
+    efparams.repeatFirstField = 0;\r
+    efparams.progressiveFrame = (surfaceFormat_ == NV12) ? 1 : 0;\r
+    efparams.bLast = lastFrame;\r
+    efparams.picBuf = 0; // Must be set to NULL in order to support device memory input\r
+\r
+    // Don't forget we need to lock/unlock between memcopies\r
+    CUresult res = cuvidCtxLock(cuCtxLock_, 0);\r
+    CV_Assert( res == CUDA_SUCCESS );\r
+\r
+    if (surfaceFormat_ == YV12)\r
+        cv::gpu::device::video_encoding::YV12_gpu(frame, frame.channels(), videoFrame_);\r
+\r
+    res = cuvidCtxUnlock(cuCtxLock_, 0);\r
+    CV_Assert( res == CUDA_SUCCESS );\r
+\r
+    int err = NVEncodeFrame(encoder_, &efparams, 0, videoFrame_.data);\r
+    CV_Assert( err == 0 );\r
+}\r
+\r
+unsigned char* NVENCAPI cv::gpu::VideoWriter_GPU::Impl::HandleAcquireBitStream(int* pBufferSize, void* pUserdata)\r
+{\r
+    Impl* thiz = static_cast<Impl*>(pUserdata);\r
+\r
+    return thiz->callback_->acquireBitStream(pBufferSize);\r
+}\r
+\r
+void NVENCAPI cv::gpu::VideoWriter_GPU::Impl::HandleReleaseBitStream(int nBytesInBuffer, unsigned char* cb, void* pUserdata)\r
+{\r
+    Impl* thiz = static_cast<Impl*>(pUserdata);\r
+\r
+    thiz->callback_->releaseBitStream(cb, nBytesInBuffer);\r
+}\r
+\r
+void NVENCAPI cv::gpu::VideoWriter_GPU::Impl::HandleOnBeginFrame(const NVVE_BeginFrameInfo* pbfi, void* pUserdata)\r
+{\r
+    Impl* thiz = static_cast<Impl*>(pUserdata);\r
+\r
+    thiz->callback_->onBeginFrame(pbfi->nFrameNumber, static_cast<EncoderCallBack::PicType>(pbfi->nPicType));\r
+}\r
+\r
+void NVENCAPI cv::gpu::VideoWriter_GPU::Impl::HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata)\r
+{\r
+    Impl* thiz = static_cast<Impl*>(pUserdata);\r
+\r
+    thiz->callback_->onEndFrame(pefi->nFrameNumber, static_cast<EncoderCallBack::PicType>(pefi->nPicType));\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+// FFMPEG\r
+\r
+class EncoderCallBackFFMPEG : public cv::gpu::VideoWriter_GPU::EncoderCallBack\r
+{\r
+public:\r
+    EncoderCallBackFFMPEG(const std::string& fileName, cv::Size frameSize, double fps);\r
+    ~EncoderCallBackFFMPEG();\r
+\r
+    unsigned char* acquireBitStream(int* bufferSize);\r
+    void releaseBitStream(unsigned char* data, int size);\r
+    void onBeginFrame(int frameNumber, PicType picType);\r
+    void onEndFrame(int frameNumber, PicType picType);\r
+\r
+private:\r
+    EncoderCallBackFFMPEG(const EncoderCallBackFFMPEG&);\r
+    EncoderCallBackFFMPEG& operator=(const EncoderCallBackFFMPEG&);\r
+\r
+    struct OutputMediaStream_FFMPEG* stream_;\r
+    std::vector<uchar> buf_;\r
+};\r
+\r
+namespace\r
+{\r
+    Create_OutputMediaStream_FFMPEG_Plugin create_OutputMediaStream_FFMPEG_p = 0;\r
+    Release_OutputMediaStream_FFMPEG_Plugin release_OutputMediaStream_FFMPEG_p = 0;\r
+    Write_OutputMediaStream_FFMPEG_Plugin write_OutputMediaStream_FFMPEG_p = 0;\r
+\r
+    bool init_MediaStream_FFMPEG()\r
+    {\r
+        static bool initialized = 0;\r
+\r
+        if (!initialized)\r
+        {\r
+        #if defined WIN32 || defined _WIN32\r
+            const char* module_name = "opencv_ffmpeg"\r
+            #if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__)\r
+                "_64"\r
+            #endif\r
+                ".dll";\r
+\r
+            static HMODULE cvFFOpenCV = LoadLibrary(module_name);\r
+\r
+            if (cvFFOpenCV)\r
+            {\r
+                create_OutputMediaStream_FFMPEG_p =\r
+                    (Create_OutputMediaStream_FFMPEG_Plugin)GetProcAddress(cvFFOpenCV, "create_OutputMediaStream_FFMPEG");\r
+                release_OutputMediaStream_FFMPEG_p =\r
+                    (Release_OutputMediaStream_FFMPEG_Plugin)GetProcAddress(cvFFOpenCV, "release_OutputMediaStream_FFMPEG");\r
+                write_OutputMediaStream_FFMPEG_p =\r
+                    (Write_OutputMediaStream_FFMPEG_Plugin)GetProcAddress(cvFFOpenCV, "write_OutputMediaStream_FFMPEG");\r
+\r
+                initialized = create_OutputMediaStream_FFMPEG_p != 0 && release_OutputMediaStream_FFMPEG_p != 0 && write_OutputMediaStream_FFMPEG_p != 0;\r
+            }\r
+        #elif defined HAVE_FFMPEG\r
+            create_OutputMediaStream_FFMPEG_p = create_OutputMediaStream_FFMPEG;\r
+            release_OutputMediaStream_FFMPEG_p = release_OutputMediaStream_FFMPEG;\r
+            write_OutputMediaStream_FFMPEG_p = write_OutputMediaStream_FFMPEG;\r
+\r
+            initialized = true;\r
+        #endif\r
+        }\r
+\r
+        return initialized;\r
+    }\r
+}\r
+\r
+EncoderCallBackFFMPEG::EncoderCallBackFFMPEG(const std::string& fileName, cv::Size frameSize, double fps) :\r
+    stream_(0)\r
+{\r
+    int buf_size = std::max(frameSize.area() * 4, 1024 * 1024);\r
+    buf_.resize(buf_size);\r
+\r
+    CV_Assert( init_MediaStream_FFMPEG() );\r
+\r
+    stream_ = create_OutputMediaStream_FFMPEG_p(fileName.c_str(), frameSize.width, frameSize.height, fps);\r
+    CV_Assert( stream_ != 0 );\r
+}\r
+\r
+EncoderCallBackFFMPEG::~EncoderCallBackFFMPEG()\r
+{\r
+    release_OutputMediaStream_FFMPEG_p(stream_);\r
+}\r
+\r
+unsigned char* EncoderCallBackFFMPEG::acquireBitStream(int* bufferSize)\r
+{\r
+    *bufferSize = static_cast<int>(buf_.size());\r
+    return &buf_[0];\r
+}\r
+\r
+void EncoderCallBackFFMPEG::releaseBitStream(unsigned char* data, int size)\r
+{\r
+    write_OutputMediaStream_FFMPEG_p(stream_, data, size);\r
+}\r
+\r
+void EncoderCallBackFFMPEG::onBeginFrame(int frameNumber, PicType picType)\r
+{\r
+}\r
+\r
+void EncoderCallBackFFMPEG::onEndFrame(int frameNumber, PicType picType)\r
+{\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+// VideoWriter_GPU\r
+\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU()\r
+{\r
+}\r
+\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps)\r
+{\r
+    open(fileName, frameSize, fps);\r
+}\r
+\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params)\r
+{\r
+    open(fileName, frameSize, fps, params);\r
+}\r
+\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps)\r
+{\r
+    open(encoderCallback, frameSize, fps);\r
+}\r
+\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params)\r
+{\r
+    open(encoderCallback, frameSize, fps, params);\r
+}\r
+\r
+cv::gpu::VideoWriter_GPU::~VideoWriter_GPU()\r
+{\r
+    close();\r
+}\r
+\r
+void cv::gpu::VideoWriter_GPU::open(const std::string& fileName, cv::Size frameSize, double fps)\r
+{\r
+    close();\r
+    cv::Ptr<EncoderCallBack> encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps));\r
+    open(encoderCallback, frameSize, fps);\r
+}\r
+\r
+void cv::gpu::VideoWriter_GPU::open(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params)\r
+{\r
+    close();\r
+    cv::Ptr<EncoderCallBack> encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps));\r
+    open(encoderCallback, frameSize, fps, params);\r
+}\r
+\r
+void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps)\r
+{\r
+    close();\r
+    impl_.reset(new Impl(encoderCallback, frameSize, fps));\r
+}\r
+\r
+void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params)\r
+{\r
+    close();\r
+    impl_.reset(new Impl(encoderCallback, frameSize, fps, params));\r
+}\r
+\r
+bool cv::gpu::VideoWriter_GPU::isOpened() const\r
+{\r
+    return impl_.get() != 0;\r
+}\r
+\r
+void cv::gpu::VideoWriter_GPU::close()\r
+{\r
+    impl_.reset();\r
+}\r
+\r
+void cv::gpu::VideoWriter_GPU::write(const cv::gpu::GpuMat& image, bool lastFrame)\r
+{\r
+    CV_Assert( isOpened() );\r
+\r
+    impl_->write(image, lastFrame);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+// VideoWriter_GPU::EncoderParams\r
+\r
+cv::gpu::VideoWriter_GPU::EncoderParams::EncoderParams()\r
+{\r
+    P_Interval = 3;\r
+    IDR_Period = 15;\r
+    DynamicGOP = 0;\r
+    RCType = 1;\r
+    AvgBitrate = 4000000;\r
+    PeakBitrate = 10000000;\r
+    QP_Level_Intra = 25;\r
+    QP_Level_InterP = 28;\r
+    QP_Level_InterB = 31;\r
+    DeblockMode = 1;\r
+    ProfileLevel = 65357;\r
+    ForceIntra = 0;\r
+    ForceIDR = 0;\r
+    ClearStat = 0;\r
+    DIMode = 1;\r
+    Presets = 2;\r
+    DisableCabac = 0;\r
+    NaluFramingType = 0;\r
+    DisableSPSPPS = 0;\r
+}\r
+\r
+cv::gpu::VideoWriter_GPU::EncoderParams::EncoderParams(const std::string& configFile)\r
+{\r
+    load(configFile);\r
+}\r
+\r
+void cv::gpu::VideoWriter_GPU::EncoderParams::load(const std::string& configFile)\r
+{\r
+    cv::FileStorage fs(configFile, cv::FileStorage::READ);\r
+    CV_Assert( fs.isOpened() );\r
+\r
+    cv::read(fs["P_Interval"     ], P_Interval, 3);\r
+    cv::read(fs["IDR_Period"     ], IDR_Period, 15);\r
+    cv::read(fs["DynamicGOP"     ], DynamicGOP, 0);\r
+    cv::read(fs["RCType"         ], RCType, 1);\r
+    cv::read(fs["AvgBitrate"     ], AvgBitrate, 4000000);\r
+    cv::read(fs["PeakBitrate"    ], PeakBitrate, 10000000);\r
+    cv::read(fs["QP_Level_Intra" ], QP_Level_Intra, 25);\r
+    cv::read(fs["QP_Level_InterP"], QP_Level_InterP, 28);\r
+    cv::read(fs["QP_Level_InterB"], QP_Level_InterB, 31);\r
+    cv::read(fs["DeblockMode"    ], DeblockMode, 1);\r
+    cv::read(fs["ProfileLevel"   ], ProfileLevel, 65357);\r
+    cv::read(fs["ForceIntra"     ], ForceIntra, 0);\r
+    cv::read(fs["ForceIDR"       ], ForceIDR, 0);\r
+    cv::read(fs["ClearStat"      ], ClearStat, 0);\r
+    cv::read(fs["DIMode"         ], DIMode, 1);\r
+    cv::read(fs["Presets"        ], Presets, 2);\r
+    cv::read(fs["DisableCabac"   ], DisableCabac, 0);\r
+    cv::read(fs["NaluFramingType"], NaluFramingType, 0);\r
+    cv::read(fs["DisableSPSPPS"  ], DisableSPSPPS, 0);\r
+}\r
+\r
+void cv::gpu::VideoWriter_GPU::EncoderParams::save(const std::string& configFile) const\r
+{\r
+    cv::FileStorage fs(configFile, cv::FileStorage::WRITE);\r
+    CV_Assert( fs.isOpened() );\r
+\r
+    cv::write(fs, "P_Interval"     , P_Interval);\r
+    cv::write(fs, "IDR_Period"     , IDR_Period);\r
+    cv::write(fs, "DynamicGOP"     , DynamicGOP);\r
+    cv::write(fs, "RCType"         , RCType);\r
+    cv::write(fs, "AvgBitrate"     , AvgBitrate);\r
+    cv::write(fs, "PeakBitrate"    , PeakBitrate);\r
+    cv::write(fs, "QP_Level_Intra" , QP_Level_Intra);\r
+    cv::write(fs, "QP_Level_InterP", QP_Level_InterP);\r
+    cv::write(fs, "QP_Level_InterB", QP_Level_InterB);\r
+    cv::write(fs, "DeblockMode"    , DeblockMode);\r
+    cv::write(fs, "ProfileLevel"   , ProfileLevel);\r
+    cv::write(fs, "ForceIntra"     , ForceIntra);\r
+    cv::write(fs, "ForceIDR"       , ForceIDR);\r
+    cv::write(fs, "ClearStat"      , ClearStat);\r
+    cv::write(fs, "DIMode"         , DIMode);\r
+    cv::write(fs, "Presets"        , Presets);\r
+    cv::write(fs, "DisableCabac"   , DisableCabac);\r
+    cv::write(fs, "NaluFramingType", NaluFramingType);\r
+    cv::write(fs, "DisableSPSPPS"  , DisableSPSPPS);\r
+}\r
+\r
+#endif // !defined HAVE_CUDA || !defined WIN32\r
index 7fe0b27..2d59f55 100644 (file)
@@ -384,4 +384,66 @@ INSTANTIATE_TEST_CASE_P(GPU_Video, FarnebackOpticalFlow, testing::Combine(
     testing::Values(FarnebackOptFlowFlags(0), FarnebackOptFlowFlags(cv::OPTFLOW_FARNEBACK_GAUSSIAN)),\r
     testing::Values(UseInitFlow(false), UseInitFlow(true))));\r
 \r
+/////////////////////////////////////////////////////////////////////////////////////////////////\r
+// VideoWriter\r
+\r
+PARAM_TEST_CASE(VideoWriter, cv::gpu::DeviceInfo, std::string)\r
+{\r
+    cv::gpu::DeviceInfo devInfo;\r
+    std::string inputFile;\r
+\r
+    std::string outputFile;\r
+\r
+    virtual void SetUp()\r
+    {\r
+        devInfo = GET_PARAM(0);\r
+        inputFile = GET_PARAM(1);\r
+\r
+        cv::gpu::setDevice(devInfo.deviceID());\r
+\r
+        inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "video/" + inputFile;\r
+        outputFile = inputFile.substr(0, inputFile.find('.')) + "_test.avi";\r
+    }\r
+};\r
+\r
+TEST_P(VideoWriter, Regression)\r
+{\r
+    const double FPS = 25.0;\r
+\r
+    cv::VideoCapture reader(inputFile);\r
+    ASSERT_TRUE( reader.isOpened() );\r
+\r
+    cv::gpu::VideoWriter_GPU d_writer;\r
+\r
+    cv::Mat frame;\r
+    std::vector<cv::Mat> frames;\r
+    cv::gpu::GpuMat d_frame;\r
+\r
+    for (int i = 1; i < 10; ++i)\r
+    {\r
+        reader >> frame;\r
+\r
+        if (frame.empty())\r
+            break;\r
+\r
+        frames.push_back(frame.clone());\r
+        d_frame.upload(frame);\r
+\r
+        if (!d_writer.isOpened())\r
+            d_writer.open(outputFile, frame.size(), FPS);\r
+\r
+        d_writer.write(d_frame);\r
+    }\r
+\r
+    reader.release();\r
+    d_writer.close();\r
+\r
+    reader.open(outputFile);\r
+    ASSERT_TRUE( reader.isOpened() );\r
+}\r
+\r
+INSTANTIATE_TEST_CASE_P(GPU_Video, VideoWriter, testing::Combine(\r
+    ALL_DEVICES,\r
+    testing::Values("VID00003-20100701-2204.3GP", "big_buck_bunny.mpg")));\r
+\r
 } // namespace\r
index de9ad67..5aad37a 100644 (file)
@@ -65,6 +65,18 @@ typedef int (*CvWriteFrame_Plugin)( void* writer_handle, const unsigned char* da
                                     int width, int height, int cn, int origin);
 typedef void (*CvReleaseVideoWriter_Plugin)( void** writer );
 
+/*
+ * For CUDA encoder
+ */
+OPENCV_FFMPEG_API struct OutputMediaStream_FFMPEG* create_OutputMediaStream_FFMPEG(const char* fileName, int width, int height, double fps);
+OPENCV_FFMPEG_API void release_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream);
+OPENCV_FFMPEG_API void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size);
+
+typedef struct OutputMediaStream_FFMPEG* (*Create_OutputMediaStream_FFMPEG_Plugin)(const char* fileName, int width, int height, double fps);
+typedef void (*Release_OutputMediaStream_FFMPEG_Plugin)(struct OutputMediaStream_FFMPEG* stream);
+typedef void (*Write_OutputMediaStream_FFMPEG_Plugin)(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size);
+
 #ifdef __cplusplus
 }
 #endif
index c27cd02..973d392 100644 (file)
@@ -1446,3 +1446,295 @@ void CvVideoWriter_FFMPEG::close()
         return writer->writeFrame(data, step, width, height, cn, origin);
     }
 
+
+/*
+ * For CUDA encoder
+ */
+
+struct OutputMediaStream_FFMPEG
+{
+    bool open(const char* fileName, int width, int height, double fps);
+    void write(unsigned char* data, int size);
+
+    void close();
+
+    // add a video output stream to the container
+    static AVStream* addVideoStream(AVFormatContext *oc, CodecID codec_id, int w, int h, int bitrate, double fps, PixelFormat pixel_format);
+
+    AVOutputFormat* fmt_;
+    AVFormatContext* oc_;
+    AVStream* video_st_;
+};
+
+void OutputMediaStream_FFMPEG::close()
+{
+    // no more frame to compress. The codec has a latency of a few
+    // frames if using B frames, so we get the last frames by
+    // passing the same picture again
+
+    // TODO -- do we need to account for latency here?
+
+    if (oc_)
+    {
+        // write the trailer, if any
+        av_write_trailer(oc_);
+
+        // free the streams
+        for (unsigned int i = 0; i < oc_->nb_streams; ++i)
+        {
+            av_freep(&oc_->streams[i]->codec);
+            av_freep(&oc_->streams[i]);
+        }
+
+        if (!(fmt_->flags & AVFMT_NOFILE) && oc_->pb)
+        {
+            // close the output file
+
+            #if LIBAVCODEC_VERSION_INT < ((52<<16)+(123<<8)+0)
+                #if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0)
+                    url_fclose(oc_->pb);
+                #else
+                    url_fclose(&oc_->pb);
+                #endif
+            #else
+                avio_close(oc_->pb);
+            #endif
+        }
+
+        // free the stream
+        av_free(oc_);
+    }
+}
+
+AVStream* OutputMediaStream_FFMPEG::addVideoStream(AVFormatContext *oc, CodecID codec_id, int w, int h, int bitrate, double fps, PixelFormat pixel_format)
+{
+    #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 10, 0)
+        AVStream* st = avformat_new_stream(oc, 0);
+    #else
+        AVStream* st = av_new_stream(oc, 0);
+    #endif
+    if (!st)
+        return 0;
+
+    #if LIBAVFORMAT_BUILD > 4628
+        AVCodecContext* c = st->codec;
+    #else
+        AVCodecContext* c = &(st->codec);
+    #endif
+
+    c->codec_id = codec_id;
+    c->codec_type = AVMEDIA_TYPE_VIDEO;
+
+    // put sample parameters
+    unsigned long long lbit_rate = static_cast<unsigned long long>(bitrate);
+    lbit_rate += (bitrate / 4);
+    lbit_rate = std::min(lbit_rate, static_cast<unsigned long long>(std::numeric_limits<int>::max()));
+    c->bit_rate = bitrate;
+
+    // took advice from
+    // http://ffmpeg-users.933282.n4.nabble.com/warning-clipping-1-dct-coefficients-to-127-127-td934297.html
+    c->qmin = 3;
+
+    // resolution must be a multiple of two
+    c->width = w;
+    c->height = h;
+
+    AVCodec* codec = avcodec_find_encoder(c->codec_id);
+
+    // time base: this is the fundamental unit of time (in seconds) in terms
+    // of which frame timestamps are represented. for fixed-fps content,
+    // timebase should be 1/framerate and timestamp increments should be
+    // identically 1
+
+    int frame_rate = static_cast<int>(fps+0.5);
+    int frame_rate_base = 1;
+    while (fabs(static_cast<double>(frame_rate)/frame_rate_base) - fps > 0.001)
+    {
+        frame_rate_base *= 10;
+        frame_rate = static_cast<int>(fps*frame_rate_base + 0.5);
+    }
+    c->time_base.den = frame_rate;
+    c->time_base.num = frame_rate_base;
+
+    #if LIBAVFORMAT_BUILD > 4752
+        // adjust time base for supported framerates
+        if (codec && codec->supported_framerates)
+        {
+            AVRational req = {frame_rate, frame_rate_base};
+            const AVRational* best = NULL;
+            AVRational best_error = {INT_MAX, 1};
+
+            for (const AVRational* p = codec->supported_framerates; p->den!=0; ++p)
+            {
+                AVRational error = av_sub_q(req, *p);
+
+                if (error.num < 0) 
+                    error.num *= -1;
+
+                if (av_cmp_q(error, best_error) < 0)
+                {
+                    best_error= error;
+                    best= p;
+                }
+            }
+
+            c->time_base.den= best->num;
+            c->time_base.num= best->den;
+        }
+    #endif
+
+    c->gop_size = 12; // emit one intra frame every twelve frames at most
+    c->pix_fmt = pixel_format;
+
+    if (c->codec_id == CODEC_ID_MPEG2VIDEO)
+        c->max_b_frames = 2;
+
+    if (c->codec_id == CODEC_ID_MPEG1VIDEO || c->codec_id == CODEC_ID_MSMPEG4V3)
+    {
+        // needed to avoid using macroblocks in which some coeffs overflow
+        // this doesnt happen with normal video, it just happens here as the
+        // motion of the chroma plane doesnt match the luma plane
+
+        // avoid FFMPEG warning 'clipping 1 dct coefficients...'
+
+        c->mb_decision = 2;
+    }
+
+    #if LIBAVCODEC_VERSION_INT > 0x000409
+        // some formats want stream headers to be seperate
+        if (oc->oformat->flags & AVFMT_GLOBALHEADER)
+        {
+            c->flags |= CODEC_FLAG_GLOBAL_HEADER;
+        }
+    #endif
+
+    return st;
+}
+
+bool OutputMediaStream_FFMPEG::open(const char* fileName, int width, int height, double fps)
+{
+    fmt_ = 0;
+    oc_ = 0;
+    video_st_ = 0;
+
+    // tell FFMPEG to register codecs
+    av_register_all();
+
+    av_log_set_level(AV_LOG_ERROR);
+
+    // auto detect the output format from the name and fourcc code
+    #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
+        fmt_ = av_guess_format(NULL, fileName, NULL);
+    #else
+        fmt_ = guess_format(NULL, fileName, NULL);
+    #endif
+    if (!fmt_)
+        return false;
+
+    CodecID codec_id = CODEC_ID_H264;
+
+    // alloc memory for context
+    #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
+        oc_ = avformat_alloc_context();
+    #else
+        oc_ = av_alloc_format_context();
+    #endif
+    if (!oc_)
+        return false;
+
+    // set some options
+    oc_->oformat = fmt_;
+    snprintf(oc_->filename, sizeof(oc_->filename), "%s", fileName);
+
+    oc_->max_delay = (int)(0.7 * AV_TIME_BASE); // This reduces buffer underrun warnings with MPEG
+
+    // set a few optimal pixel formats for lossless codecs of interest..
+    PixelFormat codec_pix_fmt = PIX_FMT_YUV420P;
+    int bitrate_scale = 64;
+
+    // TODO -- safe to ignore output audio stream?
+    video_st_ = addVideoStream(oc_, codec_id, width, height, width * height * bitrate_scale, fps, codec_pix_fmt);
+    if (!video_st_)
+        return false;
+
+    // set the output parameters (must be done even if no parameters)
+    #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
+        if (av_set_parameters(oc_, NULL) < 0)
+            return false;
+    #endif
+
+    // now that all the parameters are set, we can open the audio and
+    // video codecs and allocate the necessary encode buffers
+
+    #if LIBAVFORMAT_BUILD > 4628
+        AVCodecContext* c = (video_st_->codec);
+    #else
+        AVCodecContext* c = &(video_st_->codec);
+    #endif
+
+    c->codec_tag = MKTAG('H', '2', '6', '4');
+    c->bit_rate_tolerance = c->bit_rate;
+
+    // open the output file, if needed
+    if (!(fmt_->flags & AVFMT_NOFILE))
+    {
+        #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
+            int err = url_fopen(&oc_->pb, fileName, URL_WRONLY);
+        #else
+            int err = avio_open(&oc_->pb, fileName, AVIO_FLAG_WRITE);
+        #endif
+
+        if (err != 0)
+            return false;
+    }
+
+    // write the stream header, if any
+    #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
+        av_write_header(oc_);
+    #else
+        avformat_write_header(oc_, NULL);
+    #endif
+
+    return true;
+}
+
+void OutputMediaStream_FFMPEG::write(unsigned char* data, int size)
+{
+    // if zero size, it means the image was buffered
+    if (size > 0) 
+    {
+        AVPacket pkt;
+        av_init_packet(&pkt);
+
+        pkt.stream_index = video_st_->index;
+        pkt.data = data;
+        pkt.size = size;
+
+        // write the compressed frame in the media file
+        av_write_frame(oc_, &pkt);
+    }
+}
+
+struct OutputMediaStream_FFMPEG* create_OutputMediaStream_FFMPEG(const char* fileName, int width, int height, double fps)
+{
+    OutputMediaStream_FFMPEG* stream = (OutputMediaStream_FFMPEG*) malloc(sizeof(OutputMediaStream_FFMPEG));
+
+    if (stream->open(fileName, width, height, fps))
+        return stream;
+
+    stream->close();
+    free(stream);
+    
+    return 0;
+}
+
+void release_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream)
+{
+    stream->close();
+    free(stream);
+}
+
+void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size)
+{
+    stream->write(data, size);
+}
index e89af78..4e5b425 100755 (executable)
@@ -43,6 +43,7 @@
 #include "cap_ffmpeg_api.hpp"
 #include <assert.h>
 #include <algorithm>
+#include <limits>
 
 #if defined _MSC_VER && _MSC_VER >= 1200
 #pragma warning( disable: 4244 4510 4512 4610 )
@@ -1611,3 +1612,295 @@ void CvVideoWriter_FFMPEG::close()
         return writer->writeFrame(data, step, width, height, cn, origin);
     }
 
+
+/*
+ * For CUDA encoder
+ */
+
+struct OutputMediaStream_FFMPEG
+{
+    bool open(const char* fileName, int width, int height, double fps);
+    void write(unsigned char* data, int size);
+
+    void close();
+
+    // add a video output stream to the container
+    static AVStream* addVideoStream(AVFormatContext *oc, CodecID codec_id, int w, int h, int bitrate, double fps, PixelFormat pixel_format);
+
+    AVOutputFormat* fmt_;
+    AVFormatContext* oc_;
+    AVStream* video_st_;
+};
+
+void OutputMediaStream_FFMPEG::close()
+{
+    // no more frame to compress. The codec has a latency of a few
+    // frames if using B frames, so we get the last frames by
+    // passing the same picture again
+
+    // TODO -- do we need to account for latency here?
+
+    if (oc_)
+    {
+        // write the trailer, if any
+        av_write_trailer(oc_);
+
+        // free the streams
+        for (unsigned int i = 0; i < oc_->nb_streams; ++i)
+        {
+            av_freep(&oc_->streams[i]->codec);
+            av_freep(&oc_->streams[i]);
+        }
+
+        if (!(fmt_->flags & AVFMT_NOFILE) && oc_->pb)
+        {
+            // close the output file
+
+            #if LIBAVCODEC_VERSION_INT < ((52<<16)+(123<<8)+0)
+                #if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0)
+                    url_fclose(oc_->pb);
+                #else
+                    url_fclose(&oc_->pb);
+                #endif
+            #else
+                avio_close(oc_->pb);
+            #endif
+        }
+
+        // free the stream
+        av_free(oc_);
+    }
+}
+
+AVStream* OutputMediaStream_FFMPEG::addVideoStream(AVFormatContext *oc, CodecID codec_id, int w, int h, int bitrate, double fps, PixelFormat pixel_format)
+{
+    #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 10, 0)
+        AVStream* st = avformat_new_stream(oc, 0);
+    #else
+        AVStream* st = av_new_stream(oc, 0);
+    #endif
+    if (!st)
+        return 0;
+
+    #if LIBAVFORMAT_BUILD > 4628
+        AVCodecContext* c = st->codec;
+    #else
+        AVCodecContext* c = &(st->codec);
+    #endif
+
+    c->codec_id = codec_id;
+    c->codec_type = AVMEDIA_TYPE_VIDEO;
+
+    // put sample parameters
+    unsigned long long lbit_rate = static_cast<unsigned long long>(bitrate);
+    lbit_rate += (bitrate / 4);
+    lbit_rate = std::min(lbit_rate, static_cast<unsigned long long>(std::numeric_limits<int>::max()));
+    c->bit_rate = bitrate;
+
+    // took advice from
+    // http://ffmpeg-users.933282.n4.nabble.com/warning-clipping-1-dct-coefficients-to-127-127-td934297.html
+    c->qmin = 3;
+
+    // resolution must be a multiple of two
+    c->width = w;
+    c->height = h;
+
+    AVCodec* codec = avcodec_find_encoder(c->codec_id);
+
+    // time base: this is the fundamental unit of time (in seconds) in terms
+    // of which frame timestamps are represented. for fixed-fps content,
+    // timebase should be 1/framerate and timestamp increments should be
+    // identically 1
+
+    int frame_rate = static_cast<int>(fps+0.5);
+    int frame_rate_base = 1;
+    while (fabs(static_cast<double>(frame_rate)/frame_rate_base) - fps > 0.001)
+    {
+        frame_rate_base *= 10;
+        frame_rate = static_cast<int>(fps*frame_rate_base + 0.5);
+    }
+    c->time_base.den = frame_rate;
+    c->time_base.num = frame_rate_base;
+
+    #if LIBAVFORMAT_BUILD > 4752
+        // adjust time base for supported framerates
+        if (codec && codec->supported_framerates)
+        {
+            AVRational req = {frame_rate, frame_rate_base};
+            const AVRational* best = NULL;
+            AVRational best_error = {INT_MAX, 1};
+
+            for (const AVRational* p = codec->supported_framerates; p->den!=0; ++p)
+            {
+                AVRational error = av_sub_q(req, *p);
+
+                if (error.num < 0) 
+                    error.num *= -1;
+
+                if (av_cmp_q(error, best_error) < 0)
+                {
+                    best_error= error;
+                    best= p;
+                }
+            }
+
+            c->time_base.den= best->num;
+            c->time_base.num= best->den;
+        }
+    #endif
+
+    c->gop_size = 12; // emit one intra frame every twelve frames at most
+    c->pix_fmt = pixel_format;
+
+    if (c->codec_id == CODEC_ID_MPEG2VIDEO)
+        c->max_b_frames = 2;
+
+    if (c->codec_id == CODEC_ID_MPEG1VIDEO || c->codec_id == CODEC_ID_MSMPEG4V3)
+    {
+        // needed to avoid using macroblocks in which some coeffs overflow
+        // this doesnt happen with normal video, it just happens here as the
+        // motion of the chroma plane doesnt match the luma plane
+
+        // avoid FFMPEG warning 'clipping 1 dct coefficients...'
+
+        c->mb_decision = 2;
+    }
+
+    #if LIBAVCODEC_VERSION_INT > 0x000409
+        // some formats want stream headers to be seperate
+        if (oc->oformat->flags & AVFMT_GLOBALHEADER)
+        {
+            c->flags |= CODEC_FLAG_GLOBAL_HEADER;
+        }
+    #endif
+
+    return st;
+}
+
+bool OutputMediaStream_FFMPEG::open(const char* fileName, int width, int height, double fps)
+{
+    fmt_ = 0;
+    oc_ = 0;
+    video_st_ = 0;
+
+    // tell FFMPEG to register codecs
+    av_register_all();
+
+    av_log_set_level(AV_LOG_ERROR);
+
+    // auto detect the output format from the name and fourcc code
+    #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
+        fmt_ = av_guess_format(NULL, fileName, NULL);
+    #else
+        fmt_ = guess_format(NULL, fileName, NULL);
+    #endif
+    if (!fmt_)
+        return false;
+
+    CodecID codec_id = CODEC_ID_H264;
+
+    // alloc memory for context
+    #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
+        oc_ = avformat_alloc_context();
+    #else
+        oc_ = av_alloc_format_context();
+    #endif
+    if (!oc_)
+        return false;
+
+    // set some options
+    oc_->oformat = fmt_;
+    snprintf(oc_->filename, sizeof(oc_->filename), "%s", fileName);
+
+    oc_->max_delay = (int)(0.7 * AV_TIME_BASE); // This reduces buffer underrun warnings with MPEG
+
+    // set a few optimal pixel formats for lossless codecs of interest..
+    PixelFormat codec_pix_fmt = PIX_FMT_YUV420P;
+    int bitrate_scale = 64;
+
+    // TODO -- safe to ignore output audio stream?
+    video_st_ = addVideoStream(oc_, codec_id, width, height, width * height * bitrate_scale, fps, codec_pix_fmt);
+    if (!video_st_)
+        return false;
+
+    // set the output parameters (must be done even if no parameters)
+    #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
+        if (av_set_parameters(oc_, NULL) < 0)
+            return false;
+    #endif
+
+    // now that all the parameters are set, we can open the audio and
+    // video codecs and allocate the necessary encode buffers
+
+    #if LIBAVFORMAT_BUILD > 4628
+        AVCodecContext* c = (video_st_->codec);
+    #else
+        AVCodecContext* c = &(video_st_->codec);
+    #endif
+
+    c->codec_tag = MKTAG('H', '2', '6', '4');
+    c->bit_rate_tolerance = c->bit_rate;
+
+    // open the output file, if needed
+    if (!(fmt_->flags & AVFMT_NOFILE))
+    {
+        #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
+            int err = url_fopen(&oc_->pb, fileName, URL_WRONLY);
+        #else
+            int err = avio_open(&oc_->pb, fileName, AVIO_FLAG_WRITE);
+        #endif
+
+        if (err != 0)
+            return false;
+    }
+
+    // write the stream header, if any
+    #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
+        av_write_header(oc_);
+    #else
+        avformat_write_header(oc_, NULL);
+    #endif
+
+    return true;
+}
+
+void OutputMediaStream_FFMPEG::write(unsigned char* data, int size)
+{
+    // if zero size, it means the image was buffered
+    if (size > 0) 
+    {
+        AVPacket pkt;
+        av_init_packet(&pkt);
+
+        pkt.stream_index = video_st_->index;
+        pkt.data = data;
+        pkt.size = size;
+
+        // write the compressed frame in the media file
+        av_write_frame(oc_, &pkt);
+    }
+}
+
+struct OutputMediaStream_FFMPEG* create_OutputMediaStream_FFMPEG(const char* fileName, int width, int height, double fps)
+{
+    OutputMediaStream_FFMPEG* stream = (OutputMediaStream_FFMPEG*) malloc(sizeof(OutputMediaStream_FFMPEG));
+
+    if (stream->open(fileName, width, height, fps))
+        return stream;
+
+    stream->close();
+    free(stream);
+    
+    return 0;
+}
+
+void release_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream)
+{
+    stream->close();
+    free(stream);
+}
+
+void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size)
+{
+    stream->write(data, size);
+}
diff --git a/samples/gpu/video_writer.cpp b/samples/gpu/video_writer.cpp
new file mode 100644 (file)
index 0000000..cb1e5ed
--- /dev/null
@@ -0,0 +1,96 @@
+#include <iostream>\r
+#include <vector>\r
+#include <numeric>\r
+\r
+#include "opencv2/core/core.hpp"\r
+#include "opencv2/gpu/gpu.hpp"\r
+#include "opencv2/highgui/highgui.hpp"\r
+#include "opencv2/contrib/contrib.hpp"\r
+\r
+int main(int argc, const char* argv[])\r
+{\r
+    if (argc != 2)\r
+    {\r
+        std::cerr << "Usage : video_writer <input video file>" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    const double FPS = 25.0;\r
+\r
+    cv::VideoCapture reader(argv[1]);\r
+\r
+    if (!reader.isOpened())\r
+    {\r
+        std::cerr << "Can't open input video file" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    cv::gpu::printShortCudaDeviceInfo(cv::gpu::getDevice());\r
+\r
+    cv::VideoWriter writer;\r
+    cv::gpu::VideoWriter_GPU d_writer;\r
+\r
+    cv::Mat frame;\r
+    cv::gpu::GpuMat d_frame;\r
+\r
+    std::vector<double> cpu_times;\r
+    std::vector<double> gpu_times;\r
+    cv::TickMeter tm;\r
+\r
+    for (int i = 1;; ++i)\r
+    {\r
+        std::cout << "Read " << i << " frame" << std::endl;\r
+\r
+        reader >> frame;\r
+\r
+        if (frame.empty())\r
+        {\r
+            std::cout << "Stop" << std::endl;\r
+            break;\r
+        }\r
+\r
+        if (!writer.isOpened())\r
+        {\r
+            std::cout << "Frame Size : " << frame.cols << "x" << frame.rows << std::endl;\r
+\r
+            std::cout << "Open CPU Writer" << std::endl;\r
+\r
+            if (!writer.open("output_cpu.avi", CV_FOURCC('X', 'V', 'I', 'D'), FPS, frame.size()))\r
+                return -1;\r
+        }\r
+\r
+        if (!d_writer.isOpened())\r
+        {\r
+            std::cout << "Open GPU Writer" << std::endl;\r
+\r
+            d_writer.open("output_gpu.avi", frame.size(), FPS);\r
+        }\r
+\r
+        d_frame.upload(frame);\r
+\r
+        std::cout << "Write " << i << " frame" << std::endl;\r
+\r
+        tm.reset(); tm.start();\r
+        writer.write(frame);\r
+        tm.stop();\r
+        cpu_times.push_back(tm.getTimeMilli());\r
+\r
+        tm.reset(); tm.start();\r
+        d_writer.write(d_frame);\r
+        tm.stop();\r
+        gpu_times.push_back(tm.getTimeMilli());\r
+    }\r
+\r
+    std::cout << std::endl << "Results:" << std::endl;\r
+\r
+    std::sort(cpu_times.begin(), cpu_times.end());\r
+    std::sort(gpu_times.begin(), gpu_times.end());\r
+\r
+    double cpu_avg = std::accumulate(cpu_times.begin(), cpu_times.end(), 0.0) / cpu_times.size();\r
+    double gpu_avg = std::accumulate(gpu_times.begin(), gpu_times.end(), 0.0) / gpu_times.size();\r
+\r
+    std::cout << "CPU [XVID] : Avg : " << cpu_avg << " ms FPS : " << 1000.0 / cpu_avg << std::endl;\r
+    std::cout << "GPU [H264] : Avg : " << gpu_avg << " ms FPS : " << 1000.0 / gpu_avg << std::endl;\r
+\r
+    return 0;\r
+}\r