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