文章实时采集(编码h264还是一样使用ffmpeg_encode技术交流讨论(一))
优采云 发布时间: 2021-09-03 06:06文章实时采集(编码h264还是一样使用ffmpeg_encode技术交流讨论(一))
采集屏幕图像之前介绍过,转换为YUV420p。传送门
YUV420p数据为原创图片数据,100张1920x1080图片总大小达到300M。太可怕了!可见这种方式直接写入文件是行不通的。因此,我们需要先将其编码为h264,然后再将其写入文件。至于什么是h264,之前已经介绍过了,这里就不介绍了。
废话不多说,直接看正文。
编码h264还是一样使用ffmpeg,方法如下:
1.打开编码器
AVCodecContext* pCodecCtx; AVCodec* pCodec;
uint8_t* picture_buf;
AVFrame* picture;
bool H264Encoder::openEncoder()
{
int size;
int in_w = mWidth;
int in_h = mHeight;//宽高
//查找h264编码器
pCodec = avcodec_find_encoder(AV_CODEC_ID_H264);
if(!pCodec)
{
fprintf(stderr, "h264 codec not found
");
exit(1);
}
pCodecCtx = avcodec_alloc_context3(pCodec);
pCodecCtx->codec_id = AV_CODEC_ID_H264;
pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
pCodecCtx->width = in_w;
pCodecCtx->height = in_h;
pCodecCtx->time_base.num = 1;
pCodecCtx->time_base.den = 15;//帧率(既一秒钟多少张图片)
pCodecCtx->bit_rate = mBitRate; //比特率(调节这个大小可以改变编码后视频的质量)
pCodecCtx->gop_size=12;
// some formats want stream headers to be separate
if (pCodecCtx->flags & AVFMT_GLOBALHEADER)
pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
// Set Option
AVDictionary *param = 0;
//H.264
//av_dict_set(¶m, "preset", "slow", 0);
av_dict_set(¶m, "preset", "superfast", 0);
av_dict_set(¶m, "tune", "zerolatency", 0); //实现实时编码
pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
if (!pCodec){
printf("Can not find video encoder! 没有找到合适的编码器!
");
return false;
}
if (avcodec_open2(pCodecCtx, pCodec,¶m) pix_fmt, pCodecCtx->width, pCodecCtx->height); //计算需要用到的数据大小
picture_buf = (uint8_t *)av_malloc(size); //分配空间
avpicture_fill((AVPicture *)picture, picture_buf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
return true;
}
2.coding
编码前的数据必须是Yuv420p格式。我们已经获得了这样的数据。使用 avcodec_encode_video2 实现编码:
picture->data[0] = node.buffer; // 亮度Y
picture->data[1] = node.buffer + y_size; // U
picture->data[2] = node.buffer + y_size*5/4; // V
int got_picture=0;
//编码
int ret = avcodec_encode_video2(pCodecCtx, &pkt,picture, &got_picture);
if (got_picture==1)
{
// bool isKeyFrame = pkt.flags & AV_PKT_FLAG_KEY; //判断是否关键帧
int w = fwrite(pkt.data,1,pkt.size,h264Fp); //写入文件中 (h264的裸数据 直接写入文件 也可以播放 因为这里包含H264关键帧)
}
最近时间比较少,代码就不多解释了,直接看完整项目。
完整的项目下载链接:
最终生成的out.h264可以直接用普通播放器打开播放。
保存的文件比以前小了数百倍!
注意:由于h264没有时间戳,只有帧率,这里设置为15。但是,我们采集桌面时,采集每秒不到15帧,所以玩的时候速度玩家开会快很多是正常的。
了解音视频技术,欢迎访问
欢迎加入QQ群121376426进行音视频技术交流与讨论