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