The simplest Video Encoder: libvpx (YUV is VP8) and libvpxvp8
This document records a simple VP8 Video Encoder Based on libvpx. This example is simplified from the official sample code. I found that unlike H.264, VP8 bare streams (that is, pure video data streams without encapsulation formats) cannot be played. In other words, the VP8 bare stream must be stored in the container for playback. In the official sample code, the Encapsulation Format for storing VP8 video streams is IVF. The Encapsulation Format of IVF is not very common, and relevant documents can be queried.
In addition, libvpx in this project can also encode videos in the VP9 format. However, there is a problem with the Encapsulation Format, so there is no code containing the VP9 code. The function calls that encode VP9 and VP8 are exactly the same.
The flowchart of calling libvpx for video encoding is as follows.
The main functions in the flowchart are as follows.
Vpx_img_alloc (): allocates memory for the image struct vpx_image_t.
Vpx_codec_enc_config_default (): sets the default value of the parameter set struct vpx_codec_enc_1__t.
Vpx_codec_enc_init (): Enable the encoder.
Vpx_codec_encode (): encode an image.
Vpx_codec_get_cx_data (): obtains a frame of compressed encoding data.
Vpx_codec_destroy (): Disable the encoder.
The structure of the stored data is as follows.
Vpx_image_t: stores pre-compressed pixel data.
Vpx_codec_cx_pkt_t: stores the compressed code stream data.
The functions for processing the IVF Encapsulation Format are as follows.
Write_ivf_file_header (): Write the file header in the IVF Encapsulation Format.
Write_ivf_frame_header (): Write the frame header of each frame in the IVF Encapsulation Format.
The flowchart also contains a "flush_encoder" module, which uses the same functions as the encoding module. The only difference is that no video pixel data is input. It is used to output the remaining bitstream data in the encoder.
Source code
/*** The Simplest VPX-Based Video Encoder * Simplest VPX Encoder ** leixiao Lei Xiaohua * leixiaohua1020@126.com * China Media University/Digital TV technology * Communication University of China/Digital TV Technology * http://blog.csdn.net/leixiaohua1020 ** this program simplifies a sample code in libvpx. * Pixel data in YUV format can be encoded as a VPx (VP8/VP9) code stream, which is the simplest * libvpx-Based Video Encoder * Note that, the Encapsulation Format of the encoding output is IVF ** This example modified from an example from vpx project. * It encode YUV data to VPX (VP8/VP9) bitstream. * It's the simplest encoder example based on libvpx. */# include <stdio. h> # include <stdlib. h> # define VPX_CODEC_DISABLE_COMPAT 1 # include "vpx/vpx_encoder.h" # include "vpx/vp8cx. h "# define interface (& vpx_codec_vp8_c X_algo) # define fourcc 0x30385056 # define IVF_FILE_HDR_SZ (32) # define IVF_FRAME_HDR_SZ (12) static void mem_put_le16 (char * mem, unsigned int val) {mem [0] = val; mem [1] = val> 8;} static void mem_put_le32 (char * mem, unsigned int val) {mem [0] = val; mem [1] = val> 8; mem [2] = val> 16; mem [3] = val> 24;} static void write_ivf_file_header (FILE * outfile, const vpx_codec_enc_1__t * cfg, int frame_cnt) {Char header [32]; if (cfg-> g_pass! = VPX_RC_ONE_PASS & cfg-> g_pass! = VPX_RC_LAST_PASS) return; header [0] = 'D'; header [1] = 'K'; header [2] = 'I'; header [3] = 'F '; mem_put_le16 (header + 4, 0);/* version */mem_put_le16 (header + 6, 32);/* headersize */mem_put_le32 (header + 8, fourcc ); /* headersize */mem_put_le16 (header + 12, cfg-> g_w);/* width */mem_put_le16 (header + 14, cfg-> g_h ); /* height */mem_put_le32 (header + 16, cfg-> g_timebase.den);/* rate */mem_put_le32 (heade R + 20, cfg-> g_timebase.num);/* scale */mem_put_le32 (header + 24, frame_cnt);/* length */mem_put_le32 (header + 28, 0 ); /* unused */fwrite (header, 1, 32, outfile);} static void write_ivf_frame_header (FILE * outfile, const vpx_codec_cx_pkt_t * pkt) {char header [12]; vpx_codec_pts_t pts; if (pkt-> kind! = VPX_CODEC_CX_FRAME_PKT) return; pts = pkt-> data. frame. pts; mem_put_le32 (header, pkt-> data. frame. sz); mem_put_le32 (header + 4, pts & 0 xFFFFFFFF); mem_put_le32 (header + 8, pts> 32); fwrite (header, 1, 12, outfile );} int main (int argc, char ** argv) {FILE * infile, * outfile; vpx_codec_ctx_t codec; struct cfg; int frame_cnt = 0; unsigned char file_hdr [IVF_FILE_HDR_SZ]; unsigned char frame_hdr [IVF_FRAME_HDR_SZ]; vpx_image_t raw; vpx_codec_err_t ret; int width, height; int y_size; int frame_avail; int got_data; int flags = 0; width = 640; height = 360; /* Open input file for this encoding pass */infile = fopen (".. /cuc_ieschool_640x360_yuv420p.yuv "," rb "); outfile = fopen (" cuc_ieschool.ivf "," wb "); if (infile = NULL | outfile = NULL) {printf ("Error open files. \ n "); return-1;} if (! Vpx_img_alloc (& raw, VPX_IMG_FMT_I420, width, height, 1) {printf ("Fail to allocate image \ n"); return-1 ;} printf ("Using % s \ n", vpx_codec_iface_name (interface);/* Populate encoder configuration */ret = vpx_codec_enc_config_default (interface, & cfg, 0); if (ret) {printf ("Failed to get config: % s \ n", vpx_codec_err_to_string (ret); return-1 ;}/ * Update the default configuration with our settings */ Cfg. rc_target_bitrate = 800; cfg. g_w = width; cfg. g_h = height; write_ivf_file_header (outfile, & cfg, 0);/* Initialize codec */if (vpx_codec_enc_init (& codec, interface, & cfg, 0 )) {printf ("Failed to initialize encoder \ n"); return-1;} frame_avail = 1; got_data = 0; y_size = cfg. g_w * cfg. g_h; while (frame_avail | got_data) {vpx_codec_iter_t iter = NULL; const vpx_codec_cx_pkt_t * pkt; if (fread (raw. pla Nes [0], 1, y_size * 3/2, infile )! = Y_size * 3/2) {frame_avail = 0;} if (frame_avail) {ret = vpx_codec_encode (& codec, & raw, frame_cnt, 1, flags, VPX_DL_REALTIME );} else {ret = vpx_codec_encode (& codec, NULL, frame_cnt, 1, flags, VPX_DL_REALTIME);} if (ret) {printf ("Failed to encode frame \ n "); return-1;} got_data = 0; while (pkt = vpx_codec_get_cx_data (& codec, & iter) {got_data = 1; switch (pkt-> kind) {case VPX_CODEC_CX_FRAME_PKT: write_ivf_frame _ Header (outfile, pkt); fwrite (pkt-> data. frame. buf, 1, pkt-> data. frame. sz, outfile); break; default: break;} printf ("Succeed encode frame: % 5d \ n", frame_cnt); frame_cnt ++;} fclose (infile ); vpx_codec_destroy (& codec);/* Try to rewrite the file header with the actual frame count */if (! Fseek (outfile, 0, SEEK_SET) write_ivf_file_header (outfile, & cfg, frame_cnt-1); fclose (outfile); return 0 ;}
Running result
The program input is a YUV file (the YUV420P format has been tested ).
Output The VP8 code stream file in the IVF Encapsulation Format.
The VP8 code stream file information is as follows.
Download
Simplest Encoder
SourceForge project home: https://sourceforge.net/projects/simplestencoder/
CDSN: http://download.csdn.net/detail/leixiaohua1020/8284105
This solution contains several common encoder usage examples:
Simplest_vpx_encoder: the simplest Video Encoder Based on libvpx
Simplest_x1__encoder: the simplest Video Encoder Based on libx264
Simplest_x265_encoder: the simplest Video Encoder Based on libx265