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

1.nvenc编码

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

  1. #include "stdafx.h"
  2.  
  3. /*
  4. * Video encoding example
  5. */
  6. static void video_encode_example(const char *filename)
  7. {
  8. AVCodec *codec;
  9. AVCodecContext *c = NULL;
  10. int i, ret, x, y, got_output;
  11. AVFrame *frame;
  12. AVPacket pkt;
  13. uint8_t endcode[] = { , , , 0xb7 };
  14.  
  15. av_log_set_level();
  16.  
  17. //AVBufferRef *device_ref = NULL;
  18. //AVBufferRef *hw_frames_ctx = NULL;
  19. //hw_frames_ctx = (AVBufferRef *)av_mallocz(sizeof(AVBufferRef));
  20. //if (!hw_frames_ctx) {
  21. // ret = AVERROR(ENOMEM);
  22. // return ;
  23. //}
  24.  
  25. //ret = av_hwdevice_ctx_create(&device_ref, AV_HWDEVICE_TYPE_CUDA,"CUDA", NULL, 0);
  26. //if (ret < 0)
  27. // return;
  28.  
  29. //hw_frames_ctx = av_hwframe_ctx_alloc(device_ref);
  30. //if (!hw_frames_ctx) {
  31. // av_log(NULL, AV_LOG_ERROR, "av_hwframe_ctx_alloc failed\n");
  32. // ret = AVERROR(ENOMEM);
  33. // return;
  34. //}
  35. //av_buffer_unref(&device_ref);
  36.  
  37. //c->hw_frames_ctx = av_buffer_ref(hw_frames_ctx);
  38. //if (!hw_frames_ctx) {
  39. // av_log(NULL, AV_LOG_ERROR, "av_buffer_ref failed\n");
  40. // ret = AVERROR(ENOMEM);
  41. // return;
  42. //}
  43.  
  44. printf("Encode video file %s\n", filename);
  45.  
  46. /* find the video encoder */
  47. codec = avcodec_find_encoder_by_name("hevc_nvenc");
  48. //codec = avcodec_find_encoder(AV_CODEC_ID_H265);
  49. //codec = avcodec_find_encoder_by_name("h264_nvenc");
  50. //codec = avcodec_find_encoder(AV_CODEC_ID_H264);
  51. if (!codec) {
  52. fprintf(stderr, "Codec not found\n");
  53. exit();
  54. }
  55.  
  56. c = avcodec_alloc_context3(codec);
  57. if (!c) {
  58. fprintf(stderr, "Could not allocate video codec context\n");
  59. exit();
  60. }
  61.  
  62. /* put sample parameters */
  63. c->bit_rate = ;
  64. /* resolution must be a multiple of two */
  65. c->width = ;
  66. c->height = ;
  67. /* frames per second */
  68. c->time_base.num = ;
  69. c->time_base.den = ;
  70. /* emit one intra frame every ten frames
  71. * check frame pict_type before passing frame
  72. * to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
  73. * then gop_size is ignored and the output of encoder
  74. * will always be I frame irrespective to gop_size
  75. */
  76. c->gop_size = ;
  77. c->max_b_frames = ;
  78. c->pix_fmt = AV_PIX_FMT_YUV420P;//AV_PIX_FMT_CUDA;
  79. c->max_b_frames = ;
  80.  
  81. AVDictionary *param = ;
  82. //H.264
  83. if (codec->id == AV_CODEC_ID_H264) {
  84. av_dict_set(&param, "preset", "medium", );
  85. av_dict_set(&param, "tune", "zerolatency", );
  86. }
  87. //H.265
  88. if (codec->id == AV_CODEC_ID_H265 || codec->id == AV_CODEC_ID_HEVC){
  89. //av_dict_set(&param, "x265-params", "qp=20", 0);
  90. av_dict_set(&param, "x265-params", "crf=25", );
  91. av_dict_set(&param, "preset", "fast", );
  92. av_dict_set(&param, "tune", "zero-latency", );
  93. }
  94.  
  95. /* open it */
  96. if (avcodec_open2(c, codec, &param) < ) {
  97. fprintf(stderr, "Could not open codec\n");
  98. system("pause");
  99. exit();
  100. }
  101.  
  102. FILE *f;
  103. f = fopen(filename, "wb");
  104. if (!f) {
  105. fprintf(stderr, "Could not open %s\n", filename);
  106. exit();
  107. }
  108.  
  109. frame = av_frame_alloc();
  110. if (!frame) {
  111. fprintf(stderr, "Could not allocate video frame\n");
  112. exit();
  113. }
  114. frame->format = c->pix_fmt;
  115. frame->width = c->width;
  116. frame->height = c->height;
  117.  
  118. /* the image can be allocated by any means and av_image_alloc() is
  119. * just the most convenient way if av_malloc() is to be used */
  120. ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height,
  121. c->pix_fmt, );
  122. if (ret < ) {
  123. fprintf(stderr, "Could not allocate raw picture buffer\n");
  124. exit();
  125. }
  126.  
  127. /* encode 1 second of video */
  128. for (i = ; i < ; i++) {
  129. av_init_packet(&pkt);
  130. pkt.data = NULL; // packet data will be allocated by the encoder
  131. pkt.size = ;
  132.  
  133. fflush(stdout);
  134. /* prepare a dummy image */
  135. /* Y */
  136. for (y = ; y < c->height; y++) {
  137. for (x = ; x < c->width; x++) {
  138. frame->data[][y * frame->linesize[] + x] = x + y + i * ;
  139. }
  140. }
  141.  
  142. /* Cb and Cr */
  143. for (y = ; y < c->height / ; y++) {
  144. for (x = ; x < c->width / ; x++) {
  145. frame->data[][y * frame->linesize[] + x] = + y + i * ;
  146. frame->data[][y * frame->linesize[] + x] = + x + i * ;
  147. }
  148. }
  149.  
  150. frame->pts = i;
  151.  
  152. /* encode the image */
  153. ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
  154. if (ret < ) {
  155. fprintf(stderr, "Error encoding frame\n");
  156. exit();
  157. }
  158.  
  159. if (got_output) {
  160. printf("Write frame %3d (size=%5d)\n", i, pkt.size);
  161. fwrite(pkt.data, , pkt.size, f);
  162. av_packet_unref(&pkt);
  163. }
  164. }
  165.  
  166. /* get the delayed frames */
  167. for (got_output = ; got_output; i++) {
  168. fflush(stdout);
  169.  
  170. ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
  171. if (ret < ) {
  172. fprintf(stderr, "Error encoding frame\n");
  173. exit();
  174. }
  175.  
  176. if (got_output) {
  177. printf("Write frame %3d (size=%5d)\n", i, pkt.size);
  178. fwrite(pkt.data, , pkt.size, f);
  179. av_packet_unref(&pkt);
  180. }
  181. }
  182.  
  183. /* add sequence end code to have a real MPEG file */
  184. fwrite(endcode, , sizeof(endcode), f);
  185. fclose(f);
  186.  
  187. avcodec_close(c);
  188. av_free(c);
  189. av_freep(&frame->data[]);
  190. av_frame_free(&frame);
  191. printf("\n");
  192. }
  193.  
  194. int main(int argc, char **argv)
  195. {
  196. /* register all the codecs */
  197. avcodec_register_all();
  198.  
  199. avcodec_register_all();
  200.  
  201. avdevice_register_all();
  202.  
  203. avfilter_register_all();
  204. av_register_all();
  205. avformat_network_init();
  206.  
  207. video_encode_example("test.hevc");
  208.  
  209. system("pause");
  210.  
  211. return ;
  212. }

代码中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来编码,缺点当然是这样比较慢了。

  1. #include "stdafx.h"
  2.  
  3. #include <stdio.h>
  4. #include <io.h>
  5.  
  6. /*
  7. * Video encoding example
  8. */
  9. static void video_encode_example(const char *filename)
  10. {
  11. AVCodec *codec;
  12. AVCodecContext *c = NULL;
  13. int i, ret, x, y, got_output;
  14. AVPacket pkt;
  15. uint8_t endcode[] = { , , , 0xb7 };
  16.  
  17. av_log_set_level();
  18.  
  19. AVFormatContext *pFormatCtx;
  20. int videoindex;
  21. AVCodecContext *pCodecCtx;
  22. AVCodec *pCodec;
  23. AVFrame *pFrame, *pFrameYUV;
  24. uint8_t *out_buffer;
  25.  
  26. char filepath[] = "H:\\nvenc\\灿烂人生1280.rmvb";
  27.  
  28. av_register_all();
  29. avformat_network_init();
  30. pFormatCtx = avformat_alloc_context();
  31.  
  32. if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != ){
  33. printf("Couldn't open input stream.\n");
  34. return ;
  35. }
  36. if (avformat_find_stream_info(pFormatCtx, NULL)<){
  37. printf("Couldn't find stream information.\n");
  38. return ;
  39. }
  40. videoindex = -;
  41. for (i = ; i<pFormatCtx->nb_streams; i++)
  42. if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
  43. videoindex = i;
  44. break;
  45. }
  46.  
  47. if (videoindex == -){
  48. printf("Didn't find a video stream.\n");
  49. return ;
  50. }
  51.  
  52. pCodecCtx = pFormatCtx->streams[videoindex]->codec;
  53. pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
  54. if (pCodec == NULL){
  55. printf("Codec not found.\n");
  56. return ;
  57. }
  58. if (avcodec_open2(pCodecCtx, pCodec, NULL)<){
  59. printf("Could not open codec.\n");
  60. return ;
  61. }
  62.  
  63. pFrame = av_frame_alloc();
  64. pFrameYUV = av_frame_alloc();
  65. out_buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
  66. avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
  67.  
  68. //Output Info-----------------------------
  69. printf("--------------- File Information ----------------\n");
  70. av_dump_format(pFormatCtx, , filepath, );
  71. printf("-------------------------------------------------\n");
  72. struct SwsContext *img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
  73. pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
  74.  
  75. printf("Encode video file %s\n", filename);
  76.  
  77. /* find the video encoder */
  78. codec = avcodec_find_encoder_by_name("hevc_nvenc");
  79. //codec = avcodec_find_encoder(AV_CODEC_ID_H265);
  80. //codec = avcodec_find_encoder_by_name("h264_nvenc");
  81. //codec = avcodec_find_encoder(AV_CODEC_ID_H264);
  82. if (!codec) {
  83. fprintf(stderr, "Codec not found\n");
  84. exit();
  85. }
  86.  
  87. c = avcodec_alloc_context3(codec);
  88. if (!c) {
  89. fprintf(stderr, "Could not allocate video codec context\n");
  90. exit();
  91. }
  92.  
  93. /* put sample parameters */
  94. c->bit_rate = pCodecCtx->bit_rate;
  95. /* resolution must be a multiple of two */
  96. c->width = pCodecCtx->width;
  97. c->height = pCodecCtx->height;
  98. c->time_base = pCodecCtx->time_base;
  99. c->gop_size = pCodecCtx->gop_size;
  100.  
  101. c->pix_fmt = AV_PIX_FMT_YUV420P;
  102. c->max_b_frames = ;
  103.  
  104. AVDictionary *param = ;
  105. //H.264
  106. if (codec->id == AV_CODEC_ID_H264) {
  107. av_dict_set(&param, "preset", "medium", );
  108. av_dict_set(&param, "tune", "zerolatency", );
  109. }
  110. //H.265
  111. if (codec->id == AV_CODEC_ID_H265 || codec->id == AV_CODEC_ID_HEVC){
  112. //av_dict_set(&param, "x265-params", "qp=20", 0);
  113. av_dict_set(&param, "x265-params", "crf=25", );
  114. av_dict_set(&param, "preset", "fast", );
  115. av_dict_set(&param, "tune", "zero-latency", );
  116. }
  117.  
  118. /* open it */
  119. if (avcodec_open2(c, codec, &param) < ) {
  120. fprintf(stderr, "Could not open codec\n");
  121. system("pause");
  122. exit();
  123. }
  124.  
  125. FILE *f;
  126. f = fopen(filename, "wb");
  127. if (!f) {
  128. fprintf(stderr, "Could not open %s\n", filename);
  129. exit();
  130. }
  131.  
  132. AVPacket *packet;
  133. packet = (AVPacket *)av_malloc(sizeof(AVPacket));
  134. int got_picture;
  135. int iCount = ;
  136. int64_t iStart = av_gettime();
  137. while (av_read_frame(pFormatCtx, packet) >= ){
  138. if (packet->stream_index == videoindex){
  139. ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
  140. if (ret < ){
  141. printf("Decode Error.\n");
  142. return ;
  143. }
  144. if (got_picture){
  145. sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, , pCodecCtx->height,
  146. pFrameYUV->data, pFrameYUV->linesize);
  147.  
  148. av_init_packet(&pkt);
  149. pkt.data = NULL; // packet data will be allocated by the encoder
  150. pkt.size = ;
  151.  
  152. pFrameYUV->width = c->width;
  153. pFrameYUV->height = c->height;
  154. pFrameYUV->format = c->pix_fmt;
  155.  
  156. /* encode the image */
  157. ret = avcodec_encode_video2(c, &pkt, pFrameYUV, &got_output);
  158. if (ret < ) {
  159. fprintf(stderr, "Error encoding frame\n");
  160. exit();
  161. }
  162.  
  163. if (got_output) {
  164.  
  165. iCount++;
  166. fwrite(pkt.data, , pkt.size, f);
  167. av_packet_unref(&pkt);
  168.  
  169. if (iCount % == )
  170. {
  171. printf("1000帧用时:%d 平均每秒 %f 帧 \n", (av_gettime() - iStart)/, (double) * / (av_gettime() - iStart));
  172. printf("Write frame %3d (size=%5d)\n", i, pkt.size);
  173.  
  174. int fd = _fileno(f); //获取文件描述符
  175. _commit(fd);
  176.  
  177. iStart = av_gettime();
  178. }
  179.  
  180. }
  181.  
  182. }
  183. }
  184. av_free_packet(packet);
  185. }
  186.  
  187. /* get the delayed frames */
  188. for (got_output = ; got_output; i++) {
  189. fflush(stdout);
  190.  
  191. ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
  192. if (ret < ) {
  193. fprintf(stderr, "Error encoding frame\n");
  194. exit();
  195. }
  196.  
  197. if (got_output) {
  198. printf("Write frame %3d (size=%5d)\n", i, pkt.size);
  199. fwrite(pkt.data, , pkt.size, f);
  200. av_packet_unref(&pkt);
  201. }
  202. }
  203.  
  204. /* add sequence end code to have a real MPEG file */
  205. fwrite(endcode, , sizeof(endcode), f);
  206. fclose(f);
  207.  
  208. avcodec_close(c);
  209. av_free(c);
  210. printf("\n");
  211. }
  212.  
  213. int main(int argc, char **argv)
  214. {
  215. /* register all the codecs */
  216. avcodec_register_all();
  217.  
  218. avcodec_register_all();
  219.  
  220. avdevice_register_all();
  221.  
  222. avfilter_register_all();
  223. av_register_all();
  224. avformat_network_init();
  225.  
  226. video_encode_example("H:\\nvenc\\test.hevc");
  227.  
  228. system("pause");
  229.  
  230. return ;
  231. }

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

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

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

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

源码的ffmpg是64位的。

ffmpeg nvenc编码的更多相关文章

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

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

  2. ffmpeg音频编码

    在弄音频采集时,需要设置缓存的大小,如果只是简单的采集和直接播放PCM数据,缓存的大小一般不影响播放和保存. 但是,如果需要使用FFMpeg音频编码,这时,音频缓存的大小必须设置av_samples_ ...

  3. ffmpeg h264编码 extradata 为空

    ffmpeg h264编码的例子前面的文章已经介绍,本来主要讲述影响AVCodecContext extradata是否为 空的配置项.如果要求open编码器以后AVCodecContext extr ...

  4. Ffmpeg AAC 编码错误 Input contains (near) NaN/+-Inf

    Ffmpeg AAC编码 如果传入参Frame的Sample Format 为 AV_SAMPLE_FMT_S16,会出现 错误提示 Input contains (near) NaN/+-Inf,需 ...

  5. ffmpeg,X264编码结果I帧QP比P帧还大

    enc_ctx->profile =FF_PROFILE_H264_MAIN ; enc_ctx->time_base.den = 24; enc_ctx->time_base.nu ...

  6. 使用ffmpeg视频编码过程中踩的一个坑

           今天说说使用ffmpeg在写视频编码程序中踩的一个坑,这个坑让我花了好多时间,回头想想,非常多时候一旦思维定势真的挺难突破的.以下是不对的编码结果:                   ...

  7. 基于ffmpeg不同编码方式转码后的psnr对比

    一.测试说明: 源文件:1080psrc.mp4 时长:900秒 源文件信息:Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080 [S ...

  8. JavaCV FFmpeg H264编码

    上次成功通过FFmpeg采集摄像头的YUV数据,这次针对上一次的程序进行了改造,使用H264编码采集后的数据. (传送门) JavaCV FFmpeg采集摄像头YUV数据 采集摄像头数据是一个解码过程 ...

  9. JavaCV FFmpeg AAC编码

    上次成功通过FFmpeg采集麦克风的PCM数据,这次针对上一次的程序进行了改造,使用AAC编码采集后的数据. (传送门) JavaCV FFmpeg采集麦克风PCM音频数据 采集麦克风数据是一个解码过 ...

随机推荐

  1. windows 本地配置hadoop客户端

    下载解压 hadoop 至D:\hadoop2.6.0 配置环境变量 HADOOP_HOME=D:\hadoop2.6.0 下载hadoop windows插件  将dll文件放入C:\Windows ...

  2. 【转载】IDEA:放置型塔防备忘录

    下周开始做原型了,我需要再次细细的整理一遍设计思路,确保每一个设计都能为了我所追求的玩家体验添砖加瓦,而不是互相打架.同时本文还能提供最原始的VISION,待到将来开发万一陷入泥淖,翻出此文来可以起到 ...

  3. TortoiseSVN_1.9.1.267_x64版本控制系统(针对Visual SVN Server)使用简单介绍

    软件下载地址:TortoiseSVN(SVN客户端)64位 V1.9.1.267简体中文免费版 软件详细操作说明:TortoiseSVN使用说明书(超详细) 文章内容:此篇是简单记录如何从Visual ...

  4. sublime 安装插件报错

    sublime  安装插件报错,大部分原因是本地防火墙开启了,关闭本地防火墙

  5. selenim之ActionChains 用法

    常见的点击方法集锦: 参数: 1.driver是我们的浏览器 2.Actions是我们系统内置的执行鼠标一系列操作的对象 鼠标左击:Actions actions=new Actions(driver ...

  6. Storm完整例子

    import backtype.storm.spout.SpoutOutputCollector; import backtype.storm.task.TopologyContext; import ...

  7. 20145310《Java程序设计》第2次实验报告

    20145310<Java程序设计>第2次实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计 ...

  8. JavaScript 数据类型小结

    数据类型对于机器而言,其意义在于更加合理的分配内存空间,而对于编程者而言,数据类型提供了我们相对应的一系列方法,对数据进行分析与处理. 在本文中,将对JavaScript数据类型的基础知识进行总结,全 ...

  9. MR案例:内连接代码实现

    本文是对Hive中[内连接]的Java-API的实现,具体的HQL语句详见Hive查询Join package join.map; import java.io.IOException; import ...

  10. optind变量

    1.这个变量是在什么地方定义的? 答:系统定义的 2.这个变量在什么场景下使用? 答:在解析命令行参数时会用到 3.这个变量存在的意义? 在每调用一次getopt()或getopt_long()类似函 ...