Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与

2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与

作者头像
福大大架构师每日一题
发布于 2023-06-08 07:34:22
发布于 2023-06-08 07:34:22
50600
代码可运行
举报
运行总次数:0
代码可运行

2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与开发体验。

答案2023-04-01:

步骤如下:

1.导入必要的依赖库,包括 fmt、os、unsafe 和其它 FFmpeg 库相关的 Go 库。

2.定义一个名为 main0() 的函数,该函数负责视频解码操作。在函数中定义了许多变量,例如文件名、编解码器、解析器、编解码器上下文、文件句柄、AVFrame 等等。

3.通过命令行参数获取输入文件名和输出文件名,并进行一些基本的参数检查。

4.通过调用 AvPacketAlloc() 函数创建一个 AVPacket 对象,用于存储解码后的帧数据。如果创建失败,则退出程序。

5.初始化输入缓冲区 inbuf 并设置结尾填充字节为 0。

6.调用 AvcodecFindDecoder() 函数查找 MPEG-1 视频解码器。如果找不到,则退出程序。

7.调用 AvParserInit() 函数初始化解析器。如果初始化失败,则退出程序。

8.调用 AvCodecAllocContext3() 函数分配一个新的编解码器上下文对象。如果分配失败,则退出程序。

9.调用 AvcodecOpen2() 函数打开编解码器。如果打开失败,则退出程序。

10.打开输入文件,并创建一个 AVFrame 对象。

11.进入循环,读取输入文件并将其分解成视频帧。如果读取失败或读取完毕,则跳出循环。

12.调用 AvParserParse2() 函数将输入缓冲区中的数据解析为视频帧,并存储在 AVPacket 对象中。如果解析失败,则退出程序。

13.如果成功解析到一个视频帧,则调用 decode() 函数对其进行解码并保存到输出文件中。

14.在循环结束后,调用 decode() 函数对剩余的数据进行解码并保存到输出文件中。

15.关闭输入文件句柄、解析器、编解码器上下文和 AVFrame 对象等资源,以避免内存泄漏。

16.定义一个名为 pgm_save() 的函数,该函数用于将视频帧写入 PGM 格式文件。

17.定义一个名为 decode() 的函数,该函数用于对视频帧进行解码并调用 pgm_save() 函数将其写入 PGM 格式文件。

18.定义 main() 函数,该函数将 FFmpeg 库的路径设置为当前目录下的 lib 子目录,并调用 main0() 函数进行视频解码操作。

注意:在 Windows 操作系统中,您可能需要将 FFmpeg 库的可执行文件添加到 PATH 环境变量中,或者使用 SetXXXPath() 函数设置它们的路径,才能够正常运行此代码。

代码见github/moonfdd/ffmpeg-go。

执行命令:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
./lib/ffmpeg -i ./resources/big_buck_bunny.mp4 -c:v mpeg1video ./out/big_buck_bunny.mpg

go run ./examples/internalexamples/decode_video/main.go ./out/big_buck_bunny.mpg ./out/ppm/big_buck_bunny.yuv

./lib/ffplay  ./out/ppm/big_buck_bunny.yuv-113.ppm

golang代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
  "fmt"
  "os"
  "unsafe"

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

func main0() (ret ffcommon.FInt) {
  var filename, outfilename string
  var codec *libavcodec.AVCodec
  var parser *libavcodec.AVCodecParserContext
  var c *libavcodec.AVCodecContext
  var f *os.File
  var frame *libavutil.AVFrame
  var inbuf [INBUF_SIZE + libavcodec.AV_INPUT_BUFFER_PADDING_SIZE]ffcommon.FUint8T
  var data *ffcommon.FUint8T
  var data_size ffcommon.FSizeT
  var pkt *libavcodec.AVPacket

  if len(os.Args) <= 2 {
    fmt.Printf("Usage: %s <input file> <output file>\nAnd check your input file is encoded by mpeg1video please.\n", os.Args[0])
    os.Exit(0)
  }
  filename = os.Args[1]
  outfilename = os.Args[2]

  pkt = libavcodec.AvPacketAlloc()
  if pkt == nil {
    os.Exit(1)
  }

  /* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */
  //memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);

  /* find the MPEG-1 video decoder */
  codec = libavcodec.AvcodecFindDecoder(libavcodec.AV_CODEC_ID_MPEG1VIDEO)
  if codec == nil {
    fmt.Printf("Codec not found\n")
    os.Exit(1)
  }

  parser = libavcodec.AvParserInit(int32(codec.Id))
  if parser == nil {
    fmt.Printf("parser not found\n")
    os.Exit(1)
  }

  c = codec.AvcodecAllocContext3()
  if c == nil {
    fmt.Printf("Could not allocate video codec context\n")
    os.Exit(1)
  }

  /* For some codecs, such as msmpeg4 and mpeg4, width and height
     MUST be initialized there because this information is not
     available in the bitstream. */

  /* open it */
  if c.AvcodecOpen2(codec, nil) < 0 {
    fmt.Printf("Could not open codec\n")
    os.Exit(1)
  }

  var err error
  f, err = os.Open(filename)
  if err != nil {
    fmt.Printf("Could not open %s,err = %s\n", filename, err)
    os.Exit(1)
  }

  frame = libavutil.AvFrameAlloc()
  if frame == nil {
    fmt.Printf("Could not allocate video frame\n")
    os.Exit(1)
  }

  for {
    /* read raw data from the input file */
    var n int
    n, err = f.Read(inbuf[:INBUF_SIZE])
    if err != nil {
      break
    }
    data_size = uint64(n)
    if data_size == 0 {
      break
    }

    /* use the parser to split the data into frames */
    data = (*byte)(unsafe.Pointer(&inbuf))
    for data_size > 0 {
      ret = parser.AvParserParse2(c, &pkt.Data, (*int32)(unsafe.Pointer(&pkt.Size)),
        data, int32(data_size), libavutil.AV_NOPTS_VALUE, libavutil.AV_NOPTS_VALUE, 0)
      if ret < 0 {
        fmt.Printf("Error while parsing\n")
        os.Exit(1)
      }
      data = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(data)) + uintptr(ret)))
      data_size -= uint64(ret)

      if pkt.Size != 0 {
        decode(c, frame, pkt, outfilename)
      }
    }
  }

  /* flush the decoder */
  decode(c, frame, nil, outfilename)

  f.Close()

  parser.AvParserClose()
  libavcodec.AvcodecFreeContext(&c)
  libavutil.AvFrameFree(&frame)
  libavcodec.AvPacketFree(&pkt)

  return 0
}

const INBUF_SIZE = 4096

func pgm_save(buf ffcommon.FBuf, wrap, xsize, ysize ffcommon.FInt, filename string) {
  var f *os.File
  var i ffcommon.FInt

  var err error
  f, err = os.Create(filename)
  if err != nil {
    return
  }
  f.WriteString(fmt.Sprintf("P5\n%d %d\n%d\n", xsize, ysize, 255))
  bytes := []byte{}
  for i = 0; i < ysize; i++ {
    for j := int32(0); j < xsize; j++ {
      bytes = append(bytes, *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(buf)) + uintptr(i*wrap+j))))
    }
  }
  f.Write(bytes)
  f.Close()
}

func decode(dec_ctx *libavcodec.AVCodecContext, frame *libavutil.AVFrame, pkt *libavcodec.AVPacket, filename string) {
  // var buf [1024]byte
  var ret ffcommon.FInt

  ret = dec_ctx.AvcodecSendPacket(pkt)
  if ret < 0 {
    fmt.Printf("Error sending a packet for decoding\n")
    os.Exit(1)
  }

  for ret >= 0 {
    ret = dec_ctx.AvcodecReceiveFrame(frame)
    if ret == -libavutil.EAGAIN || ret == libavutil.AVERROR_EOF {
      return
    } else if ret < 0 {
      fmt.Printf("Error during decoding %d\n", ret)
      os.Exit(1)
    }

    fmt.Printf("saving frame %3d\n", dec_ctx.FrameNumber)
    //fflush(stdout)

    /* the picture is allocated by the decoder. no need to
       free it */
    pgm_save(frame.Data[0], frame.Linesize[0],
      frame.Width, frame.Height, fmt.Sprintf("%s-%d.ppm", filename, dec_ctx.FrameNumber))
  }
}

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

  main0()
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-04-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 福大大架构师每日一题 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与开发体验。
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与开发体验。
福大大架构师每日一题
2023/04/01
8030
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与开发体验。
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
福大大架构师每日一题
2023/06/08
3090
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
福大大架构师每日一题
2023/03/30
4540
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
福大大架构师每日一题
2023/04/12
5170
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频分离解码技巧。
福大大架构师每日一题
2023/06/08
7140
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频分离解码技巧。
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频分离解码技巧。
福大大架构师每日一题
2023/04/05
1.6K0
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频分离解码技巧。
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
福大大架构师每日一题
2023/04/06
3820
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
2023-04-09:使用 Golang 重写的 ffmpeg 示例encode_video.c,实现视频编码并将编码后的数据封装为容器格式,最终写入输出文件。
2023-04-09:使用 Golang 重写的 ffmpeg 示例encode_video.c,实现视频编码并将编码后的数据封装为容器格式,最终写入输出文件。
福大大架构师每日一题
2023/04/09
4700
2023-04-09:使用 Golang 重写的 ffmpeg 示例encode_video.c,实现视频编码并将编码后的数据封装为容器格式,最终写入输出文件。
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
福大大架构师每日一题
2023/06/08
2650
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
福大大架构师每日一题
2023/06/08
2990
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
2022-04-24:用go语言重写ffmpeg的muxing.c示例。
总体上,本程序实现了将虚假音频和视频数据编码成指定格式并写入输出文件的功能。其中,步骤 2 的主要作用是为音频和视频流创建必要的对象和参数,以便后续进行编码和写入;步骤 3 和 4 则是生成虚假数据并进行编码和写入的具体实现。
福大大架构师每日一题
2023/04/24
3770
2023-02-28:moonfdd/ffmpeg-go是用go语言绑定ffmpeg的库,目前是github上最好用的库。请用go语言将yuv文件编码为h264
2023-02-28:moonfdd/ffmpeg-go是用go语言绑定ffmpeg的库,目前是github上最好用的库。请用go语言将yuv文件编码为h264文件。
福大大架构师每日一题
2023/02/28
8080
2023-02-28:moonfdd/ffmpeg-go是用go语言绑定ffmpeg的库,目前是github上最好用的库。请用go语言将yuv文件编码为h264
2023-03-03:请用go语言调用ffmpeg,摄像头捕获并编码为h264文件,不管音频。
2023-03-03:请用go语言调用ffmpeg,摄像头捕获并编码为h264文件,不管音频。
福大大架构师每日一题
2023/03/03
4860
2023-03-03:请用go语言调用ffmpeg,摄像头捕获并编码为h264文件,不管音频。
2023-02-22:请用go语言调用ffmpeg,保存mp4文件的视频帧,每帧用ppm图片保存。
2023-02-22:请用go语言调用ffmpeg,保存mp4文件的视频帧,每帧用ppm图片保存。
福大大架构师每日一题
2023/02/22
5460
2023-02-22:请用go语言调用ffmpeg,保存mp4文件的视频帧,每帧用ppm图片保存。
2023-02-23:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420P格式文件。
2023-02-23:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420P格式文件。
福大大架构师每日一题
2023/02/23
3360
2023-02-23:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420P格式文件。
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Inte
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Intel Quick Sync Video 等)对视频进行解码,从而提高解码效率和性能。在进行硬件加速解码时,相较于 CPU 的软件解码方式,GPU 可以利用其并行处理能力和更高的带宽进行更高效的解码操作。请用go语言改写hw_decode.c文件。
福大大架构师每日一题
2023/06/09
8070
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Inte
2023-03-19:使用Go语言和FFmpeg库实现pcm编码为mp3。
本文将介绍如何使用Go语言和FFmpeg库实现PCM音频文件编码为MP3格式。我们将使用moonfdd/ffmpeg-go库,并在Windows 10 64位操作系统下完成本次实验。
福大大架构师每日一题
2023/03/19
6760
2023-03-19:使用Go语言和FFmpeg库实现pcm编码为mp3。
2023-02-25:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420SP格式文件,YUV420P不要转换成YUV420SP。
2023-02-25:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420SP格式文件,YUV420P不要转换成YUV420SP。
福大大架构师每日一题
2023/02/25
3390
2023-03-17:使用Go语言和FFmpeg库实现音频重采样解码,并将其保存为PCM格式的文件。
2023-03-17:使用Go语言和FFmpeg库实现音频重采样解码,并将其保存为PCM格式的文件。
福大大架构师每日一题
2023/03/17
2K0
2023-03-17:使用Go语言和FFmpeg库实现音频重采样解码,并将其保存为PCM格式的文件。
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Intel Quick Sync Vid
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Intel Quick Sync Video 等)对视频进行解码,从而提高解码效率和性能。在进行硬件加速解码时,相较于 CPU 的软件解码方式,GPU 可以利用其并行处理能力和更高的带宽进行更高效的解码操作。请用go语言改写hw_decode.c文件。
福大大架构师每日一题
2023/04/18
9800
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Intel Quick Sync Vid
推荐阅读
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与开发体验。
8030
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
3090
2023-03-30:用Go语言改写FFmpeg示例decode_audio.c,实现高效音频解码。
4540
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
5170
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频
7140
2023-04-04:使用 Golang 和 ffmpeg-go 库实现 demuxing_decoding.c,轻松掌握音视频分离解码技巧。
1.6K0
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
3820
2023-04-09:使用 Golang 重写的 ffmpeg 示例encode_video.c,实现视频编码并将编码后的数据封装为容器格式,最终写入输出文件。
4700
2023-04-12:使用 Go 重写 FFmpeg 的 extract_mvs.c 工具程序,提取视频中的运动矢量信息。
2650
2023-04-06:拥抱Golang,优化FFmpeg音频编码器,探究encode_audio.c的内部结构。
2990
2022-04-24:用go语言重写ffmpeg的muxing.c示例。
3770
2023-02-28:moonfdd/ffmpeg-go是用go语言绑定ffmpeg的库,目前是github上最好用的库。请用go语言将yuv文件编码为h264
8080
2023-03-03:请用go语言调用ffmpeg,摄像头捕获并编码为h264文件,不管音频。
4860
2023-02-22:请用go语言调用ffmpeg,保存mp4文件的视频帧,每帧用ppm图片保存。
5460
2023-02-23:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420P格式文件。
3360
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Inte
8070
2023-03-19:使用Go语言和FFmpeg库实现pcm编码为mp3。
6760
2023-02-25:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420SP格式文件,YUV420P不要转换成YUV420SP。
3390
2023-03-17:使用Go语言和FFmpeg库实现音频重采样解码,并将其保存为PCM格式的文件。
2K0
2023-04-18:ffmpeg中的hw_decode.c的功能是通过使用显卡硬件加速器(如 NVIDIA CUDA、Intel Quick Sync Vid
9800
相关推荐
2023-04-01:当Go语言遇见FFmpeg视频解码器,使用Go语言改写decode_video.c文件,提升视频解码效率与开发体验。
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验