ffmpeg nvenc编码
花时间研究了一些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[] = { , , , 0xb7 }; av_log_set_level(); //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();
} c = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate video codec context\n");
exit();
} /* put sample parameters */
c->bit_rate = ;
/* resolution must be a multiple of two */
c->width = ;
c->height = ;
/* frames per second */
c->time_base.num = ;
c->time_base.den = ;
/* 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 = ;
c->max_b_frames = ;
c->pix_fmt = AV_PIX_FMT_YUV420P;//AV_PIX_FMT_CUDA;
c->max_b_frames = ; AVDictionary *param = ;
//H.264
if (codec->id == AV_CODEC_ID_H264) {
av_dict_set(¶m, "preset", "medium", );
av_dict_set(¶m, "tune", "zerolatency", );
}
//H.265
if (codec->id == AV_CODEC_ID_H265 || codec->id == AV_CODEC_ID_HEVC){
//av_dict_set(¶m, "x265-params", "qp=20", 0);
av_dict_set(¶m, "x265-params", "crf=25", );
av_dict_set(¶m, "preset", "fast", );
av_dict_set(¶m, "tune", "zero-latency", );
} /* open it */
if (avcodec_open2(c, codec, ¶m) < ) {
fprintf(stderr, "Could not open codec\n");
system("pause");
exit();
} FILE *f;
f = fopen(filename, "wb");
if (!f) {
fprintf(stderr, "Could not open %s\n", filename);
exit();
} frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate video frame\n");
exit();
}
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, );
if (ret < ) {
fprintf(stderr, "Could not allocate raw picture buffer\n");
exit();
} /* encode 1 second of video */
for (i = ; i < ; i++) {
av_init_packet(&pkt);
pkt.data = NULL; // packet data will be allocated by the encoder
pkt.size = ; fflush(stdout);
/* prepare a dummy image */
/* Y */
for (y = ; y < c->height; y++) {
for (x = ; x < c->width; x++) {
frame->data[][y * frame->linesize[] + x] = x + y + i * ;
}
} /* Cb and Cr */
for (y = ; y < c->height / ; y++) {
for (x = ; x < c->width / ; x++) {
frame->data[][y * frame->linesize[] + x] = + y + i * ;
frame->data[][y * frame->linesize[] + x] = + x + i * ;
}
} frame->pts = i; /* encode the image */
ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
if (ret < ) {
fprintf(stderr, "Error encoding frame\n");
exit();
} if (got_output) {
printf("Write frame %3d (size=%5d)\n", i, pkt.size);
fwrite(pkt.data, , pkt.size, f);
av_packet_unref(&pkt);
}
} /* get the delayed frames */
for (got_output = ; got_output; i++) {
fflush(stdout); ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
if (ret < ) {
fprintf(stderr, "Error encoding frame\n");
exit();
} if (got_output) {
printf("Write frame %3d (size=%5d)\n", i, pkt.size);
fwrite(pkt.data, , pkt.size, f);
av_packet_unref(&pkt);
}
} /* add sequence end code to have a real MPEG file */
fwrite(endcode, , sizeof(endcode), f);
fclose(f); avcodec_close(c);
av_free(c);
av_freep(&frame->data[]);
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 ;
}
代码中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[] = { , , , 0xb7 }; av_log_set_level(); 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) != ){
printf("Couldn't open input stream.\n");
return ;
}
if (avformat_find_stream_info(pFormatCtx, NULL)<){
printf("Couldn't find stream information.\n");
return ;
}
videoindex = -;
for (i = ; i<pFormatCtx->nb_streams; i++)
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
videoindex = i;
break;
} if (videoindex == -){
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)<){
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, , filepath, );
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();
} c = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate video codec context\n");
exit();
} /* 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 = ; AVDictionary *param = ;
//H.264
if (codec->id == AV_CODEC_ID_H264) {
av_dict_set(¶m, "preset", "medium", );
av_dict_set(¶m, "tune", "zerolatency", );
}
//H.265
if (codec->id == AV_CODEC_ID_H265 || codec->id == AV_CODEC_ID_HEVC){
//av_dict_set(¶m, "x265-params", "qp=20", 0);
av_dict_set(¶m, "x265-params", "crf=25", );
av_dict_set(¶m, "preset", "fast", );
av_dict_set(¶m, "tune", "zero-latency", );
} /* open it */
if (avcodec_open2(c, codec, ¶m) < ) {
fprintf(stderr, "Could not open codec\n");
system("pause");
exit();
} FILE *f;
f = fopen(filename, "wb");
if (!f) {
fprintf(stderr, "Could not open %s\n", filename);
exit();
} AVPacket *packet;
packet = (AVPacket *)av_malloc(sizeof(AVPacket));
int got_picture;
int iCount = ;
int64_t iStart = av_gettime();
while (av_read_frame(pFormatCtx, packet) >= ){
if (packet->stream_index == videoindex){
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
if (ret < ){
printf("Decode Error.\n");
return ;
}
if (got_picture){
sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, , pCodecCtx->height,
pFrameYUV->data, pFrameYUV->linesize); av_init_packet(&pkt);
pkt.data = NULL; // packet data will be allocated by the encoder
pkt.size = ; 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 < ) {
fprintf(stderr, "Error encoding frame\n");
exit();
} if (got_output) { iCount++;
fwrite(pkt.data, , pkt.size, f);
av_packet_unref(&pkt); if (iCount % == )
{
printf("1000帧用时:%d 平均每秒 %f 帧 \n", (av_gettime() - iStart)/, (double) * / (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 = ; got_output; i++) {
fflush(stdout); ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
if (ret < ) {
fprintf(stderr, "Error encoding frame\n");
exit();
} if (got_output) {
printf("Write frame %3d (size=%5d)\n", i, pkt.size);
fwrite(pkt.data, , pkt.size, f);
av_packet_unref(&pkt);
}
} /* add sequence end code to have a real MPEG file */
fwrite(endcode, , 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 ;
}
上面用nvenc编出来的并没有封装成文件。h264格式potplayer还可以直接播放,hevc格式就不行了。hevc必须先封装,比如封装成mp4文件,然后才能播放。如何封装的例子网上比较多,我这里给个ffmpeg命令行的示例:
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编码的更多相关文章
- 【视频开发】【CUDA开发】ffmpeg nvenc编码
花时间研究了一些ffmpeg的nvenc,本来想我已经有了cuvid,然后又搞出来了nvenc,应该可以做个全套的英伟达的转码了,没想到ffmpeg官网下载的动态库没有cuvid,windows上编译 ...
- ffmpeg音频编码
在弄音频采集时,需要设置缓存的大小,如果只是简单的采集和直接播放PCM数据,缓存的大小一般不影响播放和保存. 但是,如果需要使用FFMpeg音频编码,这时,音频缓存的大小必须设置av_samples_ ...
- ffmpeg h264编码 extradata 为空
ffmpeg h264编码的例子前面的文章已经介绍,本来主要讲述影响AVCodecContext extradata是否为 空的配置项.如果要求open编码器以后AVCodecContext extr ...
- Ffmpeg AAC 编码错误 Input contains (near) NaN/+-Inf
Ffmpeg AAC编码 如果传入参Frame的Sample Format 为 AV_SAMPLE_FMT_S16,会出现 错误提示 Input contains (near) NaN/+-Inf,需 ...
- ffmpeg,X264编码结果I帧QP比P帧还大
enc_ctx->profile =FF_PROFILE_H264_MAIN ; enc_ctx->time_base.den = 24; enc_ctx->time_base.nu ...
- 使用ffmpeg视频编码过程中踩的一个坑
今天说说使用ffmpeg在写视频编码程序中踩的一个坑,这个坑让我花了好多时间,回头想想,非常多时候一旦思维定势真的挺难突破的.以下是不对的编码结果: ...
- 基于ffmpeg不同编码方式转码后的psnr对比
一.测试说明: 源文件:1080psrc.mp4 时长:900秒 源文件信息:Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080 [S ...
- JavaCV FFmpeg H264编码
上次成功通过FFmpeg采集摄像头的YUV数据,这次针对上一次的程序进行了改造,使用H264编码采集后的数据. (传送门) JavaCV FFmpeg采集摄像头YUV数据 采集摄像头数据是一个解码过程 ...
- JavaCV FFmpeg AAC编码
上次成功通过FFmpeg采集麦克风的PCM数据,这次针对上一次的程序进行了改造,使用AAC编码采集后的数据. (传送门) JavaCV FFmpeg采集麦克风PCM音频数据 采集麦克风数据是一个解码过 ...
随机推荐
- Oracle DB 移动数据
描述移动数据的方式 • 创建和使用目录对象 • 使用SQL*Loader 加载非Oracle DB(或用户文件)中的数据 • 使用外部表并通过与平台无关的文件移动数据 • 说明Oracle 数据泵的 ...
- appium 中手势密码的定位坐标
原文地址http://www.cnblogs.com/smallTestKK/p/5408143.html 1.press方法中的坐标为绝对坐标,moveTO方法中的坐标都是相对坐标,具体来说第一个m ...
- 进程 、进程组、会话、控制终端之间的关系 (转载 http://blog.csdn.net/yh1548503342/article/details/41891047)
一个进程组可以包含多个进程 进程组中的这些进程之间不是孤立的,他们彼此之间或者存在者父子.兄弟关系,或者在功能有相近的联系. 那linux为什么要有进程组呢?其实提供进程组就是方便管理这些进程.假设要 ...
- CCF 工资计算
思路: 因为T<=10000,所以税前极限金额肯定不超过1000000(设个比较大的数字就行),然后逐一计算即可. #include<cstdio> int main() { int ...
- maven 项目配置到tomcat不能正常启动
最近使用IntelliJ IDEA搭建公司项目,该项目是maven项目,加载jar和编译的时候没有任何异常,但是部署到tomcat上之后,就会出现如下异常: org.apache.catalina.L ...
- cgwin的ssh错误解决办法
参考博客 http://hi.baidu.com/luckygirl/item/bd00a6d8a05c310d20e25039 方法一(推荐): 修改/etc/passwd文件,在其中加入 s ...
- typeof instanceof 和 obj.constructor
1.typeof用以获取一个变量或者表达式的类型,typeof一般只能返回如下几个结果: 'number','boolean','string','function'(函数),'object'(NU ...
- python单元测试框架pytest——fixture函数(类似unitest的setup和teardown)
pytest的setup和teardown函数(曾被一家云计算面试官问到过). pytest提供了fixture函数用以在测试执行前和执行后进行必要的准备和清理工作.与python自带的unitest ...
- 【转载】redis优化
原文链接 批量操作优化: 在使用redis的时候,客户端通过socket向redis服务端发起请求后,等待服务端的返回结果. 客户端请求服务器一次就发送一个报文 -> 等待服务端的返回 -> ...
- 【Head First Servlets and JSP】笔记 26: web 应用部署
物理目录结构与虚拟目录结构的差异 WAR 实际上就是 JAR 什么东西应该放在 WEB-INF 文件夹下? <mime-mapping> 相关 <env-entry> 相关 [ ...