`MSS`修正`TrackId`后应重新解密

This commit is contained in:
nilaoda 2022-11-28 22:21:16 +08:00
parent 386c2bb46a
commit 0b19fd0f3a
5 changed files with 73 additions and 18 deletions

View File

@ -288,9 +288,9 @@ namespace N_m3u8DL_RE.Common.Resource
),
["cmd_customHLSMethod"] = new TextContainer
(
zhCN: "指定HLS加密方式 (AES_128|AES_128_ECB|CENC|CHACHA20|NONE|SAMPLE_AES|SAMPLE_AES_CTR|UNKNOWN)",
zhTW: "指定HLS加密方式 (AES_128|AES_128_ECB|CENC|CHACHA20|NONE|SAMPLE_AES|SAMPLE_AES_CTR|UNKNOWN)",
enUS: "Set HLS encryption method (AES_128|AES_128_ECB|CENC|CHACHA20|NONE|SAMPLE_AES|SAMPLE_AES_CTR|UNKNOWN)"
zhCN: "指定HLS加密方式 (AES_128|AES_128_ECB|CENC|PLAYREADY|CHACHA20|NONE|SAMPLE_AES|SAMPLE_AES_CTR|UNKNOWN)",
zhTW: "指定HLS加密方式 (AES_128|AES_128_ECB|CENC|PLAYREADY|CHACHA20|NONE|SAMPLE_AES|SAMPLE_AES_CTR|UNKNOWN)",
enUS: "Set HLS encryption method (AES_128|AES_128_ECB|CENC|PLAYREADY|CHACHA20|NONE|SAMPLE_AES|SAMPLE_AES_CTR|UNKNOWN)"
),
["cmd_customHLSKey"] = new TextContainer
(

View File

@ -164,6 +164,11 @@ namespace N_m3u8DL_RE.Parser.Extractor
var _duration = Convert.ToInt64(_durationStr);
var timescale = Convert.ToInt32(timeScaleStr);
var _repeatCount = Convert.ToInt64(_repeatCountStr);
if (_repeatCount > 0)
{
// This value is one-based. (A value of 2 means two fragments in the contiguous series).
_repeatCount -= 1;
}
varDic[MSSTags.StartTime] = currentTime;
var oriUrl = ParserUtil.CombineURL(this.BaseUrl, urlPattern!);
@ -215,10 +220,6 @@ namespace N_m3u8DL_RE.Parser.Extractor
ProtectionData = protectionData,
ProtectionSystemID = protectionSystemId,
};
if (streamSpec.MSSData.Duration == 0)
{
streamSpec.MSSData.Duration = streamSpec.MSSData.Timesacle;
}
var processor = new MSSMoovProcessor(streamSpec);
var header = processor.GenHeader(); //trackId可能不正确
streamSpec.Playlist!.MediaInit!.Url = $"base64://{Convert.ToBase64String(header)}";

View File

@ -37,6 +37,7 @@ namespace N_m3u8DL_RE.Parser.Mp4
private string ProtectionSystemId;
private string ProtectionData;
private string ProtecitonKID;
private string ProtecitonKID_PR;
private byte[] UnityMatrix
{
get
@ -165,6 +166,8 @@ namespace N_m3u8DL_RE.Parser.Mp4
var bytes = HexUtil.HexToBytes(ProtectionData.Replace("00", ""));
var text = Encoding.ASCII.GetString(bytes);
var kidBytes = Convert.FromBase64String(KIDRegex().Match(text).Groups[1].Value);
//save kid for playready
this.ProtecitonKID_PR = HexUtil.BytesToHex(kidBytes);
//fix byte order
var reverse1 = new byte[4] { kidBytes[3], kidBytes[2], kidBytes[1], kidBytes[0] };
var reverse2 = new byte[4] { kidBytes[5], kidBytes[4], kidBytes[7], kidBytes[6] };
@ -244,7 +247,7 @@ namespace N_m3u8DL_RE.Parser.Mp4
writer.Write("iso6"); //major brand
writer.WriteUInt(1); //minor version
writer.Write("isom"); //compatible brand
writer.Write("iso6"); //compatible brand
writer.Write("iso5"); //compatible brand
writer.Write("msdh"); //compatible brand
return Box("ftyp", stream.ToArray());
@ -525,9 +528,9 @@ namespace N_m3u8DL_RE.Parser.Mp4
else if (FourCC == "HVC1" || FourCC == "HEV1")
{
var arr = CodecPrivateData.Split(new[] { StartCode }, StringSplitOptions.RemoveEmptyEntries);
var vps = HexUtil.HexToBytes(arr.Where(x => (HexUtil.HexToBytes(x[0..2])[0] & 0x3F) == 0x20).First());
var sps = HexUtil.HexToBytes(arr.Where(x => (HexUtil.HexToBytes(x[0..2])[0] & 0x3F) == 0x21).First());
var pps = HexUtil.HexToBytes(arr.Where(x => (HexUtil.HexToBytes(x[0..2])[0] & 0x3F) == 0x22).First());
var vps = HexUtil.HexToBytes(arr.Where(x => (HexUtil.HexToBytes(x[0..2])[0] >> 1) == 0x20).First());
var sps = HexUtil.HexToBytes(arr.Where(x => (HexUtil.HexToBytes(x[0..2])[0] >> 1) == 0x21).First());
var pps = HexUtil.HexToBytes(arr.Where(x => (HexUtil.HexToBytes(x[0..2])[0] >> 1) == 0x22).First());
//make hvcC
var hvcC = GetHvcC(sps, pps, vps);
writer.Write(hvcC);
@ -730,6 +733,35 @@ namespace N_m3u8DL_RE.Parser.Mp4
return FullBox("trex", 0, 0, stream.ToArray()); //Track Extends Box
}
private byte[] GenPsshBoxForPlayReady()
{
using var _stream = new MemoryStream();
using var _writer = new BinaryWriter2(_stream);
var sysIdData = HexUtil.HexToBytes(ProtectionSystemId.Replace("-", ""));
var psshData = HexUtil.HexToBytes(ProtectionData);
_writer.Write(sysIdData); // SystemID 16 bytes
_writer.WriteUInt(psshData.Length); //Size of Data 4 bytes
_writer.Write(psshData); //Data
var psshBox = FullBox("pssh", 0, 0, _stream.ToArray());
return psshBox;
}
private byte[] GenPsshBoxForWideVine()
{
using var _stream = new MemoryStream();
using var _writer = new BinaryWriter2(_stream);
var sysIdData = HexUtil.HexToBytes("edef8ba9-79d6-4ace-a3c8-27dcd51d21ed".Replace("-", ""));
//var kid = HexUtil.HexToBytes(ProtecitonKID);
_writer.Write(sysIdData); // SystemID 16 bytes
var psshData = HexUtil.HexToBytes($"08011210{ProtecitonKID}1A046E647265220400000000");
_writer.WriteUInt(psshData.Length); //Size of Data 4 bytes
_writer.Write(psshData); //Data
var psshBox = FullBox("pssh", 0, 0, _stream.ToArray());
return psshBox;
}
public byte[] GenHeader(byte[] firstSegment)
{
new MP4Parser()
@ -801,12 +833,12 @@ namespace N_m3u8DL_RE.Parser.Mp4
var mvexBox = Box("mvex", mvexPayload); //Movie Extends Box
moovPayload = moovPayload.Concat(mvexBox).ToArray();
/*if (IsProtection) //gen pssh
if (IsProtection)
{
var pssh = HexUtil.HexToBytes(ProtectionData);
var psshBox = FullBox("pssh", 1, 0, pssh);
moovPayload = moovPayload.Concat(psshBox).ToArray();
}*/
var psshBox1 = GenPsshBoxForPlayReady();
var psshBox2 = GenPsshBoxForWideVine();
moovPayload = moovPayload.Concat(psshBox1).Concat(psshBox2).ToArray();
}
var moovBox = Box("moov", moovPayload); //Movie Box

View File

@ -178,7 +178,7 @@ namespace N_m3u8DL_RE.DownloadManager
//从文件读取KEY
await SearchKeyAsync(currentKID);
//实时解密
if (DownloaderConfig.MyOptions.MP4RealTimeDecryption && !string.IsNullOrEmpty(currentKID))
if (DownloaderConfig.MyOptions.MP4RealTimeDecryption && !string.IsNullOrEmpty(currentKID) && StreamExtractor.ExtractorType != ExtractorType.MSS)
{
var enc = result.ActualFilePath;
var dec = Path.Combine(Path.GetDirectoryName(enc)!, Path.GetFileNameWithoutExtension(enc) + "_dec" + Path.GetExtension(enc));
@ -226,6 +226,17 @@ namespace N_m3u8DL_RE.DownloadManager
var processor = new MSSMoovProcessor(streamSpec);
var header = processor.GenHeader(File.ReadAllBytes(result.ActualFilePath));
await File.WriteAllBytesAsync(FileDic[streamSpec.Playlist!.MediaInit!]!.ActualFilePath, header);
if (DownloaderConfig.MyOptions.MP4RealTimeDecryption && !string.IsNullOrEmpty(currentKID))
{
//需要重新解密init
var enc = FileDic[streamSpec.Playlist!.MediaInit!]!.ActualFilePath;
var dec = Path.Combine(Path.GetDirectoryName(enc)!, Path.GetFileNameWithoutExtension(enc) + "_dec" + Path.GetExtension(enc));
var dResult = await MP4DecryptUtil.DecryptAsync(DownloaderConfig.MyOptions.UseShakaPackager, mp4decrypt, DownloaderConfig.MyOptions.Keys, enc, dec, currentKID);
if (dResult)
{
FileDic[streamSpec.Playlist!.MediaInit!]!.ActualFilePath = dec;
}
}
}
//读取init信息
if (string.IsNullOrEmpty(currentKID))

View File

@ -241,7 +241,7 @@ namespace N_m3u8DL_RE.DownloadManager
//从文件读取KEY
await SearchKeyAsync(currentKID);
//实时解密
if (DownloaderConfig.MyOptions.MP4RealTimeDecryption && !string.IsNullOrEmpty(currentKID))
if (DownloaderConfig.MyOptions.MP4RealTimeDecryption && !string.IsNullOrEmpty(currentKID) && StreamExtractor.ExtractorType != ExtractorType.MSS)
{
var enc = result.ActualFilePath;
var dec = Path.Combine(Path.GetDirectoryName(enc)!, Path.GetFileNameWithoutExtension(enc) + "_dec" + Path.GetExtension(enc));
@ -296,6 +296,17 @@ namespace N_m3u8DL_RE.DownloadManager
var processor = new MSSMoovProcessor(streamSpec);
var header = processor.GenHeader(File.ReadAllBytes(result.ActualFilePath));
await File.WriteAllBytesAsync(FileDic[streamSpec.Playlist!.MediaInit!]!.ActualFilePath, header);
if (DownloaderConfig.MyOptions.MP4RealTimeDecryption && !string.IsNullOrEmpty(currentKID))
{
//需要重新解密init
var enc = FileDic[streamSpec.Playlist!.MediaInit!]!.ActualFilePath;
var dec = Path.Combine(Path.GetDirectoryName(enc)!, Path.GetFileNameWithoutExtension(enc) + "_dec" + Path.GetExtension(enc));
var dResult = await MP4DecryptUtil.DecryptAsync(DownloaderConfig.MyOptions.UseShakaPackager, mp4decrypt, DownloaderConfig.MyOptions.Keys, enc, dec, currentKID);
if (dResult)
{
FileDic[streamSpec.Playlist!.MediaInit!]!.ActualFilePath = dec;
}
}
}
//读取init信息
if (string.IsNullOrEmpty(currentKID))