x264 yuv to h264 c99

如何编译引入x264

正式编码

#include <stdint.h>
#include <x264.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>


#define CLEAR(x) (memset((&x),0,sizeof(x)))
#define IMAGE_WIDTH   1920
#define IMAGE_HEIGHT  1080
#define ENCODER_PRESET "veryfast"
#define ENCODER_TUNE   "zerolatency"
#define ENCODER_PROFILE  "baseline"
#define ENCODER_COLORSPACE X264_CSP_I420

typedef struct my_x264_encoder
{
    x264_param_t* x264_parameter;
    char parameter_preset[20];
    char parameter_tune[20];
    char parameter_profile[20];
    x264_t* x264_encoder;
    x264_picture_t* yuv420p_picture;
    long colorspace;
    unsigned char* yuv;
    x264_nal_t* nal;
} my_x264_encoder;

char* read_filename = "/Users/jimogangdan/Downloads/video1.yuv";
char* write_filename = "/Users/jimogangdan/CLionProjects/x264_encoder/video1.h264";

int main(int argc, char** argv)
{
    //  初始化my_x264_encoder结构体,并设置编码器的参数preset、tune
    my_x264_encoder* encoder = malloc(sizeof(my_x264_encoder));
    if (!encoder)
    {
        printf("cannot malloc my_x264_encoder !\n");
        exit(EXIT_FAILURE);
    }
    CLEAR(*encoder);

    strcpy(encoder->parameter_preset, ENCODER_PRESET); // 高速编码
    strcpy(encoder->parameter_tune, ENCODER_TUNE); //低延迟


    // 参数初始化
    encoder->x264_parameter = (x264_param_t*)malloc(sizeof(x264_param_t));
    if (!encoder->x264_parameter)
    {
        printf("malloc x264_parameter error!\n");
        exit(EXIT_FAILURE);
    }
    CLEAR(*(encoder->x264_parameter));

    //  分配内存并初始化x264参数对象x264_param_t,设置视频帧宽高、关键帧间隔、B帧数等编码参数。
    x264_param_default(encoder->x264_parameter);
    if (x264_param_default_preset(encoder->x264_parameter, encoder->parameter_preset, encoder->parameter_tune) < 0)
    {
        printf("x264_param_default_preset error!\n");
        exit(EXIT_FAILURE);
    }

    // 编码参数
    encoder->x264_parameter->i_threads = X264_SYNC_LOOKAHEAD_AUTO; //自适应线程数
    encoder->x264_parameter->i_width = IMAGE_WIDTH; // 分辨率的宽度
    encoder->x264_parameter->i_height = IMAGE_HEIGHT; // 分辨率的高度
    encoder->x264_parameter->i_frame_total = 0; // 帧总数 默认0
    encoder->x264_parameter->i_keyint_max = 25; // I帧最大间隔
    encoder->x264_parameter->i_bframe = 5; // B帧的数量
    encoder->x264_parameter->b_open_gop = 0; // 闭合式GOP 不共享帧
    encoder->x264_parameter->i_bframe_pyramid = 0; // 关闭了B帧金字塔模式 按照默认顺序
    encoder->x264_parameter->i_bframe_adaptive = X264_B_ADAPT_TRELLIS; //  帧自适应性模式中采用 Trellis 模式

    // 流参数
    encoder->x264_parameter->i_fps_den = 1; //fps帧率的分母 不限制帧率
    encoder->x264_parameter->i_fps_num = 25; //fps帧率的分子 每秒25帧
    encoder->x264_parameter->b_intra_refresh = 1; // 启用了关键帧刷新模式 周期性地额外插入关键帧
    encoder->x264_parameter->b_annexb = 1; // 输出的AnnexB格式为比特流

    // 日志
    encoder->x264_parameter->i_log_level = X264_LOG_DEBUG;

    // 打开编码器
    strcpy(encoder->parameter_profile, ENCODER_PROFILE);
    encoder->x264_encoder = x264_encoder_open(encoder->x264_parameter);
    encoder->colorspace = ENCODER_COLORSPACE; // 颜色空间格式使用YUV420

    // yuv初始化
    encoder->yuv420p_picture = (x264_picture_t*)malloc(sizeof(x264_picture_t));
    if (!encoder->yuv420p_picture)
    {
        printf("malloc encoder->yuv420p_picture error!\n");
        exit(EXIT_FAILURE);
    }
    if (x264_picture_alloc(encoder->yuv420p_picture, encoder->colorspace,IMAGE_WIDTH,IMAGE_HEIGHT) < 0)
    {
        printf("ret=%d\n", -1);
        printf("x264_picture_alloc error!\n");
        exit(EXIT_FAILURE);
    }

    // yuv 模型、平面、类型参数
    encoder->yuv420p_picture->img.i_csp = encoder->colorspace;
    encoder->yuv420p_picture->img.i_plane = 3; // 平面数设置为 3 包含亮度(Y)平面和两个色度(UV)平面
    encoder->yuv420p_picture->i_type = X264_TYPE_AUTO; // 图像的类型设置为自动类型


    // 指定帧的像素数目
    encoder->yuv = (uint8_t*)malloc(IMAGE_WIDTH * IMAGE_HEIGHT * 3 / 2);
    if (!encoder->yuv)
    {
        printf("malloc yuv error!\n");
        exit(EXIT_FAILURE);
    }
    CLEAR(*(encoder->yuv));

    //  Y 、U 、V分量的数据关联起始地址
    encoder->yuv420p_picture->img.plane[0] = encoder->yuv;
    encoder->yuv420p_picture->img.plane[1] = encoder->yuv + IMAGE_WIDTH * IMAGE_HEIGHT;
    encoder->yuv420p_picture->img.plane[2] = encoder->yuv + IMAGE_WIDTH * IMAGE_HEIGHT + IMAGE_WIDTH * IMAGE_HEIGHT / 4;

    // 打开yuv源文件
    int fd_read, fd_write;
    if ((fd_read = open(read_filename,O_RDONLY)) < 0)
    {
        printf("cannot open input file!\n");
        exit(EXIT_FAILURE);
    }

    // 打开h264目标文件
    if ((fd_write = open(write_filename,O_WRONLY | O_APPEND | O_CREAT, 0777)) < 0)
    {
        printf("cannot open output file!\n");
        exit(EXIT_FAILURE);
    }

    // nal单元初始化
    encoder->nal = (x264_nal_t*)malloc(sizeof(x264_nal_t));
    if (!encoder->nal)
    {
        printf("malloc x264_nal_t error!\n");
        exit(EXIT_FAILURE);
    }
    CLEAR(*(encoder->nal));


    // 数据读入到encoder->yuv纳冲中
    int n_nal = 0;
    x264_picture_t pic_out;
    x264_nal_t* my_nal;
    while (read(fd_read, encoder->yuv,IMAGE_WIDTH * IMAGE_HEIGHT * 3 / 2) > 0)
    {
        encoder->yuv420p_picture->i_pts++; // 自增时间帧
        if (x264_encoder_encode(encoder->x264_encoder, &encoder->nal, &n_nal, encoder->yuv420p_picture, &pic_out) < 0)
        {
            printf("x264_encoder_encode error!\n");
            exit(EXIT_FAILURE);
        }

        // 读取当前缓冲全部NAL单元
        for (my_nal = encoder->nal; my_nal < encoder->nal + n_nal; ++my_nal)
        {
            //写入数据内容p_payload ,写入长度i_payload
            write(fd_write, my_nal->p_payload, my_nal->i_payload);
        }
    }

    // 释放内存
    free(encoder->yuv);
    free(encoder->yuv420p_picture);
    free(encoder->x264_parameter);
    x264_encoder_close(encoder->x264_encoder);
    free(encoder);

    // 关闭文件
    close(fd_read);
    close(fd_write);

    return 0;
}

posted @ 2024-02-21 14:49  vx_guanchaoguo0  阅读(3)  评论(0编辑  收藏  举报