使用FFMpeg实现视频剪切功能

这篇具有很好参考价值的文章主要介绍了使用FFMpeg实现视频剪切功能。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

首先致敬雷神提供的资源,使用雷神的代码实现视频剪切功能

雷神实现的ffmpeg代码文章

说明一下,这里转载首先是记录一下实现方法,其次就是解决代码无法正常运行问题(avformat_write_header返回-22)

本文介绍一个基于FFMPEG的封装格式转换器。所谓的封装格式转换,就是在AVI,FLV,MKV,MP4这些格式之间转换(对应.avi,.flv,.mkv,.mp4文件)。需要注意的是,本程序并不进行视音频的编码和解码工作。而是直接将视音频压缩码流从一种封装格式文件中获取出来然后打包成另外一种封装格式的文件。传统的转码程序工作原理如下图所示:
使用FFMpeg实现视频剪切功能
上图例举了一个举例:FLV(视频:H.264,音频:AAC)转码为AVI(视频:MPEG2,音频MP3)的例子。可见视频转码的过程通俗地讲相当于把视频和音频重新“录”了一遍。

本程序的工作原理如下图所示:
使用FFMpeg实现视频剪切功能
由图可见,本程序并不进行视频和音频的编解码工作,因此本程序和普通的转码软件相比,有以下两个特点:
处理速度极快。视音频编解码算法十分复杂,占据了转码的绝大部分时间。因为不需要进行视音频的编码和解码,所以节约了大量的时间。
视音频质量无损。因为不需要进行视音频的编码和解码,所以不会有视音频的压缩损伤。


#include <stdio.h>
extern "C"
{
#include <FFmpeg\libavcodec\avcodec.h>
#include <FFmpeg\libavformat\avformat.h>
}
#pragma comment (lib, "avcodec.lib")
#pragma comment (lib, "avformat.lib")
#pragma comment (lib, "avutil.lib")

int main(int argc, char* argv[])
{
	int startTime = 1;//起始时间  如果为0就不启用该变量
	int endTime = 4;//结束时间   如果为0就不启用该变量
	AVCodecContext* pCodecCtx = NULL;
	AVCodecContext *pAVCodecContext = NULL;
	AVOutputFormat *ofmt = NULL;
	AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
	AVPacket pkt;
	const char *in_filename, *out_filename;
	int ret, i;

	in_filename = "e://Test.mp4";
	out_filename = "e://Temp.mp4";
	av_register_all();
	//输入(Input)
	if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
		printf("Could not open input file.");
		goto end;
	}
	if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
		printf("Failed to retrieve input stream information");
		goto end;
	}
	av_dump_format(ifmt_ctx, 0, in_filename, 0);
	//输出(Output)
	avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
	if (!ofmt_ctx) {
		printf("Could not create output context\n");
		ret = AVERROR_UNKNOWN;
		goto end;
	}
	ofmt = ofmt_ctx->oformat;
	for (i = 0; i < ifmt_ctx->nb_streams; i++) {
		//根据输入流创建输出流(Create output AVStream according to input AVStream)
		AVStream *in_stream = ifmt_ctx->streams[i];
		AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
		if (!out_stream) {
			printf("Failed allocating output stream\n");
			ret = AVERROR_UNKNOWN;
			goto end;
		}
		ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
		if (ret < 0) 
		{
			printf("Failed to copy context from input to output stream codec context\n");
			goto end;
		}
		out_stream->codec->codec_tag = 0;
		if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
			out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
		//Param that must set
		pCodecCtx = out_stream->codec;
		
		/*
			//特殊处理 
			如果使用雷神的代码这里不增加特殊的处理,会在avformat_write_header函数执行的时候
			返回-22
			i=0: codec_id = AV_CODEC_ID_HEV //H265
			i=1:codec_id = AV_CODEC_ID_AAC
			i=2:codec_id = AV_CODEC_ID_NONE
			i=3:codec_id = AV_CODEC_ID_NONE
			i=4:codec_id = AV_CODEC_ID_NONE
		*/
		pAVCodecContext = ifmt_ctx->streams[i]->codec;
		if (i < 2)
			pCodecCtx->codec_id = ifmt_ctx->streams[i]->codec->codec_id;
		else
			pCodecCtx->codec_id = ifmt_ctx->streams[i%2]->codec->codec_id;
		
#if 0
		//其他参数配置
		pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
		pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
		pCodecCtx->width = 1920;
		pCodecCtx->height = 1080;
		pCodecCtx->bit_rate = pAVCodecContext->bit_rate;
		pCodecCtx->gop_size = 250;
		pCodecCtx->time_base.num = 1;
		pCodecCtx->time_base.den = 25;
		pCodecCtx->qmin = 10;
		pCodecCtx->qmax = 51;
		//Optional Param
		pCodecCtx->max_b_frames = 3;
#endif
	}
	pAVCodecContext = ifmt_ctx->streams[0]->codec;
	// 显示视频相关的参数信息(编码上下文)
	printf("比特率: = %lld\n", pAVCodecContext->bit_rate);
	printf("宽高: = %d\n" , pAVCodecContext->width );
	printf("格式: = %d\n" , pAVCodecContext->pix_fmt);  // AV_PIX_FMT_YUV420P 0
	printf("帧率: = %d\n",pAVCodecContext->time_base.den );
	printf("总时长: = %f s\n", (ifmt_ctx->duration) / AV_TIME_BASE );
	printf("总帧数: = %d\n", ifmt_ctx->streams[0]->nb_frames );
	int fps = ifmt_ctx->streams[0]->avg_frame_rate.num * 1.0f / ifmt_ctx->streams[0]->avg_frame_rate.den;
	int interval = 1 * 1000 / fps;
	printf("平均帧率: = %d\n", fps );
	printf("帧间隔: = %d ms\n", interval);

	//输出一下格式------------------
	av_dump_format(ofmt_ctx, 0, out_filename, 1);
	//打开输出文件(Open output file)
	if (!(ofmt->flags & AVFMT_NOFILE)) {
		ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
		if (ret < 0) {
			printf("Could not open output file '%s'", out_filename);
			goto end;
		}
	}
	//写文件头(Write file header)
	ret = avformat_write_header(ofmt_ctx, NULL);
	if (ret < 0) {
		printf("Error occurred when opening output file\n");
		goto end;
	}

	//跳转到多少秒
	if(startTime <= 0)
	{
		ret = av_seek_frame(ifmt_ctx, -1, startTime * AV_TIME_BASE, AVSEEK_FLAG_ANY);
		if (ret<0) {
			fprintf(stderr, "Error seek\n");
		}
	}
	

	int frame_index = 0;
	while (1) {
		AVStream *in_stream, *out_stream;

		//获取一个AVPacket(Get an AVPacket)
		ret = av_read_frame(ifmt_ctx, &pkt);
		if (ret < 0)
			break;
		in_stream = ifmt_ctx->streams[pkt.stream_index];
		out_stream = ofmt_ctx->streams[pkt.stream_index];


		//裁剪区域
		if (endTime > startTime)
		{
			if (av_q2d(in_stream->time_base) * pkt.pts > (startTime + endTime))
			{
				av_packet_unref(&pkt);
				break;
			}
		}
		/* copy packet */
		//转换PTS/DTS(Convert PTS/DTS)
		pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
		pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
		pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
		pkt.pos = -1;
		//写入(Write)
		ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
		if (ret < 0) {
			printf("Error muxing packet\n");
			break;
		}
		printf("Write %8d frames to output file\n", frame_index);
		av_free_packet(&pkt);
		frame_index++;
	}
	//写文件尾(Write file trailer)
	av_write_trailer(ofmt_ctx);
end:
	avformat_close_input(&ifmt_ctx);
	/* close output */
	if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
		avio_close(ofmt_ctx->pb);
	avformat_free_context(ofmt_ctx);
	if (ret < 0 && ret != AVERROR_EOF) {
		printf("Error occurred.\n");
		return -1;
	}
	return 0;
}

转:文章资源:https://blog.csdn.net/leixiaohua1020/article/details/84597944

完整工程下载地址(代码是一样的,就是包含了ffmpeg运行所需要的环境,能直接编译通过):
https://download.csdn.net/download/qq_36351159/85748703
工程项目VS2015 x64 Debug下载 (包括ffmpeg库,配置好的所需包含目录、库,可直接编译)文章来源地址https://www.toymoban.com/news/detail-406531.html

到了这里,关于使用FFMpeg实现视频剪切功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 纯前端使用ffmpeg实现视频压缩

    实现需求 用户上传视频并压缩,并且可以选择压缩程度,搜索遍各大网站,最终选择了ffmpeg进行操作。本文包含具体如何实现加上过程中遇到的各种坑 ffmpeg视频压缩代码使用很简单,上代码 html部分  js部分 这个ffmpeg大神处理好的cdn我也是找了好久才找到,之前找的各种版本

    2024年02月04日
    浏览(48)
  • 2023-05-04:用go语言重写ffmpeg的scaling_video.c示例,用于实现视频缩放(Scaling)功能。

    2023-05-04:用go语言重写ffmpeg的scaling_video.c示例,用于实现视频缩放(Scaling)功能。 答案2023-05-04: 这段代码实现了使用 libswscale 库进行视频缩放的功能。下面是程序的主要流程: 1.获取命令行参数,包括输出文件名和目标图像大小。 2.解析目标图像大小,生成指定大小的输出

    2024年02月02日
    浏览(40)
  • 【Unity复制功能】Unity复制到剪切板三端实现方法

    一、安卓和IOS方案 直接使用Unity提供的GUIUtility.systemCopyBuffer方案 链接: https://docs.unity.cn/cn/2021.3/ScriptReference/GUIUtility.html 例如: 二、小程序(WebGL) 1、web这边需要定义复制接口:WebSetCopy 2、Unity这边 首先定义方法调用web接口 然后在胶水函数中声明

    2024年04月16日
    浏览(32)
  • 使用ffmpeg实现给音频,视频添加水印的操作

    本文主要针对ffmpeg进行整理,从而解决在现实中可能存在的问题。 这里参考的是 Java后台用ffmpeg命令给视频添加水印 - ^身后有尾巴^ - 博客园 (cnblogs.com) 1:先去ffmpeg官网下载其压缩包  Download FFmpeg 下载,解压到指定位置  2.将压缩包拷贝到你想的任意位置并解压,正常解压出

    2023年04月08日
    浏览(42)
  • 使用ffmpeg实现视频旋转并保持清晰度不变

    通过ffmpeg -i命令查看视频基本信息 通过命令查看,原始视频信息 分辨率为1920x1080,码率19977k, 帧率59.94 -qscale value:使用固定的视频量化标度(VBR),以value质量为基础的VBR,取值0.01-255,越小质量越好 -q:v:表示存储jpeg的图像质量 -b:v:设置输出文件的视频比特率(码率),本

    2024年01月25日
    浏览(45)
  • Windows上使用FFmpeg实现本地视频推送模拟海康协议rtsp视频流

    Nginx搭建RTMP服务器+FFmpeg实现海康威视摄像头预览: Nginx搭建RTMP服务器+FFmpeg实现海康威视摄像头预览_nginx rtmp 海康摄像头_霸道流氓气质的博客-CSDN博客 上面记录的是使用FFmpeg拉取海康协议摄像头的rtsp流并推流到流媒体服务器。 如果在其它业务场景下需要本地的视频文件模拟

    2024年02月12日
    浏览(44)
  • Android 使用FFmpeg3.3.9基于命令实现视频压缩

    前言 首先利用linux平台编译ffmpeg的so库,具体详情请查看文章:Android NDK(ndk-r16b)交叉编译FFmpeg(3.3.9)_jszlittlecat_720的博客-CSDN博客    点击Create JNI function for compressVideo 自动打开native-lib.cpp并创建完成Java_com_suoer_ndk_ffmpegtestapplication_VideoCompress_compressVideo 方法  在此方法下实现压缩

    2024年02月02日
    浏览(53)
  • 音视频开发:ffplay使用ffmpeg滤镜实现倍速播放

    曾经为实现倍速播放使用过ffmpeg,对音频使用atempo滤镜即可实现变速不变调。但是当时效果并不是特别好,和soundtouch相比处理后的音质有明显的区别。最近用新版本的ffmpeg滤镜重新实现了倍速播放,发现效果变好,已经达到可接受的程度,所以在此分享具体实现。 ffmpeg倍速

    2024年02月03日
    浏览(110)
  • 【JS】纯web端使用ffmpeg实现的视频编辑器

    废话不多,先上视频。 ffmpeg编辑器 这是一个纯前端实现的视频编辑器,用的ffmpeg的wasm,web框架用的vue3。界面手撸。 用vite的vue3模板创建一个就可以。 package.json 创建页面和路由,用的vue-router,简单的添加一下。 router.js 主要项目结构 组件代码 progress-dialog.vue resource-item.vue t

    2024年02月12日
    浏览(47)
  • 使用EasyDarwin + ffmpeg 搭建流媒体服务器,实现多台智能电视同步播放宣传视频

    近期单位用户提出需求,需要在单位内部的9台安卓智能电视(小米电视)上同步播放用户提供的宣传视频,希望能够做到所有电视音视频同步播放(电视均位于食堂内部,使用内置扬声器,各电视间音频延迟不同会导致混响) 。 由于电视在安装时只预留了电源线,使用HDM

    2024年02月10日
    浏览(79)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包