ffmpeg api实现将音视频混合

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

需求:

将一首歌mp3格式,和一段无声音录屏mp4格式,合成到一起,使播放视频时能听到这首歌。

实现原理:

打开mp3音频,解析出输入音频流,再打开mp4视频,解析出输入视频流。

然后打开输出环境,创建2个输出流,分别对应音频输入流和视频输入流。

最后循环交替从音频流和视频流读取AVPacket,依次写入输出环境。

使用ffmpeg命令实现音视频混合很简单:

ffmpeg -i xxx1.mp3 -i xxx2.mp4 out.mp4

要点:

1 AVPacket::stream_index

将AVPacket写入输出环境时,音频和视频的stream_index不能相等,如果音频的stream_index等于0,那么视频的stream_index需要等于1,可以手动改。出现这种情况的原因是输入的xxx1.mp3可能包含2个流,一个是音频,另一个是视频,音频流索引是0,视频流索引是1。这里的视频实际上是播放音乐时显示的一张图片。输入的xxx2.mp4至少包含2个流,一个是音频,另一个是视频,而这里视频流索引是0,音频流索引是1。画个图:

xxx1.mp3

- stream0(audio)

- stream1(video)

xxx2.mp4

- stream0(video)

- stream1(audio)

出现这种情况,从xxx1.mp3解析出来的AVPacket和xxx2.mp4解析出来的AVPacket的stream_index都为0,如果不改直接写到输出环境,ffmpeg就会报错。

2 void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst);

 * Convert valid timing fields (timestamps / durations) in a packet from one
 * timebase to another. Timestamps with unknown values (AV_NOPTS_VALUE) will be
 * ignored.

将从输入流解析出的AVPacket的跟时间相关字段,从当前的输入流时基对应的值转为输出流时基对应的值。音频和视频都是用这个函数。这样合成后的音频和视频就能有序播放。

3 别犯低级错误,比如成员变量pkg与pkg2混淆导致出问题。

附上调试学习研究用的代码

文件名xxx.c(cpp会编不过)

包含目录,ffmpeg头文件所在的目录

C:\work\env\msys2\usr\local\include;

包含库目录,ffmpeg静态库所在的目录

C:\work\env\msys2\usr\local\lib;

依赖的静态库

libavcodec.a

libavdevice.a

libavfilter.a

libavformat.a

libavutil.a

libswresample.a

libswscale.a

SDL2.lib

SDL2main.lib

mfuuid.lib

ole32.lib

strmiids.lib

user32.lib

psapi.lib

uuid.lib

oleaut32.lib

shlwapi.lib

gdi32.lib

vfw32.lib

secur32.lib

ws2_32.lib

bcrypt.lib文章来源地址https://www.toymoban.com/news/detail-629293.html

// 需求:将一首歌mp3格式,和一段无声音录屏mp4格式,合成到一起,使播放视频时能听到这首歌。

//#include <file.h>

#include "libavformat/avformat.h"
#include "libavutil/dict.h"
#include "libavutil/opt.h"
#include "libavutil/timestamp.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/imgutils.h" 
#include "libavcodec/avcodec.h"


static void log_packet(const AVFormatContext* fmt_ctx, const AVPacket* pkt, const char* tag)
{
	AVRational* time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;

	printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
		tag,
		av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
		av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
		av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
		pkt->stream_index);
}


int main()
{
	int ret = 0;

	// 打开音频流
	avformat_network_init();
	AVFormatContext* ifmt_ctx = NULL;
	const char* inputUrl = "jietuo.mp3";
	ret = avformat_open_input(&ifmt_ctx, inputUrl, NULL, NULL);
	if (ret != 0)
	{
		printf("Couldn't open input stream.\n");
		return -1;
	}
	if (avformat_find_stream_info(ifmt_ctx, NULL) < 0)
	{
		printf("Couldn't find stream information.\n");
		return -1;
	}
	av_dump_format(ifmt_ctx, 0, inputUrl, 0);
	int audio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
	AVStream* st = ifmt_ctx->streams[audio_index];
	const AVCodec* codec = NULL;
	codec = avcodec_find_decoder(st->codecpar->codec_id);
	if (!codec)
	{
		fprintf(stderr, "Codec not found\n");
		exit(1);
	}
	AVCodecContext* codec_ctx = NULL;
	codec_ctx = avcodec_alloc_context3(codec);
	if (!codec_ctx)
	{
		exit(1);
	}
	avcodec_parameters_to_context(codec_ctx, ifmt_ctx->streams[audio_index]->codecpar);
	if ((ret = avcodec_open2(codec_ctx, codec, NULL) < 0))
	{
		return -1;
	}
	AVPacket* pkt = av_packet_alloc();

	// 打开视频流
	AVFormatContext* ifmt_ctx2 = NULL;
	const char* inputUrl2 = "luping.mp4";
	ret = avformat_open_input(&ifmt_ctx2, inputUrl2, NULL, NULL);
	if (ret != 0)
	{
		printf("Couldn't open input stream %s.\n", inputUrl2);
		return -1;
	}
	if (avformat_find_stream_info(ifmt_ctx2, NULL) < 0)
	{
		printf("Couldn't find stream information.\n");
		return -1;
	}
	av_dump_format(ifmt_ctx2, 0, inputUrl2, 0);
	int video_index = av_find_best_stream(ifmt_ctx2, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
	AVStream* st2 = ifmt_ctx2->streams[video_index];
	const AVCodec* codec2 = NULL;
	codec2 = avcodec_find_decoder(st2->codecpar->codec_id);
	if (!codec2)
	{
		fprintf(stderr, "Codec not found\n");
		exit(1);
	}
	AVCodecContext* codec_ctx2 = NULL;
	codec_ctx2 = avcodec_alloc_context3(codec2);
	if (!codec_ctx2)
	{
		exit(1);
	}
	avcodec_parameters_to_context(codec_ctx2, ifmt_ctx2->streams[video_index]->codecpar);
	if ((ret = avcodec_open2(codec_ctx2, codec2, NULL) < 0))
	{
		return -1;
	}
	AVPacket* pkt2 = av_packet_alloc();


	// 打开输出流
	const char* outputUrl = "out.mp4";
	AVFormatContext* ofmt_ctx = NULL;
	avformat_alloc_output_context2(&ofmt_ctx, NULL, "mpegts", outputUrl);
	if (!ofmt_ctx) {
		printf("Could not create output context\n");
		return -1;
	}
	const AVOutputFormat* ofmt = ofmt_ctx->oformat;
	{
		//创建输出音频流
		AVStream* out = avformat_new_stream(ofmt_ctx, NULL);
		if (!out)
		{
			return -1;
		}
		//复制配置信息
		AVCodecParameters* codecpar = ifmt_ctx->streams[audio_index]->codecpar;
		avcodec_parameters_copy(out->codecpar, codecpar);
		out->codecpar->codec_tag = 0;
	}
	{
		//创建输出视频流
		AVStream* out = avformat_new_stream(ofmt_ctx, NULL);
		if (!out)
		{
			return -1;
		}
		//复制配置信息
		AVCodecParameters* codecpar = ifmt_ctx2->streams[video_index]->codecpar;
		avcodec_parameters_copy(out->codecpar, codecpar);
		out->codecpar->codec_tag = 0;
	}
	av_dump_format(ofmt_ctx, 0, outputUrl, 1);
	
	//Open output URL
	if (!(ofmt->flags & AVFMT_NOFILE)) {
		ret = avio_open(&ofmt_ctx->pb, outputUrl, AVIO_FLAG_WRITE);
		if (ret < 0) {
			printf("Could not open output URL '%s'", outputUrl);
			return -1;
		}
	}
	//Write file header
	ret = avformat_write_header(ofmt_ctx, NULL);
	if (ret < 0) {
		printf("Error occurred when opening output URL\n");
		return -1;
	}

	int duration_audio = 0;
	int duration_video = 0;
	// 音视频合成
	while (1)
	{
		//if (duration_audio < duration_video)
		{
			AVStream* in_stream, * out_stream;

			ret = av_read_frame(ifmt_ctx, pkt);
			if (ret < 0)
				break;

			if (pkt->stream_index == audio_index)
			{
				in_stream = ifmt_ctx->streams[pkt->stream_index];

				out_stream = ofmt_ctx->streams[0];
				log_packet(ifmt_ctx, pkt, "in");

				/* copy packet */
				av_packet_rescale_ts(pkt, in_stream->time_base, out_stream->time_base);
				pkt->pos = -1;
				log_packet(ofmt_ctx, pkt, "out");
				duration_audio += pkt->duration;
				ret = av_interleaved_write_frame(ofmt_ctx, pkt);
				/* pkt is now blank (av_interleaved_write_frame() takes ownership of
				 * its contents and resets pkt), so that no unreferencing is necessary.
				 * This would be different if one used av_write_frame(). */
				if (ret < 0) {
					fprintf(stderr, "Error muxing packet\n");
					break;
				}
			}
			else
			{
				av_packet_unref(pkt);
			}
		}
		//else
		{
			AVStream* in_stream, * out_stream;

			ret = av_read_frame(ifmt_ctx2, pkt2);
			if (ret < 0)
				break;

			if (pkt2->stream_index == video_index)
			{
				in_stream = ifmt_ctx2->streams[pkt2->stream_index];

				pkt2->stream_index = 1;
				out_stream = ofmt_ctx->streams[1];
				log_packet(ifmt_ctx2, pkt2, "in");

				/* copy packet */
				av_packet_rescale_ts(pkt2, in_stream->time_base, out_stream->time_base);
				pkt2->pos = -1;
				log_packet(ofmt_ctx, pkt2, "out");
				duration_video += pkt2->duration;
				ret = av_interleaved_write_frame(ofmt_ctx, pkt2);
				/* pkt is now blank (av_interleaved_write_frame() takes ownership of
				 * its contents and resets pkt), so that no unreferencing is necessary.
				 * This would be different if one used av_write_frame(). */
				if (ret < 0) {
					fprintf(stderr, "Error muxing packet\n");
					break;
				}
			}
			else
			{
				av_packet_unref(pkt2);
			}
			
		}





		/*if (av_read_frame(ifmt_ctx2, pkt2) >= 0)
		{
			if (pkt2->stream_index == video_index)
			{
				int video = av_find_best_stream(ofmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
     				av_packet_rescale_ts(pkt2, st2->time_base, ofmt_ctx->streams[video]->time_base);
				av_interleaved_write_frame(ofmt_ctx, pkt2);
			}
		}
		else
		{
			break;
		}
		

		if (av_read_frame(ifmt_ctx, pkt) >= 0)
		{
			if (pkt->stream_index == audio_index)
			{
				int audio = av_find_best_stream(ofmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
				
				av_interleaved_write_frame(ofmt_ctx, pkt);
			}
		}*/
	}

	
	av_write_trailer(ofmt_ctx);


	return 0;
}

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

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

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

相关文章

  • 哔哩哔哩视频合并 B站缓存视频合并 安卓版 音视频合并 基于ffmpeg

    此软件是为了帮助网友合并哔哩哔哩缓存视频,Android上将bilibili缓存视频合并导出为mp4,你可以将它理解为一个专用的格式工厂,并不涉及破解相关内容,仅仅用于学习技术交流,严禁用于商业用途,如有侵权请联系我删档,对你带来困惑和不便我深感抱歉。 合并(导出)B站缓

    2024年02月02日
    浏览(52)
  • 音视频八股文(11)-- ffmpeg 音频重采样

    所谓的重采样,就是改变⾳频的采样率、sample format、声道数等参数,使之按照我们期望的参数输出。 为什么要重采样?当然是原有的⾳频参数不满⾜我们的需求,⽐如在FFmpeg解码⾳频的时候,不同的⾳源有不同的格式,采样率等,在解码后的数据中的这些参数也会不⼀致(最

    2024年02月04日
    浏览(49)
  • 音视频剪辑|FFMPEG|windows10下的音视频格式转换,遮挡填充,GIF动图制作,背景音频抽取,替换

    最近对于音视频和图像的处理问题比较感兴趣,但发现很多目前需要的功能要么需要付费但不会过于麻烦,要么比较麻烦,很可能某个功能实现需要安装很多软件 例如,视频转GIF动图,该功能的实现要么使用Photoshop全家桶,要么找在线网站,或者是wps充会员,或者找其它方法

    2024年02月20日
    浏览(44)
  • 【FFmpeg】ffmpeg 命令行参数 ⑧ ( 使用 ffmpeg 转换封装格式 | 音视频编解码器参数设置 | 视频 帧率 / 码率 / 分辨率 设置 | 音频 码率 / 采样率 设置 )

    音视频 文件 从 采样 - 处理 - 得到原始数据帧队列 - 音视频编码 - 音视频包队列 - 格式封装 的过程如下 : 封装格式 参考 【音视频原理】音视频 “ 采样 - 编码 - 封装 过程 “ 和 “ 解封装 - 解码 - 播放 过程 “ 分析 ( 视频采集处理流程 | 音频采集处理流程 | 音视频文件解封装

    2024年04月17日
    浏览(62)
  • FFMpeg-3、基于QT实现音视频播放显示

    1、音视频播放的基础知识 内容来自雷神博客 1、在Windows平台下的视频播放技术主要有以下三种:GDI,Direct3D和OpenGL;音频播放技术主要是DirectSound。 SDL本身并不具有播放显示的功能,它只是封装了底层播放显示的代码 记录三种视频显示技术:GDI,Direct3D,OpenGL。其中Direct3D包

    2024年02月03日
    浏览(47)
  • 项目实战——Qt实现FFmpeg音视频转码器

    本文记录使用 Qt 实现 FFmepg 音视频转码器项目的开发过程。 1、首先创建一个 Qt 项目,选择 MSVC2017 32bit 作为其编译器 2、将 FFmpeg 相关库及源文件拷贝到当前目录下 3、注释 prepare_app_arguments 函数(这里方便后面我们运行时可以指定相应的转码参数) 4、将所需的一些 dll 动态库

    2024年01月23日
    浏览(49)
  • FFmpeg 播放器实现音视频同步的三种方式

    我们基于 FFmpeg 利用 OpenGL ES 和 OpenSL ES 分别实现了对解码后视频和音频的渲染,本文将实现播放器的最后一个重要功能:音视频同步。 老人们经常说, 播放器对音频和视频的播放没有绝对的静态的同步,只有相对的动态的同步,实际上音视频同步就是一个“你追我赶”的过

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

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

    2024年02月03日
    浏览(67)
  • 音视频 FFmpeg音视频处理流程

    推荐一个零声学院项目课,个人觉得老师讲得不错,分享给大家: 零声白金学习卡(含基础架构/高性能存储/golang云原生/音视频/Linux内核) https://xxetb.xet.tech/s/VsFMs

    2024年02月12日
    浏览(44)
  • 音视频 ffmpeg命令提取音视频数据

    保留封装格式 提取视频 提取音频 推荐一个零声学院项目课,个人觉得老师讲得不错,分享给大家: 零声白金学习卡(含基础架构/高性能存储/golang云原生/音视频/Linux内核) https://xxetb.xet.tech/s/VsFMs

    2024年02月10日
    浏览(45)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包