mirror of
https://github.com/NohamR/N_m3u8DL-RE.git
synced 2025-05-24 14:21:58 +00:00
95 lines
3.6 KiB
C#
95 lines
3.6 KiB
C#
using N_m3u8DL_RE.Common.Util;
|
|
using System.Security.Cryptography;
|
|
|
|
namespace Mp4SubtitleParser
|
|
{
|
|
public class ParsedMP4Info
|
|
{
|
|
public string? PSSH;
|
|
public string? KID;
|
|
public string? Scheme;
|
|
public bool isMultiDRM;
|
|
}
|
|
|
|
public class MP4InitUtil
|
|
{
|
|
private static readonly byte[] SYSTEM_ID_WIDEVINE = { 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED };
|
|
private static readonly byte[] SYSTEM_ID_PLAYREADY = { 0x9A, 0x04, 0xF0, 0x79, 0x98, 0x40, 0x42, 0x86, 0xAB, 0x92, 0xE6, 0x5B, 0xE0, 0x88, 0x5F, 0x95 };
|
|
|
|
public static ParsedMP4Info ReadInit(byte[] data)
|
|
{
|
|
var info = new ParsedMP4Info();
|
|
|
|
// parse init
|
|
new MP4Parser()
|
|
.Box("moov", MP4Parser.Children)
|
|
.Box("trak", MP4Parser.Children)
|
|
.Box("mdia", MP4Parser.Children)
|
|
.Box("minf", MP4Parser.Children)
|
|
.Box("stbl", MP4Parser.Children)
|
|
.FullBox("stsd", MP4Parser.SampleDescription)
|
|
.FullBox("pssh", (box) =>
|
|
{
|
|
if (!(box.Version == 0 || box.Version == 1))
|
|
throw new Exception("PSSH version can only be 0 or 1");
|
|
var systemId = box.Reader.ReadBytes(16);
|
|
if (SYSTEM_ID_WIDEVINE.SequenceEqual(systemId))
|
|
{
|
|
var dataSize = box.Reader.ReadUInt32();
|
|
var psshData = box.Reader.ReadBytes((int)dataSize);
|
|
info.PSSH = Convert.ToBase64String(psshData);
|
|
if (info.KID == "00000000000000000000000000000000")
|
|
{
|
|
info.KID = HexUtil.BytesToHex(psshData[2..18]).ToLower();
|
|
info.isMultiDRM = true;
|
|
}
|
|
}
|
|
})
|
|
.FullBox("encv", MP4Parser.AllData(data => ReadBox(data, info)))
|
|
.FullBox("enca", MP4Parser.AllData(data => ReadBox(data, info)))
|
|
.FullBox("enct", MP4Parser.AllData(data => ReadBox(data, info)))
|
|
.FullBox("encs", MP4Parser.AllData(data => ReadBox(data, info)))
|
|
.Parse(data, stopOnPartial: true);
|
|
|
|
return info;
|
|
}
|
|
|
|
private static void ReadBox(byte[] data, ParsedMP4Info info)
|
|
{
|
|
// find schm
|
|
var schmBytes = new byte[4] { 0x73, 0x63, 0x68, 0x6d };
|
|
var schmIndex = 0;
|
|
for (int i = 0; i < data.Length - 4; i++)
|
|
{
|
|
if (new byte[4] { data[i], data[i + 1], data[i + 2], data[i + 3] }.SequenceEqual(schmBytes))
|
|
{
|
|
schmIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
if (schmIndex + 8 < data.Length)
|
|
{
|
|
info.Scheme = System.Text.Encoding.UTF8.GetString(data[schmIndex..][8..12]);
|
|
}
|
|
|
|
// if (info.Scheme != "cenc") return;
|
|
|
|
// find KID
|
|
var tencBytes = new byte[4] { 0x74, 0x65, 0x6E, 0x63 };
|
|
var tencIndex = -1;
|
|
for (int i = 0; i < data.Length - 4; i++)
|
|
{
|
|
if (new byte[4] { data[i], data[i + 1], data[i + 2], data[i + 3] }.SequenceEqual(tencBytes))
|
|
{
|
|
tencIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
if (tencIndex != -1 && tencIndex + 12 < data.Length)
|
|
{
|
|
info.KID = HexUtil.BytesToHex(data[tencIndex..][12..28]).ToLower();
|
|
}
|
|
}
|
|
}
|
|
}
|