Home | History | Annotate | Download | only in src
      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