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 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 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 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 119 DecoderSource::~DecoderSource() { 120 mDec = nullptr; 121 mEx = nullptr; 122 mFormat = nullptr; 123 } 124 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 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 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 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 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