Skip to content

Instantly share code, notes, and snippets.

@Diniboy1123
Created February 25, 2024 02:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Diniboy1123/a865ebbd3ee0bd86c506574b4467aea7 to your computer and use it in GitHub Desktop.
Save Diniboy1123/a865ebbd3ee0bd86c506574b4467aea7 to your computer and use it in GitHub Desktop.
package main
import (
"bytes"
"encoding/base64"
"encoding/hex"
"log"
"os"
"regexp"
"unicode/utf16"
"github.com/Eyevinn/mp4ff/mp4"
)
var (
PlayReadyRegexp = regexp.MustCompile(`^.+<KID>([^<]+)</KID>.+$`)
)
// function shamefully stolen from https://github.com/canalplus/DashMe/blob/f1f0bfa654ac1dedb2bf7ffbf8c75772084ae426/src/parser/SmoothDemuxer.go#L309-L334
func extractKeyId(data []byte) []byte {
/* Convert utf16 to usable byte array */
shorts := make([]uint16, len(data)/2-5)
for i := 0; i < len(data)-10; i += 2 {
shorts[(i)/2] = (uint16(data[i+11]) << 8) | uint16(data[i+10])
}
bytes, err := base64.StdEncoding.DecodeString(PlayReadyRegexp.FindStringSubmatch(string(utf16.Decode(shorts)))[1])
if err != nil {
return nil
}
/* Encode string in hex and convert from GUID to UUID */
key := hex.EncodeToString(bytes)
res, err := hex.DecodeString(string([]uint8{
key[6], key[7], key[4], key[5], key[2], key[3], key[0], key[1],
key[10], key[11], key[8], key[9],
key[14], key[15], key[12], key[13],
key[16], key[17], key[18], key[19],
key[20], key[21], key[22], key[23], key[24], key[25],
key[26], key[27], key[28], key[29], key[30], key[31],
}))
if err != nil {
return nil
}
return res
}
func main() {
codecPrivateData, _ := hex.DecodeString("00000001674d40209e52820276028404040500000300010000030064e000057e000afc3f13e0a00000000168ef7520")
delimiter := []byte{0, 0, 0, 1}
split := bytes.SplitN(codecPrivateData, delimiter, 3)
if len(split) != 3 {
log.Fatal("invalid codecPrivateData")
}
spsNALUs := [][]byte{split[1]}
ppsNALUs := [][]byte{split[2]}
pssh := "XAMAAAEAAQBSAzwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4ANABSAHAAbABiACsAVABiAE4ARQBTADgAdABHAGsATgBGAFcAVABFAEgAQQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBLAEwAagAzAFEAegBRAFAALwBOAEEAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APABMAEEAXwBVAFIATAA+AGgAdAB0AHAAcwA6AC8ALwBwAHIAbwBmAGYAaQBjAGkAYQBsAHMAaQB0AGUALgBrAGUAeQBkAGUAbABpAHYAZQByAHkALgBtAGUAZABpAGEAcwBlAHIAdgBpAGMAZQBzAC4AdwBpAG4AZABvAHcAcwAuAG4AZQB0AC8AUABsAGEAeQBSAGUAYQBkAHkALwA8AC8ATABBAF8AVQBSAEwAPgA8AEMAVQBTAFQATwBNAEEAVABUAFIASQBCAFUAVABFAFMAPgA8AEkASQBTAF8ARABSAE0AXwBWAEUAUgBTAEkATwBOAD4AOAAuADEALgAyADMAMAA0AC4AMwAxADwALwBJAEkAUwBfAEQAUgBNAF8AVgBFAFIAUwBJAE8ATgA+ADwALwBDAFUAUwBUAE8ATQBBAFQAVABSAEkAQgBVAFQARQBTAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA="
psshByte, err := base64.StdEncoding.DecodeString(pssh)
if err != nil {
log.Fatal(err)
}
psshBox := mp4.PsshBox{
SystemID: mp4.UUID{0x9a, 0x04, 0xf0, 0x79, 0x48, 0x5b, 0x48, 0x5a, 0x8b, 0x6a, 0x4f, 0x14, 0x8f, 0x17, 0x9a, 0x17},
Data: psshByte,
}
keyId := extractKeyId(psshByte)
log.Printf("KeyId: %x", keyId)
videoTimescale := uint32(10000000)
init := mp4.CreateEmptyInit()
init.AddEmptyTrack(videoTimescale, "video", "und")
trak := init.Moov.Trak
err = trak.SetAVCDescriptor("avc1", spsNALUs, ppsNALUs, true)
if err != nil {
log.Fatal(err)
}
width := trak.Mdia.Minf.Stbl.Stsd.AvcX.Width
height := trak.Mdia.Minf.Stbl.Stsd.AvcX.Height
log.Printf("Width: %d, Height: %d", width, height)
_, err = mp4.InitProtect(init, nil, nil, "cenc", keyId, []*mp4.PsshBox{&psshBox})
if err != nil {
log.Fatal(err)
}
outFile, err := os.Create("init.mp4")
if err != nil {
log.Fatal(err)
}
defer outFile.Close()
err = init.Encode(outFile)
if err != nil {
log.Fatal(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment