blob: b0bf59fe3f7d897ecf3898b4ae58f1e21b95e7a4 [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 {
43 std::unique_lock<std::mutex> lock(mMutex);
44 if (front) {
45 mQueue.push_front(value);
46 } else {
47 mQueue.push_back(value);
48 }
49 }
50 mCondition.notify_one();
51}
52
53template <typename T>
54T VideoTrackTranscoder::BlockingQueue<T>::pop() {
55 std::unique_lock<std::mutex> lock(mMutex);
56 while (mQueue.empty()) {
57 mCondition.wait(lock);
58 }
59 T value = mQueue.front();
60 mQueue.pop_front();
61 return value;
62}
63
Linus Nilssone4716f22020-07-10 16:07:57 -070064// The CodecWrapper class is used to let AMediaCodec instances outlive the transcoder object itself
65// by giving the codec a weak pointer to the transcoder. Codecs wrapped in this object are kept
66// alive by the transcoder and the codec's outstanding buffers. Once the transcoder stops and all
67// output buffers have been released by downstream components the codec will also be released.
68class VideoTrackTranscoder::CodecWrapper {
69public:
70 CodecWrapper(AMediaCodec* codec, const std::weak_ptr<VideoTrackTranscoder>& transcoder)
71 : mCodec(codec), mTranscoder(transcoder), mCodecStarted(false) {}
72 ~CodecWrapper() {
73 if (mCodecStarted) {
74 AMediaCodec_stop(mCodec);
75 }
76 AMediaCodec_delete(mCodec);
77 }
78
79 AMediaCodec* getCodec() { return mCodec; }
80 std::shared_ptr<VideoTrackTranscoder> getTranscoder() const { return mTranscoder.lock(); };
81 void setStarted() { mCodecStarted = true; }
82
83private:
84 AMediaCodec* mCodec;
85 std::weak_ptr<VideoTrackTranscoder> mTranscoder;
86 bool mCodecStarted;
87};
88
Linus Nilsson0da327a2020-01-31 16:22:18 -080089// Dispatch responses to codec callbacks onto the message queue.
90struct AsyncCodecCallbackDispatch {
91 static void onAsyncInputAvailable(AMediaCodec* codec, void* userdata, int32_t index) {
Linus Nilssone4716f22020-07-10 16:07:57 -070092 VideoTrackTranscoder::CodecWrapper* wrapper =
93 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
94 if (auto transcoder = wrapper->getTranscoder()) {
95 if (codec == transcoder->mDecoder) {
96 transcoder->mCodecMessageQueue.push(
97 [transcoder, index] { transcoder->enqueueInputSample(index); });
98 }
Linus Nilsson0da327a2020-01-31 16:22:18 -080099 }
100 }
101
102 static void onAsyncOutputAvailable(AMediaCodec* codec, void* userdata, int32_t index,
103 AMediaCodecBufferInfo* bufferInfoPtr) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700104 VideoTrackTranscoder::CodecWrapper* wrapper =
105 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800106 AMediaCodecBufferInfo bufferInfo = *bufferInfoPtr;
Linus Nilssone4716f22020-07-10 16:07:57 -0700107 if (auto transcoder = wrapper->getTranscoder()) {
108 transcoder->mCodecMessageQueue.push([transcoder, index, codec, bufferInfo] {
109 if (codec == transcoder->mDecoder) {
110 transcoder->transferBuffer(index, bufferInfo);
111 } else if (codec == transcoder->mEncoder->getCodec()) {
112 transcoder->dequeueOutputSample(index, bufferInfo);
113 }
114 });
115 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800116 }
117
118 static void onAsyncFormatChanged(AMediaCodec* codec, void* userdata, AMediaFormat* format) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700119 VideoTrackTranscoder::CodecWrapper* wrapper =
120 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
121 if (auto transcoder = wrapper->getTranscoder()) {
122 const char* kCodecName = (codec == transcoder->mDecoder ? "Decoder" : "Encoder");
123 LOG(DEBUG) << kCodecName << " format changed: " << AMediaFormat_toString(format);
124 if (codec == transcoder->mEncoder->getCodec()) {
125 transcoder->mCodecMessageQueue.push(
126 [transcoder, format] { transcoder->updateTrackFormat(format); });
127 }
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700128 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800129 }
130
131 static void onAsyncError(AMediaCodec* codec, void* userdata, media_status_t error,
132 int32_t actionCode, const char* detail) {
133 LOG(ERROR) << "Error from codec " << codec << ", userdata " << userdata << ", error "
134 << error << ", action " << actionCode << ", detail " << detail;
Linus Nilssone4716f22020-07-10 16:07:57 -0700135 VideoTrackTranscoder::CodecWrapper* wrapper =
136 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
137 if (auto transcoder = wrapper->getTranscoder()) {
138 transcoder->mCodecMessageQueue.push(
139 [transcoder, error] {
140 transcoder->mStatus = error;
141 transcoder->mStopRequested = true;
142 },
143 true);
144 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800145 }
146};
147
Linus Nilssone4716f22020-07-10 16:07:57 -0700148// static
149std::shared_ptr<VideoTrackTranscoder> VideoTrackTranscoder::create(
150 const std::weak_ptr<MediaTrackTranscoderCallback>& transcoderCallback) {
151 return std::shared_ptr<VideoTrackTranscoder>(new VideoTrackTranscoder(transcoderCallback));
152}
153
Linus Nilsson0da327a2020-01-31 16:22:18 -0800154VideoTrackTranscoder::~VideoTrackTranscoder() {
155 if (mDecoder != nullptr) {
156 AMediaCodec_delete(mDecoder);
157 }
158
Linus Nilsson0da327a2020-01-31 16:22:18 -0800159 if (mSurface != nullptr) {
160 ANativeWindow_release(mSurface);
161 }
162}
163
164// Creates and configures the codecs.
165media_status_t VideoTrackTranscoder::configureDestinationFormat(
166 const std::shared_ptr<AMediaFormat>& destinationFormat) {
Linus Nilsson800793f2020-07-31 16:16:38 -0700167 static constexpr int32_t kDefaultBitrateMbps = 10 * 1000 * 1000;
168
Linus Nilsson0da327a2020-01-31 16:22:18 -0800169 media_status_t status = AMEDIA_OK;
170
171 if (destinationFormat == nullptr) {
Linus Nilssoncab39d82020-05-14 16:32:21 -0700172 LOG(ERROR) << "Destination format is null, use passthrough transcoder";
Linus Nilsson0da327a2020-01-31 16:22:18 -0800173 return AMEDIA_ERROR_INVALID_PARAMETER;
174 }
175
Linus Nilssoncab39d82020-05-14 16:32:21 -0700176 AMediaFormat* encoderFormat = AMediaFormat_new();
177 if (!encoderFormat || AMediaFormat_copy(encoderFormat, destinationFormat.get()) != AMEDIA_OK) {
178 LOG(ERROR) << "Unable to copy destination format";
179 return AMEDIA_ERROR_INVALID_PARAMETER;
180 }
181
Linus Nilsson800793f2020-07-31 16:16:38 -0700182 int32_t bitrate;
183 if (!AMediaFormat_getInt32(encoderFormat, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate)) {
184 status = mMediaSampleReader->getEstimatedBitrateForTrack(mTrackIndex, &bitrate);
185 if (status != AMEDIA_OK) {
186 LOG(ERROR) << "Unable to estimate bitrate. Using default " << kDefaultBitrateMbps;
187 bitrate = kDefaultBitrateMbps;
188 }
189
190 LOG(INFO) << "Configuring bitrate " << bitrate;
191 AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_BIT_RATE, bitrate);
192 }
193
Linus Nilssoncab39d82020-05-14 16:32:21 -0700194 float tmp;
195 if (!AMediaFormat_getFloat(encoderFormat, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, &tmp)) {
196 AMediaFormat_setFloat(encoderFormat, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL,
197 kDefaultKeyFrameIntervalSeconds);
198 }
199 AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, kColorFormatSurface);
200
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700201 // Always encode without rotation. The rotation degree will be transferred directly to
202 // MediaSampleWriter track format, and MediaSampleWriter will call AMediaMuxer_setOrientationHint.
203 AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_ROTATION, 0);
204
Linus Nilssoncab39d82020-05-14 16:32:21 -0700205 mDestinationFormat = std::shared_ptr<AMediaFormat>(encoderFormat, &AMediaFormat_delete);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800206
207 // Create and configure the encoder.
208 const char* destinationMime = nullptr;
209 bool ok = AMediaFormat_getString(mDestinationFormat.get(), AMEDIAFORMAT_KEY_MIME,
210 &destinationMime);
211 if (!ok) {
212 LOG(ERROR) << "Destination MIME type is required for transcoding.";
213 return AMEDIA_ERROR_INVALID_PARAMETER;
214 }
215
Linus Nilssonc6221db2020-03-18 14:46:22 -0700216 AMediaCodec* encoder = AMediaCodec_createEncoderByType(destinationMime);
217 if (encoder == nullptr) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800218 LOG(ERROR) << "Unable to create encoder for type " << destinationMime;
219 return AMEDIA_ERROR_UNSUPPORTED;
220 }
Linus Nilssone4716f22020-07-10 16:07:57 -0700221 mEncoder = std::make_shared<CodecWrapper>(encoder, shared_from_this());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800222
Linus Nilssone4716f22020-07-10 16:07:57 -0700223 status = AMediaCodec_configure(mEncoder->getCodec(), mDestinationFormat.get(),
224 NULL /* surface */, NULL /* crypto */,
225 AMEDIACODEC_CONFIGURE_FLAG_ENCODE);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800226 if (status != AMEDIA_OK) {
227 LOG(ERROR) << "Unable to configure video encoder: " << status;
228 return status;
229 }
230
Linus Nilssone4716f22020-07-10 16:07:57 -0700231 status = AMediaCodec_createInputSurface(mEncoder->getCodec(), &mSurface);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800232 if (status != AMEDIA_OK) {
233 LOG(ERROR) << "Unable to create an encoder input surface: %d" << status;
234 return status;
235 }
236
237 // Create and configure the decoder.
238 const char* sourceMime = nullptr;
239 ok = AMediaFormat_getString(mSourceFormat.get(), AMEDIAFORMAT_KEY_MIME, &sourceMime);
240 if (!ok) {
241 LOG(ERROR) << "Source MIME type is required for transcoding.";
242 return AMEDIA_ERROR_INVALID_PARAMETER;
243 }
244
245 mDecoder = AMediaCodec_createDecoderByType(sourceMime);
246 if (mDecoder == nullptr) {
247 LOG(ERROR) << "Unable to create decoder for type " << sourceMime;
248 return AMEDIA_ERROR_UNSUPPORTED;
249 }
250
Linus Nilsson93591892020-08-03 18:56:55 -0700251 auto decoderFormat = std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
252 if (!decoderFormat ||
253 AMediaFormat_copy(decoderFormat.get(), mSourceFormat.get()) != AMEDIA_OK) {
254 LOG(ERROR) << "Unable to copy source format";
255 return AMEDIA_ERROR_INVALID_PARAMETER;
256 }
257
258 // Prevent decoder from overwriting frames that the encoder has not yet consumed.
259 AMediaFormat_setInt32(decoderFormat.get(), TBD_AMEDIACODEC_PARAMETER_KEY_ALLOW_FRAME_DROP, 0);
260
261 status = AMediaCodec_configure(mDecoder, decoderFormat.get(), mSurface, NULL /* crypto */,
Linus Nilsson0da327a2020-01-31 16:22:18 -0800262 0 /* flags */);
263 if (status != AMEDIA_OK) {
264 LOG(ERROR) << "Unable to configure video decoder: " << status;
265 return status;
266 }
267
268 // Configure codecs to run in async mode.
269 AMediaCodecOnAsyncNotifyCallback asyncCodecCallbacks = {
270 .onAsyncInputAvailable = AsyncCodecCallbackDispatch::onAsyncInputAvailable,
271 .onAsyncOutputAvailable = AsyncCodecCallbackDispatch::onAsyncOutputAvailable,
272 .onAsyncFormatChanged = AsyncCodecCallbackDispatch::onAsyncFormatChanged,
273 .onAsyncError = AsyncCodecCallbackDispatch::onAsyncError};
274
Linus Nilssone4716f22020-07-10 16:07:57 -0700275 // Note: The decoder does not need its own wrapper because its lifetime is tied to the
276 // transcoder. But the same callbacks are reused for decoder and encoder so we pass the encoder
277 // wrapper as userdata here but never read the codec from it in the callback.
278 status = AMediaCodec_setAsyncNotifyCallback(mDecoder, asyncCodecCallbacks, mEncoder.get());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800279 if (status != AMEDIA_OK) {
280 LOG(ERROR) << "Unable to set decoder to async mode: " << status;
281 return status;
282 }
283
Linus Nilssone4716f22020-07-10 16:07:57 -0700284 status = AMediaCodec_setAsyncNotifyCallback(mEncoder->getCodec(), asyncCodecCallbacks,
285 mEncoder.get());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800286 if (status != AMEDIA_OK) {
287 LOG(ERROR) << "Unable to set encoder to async mode: " << status;
288 return status;
289 }
290
291 return AMEDIA_OK;
292}
293
294void VideoTrackTranscoder::enqueueInputSample(int32_t bufferIndex) {
295 media_status_t status = AMEDIA_OK;
296
Linus Nilssonc6221db2020-03-18 14:46:22 -0700297 if (mEosFromSource) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800298 return;
299 }
300
301 status = mMediaSampleReader->getSampleInfoForTrack(mTrackIndex, &mSampleInfo);
302 if (status != AMEDIA_OK && status != AMEDIA_ERROR_END_OF_STREAM) {
303 LOG(ERROR) << "Error getting next sample info: " << status;
304 mStatus = status;
305 return;
306 }
307 const bool endOfStream = (status == AMEDIA_ERROR_END_OF_STREAM);
308
309 if (!endOfStream) {
310 size_t bufferSize = 0;
311 uint8_t* sourceBuffer = AMediaCodec_getInputBuffer(mDecoder, bufferIndex, &bufferSize);
312 if (sourceBuffer == nullptr) {
313 LOG(ERROR) << "Decoder returned a NULL input buffer.";
314 mStatus = AMEDIA_ERROR_UNKNOWN;
315 return;
316 } else if (bufferSize < mSampleInfo.size) {
317 LOG(ERROR) << "Decoder returned an input buffer that is smaller than the sample.";
318 mStatus = AMEDIA_ERROR_UNKNOWN;
319 return;
320 }
321
322 status = mMediaSampleReader->readSampleDataForTrack(mTrackIndex, sourceBuffer,
323 mSampleInfo.size);
324 if (status != AMEDIA_OK) {
325 LOG(ERROR) << "Unable to read next sample data. Aborting transcode.";
326 mStatus = status;
327 return;
328 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800329 } else {
330 LOG(DEBUG) << "EOS from source.";
Linus Nilssonc6221db2020-03-18 14:46:22 -0700331 mEosFromSource = true;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800332 }
333
334 status = AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, mSampleInfo.size,
335 mSampleInfo.presentationTimeUs, mSampleInfo.flags);
336 if (status != AMEDIA_OK) {
337 LOG(ERROR) << "Unable to queue input buffer for decode: " << status;
338 mStatus = status;
339 return;
340 }
341}
342
343void VideoTrackTranscoder::transferBuffer(int32_t bufferIndex, AMediaCodecBufferInfo bufferInfo) {
344 if (bufferIndex >= 0) {
345 bool needsRender = bufferInfo.size > 0;
346 AMediaCodec_releaseOutputBuffer(mDecoder, bufferIndex, needsRender);
347 }
348
349 if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
350 LOG(DEBUG) << "EOS from decoder.";
Linus Nilssone4716f22020-07-10 16:07:57 -0700351 media_status_t status = AMediaCodec_signalEndOfInputStream(mEncoder->getCodec());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800352 if (status != AMEDIA_OK) {
353 LOG(ERROR) << "SignalEOS on encoder returned error: " << status;
354 mStatus = status;
355 }
356 }
357}
358
359void VideoTrackTranscoder::dequeueOutputSample(int32_t bufferIndex,
360 AMediaCodecBufferInfo bufferInfo) {
361 if (bufferIndex >= 0) {
362 size_t sampleSize = 0;
Linus Nilssone4716f22020-07-10 16:07:57 -0700363 uint8_t* buffer =
364 AMediaCodec_getOutputBuffer(mEncoder->getCodec(), bufferIndex, &sampleSize);
Linus Nilssonc6221db2020-03-18 14:46:22 -0700365
Linus Nilssone4716f22020-07-10 16:07:57 -0700366 MediaSample::OnSampleReleasedCallback bufferReleaseCallback =
367 [encoder = mEncoder](MediaSample* sample) {
368 AMediaCodec_releaseOutputBuffer(encoder->getCodec(), sample->bufferId,
369 false /* render */);
370 };
Linus Nilsson0da327a2020-01-31 16:22:18 -0800371
372 std::shared_ptr<MediaSample> sample = MediaSample::createWithReleaseCallback(
Linus Nilssonc6221db2020-03-18 14:46:22 -0700373 buffer, bufferInfo.offset, bufferIndex, bufferReleaseCallback);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800374 sample->info.size = bufferInfo.size;
375 sample->info.flags = bufferInfo.flags;
376 sample->info.presentationTimeUs = bufferInfo.presentationTimeUs;
377
Linus Nilssoncab39d82020-05-14 16:32:21 -0700378 const bool aborted = mOutputQueue->enqueue(sample);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800379 if (aborted) {
380 LOG(ERROR) << "Output sample queue was aborted. Stopping transcode.";
381 mStatus = AMEDIA_ERROR_IO; // TODO: Define custom error codes?
382 return;
383 }
384 } else if (bufferIndex == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700385 AMediaFormat* newFormat = AMediaCodec_getOutputFormat(mEncoder->getCodec());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800386 LOG(DEBUG) << "Encoder output format changed: " << AMediaFormat_toString(newFormat);
387 }
388
389 if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
390 LOG(DEBUG) << "EOS from encoder.";
Linus Nilssonc6221db2020-03-18 14:46:22 -0700391 mEosFromEncoder = true;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800392 }
393}
394
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700395void VideoTrackTranscoder::updateTrackFormat(AMediaFormat* outputFormat) {
396 if (mActualOutputFormat != nullptr) {
397 LOG(WARNING) << "Ignoring duplicate format change.";
398 return;
399 }
400
401 AMediaFormat* formatCopy = AMediaFormat_new();
402 if (!formatCopy || AMediaFormat_copy(formatCopy, outputFormat) != AMEDIA_OK) {
403 LOG(ERROR) << "Unable to copy outputFormat";
404 AMediaFormat_delete(formatCopy);
405 mStatus = AMEDIA_ERROR_INVALID_PARAMETER;
406 return;
407 }
408
409 // Generate the actual track format for muxer based on the encoder output format,
410 // since many vital information comes in the encoder format (eg. CSD).
411 // Transfer necessary fields from the user-configured track format (derived from
412 // source track format and user transcoding request) where needed.
413
414 // Transfer SAR settings:
415 // If mDestinationFormat has SAR set, it means the original source has SAR specified
416 // at container level. This is supposed to override any SAR settings in the bitstream,
417 // thus should always be transferred to the container of the transcoded file.
418 int32_t sarWidth, sarHeight;
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700419 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_SAR_WIDTH, &sarWidth) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700420 (sarWidth > 0) &&
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700421 AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_SAR_HEIGHT, &sarHeight) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700422 (sarHeight > 0)) {
423 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_WIDTH, sarWidth);
424 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_HEIGHT, sarHeight);
425 }
426 // Transfer DAR settings.
427 int32_t displayWidth, displayHeight;
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700428 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_WIDTH, &displayWidth) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700429 (displayWidth > 0) &&
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700430 AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_HEIGHT,
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700431 &displayHeight) &&
432 (displayHeight > 0)) {
433 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_WIDTH, displayWidth);
434 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_HEIGHT, displayHeight);
435 }
436
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700437 // Transfer rotation settings.
438 // Note that muxer itself doesn't take rotation from the track format. It requires
439 // AMediaMuxer_setOrientationHint to set the rotation. Here we pass the rotation to
440 // MediaSampleWriter using the track format. MediaSampleWriter will then call
441 // AMediaMuxer_setOrientationHint as needed.
442 int32_t rotation;
443 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_ROTATION, &rotation) &&
444 (rotation != 0)) {
445 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_ROTATION, rotation);
446 }
447
Linus Nilsson42a971b2020-07-01 16:41:11 -0700448 // Transfer track duration.
449 // Preserve the source track duration by sending it to MediaSampleWriter.
450 int64_t durationUs;
451 if (AMediaFormat_getInt64(mSourceFormat.get(), AMEDIAFORMAT_KEY_DURATION, &durationUs) &&
452 durationUs > 0) {
453 AMediaFormat_setInt64(formatCopy, AMEDIAFORMAT_KEY_DURATION, durationUs);
454 }
455
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700456 // TODO: transfer other fields as required.
457
458 mActualOutputFormat = std::shared_ptr<AMediaFormat>(formatCopy, &AMediaFormat_delete);
459
460 notifyTrackFormatAvailable();
461}
462
Linus Nilsson0da327a2020-01-31 16:22:18 -0800463media_status_t VideoTrackTranscoder::runTranscodeLoop() {
Linus Nilssonb09aac22020-07-29 11:56:53 -0700464 androidSetThreadPriority(0 /* tid (0 = current) */, ANDROID_PRIORITY_VIDEO);
465
Chong Zhangb55c5452020-06-26 14:32:12 -0700466 // Push start decoder and encoder as two messages, so that these are subject to the
467 // stop request as well. If the job is cancelled (or paused) immediately after start,
468 // we don't need to waste time start then stop the codecs.
469 mCodecMessageQueue.push([this] {
470 media_status_t status = AMediaCodec_start(mDecoder);
471 if (status != AMEDIA_OK) {
472 LOG(ERROR) << "Unable to start video decoder: " << status;
473 mStatus = status;
474 }
475 });
Linus Nilsson0da327a2020-01-31 16:22:18 -0800476
Chong Zhangb55c5452020-06-26 14:32:12 -0700477 mCodecMessageQueue.push([this] {
Linus Nilssone4716f22020-07-10 16:07:57 -0700478 media_status_t status = AMediaCodec_start(mEncoder->getCodec());
Chong Zhangb55c5452020-06-26 14:32:12 -0700479 if (status != AMEDIA_OK) {
480 LOG(ERROR) << "Unable to start video encoder: " << status;
481 mStatus = status;
482 }
Linus Nilssone4716f22020-07-10 16:07:57 -0700483 mEncoder->setStarted();
Chong Zhangb55c5452020-06-26 14:32:12 -0700484 });
Linus Nilsson0da327a2020-01-31 16:22:18 -0800485
486 // Process codec events until EOS is reached, transcoding is stopped or an error occurs.
Linus Nilssonc6221db2020-03-18 14:46:22 -0700487 while (!mStopRequested && !mEosFromEncoder && mStatus == AMEDIA_OK) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800488 std::function<void()> message = mCodecMessageQueue.pop();
489 message();
490 }
491
492 // Return error if transcoding was stopped before it finished.
Linus Nilssonc6221db2020-03-18 14:46:22 -0700493 if (mStopRequested && !mEosFromEncoder && mStatus == AMEDIA_OK) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800494 mStatus = AMEDIA_ERROR_UNKNOWN; // TODO: Define custom error codes?
495 }
496
497 AMediaCodec_stop(mDecoder);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800498 return mStatus;
499}
500
501void VideoTrackTranscoder::abortTranscodeLoop() {
502 // Push abort message to the front of the codec event queue.
503 mCodecMessageQueue.push([this] { mStopRequested = true; }, true /* front */);
504}
505
Linus Nilssoncab39d82020-05-14 16:32:21 -0700506std::shared_ptr<AMediaFormat> VideoTrackTranscoder::getOutputFormat() const {
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700507 return mActualOutputFormat;
Linus Nilssoncab39d82020-05-14 16:32:21 -0700508}
509
Linus Nilsson0da327a2020-01-31 16:22:18 -0800510} // namespace android