|
研究了一段时间Android的surface系统,一直执着地认为所有在surface或者屏幕上显示的画面,必须要转换成RGB才能显示,yuv数据也要通过颜色空间转换成RGB才能显示。可最近在研究stagefright视频显示时发现,根本找不到omx解码后的yuv是怎么转换成RGB的代码,yuv数据在render之后就找不到去向了,可画面确确实实的显示出来了,这从此颠覆了yuv必须要转换成RGB才能显示的真理了。
稍微看一下AsomePlayer的代码,不难发现,视频的每一帧是通过调用了SoftwareRenderer来渲染显示的,我也尝试用利用SoftwareRenderer来直接render yuv数据显示,竟然成功了,这是一个很大的突破,比如以后摄像头采集到的yuv,可以直接丢yuv数据到surface显示,无需耗时耗效率的yuv转RGB了。
上一篇文章主要是参照AwesomePlayer直接用SoftwareRenderer类来显示yuv,为了能用到这个类,不惜依赖了libstagefright、libstagefright_color_conversion等动态静态库,从而造成程序具有很高的耦合度,也不便于我们理解yuv数据直接显示的深层次原因。
于是我开始研究SoftwareRenderer的具体实现,我们来提取SoftwareRenderer的核心代码,自己来实现yuv的显示。
SoftwareRenderer就只有三个方法,一个构造函数,一个析构函数,还有一个负责显示的render方法。构造方法里有个很重要的地方native_window_set_buffers_geometry这里是配置即将申请的图形缓冲区的宽高和颜色空间,忽略了这个地方,画面将用默认的值显示,将造成显示不正确。render函数里最重要的三个地方,一个的dequeBuffer,一个是mapper,一个是queue_buffer。
-
native_window_set_buffers_geometry;
-
native_window_dequeue_buffer_and_wait;
-
mapper.lock(buf->handle,GRALLOC_USAGE_SW_WRITE_OFTEN,bounds,&dst));
-
memcpy(dst,data,dst_y_size+dst_c_size*2);
-
mNativeWindow->queueBuffer;
以上五步是surface显示图形必不可少的五步。
有了以上分析,我们直接上代码:(yuv数据下载地址点击打开链接,放到sdcard)
main.cpp
-
#include<cutils/memory.h>
-
-
#include<unistd.h>
-
#include<utils/Log.h>
-
-
#include<binder/IPCThreadState.h>
-
#include<binder/ProcessState.h>
-
#include<binder/IServiceManager.h>
-
#include<media/stagefright/foundation/ADebug.h>
-
#include<gui/Surface.h>
-
#include<gui/SurfaceComposerClient.h>
-
#include<gui/ISurfaceComposer.h>
-
#include<ui/DisplayInfo.h>
-
#include<android/native_window.h>
-
#include<system/window.h>
-
#include<ui/GraphicBufferMapper.h>
-
-
usingnamespaceandroid;
-
-
-
staticintALIGN(intx,inty){
-
-
return(x+y-1)&~(y-1);
-
}
-
-
voidrender(
-
constvoid*data,size_tsize,constsp<ANativeWindow>&nativeWindow,intwidth,intheight){
-
sp<ANativeWindow>mNativeWindow=nativeWindow;
-
interr;
-
intmCropWidth=width;
-
intmCropHeight=height;
-
-
inthalFormat=HAL_PIXEL_FORMAT_YV12;
-
intbufWidth=(mCropWidth+1)&~1;
-
intbufHeight=(mCropHeight+1)&~1;
-
-
CHECK_EQ(0,
-
native_window_set_usage(
-
mNativeWindow.get(),
-
GRALLOC_USAGE_SW_READ_NEVER|GRALLOC_USAGE_SW_WRITE_OFTEN
-
|GRALLOC_USAGE_HW_TEXTURE|GRALLOC_USAGE_EXTERNAL_DISP));
-
-
CHECK_EQ(0,
-
native_window_set_scaling_mode(
-
mNativeWindow.get(),
-
NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW));
-
-
-
-
-
CHECK_EQ(0,native_window_set_buffers_geometry(
-
mNativeWindow.get(),
-
bufWidth,
-
bufHeight,
-
halFormat));
-
-
-
ANativeWindowBuffer*buf;
-
-
if((err=native_window_dequeue_buffer_and_wait(mNativeWindow.get(),
-
&buf))!=0){
-
ALOGW("Surface::dequeueBufferreturnederror%d",err);
-
return;
-
}
-
-
GraphicBufferMapper&mapper=GraphicBufferMapper::get();
-
-
Rectbounds(mCropWidth,mCropHeight);
-
-
void*dst;
-
CHECK_EQ(0,mapper.lock(
-
buf->handle,GRALLOC_USAGE_SW_WRITE_OFTEN,bounds,&dst));
-
-
if(true){
-
size_tdst_y_size=buf->stride*buf->height;
-
size_tdst_c_stride=ALIGN(buf->stride/2,16);
-
size_tdst_c_size=dst_c_stride*buf->height/2;
-
-
memcpy(dst,data,dst_y_size+dst_c_size*2);
-
}
-
-
CHECK_EQ(0,mapper.unlock(buf->handle));
-
-
if((err=mNativeWindow->queueBuffer(mNativeWindow.get(),buf,
-
-1))!=0){
-
ALOGW("Surface::queueBufferreturnederror%d",err);
-
}
-
buf=NULL;
-
}
-
-
boolgetYV12Data(constchar*path,unsignedchar*pYUVData,intsize){
-
FILE*fp=fopen(path,"rb");
-
if(fp==NULL){
-
printf("read%sfail!!!!!!!!!!!!!!!!!!!\n",path);
-
returnfalse;
-
}
-
fread(pYUVData,size,1,fp);
-
fclose(fp);
-
returntrue;
-
}
-
-
intmain(void){
-
-
sp<ProcessState>proc(ProcessState::self());
-
ProcessState::self()->startThreadPool();
-
-
-
sp<SurfaceComposerClient>client=newSurfaceComposerClient();
-
sp<IBinder>dtoken(SurfaceComposerClient::getBuiltInDisplay(
-
ISurfaceComposer::eDisplayIdMain));
-
DisplayInfodinfo;
-
-
status_tstatus=SurfaceComposerClient::getDisplayInfo(dtoken,&dinfo);
-
printf("w=%d,h=%d,xdpi=%f,ydpi=%f,fps=%f,ds=%f\n",
-
dinfo.w,dinfo.h,dinfo.xdpi,dinfo.ydpi,dinfo.fps,dinfo.density);
-
if(status)
-
return-1;
-
-
sp<SurfaceControl>surfaceControl=client->createSurface(String8("testsurface"),
-
dinfo.w,dinfo.h,PIXEL_FORMAT_RGBA_8888,0);
-
-
-
printf("[%s][%d]\n",__FILE__,__LINE__);
-
intwidth,height;
-
width=320;
-
height=240;
-
intsize=width*height*3/2;
-
unsignedchar*data=newunsignedchar[size];
-
constchar*path="/mnt/sdcard/yuv_320_240.yuv";
-
getYV12Data(path,data,size);
-
-
-
SurfaceComposerClient::openGlobalTransaction();
-
surfaceControl->setLayer(100000);
-
surfaceControl->setPosition(100,100);
-
surfaceControl->setSize(width,height);
-
SurfaceComposerClient::closeGlobalTransaction();
-
sp<Surface>surface=surfaceControl->getSurface();
-
printf("[%s][%d]\n",__FILE__,__LINE__);
-
-
-
render(data,size,surface,width,height);
-
printf("[%s][%d]\n",__FILE__,__LINE__);
-
-
IPCThreadState::self()->joinThreadPool();
-
IPCThreadState::self()->stopProcess();
-
return0;
-
}
Android.mk (这次依赖的库少了很多)
-
LOCAL_PATH:=$(callmy-dir)
-
include$(CLEAR_VARS)
-
-
LOCAL_SRC_FILES:=\
-
main.cpp
-
-
LOCAL_SHARED_LIBRARIES:=\
-
libcutils\
-
libutils\
-
libbinder\
-
libui\
-
libgui\
-
libstagefright_foundation
-
-
LOCAL_MODULE:=MyShowYUV
-
-
LOCAL_MODULE_TAGS:=tests
-
-
include$(BUILD_EXECUTABLE)
转载请注明出处http://blog.csdn.net/tung214/article/details/37651825
感谢这篇文章总结:http://blog.csdn.net/crazyman2010/article/details/41750623
|