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音频数据 采集麦克风数据是一个解码过 ...
随机推荐
- windows 本地配置hadoop客户端
下载解压 hadoop 至D:\hadoop2.6.0 配置环境变量 HADOOP_HOME=D:\hadoop2.6.0 下载hadoop windows插件 将dll文件放入C:\Windows ...
- 【转载】IDEA:放置型塔防备忘录
下周开始做原型了,我需要再次细细的整理一遍设计思路,确保每一个设计都能为了我所追求的玩家体验添砖加瓦,而不是互相打架.同时本文还能提供最原始的VISION,待到将来开发万一陷入泥淖,翻出此文来可以起到 ...
- TortoiseSVN_1.9.1.267_x64版本控制系统(针对Visual SVN Server)使用简单介绍
软件下载地址:TortoiseSVN(SVN客户端)64位 V1.9.1.267简体中文免费版 软件详细操作说明:TortoiseSVN使用说明书(超详细) 文章内容:此篇是简单记录如何从Visual ...
- sublime 安装插件报错
sublime 安装插件报错,大部分原因是本地防火墙开启了,关闭本地防火墙
- selenim之ActionChains 用法
常见的点击方法集锦: 参数: 1.driver是我们的浏览器 2.Actions是我们系统内置的执行鼠标一系列操作的对象 鼠标左击:Actions actions=new Actions(driver ...
- Storm完整例子
import backtype.storm.spout.SpoutOutputCollector; import backtype.storm.task.TopologyContext; import ...
- 20145310《Java程序设计》第2次实验报告
20145310<Java程序设计>第2次实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计 ...
- JavaScript 数据类型小结
数据类型对于机器而言,其意义在于更加合理的分配内存空间,而对于编程者而言,数据类型提供了我们相对应的一系列方法,对数据进行分析与处理. 在本文中,将对JavaScript数据类型的基础知识进行总结,全 ...
- MR案例:内连接代码实现
本文是对Hive中[内连接]的Java-API的实现,具体的HQL语句详见Hive查询Join package join.map; import java.io.IOException; import ...
- optind变量
1.这个变量是在什么地方定义的? 答:系统定义的 2.这个变量在什么场景下使用? 答:在解析命令行参数时会用到 3.这个变量存在的意义? 在每调用一次getopt()或getopt_long()类似函 ...