1. 程式人生 > 其它 >網路視訊流 -- 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庫與之前的有些不同,需要對應修改。