@@ -982,8 +982,8 @@ private void ReadChapters(IntPtr fileHandle)
982
982
this . chapters . Clear ( ) ;
983
983
IntPtr chapterListPointer = IntPtr . Zero ;
984
984
int chapterCount = 0 ;
985
- NativeMethods . MP4GetChapters ( fileHandle , ref chapterListPointer , ref chapterCount , NativeMethods . MP4ChapterType . Qt ) ;
986
- if ( chapterListPointer != IntPtr . Zero )
985
+ NativeMethods . MP4ChapterType chapterType = NativeMethods . MP4GetChapters ( fileHandle , ref chapterListPointer , ref chapterCount , NativeMethods . MP4ChapterType . Qt ) ;
986
+ if ( chapterType != NativeMethods . MP4ChapterType . None && chapterCount != 0 )
987
987
{
988
988
IntPtr currentChapterPointer = chapterListPointer ;
989
989
for ( int i = 0 ; i < chapterCount ; i ++ )
@@ -1001,63 +1001,74 @@ private void ReadChapters(IntPtr fileHandle)
1001
1001
this . chapters . Add ( new Chapter ( ) { Duration = duration , Title = title } ) ;
1002
1002
currentChapterPointer = IntPtr . Add ( currentChapterPointer , Marshal . SizeOf ( currentChapter ) ) ;
1003
1003
}
1004
+ }
1005
+ else
1006
+ {
1007
+ int timeScale = NativeMethods . MP4GetTimeScale ( fileHandle ) ;
1008
+ long duration = NativeMethods . MP4GetDuration ( fileHandle ) ;
1009
+ this . chapters . Add ( new Chapter ( ) { Duration = TimeSpan . FromSeconds ( duration / timeScale ) , Title = "Chapter 1" } ) ;
1010
+ }
1004
1011
1012
+ if ( chapterListPointer != IntPtr . Zero )
1013
+ {
1005
1014
NativeMethods . MP4Free ( chapterListPointer ) ;
1006
1015
}
1007
1016
}
1008
1017
1009
1018
private void WriteChapters ( IntPtr fileHandle )
1010
1019
{
1011
- IntPtr chapterList = IntPtr . Zero ;
1012
- int chapterCount = 0 ;
1013
- NativeMethods . MP4GetChapters ( fileHandle , ref chapterList , ref chapterCount , NativeMethods . MP4ChapterType . Qt ) ;
1014
- NativeMethods . MP4DeleteChapters ( fileHandle , NativeMethods . MP4ChapterType . Any , NativeMethods . MP4InvalidTrackId ) ;
1015
-
1016
- int maxTrackId = 0 ;
1020
+ // Find the first video track, so that we make sure the total duration
1021
+ // of the chapters we add does not exceed the length of the file.
1017
1022
int referenceTrackId = - 1 ;
1018
1023
for ( short i = 0 ; i < NativeMethods . MP4GetNumberOfTracks ( fileHandle , null , 0 ) ; i ++ )
1019
1024
{
1020
- maxTrackId = NativeMethods . MP4FindTrackId ( fileHandle , i , null , 0 ) ;
1021
- string trackType = NativeMethods . MP4GetTrackType ( fileHandle , maxTrackId ) ;
1022
- if ( trackType == NativeMethods . MP4VideoTrackType && referenceTrackId < 0 )
1025
+ int currentTrackId = NativeMethods . MP4FindTrackId ( fileHandle , i , null , 0 ) ;
1026
+ string trackType = NativeMethods . MP4GetTrackType ( fileHandle , currentTrackId ) ;
1027
+ if ( trackType == NativeMethods . MP4VideoTrackType )
1023
1028
{
1024
- referenceTrackId = maxTrackId ;
1025
- }
1026
-
1027
- if ( NativeMethods . MP4HaveTrackAtom ( fileHandle , maxTrackId , "tref.chap" ) )
1028
- {
1029
- // Subler does some work here to remove references to
1030
- // the chapter track that other tracks may have. If/when
1031
- // the Subler changes to the mp4v2 library are merged,
1032
- // we will consider doing that here.
1029
+ referenceTrackId = currentTrackId ;
1030
+ break ;
1033
1031
}
1034
1032
}
1035
1033
1036
- NativeMethods . MP4SetIntegerProperty ( fileHandle , "moov.mvhd.nextTrackId" , maxTrackId + 1 ) ;
1034
+ // If we don't have a video track, then we have an audio file, which has
1035
+ // only one track, and we can use it to find the duration.
1037
1036
referenceTrackId = referenceTrackId <= 0 ? 1 : referenceTrackId ;
1038
1037
long referenceTrackDuration = NativeMethods . MP4ConvertFromTrackDuration ( fileHandle , referenceTrackId , NativeMethods . MP4GetTrackDuration ( fileHandle , referenceTrackId ) , NativeMethods . MP4TimeScale . Milliseconds ) ;
1039
1038
1040
- long total = 0 ;
1039
+ long runningTotal = 0 ;
1041
1040
List < NativeMethods . MP4Chapter > nativeChapters = new List < NativeMethods . MP4Chapter > ( ) ;
1042
1041
foreach ( Chapter chapter in this . chapters )
1043
1042
{
1044
1043
NativeMethods . MP4Chapter nativeChapter = new NativeMethods . MP4Chapter ( ) ;
1044
+
1045
+ // Set the title
1045
1046
nativeChapter . title = new byte [ 1024 ] ;
1046
1047
byte [ ] titleByteArray = Encoding . UTF8 . GetBytes ( chapter . Title ) ;
1047
1048
Array . Copy ( titleByteArray , nativeChapter . title , titleByteArray . Length ) ;
1049
+
1050
+ // Set the duration, making sure that we only use durations up to
1051
+ // the length of the reference track.
1048
1052
long chapterLength = ( long ) chapter . Duration . TotalMilliseconds ;
1049
- nativeChapter . duration = total + chapterLength > referenceTrackDuration ? referenceTrackDuration - total : chapterLength ;
1050
- total += chapterLength ;
1053
+ if ( runningTotal + chapterLength > referenceTrackDuration )
1054
+ {
1055
+ nativeChapter . duration = referenceTrackDuration - runningTotal ;
1056
+ }
1057
+ else
1058
+ {
1059
+ nativeChapter . duration = chapterLength ;
1060
+ }
1061
+
1062
+ runningTotal += chapterLength ;
1051
1063
nativeChapters . Add ( nativeChapter ) ;
1052
- if ( total > referenceTrackDuration )
1064
+ if ( runningTotal > referenceTrackDuration )
1053
1065
{
1054
1066
break ;
1055
1067
}
1056
1068
}
1057
1069
1058
1070
NativeMethods . MP4Chapter [ ] chapterArray = nativeChapters . ToArray ( ) ;
1059
1071
NativeMethods . MP4SetChapters ( fileHandle , chapterArray , chapterArray . Length , NativeMethods . MP4ChapterType . Qt ) ;
1060
- NativeMethods . MP4Free ( chapterList ) ;
1061
1072
}
1062
1073
}
1063
1074
}
0 commit comments