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)
}
}

2023-03-24:音视频mp3和h264混合(muxer)编码为mp4,用go语言编写。的更多相关文章

  1. 音视频处理之H264编码标准20170906

    一. H264基础概念 1.名词解释 场和帧 :    视频的一场或一帧可用来产生一个编码图像.在电视中,为减少大面积闪烁现象,把一帧分成两个隔行的场. 片:             每个图象中,若干 ...

  2. 第六十篇、音视频采集硬编码(H264+ACC)

    使用 AVCaptureSession进行实时采集音视频(YUV.),编码 通过AVCaptureVideoDataOutputSampleBufferDelegate获取到音视频buffer- 数据 ...

  3. 音视频通讯QoS技术及其演进

    利用多种算法和策略进行网络传输控制,最大限度满足弱网场景下的音视频用户体验. 良逸|技术作者 01 什么是QoS?音视频通讯QoS是哪一类? QoS(Quality of Service)是服务质量的 ...

  4. HTML5_音视频标签 <audio> 和 <video>

    HTML5_音视频标签 <audio> 和 <video> audio 和 video 都是 inline行内元素 如果浏览器支持,则不显示标签文本 IE8 不支持 audio ...

  5. 手机Android音视频採集与直播推送,实现单兵、移动监控类应用

    最新手机採集推送直播监控以及EasyDarwin开源流媒体平台的版本号及代码: EasyDarwin 开源流媒体云平台:https://github.com/easydarwin EasyClient ...

  6. 音视频编解码问题:javaCV如何快速进行音频预处理和解复用编解码(基于javaCV-FFMPEG)

    前言: 前面我用了很多章实现了javaCV的基本操作,包括:音视频捕捉(摄像头视频捕捉和话筒音频捕捉),推流(本地音视频或者摄像头话筒混合推流到服务器),转流(rtsp->rtmp),收流(录制 ...

  7. 【FFMPEG】各种音视频编解码学习详解 h264 ,mpeg4 ,aac 等所有音视频格式

    目录(?)[-] 编解码学习笔记二codec类型 编解码学习笔记三Mpeg系列Mpeg 1和Mpeg 2 编解码学习笔记四Mpeg系列Mpeg 4 编解码学习笔记五Mpeg系列AAC音频 编解码学习笔 ...

  8. 全志Tina_dolphin播放音视频裸流(h264,pcm)验证

    最近在验证tina对裸流音视频的支持,主要指h264视频裸流及pcm音频裸流. 在原始sdk中有针对很多video和audio类型的parser,但就是没有找到pcm和h264的parser,所以需要 ...

  9. RTP协议解析及H264/H265 音视频RTP打包分析

    一 概述 实时传输协议(Real-time Transport Protocol或简写RTP)是一个网络传输协议,它是由IETF的多媒体传输工作小组1996年在RFC 1889中公布的. RTP协议详 ...

  10. Android音视频开发(1):H264 基本原理

    前言 H264 视频压缩算法现在无疑是所有视频压缩技术中使用最广泛,最流行的.随着 x264/openh264 以及 ffmpeg 等开源库的推出,大多数使用者无需再对H264的细节做过多的研究,这大 ...

随机推荐

  1. 记我的第一个UVM项目

    没有天天写博客的习惯,后果就是老是忘记自己的排版风格.为了追求统一还要翻一下之前是怎么写的.这也算是意料之外的发现吧. 说实话,没人教的话从零开始学一个新的东西实在是太难了.即使互联网的存在已经大幅降 ...

  2. Xamarin.Android 利用作业计划程序实现ImageSwitcher图片自动定时轮播

    在开发android程序时,遇到一个问题,ImageSwitcher只支持手动的切换图片,不支持自动定时的切换.因为xamarin的资料很少,官方也没有相应的教程,所以想到这个方法,利用job程序来实 ...

  3. RealWorldCTF渗透赛第二期复现-ctfshow

    比赛概述 开始时间:2023年3月10日15时 环境保留时间:72小时 环境重置时间:20分钟 官方wp链接:Docs (feishu.cn) [本次复现跟着官方WP进行,只做记录学习之用] 0x1 ...

  4. 解放AI生产力——ComfyUI

    最近状态不好,所以这几天基本没干什么,就分享一下和AI绘画工作流有关的东西吧. 此前我都没有抱着一种教学的心态来写博客,因为我所掌握的东西实在太过简单,只要一说大家就会了,我害怕我在人群里失去自己的特 ...

  5. 数据库相关知识点整理,助力拿到心仪的offer

    1. 数据库的事务 1.1 什么是数据库事务? 事务是指一组逻辑上相关的操作,这些操作要么全部完成,要么全部不完成. 事务是数据库管理系统执行过程中的一个逻辑工作单位,是用户定义的一个操作序列,这些操 ...

  6. Linux环境下使用jsoncpp

    目录 1. 下载jsoncpp 2. 生成静态库libjsoncpp.a 3. 复制相关文件至/usr/local下(方便编程) 4. CMakeList.txt编写(需要新增的) 1. 下载json ...

  7. asp.net 应用程序中同步方法调用异步方法无响应解决方法

    微软发布 C# async/await 异步语法功能已经好久了,但是目前来看使用并不广泛.本人经过实践在开发过程中使用 async/await 一路到底确实很爽,而且也没有啥问题.但是在面对旧项目变更 ...

  8. 重磅!AWS升级对Apache Hudi的集成

    全球最大云厂商AWS的 Athena 团队又更新了 Athena 与 Apache Hudi 的集成,以支持新功能及最新的 0.8.0 社区版本.早在Apache Hudi还处于孵化阶段时,AWS A ...

  9. ChatGPT 与 Midjourney 强强联手,让先秦阿房宫重现辉煌!

    Midjourney 是一款非常特殊的 AI 绘画聊天机器人,它并不是软件,也不用安装,而是直接搭载在 Discord 平台之上,所有的功能都是通过调用 Discord 的聊天机器人程序实现的.要想使 ...

  10. [网络]公共网络安全漏洞库: CVE / CNCVE

    本文博主的经历与该博文处理绿盟科技安全评估的系统漏洞 - 博客园的经历相同: 处理[第三方网络安全公司]给[公司产品]的[客户的服务器]扫描后生成的[安全漏洞报告]. 1 前言 以网络安全行业中最大的 ...