Ocean
Loading...
Searching...
No Matches
avfoundation/VideoEncoder.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_ENCODER_H
9#define META_OCEAN_MEDIA_AVF_VIDEO_ENCODER_H
10
12
13#include "ocean/base/Frame.h"
14#include "ocean/base/Lock.h"
15
16#include "ocean/math/Numeric.h"
17
18#include <VideoToolbox/VideoToolbox.h>
19
20#include <deque>
21
22namespace Ocean
23{
24
25namespace Media
26{
27
28namespace AVFoundation
29{
30
31/**
32 * This class implements a simple video encoder for iOS/macOS using Ocean::Frame objects as input.
33 * The encoder uses Apple's VideoToolbox framework (VTCompressionSession) for hardware-accelerated encoding.
34 *
35 * Usage:
36 * @code
37 * // a function which is e.g., running in a separate thread
38 * void threadRun()
39 * {
40 * VideoEncoder videoEncoder;
41 *
42 * if (!videoEncoder.initialize(1920u, 1080u))
43 * {
44 * // handle error
45 * }
46 *
47 * if (!videoEncoder.start())
48 * {
49 * // handle error
50 * }
51 *
52 * unsigned int frameIndex = 0u;
53 * double frameRate = 30.0;
54 *
55 * while (true)
56 * {
57 * Frame frame;
58 *
59 * // external function: function needs to provide frames from an external source - e.g., from a camera, a video stream, etc.
60 * if (doesNewFrameExist(frame))
61 * {
62 * // presentation time in microseconds
63 * uint64_t presentationTime = uint64_t(1.0e6 * double(frameIndex) / frameRate);
64 *
65 * // we forward the frame to the encoder, eventually it will be encoded and will be available through popSample()
66 * if (!videoEncoder.pushFrame(frame, presentationTime))
67 * {
68 * // handle error
69 * }
70 *
71 * ++frameIndex;
72 * }
73 *
74 * // we simply check whether another sample has been encoded
75 * VideoEncoder::Sample encodedSample = videoEncoder.popSample();
76 *
77 * if (encodedSample.isValid())
78 * {
79 * // external function: receiving encoded samples and processes them
80 * sendSampleToReceiver(std::move(encodedSample));
81 * }
82 * }
83 * }
84 * @endcode
85 * @ingroup mediaavf
86 */
88{
89 public:
90
91 /// Definition of a 1 Mbps bit rate
92 static constexpr int bitrateMbps1_ = 1000 * 1000;
93
94 /// Definition of a 2 Mbps bit rate
95 static constexpr int bitrateMbps2_ = bitrateMbps1_ * 2;
96
97 /// Definition of a 5 Mbps bit rate
98 static constexpr int bitrateMbps5_ = bitrateMbps1_ * 5;
99
100 /// Definition of a 10 Mbps bit rate
101 static constexpr int bitrateMbps10_ = bitrateMbps1_ * 10;
102
103 /**
104 * Definition of individual buffer flag constants.
105 * Modeled after Android's MediaCodec.BufferInfo for API compatibility.
106 */
107 enum BufferFlags : uint32_t
108 {
109 /// The buffer has no special property.
111 /// Indicates that the (encoded) buffer marked as such contains the data for a key frame.
113 /// Indicates that the buffer marked as such contains codec initialization / codec specific data instead of media data.
115 /// Indicates that the buffer is the last buffer in the stream.
117 /// Indicates that the buffer only contains part of a frame.
119 };
120
121 /**
122 * Definition of an encoded sample.
123 */
124 class Sample
125 {
126 friend class VideoEncoder;
127
128 public:
129
130 /**
131 * Creates an invalid sample.
132 */
133 Sample() = default;
134
135 /**
136 * Move constructor.
137 * @param sample The sample to be moved
138 */
139 inline Sample(Sample&& sample) noexcept;
140
141 /**
142 * Returns whether this sample is valid.
143 * @return True, if so
144 */
145 inline bool isValid() const;
146
147 /**
148 * Returns the encoded data.
149 * @return The encoded data
150 */
151 inline const std::vector<uint8_t>& data() const;
152
153 /**
154 * Returns the presentation time in microseconds.
155 * @return The presentation time
156 */
157 inline int64_t presentationTime() const;
158
159 /**
160 * Returns whether this sample is a key frame.
161 * @return True, if so
162 */
163 inline bool isKeyFrame() const;
164
165 /**
166 * Returns whether this sample contains codec configuration data instead of media data.
167 * @return True, if so
168 */
169 inline bool isConfiguration() const;
170
171 /**
172 * Returns whether this sample marks the end of the stream.
173 * @return True, if so
174 */
175 inline bool isEndOfStream() const;
176
177 /**
178 * Returns whether this sample contains only part of a frame.
179 * @return True, if so
180 */
181 inline bool isPartialFrame() const;
182
183 /**
184 * Move operator.
185 * @param sample The sample to be moved
186 * @return Reference to this object
187 */
188 inline Sample& operator=(Sample&& sample) noexcept;
189
190 /**
191 * Returns whether this sample is valid.
192 * @return True, if so
193 */
194 inline explicit operator bool() const;
195
196 protected:
197
198 /**
199 * Creates a sample with specified data.
200 * @param data The encoded data, will be moved
201 * @param presentationTime The presentation time in microseconds, with range [0, infinity)
202 * @param bufferFlags The buffer flags of the sample
203 */
204 inline Sample(std::vector<uint8_t>&& data, const int64_t presentationTime, const BufferFlags bufferFlags);
205
206 /**
207 * Disabled copy constructor.
208 */
209 Sample(const Sample&) = delete;
210
211 /**
212 * Disabled copy operator.
213 * @return Reference to this object
214 */
215 Sample& operator=(const Sample&) = delete;
216
217 protected:
218
219 /// The encoded data.
220 std::vector<uint8_t> data_;
221
222 /// The presentation time in microseconds.
224
225 /// The buffer flags.
227 };
228
229 /**
230 * Definition of a vector holding sample objects.
231 */
232 using Samples = std::vector<Sample>;
233
234 protected:
235
236 /// Definition of the maximal image width.
237 static constexpr unsigned int maximalWidth_ = 1920u * 8u;
238
239 /// Definition of the maximal image height.
240 static constexpr unsigned int maximalHeight_ = 1080u * 8u;
241
242 /// Definition of the maximal bit rate.
243 static constexpr int maximalBitrate_ = bitrateMbps10_ * 10;
244
245 /**
246 * Release function for VTCompressionSessionRef that invalidates and releases the session.
247 * @param session The session to release
248 */
249 static inline void releaseVTCompressionSession(VTCompressionSessionRef session);
250
251 /**
252 * Definition of a scoped object holding a VTCompressionSessionRef object.
253 * The wrapped VTCompressionSessionRef object will be invalidated and released automatically once the scoped object does not exist anymore.
254 */
256
257 public:
258
259 /**
260 * Default constructor creating an un-initialized encoder.
261 */
263
264 /**
265 * Destructs the video encoder and releases all associated resources.
266 */
268
269 /**
270 * Initializes the video encoder with the specified configuration.
271 * @param width The width of the video to be encoded, in pixel, with range [1, infinity)
272 * @param height The height of the video to be encoded, in pixel, with range [1, infinity)
273 * @param mime The MIME type (Multipurpose Internet Mail Extensions) of the video to be encoded, e.g., "video/avc", "video/hevc", ...
274 * @param frameRate The target frame rate in frames per second, with range (0, infinity), e.g., 30.0
275 * @param bitrate The target bitrate in bits per second, with range [1, infinity), e.g., 5000000 for 5 Mbps
276 * @param iFrameInterval The interval between I-frames (key frames) in seconds: negative value = no key frames after first frame, 0 = all frames are key frames, positive value = key frames every N seconds
277 * @return True, if succeeded
278 * @see isInitialized().
279 */
280 bool initialize(const unsigned int width, const unsigned int height, const std::string& mime = "video/avc", const double frameRate = 30.0, const unsigned int bitrate = bitrateMbps2_, const int iFrameInterval = 1);
281
282 /**
283 * Starts the video encoder.
284 * @return True, if succeeded
285 * @see isStarted().
286 */
287 bool start();
288
289 /**
290 * Stops the video encoder.
291 * @return True, if succeeded
292 */
293 bool stop();
294
295 /**
296 * Adds a new frame which needs to be encoded to the video encoder.
297 * The encoder needs to be initialized and started.
298 * The presentation time is mainly intended to allow associating the provided frame with the resulting encoded sample when calling popSample().
299 * However, it's recommended to define a reasonable presentation time for each frame (e.g., let the first frame start at 0 and increment the time by 1^6/fps for each following frame).
300 * @param frame The frame to be encoded, must be valid
301 * @param presentationTime The presentation time of the frame, in microseconds, with range [0, infinity)
302 * @return True, if succeeded
303 * @see start(), isInitialized(), isStarted().
304 */
305 bool pushFrame(const Frame& frame, const uint64_t presentationTime);
306
307 /**
308 * Returns the next encoded sample if available.
309 * @return The resulting encoded sample, invalid if currently no encoded sample is available
310 * @see pushFrame().
311 */
313
314 /**
315 * Returns whether this encoder is initialized.
316 * @return True, if so
317 * @see initialize().
318 */
319 inline bool isInitialized() const;
320
321 /**
322 * Returns whether this encoder is currently running.
323 * @return True, if so
324 * @see start().
325 */
326 inline bool isStarted() const;
327
328 /**
329 * Explicitly releases this video encoder.
330 * If the encoder is still running, the encoder will be stopped as well.
331 */
332 void release();
333
334 protected:
335
336 /**
337 * Definition of a scoped object holding a CFNumberRef object.
338 * The wrapped CFNumberRef object will be released automatically once the scoped object does not exist anymore.
339 */
341
342 /**
343 * Disabled copy constructor.
344 */
345 VideoEncoder(const VideoEncoder&) = delete;
346
347 /**
348 * Disabled move constructor, a video encoder cannot be moved.
349 * `VTCompressionSessionCreate()` stores the address of the encoder as the reference constant of the output callback, and VideoToolbox provides no way to change it afterwards, so a moved session would keep reporting its samples to the moved-from object.
350 */
352
353 /**
354 * Disabled copy operator.
355 * @return Reference to this object
356 */
358
359 /**
360 * Disabled move operator, a video encoder cannot be moved.
361 * @return Reference to this object
362 */
364
365 /**
366 * Callback function for encoded samples from VideoToolbox.
367 * @param outputCallbackRefCon Reference to this encoder
368 * @param sourceFrameRefCon Reference containing the presentation time
369 * @param status The status of the compression operation
370 * @param infoFlags Information flags
371 * @param sampleBuffer The encoded sample buffer, may be nullptr on error
372 */
373 static void compressionOutputCallback(void* outputCallbackRefCon, void* sourceFrameRefCon, OSStatus status, VTEncodeInfoFlags infoFlags, CMSampleBufferRef sampleBuffer);
374
375 /**
376 * Translates a MIME type to a CMVideoCodecType.
377 * @param mime The MIME type
378 * @return The corresponding codec type, 0 if not supported
379 */
380 static CMVideoCodecType mimeToCodecType(const std::string& mime);
381
382 protected:
383
384 /// The compression session.
386
387 /// The queue of encoded samples.
388 std::deque<Sample> encodedSamples_;
389
390 /// The width of the video.
391 unsigned int width_ = 0u;
392
393 /// The height of the video.
394 unsigned int height_ = 0u;
395
396 /// True, if the encoder is currently started.
397 bool isStarted_ = false;
398
399 /// The encoder's lock.
400 mutable Lock lock_;
401
402 /// The lock for the encoded samples queue.
404
405#ifdef OCEAN_DEBUG
406 /// The previous presentation timestamp submitted via pushFrame(), in microseconds, -1 if no frame has been submitted yet.
408
409 /// The previous presentation timestamp of an encoded sample in the compression callback, in microseconds, NumericT<int64_t>::minValue() if no sample has been encoded yet.
411#endif
412};
413
414inline VideoEncoder::Sample::Sample(std::vector<uint8_t>&& data, const int64_t presentationTime, const BufferFlags bufferFlags) :
415 data_(std::move(data)),
416 presentationTime_(presentationTime),
417 bufferFlags_(bufferFlags)
418{
419 // nothing to do here
420}
421
422inline VideoEncoder::Sample::Sample(Sample&& sample) noexcept
423{
424 *this = std::move(sample);
425}
426
428{
429 return !data_.empty();
430}
431
432inline const std::vector<uint8_t>& VideoEncoder::Sample::data() const
433{
434 return data_;
435}
436
438{
439 return presentationTime_;
440}
441
443{
444 return bufferFlags_ & BUFFER_FLAG_KEY_FRAME;
445}
446
448{
449 return bufferFlags_ & BUFFER_FLAG_CODEC_CONFIG;
450}
451
453{
454 return bufferFlags_ & BUFFER_FLAG_END_OF_STREAM;
455}
456
458{
459 return bufferFlags_ & BUFFER_FLAG_PARTIAL_FRAME;
460}
461
463{
464 if (this != &sample)
465 {
466 data_ = std::move(sample.data_);
467 presentationTime_ = sample.presentationTime_;
468 bufferFlags_ = sample.bufferFlags_;
469
470 sample.presentationTime_ = NumericT<int64_t>::minValue();
471 sample.bufferFlags_ = BUFFER_FLAG_NONE;
472 }
473
474 return *this;
475}
476
477inline VideoEncoder::Sample::operator bool() const
478{
479 return isValid();
480}
481
483{
484 if (session != nullptr)
485 {
486 VTCompressionSessionInvalidate(session);
487 CFRelease(session);
488 }
489}
490
492{
493 const ScopedLock scopedLock(lock_);
494
496}
497
498inline bool VideoEncoder::isStarted() const
499{
500 const ScopedLock scopedLock(lock_);
501
502 ocean_assert(!isStarted_ || isInitialized());
503
504 return isStarted_;
505}
506
507}
508
509}
510
511}
512
513#endif // META_OCEAN_MEDIA_AVF_VIDEO_ENCODER_H
This class implements Ocean's image class.
Definition Frame.h:1969
This class implements a recursive lock object.
Definition Lock.h:31
Definition of an encoded sample.
Definition avfoundation/VideoEncoder.h:125
bool isPartialFrame() const
Returns whether this sample contains only part of a frame.
Definition avfoundation/VideoEncoder.h:457
int64_t presentationTime_
The presentation time in microseconds.
Definition avfoundation/VideoEncoder.h:223
const std::vector< uint8_t > & data() const
Returns the encoded data.
Definition avfoundation/VideoEncoder.h:432
BufferFlags bufferFlags_
The buffer flags.
Definition avfoundation/VideoEncoder.h:226
std::vector< uint8_t > data_
The encoded data.
Definition avfoundation/VideoEncoder.h:220
bool isConfiguration() const
Returns whether this sample contains codec configuration data instead of media data.
Definition avfoundation/VideoEncoder.h:447
int64_t presentationTime() const
Returns the presentation time in microseconds.
Definition avfoundation/VideoEncoder.h:437
Sample(const Sample &)=delete
Disabled copy constructor.
Sample & operator=(const Sample &)=delete
Disabled copy operator.
bool isValid() const
Returns whether this sample is valid.
Definition avfoundation/VideoEncoder.h:427
bool isEndOfStream() const
Returns whether this sample marks the end of the stream.
Definition avfoundation/VideoEncoder.h:452
Sample()=default
Creates an invalid sample.
Sample & operator=(Sample &&sample) noexcept
Move operator.
Definition avfoundation/VideoEncoder.h:462
bool isKeyFrame() const
Returns whether this sample is a key frame.
Definition avfoundation/VideoEncoder.h:442
This class implements a simple video encoder for iOS/macOS using Ocean::Frame objects as input.
Definition avfoundation/VideoEncoder.h:88
static CMVideoCodecType mimeToCodecType(const std::string &mime)
Translates a MIME type to a CMVideoCodecType.
static void releaseVTCompressionSession(VTCompressionSessionRef session)
Release function for VTCompressionSessionRef that invalidates and releases the session.
Definition avfoundation/VideoEncoder.h:482
VideoEncoder(const VideoEncoder &)=delete
Disabled copy constructor.
VideoEncoder()
Default constructor creating an un-initialized encoder.
static constexpr int bitrateMbps5_
Definition of a 5 Mbps bit rate.
Definition avfoundation/VideoEncoder.h:98
VideoEncoder & operator=(VideoEncoder &&)=delete
Disabled move operator, a video encoder cannot be moved.
int64_t debugPreviousEncodedTimestamp_
The previous presentation timestamp of an encoded sample in the compression callback,...
Definition avfoundation/VideoEncoder.h:410
Lock encodedSamplesLock_
The lock for the encoded samples queue.
Definition avfoundation/VideoEncoder.h:403
static constexpr unsigned int maximalWidth_
Definition of the maximal image width.
Definition avfoundation/VideoEncoder.h:237
static constexpr int bitrateMbps10_
Definition of a 10 Mbps bit rate.
Definition avfoundation/VideoEncoder.h:101
static void compressionOutputCallback(void *outputCallbackRefCon, void *sourceFrameRefCon, OSStatus status, VTEncodeInfoFlags infoFlags, CMSampleBufferRef sampleBuffer)
Callback function for encoded samples from VideoToolbox.
bool isInitialized() const
Returns whether this encoder is initialized.
Definition avfoundation/VideoEncoder.h:491
Lock lock_
The encoder's lock.
Definition avfoundation/VideoEncoder.h:400
std::vector< Sample > Samples
Definition of a vector holding sample objects.
Definition avfoundation/VideoEncoder.h:232
bool isStarted() const
Returns whether this encoder is currently running.
Definition avfoundation/VideoEncoder.h:498
bool initialize(const unsigned int width, const unsigned int height, const std::string &mime="video/avc", const double frameRate=30.0, const unsigned int bitrate=bitrateMbps2_, const int iFrameInterval=1)
Initializes the video encoder with the specified configuration.
static constexpr unsigned int maximalHeight_
Definition of the maximal image height.
Definition avfoundation/VideoEncoder.h:240
int64_t debugPreviousSubmittedTimestamp_
The previous presentation timestamp submitted via pushFrame(), in microseconds, -1 if no frame has be...
Definition avfoundation/VideoEncoder.h:407
unsigned int height_
The height of the video.
Definition avfoundation/VideoEncoder.h:394
bool pushFrame(const Frame &frame, const uint64_t presentationTime)
Adds a new frame which needs to be encoded to the video encoder.
~VideoEncoder()
Destructs the video encoder and releases all associated resources.
std::deque< Sample > encodedSamples_
The queue of encoded samples.
Definition avfoundation/VideoEncoder.h:388
ScopedVTCompressionSessionRef compressionSession_
The compression session.
Definition avfoundation/VideoEncoder.h:385
bool start()
Starts the video encoder.
bool stop()
Stops the video encoder.
static constexpr int maximalBitrate_
Definition of the maximal bit rate.
Definition avfoundation/VideoEncoder.h:243
VideoEncoder & operator=(const VideoEncoder &)=delete
Disabled copy operator.
unsigned int width_
The width of the video.
Definition avfoundation/VideoEncoder.h:391
void release()
Explicitly releases this video encoder.
static constexpr int bitrateMbps2_
Definition of a 2 Mbps bit rate.
Definition avfoundation/VideoEncoder.h:95
VideoEncoder(VideoEncoder &&)=delete
Disabled move constructor, a video encoder cannot be moved.
BufferFlags
Definition of individual buffer flag constants.
Definition avfoundation/VideoEncoder.h:108
@ BUFFER_FLAG_KEY_FRAME
Indicates that the (encoded) buffer marked as such contains the data for a key frame.
Definition avfoundation/VideoEncoder.h:112
@ BUFFER_FLAG_PARTIAL_FRAME
Indicates that the buffer only contains part of a frame.
Definition avfoundation/VideoEncoder.h:118
@ BUFFER_FLAG_END_OF_STREAM
Indicates that the buffer is the last buffer in the stream.
Definition avfoundation/VideoEncoder.h:116
@ BUFFER_FLAG_NONE
The buffer has no special property.
Definition avfoundation/VideoEncoder.h:110
@ BUFFER_FLAG_CODEC_CONFIG
Indicates that the buffer marked as such contains codec initialization / codec specific data instead ...
Definition avfoundation/VideoEncoder.h:114
static constexpr int bitrateMbps1_
Definition of a 1 Mbps bit rate.
Definition avfoundation/VideoEncoder.h:92
bool isStarted_
True, if the encoder is currently started.
Definition avfoundation/VideoEncoder.h:397
Sample popSample()
Returns the next encoded sample if available.
static constexpr T minValue()
Returns the min scalar value.
Definition Numeric.h:3259
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
The namespace covering the entire Ocean framework.
Definition Accessor.h:15