您的位置:首页 > 移动开发 > Android开发

Android MediaPlayer stream实现

2013-06-28 09:45 513 查看
对于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\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;
}
}


3、CameraHD应用中的考虑

在Camera Service中将MyClient中的实现移植到startPreview中,获取到H264数据后,打包成TS流,通过MyStreamSource将数据写入MediaPlayerService的buffer中。
http://pan.baidu.com/share/link?shareid=3224742726&uk=2852507874
这是将H264数据打包为TS流的工程,备份
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: