Home | History | Annotate | Download | only in mpeg2ts
      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/ADebug.h>
     25 #include <media/stagefright/DataSource.h>
     26 #include <media/stagefright/MediaDefs.h>
     27 #include <media/stagefright/MediaErrors.h>
     28 #include <media/stagefright/MediaSource.h>
     29 #include <media/stagefright/MetaData.h>
     30 #include <utils/String8.h>
     31 
     32 #include "AnotherPacketSource.h"
     33 #include "ATSParser.h"
     34 
     35 namespace android {
     36 
     37 static const size_t kTSPacketSize = 188;
     38 
     39 struct MPEG2TSSource : public MediaSource {
     40     MPEG2TSSource(
     41             const sp<MPEG2TSExtractor> &extractor,
     42             const sp<AnotherPacketSource> &impl,
     43             bool seekable);
     44 
     45     virtual status_t start(MetaData *params = NULL);
     46     virtual status_t stop();
     47     virtual sp<MetaData> getFormat();
     48 
     49     virtual status_t read(
     50             MediaBuffer **buffer, const ReadOptions *options = NULL);
     51 
     52 private:
     53     sp<MPEG2TSExtractor> mExtractor;
     54     sp<AnotherPacketSource> mImpl;
     55 
     56     // If there are both audio and video streams, only the video stream
     57     // will be seekable, otherwise the single stream will be seekable.
     58     bool mSeekable;
     59 
     60     DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSSource);
     61 };
     62 
     63 MPEG2TSSource::MPEG2TSSource(
     64         const sp<MPEG2TSExtractor> &extractor,
     65         const sp<AnotherPacketSource> &impl,
     66         bool seekable)
     67     : mExtractor(extractor),
     68       mImpl(impl),
     69       mSeekable(seekable) {
     70 }
     71 
     72 status_t MPEG2TSSource::start(MetaData *params) {
     73     return mImpl->start(params);
     74 }
     75 
     76 status_t MPEG2TSSource::stop() {
     77     return mImpl->stop();
     78 }
     79 
     80 sp<MetaData> MPEG2TSSource::getFormat() {
     81     return mImpl->getFormat();
     82 }
     83 
     84 status_t MPEG2TSSource::read(
     85         MediaBuffer **out, const ReadOptions *options) {
     86     *out = NULL;
     87 
     88     int64_t seekTimeUs;
     89     ReadOptions::SeekMode seekMode;
     90     if (mSeekable && options && options->getSeekTo(&seekTimeUs, &seekMode)) {
     91         return ERROR_UNSUPPORTED;
     92     }
     93 
     94     status_t finalResult;
     95     while (!mImpl->hasBufferAvailable(&finalResult)) {
     96         if (finalResult != OK) {
     97             return ERROR_END_OF_STREAM;
     98         }
     99 
    100         status_t err = mExtractor->feedMore();
    101         if (err != OK) {
    102             mImpl->signalEOS(err);
    103         }
    104     }
    105 
    106     return mImpl->read(out, options);
    107 }
    108 
    109 ////////////////////////////////////////////////////////////////////////////////
    110 
    111 MPEG2TSExtractor::MPEG2TSExtractor(const sp<DataSource> &source)
    112     : mDataSource(source),
    113       mParser(new ATSParser),
    114       mOffset(0) {
    115     init();
    116 }
    117 
    118 size_t MPEG2TSExtractor::countTracks() {
    119     return mSourceImpls.size();
    120 }
    121 
    122 sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) {
    123     if (index >= mSourceImpls.size()) {
    124         return NULL;
    125     }
    126 
    127     bool seekable = true;
    128     if (mSourceImpls.size() > 1) {
    129         CHECK_EQ(mSourceImpls.size(), 2u);
    130 
    131         sp<MetaData> meta = mSourceImpls.editItemAt(index)->getFormat();
    132         const char *mime;
    133         CHECK(meta->findCString(kKeyMIMEType, &mime));
    134 
    135         if (!strncasecmp("audio/", mime, 6)) {
    136             seekable = false;
    137         }
    138     }
    139 
    140     return new MPEG2TSSource(this, mSourceImpls.editItemAt(index), seekable);
    141 }
    142 
    143 sp<MetaData> MPEG2TSExtractor::getTrackMetaData(
    144         size_t index, uint32_t flags) {
    145     return index < mSourceImpls.size()
    146         ? mSourceImpls.editItemAt(index)->getFormat() : NULL;
    147 }
    148 
    149 sp<MetaData> MPEG2TSExtractor::getMetaData() {
    150     sp<MetaData> meta = new MetaData;
    151     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
    152 
    153     return meta;
    154 }
    155 
    156 void MPEG2TSExtractor::init() {
    157     bool haveAudio = false;
    158     bool haveVideo = false;
    159     int numPacketsParsed = 0;
    160 
    161     while (feedMore() == OK) {
    162         ATSParser::SourceType type;
    163         if (haveAudio && haveVideo) {
    164             break;
    165         }
    166         if (!haveVideo) {
    167             sp<AnotherPacketSource> impl =
    168                 (AnotherPacketSource *)mParser->getSource(
    169                         ATSParser::VIDEO).get();
    170 
    171             if (impl != NULL) {
    172                 haveVideo = true;
    173                 mSourceImpls.push(impl);
    174             }
    175         }
    176 
    177         if (!haveAudio) {
    178             sp<AnotherPacketSource> impl =
    179                 (AnotherPacketSource *)mParser->getSource(
    180                         ATSParser::AUDIO).get();
    181 
    182             if (impl != NULL) {
    183                 haveAudio = true;
    184                 mSourceImpls.push(impl);
    185             }
    186         }
    187 
    188         if (++numPacketsParsed > 10000) {
    189             break;
    190         }
    191     }
    192 
    193     ALOGI("haveAudio=%d, haveVideo=%d", haveAudio, haveVideo);
    194 }
    195 
    196 status_t MPEG2TSExtractor::feedMore() {
    197     Mutex::Autolock autoLock(mLock);
    198 
    199     uint8_t packet[kTSPacketSize];
    200     ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize);
    201 
    202     if (n < (ssize_t)kTSPacketSize) {
    203         return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
    204     }
    205 
    206     mOffset += n;
    207     return mParser->feedTSPacket(packet, kTSPacketSize);
    208 }
    209 
    210 uint32_t MPEG2TSExtractor::flags() const {
    211     return CAN_PAUSE;
    212 }
    213 
    214 ////////////////////////////////////////////////////////////////////////////////
    215 
    216 bool SniffMPEG2TS(
    217         const sp<DataSource> &source, String8 *mimeType, float *confidence,
    218         sp<AMessage> *) {
    219     for (int i = 0; i < 5; ++i) {
    220         char header;
    221         if (source->readAt(kTSPacketSize * i, &header, 1) != 1
    222                 || header != 0x47) {
    223             return false;
    224         }
    225     }
    226 
    227     *confidence = 0.1f;
    228     mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
    229 
    230     return true;
    231 }
    232 
    233 }  // namespace android
    234