Home | History | Annotate | Download | only in stagefright
      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 "stream"
     19 #include "utils/Log.h"
     20 
     21 #include <binder/ProcessState.h>
     22 #include <cutils/properties.h> // for property_get
     23 
     24 #include <media/IStreamSource.h>
     25 #include <media/mediaplayer.h>
     26 #include <media/stagefright/foundation/ADebug.h>
     27 #include <media/stagefright/foundation/AMessage.h>
     28 #include <media/stagefright/DataSource.h>
     29 #include <media/stagefright/MPEG2TSWriter.h>
     30 #include <media/stagefright/MediaExtractor.h>
     31 #include <media/stagefright/MediaSource.h>
     32 #include <media/stagefright/MetaData.h>
     33 
     34 #include <binder/IServiceManager.h>
     35 #include <media/IMediaPlayerService.h>
     36 #include <gui/ISurfaceComposer.h>
     37 #include <gui/SurfaceComposerClient.h>
     38 
     39 #include <fcntl.h>
     40 #include <ui/DisplayInfo.h>
     41 
     42 using namespace android;
     43 
     44 struct MyStreamSource : public BnStreamSource {
     45     // Object assumes ownership of fd.
     46     MyStreamSource(int fd);
     47 
     48     virtual void setListener(const sp<IStreamListener> &listener);
     49     virtual void setBuffers(const Vector<sp<IMemory> > &buffers);
     50 
     51     virtual void onBufferAvailable(size_t index);
     52 
     53 protected:
     54     virtual ~MyStreamSource();
     55 
     56 private:
     57     int mFd;
     58     off64_t mFileSize;
     59     uint64_t mNumPacketsSent;
     60 
     61     sp<IStreamListener> mListener;
     62     Vector<sp<IMemory> > mBuffers;
     63 
     64     DISALLOW_EVIL_CONSTRUCTORS(MyStreamSource);
     65 };
     66 
     67 MyStreamSource::MyStreamSource(int fd)
     68     : mFd(fd),
     69       mFileSize(0),
     70       mNumPacketsSent(0) {
     71     CHECK_GE(fd, 0);
     72 
     73     mFileSize = lseek64(fd, 0, SEEK_END);
     74     lseek64(fd, 0, SEEK_SET);
     75 }
     76 
     77 MyStreamSource::~MyStreamSource() {
     78     close(mFd);
     79     mFd = -1;
     80 }
     81 
     82 void MyStreamSource::setListener(const sp<IStreamListener> &listener) {
     83     mListener = listener;
     84 }
     85 
     86 void MyStreamSource::setBuffers(const Vector<sp<IMemory> > &buffers) {
     87     mBuffers = buffers;
     88 }
     89 
     90 void MyStreamSource::onBufferAvailable(size_t index) {
     91     CHECK_LT(index, mBuffers.size());
     92 
     93 #if 0
     94     if (mNumPacketsSent >= 20000) {
     95         ALOGI("signalling discontinuity now");
     96 
     97         off64_t offset = 0;
     98         CHECK((offset % 188) == 0);
     99 
    100         lseek(mFd, offset, SEEK_SET);
    101 
    102         sp<AMessage> extra = new AMessage;
    103         extra->setInt32(IStreamListener::kKeyFormatChange, 0);
    104 
    105         mListener->issueCommand(
    106                 IStreamListener::DISCONTINUITY, false /* synchronous */, extra);
    107 
    108         mNumPacketsSent = 0;
    109     }
    110 #endif
    111 
    112     sp<IMemory> mem = mBuffers.itemAt(index);
    113 
    114     ssize_t n = read(mFd, mem->pointer(), mem->size());
    115     if (n <= 0) {
    116         mListener->issueCommand(IStreamListener::EOS, false /* synchronous */);
    117     } else {
    118         mListener->queueBuffer(index, n);
    119 
    120         mNumPacketsSent += n / 188;
    121     }
    122 }
    123 ////////////////////////////////////////////////////////////////////////////////
    124 
    125 struct MyConvertingStreamSource : public BnStreamSource {
    126     MyConvertingStreamSource(const char *filename);
    127 
    128     virtual void setListener(const sp<IStreamListener> &listener);
    129     virtual void setBuffers(const Vector<sp<IMemory> > &buffers);
    130 
    131     virtual void onBufferAvailable(size_t index);
    132 
    133 protected:
    134     virtual ~MyConvertingStreamSource();
    135 
    136 private:
    137     Mutex mLock;
    138     Condition mCondition;
    139 
    140     sp<IStreamListener> mListener;
    141     Vector<sp<IMemory> > mBuffers;
    142 
    143     sp<MPEG2TSWriter> mWriter;
    144 
    145     ssize_t mCurrentBufferIndex;
    146     size_t mCurrentBufferOffset;
    147 
    148     List<size_t> mBufferQueue;
    149 
    150     static ssize_t WriteDataWrapper(void *me, const void *data, size_t size);
    151     ssize_t writeData(const void *data, size_t size);
    152 
    153     DISALLOW_EVIL_CONSTRUCTORS(MyConvertingStreamSource);
    154 };
    155 
    156 ////////////////////////////////////////////////////////////////////////////////
    157 
    158 MyConvertingStreamSource::MyConvertingStreamSource(const char *filename)
    159     : mCurrentBufferIndex(-1),
    160       mCurrentBufferOffset(0) {
    161     sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
    162     CHECK(dataSource != NULL);
    163 
    164     sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
    165     CHECK(extractor != NULL);
    166 
    167     mWriter = new MPEG2TSWriter(
    168             this, &MyConvertingStreamSource::WriteDataWrapper);
    169 
    170     for (size_t i = 0; i < extractor->countTracks(); ++i) {
    171         const sp<MetaData> &meta = extractor->getTrackMetaData(i);
    172 
    173         const char *mime;
    174         CHECK(meta->findCString(kKeyMIMEType, &mime));
    175 
    176         if (strncasecmp("video/", mime, 6) && strncasecmp("audio/", mime, 6)) {
    177             continue;
    178         }
    179 
    180         CHECK_EQ(mWriter->addSource(extractor->getTrack(i)), (status_t)OK);
    181     }
    182 
    183     CHECK_EQ(mWriter->start(), (status_t)OK);
    184 }
    185 
    186 MyConvertingStreamSource::~MyConvertingStreamSource() {
    187 }
    188 
    189 void MyConvertingStreamSource::setListener(
    190         const sp<IStreamListener> &listener) {
    191     mListener = listener;
    192 }
    193 
    194 void MyConvertingStreamSource::setBuffers(
    195         const Vector<sp<IMemory> > &buffers) {
    196     mBuffers = buffers;
    197 }
    198 
    199 ssize_t MyConvertingStreamSource::WriteDataWrapper(
    200         void *me, const void *data, size_t size) {
    201     return static_cast<MyConvertingStreamSource *>(me)->writeData(data, size);
    202 }
    203 
    204 ssize_t MyConvertingStreamSource::writeData(const void *data, size_t size) {
    205     size_t totalWritten = 0;
    206 
    207     while (size > 0) {
    208         Mutex::Autolock autoLock(mLock);
    209 
    210         if (mCurrentBufferIndex < 0) {
    211             while (mBufferQueue.empty()) {
    212                 mCondition.wait(mLock);
    213             }
    214 
    215             mCurrentBufferIndex = *mBufferQueue.begin();
    216             mCurrentBufferOffset = 0;
    217 
    218             mBufferQueue.erase(mBufferQueue.begin());
    219         }
    220 
    221         sp<IMemory> mem = mBuffers.itemAt(mCurrentBufferIndex);
    222 
    223         size_t copy = size;
    224         if (copy + mCurrentBufferOffset > mem->size()) {
    225             copy = mem->size() - mCurrentBufferOffset;
    226         }
    227 
    228         memcpy((uint8_t *)mem->pointer() + mCurrentBufferOffset, data, copy);
    229         mCurrentBufferOffset += copy;
    230 
    231         if (mCurrentBufferOffset == mem->size()) {
    232             mListener->queueBuffer(mCurrentBufferIndex, mCurrentBufferOffset);
    233             mCurrentBufferIndex = -1;
    234         }
    235 
    236         data = (const uint8_t *)data + copy;
    237         size -= copy;
    238 
    239         totalWritten += copy;
    240     }
    241 
    242     return (ssize_t)totalWritten;
    243 }
    244 
    245 void MyConvertingStreamSource::onBufferAvailable(size_t index) {
    246     Mutex::Autolock autoLock(mLock);
    247 
    248     mBufferQueue.push_back(index);
    249     mCondition.signal();
    250 
    251     if (mWriter->reachedEOS()) {
    252         if (mCurrentBufferIndex >= 0) {
    253             mListener->queueBuffer(mCurrentBufferIndex, mCurrentBufferOffset);
    254             mCurrentBufferIndex = -1;
    255         }
    256 
    257         mListener->issueCommand(IStreamListener::EOS, false /* synchronous */);
    258     }
    259 }
    260 
    261 ////////////////////////////////////////////////////////////////////////////////
    262 
    263 struct MyClient : public BnMediaPlayerClient {
    264     MyClient()
    265         : mEOS(false) {
    266     }
    267 
    268     virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) {
    269         Mutex::Autolock autoLock(mLock);
    270 
    271         if (msg == MEDIA_ERROR || msg == MEDIA_PLAYBACK_COMPLETE) {
    272             mEOS = true;
    273             mCondition.signal();
    274         }
    275     }
    276 
    277     void waitForEOS() {
    278         Mutex::Autolock autoLock(mLock);
    279         while (!mEOS) {
    280             mCondition.wait(mLock);
    281         }
    282     }
    283 
    284 protected:
    285     virtual ~MyClient() {
    286     }
    287 
    288 private:
    289     Mutex mLock;
    290     Condition mCondition;
    291 
    292     bool mEOS;
    293 
    294     DISALLOW_EVIL_CONSTRUCTORS(MyClient);
    295 };
    296 
    297 int main(int argc, char **argv) {
    298     android::ProcessState::self()->startThreadPool();
    299 
    300     DataSource::RegisterDefaultSniffers();
    301 
    302     if (argc != 2) {
    303         fprintf(stderr, "Usage: %s filename\n", argv[0]);
    304         return 1;
    305     }
    306 
    307     sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
    308     CHECK_EQ(composerClient->initCheck(), (status_t)OK);
    309 
    310     sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
    311             ISurfaceComposer::eDisplayIdMain));
    312     DisplayInfo info;
    313     SurfaceComposerClient::getDisplayInfo(display, &info);
    314     ssize_t displayWidth = info.w;
    315     ssize_t displayHeight = info.h;
    316 
    317     ALOGV("display is %d x %d\n", displayWidth, displayHeight);
    318 
    319     sp<SurfaceControl> control =
    320         composerClient->createSurface(
    321                 String8("A Surface"),
    322                 displayWidth,
    323                 displayHeight,
    324                 PIXEL_FORMAT_RGB_565,
    325                 0);
    326 
    327     CHECK(control != NULL);
    328     CHECK(control->isValid());
    329 
    330     SurfaceComposerClient::openGlobalTransaction();
    331     CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
    332     CHECK_EQ(control->show(), (status_t)OK);
    333     SurfaceComposerClient::closeGlobalTransaction();
    334 
    335     sp<Surface> surface = control->getSurface();
    336     CHECK(surface != NULL);
    337 
    338     sp<IServiceManager> sm = defaultServiceManager();
    339     sp<IBinder> binder = sm->getService(String16("media.player"));
    340     sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
    341 
    342     CHECK(service.get() != NULL);
    343 
    344     sp<MyClient> client = new MyClient;
    345 
    346     sp<IStreamSource> source;
    347 
    348     char prop[PROPERTY_VALUE_MAX];
    349     bool usemp4 = property_get("media.stagefright.use-mp4source", prop, NULL) &&
    350             (!strcmp(prop, "1") || !strcasecmp(prop, "true"));
    351 
    352     size_t len = strlen(argv[1]);
    353     if ((!usemp4 && len >= 3 && !strcasecmp(".ts", &argv[1][len - 3])) ||
    354         (usemp4 && len >= 4 &&
    355          (!strcasecmp(".mp4", &argv[1][len - 4])
    356             || !strcasecmp(".3gp", &argv[1][len- 4])
    357             || !strcasecmp(".3g2", &argv[1][len- 4])))) {
    358         int fd = open(argv[1], O_RDONLY);
    359 
    360         if (fd < 0) {
    361             fprintf(stderr, "Failed to open file '%s'.", argv[1]);
    362             return 1;
    363         }
    364 
    365         source = new MyStreamSource(fd);
    366     } else {
    367         printf("Converting file to transport stream for streaming...\n");
    368 
    369         source = new MyConvertingStreamSource(argv[1]);
    370     }
    371 
    372     sp<IMediaPlayer> player =
    373         service->create(getpid(), client, 0);
    374 
    375     if (player != NULL && player->setDataSource(source) == NO_ERROR) {
    376         player->setVideoSurfaceTexture(surface->getSurfaceTexture());
    377         player->start();
    378 
    379         client->waitForEOS();
    380 
    381         player->stop();
    382     } else {
    383         fprintf(stderr, "failed to instantiate player.\n");
    384     }
    385 
    386     composerClient->dispose();
    387 
    388     return 0;
    389 }
    390