zoukankan      html  css  js  c++  java
  • 最简单的视频编码器:基于libx265(编码YUV为H.265)

    =====================================================

    最简单的视频编码器系列文章列表:

    最简单的视频编码器:编译

    最简单的视频编码器:基于libx264(编码YUV为H.264)

    最简单的视频编码器:基于libx265(编码YUV为H.265)

    最简单的视频编码器:libvpx(编码YUV为VP8)

    =====================================================

    本文记录一个最简单的基于libx265的H.265(HEVC)视频编码器。此前记录的编码器是通过FFmpeg调用libx265完毕编码的,比如:

    《最简单的基于FFmpeg的视频编码器-更新版(YUV编码为HEVC(H.265))》

    相比与上文中的编码器,本文记录的编码器属于“轻量级”的编码器。由于它不再包括FFmpeg的代码。直接调用libx265完毕编码。因此项目的体积很小巧。该编码器能够将输入的YUV数据编码为H.265码流文件。

    流程图

    调用libx265进行视频编码的流程图例如以下所看到的。

     

    从流程图中能够看出x265的API和x264的API十分类似。它们在使用方法上仅仅有微小的不同。
    流程图中基本的函数例如以下所看到的。
    x265_param_alloc():为參数集结构体x265_param分配内存。
    x265_param_default():设置參数集结构体x265_param的缺省值。


    x265_picture_alloc():为图像结构体x265_picture分配内存。
    x265_picture_init():设置图像结构体x265_picture的缺省值。


    x265_encoder_open():打开编码器。


    x265_encoder_encode():编码一帧图像。
    x265_encoder_close():关闭编码器。
    x265_picture_free():释放x265_picture_alloc()申请的资源。
    x265_param_free():释放x265_param_alloc()申请的资源。



    存储数据的结构体例如以下所看到的。
    x265_picture:存储压缩编码前的像素数据。
    x265_nal:存储压缩编码后的码流数据。

    此外流程图中还包括一个“flush_encoder”模块。该模块使用的函数和编码模块是一样的。唯一的不同在于不再输入视频像素数据。它的作用是输出编码器中剩余的码流数据。

    源码

    /**
     * 最简单的基于X265的视频编码器
     * Simplest X265 Encoder
     *
     * 雷霄骅 Lei Xiaohua
     * leixiaohua1020@126.com
     * 中国传媒大学/数字电视技术
     * Communication University of China / Digital TV Technology
     * http://blog.csdn.net/leixiaohua1020
     *
     * 本程序能够YUV格式的像素数据编码为H.265码流,是最简单的
     * 基于libx265的视频编码器
     *
     * This software encode YUV data to H.265 bitstream.
     * It's the simplest encoder example based on libx265.
     */
    #include <stdio.h>
    #include <stdlib.h>
    
    #if defined ( __cplusplus)
    extern "C"
    {
    #include "x265.h"
    };
    #else
    #include "x265.h"
    #endif
    
    int main(int argc, char** argv){
    	int i,j;
    	FILE *fp_src=NULL;
    	FILE *fp_dst=NULL;
    	int y_size;
    	int buff_size;
    	char *buff=NULL;
    	int ret;
    	x265_nal *pNals=NULL;
    	uint32_t iNal=0;
    
    	x265_param* pParam=NULL;
    	x265_encoder* pHandle=NULL;
    	x265_picture *pPic_in=NULL;
    
    	//Encode 50 frame
    	//if set 0, encode all frame
    	int frame_num=50;
    	int csp=X265_CSP_I420;
    	int width=640,height=360;
    
    	fp_src=fopen("../cuc_ieschool_640x360_yuv420p.yuv","rb");
    	//fp_src=fopen("../cuc_ieschool_640x360_yuv444p.yuv","rb");
    
    	fp_dst=fopen("cuc_ieschool.h265","wb");
    	//Check
    	if(fp_src==NULL||fp_dst==NULL){
    		return -1;
    	}
    
    	pParam=x265_param_alloc();
    	x265_param_default(pParam);
    	pParam->bRepeatHeaders=1;//write sps,pps before keyframe
    	pParam->internalCsp=csp;
    	pParam->sourceWidth=width;
    	pParam->sourceHeight=height;
    	pParam->fpsNum=25;
    	pParam->fpsDenom=1;
    	//Init
    	pHandle=x265_encoder_open(pParam);
    	if(pHandle==NULL){
    		printf("x265_encoder_open err
    ");
    		return 0;
    	}
    	y_size = pParam->sourceWidth * pParam->sourceHeight;
    
    	pPic_in = x265_picture_alloc();
    	x265_picture_init(pParam,pPic_in);
    	switch(csp){
    	case X265_CSP_I444:{
    		buff=(char *)malloc(y_size*3);
    		pPic_in->planes[0]=buff;
    		pPic_in->planes[1]=buff+y_size;
    		pPic_in->planes[2]=buff+y_size*2;
    		pPic_in->stride[0]=width;
    		pPic_in->stride[1]=width;
    		pPic_in->stride[2]=width;
    		break;
    					   }
    	case X265_CSP_I420:{
    		buff=(char *)malloc(y_size*3/2);
    		pPic_in->planes[0]=buff;
    		pPic_in->planes[1]=buff+y_size;
    		pPic_in->planes[2]=buff+y_size*5/4;
    		pPic_in->stride[0]=width;
    		pPic_in->stride[1]=width/2;
    		pPic_in->stride[2]=width/2;
    		break;
    					   }
    	default:{
    		printf("Colorspace Not Support.
    ");
    		return -1;
    			}
    	}
    	
    	//detect frame number
    	if(frame_num==0){
    		fseek(fp_src,0,SEEK_END);
    		switch(csp){
    		case X265_CSP_I444:frame_num=ftell(fp_src)/(y_size*3);break;
    		case X265_CSP_I420:frame_num=ftell(fp_src)/(y_size*3/2);break;
    		default:printf("Colorspace Not Support.
    ");return -1;
    		}
    		fseek(fp_src,0,SEEK_SET);
    	}
    
    	//Loop to Encode
    	for( i=0;i<frame_num;i++){
    		switch(csp){
    		case X265_CSP_I444:{
    			fread(pPic_in->planes[0],1,y_size,fp_src);		//Y
    			fread(pPic_in->planes[1],1,y_size,fp_src);		//U
    			fread(pPic_in->planes[2],1,y_size,fp_src);		//V
    			break;}
    		case X265_CSP_I420:{
    			fread(pPic_in->planes[0],1,y_size,fp_src);		//Y
    			fread(pPic_in->planes[1],1,y_size/4,fp_src);	//U
    			fread(pPic_in->planes[2],1,y_size/4,fp_src);	//V
    			break;}
    		default:{
    			printf("Colorspace Not Support.
    ");
    			return -1;}
    		}
    
    		ret=x265_encoder_encode(pHandle,&pNals,&iNal,pPic_in,NULL);	
    		printf("Succeed encode %5d frames
    ",i);
    
    		for(j=0;j<iNal;j++){
    			fwrite(pNals[j].payload,1,pNals[j].sizeBytes,fp_dst);
    		}	
    	}
    	//Flush Decoder
    	while(1){
    		ret=x265_encoder_encode(pHandle,&pNals,&iNal,NULL,NULL);
    		if(ret==0){
    			break;
    		}
    		printf("Flush 1 frame.
    ");
    
    		for(j=0;j<iNal;j++){
    			fwrite(pNals[j].payload,1,pNals[j].sizeBytes,fp_dst);
    		}
    	}
    	
    	x265_encoder_close(pHandle);
    	x265_picture_free(pPic_in);
    	x265_param_free(pParam);
    	free(buff);
    	fclose(fp_src);
    	fclose(fp_dst);
    	
    	return 0;
    }

    执行结果

    程序的输入为一个YUV文件(已经測试过YUV444P和YUV420P两种格式)。


    输出为H.265码流文件。


    H.265码流文件的信息例如以下所看到的。


    下载


    Simplest Encoder

    项目主页

    SourceForge:https://sourceforge.net/projects/simplestencoder/

    Github:https://github.com/leixiaohua1020/simplest_encoder

    开源中国:http://git.oschina.net/leixiaohua1020/simplest_encoder


    CDSN下载地址:http://download.csdn.net/detail/leixiaohua1020/8284105


    该解决方式包括了几个常见的编码器的使用演示样例:
    simplest_vpx_encoder:最简单的基于libvpx的视频编码器
    simplest_x264_encoder:最简单的基于libx264的视频编码器
    simplest_x265_encoder:最简单的基于libx265的视频编码器

  • 相关阅读:
    简单下拉列表的实现
    App Store 加急审核解析
    iOS 封装一个带复制功能的UILabel
    Xcode 控制台打印Unicode字符串转换为中文
    修改系统UITableViewCell的ImageView大小
    iOS SDWebImage实现原理详解
    Mac电脑用终端生成SSH key 访问自己的Github
    MVC与MVVM之间在IOS中的区别
    iOS TabBarItem设置红点(未读消息)
    virtualenv 创建python虚拟环境
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5058830.html
Copyright © 2011-2022 走看看