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