• VPU硬编码


      平台是RK3066(福州瑞芯微公司),android 4.2.0,其实时VP8硬编码,与软件编码是ffpmeg,x264,xvid等软编码是有区别的。硬编码主要是依赖于
    硬件。

      硬编码:通过调用Android系统自带的Camera录制视频,实际上是调用了底层的高清编码硬件模块,也即显卡,不使用CPU,速度快
      软编码:使用CPU进行编码,如常见C/C++代码,一般编译生成的二进制都是的,速度相对较慢。例如使用Android NDK编译H264生成so库,编写jni接口,再使用java调用so库
    VPUCoder.h

    /*
     * VPUCoder.h
     *
     * Current, Only Support YUV420sp encoder and decoder
     *
     *  Created on: Dec 16, 2013
     *      Author: henry
     *
     *  Example:
     *
     *  int main()
     *  {
     *  	int ret = InitCodec();
     *  	//===========encode video
     *  	ret = StartEnc("/sdcard/test.mkv", 1280, 720, 30);
     *
     *  	while(1)
     *  	{
     *  		//get data and length, //unsigned char* data; int length
     *  		ret = ProcessEnc(data, length);
     *  	}
     *  	ret = StopEnc();
     *
     *  	//===========decode video
     *  	ret = ProcessDec("/sdcard/test.mkv", 1280, 720);
     *  	return 0;
     *  }
     */
    
    #ifndef VPUCODER_H_
    #define VPUCODER_H_
    
    /**
     * Init encoder and decoder handle, only call once, must first call
     *
     * @return 0 is successful, another fail
     */
    int InitCodec();
    
    /**
     * setup encoder configure
     * @param filePath   : save file path
     * @param enc_width  : video width
     * @param enc_height : video height
     * @param enc_fps    : video fps
     *
     * @return 0 is successful, another fail
     */
    int StartEnc(const char* filePath, uint32_t enc_width, uint32_t enc_height, uint32_t enc_fps);
    
    /**
     * stop encode video
     */
    void StopEnc();
    
    /**
     * @params data   : frame data
     * @params length : frame length
     *
     * @return 0 is successful, another fail
     */
    int ProcessEnc(const unsigned char* data, uint32_t length);
    
    /**
     * setup decoder configure
     * @param filePath   : source file path
     * @param enc_width  : video width
     * @param enc_height : video height
     *
     * @return 0 is successful, another fail
     */
    int ProcessDec(const char* filePath, uint32_t dec_width, uint32_t dec_height);
    
    #endif /* VPUCODER_H_ */
    

      VPUCoder.cpp

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    #include <vpu_global.h>
    #include <SoftwareRenderer.h>
    #include <vpu_api_interface.h>
    
    #include <utils/Log.h>
    #include <ui/DisplayInfo.h>
    #include <gui/ISurfaceTexture.h>
    #include <gui/ISurfaceComposer.h>
    #include <gui/SurfaceTextureClient.h>
    #include <gui/SurfaceComposerClient.h>
    #include <media/stagefright/MetaData.h>
    
    using namespace android;
    
    #ifdef LOGI
    	#undef LOGI
    	#undef LOGW
    	#undef LOGE
    	#undef LOGD
    #endif
    
    #define  LOG_TAG_SERVICE    "TeliDHVPU8Codec"
    #define  LOGW(...)  __android_log_print(ANDROID_LOG_WARN,  LOG_TAG_SERVICE, __VA_ARGS__)
    #define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG_SERVICE, __VA_ARGS__)
    #define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG_SERVICE, __VA_ARGS__)
    #define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,  LOG_TAG_SERVICE, __VA_ARGS__)
    
    #define MAX_STREM_LENGTH        (1280 * 400)
    
    static uint32_t g_lenght_enc        = MAX_STREM_LENGTH;
    static FILE*    g_file_enc          = NULL;
    static FILE*    g_file_dec          = NULL;
    static VPU_API  g_vpu_api;
    static void*    g_vp8encHandle      = NULL;
    static void*    g_vp8decHandle      = NULL;
    static unsigned int g_bufferLen     = 0;
    static unsigned char* g_frameBuffer = NULL;
    
    static EncParams1     g_encParams;
    static int            g_SyncFlag = 0;
    static unsigned int   g_dataSize;
    static unsigned int   g_InputTimestamp;
    static int            g_nal = 0;
    static int            g_ret = 0;
    
    int InitCodec()
    {
    	vpu_api_init(&g_vpu_api, OMX_ON2_VIDEO_CodingVPX);
    	return 0;
    }
    
    int StartEnc(const char* filePath, uint32_t enc_width, uint32_t enc_height, uint32_t enc_fps)
    {
    	LOGI("StartEnc Begin ====================");
    	if(!filePath)
    	{
    		LOGD("Please make sure file path not null!");
    		return -1;
    	}
    
    	if(g_file_enc)
    	{
    		LOGD("Another file is being encoded!");
    		return -1;
    	}
    
    	g_file_enc = fopen(filePath, "wb+");
    	if(!g_file_enc)
    	{
    		LOGD("file open fail!");
    		return -1;
    	}
    
    	g_lenght_enc = enc_width * enc_height * 3 >> 1;
    
    	memset(&g_encParams, 0, sizeof(EncParams1));
    	g_encParams.width = enc_width;
    	g_encParams.height = enc_height;
    	g_encParams.framerate = 25;
    	g_encParams.bitRate = 10000;
    
    	g_frameBuffer = (unsigned char*)malloc(MAX_STREM_LENGTH);
    
    	g_vp8encHandle = g_vpu_api.get_class_On2Encoder();
    	g_vpu_api.init_class_On2Encoder(g_vp8encHandle, &g_encParams, g_frameBuffer, &g_bufferLen);
    
    	g_nal = g_bufferLen;
    	fwrite(&g_nal, 1, sizeof(g_nal), g_file_enc);
    	fwrite(g_frameBuffer, 1, g_bufferLen, g_file_enc);
    
    	LOGI("StartEnc End g_bufferLen = %d   ====================", g_bufferLen);
    
    	return 0;
    }
    
    void StopEnc()
    {
    	LOGI("StartEnc Begin ====================");
    	g_lenght_enc = 0;
    	if(g_frameBuffer)
    	{
    		free(g_frameBuffer);
    		g_frameBuffer = NULL;
    	}
    
    	if(g_file_enc)
    	{
    		fclose(g_file_enc);
    		g_file_enc = NULL;
    	}
    
    	if(g_vp8encHandle)
    	{
    		g_vpu_api.deinit_class_On2Encoder(g_vp8encHandle);
    		g_vpu_api.destroy_class_On2Encoder(g_vp8encHandle);
    		g_vp8encHandle = NULL;
    	}
    	LOGI("StartEnc End ====================");
    }
    
    int ProcessEnc(const unsigned char* data, uint32_t length)
    {
    	if(length != g_lenght_enc)
    	{
    		LOGD("encode frame length is error!");
    		StopEnc();
    		return -1;
    	}
    
    	if(!g_file_enc)
    	{
    		LOGD("file not open!");
    		return -1;
    	}
    
    	LOGD("enc_oneframe_class_On2AvcEncoder");
    
    	g_SyncFlag = 0;
    	g_ret = g_vpu_api.enc_oneframe_class_On2Encoder(g_vp8encHandle, g_frameBuffer, &g_bufferLen
    			, (unsigned char*)data, 0, &g_dataSize, &g_InputTimestamp, &g_SyncFlag);
    
    	if(g_bufferLen > 0 && g_ret >=0)
    	{
    		LOGI("ProcessEnc encode one frame ====================");
    		g_nal = g_bufferLen;
    		fwrite(&g_nal, 1, sizeof(g_nal), g_file_enc);
    		fwrite(g_frameBuffer, 1, g_bufferLen, g_file_enc);
    		fflush(g_file_enc);
    	}
    	else
    	{
    		LOGD("ProcessEnc encode frame fail!");
    		return -1;
    	}
    	g_bufferLen = 0;
    
    	return 0;
    }
    
    int32_t FillFrameHead(unsigned char* dst, unsigned char* src, uint32_t size
    		, uint32_t bitsreamLen, int64_t time, uint32_t type, uint32_t num)
    {
    	VPU_BITSTREAM h;
    	uint32_t TimeLow = (uint32_t)(time/1000);
    	h.StartCode = BSWAP(VPU_BITSTREAM_START_CODE);
    	h.SliceLength= BSWAP(size);
    	h.SliceTime.TimeLow = BSWAP(TimeLow);
    	h.SliceTime.TimeHigh= 0;
    	h.SliceType= BSWAP(type);
    	h.SliceNum= BSWAP(num);
    	h.Res[0] = 0;
    	h.Res[1] = 0;
    	memcpy(dst, &h, bitsreamLen);
    
    	return 0;
    }
    
    int ProcessDec(const char* filePath, uint32_t dec_width, uint32_t dec_height)
    {
    	LOGI("ProcessDec Begin dec_width = %d dec_height = %d====================", dec_width, dec_height);
    	if(!filePath)
    	{
    		LOGD("src file path is null");
    		return -1;
    	}
    
    	FILE *fp_in = fopen(filePath, "rb");
    	if(!fp_in)
    	{
    		LOGD("File not exist!");
    		return -1;
    	}
    
    	char filePathOut[64];
    	memset(filePathOut, 0, 64);
    	sprintf(filePathOut, "%s.yuv", filePath);
    	g_file_dec = fopen(filePathOut, "wb+");
    
    	if(!g_file_dec)
    	{
    		LOGD("file open fail!");
    		fclose(fp_in);
    		return -1;
    	}
    
    	unsigned char* aOutBuffer;
    	unsigned char* aInputBuf  = NULL;
    	unsigned char* aInputData = NULL;
    	unsigned int   aOutputLength;
    	unsigned int   aInBufSize = MAX_STREM_LENGTH;
    
    	g_vp8decHandle = g_vpu_api.get_class_On2Decoder();
    	g_vpu_api.init_class_On2Decoder(g_vp8decHandle);
    
    	int tmp_length = (dec_width * dec_height * 3) >> 1;
    
    	LOGI(" init_class_On2AvcDecoder OK! tmp_length=%d", tmp_length);
    
    	aOutBuffer = (unsigned char*)malloc(tmp_length);
    	aInputBuf = (unsigned char*)malloc(MAX_STREM_LENGTH);
    
    	fread(&g_nal, 1, sizeof(g_nal), fp_in);
    
    	if(g_nal > 0)
    	{
    		fread(aInputBuf, 1, g_nal, fp_in);
    	}
    	else
    	{
    		LOGD("Can't decoder the video!");
    		goto fail;
    	}
    
    	int ret;
    	uint32_t bitsLen;
    	uint32_t vpu_stream_lenc;
    
    	vpu_stream_lenc = sizeof(VPU_BITSTREAM);
    	aInputData = aInputBuf + vpu_stream_lenc;
    
    	while(1)
    	{
    		ret = fread(&g_nal, 1, sizeof(g_nal), fp_in);
    		if(ret <= 0)
    			break;
    
    		fread(aInputData, 1, g_nal, fp_in);
    		aInBufSize = g_nal;
    		bitsLen    = vpu_stream_lenc + aInBufSize;
    		FillFrameHead(aInputBuf, aInputData, aInBufSize, vpu_stream_lenc, 0, 0, 0);
    
    		ret = g_vpu_api.dec_oneframe_class_On2Decoder(g_vp8decHandle, aOutBuffer, &aOutputLength, aInputBuf, &bitsLen);
    		LOGI("out_length=%d in_length=%d ret=%d", aOutputLength, bitsLen, ret);
    
    		if(aOutputLength > 0)
    		{
    			VPU_FRAME *frame = (VPU_FRAME *)aOutBuffer;
    
    			if(frame->vpumem.phy_addr)
    			{
    				VPUMemLink(&frame->vpumem);
    
    				if(frame->vpumem.vir_addr)
    				{
    					LOGI("VPUMemLinear_t size=%d", frame->vpumem.size);
    					fwrite(frame->vpumem.vir_addr, 1, tmp_length, g_file_dec);
    					fflush(g_file_dec);
    				}
    				else
    				{
    					LOGI("vir_addr is null");
    				}
    				VPUFreeLinear(&frame->vpumem);
    			}
    			else
    			{
    				LOGI("phy_addr is null");
    			}
    		}
    		fflush(fp_in);
    	}
    
    fail:
    	if(aOutBuffer)
    	{
    		free(aOutBuffer);
    		aOutBuffer = NULL;
    	}
    
    	if(aInputBuf)
    	{
    		free(aInputBuf);
    		aInputBuf = NULL;
    	}
    
    	if(g_file_dec)
    	{
    	   fclose(g_file_dec);
    	   g_file_dec = NULL;
    	}
    
    	if(fp_in)
    	{
    		fclose(fp_in);
    		fp_in = NULL;
    	}
    
    	if(g_vp8decHandle)
    	{
    	   g_vpu_api.deinit_class_On2Decoder(g_vp8decHandle);
    	   g_vpu_api.destroy_class_On2Decoder(g_vp8decHandle);
    
    	   g_vp8decHandle = NULL;
    	}
    	LOGI("ProcessDec End ====================");
    
    	return 0;
    }
    

      android.mk

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)

    VISION=1.0.1

    LOCAL_MODULE := VPU8Coder_${VISION}
    LOCAL_SRC_FILES := VPUCoder.cpp

    LOCAL_LDLIBS := -L$(LOCAL_PATH)/libs
    -lvpu
    -lcutils
    -lutils
    -lgui
    -lrk_on2
    -lstagefright

    LOCAL_C_INCLUDES :=
    $(JNI_H_INCLUDE)
    $(LOCAL_PATH)/include
    $(LOCAL_PATH)/include/media/openmax

    LOCAL_CFLAGS := -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=

    include $(BUILD_SHARED_LIBRARY)

  • 相关阅读:
    测试工作中需要用到的一些linux命令
    软件的性能测试到底是测试哪些方面
    软件测试中的安全测试包括哪些方面
    git一不小心上传了大文件,怎么破?
    接口测试校验返回数据格式,JasonSchema使用详解
    selenium定位中需要鼠标悬浮才能显示的按钮
    jenknis参数化构建,windows和shell引用变量
    selenium元素定位之父子节点、胞节点
    selenium元素定位之多个元素中选择其中的一个
    Python实现注册和三次验证登录
  • 原文地址:https://www.cnblogs.com/wenrenhua08/p/3937549.html
Copyright © 2020-2023  润新知