編輯:關於Android編程
上一篇文章主要是參照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;//設置寬高以及顏色空間yuv420 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);//填充yuv數據到圖形緩沖區 mNativeWindow->queueBuffer;//顯示
有了以上分析,我們直接上代碼:(yuv數據下載地址點擊打開鏈接,放到sdcard)
main.cpp
#include#include #include #include #include #include #include #include #include #include #include #include #include #include //ANativeWindow 就是surface,對應surface.cpp裡的code using namespace android; //將x規整為y的倍數,也就是將x按y對齊 static int ALIGN(int x, int y) { // y must be a power of 2. return (x + y - 1) & ~(y - 1); } void render( const void *data, size_t size, const sp &nativeWindow,int width,int height) { sp mNativeWindow = nativeWindow; int err; int mCropWidth = width; int mCropHeight = height; int halFormat = HAL_PIXEL_FORMAT_YV12;//顏色空間 int bufWidth = (mCropWidth + 1) & ~1;//按2對齊 int bufHeight = (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)); // Width must be multiple of 32??? //很重要,配置寬高和和指定顏色空間yuv420 //如果這裡不配置好,下面deque_buffer只能去申請一個默認寬高的圖形緩沖區 CHECK_EQ(0, native_window_set_buffers_geometry( mNativeWindow.get(), bufWidth, bufHeight, halFormat)); ANativeWindowBuffer *buf;//描述buffer //申請一塊空閒的圖形緩沖區 if ((err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf)) != 0) { ALOGW(Surface::dequeueBuffer returned error %d, err); return; } GraphicBufferMapper &mapper = GraphicBufferMapper::get(); Rect bounds(mCropWidth, mCropHeight); void *dst; CHECK_EQ(0, mapper.lock(//用來鎖定一個圖形緩沖區並將緩沖區映射到用戶進程 buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));//dst就指向圖形緩沖區首地址 if (true){ size_t dst_y_size = buf->stride * buf->height; size_t dst_c_stride = ALIGN(buf->stride / 2, 16);//1行v/u的大小 size_t dst_c_size = dst_c_stride * buf->height / 2;//u/v的大小 memcpy(dst, data, dst_y_size + dst_c_size*2);//將yuv數據copy到圖形緩沖區 } CHECK_EQ(0, mapper.unlock(buf->handle)); if ((err = mNativeWindow->queueBuffer(mNativeWindow.get(), buf, -1)) != 0) { ALOGW(Surface::queueBuffer returned error %d, err); } buf = NULL; } bool getYV12Data(const char *path,unsigned char * pYUVData,int size){ FILE *fp = fopen(path,rb); if(fp == NULL){ printf(read %s fail !!!!!!!!!!!!!!!!!!! ,path); return false; } fread(pYUVData,size,1,fp); fclose(fp); return true; } int main(void){ // set up the thread-pool sp proc(ProcessState::self()); ProcessState::self()->startThreadPool(); // create a client to surfaceflinger sp client = new SurfaceComposerClient(); sp dtoken(SurfaceComposerClient::getBuiltInDisplay( ISurfaceComposer::eDisplayIdMain)); DisplayInfo dinfo; //獲取屏幕的寬高等信息 status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo); printf(w=%d,h=%d,xdpi=%f,ydpi=%f,fps=%f,ds=%f , dinfo.w, dinfo.h, dinfo.xdpi, dinfo.ydpi, dinfo.fps, dinfo.density); if (status) return -1; //創建surface sp surfaceControl = client->createSurface(String8(testsurface), dinfo.w, dinfo.h, PIXEL_FORMAT_RGBA_8888, 0); /*************************get yuv data from file;****************************************/ printf([%s][%d] ,__FILE__,__LINE__); int width,height; width = 320; height = 240; int size = width * height * 3/2; unsigned char *data = new unsigned char[size]; const char *path = /mnt/sdcard/yuv_320_240.yuv; getYV12Data(path,data,size);//get yuv data from file; /*********************配置surface*******************************************************************/ SurfaceComposerClient::openGlobalTransaction(); surfaceControl->setLayer(100000);//設定Z坐標 surfaceControl->setPosition(100, 100);//以左上角為(0,0)設定顯示位置 surfaceControl->setSize(width, height);//設定視頻顯示大小 SurfaceComposerClient::closeGlobalTransaction(); sp surface = surfaceControl->getSurface(); printf([%s][%d] ,__FILE__,__LINE__); /**********************顯示yuv數據******************************************************************/ render(data,size,surface,width,height); printf([%s][%d] ,__FILE__,__LINE__); IPCThreadState::self()->joinThreadPool();//可以保證畫面一直顯示,否則瞬間消失 IPCThreadState::self()->stopProcess(); return 0; }
LOCAL_PATH:= $(call my-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)
來這實習已經10多天了,今天整理整理學習時的Android筆記。正所謂好記性不如爛筆頭,今天來說說service組件。 service可以在和多
本文實例為大家分享了Android自定義加載控件,第一次小人跑動的加載效果眼前一亮,相比傳統的PrograssBar高大上不止一點,於是走起,自定義了控件LoadingV
紅米note3介紹:外觀設計紅米Note3金屬機身背面是三段式設計,上下兩端為塑料材質。配置方面紅米Note3采用5.5英寸1080P屏幕,1300萬像素後
不知道童學們是不是喜歡,個人覺得還是可以的,直接上代碼:public class ToggleButton extends View { private Sprin