Android MediaPlayer stream實現

對於Ait類的Camera,使用已編碼數據(H264)進行Preview.若使用原始的SurfaceTexture實現,須要擴展ANativeWindow支持的視頻格式,也會涉及到OpenGL相關的內容,工做量巨大。java

另外一種方式是使用MediaPlayer實現,MediaPlayer支持三種源,咱們應該要使用Stream方式,但也不肯定,看一下service的底層實現,也就是與Hardcodec的對接。另外關注一下Buffer的傳遞過程。android

Java Frameworkapp

  frameworks/base/media/java/android/media/MediaPlayer.java框架

JNIide

  frameworks/base/media/jni/android_media_MediaPlayer.cpp函數

cpp Framework(libmedia.so):clientui

  frameworks/av/media/libmediathis

include 編碼

  frameworks/av/include/mediaspa

Service

  frameworks/av/media/libmediaplayerservice

一、APP@packages/apps/Launchertv/src/com/xxxx/Launcher/VideoMediaPlayer.java

對於一個簡單的APP,例如Jervis的Launcher 播放窗口,app須要作的較爲簡單

mMediaPlayer = new MediaPlayer();
mMediaPlayer.reset();
mMediaPlayer.setDataSource(VIDEO_PATH + mFileName.get(mCurrentItem));// 針對與本地視頻文件播放
mMediaPlayer.prepare(); 
mMediaPlayer.start();

 

二、實現

源碼中有一個stream的參考,framework/av/cmds/stagefright/stream.cpp,但不可用,看了如下代碼,沒有mMediaPlayer.prepare的調用,且原代碼中並不是對框架中MediaPlayer的調用,而是本身申請service。

所以新建類MyClient

struct MyClient : RefBase {
    MyClient()
        : mEOS(false) {
        mp = new MediaPlayer();
        mp->setListener(new MyListener(this));
    }

    class MyListener: public MediaPlayerListener {
    public:
        MyListener(sp<MyClient> mc) {
        mc4listener = mc;
        }

        ~MyListener() {
        }


            virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) {
                Mutex::Autolock autoLock(mc4listener->mLock);
            
        
        fprintf(stderr, "leon msg=%d\n", msg);
                if (msg == MEDIA_ERROR || msg == MEDIA_PLAYBACK_COMPLETE) {
                    mc4listener->mEOS = true;
                    mc4listener->mCondition.signal();
                }
            }
        sp<MyClient> mc4listener;
    };

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

    sp<MediaPlayer> mp;
protected:
    virtual ~MyClient() {
    }

private:
    Mutex mLock;
    Condition mCondition;

    bool mEOS;

    DISALLOW_EVIL_CONSTRUCTORS(MyClient);
};

在構造函數中new 一個MediaPlayer類,並設置Listener,此Listener是Service想MediaPlayer的通知。

另外新建streamSource類,在本例中,是經過打開一個Ts文件,讀取數據並通知service進行播放,他繼承了BnStreamSource類,並實現了三個重要的虛函數

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);
};

 setListener:設置mListener,經過此listener可調用service的一些函數實現。例以下面的兩個函數

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

 

setBuffers:將server中申請的IMemory容器傳遞給StreamSource類,用於向其中寫入ts數據。

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

 

onBufferAvailable(size_t index):向可用的內存塊中寫入數據,完成後經過IStreamListener通知server

void MyStreamSource::onBufferAvailable(size_t index) {
    //CHECK_LT(index, mBuffers.size());
    if (index<0 || index >=8 )
    {
        fprintf(stderr, "size=%d,\tindex=%u\n", mBuffers.size(), index);
        return;
    }
    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;
    }
}

 

三、CameraHD應用中的考慮

在Camera Service中將MyClient中的實現移植到startPreview中,獲取到H264數據後,打包成TS流,經過MyStreamSource將數據寫入MediaPlayerService的buffer中。

http://pan.baidu.com/share/link?shareid=3224742726&uk=2852507874

這是將H264數據打包爲TS流的工程,備份

相關文章
相關標籤/搜索