使用MediaPlayer中的setParameter或者invoke方法(需要反射),伪代码示例:
应用层Java伪代码:
public Parcel newRequest() {
Parcel parcel = Parcel.obtain();
parcel.writeInterfaceToken(IMEDIA_PLAYER);
return parcel;
}
public void setSurface(Surface surface) {
Parcel request= newRequest();
Parcel reply = Parcel.obtain();
request.writeInt(KEY_ID);
surface.writeToParcel(request, 0);
invokeAPI (request, reply);
}
private int invokeAPI(Parcel request, Parcel reply) {
int ret = -1;
try {
Class<?> clsMediaPlayer = Class.forName("android.media.MediaPlayer");
Method getInvoke = clsMediaPlayer.getMethod("invoke",Parcel.class, Parcel.class);
getInvoke.setAccessible(true);
getInvoke.invoke(mMediaPlayer, request , reply);
ret = reply.readInt();
Log.d(TAG,"invokeExtend reply =" + ret);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} finally {
return ret;
}
}
本地层MediaPlayerService中读取:
#include <gui/view/Surface.h>
#include <gui/IGraphicBufferProducer.h>
status_t MediaPlayerService::invoke(const Parcel &request, Parcel *reply) {
if (reply == NULL) {
return BAD_VALUE;
}
int32_t key;
status_t ret = request.readInt32(&key);
if (ret != OK) {
return ret;
}
switch (key) {
case KEY_ID :
{
android::view::Surface surfaceShim;
surfaceShim.readFromParcel(&request, /*nameAlreadyRead*/false);
if (surfaceShim.graphicBufferProducer != nullptr) {
sp<IGraphicBufferProducer> graphicBufferProducer = surfaceShim.graphicBufferProducer;
/*如此可以获取到IGraphicBufferProducer */
return OK;
}
return BAD_VALUE;
}
default:
{
return INVALID_OPERATION;
}
}
}
备注:
surfaceShim.readFromParcel( &request, /*nameAlreadyRead*/false); //第二个参数要设置为false
因为parcel中默认添加了一个name字段,这里是第一次读取这个parcel,设置false后surfaceShim.readFromParcel函数会去取这个name字段,不影响后读取parcel其他字段。
参考:
Android11\frameworks\native\libs\gui\view\Surface.cpp