Created
February 25, 2024 02:10
-
-
Save Diniboy1123/a865ebbd3ee0bd86c506574b4467aea7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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