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