Merge remote-tracking branch 'upstream/3.4' into merge-3.4
[platform/upstream/opencv.git] / modules / videoio / src / cap_mjpeg_decoder.cpp
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) 2015, OpenCV Foundation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "precomp.hpp"
43 #include "opencv2/videoio/container_avi.private.hpp"
44
45 namespace cv
46 {
47
48 class MotionJpegCapture: public IVideoCapture
49 {
50 public:
51     virtual ~MotionJpegCapture() CV_OVERRIDE;
52     virtual double getProperty(int) const CV_OVERRIDE;
53     virtual bool setProperty(int, double) CV_OVERRIDE;
54     virtual bool grabFrame() CV_OVERRIDE;
55     virtual bool retrieveFrame(int, OutputArray) CV_OVERRIDE;
56     virtual bool isOpened() const CV_OVERRIDE;
57     virtual int getCaptureDomain() CV_OVERRIDE { return CAP_OPENCV_MJPEG; }
58     MotionJpegCapture(const String&);
59
60     bool open(const String&);
61     void close();
62 protected:
63
64     inline uint64_t getFramePos() const;
65
66     Ptr<AVIReadContainer> m_avi_container;
67     bool             m_is_first_frame;
68     frame_list       m_mjpeg_frames;
69
70     frame_iterator   m_frame_iterator;
71     Mat              m_current_frame;
72
73     //frame width/height and fps could be different for
74     //each frame/stream. At the moment we suppose that they
75     //stays the same within single avi file.
76     uint32_t         m_frame_width;
77     uint32_t         m_frame_height;
78     double           m_fps;
79 };
80
81 uint64_t MotionJpegCapture::getFramePos() const
82 {
83     if(m_is_first_frame)
84         return 0;
85
86     if(m_frame_iterator == m_mjpeg_frames.end())
87         return m_mjpeg_frames.size();
88
89     return m_frame_iterator - m_mjpeg_frames.begin() + 1;
90 }
91
92 bool MotionJpegCapture::setProperty(int property, double value)
93 {
94     if(property == CAP_PROP_POS_FRAMES)
95     {
96         if(int(value) == 0)
97         {
98             m_is_first_frame = true;
99             m_frame_iterator = m_mjpeg_frames.end();
100             return true;
101         }
102         else if(m_mjpeg_frames.size() > value)
103         {
104             m_frame_iterator = m_mjpeg_frames.begin() + int(value - 1);
105             m_is_first_frame = false;
106             return true;
107         }
108     }
109
110     return false;
111 }
112
113 double MotionJpegCapture::getProperty(int property) const
114 {
115     switch(property)
116     {
117         case CAP_PROP_POS_FRAMES:
118             return (double)getFramePos();
119         case CAP_PROP_POS_MSEC:
120             return (double)getFramePos() * (1000. / m_fps);
121         case CAP_PROP_POS_AVI_RATIO:
122             return double(getFramePos())/m_mjpeg_frames.size();
123         case CAP_PROP_FRAME_WIDTH:
124             return (double)m_frame_width;
125         case CAP_PROP_FRAME_HEIGHT:
126             return (double)m_frame_height;
127         case CAP_PROP_FPS:
128             return m_fps;
129         case CAP_PROP_FOURCC:
130             return (double)CV_FOURCC('M','J','P','G');
131         case CAP_PROP_FRAME_COUNT:
132             return (double)m_mjpeg_frames.size();
133         case CAP_PROP_FORMAT:
134             return 0;
135         default:
136             return 0;
137     }
138 }
139
140 bool MotionJpegCapture::grabFrame()
141 {
142     if(isOpened())
143     {
144         if(m_is_first_frame)
145         {
146             m_is_first_frame = false;
147             m_frame_iterator = m_mjpeg_frames.begin();
148         }
149         else
150         {
151             if (m_frame_iterator == m_mjpeg_frames.end())
152                 return false;
153
154             ++m_frame_iterator;
155         }
156     }
157
158     return m_frame_iterator != m_mjpeg_frames.end();
159 }
160
161 bool MotionJpegCapture::retrieveFrame(int, OutputArray output_frame)
162 {
163     if(m_frame_iterator != m_mjpeg_frames.end())
164     {
165         std::vector<char> data = m_avi_container->readFrame(m_frame_iterator);
166
167         if(data.size())
168         {
169             m_current_frame = imdecode(data, IMREAD_ANYDEPTH | IMREAD_COLOR | IMREAD_IGNORE_ORIENTATION);
170         }
171
172         m_current_frame.copyTo(output_frame);
173
174         return true;
175     }
176
177     return false;
178 }
179
180 MotionJpegCapture::~MotionJpegCapture()
181 {
182     close();
183 }
184
185 MotionJpegCapture::MotionJpegCapture(const String& filename)
186 {
187     m_avi_container = makePtr<AVIReadContainer>();
188     m_avi_container->initStream(filename);
189     open(filename);
190 }
191
192 bool MotionJpegCapture::isOpened() const
193 {
194     return m_mjpeg_frames.size() > 0;
195 }
196
197 void MotionJpegCapture::close()
198 {
199     m_avi_container->close();
200     m_frame_iterator = m_mjpeg_frames.end();
201 }
202
203 bool MotionJpegCapture::open(const String& filename)
204 {
205     close();
206
207     m_avi_container = makePtr<AVIReadContainer>();
208     m_avi_container->initStream(filename);
209
210     m_frame_iterator = m_mjpeg_frames.end();
211     m_is_first_frame = true;
212
213     if(!m_avi_container->parseRiff(m_mjpeg_frames))
214     {
215         close();
216     } else
217     {
218         m_frame_width = m_avi_container->getWidth();
219         m_frame_height = m_avi_container->getHeight();
220         m_fps = m_avi_container->getFps();
221     }
222
223     return isOpened();
224 }
225
226 Ptr<IVideoCapture> createMotionJpegCapture(const String& filename)
227 {
228     Ptr<MotionJpegCapture> mjdecoder(new MotionJpegCapture(filename));
229     if( mjdecoder->isOpened() )
230         return mjdecoder;
231     return Ptr<MotionJpegCapture>();
232 }
233
234 }