首页 > 其他分享 >ffmpeg实现视频的合成与分割

ffmpeg实现视频的合成与分割

时间:2024-09-12 15:16:20浏览次数:1  
标签:视频 分割 return ffmpeg errnum pVideoCodecCtx NULL pFormatCtx

视频合成与分割程序使用    

    作者开发了一款软件,可以实现对视频的合成和分割,界面如下:

     播放时,可以选择多个视频源;在选中“保存视频”情况下,会将多个视频源合成一个视频。如果只取一个视频源中一段视频,就实现了视频分割。

      对视频的处理采用了ffmpeg库。作者在此库的基础上,做了进一步封装,使用起来更加简便。

 底层处理逻辑可用如下函数表示

bool InitVideo();
bool AddImage(unsigned char* imageFileBuffer, int bufferSize);
bool CloseVideo();

    可见底层函数是十分简洁的;  但是ffmpeg函数调用复杂,使用起来不便; 将ffmpeg封装亦非易事;本文就讲述对ffmpeg封装的过程。

视频编码与解码

    对视频的处理分为两种:解码和编码。视频播放属于解码,视频生成属于编码。视频播放方面的文章和例子很多;我也写过一篇文章《使用Emgu.CV开发视频播放器简述》

      视频其实就是连续的图片,编码的作用就是压缩图片,减小视频文件的占用。可以把视频文件想象成容器,把一些列图片放入容器,经过编码,生成标准格式的视频文件(如mp4),这个过程就是编码;

      把不同视频来源的图片放入容器,就实现了视频的合成;把视频中某段包含的图片放入容器,就实现了视频的分割。只要实现了对多个图片到视频的编码,就实现了视频的合成和分割。

 

初始化编码器,包括选择编码器,生成输入流,写入文件头等操作。

bool ImageToVideo::InitVideo()
{
	InitFfmpeg();

	AVFormatContext* pFormatCtx = NULL;
	_errnum = avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, _destVideoFileName.c_str());
	if (_errnum < 0)
	{
		av_strerror(_errnum, _errbuf, sizeof(_errbuf));
		return false;
	}

	_initFree.pFormatCtx = pFormatCtx;

	// h264视频编码器
	const AVCodec* vcodec = avcodec_find_encoder(AVCodecID::AV_CODEC_ID_H264);
	if (!vcodec)
	{
		return false;
	}

	// 创建编码器上下文
	AVCodecContext* pVideoCodecCtx = avcodec_alloc_context3(vcodec);
	if (!pVideoCodecCtx)
	{
		return false;
	}
	_initFree.pVideoCodecCtx = pVideoCodecCtx;

	// 比特率、宽度、高度
	pVideoCodecCtx->bit_rate = 4000000;
	pVideoCodecCtx->width = _videoWidth; // 视频宽度
	pVideoCodecCtx->height = _videoHeight; // 视频高度
	// 时间基数、帧率
	pVideoCodecCtx->time_base = { 1, 25 };
	pVideoCodecCtx->framerate = { 25, 1 };
	// 关键帧间隔
	pVideoCodecCtx->gop_size = 10;
	// 不使用b帧
	pVideoCodecCtx->max_b_frames = 0;
	// 帧、编码格式
	pVideoCodecCtx->pix_fmt = AVPixelFormat::AV_PIX_FMT_YUV420P;
	pVideoCodecCtx->codec_id = AVCodecID::AV_CODEC_ID_H264;
	// 预设:快速
	av_opt_set(pVideoCodecCtx->priv_data, "preset", "superfast", 0);
	// 全局头
	pVideoCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

	_errnum = avcodec_open2(pVideoCodecCtx, vcodec, NULL);
	if (_errnum < 0)
	{
		return false;
	}

	// 为封装器创建视频流
	AVStream* pVideoStream = avformat_new_stream(pFormatCtx, NULL);
	if (!pVideoStream)
	{
		return false;
	}
	_initFree.pVideoStream = pVideoStream;

	pVideoStream->codec->codec_tag = 0;
	pVideoStream->codecpar->codec_tag = 0;
	// 配置视频流的编码参数
	avcodec_parameters_from_context(pVideoStream->codecpar, pVideoCodecCtx);

	// 打开输出流IO
	_errnum = avio_open(&pFormatCtx->pb, _destVideoFileName.c_str(), AVIO_FLAG_WRITE); // 打开AVIO流
	if (_errnum < 0)
	{
		avio_close(pFormatCtx->pb);
		return false;
	}

	_errnum = avformat_write_header(pFormatCtx, NULL);
	if (_errnum < 0)
	{
		return false;
	}

	return true;
}

添加图片

1 对添加的图片缩放处理:

SwsContext* pSwsCtx = sws_getContext(
    imageWidth, imageHeight, srcFormat, 
    _initFree.pVideoCodecCtx->width, _initFree.pVideoCodecCtx->height, AVPixelFormat::AV_PIX_FMT_YUV420P, // 输出
    SWS_BICUBIC, 
    0, 0, 0);

2 发送frame ,接收编码后的packet

vframe->pts = vpts++;
_errnum = avcodec_send_frame(_initFree.pVideoCodecCtx, vframe);
if (_errnum < 0)
{
    // cout << "avcodec_send_frame failed" << endl;
    av_frame_free(&vframe);
    return false;
}

// 视频编码报文
AVPacket* packet = av_packet_alloc();
int writeCount = 0;

while (true)
{
    _errnum = avcodec_receive_packet(_initFree.pVideoCodecCtx, packet);
    if (_errnum < 0 || packet->size <= 0)
    {
        int e1 = AVERROR_EOF;
        int e2 = AVERROR(EAGAIN);

        if (writeCount == 0)
        {
            av_frame_free(&vframe);
            av_packet_free(&packet);
            // cout << "avcodec_receive_packet failed" << endl;
            return false;
        }
        else
        {
            break;
        }
    }

编码完成:写入文件尾数据,释放资源

_errnum = av_write_trailer(_initFree.pFormatCtx);
if (_errnum != 0)
{
    return false;
}

if (pFormatCtx != NULL)
{
    avio_closep(&pFormatCtx->pb);
    avformat_close_input(&pFormatCtx);
}

if (pVideoCodecCtx != NULL)
{
    avcodec_close(pVideoCodecCtx);
    avcodec_free_context(&pVideoCodecCtx);
}


if (pSwsCtx != NULL)
{
    sws_freeContext(pSwsCtx);
}

后记:对于视频的合成和分割,网上有不少这方面的文章,大都是讲述如何使用ffmpeg工具操作,这些方法不灵活,很难满足个性化的需求。本文从视频最基本的原理剖析,实现了图片合成视频的功能;这样就为上层丰富多彩的应用打开了大门。

       比如 将两个视频文件合成到一个播放画面;处理过程为:同时读取两个视频源的文件,将两个图片拼接,再放入视频容器。

标签:视频,分割,return,ffmpeg,errnum,pVideoCodecCtx,NULL,pFormatCtx
From: https://www.cnblogs.com/yuanchenhui/p/18410039/ffmpeg-video-creator

相关文章

  • 视频监控推流助手/极低延迟/支持N路批量多线程推流/264和265推流/监控转网页
    一、前言说明搞视频监控开发除了基本的拉流以外,还有个需求是推流,需要将拉到的流重新推流到流媒体服务器,让流媒体服务做转发和负载均衡,这样其他地方只需要问流媒体服务器要视频流即可。为什么拉了又重新推呢,因为软件这边和可能拉流后做了处理,比如做了人工智能运算,识别到了物体方框......
  • TPAMI 2024 | 点云分割领域自适应的组合语义混合
    CompositionalSemanticMixforDomainAdaptationinPointCloudSegmentation点云分割领域自适应的组合语义混合CristianoSaltori,FabioGalasso,GiuseppeFiameni,NicuSebe,FabioPoiesi,ElisaRicci代码:https://github.com/saltoricristiano/cosmix-uda摘......
  • 常见的web音视频播放器
    1.video-js是否开源:是是否免费:是官网地址:https://videojs.com/特点:支持hls、dash、.mp4、webm等多种视频类型,2.西瓜播放器是否开源:是是否免费:是官网地址:https://v2.h5player.bytedance.com/特点:一款带解析器、能节省流量的HTML5视频播放器。支持播放hls、.m3u8、.flv、......
  • 【开源免费】基于SpringBoot+Vue.JS在线视频教育平台(JAVA毕业设计)
    本文项目编号T027,文末自助获取源码\color{red}{T027,文末自助获取源码}......
  • 锋哥写一套前后端分离Python权限系统 基于Django5+DRF+Vue3.2+Element Plus+Jwt 视频
    大家好,我是java1234_小锋老师,最近写了一套【前后端分离Python权限系统基于Django5+DRF+Vue3.2+ElementPlus+Jwt】视频教程,持续更新中,计划月底更新完,感谢支持。视频在线地址:打造前后端分离Python权限系统基于Django5+DRF+Vue3.2+ElementPlus+Jwt视频教程(火爆连载更新中......
  • 视频智能行为分析系统
    视频智能行为分析系统可以借助现场已有的不同品牌的监控摄像机开展实时分析识别,视频智能行为分析系统以检验视频监控画面中身体构造的行为形态为载体,从了四个维度:时间、行为、人数和方向多个维度对现场作业人员进行识别分析,如:非法闯入、倒地事件、打架事件、离岗检测、睡岗检测、......
  • 监控视频行为分析系统
    监控视频行为分析系统是可以通过利用现场监控摄像头传回的现场画面视频利用AI神经网络模型的人工优化算法分析识别人们运动轨迹,监控视频行为分析系统去识别监控摄像机拍摄到的各种人的异常行为,甚至很多行为识别规则大多数场景下都可以做到零误报。这大大降低了系统对硬件的依赖,提......
  • 养老院视频监控分析系统
    养老院视频监控分析系统24h不需要人员监控,对养老院360度及时高清视频监控,即时自动分析和识别养老院监控区域内的异常情况。一旦出现异常,养老院视频监控分析系统马上记录和储存,并把报警信息上传至综合服务平台。除此之外,依据智能视频分析,识别监控区域内的工作人员入睡、换岗、玩手......
  • 编程讲解视频中老师们经常用的截图软件
    前言:        本人第一次发博客,如果写的不好请见谅进入主题:    本人应为学编程的过程中看到很多的编程老师们在讲解的过程中经常使用一款叫做Snipaste的截图软件,本人认为很不错,挺方便的,于是在网上查找这款软件,因为开始不知道这款软件的名字是什么,于是就奔......
  • 基于FPGA与RK3588的多通道低延时3G-SDI视频信号
    目录简介主要用途:项目简介:详细过程:BT1120视频时序转CEA861视频像素编码格式转换低延时处理MIPI接口处理视频处理模块​​​​​​​简介主要解决 RK3588支持多种视频格式输入,但是没有支持多路SDI接口的设计方案,系统利用实现四路SDI视频图像的采集。传输。处理,以......