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 * Move constructor.
266 * @param videoEncoder The encoder to be moved
267 */
268 inline VideoEncoder(VideoEncoder&& videoEncoder) noexcept;
269
270 /**
271 * Destructs the video encoder and releases all associated resources.
272 */
274
275 /**
276 * Initializes the video encoder with the specified configuration.
277 * @param width The width of the video to be encoded, in pixel, with range [1, infinity)
278 * @param height The height of the video to be encoded, in pixel, with range [1, infinity)
279 * @param mime The MIME type (Multipurpose Internet Mail Extensions) of the video to be encoded, e.g., "video/avc", "video/hevc", ...
280 * @param frameRate The target frame rate in frames per second, with range (0, infinity), e.g., 30.0
281 * @param bitrate The target bitrate in bits per second, with range [1, infinity), e.g., 5000000 for 5 Mbps
282 * @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
283 * @return True, if succeeded
284 * @see isInitialized().
285 */
286 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);
287
288 /**
289 * Starts the video encoder.
290 * @return True, if succeeded
291 * @see isStarted().
292 */
293 bool start();
294
295 /**
296 * Stops the video encoder.
297 * @return True, if succeeded
298 */
299 bool stop();
300
301 /**
302 * Adds a new frame which needs to be encoded to the video encoder.
303 * The encoder needs to be initialized and started.
304 * The presentation time is mainly intended to allow associating the provided frame with the resulting encoded sample when calling popSample().
305 * 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).
306 * @param frame The frame to be encoded, must be valid
307 * @param presentationTime The presentation time of the frame, in microseconds, with range [0, infinity)
308 * @return True, if succeeded
309 * @see start(), isInitialized(), isStarted().
310 */
311 bool pushFrame(const Frame& frame, const uint64_t presentationTime);
312
313 /**
314 * Returns the next encoded sample if available.
315 * @return The resulting encoded sample, invalid if currently no encoded sample is available
316 * @see pushFrame().
317 */
319
320 /**
321 * Returns whether this encoder is initialized.
322 * @return True, if so
323 * @see initialize().
324 */
325 inline bool isInitialized() const;
326
327 /**
328 * Returns whether this encoder is currently running.
329 * @return True, if so
330 * @see start().
331 */
332 inline bool isStarted() const;
333
334 /**
335 * Explicitly releases this video encoder.
336 * If the encoder is still running, the encoder will be stopped as well.
337 */
338 void release();
339
340 /**
341 * Move operator.
342 * @param videoEncoder The video encoder to be moved
343 * @return Reference to this object
344 */
345 inline VideoEncoder& operator=(VideoEncoder&& videoEncoder) noexcept;
346
347 protected:
348
349 /**
350 * Definition of a scoped object holding a CFNumberRef object.
351 * The wrapped CFNumberRef object will be released automatically once the scoped object does not exist anymore.
352 */
354
355 /**
356 * Disabled copy constructor.
357 */
358 VideoEncoder(const VideoEncoder&) = delete;
359
360 /**
361 * Disabled copy operator.
362 * @return Reference to this object
363 */
365
366 /**
367 * Callback function for encoded samples from VideoToolbox.
368 * @param outputCallbackRefCon Reference to this encoder
369 * @param sourceFrameRefCon Reference containing the presentation time
370 * @param status The status of the compression operation
371 * @param infoFlags Information flags
372 * @param sampleBuffer The encoded sample buffer, may be nullptr on error
373 */
374 static void compressionOutputCallback(void* outputCallbackRefCon, void* sourceFrameRefCon, OSStatus status, VTEncodeInfoFlags infoFlags, CMSampleBufferRef sampleBuffer);
375
376 /**
377 * Translates a MIME type to a CMVideoCodecType.
378 * @param mime The MIME type
379 * @return The corresponding codec type, 0 if not supported
380 */
381 static CMVideoCodecType mimeToCodecType(const std::string& mime);
382
383 protected:
384
385 /// The compression session.
387
388 /// The queue of encoded samples.
389 std::deque<Sample> encodedSamples_;
390
391 /// The width of the video.
392 unsigned int width_ = 0u;
393
394 /// The height of the video.
395 unsigned int height_ = 0u;
396
397 /// True, if the encoder is currently started.
398 bool isStarted_ = false;
399
400 /// The encoder's lock.
401 mutable Lock lock_;
402
403 /// The lock for the encoded samples queue.
405};
406
407inline VideoEncoder::Sample::Sample(std::vector<uint8_t>&& data, const int64_t presentationTime, const BufferFlags bufferFlags) :
408 data_(std::move(data)),
409 presentationTime_(presentationTime),
410 bufferFlags_(bufferFlags)
411{
412 // nothing to do here
413}
414
415inline VideoEncoder::Sample::Sample(Sample&& sample) noexcept
416{
417 *this = std::move(sample);
418}
419
421{
422 return !data_.empty();
423}
424
425inline const std::vector<uint8_t>& VideoEncoder::Sample::data() const
426{
427 return data_;
428}
429
431{
432 return presentationTime_;
433}
434
436{
437 return bufferFlags_ & BUFFER_FLAG_KEY_FRAME;
438}
439
441{
442 return bufferFlags_ & BUFFER_FLAG_CODEC_CONFIG;
443}
444
446{
447 return bufferFlags_ & BUFFER_FLAG_END_OF_STREAM;
448}
449
451{
452 return bufferFlags_ & BUFFER_FLAG_PARTIAL_FRAME;
453}
454
456{
457 if (this != &sample)
458 {
459 data_ = std::move(sample.data_);
460 presentationTime_ = sample.presentationTime_;
461 bufferFlags_ = sample.bufferFlags_;
462
463 sample.presentationTime_ = NumericT<int64_t>::minValue();
464 sample.bufferFlags_ = BUFFER_FLAG_NONE;
465 }
466
467 return *this;
468}
469
470inline VideoEncoder::Sample::operator bool() const
471{
472 return isValid();
473}
474
476{
477 if (session != nullptr)
478 {
479 VTCompressionSessionInvalidate(session);
480 CFRelease(session);
481 }
482}
483
484inline VideoEncoder::VideoEncoder(VideoEncoder&& videoEncoder) noexcept
485{
486 *this = std::move(videoEncoder);
487}
488
490{
491 const ScopedLock scopedLock(lock_);
492
494}
495
496inline bool VideoEncoder::isStarted() const
497{
498 const ScopedLock scopedLock(lock_);
499
500 ocean_assert(!isStarted_ || isInitialized());
501
502 return isStarted_;
503}
504
505inline VideoEncoder& VideoEncoder::operator=(VideoEncoder&& videoEncoder) noexcept
506{
507 if (this != &videoEncoder)
508 {
509 release();
510
511 compressionSession_ = std::move(videoEncoder.compressionSession_);
512
513 encodedSamples_ = std::move(videoEncoder.encodedSamples_);
514
515 width_ = videoEncoder.width_;
516 videoEncoder.width_ = 0u;
517
518 height_ = videoEncoder.height_;
519 videoEncoder.height_ = 0u;
520
521 isStarted_ = videoEncoder.isStarted_;
522 videoEncoder.isStarted_ = false;
523 }
524
525 return *this;
526}
527
528}
529
530}
531
532}
533
534#endif // META_OCEAN_MEDIA_AVF_VIDEO_ENCODER_H
This class implements Ocean's image class.
Definition Frame.h:1879
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:450
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:425
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:440
int64_t presentationTime() const
Returns the presentation time in microseconds.
Definition avfoundation/VideoEncoder.h:430
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:420
bool isEndOfStream() const
Returns whether this sample marks the end of the stream.
Definition avfoundation/VideoEncoder.h:445
Sample()=default
Creates an invalid sample.
Sample & operator=(Sample &&sample) noexcept
Move operator.
Definition avfoundation/VideoEncoder.h:455
bool isKeyFrame() const
Returns whether this sample is a key frame.
Definition avfoundation/VideoEncoder.h:435
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:475
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
Lock encodedSamplesLock_
The lock for the encoded samples queue.
Definition avfoundation/VideoEncoder.h:404
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:489
Lock lock_
The encoder's lock.
Definition avfoundation/VideoEncoder.h:401
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:496
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
unsigned int height_
The height of the video.
Definition avfoundation/VideoEncoder.h:395
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:389
ScopedVTCompressionSessionRef compressionSession_
The compression session.
Definition avfoundation/VideoEncoder.h:386
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:392
void release()
Explicitly releases this video encoder.
static constexpr int bitrateMbps2_
Definition of a 2 Mbps bit rate.
Definition avfoundation/VideoEncoder.h:95
VideoEncoder & operator=(VideoEncoder &&videoEncoder) noexcept
Move operator.
Definition avfoundation/VideoEncoder.h:505
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:398
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