Golang视频流头部信息提取包使用指南

Golang视频流头部信息提取包使用指南 我需要从示例视频文件中获取视频头信息。是否有可用的包可以实现这个功能?我在下面的URL中找到了PESHeader方法(仅适用于PES)。有没有办法获取通用的头信息?

	newPacket := make([]byte, len(packet))
	copy(newPacket, packet)
	ccByte := newPacket[3]
	newCCByte := (ccByte & byte(0xf0)) | newCC
	newPacket[3] = newCCByte
	return newPacket, nil
}

// Returns a byte slice containing the PES header if the Packet contains one,
// otherwise returns an error
func PESHeader(packet Packet) ([]byte, error) {
	if badLen(packet) {
		return emptyByteSlice, gots.ErrInvalidPacketLength
	}
	if containsPayload(packet) && payloadUnitStartIndicator(packet) {
		dataOffset := payloadStart(packet)
		// A PES Header has a Packet Start Code Prefix of 0x000001
		if int(packet[dataOffset+0]) == 0 &&
			int(packet[dataOffset+1]) == 0 &&
			int(packet[dataOffset+2]) == 1 {
			start := payloadStart(packet)

更多关于Golang视频流头部信息提取包使用指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html

8 回复

感谢Lutzhorn

更多关于Golang视频流头部信息提取包使用指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我只能获取到头部同步字节(0X47)的详细信息。但我需要获取完整的头部信息0X471fff17。我没有找到读取头部详细信息的方法。是否有其他可用方法来实现这个需求?

你能提供一些能重现问题或更好解释问题的最小代码示例,或许再加个短视频吗?

从你的评论来看,似乎你只考虑单个字节,而实际上需要处理多个字节的情况…

我能够使用 pkt(0) 获取同步字节

package main

import (
    "fmt"
    "os"
    "github.com/Comcast/gots/packet"
)

func main() {
    pidSet := make(map[uint16]bool, 5) //创建一个容量为5对的空map[键类型]值类型
    filename := "C:/Users/PTS.ts"

    file, err := os.Open(filename)
    if err == nil {
        pkt := make([]byte, packet.PacketSize) //创建packetsize大小的空动态数组
        for read, err := file.Read(pkt); read > 0 && err == nil; read, err = file.Read(pkt) {
            if err != nil {
                println(err)
                return
            }
            pid, err := packet.Pid(pkt)
            if err != nil {
                println(err)
                continue
            }
            pidSet[pid] = true
        }

        for v := range pidSet {
            fmt.Printf("Found pid %d\n", v)
        }
    } else {
        fmt.Printf("Unable to open file [%s] due to [%s]\n", filename, err.Error())
    }
}

你是指 pkt[0] 吗?如果是这样,剩余的字节可能位于 pkt[1]pkt[2]pkt[3] 中。

此外,读取循环中的第一个 if err != nil {…} 永远不会触发,因为你只有在 err == nil 时才会进入循环体。

能否请你帮个忙,使用正确的 Markdown 格式来格式化你的代码?你有多种方式可以实现:

  1. 编写代码,选中它,然后点击编辑器工具栏中的 </> 按钮,
  2. 将所有代码额外缩进四个空格,
  3. 或者使用围栏式代码块:在代码开头使用至少三个反引号(`)或波浪号(~)的行,后跟可选的语言名称和换行符,代码块结束时使用仅包含相同数量反引号/波浪号和换行符的行。

在Go语言中,处理视频流头部信息提取可以使用标准库和一些第三方包。对于通用的视频头信息提取,推荐使用 github.com/abema/go-mp4 包来处理MP4格式,或 github.com/u2takey/ffmpeg-go 结合FFmpeg来获取多种格式的视频元数据。以下是一个使用 ffmpeg-go 提取视频头信息的示例:

package main

import (
	"context"
	"fmt"
	"log"

	ffmpeg "github.com/u2takey/ffmpeg-go"
)

func main() {
	// 指定视频文件路径
	inputPath := "example.mp4"

	// 使用ffmpeg-go执行probe命令获取视频流信息
	probe, err := ffmpeg.Probe(inputPath)
	if err != nil {
		log.Fatalf("Error probing video file: %v", err)
	}

	// 输出视频头信息(包括格式、流等元数据)
	fmt.Println("Video header information:")
	fmt.Println(probe)
}

对于更底层的处理,如您提到的PES头提取(常见于MPEG-TS流),可以使用 github.com/asticode/go-astits 包来解析MPEG传输流。以下是一个示例,展示如何从TS文件中读取包并检查PES头:

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/asticode/go-astits"
)

func main() {
	// 打开TS文件
	file, err := os.Open("example.ts")
	if err != nil {
		log.Fatalf("Error opening file: %v", err)
	}
	defer file.Close()

	// 创建demuxer
	dmx := astits.NewDemuxer(context.Background(), file)

	// 循环读取数据包
	for {
		// 读取下一个数据包
		pkt, err := dmx.NextPacket()
		if err != nil {
			log.Fatalf("Error reading packet: %v", err)
		}

		// 检查是否为PES包并包含有效负载
		if pkt.Header.PayloadUnitStartIndicator && pkt.Payload != nil {
			// 提取PES头:前三个字节应为0x000001
			if len(pkt.Payload) >= 3 && pkt.Payload[0] == 0x00 && pkt.Payload[1] == 0x00 && pkt.Payload[2] == 0x01 {
				fmt.Printf("Found PES header at packet PID: %d\n", pkt.Header.PID)
				// 这里可以进一步解析PES头细节,如流ID、PES包长度等
				break // 示例中仅处理第一个找到的PES头
			}
		}
	}
}

如果您需要处理特定格式(如MP4),可以使用 go-mp4 包来读取基础头信息:

package main

import (
	"fmt"
	"log"
	"os"

	mp4 "github.com/abema/go-mp4"
)

func main() {
	// 打开MP4文件
	file, err := os.Open("example.mp4")
	if err != nil {
		log.Fatalf("Error opening file: %v", err)
	}
	defer file.Close()

	// 解析MP4文件结构
	info, err := mp4.Probe(file)
	if err != nil {
		log.Fatalf("Error probing MP4 file: %v", err)
	}

	// 输出基础头信息,如时长、轨道等
	fmt.Printf("MP4 header info: %+v\n", info)
}

这些方法覆盖了从高层元数据提取到底层流解析的需求。根据您的视频格式(如MP4、TS等),选择相应的包来实现。

回到顶部