• 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 #ifndef ANDROID_MEDIA_TRACK_TRANSCODER_H
18 #define ANDROID_MEDIA_TRACK_TRANSCODER_H
19 
20 #include <media/MediaSampleQueue.h>
21 #include <media/MediaSampleReader.h>
22 #include <media/MediaSampleWriter.h>
23 #include <media/NdkMediaError.h>
24 #include <media/NdkMediaFormat.h>
25 #include <utils/Mutex.h>
26 
27 #include <functional>
28 #include <memory>
29 #include <mutex>
30 #include <thread>
31 
32 namespace android {
33 
34 class MediaTrackTranscoderCallback;
35 
36 /**
37  * Base class for all track transcoders. MediaTrackTranscoder operates asynchronously on an internal
38  * thread and communicates through a MediaTrackTranscoderCallback instance. Transcoded samples are
39  * enqueued on the MediaTrackTranscoder's output queue. Samples need to be dequeued from the output
40  * queue or the transcoder will run out of buffers and stall. Once the consumer is done with a
41  * transcoded sample it is the consumer's responsibility to as soon as possible release all
42  * references to that sample in order to return the buffer to the transcoder. MediaTrackTranscoder
43  * is an abstract class and instances are created through one of the concrete subclasses.
44  *
45  * The base class MediaTrackTranscoder is responsible for thread and state management and guarantees
46  * that operations {configure, start, stop} are sent to the derived class in correct order.
47  * MediaTrackTranscoder is also responsible for delivering callback notifications once the
48  * transcoder has been successfully started.
49  */
50 class MediaTrackTranscoder {
51 public:
52     /**
53      * Configures the track transcoder with an input MediaSampleReader and a destination format.
54      * A track transcoder have to be configured before it is started.
55      * @param mediaSampleReader The MediaSampleReader to read input samples from.
56      * @param trackIndex The index of the track to transcode in mediaSampleReader.
57      * @param destinationFormat The destination format.
58      * @return AMEDIA_OK if the track transcoder was successfully configured.
59      */
60     media_status_t configure(const std::shared_ptr<MediaSampleReader>& mediaSampleReader,
61                              int trackIndex,
62                              const std::shared_ptr<AMediaFormat>& destinationFormat);
63 
64     /**
65      * Starts the track transcoder. After the track transcoder is successfully started it will run
66      * until a callback signals that transcoding has ended. Start should only be called once.
67      * @return True if the track transcoder started, or false if it had already been started.
68      */
69     bool start();
70 
71     /**
72      * Stops the track transcoder. Once the transcoding has been stopped it cannot be restarted
73      * again. It is safe to call stop multiple times. Stop is an asynchronous operation. Once the
74      * track transcoder has stopped the onTrackStopped callback will get called, unless the
75      * transcoding finished or encountered an error before it could be stopped in which case the
76      * callbacks corresponding to those events will be called instead.
77      * @param stopOnSyncSample Request the transcoder to stop after emitting a sync sample.
78      */
79     void stop(bool stopOnSyncSample = false);
80 
81     /**
82      * Set the sample consumer function. The MediaTrackTranscoder will deliver transcoded samples to
83      * this function. If the MediaTrackTranscoder is started before a consumer is set the transcoder
84      * will buffer a limited number of samples internally before stalling. Once a consumer has been
85      * set the internally buffered samples will be delivered to the consumer.
86      * @param sampleConsumer The sample consumer function.
87      */
88     void setSampleConsumer(const MediaSampleWriter::MediaSampleConsumerFunction& sampleConsumer);
89 
90     /**
91       * Retrieves the track transcoder's final output format. The output is available after the
92       * track transcoder has been successfully configured.
93       * @return The track output format.
94       */
95     virtual std::shared_ptr<AMediaFormat> getOutputFormat() const = 0;
96 
97     virtual ~MediaTrackTranscoder() = default;
98 
99 protected:
MediaTrackTranscoder(const std::weak_ptr<MediaTrackTranscoderCallback> & transcoderCallback)100     MediaTrackTranscoder(const std::weak_ptr<MediaTrackTranscoderCallback>& transcoderCallback)
101           : mTranscoderCallback(transcoderCallback){};
102 
103     // Called by subclasses when the actual track format becomes available.
104     void notifyTrackFormatAvailable();
105 
106     // Called by subclasses when a transcoded sample is available. Samples must not hold a strong
107     // reference to the track transcoder in order to avoid retain cycles through the track
108     // transcoder's sample queue.
109     void onOutputSampleAvailable(const std::shared_ptr<MediaSample>& sample);
110 
111     // configureDestinationFormat needs to be implemented by subclasses, and gets called on an
112     // external thread before start.
113     virtual media_status_t configureDestinationFormat(
114             const std::shared_ptr<AMediaFormat>& destinationFormat) = 0;
115 
116     // runTranscodeLoop needs to be implemented by subclasses, and gets called on
117     // MediaTrackTranscoder's internal thread when the track transcoder is started.
118     virtual media_status_t runTranscodeLoop(bool* stopped) = 0;
119 
120     // abortTranscodeLoop needs to be implemented by subclasses, and should request transcoding to
121     // be aborted as soon as possible. It should be safe to call abortTranscodeLoop multiple times.
122     virtual void abortTranscodeLoop() = 0;
123 
124     std::shared_ptr<MediaSampleReader> mMediaSampleReader;
125     int mTrackIndex;
126     std::shared_ptr<AMediaFormat> mSourceFormat;
127 
128     enum StopRequest {
129         NONE,
130         STOP_NOW,
131         STOP_ON_SYNC,
132     };
133     std::atomic<StopRequest> mStopRequest = NONE;
134 
135 private:
136     std::mutex mSampleMutex;
137     // SampleQueue for buffering output samples before a sample consumer has been set.
138     MediaSampleQueue mSampleQueue GUARDED_BY(mSampleMutex);
139     MediaSampleWriter::MediaSampleConsumerFunction mSampleConsumer GUARDED_BY(mSampleMutex);
140     const std::weak_ptr<MediaTrackTranscoderCallback> mTranscoderCallback;
141     std::mutex mStateMutex;
142     enum {
143         UNINITIALIZED,
144         CONFIGURED,
145         STARTED,
146         STOPPED,
147     } mState GUARDED_BY(mStateMutex) = UNINITIALIZED;
148 };
149 
150 }  // namespace android
151 #endif  // ANDROID_MEDIA_TRACK_TRANSCODER_H
152