自动计算stpp字幕时间轴
This commit is contained in:
parent
02efb814e9
commit
4ba8f48835
|
@ -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; }
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -190,6 +190,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
|
||||||
var segmentBaseElement = representation.Elements().Where(e => e.Name.LocalName == "SegmentBase").FirstOrDefault();
|
var segmentBaseElement = representation.Elements().Where(e => e.Name.LocalName == "SegmentBase").FirstOrDefault();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue