blob: 7272a747ef4e296c3309ff247c162ee8b1182cec [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>
Linus Nilsson22df0f22021-04-21 15:11:27 -070024#include <sys/prctl.h>
Linus Nilsson0da327a2020-01-31 16:22:18 -080025
Linus Nilsson7a127b22020-10-15 16:23:54 -070026using namespace AMediaFormatUtils;
27
Linus Nilsson0da327a2020-01-31 16:22:18 -080028namespace android {
29
30// Check that the codec sample flags have the expected NDK meaning.
31static_assert(SAMPLE_FLAG_CODEC_CONFIG == AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG,
32 "Sample flag mismatch: CODEC_CONFIG");
33static_assert(SAMPLE_FLAG_END_OF_STREAM == AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM,
34 "Sample flag mismatch: END_OF_STREAM");
35static_assert(SAMPLE_FLAG_PARTIAL_FRAME == AMEDIACODEC_BUFFER_FLAG_PARTIAL_FRAME,
36 "Sample flag mismatch: PARTIAL_FRAME");
37
Linus Nilssoncab39d82020-05-14 16:32:21 -070038// Color format defined by surface. (See MediaCodecInfo.CodecCapabilities#COLOR_FormatSurface.)
39static constexpr int32_t kColorFormatSurface = 0x7f000789;
40// Default key frame interval in seconds.
41static constexpr float kDefaultKeyFrameIntervalSeconds = 1.0f;
Linus Nilsson7a127b22020-10-15 16:23:54 -070042// Default codec operating rate.
Linus Nilsson504394a2020-12-16 11:10:10 -080043static int32_t kDefaultCodecOperatingRate720P = base::GetIntProperty(
hkuangbcb9ec12020-12-14 22:16:09 -080044 "debug.media.transcoding.codec_max_operating_rate_720P", /*default*/ 480);
45static int32_t kDefaultCodecOperatingRate1080P = base::GetIntProperty(
46 "debug.media.transcoding.codec_max_operating_rate_1080P", /*default*/ 240);
Linus Nilsson7a127b22020-10-15 16:23:54 -070047// Default codec priority.
48static constexpr int32_t kDefaultCodecPriority = 1;
49// Default bitrate, in case source estimation fails.
50static constexpr int32_t kDefaultBitrateMbps = 10 * 1000 * 1000;
Linus Nilssonaf4a3212020-12-15 08:18:25 -080051// Default frame rate.
52static constexpr int32_t kDefaultFrameRate = 30;
Linus Nilssoncab39d82020-05-14 16:32:21 -070053
Linus Nilsson0da327a2020-01-31 16:22:18 -080054template <typename T>
55void VideoTrackTranscoder::BlockingQueue<T>::push(T const& value, bool front) {
56 {
Linus Nilsson93cf9132020-09-24 12:12:48 -070057 std::scoped_lock lock(mMutex);
58 if (mAborted) {
59 return;
60 }
61
Linus Nilsson0da327a2020-01-31 16:22:18 -080062 if (front) {
63 mQueue.push_front(value);
64 } else {
65 mQueue.push_back(value);
66 }
67 }
68 mCondition.notify_one();
69}
70
71template <typename T>
72T VideoTrackTranscoder::BlockingQueue<T>::pop() {
Linus Nilsson93cf9132020-09-24 12:12:48 -070073 std::unique_lock lock(mMutex);
Linus Nilsson0da327a2020-01-31 16:22:18 -080074 while (mQueue.empty()) {
75 mCondition.wait(lock);
76 }
77 T value = mQueue.front();
78 mQueue.pop_front();
79 return value;
80}
81
Linus Nilsson93cf9132020-09-24 12:12:48 -070082// Note: Do not call if another thread might waiting in pop.
83template <typename T>
84void VideoTrackTranscoder::BlockingQueue<T>::abort() {
85 std::scoped_lock lock(mMutex);
86 mAborted = true;
87 mQueue.clear();
88}
89
Linus Nilssone4716f22020-07-10 16:07:57 -070090// The CodecWrapper class is used to let AMediaCodec instances outlive the transcoder object itself
91// by giving the codec a weak pointer to the transcoder. Codecs wrapped in this object are kept
92// alive by the transcoder and the codec's outstanding buffers. Once the transcoder stops and all
93// output buffers have been released by downstream components the codec will also be released.
94class VideoTrackTranscoder::CodecWrapper {
95public:
96 CodecWrapper(AMediaCodec* codec, const std::weak_ptr<VideoTrackTranscoder>& transcoder)
97 : mCodec(codec), mTranscoder(transcoder), mCodecStarted(false) {}
98 ~CodecWrapper() {
99 if (mCodecStarted) {
100 AMediaCodec_stop(mCodec);
101 }
102 AMediaCodec_delete(mCodec);
103 }
104
105 AMediaCodec* getCodec() { return mCodec; }
106 std::shared_ptr<VideoTrackTranscoder> getTranscoder() const { return mTranscoder.lock(); };
107 void setStarted() { mCodecStarted = true; }
108
109private:
110 AMediaCodec* mCodec;
111 std::weak_ptr<VideoTrackTranscoder> mTranscoder;
112 bool mCodecStarted;
113};
114
Linus Nilsson0da327a2020-01-31 16:22:18 -0800115// Dispatch responses to codec callbacks onto the message queue.
116struct AsyncCodecCallbackDispatch {
117 static void onAsyncInputAvailable(AMediaCodec* codec, void* userdata, int32_t index) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700118 VideoTrackTranscoder::CodecWrapper* wrapper =
119 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
120 if (auto transcoder = wrapper->getTranscoder()) {
121 if (codec == transcoder->mDecoder) {
122 transcoder->mCodecMessageQueue.push(
123 [transcoder, index] { transcoder->enqueueInputSample(index); });
124 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800125 }
126 }
127
128 static void onAsyncOutputAvailable(AMediaCodec* codec, void* userdata, int32_t index,
129 AMediaCodecBufferInfo* bufferInfoPtr) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700130 VideoTrackTranscoder::CodecWrapper* wrapper =
131 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800132 AMediaCodecBufferInfo bufferInfo = *bufferInfoPtr;
Linus Nilssone4716f22020-07-10 16:07:57 -0700133 if (auto transcoder = wrapper->getTranscoder()) {
134 transcoder->mCodecMessageQueue.push([transcoder, index, codec, bufferInfo] {
135 if (codec == transcoder->mDecoder) {
136 transcoder->transferBuffer(index, bufferInfo);
137 } else if (codec == transcoder->mEncoder->getCodec()) {
138 transcoder->dequeueOutputSample(index, bufferInfo);
139 }
140 });
141 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800142 }
143
144 static void onAsyncFormatChanged(AMediaCodec* codec, void* userdata, AMediaFormat* format) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700145 VideoTrackTranscoder::CodecWrapper* wrapper =
146 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
147 if (auto transcoder = wrapper->getTranscoder()) {
Linus Nilsson52df71c2021-03-08 13:01:11 -0800148 const bool isDecoder = codec == transcoder->mDecoder;
149 const char* kCodecName = (isDecoder ? "Decoder" : "Encoder");
Linus Nilssona676a9a2021-03-15 18:22:43 -0700150 LOG(INFO) << kCodecName << " format changed: " << AMediaFormat_toString(format);
Linus Nilsson52df71c2021-03-08 13:01:11 -0800151 transcoder->mCodecMessageQueue.push([transcoder, format, isDecoder] {
152 transcoder->updateTrackFormat(format, isDecoder);
153 });
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700154 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800155 }
156
157 static void onAsyncError(AMediaCodec* codec, void* userdata, media_status_t error,
158 int32_t actionCode, const char* detail) {
159 LOG(ERROR) << "Error from codec " << codec << ", userdata " << userdata << ", error "
160 << error << ", action " << actionCode << ", detail " << detail;
Linus Nilssone4716f22020-07-10 16:07:57 -0700161 VideoTrackTranscoder::CodecWrapper* wrapper =
162 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
163 if (auto transcoder = wrapper->getTranscoder()) {
164 transcoder->mCodecMessageQueue.push(
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700165 [transcoder, error] { transcoder->mStatus = error; }, true);
Linus Nilssone4716f22020-07-10 16:07:57 -0700166 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800167 }
168};
169
Linus Nilssone4716f22020-07-10 16:07:57 -0700170// static
171std::shared_ptr<VideoTrackTranscoder> VideoTrackTranscoder::create(
Chong Zhangbbb4eac2020-11-18 11:12:06 -0800172 const std::weak_ptr<MediaTrackTranscoderCallback>& transcoderCallback, pid_t pid,
173 uid_t uid) {
174 return std::shared_ptr<VideoTrackTranscoder>(
175 new VideoTrackTranscoder(transcoderCallback, pid, uid));
Linus Nilssone4716f22020-07-10 16:07:57 -0700176}
177
Linus Nilsson0da327a2020-01-31 16:22:18 -0800178VideoTrackTranscoder::~VideoTrackTranscoder() {
179 if (mDecoder != nullptr) {
180 AMediaCodec_delete(mDecoder);
181 }
182
Linus Nilsson0da327a2020-01-31 16:22:18 -0800183 if (mSurface != nullptr) {
184 ANativeWindow_release(mSurface);
185 }
186}
187
hkuangbcb9ec12020-12-14 22:16:09 -0800188// Search the default operating rate based on resolution.
189static int32_t getDefaultOperatingRate(AMediaFormat* encoderFormat) {
190 int32_t width, height;
191 if (AMediaFormat_getInt32(encoderFormat, AMEDIAFORMAT_KEY_WIDTH, &width) && (width > 0) &&
192 AMediaFormat_getInt32(encoderFormat, AMEDIAFORMAT_KEY_HEIGHT, &height) && (height > 0)) {
193 if ((width == 1280 && height == 720) || (width == 720 && height == 1280)) {
Linus Nilsson504394a2020-12-16 11:10:10 -0800194 return kDefaultCodecOperatingRate720P;
hkuangbcb9ec12020-12-14 22:16:09 -0800195 } else if ((width == 1920 && height == 1080) || (width == 1080 && height == 1920)) {
196 return kDefaultCodecOperatingRate1080P;
hkuangbcb9ec12020-12-14 22:16:09 -0800197 } else {
198 LOG(WARNING) << "Could not find default operating rate: " << width << " " << height;
Linus Nilsson504394a2020-12-16 11:10:10 -0800199 // Don't set operating rate if the correct dimensions are not found.
hkuangbcb9ec12020-12-14 22:16:09 -0800200 }
201 } else {
202 LOG(ERROR) << "Failed to get default operating rate due to missing resolution";
203 }
204 return -1;
205}
206
Linus Nilsson0da327a2020-01-31 16:22:18 -0800207// Creates and configures the codecs.
208media_status_t VideoTrackTranscoder::configureDestinationFormat(
209 const std::shared_ptr<AMediaFormat>& destinationFormat) {
210 media_status_t status = AMEDIA_OK;
211
212 if (destinationFormat == nullptr) {
Linus Nilssoncab39d82020-05-14 16:32:21 -0700213 LOG(ERROR) << "Destination format is null, use passthrough transcoder";
Linus Nilsson0da327a2020-01-31 16:22:18 -0800214 return AMEDIA_ERROR_INVALID_PARAMETER;
215 }
216
Linus Nilssoncab39d82020-05-14 16:32:21 -0700217 AMediaFormat* encoderFormat = AMediaFormat_new();
218 if (!encoderFormat || AMediaFormat_copy(encoderFormat, destinationFormat.get()) != AMEDIA_OK) {
219 LOG(ERROR) << "Unable to copy destination format";
220 return AMEDIA_ERROR_INVALID_PARAMETER;
221 }
222
Linus Nilsson1184f932021-04-12 16:13:39 -0700223 if (!AMediaFormat_getInt32(encoderFormat, AMEDIAFORMAT_KEY_BIT_RATE, &mConfiguredBitrate)) {
224 status = mMediaSampleReader->getEstimatedBitrateForTrack(mTrackIndex, &mConfiguredBitrate);
Linus Nilsson800793f2020-07-31 16:16:38 -0700225 if (status != AMEDIA_OK) {
226 LOG(ERROR) << "Unable to estimate bitrate. Using default " << kDefaultBitrateMbps;
Linus Nilsson1184f932021-04-12 16:13:39 -0700227 mConfiguredBitrate = kDefaultBitrateMbps;
Linus Nilsson800793f2020-07-31 16:16:38 -0700228 }
229
Linus Nilsson1184f932021-04-12 16:13:39 -0700230 LOG(INFO) << "Configuring bitrate " << mConfiguredBitrate;
231 AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_BIT_RATE, mConfiguredBitrate);
Linus Nilsson800793f2020-07-31 16:16:38 -0700232 }
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 Nilsson6bc185f2021-04-22 17:03:07 -0700256 // Request encoder to use background priorities by default.
257 SetDefaultFormatValueInt32(TBD_AMEDIACODEC_PARAMETER_KEY_BACKGROUND_MODE, encoderFormat,
258 1 /* true */);
259
Linus Nilssoncab39d82020-05-14 16:32:21 -0700260 mDestinationFormat = std::shared_ptr<AMediaFormat>(encoderFormat, &AMediaFormat_delete);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800261
262 // Create and configure the encoder.
263 const char* destinationMime = nullptr;
264 bool ok = AMediaFormat_getString(mDestinationFormat.get(), AMEDIAFORMAT_KEY_MIME,
265 &destinationMime);
266 if (!ok) {
267 LOG(ERROR) << "Destination MIME type is required for transcoding.";
268 return AMEDIA_ERROR_INVALID_PARAMETER;
269 }
270
Chong Zhang5945dbe2021-04-21 17:34:51 -0700271#define __TRANSCODING_MIN_API__ 31
Jiyong Park26ddfc52021-01-22 16:26:40 +0900272
273 AMediaCodec* encoder;
274 if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
275 encoder = AMediaCodec_createEncoderByTypeForClient(destinationMime, mPid, mUid);
276 } else {
277 encoder = AMediaCodec_createEncoderByType(destinationMime);
278 }
Linus Nilssonc6221db2020-03-18 14:46:22 -0700279 if (encoder == nullptr) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800280 LOG(ERROR) << "Unable to create encoder for type " << destinationMime;
281 return AMEDIA_ERROR_UNSUPPORTED;
282 }
Linus Nilssone4716f22020-07-10 16:07:57 -0700283 mEncoder = std::make_shared<CodecWrapper>(encoder, shared_from_this());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800284
Linus Nilssona676a9a2021-03-15 18:22:43 -0700285 LOG(INFO) << "Configuring encoder with: " << AMediaFormat_toString(mDestinationFormat.get());
Linus Nilssone4716f22020-07-10 16:07:57 -0700286 status = AMediaCodec_configure(mEncoder->getCodec(), mDestinationFormat.get(),
287 NULL /* surface */, NULL /* crypto */,
288 AMEDIACODEC_CONFIGURE_FLAG_ENCODE);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800289 if (status != AMEDIA_OK) {
290 LOG(ERROR) << "Unable to configure video encoder: " << status;
291 return status;
292 }
293
Linus Nilssone4716f22020-07-10 16:07:57 -0700294 status = AMediaCodec_createInputSurface(mEncoder->getCodec(), &mSurface);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800295 if (status != AMEDIA_OK) {
296 LOG(ERROR) << "Unable to create an encoder input surface: %d" << status;
297 return status;
298 }
299
300 // Create and configure the decoder.
301 const char* sourceMime = nullptr;
302 ok = AMediaFormat_getString(mSourceFormat.get(), AMEDIAFORMAT_KEY_MIME, &sourceMime);
303 if (!ok) {
304 LOG(ERROR) << "Source MIME type is required for transcoding.";
305 return AMEDIA_ERROR_INVALID_PARAMETER;
306 }
307
Jiyong Park26ddfc52021-01-22 16:26:40 +0900308 if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
309 mDecoder = AMediaCodec_createDecoderByTypeForClient(sourceMime, mPid, mUid);
310 } else {
311 mDecoder = AMediaCodec_createDecoderByType(sourceMime);
312 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800313 if (mDecoder == nullptr) {
314 LOG(ERROR) << "Unable to create decoder for type " << sourceMime;
315 return AMEDIA_ERROR_UNSUPPORTED;
316 }
317
Linus Nilsson93591892020-08-03 18:56:55 -0700318 auto decoderFormat = std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
319 if (!decoderFormat ||
320 AMediaFormat_copy(decoderFormat.get(), mSourceFormat.get()) != AMEDIA_OK) {
321 LOG(ERROR) << "Unable to copy source format";
322 return AMEDIA_ERROR_INVALID_PARAMETER;
323 }
324
Linus Nilssonf4641542021-02-04 15:12:26 -0800325 // Request decoder to convert HDR content to SDR.
Linus Nilssona99f4042021-02-25 15:49:43 -0800326 const bool sourceIsHdr = VideoIsHdr(mSourceFormat.get());
Linus Nilssonf4641542021-02-04 15:12:26 -0800327 if (sourceIsHdr) {
328 AMediaFormat_setInt32(decoderFormat.get(),
329 TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST,
330 COLOR_TRANSFER_SDR_VIDEO);
331 }
332
Linus Nilsson93591892020-08-03 18:56:55 -0700333 // Prevent decoder from overwriting frames that the encoder has not yet consumed.
334 AMediaFormat_setInt32(decoderFormat.get(), TBD_AMEDIACODEC_PARAMETER_KEY_ALLOW_FRAME_DROP, 0);
335
Linus Nilsson16d772b2020-09-29 19:21:11 -0700336 // Copy over configurations that apply to both encoder and decoder.
Linus Nilssona676a9a2021-03-15 18:22:43 -0700337 static const std::vector<EntryCopier> kEncoderEntriesToCopy{
Linus Nilsson16d772b2020-09-29 19:21:11 -0700338 ENTRY_COPIER2(AMEDIAFORMAT_KEY_OPERATING_RATE, Float, Int32),
339 ENTRY_COPIER(AMEDIAFORMAT_KEY_PRIORITY, Int32),
Linus Nilsson6bc185f2021-04-22 17:03:07 -0700340 ENTRY_COPIER(TBD_AMEDIACODEC_PARAMETER_KEY_BACKGROUND_MODE, Int32),
Linus Nilsson16d772b2020-09-29 19:21:11 -0700341 };
Linus Nilssona676a9a2021-03-15 18:22:43 -0700342 CopyFormatEntries(mDestinationFormat.get(), decoderFormat.get(), kEncoderEntriesToCopy);
Linus Nilsson16d772b2020-09-29 19:21:11 -0700343
Linus Nilssona676a9a2021-03-15 18:22:43 -0700344 LOG(INFO) << "Configuring decoder with: " << AMediaFormat_toString(decoderFormat.get());
Linus Nilsson93591892020-08-03 18:56:55 -0700345 status = AMediaCodec_configure(mDecoder, decoderFormat.get(), mSurface, NULL /* crypto */,
Linus Nilsson0da327a2020-01-31 16:22:18 -0800346 0 /* flags */);
347 if (status != AMEDIA_OK) {
348 LOG(ERROR) << "Unable to configure video decoder: " << status;
349 return status;
350 }
351
Linus Nilssonf4641542021-02-04 15:12:26 -0800352 if (sourceIsHdr) {
353 bool supported = false;
354 AMediaFormat* inputFormat = AMediaCodec_getInputFormat(mDecoder);
355
356 if (inputFormat != nullptr) {
357 int32_t transferFunc;
358 supported = AMediaFormat_getInt32(inputFormat,
359 TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST,
360 &transferFunc) &&
361 transferFunc == COLOR_TRANSFER_SDR_VIDEO;
362 AMediaFormat_delete(inputFormat);
363 }
364
365 if (!supported) {
366 LOG(ERROR) << "HDR to SDR conversion unsupported by the codec";
367 return AMEDIA_ERROR_UNSUPPORTED;
368 }
369 }
370
Linus Nilsson0da327a2020-01-31 16:22:18 -0800371 // Configure codecs to run in async mode.
372 AMediaCodecOnAsyncNotifyCallback asyncCodecCallbacks = {
373 .onAsyncInputAvailable = AsyncCodecCallbackDispatch::onAsyncInputAvailable,
374 .onAsyncOutputAvailable = AsyncCodecCallbackDispatch::onAsyncOutputAvailable,
375 .onAsyncFormatChanged = AsyncCodecCallbackDispatch::onAsyncFormatChanged,
376 .onAsyncError = AsyncCodecCallbackDispatch::onAsyncError};
377
Linus Nilssone4716f22020-07-10 16:07:57 -0700378 // Note: The decoder does not need its own wrapper because its lifetime is tied to the
379 // transcoder. But the same callbacks are reused for decoder and encoder so we pass the encoder
380 // wrapper as userdata here but never read the codec from it in the callback.
381 status = AMediaCodec_setAsyncNotifyCallback(mDecoder, asyncCodecCallbacks, mEncoder.get());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800382 if (status != AMEDIA_OK) {
383 LOG(ERROR) << "Unable to set decoder to async mode: " << status;
384 return status;
385 }
386
Linus Nilssone4716f22020-07-10 16:07:57 -0700387 status = AMediaCodec_setAsyncNotifyCallback(mEncoder->getCodec(), asyncCodecCallbacks,
388 mEncoder.get());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800389 if (status != AMEDIA_OK) {
390 LOG(ERROR) << "Unable to set encoder to async mode: " << status;
391 return status;
392 }
393
394 return AMEDIA_OK;
395}
396
397void VideoTrackTranscoder::enqueueInputSample(int32_t bufferIndex) {
398 media_status_t status = AMEDIA_OK;
399
Linus Nilssonc6221db2020-03-18 14:46:22 -0700400 if (mEosFromSource) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800401 return;
402 }
403
404 status = mMediaSampleReader->getSampleInfoForTrack(mTrackIndex, &mSampleInfo);
405 if (status != AMEDIA_OK && status != AMEDIA_ERROR_END_OF_STREAM) {
406 LOG(ERROR) << "Error getting next sample info: " << status;
407 mStatus = status;
408 return;
409 }
410 const bool endOfStream = (status == AMEDIA_ERROR_END_OF_STREAM);
411
412 if (!endOfStream) {
413 size_t bufferSize = 0;
414 uint8_t* sourceBuffer = AMediaCodec_getInputBuffer(mDecoder, bufferIndex, &bufferSize);
415 if (sourceBuffer == nullptr) {
416 LOG(ERROR) << "Decoder returned a NULL input buffer.";
417 mStatus = AMEDIA_ERROR_UNKNOWN;
418 return;
419 } else if (bufferSize < mSampleInfo.size) {
420 LOG(ERROR) << "Decoder returned an input buffer that is smaller than the sample.";
421 mStatus = AMEDIA_ERROR_UNKNOWN;
422 return;
423 }
424
425 status = mMediaSampleReader->readSampleDataForTrack(mTrackIndex, sourceBuffer,
426 mSampleInfo.size);
427 if (status != AMEDIA_OK) {
428 LOG(ERROR) << "Unable to read next sample data. Aborting transcode.";
429 mStatus = status;
430 return;
431 }
Linus Nilsson47352412020-12-16 12:21:26 -0800432
433 if (mSampleInfo.size) {
434 ++mInputFrameCount;
435 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800436 } else {
437 LOG(DEBUG) << "EOS from source.";
Linus Nilssonc6221db2020-03-18 14:46:22 -0700438 mEosFromSource = true;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800439 }
440
441 status = AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, mSampleInfo.size,
442 mSampleInfo.presentationTimeUs, mSampleInfo.flags);
443 if (status != AMEDIA_OK) {
444 LOG(ERROR) << "Unable to queue input buffer for decode: " << status;
445 mStatus = status;
446 return;
447 }
448}
449
450void VideoTrackTranscoder::transferBuffer(int32_t bufferIndex, AMediaCodecBufferInfo bufferInfo) {
451 if (bufferIndex >= 0) {
452 bool needsRender = bufferInfo.size > 0;
453 AMediaCodec_releaseOutputBuffer(mDecoder, bufferIndex, needsRender);
454 }
455
456 if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
457 LOG(DEBUG) << "EOS from decoder.";
Linus Nilssone4716f22020-07-10 16:07:57 -0700458 media_status_t status = AMediaCodec_signalEndOfInputStream(mEncoder->getCodec());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800459 if (status != AMEDIA_OK) {
460 LOG(ERROR) << "SignalEOS on encoder returned error: " << status;
461 mStatus = status;
462 }
463 }
464}
465
466void VideoTrackTranscoder::dequeueOutputSample(int32_t bufferIndex,
467 AMediaCodecBufferInfo bufferInfo) {
468 if (bufferIndex >= 0) {
469 size_t sampleSize = 0;
Linus Nilssone4716f22020-07-10 16:07:57 -0700470 uint8_t* buffer =
471 AMediaCodec_getOutputBuffer(mEncoder->getCodec(), bufferIndex, &sampleSize);
Linus Nilssonc6221db2020-03-18 14:46:22 -0700472
Linus Nilssone4716f22020-07-10 16:07:57 -0700473 MediaSample::OnSampleReleasedCallback bufferReleaseCallback =
474 [encoder = mEncoder](MediaSample* sample) {
475 AMediaCodec_releaseOutputBuffer(encoder->getCodec(), sample->bufferId,
476 false /* render */);
477 };
Linus Nilsson0da327a2020-01-31 16:22:18 -0800478
479 std::shared_ptr<MediaSample> sample = MediaSample::createWithReleaseCallback(
Linus Nilssonc6221db2020-03-18 14:46:22 -0700480 buffer, bufferInfo.offset, bufferIndex, bufferReleaseCallback);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800481 sample->info.size = bufferInfo.size;
482 sample->info.flags = bufferInfo.flags;
483 sample->info.presentationTimeUs = bufferInfo.presentationTimeUs;
484
Linus Nilsson47352412020-12-16 12:21:26 -0800485 if (bufferInfo.size > 0 && (bufferInfo.flags & SAMPLE_FLAG_CODEC_CONFIG) == 0) {
486 ++mOutputFrameCount;
487 }
Linus Nilssonc31d2492020-09-23 12:30:00 -0700488 onOutputSampleAvailable(sample);
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700489
490 mLastSampleWasSync = sample->info.flags & SAMPLE_FLAG_SYNC_SAMPLE;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800491 }
492
493 if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
494 LOG(DEBUG) << "EOS from encoder.";
Linus Nilssonc6221db2020-03-18 14:46:22 -0700495 mEosFromEncoder = true;
Linus Nilsson47352412020-12-16 12:21:26 -0800496
497 if (mInputFrameCount != mOutputFrameCount) {
498 LOG(WARNING) << "Input / Output frame count mismatch: " << mInputFrameCount << " vs "
499 << mOutputFrameCount;
500 if (mInputFrameCount > 0 && mOutputFrameCount == 0) {
501 LOG(ERROR) << "Encoder did not produce any output frames.";
502 mStatus = AMEDIA_ERROR_UNKNOWN;
503 }
504 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800505 }
506}
507
Linus Nilsson52df71c2021-03-08 13:01:11 -0800508void VideoTrackTranscoder::updateTrackFormat(AMediaFormat* outputFormat, bool fromDecoder) {
509 if (fromDecoder) {
Linus Nilssona676a9a2021-03-15 18:22:43 -0700510 static const std::vector<AMediaFormatUtils::EntryCopier> kValuesToCopy{
Linus Nilsson52df71c2021-03-08 13:01:11 -0800511 ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_RANGE, Int32),
512 ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_STANDARD, Int32),
513 ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_TRANSFER, Int32),
514 };
515 AMediaFormat* params = AMediaFormat_new();
516 if (params != nullptr) {
Linus Nilssona676a9a2021-03-15 18:22:43 -0700517 AMediaFormatUtils::CopyFormatEntries(outputFormat, params, kValuesToCopy);
Linus Nilsson52df71c2021-03-08 13:01:11 -0800518 if (AMediaCodec_setParameters(mEncoder->getCodec(), params) != AMEDIA_OK) {
519 LOG(WARNING) << "Unable to update encoder with color information";
520 }
521 AMediaFormat_delete(params);
522 }
523 return;
524 }
525
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700526 if (mActualOutputFormat != nullptr) {
527 LOG(WARNING) << "Ignoring duplicate format change.";
528 return;
529 }
530
531 AMediaFormat* formatCopy = AMediaFormat_new();
532 if (!formatCopy || AMediaFormat_copy(formatCopy, outputFormat) != AMEDIA_OK) {
533 LOG(ERROR) << "Unable to copy outputFormat";
534 AMediaFormat_delete(formatCopy);
535 mStatus = AMEDIA_ERROR_INVALID_PARAMETER;
536 return;
537 }
538
539 // Generate the actual track format for muxer based on the encoder output format,
540 // since many vital information comes in the encoder format (eg. CSD).
541 // Transfer necessary fields from the user-configured track format (derived from
542 // source track format and user transcoding request) where needed.
543
544 // Transfer SAR settings:
545 // If mDestinationFormat has SAR set, it means the original source has SAR specified
546 // at container level. This is supposed to override any SAR settings in the bitstream,
547 // thus should always be transferred to the container of the transcoded file.
548 int32_t sarWidth, sarHeight;
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700549 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_SAR_WIDTH, &sarWidth) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700550 (sarWidth > 0) &&
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700551 AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_SAR_HEIGHT, &sarHeight) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700552 (sarHeight > 0)) {
553 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_WIDTH, sarWidth);
554 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_HEIGHT, sarHeight);
555 }
556 // Transfer DAR settings.
557 int32_t displayWidth, displayHeight;
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700558 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_WIDTH, &displayWidth) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700559 (displayWidth > 0) &&
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700560 AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_HEIGHT,
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700561 &displayHeight) &&
562 (displayHeight > 0)) {
563 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_WIDTH, displayWidth);
564 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_HEIGHT, displayHeight);
565 }
566
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700567 // Transfer rotation settings.
568 // Note that muxer itself doesn't take rotation from the track format. It requires
569 // AMediaMuxer_setOrientationHint to set the rotation. Here we pass the rotation to
570 // MediaSampleWriter using the track format. MediaSampleWriter will then call
571 // AMediaMuxer_setOrientationHint as needed.
572 int32_t rotation;
573 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_ROTATION, &rotation) &&
574 (rotation != 0)) {
575 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_ROTATION, rotation);
576 }
577
Linus Nilsson42a971b2020-07-01 16:41:11 -0700578 // Transfer track duration.
579 // Preserve the source track duration by sending it to MediaSampleWriter.
580 int64_t durationUs;
581 if (AMediaFormat_getInt64(mSourceFormat.get(), AMEDIAFORMAT_KEY_DURATION, &durationUs) &&
582 durationUs > 0) {
583 AMediaFormat_setInt64(formatCopy, AMEDIAFORMAT_KEY_DURATION, durationUs);
584 }
585
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700586 // TODO: transfer other fields as required.
587
588 mActualOutputFormat = std::shared_ptr<AMediaFormat>(formatCopy, &AMediaFormat_delete);
Linus Nilssona676a9a2021-03-15 18:22:43 -0700589 LOG(INFO) << "Actual output format: " << AMediaFormat_toString(formatCopy);
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700590
591 notifyTrackFormatAvailable();
592}
593
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700594media_status_t VideoTrackTranscoder::runTranscodeLoop(bool* stopped) {
Linus Nilsson22df0f22021-04-21 15:11:27 -0700595 prctl(PR_SET_NAME, (unsigned long)"VideTranscodTrd", 0, 0, 0);
596
Chong Zhangb55c5452020-06-26 14:32:12 -0700597 // Push start decoder and encoder as two messages, so that these are subject to the
Chong Zhangbc062482020-10-14 16:43:53 -0700598 // stop request as well. If the session is cancelled (or paused) immediately after start,
Chong Zhangb55c5452020-06-26 14:32:12 -0700599 // we don't need to waste time start then stop the codecs.
600 mCodecMessageQueue.push([this] {
601 media_status_t status = AMediaCodec_start(mDecoder);
602 if (status != AMEDIA_OK) {
603 LOG(ERROR) << "Unable to start video decoder: " << status;
604 mStatus = status;
605 }
606 });
Linus Nilsson0da327a2020-01-31 16:22:18 -0800607
Chong Zhangb55c5452020-06-26 14:32:12 -0700608 mCodecMessageQueue.push([this] {
Linus Nilssone4716f22020-07-10 16:07:57 -0700609 media_status_t status = AMediaCodec_start(mEncoder->getCodec());
Chong Zhangb55c5452020-06-26 14:32:12 -0700610 if (status != AMEDIA_OK) {
611 LOG(ERROR) << "Unable to start video encoder: " << status;
612 mStatus = status;
613 }
Linus Nilssone4716f22020-07-10 16:07:57 -0700614 mEncoder->setStarted();
Chong Zhangb55c5452020-06-26 14:32:12 -0700615 });
Linus Nilsson0da327a2020-01-31 16:22:18 -0800616
617 // Process codec events until EOS is reached, transcoding is stopped or an error occurs.
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700618 while (mStopRequest != STOP_NOW && !mEosFromEncoder && mStatus == AMEDIA_OK) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800619 std::function<void()> message = mCodecMessageQueue.pop();
620 message();
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700621
622 if (mStopRequest == STOP_ON_SYNC && mLastSampleWasSync) {
623 break;
624 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800625 }
626
Linus Nilsson93cf9132020-09-24 12:12:48 -0700627 mCodecMessageQueue.abort();
628 AMediaCodec_stop(mDecoder);
629
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700630 // Signal if transcoding was stopped before it finished.
631 if (mStopRequest != NONE && !mEosFromEncoder && mStatus == AMEDIA_OK) {
632 *stopped = true;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800633 }
634
Linus Nilsson0da327a2020-01-31 16:22:18 -0800635 return mStatus;
636}
637
638void VideoTrackTranscoder::abortTranscodeLoop() {
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700639 if (mStopRequest == STOP_NOW) {
640 // Wake up transcoder thread.
641 mCodecMessageQueue.push([] {}, true /* front */);
642 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800643}
644
Linus Nilssoncab39d82020-05-14 16:32:21 -0700645std::shared_ptr<AMediaFormat> VideoTrackTranscoder::getOutputFormat() const {
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700646 return mActualOutputFormat;
Linus Nilssoncab39d82020-05-14 16:32:21 -0700647}
648
Linus Nilsson0da327a2020-01-31 16:22:18 -0800649} // namespace android