1793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler/*M///////////////////////////////////////////////////////////////////////////////////////
2793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
3793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
5793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//  By downloading, copying, installing or using the software you agree to this license.
6793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//  If you do not agree to this license, do not download, install,
7793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//  copy or use the software.
8793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
9793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
10793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//                           License Agreement
11793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//                For Open Source Computer Vision Library
12793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
13793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Third party copyrights are property of their respective owners.
16793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
17793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// Redistribution and use in source and binary forms, with or without modification,
18793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// are permitted provided that the following conditions are met:
19793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
20793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//   * Redistribution's of source code must retain the above copyright notice,
21793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//     this list of conditions and the following disclaimer.
22793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
23793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//   * Redistribution's in binary form must reproduce the above copyright notice,
24793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//     this list of conditions and the following disclaimer in the documentation
25793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//     and/or other materials provided with the distribution.
26793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
27793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//   * The name of the copyright holders may not be used to endorse or promote products
28793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//     derived from this software without specific prior written permission.
29793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
30793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// This software is provided by the copyright holders and contributors "as is" and
31793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// any express or implied warranties, including, but not limited to, the implied
32793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// warranties of merchantability and fitness for a particular purpose are disclaimed.
33793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// In no event shall the Intel Corporation or contributors be liable for any direct,
34793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// indirect, incidental, special, exemplary, or consequential damages
35793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// (including, but not limited to, procurement of substitute goods or services;
36793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// loss of use, data, or profits; or business interruption) however caused
37793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// and on any theory of liability, whether in contract, strict liability,
38793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// or tort (including negligence or otherwise) arising in any way out of
39793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler// the use of this software, even if advised of the possibility of such damage.
40793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//
41793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler//M*/
42793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
43793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#include "precomp.hpp"
44793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
45793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerusing namespace cv;
46793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerusing namespace cv::cuda;
47793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerusing namespace cv::cudacodec;
48793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
49793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#ifndef HAVE_NVCUVID
50793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
51793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerPtr<VideoReader> cv::cudacodec::createVideoReader(const String&) { throw_no_cuda(); return Ptr<VideoReader>(); }
52793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerPtr<VideoReader> cv::cudacodec::createVideoReader(const Ptr<RawVideoSource>&) { throw_no_cuda(); return Ptr<VideoReader>(); }
53793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
54793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#else // HAVE_NVCUVID
55793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
56793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslervoid videoDecPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame, int width, int height);
57793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
58793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslerusing namespace cv::cudacodec::detail;
59793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
60793ee12c6df9cad3806238d32528c49a3ff9331dNoah Preslernamespace
61793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
62793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    class VideoReaderImpl : public VideoReader
63793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
64793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    public:
65793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        explicit VideoReaderImpl(const Ptr<VideoSource>& source);
66793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        ~VideoReaderImpl();
67793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
68793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        bool nextFrame(OutputArray frame);
69793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
70793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        FormatInfo format() const;
71793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
72793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    private:
73793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        Ptr<VideoSource> videoSource_;
74793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
75793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        Ptr<FrameQueue> frameQueue_;
76793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        Ptr<VideoDecoder> videoDecoder_;
77793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        Ptr<VideoParser> videoParser_;
78793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
79793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CUvideoctxlock lock_;
80793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
81793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        std::deque< std::pair<CUVIDPARSERDISPINFO, CUVIDPROCPARAMS> > frames_;
82793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    };
83793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
84793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    FormatInfo VideoReaderImpl::format() const
85793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
86793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        return videoSource_->format();
87793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
88793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
89793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    VideoReaderImpl::VideoReaderImpl(const Ptr<VideoSource>& source) :
90793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        videoSource_(source),
91793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        lock_(0)
92793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
93793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        // init context
94793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        GpuMat temp(1, 1, CV_8UC1);
95793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        temp.release();
96793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
97793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CUcontext ctx;
98793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cuSafeCall( cuCtxGetCurrent(&ctx) );
99793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        cuSafeCall( cuvidCtxLockCreate(&lock_, ctx) );
100793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
101793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        frameQueue_.reset(new FrameQueue);
102793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        videoDecoder_.reset(new VideoDecoder(videoSource_->format(), lock_));
103793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        videoParser_.reset(new VideoParser(videoDecoder_, frameQueue_));
104793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
105793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        videoSource_->setVideoParser(videoParser_);
106793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        videoSource_->start();
107793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
108793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
109793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    VideoReaderImpl::~VideoReaderImpl()
110793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
111793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        frameQueue_->endDecode();
112793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        videoSource_->stop();
113793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
114793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
115793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    class VideoCtxAutoLock
116793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
117793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    public:
118793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        VideoCtxAutoLock(CUvideoctxlock lock) : m_lock(lock) { cuSafeCall( cuvidCtxLock(m_lock, 0) ); }
119793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        ~VideoCtxAutoLock() { cuvidCtxUnlock(m_lock, 0); }
120793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
121793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    private:
122793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        CUvideoctxlock m_lock;
123793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    };
124793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
125793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    bool VideoReaderImpl::nextFrame(OutputArray frame)
126793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
127793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if (videoSource_->hasError() || videoParser_->hasError())
128793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CV_Error(Error::StsUnsupportedFormat, "Unsupported video source");
129793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
130793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if (!videoSource_->isStarted() || frameQueue_->isEndOfDecode())
131793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            return false;
132793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
133793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if (frames_.empty())
134793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
135793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            CUVIDPARSERDISPINFO displayInfo;
136793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
137793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for (;;)
138793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
139793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if (frameQueue_->dequeue(displayInfo))
140793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    break;
141793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
142793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if (videoSource_->hasError() || videoParser_->hasError())
143793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    CV_Error(Error::StsUnsupportedFormat, "Unsupported video source");
144793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
145793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                if (frameQueue_->isEndOfDecode())
146793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                    return false;
147793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
148793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                // Wait a bit
149793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                Thread::sleep(1);
150793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
151793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
152793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            bool isProgressive = displayInfo.progressive_frame != 0;
153793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            const int num_fields = isProgressive ? 1 : 2 + displayInfo.repeat_first_field;
154793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
155793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            for (int active_field = 0; active_field < num_fields; ++active_field)
156793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            {
157793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                CUVIDPROCPARAMS videoProcParams;
158793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                std::memset(&videoProcParams, 0, sizeof(CUVIDPROCPARAMS));
159793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
160793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                videoProcParams.progressive_frame = displayInfo.progressive_frame;
161793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                videoProcParams.second_field      = active_field;
162793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                videoProcParams.top_field_first   = displayInfo.top_field_first;
163793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                videoProcParams.unpaired_field    = (num_fields == 1);
164793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
165793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler                frames_.push_back(std::make_pair(displayInfo, videoProcParams));
166793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            }
167793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
168793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
169793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if (frames_.empty())
170793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            return false;
171793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
172793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        std::pair<CUVIDPARSERDISPINFO, CUVIDPROCPARAMS> frameInfo = frames_.front();
173793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        frames_.pop_front();
174793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
175793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        {
176793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            VideoCtxAutoLock autoLock(lock_);
177793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
178793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            // map decoded video frame to CUDA surface
179793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            GpuMat decodedFrame = videoDecoder_->mapFrame(frameInfo.first.picture_index, frameInfo.second);
180793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
181793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            // perform post processing on the CUDA surface (performs colors space conversion and post processing)
182793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            // comment this out if we inclue the line of code seen above
183793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            videoDecPostProcessFrame(decodedFrame, frame, videoDecoder_->targetWidth(), videoDecoder_->targetHeight());
184793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
185793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            // unmap video frame
186793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            // unmapFrame() synchronizes with the VideoDecode API (ensures the frame has finished decoding)
187793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            videoDecoder_->unmapFrame(decodedFrame);
188793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        }
189793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
190793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        // release the frame, so it can be re-used in decoder
191793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        if (frames_.empty())
192793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler            frameQueue_->releaseFrame(frameInfo.first);
193793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
194793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        return true;
195793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
196793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
197793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
198793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerPtr<VideoReader> cv::cudacodec::createVideoReader(const String& filename)
199793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
200793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    CV_Assert( !filename.empty() );
201793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
202793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Ptr<VideoSource> videoSource;
203793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
204793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    try
205793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
206793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        videoSource.reset(new CuvidVideoSource(filename));
207793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
208793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    catch (...)
209793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    {
210793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        Ptr<RawVideoSource> source(new FFmpegVideoSource(filename));
211793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler        videoSource.reset(new RawVideoSourceWrapper(source));
212793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    }
213793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
214793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return makePtr<VideoReaderImpl>(videoSource);
215793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
216793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
217793ee12c6df9cad3806238d32528c49a3ff9331dNoah PreslerPtr<VideoReader> cv::cudacodec::createVideoReader(const Ptr<RawVideoSource>& source)
218793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler{
219793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    Ptr<VideoSource> videoSource(new RawVideoSourceWrapper(source));
220793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler    return makePtr<VideoReaderImpl>(videoSource);
221793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler}
222793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler
223793ee12c6df9cad3806238d32528c49a3ff9331dNoah Presler#endif // HAVE_NVCUVID
224