ffmpeg NVIDIA编解码三:英伟达硬编码

ffmpeg NVIDIA编解码系列

ffmpeg NVIDIA编解码一:ffmpeg编译安装

ffmpeg NVIDIA编解码二:英伟达硬解码

ffmpeg NVIDIA编解码三:英伟达硬编码

★我的音视频编解码开源项目-FFmpeg-Media-Codec-Pipeline

        

        ffmpeg硬编码流程和软编码流程完全一样:打开编码器、分配编码器上下文,读取视频帧(YUV420P)、avcodec_send_frame送入编码器、avcodec_receive_packet获取编码后的视频帧、关闭编码器。只不过在打开编码器的时候要使用ffmpeg英伟达的编码器(H264:h264_nvenc H265:hevc_nvenc)。

        下面是ffmpeg NVIDIA编码流程图:

        完整代码:

#include <libavcodec/avcodec.h>
#include <libavfilter/avfilter.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/hwcontext.h>
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <libavutil/pixdesc.h>
#include <libavutil/pixfmt.h>
#include <libswresample/swresample.h>
#include <libswscale/swscale.h>
#include <stdio.h>
AVCodecContext *h264_codec_ctx = NULL;
AVCodec *h264_codec = NULL;
static int enc_init(int width, int height, int fps)
{
    char *codec_name = "h264_nvenc";
    enum AVCodecID decodec_id = AV_CODEC_ID_H264;
    // 列举支持的硬解码
    enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
    printf("Available device types:\n");
    while ((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE) {
        const char *type_name = av_hwdevice_get_type_name(type);
        if (type_name) {
            printf("%s\n", type_name);
        } else {
            printf("Unknown device type\n");
        }
    }
    type = av_hwdevice_find_type_by_name("cuda");
    if (type == AV_HWDEVICE_TYPE_NONE) {
        printf("not support nvidia codec\n");
        exit(0);
    }
    h264_codec = avcodec_find_encoder_by_name(codec_name);
    if (!h264_codec) {
        printf("not find codec\n");
        exit(0);
    }
    h264_codec_ctx = avcodec_alloc_context3(h264_codec);
    if (!h264_codec_ctx) {
        printf("avcodec_alloc_context3 error\n");
        exit(0);
    }
    h264_codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
    h264_codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
    h264_codec_ctx->width = width;
    h264_codec_ctx->height = height;
    h264_codec_ctx->time_base.num = 1;
    h264_codec_ctx->time_base.den = fps;
    h264_codec_ctx->bit_rate = 4000000;
    h264_codec_ctx->gop_size = 2 * fps;
    h264_codec_ctx->thread_count = 1;
    h264_codec_ctx->slices = 1; // int slice_count; // slice数 int slices; // 切片数量。 表示图片细分的数量。 用于并行解码。
    /**
     * 遇到问题:编码得到的h264文件播放时提示"non-existing PPS 0 referenced"
     * 分析原因:未将pps sps 等信息写入
     * 解决方案:加入标记AV_CODEC_FLAG2_LOCAL_HEADER
     */
    h264_codec_ctx->flags |= AV_CODEC_FLAG2_LOCAL_HEADER;
    h264_codec_ctx->flags |= AV_CODEC_FLAG_LOW_DELAY;

    // 不能使用下面的参数,否则硬编码器打不开
    // AVDictionary *param = 0;
    // priv_data  属于每个编码器特有的设置域,用av_opt_set 设置
    // av_opt_set(h264_codec_ctx_->priv_data, "preset", "ultrafast", 0);
    // av_opt_set(h264_codec_ctx_->priv_data, "tune", "zerolatency", 0);
    // av_dict_set(&param, "preset", "ultrafast", 0);
    // av_dict_set(&param, "profile", "baseline", 0);

    if (avcodec_open2(h264_codec_ctx, h264_codec, NULL) < 0) {
        printf("avcodec_open2 error\n");
        exit(0);
    }
    printf("enc_init ok\n");
    return 0;
}
static int enc_uninit()
{
    avcodec_close(h264_codec_ctx);
    avcodec_free_context(&h264_codec_ctx);
    printf("enc_uninit ok\n");
    return 0;
}
static enc_write(AVFrame *frame, int width, int height, FILE *fp_dst)
{
    int ret = avcodec_send_frame(h264_codec_ctx, frame);
    if (ret < 0) {
        printf("Error sending a frame for encoding\n");
        return -1;
    }
    AVPacket *packet = av_packet_alloc();
    av_init_packet(packet);
    packet->data = NULL;
    packet->size = 0;
    while (ret >= 0) {
        ret = avcodec_receive_packet(h264_codec_ctx, packet);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            break;
        } else if (ret < 0) {
            printf("Error during encoding\n");
            break;
        }
        fwrite(packet->data, packet->size, 1, fp_dst);
        av_packet_unref(packet);
    }
    av_packet_free(&packet);
    return 0;
}
int main(int argc, char **argv)
{
    if (argc < 6) {
        printf("./bin input(YUV420P) output width height fps\n");
        return -1;
    }

    FILE *fp_src = fopen(argv[1], "rb");
    FILE *fp_dst = fopen(argv[2], "wb");
    if (fp_src == NULL || fp_dst == NULL) {
        printf("Error opening files.\n");
        return -1;
    }

    int width = atoi(argv[3]);
    int height = atoi(argv[4]);
    int fps = atoi(argv[5]);
    enc_init(width, height, fps);
    AVFrame *frame = av_frame_alloc();
    if (!frame) {
        printf("Error allocating AVFrame.\n");
        return -1;
    }
    frame->width = width;
    frame->height = height;
    frame->format = AV_PIX_FMT_YUV420P;

    // Allocate buffer for AVFrame data
    int ret = av_frame_get_buffer(frame, 0);
    if (ret < 0) {
        printf("Error allocating buffer for AVFrame.\n");
        return -1;
    }
    int num = 0;
    while (1) {
        // Y
        if (fread(frame->data[0], width * height, 1, fp_src) != 1)
            break;

        // U
        if (fread(frame->data[1], width * height / 4, 1, fp_src) != 1)
            break;

        // V
        if (fread(frame->data[2], width * height / 4, 1, fp_src) != 1)
            break;
        num++;
        printf("frame num:%d\n", num);
        enc_write(frame, width, height, fp_dst);
    }
    // fflush
    enc_write(NULL, width, height, fp_dst);
    av_frame_free(&frame);
    fclose(fp_src);
    fclose(fp_dst);
    enc_uninit();

    return 0;
}

 

         我的开源:

         1、Nvidia视频硬解码、渲染、软/硬编码并写入MP4文件。项目地址:https://github.com/BreakingY/Nvidia-Video-Codec
        2、Jetson Jetpack5.x视频编解码。项目地址:https://github.com/BreakingY/jetpack-dec-enc
        3、音视频(H264/H265/AAC)封装、解封装、编解码pipeline,支持NVIDIA、昇腾DVPP硬编解码。项目地址:https://github.com/BreakingY/Media-Codec-Pipeline
        4、simple rtsp server,小而高效的rtsp服务器,支持H264、H265、AAC、PCMA;支持TCP、UDP;支持鉴权。项目地址:https://github.com/BreakingY/simple-rtsp-server

        5、simple rtsp client,rtsp客户端,支持TCP、UDP、H264、H265、AAC、PCMA,支持鉴权。项目地址:https://github.com/BreakingY/simple-rtsp-client

        6、libflv,flv muxer/demuxer,支持H264/H265、AAC。项目地址:https://github.com/BreakingY/libflv

        7、mpeg2 ts ps muxer/demuxer,支持H264/H265/MPEG1 audio/MP3/AAC/AAC_LATM/G711。项目地址:https://github.com/BreakingY/libmpeg2core

posted @   BreakingY  阅读(19)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示