blob: 22ab7a50fde94bc506d589e99fe059108d9fba86 [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 Nilssonb09aac22020-07-29 11:56:53 -070024#include <utils/AndroidThreads.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.
hkuangbcb9ec12020-12-14 22:16:09 -080043static int32_t kDefaultCodecOperatingRate7200P = base::GetIntProperty(
44 "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);
47static int32_t kDefaultCodecOperatingRate4K = base::GetIntProperty(
48 "debug.media.transcoding.codec_max_operating_rate_4K", /*default*/ 120);
Linus Nilsson7a127b22020-10-15 16:23:54 -070049// Default codec priority.
50static constexpr int32_t kDefaultCodecPriority = 1;
51// Default bitrate, in case source estimation fails.
52static constexpr int32_t kDefaultBitrateMbps = 10 * 1000 * 1000;
Linus Nilssonaf4a3212020-12-15 08:18:25 -080053// Default frame rate.
54static constexpr int32_t kDefaultFrameRate = 30;
Linus Nilssoncab39d82020-05-14 16:32:21 -070055
Linus Nilsson0da327a2020-01-31 16:22:18 -080056template <typename T>
57void VideoTrackTranscoder::BlockingQueue<T>::push(T const& value, bool front) {
58 {
Linus Nilsson93cf9132020-09-24 12:12:48 -070059 std::scoped_lock lock(mMutex);
60 if (mAborted) {
61 return;
62 }
63
Linus Nilsson0da327a2020-01-31 16:22:18 -080064 if (front) {
65 mQueue.push_front(value);
66 } else {
67 mQueue.push_back(value);
68 }
69 }
70 mCondition.notify_one();
71}
72
73template <typename T>
74T VideoTrackTranscoder::BlockingQueue<T>::pop() {
Linus Nilsson93cf9132020-09-24 12:12:48 -070075 std::unique_lock lock(mMutex);
Linus Nilsson0da327a2020-01-31 16:22:18 -080076 while (mQueue.empty()) {
77 mCondition.wait(lock);
78 }
79 T value = mQueue.front();
80 mQueue.pop_front();
81 return value;
82}
83
Linus Nilsson93cf9132020-09-24 12:12:48 -070084// Note: Do not call if another thread might waiting in pop.
85template <typename T>
86void VideoTrackTranscoder::BlockingQueue<T>::abort() {
87 std::scoped_lock lock(mMutex);
88 mAborted = true;
89 mQueue.clear();
90}
91
Linus Nilssone4716f22020-07-10 16:07:57 -070092// The CodecWrapper class is used to let AMediaCodec instances outlive the transcoder object itself
93// by giving the codec a weak pointer to the transcoder. Codecs wrapped in this object are kept
94// alive by the transcoder and the codec's outstanding buffers. Once the transcoder stops and all
95// output buffers have been released by downstream components the codec will also be released.
96class VideoTrackTranscoder::CodecWrapper {
97public:
98 CodecWrapper(AMediaCodec* codec, const std::weak_ptr<VideoTrackTranscoder>& transcoder)
99 : mCodec(codec), mTranscoder(transcoder), mCodecStarted(false) {}
100 ~CodecWrapper() {
101 if (mCodecStarted) {
102 AMediaCodec_stop(mCodec);
103 }
104 AMediaCodec_delete(mCodec);
105 }
106
107 AMediaCodec* getCodec() { return mCodec; }
108 std::shared_ptr<VideoTrackTranscoder> getTranscoder() const { return mTranscoder.lock(); };
109 void setStarted() { mCodecStarted = true; }
110
111private:
112 AMediaCodec* mCodec;
113 std::weak_ptr<VideoTrackTranscoder> mTranscoder;
114 bool mCodecStarted;
115};
116
Linus Nilsson0da327a2020-01-31 16:22:18 -0800117// Dispatch responses to codec callbacks onto the message queue.
118struct AsyncCodecCallbackDispatch {
119 static void onAsyncInputAvailable(AMediaCodec* codec, void* userdata, int32_t index) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700120 VideoTrackTranscoder::CodecWrapper* wrapper =
121 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
122 if (auto transcoder = wrapper->getTranscoder()) {
123 if (codec == transcoder->mDecoder) {
124 transcoder->mCodecMessageQueue.push(
125 [transcoder, index] { transcoder->enqueueInputSample(index); });
126 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800127 }
128 }
129
130 static void onAsyncOutputAvailable(AMediaCodec* codec, void* userdata, int32_t index,
131 AMediaCodecBufferInfo* bufferInfoPtr) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700132 VideoTrackTranscoder::CodecWrapper* wrapper =
133 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800134 AMediaCodecBufferInfo bufferInfo = *bufferInfoPtr;
Linus Nilssone4716f22020-07-10 16:07:57 -0700135 if (auto transcoder = wrapper->getTranscoder()) {
136 transcoder->mCodecMessageQueue.push([transcoder, index, codec, bufferInfo] {
137 if (codec == transcoder->mDecoder) {
138 transcoder->transferBuffer(index, bufferInfo);
139 } else if (codec == transcoder->mEncoder->getCodec()) {
140 transcoder->dequeueOutputSample(index, bufferInfo);
141 }
142 });
143 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800144 }
145
146 static void onAsyncFormatChanged(AMediaCodec* codec, void* userdata, AMediaFormat* format) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700147 VideoTrackTranscoder::CodecWrapper* wrapper =
148 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
149 if (auto transcoder = wrapper->getTranscoder()) {
150 const char* kCodecName = (codec == transcoder->mDecoder ? "Decoder" : "Encoder");
151 LOG(DEBUG) << kCodecName << " format changed: " << AMediaFormat_toString(format);
152 if (codec == transcoder->mEncoder->getCodec()) {
153 transcoder->mCodecMessageQueue.push(
154 [transcoder, format] { transcoder->updateTrackFormat(format); });
155 }
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700156 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800157 }
158
159 static void onAsyncError(AMediaCodec* codec, void* userdata, media_status_t error,
160 int32_t actionCode, const char* detail) {
161 LOG(ERROR) << "Error from codec " << codec << ", userdata " << userdata << ", error "
162 << error << ", action " << actionCode << ", detail " << detail;
Linus Nilssone4716f22020-07-10 16:07:57 -0700163 VideoTrackTranscoder::CodecWrapper* wrapper =
164 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
165 if (auto transcoder = wrapper->getTranscoder()) {
166 transcoder->mCodecMessageQueue.push(
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700167 [transcoder, error] { transcoder->mStatus = error; }, true);
Linus Nilssone4716f22020-07-10 16:07:57 -0700168 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800169 }
170};
171
Linus Nilssone4716f22020-07-10 16:07:57 -0700172// static
173std::shared_ptr<VideoTrackTranscoder> VideoTrackTranscoder::create(
Chong Zhangbbb4eac2020-11-18 11:12:06 -0800174 const std::weak_ptr<MediaTrackTranscoderCallback>& transcoderCallback, pid_t pid,
175 uid_t uid) {
176 return std::shared_ptr<VideoTrackTranscoder>(
177 new VideoTrackTranscoder(transcoderCallback, pid, uid));
Linus Nilssone4716f22020-07-10 16:07:57 -0700178}
179
Linus Nilsson0da327a2020-01-31 16:22:18 -0800180VideoTrackTranscoder::~VideoTrackTranscoder() {
181 if (mDecoder != nullptr) {
182 AMediaCodec_delete(mDecoder);
183 }
184
Linus Nilsson0da327a2020-01-31 16:22:18 -0800185 if (mSurface != nullptr) {
186 ANativeWindow_release(mSurface);
187 }
188}
189
hkuangbcb9ec12020-12-14 22:16:09 -0800190// Search the default operating rate based on resolution.
191static int32_t getDefaultOperatingRate(AMediaFormat* encoderFormat) {
192 int32_t width, height;
193 if (AMediaFormat_getInt32(encoderFormat, AMEDIAFORMAT_KEY_WIDTH, &width) && (width > 0) &&
194 AMediaFormat_getInt32(encoderFormat, AMEDIAFORMAT_KEY_HEIGHT, &height) && (height > 0)) {
195 if ((width == 1280 && height == 720) || (width == 720 && height == 1280)) {
196 return kDefaultCodecOperatingRate1080P;
197 } else if ((width == 1920 && height == 1080) || (width == 1080 && height == 1920)) {
198 return kDefaultCodecOperatingRate1080P;
199 } else if (((width == 3840 && height == 2160) || (width == 2160 && height == 3840))) {
200 return kDefaultCodecOperatingRate4K;
201 } else {
202 LOG(WARNING) << "Could not find default operating rate: " << width << " " << height;
203 // Use 4K as that should be the lowest for the devices.
204 return kDefaultCodecOperatingRate4K;
205 }
206 } else {
207 LOG(ERROR) << "Failed to get default operating rate due to missing resolution";
208 }
209 return -1;
210}
211
Linus Nilsson0da327a2020-01-31 16:22:18 -0800212// Creates and configures the codecs.
213media_status_t VideoTrackTranscoder::configureDestinationFormat(
214 const std::shared_ptr<AMediaFormat>& destinationFormat) {
215 media_status_t status = AMEDIA_OK;
216
217 if (destinationFormat == nullptr) {
Linus Nilssoncab39d82020-05-14 16:32:21 -0700218 LOG(ERROR) << "Destination format is null, use passthrough transcoder";
Linus Nilsson0da327a2020-01-31 16:22:18 -0800219 return AMEDIA_ERROR_INVALID_PARAMETER;
220 }
221
Linus Nilssoncab39d82020-05-14 16:32:21 -0700222 AMediaFormat* encoderFormat = AMediaFormat_new();
223 if (!encoderFormat || AMediaFormat_copy(encoderFormat, destinationFormat.get()) != AMEDIA_OK) {
224 LOG(ERROR) << "Unable to copy destination format";
225 return AMEDIA_ERROR_INVALID_PARAMETER;
226 }
227
Linus Nilsson800793f2020-07-31 16:16:38 -0700228 int32_t bitrate;
229 if (!AMediaFormat_getInt32(encoderFormat, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate)) {
230 status = mMediaSampleReader->getEstimatedBitrateForTrack(mTrackIndex, &bitrate);
231 if (status != AMEDIA_OK) {
232 LOG(ERROR) << "Unable to estimate bitrate. Using default " << kDefaultBitrateMbps;
233 bitrate = kDefaultBitrateMbps;
234 }
235
236 LOG(INFO) << "Configuring bitrate " << bitrate;
237 AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_BIT_RATE, bitrate);
238 }
239
Linus Nilsson7a127b22020-10-15 16:23:54 -0700240 SetDefaultFormatValueFloat(AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, encoderFormat,
241 kDefaultKeyFrameIntervalSeconds);
hkuangbcb9ec12020-12-14 22:16:09 -0800242
243 int32_t operatingRate = getDefaultOperatingRate(encoderFormat);
244
245 if (operatingRate != -1) {
246 SetDefaultFormatValueInt32(AMEDIAFORMAT_KEY_OPERATING_RATE, encoderFormat, operatingRate);
247 }
248
Linus Nilsson7a127b22020-10-15 16:23:54 -0700249 SetDefaultFormatValueInt32(AMEDIAFORMAT_KEY_PRIORITY, encoderFormat, kDefaultCodecPriority);
Linus Nilssonaf4a3212020-12-15 08:18:25 -0800250 SetDefaultFormatValueInt32(AMEDIAFORMAT_KEY_FRAME_RATE, encoderFormat, kDefaultFrameRate);
Linus Nilssoncab39d82020-05-14 16:32:21 -0700251 AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, kColorFormatSurface);
252
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700253 // Always encode without rotation. The rotation degree will be transferred directly to
254 // MediaSampleWriter track format, and MediaSampleWriter will call AMediaMuxer_setOrientationHint.
255 AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_ROTATION, 0);
256
Linus Nilssoncab39d82020-05-14 16:32:21 -0700257 mDestinationFormat = std::shared_ptr<AMediaFormat>(encoderFormat, &AMediaFormat_delete);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800258
259 // Create and configure the encoder.
260 const char* destinationMime = nullptr;
261 bool ok = AMediaFormat_getString(mDestinationFormat.get(), AMEDIAFORMAT_KEY_MIME,
262 &destinationMime);
263 if (!ok) {
264 LOG(ERROR) << "Destination MIME type is required for transcoding.";
265 return AMEDIA_ERROR_INVALID_PARAMETER;
266 }
267
Chong Zhangbbb4eac2020-11-18 11:12:06 -0800268 AMediaCodec* encoder = AMediaCodec_createEncoderByTypeForClient(destinationMime, mPid, mUid);
Linus Nilssonc6221db2020-03-18 14:46:22 -0700269 if (encoder == nullptr) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800270 LOG(ERROR) << "Unable to create encoder for type " << destinationMime;
271 return AMEDIA_ERROR_UNSUPPORTED;
272 }
Linus Nilssone4716f22020-07-10 16:07:57 -0700273 mEncoder = std::make_shared<CodecWrapper>(encoder, shared_from_this());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800274
Linus Nilssonaf4a3212020-12-15 08:18:25 -0800275 LOG(DEBUG) << "Configuring encoder with: " << AMediaFormat_toString(mDestinationFormat.get());
Linus Nilssone4716f22020-07-10 16:07:57 -0700276 status = AMediaCodec_configure(mEncoder->getCodec(), mDestinationFormat.get(),
277 NULL /* surface */, NULL /* crypto */,
278 AMEDIACODEC_CONFIGURE_FLAG_ENCODE);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800279 if (status != AMEDIA_OK) {
280 LOG(ERROR) << "Unable to configure video encoder: " << status;
281 return status;
282 }
283
Linus Nilssone4716f22020-07-10 16:07:57 -0700284 status = AMediaCodec_createInputSurface(mEncoder->getCodec(), &mSurface);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800285 if (status != AMEDIA_OK) {
286 LOG(ERROR) << "Unable to create an encoder input surface: %d" << status;
287 return status;
288 }
289
290 // Create and configure the decoder.
291 const char* sourceMime = nullptr;
292 ok = AMediaFormat_getString(mSourceFormat.get(), AMEDIAFORMAT_KEY_MIME, &sourceMime);
293 if (!ok) {
294 LOG(ERROR) << "Source MIME type is required for transcoding.";
295 return AMEDIA_ERROR_INVALID_PARAMETER;
296 }
297
Chong Zhangbbb4eac2020-11-18 11:12:06 -0800298 mDecoder = AMediaCodec_createDecoderByTypeForClient(sourceMime, mPid, mUid);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800299 if (mDecoder == nullptr) {
300 LOG(ERROR) << "Unable to create decoder for type " << sourceMime;
301 return AMEDIA_ERROR_UNSUPPORTED;
302 }
303
Linus Nilsson93591892020-08-03 18:56:55 -0700304 auto decoderFormat = std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
305 if (!decoderFormat ||
306 AMediaFormat_copy(decoderFormat.get(), mSourceFormat.get()) != AMEDIA_OK) {
307 LOG(ERROR) << "Unable to copy source format";
308 return AMEDIA_ERROR_INVALID_PARAMETER;
309 }
310
311 // Prevent decoder from overwriting frames that the encoder has not yet consumed.
312 AMediaFormat_setInt32(decoderFormat.get(), TBD_AMEDIACODEC_PARAMETER_KEY_ALLOW_FRAME_DROP, 0);
313
Linus Nilsson16d772b2020-09-29 19:21:11 -0700314 // Copy over configurations that apply to both encoder and decoder.
Linus Nilsson7a127b22020-10-15 16:23:54 -0700315 static const EntryCopier kEncoderEntriesToCopy[] = {
Linus Nilsson16d772b2020-09-29 19:21:11 -0700316 ENTRY_COPIER2(AMEDIAFORMAT_KEY_OPERATING_RATE, Float, Int32),
317 ENTRY_COPIER(AMEDIAFORMAT_KEY_PRIORITY, Int32),
318 };
319 const size_t entryCount = sizeof(kEncoderEntriesToCopy) / sizeof(kEncoderEntriesToCopy[0]);
Linus Nilsson7a127b22020-10-15 16:23:54 -0700320 CopyFormatEntries(mDestinationFormat.get(), decoderFormat.get(), kEncoderEntriesToCopy,
321 entryCount);
Linus Nilsson16d772b2020-09-29 19:21:11 -0700322
Linus Nilssonaf4a3212020-12-15 08:18:25 -0800323 LOG(DEBUG) << "Configuring decoder with: " << AMediaFormat_toString(decoderFormat.get());
Linus Nilsson93591892020-08-03 18:56:55 -0700324 status = AMediaCodec_configure(mDecoder, decoderFormat.get(), mSurface, NULL /* crypto */,
Linus Nilsson0da327a2020-01-31 16:22:18 -0800325 0 /* flags */);
326 if (status != AMEDIA_OK) {
327 LOG(ERROR) << "Unable to configure video decoder: " << status;
328 return status;
329 }
330
331 // Configure codecs to run in async mode.
332 AMediaCodecOnAsyncNotifyCallback asyncCodecCallbacks = {
333 .onAsyncInputAvailable = AsyncCodecCallbackDispatch::onAsyncInputAvailable,
334 .onAsyncOutputAvailable = AsyncCodecCallbackDispatch::onAsyncOutputAvailable,
335 .onAsyncFormatChanged = AsyncCodecCallbackDispatch::onAsyncFormatChanged,
336 .onAsyncError = AsyncCodecCallbackDispatch::onAsyncError};
337
Linus Nilssone4716f22020-07-10 16:07:57 -0700338 // Note: The decoder does not need its own wrapper because its lifetime is tied to the
339 // transcoder. But the same callbacks are reused for decoder and encoder so we pass the encoder
340 // wrapper as userdata here but never read the codec from it in the callback.
341 status = AMediaCodec_setAsyncNotifyCallback(mDecoder, asyncCodecCallbacks, mEncoder.get());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800342 if (status != AMEDIA_OK) {
343 LOG(ERROR) << "Unable to set decoder to async mode: " << status;
344 return status;
345 }
346
Linus Nilssone4716f22020-07-10 16:07:57 -0700347 status = AMediaCodec_setAsyncNotifyCallback(mEncoder->getCodec(), asyncCodecCallbacks,
348 mEncoder.get());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800349 if (status != AMEDIA_OK) {
350 LOG(ERROR) << "Unable to set encoder to async mode: " << status;
351 return status;
352 }
353
354 return AMEDIA_OK;
355}
356
357void VideoTrackTranscoder::enqueueInputSample(int32_t bufferIndex) {
358 media_status_t status = AMEDIA_OK;
359
Linus Nilssonc6221db2020-03-18 14:46:22 -0700360 if (mEosFromSource) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800361 return;
362 }
363
364 status = mMediaSampleReader->getSampleInfoForTrack(mTrackIndex, &mSampleInfo);
365 if (status != AMEDIA_OK && status != AMEDIA_ERROR_END_OF_STREAM) {
366 LOG(ERROR) << "Error getting next sample info: " << status;
367 mStatus = status;
368 return;
369 }
370 const bool endOfStream = (status == AMEDIA_ERROR_END_OF_STREAM);
371
372 if (!endOfStream) {
373 size_t bufferSize = 0;
374 uint8_t* sourceBuffer = AMediaCodec_getInputBuffer(mDecoder, bufferIndex, &bufferSize);
375 if (sourceBuffer == nullptr) {
376 LOG(ERROR) << "Decoder returned a NULL input buffer.";
377 mStatus = AMEDIA_ERROR_UNKNOWN;
378 return;
379 } else if (bufferSize < mSampleInfo.size) {
380 LOG(ERROR) << "Decoder returned an input buffer that is smaller than the sample.";
381 mStatus = AMEDIA_ERROR_UNKNOWN;
382 return;
383 }
384
385 status = mMediaSampleReader->readSampleDataForTrack(mTrackIndex, sourceBuffer,
386 mSampleInfo.size);
387 if (status != AMEDIA_OK) {
388 LOG(ERROR) << "Unable to read next sample data. Aborting transcode.";
389 mStatus = status;
390 return;
391 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800392 } else {
393 LOG(DEBUG) << "EOS from source.";
Linus Nilssonc6221db2020-03-18 14:46:22 -0700394 mEosFromSource = true;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800395 }
396
397 status = AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, mSampleInfo.size,
398 mSampleInfo.presentationTimeUs, mSampleInfo.flags);
399 if (status != AMEDIA_OK) {
400 LOG(ERROR) << "Unable to queue input buffer for decode: " << status;
401 mStatus = status;
402 return;
403 }
404}
405
406void VideoTrackTranscoder::transferBuffer(int32_t bufferIndex, AMediaCodecBufferInfo bufferInfo) {
407 if (bufferIndex >= 0) {
408 bool needsRender = bufferInfo.size > 0;
409 AMediaCodec_releaseOutputBuffer(mDecoder, bufferIndex, needsRender);
410 }
411
412 if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
413 LOG(DEBUG) << "EOS from decoder.";
Linus Nilssone4716f22020-07-10 16:07:57 -0700414 media_status_t status = AMediaCodec_signalEndOfInputStream(mEncoder->getCodec());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800415 if (status != AMEDIA_OK) {
416 LOG(ERROR) << "SignalEOS on encoder returned error: " << status;
417 mStatus = status;
418 }
419 }
420}
421
422void VideoTrackTranscoder::dequeueOutputSample(int32_t bufferIndex,
423 AMediaCodecBufferInfo bufferInfo) {
424 if (bufferIndex >= 0) {
425 size_t sampleSize = 0;
Linus Nilssone4716f22020-07-10 16:07:57 -0700426 uint8_t* buffer =
427 AMediaCodec_getOutputBuffer(mEncoder->getCodec(), bufferIndex, &sampleSize);
Linus Nilssonc6221db2020-03-18 14:46:22 -0700428
Linus Nilssone4716f22020-07-10 16:07:57 -0700429 MediaSample::OnSampleReleasedCallback bufferReleaseCallback =
430 [encoder = mEncoder](MediaSample* sample) {
431 AMediaCodec_releaseOutputBuffer(encoder->getCodec(), sample->bufferId,
432 false /* render */);
433 };
Linus Nilsson0da327a2020-01-31 16:22:18 -0800434
435 std::shared_ptr<MediaSample> sample = MediaSample::createWithReleaseCallback(
Linus Nilssonc6221db2020-03-18 14:46:22 -0700436 buffer, bufferInfo.offset, bufferIndex, bufferReleaseCallback);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800437 sample->info.size = bufferInfo.size;
438 sample->info.flags = bufferInfo.flags;
439 sample->info.presentationTimeUs = bufferInfo.presentationTimeUs;
440
Linus Nilssonc31d2492020-09-23 12:30:00 -0700441 onOutputSampleAvailable(sample);
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700442
443 mLastSampleWasSync = sample->info.flags & SAMPLE_FLAG_SYNC_SAMPLE;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800444 } else if (bufferIndex == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700445 AMediaFormat* newFormat = AMediaCodec_getOutputFormat(mEncoder->getCodec());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800446 LOG(DEBUG) << "Encoder output format changed: " << AMediaFormat_toString(newFormat);
447 }
448
449 if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
450 LOG(DEBUG) << "EOS from encoder.";
Linus Nilssonc6221db2020-03-18 14:46:22 -0700451 mEosFromEncoder = true;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800452 }
453}
454
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700455void VideoTrackTranscoder::updateTrackFormat(AMediaFormat* outputFormat) {
456 if (mActualOutputFormat != nullptr) {
457 LOG(WARNING) << "Ignoring duplicate format change.";
458 return;
459 }
460
461 AMediaFormat* formatCopy = AMediaFormat_new();
462 if (!formatCopy || AMediaFormat_copy(formatCopy, outputFormat) != AMEDIA_OK) {
463 LOG(ERROR) << "Unable to copy outputFormat";
464 AMediaFormat_delete(formatCopy);
465 mStatus = AMEDIA_ERROR_INVALID_PARAMETER;
466 return;
467 }
468
469 // Generate the actual track format for muxer based on the encoder output format,
470 // since many vital information comes in the encoder format (eg. CSD).
471 // Transfer necessary fields from the user-configured track format (derived from
472 // source track format and user transcoding request) where needed.
473
474 // Transfer SAR settings:
475 // If mDestinationFormat has SAR set, it means the original source has SAR specified
476 // at container level. This is supposed to override any SAR settings in the bitstream,
477 // thus should always be transferred to the container of the transcoded file.
478 int32_t sarWidth, sarHeight;
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700479 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_SAR_WIDTH, &sarWidth) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700480 (sarWidth > 0) &&
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700481 AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_SAR_HEIGHT, &sarHeight) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700482 (sarHeight > 0)) {
483 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_WIDTH, sarWidth);
484 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_HEIGHT, sarHeight);
485 }
486 // Transfer DAR settings.
487 int32_t displayWidth, displayHeight;
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700488 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_WIDTH, &displayWidth) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700489 (displayWidth > 0) &&
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700490 AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_HEIGHT,
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700491 &displayHeight) &&
492 (displayHeight > 0)) {
493 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_WIDTH, displayWidth);
494 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_HEIGHT, displayHeight);
495 }
496
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700497 // Transfer rotation settings.
498 // Note that muxer itself doesn't take rotation from the track format. It requires
499 // AMediaMuxer_setOrientationHint to set the rotation. Here we pass the rotation to
500 // MediaSampleWriter using the track format. MediaSampleWriter will then call
501 // AMediaMuxer_setOrientationHint as needed.
502 int32_t rotation;
503 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_ROTATION, &rotation) &&
504 (rotation != 0)) {
505 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_ROTATION, rotation);
506 }
507
Linus Nilsson42a971b2020-07-01 16:41:11 -0700508 // Transfer track duration.
509 // Preserve the source track duration by sending it to MediaSampleWriter.
510 int64_t durationUs;
511 if (AMediaFormat_getInt64(mSourceFormat.get(), AMEDIAFORMAT_KEY_DURATION, &durationUs) &&
512 durationUs > 0) {
513 AMediaFormat_setInt64(formatCopy, AMEDIAFORMAT_KEY_DURATION, durationUs);
514 }
515
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700516 // TODO: transfer other fields as required.
517
518 mActualOutputFormat = std::shared_ptr<AMediaFormat>(formatCopy, &AMediaFormat_delete);
519
520 notifyTrackFormatAvailable();
521}
522
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700523media_status_t VideoTrackTranscoder::runTranscodeLoop(bool* stopped) {
Linus Nilssonb09aac22020-07-29 11:56:53 -0700524 androidSetThreadPriority(0 /* tid (0 = current) */, ANDROID_PRIORITY_VIDEO);
525
Chong Zhangb55c5452020-06-26 14:32:12 -0700526 // Push start decoder and encoder as two messages, so that these are subject to the
Chong Zhangbc062482020-10-14 16:43:53 -0700527 // stop request as well. If the session is cancelled (or paused) immediately after start,
Chong Zhangb55c5452020-06-26 14:32:12 -0700528 // we don't need to waste time start then stop the codecs.
529 mCodecMessageQueue.push([this] {
530 media_status_t status = AMediaCodec_start(mDecoder);
531 if (status != AMEDIA_OK) {
532 LOG(ERROR) << "Unable to start video decoder: " << status;
533 mStatus = status;
534 }
535 });
Linus Nilsson0da327a2020-01-31 16:22:18 -0800536
Chong Zhangb55c5452020-06-26 14:32:12 -0700537 mCodecMessageQueue.push([this] {
Linus Nilssone4716f22020-07-10 16:07:57 -0700538 media_status_t status = AMediaCodec_start(mEncoder->getCodec());
Chong Zhangb55c5452020-06-26 14:32:12 -0700539 if (status != AMEDIA_OK) {
540 LOG(ERROR) << "Unable to start video encoder: " << status;
541 mStatus = status;
542 }
Linus Nilssone4716f22020-07-10 16:07:57 -0700543 mEncoder->setStarted();
Chong Zhangb55c5452020-06-26 14:32:12 -0700544 });
Linus Nilsson0da327a2020-01-31 16:22:18 -0800545
546 // Process codec events until EOS is reached, transcoding is stopped or an error occurs.
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700547 while (mStopRequest != STOP_NOW && !mEosFromEncoder && mStatus == AMEDIA_OK) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800548 std::function<void()> message = mCodecMessageQueue.pop();
549 message();
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700550
551 if (mStopRequest == STOP_ON_SYNC && mLastSampleWasSync) {
552 break;
553 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800554 }
555
Linus Nilsson93cf9132020-09-24 12:12:48 -0700556 mCodecMessageQueue.abort();
557 AMediaCodec_stop(mDecoder);
558
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700559 // Signal if transcoding was stopped before it finished.
560 if (mStopRequest != NONE && !mEosFromEncoder && mStatus == AMEDIA_OK) {
561 *stopped = true;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800562 }
563
Linus Nilsson0da327a2020-01-31 16:22:18 -0800564 return mStatus;
565}
566
567void VideoTrackTranscoder::abortTranscodeLoop() {
Linus Nilssonfdb3e332020-09-18 17:11:41 -0700568 if (mStopRequest == STOP_NOW) {
569 // Wake up transcoder thread.
570 mCodecMessageQueue.push([] {}, true /* front */);
571 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800572}
573
Linus Nilssoncab39d82020-05-14 16:32:21 -0700574std::shared_ptr<AMediaFormat> VideoTrackTranscoder::getOutputFormat() const {
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700575 return mActualOutputFormat;
Linus Nilssoncab39d82020-05-14 16:32:21 -0700576}
577
Linus Nilsson0da327a2020-01-31 16:22:18 -0800578} // namespace android