1 /* 2 * Copyright (C) 2012 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 #include "MP4Source.h" 18 19 #include "FragmentedMP4Parser.h" 20 #include "../NuPlayerStreamListener.h" 21 22 #include <media/IStreamSource.h> 23 #include <media/stagefright/foundation/AMessage.h> 24 #include <media/stagefright/MediaErrors.h> 25 #include <media/stagefright/MetaData.h> 26 27 namespace android { 28 29 struct StreamSource : public FragmentedMP4Parser::Source { 30 StreamSource(const sp<IStreamSource> &source) 31 : mListener(new NuPlayer::NuPlayerStreamListener(source, 0)), 32 mPosition(0) { 33 mListener->start(); 34 } 35 36 virtual ssize_t readAt(off64_t offset, void *data, size_t size) { 37 if (offset < mPosition) { 38 return -EPIPE; 39 } 40 41 while (offset > mPosition) { 42 char buffer[1024]; 43 off64_t skipBytes = offset - mPosition; 44 if (skipBytes > sizeof(buffer)) { 45 skipBytes = sizeof(buffer); 46 } 47 48 sp<AMessage> extra; 49 ssize_t n; 50 for (;;) { 51 n = mListener->read(buffer, skipBytes, &extra); 52 53 if (n == -EWOULDBLOCK) { 54 usleep(10000); 55 continue; 56 } 57 58 break; 59 } 60 61 ALOGV("skipped %ld bytes at offset %lld", n, mPosition); 62 63 if (n < 0) { 64 return n; 65 } 66 67 mPosition += n; 68 } 69 70 sp<AMessage> extra; 71 size_t total = 0; 72 while (total < size) { 73 ssize_t n = mListener->read( 74 (uint8_t *)data + total, size - total, &extra); 75 76 if (n == -EWOULDBLOCK) { 77 usleep(10000); 78 continue; 79 } else if (n == 0) { 80 break; 81 } else if (n < 0) { 82 mPosition += total; 83 return n; 84 } 85 86 total += n; 87 } 88 89 ALOGV("read %ld bytes at offset %lld", n, mPosition); 90 91 mPosition += total; 92 93 return total; 94 } 95 96 bool isSeekable() { 97 return false; 98 } 99 100 private: 101 sp<NuPlayer::NuPlayerStreamListener> mListener; 102 off64_t mPosition; 103 104 DISALLOW_EVIL_CONSTRUCTORS(StreamSource); 105 }; 106 107 MP4Source::MP4Source( 108 const sp<AMessage> ¬ify, const sp<IStreamSource> &source) 109 : Source(notify), 110 mSource(source), 111 mLooper(new ALooper), 112 mParser(new FragmentedMP4Parser), 113 mEOS(false) { 114 mLooper->registerHandler(mParser); 115 } 116 117 MP4Source::~MP4Source() { 118 } 119 120 void MP4Source::prepareAsync() { 121 notifyVideoSizeChanged(0, 0); 122 notifyFlagsChanged(0); 123 notifyPrepared(); 124 } 125 126 void MP4Source::start() { 127 mLooper->start(false /* runOnCallingThread */); 128 mParser->start(new StreamSource(mSource)); 129 } 130 131 status_t MP4Source::feedMoreTSData() { 132 return mEOS ? ERROR_END_OF_STREAM : (status_t)OK; 133 } 134 135 sp<AMessage> MP4Source::getFormat(bool audio) { 136 return mParser->getFormat(audio); 137 } 138 139 status_t MP4Source::dequeueAccessUnit( 140 bool audio, sp<ABuffer> *accessUnit) { 141 return mParser->dequeueAccessUnit(audio, accessUnit); 142 } 143 144 } // namespace android 145