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