blob: 383beddc4cc50e2ba8e06837403e6c166738f163 [file] [log] [blame]
Linus Nilsson0da327a2020-01-31 16:22:18 -08001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// #define LOG_NDEBUG 0
18#define LOG_TAG "VideoTrackTranscoder"
19
20#include <android-base/logging.h>
Hangyu Kuang0d93f0b2020-12-11 18:51:16 +000021#include <android-base/properties.h>
Linus Nilsson93591892020-08-03 18:56:55 -070022#include <media/NdkCommon.h>
Linus Nilsson0da327a2020-01-31 16:22:18 -080023#include <media/VideoTrackTranscoder.h>
24
Linus Nilsson7a127b22020-10-15 16:23:54 -070025using namespace AMediaFormatUtils;
26
Linus Nilsson0da327a2020-01-31 16:22:18 -080027namespace android {
28
29// Check that the codec sample flags have the expected NDK meaning.
30static_assert(SAMPLE_FLAG_CODEC_CONFIG == AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG,
31 "Sample flag mismatch: CODEC_CONFIG");
32static_assert(SAMPLE_FLAG_END_OF_STREAM == AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM,
33 "Sample flag mismatch: END_OF_STREAM");
34static_assert(SAMPLE_FLAG_PARTIAL_FRAME == AMEDIACODEC_BUFFER_FLAG_PARTIAL_FRAME,
35 "Sample flag mismatch: PARTIAL_FRAME");
36
Linus Nilssoncab39d82020-05-14 16:32:21 -070037// Color format defined by surface. (See MediaCodecInfo.CodecCapabilities#COLOR_FormatSurface.)
38static constexpr int32_t kColorFormatSurface = 0x7f000789;
39// Default key frame interval in seconds.
40static constexpr float kDefaultKeyFrameIntervalSeconds = 1.0f;
Linus Nilsson7a127b22020-10-15 16:23:54 -070041// Default codec operating rate.
Linus Nilsson504394a2020-12-16 11:10:10 -080042static int32_t kDefaultCodecOperatingRate720P = base::GetIntProperty(
hkuangbcb9ec12020-12-14 22:16:09 -080043 "debug.media.transcoding.codec_max_operating_rate_720P", /*default*/ 480);
44static int32_t kDefaultCodecOperatingRate1080P = base::GetIntProperty(
45 "debug.media.transcoding.codec_max_operating_rate_1080P", /*default*/ 240);
Linus Nilsson7a127b22020-10-15 16:23:54 -070046// Default codec priority.
47static constexpr int32_t kDefaultCodecPriority = 1;
48// Default bitrate, in case source estimation fails.
49static constexpr int32_t kDefaultBitrateMbps = 10 * 1000 * 1000;
Linus Nilssonaf4a3212020-12-15 08:18:25 -080050// Default frame rate.
51static constexpr int32_t kDefaultFrameRate = 30;
Linus Nilssoncab39d82020-05-14 16:32:21 -070052
Linus Nilsson0da327a2020-01-31 16:22:18 -080053template <typename T>
54void VideoTrackTranscoder::BlockingQueue<T>::push(T const& value, bool front) {
55 {
Linus Nilsson93cf9132020-09-24 12:12:48 -070056 std::scoped_lock lock(mMutex);
57 if (mAborted) {
58 return;
59 }
60
Linus Nilsson0da327a2020-01-31 16:22:18 -080061 if (front) {
62 mQueue.push_front(value);
63 } else {
64 mQueue.push_back(value);
65 }
66 }
67 mCondition.notify_one();
68}
69
70template <typename T>
71T VideoTrackTranscoder::BlockingQueue<T>::pop() {
Linus Nilsson93cf9132020-09-24 12:12:48 -070072 std::unique_lock lock(mMutex);
Linus Nilsson0da327a2020-01-31 16:22:18 -080073 while (mQueue.empty()) {
74 mCondition.wait(lock);
75 }
76 T value = mQueue.front();
77 mQueue.pop_front();
78 return value;
79}
80
Linus Nilsson93cf9132020-09-24 12:12:48 -070081// Note: Do not call if another thread might waiting in pop.
82template <typename T>
83void VideoTrackTranscoder::BlockingQueue<T>::abort() {
84 std::scoped_lock lock(mMutex);
85 mAborted = true;
86 mQueue.clear();
87}
88
Linus Nilssone4716f22020-07-10 16:07:57 -070089// The CodecWrapper class is used to let AMediaCodec instances outlive the transcoder object itself
90// by giving the codec a weak pointer to the transcoder. Codecs wrapped in this object are kept
91// alive by the transcoder and the codec's outstanding buffers. Once the transcoder stops and all
92// output buffers have been released by downstream components the codec will also be released.
93class VideoTrackTranscoder::CodecWrapper {
94public:
95 CodecWrapper(AMediaCodec* codec, const std::weak_ptr<VideoTrackTranscoder>& transcoder)
96 : mCodec(codec), mTranscoder(transcoder), mCodecStarted(false) {}
97 ~CodecWrapper() {
98 if (mCodecStarted) {
99 AMediaCodec_stop(mCodec);
100 }
101 AMediaCodec_delete(mCodec);
102 }
103
104 AMediaCodec* getCodec() { return mCodec; }
105 std::shared_ptr<VideoTrackTranscoder> getTranscoder() const { return mTranscoder.lock(); };
106 void setStarted() { mCodecStarted = true; }
107
108private:
109 AMediaCodec* mCodec;
110 std::weak_ptr<VideoTrackTranscoder> mTranscoder;
111 bool mCodecStarted;
112};
113
Linus Nilsson0da327a2020-01-31 16:22:18 -0800114// Dispatch responses to codec callbacks onto the message queue.
115struct AsyncCodecCallbackDispatch {
116 static void onAsyncInputAvailable(AMediaCodec* codec, void* userdata, int32_t index) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700117 VideoTrackTranscoder::CodecWrapper* wrapper =
118 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
119 if (auto transcoder = wrapper->getTranscoder()) {
120 if (codec == transcoder->mDecoder) {
121 transcoder->mCodecMessageQueue.push(
122 [transcoder, index] { transcoder->enqueueInputSample(index); });
123 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800124 }
125 }
126
127 static void onAsyncOutputAvailable(AMediaCodec* codec, void* userdata, int32_t index,
128 AMediaCodecBufferInfo* bufferInfoPtr) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700129 VideoTrackTranscoder::CodecWrapper* wrapper =
130 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800131 AMediaCodecBufferInfo bufferInfo = *bufferInfoPtr;
Linus Nilssone4716f22020-07-10 16:07:57 -0700132 if (auto transcoder = wrapper->getTranscoder()) {
133 transcoder->mCodecMessageQueue.push([transcoder, index, codec, bufferInfo] {
134 if (codec == transcoder->mDecoder) {
135 transcoder->transferBuffer(index, bufferInfo);
136 } else if (codec == transcoder->mEncoder->getCodec()) {
137 transcoder->dequeueOutputSample(index, bufferInfo);
138 }
139 });
140 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800141 }
142
143 static void onAsyncFormatChanged(AMediaCodec* codec, void* userdata, AMediaFormat* format) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700144 VideoTrackTranscoder::CodecWrapper* wrapper =
145 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
146 if (auto transcoder = wrapper->getTranscoder()) {
Linus Nilsson52df71c2021-03-08 13:01:11 -0800147 const bool isDecoder = codec == transcoder->mDecoder;
148 const char* kCodecName = (isDecoder ? "Decoder" : "Encoder");
Linus Nilssona676a9a2021-03-15 18:22:43 -0700149 LOG(INFO) << kCodecName << " format changed: " << AMediaFormat_toString(format);
Linus Nilsson52df71c2021-03-08 13:01:11 -0800150 transcoder->mCodecMessageQueue.push([transcoder, format, isDecoder] {
151 transcoder->updateTrackFormat(format, isDecoder);
152 });
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700153 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800154 }
155
156 static void onAsyncError(AMediaCodec* codec, void* userdata, media_status_t error,
157 int32_t actionCode, const char* detail) {
158 LOG(ERROR) << "Error from codec " << codec << ", userdata " << userdata << ", error "
159 << error << ", action " << actionCode << ", detail " << detail;
Linus Nilssone4716f22020-07-10 16:07:57 -0700160 VideoTrackTranscoder::CodecWrapper* wrapper =
161 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
162 if (auto transcoder = wrapper->getTranscoder()) {
163 transcoder->mCodecMessageQueue.push(
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700164 [transcoder, error] { transcoder->mStatus = error; }, true);
Linus Nilssone4716f22020-07-10 16:07:57 -0700165 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800166 }
167};
168
Linus Nilssone4716f22020-07-10 16:07:57 -0700169// static
170std::shared_ptr<VideoTrackTranscoder> VideoTrackTranscoder::create(
Chong Zhangbbb4eac2020-11-18 11:12:06 -0800171 const std::weak_ptr<MediaTrackTranscoderCallback>& transcoderCallback, pid_t pid,
172 uid_t uid) {
173 return std::shared_ptr<VideoTrackTranscoder>(
174 new VideoTrackTranscoder(transcoderCallback, pid, uid));
Linus Nilssone4716f22020-07-10 16:07:57 -0700175}
176
Linus Nilsson0da327a2020-01-31 16:22:18 -0800177VideoTrackTranscoder::~VideoTrackTranscoder() {
178 if (mDecoder != nullptr) {
179 AMediaCodec_delete(mDecoder);
180 }
181
Linus Nilsson0da327a2020-01-31 16:22:18 -0800182 if (mSurface != nullptr) {
183 ANativeWindow_release(mSurface);
184 }
185}
186
hkuangbcb9ec12020-12-14 22:16:09 -0800187// Search the default operating rate based on resolution.
188static int32_t getDefaultOperatingRate(AMediaFormat* encoderFormat) {
189 int32_t width, height;
190 if (AMediaFormat_getInt32(encoderFormat, AMEDIAFORMAT_KEY_WIDTH, &width) && (width > 0) &&
191 AMediaFormat_getInt32(encoderFormat, AMEDIAFORMAT_KEY_HEIGHT, &height) && (height > 0)) {
192 if ((width == 1280 && height == 720) || (width == 720 && height == 1280)) {
Linus Nilsson504394a2020-12-16 11:10:10 -0800193 return kDefaultCodecOperatingRate720P;
hkuangbcb9ec12020-12-14 22:16:09 -0800194 } else if ((width == 1920 && height == 1080) || (width == 1080 && height == 1920)) {
195 return kDefaultCodecOperatingRate1080P;
hkuangbcb9ec12020-12-14 22:16:09 -0800196 } else {
197 LOG(WARNING) << "Could not find default operating rate: " << width << " " << height;
Linus Nilsson504394a2020-12-16 11:10:10 -0800198 // Don't set operating rate if the correct dimensions are not found.
hkuangbcb9ec12020-12-14 22:16:09 -0800199 }
200 } else {
201 LOG(ERROR) << "Failed to get default operating rate due to missing resolution";
202 }
203 return -1;
204}
205
Linus Nilsson0da327a2020-01-31 16:22:18 -0800206// Creates and configures the codecs.
207media_status_t VideoTrackTranscoder::configureDestinationFormat(
208 const std::shared_ptr<AMediaFormat>& destinationFormat) {
209 media_status_t status = AMEDIA_OK;
210
211 if (destinationFormat == nullptr) {
Linus Nilssoncab39d82020-05-14 16:32:21 -0700212 LOG(ERROR) << "Destination format is null, use passthrough transcoder";
Linus Nilsson0da327a2020-01-31 16:22:18 -0800213 return AMEDIA_ERROR_INVALID_PARAMETER;
214 }
215
Linus Nilssoncab39d82020-05-14 16:32:21 -0700216 AMediaFormat* encoderFormat = AMediaFormat_new();
217 if (!encoderFormat || AMediaFormat_copy(encoderFormat, destinationFormat.get()) != AMEDIA_OK) {
218 LOG(ERROR) << "Unable to copy destination format";
219 return AMEDIA_ERROR_INVALID_PARAMETER;
220 }
221
Linus Nilsson800793f2020-07-31 16:16:38 -0700222 int32_t bitrate;
223 if (!AMediaFormat_getInt32(encoderFormat, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate)) {
224 status = mMediaSampleReader->getEstimatedBitrateForTrack(mTrackIndex, &bitrate);
225 if (status != AMEDIA_OK) {
226 LOG(ERROR) << "Unable to estimate bitrate. Using default " << kDefaultBitrateMbps;
227 bitrate = kDefaultBitrateMbps;
228 }
229
230 LOG(INFO) << "Configuring bitrate " << bitrate;
231 AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_BIT_RATE, bitrate);
232 }
233
Linus Nilsson7a127b22020-10-15 16:23:54 -0700234 SetDefaultFormatValueFloat(AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, encoderFormat,
235 kDefaultKeyFrameIntervalSeconds);
hkuangbcb9ec12020-12-14 22:16:09 -0800236
237 int32_t operatingRate = getDefaultOperatingRate(encoderFormat);
238
239 if (operatingRate != -1) {
Linus Nilsson4aef0de2021-01-29 17:58:55 -0800240 float tmpf;
241 int32_t tmpi;
242 if (!AMediaFormat_getFloat(encoderFormat, AMEDIAFORMAT_KEY_OPERATING_RATE, &tmpf) &&
243 !AMediaFormat_getInt32(encoderFormat, AMEDIAFORMAT_KEY_OPERATING_RATE, &tmpi)) {
244 AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_OPERATING_RATE, operatingRate);
245 }
hkuangbcb9ec12020-12-14 22:16:09 -0800246 }
247
Linus Nilsson7a127b22020-10-15 16:23:54 -0700248 SetDefaultFormatValueInt32(AMEDIAFORMAT_KEY_PRIORITY, encoderFormat, kDefaultCodecPriority);
Linus Nilssonaf4a3212020-12-15 08:18:25 -0800249 SetDefaultFormatValueInt32(AMEDIAFORMAT_KEY_FRAME_RATE, encoderFormat, kDefaultFrameRate);
Linus Nilssoncab39d82020-05-14 16:32:21 -0700250 AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, kColorFormatSurface);
251
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700252 // Always encode without rotation. The rotation degree will be transferred directly to
253 // MediaSampleWriter track format, and MediaSampleWriter will call AMediaMuxer_setOrientationHint.
254 AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_ROTATION, 0);
255
Linus Nilssoncab39d82020-05-14 16:32:21 -0700256 mDestinationFormat = std::shared_ptr<AMediaFormat>(encoderFormat, &AMediaFormat_delete);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800257
258 // Create and configure the encoder.
259 const char* destinationMime = nullptr;
260 bool ok = AMediaFormat_getString(mDestinationFormat.get(), AMEDIAFORMAT_KEY_MIME,
261 &destinationMime);
262 if (!ok) {
263 LOG(ERROR) << "Destination MIME type is required for transcoding.";
264 return AMEDIA_ERROR_INVALID_PARAMETER;
265 }
266
Linus Nilsson4aef0de2021-01-29 17:58:55 -0800267// TODO: replace __ANDROID_API_FUTURE__with 31 when it's official (b/178144708)
268#define __TRANSCODING_MIN_API__ __ANDROID_API_FUTURE__
Jiyong Park26ddfc52021-01-22 16:26:40 +0900269
270 AMediaCodec* encoder;
271 if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
272 encoder = AMediaCodec_createEncoderByTypeForClient(destinationMime, mPid, mUid);
273 } else {
274 encoder = AMediaCodec_createEncoderByType(destinationMime);
275 }
Linus Nilssonc6221db2020-03-18 14:46:22 -0700276 if (encoder == nullptr) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800277 LOG(ERROR) << "Unable to create encoder for type " << destinationMime;
278 return AMEDIA_ERROR_UNSUPPORTED;
279 }
Linus Nilssone4716f22020-07-10 16:07:57 -0700280 mEncoder = std::make_shared<CodecWrapper>(encoder, shared_from_this());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800281
Linus Nilssona676a9a2021-03-15 18:22:43 -0700282 LOG(INFO) << "Configuring encoder with: " << AMediaFormat_toString(mDestinationFormat.get());
Linus Nilssone4716f22020-07-10 16:07:57 -0700283 status = AMediaCodec_configure(mEncoder->getCodec(), mDestinationFormat.get(),
284 NULL /* surface */, NULL /* crypto */,
285 AMEDIACODEC_CONFIGURE_FLAG_ENCODE);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800286 if (status != AMEDIA_OK) {
287 LOG(ERROR) << "Unable to configure video encoder: " << status;
288 return status;
289 }
290
Linus Nilssone4716f22020-07-10 16:07:57 -0700291 status = AMediaCodec_createInputSurface(mEncoder->getCodec(), &mSurface);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800292 if (status != AMEDIA_OK) {
293 LOG(ERROR) << "Unable to create an encoder input surface: %d" << status;
294 return status;
295 }
296
297 // Create and configure the decoder.
298 const char* sourceMime = nullptr;
299 ok = AMediaFormat_getString(mSourceFormat.get(), AMEDIAFORMAT_KEY_MIME, &sourceMime);
300 if (!ok) {
301 LOG(ERROR) << "Source MIME type is required for transcoding.";
302 return AMEDIA_ERROR_INVALID_PARAMETER;
303 }
304
Jiyong Park26ddfc52021-01-22 16:26:40 +0900305 if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
306 mDecoder = AMediaCodec_createDecoderByTypeForClient(sourceMime, mPid, mUid);
307 } else {
308 mDecoder = AMediaCodec_createDecoderByType(sourceMime);
309 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800310 if (mDecoder == nullptr) {
311 LOG(ERROR) << "Unable to create decoder for type " << sourceMime;
312 return AMEDIA_ERROR_UNSUPPORTED;
313 }
314
Linus Nilsson93591892020-08-03 18:56:55 -0700315 auto decoderFormat = std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
316 if (!decoderFormat ||
317 AMediaFormat_copy(decoderFormat.get(), mSourceFormat.get()) != AMEDIA_OK) {
318 LOG(ERROR) << "Unable to copy source format";
319 return AMEDIA_ERROR_INVALID_PARAMETER;
320 }
321
Linus Nilssonf4641542021-02-04 15:12:26 -0800322 // Request decoder to convert HDR content to SDR.
Linus Nilssona99f4042021-02-25 15:49:43 -0800323 const bool sourceIsHdr = VideoIsHdr(mSourceFormat.get());
Linus Nilssonf4641542021-02-04 15:12:26 -0800324 if (sourceIsHdr) {
325 AMediaFormat_setInt32(decoderFormat.get(),
326 TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST,
327 COLOR_TRANSFER_SDR_VIDEO);
328 }
329
Linus Nilsson93591892020-08-03 18:56:55 -0700330 // Prevent decoder from overwriting frames that the encoder has not yet consumed.
331 AMediaFormat_setInt32(decoderFormat.get(), TBD_AMEDIACODEC_PARAMETER_KEY_ALLOW_FRAME_DROP, 0);
332
Linus Nilsson16d772b2020-09-29 19:21:11 -0700333 // Copy over configurations that apply to both encoder and decoder.
Linus Nilssona676a9a2021-03-15 18:22:43 -0700334 static const std::vector<EntryCopier> kEncoderEntriesToCopy{
Linus Nilsson16d772b2020-09-29 19:21:11 -0700335 ENTRY_COPIER2(AMEDIAFORMAT_KEY_OPERATING_RATE, Float, Int32),
336 ENTRY_COPIER(AMEDIAFORMAT_KEY_PRIORITY, Int32),
337 };
Linus Nilssona676a9a2021-03-15 18:22:43 -0700338 CopyFormatEntries(mDestinationFormat.get(), decoderFormat.get(), kEncoderEntriesToCopy);
Linus Nilsson16d772b2020-09-29 19:21:11 -0700339
Linus Nilssona676a9a2021-03-15 18:22:43 -0700340 LOG(INFO) << "Configuring decoder with: " << AMediaFormat_toString(decoderFormat.get());
Linus Nilsson93591892020-08-03 18:56:55 -0700341 status = AMediaCodec_configure(mDecoder, decoderFormat.get(), mSurface, NULL /* crypto */,
Linus Nilsson0da327a2020-01-31 16:22:18 -0800342 0 /* flags */);
343 if (status != AMEDIA_OK) {
344 LOG(ERROR) << "Unable to configure video decoder: " << status;
345 return status;
346 }
347
Linus Nilssonf4641542021-02-04 15:12:26 -0800348 if (sourceIsHdr) {
349 bool supported = false;
350 AMediaFormat* inputFormat = AMediaCodec_getInputFormat(mDecoder);
351
352 if (inputFormat != nullptr) {
353 int32_t transferFunc;
354 supported = AMediaFormat_getInt32(inputFormat,
355 TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST,
356 &transferFunc) &&
357 transferFunc == COLOR_TRANSFER_SDR_VIDEO;
358 AMediaFormat_delete(inputFormat);
359 }
360
361 if (!supported) {
362 LOG(ERROR) << "HDR to SDR conversion unsupported by the codec";
363 return AMEDIA_ERROR_UNSUPPORTED;
364 }
365 }
366
Linus Nilsson0da327a2020-01-31 16:22:18 -0800367 // Configure codecs to run in async mode.
368 AMediaCodecOnAsyncNotifyCallback asyncCodecCallbacks = {
369 .onAsyncInputAvailable = AsyncCodecCallbackDispatch::onAsyncInputAvailable,
370 .onAsyncOutputAvailable = AsyncCodecCallbackDispatch::onAsyncOutputAvailable,
371 .onAsyncFormatChanged = AsyncCodecCallbackDispatch::onAsyncFormatChanged,
372 .onAsyncError = AsyncCodecCallbackDispatch::onAsyncError};
373
Linus Nilssone4716f22020-07-10 16:07:57 -0700374 // Note: The decoder does not need its own wrapper because its lifetime is tied to the
375 // transcoder. But the same callbacks are reused for decoder and encoder so we pass the encoder
376 // wrapper as userdata here but never read the codec from it in the callback.
377 status = AMediaCodec_setAsyncNotifyCallback(mDecoder, asyncCodecCallbacks, mEncoder.get());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800378 if (status != AMEDIA_OK) {
379 LOG(ERROR) << "Unable to set decoder to async mode: " << status;
380 return status;
381 }
382
Linus Nilssone4716f22020-07-10 16:07:57 -0700383 status = AMediaCodec_setAsyncNotifyCallback(mEncoder->getCodec(), asyncCodecCallbacks,
384 mEncoder.get());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800385 if (status != AMEDIA_OK) {
386 LOG(ERROR) << "Unable to set encoder to async mode: " << status;
387 return status;
388 }
389
390 return AMEDIA_OK;
391}
392
393void VideoTrackTranscoder::enqueueInputSample(int32_t bufferIndex) {
394 media_status_t status = AMEDIA_OK;
395
Linus Nilssonc6221db2020-03-18 14:46:22 -0700396 if (mEosFromSource) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800397 return;
398 }
399
400 status = mMediaSampleReader->getSampleInfoForTrack(mTrackIndex, &mSampleInfo);
401 if (status != AMEDIA_OK && status != AMEDIA_ERROR_END_OF_STREAM) {
402 LOG(ERROR) << "Error getting next sample info: " << status;
403 mStatus = status;
404 return;
405 }
406 const bool endOfStream = (status == AMEDIA_ERROR_END_OF_STREAM);
407
408 if (!endOfStream) {
409 size_t bufferSize = 0;
410 uint8_t* sourceBuffer = AMediaCodec_getInputBuffer(mDecoder, bufferIndex, &bufferSize);
411 if (sourceBuffer == nullptr) {
412 LOG(ERROR) << "Decoder returned a NULL input buffer.";
413 mStatus = AMEDIA_ERROR_UNKNOWN;
414 return;
415 } else if (bufferSize < mSampleInfo.size) {
416 LOG(ERROR) << "Decoder returned an input buffer that is smaller than the sample.";
417 mStatus = AMEDIA_ERROR_UNKNOWN;
418 return;
419 }
420
421 status = mMediaSampleReader->readSampleDataForTrack(mTrackIndex, sourceBuffer,
422 mSampleInfo.size);
423 if (status != AMEDIA_OK) {
424 LOG(ERROR) << "Unable to read next sample data. Aborting transcode.";
425 mStatus = status;
426 return;
427 }
Linus Nilsson47352412020-12-16 12:21:26 -0800428
429 if (mSampleInfo.size) {
430 ++mInputFrameCount;
431 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800432 } else {
433 LOG(DEBUG) << "EOS from source.";
Linus Nilssonc6221db2020-03-18 14:46:22 -0700434 mEosFromSource = true;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800435 }
436
437 status = AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, mSampleInfo.size,
438 mSampleInfo.presentationTimeUs, mSampleInfo.flags);
439 if (status != AMEDIA_OK) {
440 LOG(ERROR) << "Unable to queue input buffer for decode: " << status;
441 mStatus = status;
442 return;
443 }
444}
445
446void VideoTrackTranscoder::transferBuffer(int32_t bufferIndex, AMediaCodecBufferInfo bufferInfo) {
447 if (bufferIndex >= 0) {
448 bool needsRender = bufferInfo.size > 0;
449 AMediaCodec_releaseOutputBuffer(mDecoder, bufferIndex, needsRender);
450 }
451
452 if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
453 LOG(DEBUG) << "EOS from decoder.";
Linus Nilssone4716f22020-07-10 16:07:57 -0700454 media_status_t status = AMediaCodec_signalEndOfInputStream(mEncoder->getCodec());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800455 if (status != AMEDIA_OK) {
456 LOG(ERROR) << "SignalEOS on encoder returned error: " << status;
457 mStatus = status;
458 }
459 }
460}
461
462void VideoTrackTranscoder::dequeueOutputSample(int32_t bufferIndex,
463 AMediaCodecBufferInfo bufferInfo) {
464 if (bufferIndex >= 0) {
465 size_t sampleSize = 0;
Linus Nilssone4716f22020-07-10 16:07:57 -0700466 uint8_t* buffer =
467 AMediaCodec_getOutputBuffer(mEncoder->getCodec(), bufferIndex, &sampleSize);
Linus Nilssonc6221db2020-03-18 14:46:22 -0700468
Linus Nilssone4716f22020-07-10 16:07:57 -0700469 MediaSample::OnSampleReleasedCallback bufferReleaseCallback =
470 [encoder = mEncoder](MediaSample* sample) {
471 AMediaCodec_releaseOutputBuffer(encoder->getCodec(), sample->bufferId,
472 false /* render */);
473 };
Linus Nilsson0da327a2020-01-31 16:22:18 -0800474
475 std::shared_ptr<MediaSample> sample = MediaSample::createWithReleaseCallback(
Linus Nilssonc6221db2020-03-18 14:46:22 -0700476 buffer, bufferInfo.offset, bufferIndex, bufferReleaseCallback);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800477 sample->info.size = bufferInfo.size;
478 sample->info.flags = bufferInfo.flags;
479 sample->info.presentationTimeUs = bufferInfo.presentationTimeUs;
480
Linus Nilsson47352412020-12-16 12:21:26 -0800481 if (bufferInfo.size > 0 && (bufferInfo.flags & SAMPLE_FLAG_CODEC_CONFIG) == 0) {
482 ++mOutputFrameCount;
483 }
Linus Nilssonc31d2492020-09-23 12:30:00 -0700484 onOutputSampleAvailable(sample);
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700485
486 mLastSampleWasSync = sample->info.flags & SAMPLE_FLAG_SYNC_SAMPLE;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800487 }
488
489 if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
490 LOG(DEBUG) << "EOS from encoder.";
Linus Nilssonc6221db2020-03-18 14:46:22 -0700491 mEosFromEncoder = true;
Linus Nilsson47352412020-12-16 12:21:26 -0800492
493 if (mInputFrameCount != mOutputFrameCount) {
494 LOG(WARNING) << "Input / Output frame count mismatch: " << mInputFrameCount << " vs "
495 << mOutputFrameCount;
496 if (mInputFrameCount > 0 && mOutputFrameCount == 0) {
497 LOG(ERROR) << "Encoder did not produce any output frames.";
498 mStatus = AMEDIA_ERROR_UNKNOWN;
499 }
500 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800501 }
502}
503
Linus Nilsson52df71c2021-03-08 13:01:11 -0800504void VideoTrackTranscoder::updateTrackFormat(AMediaFormat* outputFormat, bool fromDecoder) {
505 if (fromDecoder) {
Linus Nilssona676a9a2021-03-15 18:22:43 -0700506 static const std::vector<AMediaFormatUtils::EntryCopier> kValuesToCopy{
Linus Nilsson52df71c2021-03-08 13:01:11 -0800507 ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_RANGE, Int32),
508 ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_STANDARD, Int32),
509 ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_TRANSFER, Int32),
510 };
511 AMediaFormat* params = AMediaFormat_new();
512 if (params != nullptr) {
Linus Nilssona676a9a2021-03-15 18:22:43 -0700513 AMediaFormatUtils::CopyFormatEntries(outputFormat, params, kValuesToCopy);
Linus Nilsson52df71c2021-03-08 13:01:11 -0800514 if (AMediaCodec_setParameters(mEncoder->getCodec(), params) != AMEDIA_OK) {
515 LOG(WARNING) << "Unable to update encoder with color information";
516 }
517 AMediaFormat_delete(params);
518 }
519 return;
520 }
521
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700522 if (mActualOutputFormat != nullptr) {
523 LOG(WARNING) << "Ignoring duplicate format change.";
524 return;
525 }
526
527 AMediaFormat* formatCopy = AMediaFormat_new();
528 if (!formatCopy || AMediaFormat_copy(formatCopy, outputFormat) != AMEDIA_OK) {
529 LOG(ERROR) << "Unable to copy outputFormat";
530 AMediaFormat_delete(formatCopy);
531 mStatus = AMEDIA_ERROR_INVALID_PARAMETER;
532 return;
533 }
534
535 // Generate the actual track format for muxer based on the encoder output format,
536 // since many vital information comes in the encoder format (eg. CSD).
537 // Transfer necessary fields from the user-configured track format (derived from
538 // source track format and user transcoding request) where needed.
539
540 // Transfer SAR settings:
541 // If mDestinationFormat has SAR set, it means the original source has SAR specified
542 // at container level. This is supposed to override any SAR settings in the bitstream,
543 // thus should always be transferred to the container of the transcoded file.
544 int32_t sarWidth, sarHeight;
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700545 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_SAR_WIDTH, &sarWidth) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700546 (sarWidth > 0) &&
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700547 AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_SAR_HEIGHT, &sarHeight) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700548 (sarHeight > 0)) {
549 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_WIDTH, sarWidth);
550 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_HEIGHT, sarHeight);
551 }
552 // Transfer DAR settings.
553 int32_t displayWidth, displayHeight;
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700554 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_WIDTH, &displayWidth) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700555 (displayWidth > 0) &&
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700556 AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_HEIGHT,
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700557 &displayHeight) &&
558 (displayHeight > 0)) {
559 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_WIDTH, displayWidth);
560 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_HEIGHT, displayHeight);
561 }
562
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700563 // Transfer rotation settings.
564 // Note that muxer itself doesn't take rotation from the track format. It requires
565 // AMediaMuxer_setOrientationHint to set the rotation. Here we pass the rotation to
566 // MediaSampleWriter using the track format. MediaSampleWriter will then call
567 // AMediaMuxer_setOrientationHint as needed.
568 int32_t rotation;
569 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_ROTATION, &rotation) &&
570 (rotation != 0)) {
571 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_ROTATION, rotation);
572 }
573
Linus Nilsson42a971b2020-07-01 16:41:11 -0700574 // Transfer track duration.
575 // Preserve the source track duration by sending it to MediaSampleWriter.
576 int64_t durationUs;
577 if (AMediaFormat_getInt64(mSourceFormat.get(), AMEDIAFORMAT_KEY_DURATION, &durationUs) &&
578 durationUs > 0) {
579 AMediaFormat_setInt64(formatCopy, AMEDIAFORMAT_KEY_DURATION, durationUs);
580 }
581
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700582 // TODO: transfer other fields as required.
583
584 mActualOutputFormat = std::shared_ptr<AMediaFormat>(formatCopy, &AMediaFormat_delete);
Linus Nilssona676a9a2021-03-15 18:22:43 -0700585 LOG(INFO) << "Actual output format: " << AMediaFormat_toString(formatCopy);
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700586
587 notifyTrackFormatAvailable();
588}
589
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700590media_status_t VideoTrackTranscoder::runTranscodeLoop(bool* stopped) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700591 // Push start decoder and encoder as two messages, so that these are subject to the
Chong Zhangbc062482020-10-14 16:43:53 -0700592 // stop request as well. If the session is cancelled (or paused) immediately after start,
Chong Zhangb55c5452020-06-26 14:32:12 -0700593 // we don't need to waste time start then stop the codecs.
594 mCodecMessageQueue.push([this] {
595 media_status_t status = AMediaCodec_start(mDecoder);
596 if (status != AMEDIA_OK) {
597 LOG(ERROR) << "Unable to start video decoder: " << status;
598 mStatus = status;
599 }
600 });
Linus Nilsson0da327a2020-01-31 16:22:18 -0800601
Chong Zhangb55c5452020-06-26 14:32:12 -0700602 mCodecMessageQueue.push([this] {
Linus Nilssone4716f22020-07-10 16:07:57 -0700603 media_status_t status = AMediaCodec_start(mEncoder->getCodec());
Chong Zhangb55c5452020-06-26 14:32:12 -0700604 if (status != AMEDIA_OK) {
605 LOG(ERROR) << "Unable to start video encoder: " << status;
606 mStatus = status;
607 }
Linus Nilssone4716f22020-07-10 16:07:57 -0700608 mEncoder->setStarted();
Chong Zhangb55c5452020-06-26 14:32:12 -0700609 });
Linus Nilsson0da327a2020-01-31 16:22:18 -0800610
611 // Process codec events until EOS is reached, transcoding is stopped or an error occurs.
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700612 while (mStopRequest != STOP_NOW && !mEosFromEncoder && mStatus == AMEDIA_OK) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800613 std::function<void()> message = mCodecMessageQueue.pop();
614 message();
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700615
616 if (mStopRequest == STOP_ON_SYNC && mLastSampleWasSync) {
617 break;
618 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800619 }
620
Linus Nilsson93cf9132020-09-24 12:12:48 -0700621 mCodecMessageQueue.abort();
622 AMediaCodec_stop(mDecoder);
623
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700624 // Signal if transcoding was stopped before it finished.
625 if (mStopRequest != NONE && !mEosFromEncoder && mStatus == AMEDIA_OK) {
626 *stopped = true;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800627 }
628
Linus Nilsson0da327a2020-01-31 16:22:18 -0800629 return mStatus;
630}
631
632void VideoTrackTranscoder::abortTranscodeLoop() {
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700633 if (mStopRequest == STOP_NOW) {
634 // Wake up transcoder thread.
635 mCodecMessageQueue.push([] {}, true /* front */);
636 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800637}
638
Linus Nilssoncab39d82020-05-14 16:32:21 -0700639std::shared_ptr<AMediaFormat> VideoTrackTranscoder::getOutputFormat() const {
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700640 return mActualOutputFormat;
Linus Nilssoncab39d82020-05-14 16:32:21 -0700641}
642
Linus Nilsson0da327a2020-01-31 16:22:18 -0800643} // namespace android