Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

修复多DRM文件KID读取异常问题 #422

Merged
merged 5 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build_latest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ on:

env:
DOTNET_SDK_VERSION: "8.0.*"
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true

jobs:
build-win-x64-arm64:
Expand Down
10 changes: 8 additions & 2 deletions src/N_m3u8DL-RE.Parser/Mp4/MP4InitUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public class ParsedMP4Info
public string? PSSH;
public string? KID;
public string? Scheme;
public bool isMultiDRM;
}

public class MP4InitUtil
Expand All @@ -19,7 +20,6 @@ public static ParsedMP4Info ReadInit(byte[] data)
{
var info = new ParsedMP4Info();


//parse init
new MP4Parser()
.Box("moov", MP4Parser.Children)
Expand All @@ -36,7 +36,13 @@ public static ParsedMP4Info ReadInit(byte[] data)
if (SYSTEM_ID_WIDEVINE.SequenceEqual(systemId))
{
var dataSize = box.Reader.ReadUInt32();
info.PSSH = Convert.ToBase64String(box.Reader.ReadBytes((int)dataSize));
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)))
Expand Down
17 changes: 10 additions & 7 deletions src/N_m3u8DL-RE/DownloadManager/SimpleDownloadManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ private void ChangeSpecInfo(StreamSpec streamSpec, List<Mediainfo> mediainfos, r
}
}


private async Task<bool> DownloadStreamAsync(StreamSpec streamSpec, ProgressTask task, SpeedContainer speedContainer)
{
speedContainer.ResetVars();
Expand Down Expand Up @@ -167,7 +166,8 @@ private async Task<bool> DownloadStreamAsync(StreamSpec streamSpec, ProgressTask
//读取mp4信息
if (result != null && result.Success)
{
currentKID = MP4DecryptUtil.ReadInit(result.ActualFilePath);
AdiEcho marked this conversation as resolved.
Show resolved Hide resolved
var info = MP4DecryptUtil.GetMP4Info(result.ActualFilePath);
currentKID = info.KID;
// try shaka packager, which can handle WebM
if (string.IsNullOrEmpty(currentKID) && DownloaderConfig.MyOptions.UseShakaPackager) {
currentKID = MP4DecryptUtil.ReadInitShaka(result.ActualFilePath, mp4decrypt);
Expand All @@ -179,7 +179,7 @@ private async Task<bool> DownloadStreamAsync(StreamSpec streamSpec, ProgressTask
{
var enc = result.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);
var dResult = await MP4DecryptUtil.DecryptAsync(DownloaderConfig.MyOptions.UseShakaPackager, mp4decrypt, DownloaderConfig.MyOptions.Keys, enc, dec, currentKID, isMultiDRM: info.isMultiDRM);
if (dResult)
{
FileDic[streamSpec.Playlist.MediaInit]!.ActualFilePath = dec;
Expand Down Expand Up @@ -251,7 +251,8 @@ private async Task<bool> DownloadStreamAsync(StreamSpec streamSpec, ProgressTask
{
var enc = result.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, mp4InitFile);
var info = MP4DecryptUtil.GetMP4Info(enc);
var dResult = await MP4DecryptUtil.DecryptAsync(DownloaderConfig.MyOptions.UseShakaPackager, mp4decrypt, DownloaderConfig.MyOptions.Keys, enc, dec, currentKID, mp4InitFile, isMultiDRM: info.isMultiDRM);
if (dResult)
{
File.Delete(enc);
Expand Down Expand Up @@ -288,7 +289,8 @@ await Parallel.ForEachAsync(segments, options, async (seg, _) =>
{
var enc = result.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, mp4InitFile);
var info = MP4DecryptUtil.GetMP4Info(enc);
var dResult = await MP4DecryptUtil.DecryptAsync(DownloaderConfig.MyOptions.UseShakaPackager, mp4decrypt, DownloaderConfig.MyOptions.Keys, enc, dec, currentKID, mp4InitFile, isMultiDRM: info.isMultiDRM);
if (dResult)
{
File.Delete(enc);
Expand Down Expand Up @@ -594,12 +596,13 @@ await Parallel.ForEachAsync(segments, options, async (seg, _) =>
}

//调用mp4decrypt解密
if (mergeSuccess && File.Exists(output) && !string.IsNullOrEmpty(currentKID) && !DownloaderConfig.MyOptions.MP4RealTimeDecryption && DownloaderConfig.MyOptions.Keys != null && DownloaderConfig.MyOptions.Keys.Length > 0)
if (mergeSuccess && File.Exists(output) && !string.IsNullOrEmpty(currentKID) && !DownloaderConfig.MyOptions.MP4RealTimeDecryption && DownloaderConfig.MyOptions.Keys != null && DownloaderConfig.MyOptions.Keys.Length > 0)
{
var enc = output;
var dec = Path.Combine(Path.GetDirectoryName(enc)!, Path.GetFileNameWithoutExtension(enc) + "_dec" + Path.GetExtension(enc));
var info = MP4DecryptUtil.GetMP4Info(enc);
Logger.InfoMarkUp($"[grey]Decrypting...[/]");
var result = await MP4DecryptUtil.DecryptAsync(DownloaderConfig.MyOptions.UseShakaPackager, mp4decrypt, DownloaderConfig.MyOptions.Keys, enc, dec, currentKID);
var result = await MP4DecryptUtil.DecryptAsync(DownloaderConfig.MyOptions.UseShakaPackager, mp4decrypt, DownloaderConfig.MyOptions.Keys, enc, dec, currentKID, isMultiDRM: info.isMultiDRM);
if (result)
{
File.Delete(enc);
Expand Down
27 changes: 26 additions & 1 deletion src/N_m3u8DL-RE/Util/MP4DecryptUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,18 @@ namespace N_m3u8DL_RE.Util
internal class MP4DecryptUtil
{
private static string ZeroKid = "00000000000000000000000000000000";
public static async Task<bool> DecryptAsync(bool shakaPackager, string bin, string[]? keys, string source, string dest, string? kid, string init = "")
public static async Task<bool> DecryptAsync(bool shakaPackager, string bin, string[]? keys, string source, string dest, string? kid, string init = "", bool isMultiDRM=false)
{
if (keys == null || keys.Length == 0) return false;

string? keyPair = null;
string? trackId = null;

if (isMultiDRM)
{
trackId = "1";
}

if (!string.IsNullOrEmpty(kid))
{
var test = keys.Where(k => k.StartsWith(kid));
Expand Down Expand Up @@ -146,6 +152,25 @@ await Process.Start(new ProcessStartInfo()
}
}

public static ParsedMP4Info GetMP4Info(byte[] data)
{
var info = MP4InitUtil.ReadInit(data);
if (info.Scheme != null) Logger.WarnMarkUp($"[grey]Type: {info.Scheme}[/]");
if (info.PSSH != null) Logger.WarnMarkUp($"[grey]PSSH(WV): {info.PSSH}[/]");
if (info.KID != null) Logger.WarnMarkUp($"[grey]KID: {info.KID}[/]");
return info;
}

public static ParsedMP4Info GetMP4Info(string output)
{
using (var fs = File.OpenRead(output))
{
var header = new byte[1 * 1024 * 1024]; //1MB
fs.Read(header);
return GetMP4Info(header);
}
}

public static string? ReadInitShaka(string output, string bin)
{
Regex ShakaKeyIDRegex = new Regex("Key for key_id=([0-9a-f]+) was not found");
Expand Down