x264 c++ encode example

有了 libx264 當然要試編一下影片,encode 出的檔案只是為 h264 的 bitstream ,並不是直接封裝成可直接撥放的檔案,還需要一些 wrapper 程序封裝成常見的影片格式如 ( mp4, mkv …)

不過也可以懶人用 ffmpeg 封裝 XD

ffmpeg -i in_file.h264 -vcodec copy out_file.mp4

 

這基本上就是一連串的繼承寄生關係,階層越高越笨重,也越複雜,這邊就第一步 codec 層來做個小實驗。

  1. codec library: e.g. x264
    • only encoder & decoder for data stream  (h264)
  2. video file container: e.g. libav
    • pack/unpack video file (mp4, avi, mkv)
  3. multi container & codec: e.g. ffmpeg
    • All file formats & all codecs (avi:h264, avi:h265, mkv:h264…)

 

Reference: h264/h265 bit stream 分析工具,可以幫助理解檔案格式

後面附上程式碼

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <x264.h>

int imgSizeX = 1920;
int imgSizeY = 1080;
int frameNum = 60;

void setParam(x264_param_t &param) {
	x264_param_default_preset( &param, "medium", NULL );
	param.i_csp            = X264_CSP_I420;
	param.i_width          = imgSizeX;
	param.i_height         = imgSizeY;
	param.b_vfr_input      = 0;
	param.b_repeat_headers = 1;
	param.i_keyint_max     = 5;
	param.b_annexb         = 1;
	param.b_opencl         = 1;
	param.i_fps_den        = 1001;
	param.i_fps_num        = 30000;
	x264_param_apply_profile( &param, "high" );
}

void drawImgYUV(x264_picture_t &pic) {
	static int count = 0;
	// image input settings
	for (int y = 0, j = 0; y < imgSizeY; ++y) {
		for (int x = 0; x < imgSizeX; ++x, j++) {
			// only draw Y channel, let UV channel to be default values.
			pic.img.plane[0][j] = (x+count*5) & 0xFF;
		}
	}
	count++;
}

int main() {
	FILE *file = fopen("out.h264", "wb");

	x264_param_t param;
	setParam( param );

	x264_t *h = x264_encoder_open( &param );

	x264_picture_t pic;
	x264_picture_t pic_out;
	x264_nal_t *nal;
	int i_nal;
	x264_picture_alloc( &pic, param.i_csp, param.i_width, param.i_height );

	for (int i = 0; i < frameNum; ++i) {
		drawImgYUV( pic );
		int bytes = x264_encoder_encode( h, &nal, &i_nal, &pic, &pic_out );
		printf("frame %d bytes %d\n", i, bytes);
		if ( bytes > 0 ) {
			fwrite( nal->p_payload, bytes, 1, file );
		}
	}

	/* Flush delayed frames */
	while( x264_encoder_delayed_frames( h ) )
	{
		static int count = 0;
		int bytes = x264_encoder_encode( h, &nal, &i_nal, NULL, &pic_out );
		printf("frame %d bytes %d\n", count++, bytes);
		if ( bytes > 0 ) {
			fwrite( nal->p_payload, bytes, 1, file );
		}
	}

	x264_picture_clean( &pic );
	x264_encoder_close( h );
	fclose(file);
	return 0;
}

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *