Work on mp4 vtt sub - thx Lars/Martin :)

This commit is contained in:
niksedk 2021-12-16 19:16:28 +01:00
parent 09dc4895c8
commit 39d8290830
9 changed files with 107 additions and 21 deletions

View File

@ -23,11 +23,13 @@ namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes
if (Name == "vttc")
{
var vttc = new Vttc(fs, Position);
if (vttc.Payload != null)
{
Payloads.AddRange(vttc.Payload);
}
Payloads.AddRange(vttc.Payload);
}
else if (Name == "vtte")
{
Payloads.Add(null);
}
fs.Seek((long)Position, SeekOrigin.Begin);
}
}

View File

@ -25,13 +25,10 @@ namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes
{
Trun = new Trun(fs, Position);
}
else if (Name == "tfdt")
{
Tfdt = new Tfdt(fs, Size);
}
fs.Seek((long)Position, SeekOrigin.Begin);
}
if (Trun?.Samples != null && Tfdt != null)
{
foreach (var timeSegment in Trun.Samples)

View File

@ -21,11 +21,6 @@ namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes
Buffer = new byte[maximumLength - 4];
var readCount = fs.Read(Buffer, 0, Buffer.Length);
if (readCount < (int)maximumLength - 4)
{
return;
}
var versionAndFlags = GetUInt(0);
var version = versionAndFlags >> 24;
var flags = versionAndFlags & 0xFFFFFF;

View File

@ -46,6 +46,7 @@ namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes
fs.Seek((long)Position, SeekOrigin.Begin);
}
if (count == 0)
{
Payload.Add(null);

View File

@ -118,8 +118,8 @@ namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4
}
}
}
Subtitle.Renumber();
}
}
}

View File

@ -1,4 +1,5 @@
using Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes;
using Nikse.SubtitleEdit.Core.Common;
using Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes;
using System;
using System.Collections.Generic;
using System.IO;
@ -13,6 +14,8 @@ namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4
{
public string FileName { get; }
public Moov Moov { get; private set; }
internal Moof Moof { get; private set; }
public Subtitle VttcSubtitle { get; private set; }
public List<Trak> GetSubtitleTracks()
{
@ -23,10 +26,14 @@ namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4
{
if (trak.Mdia != null && (trak.Mdia.IsTextSubtitle || trak.Mdia.IsVobSubSubtitle || trak.Mdia.IsClosedCaption) && trak.Mdia.Minf?.Stbl != null)
{
list.Add(trak);
if (trak.Mdia.Minf.Stbl.GetParagraphs().Count > 0)
{
list.Add(trak);
}
}
}
}
return list;
}
@ -128,6 +135,7 @@ namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4
Position = 0;
fs.Seek(0, SeekOrigin.Begin);
bool moreBytes = true;
var timeTotalMs = 0d;
while (moreBytes)
{
moreBytes = InitializeSizeAndName(fs);
@ -140,9 +148,46 @@ namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4
{
Moov = new Moov(fs, Position); // only scan first "moov" element
}
else if (Name == "moof")
{
Moof = new Moof(fs, Position);
}
else if (Name == "mdat" && Moof != null && Moof?.Traf?.Trun?.Samples?.Count > 0)
{
var mdat = new Mdat(fs, Position);
if (mdat.Payloads.Count > 0)
{
if (Moof.Traf?.Trun?.Samples.Count > 0 && Moof?.Traf?.Trun?.Samples.Count >= mdat.Payloads.Count)
{
if (VttcSubtitle == null)
{
VttcSubtitle = new Subtitle();
}
var timeScale = (double)(Moov?.Mvhd?.TimeScale ?? 1000.0);
var sampleIdx = 0;
foreach (var payload in mdat.Payloads)
{
var presentation = Moof.Traf.Trun.Samples[sampleIdx];
if (presentation.Duration.HasValue)
{
var before = timeTotalMs;
timeTotalMs += presentation.Duration.Value / timeScale * 1000.0;
sampleIdx++;
if (payload != null)
{
VttcSubtitle.Paragraphs.Add(new Paragraph(payload, before, timeTotalMs));
}
}
}
}
Moof = null;
}
}
count++;
if (count > 100)
if (count > 1000)
{
break;
}
@ -154,7 +199,14 @@ namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4
fs.Seek((long)Position, SeekOrigin.Begin);
}
fs.Close();
if (VttcSubtitle != null)
{
var merged = MergeLinesSameTextUtils.MergeLinesWithSameTextInSubtitle(VttcSubtitle, false, 250);
VttcSubtitle = merged;
}
}
internal double FrameRate
@ -172,6 +224,7 @@ namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4
return sampleCount / (duration / Moov.Mvhd.TimeScale);
}
}
return 0;
}
}
@ -215,6 +268,5 @@ namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4
}
return list;
}
}
}

View File

@ -45,6 +45,5 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
subtitle.Paragraphs.Clear();
subtitle.Paragraphs.AddRange(parser.Subtitle.Paragraphs);
}
}
}

View File

@ -63,6 +63,12 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
continue;
}
if (xmlAsString.IndexOf('\0') >= 0)
{
_errorCount++;
continue;
}
var sub = new Subtitle();
var mdatLines = xmlAsString.SplitToLines(25_000);
format = sub.ReloadLoadSubtitle(mdatLines, null, format);

View File

@ -2884,7 +2884,7 @@ namespace Nikse.SubtitleEdit.Forms
}
}
if ((ext == ".mp4" || ext == ".m4v" || ext == ".3gp") && file.Length > 2000)
if ((ext == ".mp4" || ext == ".m4v" || ext == ".3gp" || ext == ".cmaf") && file.Length > 2000)
{
if (!new IsmtDfxp().IsMine(null, fileName))
{
@ -14237,6 +14237,23 @@ namespace Nikse.SubtitleEdit.Forms
var mp4SubtitleTracks = mp4Parser.GetSubtitleTracks();
if (mp4SubtitleTracks.Count == 0)
{
if (mp4Parser.VttcSubtitle?.Paragraphs.Count > 0)
{
MakeHistoryForUndo(_language.BeforeImportFromMatroskaFile);
_subtitleListViewIndex = -1;
FileNew();
_subtitle = mp4Parser.VttcSubtitle;
UpdateSourceView();
SubtitleListview1.Fill(_subtitle, _subtitleOriginal);
_subtitleListViewIndex = -1;
SubtitleListview1.FirstVisibleIndex = -1;
SubtitleListview1.SelectIndexAndEnsureVisible(0, true);
_fileName = Utilities.GetPathAndFileNameWithoutExtension(fileName) + GetCurrentSubtitleFormat().Extension;
_converted = true;
SetTitle();
return true;
}
MessageBox.Show(_language.NoSubtitlesFound);
return false;
}
@ -14541,7 +14558,7 @@ namespace Nikse.SubtitleEdit.Forms
}
}
}
if (ext == ".ismt" || ext == ".mp4" || ext == ".m4v" || ext == ".3gp")
if (ext == ".ismt" || ext == ".mp4" || ext == ".m4v" || ext == ".3gp" || ext == ".cmaf")
{
var mp4Parser = new MP4Parser(fileName);
var mp4SubtitleTracks = mp4Parser.GetSubtitleTracks();
@ -14575,6 +14592,23 @@ namespace Nikse.SubtitleEdit.Forms
return;
}
if (mp4Parser.VttcSubtitle?.Paragraphs.Count > 0)
{
MakeHistoryForUndo(_language.BeforeImportFromMatroskaFile);
_subtitleListViewIndex = -1;
FileNew();
_subtitle = mp4Parser.VttcSubtitle;
UpdateSourceView();
SubtitleListview1.Fill(_subtitle, _subtitleOriginal);
_subtitleListViewIndex = -1;
SubtitleListview1.FirstVisibleIndex = -1;
SubtitleListview1.SelectIndexAndEnsureVisible(0, true);
_fileName = Utilities.GetPathAndFileNameWithoutExtension(fileName) + GetCurrentSubtitleFormat().Extension;
_converted = true;
SetTitle();
return;
}
MessageBox.Show(_language.NoSubtitlesFound);
return;
}