FFmpeg打开x265编码器报错:Lookahead depth must be greater than the max consecutive bframe count

Posted Dontla

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FFmpeg打开x265编码器报错:Lookahead depth must be greater than the max consecutive bframe count相关的知识,希望对你有一定的参考价值。

原代码:

#pragma warning(disable : 4996)

// 2-muxing编码视频.cpp
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>       // 字符串操作
#include <direct.h>     // 文件夹
#include <stdbool.h>
#include <windows.h>


#ifdef __cplusplus
extern "C"             // ffmpeg 相关头文件
#endif
#include <libavformat/avformat.h>
//#include "libavcodec/avcodec.h"
#include <libavutil/opt.h>
#include "libavutil/imgutils.h"
#include "libswscale/swscale.h"
#ifdef __cplusplus

#endif

using namespace std;

#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "swscale.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment(lib, "postproc.lib")
#pragma comment(lib, "avdevice.lib")

/// 输入输出文件信息
//const char* Out_File_Name = "video.h264";
const char* Out_File_Name = "video_out.mp4";


#define CODEC_FLAG_GLOBAL_HEADER (1 << 22)

static void encodeMP4(AVCodecContext* enc_ctx, AVFormatContext* inFmtCtx,
	AVFormatContext* outFmtCtx, AVFrame* frame,
	AVPacket* pkt, int frameIndex);

int main()

	int ret;
	rtsp解码配置
	AVFormatContext* camFmtCtx = avformat_alloc_context();
	AVDictionary* options = NULL;
	char filepath[] = "rtsp://admin:abc12345@192.168.1.67/h264/ch1/main/av_stream";	//或"rtsp://admin:abc12345@192.168.1.67:554/h264/ch1/main/av_stream"
	av_dict_set(&options, "buffer_size", "1024000", 0); //设置缓存大小,1080p可将值跳到最大
	av_dict_set(&options, "rtsp_transport", "tcp", 0); //以tcp的方式打开,
	av_dict_set(&options, "stimeout", "5000000", 0); //设置超时断开链接时间,单位us
	av_dict_set(&options, "max_delay", "500000", 0); //设置最大时延	//不知道这些字典是干嘛用的,有的注释了也能跑


	//int ret = avformat_open_input(&camFmtCtx, "video=Vimicro USB 2.0 PC Camera (Venus)", iformat, &options);
	ret = avformat_open_input(&camFmtCtx, filepath, NULL, &options);
	if (ret != 0)
	
		av_dict_free(&options);
		return -1;
	

	av_dump_format(camFmtCtx, 0, filepath, 0);	//打印文件信息
	/*
	Input #0, rtsp, from 'rtsp://admin:abc12345@192.168.1.67/h264/ch1/main/av_stream':
  Metadata:
    title           : Media Presentation
  Duration: N/A, bitrate: N/A
    Stream #0:0: Video: h264, none, 90k tbn
    Stream #0:1: Audio: pcm_alaw, 8000 Hz, 1 channels, 64 kb/s
	*/

	//查找输入流
	ret = avformat_find_stream_info(camFmtCtx, NULL);	//将流信息填充进camFmtCtx中
	if (ret < 0)
	
		cout << "无法获取流的信息" << endl;
		return -1;
	
	int videoindex = -1;
	for (int i = 0; i < camFmtCtx->nb_streams; i++)
	
		if (camFmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
		
			videoindex = i;
			break;
		
	
	if (videoindex == -1)
	
		printf("Didn't find a video stream.\\n");
		return 0;
	
	//查找摄像头可用解码器
	AVCodecContext* camDecodeCtx = camFmtCtx->streams[videoindex]->codec;
	AVRational time_base = camFmtCtx->streams[videoindex]->time_base;

	AVCodecID codecID = camFmtCtx->streams[videoindex]->codecpar->codec_id;
	// cout << "codecID = " << codecID << endl;
	AVCodec* codec = avcodec_find_decoder(codecID);	//寻找codecID对应的编码器
	if (codec == NULL)
	
		cout << "没有解码器" << endl;
		return -1;
	

	ret = avcodec_open2(camDecodeCtx, codec, NULL);	//打开编码器
	if (ret < 0)
	
		cout << "avodec_open2 error" << endl;
		return -1;
	
	cout << "解码器打开成功" << endl;

	//H264编码器,encode函数使用
	//AVCodecID encodeID = AV_CODEC_ID_H264;
	AVCodecID encodeID = AV_CODEC_ID_H265;
	AVCodec* encodec = avcodec_find_encoder(encodeID);
	//avcodec_find_encoder_by_name();
	if (!encodec)
	
		cout << "encodec == NULL" << endl;
	
	AVCodecContext* encodeCtx = avcodec_alloc_context3(encodec);
	if (!encodeCtx)
	
		cout << "enc == NULL" << endl;
	

	encodeCtx->bit_rate = 400000;
	encodeCtx->width = camDecodeCtx->width;
	encodeCtx->height = camDecodeCtx->height;
	encodeCtx->time_base =  1, 25 ;
	encodeCtx->framerate =  25, 1 ;
	encodeCtx->gop_size = 10;
	encodeCtx->max_b_frames = 1;
	encodeCtx->pix_fmt = AV_PIX_FMT_YUV420P;
	//加载预设
	av_opt_set(encodeCtx->priv_data, "preset", "slow", 0);
	av_opt_set(encodeCtx->priv_data, "tune", "zerolatency", 0);

	ret = avcodec_open2(encodeCtx, encodec, NULL);
	if (ret < 0)
	
		cout << "encodec open error" << endl;
		exit(-1);
	

	// FILE* fp = nullptr;
	// fopen_s(&fp, "1.h264", "wb");
	// 改变为保存mp4方式
		AVFormatContext * outFmtCtx = nullptr;
	const char* fileName = "1.mp4";
	avformat_alloc_output_context2(&outFmtCtx, NULL, NULL, fileName);
	if (!outFmtCtx)
	
		printf("Could not create output context\\n");
		return -4;
	
	for (int i = 0; i < camFmtCtx->nb_streams; i++)
	
		AVStream* in_stream = camFmtCtx->streams[i];
		AVStream* out_stream = avformat_new_stream(outFmtCtx, in_stream->codec->
			codec);
		if (!out_stream)
		
			printf("Failed allocating output stream\\n");
			return -5;
		
		//Copy the settings of AVCodecContext
		if (avcodec_copy_context(out_stream->codec, in_stream->codec) < 0)
		
			printf("Failed to copy context from input to output stream codec context\\n"
			);
			return -6;
		
		out_stream->codec->codec_tag = 0;
		if (outFmtCtx->oformat->flags & AVFMT_GLOBALHEADER)
		
			out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
		

		avcodec_parameters_from_context(out_stream->codecpar, encodeCtx); //必须
	

	av_dump_format(outFmtCtx, 0, fileName, 1);

	if (!(outFmtCtx->oformat->flags & AVFMT_NOFILE))
	
		ret = avio_open(&outFmtCtx->pb, fileName, AVIO_FLAG_WRITE);
		if (ret < 0)
		
			printf("Could not open output file '%s'", fileName);
			return -7;
		
	


	if (avformat_write_header(outFmtCtx, NULL) < 0)
	
		printf("Error occurred when opening output file\\n");
		return -8;
	
	// 改变为保存mp4方式

		AVPacket * packetIn = av_packet_alloc();
	AVPacket* packetOut = av_packet_alloc();
	AVFrame* pFrameOut = av_frame_alloc();

	int got_picture;

	struct SwsContext* img_convert_ctx = sws_getContext(camDecodeCtx->width,
		camDecodeCtx->height,
		camDecodeCtx->pix_fmt,
		camDecodeCtx->width,
		camDecodeCtx->height,
		AV_PIX_FMT_YUV420P,
		/*SWS_FAST_BILINEAR*/
		SWS_BICUBIC, NULL, NULL, NULL);

	unsigned char* out_buffer = (unsigned char*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, camDecodeCtx->width,
			camDecodeCtx->height, 16));

	for (int i = 0; i < 250; i++)
	
		ret = av_read_frame(camFmtCtx, packetIn); //摄像头取到packet,要转为pFrameYUV的yuv格式

			if (ret >= 0 && packetIn->stream_index == videoindex)
			
				AVFrame* pFrameYUV = av_frame_alloc();

				pFrameYUV->format = AV_PIX_FMT_YUV420P;
				pFrameYUV->width = camDecodeCtx->width;
				pFrameYUV->height = camDecodeCtx->height;

				avpicture_fill((AVPicture*)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P,
					camDecodeCtx->width,
					camDecodeCtx->height);

				avcodec_decode_video2(camDecodeCtx, pFrameOut, &got_picture, packetIn);
				if (got_picture)
				
					sws_scale(img_convert_ctx, (const unsigned char* const*)pFrameOut->data,
						pFrameOut->linesize, 0,
						camDecodeCtx->height,
						pFrameYUV->data, pFrameYUV->linesize);
				
				unsigned int untime = GetTickCount();
				//pFrameYUV->pts = untime;

				//encode(encodeCtx, pFrameYUV, packetOut, fp); //编码yuv
				// 改变为保存mp4方式
					encodeMP4(encodeCtx, camFmtCtx, outFmtCtx, pFrameYUV, packetOut, i);
				// 改变为保存mp4方式

					av_free(pFrameYUV);
			
	

	// 改变为保存mp4方式
		//Write file trailer
		av_write_trailer(outFmtCtx);

	if (outFmtCtx && !(outFmtCtx->oformat->flags & AVFMT_NOFILE))
		avio_close(outFmtCtx->pb);
	avformat_free_context(outFmtCtx);
	//改变为保存mp4方式

		av_free(pFrameOut);
	av_packet_free(&packetIn);
	av_packet_free(&packetOut);
	sws_freeContext(img_convert_ctx);
	avcodec_free_context(&encodeCtx);
	av_free(out_buffer);

	//fclose(fp);

	//avcodec_free_context(&camDecodeCtx);
	avformat_close_input(&camFmtCtx);
	avformat_free_context(camFmtCtx);
	av_dict_free(&options);
			


static void encodeMP4(AVCodecContext* enc_ctx, AVFormatContext* inFmtCtx,
	AVFormatContext* outFmtCtx, AVFrame* frame,
	AVPacket* pkt, int frameIndex)

	int ret;

	/* send the frame to the encoder */
	if (frame)
		printf("Send frame %3", frame->pts);

	ret = avcodec_send_frame(enc_ctx, frame);
	if (ret < 0)
	
		fprintf(stderr, "Error sending a frame for encoding\\n");
		exit(1);
	

	while (ret >= 0)
	
		ret = avcodec_receive_packet(enc_ctx, pkt);
		if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
			return;
		else if (ret < 0)
		
			fprintf(stderr, "Error during encoding\\n");
			exit(1);
		


		AVStream* in_stream = inFmtCtx->streams[pkt->stream_index];
		AVRational timeBase = in_stream->time_base;
		AVStream* out_stream = outFmtCtx->streams[pkt->stream_index];

		///如果没有显示时间戳自己加上时间戳并且将显示时间戳赋值解码时间戳
		if (pkt->pts == AV_NOPTS_VALUE)
		
			//Write PTS
			AVRational time_base1 = timeBase;
			//Duration between 2 frames (us)
			int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->
				r_frame_rate);
			//Parameters
			pkt->pts = (double)(frameIndex * calc_duration) / (double)(av_q2d(
				time_base1) * AV_TIME_BASE);
			pkt->dts = pkt->pts;
			pkt->duration = (double)calc_duration / (double)(av_q2d(time_base1) *
				AV_TIME_BASE);
			//m_frame_index++;
		

		//Convert PTS/DTS
		pkt->pts = av_rescale_q_rnd(pkt->pts, timeBase, out_stream->time_base,
			(AVRounding)(AV_ROUND_NEAR_INF |
				AV_ROUND_PASS_MINMAX));
		pkt->dts = av_rescale_q_rnd(pkt->dts, timeBase, out_stream->time_base,
			(AVRounding)(AV_ROUND_NEAR_INF |
				AV_ROUND_PASS_MINMAX));
		pkt->duration = av_rescale_q(pkt->duration, timeBase, out_stream->time_base);

		pkt->pos = -1;

		printf("Write packet %d size=%d \\n", pkt->size, pkt->pts);

		if (av_interleaved_write_frame(outFmtCtx, pkt) < 0)
		
			printf("Error muxing packet\\n");
		

		av_packet_unref(pkt);
	


解决方法:
发现它的编码码率设置为40万,即400k,我改成400万,或者不设置(它自动选定默认值)就好了

以上是关于FFmpeg打开x265编码器报错:Lookahead depth must be greater than the max consecutive bframe count的主要内容,如果未能解决你的问题,请参考以下文章

2023-03-08:x265的视频编码器,不用ffmpeg,用libx265.dll也行。请用go语言调用libx265.dll,将yuv文件编码成h265文件。

使用 pkg-config 未找到编译 FFMPEG x265

mac下使用brew安装ffmpeg支持x265

FFmpeg h.265 MP4编码告警:deprecated pixel format used, make sure you did set range correctly

FFmpeg h.265 MP4编码告警:deprecated pixel format used, make sure you did set range correctly

linux 编译ffmpeg 支持x264, x265