花时间研究了一些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.264
if (codec->id == AV_CODEC_ID_H264) {
av_dict_set(&param, "preset", "medium", 0);
av_dict_set(&param, "tune", "zerolatency", 0);
}
//H.265
if (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 encoder
pkt.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.264
if (codec->id == AV_CODEC_ID_H264) {
av_dict_set(&param, "preset", "medium", 0);
av_dict_set(&param, "tune", "zerolatency", 0);
}
//H.265
if (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 encoder
pkt.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位的。

【视频开发】【CUDA开发】ffmpeg nvenc编码的更多相关文章

  1. ffmpeg nvenc编码

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

  2. 【视频开发】【CUDA开发】FFMPEG硬件加速-nvidia方案

    1.目标 <1>显卡性能参数: <2>方案可行性: 2.平台信息 2.1.查看当前显卡信息 命令:  lspci |grep VGA  信息:  01:00.0 VGA com ...

  3. 【ARM-Linux开发】【CUDA开发】【深度学习与神经网络】Jetson Tx2安装相关之三

    JetPack(Jetson SDK)是一个按需的一体化软件包,捆绑了NVIDIA®Jetson嵌入式平台的开发人员软件.JetPack 3.0包括对Jetson TX2 , Jetson TX1和J ...

  4. WEB开发中的字符集和编码

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  5. 视频直播APP开发分析

    视频直播APP开发到目前为止都还是热门的一个行业,而且发展到现在直播的种类非常多,很多行业都打入了直播行业,再也不是单纯的人物直播这么单一了.视频直播APP开发行业就像是吃螃蟹,来的早的人不懂如何吃, ...

  6. iOS开发拓展篇—CoreLocation地理编码

    iOS开发拓展篇—CoreLocation地理编码 一.简单说明 CLGeocoder:地理编码器,其中Geo是地理的英文单词Geography的简写. 1.使用CLGeocoder可以完成“地理编码 ...

  7. 【PHP开发规范】老生常谈的编码开发规范你懂多少?

    [PHP开发规范]老生常谈的编码开发规范你懂多少? 这几天看了一下阿里技术发布的一套Java开发规范<阿里巴巴Java开发手册>,里面写了阿里内部的Java开发规范标准,写的很好.这套Ja ...

  8. Windows平台CUDA开发之前的准备工作

    CUDA是NVIDIA的GPU开发工具,眼下在大规模并行计算领域有着广泛应用. windows平台上面的CUDA开发之前.最好去NVIDIA官网查看说明,然后下载对应的driver. ToolKits ...

  9. 【CUDA开发】CUDA面内存拷贝用法总结

    [CUDA开发]CUDA面内存拷贝用法总结 标签(空格分隔): [CUDA开发] 主要是在调试CUDA硬解码并用D3D9或者D3D11显示的时候遇到了一些代码,如下所示: CUdeviceptr g_ ...

随机推荐

  1. springboot,eclipse打包出错处理

    打jar包报错 [WARNING] The POM for org.apache.maven.plugins:maven-clean-plugin:jar:3.1.0 is invalid, tran ...

  2. HTTP Status 500 - DateConverter does not support default String to 'Date' conversion.错误

    //自己指定一个类型转换器(将String转成Date) DateConverter converter = new DateConverter(); converter.setPattern(new ...

  3. CentOS7.6安装docker最新版

    注意Centos7.4系统以下需要升级内核,否则会安装失败 yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config ...

  4. nginx设置反向代理,获取真实客户端ip

    upstream这个模块提供一个简单方法来实现在轮询和客户端IP之间的后端服务器负荷平衡. upstream abc.com { server 127.0.0.1:8080; server 127.0 ...

  5. oracle中LPAD和RPAD函数的使用方法(加个人总结)

    今天看到两个没有见过的SQL中的函数,总结一下: 函数参数:lpad( string1, padded_length, [ pad_string ] ) 其中 string1:源字符串 padded_ ...

  6. 求x,y中的最大值

    分析: 输入——变量x,y存放输入的两个整数: 输出——变量m存放输入的两个整数的最大值,m为输出: 算法——如果x比y大,x赋给m,否则y赋给m. #include<stdio.h>vo ...

  7. Centos7 虚拟机里查看IP并启动网卡

    输入ip查询命名 ip addr  也可以输入 ifconfig(centOs7没有ifconfig命令)查看ip,但此命令会出现3个条目,centos的ip地址是ens33条目中的inet值. 发现 ...

  8. L1141(bfs思想)

    一,看 1,整个方格图其实可以看做是一些不连通的图. 当然图内部必然是联通的. 2,遍历的技巧没什么. 方格图入队的技巧..额,是这样的 int gtid(int x,int y) { return ...

  9. “OKR播种机”JOHN DOERR–目标是对抗纷乱思绪的一针疫苗

    OKR培养出疯狂的想法,再加上对的人,奇迹就会出现 约翰·杜尔是美国最有影响力.最具创意.最不拘传统的冒险资本投资家之一.在短短10年内创造了高达1,000亿美元的经济价值.迄今为止,他已向 250家 ...

  10. tox python项目虚拟环境管理自动化测试&&构建工具

    tox 是一个方便的工具,可以帮助我们管理python 的虚拟环境,同时可以进行项目自动测试以及构建 tox 如何工作的 说明 从上图我们也可以看出如何在我们项目中使用tox 参考资料 https:/ ...