Merge "transcoding: fix timeout value"
diff --git a/media/codec2/components/base/SimpleC2Interface.cpp b/media/codec2/components/base/SimpleC2Interface.cpp
index 5c019f3..29740d1 100644
--- a/media/codec2/components/base/SimpleC2Interface.cpp
+++ b/media/codec2/components/base/SimpleC2Interface.cpp
@@ -39,6 +39,16 @@
     setDerivedInstance(this);
 
     addParameter(
+            DefineParam(mApiFeatures, C2_PARAMKEY_API_FEATURES)
+            .withConstValue(new C2ApiFeaturesSetting(C2Config::api_feature_t(
+                    API_REFLECTION |
+                    API_VALUES |
+                    API_CURRENT_VALUES |
+                    API_DEPENDENCY |
+                    API_SAME_INPUT_BUFFER)))
+            .build());
+
+    addParameter(
             DefineParam(mName, C2_PARAMKEY_COMPONENT_NAME)
             .withConstValue(AllocSharedString<C2ComponentNameSetting>(name.c_str()))
             .build());
@@ -305,7 +315,6 @@
     Clients need to handle the following base params due to custom dependency.
 
     std::shared_ptr<C2ApiLevelSetting> mApiLevel;
-    std::shared_ptr<C2ApiFeaturesSetting> mApiFeatures;
     std::shared_ptr<C2ComponentAttributesSetting> mAttrib;
 
     std::shared_ptr<C2PortSuggestedBufferCountTuning::input> mSuggestedInputBufferCount;
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index 74e105e..7e9090f 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -460,8 +460,8 @@
 
     const C2ConstGraphicBlock inBuffer =
         inputBuffer->data().graphicBlocks().front();
-    if (inBuffer.width() != mSize->width ||
-        inBuffer.height() != mSize->height) {
+    if (inBuffer.width() < mSize->width ||
+        inBuffer.height() < mSize->height) {
         ALOGE("unexpected Input buffer attributes %d(%d) x %d(%d)",
               inBuffer.width(), mSize->width, inBuffer.height(),
               mSize->height);
@@ -472,8 +472,8 @@
     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
     vpx_image_t raw_frame;
     const C2PlanarLayout &layout = rView->layout();
-    uint32_t width = rView->width();
-    uint32_t height = rView->height();
+    uint32_t width = mSize->width;
+    uint32_t height = mSize->height;
     if (width > 0x8000 || height > 0x8000) {
         ALOGE("Image too big: %u x %u", width, height);
         work->result = C2_BAD_VALUE;
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 05e086f..70171fd 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1958,11 +1958,98 @@
             inputSurface->getHalInterface()));
 }
 
-static void MaybeLogUnrecognizedName(const char *func, const std::string &name) {
-    thread_local std::set<std::string> sLogged{};
-    if (sLogged.insert(name).second) {
-        ALOGW("%s: Unrecognized interface name: %s", func, name.c_str());
+class IntfCache {
+public:
+    IntfCache() = default;
+
+    status_t init(const std::string &name) {
+        std::shared_ptr<Codec2Client::Interface> intf{
+            Codec2Client::CreateInterfaceByName(name.c_str())};
+        if (!intf) {
+            ALOGW("IntfCache [%s]: Unrecognized interface name", name.c_str());
+            mInitStatus = NO_INIT;
+            return NO_INIT;
+        }
+        const static C2StreamUsageTuning::input sUsage{0u /* stream id */};
+        mFields.push_back(C2FieldSupportedValuesQuery::Possible(
+                C2ParamField{&sUsage, &sUsage.value}));
+        c2_status_t err = intf->querySupportedValues(mFields, C2_MAY_BLOCK);
+        if (err != C2_OK) {
+            ALOGW("IntfCache [%s]: failed to query usage supported value (err=%d)",
+                    name.c_str(), err);
+            mFields[0].status = err;
+        }
+        std::vector<std::unique_ptr<C2Param>> params;
+        err = intf->query(
+                {&mApiFeatures},
+                {C2PortAllocatorsTuning::input::PARAM_TYPE},
+                C2_MAY_BLOCK,
+                &params);
+        if (err != C2_OK && err != C2_BAD_INDEX) {
+            ALOGW("IntfCache [%s]: failed to query api features (err=%d)",
+                    name.c_str(), err);
+        }
+        while (!params.empty()) {
+            C2Param *param = params.back().release();
+            params.pop_back();
+            if (!param) {
+                continue;
+            }
+            if (param->type() == C2PortAllocatorsTuning::input::PARAM_TYPE) {
+                mInputAllocators.reset(
+                        C2PortAllocatorsTuning::input::From(params[0].get()));
+            }
+        }
+        mInitStatus = OK;
+        return OK;
     }
+
+    status_t initCheck() const { return mInitStatus; }
+
+    const C2FieldSupportedValuesQuery &getUsageSupportedValues() const {
+        CHECK_EQ(1u, mFields.size());
+        return mFields[0];
+    }
+
+    const C2ApiFeaturesSetting &getApiFeatures() const {
+        return mApiFeatures;
+    }
+
+    const C2PortAllocatorsTuning::input &getInputAllocators() const {
+        static std::unique_ptr<C2PortAllocatorsTuning::input> sInvalidated = []{
+            std::unique_ptr<C2PortAllocatorsTuning::input> param =
+                C2PortAllocatorsTuning::input::AllocUnique(0);
+            param->invalidate();
+            return param;
+        }();
+        return mInputAllocators ? *mInputAllocators : *sInvalidated;
+    }
+
+private:
+    status_t mInitStatus{NO_INIT};
+
+    std::vector<C2FieldSupportedValuesQuery> mFields;
+    C2ApiFeaturesSetting mApiFeatures;
+    std::unique_ptr<C2PortAllocatorsTuning::input> mInputAllocators;
+};
+
+static const IntfCache &GetIntfCache(const std::string &name) {
+    static IntfCache sNullIntfCache;
+    static std::mutex sMutex;
+    static std::map<std::string, IntfCache> sCache;
+    std::unique_lock<std::mutex> lock{sMutex};
+    auto it = sCache.find(name);
+    if (it == sCache.end()) {
+        lock.unlock();
+        IntfCache intfCache;
+        status_t err = intfCache.init(name);
+        if (err != OK) {
+            return sNullIntfCache;
+        }
+        lock.lock();
+        it = sCache.insert({name, std::move(intfCache)}).first;
+    }
+    return it->second;
 }
 
 static status_t GetCommonAllocatorIds(
@@ -1980,24 +2067,16 @@
     }
     bool firstIteration = true;
     for (const std::string &name : names) {
-        std::shared_ptr<Codec2Client::Interface> intf{
-            Codec2Client::CreateInterfaceByName(name.c_str())};
-        if (!intf) {
-            MaybeLogUnrecognizedName(__FUNCTION__, name);
+        const IntfCache &intfCache = GetIntfCache(name);
+        if (intfCache.initCheck() != OK) {
             continue;
         }
-        std::vector<std::unique_ptr<C2Param>> params;
-        c2_status_t err = intf->query(
-                {}, {C2PortAllocatorsTuning::input::PARAM_TYPE}, C2_MAY_BLOCK, &params);
+        const C2PortAllocatorsTuning::input &allocators = intfCache.getInputAllocators();
         if (firstIteration) {
             firstIteration = false;
-            if (err == C2_OK && params.size() == 1u) {
-                C2PortAllocatorsTuning::input *allocators =
-                    C2PortAllocatorsTuning::input::From(params[0].get());
-                if (allocators && allocators->flexCount() > 0) {
-                    ids->insert(allocators->m.values,
-                                allocators->m.values + allocators->flexCount());
-                }
+            if (allocators && allocators.flexCount() > 0) {
+                ids->insert(allocators.m.values,
+                            allocators.m.values + allocators.flexCount());
             }
             if (ids->empty()) {
                 // The component does not advertise allocators. Use default.
@@ -2006,24 +2085,20 @@
             continue;
         }
         bool filtered = false;
-        if (err == C2_OK && params.size() == 1u) {
-            C2PortAllocatorsTuning::input *allocators =
-                C2PortAllocatorsTuning::input::From(params[0].get());
-            if (allocators && allocators->flexCount() > 0) {
-                filtered = true;
-                for (auto it = ids->begin(); it != ids->end(); ) {
-                    bool found = false;
-                    for (size_t j = 0; j < allocators->flexCount(); ++j) {
-                        if (allocators->m.values[j] == *it) {
-                            found = true;
-                            break;
-                        }
+        if (allocators && allocators.flexCount() > 0) {
+            filtered = true;
+            for (auto it = ids->begin(); it != ids->end(); ) {
+                bool found = false;
+                for (size_t j = 0; j < allocators.flexCount(); ++j) {
+                    if (allocators.m.values[j] == *it) {
+                        found = true;
+                        break;
                     }
-                    if (found) {
-                        ++it;
-                    } else {
-                        it = ids->erase(it);
-                    }
+                }
+                if (found) {
+                    ++it;
+                } else {
+                    it = ids->erase(it);
                 }
             }
         }
@@ -2055,23 +2130,16 @@
     *minUsage = 0;
     *maxUsage = ~0ull;
     for (const std::string &name : names) {
-        std::shared_ptr<Codec2Client::Interface> intf{
-            Codec2Client::CreateInterfaceByName(name.c_str())};
-        if (!intf) {
-            MaybeLogUnrecognizedName(__FUNCTION__, name);
+        const IntfCache &intfCache = GetIntfCache(name);
+        if (intfCache.initCheck() != OK) {
             continue;
         }
-        std::vector<C2FieldSupportedValuesQuery> fields;
-        fields.push_back(C2FieldSupportedValuesQuery::Possible(
-                C2ParamField{&sUsage, &sUsage.value}));
-        c2_status_t err = intf->querySupportedValues(fields, C2_MAY_BLOCK);
-        if (err != C2_OK) {
+        const C2FieldSupportedValuesQuery &usageSupportedValues =
+            intfCache.getUsageSupportedValues();
+        if (usageSupportedValues.status != C2_OK) {
             continue;
         }
-        if (fields[0].status != C2_OK) {
-            continue;
-        }
-        const C2FieldSupportedValues &supported = fields[0].values;
+        const C2FieldSupportedValues &supported = usageSupportedValues.values;
         if (supported.type != C2FieldSupportedValues::FLAGS) {
             continue;
         }
@@ -2092,6 +2160,17 @@
 // static
 status_t CCodec::CanFetchLinearBlock(
         const std::vector<std::string> &names, const C2MemoryUsage &usage, bool *isCompatible) {
+    for (const std::string &name : names) {
+        const IntfCache &intfCache = GetIntfCache(name);
+        if (intfCache.initCheck() != OK) {
+            continue;
+        }
+        const C2ApiFeaturesSetting &features = intfCache.getApiFeatures();
+        if (features && !(features.value & API_SAME_INPUT_BUFFER)) {
+            *isCompatible = false;
+            return OK;
+        }
+    }
     uint64_t minUsage = usage.expected;
     uint64_t maxUsage = ~0ull;
     std::set<C2Allocator::id_t> allocators;
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 4345a9f..c07f3dc 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -916,6 +916,12 @@
 
     if (inputFormat != nullptr) {
         bool graphic = (iStreamFormat.value == C2BufferData::GRAPHIC);
+        C2Config::api_feature_t apiFeatures = C2Config::api_feature_t(
+                API_REFLECTION |
+                API_VALUES |
+                API_CURRENT_VALUES |
+                API_DEPENDENCY |
+                API_SAME_INPUT_BUFFER);
         std::shared_ptr<C2BlockPool> pool;
         {
             Mutexed<BlockPools>::Locked pools(mBlockPools);
@@ -927,14 +933,15 @@
             // query C2PortAllocatorsTuning::input from component. If an allocator ID is obtained
             // from component, create the input block pool with given ID. Otherwise, use default IDs.
             std::vector<std::unique_ptr<C2Param>> params;
-            err = mComponent->query({ },
+            C2ApiFeaturesSetting featuresSetting{apiFeatures};
+            err = mComponent->query({ &featuresSetting },
                                     { C2PortAllocatorsTuning::input::PARAM_TYPE },
                                     C2_DONT_BLOCK,
                                     &params);
             if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
                 ALOGD("[%s] Query input allocators returned %zu params => %s (%u)",
                         mName, params.size(), asString(err), err);
-            } else if (err == C2_OK && params.size() == 1) {
+            } else if (params.size() == 1) {
                 C2PortAllocatorsTuning::input *inputAllocators =
                     C2PortAllocatorsTuning::input::From(params[0].get());
                 if (inputAllocators && inputAllocators->flexCount() > 0) {
@@ -949,6 +956,9 @@
                     }
                 }
             }
+            if (featuresSetting) {
+                apiFeatures = featuresSetting.value;
+            }
 
             // TODO: use C2Component wrapper to associate this pool with ourselves
             if ((poolMask >> pools->inputAllocatorId) & 1) {
@@ -982,7 +992,10 @@
         input->numSlots = numInputSlots;
         input->extraBuffers.flush();
         input->numExtraSlots = 0u;
-        if (!buffersBoundToCodec) {
+        bool conforming = (apiFeatures & API_SAME_INPUT_BUFFER);
+        // For encrypted content, framework decrypts source buffer (ashmem) into
+        // C2Buffers. Thus non-conforming codecs can process these.
+        if (!buffersBoundToCodec && (hasCryptoOrDescrambler() || conforming)) {
             input->buffers.reset(new SlotInputBuffers(mName));
         } else if (graphic) {
             if (mInputSurface) {
diff --git a/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
index 10c0c6c..3a281ba 100644
--- a/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
@@ -19,6 +19,7 @@
 
 #include <android-base/logging.h>
 #include <media/MediaTrackTranscoder.h>
+#include <media/MediaTrackTranscoderCallback.h>
 
 namespace android {
 
diff --git a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
index f2f7810..3db7455 100644
--- a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
@@ -20,6 +20,7 @@
 #include <android-base/logging.h>
 #include <fcntl.h>
 #include <media/MediaSampleReaderNDK.h>
+#include <media/MediaSampleWriter.h>
 #include <media/MediaTranscoder.h>
 #include <media/PassthroughTrackTranscoder.h>
 #include <media/VideoTrackTranscoder.h>
@@ -92,11 +93,10 @@
         }
 
         // Transcoding is done and the callback to the client has been sent, so tear down the
-        // pipeline but do it asynchronously to avoid deadlocks. If an error occurred then
-        // automatically delete the output file.
-        const bool deleteOutputFile = status != AMEDIA_OK;
+        // pipeline but do it asynchronously to avoid deadlocks. If an error occurred, client
+        // should clean up the file.
         std::thread asyncCancelThread{
-                [self = shared_from_this(), deleteOutputFile] { self->cancel(deleteOutputFile); }};
+                [self = shared_from_this()] { self->cancel(); }};
         asyncCancelThread.detach();
     }
 }
@@ -115,6 +115,9 @@
     sendCallback(status);
 }
 
+MediaTranscoder::MediaTranscoder(const std::shared_ptr<CallbackInterface>& callbacks)
+     : mCallbacks(callbacks) {}
+
 std::shared_ptr<MediaTranscoder> MediaTranscoder::create(
         const std::shared_ptr<CallbackInterface>& callbacks,
         const std::shared_ptr<Parcel>& pausedState) {
@@ -129,15 +132,9 @@
     return std::shared_ptr<MediaTranscoder>(new MediaTranscoder(callbacks));
 }
 
-media_status_t MediaTranscoder::configureSource(const char* path) {
-    if (path == nullptr) {
-        LOG(ERROR) << "Source path cannot be null";
-        return AMEDIA_ERROR_INVALID_PARAMETER;
-    }
-
-    const int fd = open(path, O_RDONLY);
-    if (fd <= 0) {
-        LOG(ERROR) << "Unable to open source path: " << path;
+media_status_t MediaTranscoder::configureSource(int fd) {
+    if (fd < 0) {
+        LOG(ERROR) << "Invalid source fd: " << fd;
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
@@ -145,10 +142,9 @@
     lseek(fd, 0, SEEK_SET);
 
     mSampleReader = MediaSampleReaderNDK::createFromFd(fd, 0 /* offset */, fileSize);
-    close(fd);
 
     if (mSampleReader == nullptr) {
-        LOG(ERROR) << "Unable to parse source file: " << path;
+        LOG(ERROR) << "Unable to parse source fd: " << fd;
         return AMEDIA_ERROR_UNSUPPORTED;
     }
 
@@ -239,35 +235,23 @@
     return AMEDIA_OK;
 }
 
-media_status_t MediaTranscoder::configureDestination(const char* path) {
-    if (path == nullptr || strlen(path) < 1) {
-        LOG(ERROR) << "Invalid destination path: " << path;
+media_status_t MediaTranscoder::configureDestination(int fd) {
+    if (fd < 0) {
+        LOG(ERROR) << "Invalid destination fd: " << fd;
         return AMEDIA_ERROR_INVALID_PARAMETER;
-    } else if (mSampleWriter != nullptr) {
+    }
+
+    if (mSampleWriter != nullptr) {
         LOG(ERROR) << "Destination is already configured.";
         return AMEDIA_ERROR_INVALID_OPERATION;
     }
 
-    // Write-only, create file if non-existent, don't overwrite existing file.
-    static constexpr int kOpenFlags = O_WRONLY | O_CREAT | O_EXCL;
-    // User R+W permission.
-    static constexpr int kFileMode = S_IRUSR | S_IWUSR;
-
-    const int fd = open(path, kOpenFlags, kFileMode);
-    if (fd < 0) {
-        LOG(ERROR) << "Unable to open destination file \"" << path << "\" for writing: " << fd;
-        return AMEDIA_ERROR_INVALID_PARAMETER;
-    }
-
-    mDestinationPath = std::string(path);
-
     mSampleWriter = std::make_unique<MediaSampleWriter>();
     const bool initOk = mSampleWriter->init(
             fd, std::bind(&MediaTranscoder::onSampleWriterFinished, this, std::placeholders::_1));
-    close(fd);
 
     if (!initOk) {
-        LOG(ERROR) << "Unable to initialize sample writer with destination path " << path;
+        LOG(ERROR) << "Unable to initialize sample writer with destination fd: " << fd;
         mSampleWriter.reset();
         return AMEDIA_ERROR_UNKNOWN;
     }
@@ -305,7 +289,7 @@
         started = transcoder->start();
         if (!started) {
             LOG(ERROR) << "Unable to start track transcoder.";
-            cancel(true);
+            cancel();
             return AMEDIA_ERROR_UNKNOWN;
         }
     }
@@ -323,7 +307,7 @@
     return AMEDIA_ERROR_UNSUPPORTED;
 }
 
-media_status_t MediaTranscoder::cancel(bool deleteDestinationFile) {
+media_status_t MediaTranscoder::cancel() {
     bool expected = false;
     if (!mCancelled.compare_exchange_strong(expected, true)) {
         // Already cancelled.
@@ -335,15 +319,6 @@
         transcoder->stop();
     }
 
-    // TODO(chz): file deletion should be done by upper level from the content URI.
-    if (deleteDestinationFile && !mDestinationPath.empty()) {
-        int error = unlink(mDestinationPath.c_str());
-        if (error) {
-            LOG(ERROR) << "Unable to delete destination file " << mDestinationPath.c_str() << ": "
-                       << error;
-            return AMEDIA_ERROR_IO;
-        }
-    }
     return AMEDIA_OK;
 }
 
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h b/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h
index a71db67..0a35a57 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h
@@ -30,28 +30,7 @@
 
 namespace android {
 
-class MediaTrackTranscoder;
-
-/** Callback interface for MediaTrackTranscoder. */
-class MediaTrackTranscoderCallback {
-public:
-    /**
-     * Called when the MediaTrackTranscoder instance have finished transcoding all media samples
-     * successfully.
-     * @param transcoder The MediaTrackTranscoder that finished the transcoding.
-     */
-    virtual void onTrackFinished(const MediaTrackTranscoder* transcoder);
-
-    /**
-     * Called when the MediaTrackTranscoder instance encountered an error it could not recover from.
-     * @param transcoder The MediaTrackTranscoder that encountered the error.
-     * @param status The non-zero error code describing the encountered error.
-     */
-    virtual void onTrackError(const MediaTrackTranscoder* transcoder, media_status_t status);
-
-protected:
-    virtual ~MediaTrackTranscoderCallback() = default;
-};
+class MediaTrackTranscoderCallback;
 
 /**
  * Base class for all track transcoders. MediaTrackTranscoder operates asynchronously on an internal
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoderCallback.h b/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoderCallback.h
new file mode 100644
index 0000000..d535ada
--- /dev/null
+++ b/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoderCallback.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_TRACK_TRANSCODER_CALLBACK_H
+#define ANDROID_MEDIA_TRACK_TRANSCODER_CALLBACK_H
+
+#include <media/NdkMediaError.h>
+
+namespace android {
+
+class MediaTrackTranscoder;
+
+/** Callback interface for MediaTrackTranscoder. */
+class MediaTrackTranscoderCallback {
+public:
+    /**
+     * Called when the MediaTrackTranscoder instance have finished transcoding all media samples
+     * successfully.
+     * @param transcoder The MediaTrackTranscoder that finished the transcoding.
+     */
+    virtual void onTrackFinished(const MediaTrackTranscoder* transcoder);
+
+    /**
+     * Called when the MediaTrackTranscoder instance encountered an error it could not recover from.
+     * @param transcoder The MediaTrackTranscoder that encountered the error.
+     * @param status The non-zero error code describing the encountered error.
+     */
+    virtual void onTrackError(const MediaTrackTranscoder* transcoder, media_status_t status);
+
+protected:
+    virtual ~MediaTrackTranscoderCallback() = default;
+};
+
+}  // namespace android
+#endif  // ANDROID_MEDIA_TRACK_TRANSCODER_CALLBACK_H
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h b/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h
index 2d18eea..72a5559 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h
@@ -19,9 +19,7 @@
 
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
-#include <media/MediaSampleReader.h>
-#include <media/MediaSampleWriter.h>
-#include <media/MediaTrackTranscoder.h>
+#include <media/MediaTrackTranscoderCallback.h>
 #include <media/NdkMediaError.h>
 #include <media/NdkMediaFormat.h>
 
@@ -31,6 +29,9 @@
 
 namespace android {
 
+class MediaSampleReader;
+class MediaSampleWriter;
+
 class MediaTranscoder : public std::enable_shared_from_this<MediaTranscoder>,
                         public MediaTrackTranscoderCallback {
 public:
@@ -68,8 +69,8 @@
             const std::shared_ptr<CallbackInterface>& callbacks,
             const std::shared_ptr<Parcel>& pausedState = nullptr);
 
-    /** Configures source from path. */
-    media_status_t configureSource(const char* path);
+    /** Configures source from path fd. */
+    media_status_t configureSource(int fd);
 
     /** Gets the media formats of all tracks in the file. */
     std::vector<std::shared_ptr<AMediaFormat>> getTrackFormats() const;
@@ -83,8 +84,8 @@
      */
     media_status_t configureTrackFormat(size_t trackIndex, AMediaFormat* trackFormat);
 
-    /** Configures destination from path. */
-    media_status_t configureDestination(const char* path);
+    /** Configures destination from fd. */
+    media_status_t configureDestination(int fd);
 
     /** Starts transcoding. No configurations can be made once the transcoder has started. */
     media_status_t start();
@@ -105,19 +106,14 @@
     /** Resumes a paused transcoding. */
     media_status_t resume();
 
-    /** Cancels the transcoding. Once canceled the transcoding can not be restarted. returns error
-     * if file could not be deleted. */
-    media_status_t cancel(bool deleteDestinationFile = true);
+    /** Cancels the transcoding. Once canceled the transcoding can not be restarted. Client
+     * will be responsible for cleaning up the abandoned file. */
+    media_status_t cancel();
 
     virtual ~MediaTranscoder() = default;
 
 private:
-    MediaTranscoder(const std::shared_ptr<CallbackInterface>& callbacks)
-          : mCallbacks(callbacks),
-            mSampleReader(nullptr),
-            mSampleWriter(nullptr),
-            mSourceTrackFormats(),
-            mTrackTranscoders() {}
+    MediaTranscoder(const std::shared_ptr<CallbackInterface>& callbacks);
 
     // MediaTrackTranscoderCallback
     virtual void onTrackFinished(const MediaTrackTranscoder* transcoder) override;
@@ -133,7 +129,6 @@
     std::vector<std::shared_ptr<AMediaFormat>> mSourceTrackFormats;
     std::vector<std::unique_ptr<MediaTrackTranscoder>> mTrackTranscoders;
 
-    std::string mDestinationPath;
     std::atomic_bool mCallbackSent = false;
     std::atomic_bool mCancelled = false;
 };
diff --git a/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
index c4a67bb..09c24b5 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
@@ -68,6 +68,10 @@
 
 static const char* SOURCE_PATH =
         "/data/local/tmp/TranscoderTestAssets/cubicle_avc_480x240_aac_24KHz.mp4";
+// Write-only, create file if non-existent, don't overwrite existing file.
+static constexpr int kOpenFlags = O_WRONLY | O_CREAT | O_EXCL;
+// User R+W permission.
+static constexpr int kFileMode = S_IRUSR | S_IWUSR;
 
 class MediaTranscoderTests : public ::testing::Test {
 public:
@@ -92,7 +96,8 @@
         auto transcoder = MediaTranscoder::create(mCallbacks, nullptr);
         EXPECT_NE(transcoder, nullptr);
 
-        EXPECT_EQ(transcoder->configureSource(SOURCE_PATH), AMEDIA_OK);
+        const int srcFd = open(SOURCE_PATH, O_RDONLY);
+        EXPECT_EQ(transcoder->configureSource(srcFd), AMEDIA_OK);
 
         std::vector<std::shared_ptr<AMediaFormat>> trackFormats = transcoder->getTrackFormats();
         EXPECT_GT(trackFormats.size(), 0);
@@ -105,13 +110,16 @@
             }
         }
         deleteFile(destPath);
-        EXPECT_EQ(transcoder->configureDestination(destPath), AMEDIA_OK);
+        const int dstFd = open(destPath, kOpenFlags, kFileMode);
+        EXPECT_EQ(transcoder->configureDestination(dstFd), AMEDIA_OK);
 
         media_status_t startStatus = transcoder->start();
         EXPECT_EQ(startStatus, AMEDIA_OK);
         if (startStatus == AMEDIA_OK) {
             mCallbacks->waitForTranscodingFinished();
         }
+        close(srcFd);
+        close(dstFd);
 
         return mCallbacks->mStatus;
     }
diff --git a/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h b/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
index 79c227b..32a1a0a 100644
--- a/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
+++ b/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
@@ -15,6 +15,7 @@
  */
 
 #include <media/MediaTrackTranscoder.h>
+#include <media/MediaTrackTranscoderCallback.h>
 
 #include <condition_variable>
 #include <memory>
diff --git a/media/libstagefright/flac/dec/FLACDecoder.cpp b/media/libstagefright/flac/dec/FLACDecoder.cpp
index cef0bc6..f5e9532 100644
--- a/media/libstagefright/flac/dec/FLACDecoder.cpp
+++ b/media/libstagefright/flac/dec/FLACDecoder.cpp
@@ -433,7 +433,7 @@
             if (mBuffer == nullptr) {
                 mBufferDataSize = 0;
                 mBufferLen = 0;
-                ALOGE("decodeOneFrame: failed to allocate memory for input buffer");
+                ALOGE("addDataToBuffer: failed to allocate memory for input buffer");
                 return NO_MEMORY;
             }
             mBufferLen = mBufferDataSize + inBufferLen;