网络视频流 -- ffmpeg 视频编码

        ffmpeg 作为通用,好用,耐用的视频处理开源库,是大多数视频开发者的唯一选择,因为没钱,我也只能用这个。。

        网络视频流 -- ffmpeg 视频编码

        使用FFmpeg-4.3.1,DLL版本如上,由于调用软件兼容性问题,采用64位版本,直接上代码了:

DWORD WINAPI H264CoderFunc(LPVOID pParam)
{
	MSG msg;
	unsigned char* p;

	AVCodecContext* pCodecCtx = 0;
	AVCodec* pCodec;
	int in_w, in_h, got_picture, ret;
	AVPacket pkt;
	uint8_t* picture_buf;
	AVFrame* pFrame = 0;
	int picture_size;
	struct SwsContext* img_convert_ctx;
	AVDictionary* param = 0;

//	avcodec_register_all();新版本不需要初始化这个了
//	avformat_network_init();

	//查找h264编码器
	pCodec = avcodec_find_encoder(AV_CODEC_ID_H264);
	if (!pCodec)
	{
		goto o_Terminate_Coder_Thread;
	}

	pCodecCtx = avcodec_alloc_context3(pCodec);

	pCodecCtx->codec_id = AV_CODEC_ID_H264;
	pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
	pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
	pCodecCtx->width = pInf->width;
	pCodecCtx->height = pInf->height;
	pCodecCtx->time_base.num = 1;
	pCodecCtx->time_base.den = pInf->frame_rate;//帧率
	pCodecCtx->bit_rate = 5*1024 * 1024;
	pCodecCtx->bit_rate_tolerance = 5 * 1024 * 1024;
	pCodecCtx->rc_min_rate = 5 * 1024 * 1024;
	pCodecCtx->rc_max_rate = 5 * 1024 * 1024;
	pCodecCtx->bit_rate_tolerance = 5 * 1024 * 1024;
	pCodecCtx->rc_buffer_size = 5 * 1024 * 1024;
	pCodecCtx->rc_initial_buffer_occupancy = pCodecCtx->rc_buffer_size * 3 / 4;
	pCodecCtx->gop_size = pInf->gop;

	if (pCodecCtx->flags & AVFMT_GLOBALHEADER)
		pCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

	//H.264
	av_dict_set(&param, "preset", "superfast", 0);
	av_dict_set(&param, "tune", "zerolatency", 0);  //实现实时编码
	av_dict_set(&param, "profile", "main", 0);
	if (avcodec_open2(pCodecCtx, pCodec, &param) < 0) 
	{
		printf("Failed to open video encoder1! 编码器打开失败!\n");
		goto o_Terminate_Coder_Thread;
	}

	pFrame = av_frame_alloc();
	if (!pFrame) 
	{
		fprintf(stderr, "Could not allocate video frame\n");
		goto o_Terminate_Coder_Thread;
	}
	//AVFrame 内存获取与老版本不同,已修改
	picture_size = av_image_get_buffer_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, 1);
	picture_buf = (uint8_t*)av_mallocz(picture_size);
	av_image_fill_arrays(pFrame->data, pFrame->linesize, picture_buf, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);
	pFrame->width = pCodecCtx->width;
	pFrame->height = pCodecCtx->height;
	pFrame->format = pCodecCtx->pix_fmt;


	while (GetMessage(&msg, NULL, 0, 0))
	{
		p = (unsigned char*)msg.wParam;//由于是实时数据,采用message机制更容易处理

		//将灰度数据转化为YUV420,要不然无法压缩
		memcpy(pFrame->data[0], p, pCodecCtx->width * pCodecCtx->height);
		memset(pFrame->data[1], 128, pCodecCtx->width * pCodecCtx->height / 4);
		memset(pFrame->data[2], 128, pCodecCtx->width * pCodecCtx->height / 4);

		pkt.data = NULL;
		pkt.size = 0;
		av_init_packet(&pkt);

		//新版本的编码函数分成了两部分,已修改
		//int iRet = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_picture);
		int iRet = avcodec_send_frame(pCodecCtx, pFrame);
		if (iRet != 0)
		{
			int a = 0;
			a = iRet;
		}
		got_picture = avcodec_receive_packet(pCodecCtx, &pkt);

		SendToRTSP(pInf, pkt.data + 4, pkt.size - 4);//发送到RTSP流进行传输,注意已去掉H264默认的00 00 00 01头

		av_packet_unref(&pkt);
		delete[] p;
	}

	//注意!未做释放!

	return 0;
}

        以上代码实现了实时视频数据的H264编码格式,需要修改分辨率、帧率和码流,H264数据中未添加时间戳,某些播放器可能无法播放。新版本的ffmpeg库与之前的有些不同,需要对应修改。

上一篇:ffmpeg视频解码,输出YUV图像到文件


下一篇:计数排序