MPEG2TSExtractor.cpp revision 06528d7f18ad01377357d337eaa3e875a242bd2d
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::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::AUDIO).get();
190
191            if (impl != NULL) {
192                haveAudio = true;
193                mSourceImpls.push(impl);
194            }
195        }
196
197        if (++numPacketsParsed > 10000) {
198            break;
199        }
200    }
201
202    LOGI("haveAudio=%d, haveVideo=%d", haveAudio, haveVideo);
203}
204
205status_t MPEG2TSExtractor::feedMore() {
206    Mutex::Autolock autoLock(mLock);
207
208    uint8_t packet[kTSPacketSize];
209    ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize);
210
211    if (n < (ssize_t)kTSPacketSize) {
212        return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
213    }
214
215    mOffset += n;
216    return mParser->feedTSPacket(packet, kTSPacketSize);
217}
218
219void MPEG2TSExtractor::setLiveSession(const sp<LiveSession> &liveSession) {
220    Mutex::Autolock autoLock(mLock);
221
222    mLiveSession = liveSession;
223}
224
225void MPEG2TSExtractor::seekTo(int64_t seekTimeUs) {
226    Mutex::Autolock autoLock(mLock);
227
228    if (mLiveSession == NULL) {
229        return;
230    }
231
232    mLiveSession->seekTo(seekTimeUs);
233}
234
235uint32_t MPEG2TSExtractor::flags() const {
236    Mutex::Autolock autoLock(mLock);
237
238    uint32_t flags = CAN_PAUSE;
239
240    if (mLiveSession != NULL && mLiveSession->isSeekable()) {
241        flags |= CAN_SEEK_FORWARD | CAN_SEEK_BACKWARD | CAN_SEEK;
242    }
243
244    return flags;
245}
246
247////////////////////////////////////////////////////////////////////////////////
248
249bool SniffMPEG2TS(
250        const sp<DataSource> &source, String8 *mimeType, float *confidence,
251        sp<AMessage> *) {
252    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        }
258    }
259
260    *confidence = 0.1f;
261    mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
262
263    return true;
264}
265
266}  // namespace android
267