Commit 53b9880f authored by cudawarped's avatar cudawarped Committed by Alexander Alekhin
Browse files

Merge pull request #2180 from cudawarped:example_fix_for_cudacodec

OpenCV fix 14774 breaks cudacodec

* Example to describe comilation issue

* Added required changes, builds with -DWITH_FFMPEG=ON|OFF

* Working with standard ffmpeg cap.

* Changed cudacodec to use new retrieveRaw() function, to retrieve the raw encoded bitstream, from the videoio module  instead of its own implementation.

* Fix cv::cudacodec::VideoWriter

* Update to use VideoContainer

* Remove header used in testing

* Remove warning

* remove dependence on redundant ffmpeg codecs

* cudacodec: use .set(CAP_PROP_FORMAT, -1) to extract RAW streams

* whitespace

* addressed alalek's comment
parent 35972a1e
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -59,6 +59,8 @@

namespace cv { namespace cudacodec {

using namespace cuda;  // Stream

//! @addtogroup cudacodec
//! @{

@@ -253,6 +255,7 @@ enum Codec
    HEVC,
    VP8,
    VP9,
    NumCodecs,

    Uncompressed_YUV420 = (('I'<<24)|('Y'<<16)|('U'<<8)|('V')),   //!< Y,U,V (4:2:0)
    Uncompressed_YV12   = (('Y'<<24)|('V'<<16)|('1'<<8)|('2')),   //!< Y,V,U (4:2:0)
@@ -268,7 +271,8 @@ enum ChromaFormat
    Monochrome = 0,
    YUV420,
    YUV422,
    YUV444
    YUV444,
    NumFormats
};

/** @brief Struct providing information about video file format. :
@@ -298,7 +302,7 @@ public:
    If no frames has been grabbed (there are no more frames in video file), the methods return false .
    The method throws Exception if error occurs.
     */
    CV_WRAP virtual bool nextFrame(OutputArray frame) = 0;
    CV_WRAP virtual bool nextFrame(OutputArray frame, Stream &stream = Stream::Null()) = 0;

    /** @brief Returns information about video file format.
    */
@@ -318,9 +322,8 @@ public:

    @param data Pointer to frame data.
    @param size Size in bytes of current frame.
    @param endOfFile Indicates that it is end of stream.
     */
    virtual bool getNextPacket(unsigned char** data, int* size, bool* endOfFile) = 0;
    virtual bool getNextPacket(unsigned char** data, size_t* size) = 0;

    /** @brief Returns information about video file format.
    */
+11 −4
Original line number Diff line number Diff line
@@ -46,14 +46,21 @@

namespace opencv_test { namespace {

#if defined(HAVE_NVCUVID)

#if defined(HAVE_FFMPEG_WRAPPER) // should this be set in preprocessor or in cvconfig.h
#define VIDEO_SRC Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi")
#else
// CUDA demuxer has to fall back to ffmpeg to process "gpu/video/768x576.avi"
#define VIDEO_SRC Values( "gpu/video/1920x1080.avi")
#endif

DEF_PARAM_TEST_1(FileName, string);

//////////////////////////////////////////////////////
// VideoReader

#if defined(HAVE_NVCUVID)

PERF_TEST_P(FileName, VideoReader, Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"))
PERF_TEST_P(FileName, VideoReader, VIDEO_SRC)
{
    declare.time(20);

@@ -89,7 +96,7 @@ PERF_TEST_P(FileName, VideoReader, Values("gpu/video/768x576.avi", "gpu/video/19

#if defined(HAVE_NVCUVID) && defined(_WIN32)

PERF_TEST_P(FileName, VideoWriter, Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"))
PERF_TEST_P(FileName, VideoWriter, VIDEO_SRC)
{
    declare.time(30);

+5 −4
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@
using namespace cv;
using namespace cv::cudev;

void videoDecPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame, int width, int height);
void videoDecPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame, int width, int height, cudaStream_t stream);

namespace
{
@@ -186,7 +186,7 @@ namespace
    }
}

void videoDecPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame, int width, int height)
void videoDecPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame, int width, int height, cudaStream_t stream)
{
    // Final Stage: NV12toARGB color space conversion

@@ -196,11 +196,12 @@ void videoDecPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame,
    dim3 block(32, 8);
    dim3 grid(divUp(width, 2 * block.x), divUp(height, block.y));

    NV12_to_RGB<<<grid, block>>>(decodedFrame.ptr<uchar>(), decodedFrame.step,
    NV12_to_RGB<<<grid, block, 0, stream>>>(decodedFrame.ptr<uchar>(), decodedFrame.step,
                                 outFrame.ptr<uint>(), outFrame.step,
                                 width, height);

    CV_CUDEV_SAFE_CALL( cudaGetLastError() );
    if (stream == 0)
      CV_CUDEV_SAFE_CALL( cudaDeviceSynchronize() );
}

+1 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ cv::cudacodec::detail::CuvidVideoSource::CuvidVideoSource(const String& fname)
    CUVIDEOFORMAT vidfmt;
    cuSafeCall( cuvidGetSourceVideoFormat(videoSource_, &vidfmt, 0) );

    CV_Assert(Codec::NumCodecs == cudaVideoCodec::cudaVideoCodec_NumCodecs);
    format_.codec = static_cast<Codec>(vidfmt.codec);
    format_.chromaFormat = static_cast<ChromaFormat>(vidfmt.chroma_format);
    format_.nBitDepthMinus8 = vidfmt.bit_depth_luma_minus8;
+80 −64
Original line number Diff line number Diff line
@@ -44,82 +44,100 @@
#include "precomp.hpp"

#ifdef HAVE_NVCUVID

using namespace cv;
using namespace cv::cudacodec;
using namespace cv::cudacodec::detail;

namespace
{
    Create_InputMediaStream_FFMPEG_Plugin create_InputMediaStream_FFMPEG_p = 0;
    Release_InputMediaStream_FFMPEG_Plugin release_InputMediaStream_FFMPEG_p = 0;
    Read_InputMediaStream_FFMPEG_Plugin read_InputMediaStream_FFMPEG_p = 0;
#ifndef CV_FOURCC_MACRO
#define CV_FOURCC_MACRO(c1, c2, c3, c4) (((c1) & 255) + (((c2) & 255) << 8) + (((c3) & 255) << 16) + (((c4) & 255) << 24))
#endif

    bool init_MediaStream_FFMPEG()
static std::string fourccToString(int fourcc)
{
        static bool initialized = 0;
    union {
        int u32;
        unsigned char c[4];
    } i32_c;
    i32_c.u32 = fourcc;
    return cv::format("%c%c%c%c",
        (i32_c.c[0] >= ' ' && i32_c.c[0] < 128) ? i32_c.c[0] : '?',
        (i32_c.c[1] >= ' ' && i32_c.c[1] < 128) ? i32_c.c[1] : '?',
        (i32_c.c[2] >= ' ' && i32_c.c[2] < 128) ? i32_c.c[2] : '?',
        (i32_c.c[3] >= ' ' && i32_c.c[3] < 128) ? i32_c.c[3] : '?');
}

        if (!initialized)
static
Codec FourccToCodec(int codec)
{
            #if defined _WIN32
                const char* module_name = "opencv_ffmpeg"
                    CVAUX_STR(CV_VERSION_MAJOR) CVAUX_STR(CV_VERSION_MINOR) CVAUX_STR(CV_VERSION_REVISION)
                #if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__)
                    "_64"
                #endif
                    ".dll";

                static HMODULE cvFFOpenCV = LoadLibrary(module_name);

                if (cvFFOpenCV)
    switch (codec)
    {
                    create_InputMediaStream_FFMPEG_p =
                        (Create_InputMediaStream_FFMPEG_Plugin)GetProcAddress(cvFFOpenCV, "create_InputMediaStream_FFMPEG");
                    release_InputMediaStream_FFMPEG_p =
                        (Release_InputMediaStream_FFMPEG_Plugin)GetProcAddress(cvFFOpenCV, "release_InputMediaStream_FFMPEG");
                    read_InputMediaStream_FFMPEG_p =
                        (Read_InputMediaStream_FFMPEG_Plugin)GetProcAddress(cvFFOpenCV, "read_InputMediaStream_FFMPEG");

                    initialized = create_InputMediaStream_FFMPEG_p != 0 && release_InputMediaStream_FFMPEG_p != 0 && read_InputMediaStream_FFMPEG_p != 0;
    case CV_FOURCC_MACRO('m', 'p', 'e', 'g'): // fallthru
    case CV_FOURCC_MACRO('M', 'P', 'G', '1'): return MPEG1;
    case CV_FOURCC_MACRO('M', 'P', 'G', '2'): return MPEG2;
    case CV_FOURCC_MACRO('X', 'V', 'I', 'D'): // fallthru
    case CV_FOURCC_MACRO('D', 'I', 'V', 'X'): return MPEG4;
    case CV_FOURCC_MACRO('W', 'V', 'C', '1'): return VC1;
    case CV_FOURCC_MACRO('H', '2', '6', '4'): // fallthru
    case CV_FOURCC_MACRO('h', '2', '6', '4'): // fallthru
    case CV_FOURCC_MACRO('a', 'v', 'c', '1'): return H264;
    case CV_FOURCC_MACRO('H', '2', '6', '5'): // fallthru
    case CV_FOURCC_MACRO('h', '2', '6', '5'): // fallthru
    case CV_FOURCC_MACRO('h', 'e', 'v', 'c'): return HEVC;
    case CV_FOURCC_MACRO('M', 'J', 'P', 'G'): return JPEG;
    case CV_FOURCC_MACRO('V', 'P', '8', '0'): return VP8;
    case CV_FOURCC_MACRO('V', 'P', '9', '0'): return VP9;
    default:
        break;
    }
            #elif defined HAVE_FFMPEG
                create_InputMediaStream_FFMPEG_p = create_InputMediaStream_FFMPEG;
                release_InputMediaStream_FFMPEG_p = release_InputMediaStream_FFMPEG;
                read_InputMediaStream_FFMPEG_p = read_InputMediaStream_FFMPEG;

                initialized = true;
            #endif
    std::string msg = cv::format("Unknown codec FOURCC: 0x%08X (%s)", codec, fourccToString(codec).c_str());
    CV_LOG_WARNING(NULL, msg);
    CV_Error(Error::StsUnsupportedFormat, msg);
}

        return initialized;
static
void FourccToChromaFormat(const int pixelFormat, ChromaFormat &chromaFormat, int & nBitDepthMinus8)
{
    switch (pixelFormat)
    {
    case CV_FOURCC_MACRO('I', '4', '2', '0'):
        chromaFormat = YUV420;
        nBitDepthMinus8 = 0;
        break;
    default:
        CV_LOG_WARNING(NULL, cv::format("ChromaFormat not recognized: 0x%08X (%s). Assuming I420", pixelFormat, fourccToString(pixelFormat).c_str()));
        chromaFormat = YUV420;
        nBitDepthMinus8 = 0;
        break;
    }
}

cv::cudacodec::detail::FFmpegVideoSource::FFmpegVideoSource(const String& fname) :
    stream_(0)
cv::cudacodec::detail::FFmpegVideoSource::FFmpegVideoSource(const String& fname)
{
    CV_Assert( init_MediaStream_FFMPEG() );
    if (!videoio_registry::hasBackend(CAP_FFMPEG))
        CV_Error(Error::StsNotImplemented, "FFmpeg backend not found");

    int codec;
    int chroma_format;
    int width;
    int height;

    stream_ = create_InputMediaStream_FFMPEG_p(fname.c_str(), &codec, &chroma_format, &width, &height);
    if (!stream_)
    cap.open(fname, CAP_FFMPEG);
    if (!cap.isOpened())
        CV_Error(Error::StsUnsupportedFormat, "Unsupported video source");

    format_.codec = static_cast<Codec>(codec);
    format_.chromaFormat = static_cast<ChromaFormat>(chroma_format);
    format_.nBitDepthMinus8 = -1;
    format_.width = width;
    format_.height = height;
    if (!cap.set(CAP_PROP_FORMAT, -1))  // turn off video decoder (extract stream)
        CV_Error(Error::StsUnsupportedFormat, "Fetching of RAW video streams is not supported");
    CV_Assert(cap.get(CAP_PROP_FORMAT) == -1);

    int codec = (int)cap.get(CAP_PROP_FOURCC);
    int pixelFormat = (int)cap.get(CAP_PROP_CODEC_PIXEL_FORMAT);

    format_.codec = FourccToCodec(codec);
    format_.height = cap.get(CAP_PROP_FRAME_HEIGHT);
    format_.width = cap.get(CAP_PROP_FRAME_WIDTH);
    FourccToChromaFormat(pixelFormat, format_.chromaFormat, format_.nBitDepthMinus8);
}

cv::cudacodec::detail::FFmpegVideoSource::~FFmpegVideoSource()
{
    if (stream_)
        release_InputMediaStream_FFMPEG_p(stream_);
    if (cap.isOpened())
        cap.release();
}

FormatInfo cv::cudacodec::detail::FFmpegVideoSource::format() const
@@ -127,14 +145,12 @@ FormatInfo cv::cudacodec::detail::FFmpegVideoSource::format() const
    return format_;
}

bool cv::cudacodec::detail::FFmpegVideoSource::getNextPacket(unsigned char** data, int* size, bool* bEndOfFile)
bool cv::cudacodec::detail::FFmpegVideoSource::getNextPacket(unsigned char** data, size_t* size)
{
    int endOfFile;

    int res = read_InputMediaStream_FFMPEG_p(stream_, data, size, &endOfFile);

    *bEndOfFile = (endOfFile != 0);
    return res != 0;
    cap >> rawFrame;
    *data = rawFrame.data;
    *size = rawFrame.total();
    return *size != 0;
}

#endif // HAVE_CUDA
Loading