同步转码(边转边播)

最近更新时间:2025-06-17 20:27:42

我的收藏

简介

本文档提供关于同步转码(边转边播)的相关 API 概览以及 SDK 示例代码。
API
操作描述
生成边转边播的播放列表能够分析视频文件产出 m3u8文件。生成播放列表后即时播放,并根据播放进度实施按需转码,相比离线转码能极大减少了转码等待时间并大幅度降低了转码和存储开销。

生成播放列表任务

方法原型

func (s *CIService) CreateGeneratePlayListJob(ctx context.Context, opt *CreateGeneratePlayListJobOptions) (*CreateJobsResult, *Response, error)

参数说明

请参见 API 文档 中参数说明,与 SDK 字段一一对应。
type LiveTanscodeVideo struct {
Codec string `xml:"Codec"`
Width string `xml:"Width,omitempty"`
Height string `xml:"Height,omitempty"`
Fps string `xml:"Fps,omitempty"`
Profile string `xml:"Profile,omitempty"`
Bitrate string `xml:"Bitrate,omitempty"`
Gop string `xml:"Gop,omitempty"`
Maxrate string `xml:"Maxrate,omitempty"`
Crf string `xml:"Crf,omitempty"`
Pixfmt string `xml:"Pixfmt,omitempty"`
LongShortMode string `xml:"LongShortMode,omitempty"`
Interlaced string `xml:"Interlaced,omitempty"`
ColorParam *VideoColorParam `xml:"ColorParam,omitempty"`
}
type LiveTanscodeTransConfig struct {
InitialClipNum string `xml:"InitialClipNum,omitempty"`
CosTag string `xml:"CosTag,omitempty"`
HlsEncrypt *HlsEncrypt `xml:"HlsEncrypt,omitempty"`
}
type LiveTanscode struct {
Container *Container `xml:"Container,omitempty"`
Video *LiveTanscodeVideo `xml:"Video,omitempty"`
// TimeInterval *TimeInterval `xml:"TimeInterval,omitempty"`
// Audio *Audio `xml:"Audio,omitempty"`
TransConfig *LiveTanscodeTransConfig `xml:"TransConfig,omitempty"`
}
type GeneratePlayListJobOperation struct {
Tag string `xml:"Tag,omitempty"`
Output *JobOutput `xml:"Output,omitempty"`
MediaResult *MediaResult `xml:"MediaResult,omitempty"`
MediaInfo *MediaInfo `xml:"MediaInfo,omitempty"`
Transcode *LiveTanscode `xml:"Transcode,omitempty"`
UserData string `xml:"UserData,omitempty"`
JobLevel int `xml:"JobLevel,omitempty"`
Watermark []Watermark `xml:"Watermark,omitempty"`
WatermarkTemplateId []string `xml:"WatermarkTemplateId,omitempty"`
}
type CreateGeneratePlayListJobOptions struct {
XMLName xml.Name `xml:"Request"`
Tag string `xml:"Tag,omitempty"`
Input *JobInput `xml:"Input,omitempty"`
Operation *GeneratePlayListJobOperation `xml:"Operation,omitempty"`
QueueId string `xml:"QueueId,omitempty"`
QueueType string `xml:"QueueType,omitempty"`
CallBackFormat string `xml:"CallBackFormat,omitempty"`
CallBackType string `xml:"CallBackType,omitempty"`
CallBack string `xml:"CallBack,omitempty"`
CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"`
}

请求示例

// 将 examplebucket-1250000000 和 COS_REGION 修改为真实的信息
bu, _ := url.Parse("https://examplebucket-1250000000.cos.COS_REGION.myqcloud.com")
cu, _ := url.Parse("https://examplebucket-1250000000.ci.COS_REGION.myqcloud.com")
b := &cos.BaseURL{BucketURL: bu, CIURL: cu}
c := cos.NewClient(b, &http.Client{
Transport: &cos.AuthorizationTransport{
SecretID: os.Getenv("SECRETID"),
SecretKey: os.Getenv("SECRETKEY"),
},
})

createJobOpt := &cos.CreateGeneratePlayListJobOptions{
Tag: "GeneratePlayList",
Input: &cos.JobInput{
Object: "a.mp4",
},
Operation: &cos.GeneratePlayListJobOperation{
Output: &cos.JobOutput{
Region: "ap-chongqing",
Bucket: "test-1250000000",
Object: "live/a.m3u8",
},
Transcode: &cos.LiveTanscode{
Video: &cos.LiveTanscodeVideo{
Codec: "H.264",
Width: "960", // 设置480、720、960、1080
Bitrate: "2000",
Maxrate: "5000",
Fps: "30",
},
Container: &cos.Container{
Format: "hls",
ClipConfig: &cos.ClipConfig{
Duration: "5",
},
},
TransConfig: &cos.LiveTanscodeTransConfig{
// HlsEncrypt: &cos.HlsEncrypt{
// IsHlsEncrypt: true,
// },
InitialClipNum: "10",
CosTag: "a=a&b=b",
},
},
Watermark: []cos.Watermark{
{
Type: "Text",
LocMode: "Absolute",
Dx: "640",
Pos: "TopLeft",
Text: &cos.Text{
Text: "helloworld",
FontSize: "25",
FontType: "simfang.ttf",
FontColor: "0xff0000",
Transparency: "100",
},
},
},
},
}
createJobRes, _, err := c.CI.CreateGeneratePlayListJob(context.Background(), createJobOpt)
log_status(err)
fmt.Printf("%+v\\n", createJobRes.JobsDetail)

获取边转边播播放地址

获取未加密场景的播放地址

type URLToken struct {
SessionToken string `url:"x-cos-security-token,omitempty" header:"-"`
}

// https://github.com/tencentyun/cos-go-sdk-v5/blob/master/example/CI/media_process/livetranscode.go
func GetCOSDomainURL(tak string, tsk string, token *URLToken, appId string, bucketId string, region string, objectKey string) string {
u, _ := url.Parse("https://" + bucketId + ".cos." + region + ".myqcloud.com")
b := &cos.BaseURL{BucketURL: u}
c := cos.NewClient(b, &http.Client{
Transport: &cos.AuthorizationTransport{
SecretID: tak,
SecretKey: tsk,
SessionToken: token.SessionToken,
},
})
ctx := context.Background()
opt := &cos.PresignedURLOptions{
Query: &url.Values{},
Header: &http.Header{},
}
opt.Query.Add("ci-process", "getplaylist")
opt.Query.Add("signType", "cos")
opt.Query.Add("expires", "43200")
// opt.Query.Add("exper", "30") 试看时长
var signHost bool = true
// 获取预签名
presignedURL, err := c.Object.GetPresignedURL2(ctx, http.MethodGet, objectKey, time.Hour, opt, signHost)
if err != nil {
fmt.Printf("Error: %v\\n", err)
return ""
}
resultUrl := presignedURL.String()
return resultUrl
}

// CDN域名
func GetCDNDomainURL(cdn string, objectKey string) string {
url := cdn + "/" + objectKey
resultUrl := url + "?ci-process=getplaylist&signType=no"
return resultUrl
}

func main() {
// 替换成您的密钥
tak := os.Getenv("COS_SECRETID")
tsk := os.Getenv("COS_SECRETKEY")
token := &URLToken{
SessionToken: "",
}
// 替换成您的桶名称
appId := "1250000000"
// 替换成您的桶名称
bucketId := "test-1250000000"
// 替换成您桶所在的 region
region := "ap-chongqing"
// 替换成您需要播放的视频名称
objectKey := "live/a.m3u8"

playUrl := ""
playUrl = GetCOSDomainURL(tak, tsk, token, appId, bucketId, region, objectKey)
fmt.Println(playUrl)
// 替换为自己 cdn 域名
cdn := "http://abc.cdn.com"
playUrl = GetCDNDomainURL(cdn, objectKey)
fmt.Println(playUrl)
}

获取加密场景的播放地址

type URLToken struct {
SessionToken string `url:"x-cos-security-token,omitempty" header:"-"`
}

type JwtTokens struct {
// base info
Type string `json:"Type"`
AppId string `json:"AppId"`
BucketId string `json:"BucketId"`
Object string `json:"Object"`
Issuer string `json:"Issuer"`
// time info
IssuedTimeStamp int64 `json:"IssuedTimeStamp"`
ExpireTimeStamp int64 `json:"ExpireTimeStamp"`
// other info
Random int64 `json:"Random"`
// times info
UsageLimit int `json:"UsageLimit"`
// secret info
ProtectSchema string `json:"ProtectSchema"`
PublicKey string `json:"PublicKey"`
ProtectContentKey int `json:"ProtectContentKey"`
}
func (token JwtTokens) Valid() error {
return nil
}
// 生成jwt
func GenerateToken(appId string, bucketId string, objectKey string, secret []byte) (string, error) {
t := time.Now()
now := t.Unix()
payLoad := JwtTokens{
// 固定为 CosCiToken, 必填参数
Type: "CosCiToken",
// app id,必填参数
AppId: appId,
// 播放文件所在的 BucketId, 必填参数
BucketId: bucketId,
// 播放文件名
Object: url.QueryEscape(objectKey),
// 固定为 client,必填参数
Issuer: "client",
// token 颁发时间戳,必填参数
IssuedTimeStamp: now,
// token 过期时间戳,非必填参数,默认1天过期
ExpireTimeStamp: t.Add(time.Hour * 24 * 6).Unix(),
// token 使用次数限制,非必填参数,默认限制100次
UsageLimit: 20,
// 保护模式,填写为 rsa1024 ,则表示使用 RSA 非对称加密的方式保护,公私钥对长度为1024 bit
ProtectSchema: "rsa1024",
// 公钥。1024 bit 的 RSA 公钥,需使用 Base64进行编码
PublicKey: "xxx",
// 是否加密解密密钥(播放时解密 ts 视频流的密钥),1表示对解密密钥加密,0表示不对解密密钥加密。
ProtectContentKey: 0,
}
//使用指定的签名方法创建签名对象
token := jwt.NewWithClaims(jwt.SigningMethodHS256, payLoad)
//使用指定的 secret 签名并获得完成的编码后的字符串 token
return token.SignedString(secret)
}
// COS环境
func GetCOSDomainVideoEncryptionURL(tak string, tsk string, token *URLToken, bucketId string, region string, objectKey string, jwtToken string) string {
u, _ := url.Parse("https://" + bucketId + ".cos." + region + ".myqcloud.com")
b := &cos.BaseURL{BucketURL: u}
c := cos.NewClient(b, &http.Client{
Transport: &cos.AuthorizationTransport{
SecretID: tak,
SecretKey: tsk,
SessionToken: token.SessionToken,
},
})
ctx := context.Background()
opt := &cos.PresignedURLOptions{
Query: &url.Values{},
Header: &http.Header{},
}
opt.Query.Add("ci-process", "getplaylist")
opt.Query.Add("signType", "cos")
opt.Query.Add("expires", "43200")
// opt.Query.Add("exper", "30") 试看时长
opt.Query.Add("tokenType", "JwtToken")
opt.Query.Add("token", jwtToken)

var signHost bool = true
// 获取预签名
presignedURL, err := c.Object.GetPresignedURL2(ctx, http.MethodGet, objectKey, 10*time.Hour, opt, signHost)
if err != nil {
fmt.Printf("Error: %v\\n", err)
return ""
}
resultUrl := presignedURL.String()
return resultUrl
}

// CDN域名
func GetCDNDomainVideoEncryptionURL(cdn string, objectKey string, jwtToken string) string {
url := cdn + "/" + objectKey
resultUrl := url + "?ci-process=getplaylist&signType=no&expires=43200&&tokenType=JwtToken&token=" + jwtToken
return resultUrl
}

func main() {
// 替换成您的密钥
tak := os.Getenv("COS_SECRETID")
tsk := os.Getenv("COS_SECRETKEY")
token := &URLToken{
SessionToken: "",
}
// 替换成您的桶名称
appId := "1250000000"
// 替换成您的桶名称
bucketId := "test-1250000000"
// 替换成您桶所在的 region
region := "ap-chongqing"
// 替换成您需要播放的视频名称
objectKey := "live/a.m3u8"
// 替换为自己 cdn 域名
cdn := "http://abc.cdn.com"

// 替换为自己播放密钥,控制台可以查询
var playkey = []byte("aaaaaaaaaaa")
// 生成token
jwtToken, _ := GenerateToken(appId, bucketId, objectKey, playkey)
playUrl := ""
playUrl = GetCOSDomainVideoEncryptionURL(tak, tsk, token, bucketId, region, objectKey, jwtToken)
fmt.Println(playUrl)
playUrl = GetCDNDomainVideoEncryptionURL(cdn, objectKey, jwtToken)
fmt.Println(playUrl)
}

播放地址使用

请参见 COS 音视频播放器概述 选择合适的方式。

SDK 代码完整示例

请参见 GeneratePlayListDemo 获取完整示例。
注意:
执行代码前建议执行以下命令安装最新的第三方依赖库:
go get -u github.com/golang-jwt/jwt/v5