Ocean
Loading...
Searching...
No Matches
avfoundation/VideoDecoder.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_MEDIA_AVF_VIDEO_DECODER_H
9#define META_OCEAN_MEDIA_AVF_VIDEO_DECODER_H
10
12
13#include "ocean/base/Frame.h"
14#include "ocean/base/Lock.h"
15
16#include <VideoToolbox/VideoToolbox.h>
17
18#include <deque>
19
20namespace Ocean
21{
22
23namespace Media
24{
25
26namespace AVFoundation
27{
28
29/**
30 * Definition of a scoped object holding a CMFormatDescriptionRef object.
31 * The wrapped CMFormatDescriptionRef object will be released automatically once the scoped object does not exist anymore.
32 */
34
35/**
36 * Release function for VTDecompressionSessionRef that invalidates and releases the session.
37 * @param session The session to release
38 */
40{
41 if (session != nullptr)
42 {
43 VTDecompressionSessionInvalidate(session);
44 CFRelease(session);
45 }
46}
47
48/**
49 * Definition of a scoped object holding a VTDecompressionSessionRef object.
50 * The wrapped VTDecompressionSessionRef object will be invalidated and released automatically once the scoped object does not exist anymore.
51 */
53
54/**
55 * This class implements a simple video decoder for iOS/macOS using encoded media samples from memory as input.
56 * The decoder uses Apple's VideoToolbox framework (VTDecompressionSession) for hardware-accelerated decoding.
57 *
58 * Usage:
59 * @code
60 * // a function which is e.g., running in a separate thread
61 * void threadRun()
62 * {
63 * VideoDecoder videoDecoder;
64 *
65 * // initializing the decoder with the input format of the media samples
66 * if (!videoDecoder.initialize("video/avc", 1920u, 1080u))
67 * {
68 * // handle error
69 * }
70 *
71 * if (!videoDecoder.start())
72 * {
73 * // handle error
74 * }
75 *
76 * unsigned int frameIndex = 0u;
77 * double frameRate = 30.0;
78 *
79 * while (true)
80 * {
81 * void* sampleData = nullptr;
82 * size_t sampleSize = 0;
83 *
84 * // external function: function needs to provide the new media samples from an external source - e.g., from an external webcam, a video stream, etc.
85 * if (doesNewInputSampleExist(sampleData, &sampleSize))
86 * {
87 * // presentation time in microseconds
88 * uint64_t presentationTime = uint64_t(1.0e6 * double(frameIndex) / frameRate);
89 *
90 * // we forward the media sample to the decoder, eventually it will be decoded and will be available through decodedFrame()
91 * if (!videoDecoder.pushSample(sampleData, sampleSize, presentationTime))
92 * {
93 * // handle error
94 * }
95 *
96 * ++frameIndex;
97 * }
98 *
99 * // we simply check whether another frame has been decoded (there may be a delay between
100 * Frame newFrame = videoDecoder.popFrame();
101 *
102 * if (newFrame.isValid())
103 * {
104 * // external function: receiving new frames and processes the frames
105 * sendFrameToReceiver(std::move(newFrame));
106 * }
107 * }
108 * }
109 * @endcode
110 * @ingroup mediaavf
111 */
113{
114 protected:
115
116 /**
117 * Definition of a scoped object holding a CMBlockBufferRef object.
118 * The wrapped CMBlockBufferRef object will be released automatically once the scoped object does not exist anymore.
119 */
121
122 /**
123 * Definition of a decoded frame entry.
124 */
126 {
127 /// The decoded frame.
129
130 /// The presentation time in microseconds.
131 int64_t presentationTime_ = 0;
132 };
133
134 public:
135
136 /**
137 * Default constructor creating an un-initialized decoder.
138 */
140
141 /**
142 * Move constructor.
143 * @param videoDecoder The decoder to be moved
144 */
145 inline VideoDecoder(VideoDecoder&& videoDecoder) noexcept;
146
147 /**
148 * Destructs the video decoder and releases all associated resources.
149 */
151
152 /**
153 * Initializes the video decoder with codec configuration data (SPS/PPS for H.264, VPS/SPS/PPS for HEVC).
154 * @param mime The MIME type (Multipurpose Internet Mail Extensions) of the video to be decoded, e.g., "video/avc", "video/hevc", ...
155 * @param width The width of the video to be decoded, in pixel, with range [1, infinity)
156 * @param height The height of the video to be decoded, in pixel, with range [1, infinity)
157 * @param codecConfigData The codec configuration data containing parameter sets (SPS/PPS for H.264), can be nullptr if not available yet
158 * @param codecConfigSize The size of the codec configuration data in bytes, 0 if not available yet
159 * @return True, if succeeded
160 * @see isInitialized().
161 */
162 bool initialize(const std::string& mime, const unsigned int width, const unsigned int height, const void* codecConfigData = nullptr, const size_t codecConfigSize = 0);
163
164 /**
165 * Starts the video decoder.
166 * @return True, if succeeded
167 * @see isStarted().
168 */
169 bool start();
170
171 /**
172 * Stops the video decoder.
173 * @return True, if succeeded
174 */
175 bool stop();
176
177 /**
178 * Adds a new media sample which needs to be decoded to the video decoder.
179 * The decoder needs to be initialized and started.
180 * The presentation time is mainly intended to allow associating the provided encoded media sample with the resulting decoded frame when calling popFrame().
181 * However, it's recommended to define a reasonable presentation time for each sample (e.g., let the first sample start at 0 and increment the time by 1^6/fps for each following sample.
182 * @param data The data of the encoded media sample, must be valid
183 * @param size The size of the encoded media sample, in bytes, with range [1, infinity)
184 * @param presentationTime The presentation time of the sample, in microseconds, with range [0, infinity)
185 * @return True, if succeeded
186 * @see start(), isInitialized(), isStarted().
187 */
188 bool pushSample(const void* data, const size_t size, const uint64_t presentationTime);
189
190 /**
191 * Pops the next decoded frame from the decoder.
192 * Optional the frame's presentation time will be returned, this is the presentation time which was used when the corresponding sample was provided in pushSample().
193 * @param presentationTime Optional resulting presentation time in micro seconds, with range (-infinity, infinity)
194 * @return The resulting frame, invalid if currently no decoded frame is available
195 * @see pushSample().
196 */
197 Frame popFrame(int64_t* presentationTime = nullptr);
198
199 /**
200 * Returns whether this decoder is initialized.
201 * @return True, if so
202 * @see initialize().
203 */
204 inline bool isInitialized() const;
205
206 /**
207 * Returns whether this decoder is currently running.
208 * @return True, if so
209 * @see start().
210 */
211 inline bool isStarted() const;
212
213 /**
214 * Explicitly releases this video decoder.
215 * If the decoder is still running, the decoder will be stopped as well.
216 */
217 void release();
218
219 /**
220 * Move operator.
221 * @param videoDecoder The video decoder to be moved
222 * @return Reference to this object
223 */
224 inline VideoDecoder& operator=(VideoDecoder&& videoDecoder) noexcept;
225
226 protected:
227
228 /**
229 * Disabled copy constructor.
230 */
231 VideoDecoder(const VideoDecoder&) = delete;
232
233 /**
234 * Disabled copy operator.
235 * @return Reference to this object
236 */
238
239 /**
240 * Callback function for decoded frames from VideoToolbox.
241 * @param decompressionOutputRefCon Reference to this decoder
242 * @param sourceFrameRefCon Reference containing the presentation time
243 * @param status The status of the decompression operation
244 * @param infoFlags Information flags
245 * @param imageBuffer The decoded image buffer, may be nullptr on error
246 * @param presentationTimeStamp The presentation time stamp
247 * @param presentationDuration The presentation duration
248 */
249 static void decompressionOutputCallback(void* decompressionOutputRefCon, void* sourceFrameRefCon, OSStatus status, VTDecodeInfoFlags infoFlags, CVImageBufferRef imageBuffer, CMTime presentationTimeStamp, CMTime presentationDuration);
250
251 /**
252 * Translates a MIME type to a CMVideoCodecType.
253 * @param mime The MIME type
254 * @return The corresponding codec type, 0 if not supported
255 */
256 static CMVideoCodecType mimeToCodecType(const std::string& mime);
257
258 protected:
259
260 /// The video format description.
262
263 /// The decompression session.
265
266 /// The queue of decoded frames.
267 std::deque<DecodedFrame> decodedFrames_;
268
269 /// The width of the video.
270 unsigned int width_ = 0u;
271
272 /// The height of the video.
273 unsigned int height_ = 0u;
274
275 /// True, if the decoder is currently started.
276 bool isStarted_ = false;
277
278 /// The decoder's lock.
279 mutable Lock lock_;
280
281 /// The lock for the decoded frames queue.
283};
284
285inline VideoDecoder::VideoDecoder(VideoDecoder&& videoDecoder) noexcept
286{
287 *this = std::move(videoDecoder);
288}
289
291{
292 const ScopedLock scopedLock(lock_);
293
295}
296
297inline bool VideoDecoder::isStarted() const
298{
299 const ScopedLock scopedLock(lock_);
300
301 ocean_assert(!isStarted_ || isInitialized());
302
303 return isStarted_;
304}
305
306inline VideoDecoder& VideoDecoder::operator=(VideoDecoder&& videoDecoder) noexcept
307{
308 if (this != &videoDecoder)
309 {
310 release();
311
312 formatDescription_ = std::move(videoDecoder.formatDescription_);
313 decompressionSession_ = std::move(videoDecoder.decompressionSession_);
314
315 decodedFrames_ = std::move(videoDecoder.decodedFrames_);
316
317 width_ = videoDecoder.width_;
318 videoDecoder.width_ = 0u;
319
320 height_ = videoDecoder.height_;
321 videoDecoder.height_ = 0u;
322
323 isStarted_ = videoDecoder.isStarted_;
324 videoDecoder.isStarted_ = false;
325 }
326
327 return *this;
328}
329
330}
331
332}
333
334}
335
336#endif // META_OCEAN_MEDIA_AVF_VIDEO_DECODER_H
This class implements Ocean's image class.
Definition Frame.h:1879
This class implements a recursive lock object.
Definition Lock.h:31
This class implements a simple video decoder for iOS/macOS using encoded media samples from memory as...
Definition avfoundation/VideoDecoder.h:113
VideoDecoder & operator=(const VideoDecoder &)=delete
Disabled copy operator.
bool start()
Starts the video decoder.
unsigned int width_
The width of the video.
Definition avfoundation/VideoDecoder.h:270
std::deque< DecodedFrame > decodedFrames_
The queue of decoded frames.
Definition avfoundation/VideoDecoder.h:267
Lock decodedFramesLock_
The lock for the decoded frames queue.
Definition avfoundation/VideoDecoder.h:282
~VideoDecoder()
Destructs the video decoder and releases all associated resources.
ScopedCMFormatDescriptionRef formatDescription_
The video format description.
Definition avfoundation/VideoDecoder.h:261
VideoDecoder & operator=(VideoDecoder &&videoDecoder) noexcept
Move operator.
Definition avfoundation/VideoDecoder.h:306
bool pushSample(const void *data, const size_t size, const uint64_t presentationTime)
Adds a new media sample which needs to be decoded to the video decoder.
bool isStarted_
True, if the decoder is currently started.
Definition avfoundation/VideoDecoder.h:276
Lock lock_
The decoder's lock.
Definition avfoundation/VideoDecoder.h:279
void release()
Explicitly releases this video decoder.
bool initialize(const std::string &mime, const unsigned int width, const unsigned int height, const void *codecConfigData=nullptr, const size_t codecConfigSize=0)
Initializes the video decoder with codec configuration data (SPS/PPS for H.264, VPS/SPS/PPS for HEVC)...
static CMVideoCodecType mimeToCodecType(const std::string &mime)
Translates a MIME type to a CMVideoCodecType.
bool isStarted() const
Returns whether this decoder is currently running.
Definition avfoundation/VideoDecoder.h:297
VideoDecoder(const VideoDecoder &)=delete
Disabled copy constructor.
static void decompressionOutputCallback(void *decompressionOutputRefCon, void *sourceFrameRefCon, OSStatus status, VTDecodeInfoFlags infoFlags, CVImageBufferRef imageBuffer, CMTime presentationTimeStamp, CMTime presentationDuration)
Callback function for decoded frames from VideoToolbox.
bool isInitialized() const
Returns whether this decoder is initialized.
Definition avfoundation/VideoDecoder.h:290
VideoDecoder()
Default constructor creating an un-initialized decoder.
bool stop()
Stops the video decoder.
unsigned int height_
The height of the video.
Definition avfoundation/VideoDecoder.h:273
Frame popFrame(int64_t *presentationTime=nullptr)
Pops the next decoded frame from the decoder.
ScopedVTDecompressionSessionRef decompressionSession_
The decompression session.
Definition avfoundation/VideoDecoder.h:264
This class implements a scoped lock object for recursive lock objects.
Definition Lock.h:147
bool isValid() const
Returns whether this scoped object holds a valid object.
Definition ScopedObject.h:460
void releaseVTDecompressionSession(VTDecompressionSessionRef session)
Release function for VTDecompressionSessionRef that invalidates and releases the session.
Definition avfoundation/VideoDecoder.h:39
The namespace covering the entire Ocean framework.
Definition Accessor.h:15
Definition of a decoded frame entry.
Definition avfoundation/VideoDecoder.h:126
int64_t presentationTime_
The presentation time in microseconds.
Definition avfoundation/VideoDecoder.h:131
Frame frame_
The decoded frame.
Definition avfoundation/VideoDecoder.h:128