【第一篇章-android平台buffer播放探索】buffer play demo

从google发布的各个android版本源码看,android4.0开始就做了支持buffer播放的接口及demo了,编译完android SDK后在out中会生成一个可执行文件stream,这个就是一个非常好的demo测试程序,支持H264的ts播放,程序源代码位置以android4.3为例说明下,目录:android4.3\frameworks\av\cmds\stagefright,对应文件为stream.cpp,通用播放器用buffer来做突破口就在此哦,从这里开始,感兴趣的可以这么做,先做一个自己的DEMO,先播放本地文件,然后再把流媒体协议加进来集成就OK,此文件代码如下:

/*

 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


//#define LOG_NDEBUG 0
#define LOG_TAG "stream"
#include "utils/Log.h"


#include <binder/ProcessState.h>
#include <cutils/properties.h> // for property_get


#include <media/IStreamSource.h>
#include <media/mediaplayer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MPEG2TSWriter.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>


#include <binder/IServiceManager.h>
#include <media/IMediaPlayerService.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/Surface.h>


#include <fcntl.h>
#include <ui/DisplayInfo.h>


using namespace android;


struct MyStreamSource : public BnStreamSource {
    // Object assumes ownership of fd.
    MyStreamSource(int fd);


    virtual void setListener(const sp<IStreamListener> &listener);
    virtual void setBuffers(const Vector<sp<IMemory> > &buffers);


    virtual void onBufferAvailable(size_t index);


protected:
    virtual ~MyStreamSource();


private:
    int mFd;
    off64_t mFileSize;
    uint64_t mNumPacketsSent;


    sp<IStreamListener> mListener;
    Vector<sp<IMemory> > mBuffers;


    DISALLOW_EVIL_CONSTRUCTORS(MyStreamSource);
};


MyStreamSource::MyStreamSource(int fd)
    : mFd(fd),
      mFileSize(0),
      mNumPacketsSent(0) {
    CHECK_GE(fd, 0);


    mFileSize = lseek64(fd, 0, SEEK_END);
    lseek64(fd, 0, SEEK_SET);
}


MyStreamSource::~MyStreamSource() {
    close(mFd);
    mFd = -1;
}


void MyStreamSource::setListener(const sp<IStreamListener> &listener) {
    mListener = listener;
}


void MyStreamSource::setBuffers(const Vector<sp<IMemory> > &buffers) {
    mBuffers = buffers;
}


void MyStreamSource::onBufferAvailable(size_t index) {
    CHECK_LT(index, mBuffers.size());


#if 0
    if (mNumPacketsSent >= 20000) {
        ALOGI("signalling discontinuity now");


        off64_t offset = 0;
        CHECK((offset % 188) == 0);


        lseek(mFd, offset, SEEK_SET);


        sp<AMessage> extra = new AMessage;
        extra->setInt32(IStreamListener::kKeyFormatChange, 0);


        mListener->issueCommand(
                IStreamListener::DISCONTINUITY, false /* synchronous */, extra);


        mNumPacketsSent = 0;
    }
#endif


    sp<IMemory> mem = mBuffers.itemAt(index);


    ssize_t n = read(mFd, mem->pointer(), mem->size());
    if (n <= 0) {
        mListener->issueCommand(IStreamListener::EOS, false /* synchronous */);
    } else {
        mListener->queueBuffer(index, n);


        mNumPacketsSent += n / 188;
    }
}



struct MyConvertingStreamSource : public BnStreamSource {
    MyConvertingStreamSource(const char *filename);


    virtual void setListener(const sp<IStreamListener> &listener);
    virtual void setBuffers(const Vector<sp<IMemory> > &buffers);


    virtual void onBufferAvailable(size_t index);


protected:
    virtual ~MyConvertingStreamSource();


private:
    Mutex mLock;
    Condition mCondition;


    sp<IStreamListener> mListener;
    Vector<sp<IMemory> > mBuffers;


    sp<MPEG2TSWriter> mWriter;


    ssize_t mCurrentBufferIndex;
    size_t mCurrentBufferOffset;


    List<size_t> mBufferQueue;


    static ssize_t WriteDataWrapper(void *me, const void *data, size_t size);
    ssize_t writeData(const void *data, size_t size);


    DISALLOW_EVIL_CONSTRUCTORS(MyConvertingStreamSource);
};





MyConvertingStreamSource::MyConvertingStreamSource(const char *filename)
    : mCurrentBufferIndex(-1),
      mCurrentBufferOffset(0) {
    sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
    CHECK(dataSource != NULL);


    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
    CHECK(extractor != NULL);


    mWriter = new MPEG2TSWriter(
            this, &MyConvertingStreamSource::WriteDataWrapper);


    for (size_t i = 0; i < extractor->countTracks(); ++i) {
        const sp<MetaData> &meta = extractor->getTrackMetaData(i);


        const char *mime;
        CHECK(meta->findCString(kKeyMIMEType, &mime));


        if (strncasecmp("video/", mime, 6) && strncasecmp("audio/", mime, 6)) {
            continue;
        }


        CHECK_EQ(mWriter->addSource(extractor->getTrack(i)), (status_t)OK);
    }


    CHECK_EQ(mWriter->start(), (status_t)OK);
}


MyConvertingStreamSource::~MyConvertingStreamSource() {
}


void MyConvertingStreamSource::setListener(
        const sp<IStreamListener> &listener) {
    mListener = listener;
}


void MyConvertingStreamSource::setBuffers(
        const Vector<sp<IMemory> > &buffers) {
    mBuffers = buffers;
}


ssize_t MyConvertingStreamSource::WriteDataWrapper(
        void *me, const void *data, size_t size) {
    return static_cast<MyConvertingStreamSource *>(me)->writeData(data, size);
}


ssize_t MyConvertingStreamSource::writeData(const void *data, size_t size) {
    size_t totalWritten = 0;


    while (size > 0) {
        Mutex::Autolock autoLock(mLock);


        if (mCurrentBufferIndex < 0) {
            while (mBufferQueue.empty()) {
                mCondition.wait(mLock);
            }


            mCurrentBufferIndex = *mBufferQueue.begin();
            mCurrentBufferOffset = 0;


            mBufferQueue.erase(mBufferQueue.begin());
        }


        sp<IMemory> mem = mBuffers.itemAt(mCurrentBufferIndex);


        size_t copy = size;
        if (copy + mCurrentBufferOffset > mem->size()) {
            copy = mem->size() - mCurrentBufferOffset;
        }


        memcpy((uint8_t *)mem->pointer() + mCurrentBufferOffset, data, copy);
        mCurrentBufferOffset += copy;


        if (mCurrentBufferOffset == mem->size()) {
            mListener->queueBuffer(mCurrentBufferIndex, mCurrentBufferOffset);
            mCurrentBufferIndex = -1;
        }


        data = (const uint8_t *)data + copy;
        size -= copy;


        totalWritten += copy;
    }


    return (ssize_t)totalWritten;
}


void MyConvertingStreamSource::onBufferAvailable(size_t index) {
    Mutex::Autolock autoLock(mLock);


    mBufferQueue.push_back(index);
    mCondition.signal();


    if (mWriter->reachedEOS()) {
        if (mCurrentBufferIndex >= 0) {
            mListener->queueBuffer(mCurrentBufferIndex, mCurrentBufferOffset);
            mCurrentBufferIndex = -1;
        }


        mListener->issueCommand(IStreamListener::EOS, false /* synchronous */);
    }
}





struct MyClient : public BnMediaPlayerClient {
    MyClient()
        : mEOS(false) {
    }


    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) {
        Mutex::Autolock autoLock(mLock);


        if (msg == MEDIA_ERROR || msg == MEDIA_PLAYBACK_COMPLETE) {
            mEOS = true;
            mCondition.signal();
        }
    }


    void waitForEOS() {
        Mutex::Autolock autoLock(mLock);
        while (!mEOS) {
            mCondition.wait(mLock);
        }
    }


protected:
    virtual ~MyClient() {
    }


private:
    Mutex mLock;
    Condition mCondition;


    bool mEOS;


    DISALLOW_EVIL_CONSTRUCTORS(MyClient);
};


int main(int argc, char **argv) {
    android::ProcessState::self()->startThreadPool();


    DataSource::RegisterDefaultSniffers();


    if (argc != 2) {
        fprintf(stderr, "Usage: %s filename\n", argv[0]);
        return 1;
    }


    sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
    CHECK_EQ(composerClient->initCheck(), (status_t)OK);


    sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
            ISurfaceComposer::eDisplayIdMain));
    DisplayInfo info;
    SurfaceComposerClient::getDisplayInfo(display, &info);
    ssize_t displayWidth = info.w;
    ssize_t displayHeight = info.h;


    ALOGV("display is %d x %d\n", displayWidth, displayHeight);


    sp<SurfaceControl> control =
        composerClient->createSurface(
                String8("A Surface"),
                displayWidth,
                displayHeight,
                PIXEL_FORMAT_RGB_565,
                0);


    CHECK(control != NULL);
    CHECK(control->isValid());


    SurfaceComposerClient::openGlobalTransaction();
    CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
    CHECK_EQ(control->show(), (status_t)OK);
    SurfaceComposerClient::closeGlobalTransaction();


    sp<Surface> surface = control->getSurface();
    CHECK(surface != NULL);


    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(String16("media.player"));
    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);


    CHECK(service.get() != NULL);


    sp<MyClient> client = new MyClient;


    sp<IStreamSource> source;


    char prop[PROPERTY_VALUE_MAX];
    bool usemp4 = property_get("media.stagefright.use-mp4source", prop, NULL) &&
            (!strcmp(prop, "1") || !strcasecmp(prop, "true"));


    size_t len = strlen(argv[1]);
    if ((!usemp4 && len >= 3 && !strcasecmp(".ts", &argv[1][len - 3])) ||
        (usemp4 && len >= 4 &&
         (!strcasecmp(".mp4", &argv[1][len - 4])
            || !strcasecmp(".3gp", &argv[1][len- 4])
            || !strcasecmp(".3g2", &argv[1][len- 4])))) {
        int fd = open(argv[1], O_RDONLY);


        if (fd < 0) {
            fprintf(stderr, "Failed to open file '%s'.", argv[1]);
            return 1;
        }


        source = new MyStreamSource(fd);
    } else {
        printf("Converting file to transport stream for streaming...\n");


        source = new MyConvertingStreamSource(argv[1]);
    }


    sp<IMediaPlayer> player =
        service->create(client, 0);


    if (player != NULL && player->setDataSource(source) == NO_ERROR) {
        player->setVideoSurfaceTexture(surface->getIGraphicBufferProducer());
        player->start();


        client->waitForEOS();


        player->stop();
    } else {
        fprintf(stderr, "failed to instantiate player.\n");
    }


    composerClient->dispose();


    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值