Merge "Transcoder: Don't preserve profile/level when switching codec." into sc-dev
diff --git a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
index 74ddce4..413f049 100644
--- a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
@@ -29,24 +29,37 @@
 
 namespace android {
 
-static AMediaFormat* mergeMediaFormats(AMediaFormat* base, AMediaFormat* overlay) {
-    if (base == nullptr || overlay == nullptr) {
+static std::shared_ptr<AMediaFormat> createVideoTrackFormat(AMediaFormat* srcFormat,
+                                                            AMediaFormat* options) {
+    if (srcFormat == nullptr || options == nullptr) {
         LOG(ERROR) << "Cannot merge null formats";
         return nullptr;
     }
 
-    AMediaFormat* format = AMediaFormat_new();
-    if (AMediaFormat_copy(format, base) != AMEDIA_OK) {
-        AMediaFormat_delete(format);
-        return nullptr;
+    // ------- Define parameters to copy from the source track format -------
+    std::vector<AMediaFormatUtils::EntryCopier> srcParamsToCopy{
+            ENTRY_COPIER(AMEDIAFORMAT_KEY_MIME, String),
+            ENTRY_COPIER(AMEDIAFORMAT_KEY_DURATION, Int64),
+            ENTRY_COPIER(AMEDIAFORMAT_KEY_WIDTH, Int32),
+            ENTRY_COPIER(AMEDIAFORMAT_KEY_HEIGHT, Int32),
+            ENTRY_COPIER(AMEDIAFORMAT_KEY_FRAME_RATE, Int32),
+            ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_RANGE, Int32),
+            ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_STANDARD, Int32),
+            ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_TRANSFER, Int32),
+    };
+
+    // If the destination codec is the same as the source codec, we can preserve profile and level
+    // from the source track as default values. Otherwise leave them unspecified.
+    const char *srcMime, *dstMime;
+    AMediaFormat_getString(srcFormat, AMEDIAFORMAT_KEY_MIME, &srcMime);
+    if (!AMediaFormat_getString(options, AMEDIAFORMAT_KEY_MIME, &dstMime) ||
+        strcmp(srcMime, dstMime) == 0) {
+        srcParamsToCopy.push_back(ENTRY_COPIER(AMEDIAFORMAT_KEY_PROFILE, String));
+        srcParamsToCopy.push_back(ENTRY_COPIER(AMEDIAFORMAT_KEY_LEVEL, String));
     }
 
-    // Note: AMediaFormat does not expose a function for appending values from another format or for
-    // iterating over all values and keys in a format. Instead we define a static list of known keys
-    // along with their value types and copy the ones that are present. A better solution would be
-    // to either implement required functions in NDK or to parse the overlay format's string
-    // representation and copy all existing keys.
-    static const AMediaFormatUtils::EntryCopier kSupportedFormatEntries[] = {
+    // ------- Define parameters to copy from the caller's options -------
+    static const std::vector<AMediaFormatUtils::EntryCopier> kSupportedOptions{
             ENTRY_COPIER(AMEDIAFORMAT_KEY_MIME, String),
             ENTRY_COPIER(AMEDIAFORMAT_KEY_DURATION, Int64),
             ENTRY_COPIER(AMEDIAFORMAT_KEY_WIDTH, Int32),
@@ -54,7 +67,6 @@
             ENTRY_COPIER(AMEDIAFORMAT_KEY_BIT_RATE, Int32),
             ENTRY_COPIER(AMEDIAFORMAT_KEY_PROFILE, Int32),
             ENTRY_COPIER(AMEDIAFORMAT_KEY_LEVEL, Int32),
-            ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_FORMAT, Int32),
             ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_RANGE, Int32),
             ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_STANDARD, Int32),
             ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_TRANSFER, Int32),
@@ -63,10 +75,12 @@
             ENTRY_COPIER(AMEDIAFORMAT_KEY_PRIORITY, Int32),
             ENTRY_COPIER2(AMEDIAFORMAT_KEY_OPERATING_RATE, Float, Int32),
     };
-    const size_t entryCount = sizeof(kSupportedFormatEntries) / sizeof(kSupportedFormatEntries[0]);
 
-    AMediaFormatUtils::CopyFormatEntries(overlay, format, kSupportedFormatEntries, entryCount);
-    return format;
+    // ------- Copy parameters from source and options to the destination -------
+    auto trackFormat = std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
+    AMediaFormatUtils::CopyFormatEntries(srcFormat, trackFormat.get(), srcParamsToCopy);
+    AMediaFormatUtils::CopyFormatEntries(options, trackFormat.get(), kSupportedOptions);
+    return trackFormat;
 }
 
 void MediaTranscoder::onThreadFinished(const void* thread, media_status_t threadStatus,
@@ -270,7 +284,8 @@
     return trackFormats;
 }
 
-media_status_t MediaTranscoder::configureTrackFormat(size_t trackIndex, AMediaFormat* trackFormat) {
+media_status_t MediaTranscoder::configureTrackFormat(size_t trackIndex,
+                                                     AMediaFormat* destinationOptions) {
     if (mSampleReader == nullptr) {
         LOG(ERROR) << "Source must be configured before tracks";
         return AMEDIA_ERROR_INVALID_OPERATION;
@@ -281,14 +296,15 @@
     }
 
     std::shared_ptr<MediaTrackTranscoder> transcoder;
-    std::shared_ptr<AMediaFormat> format;
+    std::shared_ptr<AMediaFormat> trackFormat;
 
-    if (trackFormat == nullptr) {
+    if (destinationOptions == nullptr) {
         transcoder = std::make_shared<PassthroughTrackTranscoder>(shared_from_this());
     } else {
+        AMediaFormat* srcTrackFormat = mSourceTrackFormats[trackIndex].get();
+
         const char* srcMime = nullptr;
-        if (!AMediaFormat_getString(mSourceTrackFormats[trackIndex].get(), AMEDIAFORMAT_KEY_MIME,
-                                    &srcMime)) {
+        if (!AMediaFormat_getString(srcTrackFormat, AMEDIAFORMAT_KEY_MIME, &srcMime)) {
             LOG(ERROR) << "Source track #" << trackIndex << " has no mime type";
             return AMEDIA_ERROR_MALFORMED;
         }
@@ -301,7 +317,7 @@
         }
 
         const char* dstMime = nullptr;
-        if (AMediaFormat_getString(trackFormat, AMEDIAFORMAT_KEY_MIME, &dstMime)) {
+        if (AMediaFormat_getString(destinationOptions, AMEDIAFORMAT_KEY_MIME, &dstMime)) {
             if (strncmp(dstMime, "video/", 6) != 0) {
                 LOG(ERROR) << "Unable to convert media types for track #" << trackIndex << ", from "
                            << srcMime << " to " << dstMime;
@@ -311,14 +327,11 @@
 
         transcoder = VideoTrackTranscoder::create(shared_from_this(), mPid, mUid);
 
-        AMediaFormat* mergedFormat =
-                mergeMediaFormats(mSourceTrackFormats[trackIndex].get(), trackFormat);
-        if (mergedFormat == nullptr) {
-            LOG(ERROR) << "Unable to merge source and destination formats";
+        trackFormat = createVideoTrackFormat(srcTrackFormat, destinationOptions);
+        if (trackFormat == nullptr) {
+            LOG(ERROR) << "Unable to create video track format";
             return AMEDIA_ERROR_UNKNOWN;
         }
-
-        format = std::shared_ptr<AMediaFormat>(mergedFormat, &AMediaFormat_delete);
     }
 
     media_status_t status = mSampleReader->selectTrack(trackIndex);
@@ -327,7 +340,7 @@
         return status;
     }
 
-    status = transcoder->configure(mSampleReader, trackIndex, format);
+    status = transcoder->configure(mSampleReader, trackIndex, trackFormat);
     if (status != AMEDIA_OK) {
         LOG(ERROR) << "Configure track transcoder for track #" << trackIndex << " returned error "
                    << status;
diff --git a/media/libmediatranscoding/transcoder/NdkCommon.cpp b/media/libmediatranscoding/transcoder/NdkCommon.cpp
index fb909b2..2d85df7 100644
--- a/media/libmediatranscoding/transcoder/NdkCommon.cpp
+++ b/media/libmediatranscoding/transcoder/NdkCommon.cpp
@@ -60,19 +60,19 @@
 DEFINE_FORMAT_VALUE_COPY_FUNC(int32_t, Int32);
 DEFINE_FORMAT_VALUE_COPY_FUNC(float, Float);
 
-void CopyFormatEntries(AMediaFormat* from, AMediaFormat* to, const EntryCopier* entries,
-                       size_t entryCount) {
+void CopyFormatEntries(AMediaFormat* from, AMediaFormat* to,
+                       const std::vector<EntryCopier>& entries) {
     if (from == nullptr || to == nullptr) {
         LOG(ERROR) << "Cannot copy null formats";
         return;
-    } else if (entries == nullptr || entryCount < 1) {
+    } else if (entries.empty()) {
         LOG(WARNING) << "No entries to copy";
         return;
     }
 
-    for (size_t i = 0; i < entryCount; ++i) {
-        if (!entries[i].copy(entries[i].key, from, to) && entries[i].copy2 != nullptr) {
-            entries[i].copy2(entries[i].key, from, to);
+    for (auto& entry : entries) {
+        if (!entry.copy(entry.key, from, to) && entry.copy2 != nullptr) {
+            entry.copy2(entry.key, from, to);
         }
     }
 }
diff --git a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index ab08d73..4405180 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -147,7 +147,7 @@
         if (auto transcoder = wrapper->getTranscoder()) {
             const bool isDecoder = codec == transcoder->mDecoder;
             const char* kCodecName = (isDecoder ? "Decoder" : "Encoder");
-            LOG(DEBUG) << kCodecName << " format changed: " << AMediaFormat_toString(format);
+            LOG(INFO) << kCodecName << " format changed: " << AMediaFormat_toString(format);
             transcoder->mCodecMessageQueue.push([transcoder, format, isDecoder] {
                 transcoder->updateTrackFormat(format, isDecoder);
             });
@@ -280,7 +280,7 @@
     }
     mEncoder = std::make_shared<CodecWrapper>(encoder, shared_from_this());
 
-    LOG(DEBUG) << "Configuring encoder with: " << AMediaFormat_toString(mDestinationFormat.get());
+    LOG(INFO) << "Configuring encoder with: " << AMediaFormat_toString(mDestinationFormat.get());
     status = AMediaCodec_configure(mEncoder->getCodec(), mDestinationFormat.get(),
                                    NULL /* surface */, NULL /* crypto */,
                                    AMEDIACODEC_CONFIGURE_FLAG_ENCODE);
@@ -332,15 +332,13 @@
     AMediaFormat_setInt32(decoderFormat.get(), TBD_AMEDIACODEC_PARAMETER_KEY_ALLOW_FRAME_DROP, 0);
 
     // Copy over configurations that apply to both encoder and decoder.
-    static const EntryCopier kEncoderEntriesToCopy[] = {
+    static const std::vector<EntryCopier> kEncoderEntriesToCopy{
             ENTRY_COPIER2(AMEDIAFORMAT_KEY_OPERATING_RATE, Float, Int32),
             ENTRY_COPIER(AMEDIAFORMAT_KEY_PRIORITY, Int32),
     };
-    const size_t entryCount = sizeof(kEncoderEntriesToCopy) / sizeof(kEncoderEntriesToCopy[0]);
-    CopyFormatEntries(mDestinationFormat.get(), decoderFormat.get(), kEncoderEntriesToCopy,
-                      entryCount);
+    CopyFormatEntries(mDestinationFormat.get(), decoderFormat.get(), kEncoderEntriesToCopy);
 
-    LOG(DEBUG) << "Configuring decoder with: " << AMediaFormat_toString(decoderFormat.get());
+    LOG(INFO) << "Configuring decoder with: " << AMediaFormat_toString(decoderFormat.get());
     status = AMediaCodec_configure(mDecoder, decoderFormat.get(), mSurface, NULL /* crypto */,
                                    0 /* flags */);
     if (status != AMEDIA_OK) {
@@ -487,9 +485,6 @@
         onOutputSampleAvailable(sample);
 
         mLastSampleWasSync = sample->info.flags & SAMPLE_FLAG_SYNC_SAMPLE;
-    } else if (bufferIndex == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
-        AMediaFormat* newFormat = AMediaCodec_getOutputFormat(mEncoder->getCodec());
-        LOG(DEBUG) << "Encoder output format changed: " << AMediaFormat_toString(newFormat);
     }
 
     if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
@@ -509,15 +504,14 @@
 
 void VideoTrackTranscoder::updateTrackFormat(AMediaFormat* outputFormat, bool fromDecoder) {
     if (fromDecoder) {
-        static const AMediaFormatUtils::EntryCopier kValuesToCopy[] = {
+        static const std::vector<AMediaFormatUtils::EntryCopier> kValuesToCopy{
                 ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_RANGE, Int32),
                 ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_STANDARD, Int32),
                 ENTRY_COPIER(AMEDIAFORMAT_KEY_COLOR_TRANSFER, Int32),
         };
         AMediaFormat* params = AMediaFormat_new();
         if (params != nullptr) {
-            AMediaFormatUtils::CopyFormatEntries(outputFormat, params, kValuesToCopy,
-                                                 std::size(kValuesToCopy));
+            AMediaFormatUtils::CopyFormatEntries(outputFormat, params, kValuesToCopy);
             if (AMediaCodec_setParameters(mEncoder->getCodec(), params) != AMEDIA_OK) {
                 LOG(WARNING) << "Unable to update encoder with color information";
             }
@@ -589,7 +583,7 @@
     // TODO: transfer other fields as required.
 
     mActualOutputFormat = std::shared_ptr<AMediaFormat>(formatCopy, &AMediaFormat_delete);
-    LOG(DEBUG) << "Actual output format: " << AMediaFormat_toString(formatCopy);
+    LOG(INFO) << "Actual output format: " << AMediaFormat_toString(formatCopy);
 
     notifyTrackFormatAvailable();
 }
diff --git a/media/libmediatranscoding/transcoder/include/media/NdkCommon.h b/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
index a7ed6a7..c5547c6 100644
--- a/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
+++ b/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
@@ -19,6 +19,8 @@
 
 #include <media/NdkMediaFormat.h>
 
+#include <vector>
+
 extern const char* AMEDIA_MIMETYPE_VIDEO_VP8;
 extern const char* AMEDIA_MIMETYPE_VIDEO_VP9;
 extern const char* AMEDIA_MIMETYPE_VIDEO_AV1;
@@ -82,8 +84,8 @@
 bool CopyFormatEntryInt32(const char* key, AMediaFormat* from, AMediaFormat* to);
 bool CopyFormatEntryFloat(const char* key, AMediaFormat* from, AMediaFormat* to);
 
-void CopyFormatEntries(AMediaFormat* from, AMediaFormat* to, const EntryCopier* entries,
-                       size_t entryCount);
+void CopyFormatEntries(AMediaFormat* from, AMediaFormat* to,
+                       const std::vector<EntryCopier>& entries);
 
 bool SetDefaultFormatValueFloat(const char* key, AMediaFormat* format, float value);
 bool SetDefaultFormatValueInt32(const char* key, AMediaFormat* format, int32_t value);