MPEG2TSExtractor.cpp revision f933441648ef6a71dee783d733aac17b9508b452
1/* 2 * Copyright (C) 2010 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 "MPEG2TSExtractor" 19#include <utils/Log.h> 20 21#include "include/MPEG2TSExtractor.h" 22#include "include/LiveSession.h" 23#include "include/NuCachedSource2.h" 24 25#include <media/stagefright/DataSource.h> 26#include <media/stagefright/MediaDebug.h> 27#include <media/stagefright/MediaDefs.h> 28#include <media/stagefright/MediaErrors.h> 29#include <media/stagefright/MediaSource.h> 30#include <media/stagefright/MetaData.h> 31#include <utils/String8.h> 32 33#include "AnotherPacketSource.h" 34#include "ATSParser.h" 35 36namespace android { 37 38static const size_t kTSPacketSize = 188; 39 40struct MPEG2TSSource : public MediaSource { 41 MPEG2TSSource( 42 const sp<MPEG2TSExtractor> &extractor, 43 const sp<AnotherPacketSource> &impl, 44 bool seekable); 45 46 virtual status_t start(MetaData *params = NULL); 47 virtual status_t stop(); 48 virtual sp<MetaData> getFormat(); 49 50 virtual status_t read( 51 MediaBuffer **buffer, const ReadOptions *options = NULL); 52 53private: 54 sp<MPEG2TSExtractor> mExtractor; 55 sp<AnotherPacketSource> mImpl; 56 57 // If there are both audio and video streams, only the video stream 58 // will be seekable, otherwise the single stream will be seekable. 59 bool mSeekable; 60 61 DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSSource); 62}; 63 64MPEG2TSSource::MPEG2TSSource( 65 const sp<MPEG2TSExtractor> &extractor, 66 const sp<AnotherPacketSource> &impl, 67 bool seekable) 68 : mExtractor(extractor), 69 mImpl(impl), 70 mSeekable(seekable) { 71} 72 73status_t MPEG2TSSource::start(MetaData *params) { 74 return mImpl->start(params); 75} 76 77status_t MPEG2TSSource::stop() { 78 return mImpl->stop(); 79} 80 81sp<MetaData> MPEG2TSSource::getFormat() { 82 sp<MetaData> meta = mImpl->getFormat(); 83 84 int64_t durationUs; 85 if (mExtractor->mLiveSession != NULL 86 && mExtractor->mLiveSession->getDuration(&durationUs) == OK) { 87 meta->setInt64(kKeyDuration, durationUs); 88 } 89 90 return meta; 91} 92 93status_t MPEG2TSSource::read( 94 MediaBuffer **out, const ReadOptions *options) { 95 *out = NULL; 96 97 int64_t seekTimeUs; 98 ReadOptions::SeekMode seekMode; 99 if (mSeekable && options && options->getSeekTo(&seekTimeUs, &seekMode)) { 100 mExtractor->seekTo(seekTimeUs); 101 } 102 103 status_t finalResult; 104 while (!mImpl->hasBufferAvailable(&finalResult)) { 105 if (finalResult != OK) { 106 return ERROR_END_OF_STREAM; 107 } 108 109 status_t err = mExtractor->feedMore(); 110 if (err != OK) { 111 mImpl->signalEOS(err); 112 } 113 } 114 115 return mImpl->read(out, options); 116} 117 118//////////////////////////////////////////////////////////////////////////////// 119 120MPEG2TSExtractor::MPEG2TSExtractor(const sp<DataSource> &source) 121 : mDataSource(source), 122 mParser(new ATSParser), 123 mOffset(0) { 124 init(); 125} 126 127size_t MPEG2TSExtractor::countTracks() { 128 return mSourceImpls.size(); 129} 130 131sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) { 132 if (index >= mSourceImpls.size()) { 133 return NULL; 134 } 135 136 bool seekable = true; 137 if (mSourceImpls.size() > 1) { 138 CHECK_EQ(mSourceImpls.size(), 2u); 139 140 sp<MetaData> meta = mSourceImpls.editItemAt(index)->getFormat(); 141 const char *mime; 142 CHECK(meta->findCString(kKeyMIMEType, &mime)); 143 144 if (!strncasecmp("audio/", mime, 6)) { 145 seekable = false; 146 } 147 } 148 149 return new MPEG2TSSource(this, mSourceImpls.editItemAt(index), seekable); 150} 151 152sp<MetaData> MPEG2TSExtractor::getTrackMetaData( 153 size_t index, uint32_t flags) { 154 return index < mSourceImpls.size() 155 ? mSourceImpls.editItemAt(index)->getFormat() : NULL; 156} 157 158sp<MetaData> MPEG2TSExtractor::getMetaData() { 159 sp<MetaData> meta = new MetaData; 160 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2TS); 161 162 return meta; 163} 164 165void MPEG2TSExtractor::init() { 166 bool haveAudio = false; 167 bool haveVideo = false; 168 int numPacketsParsed = 0; 169 170 while (feedMore() == OK) { 171 ATSParser::SourceType type; 172 if (haveAudio && haveVideo) { 173 break; 174 } 175 if (!haveVideo) { 176 sp<AnotherPacketSource> impl = 177 (AnotherPacketSource *)mParser->getSource( 178 ATSParser::AVC_VIDEO).get(); 179 180 if (impl != NULL) { 181 haveVideo = true; 182 mSourceImpls.push(impl); 183 } 184 } 185 186 if (!haveAudio) { 187 sp<AnotherPacketSource> impl = 188 (AnotherPacketSource *)mParser->getSource( 189 ATSParser::MPEG2ADTS_AUDIO).get(); 190 191 if (impl != NULL) { 192 haveAudio = true; 193 mSourceImpls.push(impl); 194 } 195 } 196 197 if (++numPacketsParsed > 2500) { 198 break; 199 } 200 } 201 202 LOGI("haveAudio=%d, haveVideo=%d", haveAudio, haveVideo); 203} 204 205static bool isDiscontinuity(const uint8_t *data, ssize_t size) { 206 return size == 188 && data[0] == 0x00; 207} 208 209status_t MPEG2TSExtractor::feedMore() { 210 Mutex::Autolock autoLock(mLock); 211 212 uint8_t packet[kTSPacketSize]; 213 ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize); 214 215 if (isDiscontinuity(packet, n)) { 216 LOGI("XXX discontinuity detected"); 217 mParser->signalDiscontinuity(ATSParser::DISCONTINUITY_HTTPLIVE); 218 } else if (n < (ssize_t)kTSPacketSize) { 219 return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM; 220 } else { 221 mParser->feedTSPacket(packet, kTSPacketSize); 222 } 223 224 mOffset += n; 225 226 return OK; 227} 228 229void MPEG2TSExtractor::setLiveSession(const sp<LiveSession> &liveSession) { 230 Mutex::Autolock autoLock(mLock); 231 232 mLiveSession = liveSession; 233} 234 235void MPEG2TSExtractor::seekTo(int64_t seekTimeUs) { 236 Mutex::Autolock autoLock(mLock); 237 238 if (mLiveSession == NULL) { 239 return; 240 } 241 242 mLiveSession->seekTo(seekTimeUs); 243} 244 245uint32_t MPEG2TSExtractor::flags() const { 246 Mutex::Autolock autoLock(mLock); 247 248 uint32_t flags = CAN_PAUSE; 249 250 if (mLiveSession != NULL && mLiveSession->isSeekable()) { 251 flags |= CAN_SEEK_FORWARD | CAN_SEEK_BACKWARD | CAN_SEEK; 252 } 253 254 return flags; 255} 256 257//////////////////////////////////////////////////////////////////////////////// 258 259bool SniffMPEG2TS( 260 const sp<DataSource> &source, String8 *mimeType, float *confidence, 261 sp<AMessage> *) { 262 for (int i = 0; i < 5; ++i) { 263 char header; 264 if (source->readAt(kTSPacketSize * i, &header, 1) != 1 265 || header != 0x47) { 266 return false; 267 } 268 } 269 270 *confidence = 0.1f; 271 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS); 272 273 return true; 274} 275 276} // namespace android 277