MPEG2TSExtractor.cpp revision 540006666b4191cd78391378f1c66c21bcf0c4cd
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/ABuffer.h>
25#include <media/stagefright/foundation/ADebug.h>
26#include <media/stagefright/DataSource.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 <media/IStreamSource.h>
32#include <utils/String8.h>
33
34#include "AnotherPacketSource.h"
35#include "ATSParser.h"
36
37namespace android {
38
39static const size_t kTSPacketSize = 188;
40
41struct MPEG2TSSource : public MediaSource {
42    MPEG2TSSource(
43            const sp<MPEG2TSExtractor> &extractor,
44            const sp<AnotherPacketSource> &impl,
45            bool doesSeek);
46
47    virtual status_t start(MetaData *params = NULL);
48    virtual status_t stop();
49    virtual sp<MetaData> getFormat();
50
51    virtual status_t read(
52            MediaBuffer **buffer, const ReadOptions *options = NULL);
53
54private:
55    sp<MPEG2TSExtractor> mExtractor;
56    sp<AnotherPacketSource> mImpl;
57
58    // If there are both audio and video streams, only the video stream
59    // will signal seek on the extractor; otherwise the single stream will seek.
60    bool mDoesSeek;
61
62    DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSSource);
63};
64
65MPEG2TSSource::MPEG2TSSource(
66        const sp<MPEG2TSExtractor> &extractor,
67        const sp<AnotherPacketSource> &impl,
68        bool doesSeek)
69    : mExtractor(extractor),
70      mImpl(impl),
71      mDoesSeek(doesSeek) {
72}
73
74status_t MPEG2TSSource::start(MetaData *params) {
75    return mImpl->start(params);
76}
77
78status_t MPEG2TSSource::stop() {
79    return mImpl->stop();
80}
81
82sp<MetaData> MPEG2TSSource::getFormat() {
83    return mImpl->getFormat();
84}
85
86status_t MPEG2TSSource::read(
87        MediaBuffer **out, const ReadOptions *options) {
88    *out = NULL;
89
90    int64_t seekTimeUs;
91    ReadOptions::SeekMode seekMode;
92    if (mDoesSeek && options && options->getSeekTo(&seekTimeUs, &seekMode)) {
93        // seek is needed
94        status_t err = mExtractor->seek(seekTimeUs, seekMode);
95        if (err != OK) {
96            return err;
97        }
98    }
99
100    if (mExtractor->feedUntilBufferAvailable(mImpl) != OK) {
101        return ERROR_END_OF_STREAM;
102    }
103
104    return mImpl->read(out, options);
105}
106
107////////////////////////////////////////////////////////////////////////////////
108
109MPEG2TSExtractor::MPEG2TSExtractor(const sp<DataSource> &source)
110    : mDataSource(source),
111      mParser(new ATSParser),
112      mOffset(0) {
113    init();
114}
115
116size_t MPEG2TSExtractor::countTracks() {
117    return mSourceImpls.size();
118}
119
120sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) {
121    if (index >= mSourceImpls.size()) {
122        return NULL;
123    }
124
125    // The seek reference track (video if present; audio otherwise) performs
126    // seek requests, while other tracks ignore requests.
127    return new MPEG2TSSource(this, mSourceImpls.editItemAt(index),
128            (mSeekSyncPoints == &mSyncPoints.editItemAt(index)));
129}
130
131sp<MetaData> MPEG2TSExtractor::getTrackMetaData(
132        size_t index, uint32_t /* flags */) {
133    return index < mSourceImpls.size()
134        ? mSourceImpls.editItemAt(index)->getFormat() : NULL;
135}
136
137sp<MetaData> MPEG2TSExtractor::getMetaData() {
138    sp<MetaData> meta = new MetaData;
139    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
140
141    return meta;
142}
143
144void MPEG2TSExtractor::init() {
145    bool haveAudio = false;
146    bool haveVideo = false;
147    int numPacketsParsed = 0;
148
149    while (feedMore() == OK) {
150        if (haveAudio && haveVideo) {
151            break;
152        }
153        if (!haveVideo) {
154            sp<AnotherPacketSource> impl =
155                (AnotherPacketSource *)mParser->getSource(
156                        ATSParser::VIDEO).get();
157
158            if (impl != NULL) {
159                haveVideo = true;
160                mSourceImpls.push(impl);
161                mSyncPoints.push();
162                mSeekSyncPoints = &mSyncPoints.editTop();
163            }
164        }
165
166        if (!haveAudio) {
167            sp<AnotherPacketSource> impl =
168                (AnotherPacketSource *)mParser->getSource(
169                        ATSParser::AUDIO).get();
170
171            if (impl != NULL) {
172                haveAudio = true;
173                mSourceImpls.push(impl);
174                mSyncPoints.push();
175                if (!haveVideo) {
176                    mSeekSyncPoints = &mSyncPoints.editTop();
177                }
178            }
179        }
180
181        if (++numPacketsParsed > 10000) {
182            break;
183        }
184    }
185
186    off64_t size;
187    if (mDataSource->getSize(&size) == OK && (haveAudio || haveVideo)) {
188        sp<AnotherPacketSource> impl = haveVideo
189                ? (AnotherPacketSource *)mParser->getSource(
190                        ATSParser::VIDEO).get()
191                : (AnotherPacketSource *)mParser->getSource(
192                        ATSParser::AUDIO).get();
193        int64_t prevBufferedDurationUs = 0;
194        int64_t durationUs = -1;
195        List<int64_t> durations;
196        // Estimate duration --- stabilize until you get <500ms deviation.
197        for (; feedMore() == OK && numPacketsParsed <= 10000;
198                ++numPacketsParsed) {
199            status_t err;
200            int64_t bufferedDurationUs = impl->getBufferedDurationUs(&err);
201            if (err != OK) {
202                break;
203            }
204            if (bufferedDurationUs != prevBufferedDurationUs) {
205                durationUs = size * bufferedDurationUs / mOffset;
206                durations.push_back(durationUs);
207                if (durations.size() > 5) {
208                    durations.erase(durations.begin());
209                    int64_t min = *durations.begin();
210                    int64_t max = *durations.begin();
211                    for (List<int64_t>::iterator i = durations.begin();
212                            i != durations.end();
213                            ++i) {
214                        if (min > *i) {
215                            min = *i;
216                        }
217                        if (max < *i) {
218                            max = *i;
219                        }
220                    }
221                    if (max - min < 500 * 1000) {
222                        break;
223                    }
224                }
225                prevBufferedDurationUs = bufferedDurationUs;
226            }
227        }
228        if (durationUs > 0) {
229            const sp<MetaData> meta = impl->getFormat();
230            meta->setInt64(kKeyDuration, durationUs);
231            impl->setFormat(meta);
232        }
233    }
234
235    ALOGI("haveAudio=%d, haveVideo=%d", haveAudio, haveVideo);
236}
237
238status_t MPEG2TSExtractor::feedMore() {
239    Mutex::Autolock autoLock(mLock);
240
241    uint8_t packet[kTSPacketSize];
242    ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize);
243
244    if (n < (ssize_t)kTSPacketSize) {
245        if (n >= 0) {
246            mParser->signalEOS(ERROR_END_OF_STREAM);
247        }
248        return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
249    }
250
251    ATSParser::SyncEvent event(mOffset);
252    mOffset += n;
253    status_t err = mParser->feedTSPacket(packet, kTSPacketSize, &event);
254    if (event.isInit()) {
255        for (size_t i = 0; i < mSourceImpls.size(); ++i) {
256            if (mSourceImpls[i].get() == event.getMediaSource().get()) {
257                mSyncPoints.editItemAt(i).add(
258                        event.getTimeUs(), event.getOffset());
259                break;
260            }
261        }
262    }
263    return err;
264}
265
266uint32_t MPEG2TSExtractor::flags() const {
267    return CAN_PAUSE | CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD;
268}
269
270status_t MPEG2TSExtractor::seek(int64_t seekTimeUs,
271        const MediaSource::ReadOptions::SeekMode &seekMode) {
272    if (mSeekSyncPoints == NULL || mSeekSyncPoints->isEmpty()) {
273        ALOGW("No sync point to seek to.");
274        // ... and therefore we have nothing useful to do here.
275        return OK;
276    }
277
278    // Determine whether we're seeking beyond the known area.
279    bool shouldSeekBeyond =
280            (seekTimeUs > mSeekSyncPoints->keyAt(mSeekSyncPoints->size() - 1));
281
282    // Determine the sync point to seek.
283    size_t index = 0;
284    for (; index < mSeekSyncPoints->size(); ++index) {
285        int64_t timeUs = mSeekSyncPoints->keyAt(index);
286        if (timeUs > seekTimeUs) {
287            break;
288        }
289    }
290
291    switch (seekMode) {
292        case MediaSource::ReadOptions::SEEK_NEXT_SYNC:
293            if (index == mSeekSyncPoints->size()) {
294                ALOGW("Next sync not found; starting from the latest sync.");
295                --index;
296            }
297            break;
298        case MediaSource::ReadOptions::SEEK_CLOSEST_SYNC:
299        case MediaSource::ReadOptions::SEEK_CLOSEST:
300            ALOGW("seekMode not supported: %d; falling back to PREVIOUS_SYNC",
301                    seekMode);
302            // fall-through
303        case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC:
304            if (index == 0) {
305                ALOGW("Previous sync not found; starting from the earliest "
306                        "sync.");
307            } else {
308                --index;
309            }
310            break;
311    }
312    if (!shouldSeekBeyond || mOffset <= mSeekSyncPoints->valueAt(index)) {
313        int64_t actualSeekTimeUs = mSeekSyncPoints->keyAt(index);
314        mOffset = mSeekSyncPoints->valueAt(index);
315        status_t err = queueDiscontinuityForSeek(actualSeekTimeUs);
316        if (err != OK) {
317            return err;
318        }
319    }
320
321    if (shouldSeekBeyond) {
322        status_t err = seekBeyond(seekTimeUs);
323        if (err != OK) {
324            return err;
325        }
326    }
327
328    // Fast-forward to sync frame.
329    for (size_t i = 0; i < mSourceImpls.size(); ++i) {
330        const sp<AnotherPacketSource> &impl = mSourceImpls[i];
331        status_t err;
332        feedUntilBufferAvailable(impl);
333        while (impl->hasBufferAvailable(&err)) {
334            sp<AMessage> meta = impl->getMetaAfterLastDequeued(0);
335            sp<ABuffer> buffer;
336            if (meta == NULL) {
337                return UNKNOWN_ERROR;
338            }
339            int32_t sync;
340            if (meta->findInt32("isSync", &sync) && sync) {
341                break;
342            }
343            err = impl->dequeueAccessUnit(&buffer);
344            if (err != OK) {
345                return err;
346            }
347            feedUntilBufferAvailable(impl);
348        }
349    }
350
351    return OK;
352}
353
354status_t MPEG2TSExtractor::queueDiscontinuityForSeek(int64_t actualSeekTimeUs) {
355    // Signal discontinuity
356    sp<AMessage> extra(new AMessage);
357    extra->setInt64(IStreamListener::kKeyMediaTimeUs, actualSeekTimeUs);
358    mParser->signalDiscontinuity(ATSParser::DISCONTINUITY_TIME, extra);
359
360    // After discontinuity, impl should only have discontinuities
361    // with the last being what we queued. Dequeue them all here.
362    for (size_t i = 0; i < mSourceImpls.size(); ++i) {
363        const sp<AnotherPacketSource> &impl = mSourceImpls.itemAt(i);
364        sp<ABuffer> buffer;
365        status_t err;
366        while (impl->hasBufferAvailable(&err)) {
367            if (err != OK) {
368                return err;
369            }
370            err = impl->dequeueAccessUnit(&buffer);
371            // If the source contains anything but discontinuity, that's
372            // a programming mistake.
373            CHECK(err == INFO_DISCONTINUITY);
374        }
375    }
376
377    // Feed until we have a buffer for each source.
378    for (size_t i = 0; i < mSourceImpls.size(); ++i) {
379        const sp<AnotherPacketSource> &impl = mSourceImpls.itemAt(i);
380        sp<ABuffer> buffer;
381        status_t err = feedUntilBufferAvailable(impl);
382        if (err != OK) {
383            return err;
384        }
385    }
386
387    return OK;
388}
389
390status_t MPEG2TSExtractor::seekBeyond(int64_t seekTimeUs) {
391    // If we're seeking beyond where we know --- read until we reach there.
392    size_t syncPointsSize = mSeekSyncPoints->size();
393
394    while (seekTimeUs > mSeekSyncPoints->keyAt(
395            mSeekSyncPoints->size() - 1)) {
396        status_t err;
397        if (syncPointsSize < mSeekSyncPoints->size()) {
398            syncPointsSize = mSeekSyncPoints->size();
399            int64_t syncTimeUs = mSeekSyncPoints->keyAt(syncPointsSize - 1);
400            // Dequeue buffers before sync point in order to avoid too much
401            // cache building up.
402            sp<ABuffer> buffer;
403            for (size_t i = 0; i < mSourceImpls.size(); ++i) {
404                const sp<AnotherPacketSource> &impl = mSourceImpls[i];
405                int64_t timeUs;
406                while ((err = impl->nextBufferTime(&timeUs)) == OK) {
407                    if (timeUs < syncTimeUs) {
408                        impl->dequeueAccessUnit(&buffer);
409                    } else {
410                        break;
411                    }
412                }
413                if (err != OK && err != -EWOULDBLOCK) {
414                    return err;
415                }
416            }
417        }
418        if (feedMore() != OK) {
419            return ERROR_END_OF_STREAM;
420        }
421    }
422
423    return OK;
424}
425
426status_t MPEG2TSExtractor::feedUntilBufferAvailable(
427        const sp<AnotherPacketSource> &impl) {
428    status_t finalResult;
429    while (!impl->hasBufferAvailable(&finalResult)) {
430        if (finalResult != OK) {
431            return finalResult;
432        }
433
434        status_t err = feedMore();
435        if (err != OK) {
436            impl->signalEOS(err);
437        }
438    }
439    return OK;
440}
441
442////////////////////////////////////////////////////////////////////////////////
443
444bool SniffMPEG2TS(
445        const sp<DataSource> &source, String8 *mimeType, float *confidence,
446        sp<AMessage> *) {
447    for (int i = 0; i < 5; ++i) {
448        char header;
449        if (source->readAt(kTSPacketSize * i, &header, 1) != 1
450                || header != 0x47) {
451            return false;
452        }
453    }
454
455    *confidence = 0.1f;
456    mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
457
458    return true;
459}
460
461}  // namespace android
462