http://blog.youkuaiyun.com/subfate/article/details/48437693
版权声明:本文为迟思堂主人李迟原创文章,如转载请注明出处,并附带原文超链接地址。用于商业用途请付稿费¥100/千字。谢谢。
x264是一个开源的H.264编码库。本文介绍其在x86 Linux的编译方法,并给出实例。
一、编译
x264编译需要使用到yasm,到http://www.tortall.net/projects/yasm/releases/下载,最新版本为1.3.1。编译命令如下:
# ./configure;make;make install
x264官方下载:http://www.videolan.org/developers/x264.html。下载压缩包名为:last_x264.tar.bz2。解压得到的文件名为x264-snapshot-xxxx。编译命令如下:
$ ./configure --prefix=/home/latelee/bin/x264 --enable-static
$ make
$ make install
二、实例
下面给出使用的示例。
- /**
- x264库编码要使用以下库
- -lpthread -ldl
- 要求头文件:stdint.h
- ffprobe信息:
- Input #0, h264, from 'test.h264':
- Duration: N/A, bitrate: N/A
- Stream #0:0: Video: h264 (High), yuv420p, 176x144, 25 fps, 25 tbr, 1200k tbn
- , 50 tbc
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h> // for uint8_t in x264.h
- #include "x264.h"
- int x264_encode(const char* infile, int width, int height, int type, const char* outfile)
- {
- FILE *fp_src = NULL;
- FILE *fp_dst = NULL;
- unsigned int luma_size = 0;
- unsigned int chroma_size = 0;
- int i_nal = 0;
- int i_frame = 0;
- unsigned int i_frame_size = 0;
- int csp = type;//X264_CSP_I420;
- x264_nal_t* nal = NULL;
- x264_t* handle = NULL;
- x264_picture_t* pic_in = NULL;
- x264_picture_t* pic_out = NULL;
- x264_param_t param;
- fp_src = fopen(infile, "rb");
- fp_dst = fopen(outfile, "wb");
- if(fp_src==NULL || fp_dst==NULL)
- {
- perror("Error open yuv files:");
- return -1;
- }
- x264_param_default(¶m);
- param.i_width = width;
- param.i_height = height;
- /*
- //Param
- param.i_log_level = X264_LOG_DEBUG;
- param.i_threads = X264_SYNC_LOOKAHEAD_AUTO;
- param.i_frame_total = 0;
- param.i_keyint_max = 10;
- param.i_bframe = 5;
- param.b_open_gop = 0;
- param.i_bframe_pyramid = 0;
- param.rc.i_qp_constant=0;
- param.rc.i_qp_max=0;
- param.rc.i_qp_min=0;
- param.i_bframe_adaptive = X264_B_ADAPT_TRELLIS;
- param.i_fps_den = 1;
- param.i_fps_num = 25;
- param.i_timebase_den = param.i_fps_num;
- param.i_timebase_num = param.i_fps_den;
- */
- param.i_csp = csp;
- param.b_repeat_headers = 1;
- param.b_annexb = 1;
- // profile: high x264_profile_names定义见x264.h
- x264_param_apply_profile(¶m, x264_profile_names[2]);
- pic_in = (x264_picture_t*)malloc(sizeof(x264_picture_t));
- if (pic_in == NULL)
- {
- goto out;
- }
- pic_out = (x264_picture_t*)malloc(sizeof(x264_picture_t));
- if (pic_out == NULL)
- {
- goto out;
- }
- x264_picture_init(pic_out);
- x264_picture_alloc(pic_in, csp, param.i_width, param.i_height);
- handle = x264_encoder_open(¶m);
- // 计算有多少帧
- luma_size = param.i_width * param.i_height;
- fseek(fp_src, 0, SEEK_END);
- switch (csp)
- {
- case X264_CSP_I444:
- i_frame = ftell(fp_src) / (luma_size*3);
- chroma_size = luma_size;
- break;
- case X264_CSP_I420:
- i_frame = ftell(fp_src) / (luma_size*3/2);
- chroma_size = luma_size / 4;
- break;
- default:
- printf("Colorspace Not Support.\n");
- goto out;
- }
- fseek(fp_src, 0, SEEK_SET);
- printf("framecnt: %d, y: %d u: %d\n", i_frame, luma_size, chroma_size);
- // 编码
- for (int i = 0; i < i_frame; i++)
- {
- switch(csp)
- {
- case X264_CSP_I444:
- case X264_CSP_I420:
- i_frame_size = fread(pic_in->img.plane[0], 1, luma_size, fp_src);
- if (i_frame_size != luma_size)
- {
- printf("read luma failed %d.\n", i_frame_size);
- break;
- }
- i_frame_size = fread(pic_in->img.plane[1], 1, chroma_size, fp_src);
- if (i_frame_size != chroma_size)
- {
- printf("read chroma1 failed %d.\n", i_frame_size);
- break;
- }
- i_frame_size = fread(pic_in->img.plane[2], 1, chroma_size, fp_src);
- if (i_frame_size != chroma_size)
- {
- printf("read chrome2 failed %d.\n", i_frame_size);
- break;
- }
- break;
- default:
- printf("Colorspace Not Support.\n");
- return -1;
- }
- pic_in->i_pts = i;
- i_frame_size = x264_encoder_encode(handle, &nal, &i_nal, pic_in, pic_out);
- printf("encode frame: %5d framesize: %d nal: %d\n", i+1, i_frame_size, i_nal);
- if (i_frame_size < 0)
- {
- printf("Error encode frame: %d.\n", i+1);
- goto out;
- }
- #if 01
- else if (i_frame_size)
- {
- if(!fwrite(nal->p_payload, 1, i_frame_size, fp_dst))
- goto out;
- }
- #endif
- // 另一种做法
- #if 0
- // i_nal有可能为0,有可能多于1
- for (int j = 0; j < i_nal; j++)
- {
- fwrite(nal[j].p_payload, 1, nal[j].i_payload, fp_dst);
- }
- #endif
- }
- //flush encoder
- while(x264_encoder_delayed_frames(handle))
- //while(1)
- {
- static int cnt = 1;
- i_frame_size = x264_encoder_encode(handle, &nal, &i_nal, NULL, pic_out);
- printf("flush frame: %d framesize: %d nalsize: %d\n", cnt++, i_frame_size, i_nal);
- if(i_frame_size == 0)
- {
- break;
- //goto out;
- }
- #if 01
- else if(i_frame_size)
- {
- if(!fwrite(nal->p_payload, 1, i_frame_size, fp_dst))
- goto out;
- }
- #endif
- // 另一种做法
- #if 0
- // i_nal有可能为0,有可能多于1
- for (int j = 0; j < i_nal; j++)
- {
- fwrite(nal[j].p_payload, 1, nal[j].i_payload, fp_dst);
- }
- #endif
- }
- out:
- x264_picture_clean(pic_in);
- if (handle)
- {
- x264_encoder_close(handle);
- handle = NULL;
- }
- if (pic_in)
- free(pic_in);
- if (pic_out)
- free(pic_out);
- fclose(fp_src);
- fclose(fp_dst);
- return 0;
- }
使用方法:
- x264_encode("../src/suzie_qcif_176x144_yuv420p.yuv", 176, 144, 1, "test.h264");
Makefile如下:
- #
- # (C) Copyleft 2011~2015
- # Late Lee from http://www.latelee.org
- #
- # A simple Makefile for *ONE* project(c or/and cpp file) in *ONE* directory
- #
- # note:
- # you can put head file(s) in 'include' directory, so it looks
- # a little neat.
- #
- # usage: $ make
- # $ make debug=y
- #
- # log
- # 2013-05-14 sth about debug...
- ###############################################################################
- # !!!=== cross compile...
- CROSS_COMPILE =
- CC = $(CROSS_COMPILE)gcc
- CXX = $(CROSS_COMPILE)g++
- AR = $(CROSS_COMPILE)ar
- ARFLAGS = cr
- RM = -rm -rf
- MAKE = make
- CFLAGS := -Wall
- #****************************************************************************
- # debug can be set to y to include debugging info, or n otherwise
- debug := n
- #****************************************************************************
- ifeq ($(debug), y)
- CFLAGS += -ggdb -rdynamic
- else
- CFLAGS += -O2 -s
- endif
- # !!!===
- DEFS =
- CFLAGS += $(DEFS)
- LDFLAGS := $(LIBS)
- # !!!===
- INCDIRS := -I./include
- # !!!===
- CFLAGS += $(INCDIRS)
- # !!!===
- LDFLAGS += ./lib/libx264.a ./lib/libx265.a -lpthread -ldl
- # !!!===
- # source file(s), including c file(s) cpp file(s)
- # you can also use $(wildcard *.c), etc.
- SRC_C := $(wildcard *.c)
- SRC_CPP := $(wildcard *.cpp)
- # object file(s)
- OBJ_C := $(patsubst %.c,%.o,$(SRC_C))
- OBJ_CPP := $(patsubst %.cpp,%.o,$(SRC_CPP))
- # !!!===
- # executable file
- target = a.out
- ###############################################################################
- all: $(target)
- $(target): $(OBJ_C) $(OBJ_CPP)
- @echo "Generating executable file..." $(notdir $(target))
- @$(CXX) $(CFLAGS) $^ -o $(target) $(LDFLAGS)
- # make all .c or .cpp
- %.o: %.c
- @echo "Compiling: " $(addsuffix .c, $(basename $(notdir $@)))
- @$(CC) $(CFLAGS) -c $< -o $@
- %.o: %.cpp
- @echo "Compiling: " $(addsuffix .cpp, $(basename $(notdir $@)))
- @$(CXX) $(CFLAGS) -c $< -o $@
- clean:
- @echo "Cleaning..."
- @$(RM) $(target)
- @$(RM) *.o *.back *~
- .PHONY: all clean