对于Ait类的Camera,使用已编码数据(H264)进行Preview.若使用原始的SurfaceTexture实现,需要扩展ANativeWindow支持的视频格式,也会涉及到OpenGL相关的内容,工作量巨大。
另一种方式是使用MediaPlayer实现,MediaPlayer支持三种源,我们应该要使用Stream方式,但也不确定,看一下service的底层实现,也就是与Hardcodec的对接。另外关注一下Buffer的传递过程。
Java Framework
frameworks/base/media/java/android/media/MediaPlayer.java
JNI
frameworks/base/media/jni/android_media_MediaPlayer.cpp
cpp Framework(libmedia.so):client
frameworks/av/media/libmedia
include
frameworks/av/include/media
Service
frameworks/av/media/libmediaplayerservice
1、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();
2、实现
源码中有一个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 ", 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, index=%u ", 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; } }
3、CameraHD应用中的考虑
在Camera Service中将MyClient中的实现移植到startPreview中,获取到H264数据后,打包成TS流,通过MyStreamSource将数据写入MediaPlayerService的buffer中。
http://pan.baidu.com/share/link?shareid=3224742726&uk=2852507874
这是将H264数据打包为TS流的工程,备份