• 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 // #define LOG_NDEBUG 0
18 #define LOG_TAG "MediaTrackTranscoder"
19 
20 #include <android-base/logging.h>
21 #include <media/MediaTrackTranscoder.h>
22 #include <media/MediaTrackTranscoderCallback.h>
23 #include <utils/AndroidThreads.h>
24 
25 namespace android {
26 
configure(const std::shared_ptr<MediaSampleReader> & mediaSampleReader,int trackIndex,const std::shared_ptr<AMediaFormat> & destinationFormat)27 media_status_t MediaTrackTranscoder::configure(
28         const std::shared_ptr<MediaSampleReader>& mediaSampleReader, int trackIndex,
29         const std::shared_ptr<AMediaFormat>& destinationFormat) {
30     std::scoped_lock lock{mStateMutex};
31 
32     if (mState != UNINITIALIZED) {
33         LOG(ERROR) << "Configure can only be called once";
34         return AMEDIA_ERROR_UNSUPPORTED;
35     }
36 
37     if (mediaSampleReader == nullptr) {
38         LOG(ERROR) << "MediaSampleReader is null";
39         return AMEDIA_ERROR_INVALID_PARAMETER;
40     }
41     if (trackIndex < 0 || trackIndex >= mediaSampleReader->getTrackCount()) {
42         LOG(ERROR) << "TrackIndex is invalid " << trackIndex;
43         return AMEDIA_ERROR_INVALID_PARAMETER;
44     }
45 
46     mMediaSampleReader = mediaSampleReader;
47     mTrackIndex = trackIndex;
48 
49     mSourceFormat = std::shared_ptr<AMediaFormat>(mMediaSampleReader->getTrackFormat(mTrackIndex),
50                                                   &AMediaFormat_delete);
51     if (mSourceFormat == nullptr) {
52         LOG(ERROR) << "Unable to get format for track #" << mTrackIndex;
53         return AMEDIA_ERROR_MALFORMED;
54     }
55 
56     media_status_t status = configureDestinationFormat(destinationFormat);
57     if (status != AMEDIA_OK) {
58         LOG(ERROR) << "configure failed with error " << status;
59         return status;
60     }
61 
62     mState = CONFIGURED;
63     return AMEDIA_OK;
64 }
65 
start()66 bool MediaTrackTranscoder::start() {
67     std::scoped_lock lock{mStateMutex};
68 
69     if (mState != CONFIGURED) {
70         LOG(ERROR) << "TrackTranscoder must be configured before started";
71         return false;
72     }
73     mState = STARTED;
74 
75     std::thread([this] {
76         androidSetThreadPriority(0 /* tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
77         bool stopped = false;
78         media_status_t status = runTranscodeLoop(&stopped);
79 
80         // Output an EOS sample if the transcoder was stopped.
81         if (stopped) {
82             auto sample = std::make_shared<MediaSample>();
83             sample->info.flags = SAMPLE_FLAG_END_OF_STREAM;
84             onOutputSampleAvailable(sample);
85         }
86 
87         // Notify the client.
88         if (auto callbacks = mTranscoderCallback.lock()) {
89             if (stopped) {
90                 callbacks->onTrackStopped(this);
91             } else if (status == AMEDIA_OK) {
92                 callbacks->onTrackFinished(this);
93             } else {
94                 callbacks->onTrackError(this, status);
95             }
96         }
97     }).detach();
98 
99     return true;
100 }
101 
stop(bool stopOnSyncSample)102 void MediaTrackTranscoder::stop(bool stopOnSyncSample) {
103     std::scoped_lock lock{mStateMutex};
104 
105     if (mState == STARTED || (mStopRequest == STOP_ON_SYNC && !stopOnSyncSample)) {
106         mStopRequest = stopOnSyncSample ? STOP_ON_SYNC : STOP_NOW;
107         abortTranscodeLoop();
108         mState = STOPPED;
109     } else {
110         LOG(WARNING) << "TrackTranscoder must be started before stopped";
111     }
112 }
113 
notifyTrackFormatAvailable()114 void MediaTrackTranscoder::notifyTrackFormatAvailable() {
115     if (auto callbacks = mTranscoderCallback.lock()) {
116         callbacks->onTrackFormatAvailable(this);
117     }
118 }
119 
onOutputSampleAvailable(const std::shared_ptr<MediaSample> & sample)120 void MediaTrackTranscoder::onOutputSampleAvailable(const std::shared_ptr<MediaSample>& sample) {
121     std::scoped_lock lock{mSampleMutex};
122     if (mSampleConsumer == nullptr) {
123         mSampleQueue.enqueue(sample);
124     } else {
125         mSampleConsumer(sample);
126     }
127 }
128 
setSampleConsumer(const MediaSampleWriter::MediaSampleConsumerFunction & sampleConsumer)129 void MediaTrackTranscoder::setSampleConsumer(
130         const MediaSampleWriter::MediaSampleConsumerFunction& sampleConsumer) {
131     std::scoped_lock lock{mSampleMutex};
132     mSampleConsumer = sampleConsumer;
133 
134     std::shared_ptr<MediaSample> sample;
135     while (!mSampleQueue.isEmpty() && !mSampleQueue.dequeue(&sample)) {
136         mSampleConsumer(sample);
137     }
138 }
139 
140 }  // namespace android
141