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 "GenericSource.h" 18 19 #include "AnotherPacketSource.h" 20 21 #include <media/stagefright/foundation/ABuffer.h> 22 #include <media/stagefright/foundation/ADebug.h> 23 #include <media/stagefright/foundation/AMessage.h> 24 #include <media/stagefright/DataSource.h> 25 #include <media/stagefright/FileSource.h> 26 #include <media/stagefright/MediaBuffer.h> 27 #include <media/stagefright/MediaDefs.h> 28 #include <media/stagefright/MediaExtractor.h> 29 #include <media/stagefright/MediaSource.h> 30 #include <media/stagefright/MetaData.h> 31 32 namespace android { 33 34 NuPlayer::GenericSource::GenericSource( 35 const char *url, 36 const KeyedVector<String8, String8> *headers, 37 bool uidValid, 38 uid_t uid) 39 : mDurationUs(0ll), 40 mAudioIsVorbis(false) { 41 DataSource::RegisterDefaultSniffers(); 42 43 sp<DataSource> dataSource = 44 DataSource::CreateFromURI(url, headers); 45 CHECK(dataSource != NULL); 46 47 initFromDataSource(dataSource); 48 } 49 50 NuPlayer::GenericSource::GenericSource( 51 int fd, int64_t offset, int64_t length) 52 : mDurationUs(0ll), 53 mAudioIsVorbis(false) { 54 DataSource::RegisterDefaultSniffers(); 55 56 sp<DataSource> dataSource = new FileSource(dup(fd), offset, length); 57 58 initFromDataSource(dataSource); 59 } 60 61 void NuPlayer::GenericSource::initFromDataSource( 62 const sp<DataSource> &dataSource) { 63 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); 64 65 CHECK(extractor != NULL); 66 67 for (size_t i = 0; i < extractor->countTracks(); ++i) { 68 sp<MetaData> meta = extractor->getTrackMetaData(i); 69 70 const char *mime; 71 CHECK(meta->findCString(kKeyMIMEType, &mime)); 72 73 sp<MediaSource> track; 74 75 if (!strncasecmp(mime, "audio/", 6)) { 76 if (mAudioTrack.mSource == NULL) { 77 mAudioTrack.mSource = track = extractor->getTrack(i); 78 79 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { 80 mAudioIsVorbis = true; 81 } else { 82 mAudioIsVorbis = false; 83 } 84 } 85 } else if (!strncasecmp(mime, "video/", 6)) { 86 if (mVideoTrack.mSource == NULL) { 87 mVideoTrack.mSource = track = extractor->getTrack(i); 88 } 89 } 90 91 if (track != NULL) { 92 int64_t durationUs; 93 if (meta->findInt64(kKeyDuration, &durationUs)) { 94 if (durationUs > mDurationUs) { 95 mDurationUs = durationUs; 96 } 97 } 98 } 99 } 100 } 101 102 NuPlayer::GenericSource::~GenericSource() { 103 } 104 105 void NuPlayer::GenericSource::start() { 106 ALOGI("start"); 107 108 if (mAudioTrack.mSource != NULL) { 109 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK); 110 111 mAudioTrack.mPackets = 112 new AnotherPacketSource(mAudioTrack.mSource->getFormat()); 113 114 readBuffer(true /* audio */); 115 } 116 117 if (mVideoTrack.mSource != NULL) { 118 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK); 119 120 mVideoTrack.mPackets = 121 new AnotherPacketSource(mVideoTrack.mSource->getFormat()); 122 123 readBuffer(false /* audio */); 124 } 125 } 126 127 status_t NuPlayer::GenericSource::feedMoreTSData() { 128 return OK; 129 } 130 131 sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) { 132 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; 133 134 if (source == NULL) { 135 return NULL; 136 } 137 138 return source->getFormat(); 139 } 140 141 status_t NuPlayer::GenericSource::dequeueAccessUnit( 142 bool audio, sp<ABuffer> *accessUnit) { 143 Track *track = audio ? &mAudioTrack : &mVideoTrack; 144 145 if (track->mSource == NULL) { 146 return -EWOULDBLOCK; 147 } 148 149 status_t finalResult; 150 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 151 return finalResult == OK ? -EWOULDBLOCK : finalResult; 152 } 153 154 status_t result = track->mPackets->dequeueAccessUnit(accessUnit); 155 156 readBuffer(audio, -1ll); 157 158 return result; 159 } 160 161 status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) { 162 *durationUs = mDurationUs; 163 return OK; 164 } 165 166 status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { 167 if (mVideoTrack.mSource != NULL) { 168 int64_t actualTimeUs; 169 readBuffer(false /* audio */, seekTimeUs, &actualTimeUs); 170 171 seekTimeUs = actualTimeUs; 172 } 173 174 if (mAudioTrack.mSource != NULL) { 175 readBuffer(true /* audio */, seekTimeUs); 176 } 177 178 return OK; 179 } 180 181 void NuPlayer::GenericSource::readBuffer( 182 bool audio, int64_t seekTimeUs, int64_t *actualTimeUs) { 183 Track *track = audio ? &mAudioTrack : &mVideoTrack; 184 CHECK(track->mSource != NULL); 185 186 if (actualTimeUs) { 187 *actualTimeUs = seekTimeUs; 188 } 189 190 MediaSource::ReadOptions options; 191 192 bool seeking = false; 193 194 if (seekTimeUs >= 0) { 195 options.setSeekTo(seekTimeUs); 196 seeking = true; 197 } 198 199 for (;;) { 200 MediaBuffer *mbuf; 201 status_t err = track->mSource->read(&mbuf, &options); 202 203 options.clearSeekTo(); 204 205 if (err == OK) { 206 size_t outLength = mbuf->range_length(); 207 208 if (audio && mAudioIsVorbis) { 209 outLength += sizeof(int32_t); 210 } 211 212 sp<ABuffer> buffer = new ABuffer(outLength); 213 214 memcpy(buffer->data(), 215 (const uint8_t *)mbuf->data() + mbuf->range_offset(), 216 mbuf->range_length()); 217 218 if (audio && mAudioIsVorbis) { 219 int32_t numPageSamples; 220 if (!mbuf->meta_data()->findInt32( 221 kKeyValidSamples, &numPageSamples)) { 222 numPageSamples = -1; 223 } 224 225 memcpy(buffer->data() + mbuf->range_length(), 226 &numPageSamples, 227 sizeof(numPageSamples)); 228 } 229 230 int64_t timeUs; 231 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); 232 233 buffer->meta()->setInt64("timeUs", timeUs); 234 235 if (actualTimeUs) { 236 *actualTimeUs = timeUs; 237 } 238 239 mbuf->release(); 240 mbuf = NULL; 241 242 if (seeking) { 243 track->mPackets->queueDiscontinuity( 244 ATSParser::DISCONTINUITY_SEEK, NULL); 245 } 246 247 track->mPackets->queueAccessUnit(buffer); 248 break; 249 } else if (err == INFO_FORMAT_CHANGED) { 250 #if 0 251 track->mPackets->queueDiscontinuity( 252 ATSParser::DISCONTINUITY_FORMATCHANGE, NULL); 253 #endif 254 } else { 255 track->mPackets->signalEOS(err); 256 break; 257 } 258 } 259 } 260 261 bool NuPlayer::GenericSource::isSeekable() { 262 return true; 263 } 264 265 } // namespace android 266