blob: 0713eb8b9fa3ad728deb1b2b994cdfe2eff41489 [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>
Linus Nilsson93591892020-08-03 18:56:55 -070021#include <media/NdkCommon.h>
Linus Nilsson0da327a2020-01-31 16:22:18 -080022#include <media/VideoTrackTranscoder.h>
Linus Nilssonb09aac22020-07-29 11:56:53 -070023#include <utils/AndroidThreads.h>
Linus Nilsson0da327a2020-01-31 16:22:18 -080024
25namespace android {
26
27// Check that the codec sample flags have the expected NDK meaning.
28static_assert(SAMPLE_FLAG_CODEC_CONFIG == AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG,
29 "Sample flag mismatch: CODEC_CONFIG");
30static_assert(SAMPLE_FLAG_END_OF_STREAM == AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM,
31 "Sample flag mismatch: END_OF_STREAM");
32static_assert(SAMPLE_FLAG_PARTIAL_FRAME == AMEDIACODEC_BUFFER_FLAG_PARTIAL_FRAME,
33 "Sample flag mismatch: PARTIAL_FRAME");
34
Linus Nilssoncab39d82020-05-14 16:32:21 -070035// Color format defined by surface. (See MediaCodecInfo.CodecCapabilities#COLOR_FormatSurface.)
36static constexpr int32_t kColorFormatSurface = 0x7f000789;
37// Default key frame interval in seconds.
38static constexpr float kDefaultKeyFrameIntervalSeconds = 1.0f;
39
Linus Nilsson0da327a2020-01-31 16:22:18 -080040template <typename T>
41void VideoTrackTranscoder::BlockingQueue<T>::push(T const& value, bool front) {
42 {
Linus Nilsson93cf9132020-09-24 12:12:48 -070043 std::scoped_lock lock(mMutex);
44 if (mAborted) {
45 return;
46 }
47
Linus Nilsson0da327a2020-01-31 16:22:18 -080048 if (front) {
49 mQueue.push_front(value);
50 } else {
51 mQueue.push_back(value);
52 }
53 }
54 mCondition.notify_one();
55}
56
57template <typename T>
58T VideoTrackTranscoder::BlockingQueue<T>::pop() {
Linus Nilsson93cf9132020-09-24 12:12:48 -070059 std::unique_lock lock(mMutex);
Linus Nilsson0da327a2020-01-31 16:22:18 -080060 while (mQueue.empty()) {
61 mCondition.wait(lock);
62 }
63 T value = mQueue.front();
64 mQueue.pop_front();
65 return value;
66}
67
Linus Nilsson93cf9132020-09-24 12:12:48 -070068// Note: Do not call if another thread might waiting in pop.
69template <typename T>
70void VideoTrackTranscoder::BlockingQueue<T>::abort() {
71 std::scoped_lock lock(mMutex);
72 mAborted = true;
73 mQueue.clear();
74}
75
Linus Nilssone4716f22020-07-10 16:07:57 -070076// The CodecWrapper class is used to let AMediaCodec instances outlive the transcoder object itself
77// by giving the codec a weak pointer to the transcoder. Codecs wrapped in this object are kept
78// alive by the transcoder and the codec's outstanding buffers. Once the transcoder stops and all
79// output buffers have been released by downstream components the codec will also be released.
80class VideoTrackTranscoder::CodecWrapper {
81public:
82 CodecWrapper(AMediaCodec* codec, const std::weak_ptr<VideoTrackTranscoder>& transcoder)
83 : mCodec(codec), mTranscoder(transcoder), mCodecStarted(false) {}
84 ~CodecWrapper() {
85 if (mCodecStarted) {
86 AMediaCodec_stop(mCodec);
87 }
88 AMediaCodec_delete(mCodec);
89 }
90
91 AMediaCodec* getCodec() { return mCodec; }
92 std::shared_ptr<VideoTrackTranscoder> getTranscoder() const { return mTranscoder.lock(); };
93 void setStarted() { mCodecStarted = true; }
94
95private:
96 AMediaCodec* mCodec;
97 std::weak_ptr<VideoTrackTranscoder> mTranscoder;
98 bool mCodecStarted;
99};
100
Linus Nilsson0da327a2020-01-31 16:22:18 -0800101// Dispatch responses to codec callbacks onto the message queue.
102struct AsyncCodecCallbackDispatch {
103 static void onAsyncInputAvailable(AMediaCodec* codec, void* userdata, int32_t index) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700104 VideoTrackTranscoder::CodecWrapper* wrapper =
105 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
106 if (auto transcoder = wrapper->getTranscoder()) {
107 if (codec == transcoder->mDecoder) {
108 transcoder->mCodecMessageQueue.push(
109 [transcoder, index] { transcoder->enqueueInputSample(index); });
110 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800111 }
112 }
113
114 static void onAsyncOutputAvailable(AMediaCodec* codec, void* userdata, int32_t index,
115 AMediaCodecBufferInfo* bufferInfoPtr) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700116 VideoTrackTranscoder::CodecWrapper* wrapper =
117 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800118 AMediaCodecBufferInfo bufferInfo = *bufferInfoPtr;
Linus Nilssone4716f22020-07-10 16:07:57 -0700119 if (auto transcoder = wrapper->getTranscoder()) {
120 transcoder->mCodecMessageQueue.push([transcoder, index, codec, bufferInfo] {
121 if (codec == transcoder->mDecoder) {
122 transcoder->transferBuffer(index, bufferInfo);
123 } else if (codec == transcoder->mEncoder->getCodec()) {
124 transcoder->dequeueOutputSample(index, bufferInfo);
125 }
126 });
127 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800128 }
129
130 static void onAsyncFormatChanged(AMediaCodec* codec, void* userdata, AMediaFormat* format) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700131 VideoTrackTranscoder::CodecWrapper* wrapper =
132 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
133 if (auto transcoder = wrapper->getTranscoder()) {
134 const char* kCodecName = (codec == transcoder->mDecoder ? "Decoder" : "Encoder");
135 LOG(DEBUG) << kCodecName << " format changed: " << AMediaFormat_toString(format);
136 if (codec == transcoder->mEncoder->getCodec()) {
137 transcoder->mCodecMessageQueue.push(
138 [transcoder, format] { transcoder->updateTrackFormat(format); });
139 }
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700140 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800141 }
142
143 static void onAsyncError(AMediaCodec* codec, void* userdata, media_status_t error,
144 int32_t actionCode, const char* detail) {
145 LOG(ERROR) << "Error from codec " << codec << ", userdata " << userdata << ", error "
146 << error << ", action " << actionCode << ", detail " << detail;
Linus Nilssone4716f22020-07-10 16:07:57 -0700147 VideoTrackTranscoder::CodecWrapper* wrapper =
148 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
149 if (auto transcoder = wrapper->getTranscoder()) {
150 transcoder->mCodecMessageQueue.push(
151 [transcoder, error] {
152 transcoder->mStatus = error;
153 transcoder->mStopRequested = true;
154 },
155 true);
156 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800157 }
158};
159
Linus Nilssone4716f22020-07-10 16:07:57 -0700160// static
161std::shared_ptr<VideoTrackTranscoder> VideoTrackTranscoder::create(
162 const std::weak_ptr<MediaTrackTranscoderCallback>& transcoderCallback) {
163 return std::shared_ptr<VideoTrackTranscoder>(new VideoTrackTranscoder(transcoderCallback));
164}
165
Linus Nilsson0da327a2020-01-31 16:22:18 -0800166VideoTrackTranscoder::~VideoTrackTranscoder() {
167 if (mDecoder != nullptr) {
168 AMediaCodec_delete(mDecoder);
169 }
170
Linus Nilsson0da327a2020-01-31 16:22:18 -0800171 if (mSurface != nullptr) {
172 ANativeWindow_release(mSurface);
173 }
174}
175
176// Creates and configures the codecs.
177media_status_t VideoTrackTranscoder::configureDestinationFormat(
178 const std::shared_ptr<AMediaFormat>& destinationFormat) {
Linus Nilsson800793f2020-07-31 16:16:38 -0700179 static constexpr int32_t kDefaultBitrateMbps = 10 * 1000 * 1000;
180
Linus Nilsson0da327a2020-01-31 16:22:18 -0800181 media_status_t status = AMEDIA_OK;
182
183 if (destinationFormat == nullptr) {
Linus Nilssoncab39d82020-05-14 16:32:21 -0700184 LOG(ERROR) << "Destination format is null, use passthrough transcoder";
Linus Nilsson0da327a2020-01-31 16:22:18 -0800185 return AMEDIA_ERROR_INVALID_PARAMETER;
186 }
187
Linus Nilssoncab39d82020-05-14 16:32:21 -0700188 AMediaFormat* encoderFormat = AMediaFormat_new();
189 if (!encoderFormat || AMediaFormat_copy(encoderFormat, destinationFormat.get()) != AMEDIA_OK) {
190 LOG(ERROR) << "Unable to copy destination format";
191 return AMEDIA_ERROR_INVALID_PARAMETER;
192 }
193
Linus Nilsson800793f2020-07-31 16:16:38 -0700194 int32_t bitrate;
195 if (!AMediaFormat_getInt32(encoderFormat, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate)) {
196 status = mMediaSampleReader->getEstimatedBitrateForTrack(mTrackIndex, &bitrate);
197 if (status != AMEDIA_OK) {
198 LOG(ERROR) << "Unable to estimate bitrate. Using default " << kDefaultBitrateMbps;
199 bitrate = kDefaultBitrateMbps;
200 }
201
202 LOG(INFO) << "Configuring bitrate " << bitrate;
203 AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_BIT_RATE, bitrate);
204 }
205
Linus Nilssoncab39d82020-05-14 16:32:21 -0700206 float tmp;
207 if (!AMediaFormat_getFloat(encoderFormat, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, &tmp)) {
208 AMediaFormat_setFloat(encoderFormat, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL,
209 kDefaultKeyFrameIntervalSeconds);
210 }
211 AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, kColorFormatSurface);
212
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700213 // Always encode without rotation. The rotation degree will be transferred directly to
214 // MediaSampleWriter track format, and MediaSampleWriter will call AMediaMuxer_setOrientationHint.
215 AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_ROTATION, 0);
216
Linus Nilssoncab39d82020-05-14 16:32:21 -0700217 mDestinationFormat = std::shared_ptr<AMediaFormat>(encoderFormat, &AMediaFormat_delete);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800218
219 // Create and configure the encoder.
220 const char* destinationMime = nullptr;
221 bool ok = AMediaFormat_getString(mDestinationFormat.get(), AMEDIAFORMAT_KEY_MIME,
222 &destinationMime);
223 if (!ok) {
224 LOG(ERROR) << "Destination MIME type is required for transcoding.";
225 return AMEDIA_ERROR_INVALID_PARAMETER;
226 }
227
Linus Nilssonc6221db2020-03-18 14:46:22 -0700228 AMediaCodec* encoder = AMediaCodec_createEncoderByType(destinationMime);
229 if (encoder == nullptr) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800230 LOG(ERROR) << "Unable to create encoder for type " << destinationMime;
231 return AMEDIA_ERROR_UNSUPPORTED;
232 }
Linus Nilssone4716f22020-07-10 16:07:57 -0700233 mEncoder = std::make_shared<CodecWrapper>(encoder, shared_from_this());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800234
Linus Nilssone4716f22020-07-10 16:07:57 -0700235 status = AMediaCodec_configure(mEncoder->getCodec(), mDestinationFormat.get(),
236 NULL /* surface */, NULL /* crypto */,
237 AMEDIACODEC_CONFIGURE_FLAG_ENCODE);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800238 if (status != AMEDIA_OK) {
239 LOG(ERROR) << "Unable to configure video encoder: " << status;
240 return status;
241 }
242
Linus Nilssone4716f22020-07-10 16:07:57 -0700243 status = AMediaCodec_createInputSurface(mEncoder->getCodec(), &mSurface);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800244 if (status != AMEDIA_OK) {
245 LOG(ERROR) << "Unable to create an encoder input surface: %d" << status;
246 return status;
247 }
248
249 // Create and configure the decoder.
250 const char* sourceMime = nullptr;
251 ok = AMediaFormat_getString(mSourceFormat.get(), AMEDIAFORMAT_KEY_MIME, &sourceMime);
252 if (!ok) {
253 LOG(ERROR) << "Source MIME type is required for transcoding.";
254 return AMEDIA_ERROR_INVALID_PARAMETER;
255 }
256
257 mDecoder = AMediaCodec_createDecoderByType(sourceMime);
258 if (mDecoder == nullptr) {
259 LOG(ERROR) << "Unable to create decoder for type " << sourceMime;
260 return AMEDIA_ERROR_UNSUPPORTED;
261 }
262
Linus Nilsson93591892020-08-03 18:56:55 -0700263 auto decoderFormat = std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
264 if (!decoderFormat ||
265 AMediaFormat_copy(decoderFormat.get(), mSourceFormat.get()) != AMEDIA_OK) {
266 LOG(ERROR) << "Unable to copy source format";
267 return AMEDIA_ERROR_INVALID_PARAMETER;
268 }
269
270 // Prevent decoder from overwriting frames that the encoder has not yet consumed.
271 AMediaFormat_setInt32(decoderFormat.get(), TBD_AMEDIACODEC_PARAMETER_KEY_ALLOW_FRAME_DROP, 0);
272
Linus Nilsson16d772b2020-09-29 19:21:11 -0700273 // Copy over configurations that apply to both encoder and decoder.
274 static const AMediaFormatUtils::EntryCopier kEncoderEntriesToCopy[] = {
275 ENTRY_COPIER2(AMEDIAFORMAT_KEY_OPERATING_RATE, Float, Int32),
276 ENTRY_COPIER(AMEDIAFORMAT_KEY_PRIORITY, Int32),
277 };
278 const size_t entryCount = sizeof(kEncoderEntriesToCopy) / sizeof(kEncoderEntriesToCopy[0]);
279 AMediaFormatUtils::CopyFormatEntries(mDestinationFormat.get(), decoderFormat.get(),
280 kEncoderEntriesToCopy, entryCount);
281
Linus Nilsson93591892020-08-03 18:56:55 -0700282 status = AMediaCodec_configure(mDecoder, decoderFormat.get(), mSurface, NULL /* crypto */,
Linus Nilsson0da327a2020-01-31 16:22:18 -0800283 0 /* flags */);
284 if (status != AMEDIA_OK) {
285 LOG(ERROR) << "Unable to configure video decoder: " << status;
286 return status;
287 }
288
289 // Configure codecs to run in async mode.
290 AMediaCodecOnAsyncNotifyCallback asyncCodecCallbacks = {
291 .onAsyncInputAvailable = AsyncCodecCallbackDispatch::onAsyncInputAvailable,
292 .onAsyncOutputAvailable = AsyncCodecCallbackDispatch::onAsyncOutputAvailable,
293 .onAsyncFormatChanged = AsyncCodecCallbackDispatch::onAsyncFormatChanged,
294 .onAsyncError = AsyncCodecCallbackDispatch::onAsyncError};
295
Linus Nilssone4716f22020-07-10 16:07:57 -0700296 // Note: The decoder does not need its own wrapper because its lifetime is tied to the
297 // transcoder. But the same callbacks are reused for decoder and encoder so we pass the encoder
298 // wrapper as userdata here but never read the codec from it in the callback.
299 status = AMediaCodec_setAsyncNotifyCallback(mDecoder, asyncCodecCallbacks, mEncoder.get());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800300 if (status != AMEDIA_OK) {
301 LOG(ERROR) << "Unable to set decoder to async mode: " << status;
302 return status;
303 }
304
Linus Nilssone4716f22020-07-10 16:07:57 -0700305 status = AMediaCodec_setAsyncNotifyCallback(mEncoder->getCodec(), asyncCodecCallbacks,
306 mEncoder.get());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800307 if (status != AMEDIA_OK) {
308 LOG(ERROR) << "Unable to set encoder to async mode: " << status;
309 return status;
310 }
311
312 return AMEDIA_OK;
313}
314
315void VideoTrackTranscoder::enqueueInputSample(int32_t bufferIndex) {
316 media_status_t status = AMEDIA_OK;
317
Linus Nilssonc6221db2020-03-18 14:46:22 -0700318 if (mEosFromSource) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800319 return;
320 }
321
322 status = mMediaSampleReader->getSampleInfoForTrack(mTrackIndex, &mSampleInfo);
323 if (status != AMEDIA_OK && status != AMEDIA_ERROR_END_OF_STREAM) {
324 LOG(ERROR) << "Error getting next sample info: " << status;
325 mStatus = status;
326 return;
327 }
328 const bool endOfStream = (status == AMEDIA_ERROR_END_OF_STREAM);
329
330 if (!endOfStream) {
331 size_t bufferSize = 0;
332 uint8_t* sourceBuffer = AMediaCodec_getInputBuffer(mDecoder, bufferIndex, &bufferSize);
333 if (sourceBuffer == nullptr) {
334 LOG(ERROR) << "Decoder returned a NULL input buffer.";
335 mStatus = AMEDIA_ERROR_UNKNOWN;
336 return;
337 } else if (bufferSize < mSampleInfo.size) {
338 LOG(ERROR) << "Decoder returned an input buffer that is smaller than the sample.";
339 mStatus = AMEDIA_ERROR_UNKNOWN;
340 return;
341 }
342
343 status = mMediaSampleReader->readSampleDataForTrack(mTrackIndex, sourceBuffer,
344 mSampleInfo.size);
345 if (status != AMEDIA_OK) {
346 LOG(ERROR) << "Unable to read next sample data. Aborting transcode.";
347 mStatus = status;
348 return;
349 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800350 } else {
351 LOG(DEBUG) << "EOS from source.";
Linus Nilssonc6221db2020-03-18 14:46:22 -0700352 mEosFromSource = true;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800353 }
354
355 status = AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, mSampleInfo.size,
356 mSampleInfo.presentationTimeUs, mSampleInfo.flags);
357 if (status != AMEDIA_OK) {
358 LOG(ERROR) << "Unable to queue input buffer for decode: " << status;
359 mStatus = status;
360 return;
361 }
362}
363
364void VideoTrackTranscoder::transferBuffer(int32_t bufferIndex, AMediaCodecBufferInfo bufferInfo) {
365 if (bufferIndex >= 0) {
366 bool needsRender = bufferInfo.size > 0;
367 AMediaCodec_releaseOutputBuffer(mDecoder, bufferIndex, needsRender);
368 }
369
370 if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
371 LOG(DEBUG) << "EOS from decoder.";
Linus Nilssone4716f22020-07-10 16:07:57 -0700372 media_status_t status = AMediaCodec_signalEndOfInputStream(mEncoder->getCodec());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800373 if (status != AMEDIA_OK) {
374 LOG(ERROR) << "SignalEOS on encoder returned error: " << status;
375 mStatus = status;
376 }
377 }
378}
379
380void VideoTrackTranscoder::dequeueOutputSample(int32_t bufferIndex,
381 AMediaCodecBufferInfo bufferInfo) {
382 if (bufferIndex >= 0) {
383 size_t sampleSize = 0;
Linus Nilssone4716f22020-07-10 16:07:57 -0700384 uint8_t* buffer =
385 AMediaCodec_getOutputBuffer(mEncoder->getCodec(), bufferIndex, &sampleSize);
Linus Nilssonc6221db2020-03-18 14:46:22 -0700386
Linus Nilssone4716f22020-07-10 16:07:57 -0700387 MediaSample::OnSampleReleasedCallback bufferReleaseCallback =
388 [encoder = mEncoder](MediaSample* sample) {
389 AMediaCodec_releaseOutputBuffer(encoder->getCodec(), sample->bufferId,
390 false /* render */);
391 };
Linus Nilsson0da327a2020-01-31 16:22:18 -0800392
393 std::shared_ptr<MediaSample> sample = MediaSample::createWithReleaseCallback(
Linus Nilssonc6221db2020-03-18 14:46:22 -0700394 buffer, bufferInfo.offset, bufferIndex, bufferReleaseCallback);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800395 sample->info.size = bufferInfo.size;
396 sample->info.flags = bufferInfo.flags;
397 sample->info.presentationTimeUs = bufferInfo.presentationTimeUs;
398
Linus Nilssonc31d2492020-09-23 12:30:00 -0700399 onOutputSampleAvailable(sample);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800400 } else if (bufferIndex == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700401 AMediaFormat* newFormat = AMediaCodec_getOutputFormat(mEncoder->getCodec());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800402 LOG(DEBUG) << "Encoder output format changed: " << AMediaFormat_toString(newFormat);
403 }
404
405 if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
406 LOG(DEBUG) << "EOS from encoder.";
Linus Nilssonc6221db2020-03-18 14:46:22 -0700407 mEosFromEncoder = true;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800408 }
409}
410
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700411void VideoTrackTranscoder::updateTrackFormat(AMediaFormat* outputFormat) {
412 if (mActualOutputFormat != nullptr) {
413 LOG(WARNING) << "Ignoring duplicate format change.";
414 return;
415 }
416
417 AMediaFormat* formatCopy = AMediaFormat_new();
418 if (!formatCopy || AMediaFormat_copy(formatCopy, outputFormat) != AMEDIA_OK) {
419 LOG(ERROR) << "Unable to copy outputFormat";
420 AMediaFormat_delete(formatCopy);
421 mStatus = AMEDIA_ERROR_INVALID_PARAMETER;
422 return;
423 }
424
425 // Generate the actual track format for muxer based on the encoder output format,
426 // since many vital information comes in the encoder format (eg. CSD).
427 // Transfer necessary fields from the user-configured track format (derived from
428 // source track format and user transcoding request) where needed.
429
430 // Transfer SAR settings:
431 // If mDestinationFormat has SAR set, it means the original source has SAR specified
432 // at container level. This is supposed to override any SAR settings in the bitstream,
433 // thus should always be transferred to the container of the transcoded file.
434 int32_t sarWidth, sarHeight;
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700435 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_SAR_WIDTH, &sarWidth) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700436 (sarWidth > 0) &&
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700437 AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_SAR_HEIGHT, &sarHeight) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700438 (sarHeight > 0)) {
439 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_WIDTH, sarWidth);
440 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_HEIGHT, sarHeight);
441 }
442 // Transfer DAR settings.
443 int32_t displayWidth, displayHeight;
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700444 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_WIDTH, &displayWidth) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700445 (displayWidth > 0) &&
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700446 AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_HEIGHT,
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700447 &displayHeight) &&
448 (displayHeight > 0)) {
449 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_WIDTH, displayWidth);
450 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_HEIGHT, displayHeight);
451 }
452
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700453 // Transfer rotation settings.
454 // Note that muxer itself doesn't take rotation from the track format. It requires
455 // AMediaMuxer_setOrientationHint to set the rotation. Here we pass the rotation to
456 // MediaSampleWriter using the track format. MediaSampleWriter will then call
457 // AMediaMuxer_setOrientationHint as needed.
458 int32_t rotation;
459 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_ROTATION, &rotation) &&
460 (rotation != 0)) {
461 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_ROTATION, rotation);
462 }
463
Linus Nilsson42a971b2020-07-01 16:41:11 -0700464 // Transfer track duration.
465 // Preserve the source track duration by sending it to MediaSampleWriter.
466 int64_t durationUs;
467 if (AMediaFormat_getInt64(mSourceFormat.get(), AMEDIAFORMAT_KEY_DURATION, &durationUs) &&
468 durationUs > 0) {
469 AMediaFormat_setInt64(formatCopy, AMEDIAFORMAT_KEY_DURATION, durationUs);
470 }
471
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700472 // TODO: transfer other fields as required.
473
474 mActualOutputFormat = std::shared_ptr<AMediaFormat>(formatCopy, &AMediaFormat_delete);
475
476 notifyTrackFormatAvailable();
477}
478
Linus Nilsson0da327a2020-01-31 16:22:18 -0800479media_status_t VideoTrackTranscoder::runTranscodeLoop() {
Linus Nilssonb09aac22020-07-29 11:56:53 -0700480 androidSetThreadPriority(0 /* tid (0 = current) */, ANDROID_PRIORITY_VIDEO);
481
Chong Zhangb55c5452020-06-26 14:32:12 -0700482 // Push start decoder and encoder as two messages, so that these are subject to the
483 // stop request as well. If the job is cancelled (or paused) immediately after start,
484 // we don't need to waste time start then stop the codecs.
485 mCodecMessageQueue.push([this] {
486 media_status_t status = AMediaCodec_start(mDecoder);
487 if (status != AMEDIA_OK) {
488 LOG(ERROR) << "Unable to start video decoder: " << status;
489 mStatus = status;
490 }
491 });
Linus Nilsson0da327a2020-01-31 16:22:18 -0800492
Chong Zhangb55c5452020-06-26 14:32:12 -0700493 mCodecMessageQueue.push([this] {
Linus Nilssone4716f22020-07-10 16:07:57 -0700494 media_status_t status = AMediaCodec_start(mEncoder->getCodec());
Chong Zhangb55c5452020-06-26 14:32:12 -0700495 if (status != AMEDIA_OK) {
496 LOG(ERROR) << "Unable to start video encoder: " << status;
497 mStatus = status;
498 }
Linus Nilssone4716f22020-07-10 16:07:57 -0700499 mEncoder->setStarted();
Chong Zhangb55c5452020-06-26 14:32:12 -0700500 });
Linus Nilsson0da327a2020-01-31 16:22:18 -0800501
502 // Process codec events until EOS is reached, transcoding is stopped or an error occurs.
Linus Nilssonc6221db2020-03-18 14:46:22 -0700503 while (!mStopRequested && !mEosFromEncoder && mStatus == AMEDIA_OK) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800504 std::function<void()> message = mCodecMessageQueue.pop();
505 message();
506 }
507
Linus Nilsson93cf9132020-09-24 12:12:48 -0700508 mCodecMessageQueue.abort();
509 AMediaCodec_stop(mDecoder);
510
Linus Nilsson0da327a2020-01-31 16:22:18 -0800511 // Return error if transcoding was stopped before it finished.
Linus Nilssonc6221db2020-03-18 14:46:22 -0700512 if (mStopRequested && !mEosFromEncoder && mStatus == AMEDIA_OK) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800513 mStatus = AMEDIA_ERROR_UNKNOWN; // TODO: Define custom error codes?
514 }
515
Linus Nilsson0da327a2020-01-31 16:22:18 -0800516 return mStatus;
517}
518
519void VideoTrackTranscoder::abortTranscodeLoop() {
520 // Push abort message to the front of the codec event queue.
521 mCodecMessageQueue.push([this] { mStopRequested = true; }, true /* front */);
522}
523
Linus Nilssoncab39d82020-05-14 16:32:21 -0700524std::shared_ptr<AMediaFormat> VideoTrackTranscoder::getOutputFormat() const {
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700525 return mActualOutputFormat;
Linus Nilssoncab39d82020-05-14 16:32:21 -0700526}
527
Linus Nilsson0da327a2020-01-31 16:22:18 -0800528} // namespace android