blob: 8776dc92ef35c66258f109965b60537a755d2782 [file] [log] [blame]
/*
* 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_TRANSCODER_H
#define ANDROID_MEDIA_TRANSCODER_H
#include <android/binder_auto_utils.h>
#include <media/MediaSampleWriter.h>
#include <media/MediaTrackTranscoderCallback.h>
#include <media/NdkMediaCodecPlatform.h>
#include <media/NdkMediaError.h>
#include <media/NdkMediaFormat.h>
#include <utils/Mutex.h>
#include <atomic>
#include <memory>
#include <mutex>
#include <unordered_set>
namespace android {
class MediaSampleReader;
class MediaTranscoder : public std::enable_shared_from_this<MediaTranscoder>,
public MediaTrackTranscoderCallback,
public MediaSampleWriter::CallbackInterface {
public:
/** Callbacks from transcoder to client. */
class CallbackInterface {
public:
/** Transcoder finished successfully. */
virtual void onFinished(const MediaTranscoder* transcoder) = 0;
/** Transcoder encountered an unrecoverable error. */
virtual void onError(const MediaTranscoder* transcoder, media_status_t error) = 0;
/** Transcoder progress update reported in percent from 0 to 100. */
virtual void onProgressUpdate(const MediaTranscoder* transcoder, int32_t progress) = 0;
/** Transcoder heart-beat signal. */
virtual void onHeartBeat(const MediaTranscoder* transcoder) = 0;
/**
* Transcoder lost codec resources and paused operations. The client can resume transcoding
* again when resources are available by either:
* 1) Calling resume on the same MediaTranscoder instance.
* 2) Creating a new MediaTranscoding instance with the paused state and then calling
* resume.
*/
virtual void onCodecResourceLost(
const MediaTranscoder* transcoder,
const std::shared_ptr<ndk::ScopedAParcel>& pausedState) = 0;
virtual ~CallbackInterface() = default;
};
/**
* Creates a new MediaTranscoder instance. If the supplied paused state is valid, the transcoder
* will be initialized with the paused state and be ready to be resumed right away. It is not
* possible to change any configurations on a paused transcoder.
*/
static std::shared_ptr<MediaTranscoder> create(
const std::shared_ptr<CallbackInterface>& callbacks, int64_t heartBeatIntervalUs = -1,
pid_t pid = AMEDIACODEC_CALLING_PID, uid_t uid = AMEDIACODEC_CALLING_UID,
const std::shared_ptr<ndk::ScopedAParcel>& pausedState = nullptr);
/** 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;
/**
* Configures transcoding of a track. Tracks that are not configured will not present in the
* final transcoded file, i.e. tracks will be dropped by default. Passing nullptr for
* trackFormat means the track will be copied unchanged ("passthrough") to the destination.
* Track configurations must be done after the source has been configured.
* Note: trackFormat is not modified but cannot be const.
*/
media_status_t configureTrackFormat(size_t trackIndex, AMediaFormat* trackFormat);
/** 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();
/**
* Pauses transcoding and finalizes the partial transcoded file to disk. Pause is a synchronous
* operation and will wait until all internal components are done. Once this method returns it
* is safe to release the transcoder instance. No callback will be called if the transcoder was
* paused successfully. But if the transcoding finishes or encountered an error during pause,
* the corresponding callback will be called.
*/
media_status_t pause(std::shared_ptr<ndk::ScopedAParcel>* pausedState);
/** Resumes a paused transcoding. */
media_status_t resume();
/**
* Cancels the transcoding. Once canceled the transcoding can not be restarted. Client
* will be responsible for cleaning up the abandoned file. Cancel is a synchronous operation and
* will wait until all internal components are done. Once this method returns it is safe to
* release the transcoder instance. Normally no callback will be called when the transcoder is
* cancelled. But if the transcoding finishes or encountered an error during cancel, the
* corresponding callback will be called.
*/
media_status_t cancel();
virtual ~MediaTranscoder() = default;
private:
MediaTranscoder(const std::shared_ptr<CallbackInterface>& callbacks,
int64_t heartBeatIntervalUs, pid_t pid, uid_t uid);
// MediaTrackTranscoderCallback
virtual void onTrackFormatAvailable(const MediaTrackTranscoder* transcoder) override;
virtual void onTrackFinished(const MediaTrackTranscoder* transcoder) override;
virtual void onTrackStopped(const MediaTrackTranscoder* transcoder) override;
virtual void onTrackError(const MediaTrackTranscoder* transcoder,
media_status_t status) override;
// ~MediaTrackTranscoderCallback
// MediaSampleWriter::CallbackInterface
virtual void onFinished(const MediaSampleWriter* writer, media_status_t status) override;
virtual void onStopped(const MediaSampleWriter* writer) override;
virtual void onProgressUpdate(const MediaSampleWriter* writer, int32_t progress) override;
virtual void onHeartBeat(const MediaSampleWriter* writer) override;
// ~MediaSampleWriter::CallbackInterface
void onThreadFinished(const void* thread, media_status_t threadStatus, bool threadStopped);
media_status_t requestStop(bool stopOnSync);
void waitForThreads();
std::shared_ptr<CallbackInterface> mCallbacks;
std::shared_ptr<MediaSampleReader> mSampleReader;
std::shared_ptr<MediaSampleWriter> mSampleWriter;
std::vector<std::shared_ptr<AMediaFormat>> mSourceTrackFormats;
std::vector<std::shared_ptr<MediaTrackTranscoder>> mTrackTranscoders;
std::mutex mTracksAddedMutex;
std::unordered_set<const MediaTrackTranscoder*> mTracksAdded GUARDED_BY(mTracksAddedMutex);
int64_t mHeartBeatIntervalUs;
pid_t mPid;
uid_t mUid;
enum ThreadState {
PENDING = 0, // Not yet started.
RUNNING, // Currently running.
DONE, // Done running (can be finished, stopped or error).
};
std::mutex mThreadStateMutex;
std::condition_variable mThreadsDoneSignal;
std::unordered_map<const void*, ThreadState> mThreadStates GUARDED_BY(mThreadStateMutex);
media_status_t mTranscoderStatus GUARDED_BY(mThreadStateMutex) = AMEDIA_OK;
bool mTranscoderStopped GUARDED_BY(mThreadStateMutex) = false;
bool mThreadsDone GUARDED_BY(mThreadStateMutex) = false;
bool mCallbackSent GUARDED_BY(mThreadStateMutex) = false;
bool mSampleWriterStopped GUARDED_BY(mThreadStateMutex) = false;
std::atomic_bool mCancelled = false;
};
} // namespace android
#endif // ANDROID_MEDIA_TRANSCODER_H