blob: 17cf45ad8b12c4a9ec5e33ae8f0ad6448f894a4c [file] [log] [blame]
Andreas Hubera557b242010-06-07 13:05:37 -07001/*
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"
Andreas Huberb5590842010-12-03 16:12:25 -080022#include "include/LiveSession.h"
Andreas Huber54d09722010-10-12 11:34:37 -070023#include "include/NuCachedSource2.h"
Andreas Hubera557b242010-06-07 13:05:37 -070024
25#include <media/stagefright/DataSource.h>
Andreas Huber54d09722010-10-12 11:34:37 -070026#include <media/stagefright/MediaDebug.h>
Andreas Hubera557b242010-06-07 13:05:37 -070027#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
Andreas Huberc751ecc2010-09-27 12:04:43 -070038static const size_t kTSPacketSize = 188;
39
Andreas Hubera557b242010-06-07 13:05:37 -070040struct MPEG2TSSource : public MediaSource {
41 MPEG2TSSource(
42 const sp<MPEG2TSExtractor> &extractor,
Andreas Huber54d09722010-10-12 11:34:37 -070043 const sp<AnotherPacketSource> &impl,
44 bool seekable);
Andreas Hubera557b242010-06-07 13:05:37 -070045
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
Andreas Huber54d09722010-10-12 11:34:37 -070057 // 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
Andreas Hubera557b242010-06-07 13:05:37 -070061 DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSSource);
62};
63
64MPEG2TSSource::MPEG2TSSource(
65 const sp<MPEG2TSExtractor> &extractor,
Andreas Huber54d09722010-10-12 11:34:37 -070066 const sp<AnotherPacketSource> &impl,
67 bool seekable)
Andreas Hubera557b242010-06-07 13:05:37 -070068 : mExtractor(extractor),
Andreas Huber54d09722010-10-12 11:34:37 -070069 mImpl(impl),
70 mSeekable(seekable) {
Andreas Hubera557b242010-06-07 13:05:37 -070071}
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() {
Andreas Huber54d09722010-10-12 11:34:37 -070082 sp<MetaData> meta = mImpl->getFormat();
83
84 int64_t durationUs;
Andreas Huberb5590842010-12-03 16:12:25 -080085 if (mExtractor->mLiveSession != NULL
86 && mExtractor->mLiveSession->getDuration(&durationUs) == OK) {
Andreas Huber54d09722010-10-12 11:34:37 -070087 meta->setInt64(kKeyDuration, durationUs);
88 }
89
90 return meta;
Andreas Hubera557b242010-06-07 13:05:37 -070091}
92
93status_t MPEG2TSSource::read(
94 MediaBuffer **out, const ReadOptions *options) {
95 *out = NULL;
96
Andreas Huber54d09722010-10-12 11:34:37 -070097 int64_t seekTimeUs;
98 ReadOptions::SeekMode seekMode;
99 if (mSeekable && options && options->getSeekTo(&seekTimeUs, &seekMode)) {
100 mExtractor->seekTo(seekTimeUs);
101 }
102
Andreas Hubera557b242010-06-07 13:05:37 -0700103 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
Andreas Huber54d09722010-10-12 11:34:37 -0700136 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);
Andreas Hubera557b242010-06-07 13:05:37 -0700150}
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;
Andreas Huberc751ecc2010-09-27 12:04:43 -0700168 int numPacketsParsed = 0;
Andreas Hubera557b242010-06-07 13:05:37 -0700169
170 while (feedMore() == OK) {
171 ATSParser::SourceType type;
172 if (haveAudio && haveVideo) {
173 break;
174 }
Andreas Huberc751ecc2010-09-27 12:04:43 -0700175 if (!haveVideo) {
176 sp<AnotherPacketSource> impl =
177 (AnotherPacketSource *)mParser->getSource(
Andreas Hubereb2f9c12011-05-19 08:37:39 -0700178 ATSParser::VIDEO).get();
Andreas Hubera557b242010-06-07 13:05:37 -0700179
Andreas Huberc751ecc2010-09-27 12:04:43 -0700180 if (impl != NULL) {
Andreas Hubera557b242010-06-07 13:05:37 -0700181 haveVideo = true;
Andreas Huberc751ecc2010-09-27 12:04:43 -0700182 mSourceImpls.push(impl);
Andreas Hubera557b242010-06-07 13:05:37 -0700183 }
Andreas Huberc751ecc2010-09-27 12:04:43 -0700184 }
185
186 if (!haveAudio) {
187 sp<AnotherPacketSource> impl =
188 (AnotherPacketSource *)mParser->getSource(
Andreas Hubereb2f9c12011-05-19 08:37:39 -0700189 ATSParser::AUDIO).get();
Andreas Huberc751ecc2010-09-27 12:04:43 -0700190
191 if (impl != NULL) {
192 haveAudio = true;
193 mSourceImpls.push(impl);
194 }
195 }
196
Andreas Hubereb2f9c12011-05-19 08:37:39 -0700197 if (++numPacketsParsed > 10000) {
Andreas Huberc751ecc2010-09-27 12:04:43 -0700198 break;
Andreas Hubera557b242010-06-07 13:05:37 -0700199 }
200 }
201
202 LOGI("haveAudio=%d, haveVideo=%d", haveAudio, haveVideo);
203}
204
205status_t MPEG2TSExtractor::feedMore() {
206 Mutex::Autolock autoLock(mLock);
207
Andreas Hubera557b242010-06-07 13:05:37 -0700208 uint8_t packet[kTSPacketSize];
209 ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize);
210
Andreas Huberd6c421f2011-02-16 09:05:38 -0800211 if (n < (ssize_t)kTSPacketSize) {
Andreas Hubera557b242010-06-07 13:05:37 -0700212 return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
213 }
214
Andreas Huber4c19bf92010-09-08 14:32:20 -0700215 mOffset += n;
Andreas Hubereeddb0e2011-08-31 16:29:05 -0700216 return mParser->feedTSPacket(packet, kTSPacketSize);
Andreas Hubera557b242010-06-07 13:05:37 -0700217}
218
Andreas Huberb5590842010-12-03 16:12:25 -0800219void MPEG2TSExtractor::setLiveSession(const sp<LiveSession> &liveSession) {
Andreas Huber54d09722010-10-12 11:34:37 -0700220 Mutex::Autolock autoLock(mLock);
221
Andreas Huberb5590842010-12-03 16:12:25 -0800222 mLiveSession = liveSession;
Andreas Huber54d09722010-10-12 11:34:37 -0700223}
224
225void MPEG2TSExtractor::seekTo(int64_t seekTimeUs) {
226 Mutex::Autolock autoLock(mLock);
227
Andreas Huberb5590842010-12-03 16:12:25 -0800228 if (mLiveSession == NULL) {
Andreas Huber54d09722010-10-12 11:34:37 -0700229 return;
230 }
231
Andreas Huberb5590842010-12-03 16:12:25 -0800232 mLiveSession->seekTo(seekTimeUs);
Andreas Huber54d09722010-10-12 11:34:37 -0700233}
234
235uint32_t MPEG2TSExtractor::flags() const {
236 Mutex::Autolock autoLock(mLock);
237
238 uint32_t flags = CAN_PAUSE;
239
Andreas Huberb5590842010-12-03 16:12:25 -0800240 if (mLiveSession != NULL && mLiveSession->isSeekable()) {
Andreas Huber54d09722010-10-12 11:34:37 -0700241 flags |= CAN_SEEK_FORWARD | CAN_SEEK_BACKWARD | CAN_SEEK;
242 }
243
244 return flags;
245}
246
Andreas Hubera557b242010-06-07 13:05:37 -0700247////////////////////////////////////////////////////////////////////////////////
248
249bool SniffMPEG2TS(
Andreas Huberefdd0882010-08-25 11:09:41 -0700250 const sp<DataSource> &source, String8 *mimeType, float *confidence,
251 sp<AMessage> *) {
Andreas Huberc751ecc2010-09-27 12:04:43 -0700252 for (int i = 0; i < 5; ++i) {
253 char header;
254 if (source->readAt(kTSPacketSize * i, &header, 1) != 1
255 || header != 0x47) {
256 return false;
257 }
Andreas Hubera557b242010-06-07 13:05:37 -0700258 }
259
Andreas Huberc751ecc2010-09-27 12:04:43 -0700260 *confidence = 0.1f;
Andreas Hubera557b242010-06-07 13:05:37 -0700261 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
262
263 return true;
Andreas Hubera557b242010-06-07 13:05:37 -0700264}
265
266} // namespace android