libx264
libx264是一個自由的H.264編碼庫,是x264項目的一部分,使用廣泛,ffmpeg的H.264實現就是用的libx264。
代碼
要把一個I420視頻文件編碼為H264格式。I420是YUV中planar格式的一種,一張I420圖片中有三個plane,分別存放整張圖片的Y、U、V分量;采樣比例為4:2:0,12bpp,Y:U:V的分量長度是4:1:1。
頭文件
1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <x264.h>
變量聲明和參數
1 int width = 480;
2 int height = 360;
3 int fps = 25;
4 size_t yuv_size = width * height * 3 / 2;
5 x264_t *encoder;
6 x264_picture_t pic_in, pic_out;
7 int inf, outf;
8 uint8_t *yuv_buffer;
9
10 if (argc != 3) {
11 printf("usage: %s input output\n", argv[0]);
12 }
- 視頻尺寸是480×360,YUV I420格式,每個像素1.5個字節,所以一張YUV圖片大小是width * height * 1.5
-
encoder就是編碼器,x264_t格式在x264.h文件中只有
typedef struct x264_t x264_t
編碼器類型只需要也只能聲明為x264_t的指針類型
- 每次編碼時,YUV圖片的信息都保存在pic_in中
- 輸入輸出的文件描述符
- 從文件讀入的YUV的緩沖區
初始化encoder
1 x264_param_t param;
2 x264_param_default_preset(¶m, "veryfast", "zerolatency");
3 param.i_threads = 1;
4 param.i_width = width;
5 param.i_height = height;
6 param.i_fps_num = fps;
7 param.i_fps_den = 1;
8
9 param.i_keyint_max = 25;
10 param.b_intra_refresh = 1;
11
12 param.b_annexb = 1;
13
14 x264_param_apply_profile(¶m, "baseline");
15 encoder = x264_encoder_open(¶m);
初始化pic_in
1 x264_picture_alloc(&pic_in, X264_CSP_I420, width, height);
2
3 yuv_buffer = malloc(yuv_size);
4
5 pic_in.img.plane[0] = yuv_buffer;
6 pic_in.img.plane[1] = pic_in.img.plane[0] + width * height;
7 pic_in.img.plane[2] = pic_in.img.plane[1] + width * height / 4;
初始化文件描述符
1 inf = open(argv[1], O_RDONLY);
2 if (inf < 0) {
3 return -1;
4 }
5 outf = open(argv[2], O_CREAT | O_WRONLY, 444);
6 if (outf < 0) {
7 return -1;
8 }
編碼
1 int64_t i_pts = 0;
2
3 x264_nal_t *nals;
4 int nnal;
5 while (read(inf, yuv_buffer, yuv_size) > 0) {
6 pic_in.i_pts = i_pts++;
7 x264_encoder_encode(encoder, &nals, &nnal, &pic_in, &pic_out);
8 x264_nal_t *nal;
9 for (nal = nals; nal < nals + nnal; nal++) {
10 write(outf, nal->p_payload, nal->i_payload);
11 }
12 }
- 關于ffmpeg的pts,網上有好多種公式,其實只要步長為1遞增就行了
- H.264的NAL層是為了適應網絡傳輸的需要,將大的編碼后的幀分成多個塊
- p_payload就是編碼后的H.264的幀數據,寫入輸出文件
掃尾
1 x264_encoder_close(encoder);
2 close(inf);
3 close(outf);
4 free(yuv_buffer);
5 return 0;
編譯
gcc sourcefile -lx264 -Wall -o execfile
這里有一段I420視頻可供測試。
參考
- How does one encode a series of images into H264 using the x264 C API? - Stack Overflow
- YUV RGB 常見視頻格式解析 - 一指流砂 - 博客園