• X264编码实现


    H264
      H264的官方测试源码,由德国hhi研究所负责开发。
    特点:实现了264所有的特性,由于是官方的测试源码,所以学术研究的算法都是在JM基础上实现并和JM进行比较。但其程序结构冗长,
    只考虑引入各种新特性以提高编码性能,忽视了编码复杂度,其编码复杂度极高,不宜实用。
    X264
      网上自由组织联合开发的兼容264标准码流的编码器,创始人是一个法国人。X264在网上的口碑极佳。
    特点:注重实用。和JM相比,在不明显降低编码性能的前提下,努力降低编码的计算复杂度,故X264摈弃了264中一些对编码性能贡献
    微笑但计算复杂度极高的新特性,如多参考帧、帧间预测中不必要的块模式、CABAC等。
    编码格式输出:
      总的来说H264的码流的打包方式有两种,一种为annex-b byte stream format的格式,这个是绝大部分编码器的默认输出格式,就是
    每个帧的开头的3~4个字节是H264的start_code,0x00000001或者0x000001。
    另一种是原始的NAL打包格式,就是开始的若干字节(1,2,4字节)是NAL的长度,而不是start_code,此时必须借助某个全局的数据
    来获得编码器的profile,level,PPS,SPS等信息才可以解码。

    h264encoder.h

    /**
    *
    * Created on: Dec 10, 2010
    *  Author: Henry.wen
    */
    #ifndef _H264ENCODER_H
    #define _H264ENCODER_H
    
    #include <stdint.h>
    #include <inttypes.h>
    
    extern "C"
    {
    #include "matroska.h"
    }
    
    void save_image(const char* filePath, const void* bufferBase, int width, int height);
    
    int encoder_init(const char* filePath, int width, int height);
    
    int encoder_frame(const void* frame);
    
    void encoder_close();
    
    #endif
    

     h264encoder.cpp

    extern "C"
    {
    #include <matroska.h>
    }
    
    #include <skia/core/SkBitmap.h>
    #include <skia/images/SkImageEncoder.h>
    
    #include <android_runtime/AndroidRuntime.h>
    
    #include "h264encoder.h"
    
    #ifndef X264_MAX
    #define X264_MAX( a, b ) ( (a) < (b) ? (b) : (a))
    #endif
    
    x264_param_t    g_param;
    x264_picture_t  g_pic_in;
    x264_picture_t  g_pic_out;
    x264_t         *g_encoder  = NULL;
    int             g_width    = 0;
    int             g_height   = 0;
    FILE*           g_file     = 0;
    int64_t         g_pts      = 0;
    int             g_flagInit = 0;
    
    using namespace android;
    static Mutex sg_mutexLock;
    
    #ifndef LOGI
    #define LOGI(...) ((void)__android_log_print("H264ENCODE",  MOBIHEARTCAMERA_LOG_TAG, __VA_ARGS__))
    #endif
    
    void save_image(const char* filePath, const void* bufferBase, int width, int height)
    {
    	Mutex::Autolock lock(sg_mutexLock);
    	SkBitmap b;
    	b.setConfig(SkBitmap::kARGB_8888_Config, width, height);
    	b.setPixels((void*)bufferBase);
    	SkImageEncoder::EncodeFile(filePath, b, SkImageEncoder::kJPEG_Type, SkImageEncoder::kDefaultQuality);
    }
    
    int encoder_init(const char* filePath, int width, int height)
    {
    	LOGI("encoder_init ============begin");
    	if(g_flagInit != 0)
    	{
    		LOGI("encoder_init have encoding!");
    		return 0;
    	}
    
    	Mutex::Autolock lock(sg_mutexLock);
    
    	x264_param_default_preset(&g_param, "fast", "zerolatency");
    
    	g_param.i_width = width;
    	g_param.i_height = height;
    	g_param.i_fps_num = 25;
    	g_param.i_fps_den = 1;
    
    	g_width = width;
    	g_height = height;
    
    	g_param.i_keyint_max = 25;
    	g_param.b_intra_refresh = 1;
    	g_param.b_annexb = 1;
    
    	x264_param_apply_profile(&g_param, x264_profile_names[0]);
    
    	g_encoder = x264_encoder_open(&g_param);
    	if(g_encoder == 0)
    	{
    		LOGI("encoder_init open encoder fail!");
    		return -1;
    	}
    	g_param.rc.i_lookahead = 0;
    
    	if( 0 != x264_picture_alloc(&g_pic_in, X264_CSP_I420, width, height))//X264_CSP_I420
    	{
    		LOGI("encoder_init alloc picture fail!");
    		x264_encoder_close(g_encoder);
    		g_encoder = 0;
    		return -1;
    	}
    
    	g_file     = fopen(filePath, "w+b");
    	if(g_file == NULL)
    	{
    		x264_encoder_close(g_encoder);
    		g_encoder = 0;
    		return -1;
    	}
    
    	g_flagInit = 1;
    	g_pts      = 0;
    
    	return 0;
    }
    
    int encoder_frame(const void* frame)
    {
    	LOGI("encoder_frame ============begin");
    	if(g_flagInit > 0)
    	{
    		Mutex::Autolock lock(sg_mutexLock);
    
    		g_pic_in.img.plane[0] = (uint8_t*)frame;
    
    		uint8_t* tmpBuffer_uv = g_pic_in.img.plane[0] + g_width * g_height;
    		uint8_t* tmpBuffer_u = g_pic_in.img.plane[1];
    		uint8_t* tmpBuffer_v = g_pic_in.img.plane[2];
    
    		int index = 0;
    		for(int j = 0, nCount = (g_height >> 1) * g_width; j < nCount; j +=2)
    		{
    			*(tmpBuffer_u + index) = *(tmpBuffer_uv + index);
    			*(tmpBuffer_v + index + 1) = *(tmpBuffer_uv + index + 1);
    
    			++index;
    		}
    
    		int nnal;
    		x264_nal_t *nals;
    
    		g_pic_in.i_pts = g_pts;
    		g_pic_in.i_type = X264_TYPE_AUTO;
    
    		int ret = x264_encoder_encode(g_encoder, &nals, &nnal, &g_pic_in, &g_pic_out);
    		if( ret < 0)
    		{
    			LOGI("encoder_frame encode frame fail, ret = %d", ret);
    			return 0;
    		}
    		++g_pts;
    
    		fwrite(nals[0].p_payload, ret, 1, g_file );
    	}
    	LOGI("encoder_frame ============end");
    	return 0;
    }
    
    void encoder_close()
    {
    	LOGI("encoder_close ============begin");
    	Mutex::Autolock lock(sg_mutexLock);
    
    	if(g_encoder)
    		x264_encoder_close(g_encoder);
    
    	g_encoder = 0;
    
    	if(g_file)
    		fclose(g_file);
    
    	g_file = 0;
    
    	g_flagInit = 0;
    	LOGI("encoder_close ============end");
    }
    

      

     

  • 相关阅读:
    类别category 总结
    autorelease理解
    NSAutoreleasePool drain release的区别
    ios 文件管理 目录
    关于autorelease pool一个较好的理解
    iOS中四种实例变量的范围类型@private@protected@public@package
    批量删除
    会话用法 和留言板例题
    运用php做投票题,例题
    php 封装
  • 原文地址:https://www.cnblogs.com/wenrenhua08/p/3937607.html
Copyright © 2020-2023  润新知