2023-03-01:用moonfdd/ffmpeg-go库,将h264文件编码为mp4文件。

答案2023-03-01:

使用 github.com/moonfdd/ffmpeg-go 库。现在我们有h264的流,创建一个mp4文件,新建一条流并将h264流插入进去。(暂时没有音频部分)。

转换流程图为:

命令如下:

  1. go run ./examples/a13.video_encode_h2642mp4/main.go

参考了13:h264编码为mp4,代码用golang编写。代码如下:

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "os/exec"
  6. "github.com/moonfdd/ffmpeg-go/ffcommon"
  7. "github.com/moonfdd/ffmpeg-go/libavcodec"
  8. "github.com/moonfdd/ffmpeg-go/libavformat"
  9. "github.com/moonfdd/ffmpeg-go/libavutil"
  10. )
  11. func main() {
  12. os.Setenv("Path", os.Getenv("Path")+";./lib")
  13. ffcommon.SetAvutilPath("./lib/avutil-56.dll")
  14. ffcommon.SetAvcodecPath("./lib/avcodec-58.dll")
  15. ffcommon.SetAvdevicePath("./lib/avdevice-56.dll")
  16. ffcommon.SetAvfilterPath("./lib/avfilter-56.dll")
  17. ffcommon.SetAvformatPath("./lib/avformat-58.dll")
  18. ffcommon.SetAvpostprocPath("./lib/postproc-55.dll")
  19. ffcommon.SetAvswresamplePath("./lib/swresample-3.dll")
  20. ffcommon.SetAvswscalePath("./lib/swscale-5.dll")
  21. genDir := "./out"
  22. _, err := os.Stat(genDir)
  23. if err != nil {
  24. if os.IsNotExist(err) {
  25. os.Mkdir(genDir, 0777) // Everyone can read write and execute
  26. }
  27. }
  28. frame_index := 0 //统计帧数
  29. inVStreamIndex := -1
  30. outVStreamIndex := -1 //输入输出视频流在文件中的索引位置
  31. inVFileName := "./out/result.h264"
  32. outFileName := "./out/result.mp4"
  33. //是否存在h264文件
  34. _, err = os.Stat(inVFileName)
  35. if err != nil {
  36. if os.IsNotExist(err) {
  37. fmt.Println("create h264 file")
  38. exec.Command("./lib/ffmpeg", "-i", "./resources/big_buck_bunny.mp4", "-vcodec", "copy", "-an", inVFileName, "-y").CombinedOutput()
  39. }
  40. }
  41. var inVFmtCtx *libavformat.AVFormatContext
  42. var outFmtCtx *libavformat.AVFormatContext
  43. var codecPara *libavcodec.AVCodecParameters
  44. var outVStream *libavformat.AVStream
  45. var outCodec *libavcodec.AVCodec
  46. var outCodecCtx *libavcodec.AVCodecContext
  47. var outCodecPara *libavcodec.AVCodecParameters
  48. var inVStream *libavformat.AVStream
  49. pkt := libavcodec.AvPacketAlloc()
  50. for {
  51. //======================输入部分============================//
  52. //打开输入文件
  53. if libavformat.AvformatOpenInput(&inVFmtCtx, inVFileName, nil, nil) < 0 {
  54. fmt.Printf("Cannot open input file.\n")
  55. break
  56. }
  57. //查找输入文件中的流
  58. if inVFmtCtx.AvformatFindStreamInfo(nil) < 0 {
  59. fmt.Printf("Cannot find stream info in input file.\n")
  60. break
  61. }
  62. //查找视频流在文件中的位置
  63. for i := uint32(0); i < inVFmtCtx.NbStreams; i++ {
  64. if inVFmtCtx.GetStream(i).Codecpar.CodecType == libavutil.AVMEDIA_TYPE_VIDEO {
  65. inVStreamIndex = int(i)
  66. break
  67. }
  68. }
  69. codecPara = inVFmtCtx.GetStream(uint32(inVStreamIndex)).Codecpar //输入视频流的编码参数
  70. fmt.Printf("===============Input information========>\n")
  71. inVFmtCtx.AvDumpFormat(0, inVFileName, 0)
  72. fmt.Printf("===============Input information========<\n")
  73. //=====================输出部分=========================//
  74. //打开输出文件并填充格式数据
  75. if libavformat.AvformatAllocOutputContext2(&outFmtCtx, nil, "", outFileName) < 0 {
  76. fmt.Printf("Cannot alloc output file context.\n")
  77. break
  78. }
  79. //打开输出文件并填充数据
  80. if libavformat.AvioOpen(&outFmtCtx.Pb, outFileName, libavformat.AVIO_FLAG_READ_WRITE) < 0 {
  81. fmt.Printf("output file open failed.\n")
  82. break
  83. }
  84. //在输出的mp4文件中创建一条视频流
  85. outVStream = outFmtCtx.AvformatNewStream(nil)
  86. if outVStream == nil {
  87. fmt.Printf("Failed allocating output stream.\n")
  88. break
  89. }
  90. outVStream.TimeBase.Den = 25
  91. outVStream.TimeBase.Num = 1
  92. outVStreamIndex = int(outVStream.Index)
  93. //查找编码器
  94. outCodec = libavcodec.AvcodecFindEncoder(codecPara.CodecId)
  95. if outCodec == nil {
  96. fmt.Printf("Cannot find any encoder.\n")
  97. break
  98. }
  99. //从输入的h264编码器数据复制一份到输出文件的编码器中
  100. outCodecCtx = outCodec.AvcodecAllocContext3()
  101. outCodecPara = outFmtCtx.GetStream(uint32(outVStream.Index)).Codecpar
  102. if libavcodec.AvcodecParametersCopy(outCodecPara, codecPara) < 0 {
  103. fmt.Printf("Cannot copy codec para.\n")
  104. break
  105. }
  106. if outCodecCtx.AvcodecParametersToContext(outCodecPara) < 0 {
  107. fmt.Printf("Cannot alloc codec ctx from para.\n")
  108. break
  109. }
  110. outCodecCtx.TimeBase.Den = 25
  111. outCodecCtx.TimeBase.Num = 1
  112. //打开输出文件需要的编码器
  113. if outCodecCtx.AvcodecOpen2(outCodec, nil) < 0 {
  114. fmt.Printf("Cannot open output codec.\n")
  115. break
  116. }
  117. fmt.Printf("============Output Information=============>\n")
  118. outFmtCtx.AvDumpFormat(0, outFileName, 1)
  119. fmt.Printf("============Output Information=============<\n")
  120. //写入文件头
  121. if outFmtCtx.AvformatWriteHeader(nil) < 0 {
  122. fmt.Printf("Cannot write header to file.\n")
  123. return
  124. }
  125. //===============编码部分===============//
  126. inVStream = inVFmtCtx.GetStream(uint32(inVStreamIndex))
  127. for inVFmtCtx.AvReadFrame(pkt) >= 0 { //循环读取每一帧直到读完
  128. if pkt.StreamIndex == uint32(inVStreamIndex) { //确保处理的是视频流
  129. //FIXME:No PTS (Example: Raw H.264)
  130. //Simple Write PTS
  131. //如果当前处理帧的显示时间戳为0或者没有等等不是正常值
  132. if pkt.Pts == libavutil.AV_NOPTS_VALUE {
  133. fmt.Printf("frame_index:%d\n", frame_index)
  134. //Write PTS
  135. time_base1 := inVStream.TimeBase
  136. //Duration between 2 frames (us)
  137. calc_duration := libavutil.AV_TIME_BASE / libavutil.AvQ2d(inVStream.RFrameRate)
  138. //Parameters
  139. pkt.Pts = int64((float64(frame_index) * calc_duration) / (libavutil.AvQ2d(time_base1) * float64(libavutil.AV_TIME_BASE)))
  140. pkt.Dts = pkt.Pts
  141. pkt.Duration = int64(calc_duration / (libavutil.AvQ2d(time_base1) * float64(libavutil.AV_TIME_BASE)))
  142. frame_index++
  143. }
  144. //Convert PTS/DTS
  145. pkt.Pts = libavutil.AvRescaleQRnd(pkt.Pts, inVStream.TimeBase, outVStream.TimeBase, libavutil.AV_ROUND_NEAR_INF|libavutil.AV_ROUND_PASS_MINMAX)
  146. pkt.Dts = libavutil.AvRescaleQRnd(pkt.Dts, inVStream.TimeBase, outVStream.TimeBase, libavutil.AV_ROUND_NEAR_INF|libavutil.AV_ROUND_PASS_MINMAX)
  147. pkt.Duration = libavutil.AvRescaleQ(pkt.Duration, inVStream.TimeBase, outVStream.TimeBase)
  148. pkt.Pos = -1
  149. pkt.StreamIndex = uint32(outVStreamIndex)
  150. fmt.Printf("Write 1 Packet. size:%5d\tpts:%d\tduration:%d\n", pkt.Size, pkt.Pts, pkt.Duration)
  151. //Write
  152. if outFmtCtx.AvInterleavedWriteFrame(pkt) < 0 {
  153. fmt.Printf("Error muxing packet\n")
  154. break
  155. }
  156. pkt.AvPacketUnref()
  157. }
  158. }
  159. outFmtCtx.AvWriteTrailer()
  160. break
  161. }
  162. //===========================释放所有指针===============================//
  163. libavcodec.AvPacketFree(&pkt)
  164. libavformat.AvformatCloseInput(&outFmtCtx)
  165. outCodecCtx.AvcodecClose()
  166. libavcodec.AvcodecFreeContext(&outCodecCtx)
  167. libavformat.AvformatCloseInput(&inVFmtCtx)
  168. inVFmtCtx.AvformatFreeContext()
  169. // outFmtCtx.Pb.AvioClose()//案例里面有,但个人感觉不对
  170. fmt.Println("-----------------------------------------")
  171. _, err = exec.Command("./lib/ffplay.exe", "./out/result.mp4").Output()
  172. if err != nil {
  173. fmt.Println("play err = ", err)
  174. }
  175. }

2023-03-01:用moonfdd/ffmpeg-go库,将h264文件编码为mp4文件。的更多相关文章

  1. 使用ffmpeg获取视频流后如何封装存储成mp4文件

    int main(int argc,char *argv[]) 02 { 03  AVFormatContext *pFormatCtx; 04  int i,videoStream; 05  AVC ...

  2. FFmpeg基础库编程开发学习笔记——音频常见格式及字幕格式

    声明一下:这些关于ffmpeg的文章仅仅是用于记录我的学习历程和以便于以后查阅,文章中的一些文字可能是直接摘自于其它文章.书籍或者文献,学习ffmpeg相关知识是为了使用在Android上,我也才是刚 ...

  3. 解决QZ-SDK静态库libRPToolLib.a中avfoundation.o文件和kxMovie依赖的ffmpeg静态库libavdevice.a函数重复定义的问题

    解决QZ-SDK静态库libRPToolLib.a中avfoundation.o文件和kxMovie依赖的ffmpeg静态库libavdevice.a函数重复定义的问题 在原来项目中导入全志v3相机的 ...

  4. 基于ffmpeg静态库的应用开发

    最近几天在试着做基本ffmpeg静态库的开发,只有main中包含了avdevice_register_all 或avfilter_register_all,编译就通不过,undefined refre ...

  5. ffmpeg第三方库编译记录

    最近在研究ffmpeg的编译,之前使用的Ubuntu,需要安装虚拟机,非常麻烦,所以后来改研究在Windows平台编译. 一开始遇到很多挫折,参考了网上很多的帖子,但要么不全要么内容已过期,经过我的反 ...

  6. Windows 系统 vs2012 MinGW 编译ffmpeg 静态库

    Windows系统下 vs2012编译ffmpeg 动态库 前面已经有文章讲述,本文将讲述如果编译生成ffmpeg静态库以方便 在vs2012下调用. 准备工作:安装MinGW环境,修改ffmpeg配 ...

  7. 为iOS编译FFmpeg静态库

    为iOS编译FFmpeg静态库 
 环境:OS X Yosemite (版本10.10.5) Xcode (Version 7.1.1 (7B1005)) 
 
 一.资料准备: (1)ffmpeg源 ...

  8. xcode5下一个ffmpeg静态库配置

    1.若要安装xcode命令行工具 1).xcode5安装命令行工具方法: 在终端运行命令Using xcode-select --install 2).xcode5之前安装命令行工具方法: 2.xco ...

  9. FFmpeg基础库编程开发学习笔记——视频常见格式

    声明一下:这些关于ffmpeg的文章仅仅是用于记录我的学习历程和以便于以后查阅,文章中的一些文字可能是直接摘自于其它文章.书籍或者文献,学习ffmpeg相关知识是为了使用在Android上,我也才是刚 ...

  10. FFmpeg(2)-avformat_open_input()函数详解并示例打开mp4文件

    一. 解封装 pts 是显示的时间 dts是解码的时间, 这个时间是用来做同步. av_register_all(), 注册所有的格式.包括解封装格式和加封装格式. avformat_network_ ...

随机推荐

  1. python tkinter Checkbutton的新增和清除 取值

    from tkinter import * root = Tk() name = StringVar() check_box_list = [] ent=Entry(root,textvariable ...

  2. 搬运工 - Appium Python API 中文版

    Appium_Python_Api文档 1.contextscontexts(self): Returns the contexts within the current session. 返回当前会 ...

  3. spring-mvc.xml

    <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.spr ...

  4. FastReport OpenSource发布到Linux上的准备

    一.安装libgdiplus(libgdiplus是一个Mono库,用于对非Windows操作系统提供GDI+兼容的API)   apt-get install build-essential lib ...

  5. 分布式CAP_BASE博客参考

    https://blog.csdn.net/lixinkuan328/article/details/95535691 CAP 一致性(Consistency) 可用性(Availability) 分 ...

  6. java顺序结构

    java顺序结构 java的基本结构就是顺序结构,一句一句执行 package charpter2; public class ShunXu { public static void main(Str ...

  7. Android和adb命令

    一.名词解释 1.SDK:是软件开发工具包 2.activity(活动):驱使软件运行的一段程序,软件系统和用户进行交互的界面叫一个活动 二.adb命令 1.查看连接的设备:adb devices 2 ...

  8. SQL Server修改sa用户密码

     SQL Server数据库使用windows用户登录,安全性->登录名->找到sa用户->属性: 可直接修改sa用户密码(可去掉勾选强制实施密码策略)

  9. must be reducible node 错误

    "must be reducible node"错误通常是由于使用了无法转换为表达式树的代码或表达式. 场景再现:在项目中使用GroupBy的时候,对字段进行了类型转换,接下来正常 ...

  10. 关于Java中泛型的上界和下界理解

    既然聊到了泛型的上下界问题,就先给出几个类的继承关系吧 class Fruit{}class Apple extends Fruit{}class Orange extends Fruit{}clas ...