Skip to content

Commit 9ca55fa

Browse files
committed
Move ChapterInfo into Mpeg4Lib
1 parent 219a696 commit 9ca55fa

14 files changed

Lines changed: 149 additions & 150 deletions

File tree

src/AAXClean/Chapter.cs

Lines changed: 0 additions & 42 deletions
This file was deleted.

src/AAXClean/ChapterInfo.cs

Lines changed: 0 additions & 38 deletions
This file was deleted.

src/AAXClean/ChapterQueue.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using AAXClean.FrameFilters;
2+
using Mpeg4Lib;
23
using System;
34
using System.Collections.Generic;
45
using System.Diagnostics.CodeAnalysis;

src/AAXClean/FrameFilters/Audio/MultipartFilterBase.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using Mpeg4Lib;
2+
using System;
23
using System.Collections.Generic;
34
using System.Threading.Tasks;
45

src/AAXClean/Mp4File.cs

Lines changed: 2 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22
using AAXClean.FrameFilters;
33
using AAXClean.FrameFilters.Audio;
44
using AAXClean.FrameFilters.Text;
5+
using Mpeg4Lib;
56
using Mpeg4Lib.Boxes;
6-
using Mpeg4Lib.Chunks;
77
using Mpeg4Lib.Util;
88
using System;
9-
using System.Collections.Generic;
109
using System.IO;
1110
using System.Linq;
12-
using System.Text;
1311
using System.Threading.Tasks;
1412

1513
namespace AAXClean
@@ -41,11 +39,10 @@ public enum SampleRate : int
4139

4240
public class Mp4File : Mpeg4Lib.Mpeg4File
4341
{
44-
public ChapterInfo? Chapters { get; set; }
42+
#pragma warning disable CS0618 // Type or member is obsolete
4543
[Obsolete("Use MetadataItems property instead.")]
4644
public AppleTags AppleTags => lazyAppleTags.Value;
4745

48-
#pragma warning disable CS0618 // Type or member is obsolete
4946
private readonly Lazy<AppleTags> lazyAppleTags;
5047
#pragma warning restore CS0618
5148

@@ -187,50 +184,6 @@ public Mp4Operation ConvertToMultiMp4aAsync(ChapterInfo userChapters, Action<New
187184
return ProcessAudio(TimeSpan.Zero, TimeSpan.MaxValue, continuation, (Moov.TextTrack, chapterFilter));
188185
}
189186

190-
public ChapterInfo? GetChaptersFromMetadata()
191-
{
192-
TrakBox? textTrak = Moov.TextTrack;
193-
194-
//Get chapter names from metadata box in chapter track
195-
List<string>? chapterNames =
196-
textTrak
197-
?.GetChild<UdtaBox>()
198-
?.GetChild<MetaBox>()
199-
?.GetChild<AppleListBox>()
200-
?.Children
201-
?.OfType<AppleTagBox>()
202-
?.Where(b => b.Header.Type == "©nam")
203-
?.Select(b => b.Data.ReadAsString())
204-
?.ToList();
205-
206-
if (chapterNames is null) return null;
207-
208-
List<SttsBox.SampleEntry> sampleTimes = textTrak!.Mdia.Minf.Stbl.Stts.Samples;
209-
210-
if (sampleTimes.Count != chapterNames.Count) return null;
211-
212-
var cEntryList = new ChunkEntryList(textTrak).OrderBy(s => s.ChunkOffset).ToList();
213-
214-
if (cEntryList.Count != chapterNames.Count) return null;
215-
216-
ChapterInfo chapterInfo = new();
217-
218-
int subtractNext = 0;
219-
220-
for (int i = 0; i < chapterNames.Count; i++)
221-
{
222-
var sif = (int)sampleTimes[i].FrameDelta;
223-
224-
TimeSpan duration = TimeSpan.FromSeconds(Math.Max(0d, sif + subtractNext) / TimeScale);
225-
chapterInfo.AddChapter(chapterNames[(int)cEntryList[i].ChunkIndex], duration);
226-
subtractNext = sif < 0 ? sif : 0;
227-
}
228-
229-
Chapters ??= chapterInfo;
230-
231-
return chapterInfo;
232-
}
233-
234187
protected virtual IChunkReader CreateChunkReader(Stream inputStream, TimeSpan startTime, TimeSpan endTime)
235188
=> new ChunkReader(inputStream, startTime, endTime);
236189

src/AAXClean/NewSplitCallback.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.IO;
1+
using Mpeg4Lib;
2+
using System.IO;
23

34
namespace AAXClean
45
{

src/Mpeg4Lib/Chapter.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using Mpeg4Lib.Util;
2+
using System;
3+
using System.IO;
4+
using System.Text;
5+
6+
namespace Mpeg4Lib;
7+
8+
public record Chapter
9+
{
10+
public string Title { get; }
11+
public TimeSpan StartOffset { get; }
12+
public TimeSpan Duration { get; }
13+
public TimeSpan EndOffset { get; }
14+
public int RenderSize => 2 + Encoding.UTF8.GetByteCount(Title) + encd.Length;
15+
public Chapter(string title, TimeSpan start, TimeSpan duration)
16+
{
17+
ArgumentNullException.ThrowIfNull(title, nameof(title));
18+
Title = title;
19+
StartOffset = start;
20+
Duration = duration;
21+
EndOffset = StartOffset + Duration;
22+
}
23+
24+
public void WriteChapter(Stream output)
25+
{
26+
byte[] title = Encoding.UTF8.GetBytes(Title);
27+
28+
output.WriteInt16BE((short)title.Length);
29+
output.Write(title);
30+
output.Write(encd);
31+
}
32+
public override string ToString()
33+
{
34+
return $"{Title} {{{StartOffset} - {EndOffset}}}";
35+
}
36+
37+
//This is constant folr UTF-8 text
38+
//https://github.com/FFmpeg/FFmpeg/blob/master/libavformat/movenc.c
39+
private static readonly byte[] encd = [0, 0, 0, 0xc, (byte)'e', (byte)'n', (byte)'c', (byte)'d', 0, 0, 1, 0];
40+
}

src/Mpeg4Lib/ChapterInfo.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
6+
namespace Mpeg4Lib;
7+
8+
public record ChapterInfo : IEnumerable<Chapter>
9+
{
10+
public TimeSpan StartOffset { get; }
11+
public TimeSpan EndOffset => Count == 0 ? StartOffset : _chapterList.Max(c => c.EndOffset);
12+
13+
private readonly List<Chapter> _chapterList = new();
14+
public IReadOnlyList<Chapter> Chapters => _chapterList;
15+
public int Count => _chapterList.Count;
16+
public int RenderSize => _chapterList.Sum(c => c.RenderSize);
17+
18+
public ChapterInfo(TimeSpan offsetFromBeginning = default) => StartOffset = offsetFromBeginning;
19+
20+
public void AddChapter(string title, TimeSpan duration)
21+
{
22+
TimeSpan startTime = Count == 0 ? StartOffset : _chapterList[^1].EndOffset;
23+
24+
_chapterList.Add(new Chapter(title, startTime, duration));
25+
}
26+
public void Add(string title, TimeSpan duration) => AddChapter(title, duration);
27+
28+
public IEnumerator<Chapter> GetEnumerator()
29+
{
30+
return _chapterList.GetEnumerator();
31+
}
32+
33+
IEnumerator IEnumerable.GetEnumerator()
34+
{
35+
return GetEnumerator();
36+
}
37+
}

src/Mpeg4Lib/Mpeg4File.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Mpeg4Lib.Boxes;
2+
using Mpeg4Lib.Chunks;
23
using Mpeg4Lib.Util;
34
using System;
45
using System.Collections.Generic;
@@ -11,6 +12,7 @@ namespace Mpeg4Lib;
1112

1213
public class Mpeg4File : IDisposable
1314
{
15+
public ChapterInfo? Chapters { get; set; }
1416
public Stream InputStream { get; }
1517
public FtypBox Ftyp { get; set; }
1618
public MoovBox Moov { get; }
@@ -230,6 +232,50 @@ public static async Task RelocateMoovToBeginningAsync(string mp4FilePath, Progre
230232
}
231233
}
232234

235+
public ChapterInfo? GetChaptersFromMetadata()
236+
{
237+
TrakBox? textTrak = Moov.TextTrack;
238+
239+
//Get chapter names from metadata box in chapter track
240+
List<string>? chapterNames =
241+
textTrak
242+
?.GetChild<UdtaBox>()
243+
?.GetChild<MetaBox>()
244+
?.GetChild<AppleListBox>()
245+
?.Children
246+
?.OfType<AppleTagBox>()
247+
?.Where(b => b.Header.Type == "©nam")
248+
?.Select(b => b.Data.ReadAsString())
249+
?.ToList();
250+
251+
if (chapterNames is null) return null;
252+
253+
List<SttsBox.SampleEntry> sampleTimes = textTrak!.Mdia.Minf.Stbl.Stts.Samples;
254+
255+
if (sampleTimes.Count != chapterNames.Count) return null;
256+
257+
var cEntryList = new ChunkEntryList(textTrak).OrderBy(s => s.ChunkOffset).ToList();
258+
259+
if (cEntryList.Count != chapterNames.Count) return null;
260+
261+
ChapterInfo chapterInfo = new();
262+
263+
int subtractNext = 0;
264+
265+
for (int i = 0; i < chapterNames.Count; i++)
266+
{
267+
var sif = (int)sampleTimes[i].FrameDelta;
268+
269+
TimeSpan duration = TimeSpan.FromSeconds(Math.Max(0d, sif + subtractNext) / TimeScale);
270+
chapterInfo.AddChapter(chapterNames[(int)cEntryList[i].ChunkIndex], duration);
271+
subtractNext = sif < 0 ? sif : 0;
272+
}
273+
274+
Chapters ??= chapterInfo;
275+
276+
return chapterInfo;
277+
}
278+
233279
~Mpeg4File()
234280
{
235281
Dispose(disposing: false);

tests/AAXClean.Test/AC_AaxTest.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace AAXClean.Test
77
[TestClass]
88
public class AC_AaxTest : AaxTestBase
99
{
10-
private ChapterInfo _chapters;
10+
private Mpeg4Lib.ChapterInfo _chapters;
1111
private TestBookTags _tags;
1212

1313
public override string AaxFile => TestFiles.AC_BookPath;
@@ -19,13 +19,13 @@ public class AC_AaxTest : AaxTestBase
1919
public override long RenderSize => 5872527L;
2020
public override TimeSpan Duration => TimeSpan.FromTicks(618328816326);
2121

22-
public override ChapterInfo Chapters
22+
public override Mpeg4Lib.ChapterInfo Chapters
2323
{
2424
get
2525
{
2626
if (_chapters is null)
2727
{
28-
_chapters = new ChapterInfo
28+
_chapters = new Mpeg4Lib.ChapterInfo
2929
{
3030
{ "PROLOGUE", TimeSpan.FromTicks(7327059863) },
3131
{ "PART ONE: ARRIVAL - (Needlecast Download)", TimeSpan.FromTicks(32380045) },

0 commit comments

Comments
 (0)