有了 libx264 當然要試編一下影片,encode 出的檔案只是為 h264 的 bitstream ,並不是直接封裝成可直接撥放的檔案,還需要一些 wrapper 程序封裝成常見的影片格式如 ( mp4, mkv …)
不過也可以懶人用 ffmpeg 封裝 XD
ffmpeg -i in_file.h264 -vcodec copy out_file.mp4
這基本上就是一連串的繼承寄生關係,階層越高越笨重,也越複雜,這邊就第一步 codec 層來做個小實驗。
- codec library: e.g. x264
- only encoder & decoder for data stream (h264)
- video file container: e.g. libav
- pack/unpack video file (mp4, avi, mkv)
- 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 ¶m) { x264_param_default_preset( ¶m, "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( ¶m, "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( ¶m ); 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; }