From 4ba8f4883513628f639c9f4508766a27f5ce9314 Mon Sep 17 00:00:00 2001 From: nilaoda Date: Mon, 19 Sep 2022 15:07:25 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=AE=A1=E7=AE=97stpp?= =?UTF-8?q?=E5=AD=97=E5=B9=95=E6=97=B6=E9=97=B4=E8=BD=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/N_m3u8DL-RE.Common/Entity/StreamSpec.cs | 2 ++ src/N_m3u8DL-RE.Common/Entity/WebVttSub.cs | 26 +++++++++++++++---- .../Extractor/DASHExtractor2.cs | 6 +++++ src/N_m3u8DL-RE.Parser/Mp4/MP4TtmlUtil.cs | 12 ++++----- .../SimpleLiveRecordManager2.cs | 24 ++++++++++++++--- 5 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/N_m3u8DL-RE.Common/Entity/StreamSpec.cs b/src/N_m3u8DL-RE.Common/Entity/StreamSpec.cs index 932d2c5..d9db4f1 100644 --- a/src/N_m3u8DL-RE.Common/Entity/StreamSpec.cs +++ b/src/N_m3u8DL-RE.Common/Entity/StreamSpec.cs @@ -29,6 +29,8 @@ namespace N_m3u8DL_RE.Common.Entity public string? VideoRange { get; set; } //补充信息-特征 public string? Characteristics { get; set; } + //发布时间(仅MPD需要) + public DateTime? PublishTime { get; set; } //外部轨道GroupId (后续寻找对应轨道信息) public string? AudioId { get; set; } diff --git a/src/N_m3u8DL-RE.Common/Entity/WebVttSub.cs b/src/N_m3u8DL-RE.Common/Entity/WebVttSub.cs index b23a88f..51db7ad 100644 --- a/src/N_m3u8DL-RE.Common/Entity/WebVttSub.cs +++ b/src/N_m3u8DL-RE.Common/Entity/WebVttSub.cs @@ -24,9 +24,9 @@ namespace N_m3u8DL_RE.Common.Entity /// /// /// - public static WebVttSub Parse(byte[] textBytes) + public static WebVttSub Parse(byte[] textBytes, long BaseTimestamp = 0L) { - return Parse(Encoding.UTF8.GetString(textBytes)); + return Parse(Encoding.UTF8.GetString(textBytes), BaseTimestamp); } /// @@ -35,9 +35,9 @@ namespace N_m3u8DL_RE.Common.Entity /// /// /// - public static WebVttSub Parse(byte[] textBytes, Encoding encoding) + public static WebVttSub Parse(byte[] textBytes, Encoding encoding, long BaseTimestamp = 0L) { - return Parse(encoding.GetString(textBytes)); + return Parse(encoding.GetString(textBytes), BaseTimestamp); } /// @@ -45,7 +45,7 @@ namespace N_m3u8DL_RE.Common.Entity /// /// /// - public static WebVttSub Parse(string text) + public static WebVttSub Parse(string text, long BaseTimestamp = 0L) { if (!text.Trim().StartsWith("WEBVTT")) throw new Exception("Bad vtt!"); @@ -98,6 +98,22 @@ namespace N_m3u8DL_RE.Common.Entity } } + if (BaseTimestamp != 0) + { + foreach (var item in webSub.Cues) + { + if (item.StartTime.TotalMilliseconds - BaseTimestamp >= 0) + { + item.StartTime = TimeSpan.FromMilliseconds(item.StartTime.TotalMilliseconds - BaseTimestamp); + item.EndTime = TimeSpan.FromMilliseconds(item.EndTime.TotalMilliseconds - BaseTimestamp); + } + else + { + break; + } + } + } + return webSub; } diff --git a/src/N_m3u8DL-RE.Parser/Extractor/DASHExtractor2.cs b/src/N_m3u8DL-RE.Parser/Extractor/DASHExtractor2.cs index d7fb5cd..3a4bb9a 100644 --- a/src/N_m3u8DL-RE.Parser/Extractor/DASHExtractor2.cs +++ b/src/N_m3u8DL-RE.Parser/Extractor/DASHExtractor2.cs @@ -189,6 +189,12 @@ namespace N_m3u8DL_RE.Parser.Extractor { streamSpec.Channels = audioChannelConfiguration.Attribute("value")?.Value; } + + //发布时间 + if (!string.IsNullOrEmpty(publishTime)) + { + streamSpec.PublishTime = DateTime.Parse(publishTime); + } //第一种形式 SegmentBase diff --git a/src/N_m3u8DL-RE.Parser/Mp4/MP4TtmlUtil.cs b/src/N_m3u8DL-RE.Parser/Mp4/MP4TtmlUtil.cs index e7c41b8..b433da3 100644 --- a/src/N_m3u8DL-RE.Parser/Mp4/MP4TtmlUtil.cs +++ b/src/N_m3u8DL-RE.Parser/Mp4/MP4TtmlUtil.cs @@ -118,7 +118,7 @@ namespace Mp4SubtitleParser return MultiElementsFixRegex().Matches(xml).Select(m => m.Value).ToList(); } - public static WebVttSub ExtractFromMp4s(IEnumerable items, long segTimeMs) + public static WebVttSub ExtractFromMp4s(IEnumerable items, long segTimeMs, long baseTimestamp = 0L) { //read ttmls List xmls = new List(); @@ -156,10 +156,10 @@ namespace Mp4SubtitleParser segIndex++; } - return ExtractSub(xmls); + return ExtractSub(xmls, baseTimestamp); } - public static WebVttSub ExtractFromTTMLs(IEnumerable items, long segTimeMs) + public static WebVttSub ExtractFromTTMLs(IEnumerable items, long segTimeMs, long baseTimestamp = 0L) { //read ttmls List xmls = new List(); @@ -178,10 +178,10 @@ namespace Mp4SubtitleParser segIndex++; } - return ExtractSub(xmls); + return ExtractSub(xmls, baseTimestamp); } - private static WebVttSub ExtractSub(List xmls) + private static WebVttSub ExtractSub(List xmls, long baseTimestamp) { //parsing var xmlDoc = new XmlDocument(); @@ -306,7 +306,7 @@ namespace Mp4SubtitleParser vtt.AppendLine(); } - return WebVttSub.Parse(vtt.ToString()); + return WebVttSub.Parse(vtt.ToString(), baseTimestamp); } } } diff --git a/src/N_m3u8DL-RE/DownloadManager/SimpleLiveRecordManager2.cs b/src/N_m3u8DL-RE/DownloadManager/SimpleLiveRecordManager2.cs index 7931029..894a0d3 100644 --- a/src/N_m3u8DL-RE/DownloadManager/SimpleLiveRecordManager2.cs +++ b/src/N_m3u8DL-RE/DownloadManager/SimpleLiveRecordManager2.cs @@ -35,6 +35,7 @@ namespace N_m3u8DL_RE.DownloadManager StreamExtractor StreamExtractor; List SelectedSteams; DateTime NowDateTime; + DateTime? PublishDateTime; bool STOP_FLAG = false; int WAIT_SEC = 0; //刷新间隔 ConcurrentDictionary RecordingDurDic = new(); //已录制时长 @@ -46,6 +47,7 @@ namespace N_m3u8DL_RE.DownloadManager this.DownloaderConfig = downloaderConfig; Downloader = new SimpleDownloader(DownloaderConfig); NowDateTime = DateTime.Now; + PublishDateTime = selectedSteams.FirstOrDefault()?.PublishTime; StreamExtractor = streamExtractor; SelectedSteams = selectedSteams; } @@ -115,6 +117,7 @@ namespace N_m3u8DL_RE.DownloadManager private async Task RecordStreamAsync(StreamSpec streamSpec, ProgressTask task, SpeedContainer speedContainer, ISourceBlock> source) { + var baseTimestamp = PublishDateTime == null ? 0L : (long)(PublishDateTime.Value.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalMilliseconds; //mp4decrypt var mp4decrypt = DownloaderConfig.MyOptions.DecryptionBinaryPath!; var mp4InitFile = ""; @@ -321,6 +324,7 @@ namespace N_m3u8DL_RE.DownloadManager if (firstSub) { currentVtt = MP4VttUtil.ExtractSub(mp4s, timescale); + firstSub = false; } else { @@ -337,11 +341,17 @@ namespace N_m3u8DL_RE.DownloadManager var mp4s = FileDic.Values.Select(v => v!.ActualFilePath).Where(p => p.EndsWith(".ttml")).OrderBy(s => s).ToArray(); if (firstSub) { - currentVtt = MP4TtmlUtil.ExtractFromTTMLs(mp4s, 0); + if (baseTimestamp != 0) + { + var total = segments.Sum(s => s.Duration); + baseTimestamp -= (long)TimeSpan.FromSeconds(total).TotalMilliseconds; + } + currentVtt = MP4TtmlUtil.ExtractFromTTMLs(mp4s, 0, baseTimestamp); + firstSub = false; } else { - var finalVtt = MP4TtmlUtil.ExtractFromTTMLs(mp4s, 0); + var finalVtt = MP4TtmlUtil.ExtractFromTTMLs(mp4s, 0, baseTimestamp); currentVtt.AddCuesFromOne(finalVtt); } } @@ -358,11 +368,17 @@ namespace N_m3u8DL_RE.DownloadManager var mp4s = FileDic.Values.Select(v => v!.ActualFilePath).Where(p => p.EndsWith(".m4s")).OrderBy(s => s).ToArray(); if (firstSub) { - currentVtt = MP4TtmlUtil.ExtractFromMp4s(mp4s, 0); + if (baseTimestamp != 0) + { + var total = segments.Sum(s => s.Duration); + baseTimestamp -= (long)TimeSpan.FromSeconds(total).TotalMilliseconds; + } + currentVtt = MP4TtmlUtil.ExtractFromMp4s(mp4s, 0, baseTimestamp); + firstSub = false; } else { - var finalVtt = MP4TtmlUtil.ExtractFromMp4s(mp4s, 0); + var finalVtt = MP4TtmlUtil.ExtractFromMp4s(mp4s, 0, baseTimestamp); currentVtt.AddCuesFromOne(finalVtt); } }