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