视频合成与分割程序使用  

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

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

对视频的处理采用了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工具操作,这些方法不灵活,很难满足个性化的需求。本文从视频最基本的原理剖析,实现了图片合成视频的功能;这样就为上层丰富多彩的应用打开了大门。

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

ffmpeg实现视频的合成与分割的更多相关文章

  1. C# 利用ffmpeg 对视频转换系类操作 (1) 基本分析

    最近公司做一个项目,开发一个视频站点.项目需求中有很多视频转换的需求,如:格式转换(flv,Mp4),视频水印,视频截图,视频合成,获取视频的基本信息(时间戳,视频大小等).经过网络的收集资料以及自己 ...

  2. FFmpeg:视频转码、剪切、合并、播放速调整

    原文:https://fzheng.me/2016/01/08/ffmpeg/ FFmpeg:视频转码.剪切.合并.播放速调整 2016-01-08 前阵子帮导师处理项目 ppt,因为插入视频的格式问 ...

  3. Java使用FFmpeg处理视频文件指南

    Java使用FFmpeg处理视频文件指南 本文主要讲述如何使用Java + FFmpeg实现对视频文件的信息提取.码率压缩.分辨率转换等功能: 之前在网上浏览了一大圈Java使用FFmpeg处理音视频 ...

  4. 使用ffmpeg合并视频文件的三种方法

    ffmpeg合并视频的方法有三种.国内大多数仅介绍了其中之一.于是觉得有必要翻译一下.其实在ffmpeg的 FAQ文档中有比较详细的说明. 使用concat协议进行视频文件的合并 这种方式的适用场景是 ...

  5. Java使用FFmpeg处理视频文件的方法教程

    这篇文章主要给大家介绍了关于Java使用FFmpeg处理视频文件的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧 前言 本文主要 ...

  6. ffmpeg音视频基础学习

    ffmpeg音视频基础学习 从去年开始了解音视频,中间也由于项目的需要,学习过ffmpeg.live555.以及QTAV框架,一直没总结过,现在大致总结下音视频中的常见词汇,后续慢慢更新添加!博客也会 ...

  7. ffmpeg为视频添加时间戳 - 手动编译ffmpeg

    FFMPEG给视频加时间戳水印 项目中需要给视频添加时间戳,理所当然最好用的办法是ffmpeg.在找到正确的做法前,还被网上的答案timecode给水了一下(水的不轻,在这里转了2天),大概是这样写的 ...

  8. 利用FFmpeg生成视频缩略图 2.1.6

    利用FFmpeg生成视频缩略图 1.下载FFmpeg文件包,解压包里的\bin\下的文件解压到 D:\ffmpeg\ 目录下. 下载地址 http://ffmpeg.zeranoe.com/build ...

  9. 使用ffmpeg 对视频截图,和视频转换格式

    //执行CMD命令方法 public static void CmdProcess(string command)//调用CMD        {            //实例化一个进程类      ...

  10. NET 2.0(C#)调用ffmpeg处理视频的方法

    另外:ffmpeg的net封装库 http://www.intuitive.sk/fflib/ NET 2.0 调用FFMPEG,并异步读取输出信息的代码...public void ConvertV ...

随机推荐

  1. Python实现微博舆情分析的设计与实现

    引言 随着互联网的发展,社交媒体平台如微博已经成为公众表达意见.分享信息的重要渠道.微博舆情分析旨在通过大数据技术和自然语言处理技术,对微博上的海量信息进行情感分析.热点挖掘和趋势预测,为政府.企业和 ...

  2. pwn V8入门

    V8入门 && StarCTF oob 搭建环境的步骤如下: 环境搭建 #depot_tools git clone https://chromium.googlesource.com ...

  3. Hugging Face国内镜像站:告别Hugging Face模型下载难题

    Hugging Face国内镜像站: https://hf-mirror.com/

  4. games101_Homework2

    完成函数static bool insideTriangle(): 测试点是否在三角形内. 一段优雅的easy代码,没什么好说的.(但是需要修改这里传入的xy的类型为float,默认为int是想让我通 ...

  5. 利用腾讯元器,将公众号变身为强大的.NET AI智能体

    前言 经常有粉丝朋友在公众号后台私信提问,因为个人平时比较少看公众号后台的私信所以没法及时回复.最近发现腾讯推出了一个可以创建和使用各种智能体的平台(帮助小白也能快速使用AI):腾讯元器,正好自己每天 ...

  6. 来了,超全MQTT实用示例

    Air201快速入门之MQTT示例 合宙Air201资产定位模组--是一个集成超低功耗4G通信.语音通话.超低功耗定位.计步.震动.Type-C.充电.放音.录音等功能的超小PCBA. 内部集成高效. ...

  7. Gunicorn 部署 Flask-Apscheduler 重复执行问题

    目录 踩坑一:TimeZone offset does not match system offset 踩坑二:Flask-Apscheduler 多进程环境重复运行 踩坑三:集群环境下,Flask- ...

  8. 什么是静态(static)?什么是静态方法,静态变量,静态块和静态类?

    本文由 ImportNew - 唐小娟 翻译自 Journaldev.如需转载本文,请先参见文章末尾处的转载要求. static是Java中的一个关键字,我们不能声明普通外层类或者包为静态的.stat ...

  9. golang之go-spew

    github: https://github.com/davecgh/go-spew 我们在使用Golang(Go语言)开发的过程中,会通过经常通过调试的方式查找问题的原因,解决问题,尤其是当遇到一个 ...

  10. 项目部署工具之walle

    最近部署walle进行线上项目的上线发布,安装中遇到的问题,在此记录 walle(http://www.walle-web.io) git地址:https://github.com/meolu/wal ...