【ffmepg4.4_libx264 软编码】

这是一个C++程序,它利用FFmpeg库进行H264视频编码。代码首先打开输入的YUV文件,然后创建并配置AVCodecContext以指定编码参数,如分辨率、帧率和比特率。之后,程序读取YUV帧,填充AVFrame,将它们发送到编码器,并将编码后的AVPacket写入输出文件。Makefile用于编译该程序。
摘要由CSDN通过智能技术生成

一、源码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern "C"{
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
}

static int encode(AVCodecContext* enc_ctx, AVFrame* frame, AVPacket* pkt,FILE* outfile){
    int ret;
    /* send the frame to the encoder */
    if (frame){
        printf("Send frame %lld\n", frame->pts);
    }

    ret = avcodec_send_frame(enc_ctx, frame);
    if (ret < 0) {
        char errorBuf[512]={0};
        av_strerror(ret,errorBuf,sizeof(errorBuf));
        // printf("Error sending a frame for encoding ,ret=%d,%s\n",ret,errorBuf);
        return -1;
    }

    while (ret >= 0) {
        ret = avcodec_receive_packet(enc_ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
            printf("Error  AVERROR\n");
            return -1;
        }
            
        else if (ret < 0) {
            printf("Error during encoding\n");
            return -1;
        }

        printf("Write packet size=%d\n", pkt->size);
        fwrite(pkt->data, 1, pkt->size, outfile);
        av_packet_unref(pkt);
    }
    return 0;
}

int encode_file(const char *input_file,const char *filename){
    
    AVCodecContext* c = NULL;
    int  ret=-1;
    AVFrame* frame=NULL;
    AVPacket* pkt;
    int frame_num=0;
    int nv12_frameSize;
    int r_size=0;
    FILE *out_fp ;
    void *buffer;
    uint8_t endcode[] = { 0, 0, 1, 0xb7 };
    FILE *in_fp = fopen(input_file,"rb");
    if(in_fp==NULL){
        return -1;
    }
    AVCodec* codec  = (AVCodec*)avcodec_find_encoder(AV_CODEC_ID_H264);//查找编解码器
    if(NULL == codec){
        printf("find AV_CODEC_ID_H264 fail! \n");
        goto exit0;
    }

    c = avcodec_alloc_context3(codec);
    if (!c) {
        printf("Could not allocate video codec context\n");
        goto exit0;
    }

    pkt = av_packet_alloc();
    if (!pkt){
        printf("av_packet_alloc failed");
        goto exit1;
    }
    /* put sample parameters */
    c->bit_rate = 400000;
    /* resolution must be a multiple of two */
    c->width = 1920;
    c->height = 1080;
    /* frames per second */
    c->time_base.num =1;
    c->time_base.den =25;
    c->time_base.num =25;
    c->time_base.den =1;

    /* emit one intra frame every ten frames
     * check frame pict_type before passing frame
     * to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
     * then gop_size is ignored and the output of encoder
     * will always be I frame irrespective to gop_size
     */
    c->gop_size = 10;
    c->max_b_frames = 1;
    c->pix_fmt = AV_PIX_FMT_NV12;

    if (codec->id == AV_CODEC_ID_H264){
        printf("av_opt_set h264 preset slow\n");
        av_opt_set(c->priv_data, "preset", "slow", 0);
    }
    /* open it */
    ret = avcodec_open2(c, codec, NULL);
    if (ret < 0) {
        printf("Could not open codec: %d\n", ret);
        goto exit2;
    }

    out_fp = fopen(filename, "wb");
    if (!out_fp) {
        printf( "Could not open %s\n", filename);
        goto exit2;
    }

    frame = av_frame_alloc();
    if (!frame) {
        printf("Could not allocate video frame\n");
        goto exit3;
    }
    frame->format = c->pix_fmt;
    frame->width = c->width;
    frame->height = c->height;

    ret = av_frame_get_buffer(frame, 0);
    if (ret < 0) {
        printf( "Could not allocate the video frame data\n");
        goto exit4;
    }
    nv12_frameSize = av_image_get_buffer_size(c->pix_fmt, frame->width, frame->height, 1);
    printf("nv12_frameSize=%d\n",nv12_frameSize);
    buffer = (void *)calloc(1,nv12_frameSize);
    if(buffer==NULL){
        goto exit4;
    }
    
    while(1){
        r_size = fread(buffer,1,nv12_frameSize,in_fp);
        if(r_size<=0){
            printf("read file end\n");
            break;
        }
        av_image_fill_arrays(frame->data, frame->linesize, (const uint8_t *)buffer,(enum AVPixelFormat)frame->format,frame->width,frame->height, 1);
        frame_num++;
        frame->pts = frame_num;
        encode(c, frame, pkt, out_fp);
    }
    encode(c, NULL, pkt, out_fp);
exit5:
    free(buffer);
exit4:
    av_frame_free(&frame);
exit3:
    fclose(out_fp);
exit2:
    av_packet_free(&pkt);
exit1:
    avcodec_free_context(&c);
exit0:
    fclose(in_fp);
    return ret;
}
int main(int argc,char **argv){
    if(argc<2){
        printf("input yuv file and output.h264");
    }
    encode_file((const char *)argv[1],(const char *)argv[2]);
    return 0;
}

二、Makefile 文件

AR=encode
CC=$(CROSS_COMPILE)gcc
STRIP=$(CROSS_COMPILE)strip    
CC=$(CROSS_COMPILE)gcc
CPP=$(CROSS_COMPILE)g++
CFLAGS = -Wall -I /home/share/ffmpeg4.4/output/x86/include/

all +=test_encode.o


export CC
$(TAR): $(all)
        $(CC) $(CFLAGS) $(all) -o $(TAR)  -lpthread -lm  -L/usr/local/ffmpeg_x264/lib/ -lavcodec-59 -lavdev
ice-59 -lavfilter-8 -lavformat-59 -lavutil-57 -lswresample-4 -lswscale-6
        $(RM) -f *.gch *.bak $(all) 
        
%.o:%.c
        $(CC) $(CFLAGS) -c -o $@ $< 
        
%.o:%.cpp
        $(CPP) $(CFLAGS) -c -o $@ $< 

.PHONY: clean
clean:
        rm -f $(TAR) $(all) 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以按照以下步骤使用`ff_libx264_encoder`: 1. 首先,确保你已经安装了`ffmpeg`工具,因为`ff_libx264_encoder`是`ffmpeg`库的一部分。 2. 在程序中引入相关的头文件: ```c #include <libavcodec/avcodec.h> ``` 3. 初始化`ffmpeg`库: ```c av_register_all(); ``` 4. 创建编码器上下文和输出文件: ```c AVCodecContext *codec_ctx; AVCodec *codec; AVFrame *frame; AVPacket pkt; FILE *output_file; const char *filename = "output.mp4"; // 查找编码器 codec = avcodec_find_encoder_by_name("libx264"); if (!codec) { // 错误处理 } // 创建编码器上下文 codec_ctx = avcodec_alloc_context3(codec); if (!codec_ctx) { // 错误处理 } // 配置编码器参数 codec_ctx->width = width; // 视频宽度 codec_ctx->height = height; // 视频高度 // ... // 打开编码器 if (avcodec_open2(codec_ctx, codec, NULL) < 0) { // 错误处理 } // 创建输出文件 output_file = fopen(filename, "wb"); if (!output_file) { // 错误处理 } ``` 5. 分配和初始化帧数据: ```c frame = av_frame_alloc(); if (!frame) { // 错误处理 } // 设置帧参数 frame->format = codec_ctx->pix_fmt; frame->width = codec_ctx->width; frame->height = codec_ctx->height; // 分配帧数据缓冲区 int ret = av_frame_get_buffer(frame, 0); if (ret < 0) { // 错误处理 } ``` 6. 循环编码每一帧: ```c while (/* 读取下一帧图像 */) { // 将图像数据拷贝到帧数据缓冲区 // ... // 发送帧数据到编码器 ret = avcodec_send_frame(codec_ctx, frame); if (ret < 0) { // 错误处理 } // 接收编码后的数据包 while (ret >= 0) { ret = avcodec_receive_packet(codec_ctx, &pkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { // 继续下一帧 break; } else if (ret < 0) { // 错误处理 } // 写入编码后的数据到文件 fwrite(pkt.data, 1, pkt.size, output_file); // 释放数据包 av_packet_unref(&pkt); } } ``` 7. 编码完成后,进行清理工作: ```c av_frame_free(&frame); avcodec_close(codec_ctx); avcodec_free_context(&codec_ctx); fclose(output_file); ``` 这是一个基本的使用示例,具体的步骤和参数可能需要根据你的实际需求进行调整。每一步都需要进行错误处理,以确保程序的稳定运行。请参考`ffmpeg`官方文档和示例代码获取更多详细信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值