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