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