花时间研究了一些ffmpeg的nvenc,本来想我已经有了cuvid,然后又搞出来了nvenc,应该可以做个全套的英伟达的转码了,没想到ffmpeg官网下载的动态库没有cuvid,windows上编译cuvid又老是出错,忧了个伤。

1.nvenc编码

h264_nvenc是很容易调出来的,把编码器ffmpeg源码自带的例子的编码器换成h264_nvenc就行了。可是hevc_nvenc就花了我好多时间,感觉调试技术还是差了好多。

#include "stdafx.h"/*
* Video encoding example
*/
static void video_encode_example(const char *filename)
{AVCodec *codec;AVCodecContext *c = NULL;int i, ret, x, y, got_output;AVFrame *frame;AVPacket pkt;uint8_t endcode[] = { 0, 0, 1, 0xb7 };av_log_set_level(64);//AVBufferRef *device_ref = NULL;//AVBufferRef *hw_frames_ctx = NULL;//hw_frames_ctx = (AVBufferRef *)av_mallocz(sizeof(AVBufferRef));//if (!hw_frames_ctx) {//    ret = AVERROR(ENOMEM);//    return ;//}//ret = av_hwdevice_ctx_create(&device_ref, AV_HWDEVICE_TYPE_CUDA,"CUDA", NULL, 0);//if (ret < 0)//    return;//hw_frames_ctx = av_hwframe_ctx_alloc(device_ref);//if (!hw_frames_ctx) {//    av_log(NULL, AV_LOG_ERROR, "av_hwframe_ctx_alloc failed\n");//    ret = AVERROR(ENOMEM);//    return;//}//av_buffer_unref(&device_ref);//c->hw_frames_ctx = av_buffer_ref(hw_frames_ctx);//if (!hw_frames_ctx) {//    av_log(NULL, AV_LOG_ERROR, "av_buffer_ref failed\n");//    ret = AVERROR(ENOMEM);//    return;//}
printf("Encode video file %s\n", filename);/* find the video encoder */codec = avcodec_find_encoder_by_name("hevc_nvenc");//codec = avcodec_find_encoder(AV_CODEC_ID_H265);//codec = avcodec_find_encoder_by_name("h264_nvenc");//codec = avcodec_find_encoder(AV_CODEC_ID_H264);if (!codec) {fprintf(stderr, "Codec not found\n");exit(1);}c = avcodec_alloc_context3(codec);if (!c) {fprintf(stderr, "Could not allocate video codec context\n");exit(1);}/* put sample parameters */c->bit_rate = 400000;/* resolution must be a multiple of two */c->width = 352;c->height = 288;/* frames per second */c->time_base.num = 1;c->time_base.den = 25;/* 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_YUV420P;//AV_PIX_FMT_CUDA;c->max_b_frames = 0;AVDictionary *param = 0;//H.264if (codec->id == AV_CODEC_ID_H264) {av_dict_set(&param, "preset", "medium", 0);av_dict_set(&param, "tune", "zerolatency", 0);}//H.265if (codec->id == AV_CODEC_ID_H265 || codec->id == AV_CODEC_ID_HEVC){//av_dict_set(&param, "x265-params", "qp=20", 0);av_dict_set(&param, "x265-params", "crf=25", 0);av_dict_set(&param, "preset", "fast", 0);av_dict_set(&param, "tune", "zero-latency", 0);}/* open it */if (avcodec_open2(c, codec, &param) < 0) {fprintf(stderr, "Could not open codec\n");system("pause");exit(1);}FILE *f;f = fopen(filename, "wb");if (!f) {fprintf(stderr, "Could not open %s\n", filename);exit(1);}frame = av_frame_alloc();if (!frame) {fprintf(stderr, "Could not allocate video frame\n");exit(1);}frame->format = c->pix_fmt;frame->width = c->width;frame->height = c->height;/* the image can be allocated by any means and av_image_alloc() is* just the most convenient way if av_malloc() is to be used */ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height,c->pix_fmt, 32);if (ret < 0) {fprintf(stderr, "Could not allocate raw picture buffer\n");exit(1);}/* encode 1 second of video */for (i = 0; i < 500; i++) {av_init_packet(&pkt);pkt.data = NULL;    // packet data will be allocated by the encoderpkt.size = 0;fflush(stdout);/* prepare a dummy image *//* Y */for (y = 0; y < c->height; y++) {for (x = 0; x < c->width; x++) {frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;}}/* Cb and Cr */for (y = 0; y < c->height / 2; y++) {for (x = 0; x < c->width / 2; x++) {frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;}}frame->pts = i;/* encode the image */ret = avcodec_encode_video2(c, &pkt, frame, &got_output);if (ret < 0) {fprintf(stderr, "Error encoding frame\n");exit(1);}if (got_output) {printf("Write frame %3d (size=%5d)\n", i, pkt.size);fwrite(pkt.data, 1, pkt.size, f);av_packet_unref(&pkt);}}/* get the delayed frames */for (got_output = 1; got_output; i++) {fflush(stdout);ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);if (ret < 0) {fprintf(stderr, "Error encoding frame\n");exit(1);}if (got_output) {printf("Write frame %3d (size=%5d)\n", i, pkt.size);fwrite(pkt.data, 1, pkt.size, f);av_packet_unref(&pkt);}}/* add sequence end code to have a real MPEG file */fwrite(endcode, 1, sizeof(endcode), f);fclose(f);avcodec_close(c);av_free(c);av_freep(&frame->data[0]);av_frame_free(&frame);printf("\n");
}int main(int argc, char **argv)
{/* register all the codecs */avcodec_register_all();avcodec_register_all();avdevice_register_all();avfilter_register_all();av_register_all();avformat_network_init();video_encode_example("test.hevc");system("pause");return 0;
}

代码中av_log_set_level(64);可以帮助输出中间信息,参数可以自行设置,参数为越大,能输出的信息等级越多,我的问题就是通过这个函数知道的,然后到源码中找对应处才最终解决。编码器为hevc_nvenc时max_b_frames必须为0,即代码中的 c->max_b_frames = 0;另外c->pix_fmt = AV_PIX_FMT_YUV420P;//AV_PIX_FMT_CUDA;这行代码需要注意,设置为AV_PIX_FMT_YUV420P意味着数据是从内存读取的,设置为AV_PIX_FMT_CUDA意味着数据在显存中,AV_PIX_FMT_CUDA与cuvid是一起的,只有编出来的ffmpeg支持cuvid时AV_PIX_FMT_CUDA才有效。

2.用nvenc做转码

由于还没有编出支持cuvid的ffmpeg,所以解码这里就先不用cuvid了,用CPU来解码。其实这样有一个好处,就是对格式的要求低,cuvid对格式的输入是有要求的,用这种方法所有用ffmpeg解码后的数据都可以用nvenc来编码,缺点当然是这样比较慢了。

#include "stdafx.h"#include <stdio.h>
#include <io.h>/*
* Video encoding example
*/
static void video_encode_example(const char *filename)
{AVCodec *codec;AVCodecContext *c = NULL;int i, ret, x, y, got_output;AVPacket pkt;uint8_t endcode[] = { 0, 0, 1, 0xb7 };av_log_set_level(64);AVFormatContext    *pFormatCtx;int                videoindex;AVCodecContext    *pCodecCtx;AVCodec            *pCodec;AVFrame    *pFrame, *pFrameYUV;uint8_t *out_buffer;char filepath[] = "H:\\nvenc\\灿烂人生1280.rmvb";av_register_all();avformat_network_init();pFormatCtx = avformat_alloc_context();if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0){printf("Couldn't open input stream.\n");return ;}if (avformat_find_stream_info(pFormatCtx, NULL)<0){printf("Couldn't find stream information.\n");return ;}videoindex = -1;for (i = 0; i<pFormatCtx->nb_streams; i++)if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){videoindex = i;break;}if (videoindex == -1){printf("Didn't find a video stream.\n");return ;}pCodecCtx = pFormatCtx->streams[videoindex]->codec;pCodec = avcodec_find_decoder(pCodecCtx->codec_id);if (pCodec == NULL){printf("Codec not found.\n");return ;}if (avcodec_open2(pCodecCtx, pCodec, NULL)<0){printf("Could not open codec.\n");return ;}pFrame = av_frame_alloc();pFrameYUV = av_frame_alloc();out_buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);//Output Info-----------------------------printf("--------------- File Information ----------------\n");av_dump_format(pFormatCtx, 0, filepath, 0);printf("-------------------------------------------------\n");struct SwsContext *img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);printf("Encode video file %s\n", filename);/* find the video encoder */codec = avcodec_find_encoder_by_name("hevc_nvenc");//codec = avcodec_find_encoder(AV_CODEC_ID_H265);//codec = avcodec_find_encoder_by_name("h264_nvenc");//codec = avcodec_find_encoder(AV_CODEC_ID_H264);if (!codec) {fprintf(stderr, "Codec not found\n");exit(1);}c = avcodec_alloc_context3(codec);if (!c) {fprintf(stderr, "Could not allocate video codec context\n");exit(1);}/* put sample parameters */c->bit_rate = pCodecCtx->bit_rate;/* resolution must be a multiple of two */c->width = pCodecCtx->width;c->height = pCodecCtx->height;c->time_base = pCodecCtx->time_base;c->gop_size = pCodecCtx->gop_size;c->pix_fmt = AV_PIX_FMT_YUV420P;c->max_b_frames = 0;AVDictionary *param = 0;//H.264if (codec->id == AV_CODEC_ID_H264) {av_dict_set(&param, "preset", "medium", 0);av_dict_set(&param, "tune", "zerolatency", 0);}//H.265if (codec->id == AV_CODEC_ID_H265 || codec->id == AV_CODEC_ID_HEVC){//av_dict_set(&param, "x265-params", "qp=20", 0);av_dict_set(&param, "x265-params", "crf=25", 0);av_dict_set(&param, "preset", "fast", 0);av_dict_set(&param, "tune", "zero-latency", 0);}/* open it */if (avcodec_open2(c, codec, &param) < 0) {fprintf(stderr, "Could not open codec\n");system("pause");exit(1);}FILE *f;f = fopen(filename, "wb");if (!f) {fprintf(stderr, "Could not open %s\n", filename);exit(1);}AVPacket *packet;packet = (AVPacket *)av_malloc(sizeof(AVPacket));int got_picture;int iCount = 0;int64_t iStart = av_gettime();while (av_read_frame(pFormatCtx, packet) >= 0){if (packet->stream_index == videoindex){ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);if (ret < 0){printf("Decode Error.\n");return ;}if (got_picture){sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,pFrameYUV->data, pFrameYUV->linesize);av_init_packet(&pkt);pkt.data = NULL;    // packet data will be allocated by the encoderpkt.size = 0;pFrameYUV->width = c->width;pFrameYUV->height = c->height;pFrameYUV->format = c->pix_fmt;/* encode the image */ret = avcodec_encode_video2(c, &pkt, pFrameYUV, &got_output);if (ret < 0) {fprintf(stderr, "Error encoding frame\n");exit(1);}if (got_output) {iCount++;fwrite(pkt.data, 1, pkt.size, f);av_packet_unref(&pkt);if (iCount % 1000 == 0){printf("1000帧用时:%d   平均每秒 %f 帧 \n", (av_gettime() - iStart)/100000, (double)1000 * 1000000 / (av_gettime() - iStart));printf("Write frame %3d (size=%5d)\n", i, pkt.size);int fd = _fileno(f); //获取文件描述符
                        _commit(fd);iStart = av_gettime();}}}}av_free_packet(packet);}/* get the delayed frames */for (got_output = 1; got_output; i++) {fflush(stdout);ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);if (ret < 0) {fprintf(stderr, "Error encoding frame\n");exit(1);}if (got_output) {printf("Write frame %3d (size=%5d)\n", i, pkt.size);fwrite(pkt.data, 1, pkt.size, f);av_packet_unref(&pkt);}}/* add sequence end code to have a real MPEG file */fwrite(endcode, 1, sizeof(endcode), f);fclose(f);avcodec_close(c);av_free(c);printf("\n");
}int main(int argc, char **argv)
{/* register all the codecs */avcodec_register_all();avcodec_register_all();avdevice_register_all();avfilter_register_all();av_register_all();avformat_network_init();video_encode_example("H:\\nvenc\\test.hevc");system("pause");return 0;
}

上面用nvenc编出来的并没有封装成文件。h264格式potplayer还可以直接播放,hevc格式就不行了。hevc必须先封装,比如封装成mp4文件,然后才能播放。如何封装的例子网上比较多,我这里给个ffmpeg命令行的示例:

ffmpeg -i f:\25国.265 -c:v copy -f mp4 f:\25国.mp4

最后,nvenc对显卡的要求好像比较高,注意查看自己的显卡是否支持nvenc。

工程源码:http://download.csdn.net/download/qq_33892166/9840113

源码的ffmpg是64位的。

转载于:https://www.cnblogs.com/betterwgo/p/6843390.html

ffmpeg nvenc编码相关推荐

  1. 【视频开发】【CUDA开发】ffmpeg nvenc编码

    花时间研究了一些ffmpeg的nvenc,本来想我已经有了cuvid,然后又搞出来了nvenc,应该可以做个全套的英伟达的转码了,没想到ffmpeg官网下载的动态库没有cuvid,windows上编译 ...

  2. android平台Camera采集数据ffmpeg进行编码探究

      在PC机上,Camera采集数据利用ffmpeg进行编码往往没有任何问题,但是到了android平台或多或少会出现一系列问题,下面就针对这些问题总结一下. 1.在PC和android平台最大的差别 ...

  3. ffmpeg+x264编码mp4格式的视频出现视频帧率很大,导致视频无法播放的问题

    最新用ffmpeg+x264编码视频,之前使用老版本的ffmpeg编码视频文件没有问题,但是换了最新的版本之后(ffmpeg版本号2.8.2),出现了编码出来的视频帧率特别大的问题. 找了很久,终于解 ...

  4. FFMPEG之编码实现RTMP循环推流(附带av_interleaved_write_frame返回-22处理)04

    FFMPEG之编码实现RTMP循环推流(附带av_interleaved_write_frame返回-22处理) 前言 本篇是参考雷神的推流进行二次处理的,可以参考雷神这篇博客.[最简单的基于FFmp ...

  5. LiveVideoStackCon 2018技术培训 — 从FFmpeg视频编码到抖音式视频特效实现

    LiveVideoStackCon 2018技术培训,"从FFmpeg视频编码到抖音式视频特效实现".我们拒绝"纸上谈兵",坚持技术讲解与实战训练相结合.门票火 ...

  6. ffmpeg 视频编码一(精简版)

    1. ffmpeg 视频解码一 2. ffmpeg 视频解码二 3. ffmpeg 音频解码一 4. ffmpeg 音频解码二 5. ffmpeg 音视频解码 6. ffmpeg 视频编码一 7. f ...

  7. ffmpeg 视频编码三(基于 libavfilter 转换视频)

    1. ffmpeg 视频解码一 2. ffmpeg 视频解码二 3. ffmpeg 音频解码一 4. ffmpeg 音频解码二 5. ffmpeg 音视频解码 6. ffmpeg 视频编码一 7. f ...

  8. FFmpeg中编码类型为rawvideo无须解码直接显示测试代码

    在 https://blog.csdn.net/fengbingchun/article/details/93975325 中介绍过通过FFmpeg可以直接获取usb视频流并解码显示的测试代码,当时通 ...

  9. FFmpeg音频编码 ---- pcm转aac(使用新版ffmpeg API,亲测可用)

    /** * @projectName 08-01-encode_audio * @brief 音频编码 * 从本地读取PCM数据进行AAC编码 * 1. 输入PCM格式问题,通过AVCodec的sam ...

最新文章

  1. 宇宙射线会导致路由器 bug,思科你认真的吗
  2. vmware centos 7 刚装上不能上网
  3. Django项目:CRM(客户关系管理系统)--12--05PerfectCRM实现King_admin注册功能获取内存01...
  4. 单调栈 leetcode整理(三)
  5. 说一个闭包在实际开发中的应用
  6. 自动化测试框架的搭建
  7. selenium遇到的问题记录
  8. HCIE Security 防火墙带宽管理 备考笔记(幕布)
  9. 迅为IMX6ULL开发板Linux下电容触摸屏实验-实验程序编写
  10. 顺序栈的实验报告c语言,顺序栈的基本操作(C语言)
  11. linux下重启tomcat命令
  12. ubuntu22.04无法打开网易云音乐APP
  13. python中temp是什么意思_.temp(temp是什么意思?)
  14. Codeforces - Captain Flint and Treasure
  15. Python Scapy发送数据包
  16. 大数据应用实践2: IMDG应用场景
  17. matlab simulink 单相可调交流电源设计
  18. ros手柄控制机器人小车(一)
  19. Ubuntu20.04实时显示CPU、内存、网速
  20. strust2-学习(一)框架搭建和简单示例

热门文章

  1. 视图的创建(第十次作业)
  2. DHPST分销系统-EP分销-云主机分销系统
  3. 身份证号第18位(效验码)计算方法 用于检测身份证号是否正确
  4. 产业数字化时代,近千亿美元估值的阿里云必将大有所为!
  5. 出租车计价:某城市普通出租车收费标准如下:起步里程为3公里,起步费10元:超过起步里程后10公里内即每公里2元;
  6. GBASE 8A v953报错集锦56--Hadoop 加载失败问题
  7. 伏地魔爱上林黛玉?就没有B站不能组的CP!
  8. 软件测试简历上的职业技能怎么写,测试工程师岗位个人简历个人技能范文
  9. 技术博客|第8期:广告流量匹配算法在Hulu/Disney Streaming平台的实战
  10. ardupilot GPS代码分析