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 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
16 // Third party copyrights are property of their respective owners.
17 //
18 // Redistribution and use in source and binary forms, with or without modification,
19 // are permitted provided that the following conditions are met:
20 //
21 //   * Redistribution's of source code must retain the above copyright notice,
22 //     this list of conditions and the following disclaimer.
23 //
24 //   * Redistribution's in binary form must reproduce the above copyright notice,
25 //     this list of conditions and the following disclaimer in the documentation
26 //     and/or other materials provided with the distribution.
27 //
28 //   * The name of the copyright holders may not be used to endorse or promote products
29 //     derived from this software without specific prior written permission.
30 //
31 // This software is provided by the copyright holders and contributors "as is" and
32 // any express or implied warranties, including, but not limited to, the implied
33 // warranties of merchantability and fitness for a particular purpose are disclaimed.
34 // In no event shall the Intel Corporation or contributors be liable for any direct,
35 // indirect, incidental, special, exemplary, or consequential damages
36 // (including, but not limited to, procurement of substitute goods or services;
37 // loss of use, data, or profits; or business interruption) however caused
38 // and on any theory of liability, whether in contract, strict liability,
39 // or tort (including negligence or otherwise) arising in any way out of
40 // the use of this software, even if advised of the possibility of such damage.
41 //
42 //M*/
43 
44 #include "precomp.hpp"
45 
46 #ifdef HAVE_NVCUVID
47 
VideoParser(VideoDecoder * videoDecoder,FrameQueue * frameQueue)48 cv::cudacodec::detail::VideoParser::VideoParser(VideoDecoder* videoDecoder, FrameQueue* frameQueue) :
49     videoDecoder_(videoDecoder), frameQueue_(frameQueue), unparsedPackets_(0), hasError_(false)
50 {
51     CUVIDPARSERPARAMS params;
52     std::memset(&params, 0, sizeof(CUVIDPARSERPARAMS));
53 
54     params.CodecType              = videoDecoder->codec();
55     params.ulMaxNumDecodeSurfaces = videoDecoder->maxDecodeSurfaces();
56     params.ulMaxDisplayDelay      = 1; // this flag is needed so the parser will push frames out to the decoder as quickly as it can
57     params.pUserData              = this;
58     params.pfnSequenceCallback    = HandleVideoSequence;    // Called before decoding frames and/or whenever there is a format change
59     params.pfnDecodePicture       = HandlePictureDecode;    // Called when a picture is ready to be decoded (decode order)
60     params.pfnDisplayPicture      = HandlePictureDisplay;   // Called whenever a picture is ready to be displayed (display order)
61 
62     cuSafeCall( cuvidCreateVideoParser(&parser_, &params) );
63 }
64 
parseVideoData(const unsigned char * data,size_t size,bool endOfStream)65 bool cv::cudacodec::detail::VideoParser::parseVideoData(const unsigned char* data, size_t size, bool endOfStream)
66 {
67     CUVIDSOURCEDATAPACKET packet;
68     std::memset(&packet, 0, sizeof(CUVIDSOURCEDATAPACKET));
69 
70     if (endOfStream)
71         packet.flags |= CUVID_PKT_ENDOFSTREAM;
72 
73     packet.payload_size = static_cast<unsigned long>(size);
74     packet.payload = data;
75 
76     if (cuvidParseVideoData(parser_, &packet) != CUDA_SUCCESS)
77     {
78         hasError_ = true;
79         frameQueue_->endDecode();
80         return false;
81     }
82 
83     const int maxUnparsedPackets = 20;
84 
85     ++unparsedPackets_;
86     if (unparsedPackets_ > maxUnparsedPackets)
87     {
88         hasError_ = true;
89         frameQueue_->endDecode();
90         return false;
91     }
92 
93     if (endOfStream)
94         frameQueue_->endDecode();
95 
96     return !frameQueue_->isEndOfDecode();
97 }
98 
HandleVideoSequence(void * userData,CUVIDEOFORMAT * format)99 int CUDAAPI cv::cudacodec::detail::VideoParser::HandleVideoSequence(void* userData, CUVIDEOFORMAT* format)
100 {
101     VideoParser* thiz = static_cast<VideoParser*>(userData);
102 
103     thiz->unparsedPackets_ = 0;
104 
105     if (format->codec         != thiz->videoDecoder_->codec()       ||
106         format->coded_width   != thiz->videoDecoder_->frameWidth()  ||
107         format->coded_height  != thiz->videoDecoder_->frameHeight() ||
108         format->chroma_format != thiz->videoDecoder_->chromaFormat()||
109         format->bit_depth_luma_minus8 != thiz->videoDecoder_->nBitDepthMinus8())
110     {
111         FormatInfo newFormat;
112 
113         newFormat.codec = static_cast<Codec>(format->codec);
114         newFormat.chromaFormat = static_cast<ChromaFormat>(format->chroma_format);
115         newFormat.width = format->coded_width;
116         newFormat.height = format->coded_height;
117         newFormat.nBitDepthMinus8 = format->bit_depth_luma_minus8;
118 
119         try
120         {
121             thiz->videoDecoder_->release();
122             thiz->videoDecoder_->create(newFormat);
123         }
124         catch (const cv::Exception&)
125         {
126             thiz->hasError_ = true;
127             return false;
128         }
129     }
130 
131     return true;
132 }
133 
HandlePictureDecode(void * userData,CUVIDPICPARAMS * picParams)134 int CUDAAPI cv::cudacodec::detail::VideoParser::HandlePictureDecode(void* userData, CUVIDPICPARAMS* picParams)
135 {
136     VideoParser* thiz = static_cast<VideoParser*>(userData);
137 
138     thiz->unparsedPackets_ = 0;
139 
140     bool isFrameAvailable = thiz->frameQueue_->waitUntilFrameAvailable(picParams->CurrPicIdx);
141 
142     if (!isFrameAvailable)
143         return false;
144 
145     if (!thiz->videoDecoder_->decodePicture(picParams))
146     {
147         thiz->hasError_ = true;
148         return false;
149     }
150 
151     return true;
152 }
153 
HandlePictureDisplay(void * userData,CUVIDPARSERDISPINFO * picParams)154 int CUDAAPI cv::cudacodec::detail::VideoParser::HandlePictureDisplay(void* userData, CUVIDPARSERDISPINFO* picParams)
155 {
156     VideoParser* thiz = static_cast<VideoParser*>(userData);
157 
158     thiz->unparsedPackets_ = 0;
159 
160     thiz->frameQueue_->enqueue(picParams);
161 
162     return true;
163 }
164 
165 #endif // HAVE_NVCUVID
166