1 /*M/////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4 // 5 // By downloading, copying, installing or using the software you agree to this license. 6 // If you do not agree to this license, do not download, install, 7 // copy or use the software. 8 // 9 // 10 // License Agreement 11 // For Open Source Computer Vision Library 12 // 13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. 14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved. 15 // Third party copyrights are property of their respective owners. 16 // 17 // Redistribution and use in source and binary forms, with or without modification, 18 // are permitted provided that the following conditions are met: 19 // 20 // * Redistribution's of source code must retain the above copyright notice, 21 // this list of conditions and the following disclaimer. 22 // 23 // * Redistribution's in binary form must reproduce the above copyright notice, 24 // this list of conditions and the following disclaimer in the documentation 25 // and/or other materials provided with the distribution. 26 // 27 // * The name of the copyright holders may not be used to endorse or promote products 28 // derived from this software without specific prior written permission. 29 // 30 // This software is provided by the copyright holders and contributors "as is" and 31 // any express or implied warranties, including, but not limited to, the implied 32 // warranties of merchantability and fitness for a particular purpose are disclaimed. 33 // In no event shall the Intel Corporation or contributors be liable for any direct, 34 // indirect, incidental, special, exemplary, or consequential damages 35 // (including, but not limited to, procurement of substitute goods or services; 36 // loss of use, data, or profits; or business interruption) however caused 37 // and on any theory of liability, whether in contract, strict liability, 38 // or tort (including negligence or otherwise) arising in any way out of 39 // the use of this software, even if advised of the possibility of such damage. 40 // 41 //M*/ 42 43 #include "precomp.hpp" 44 45 using namespace cv; 46 using namespace cv::cuda; 47 using namespace cv::cudacodec; 48 49 #ifndef HAVE_NVCUVID 50 51 Ptr<VideoReader> cv::cudacodec::createVideoReader(const String&) { throw_no_cuda(); return Ptr<VideoReader>(); } 52 Ptr<VideoReader> cv::cudacodec::createVideoReader(const Ptr<RawVideoSource>&) { throw_no_cuda(); return Ptr<VideoReader>(); } 53 54 #else // HAVE_NVCUVID 55 56 void videoDecPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame, int width, int height); 57 58 using namespace cv::cudacodec::detail; 59 60 namespace 61 { 62 class VideoReaderImpl : public VideoReader 63 { 64 public: 65 explicit VideoReaderImpl(const Ptr<VideoSource>& source); 66 ~VideoReaderImpl(); 67 68 bool nextFrame(OutputArray frame); 69 70 FormatInfo format() const; 71 72 private: 73 Ptr<VideoSource> videoSource_; 74 75 Ptr<FrameQueue> frameQueue_; 76 Ptr<VideoDecoder> videoDecoder_; 77 Ptr<VideoParser> videoParser_; 78 79 CUvideoctxlock lock_; 80 81 std::deque< std::pair<CUVIDPARSERDISPINFO, CUVIDPROCPARAMS> > frames_; 82 }; 83 84 FormatInfo VideoReaderImpl::format() const 85 { 86 return videoSource_->format(); 87 } 88 89 VideoReaderImpl::VideoReaderImpl(const Ptr<VideoSource>& source) : 90 videoSource_(source), 91 lock_(0) 92 { 93 // init context 94 GpuMat temp(1, 1, CV_8UC1); 95 temp.release(); 96 97 CUcontext ctx; 98 cuSafeCall( cuCtxGetCurrent(&ctx) ); 99 cuSafeCall( cuvidCtxLockCreate(&lock_, ctx) ); 100 101 frameQueue_.reset(new FrameQueue); 102 videoDecoder_.reset(new VideoDecoder(videoSource_->format(), lock_)); 103 videoParser_.reset(new VideoParser(videoDecoder_, frameQueue_)); 104 105 videoSource_->setVideoParser(videoParser_); 106 videoSource_->start(); 107 } 108 109 VideoReaderImpl::~VideoReaderImpl() 110 { 111 frameQueue_->endDecode(); 112 videoSource_->stop(); 113 } 114 115 class VideoCtxAutoLock 116 { 117 public: 118 VideoCtxAutoLock(CUvideoctxlock lock) : m_lock(lock) { cuSafeCall( cuvidCtxLock(m_lock, 0) ); } 119 ~VideoCtxAutoLock() { cuvidCtxUnlock(m_lock, 0); } 120 121 private: 122 CUvideoctxlock m_lock; 123 }; 124 125 bool VideoReaderImpl::nextFrame(OutputArray frame) 126 { 127 if (videoSource_->hasError() || videoParser_->hasError()) 128 CV_Error(Error::StsUnsupportedFormat, "Unsupported video source"); 129 130 if (!videoSource_->isStarted() || frameQueue_->isEndOfDecode()) 131 return false; 132 133 if (frames_.empty()) 134 { 135 CUVIDPARSERDISPINFO displayInfo; 136 137 for (;;) 138 { 139 if (frameQueue_->dequeue(displayInfo)) 140 break; 141 142 if (videoSource_->hasError() || videoParser_->hasError()) 143 CV_Error(Error::StsUnsupportedFormat, "Unsupported video source"); 144 145 if (frameQueue_->isEndOfDecode()) 146 return false; 147 148 // Wait a bit 149 Thread::sleep(1); 150 } 151 152 bool isProgressive = displayInfo.progressive_frame != 0; 153 const int num_fields = isProgressive ? 1 : 2 + displayInfo.repeat_first_field; 154 155 for (int active_field = 0; active_field < num_fields; ++active_field) 156 { 157 CUVIDPROCPARAMS videoProcParams; 158 std::memset(&videoProcParams, 0, sizeof(CUVIDPROCPARAMS)); 159 160 videoProcParams.progressive_frame = displayInfo.progressive_frame; 161 videoProcParams.second_field = active_field; 162 videoProcParams.top_field_first = displayInfo.top_field_first; 163 videoProcParams.unpaired_field = (num_fields == 1); 164 165 frames_.push_back(std::make_pair(displayInfo, videoProcParams)); 166 } 167 } 168 169 if (frames_.empty()) 170 return false; 171 172 std::pair<CUVIDPARSERDISPINFO, CUVIDPROCPARAMS> frameInfo = frames_.front(); 173 frames_.pop_front(); 174 175 { 176 VideoCtxAutoLock autoLock(lock_); 177 178 // map decoded video frame to CUDA surface 179 GpuMat decodedFrame = videoDecoder_->mapFrame(frameInfo.first.picture_index, frameInfo.second); 180 181 // perform post processing on the CUDA surface (performs colors space conversion and post processing) 182 // comment this out if we inclue the line of code seen above 183 videoDecPostProcessFrame(decodedFrame, frame, videoDecoder_->targetWidth(), videoDecoder_->targetHeight()); 184 185 // unmap video frame 186 // unmapFrame() synchronizes with the VideoDecode API (ensures the frame has finished decoding) 187 videoDecoder_->unmapFrame(decodedFrame); 188 } 189 190 // release the frame, so it can be re-used in decoder 191 if (frames_.empty()) 192 frameQueue_->releaseFrame(frameInfo.first); 193 194 return true; 195 } 196 } 197 198 Ptr<VideoReader> cv::cudacodec::createVideoReader(const String& filename) 199 { 200 CV_Assert( !filename.empty() ); 201 202 Ptr<VideoSource> videoSource; 203 204 try 205 { 206 videoSource.reset(new CuvidVideoSource(filename)); 207 } 208 catch (...) 209 { 210 Ptr<RawVideoSource> source(new FFmpegVideoSource(filename)); 211 videoSource.reset(new RawVideoSourceWrapper(source)); 212 } 213 214 return makePtr<VideoReaderImpl>(videoSource); 215 } 216 217 Ptr<VideoReader> cv::cudacodec::createVideoReader(const Ptr<RawVideoSource>& source) 218 { 219 Ptr<VideoSource> videoSource(new RawVideoSourceWrapper(source)); 220 return makePtr<VideoReaderImpl>(videoSource); 221 } 222 223 #endif // HAVE_NVCUVID 224