自动计算stpp字幕时间轴

This commit is contained in:
nilaoda 2022-09-19 15:07:25 +08:00
parent 02efb814e9
commit 4ba8f48835
5 changed files with 55 additions and 15 deletions

View File

@ -29,6 +29,8 @@ namespace N_m3u8DL_RE.Common.Entity
public string? VideoRange { get; set; } public string? VideoRange { get; set; }
//补充信息-特征 //补充信息-特征
public string? Characteristics { get; set; } public string? Characteristics { get; set; }
//发布时间仅MPD需要
public DateTime? PublishTime { get; set; }
//外部轨道GroupId (后续寻找对应轨道信息) //外部轨道GroupId (后续寻找对应轨道信息)
public string? AudioId { get; set; } public string? AudioId { get; set; }

View File

@ -24,9 +24,9 @@ namespace N_m3u8DL_RE.Common.Entity
/// </summary> /// </summary>
/// <param name="textBytes"></param> /// <param name="textBytes"></param>
/// <returns></returns> /// <returns></returns>
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);
} }
/// <summary> /// <summary>
@ -35,9 +35,9 @@ namespace N_m3u8DL_RE.Common.Entity
/// <param name="textBytes"></param> /// <param name="textBytes"></param>
/// <param name="encoding"></param> /// <param name="encoding"></param>
/// <returns></returns> /// <returns></returns>
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);
} }
/// <summary> /// <summary>
@ -45,7 +45,7 @@ namespace N_m3u8DL_RE.Common.Entity
/// </summary> /// </summary>
/// <param name="text"></param> /// <param name="text"></param>
/// <returns></returns> /// <returns></returns>
public static WebVttSub Parse(string text) public static WebVttSub Parse(string text, long BaseTimestamp = 0L)
{ {
if (!text.Trim().StartsWith("WEBVTT")) if (!text.Trim().StartsWith("WEBVTT"))
throw new Exception("Bad vtt!"); 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; return webSub;
} }

View File

@ -189,6 +189,12 @@ namespace N_m3u8DL_RE.Parser.Extractor
{ {
streamSpec.Channels = audioChannelConfiguration.Attribute("value")?.Value; streamSpec.Channels = audioChannelConfiguration.Attribute("value")?.Value;
} }
//发布时间
if (!string.IsNullOrEmpty(publishTime))
{
streamSpec.PublishTime = DateTime.Parse(publishTime);
}
//第一种形式 SegmentBase //第一种形式 SegmentBase

View File

@ -118,7 +118,7 @@ namespace Mp4SubtitleParser
return MultiElementsFixRegex().Matches(xml).Select(m => m.Value).ToList(); return MultiElementsFixRegex().Matches(xml).Select(m => m.Value).ToList();
} }
public static WebVttSub ExtractFromMp4s(IEnumerable<string> items, long segTimeMs) public static WebVttSub ExtractFromMp4s(IEnumerable<string> items, long segTimeMs, long baseTimestamp = 0L)
{ {
//read ttmls //read ttmls
List<string> xmls = new List<string>(); List<string> xmls = new List<string>();
@ -156,10 +156,10 @@ namespace Mp4SubtitleParser
segIndex++; segIndex++;
} }
return ExtractSub(xmls); return ExtractSub(xmls, baseTimestamp);
} }
public static WebVttSub ExtractFromTTMLs(IEnumerable<string> items, long segTimeMs) public static WebVttSub ExtractFromTTMLs(IEnumerable<string> items, long segTimeMs, long baseTimestamp = 0L)
{ {
//read ttmls //read ttmls
List<string> xmls = new List<string>(); List<string> xmls = new List<string>();
@ -178,10 +178,10 @@ namespace Mp4SubtitleParser
segIndex++; segIndex++;
} }
return ExtractSub(xmls); return ExtractSub(xmls, baseTimestamp);
} }
private static WebVttSub ExtractSub(List<string> xmls) private static WebVttSub ExtractSub(List<string> xmls, long baseTimestamp)
{ {
//parsing //parsing
var xmlDoc = new XmlDocument(); var xmlDoc = new XmlDocument();
@ -306,7 +306,7 @@ namespace Mp4SubtitleParser
vtt.AppendLine(); vtt.AppendLine();
} }
return WebVttSub.Parse(vtt.ToString()); return WebVttSub.Parse(vtt.ToString(), baseTimestamp);
} }
} }
} }

View File

@ -35,6 +35,7 @@ namespace N_m3u8DL_RE.DownloadManager
StreamExtractor StreamExtractor; StreamExtractor StreamExtractor;
List<StreamSpec> SelectedSteams; List<StreamSpec> SelectedSteams;
DateTime NowDateTime; DateTime NowDateTime;
DateTime? PublishDateTime;
bool STOP_FLAG = false; bool STOP_FLAG = false;
int WAIT_SEC = 0; //刷新间隔 int WAIT_SEC = 0; //刷新间隔
ConcurrentDictionary<int, int> RecordingDurDic = new(); //已录制时长 ConcurrentDictionary<int, int> RecordingDurDic = new(); //已录制时长
@ -46,6 +47,7 @@ namespace N_m3u8DL_RE.DownloadManager
this.DownloaderConfig = downloaderConfig; this.DownloaderConfig = downloaderConfig;
Downloader = new SimpleDownloader(DownloaderConfig); Downloader = new SimpleDownloader(DownloaderConfig);
NowDateTime = DateTime.Now; NowDateTime = DateTime.Now;
PublishDateTime = selectedSteams.FirstOrDefault()?.PublishTime;
StreamExtractor = streamExtractor; StreamExtractor = streamExtractor;
SelectedSteams = selectedSteams; SelectedSteams = selectedSteams;
} }
@ -115,6 +117,7 @@ namespace N_m3u8DL_RE.DownloadManager
private async Task<bool> RecordStreamAsync(StreamSpec streamSpec, ProgressTask task, SpeedContainer speedContainer, ISourceBlock<List<MediaSegment>> source) private async Task<bool> RecordStreamAsync(StreamSpec streamSpec, ProgressTask task, SpeedContainer speedContainer, ISourceBlock<List<MediaSegment>> source)
{ {
var baseTimestamp = PublishDateTime == null ? 0L : (long)(PublishDateTime.Value.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalMilliseconds;
//mp4decrypt //mp4decrypt
var mp4decrypt = DownloaderConfig.MyOptions.DecryptionBinaryPath!; var mp4decrypt = DownloaderConfig.MyOptions.DecryptionBinaryPath!;
var mp4InitFile = ""; var mp4InitFile = "";
@ -321,6 +324,7 @@ namespace N_m3u8DL_RE.DownloadManager
if (firstSub) if (firstSub)
{ {
currentVtt = MP4VttUtil.ExtractSub(mp4s, timescale); currentVtt = MP4VttUtil.ExtractSub(mp4s, timescale);
firstSub = false;
} }
else 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(); var mp4s = FileDic.Values.Select(v => v!.ActualFilePath).Where(p => p.EndsWith(".ttml")).OrderBy(s => s).ToArray();
if (firstSub) 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 else
{ {
var finalVtt = MP4TtmlUtil.ExtractFromTTMLs(mp4s, 0); var finalVtt = MP4TtmlUtil.ExtractFromTTMLs(mp4s, 0, baseTimestamp);
currentVtt.AddCuesFromOne(finalVtt); 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(); var mp4s = FileDic.Values.Select(v => v!.ActualFilePath).Where(p => p.EndsWith(".m4s")).OrderBy(s => s).ToArray();
if (firstSub) 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 else
{ {
var finalVtt = MP4TtmlUtil.ExtractFromMp4s(mp4s, 0); var finalVtt = MP4TtmlUtil.ExtractFromMp4s(mp4s, 0, baseTimestamp);
currentVtt.AddCuesFromOne(finalVtt); currentVtt.AddCuesFromOne(finalVtt);
} }
} }