Ocean
Loading...
Searching...
No Matches
android/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_ANDROID_VIDEO_DECODER_H
9#define META_OCEAN_MEDIA_ANDROID_VIDEO_DECODER_H
10
11#if defined(__ANDROID_API__) && __ANDROID_API__ >= 24
12
13#ifndef OCEAN_MEDIA_ANDROID_VIDEODECODER_AVAILABLE
14 #define OCEAN_MEDIA_ANDROID_VIDEODECODER_AVAILABLE
15#endif
16
19
20#include "ocean/base/Frame.h"
21#include "ocean/base/Lock.h"
22
23namespace Ocean
24{
25
26namespace Media
27{
28
29namespace Android
30{
31
32/**
33 * This class implements a simple video decoder for Android using encoded media samples from memory as input.
34 *
35 * Usage:
36 * @code
37 * // a function which is e.g., running in a separate thread
38 * void threadRun()
39 * {
40 * VideoDecoder videoDecoder;
41 *
42 * // initializing the decoder with the input format of the media samples
43 * if (!videoDecoder.initialize("video/avc", 1920u, 1080u))
44 * {
45 * // handle error
46 * }
47 *
48 * if (!videoDecoder.start())
49 * {
50 * // handle error
51 * }
52 *
53 * unsigned int frameIndex = 0u;
54 * double frameRate = 30.0;
55 *
56 * while (true)
57 * {
58 * void* sampleData = nullptr;
59 * size_t sampleSize = 0;
60 *
61 * // external function: function needs to provide the new media samples from an external source - e.g., from an external webcam, a video stream, etc.
62 * if (doesNewInputSampleExist(sampleData, &sampleSize))
63 * {
64 * // presentation time in microseconds
65 * uint64_t presentationTime = uint64_t(1.0e6 * double(frameIndex) / frameRate);
66 *
67 * // we forward the media sample to the decoder, eventually it will be decoded and will be available through decodedFrame()
68 * if (!videoDecoder.pushSample(sampleData, sampleSize, presentationTime))
69 * {
70 * // handle error
71 * }
72 *
73 * ++frameIndex;
74 * }
75 *
76 * // we simply check whether another frame has been decoded (there may be a delay between
77 * Frame newFrame = videoDecoder.popFrame();
78 *
79 * if (newFrame.isValid())
80 * {
81 * // external function: receiving new frames and processes the frames
82 * sendFrameToReceiver(std::move(newFrame));
83 * }
84 * }
85 * }
86 * @endcode
87 * @ingroup mediaandroid
88 */
90{
91 public:
92
93 /**
94 * Default constructor creating an un-initialized decoder.
95 */
97
98 /**
99 * Move constructor.
100 * @param videoDecoder The decoder to be moved
101 */
102 inline VideoDecoder(VideoDecoder&& videoDecoder) noexcept;
103
104 /**
105 * Destructs the video decoder and releases all associated resources.
106 */
108
109 /**
110 * @param mime The MIME type (Multipurpose Internet Mail Extensions) of the video to be decoded, e.g., "video/avc", "video/hevc", ...
111 * @param width The width of the video to be decoded, in pixel, with range [1, infinity)
112 * @param height The height of the video to be decoded, in pixel, with range [1, infinity)
113 * @return True, if succeeded
114 * @see isInitialized().
115 */
116 bool initialize(const std::string& mime, const unsigned int width, const unsigned int height);
117
118 /**
119 * Starts the video decoder.
120 * @return True, if succeeded
121 * @see isStarted().
122 */
123 bool start();
124
125 /**
126 * Stops the video decoder.
127 * @return True, if succeeded
128 */
129 bool stop();
130
131 /**
132 * Adds a new media sample which needs to be decoded to the video decoder.
133 * The decoder needs to be initialized and started.<br>
134 * The presentation time is mainly intended to allow associating the provided encoded media sample with the resulting decoded frame when calling popFrame().<br>
135 * 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.
136 * @param data The data of the encoded media sample, must be valid
137 * @param size The size of the encoded media sample, in bytes, with range [1, infinity)
138 * @param presentationTime The presentation time of the sample, in microseconds, with range [0, infinity)
139 * @return True, if succeeded
140 * @see start(), isInitialized(), isStarted().
141 */
142 bool pushSample(const void* data, const size_t size, const uint64_t presentationTime);
143
144 /**
145 * Optional the frame's presentation time will be returned, this is the presentation time which was used when the corresponding sample was provided in decodedSample().
146 * @param presentationTime Optional resulting presentation time in micro seconds, with range (-infinity, infinity)
147 * @return The resulting frame, invalid if currently no decoded frame is available
148 * @see pushSample().
149 */
150 Frame popFrame(int64_t* presentationTime = nullptr);
151
152 /**
153 * Returns whether this decode is initialized.
154 * @return True, if so
155 * @see initialize().
156 */
157 inline bool isInitialized() const;
158
159 /**
160 * Returns whether this decoder is currently running.
161 * @return True, if so
162 * @see start().
163 */
164 inline bool isStarted() const;
165
166 /**
167 * Explicitly releases this video encoder.
168 * If the encoder is still running, the encoder will be stopped as well.
169 */
170 void release();
171
172 /**
173 * Move operator.
174 * @param videoDecoder The video decoder to be moved
175 * @return Reference to this object
176 */
177 inline VideoDecoder& operator=(VideoDecoder&& videoDecoder) noexcept;
178
179 /**
180 * Extracts the video frame from an output buffer of a video codec.
181 * @param mediaCodec The media codec to which the output buffer belongs, must be valid
182 * @param presentationTime Optional resulting presentation time in micro seconds, with range (-infinity, infinity)
183 * @return The resulting extracted frame, invalid if the frame could not be extracted
184 */
185 static Frame extractVideoFrameFromCodecOutputBuffer(AMediaCodec* const mediaCodec, int64_t* presentationTime = nullptr);
186
187 /**
188 * Converts AVCC/HVCC formatted H.264/H.265 data to Annex B format.
189 * For encoded samples (isCodecConfig = false): Replaces 4-byte big-endian length prefixes with start code prefixes (00 00 00 01).
190 * For codec config (isCodecConfig = true): Parses the AVCC/HVCC configuration record and extracts SPS/PPS (and VPS for HEVC) NAL units with start codes.
191 * @param avccData The AVCC/HVCC formatted data, must be valid
192 * @param avccSize The size of the AVCC/HVCC data in bytes, with range [4, infinity)
193 * @param annexBData The resulting Annex B formatted data with start code prefixes
194 * @param isCodecConfig True if the input is an AVCC/HVCC codec configuration record; False if it contains length-prefixed NAL units
195 * @param mime The MIME type, used only when isCodecConfig is true to determine H.264 vs HEVC format, either "video/avc" or "video/hevc"
196 * @return True if conversion succeeded; False if the input data is invalid or conversion failed
197 */
198 static bool convertAvccToAnnexB(const void* avccData, const size_t avccSize, std::vector<uint8_t>& annexBData, const bool isCodecConfig = false, const std::string& mime = "video/avc");
199
200 /**
201 * Determines whether the given data is in AVCC format (length prefixed) or Annex B format (start code prefixed).
202 * AVCC format uses 4-byte big-endian length prefixes before each NAL unit.
203 * Annex B format uses start codes (0x00 0x00 0x00 0x01 or 0x00 0x00 0x01) to delimit NAL units.
204 *
205 * Note: For codec configuration data, use isCodecConfig=true as AVCC config starts with version byte 0x01.
206 * For regular NAL unit samples, use isCodecConfig=false which applies more sophisticated detection
207 * to distinguish AVCC length prefixes from Annex B start codes (especially for NAL sizes 256-511 bytes
208 * where the length prefix 0x00 0x00 0x01 XX looks like an Annex B 3-byte start code).
209 *
210 * @param data The data to check, must be valid
211 * @param size The size of the data in bytes, with range [4, infinity)
212 * @param isCodecConfig True if the data is codec configuration (SPS/PPS), false for regular NAL samples
213 * @return True if the data is in AVCC format; false if it's in Annex B format
214 */
215 static bool isAvcc(const void* data, const size_t size, const bool isCodecConfig = false);
216
217 protected:
218
219 /**
220 * Disabled copy constructor.
221 */
222 VideoDecoder(const VideoDecoder&) = delete;
223
224 /**
225 * Disabled copy operator.
226 * @return Reference to this object
227 */
229
230 protected:
231
232 /// The subscription for the native media library.
234
235 /// The Android media decoder used to decode the video.
237
238 /// True, if the decoder is currently started.
239 bool isStarted_ = false;
240
241 /// The decoder's lock.
242 mutable Lock lock_;
243};
244
245inline VideoDecoder::VideoDecoder(VideoDecoder&& videoDecoder) noexcept
246{
247 *this = std::move(videoDecoder);
248}
249
251{
252 const ScopedLock scopedLock(lock_);
253
254 return decoder_.isValid();
255}
256
257inline bool VideoDecoder::isStarted() const
258{
259 const ScopedLock scopedLock(lock_);
260
261 ocean_assert(!isStarted_ || isInitialized());
262
263 return isStarted_;
264}
265
266inline VideoDecoder& VideoDecoder::operator=(VideoDecoder&& videoDecoder) noexcept
267{
268 if (this != &videoDecoder)
269 {
270 release();
271
272 decoder_ = std::move(videoDecoder.decoder_);
273
274 isStarted_ = videoDecoder.isStarted_;
275 videoDecoder.isStarted_ = false;
276 }
277
278 return *this;
279}
280
281}
282
283}
284
285}
286
287#endif // defined(__ANDROID_API__) && __ANDROID_API__ >= 24
288
289#endif // META_OCEAN_MEDIA_ANDROID_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
Definition of a scoped object for AMediaCodec objects.
Definition NativeMediaLibrary.h:79
This class implements a simple video decoder for Android using encoded media samples from memory as i...
Definition android/VideoDecoder.h:90
bool initialize(const std::string &mime, const unsigned int width, const unsigned int height)
VideoDecoder(const VideoDecoder &)=delete
Disabled copy constructor.
static Frame extractVideoFrameFromCodecOutputBuffer(AMediaCodec *const mediaCodec, int64_t *presentationTime=nullptr)
Extracts the video frame from an output buffer of a video codec.
NativeMediaLibrary::ScopedAMediaCodec decoder_
The Android media decoder used to decode the video.
Definition android/VideoDecoder.h:236
VideoDecoder & operator=(VideoDecoder &&videoDecoder) noexcept
Move operator.
Definition android/VideoDecoder.h:266
void release()
Explicitly releases this video encoder.
VideoDecoder()
Default constructor creating an un-initialized decoder.
Lock lock_
The decoder's lock.
Definition android/VideoDecoder.h:242
~VideoDecoder()
Destructs the video decoder and releases all associated resources.
static bool convertAvccToAnnexB(const void *avccData, const size_t avccSize, std::vector< uint8_t > &annexBData, const bool isCodecConfig=false, const std::string &mime="video/avc")
Converts AVCC/HVCC formatted H.264/H.265 data to Annex B format.
bool isStarted_
True, if the decoder is currently started.
Definition android/VideoDecoder.h:239
NativeMediaLibrary::ScopedSubscription nativeMediaLibrarySubscription_
The subscription for the native media library.
Definition android/VideoDecoder.h:233
bool isInitialized() const
Returns whether this decode is initialized.
Definition android/VideoDecoder.h:250
bool isStarted() const
Returns whether this decoder is currently running.
Definition android/VideoDecoder.h:257
bool stop()
Stops the video decoder.
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.
Frame popFrame(int64_t *presentationTime=nullptr)
Optional the frame's presentation time will be returned, this is the presentation time which was used...
bool start()
Starts the video decoder.
VideoDecoder & operator=(const VideoDecoder &)=delete
Disabled copy operator.
static bool isAvcc(const void *data, const size_t size, const bool isCodecConfig=false)
Determines whether the given data is in AVCC format (length prefixed) or Annex B format (start code p...
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 release function (which will be invoked once the obj...
Definition ScopedObject.h:351
The namespace covering the entire Ocean framework.
Definition Accessor.h:15