使用Libvpx编码视频

Posted blueberry_mu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Libvpx编码视频相关的知识,希望对你有一定的参考价值。

使用X265编码视频

环境准备

  1. 使用git下载libvpx源码
    https://chromium.googlesource.com/webm/libvpx/

  2. 如果电脑之前没有安装过 yasm,nasm 可以使用 brew 安装一下

    brew install yasm
    brew install nasm
  1. 进入到工程根目录下编译
./configure --enable-shared

配置完成之后

make
make install

命令行使用

vpxenc --codec=vp8 -w 352 -h 288  -o akiyo1.vpx akiyo_cif.yuv

更多使用方式可以参考

vpxenc --help

工程使用

  1. 资源准备

yuv 视频源: http://trace.eas.asu.edu/yuv/index.html
查看YUV视频源工具: https://files.cnblogs.com/littlejohnny/YUVviewer_src.rar
https://github.com/IENT/YUView/releases

我下载了一个资源名,名称为:akiyo_cif,是一个I420,8位深的资源

  1. CMakeList.txt
cmake_minimum_required(VERSION 3.14)
project(Vpx_encoder)
set(CMAKE_CXX_STANDARD 11)            # Enable c++11 standard

set(CMAKE_BUILD_TYPE Debug)
set(SOURCE_FILES VpxEncoder.cpp)

# https://cmake.org/cmake/help/latest/module/FindPkgConfig.html
# https://zhuanlan.zhihu.com/p/111155574
find_package(PkgConfig REQUIRED)
pkg_check_modules(vpx REQUIRED IMPORTED_TARGET vpx )


add_executable(Vpx_encoder $SOURCE_FILES)

target_link_libraries($PROJECT_NAME PRIVATE PkgConfig::vpx)
  1. 代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <iomanip>

#include <vpx/vpx_encoder.h>
#include <vpx/vp8cx.h>
#
#define fourcc 0x30385056

#define interface (&vpx_codec_vp8_cx_algo)

#define log(msg) std::cout << msg << std::endl

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_cfg_t *cfg, int frame_cnt)

    if (cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS)
    
        return;
    
    char header[32];
    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(header + 20, cfg->g_timebase.num); // scale
    mem_put_le32(header + 24, frame_cnt);           // length;
    mem_put_le32(header + 28, 0);                   // unused;

    fwrite(header, 32, 1, 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 & 0xFFFFFFFF);
    mem_put_le32(header + 8, pts >> 32);

    fwrite(header, 1, 12, outFile);


// https://blog.csdn.net/leixiaohua1020/article/details/42079101
// I420: https://blog.csdn.net/leixiaohua1020/article/details/12234821
int main(int argv, const char *args[])

    FILE *fp_src = fopen("../res/akiyo_cif.yuv", "rb");
    FILE *fp_dst = fopen("./akiyo_cif_code.vp8", "wb");

    // 352x288
    int width = 352;
    int height = 288;
    int csp = VPX_IMG_FMT_I420;
    // 设置为0,会根据文件大小计算帧数
    // 如果帧数设置的太小,可能会造成没有编码后的结果
    // int frameNum = 0;
    int frame_cnt = 0;
    int flags = 0;

    if (fp_src && fp_dst)
    
        vpx_image_t raw;
        if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 1))
        
            log("Error open files");
            return -1;
        
        std::cout << "Using: " << vpx_codec_iface_name(interface) << std::endl;
        vpx_codec_enc_cfg_t cfg;
        int ret = vpx_codec_enc_config_default(interface, &cfg, 0);
        if (ret != VPX_CODEC_OK)
        
            log("Error config ");
            return -1;
        
        cfg.rc_target_bitrate = 800;
        cfg.g_w = width;
        cfg.g_h = height;

        write_ivf_file_header(fp_dst, &cfg, 0); // frame count 0 ?
        vpx_codec_ctx_t codec;
        // Initialize codec .
        if (vpx_codec_enc_init(&codec, interface, &cfg, 0) != VPX_CODEC_OK)
        
            log("Failed to initialize encoder");
        
        int frame_avail = 1;
        int got_data = 0;
        int y_size = width * height;
        while (frame_avail || got_data)
        
            vpx_codec_iter_t iter = nullptr;
            if (fread(raw.planes[0], 1, y_size * 3 / 2, fp_src) != 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, nullptr, frame_cnt, 1, flags, VPX_DL_REALTIME);
            

            if (ret)
            
                log("Failed to  encode frame.");
                return -1;
            
            got_data = 0;
            const vpx_codec_cx_pkt_t *pkt;
            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(fp_dst, pkt);
                    fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, fp_dst);
                    break;

                default:
                    break;
                
            
            std::cout << "Succeed encode frame: " << frame_cnt << std::endl;
            frame_cnt++;
        
        vpx_img_free(&raw);
        fclose(fp_src);
        vpx_codec_destroy(&codec);
        if (!fseek(fp_dst, 0, SEEK_SET))
        
            write_ivf_file_header(fp_dst, &cfg, frame_cnt - 1);
        
        fclose(fp_dst);
        return 0;
    
    else
    
        char *buffer;
        if ((buffer = getcwd(nullptr, 0)) == nullptr)
        
            log("get cwd error.");
            free(buffer);
        
        else
        
            std::cout << "Error open files. "
                      << "the current dir is "
                      << buffer
                      << std::endl
                      << "The fpSrc is"
                      << fp_src
                      << "the fpDst is "
                      << fp_dst
                      << std::endl;
        
        return -1;
    

以上是关于使用Libvpx编码视频的主要内容,如果未能解决你的问题,请参考以下文章

使用Libvpx编码视频

LNMP架构搭建论坛

window平台音视频技术栈简单梳理

如何创建 WebM 视频文件?

ffmpeg 的交叉编译:libvpx 解码器版本必须 >=0.9.1

h264, h265 和 libvpx 比较(h264/avc, hevc 和vp9比较)