對於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流的工程,備份