blob: 5579868a1373097c1638912279b5efe6ee3fcad0 [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
273 status = AMediaCodec_configure(mDecoder, decoderFormat.get(), mSurface, NULL /* crypto */,
Linus Nilsson0da327a2020-01-31 16:22:18 -0800274 0 /* flags */);
275 if (status != AMEDIA_OK) {
276 LOG(ERROR) << "Unable to configure video decoder: " << status;
277 return status;
278 }
279
280 // Configure codecs to run in async mode.
281 AMediaCodecOnAsyncNotifyCallback asyncCodecCallbacks = {
282 .onAsyncInputAvailable = AsyncCodecCallbackDispatch::onAsyncInputAvailable,
283 .onAsyncOutputAvailable = AsyncCodecCallbackDispatch::onAsyncOutputAvailable,
284 .onAsyncFormatChanged = AsyncCodecCallbackDispatch::onAsyncFormatChanged,
285 .onAsyncError = AsyncCodecCallbackDispatch::onAsyncError};
286
Linus Nilssone4716f22020-07-10 16:07:57 -0700287 // Note: The decoder does not need its own wrapper because its lifetime is tied to the
288 // transcoder. But the same callbacks are reused for decoder and encoder so we pass the encoder
289 // wrapper as userdata here but never read the codec from it in the callback.
290 status = AMediaCodec_setAsyncNotifyCallback(mDecoder, asyncCodecCallbacks, mEncoder.get());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800291 if (status != AMEDIA_OK) {
292 LOG(ERROR) << "Unable to set decoder to async mode: " << status;
293 return status;
294 }
295
Linus Nilssone4716f22020-07-10 16:07:57 -0700296 status = AMediaCodec_setAsyncNotifyCallback(mEncoder->getCodec(), asyncCodecCallbacks,
297 mEncoder.get());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800298 if (status != AMEDIA_OK) {
299 LOG(ERROR) << "Unable to set encoder to async mode: " << status;
300 return status;
301 }
302
303 return AMEDIA_OK;
304}
305
306void VideoTrackTranscoder::enqueueInputSample(int32_t bufferIndex) {
307 media_status_t status = AMEDIA_OK;
308
Linus Nilssonc6221db2020-03-18 14:46:22 -0700309 if (mEosFromSource) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800310 return;
311 }
312
313 status = mMediaSampleReader->getSampleInfoForTrack(mTrackIndex, &mSampleInfo);
314 if (status != AMEDIA_OK && status != AMEDIA_ERROR_END_OF_STREAM) {
315 LOG(ERROR) << "Error getting next sample info: " << status;
316 mStatus = status;
317 return;
318 }
319 const bool endOfStream = (status == AMEDIA_ERROR_END_OF_STREAM);
320
321 if (!endOfStream) {
322 size_t bufferSize = 0;
323 uint8_t* sourceBuffer = AMediaCodec_getInputBuffer(mDecoder, bufferIndex, &bufferSize);
324 if (sourceBuffer == nullptr) {
325 LOG(ERROR) << "Decoder returned a NULL input buffer.";
326 mStatus = AMEDIA_ERROR_UNKNOWN;
327 return;
328 } else if (bufferSize < mSampleInfo.size) {
329 LOG(ERROR) << "Decoder returned an input buffer that is smaller than the sample.";
330 mStatus = AMEDIA_ERROR_UNKNOWN;
331 return;
332 }
333
334 status = mMediaSampleReader->readSampleDataForTrack(mTrackIndex, sourceBuffer,
335 mSampleInfo.size);
336 if (status != AMEDIA_OK) {
337 LOG(ERROR) << "Unable to read next sample data. Aborting transcode.";
338 mStatus = status;
339 return;
340 }
Linus Nilsson0da327a2020-01-31 16:22:18 -0800341 } else {
342 LOG(DEBUG) << "EOS from source.";
Linus Nilssonc6221db2020-03-18 14:46:22 -0700343 mEosFromSource = true;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800344 }
345
346 status = AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, mSampleInfo.size,
347 mSampleInfo.presentationTimeUs, mSampleInfo.flags);
348 if (status != AMEDIA_OK) {
349 LOG(ERROR) << "Unable to queue input buffer for decode: " << status;
350 mStatus = status;
351 return;
352 }
353}
354
355void VideoTrackTranscoder::transferBuffer(int32_t bufferIndex, AMediaCodecBufferInfo bufferInfo) {
356 if (bufferIndex >= 0) {
357 bool needsRender = bufferInfo.size > 0;
358 AMediaCodec_releaseOutputBuffer(mDecoder, bufferIndex, needsRender);
359 }
360
361 if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
362 LOG(DEBUG) << "EOS from decoder.";
Linus Nilssone4716f22020-07-10 16:07:57 -0700363 media_status_t status = AMediaCodec_signalEndOfInputStream(mEncoder->getCodec());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800364 if (status != AMEDIA_OK) {
365 LOG(ERROR) << "SignalEOS on encoder returned error: " << status;
366 mStatus = status;
367 }
368 }
369}
370
371void VideoTrackTranscoder::dequeueOutputSample(int32_t bufferIndex,
372 AMediaCodecBufferInfo bufferInfo) {
373 if (bufferIndex >= 0) {
374 size_t sampleSize = 0;
Linus Nilssone4716f22020-07-10 16:07:57 -0700375 uint8_t* buffer =
376 AMediaCodec_getOutputBuffer(mEncoder->getCodec(), bufferIndex, &sampleSize);
Linus Nilssonc6221db2020-03-18 14:46:22 -0700377
Linus Nilssone4716f22020-07-10 16:07:57 -0700378 MediaSample::OnSampleReleasedCallback bufferReleaseCallback =
379 [encoder = mEncoder](MediaSample* sample) {
380 AMediaCodec_releaseOutputBuffer(encoder->getCodec(), sample->bufferId,
381 false /* render */);
382 };
Linus Nilsson0da327a2020-01-31 16:22:18 -0800383
384 std::shared_ptr<MediaSample> sample = MediaSample::createWithReleaseCallback(
Linus Nilssonc6221db2020-03-18 14:46:22 -0700385 buffer, bufferInfo.offset, bufferIndex, bufferReleaseCallback);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800386 sample->info.size = bufferInfo.size;
387 sample->info.flags = bufferInfo.flags;
388 sample->info.presentationTimeUs = bufferInfo.presentationTimeUs;
389
Linus Nilssonc31d2492020-09-23 12:30:00 -0700390 onOutputSampleAvailable(sample);
Linus Nilsson0da327a2020-01-31 16:22:18 -0800391 } else if (bufferIndex == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
Linus Nilssone4716f22020-07-10 16:07:57 -0700392 AMediaFormat* newFormat = AMediaCodec_getOutputFormat(mEncoder->getCodec());
Linus Nilsson0da327a2020-01-31 16:22:18 -0800393 LOG(DEBUG) << "Encoder output format changed: " << AMediaFormat_toString(newFormat);
394 }
395
396 if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
397 LOG(DEBUG) << "EOS from encoder.";
Linus Nilssonc6221db2020-03-18 14:46:22 -0700398 mEosFromEncoder = true;
Linus Nilsson0da327a2020-01-31 16:22:18 -0800399 }
400}
401
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700402void VideoTrackTranscoder::updateTrackFormat(AMediaFormat* outputFormat) {
403 if (mActualOutputFormat != nullptr) {
404 LOG(WARNING) << "Ignoring duplicate format change.";
405 return;
406 }
407
408 AMediaFormat* formatCopy = AMediaFormat_new();
409 if (!formatCopy || AMediaFormat_copy(formatCopy, outputFormat) != AMEDIA_OK) {
410 LOG(ERROR) << "Unable to copy outputFormat";
411 AMediaFormat_delete(formatCopy);
412 mStatus = AMEDIA_ERROR_INVALID_PARAMETER;
413 return;
414 }
415
416 // Generate the actual track format for muxer based on the encoder output format,
417 // since many vital information comes in the encoder format (eg. CSD).
418 // Transfer necessary fields from the user-configured track format (derived from
419 // source track format and user transcoding request) where needed.
420
421 // Transfer SAR settings:
422 // If mDestinationFormat has SAR set, it means the original source has SAR specified
423 // at container level. This is supposed to override any SAR settings in the bitstream,
424 // thus should always be transferred to the container of the transcoded file.
425 int32_t sarWidth, sarHeight;
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700426 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_SAR_WIDTH, &sarWidth) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700427 (sarWidth > 0) &&
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700428 AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_SAR_HEIGHT, &sarHeight) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700429 (sarHeight > 0)) {
430 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_WIDTH, sarWidth);
431 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_HEIGHT, sarHeight);
432 }
433 // Transfer DAR settings.
434 int32_t displayWidth, displayHeight;
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700435 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_WIDTH, &displayWidth) &&
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700436 (displayWidth > 0) &&
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700437 AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_HEIGHT,
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700438 &displayHeight) &&
439 (displayHeight > 0)) {
440 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_WIDTH, displayWidth);
441 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_HEIGHT, displayHeight);
442 }
443
Chong Zhangd6e4aec2020-06-22 14:13:07 -0700444 // Transfer rotation settings.
445 // Note that muxer itself doesn't take rotation from the track format. It requires
446 // AMediaMuxer_setOrientationHint to set the rotation. Here we pass the rotation to
447 // MediaSampleWriter using the track format. MediaSampleWriter will then call
448 // AMediaMuxer_setOrientationHint as needed.
449 int32_t rotation;
450 if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_ROTATION, &rotation) &&
451 (rotation != 0)) {
452 AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_ROTATION, rotation);
453 }
454
Linus Nilsson42a971b2020-07-01 16:41:11 -0700455 // Transfer track duration.
456 // Preserve the source track duration by sending it to MediaSampleWriter.
457 int64_t durationUs;
458 if (AMediaFormat_getInt64(mSourceFormat.get(), AMEDIAFORMAT_KEY_DURATION, &durationUs) &&
459 durationUs > 0) {
460 AMediaFormat_setInt64(formatCopy, AMEDIAFORMAT_KEY_DURATION, durationUs);
461 }
462
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700463 // TODO: transfer other fields as required.
464
465 mActualOutputFormat = std::shared_ptr<AMediaFormat>(formatCopy, &AMediaFormat_delete);
466
467 notifyTrackFormatAvailable();
468}
469
Linus Nilsson0da327a2020-01-31 16:22:18 -0800470media_status_t VideoTrackTranscoder::runTranscodeLoop() {
Linus Nilssonb09aac22020-07-29 11:56:53 -0700471 androidSetThreadPriority(0 /* tid (0 = current) */, ANDROID_PRIORITY_VIDEO);
472
Chong Zhangb55c5452020-06-26 14:32:12 -0700473 // Push start decoder and encoder as two messages, so that these are subject to the
474 // stop request as well. If the job is cancelled (or paused) immediately after start,
475 // we don't need to waste time start then stop the codecs.
476 mCodecMessageQueue.push([this] {
477 media_status_t status = AMediaCodec_start(mDecoder);
478 if (status != AMEDIA_OK) {
479 LOG(ERROR) << "Unable to start video decoder: " << status;
480 mStatus = status;
481 }
482 });
Linus Nilsson0da327a2020-01-31 16:22:18 -0800483
Chong Zhangb55c5452020-06-26 14:32:12 -0700484 mCodecMessageQueue.push([this] {
Linus Nilssone4716f22020-07-10 16:07:57 -0700485 media_status_t status = AMediaCodec_start(mEncoder->getCodec());
Chong Zhangb55c5452020-06-26 14:32:12 -0700486 if (status != AMEDIA_OK) {
487 LOG(ERROR) << "Unable to start video encoder: " << status;
488 mStatus = status;
489 }
Linus Nilssone4716f22020-07-10 16:07:57 -0700490 mEncoder->setStarted();
Chong Zhangb55c5452020-06-26 14:32:12 -0700491 });
Linus Nilsson0da327a2020-01-31 16:22:18 -0800492
493 // Process codec events until EOS is reached, transcoding is stopped or an error occurs.
Linus Nilssonc6221db2020-03-18 14:46:22 -0700494 while (!mStopRequested && !mEosFromEncoder && mStatus == AMEDIA_OK) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800495 std::function<void()> message = mCodecMessageQueue.pop();
496 message();
497 }
498
Linus Nilsson93cf9132020-09-24 12:12:48 -0700499 mCodecMessageQueue.abort();
500 AMediaCodec_stop(mDecoder);
501
Linus Nilsson0da327a2020-01-31 16:22:18 -0800502 // Return error if transcoding was stopped before it finished.
Linus Nilssonc6221db2020-03-18 14:46:22 -0700503 if (mStopRequested && !mEosFromEncoder && mStatus == AMEDIA_OK) {
Linus Nilsson0da327a2020-01-31 16:22:18 -0800504 mStatus = AMEDIA_ERROR_UNKNOWN; // TODO: Define custom error codes?
505 }
506
Linus Nilsson0da327a2020-01-31 16:22:18 -0800507 return mStatus;
508}
509
510void VideoTrackTranscoder::abortTranscodeLoop() {
511 // Push abort message to the front of the codec event queue.
512 mCodecMessageQueue.push([this] { mStopRequested = true; }, true /* front */);
513}
514
Linus Nilssoncab39d82020-05-14 16:32:21 -0700515std::shared_ptr<AMediaFormat> VideoTrackTranscoder::getOutputFormat() const {
Chong Zhanga2cc86b2020-06-17 16:56:49 -0700516 return mActualOutputFormat;
Linus Nilssoncab39d82020-05-14 16:32:21 -0700517}
518
Linus Nilsson0da327a2020-01-31 16:22:18 -0800519} // namespace android