go - 如何使用 Pion/Webrtc 将 VP8 帧间转换为图像?
问题描述
我在Pion/Webrtc 示例中尝试了将 VP8 视频流转换为 jpeg 的快照示例。
它运行良好,但不包括帧间。我修复它时显示一条错误消息。
vp8:Golden / AltRef 框架未实现。
这个错误来自golang 的 vp8 包。
修改后的代码如下图:
if !videoKeyframe {
decoder.Init(bytes.NewReader(sample.Data), len(sample.Data))
_, err := decoder.DecodeFrameHeader()
if err != nil {
fmt.Printf("Header Error: %s\n", err)
continue
}
_, err2 := decoder.DecodeFrame()
if err2 != nil {
fmt.Printf("DecodeFrame Error: %s\n", err2)
continue
}
}
我还尝试修改 gstreamer-receive 示例。但是我很难用C做。
无论如何可以轻松地将 interframe 转换为 jpeg 吗?
解决方案
最后,我用libvpx-go解决了
我修改了代码,如下所示。
package main
import (
"bytes"
"fmt"
"image/jpeg"
// "log"
"os"
"github.com/pion/rtp"
"github.com/pion/rtp/codecs"
"github.com/pion/webrtc/v3/pkg/media/samplebuilder"
"github.com/xlab/libvpx-go/vpx"
)
// type Frame struct {
// *image.RGBA
// Timecode time.Duration
// IsKeyframe bool
// }
type VDecoder struct {
enabled bool
src <-chan *rtp.Packet
ctx *vpx.CodecCtx
iface *vpx.CodecIface
}
type VCodec string
const (
CodecVP8 VCodec = "V_VP8"
CodecVP9 VCodec = "V_VP9"
CodecVP10 VCodec = "V_VP10"
)
func NewVDecoder(codec VCodec, src <-chan *rtp.Packet) *VDecoder {
dec := &VDecoder{
src: src,
ctx: vpx.NewCodecCtx(),
}
switch codec {
case CodecVP8:
dec.iface = vpx.DecoderIfaceVP8()
case CodecVP9:
dec.iface = vpx.DecoderIfaceVP9()
default: // others are currently disabled
log.Println("[WARN] unsupported VPX codec:", codec)
return dec
}
err := vpx.Error(vpx.CodecDecInitVer(dec.ctx, dec.iface, nil, 0, vpx.DecoderABIVersion))
if err != nil {
log.Println("[WARN]", err)
return dec
}
dec.enabled = true
return dec
}
func (v *VDecoder) Save(savePath string) { //, out chan<- Frame
// defer close(out)
i := 0
sampleBuilder := samplebuilder.New(20000, &codecs.VP8Packet{}, 90000)
for pkt := range v.src {
sampleBuilder.Push(pkt)
// Use SampleBuilder to generate full picture from many RTP Packets
sample := sampleBuilder.Pop()
if sample == nil {
continue
}
if !v.enabled {
continue
}
dataSize := uint32(len(sample.Data))
err := vpx.Error(vpx.CodecDecode(v.ctx, string(sample.Data), dataSize, nil, 0))
if err != nil {
log.Println("[WARN]", err)
continue
}
var iter vpx.CodecIter
img := vpx.CodecGetFrame(v.ctx, &iter)
if img != nil {
img.Deref()
// out <- Frame{
// RGBA: img.ImageRGBA(),
// Timecode: time.Duration(pkt.Timestamp),
// }
i++
buffer := new(bytes.Buffer)
if err = jpeg.Encode(buffer, img.ImageYCbCr(), nil); err != nil {
// panic(err)
fmt.Printf("jpeg Encode Error: %s\r\n", err)
}
fo, err := os.Create(fmt.Sprintf("%s%d%s", savePath, i, ".jpg"))
if err != nil {
fmt.Printf("image create Error: %s\r\n", err)
//panic(err)
}
// close fo on exit and check for its returned error
defer func() {
if err := fo.Close(); err != nil {
panic(err)
}
}()
if _, err := fo.Write(buffer.Bytes()); err != nil {
fmt.Printf("image write Error: %s\r\n", err)
//panic(err)
}
fo.Close()
}
}
}
只需添加 2 行代码即可保存连续图像
vd := NewVDecoder(CodecVP8, rtpChan)
go vd.Save("/ramdisk/image_seq/xxx")
享受!
PS运行前别忘了安装 libvpx-go 的依赖go get
,并确保 libvpx 的版本是1.8
推荐阅读
- python-3.x - 如何在 PyCharm 中安装库?
- php - laravel 6和ajax中加载更多按钮的问题
- python - RelatedObjectDoesNotExist:用户没有卖家
- audio - 仅播放来自 youtube-dl 的 M3U8 文件中的音频 ts 流
- spring-boot - 在springboot的OAuth2框架中区分来自不同客户端的请求
- c++ - 如何将多个变量读入一个节点?
- java - JavaFX WebView:自定义光标不起作用?
- macos - 如何在 SwiftUI 中将进度指示器与标签右侧对齐并保持标签居中在 VStack 中?
- gradle - No value has been specified for property 'mainClassName' in shadowJar
- groovy - Reactive streams map operator never getting executed