2023-03-24:音视频mp3和h264混合(muxer)编码为mp4,用go语言编写。

2023-03-24:音视频mp3和h264混合(muxer)编码为mp4,用go语言编写。

答案2023-03-24:

这是一个使用FFmpeg库将MP3和H.264混合编码为MP4的Go语言程序。程序的大体过程如下:

1.设置FFmpeg库路径和环境变量。

2.检查并创建输出目录,以及输入视频和音频文件。

3.打开输入视频文件并查找视频流,打开输入音频文件并查找音频流。

4.新建输出上下文,并为视频和音频创建新的输出流。

5.打开输出文件。

6.写输出文件头。

7.读取输入视频和音频帧,将它们转换为输出格式,写入输出文件。在这个过程中,需要进行PTS/DTS转换和比特流过滤(如果需要)。

8.写输出文件尾。

9.清理资源并关闭输入和输出文件。

10.播放输出文件(可选)。

代码见github/moonfdd/ffmpeg-go库。

执行命令:

go run ./examples/a24.video_muxer_mp3h2642mp4/main.go

代码参考24:音视频mp3和h264混合(muxer)编码为mp4,代码如下:

// https://feater.top/ffmpeg/ffmpeg-muxer-encode-mp3-h264-to-mp4
package main

import (
	"fmt"
	"os"
	"os/exec"
	"unsafe"

	"github.com/moonfdd/ffmpeg-go/ffcommon"
	"github.com/moonfdd/ffmpeg-go/libavcodec"
	"github.com/moonfdd/ffmpeg-go/libavformat"
	"github.com/moonfdd/ffmpeg-go/libavutil"
)

/*
FIX: H.264 in some container format (FLV, MP4, MKV etc.) need
"h264_mp4toannexb" bitstream filter (BSF)
  *Add SPS,PPS in front of IDR frame
  *Add start code ("0,0,0,1") in front of NALU
H.264 in some container (MPEG2TS) don't need this BSF.
*/
//'1': Use H.264 Bitstream Filter
const USE_H264BSF = 0

/*
FIX:AAC in some container format (FLV, MP4, MKV etc.) need
"aac_adtstoasc" bitstream filter (BSF)
*/
//'1': Use AAC Bitstream Filter
const USE_AACBSF = 0

func main() {
	os.Setenv("Path", os.Getenv("Path")+";./lib")
	ffcommon.SetAvutilPath("./lib/avutil-56.dll")
	ffcommon.SetAvcodecPath("./lib/avcodec-58.dll")
	ffcommon.SetAvdevicePath("./lib/avdevice-58.dll")
	ffcommon.SetAvfilterPath("./lib/avfilter-56.dll")
	ffcommon.SetAvformatPath("./lib/avformat-58.dll")
	ffcommon.SetAvpostprocPath("./lib/postproc-55.dll")
	ffcommon.SetAvswresamplePath("./lib/swresample-3.dll")
	ffcommon.SetAvswscalePath("./lib/swscale-5.dll")

	genDir := "./out"
	_, err := os.Stat(genDir)
	if err != nil {
		if os.IsNotExist(err) {
			os.Mkdir(genDir, 0777) //  Everyone can read write and execute
		}
	}

	inFilenameVideo := "./out/a24.h264"
	inFilenameAudio := "./out/a24.aac"
	outFilename := "./out/a24.mp4"

	_, err = os.Stat(inFilenameVideo)
	if err != nil {
		if os.IsNotExist(err) {
			fmt.Println("create h264 file")
			exec.Command("./lib/ffmpeg", "-i", "./resources/big_buck_bunny.mp4", "-vcodec", "copy", "-an", inFilenameVideo).Output()
		}
	}

	_, err = os.Stat(inFilenameAudio)
	if err != nil {
		if os.IsNotExist(err) {
			fmt.Println("create aac file")
			exec.Command("./lib/ffmpeg", "-i", "./resources/big_buck_bunny.mp4", "-acodec", "copy", "-vn", inFilenameAudio).Output()
		}
	}

	var ifmtCtxVideo, ifmtCtxAudio, ofmtCtx *libavformat.AVFormatContext
	var packet libavcodec.AVPacket

	var inVideoIndex, inAudioIndex ffcommon.FInt = -1, -1
	var outVideoIndex, outAudioIndex ffcommon.FInt = -1, -1
	var frameIndex ffcommon.FInt = 0

	var curPstVideo, curPstAudio ffcommon.FInt64T = 0, 0

	var ret ffcommon.FInt = 0
	var i ffcommon.FUnsignedInt = 0

	var h264bsfc, aacbsfc *libavcodec.AVBitStreamFilterContext

	//打开输入视频文件
	ret = libavformat.AvformatOpenInput(&ifmtCtxVideo, inFilenameVideo, nil, nil)
	if ret < 0 {
		fmt.Printf("can't open input video file\n")
		goto end
	}

	//查找输入流
	ret = ifmtCtxVideo.AvformatFindStreamInfo(nil)
	if ret < 0 {
		fmt.Printf("failed to retrieve input video stream information\n")
		goto end
	}

	//打开输入音频文件
	ret = libavformat.AvformatOpenInput(&ifmtCtxAudio, inFilenameAudio, nil, nil)
	if ret < 0 {
		fmt.Printf("can't open input audio file\n")
		goto end
	}

	//查找输入流
	ret = ifmtCtxAudio.AvformatFindStreamInfo(nil)
	if ret < 0 {
		fmt.Printf("failed to retrieve input audio stream information\n")
		goto end
	}

	fmt.Printf("===========Input Information==========\n")
	ifmtCtxVideo.AvDumpFormat(0, inFilenameVideo, 0)
	ifmtCtxAudio.AvDumpFormat(0, inFilenameAudio, 0)
	fmt.Printf("======================================\n")

	//新建输出上下文
	libavformat.AvformatAllocOutputContext2(&ofmtCtx, nil, "", outFilename)
	if ofmtCtx == nil {
		fmt.Printf("can't create output context\n")
		goto end
	}

	//视频输入流
	for i = 0; i < ifmtCtxVideo.NbStreams; i++ {
		if ifmtCtxVideo.GetStream(i).Codecpar.CodecType == libavutil.AVMEDIA_TYPE_VIDEO {
			inStream := ifmtCtxVideo.GetStream(i)
			outStream := ofmtCtx.AvformatNewStream(nil)
			inVideoIndex = int32(i)

			if outStream == nil {
				fmt.Printf("failed to allocate output stream\n")
				goto end
			}

			outVideoIndex = outStream.Index

			if libavcodec.AvcodecParametersCopy(outStream.Codecpar, inStream.Codecpar) < 0 {
				fmt.Printf("faild to copy context from input to output stream")
				goto end
			}

			outStream.Codecpar.CodecTag = 0

			break
		}
	}

	//音频输入流
	for i = 0; i < ifmtCtxAudio.NbStreams; i++ {
		if ifmtCtxAudio.GetStream(i).Codecpar.CodecType == libavutil.AVMEDIA_TYPE_AUDIO {
			inStream := ifmtCtxAudio.GetStream(i)
			outStream := ofmtCtx.AvformatNewStream(nil)
			inAudioIndex = int32(i)

			if outStream == nil {
				fmt.Printf("failed to allocate output stream\n")
				goto end
			}

			outAudioIndex = outStream.Index

			if libavcodec.AvcodecParametersCopy(outStream.Codecpar, inStream.Codecpar) < 0 {
				fmt.Printf("faild to copy context from input to output stream")
				goto end
			}

			outStream.Codecpar.CodecTag = 0

			break
		}
	}

	fmt.Printf("==========Output Information==========\n")
	ofmtCtx.AvDumpFormat(0, outFilename, 1)
	fmt.Printf("======================================\n")

	//打开输入文件
	if ofmtCtx.Oformat.Flags&libavformat.AVFMT_NOFILE == 0 {
		if libavformat.AvioOpen(&ofmtCtx.Pb, outFilename, libavformat.AVIO_FLAG_WRITE) < 0 {
			fmt.Printf("can't open out file\n")
			goto end
		}
	}

	//写文件头
	if ofmtCtx.AvformatWriteHeader(nil) < 0 {
		fmt.Printf("Error occurred when opening output file\n")
		goto end
	}

	if USE_H264BSF != 0 {
		h264bsfc = libavcodec.AvBitstreamFilterInit("h264_mp4toannexb")
	}
	if USE_AACBSF != 0 {
		aacbsfc = libavcodec.AvBitstreamFilterInit("aac_adtstoasc")
	}
	for {
		var ifmtCtx *libavformat.AVFormatContext
		var inStream, outStream *libavformat.AVStream
		var streamIndex ffcommon.FInt = 0

		if libavutil.AvCompareTs(curPstVideo, ifmtCtxVideo.GetStream(uint32(inVideoIndex)).TimeBase, curPstAudio, ifmtCtxAudio.GetStream(uint32(inAudioIndex)).TimeBase) < 0 {
			ifmtCtx = ifmtCtxVideo
			streamIndex = outVideoIndex

			if ifmtCtx.AvReadFrame(&packet) >= 0 {
				for {
					inStream = ifmtCtx.GetStream(packet.StreamIndex)
					outStream = ofmtCtx.GetStream(uint32(streamIndex))

					if packet.StreamIndex == uint32(inVideoIndex) {
						//Fix: No PTS(Example: Raw H.264
						//Simple Write PTS
						if packet.Pts == libavutil.AV_NOPTS_VALUE {
							//write PTS
							timeBase1 := inStream.TimeBase
							//Duration between 2 frames
							calcDuration := int64(libavutil.AV_TIME_BASE / libavutil.AvQ2d(inStream.RFrameRate))
							//Parameters
							packet.Pts = int64((float64(frameIndex) * float64(calcDuration)) / (libavutil.AvQ2d(timeBase1) * libavutil.AV_TIME_BASE))
							packet.Dts = packet.Pts
							packet.Duration = int64(float64(calcDuration) / (libavutil.AvQ2d(timeBase1) * libavutil.AV_TIME_BASE))
							frameIndex++
						}

						curPstVideo = packet.Pts
						break
					}
					if ifmtCtx.AvReadFrame(&packet) >= 0 {

					} else {
						break
					}
				}
			} else {
				break
			}
		} else {
			ifmtCtx = ifmtCtxAudio
			streamIndex = outAudioIndex

			if ifmtCtx.AvReadFrame(&packet) >= 0 {
				for {
					inStream = ifmtCtx.GetStream(packet.StreamIndex)
					outStream = ofmtCtx.GetStream(uint32(streamIndex))

					if packet.StreamIndex == uint32(inAudioIndex) {
						//Fix: No PTS(Example: Raw H.264
						//Simple Write PTS
						if packet.Pts == libavutil.AV_NOPTS_VALUE {
							//write PTS
							timeBase1 := inStream.TimeBase
							//Duration between 2 frames
							calcDuration := int64(libavutil.AV_TIME_BASE / libavutil.AvQ2d(inStream.RFrameRate))
							//Parameters
							packet.Pts = int64((float64(frameIndex) * float64(calcDuration)) / (libavutil.AvQ2d(timeBase1) * libavutil.AV_TIME_BASE))
							packet.Dts = packet.Pts
							packet.Duration = int64(float64(calcDuration) / (libavutil.AvQ2d(timeBase1) * libavutil.AV_TIME_BASE))
							frameIndex++
						}

						curPstAudio = packet.Pts
						break
					}
					if ifmtCtx.AvReadFrame(&packet) >= 0 {

					} else {
						break
					}
				}
			} else {
				break
			}
		}

		//FIX:Bitstream Filter
		if USE_H264BSF != 0 {
			h264bsfc.AvBitstreamFilterFilter(inStream.Codec, "", &packet.Data, (*int32)(unsafe.Pointer(&packet.Size)), packet.Data, int32(packet.Size), 0)
		}
		if USE_AACBSF != 0 {
			aacbsfc.AvBitstreamFilterFilter(outStream.Codec, "", &packet.Data, (*int32)(unsafe.Pointer(&packet.Size)), packet.Data, int32(packet.Size), 0)
		}

		//Convert PTS/DTS
		packet.Pts = libavutil.AvRescaleQRnd(packet.Pts, inStream.TimeBase, outStream.TimeBase, libavutil.AV_ROUND_NEAR_INF|libavutil.AV_ROUND_PASS_MINMAX)
		packet.Dts = libavutil.AvRescaleQRnd(packet.Dts, inStream.TimeBase, outStream.TimeBase, libavutil.AV_ROUND_NEAR_INF|libavutil.AV_ROUND_PASS_MINMAX)
		packet.Duration = libavutil.AvRescaleQ(packet.Duration, inStream.TimeBase, outStream.TimeBase)
		packet.Pos = -1
		packet.StreamIndex = uint32(streamIndex)

		//write
		if ofmtCtx.AvInterleavedWriteFrame(&packet) < 0 {
			fmt.Printf("error muxing packet")
			break
		}

		packet.AvPacketUnref()
	}

	//Write file trailer
	ofmtCtx.AvWriteTrailer()

	if USE_H264BSF != 0 {
		h264bsfc.AvBitstreamFilterClose()
	}
	if USE_AACBSF != 0 {
		aacbsfc.AvBitstreamFilterClose()
	}

end:
	libavformat.AvformatCloseInput(&ifmtCtxVideo)
	libavformat.AvformatCloseInput(&ifmtCtxAudio)
	if ofmtCtx != nil && ofmtCtx.Oformat.Flags&libavformat.AVFMT_NOFILE == 0 {
		ofmtCtx.Pb.AvioClose()
	}

	ofmtCtx.AvformatFreeContext()
	fmt.Println("-----------------------------------------")
	_, err = exec.Command("./lib/ffplay.exe", outFilename).Output()
	if err != nil {
		fmt.Println("play err = ", err)
	}
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/4935.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ChatGPT来了,让我们快速做个AI应用

你好&#xff0c;我是徐文浩。 过去的两讲&#xff0c;我带着你通过OpenAI提供的Embedding接口&#xff0c;完成了文本分类的功能。那么&#xff0c;这一讲里&#xff0c;我们重新回到Completion接口。而且这一讲里&#xff0c;我们还会快速搭建出一个有界面的聊天机器人来给你…

五分钟了解支付、交易、清算、银行等专业名词的含义?

五分钟了解支付、交易、清算、银行等专业名词的含义&#xff1f;1. 支付类名词01 支付应用02 支付场景03 交易类型04 支付类型&#xff08;按通道类型&#xff09;05 支付类型&#xff08;按业务双方类型&#xff09;06 支付方式07 支付产品08 收银台类型09 支付通道10 通道类型…

Unity Avatar Cover System - 如何实现一个Avatar角色的智能掩体系统

文章目录简介变量说明实现动画准备动画状态机State 状态NoneStand To CoverIs CoveringCover To Stand高度适配高度检测脚部IK简介 本文介绍如何在Unity中实现一个Avatar角色的智能掩体系统&#xff0c;效果如图所示&#xff1a; 初版1.0.0代码已上传至SKFramework框架Package…

【Nginx】Nginx的学习(3.Nginx命令和nginx配置文件)

1. Nginx命令 1.1 启动nginx systemctl start nginx1.2 停止nginx systemctl stop nginx1.3 重载nginx # 重新加载配置文件 systemctl reload nginx1.4 查看nginx服务端口 netstat -anpl | grep nginx1.5 查看nginx进程 ps aux | grep nginx2. nginx的配置文件 2.1 查看…

git拉取github上的项目

git拉取github上的项目测试创建bash公钥&#xff0c;拉取代码1.先创建github账号和项目&#xff1b;系统安装git程序2.先配置ssh公钥,为了避免每次远程访问需要输密码&#xff0c;将使用ssh登陆。ssh应该与本机信息绑定&#xff0c;查看自己电脑 C:\Users\lenovo\.ssh 目录下是…

预训练语言模型(GPT,BERT)

文章目录GPT 模型预训练语言模型模型和学习BERT 模型去噪自编码器模型和学习模型特点References在自然语言处理中事先使用大规模语料学习基于 Transformer 等的语言模型&#xff0c;之后用于各种任务的学习和预测&#xff0c;称这种模型为预训练语言模型。代表性的模型有 BERT …

STA环境 - 时钟

目录1. 指定时钟create_clock1.1. 时钟延迟set_clock_latency 1.2. 时钟不确定度&#xff08;时钟抖动&#xff09;set_clock_uncertainty 1.3. 时钟过渡时间set_clock_transition 2. 衍生时钟create_generated_clock3. 划定时钟域set_clock_groupsSTA环境配置中对时钟如何约束…

【总结】爬虫4-selenium

爬虫4-selenium 1. selenium 基本操作 在使用selenium之前必须先配置浏览器对应版本的webdriver。才可以控制浏览器打开网页 1.1 创建浏览器对象 b Chrome()1.2 打开网页 &#xff08;需要哪个网页数据&#xff0c;就打开那个网页对应的网页地址&#xff09; b.get(https…

git 001--建本地仓库和远程仓库和拉代码

要使用Git对我们的代码进行管理&#xff0c;首先需要获得Git仓库。 获取Git仓库通常有两种方式&#xff1a; 在本地初始化Git仓库&#xff08;不常用&#xff09; 从远程仓库克隆&#xff08;常用&#xff09; 一.建本地仓库 方法一: 在自己电脑的任意目录下创建一个空目录…

字节测试总监,让我们用这份《测试用例规范》,再也没加班过

经常看到无论是刚入职场的新人&#xff0c;还是工作了一段时间的老人&#xff0c;都会对编写测试用例感到困扰&#xff1f;例如&#xff1a; 固然&#xff0c;编写一份好的测试用例需要&#xff1a;充分的需求分析能力 理论及经验加持&#xff0c;作为测试职场摸爬打滚的老人&…

为什么企业需要一个“企业办公浏览器”?

目前&#xff0c;大多数企业还在用着传统的Web浏览器&#xff0c;它是各行业企业办公最常用到的应用程序&#xff0c;搜索资料、打开其他应用工具、打开文档等等&#xff0c;企业员工几乎每天都在用它做这些工作。 但实际上&#xff0c;Web浏览器并不是一个企业专用的办公应用软…

炒黄金所需的k线图基础知识(上)

炒金&#xff0c;一般是指对杠杠式的黄金电子合约&#xff08;如伦敦金、黄金期货&#xff09;进行短线的多空操作&#xff0c;从中赚取波动价差的行为。无论投资者从事内盘还是外盘交易&#xff0c;K线图都是基础的、必备的知识。 1、什么叫K线图&#xff1f; K线图源于日本的…

计算机网络名词解释和简答题总结

名词解释 CSMA/CD&#xff08;载波监听多点接入/碰撞检测协议&#xff09; CSMA/CD是一种基于冲突检测的载波监听多路访问技术。CSMA/CD协议要求站点在发送数据之前先监听信道。如果信道空闲&#xff0c;站点就可以发送数据&#xff1b;如果信道忙&#xff0c;则站点不能发送…

使用CookieJar提取cookie信息

首先&#xff0c;推荐几个帖子&#xff0c;大伙可以先看看。国内通过cookiejar主要获取cookie的方法&#xff0c;大致都是如此的。 http.cookiejar库之CookieJar_pigYanYan的博客-CSDN博客 Python编程&#xff1a;cookiejar的使用_彭世瑜的博客-CSDN博客 再推荐一个资料帖&a…

Linux权限

Linux下有两种用户&#xff1a;超级用户(root)、普通用户。超级用户(root):可以在linux系统下做任何事&#xff0c;不受限制&#xff0c;只有1个。普通用户:在linux系统下做有限的事,有N个。超级用户的提示符#&#xff1b;普通用户的提示符$切换用户的命令:su切换root时可以直接…

MQ之kafka

一 概念 Kafka是最初由Linkedin公司开发&#xff0c;是一个分布式、支持分区的&#xff08;partition&#xff09;、多副本的&#xff08;replica&#xff09;&#xff0c;基于zookeeper协调的分布式消息系统&#xff0c;它的最大的特性就是可以实时的处理大量数据以满足各种需…

Visual Studio Code2023(VSCode2023)安装包下载及安装教程(最新版接入了chat GPT)

[软件名称]: Visual Studio Code2023 [软件大小]: 88.6 MB [安装环境]: Win11/Win10/Win7 [软件安装包下载]:https://pan.quark.cn/s/ee94a4aa2abc Visual Studio Code简称“VS Code”是Microsoft在2015年4月30日Build开发者大会上正式宣布一个运行于 Mac OS X、Windows和 Lin…

【Datawhale动手学深度学习笔记】多层感知机代码实践

多层感知机 激活函数 激活函数&#xff08;activation function&#xff09;通过计算加权和并加上偏置来确定神经元是否应该被激活&#xff0c; 它们将输入信号转换为输出的可微运算。 大多数激活函数都是非线性的。 由于激活函数是深度学习的基础&#xff0c;下面简要介绍一…

多线程进阶学习09------ThreadLocal详解

ThreadLocal&#xff1a;提供线程的局部变量&#xff0c;对于线程共享变量如果使用ThreadLocal则无需加锁&#xff0c;更省事省心。 ThreadLocal本地线程变量,线程自带的变量副本(实现了每一个线程副本都有一个专属的本地变量,主要解决的就是让每一个线程绑定自己的值,自己用自…

FastReport .NET 2023.2.4 Crack

FastReport .NET Reporting and documents creation library for .NET 7 FastReport .NET适用于 .NET 7、.NET Core、Blazor、ASP.NET、MVC 和 Windows Forms 的全功能报告库。它可以在微软视觉工作室 2022 和 JetBrains Rider 中使用。 利用 .NET 7、.NET Core、Blazor、ASP.N…
最新文章