/* * 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 #include #include #include #include #include #include #include #include #include #include namespace android { class MediaSampleReader; class MediaTranscoder : public std::enable_shared_from_this, 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& 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 create( const std::shared_ptr& callbacks, int64_t heartBeatIntervalUs = -1, pid_t pid = AMEDIACODEC_CALLING_PID, uid_t uid = AMEDIACODEC_CALLING_UID, const std::shared_ptr& 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> 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* 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& 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 mCallbacks; std::shared_ptr mSampleReader; std::shared_ptr mSampleWriter; std::vector> mSourceTrackFormats; std::vector> mTrackTranscoders; std::mutex mTracksAddedMutex; std::unordered_set 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 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