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(¶m, "preset", "superfast", 0);
av_dict_set(¶m, "tune", "zerolatency", 0); //实现实时编码
av_dict_set(¶m, "profile", "main", 0);
if (avcodec_open2(pCodecCtx, pCodec, ¶m) < 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库与之前的有些不同,需要对应修改。