golang解析和生成Apple HLS M3U8播放列表插件库m3u8的使用

Golang解析和生成Apple HLS M3U8播放列表插件库m3u8的使用

关于m3u8库

这是一个用于解析和生成HTTP Live Streaming(Apple HLS)互联网视频传输中使用的M3U8播放列表的最完整的开源库。

主要特性包括:

  • 支持HLS协议版本5的规范
  • 解析和生成主播放列表(master-playlists)和媒体播放列表(media-playlists)
  • 自动检测输入流是主播放列表还是媒体播放列表
  • 提供保存播放列表元数据的结构
  • 支持与Verimatrix等DRM系统一起使用的加密密钥
  • 支持Google Widevine的非标准标签

安装

使用以下命令安装:

go get github.com/grafov/m3u8

示例代码

解析播放列表

f, err := os.Open("playlist.m3u8")
if err != nil {
    panic(err)
}
p, listType, err := m3u8.DecodeFrom(bufio.NewReader(f), true)
if err != nil {
    panic(err)
}
switch listType {
case m3u8.MEDIA:
    mediapl := p.(*m3u8.MediaPlaylist)
    fmt.Printf("%+v\n", mediapl)
case m3u8.MASTER:
    masterpl := p.(*m3u8.MasterPlaylist)
    fmt.Printf("%+v\n", masterpl)
}

解析后你会得到填充了数据的结构体。对于主播放列表,你会得到包含指向Variant结构体指针切片的Master结构体(表示每个比特率的播放列表)。对于媒体播放列表,解析器返回包含Segments切片的MediaPlaylist结构体。

生成媒体播放列表

p, e := m3u8.NewMediaPlaylist(3, 10) // 窗口大小为3,容量为10
if e != nil {
    panic(fmt.Sprintf("创建媒体播放列表失败: %s", e))
}
for i := 0; i < 5; i++ {
    e = p.Append(fmt.Sprintf("test%d.ts", i), 6.0, "")
    if e != nil {
        panic(fmt.Sprintf("添加第%d段到媒体播放列表失败: %s", i, e))
    }
}
fmt.Println(p.Encode().String())

自定义标签

m3u8支持解析和写入自定义标签。你需要为播放列表中可能遇到的每个自定义标签实现CustomTagCustomDecoder接口。可以参考example/template/中的模板文件来了解如何解析自定义播放列表和段标签。

库结构

该库代码紧凑,包含三个主要文件:

  • structure.go - 声明与播放列表及其属性相关的所有结构
  • reader.go - 播放列表解析器方法
  • writer.go - 播放列表生成器方法

每个文件都有相应的测试文件*_test.go

项目状态

该项目支持已暂停,代码已移至只读存档。不过它仍然是一个功能完整的M3U8解析和生成库。

替代方案

在2013年项目开始时,Go中还没有其他m3u8库。后来出现了一些替代方案,其中一些可能更适合当前标准:

如果你知道其他相关项目,可以在issue中提供链接。

其他语言的M3U8解析/生成实现

如果你需要其他语言的实现,可以参考:


更多关于golang解析和生成Apple HLS M3U8播放列表插件库m3u8的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang解析和生成Apple HLS M3U8播放列表插件库m3u8的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用golang解析和生成Apple HLS M3U8播放列表

在Go语言中处理HLS (HTTP Live Streaming) M3U8播放列表,可以使用第三方库github.com/grafov/m3u8。这个库提供了完整的M3U8解析和生成功能,支持HLS协议的各种特性。

安装

首先安装m3u8库:

go get github.com/grafov/m3u8

解析M3U8播放列表

解析主播放列表(Master Playlist)

package main

import (
	"fmt"
	"os"
	
	"github.com/grafov/m3u8"
)

func main() {
	// 读取M3U8文件
	file, err := os.Open("master.m3u8")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	// 解析播放列表
	p, listType, err := m3u8.DecodeFrom(file, true)
	if err != nil {
		panic(err)
	}

	switch listType {
	case m3u8.MASTER:
		masterpl := p.(*m3u8.MasterPlaylist)
		fmt.Printf("Master Playlist with %d variants:\n", len(masterpl.Variants))
		for _, variant := range masterpl.Variants {
			fmt.Printf("URI: %s, Bandwidth: %d, Resolution: %s\n", 
				variant.URI, variant.Bandwidth, variant.Resolution)
		}
	case m3u8.MEDIA:
		mediapl := p.(*m3u8.MediaPlaylist)
		fmt.Printf("Media Playlist with %d segments, target duration %.2f\n", 
			mediapl.Count(), mediapl.TargetDuration)
	default:
		fmt.Println("Unknown playlist type")
	}
}

解析媒体播放列表(Media Playlist)

func parseMediaPlaylist() {
	file, err := os.Open("media.m3u8")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	p, _, err := m3u8.DecodeFrom(file, true)
	if err != nil {
		panic(err)
	}

	mediapl := p.(*m3u8.MediaPlaylist)
	fmt.Printf("Playlist is %s\n", mediapl.ListType)
	fmt.Printf("Target duration: %.2f seconds\n", mediapl.TargetDuration)
	fmt.Printf("Sequence starts at: %d\n", mediapl.SeqNo)
	fmt.Printf("Segment count: %d\n", mediapl.Count())

	for i, seg := range mediapl.Segments {
		if seg != nil {
			fmt.Printf("Segment %d: %s (%.2f sec)\n", i, seg.URI, seg.Duration)
		}
	}
}

生成M3U8播放列表

创建主播放列表

func createMasterPlaylist() {
	// 创建主播放列表
	masterpl := m3u8.NewMasterPlaylist()

	// 添加变体流
	variant := &m3u8.Variant{
		URI:        "video_800k.m3u8",
		Bandwidth:  800000,
		Resolution: "640x360",
	}
	masterpl.Append("video_800k.m3u8", variant, "")

	variant = &m3u8.Variant{
		URI:        "video_1200k.m3u8",
		Bandwidth:  1200000,
		Resolution: "854x480",
	}
	masterpl.Append("video_1200k.m3u8", variant, "")

	// 输出播放列表
	fmt.Println(masterpl.String())
}

创建媒体播放列表

func createMediaPlaylist() {
	// 创建媒体播放列表,容量为10个片段
	mediapl, err := m3u8.NewMediaPlaylist(10, 10)
	if err != nil {
		panic(err)
	}

	// 设置播放列表属性
	mediapl.TargetDuration = 6.0
	mediapl.SeqNo = 1
	mediapl.Live = false

	// 添加媒体片段
	mediapl.Append("segment1.ts", 5.0, "")
	mediapl.Append("segment2.ts", 5.5, "")
	mediapl.Append("segment3.ts", 6.0, "")

	// 关闭播放列表(对于VOD很重要)
	mediapl.Close()

	// 输出播放列表
	fmt.Println(mediapl.String())
}

高级功能

添加EXT-X-KEY加密信息

func addEncryption(mediapl *m3u8.MediaPlaylist) {
	key := &m3u8.Key{
		Method:            "AES-128",
		URI:               "https://example.com/key.bin",
		IV:                "0x1234567890ABCDEF1234567890ABCDEF",
		Keyformat:         "identity",
		Keyformatversions: "1",
	}
	mediapl.Key = key
}

添加EXT-X-DISCONTINUITY标记

func addDiscontinuity(mediapl *m3u8.MediaPlaylist) {
	mediapl.Append("segment_new.ts", 5.0, "")
	mediapl.Discontinuity()
	mediapl.Append("segment_after_discontinuity.ts", 5.0, "")
}

添加EXT-X-MAP初始化段

func addMap(mediapl *m3u8.MediaPlaylist) {
	mapTag := &m3u8.Map{
		URI:    "init.mp4",
		Limit:  1024,
		Offset: 0,
	}
	mediapl.Map = mapTag
}

注意事项

  1. 对于直播流,需要定期更新播放列表并设置Live = true
  2. 点播流(VOD)需要调用Close()方法
  3. 确保TargetDuration大于或等于所有片段的最大持续时间
  4. 处理加密内容时,确保密钥服务器可访问

这个库提供了完整的HLS M3U8处理能力,可以满足大多数流媒体应用的需求。更多高级用法可以参考库的文档和HLS协议规范。

回到顶部