Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android用surface直接顯示yuv數據(二)

Android用surface直接顯示yuv數據(二)

編輯:關於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;//顯示

以上五步是surface顯示圖形必不可少的五步。

 

有了以上分析,我們直接上代碼:(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;
}

Android.mk (這次依賴的庫少了很多)

 

 

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)


 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved