视频合成与分割程序使用  

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

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

对视频的处理采用了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. 一些常用的jQuery方法1_20220128

    1.jQuery.merge()方法 $.merge() 函数用于合并两个数组内容到第一个数组.*$*.merge( first, second ) $(function () { var arr = ...

  2. Einfuehrung in die Kuenstliche Intelligenz学习笔记

    1.Uninformed Search 1.1 State Space of a Problem 1.2 depth of the search tree and fringe of the sear ...

  3. Java常见面试真题之中级进阶(HashMap篇)

    前言 本来想着给自己放松一下,刷刷博客,突然被几道面试题难倒!说说Hashtable 与 HashMap 的区别?HashMap 中的 key 我们可以使用任何类作为 key 吗?HashMap 的长 ...

  4. SynthID Text 现已发布|在 AI 生成文本中应用不可见水印的新技术

    你是否难以分辨一段文本是由人类撰写的,还是 AI 生成的?识别 AI 生成内容对于提升信息可信度.解决归因错误以及抑制错误信息至关重要. 今天,Google DeepMind 和 Hugging Fa ...

  5. 用“tar | split ”将文件分包压缩

    1.一次打包: tar cjf - directory/ | split -b 100m -d -a 1 - filename.tar.bz2. (directory/):待压缩的目录名. (spli ...

  6. delphi Image 32 动画演示1

    Image 32 自带的Demo,添加一些注解. unit uFrmAnimation; interface uses Winapi.Windows, Winapi.Messages, System. ...

  7. 成本立降50%!在EKS上借助Karpenter部署大模型

    原文链接: https://aws.amazon.com/cn/blogs/containers/scaling-a-large-language-model-with-nvidia-nim-on-a ...

  8. Jax中关于NonZero的使用

    技术背景 在Jax的JIT即时编译中,会追踪每一个Tensor的Shape变化.如果在计算的过程中出现了一些动态Shape的Tensor(Shape大小跟输入的数据有关),那么就无法使用Jax的JIT ...

  9. k8s之Helm

    官方文档: https://helm.sh/zh/docs/intro/using_helm/ Helm 帮助您管理 Kubernetes 应用-- Helm Chart,Helm 是查找.分享和使用 ...

  10. 开源 - Ideal库 - Excel帮助类,TableHelper实现(二)

    书接上回,我们今天开始实现对象集合与DataTable的相互转换. 01.接口设计 上文中已经详细讲解了整体设计思路以及大致设计了需要哪些方法.下面我们先针对上文设计思想确定对外提供的接口.具体接口如 ...