1 /*
2  * Copyright (C) 2017 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 "NativeMediaEnc-Source"
19 #include <log/log.h>
20 
21 #include "native_media_source.h"
22 
23 using namespace Utils;
24 
25 class DecoderSource : public Thread, public Source {
26 public:
27     DecoderSource(
28         int32_t w, int32_t h, int32_t colorFormat, float fps, bool looping, bool regulate);
29     ~DecoderSource();
30     DecoderSource(const DecoderSource& ) = delete;
31 
32     Status setDataSourceFd(int sourceFileFd, off64_t sourceFileOffset, off64_t sourceFileSize);
33     Status prepare(std::shared_ptr<Listener> l, std::shared_ptr<ANativeWindow> n) override;
34     Status start() override;
35     Status stop() override;
36 
37 protected:
38     void run() override;
39 
40 private:
41     // seek the extractor back to beginning
42     void rewindExtractor();
43 
44     // When setting dynamic params, if the source is faster than the encoder,
45     // there is a possibility of param set via setParameters() will get delayed.
46     // Simulate a real-time source by slowing down the feeding rate (up to configured fps)
47     bool mRegulateFramerate;
48 
49     std::shared_ptr<AMediaExtractor> mEx;
50     std::shared_ptr<AMediaCodec> mDec;
51     std::shared_ptr<AMediaFormat> mFormat;
52     std::string mMime;
53     int mVideoTrackIndex;
54     int mFrameCount;
55     bool mStopRequest;
56     bool mStarted;
57 };
58 
createDecoderSource(int32_t w,int32_t h,int32_t colorFormat,float fps,bool looping,bool regulateFeedingRate,int sourceFileFd,off64_t sourceFileOffset,off64_t sourceFileSize)59 std::shared_ptr<Source> createDecoderSource(
60         int32_t w, int32_t h, int32_t colorFormat, float fps, bool looping,
61         bool regulateFeedingRate, /* WA for dynamic settings */
62         int sourceFileFd, off64_t sourceFileOffset, off64_t sourceFileSize) {
63     DecoderSource *d = new DecoderSource(w, h, colorFormat, fps, looping, regulateFeedingRate);
64     d->setDataSourceFd(sourceFileFd, sourceFileOffset, sourceFileSize);
65     std::shared_ptr<Source> src(d);
66     return src;
67 }
68 
DecoderSource(int32_t w,int32_t h,int32_t colorFormat,float fps,bool looping,bool regulate)69 DecoderSource::DecoderSource(
70         int32_t w, int32_t h, int32_t colorFormat, float fps, bool looping, bool regulate)
71     : Source(w, h, colorFormat, fps, looping),
72       mRegulateFramerate(regulate),
73       mEx(nullptr),
74       mDec(nullptr),
75       mFormat(nullptr),
76       mMime(""),
77       mVideoTrackIndex(-1),
78       mFrameCount(0),
79       mStopRequest(false),
80       mStarted(false) {
81 }
82 
setDataSourceFd(int sourceFileFd,off64_t sourceFileOffset,off64_t sourceFileSize)83 Status DecoderSource::setDataSourceFd(
84         int sourceFileFd, off64_t sourceFileOffset, off64_t sourceFileSize) {
85 
86     mEx = std::shared_ptr<AMediaExtractor>(AMediaExtractor_new(), deleter_AMediExtractor);
87     int err = AMediaExtractor_setDataSourceFd(mEx.get(), sourceFileFd, sourceFileOffset, sourceFileSize);
88     if (err != 0) {
89         ALOGE("setDataSource error: %d", err);
90         return FAIL;
91     }
92 
93     const char *mime;
94     mVideoTrackIndex = -1;
95     int numtracks = AMediaExtractor_getTrackCount(mEx.get());
96     for (int i = 0; i < numtracks; i++) {
97         AMediaFormat *format = AMediaExtractor_getTrackFormat(mEx.get(), i);
98         const char *s = AMediaFormat_toString(format);
99         ALOGV("track %d format: %s", i, s);
100         if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
101             ALOGE("no mime type");
102             mEx = nullptr;
103             AMediaFormat_delete(format);
104             return FAIL;
105         } else if (!strncmp(mime, "video/", 6)) {
106             mVideoTrackIndex = i;
107             mFormat = std::shared_ptr<AMediaFormat>(format, deleter_AMediaFormat);
108             mMime = mime;
109             break;
110         } else {
111             ALOGE("expected video mime type, got %s", mime);
112             mEx = nullptr;
113         }
114         AMediaFormat_delete(format);
115     }
116     return mVideoTrackIndex == -1 ? FAIL : OK;
117 }
118 
~DecoderSource()119 DecoderSource::~DecoderSource() {
120     mDec = nullptr;
121     mEx = nullptr;
122     mFormat = nullptr;
123 }
124 
run()125 void DecoderSource::run() {
126     while(!mStopRequest) {
127         int t = AMediaExtractor_getSampleTrackIndex(mEx.get());
128         if (t < 0) {
129             if (mLooping) {
130                 rewindExtractor();
131                 continue;
132             } else {
133                 ALOGV("no more samples");
134                 break;
135             }
136         } else if (t != mVideoTrackIndex) {
137             continue;
138         }
139 
140         ssize_t bufidx = AMediaCodec_dequeueInputBuffer(mDec.get(), 5000);
141         if (bufidx >= 0) {
142             size_t bufsize;
143             uint8_t *buf = AMediaCodec_getInputBuffer(mDec.get(), bufidx, &bufsize);
144             int sampleSize = AMediaExtractor_readSampleData(mEx.get(), buf, bufsize);
145             int32_t flags = 0;
146             if (sampleSize < 0) {
147                 if (mLooping) {
148                     rewindExtractor();
149                     continue;
150                 } else {
151                     flags = AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
152                 }
153             }
154             // synthesize timestamps based on required fps
155             int64_t timeStampUs = 1e6 / mFps * mFrameCount;
156             AMediaCodec_queueInputBuffer(mDec.get(), bufidx, 0, sampleSize, timeStampUs, flags);
157 
158             AMediaExtractor_advance(mEx.get());
159             ++mFrameCount;
160         }
161 
162         AMediaCodecBufferInfo info;
163         int status = AMediaCodec_dequeueOutputBuffer(mDec.get(), &info, 1000);
164         if (status >= 0) {
165             ALOGV("got decoded buffer of size=%d @%lld us",
166                     info.size, (long long)info.presentationTimeUs);
167             bool render = info.size > 0;
168             if (mBufListener != nullptr) {
169                 //TBD
170                 //mBufListener->onBufferAvailable(..);
171             }
172 
173             // WA: if decoder runs free, dynamic settings applied by
174             //     MediaCodec.setParameters() are off
175             if (mRegulateFramerate) {
176                 usleep(1e6/mFps);
177             }
178 
179             AMediaCodec_releaseOutputBuffer(mDec.get(), status, render);
180 
181             if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
182                 ALOGV("saw EOS");
183                 break;
184             }
185 
186         } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
187         } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
188             mFormat = std::shared_ptr<AMediaFormat>(
189                     AMediaCodec_getOutputFormat(mDec.get()), deleter_AMediaFormat);
190             ALOGV("format changed: %s", AMediaFormat_toString(mFormat.get()));
191         } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
192         } else {
193             ALOGV("Invalid status : %d", status);
194         }
195     }
196 }
197 
prepare(std::shared_ptr<Listener> l,std::shared_ptr<ANativeWindow> n)198 Status DecoderSource::prepare(
199         std::shared_ptr<Listener> l, std::shared_ptr<ANativeWindow> n) {
200 
201     mBufListener = l;
202     mSurface = n;
203 
204     if (mVideoTrackIndex < 0) {
205         ALOGE("Video track not found !");
206         return FAIL;
207     }
208 
209     assert(mEx.get() != nullptr);
210     AMediaExtractor_selectTrack(mEx.get(), mVideoTrackIndex);
211 
212     AMediaCodec *dec = AMediaCodec_createDecoderByType(mMime.c_str());
213     mDec = std::shared_ptr<AMediaCodec>(dec, deleter_AMediaCodec);
214 
215     ALOGI("configure decoder. surface = %p", mSurface.get());
216     media_status_t status = AMediaCodec_configure(
217             mDec.get(), mFormat.get(), mSurface.get(), NULL /* crypto */, 0);
218     if (status != AMEDIA_OK) {
219         ALOGE("failed to configure decoder");
220         return FAIL;
221     }
222     return OK;
223 }
224 
start()225 Status DecoderSource::start() {
226     ALOGV("start");
227     media_status_t status = AMediaCodec_start(mDec.get());
228     if (status != AMEDIA_OK) {
229         ALOGE("failed to start decoder");
230         return FAIL;
231     }
232     if (startThread() != OK) {
233         return FAIL;
234     }
235     mStarted = true;
236     return OK;
237 }
238 
stop()239 Status DecoderSource::stop() {
240     if (!mStarted) {
241         return FAIL;
242     }
243 
244     ALOGV("Stopping decoder source..");
245     mStopRequest = true;
246     joinThread();
247 
248     media_status_t status = AMediaCodec_stop(mDec.get());
249     if (status != AMEDIA_OK) {
250         ALOGE("failed to stop decoder");
251     }
252 
253     mDec = nullptr;
254     mEx = nullptr;
255     mFormat = nullptr;
256     return OK;
257 }
258 
rewindExtractor()259 void DecoderSource::rewindExtractor() {
260     assert(mEx.get() != nullptr);
261     media_status_t status = AMediaExtractor_seekTo(mEx.get(), 0, AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC);
262     if (status != AMEDIA_OK) {
263         ALOGE("failed to seek Extractor to 0");
264     }
265 }
266 
267