• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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>
21 #include <android-base/properties.h>
22 #include <media/NdkCommon.h>
23 #include <media/VideoTrackTranscoder.h>
24 #include <sys/prctl.h>
25 
26 using namespace AMediaFormatUtils;
27 
28 namespace android {
29 
30 // Check that the codec sample flags have the expected NDK meaning.
31 static_assert(SAMPLE_FLAG_CODEC_CONFIG == AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG,
32               "Sample flag mismatch: CODEC_CONFIG");
33 static_assert(SAMPLE_FLAG_END_OF_STREAM == AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM,
34               "Sample flag mismatch: END_OF_STREAM");
35 static_assert(SAMPLE_FLAG_PARTIAL_FRAME == AMEDIACODEC_BUFFER_FLAG_PARTIAL_FRAME,
36               "Sample flag mismatch: PARTIAL_FRAME");
37 
38 // Color format defined by surface. (See MediaCodecInfo.CodecCapabilities#COLOR_FormatSurface.)
39 static constexpr int32_t kColorFormatSurface = 0x7f000789;
40 // Default key frame interval in seconds.
41 static constexpr float kDefaultKeyFrameIntervalSeconds = 1.0f;
42 // Default codec operating rate.
43 static int32_t kDefaultCodecOperatingRate720P = base::GetIntProperty(
44         "debug.media.transcoding.codec_max_operating_rate_720P", /*default*/ 480);
45 static int32_t kDefaultCodecOperatingRate1080P = base::GetIntProperty(
46         "debug.media.transcoding.codec_max_operating_rate_1080P", /*default*/ 240);
47 // Default codec priority.
48 static constexpr int32_t kDefaultCodecPriority = 1;
49 // Default bitrate, in case source estimation fails.
50 static constexpr int32_t kDefaultBitrateMbps = 10 * 1000 * 1000;
51 // Default frame rate.
52 static constexpr int32_t kDefaultFrameRate = 30;
53 // Default codec complexity
54 static constexpr int32_t kDefaultCodecComplexity = 1;
55 
56 template <typename T>
push(T const & value,bool front)57 void VideoTrackTranscoder::BlockingQueue<T>::push(T const& value, bool front) {
58     {
59         std::scoped_lock lock(mMutex);
60         if (mAborted) {
61             return;
62         }
63 
64         if (front) {
65             mQueue.push_front(value);
66         } else {
67             mQueue.push_back(value);
68         }
69     }
70     mCondition.notify_one();
71 }
72 
73 template <typename T>
pop()74 T VideoTrackTranscoder::BlockingQueue<T>::pop() {
75     std::unique_lock lock(mMutex);
76     while (mQueue.empty()) {
77         mCondition.wait(lock);
78     }
79     T value = mQueue.front();
80     mQueue.pop_front();
81     return value;
82 }
83 
84 // Note: Do not call if another thread might waiting in pop.
85 template <typename T>
abort()86 void VideoTrackTranscoder::BlockingQueue<T>::abort() {
87     std::scoped_lock lock(mMutex);
88     mAborted = true;
89     mQueue.clear();
90 }
91 
92 // 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.
96 class VideoTrackTranscoder::CodecWrapper {
97 public:
CodecWrapper(AMediaCodec * codec,const std::weak_ptr<VideoTrackTranscoder> & transcoder)98     CodecWrapper(AMediaCodec* codec, const std::weak_ptr<VideoTrackTranscoder>& transcoder)
99           : mCodec(codec), mTranscoder(transcoder), mCodecStarted(false) {}
~CodecWrapper()100     ~CodecWrapper() {
101         if (mCodecStarted) {
102             AMediaCodec_stop(mCodec);
103         }
104         AMediaCodec_delete(mCodec);
105     }
106 
getCodec()107     AMediaCodec* getCodec() { return mCodec; }
getTranscoder() const108     std::shared_ptr<VideoTrackTranscoder> getTranscoder() const { return mTranscoder.lock(); };
setStarted()109     void setStarted() { mCodecStarted = true; }
110 
111 private:
112     AMediaCodec* mCodec;
113     std::weak_ptr<VideoTrackTranscoder> mTranscoder;
114     bool mCodecStarted;
115 };
116 
117 // Dispatch responses to codec callbacks onto the message queue.
118 struct AsyncCodecCallbackDispatch {
onAsyncInputAvailableandroid::AsyncCodecCallbackDispatch119     static void onAsyncInputAvailable(AMediaCodec* codec, void* userdata, int32_t index) {
120         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             }
127         }
128     }
129 
onAsyncOutputAvailableandroid::AsyncCodecCallbackDispatch130     static void onAsyncOutputAvailable(AMediaCodec* codec, void* userdata, int32_t index,
131                                        AMediaCodecBufferInfo* bufferInfoPtr) {
132         VideoTrackTranscoder::CodecWrapper* wrapper =
133                 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
134         AMediaCodecBufferInfo bufferInfo = *bufferInfoPtr;
135         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         }
144     }
145 
onAsyncFormatChangedandroid::AsyncCodecCallbackDispatch146     static void onAsyncFormatChanged(AMediaCodec* codec, void* userdata, AMediaFormat* format) {
147         VideoTrackTranscoder::CodecWrapper* wrapper =
148                 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
149         if (auto transcoder = wrapper->getTranscoder()) {
150             const bool isDecoder = codec == transcoder->mDecoder;
151             const char* kCodecName = (isDecoder ? "Decoder" : "Encoder");
152             LOG(INFO) << kCodecName << " format changed: " << AMediaFormat_toString(format);
153             transcoder->mCodecMessageQueue.push([transcoder, format, isDecoder] {
154                 transcoder->updateTrackFormat(format, isDecoder);
155             });
156         }
157     }
158 
onAsyncErrorandroid::AsyncCodecCallbackDispatch159     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;
163         VideoTrackTranscoder::CodecWrapper* wrapper =
164                 static_cast<VideoTrackTranscoder::CodecWrapper*>(userdata);
165         if (auto transcoder = wrapper->getTranscoder()) {
166             transcoder->mCodecMessageQueue.push(
167                     [transcoder, error] { transcoder->mStatus = error; }, true);
168         }
169     }
170 };
171 
172 // static
create(const std::weak_ptr<MediaTrackTranscoderCallback> & transcoderCallback,pid_t pid,uid_t uid)173 std::shared_ptr<VideoTrackTranscoder> VideoTrackTranscoder::create(
174         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));
178 }
179 
~VideoTrackTranscoder()180 VideoTrackTranscoder::~VideoTrackTranscoder() {
181     if (mDecoder != nullptr) {
182         AMediaCodec_delete(mDecoder);
183     }
184 
185     if (mSurface != nullptr) {
186         ANativeWindow_release(mSurface);
187     }
188 }
189 
190 // Search the default operating rate based on resolution.
getDefaultOperatingRate(AMediaFormat * encoderFormat)191 static 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 kDefaultCodecOperatingRate720P;
197         } else if ((width == 1920 && height == 1080) || (width == 1080 && height == 1920)) {
198             return kDefaultCodecOperatingRate1080P;
199         } else {
200             LOG(WARNING) << "Could not find default operating rate: " << width << " " << height;
201             // Don't set operating rate if the correct dimensions are not found.
202         }
203     } else {
204         LOG(ERROR) << "Failed to get default operating rate due to missing resolution";
205     }
206     return -1;
207 }
208 
209 // Creates and configures the codecs.
configureDestinationFormat(const std::shared_ptr<AMediaFormat> & destinationFormat)210 media_status_t VideoTrackTranscoder::configureDestinationFormat(
211         const std::shared_ptr<AMediaFormat>& destinationFormat) {
212     media_status_t status = AMEDIA_OK;
213 
214     if (destinationFormat == nullptr) {
215         LOG(ERROR) << "Destination format is null, use passthrough transcoder";
216         return AMEDIA_ERROR_INVALID_PARAMETER;
217     }
218 
219     AMediaFormat* encoderFormat = AMediaFormat_new();
220     if (!encoderFormat || AMediaFormat_copy(encoderFormat, destinationFormat.get()) != AMEDIA_OK) {
221         LOG(ERROR) << "Unable to copy destination format";
222         return AMEDIA_ERROR_INVALID_PARAMETER;
223     }
224 
225     if (!AMediaFormat_getInt32(encoderFormat, AMEDIAFORMAT_KEY_BIT_RATE, &mConfiguredBitrate)) {
226         status = mMediaSampleReader->getEstimatedBitrateForTrack(mTrackIndex, &mConfiguredBitrate);
227         if (status != AMEDIA_OK) {
228             LOG(ERROR) << "Unable to estimate bitrate. Using default " << kDefaultBitrateMbps;
229             mConfiguredBitrate = kDefaultBitrateMbps;
230         }
231 
232         LOG(INFO) << "Configuring bitrate " << mConfiguredBitrate;
233         AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_BIT_RATE, mConfiguredBitrate);
234     }
235 
236     SetDefaultFormatValueFloat(AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, encoderFormat,
237                                kDefaultKeyFrameIntervalSeconds);
238 
239     int32_t operatingRate = getDefaultOperatingRate(encoderFormat);
240 
241     if (operatingRate != -1) {
242         float tmpf;
243         int32_t tmpi;
244         if (!AMediaFormat_getFloat(encoderFormat, AMEDIAFORMAT_KEY_OPERATING_RATE, &tmpf) &&
245             !AMediaFormat_getInt32(encoderFormat, AMEDIAFORMAT_KEY_OPERATING_RATE, &tmpi)) {
246             AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_OPERATING_RATE, operatingRate);
247         }
248     }
249 
250     SetDefaultFormatValueInt32(AMEDIAFORMAT_KEY_PRIORITY, encoderFormat, kDefaultCodecPriority);
251     SetDefaultFormatValueInt32(AMEDIAFORMAT_KEY_FRAME_RATE, encoderFormat, kDefaultFrameRate);
252     SetDefaultFormatValueInt32(AMEDIAFORMAT_KEY_COMPLEXITY, encoderFormat, kDefaultCodecComplexity);
253     AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, kColorFormatSurface);
254 
255     // Always encode without rotation. The rotation degree will be transferred directly to
256     // MediaSampleWriter track format, and MediaSampleWriter will call AMediaMuxer_setOrientationHint.
257     AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_ROTATION, 0);
258 
259     // Request encoder to use background priorities by default.
260     SetDefaultFormatValueInt32(TBD_AMEDIACODEC_PARAMETER_KEY_BACKGROUND_MODE, encoderFormat,
261                                1 /* true */);
262 
263     mDestinationFormat = std::shared_ptr<AMediaFormat>(encoderFormat, &AMediaFormat_delete);
264 
265     // Create and configure the encoder.
266     const char* destinationMime = nullptr;
267     bool ok = AMediaFormat_getString(mDestinationFormat.get(), AMEDIAFORMAT_KEY_MIME,
268                                      &destinationMime);
269     if (!ok) {
270         LOG(ERROR) << "Destination MIME type is required for transcoding.";
271         return AMEDIA_ERROR_INVALID_PARAMETER;
272     }
273 
274 #define __TRANSCODING_MIN_API__ 31
275 
276     AMediaCodec* encoder;
277     if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
278         encoder = AMediaCodec_createEncoderByTypeForClient(destinationMime, mPid, mUid);
279     } else {
280         encoder = AMediaCodec_createEncoderByType(destinationMime);
281     }
282     if (encoder == nullptr) {
283         LOG(ERROR) << "Unable to create encoder for type " << destinationMime;
284         return AMEDIA_ERROR_UNSUPPORTED;
285     }
286     mEncoder = std::make_shared<CodecWrapper>(encoder, shared_from_this());
287 
288     LOG(INFO) << "Configuring encoder with: " << AMediaFormat_toString(mDestinationFormat.get());
289     status = AMediaCodec_configure(mEncoder->getCodec(), mDestinationFormat.get(),
290                                    NULL /* surface */, NULL /* crypto */,
291                                    AMEDIACODEC_CONFIGURE_FLAG_ENCODE);
292     if (status != AMEDIA_OK) {
293         LOG(ERROR) << "Unable to configure video encoder: " << status;
294         return status;
295     }
296 
297     status = AMediaCodec_createInputSurface(mEncoder->getCodec(), &mSurface);
298     if (status != AMEDIA_OK) {
299         LOG(ERROR) << "Unable to create an encoder input surface: %d" << status;
300         return status;
301     }
302 
303     // Create and configure the decoder.
304     const char* sourceMime = nullptr;
305     ok = AMediaFormat_getString(mSourceFormat.get(), AMEDIAFORMAT_KEY_MIME, &sourceMime);
306     if (!ok) {
307         LOG(ERROR) << "Source MIME type is required for transcoding.";
308         return AMEDIA_ERROR_INVALID_PARAMETER;
309     }
310 
311     if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
312         mDecoder = AMediaCodec_createDecoderByTypeForClient(sourceMime, mPid, mUid);
313     } else {
314         mDecoder = AMediaCodec_createDecoderByType(sourceMime);
315     }
316     if (mDecoder == nullptr) {
317         LOG(ERROR) << "Unable to create decoder for type " << sourceMime;
318         return AMEDIA_ERROR_UNSUPPORTED;
319     }
320 
321     auto decoderFormat = std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
322     if (!decoderFormat ||
323         AMediaFormat_copy(decoderFormat.get(), mSourceFormat.get()) != AMEDIA_OK) {
324         LOG(ERROR) << "Unable to copy source format";
325         return AMEDIA_ERROR_INVALID_PARAMETER;
326     }
327 
328     // Request decoder to convert HDR content to SDR.
329     const bool sourceIsHdr = VideoIsHdr(mSourceFormat.get());
330     if (sourceIsHdr) {
331         AMediaFormat_setInt32(decoderFormat.get(),
332                               TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST,
333                               COLOR_TRANSFER_SDR_VIDEO);
334     }
335 
336     // Prevent decoder from overwriting frames that the encoder has not yet consumed.
337     AMediaFormat_setInt32(decoderFormat.get(), TBD_AMEDIACODEC_PARAMETER_KEY_ALLOW_FRAME_DROP, 0);
338 
339     // Copy over configurations that apply to both encoder and decoder.
340     static const std::vector<EntryCopier> kEncoderEntriesToCopy{
341             ENTRY_COPIER2(AMEDIAFORMAT_KEY_OPERATING_RATE, Float, Int32),
342             ENTRY_COPIER(AMEDIAFORMAT_KEY_PRIORITY, Int32),
343             ENTRY_COPIER(TBD_AMEDIACODEC_PARAMETER_KEY_BACKGROUND_MODE, Int32),
344     };
345     CopyFormatEntries(mDestinationFormat.get(), decoderFormat.get(), kEncoderEntriesToCopy);
346 
347     LOG(INFO) << "Configuring decoder with: " << AMediaFormat_toString(decoderFormat.get());
348     status = AMediaCodec_configure(mDecoder, decoderFormat.get(), mSurface, NULL /* crypto */,
349                                    0 /* flags */);
350     if (status != AMEDIA_OK) {
351         LOG(ERROR) << "Unable to configure video decoder: " << status;
352         return status;
353     }
354 
355     if (sourceIsHdr) {
356         bool supported = false;
357         AMediaFormat* inputFormat = AMediaCodec_getInputFormat(mDecoder);
358 
359         if (inputFormat != nullptr) {
360             int32_t transferFunc;
361             supported = AMediaFormat_getInt32(inputFormat,
362                                               TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST,
363                                               &transferFunc) &&
364                         transferFunc == COLOR_TRANSFER_SDR_VIDEO;
365             AMediaFormat_delete(inputFormat);
366         }
367 
368         if (!supported) {
369             LOG(ERROR) << "HDR to SDR conversion unsupported by the codec";
370             return AMEDIA_ERROR_UNSUPPORTED;
371         }
372     }
373 
374     // Configure codecs to run in async mode.
375     AMediaCodecOnAsyncNotifyCallback asyncCodecCallbacks = {
376             .onAsyncInputAvailable = AsyncCodecCallbackDispatch::onAsyncInputAvailable,
377             .onAsyncOutputAvailable = AsyncCodecCallbackDispatch::onAsyncOutputAvailable,
378             .onAsyncFormatChanged = AsyncCodecCallbackDispatch::onAsyncFormatChanged,
379             .onAsyncError = AsyncCodecCallbackDispatch::onAsyncError};
380 
381     // Note: The decoder does not need its own wrapper because its lifetime is tied to the
382     // transcoder. But the same callbacks are reused for decoder and encoder so we pass the encoder
383     // wrapper as userdata here but never read the codec from it in the callback.
384     status = AMediaCodec_setAsyncNotifyCallback(mDecoder, asyncCodecCallbacks, mEncoder.get());
385     if (status != AMEDIA_OK) {
386         LOG(ERROR) << "Unable to set decoder to async mode: " << status;
387         return status;
388     }
389 
390     status = AMediaCodec_setAsyncNotifyCallback(mEncoder->getCodec(), asyncCodecCallbacks,
391                                                 mEncoder.get());
392     if (status != AMEDIA_OK) {
393         LOG(ERROR) << "Unable to set encoder to async mode: " << status;
394         return status;
395     }
396 
397     return AMEDIA_OK;
398 }
399 
enqueueInputSample(int32_t bufferIndex)400 void VideoTrackTranscoder::enqueueInputSample(int32_t bufferIndex) {
401     media_status_t status = AMEDIA_OK;
402 
403     if (mEosFromSource) {
404         return;
405     }
406 
407     status = mMediaSampleReader->getSampleInfoForTrack(mTrackIndex, &mSampleInfo);
408     if (status != AMEDIA_OK && status != AMEDIA_ERROR_END_OF_STREAM) {
409         LOG(ERROR) << "Error getting next sample info: " << status;
410         mStatus = status;
411         return;
412     }
413     const bool endOfStream = (status == AMEDIA_ERROR_END_OF_STREAM);
414 
415     if (!endOfStream) {
416         size_t bufferSize = 0;
417         uint8_t* sourceBuffer = AMediaCodec_getInputBuffer(mDecoder, bufferIndex, &bufferSize);
418         if (sourceBuffer == nullptr) {
419             LOG(ERROR) << "Decoder returned a NULL input buffer.";
420             mStatus = AMEDIA_ERROR_UNKNOWN;
421             return;
422         } else if (bufferSize < mSampleInfo.size) {
423             LOG(ERROR) << "Decoder returned an input buffer that is smaller than the sample.";
424             mStatus = AMEDIA_ERROR_UNKNOWN;
425             return;
426         }
427 
428         status = mMediaSampleReader->readSampleDataForTrack(mTrackIndex, sourceBuffer,
429                                                             mSampleInfo.size);
430         if (status != AMEDIA_OK) {
431             LOG(ERROR) << "Unable to read next sample data. Aborting transcode.";
432             mStatus = status;
433             return;
434         }
435 
436         if (mSampleInfo.size) {
437             ++mInputFrameCount;
438         }
439     } else {
440         LOG(DEBUG) << "EOS from source.";
441         mEosFromSource = true;
442     }
443 
444     status = AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, mSampleInfo.size,
445                                           mSampleInfo.presentationTimeUs, mSampleInfo.flags);
446     if (status != AMEDIA_OK) {
447         LOG(ERROR) << "Unable to queue input buffer for decode: " << status;
448         mStatus = status;
449         return;
450     }
451 }
452 
transferBuffer(int32_t bufferIndex,AMediaCodecBufferInfo bufferInfo)453 void VideoTrackTranscoder::transferBuffer(int32_t bufferIndex, AMediaCodecBufferInfo bufferInfo) {
454     if (bufferIndex >= 0) {
455         bool needsRender = bufferInfo.size > 0;
456         AMediaCodec_releaseOutputBuffer(mDecoder, bufferIndex, needsRender);
457     }
458 
459     if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
460         LOG(DEBUG) << "EOS from decoder.";
461         media_status_t status = AMediaCodec_signalEndOfInputStream(mEncoder->getCodec());
462         if (status != AMEDIA_OK) {
463             LOG(ERROR) << "SignalEOS on encoder returned error: " << status;
464             mStatus = status;
465         }
466     }
467 }
468 
dequeueOutputSample(int32_t bufferIndex,AMediaCodecBufferInfo bufferInfo)469 void VideoTrackTranscoder::dequeueOutputSample(int32_t bufferIndex,
470                                                AMediaCodecBufferInfo bufferInfo) {
471     if (bufferIndex >= 0) {
472         size_t sampleSize = 0;
473         uint8_t* buffer =
474                 AMediaCodec_getOutputBuffer(mEncoder->getCodec(), bufferIndex, &sampleSize);
475 
476         MediaSample::OnSampleReleasedCallback bufferReleaseCallback =
477                 [encoder = mEncoder](MediaSample* sample) {
478                     AMediaCodec_releaseOutputBuffer(encoder->getCodec(), sample->bufferId,
479                                                     false /* render */);
480                 };
481 
482         std::shared_ptr<MediaSample> sample = MediaSample::createWithReleaseCallback(
483                 buffer, bufferInfo.offset, bufferIndex, bufferReleaseCallback);
484         sample->info.size = bufferInfo.size;
485         sample->info.flags = bufferInfo.flags;
486         sample->info.presentationTimeUs = bufferInfo.presentationTimeUs;
487 
488         if (bufferInfo.size > 0 && (bufferInfo.flags & SAMPLE_FLAG_CODEC_CONFIG) == 0) {
489             ++mOutputFrameCount;
490         }
491         onOutputSampleAvailable(sample);
492 
493         mLastSampleWasSync = sample->info.flags & SAMPLE_FLAG_SYNC_SAMPLE;
494     }
495 
496     if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
497         LOG(DEBUG) << "EOS from encoder.";
498         mEosFromEncoder = true;
499 
500         if (mInputFrameCount != mOutputFrameCount) {
501             LOG(WARNING) << "Input / Output frame count mismatch: " << mInputFrameCount << " vs "
502                          << mOutputFrameCount;
503             if (mInputFrameCount > 0 && mOutputFrameCount == 0) {
504                 LOG(ERROR) << "Encoder did not produce any output frames.";
505                 mStatus = AMEDIA_ERROR_UNKNOWN;
506             }
507         }
508     }
509 }
510 
updateTrackFormat(AMediaFormat * outputFormat,bool fromDecoder)511 void VideoTrackTranscoder::updateTrackFormat(AMediaFormat* outputFormat, bool fromDecoder) {
512     if (fromDecoder) {
513         static const std::vector<AMediaFormatUtils::EntryCopier> kValuesToCopy{
514                 ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_RANGE, Int32),
515                 ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_STANDARD, Int32),
516                 ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_TRANSFER, Int32),
517         };
518         AMediaFormat* params = AMediaFormat_new();
519         if (params != nullptr) {
520             AMediaFormatUtils::CopyFormatEntries(outputFormat, params, kValuesToCopy);
521             if (AMediaCodec_setParameters(mEncoder->getCodec(), params) != AMEDIA_OK) {
522                 LOG(WARNING) << "Unable to update encoder with color information";
523             }
524             AMediaFormat_delete(params);
525         }
526         return;
527     }
528 
529     if (mActualOutputFormat != nullptr) {
530         LOG(WARNING) << "Ignoring duplicate format change.";
531         return;
532     }
533 
534     AMediaFormat* formatCopy = AMediaFormat_new();
535     if (!formatCopy || AMediaFormat_copy(formatCopy, outputFormat) != AMEDIA_OK) {
536         LOG(ERROR) << "Unable to copy outputFormat";
537         AMediaFormat_delete(formatCopy);
538         mStatus = AMEDIA_ERROR_INVALID_PARAMETER;
539         return;
540     }
541 
542     // Generate the actual track format for muxer based on the encoder output format,
543     // since many vital information comes in the encoder format (eg. CSD).
544     // Transfer necessary fields from the user-configured track format (derived from
545     // source track format and user transcoding request) where needed.
546 
547     // Transfer SAR settings:
548     // If mDestinationFormat has SAR set, it means the original source has SAR specified
549     // at container level. This is supposed to override any SAR settings in the bitstream,
550     // thus should always be transferred to the container of the transcoded file.
551     int32_t sarWidth, sarHeight;
552     if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_SAR_WIDTH, &sarWidth) &&
553         (sarWidth > 0) &&
554         AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_SAR_HEIGHT, &sarHeight) &&
555         (sarHeight > 0)) {
556         AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_WIDTH, sarWidth);
557         AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_SAR_HEIGHT, sarHeight);
558     }
559     // Transfer DAR settings.
560     int32_t displayWidth, displayHeight;
561     if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_WIDTH, &displayWidth) &&
562         (displayWidth > 0) &&
563         AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_DISPLAY_HEIGHT,
564                               &displayHeight) &&
565         (displayHeight > 0)) {
566         AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_WIDTH, displayWidth);
567         AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_DISPLAY_HEIGHT, displayHeight);
568     }
569 
570     // Transfer rotation settings.
571     // Note that muxer itself doesn't take rotation from the track format. It requires
572     // AMediaMuxer_setOrientationHint to set the rotation. Here we pass the rotation to
573     // MediaSampleWriter using the track format. MediaSampleWriter will then call
574     // AMediaMuxer_setOrientationHint as needed.
575     int32_t rotation;
576     if (AMediaFormat_getInt32(mSourceFormat.get(), AMEDIAFORMAT_KEY_ROTATION, &rotation) &&
577         (rotation != 0)) {
578         AMediaFormat_setInt32(formatCopy, AMEDIAFORMAT_KEY_ROTATION, rotation);
579     }
580 
581     // Transfer track duration.
582     // Preserve the source track duration by sending it to MediaSampleWriter.
583     int64_t durationUs;
584     if (AMediaFormat_getInt64(mSourceFormat.get(), AMEDIAFORMAT_KEY_DURATION, &durationUs) &&
585         durationUs > 0) {
586         AMediaFormat_setInt64(formatCopy, AMEDIAFORMAT_KEY_DURATION, durationUs);
587     }
588 
589     // TODO: transfer other fields as required.
590 
591     mActualOutputFormat = std::shared_ptr<AMediaFormat>(formatCopy, &AMediaFormat_delete);
592     LOG(INFO) << "Actual output format: " << AMediaFormat_toString(formatCopy);
593 
594     notifyTrackFormatAvailable();
595 }
596 
runTranscodeLoop(bool * stopped)597 media_status_t VideoTrackTranscoder::runTranscodeLoop(bool* stopped) {
598     prctl(PR_SET_NAME, (unsigned long)"VideTranscodTrd", 0, 0, 0);
599 
600     // Push start decoder and encoder as two messages, so that these are subject to the
601     // stop request as well. If the session is cancelled (or paused) immediately after start,
602     // we don't need to waste time start then stop the codecs.
603     mCodecMessageQueue.push([this] {
604         media_status_t status = AMediaCodec_start(mDecoder);
605         if (status != AMEDIA_OK) {
606             LOG(ERROR) << "Unable to start video decoder: " << status;
607             mStatus = status;
608         }
609     });
610 
611     mCodecMessageQueue.push([this] {
612         media_status_t status = AMediaCodec_start(mEncoder->getCodec());
613         if (status != AMEDIA_OK) {
614             LOG(ERROR) << "Unable to start video encoder: " << status;
615             mStatus = status;
616         }
617         mEncoder->setStarted();
618     });
619 
620     // Process codec events until EOS is reached, transcoding is stopped or an error occurs.
621     while (mStopRequest != STOP_NOW && !mEosFromEncoder && mStatus == AMEDIA_OK) {
622         std::function<void()> message = mCodecMessageQueue.pop();
623         message();
624 
625         if (mStopRequest == STOP_ON_SYNC && mLastSampleWasSync) {
626             break;
627         }
628     }
629 
630     mCodecMessageQueue.abort();
631     AMediaCodec_stop(mDecoder);
632 
633     // Signal if transcoding was stopped before it finished.
634     if (mStopRequest != NONE && !mEosFromEncoder && mStatus == AMEDIA_OK) {
635         *stopped = true;
636     }
637 
638     return mStatus;
639 }
640 
abortTranscodeLoop()641 void VideoTrackTranscoder::abortTranscodeLoop() {
642     if (mStopRequest == STOP_NOW) {
643         // Wake up transcoder thread.
644         mCodecMessageQueue.push([] {}, true /* front */);
645     }
646 }
647 
getOutputFormat() const648 std::shared_ptr<AMediaFormat> VideoTrackTranscoder::getOutputFormat() const {
649     return mActualOutputFormat;
650 }
651 
652 }  // namespace android
653