Add Swift app (#366)
|
@ -7,4 +7,4 @@ omit =
|
|||
directory = coverage/html
|
||||
|
||||
[report]
|
||||
fail_under = 78
|
||||
fail_under = 68
|
||||
|
|
3
Buzz.swift/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
build/
|
||||
Frameworks/
|
||||
|
842
Buzz.swift/Buzz.xcodeproj/project.pbxproj
Normal file
|
@ -0,0 +1,842 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 56;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
983681FE29AD3A0600B8CE08 /* CircularProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 983681FD29AD3A0600B8CE08 /* CircularProgressView.swift */; };
|
||||
9836820029ADFBF800B8CE08 /* ModelDownloadTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 983681FF29ADFBF800B8CE08 /* ModelDownloadTask.swift */; };
|
||||
98753C83299F0A8700FD06C7 /* Transcription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98753C82299F0A8700FD06C7 /* Transcription.swift */; };
|
||||
98753C85299F818300FD06C7 /* TranscriptionStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98753C84299F818300FD06C7 /* TranscriptionStore.swift */; };
|
||||
9877658C29A0E6BD001E370D /* TranscriptionExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9877658B29A0E6BD001E370D /* TranscriptionExporter.swift */; };
|
||||
98CA00E0298DB810001A70A4 /* AudioRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98CA00DF298DB810001A70A4 /* AudioRecorder.swift */; };
|
||||
98CA00E2298E8A77001A70A4 /* RecordingTranscriptionOptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98CA00E1298E8A77001A70A4 /* RecordingTranscriptionOptionsView.swift */; };
|
||||
98D5EC2F2986F6DA0011BC2D /* BuzzApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D5EC2E2986F6DA0011BC2D /* BuzzApp.swift */; };
|
||||
98D5EC312986F6DA0011BC2D /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D5EC302986F6DA0011BC2D /* ContentView.swift */; };
|
||||
98D5EC332986F6DC0011BC2D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 98D5EC322986F6DC0011BC2D /* Assets.xcassets */; };
|
||||
98D5EC362986F6DC0011BC2D /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 98D5EC352986F6DC0011BC2D /* Preview Assets.xcassets */; };
|
||||
98D5EC412986F6DD0011BC2D /* BuzzTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D5EC402986F6DD0011BC2D /* BuzzTests.swift */; };
|
||||
98D5EC4B2986F6DD0011BC2D /* BuzzUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D5EC4A2986F6DD0011BC2D /* BuzzUITests.swift */; };
|
||||
98D5EC4D2986F6DD0011BC2D /* BuzzUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D5EC4C2986F6DD0011BC2D /* BuzzUITestsLaunchTests.swift */; };
|
||||
98D5EC5B2986F71B0011BC2D /* whisper in Frameworks */ = {isa = PBXBuildFile; productRef = 98D5EC5A2986F71B0011BC2D /* whisper */; };
|
||||
98D960FF29A291630074FCFA /* FileTranscriptionOptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D960FE29A291630074FCFA /* FileTranscriptionOptionsView.swift */; };
|
||||
98D9610129A294810074FCFA /* TranscriptionOptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D9610029A294810074FCFA /* TranscriptionOptionsView.swift */; };
|
||||
98D9610329A2AA640074FCFA /* TranscriptionOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D9610229A2AA640074FCFA /* TranscriptionOptions.swift */; };
|
||||
98D9610529A3CA5E0074FCFA /* TranscriptionListRowContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D9610429A3CA5E0074FCFA /* TranscriptionListRowContentView.swift */; };
|
||||
98D9610829A3D0FD0074FCFA /* ExportFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D9610729A3D0FD0074FCFA /* ExportFormat.swift */; };
|
||||
98D9610A29A3D1440074FCFA /* FileTranscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D9610929A3D1440074FCFA /* FileTranscription.swift */; };
|
||||
98D9610E29A3D5C80074FCFA /* SheetAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D9610D29A3D5C80074FCFA /* SheetAction.swift */; };
|
||||
98D9611029A3D6270074FCFA /* Whisper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D9610F29A3D6270074FCFA /* Whisper.swift */; };
|
||||
98DA8CC62990694800634136 /* FloatingTranscriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98DA8CC52990694800634136 /* FloatingTranscriptionView.swift */; };
|
||||
98DA8CC8299102B400634136 /* RecordingTranscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98DA8CC7299102B400634136 /* RecordingTranscriber.swift */; };
|
||||
98DA8CCA29918A8000634136 /* TranscriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98DA8CC929918A8000634136 /* TranscriptionView.swift */; };
|
||||
98DA8CCC299195F800634136 /* FileTranscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98DA8CCB299195F800634136 /* FileTranscriber.swift */; };
|
||||
98DA8CCE299464D100634136 /* ModelLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98DA8CCD299464D100634136 /* ModelLoader.swift */; };
|
||||
98FF6E4129B2396B00BA5699 /* ffmpegkit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E3929B2396800BA5699 /* ffmpegkit.xcframework */; };
|
||||
98FF6E4229B2396B00BA5699 /* ffmpegkit.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E3929B2396800BA5699 /* ffmpegkit.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
98FF6E4329B2396B00BA5699 /* libavfilter.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E3A29B2396800BA5699 /* libavfilter.xcframework */; };
|
||||
98FF6E4429B2396B00BA5699 /* libavfilter.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E3A29B2396800BA5699 /* libavfilter.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
98FF6E4529B2396B00BA5699 /* libswresample.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E3B29B2396800BA5699 /* libswresample.xcframework */; };
|
||||
98FF6E4629B2396B00BA5699 /* libswresample.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E3B29B2396800BA5699 /* libswresample.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
98FF6E4729B2396B00BA5699 /* libswscale.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E3C29B2396900BA5699 /* libswscale.xcframework */; };
|
||||
98FF6E4829B2396B00BA5699 /* libswscale.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E3C29B2396900BA5699 /* libswscale.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
98FF6E4929B2396B00BA5699 /* libavutil.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E3D29B2396900BA5699 /* libavutil.xcframework */; };
|
||||
98FF6E4A29B2396C00BA5699 /* libavutil.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E3D29B2396900BA5699 /* libavutil.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
98FF6E4B29B2396C00BA5699 /* libavcodec.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E3E29B2396A00BA5699 /* libavcodec.xcframework */; };
|
||||
98FF6E4C29B2396C00BA5699 /* libavcodec.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E3E29B2396A00BA5699 /* libavcodec.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
98FF6E4D29B2396C00BA5699 /* libavformat.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E3F29B2396A00BA5699 /* libavformat.xcframework */; };
|
||||
98FF6E4E29B2396C00BA5699 /* libavformat.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E3F29B2396A00BA5699 /* libavformat.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
98FF6E4F29B2396D00BA5699 /* libavdevice.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E4029B2396A00BA5699 /* libavdevice.xcframework */; };
|
||||
98FF6E5029B2396D00BA5699 /* libavdevice.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 98FF6E4029B2396A00BA5699 /* libavdevice.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
98D5EC3D2986F6DD0011BC2D /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 98D5EC232986F6DA0011BC2D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 98D5EC2A2986F6DA0011BC2D;
|
||||
remoteInfo = Buzz;
|
||||
};
|
||||
98D5EC472986F6DD0011BC2D /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 98D5EC232986F6DA0011BC2D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 98D5EC2A2986F6DA0011BC2D;
|
||||
remoteInfo = Buzz;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
98FF6E5129B2396E00BA5699 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
98FF6E4429B2396B00BA5699 /* libavfilter.xcframework in Embed Frameworks */,
|
||||
98FF6E4E29B2396C00BA5699 /* libavformat.xcframework in Embed Frameworks */,
|
||||
98FF6E4C29B2396C00BA5699 /* libavcodec.xcframework in Embed Frameworks */,
|
||||
98FF6E4629B2396B00BA5699 /* libswresample.xcframework in Embed Frameworks */,
|
||||
98FF6E5029B2396D00BA5699 /* libavdevice.xcframework in Embed Frameworks */,
|
||||
98FF6E4829B2396B00BA5699 /* libswscale.xcframework in Embed Frameworks */,
|
||||
98FF6E4229B2396B00BA5699 /* ffmpegkit.xcframework in Embed Frameworks */,
|
||||
98FF6E4A29B2396C00BA5699 /* libavutil.xcframework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
983681FD29AD3A0600B8CE08 /* CircularProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularProgressView.swift; sourceTree = "<group>"; };
|
||||
983681FF29ADFBF800B8CE08 /* ModelDownloadTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelDownloadTask.swift; sourceTree = "<group>"; };
|
||||
9842D9AE2995CDBC0035C8E3 /* libavdevice.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libavdevice.xcframework; path = "../../../Downloads/ffmpeg-kit-full-4.5.1-macos-xcframework/libavdevice.xcframework"; sourceTree = "<group>"; };
|
||||
9842D9AF2995CDBC0035C8E3 /* libavfilter.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libavfilter.xcframework; path = "../../../Downloads/ffmpeg-kit-full-4.5.1-macos-xcframework/libavfilter.xcframework"; sourceTree = "<group>"; };
|
||||
9842D9B02995CDBD0035C8E3 /* libavcodec.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libavcodec.xcframework; path = "../../../Downloads/ffmpeg-kit-full-4.5.1-macos-xcframework/libavcodec.xcframework"; sourceTree = "<group>"; };
|
||||
9842D9B12995CDBD0035C8E3 /* libavutil.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libavutil.xcframework; path = "../../../Downloads/ffmpeg-kit-full-4.5.1-macos-xcframework/libavutil.xcframework"; sourceTree = "<group>"; };
|
||||
9842D9B22995CDBE0035C8E3 /* libswresample.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libswresample.xcframework; path = "../../../Downloads/ffmpeg-kit-full-4.5.1-macos-xcframework/libswresample.xcframework"; sourceTree = "<group>"; };
|
||||
9842D9B32995CDBE0035C8E3 /* ffmpegkit.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = ffmpegkit.xcframework; path = "../../../Downloads/ffmpeg-kit-full-4.5.1-macos-xcframework/ffmpegkit.xcframework"; sourceTree = "<group>"; };
|
||||
9842D9B42995CDBF0035C8E3 /* libswscale.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libswscale.xcframework; path = "../../../Downloads/ffmpeg-kit-full-4.5.1-macos-xcframework/libswscale.xcframework"; sourceTree = "<group>"; };
|
||||
9842D9B52995CDBF0035C8E3 /* libavformat.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libavformat.xcframework; path = "../../../Downloads/ffmpeg-kit-full-4.5.1-macos-xcframework/libavformat.xcframework"; sourceTree = "<group>"; };
|
||||
98753C81299E24A200FD06C7 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
98753C82299F0A8700FD06C7 /* Transcription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Transcription.swift; sourceTree = "<group>"; };
|
||||
98753C84299F818300FD06C7 /* TranscriptionStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranscriptionStore.swift; sourceTree = "<group>"; };
|
||||
9877658B29A0E6BD001E370D /* TranscriptionExporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranscriptionExporter.swift; sourceTree = "<group>"; };
|
||||
98CA00DF298DB810001A70A4 /* AudioRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecorder.swift; sourceTree = "<group>"; };
|
||||
98CA00E1298E8A77001A70A4 /* RecordingTranscriptionOptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordingTranscriptionOptionsView.swift; sourceTree = "<group>"; };
|
||||
98D5EC2B2986F6DA0011BC2D /* Buzz.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Buzz.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
98D5EC2E2986F6DA0011BC2D /* BuzzApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuzzApp.swift; sourceTree = "<group>"; };
|
||||
98D5EC302986F6DA0011BC2D /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
98D5EC322986F6DC0011BC2D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
98D5EC352986F6DC0011BC2D /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||
98D5EC372986F6DC0011BC2D /* Buzz.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Buzz.entitlements; sourceTree = "<group>"; };
|
||||
98D5EC3C2986F6DD0011BC2D /* BuzzTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BuzzTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
98D5EC402986F6DD0011BC2D /* BuzzTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuzzTests.swift; sourceTree = "<group>"; };
|
||||
98D5EC462986F6DD0011BC2D /* BuzzUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BuzzUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
98D5EC4A2986F6DD0011BC2D /* BuzzUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuzzUITests.swift; sourceTree = "<group>"; };
|
||||
98D5EC4C2986F6DD0011BC2D /* BuzzUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuzzUITestsLaunchTests.swift; sourceTree = "<group>"; };
|
||||
98D960FE29A291630074FCFA /* FileTranscriptionOptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileTranscriptionOptionsView.swift; sourceTree = "<group>"; };
|
||||
98D9610029A294810074FCFA /* TranscriptionOptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranscriptionOptionsView.swift; sourceTree = "<group>"; };
|
||||
98D9610229A2AA640074FCFA /* TranscriptionOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranscriptionOptions.swift; sourceTree = "<group>"; };
|
||||
98D9610429A3CA5E0074FCFA /* TranscriptionListRowContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranscriptionListRowContentView.swift; sourceTree = "<group>"; };
|
||||
98D9610729A3D0FD0074FCFA /* ExportFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExportFormat.swift; sourceTree = "<group>"; };
|
||||
98D9610929A3D1440074FCFA /* FileTranscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileTranscription.swift; sourceTree = "<group>"; };
|
||||
98D9610D29A3D5C80074FCFA /* SheetAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SheetAction.swift; sourceTree = "<group>"; };
|
||||
98D9610F29A3D6270074FCFA /* Whisper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Whisper.swift; sourceTree = "<group>"; };
|
||||
98DA8CC52990694800634136 /* FloatingTranscriptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingTranscriptionView.swift; sourceTree = "<group>"; };
|
||||
98DA8CC7299102B400634136 /* RecordingTranscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordingTranscriber.swift; sourceTree = "<group>"; };
|
||||
98DA8CC929918A8000634136 /* TranscriptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranscriptionView.swift; sourceTree = "<group>"; };
|
||||
98DA8CCB299195F800634136 /* FileTranscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileTranscriber.swift; sourceTree = "<group>"; };
|
||||
98DA8CCD299464D100634136 /* ModelLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelLoader.swift; sourceTree = "<group>"; };
|
||||
98DA8CCF2994EC4000634136 /* ffmpegkit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ffmpegkit.framework; path = Frameworks/ffmpegkit.framework; sourceTree = "<group>"; };
|
||||
98DA8CD02994EC4100634136 /* libswscale.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libswscale.framework; path = Frameworks/libswscale.framework; sourceTree = "<group>"; };
|
||||
98DA8CD12994EC4200634136 /* libavdevice.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libavdevice.framework; path = Frameworks/libavdevice.framework; sourceTree = "<group>"; };
|
||||
98DA8CD22994EC4300634136 /* libswresample.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libswresample.framework; path = Frameworks/libswresample.framework; sourceTree = "<group>"; };
|
||||
98DA8CD32994EC4400634136 /* libavutil.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libavutil.framework; path = Frameworks/libavutil.framework; sourceTree = "<group>"; };
|
||||
98DA8CD42994EC4500634136 /* libavformat.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libavformat.framework; path = Frameworks/libavformat.framework; sourceTree = "<group>"; };
|
||||
98DA8CD52994EC4600634136 /* libavcodec.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libavcodec.framework; path = Frameworks/libavcodec.framework; sourceTree = "<group>"; };
|
||||
98DA8CD62994EC4700634136 /* libavfilter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libavfilter.framework; path = Frameworks/libavfilter.framework; sourceTree = "<group>"; };
|
||||
98FF6E3929B2396800BA5699 /* ffmpegkit.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = ffmpegkit.xcframework; path = "Libraries/ffmpeg-kit-full-4.5.1-macos-xcframework/ffmpegkit.xcframework"; sourceTree = "<group>"; };
|
||||
98FF6E3A29B2396800BA5699 /* libavfilter.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libavfilter.xcframework; path = "Libraries/ffmpeg-kit-full-4.5.1-macos-xcframework/libavfilter.xcframework"; sourceTree = "<group>"; };
|
||||
98FF6E3B29B2396800BA5699 /* libswresample.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libswresample.xcframework; path = "Libraries/ffmpeg-kit-full-4.5.1-macos-xcframework/libswresample.xcframework"; sourceTree = "<group>"; };
|
||||
98FF6E3C29B2396900BA5699 /* libswscale.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libswscale.xcframework; path = "Libraries/ffmpeg-kit-full-4.5.1-macos-xcframework/libswscale.xcframework"; sourceTree = "<group>"; };
|
||||
98FF6E3D29B2396900BA5699 /* libavutil.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libavutil.xcframework; path = "Libraries/ffmpeg-kit-full-4.5.1-macos-xcframework/libavutil.xcframework"; sourceTree = "<group>"; };
|
||||
98FF6E3E29B2396A00BA5699 /* libavcodec.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libavcodec.xcframework; path = "Libraries/ffmpeg-kit-full-4.5.1-macos-xcframework/libavcodec.xcframework"; sourceTree = "<group>"; };
|
||||
98FF6E3F29B2396A00BA5699 /* libavformat.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libavformat.xcframework; path = "Libraries/ffmpeg-kit-full-4.5.1-macos-xcframework/libavformat.xcframework"; sourceTree = "<group>"; };
|
||||
98FF6E4029B2396A00BA5699 /* libavdevice.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libavdevice.xcframework; path = "Libraries/ffmpeg-kit-full-4.5.1-macos-xcframework/libavdevice.xcframework"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
98D5EC282986F6DA0011BC2D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
98FF6E4729B2396B00BA5699 /* libswscale.xcframework in Frameworks */,
|
||||
98FF6E4329B2396B00BA5699 /* libavfilter.xcframework in Frameworks */,
|
||||
98FF6E4B29B2396C00BA5699 /* libavcodec.xcframework in Frameworks */,
|
||||
98D5EC5B2986F71B0011BC2D /* whisper in Frameworks */,
|
||||
98FF6E4F29B2396D00BA5699 /* libavdevice.xcframework in Frameworks */,
|
||||
98FF6E4529B2396B00BA5699 /* libswresample.xcframework in Frameworks */,
|
||||
98FF6E4D29B2396C00BA5699 /* libavformat.xcframework in Frameworks */,
|
||||
98FF6E4929B2396B00BA5699 /* libavutil.xcframework in Frameworks */,
|
||||
98FF6E4129B2396B00BA5699 /* ffmpegkit.xcframework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
98D5EC392986F6DD0011BC2D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
98D5EC432986F6DD0011BC2D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
98D5EC222986F6DA0011BC2D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
98D5EC2D2986F6DA0011BC2D /* Buzz */,
|
||||
98D5EC3F2986F6DD0011BC2D /* BuzzTests */,
|
||||
98D5EC492986F6DD0011BC2D /* BuzzUITests */,
|
||||
98D5EC5C2987CE560011BC2D /* Frameworks */,
|
||||
98D5EC2C2986F6DA0011BC2D /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
98D5EC2C2986F6DA0011BC2D /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
98D5EC2B2986F6DA0011BC2D /* Buzz.app */,
|
||||
98D5EC3C2986F6DD0011BC2D /* BuzzTests.xctest */,
|
||||
98D5EC462986F6DD0011BC2D /* BuzzUITests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
98D5EC2D2986F6DA0011BC2D /* Buzz */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
98D5EC322986F6DC0011BC2D /* Assets.xcassets */,
|
||||
98D9611229A3D7340074FCFA /* AudioRecorder */,
|
||||
98D5EC372986F6DC0011BC2D /* Buzz.entitlements */,
|
||||
98D5EC2E2986F6DA0011BC2D /* BuzzApp.swift */,
|
||||
983681FD29AD3A0600B8CE08 /* CircularProgressView.swift */,
|
||||
98D5EC302986F6DA0011BC2D /* ContentView.swift */,
|
||||
98DA8CC52990694800634136 /* FloatingTranscriptionView.swift */,
|
||||
98DA8CCD299464D100634136 /* ModelLoader.swift */,
|
||||
98D9610629A3D0E30074FCFA /* Models */,
|
||||
98D5EC342986F6DC0011BC2D /* Preview Content */,
|
||||
98753C81299E24A200FD06C7 /* README.md */,
|
||||
98D9611329A3D7430074FCFA /* Transcriber */,
|
||||
9877658B29A0E6BD001E370D /* TranscriptionExporter.swift */,
|
||||
98D9610429A3CA5E0074FCFA /* TranscriptionListRowContentView.swift */,
|
||||
98D9610C29A3D51E0074FCFA /* TranscriptionOptionsView */,
|
||||
98753C84299F818300FD06C7 /* TranscriptionStore.swift */,
|
||||
98DA8CC929918A8000634136 /* TranscriptionView.swift */,
|
||||
);
|
||||
path = Buzz;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
98D5EC342986F6DC0011BC2D /* Preview Content */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
98D5EC352986F6DC0011BC2D /* Preview Assets.xcassets */,
|
||||
);
|
||||
path = "Preview Content";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
98D5EC3F2986F6DD0011BC2D /* BuzzTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
98D5EC402986F6DD0011BC2D /* BuzzTests.swift */,
|
||||
);
|
||||
path = BuzzTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
98D5EC492986F6DD0011BC2D /* BuzzUITests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
98D5EC4A2986F6DD0011BC2D /* BuzzUITests.swift */,
|
||||
98D5EC4C2986F6DD0011BC2D /* BuzzUITestsLaunchTests.swift */,
|
||||
);
|
||||
path = BuzzUITests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
98D5EC5C2987CE560011BC2D /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9842D9B32995CDBE0035C8E3 /* ffmpegkit.xcframework */,
|
||||
9842D9B02995CDBD0035C8E3 /* libavcodec.xcframework */,
|
||||
9842D9AE2995CDBC0035C8E3 /* libavdevice.xcframework */,
|
||||
98FF6E3E29B2396A00BA5699 /* libavcodec.xcframework */,
|
||||
98FF6E4029B2396A00BA5699 /* libavdevice.xcframework */,
|
||||
9842D9AF2995CDBC0035C8E3 /* libavfilter.xcframework */,
|
||||
9842D9B52995CDBF0035C8E3 /* libavformat.xcframework */,
|
||||
98FF6E3F29B2396A00BA5699 /* libavformat.xcframework */,
|
||||
9842D9B12995CDBD0035C8E3 /* libavutil.xcframework */,
|
||||
98FF6E3D29B2396900BA5699 /* libavutil.xcframework */,
|
||||
9842D9B22995CDBE0035C8E3 /* libswresample.xcframework */,
|
||||
9842D9B42995CDBF0035C8E3 /* libswscale.xcframework */,
|
||||
98FF6E3929B2396800BA5699 /* ffmpegkit.xcframework */,
|
||||
98FF6E3A29B2396800BA5699 /* libavfilter.xcframework */,
|
||||
98FF6E3B29B2396800BA5699 /* libswresample.xcframework */,
|
||||
98FF6E3C29B2396900BA5699 /* libswscale.xcframework */,
|
||||
98DA8CCF2994EC4000634136 /* ffmpegkit.framework */,
|
||||
98DA8CD52994EC4600634136 /* libavcodec.framework */,
|
||||
98DA8CD12994EC4200634136 /* libavdevice.framework */,
|
||||
98DA8CD62994EC4700634136 /* libavfilter.framework */,
|
||||
98DA8CD42994EC4500634136 /* libavformat.framework */,
|
||||
98DA8CD32994EC4400634136 /* libavutil.framework */,
|
||||
98DA8CD22994EC4300634136 /* libswresample.framework */,
|
||||
98DA8CD02994EC4100634136 /* libswscale.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
98D9610629A3D0E30074FCFA /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
98D9610229A2AA640074FCFA /* TranscriptionOptions.swift */,
|
||||
98753C82299F0A8700FD06C7 /* Transcription.swift */,
|
||||
98D9610929A3D1440074FCFA /* FileTranscription.swift */,
|
||||
98D9610729A3D0FD0074FCFA /* ExportFormat.swift */,
|
||||
98D9610D29A3D5C80074FCFA /* SheetAction.swift */,
|
||||
98D9610F29A3D6270074FCFA /* Whisper.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
98D9610C29A3D51E0074FCFA /* TranscriptionOptionsView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
98CA00E1298E8A77001A70A4 /* RecordingTranscriptionOptionsView.swift */,
|
||||
98D960FE29A291630074FCFA /* FileTranscriptionOptionsView.swift */,
|
||||
98D9610029A294810074FCFA /* TranscriptionOptionsView.swift */,
|
||||
983681FF29ADFBF800B8CE08 /* ModelDownloadTask.swift */,
|
||||
);
|
||||
path = TranscriptionOptionsView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
98D9611229A3D7340074FCFA /* AudioRecorder */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
98CA00DF298DB810001A70A4 /* AudioRecorder.swift */,
|
||||
);
|
||||
path = AudioRecorder;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
98D9611329A3D7430074FCFA /* Transcriber */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
98DA8CCB299195F800634136 /* FileTranscriber.swift */,
|
||||
98DA8CC7299102B400634136 /* RecordingTranscriber.swift */,
|
||||
);
|
||||
path = Transcriber;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
98D5EC2A2986F6DA0011BC2D /* Buzz */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 98D5EC502986F6DD0011BC2D /* Build configuration list for PBXNativeTarget "Buzz" */;
|
||||
buildPhases = (
|
||||
98D5EC272986F6DA0011BC2D /* Sources */,
|
||||
98D5EC282986F6DA0011BC2D /* Frameworks */,
|
||||
98D5EC292986F6DA0011BC2D /* Resources */,
|
||||
98FF6E5129B2396E00BA5699 /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Buzz;
|
||||
packageProductDependencies = (
|
||||
98D5EC5A2986F71B0011BC2D /* whisper */,
|
||||
);
|
||||
productName = Buzz;
|
||||
productReference = 98D5EC2B2986F6DA0011BC2D /* Buzz.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
98D5EC3B2986F6DD0011BC2D /* BuzzTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 98D5EC532986F6DD0011BC2D /* Build configuration list for PBXNativeTarget "BuzzTests" */;
|
||||
buildPhases = (
|
||||
98D5EC382986F6DD0011BC2D /* Sources */,
|
||||
98D5EC392986F6DD0011BC2D /* Frameworks */,
|
||||
98D5EC3A2986F6DD0011BC2D /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
98D5EC3E2986F6DD0011BC2D /* PBXTargetDependency */,
|
||||
);
|
||||
name = BuzzTests;
|
||||
productName = BuzzTests;
|
||||
productReference = 98D5EC3C2986F6DD0011BC2D /* BuzzTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
98D5EC452986F6DD0011BC2D /* BuzzUITests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 98D5EC562986F6DD0011BC2D /* Build configuration list for PBXNativeTarget "BuzzUITests" */;
|
||||
buildPhases = (
|
||||
98D5EC422986F6DD0011BC2D /* Sources */,
|
||||
98D5EC432986F6DD0011BC2D /* Frameworks */,
|
||||
98D5EC442986F6DD0011BC2D /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
98D5EC482986F6DD0011BC2D /* PBXTargetDependency */,
|
||||
);
|
||||
name = BuzzUITests;
|
||||
productName = BuzzUITests;
|
||||
productReference = 98D5EC462986F6DD0011BC2D /* BuzzUITests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.ui-testing";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
98D5EC232986F6DA0011BC2D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = 1;
|
||||
LastSwiftUpdateCheck = 1420;
|
||||
LastUpgradeCheck = 1420;
|
||||
TargetAttributes = {
|
||||
98D5EC2A2986F6DA0011BC2D = {
|
||||
CreatedOnToolsVersion = 14.2;
|
||||
};
|
||||
98D5EC3B2986F6DD0011BC2D = {
|
||||
CreatedOnToolsVersion = 14.2;
|
||||
TestTargetID = 98D5EC2A2986F6DA0011BC2D;
|
||||
};
|
||||
98D5EC452986F6DD0011BC2D = {
|
||||
CreatedOnToolsVersion = 14.2;
|
||||
TestTargetID = 98D5EC2A2986F6DA0011BC2D;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 98D5EC262986F6DA0011BC2D /* Build configuration list for PBXProject "Buzz" */;
|
||||
compatibilityVersion = "Xcode 14.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 98D5EC222986F6DA0011BC2D;
|
||||
packageReferences = (
|
||||
98D5EC592986F71B0011BC2D /* XCRemoteSwiftPackageReference "whisper" */,
|
||||
);
|
||||
productRefGroup = 98D5EC2C2986F6DA0011BC2D /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
98D5EC2A2986F6DA0011BC2D /* Buzz */,
|
||||
98D5EC3B2986F6DD0011BC2D /* BuzzTests */,
|
||||
98D5EC452986F6DD0011BC2D /* BuzzUITests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
98D5EC292986F6DA0011BC2D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
98D5EC362986F6DC0011BC2D /* Preview Assets.xcassets in Resources */,
|
||||
98D5EC332986F6DC0011BC2D /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
98D5EC3A2986F6DD0011BC2D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
98D5EC442986F6DD0011BC2D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
98D5EC272986F6DA0011BC2D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9836820029ADFBF800B8CE08 /* ModelDownloadTask.swift in Sources */,
|
||||
98D960FF29A291630074FCFA /* FileTranscriptionOptionsView.swift in Sources */,
|
||||
98D9610329A2AA640074FCFA /* TranscriptionOptions.swift in Sources */,
|
||||
98D9610A29A3D1440074FCFA /* FileTranscription.swift in Sources */,
|
||||
98DA8CCE299464D100634136 /* ModelLoader.swift in Sources */,
|
||||
98DA8CCA29918A8000634136 /* TranscriptionView.swift in Sources */,
|
||||
983681FE29AD3A0600B8CE08 /* CircularProgressView.swift in Sources */,
|
||||
98D5EC312986F6DA0011BC2D /* ContentView.swift in Sources */,
|
||||
98D9611029A3D6270074FCFA /* Whisper.swift in Sources */,
|
||||
98DA8CC62990694800634136 /* FloatingTranscriptionView.swift in Sources */,
|
||||
98753C85299F818300FD06C7 /* TranscriptionStore.swift in Sources */,
|
||||
98CA00E2298E8A77001A70A4 /* RecordingTranscriptionOptionsView.swift in Sources */,
|
||||
98DA8CC8299102B400634136 /* RecordingTranscriber.swift in Sources */,
|
||||
98753C83299F0A8700FD06C7 /* Transcription.swift in Sources */,
|
||||
98D9610529A3CA5E0074FCFA /* TranscriptionListRowContentView.swift in Sources */,
|
||||
98CA00E0298DB810001A70A4 /* AudioRecorder.swift in Sources */,
|
||||
98D9610129A294810074FCFA /* TranscriptionOptionsView.swift in Sources */,
|
||||
98D9610E29A3D5C80074FCFA /* SheetAction.swift in Sources */,
|
||||
98D9610829A3D0FD0074FCFA /* ExportFormat.swift in Sources */,
|
||||
98D5EC2F2986F6DA0011BC2D /* BuzzApp.swift in Sources */,
|
||||
98DA8CCC299195F800634136 /* FileTranscriber.swift in Sources */,
|
||||
9877658C29A0E6BD001E370D /* TranscriptionExporter.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
98D5EC382986F6DD0011BC2D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
98D5EC412986F6DD0011BC2D /* BuzzTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
98D5EC422986F6DD0011BC2D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
98D5EC4B2986F6DD0011BC2D /* BuzzUITests.swift in Sources */,
|
||||
98D5EC4D2986F6DD0011BC2D /* BuzzUITestsLaunchTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
98D5EC3E2986F6DD0011BC2D /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 98D5EC2A2986F6DA0011BC2D /* Buzz */;
|
||||
targetProxy = 98D5EC3D2986F6DD0011BC2D /* PBXContainerItemProxy */;
|
||||
};
|
||||
98D5EC482986F6DD0011BC2D /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 98D5EC2A2986F6DA0011BC2D /* Buzz */;
|
||||
targetProxy = 98D5EC472986F6DD0011BC2D /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
98D5EC4E2986F6DD0011BC2D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.1;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
98D5EC4F2986F6DD0011BC2D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.1;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
98D5EC512986F6DD0011BC2D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = Buzz/Buzz.entitlements;
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"Buzz/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = G2V69FA555;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Frameworks",
|
||||
);
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Buzz;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
INFOPLIST_KEY_NSMicrophoneUsageDescription = "Microphone access";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 0.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.chidiwilliams.Buzz;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
98D5EC522986F6DD0011BC2D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = Buzz/Buzz.entitlements;
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"Buzz/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = G2V69FA555;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Frameworks",
|
||||
);
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Buzz;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
INFOPLIST_KEY_NSMicrophoneUsageDescription = "Microphone access";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 0.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.chidiwilliams.Buzz;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
98D5EC542986F6DD0011BC2D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = G2V69FA555;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.1;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.chidiwilliams.BuzzTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Buzz.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Buzz";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
98D5EC552986F6DD0011BC2D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = G2V69FA555;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.1;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.chidiwilliams.BuzzTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Buzz.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Buzz";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
98D5EC572986F6DD0011BC2D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = G2V69FA555;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.chidiwilliams.BuzzUITests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_TARGET_NAME = Buzz;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
98D5EC582986F6DD0011BC2D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = G2V69FA555;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.chidiwilliams.BuzzUITests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_TARGET_NAME = Buzz;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
98D5EC262986F6DA0011BC2D /* Build configuration list for PBXProject "Buzz" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
98D5EC4E2986F6DD0011BC2D /* Debug */,
|
||||
98D5EC4F2986F6DD0011BC2D /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
98D5EC502986F6DD0011BC2D /* Build configuration list for PBXNativeTarget "Buzz" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
98D5EC512986F6DD0011BC2D /* Debug */,
|
||||
98D5EC522986F6DD0011BC2D /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
98D5EC532986F6DD0011BC2D /* Build configuration list for PBXNativeTarget "BuzzTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
98D5EC542986F6DD0011BC2D /* Debug */,
|
||||
98D5EC552986F6DD0011BC2D /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
98D5EC562986F6DD0011BC2D /* Build configuration list for PBXNativeTarget "BuzzUITests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
98D5EC572986F6DD0011BC2D /* Debug */,
|
||||
98D5EC582986F6DD0011BC2D /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
98D5EC592986F71B0011BC2D /* XCRemoteSwiftPackageReference "whisper" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/ggerganov/whisper.spm";
|
||||
requirement = {
|
||||
branch = master;
|
||||
kind = branch;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
98D5EC5A2986F71B0011BC2D /* whisper */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 98D5EC592986F71B0011BC2D /* XCRemoteSwiftPackageReference "whisper" */;
|
||||
productName = whisper;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 98D5EC232986F6DA0011BC2D /* Project object */;
|
||||
}
|
7
Buzz.swift/Buzz.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "whisper.spm",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/ggerganov/whisper.spm",
|
||||
"state" : {
|
||||
"branch" : "master",
|
||||
"revision" : "9653b42eb4d6d7ef08f736e20f05c4d24492407b"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 2
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<array/>
|
||||
</plist>
|
|
@ -0,0 +1,207 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<VariablesViewState
|
||||
version = "1.0">
|
||||
<ContextStates>
|
||||
<ContextState
|
||||
contextName = "Recorder.captureOutput(_:didOutput:from:):Recorder.swift">
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "closure #1 in ContentView.onDismissRecordingSheet():ContentView.swift">
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "closure #1 in ContentView.onDismissFileTranscriptionSheet():ContentView.swift">
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "ContentView.onDismissFileTranscriptionSheet():ContentView.swift">
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "closure #1 in closure #4 in ContentView.body.getter:ContentView.swift">
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "Recorder.setup(callback:):Recorder.swift">
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "TranscriptionView.onClickExport(exportFormat:):TranscriptionView.swift">
|
||||
<PersistentStrings>
|
||||
<PersistentString
|
||||
value = "panel.nameFieldStringValue">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "panel.url">
|
||||
</PersistentString>
|
||||
</PersistentStrings>
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "closure #3 in ContentView.body.getter:ContentView.swift">
|
||||
<PersistentStrings>
|
||||
<PersistentString
|
||||
value = "self.selectedTranscription?.title">
|
||||
</PersistentString>
|
||||
</PersistentStrings>
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "log_mel_spectrogram(whisper_context&, float const*, int, int, int, int, int, int, whisper_filters const&, bool, whisper_mel&):whisper.cpp">
|
||||
<PersistentStrings>
|
||||
<PersistentString
|
||||
value = "n_samples">
|
||||
</PersistentString>
|
||||
</PersistentStrings>
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "FileTranscriber.transcribe(segmentCallback:):FileTranscriber.swift">
|
||||
<PersistentStrings>
|
||||
<PersistentString
|
||||
value = "self.transcriptionOptions.model">
|
||||
</PersistentString>
|
||||
</PersistentStrings>
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "closure #2 in RecordingTranscriber.start():RecordingTranscriber.swift">
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "ContentView.saveTranscriptions():ContentView.swift">
|
||||
<PersistentStrings>
|
||||
<PersistentString
|
||||
value = "transcriptionStore.transcriptions">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "self.transcriptionStore.transcriptions">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "transcriptionStore">
|
||||
</PersistentString>
|
||||
</PersistentStrings>
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "ContentView.onClickRecord():ContentView.swift">
|
||||
<PersistentStrings>
|
||||
<PersistentString
|
||||
value = "self.currentRecordingTranscriptionTask?.transcription">
|
||||
</PersistentString>
|
||||
</PersistentStrings>
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "Processor.transcribe():ContentView.swift">
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "Processor.captureOutput(_:didOutput:from:):ContentView.swift">
|
||||
<PersistentStrings>
|
||||
<PersistentString
|
||||
value = "buf.floatChannelData?.pointee[100]">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "pcmBuffer.floatChannelData?.pointee[1]">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "buf">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "sampleBuffer.int16ChannelData">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "sampleBuffer.frameLength">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "pcmBuffer.int32ChannelData?.pointee">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "pcmBuffer.int16ChannelData?.pointee">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "buf.floatChannelData.pointee">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "sampleBuffer">
|
||||
</PersistentString>
|
||||
</PersistentStrings>
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "Recorder.process(samples:count:):Recorder.swift">
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "ModelDownloadTask.urlSession(_:downloadTask:didFinishDownloadingTo:):TranscriptionOptionsView.swift">
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "AudioRecorder.captureOutput(_:didOutput:from:):AudioRecorder.swift">
|
||||
<PersistentStrings>
|
||||
<PersistentString
|
||||
value = "sampleBuffer.formatDescription?.audioChannelLayout?.numberOfChannels">
|
||||
</PersistentString>
|
||||
</PersistentStrings>
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "static ModelLoader.isAvailable(model:):ModelLoader.swift">
|
||||
<PersistentStrings>
|
||||
<PersistentString
|
||||
value = "modelPath.path()">
|
||||
</PersistentString>
|
||||
</PersistentStrings>
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "::whisper_full(whisper_context *, whisper_full_params, const float *, int):whisper.cpp">
|
||||
<PersistentStrings>
|
||||
<PersistentString
|
||||
value = "samples[5]">
|
||||
</PersistentString>
|
||||
</PersistentStrings>
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "closure #1 in static TranscriptionStore.save(transcription:completion:):TranscriptionStore.swift">
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "closure #1 in closure #1 in ContentView.body.getter:ContentView.swift">
|
||||
<PersistentStrings>
|
||||
<PersistentString
|
||||
value = "session.outputs">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "session.isRunning">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "buf">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "AVCaptureDevice.authorizationStatus(for: .audio)">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "buf.frameLength">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "file.fileFormat.sampleRate">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "session.inputs">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "buf.">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "file.length">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "cmd?.getReturnCode()">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "file.processingFormat">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "file.processingFormat.channelCount">
|
||||
</PersistentString>
|
||||
</PersistentStrings>
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "closure #1 in closure #1 in closure #1 in ContentView.body.getter:ContentView.swift">
|
||||
</ContextState>
|
||||
<ContextState
|
||||
contextName = "LiveRecordingView.init():LiveRecordingView.swift">
|
||||
<PersistentStrings>
|
||||
<PersistentString
|
||||
value = "microphones[2].uniqueID">
|
||||
</PersistentString>
|
||||
<PersistentString
|
||||
value = "self._selectedMicrophone">
|
||||
</PersistentString>
|
||||
</PersistentStrings>
|
||||
</ContextState>
|
||||
</ContextStates>
|
||||
</VariablesViewState>
|
100
Buzz.swift/Buzz.xcodeproj/xcshareddata/xcschemes/Buzz.xcscheme
Normal file
|
@ -0,0 +1,100 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1420"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "98D5EC2A2986F6DA0011BC2D"
|
||||
BuildableName = "Buzz.app"
|
||||
BlueprintName = "Buzz"
|
||||
ReferencedContainer = "container:Buzz.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "98D5EC3B2986F6DD0011BC2D"
|
||||
BuildableName = "BuzzTests.xctest"
|
||||
BlueprintName = "BuzzTests"
|
||||
ReferencedContainer = "container:Buzz.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "98D5EC452986F6DD0011BC2D"
|
||||
BuildableName = "BuzzUITests.xctest"
|
||||
BlueprintName = "BuzzUITests"
|
||||
ReferencedContainer = "container:Buzz.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "98D5EC2A2986F6DA0011BC2D"
|
||||
BuildableName = "Buzz.app"
|
||||
BlueprintName = "Buzz"
|
||||
ReferencedContainer = "container:Buzz.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "98D5EC2A2986F6DA0011BC2D"
|
||||
BuildableName = "Buzz.app"
|
||||
BlueprintName = "Buzz"
|
||||
ReferencedContainer = "container:Buzz.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
98
Buzz.swift/Buzz.xcodeproj/xcshareddata/xcschemes/CI.xcscheme
Normal file
|
@ -0,0 +1,98 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1420"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "98D5EC2A2986F6DA0011BC2D"
|
||||
BuildableName = "Buzz.app"
|
||||
BlueprintName = "Buzz"
|
||||
ReferencedContainer = "container:Buzz.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "98D5EC3B2986F6DD0011BC2D"
|
||||
BuildableName = "BuzzTests.xctest"
|
||||
BlueprintName = "BuzzTests"
|
||||
ReferencedContainer = "container:Buzz.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "98D5EC452986F6DD0011BC2D"
|
||||
BuildableName = "BuzzUITests.xctest"
|
||||
BlueprintName = "BuzzUITests"
|
||||
ReferencedContainer = "container:Buzz.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "98D5EC2A2986F6DA0011BC2D"
|
||||
BuildableName = "Buzz.app"
|
||||
BlueprintName = "Buzz"
|
||||
ReferencedContainer = "container:Buzz.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "98D5EC2A2986F6DA0011BC2D"
|
||||
BuildableName = "Buzz.app"
|
||||
BlueprintName = "Buzz"
|
||||
ReferencedContainer = "container:Buzz.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,902 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Bucket
|
||||
uuid = "91EFC8F0-34F8-47F0-96C2-E14D0F51AEDF"
|
||||
type = "1"
|
||||
version = "2.0">
|
||||
<Breakpoints>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "229894A9-78DB-42A9-BE93-C372CC643B39"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "../../../Library/Developer/Xcode/DerivedData/Buzz-gzzxtwdbicymrpaufokihlykvkps/SourcePackages/checkouts/whisper.spm/Sources/whisper/whisper.cpp"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "2118"
|
||||
endingLineNumber = "2118"
|
||||
landmarkName = "log_mel_spectrogram(wctx, samples, n_samples, fft_size, fft_step, n_mel, n_threads, filters, speed_up, mel)"
|
||||
landmarkType = "9">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "C7C9B2DD-5EAF-4E66-9D27-91764820532D"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "../../../Library/Developer/Xcode/DerivedData/Buzz-gzzxtwdbicymrpaufokihlykvkps/SourcePackages/checkouts/whisper.spm/Sources/whisper/whisper.cpp"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "3205"
|
||||
endingLineNumber = "3205"
|
||||
landmarkName = "whisper_full(ctx, params, samples, n_samples)"
|
||||
landmarkType = "9">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "38A5C214-F5E0-4C21-9312-60531064DBC5"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/Recorder.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "53"
|
||||
endingLineNumber = "53"
|
||||
landmarkName = "setup(callback:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "E5BBDF55-5E8C-4482-984F-8B8EFD8F4233"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/Recorder.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "26"
|
||||
endingLineNumber = "26"
|
||||
landmarkName = "record()"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "B087E09A-324A-4FFE-9342-43C19449214C"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/Recorder.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "117"
|
||||
endingLineNumber = "117"
|
||||
landmarkName = "captureOutput(_:didOutput:from:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "4A79E077-796E-4729-BC9D-E592F963AED3"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/Recorder.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "141"
|
||||
endingLineNumber = "141"
|
||||
landmarkName = "captureOutput(_:didOutput:from:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "3D381302-4F3A-49DA-8FE4-90E66A6E8AFA"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/Recorder.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "155"
|
||||
endingLineNumber = "155"
|
||||
landmarkName = "process(samples:count:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "1B5F512C-391C-4E2D-BEC5-A123AC943259"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/Recorder.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "137"
|
||||
endingLineNumber = "137"
|
||||
landmarkName = "captureOutput(_:didOutput:from:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "19555087-2FC1-428D-A815-F1929C34172E"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/Recorder.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "122"
|
||||
endingLineNumber = "122"
|
||||
landmarkName = "captureOutput(_:didOutput:from:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "B2EFF599-F2EC-47EC-96A0-0A61CDC77AAB"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/RecordingTranscriber.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "63"
|
||||
endingLineNumber = "63"
|
||||
landmarkName = "start(callback:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "8DFDF951-A954-4776-910F-1C75C32A7554"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/AudioRecorder.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "95"
|
||||
endingLineNumber = "95"
|
||||
landmarkName = "captureOutput(_:didOutput:from:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "B67296B7-C6A9-42BD-BE4A-21690EC16981"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/AudioRecorder.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "104"
|
||||
endingLineNumber = "104"
|
||||
landmarkName = "captureOutput(_:didOutput:from:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "861B4EEE-24F8-491B-BFC9-2A5A4C5173E2"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/AudioRecorder.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "108"
|
||||
endingLineNumber = "108"
|
||||
landmarkName = "captureOutput(_:didOutput:from:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "99940658-8FC5-4F6F-98D3-B95932C0F70D"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/AudioRecorder.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "94"
|
||||
endingLineNumber = "94"
|
||||
landmarkName = "captureOutput(_:didOutput:from:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "FD85A874-4748-4408-9A22-7C38AB7104A2"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/AudioRecorder.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "114"
|
||||
endingLineNumber = "114"
|
||||
landmarkName = "captureOutput(_:didOutput:from:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "B145E57C-0A89-4D68-8F2E-2EF7F4CB5D6C"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/RecordingTranscriber.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "88"
|
||||
endingLineNumber = "88"
|
||||
landmarkName = "start(callback:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "D0B55BA0-5527-4D3C-B10E-D294E3E2D01E"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/RecordingTranscriber.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "62"
|
||||
endingLineNumber = "62"
|
||||
landmarkName = "start(callback:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "3C134F95-D7DC-4BE8-9F0B-CC3DCB8EC56B"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/RecordingTranscriber.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "59"
|
||||
endingLineNumber = "59"
|
||||
landmarkName = "start(callback:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "2232623D-403A-4DE2-A3D2-6F62F5E4CB05"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/ContentView.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "117"
|
||||
endingLineNumber = "117"
|
||||
landmarkName = "onClickRecord()"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "1A6F2763-3036-49BD-94F7-8A98B7DDA4E0"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/FileTranscriber.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "87"
|
||||
endingLineNumber = "87"
|
||||
landmarkName = "transcribe()"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "D14D075A-B04C-43C6-A598-252B75A9AE02"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/FileTranscriber.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "64"
|
||||
endingLineNumber = "64"
|
||||
landmarkName = "transcribe()"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "CD3A4593-E13B-4A21-BC87-6394541FA6FF"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/FileTranscriber.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "67"
|
||||
endingLineNumber = "67"
|
||||
landmarkName = "transcribe()"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "5C3BDF48-0D1D-4985-B876-F75DD9CA8530"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/FileTranscriber.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "68"
|
||||
endingLineNumber = "68"
|
||||
landmarkName = "transcribe()"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "F03F9D7C-6269-4331-A44B-CCED3279816B"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/ContentView.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "53"
|
||||
endingLineNumber = "53"
|
||||
landmarkName = "saveTranscriptions()"
|
||||
landmarkType = "7">
|
||||
<Locations>
|
||||
<Location
|
||||
uuid = "F03F9D7C-6269-4331-A44B-CCED3279816B - bc786a18a3c0a117"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
symbolName = "Buzz.ContentView.saveTranscriptions() -> ()"
|
||||
moduleName = "Buzz"
|
||||
usesParentBreakpointCondition = "Yes"
|
||||
urlString = "file:///Users/chidiwilliams/src/Buzz.swift/Buzz/Buzz/ContentView.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "30"
|
||||
endingLineNumber = "30"
|
||||
offsetFromSymbolStart = "78">
|
||||
</Location>
|
||||
<Location
|
||||
uuid = "F03F9D7C-6269-4331-A44B-CCED3279816B - 24f0f3ea06735562"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
symbolName = "closure #1 (Swift.Result<Swift.Int, Swift.Error>) -> () in Buzz.ContentView.saveTranscriptions() -> ()"
|
||||
moduleName = "Buzz"
|
||||
usesParentBreakpointCondition = "Yes"
|
||||
urlString = "file:///Users/chidiwilliams/src/Buzz.swift/Buzz/Buzz/ContentView.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "31"
|
||||
endingLineNumber = "31"
|
||||
offsetFromSymbolStart = "74">
|
||||
</Location>
|
||||
</Locations>
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "C6903C3C-9B14-4A1E-B957-FA0736818685"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/TranscriptionStore.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "67"
|
||||
endingLineNumber = "67"
|
||||
landmarkName = "save(transcriptions:completion:)"
|
||||
landmarkType = "7">
|
||||
<Locations>
|
||||
<Location
|
||||
uuid = "C6903C3C-9B14-4A1E-B957-FA0736818685 - f2e6d75d76d72258"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
symbolName = "static Buzz.TranscriptionStore.save(transcription: Swift.Array<Buzz.Transcription>, completion: (Swift.Result<Swift.Int, Swift.Error>) -> ()) -> ()"
|
||||
moduleName = "Buzz"
|
||||
usesParentBreakpointCondition = "Yes"
|
||||
urlString = "file:///Users/chidiwilliams/src/Buzz.swift/Buzz/Buzz/TranscriptionStore.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "43"
|
||||
endingLineNumber = "43"
|
||||
offsetFromSymbolStart = "283">
|
||||
</Location>
|
||||
<Location
|
||||
uuid = "C6903C3C-9B14-4A1E-B957-FA0736818685 - 831b5bcde9426a5a"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
symbolName = "closure #1 () -> () in static Buzz.TranscriptionStore.save(transcription: Swift.Array<Buzz.Transcription>, completion: (Swift.Result<Swift.Int, Swift.Error>) -> ()) -> ()"
|
||||
moduleName = "Buzz"
|
||||
usesParentBreakpointCondition = "Yes"
|
||||
urlString = "file:///Users/chidiwilliams/src/Buzz.swift/Buzz/Buzz/TranscriptionStore.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "45"
|
||||
endingLineNumber = "45"
|
||||
offsetFromSymbolStart = "322">
|
||||
</Location>
|
||||
</Locations>
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "BDA36582-6F21-4763-A222-F3CAFDF40779"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/TranscriptionStore.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "80"
|
||||
endingLineNumber = "80"
|
||||
landmarkName = "save(transcriptions:completion:)"
|
||||
landmarkType = "7">
|
||||
<Locations>
|
||||
<Location
|
||||
uuid = "BDA36582-6F21-4763-A222-F3CAFDF40779 - 831b5bcde9426b25"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
symbolName = "closure #1 () -> () in static Buzz.TranscriptionStore.save(transcription: Swift.Array<Buzz.Transcription>, completion: (Swift.Result<Swift.Int, Swift.Error>) -> ()) -> ()"
|
||||
moduleName = "Buzz"
|
||||
usesParentBreakpointCondition = "Yes"
|
||||
urlString = "file:///Users/chidiwilliams/src/Buzz.swift/Buzz/Buzz/TranscriptionStore.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "52"
|
||||
endingLineNumber = "52"
|
||||
offsetFromSymbolStart = "1098">
|
||||
</Location>
|
||||
<Location
|
||||
uuid = "BDA36582-6F21-4763-A222-F3CAFDF40779 - a52295a74dc40079"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
symbolName = "closure #2 @Swift.MainActor () -> () in closure #1 () -> () in static Buzz.TranscriptionStore.save(transcription: Swift.Array<Buzz.Transcription>, completion: (Swift.Result<Swift.Int, Swift.Error>) -> ()) -> ()"
|
||||
moduleName = "Buzz"
|
||||
usesParentBreakpointCondition = "Yes"
|
||||
urlString = "file:///Users/chidiwilliams/src/Buzz.swift/Buzz/Buzz/TranscriptionStore.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "53"
|
||||
endingLineNumber = "53"
|
||||
offsetFromSymbolStart = "52">
|
||||
</Location>
|
||||
</Locations>
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "F6AE77D4-C45E-43AE-B175-12A9E6B586BC"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/TranscriptionStore.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "77"
|
||||
endingLineNumber = "77"
|
||||
landmarkName = "save(transcriptions:completion:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "E35DFA40-15F8-454F-A838-FBC67F035DB4"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/ContentView.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "220"
|
||||
endingLineNumber = "220"
|
||||
landmarkName = "body"
|
||||
landmarkType = "24">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "FDFA078D-E230-4A3A-A6F2-0A5879EDB54C"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/ContentView.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "54"
|
||||
endingLineNumber = "54"
|
||||
landmarkName = "saveTranscriptions()"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "7D258CDB-F4E4-45CF-8BBF-601D3A5C2795"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/TranscriptionStore.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "54"
|
||||
endingLineNumber = "54"
|
||||
landmarkName = "load(completion:)"
|
||||
landmarkType = "7">
|
||||
<Locations>
|
||||
<Location
|
||||
uuid = "7D258CDB-F4E4-45CF-8BBF-601D3A5C2795 - 29fb92ca7875e7c6"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
symbolName = "closure #2 @Swift.MainActor () -> () in closure #1 () -> () in static Buzz.TranscriptionStore.load(completion: (Swift.Result<Swift.Array<Buzz.Transcription>, Swift.Error>) -> ()) -> ()"
|
||||
moduleName = "Buzz"
|
||||
usesParentBreakpointCondition = "Yes"
|
||||
urlString = "file:///Users/chidiwilliams/src/Buzz.swift/Buzz/Buzz/TranscriptionStore.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "49"
|
||||
endingLineNumber = "49"
|
||||
offsetFromSymbolStart = "63">
|
||||
</Location>
|
||||
<Location
|
||||
uuid = "7D258CDB-F4E4-45CF-8BBF-601D3A5C2795 - b18ebd4f1f815ed0"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
symbolName = "closure #1 (Buzz.TranscriptionStore.TranscriptionType) -> Buzz.Transcription in closure #2 @Swift.MainActor () -> () in closure #1 () -> () in static Buzz.TranscriptionStore.load(completion: (Swift.Result<Swift.Array<Buzz.Transcription>, Swift.Error>) -> ()) -> ()"
|
||||
moduleName = "Buzz"
|
||||
usesParentBreakpointCondition = "Yes"
|
||||
urlString = "file:///Users/chidiwilliams/src/Buzz.swift/Buzz/Buzz/TranscriptionStore.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "49"
|
||||
endingLineNumber = "49"
|
||||
offsetFromSymbolStart = "31">
|
||||
</Location>
|
||||
</Locations>
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "66C62EEE-0B27-48E0-90D0-1C9B8863E873"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/TranscriptionStore.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "71"
|
||||
endingLineNumber = "71"
|
||||
landmarkName = "save(transcriptions:completion:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "87586444-4E10-460F-A447-BDD0BF310056"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/ContentView.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "225"
|
||||
endingLineNumber = "225"
|
||||
landmarkName = "body"
|
||||
landmarkType = "24">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "7BFD476D-22B0-4425-9431-30057ABE7355"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/ContentView.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "62"
|
||||
endingLineNumber = "62"
|
||||
landmarkName = "onDismissFileTranscriptionSheet()"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "35EE5954-5D37-4641-8690-61606E07299C"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/ContentView.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "15"
|
||||
endingLineNumber = "15"
|
||||
landmarkName = "ContentView"
|
||||
landmarkType = "14">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "1403C2F5-0283-4464-988B-6854F819B713"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/ContentView.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "219"
|
||||
endingLineNumber = "219"
|
||||
landmarkName = "body"
|
||||
landmarkType = "24">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "2D8182A1-1C07-4D80-8671-42F6502A529C"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/ContentView.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "223"
|
||||
endingLineNumber = "223"
|
||||
landmarkName = "body"
|
||||
landmarkType = "24">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "75B52E99-A623-40FC-A74D-84DE0543333B"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/Transcription.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "10"
|
||||
endingLineNumber = "10"
|
||||
landmarkName = "ExportFormat"
|
||||
landmarkType = "13">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "CA0ECFE1-DB79-4F38-9D45-BBAF5B1A9540"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/Models/Transcription.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "24"
|
||||
endingLineNumber = "24"
|
||||
landmarkName = "init(title:segments:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "217691F9-012F-467B-A988-5DF1127A4D0C"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/ModelLoader.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "13"
|
||||
endingLineNumber = "13"
|
||||
landmarkName = "isAvailable(model:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "3E6BA4D3-ABD5-4672-AF9D-30BB491F6ECC"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/ModelLoader.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "16"
|
||||
endingLineNumber = "16"
|
||||
landmarkName = "isAvailable(model:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "33404C4B-137B-45C7-980E-DF8B8A887D5C"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/TranscriptionStore.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "48"
|
||||
endingLineNumber = "48"
|
||||
landmarkName = "load(completion:)"
|
||||
landmarkType = "7">
|
||||
<Locations>
|
||||
<Location
|
||||
uuid = "33404C4B-137B-45C7-980E-DF8B8A887D5C - abbb36f13f4ff563"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
symbolName = "closure #1 () -> () in static Buzz.TranscriptionStore.load(completion: (Swift.Result<Swift.Array<Buzz.Transcription>, Swift.Error>) -> ()) -> ()"
|
||||
moduleName = "Buzz"
|
||||
usesParentBreakpointCondition = "Yes"
|
||||
urlString = "file:///Users/chidiwilliams/src/Buzz.swift/Buzz/Buzz/TranscriptionStore.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "48"
|
||||
endingLineNumber = "48"
|
||||
offsetFromSymbolStart = "1983">
|
||||
</Location>
|
||||
<Location
|
||||
uuid = "33404C4B-137B-45C7-980E-DF8B8A887D5C - 29fb92ca7875e7c6"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
symbolName = "closure #2 @Swift.MainActor () -> () in closure #1 () -> () in static Buzz.TranscriptionStore.load(completion: (Swift.Result<Swift.Array<Buzz.Transcription>, Swift.Error>) -> ()) -> ()"
|
||||
moduleName = "Buzz"
|
||||
usesParentBreakpointCondition = "Yes"
|
||||
urlString = "file:///Users/chidiwilliams/src/Buzz.swift/Buzz/Buzz/TranscriptionStore.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "49"
|
||||
endingLineNumber = "49"
|
||||
offsetFromSymbolStart = "36">
|
||||
</Location>
|
||||
</Locations>
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "61E2EA0B-8FE6-4C60-85C7-0D306DAF6B5A"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/TranscriptionStore.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "38"
|
||||
endingLineNumber = "38"
|
||||
landmarkName = "load(completion:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "5BDDE7EE-840D-4E3B-BB71-26C06E4CF4E8"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/BuzzApp.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "18"
|
||||
endingLineNumber = "18">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "102EB1A7-944A-45E9-96B9-7DFEBCCBDA1D"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/TranscriptionExporter.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "70"
|
||||
endingLineNumber = "70"
|
||||
landmarkName = "export(transcription:format:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "1140C7DF-92BB-4FE0-B2D7-85617DBA41DC"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/TranscriptionExporter.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "71"
|
||||
endingLineNumber = "71"
|
||||
landmarkName = "export(transcription:format:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "88C9EB37-EDCA-4815-8C89-6AAB9EC10DCF"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Buzz/ContentView.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "231"
|
||||
endingLineNumber = "231"
|
||||
landmarkName = "body"
|
||||
landmarkType = "24">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
</Breakpoints>
|
||||
</Bucket>
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>Buzz.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>CI.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>98D5EC2A2986F6DA0011BC2D</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>98D5EC3B2986F6DD0011BC2D</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>98D5EC452986F6DD0011BC2D</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0",
|
||||
"green" : "0",
|
||||
"red" : "205"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0",
|
||||
"green" : "0",
|
||||
"red" : "205"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "mac16.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "16x16"
|
||||
},
|
||||
{
|
||||
"filename" : "mac32.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "16x16"
|
||||
},
|
||||
{
|
||||
"filename" : "mac32 1.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "32x32"
|
||||
},
|
||||
{
|
||||
"filename" : "mac64.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "32x32"
|
||||
},
|
||||
{
|
||||
"filename" : "mac128.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "128x128"
|
||||
},
|
||||
{
|
||||
"filename" : "mac256.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "128x128"
|
||||
},
|
||||
{
|
||||
"filename" : "mac256 1.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "256x256"
|
||||
},
|
||||
{
|
||||
"filename" : "mac512.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "256x256"
|
||||
},
|
||||
{
|
||||
"filename" : "mac512 1.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "512x512"
|
||||
},
|
||||
{
|
||||
"filename" : "mac1024.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "512x512"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Buzz.swift/Buzz/Assets.xcassets/AppIcon.appiconset/mac1024.png
Normal file
After Width: | Height: | Size: 217 KiB |
BIN
Buzz.swift/Buzz/Assets.xcassets/AppIcon.appiconset/mac128.png
Normal file
After Width: | Height: | Size: 8.8 KiB |
BIN
Buzz.swift/Buzz/Assets.xcassets/AppIcon.appiconset/mac16.png
Normal file
After Width: | Height: | Size: 516 B |
BIN
Buzz.swift/Buzz/Assets.xcassets/AppIcon.appiconset/mac256 1.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
Buzz.swift/Buzz/Assets.xcassets/AppIcon.appiconset/mac256.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
Buzz.swift/Buzz/Assets.xcassets/AppIcon.appiconset/mac32 1.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Buzz.swift/Buzz/Assets.xcassets/AppIcon.appiconset/mac32.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Buzz.swift/Buzz/Assets.xcassets/AppIcon.appiconset/mac512 1.png
Normal file
After Width: | Height: | Size: 75 KiB |
BIN
Buzz.swift/Buzz/Assets.xcassets/AppIcon.appiconset/mac512.png
Normal file
After Width: | Height: | Size: 75 KiB |
BIN
Buzz.swift/Buzz/Assets.xcassets/AppIcon.appiconset/mac64.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
6
Buzz.swift/Buzz/Assets.xcassets/Contents.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
119
Buzz.swift/Buzz/AudioRecorder/AudioRecorder.swift
Normal file
|
@ -0,0 +1,119 @@
|
|||
//
|
||||
// AudioRecorder.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 03/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AVFoundation
|
||||
import whisper
|
||||
|
||||
class AudioRecorder: NSObject, AVCaptureAudioDataOutputSampleBufferDelegate {
|
||||
var session: AVCaptureSession
|
||||
let recordingQueue = DispatchQueue(label: "recording",
|
||||
qos: DispatchQoS(qosClass: .userInitiated, relativePriority: 0))
|
||||
static let SAMPLE_RATE = WHISPER_SAMPLE_RATE
|
||||
var microphone: AVCaptureDevice?
|
||||
var callback: ((UnsafeMutablePointer<Float>?, Int) -> Void)?
|
||||
|
||||
init(microphoneUniqueID: String?) {
|
||||
session = AVCaptureSession()
|
||||
if let microphoneUniqueID = microphoneUniqueID {
|
||||
self.microphone = AVCaptureDevice(uniqueID: microphoneUniqueID)
|
||||
} else {
|
||||
self.microphone = AVCaptureDevice.default(for: .audio)
|
||||
}
|
||||
super.init()
|
||||
configureSession()
|
||||
|
||||
}
|
||||
|
||||
func record(callback: @escaping ((UnsafeMutablePointer<Float>?, Int) -> Void)) {
|
||||
self.callback = callback
|
||||
session.startRunning()
|
||||
}
|
||||
|
||||
func pause() {
|
||||
session.stopRunning()
|
||||
}
|
||||
|
||||
func configureSession() {
|
||||
if let device = self.microphone {
|
||||
if #available(OSX 10.14, *) {
|
||||
let status = AVCaptureDevice.authorizationStatus(for: .audio)
|
||||
if status == .notDetermined {
|
||||
AVCaptureDevice.requestAccess(for: .audio) { granted in
|
||||
self.configureSession()
|
||||
}
|
||||
return
|
||||
}
|
||||
if status != .authorized {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var input: AVCaptureDeviceInput
|
||||
do {
|
||||
try device.lockForConfiguration()
|
||||
try input = AVCaptureDeviceInput(device: device)
|
||||
device.unlockForConfiguration()
|
||||
} catch {
|
||||
device.unlockForConfiguration()
|
||||
return
|
||||
}
|
||||
|
||||
let output = AVCaptureAudioDataOutput()
|
||||
output.setSampleBufferDelegate(self, queue: recordingQueue)
|
||||
output.audioSettings = [
|
||||
AVFormatIDKey: kAudioFormatLinearPCM,
|
||||
AVSampleRateKey: AudioRecorder.SAMPLE_RATE,
|
||||
AVLinearPCMBitDepthKey: 32,
|
||||
AVLinearPCMIsFloatKey: true,
|
||||
AVNumberOfChannelsKey: 1
|
||||
] as [String : Any]
|
||||
|
||||
session.beginConfiguration()
|
||||
if !session.canAddInput(input) {
|
||||
return
|
||||
}
|
||||
session.addInput(input)
|
||||
|
||||
if !session.canAddOutput(output) {
|
||||
return
|
||||
}
|
||||
session.addOutput(output)
|
||||
session.commitConfiguration()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
|
||||
var blockBuffer: CMBlockBuffer? = nil
|
||||
|
||||
var audioBufferList = AudioBufferList( mNumberBuffers: 1, mBuffers: AudioBuffer( mNumberChannels: 0, mDataByteSize: 0, mData: nil ))
|
||||
let status = CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(
|
||||
sampleBuffer,
|
||||
bufferListSizeNeededOut: nil,
|
||||
bufferListOut: &audioBufferList,
|
||||
bufferListSize: MemoryLayout.size(ofValue: audioBufferList),
|
||||
blockBufferAllocator: kCFAllocatorSystemDefault,
|
||||
blockBufferMemoryAllocator: kCFAllocatorSystemDefault,
|
||||
flags: UInt32(kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment), blockBufferOut: &blockBuffer)
|
||||
if status != 0 {
|
||||
print("CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer failed with error code: \(status)")
|
||||
return
|
||||
}
|
||||
|
||||
let audioBufferListPointer = UnsafeMutableAudioBufferListPointer(&audioBufferList)
|
||||
for buffer in audioBufferListPointer {
|
||||
if buffer.mData != nil {
|
||||
let count = Int(buffer.mDataByteSize) / MemoryLayout<Float>.size
|
||||
let samples = UnsafeMutablePointer<Float>(OpaquePointer(buffer.mData))
|
||||
if let callback = callback {
|
||||
callback(samples, count)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
14
Buzz.swift/Buzz/Buzz.entitlements
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-write</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
17
Buzz.swift/Buzz/BuzzApp.swift
Normal file
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// BuzzApp.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 29/01/2023.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@main
|
||||
struct BuzzApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
}
|
49
Buzz.swift/Buzz/CircularProgressView.swift
Normal file
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// ProgressView.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 27/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct CircularProgressView: View {
|
||||
@Binding var current: Float
|
||||
@Binding var total: Float
|
||||
var stopAction: () -> Void = {}
|
||||
|
||||
var body: some View {
|
||||
Button(action: stopAction) {
|
||||
ZStack() {
|
||||
Circle()
|
||||
.trim(from: 0, to: CGFloat(Float(current) / Float(total)))
|
||||
.stroke(Color.accentColor, style: StrokeStyle(lineWidth: 2, lineCap: .round))
|
||||
.rotationEffect(.degrees(-90))
|
||||
.frame(width: 15, height: 15)
|
||||
Image(systemName: "stop.fill")
|
||||
.resizable()
|
||||
.frame(width: 5, height: 5)
|
||||
.foregroundColor(.accentColor)
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct CircularProgressView_Previews: PreviewProvider {
|
||||
static let timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()
|
||||
static var progress: Float = 0.0
|
||||
|
||||
static var previews: some View {
|
||||
CircularProgressView(
|
||||
current: Binding(get: {progress}, set: {
|
||||
_,_ in
|
||||
}), total: Binding(get: {1}, set: {_, _ in}))
|
||||
.onReceive(timer, perform: { _ in
|
||||
progress += 0.2
|
||||
progress = progress < 1.0 ? progress : 0.0
|
||||
})
|
||||
}
|
||||
}
|
241
Buzz.swift/Buzz/ContentView.swift
Normal file
|
@ -0,0 +1,241 @@
|
|||
//
|
||||
// ContentView.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 29/01/2023.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import AVFoundation
|
||||
|
||||
struct ContentView: View {
|
||||
@State private var isRecordingOptionsSheetPresented = false
|
||||
@State private var isFileTranscriptionOptionsSheetPresented = false
|
||||
@Environment(\.openWindow) private var openWindow
|
||||
@State var recordingOptions = RecordingTranscriptionOptions()
|
||||
@State var recordingAction: SheetAction = .none
|
||||
@State var fileTranscriptionAction: SheetAction = .none
|
||||
@State var isRecording = false
|
||||
@State var recorder: AudioRecorder? = nil
|
||||
@State var transcriptionWindow: NSWindow? = nil
|
||||
@State var line = ""
|
||||
@State var transcriber: RecordingTranscriber?
|
||||
@State var currentRecordingTranscription: Transcription?
|
||||
@StateObject private var transcriptionStore = TranscriptionStore()
|
||||
@State var selectedTranscription: Transcription? = nil
|
||||
@StateObject var fileTranscriptionOptions = FileTranscriptionOptions(file: URL(filePath: ""))
|
||||
@State var shouldShowDeleteDialog = false
|
||||
@State var searchText = ""
|
||||
|
||||
var transcriptions: [Transcription] {
|
||||
let filtered: [Transcription]
|
||||
if searchText.isEmpty {
|
||||
filtered = transcriptionStore.transcriptions
|
||||
} else {
|
||||
let searchWords = searchText.components(separatedBy: .whitespaces).filter { !$0.isEmpty }
|
||||
|
||||
// Each search word is in the title or in a segment
|
||||
filtered = transcriptionStore.transcriptions.filter { transcription in
|
||||
return searchWords.allSatisfy({ word in
|
||||
transcription.title.localizedCaseInsensitiveContains(word) ||
|
||||
transcription.segments.contains { segment in
|
||||
segment.text.localizedCaseInsensitiveContains(word)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let sorted = filtered.sorted(by: { $0.timeStarted > $1.timeStarted })
|
||||
return sorted
|
||||
}
|
||||
|
||||
private func saveTranscriptions() {
|
||||
TranscriptionStore.save(transcriptions: transcriptionStore.transcriptions) { result in
|
||||
if case .failure(let failure) = result {
|
||||
fatalError(failure.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func onDismissFileTranscriptionSheet() {
|
||||
if fileTranscriptionAction == .success {
|
||||
let transcriber = FileTranscriber(transcriptionOptions: self.fileTranscriptionOptions)
|
||||
let transcription = transcriber.transcribe()
|
||||
transcriptionStore.transcriptions.append(transcription)
|
||||
selectedTranscription = transcription
|
||||
}
|
||||
}
|
||||
|
||||
private func onDismissRecordingSheet() {
|
||||
if recordingAction == .success {
|
||||
// reset line
|
||||
line = ""
|
||||
|
||||
// TODO: can this be a view model instead?
|
||||
let transcriber = RecordingTranscriber(options: recordingOptions)
|
||||
currentRecordingTranscription = Transcription(title: "New Recording")
|
||||
transcriber.start() { segment in
|
||||
DispatchQueue.main.async {
|
||||
line = segment.text
|
||||
currentRecordingTranscription?.segments.insert(segment, at: 0)
|
||||
}
|
||||
}
|
||||
self.transcriber = transcriber
|
||||
|
||||
|
||||
let width = 500
|
||||
let height = 75
|
||||
var x: Int
|
||||
if let screen = NSScreen.main {
|
||||
x = Int(screen.frame.midX) - width / 2
|
||||
} else {
|
||||
x = 0
|
||||
}
|
||||
let y = height
|
||||
|
||||
transcriptionWindow = NSWindow(
|
||||
contentRect: NSRect(x: x, y: y, width: width, height: height),
|
||||
styleMask: [.fullSizeContentView, .resizable], backing: .buffered, defer: false
|
||||
)
|
||||
transcriptionWindow?.contentView = NSHostingView(rootView: FloatingTranscriptionView(line: $line))
|
||||
transcriptionWindow?.setContentSize(NSSize(width: width, height: height))
|
||||
transcriptionWindow?.level = .screenSaver
|
||||
transcriptionWindow?.backgroundColor = .clear
|
||||
transcriptionWindow?.isMovableByWindowBackground = true
|
||||
transcriptionWindow?.makeKeyAndOrderFront(nil)
|
||||
|
||||
isRecording = true
|
||||
// reset recording action state
|
||||
recordingAction = .none
|
||||
}
|
||||
}
|
||||
|
||||
private func onClickRecord() {
|
||||
if isRecording {
|
||||
isRecording = false
|
||||
|
||||
transcriber?.stop()
|
||||
currentRecordingTranscription?.timeEnded = .now
|
||||
|
||||
transcriptionWindow?.resignKey()
|
||||
transcriptionWindow?.close()
|
||||
|
||||
transcriptionStore.transcriptions.append(self.currentRecordingTranscription!)
|
||||
} else {
|
||||
isRecordingOptionsSheetPresented = true
|
||||
}
|
||||
}
|
||||
|
||||
private func onClickImport() {
|
||||
let panel = NSOpenPanel()
|
||||
panel.allowsMultipleSelection = false
|
||||
panel.canChooseDirectories = false
|
||||
panel.allowedContentTypes = [.audiovisualContent]
|
||||
guard panel.runModal() == .OK else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let url = panel.url else {
|
||||
return
|
||||
}
|
||||
|
||||
fileTranscriptionOptions.file = url
|
||||
isFileTranscriptionOptionsSheetPresented = true
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationSplitView(sidebar: {
|
||||
List(transcriptions, id: \.self, selection: $selectedTranscription) { transcription in
|
||||
TranscriptionListRowContentView(transcription: transcription)
|
||||
.padding(.vertical, 8)
|
||||
.padding(.horizontal, 12)
|
||||
.contextMenu() {
|
||||
Button(action: { shouldShowDeleteDialog = true }) {
|
||||
Text("Delete")
|
||||
}
|
||||
}
|
||||
}
|
||||
}, detail: {
|
||||
if let transcription = selectedTranscription {
|
||||
TranscriptionView(transcription: transcription)
|
||||
}
|
||||
})
|
||||
.searchable(text: $searchText, placement: .sidebar, prompt: "Search transcriptions")
|
||||
.onChange(of: transcriptions, perform: { transcriptions in
|
||||
// This should reset the selected transcription to the first item in the filtered list,
|
||||
// but it reports an error with updating state while the view is changing...
|
||||
selectedTranscription = nil
|
||||
})
|
||||
.toolbar() {
|
||||
Button(action: onClickRecord) {
|
||||
Image(systemName: isRecording ?
|
||||
"stop.circle" : "record.circle")
|
||||
Text(isRecording ? "Stop" : "Record")
|
||||
}
|
||||
.help(isRecording ? "Stop" : "Record")
|
||||
.sheet(isPresented: $isRecordingOptionsSheetPresented, onDismiss: onDismissRecordingSheet) {
|
||||
RecordingTranscriptionOptionsView(recordingAction: $recordingAction, options: recordingOptions)
|
||||
.frame(width: 360)
|
||||
}
|
||||
|
||||
Button(action: onClickImport) {
|
||||
Image(systemName: "square.and.arrow.down")
|
||||
Text("Import")
|
||||
}
|
||||
.help("Import")
|
||||
.sheet(isPresented: $isFileTranscriptionOptionsSheetPresented, onDismiss: onDismissFileTranscriptionSheet) {
|
||||
FileTranscriptionOptionsView(
|
||||
options: fileTranscriptionOptions,
|
||||
action: $fileTranscriptionAction
|
||||
)
|
||||
.frame(width: 360)
|
||||
}
|
||||
|
||||
if let transcription = selectedTranscription {
|
||||
Menu(content: {
|
||||
ForEach(ExportFormat.allCases, id: \.rawValue) { exportFormat in
|
||||
Button(exportFormat.rawValue) {
|
||||
TranscriptionExporter.export(transcription: transcription, format: exportFormat)
|
||||
}
|
||||
}
|
||||
}, label: {
|
||||
Image(systemName: "square.and.arrow.up")
|
||||
Text("Export")
|
||||
})
|
||||
}
|
||||
}
|
||||
.alert("Are you sure you want to permanently delete the selected transcriptions?", isPresented: $shouldShowDeleteDialog, actions: {
|
||||
Button("Delete") {
|
||||
guard let transcription = selectedTranscription else { return }
|
||||
guard let transcriptionIndex = transcriptionStore.transcriptions.firstIndex(of: transcription) else { return }
|
||||
transcriptionStore.transcriptions.remove(at: transcriptionIndex)
|
||||
}
|
||||
Button("Cancel", role: .cancel) {}
|
||||
}, message: {
|
||||
Text("You cannot undo this action.")
|
||||
})
|
||||
.onAppear() {
|
||||
TranscriptionStore.load() { result in
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
fatalError(error.localizedDescription)
|
||||
case .success(let transcriptions):
|
||||
transcriptionStore.transcriptions = transcriptions
|
||||
}
|
||||
}
|
||||
}
|
||||
.onReceive(
|
||||
NotificationCenter.default.publisher(for: NSApplication.willResignActiveNotification),
|
||||
perform: { _ in saveTranscriptions() })
|
||||
.onDeleteCommand() {
|
||||
shouldShowDeleteDialog = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ContentView(
|
||||
)
|
||||
}
|
||||
}
|
62
Buzz.swift/Buzz/FloatingTranscriptionView.swift
Normal file
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// TranscriptionViewer.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 05/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct VisualEffectView: NSViewRepresentable
|
||||
{
|
||||
let material: NSVisualEffectView.Material
|
||||
let blendingMode: NSVisualEffectView.BlendingMode
|
||||
|
||||
func makeNSView(context: Context) -> NSVisualEffectView
|
||||
{
|
||||
let visualEffectView = NSVisualEffectView()
|
||||
visualEffectView.material = material
|
||||
visualEffectView.blendingMode = blendingMode
|
||||
visualEffectView.state = NSVisualEffectView.State.active
|
||||
visualEffectView.wantsLayer = true
|
||||
visualEffectView.layer?.cornerRadius = 16.0
|
||||
visualEffectView.layer?.borderWidth = 0.0
|
||||
visualEffectView.layer?.borderColor = .clear
|
||||
return visualEffectView
|
||||
}
|
||||
|
||||
func updateNSView(_ visualEffectView: NSVisualEffectView, context: Context)
|
||||
{
|
||||
visualEffectView.material = material
|
||||
visualEffectView.blendingMode = blendingMode
|
||||
}
|
||||
}
|
||||
|
||||
struct FloatingTranscriptionView: View {
|
||||
@Binding var line: String
|
||||
|
||||
var text: some View {
|
||||
Text(line)
|
||||
.padding()
|
||||
.font(.title3)
|
||||
.multilineTextAlignment(.center)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
if line.isEmpty {
|
||||
text.background(.clear)
|
||||
} else {
|
||||
text.background(VisualEffectView(material: .fullScreenUI, blendingMode: .behindWindow))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FloatingTranscriptionView_Previews: PreviewProvider {
|
||||
@State private static var line = "On the mountains of truth you can never climb in vain: either you will reach a point higher up today, or you will be training your powers so that you will be able to climb higher tomorrow."
|
||||
|
||||
static var previews: some View {
|
||||
FloatingTranscriptionView(line: $line)
|
||||
}
|
||||
}
|
46
Buzz.swift/Buzz/ModelLoader.swift
Normal file
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// ModelLoader.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 08/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class ModelLoader {
|
||||
static func isAvailable(model: WhisperModel) -> Bool {
|
||||
do {
|
||||
let modelPath = try getModelPath(model: model)
|
||||
return FileManager.default.fileExists(atPath: modelPath.path(percentEncoded: false))
|
||||
} catch {
|
||||
print(error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
static func getModelPath(model: WhisperModel) throws -> URL {
|
||||
return try FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
|
||||
.appending(path: "Buzz")
|
||||
.appending(path: "Models")
|
||||
.appendingPathComponent("ggml-whisper-\(model.id).bin")
|
||||
}
|
||||
|
||||
static func getModelByteSize(model: WhisperModel) -> Int64 {
|
||||
switch model {
|
||||
case .tiny, .tiny_en:
|
||||
return 77_700_000
|
||||
case .base, .base_en:
|
||||
return 148_000_000
|
||||
case .small, .small_en:
|
||||
return 488_000_000
|
||||
case .medium, .medium_en:
|
||||
return 1_530_000_000
|
||||
case .large:
|
||||
return 3_090_000_000
|
||||
}
|
||||
}
|
||||
|
||||
static func getModelDownloadURL(model: WhisperModel) -> URL? {
|
||||
return URL(string: "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-\(model.id).bin")
|
||||
}
|
||||
}
|
12
Buzz.swift/Buzz/Models/ExportFormat.swift
Normal file
|
@ -0,0 +1,12 @@
|
|||
//
|
||||
// ExportFormat.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 20/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum ExportFormat: String, CaseIterable {
|
||||
case TXT, SRT, VTT
|
||||
}
|
56
Buzz.swift/Buzz/Models/FileTranscription.swift
Normal file
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// FileTranscription.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 20/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class FileTranscription: Transcription {
|
||||
@Published var file: URL
|
||||
@Published var status: Status = .inProgress(Status.Progress())
|
||||
|
||||
enum Status: Codable, Equatable, Hashable {
|
||||
struct Progress: Codable, Equatable, Hashable {
|
||||
var current = 0.0
|
||||
var total = 100.0
|
||||
}
|
||||
|
||||
case inProgress(Progress), completed
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case file, status
|
||||
}
|
||||
|
||||
init(file: URL) {
|
||||
self.file = file
|
||||
super.init(title: file.lastPathComponent)
|
||||
}
|
||||
|
||||
static func ==(lhs: FileTranscription, rhs: FileTranscription) -> Bool {
|
||||
return lhs.file == rhs.file && lhs.status == rhs.status && (lhs as Transcription) == (rhs as Transcription)
|
||||
}
|
||||
|
||||
override func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(file)
|
||||
hasher.combine(status)
|
||||
super.hash(into: &hasher)
|
||||
}
|
||||
|
||||
required init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
file = try values.decode(URL.self, forKey: .file)
|
||||
status = try values.decode(Status.self, forKey: .status)
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
override func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(file, forKey: .file)
|
||||
try container.encode(status, forKey: .status)
|
||||
try super.encode(to: encoder)
|
||||
}
|
||||
}
|
||||
|
12
Buzz.swift/Buzz/Models/SheetAction.swift
Normal file
|
@ -0,0 +1,12 @@
|
|||
//
|
||||
// SheetAction.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 20/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum SheetAction {
|
||||
case success, none
|
||||
}
|
64
Buzz.swift/Buzz/Models/Transcription.swift
Normal file
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// Transcription.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 17/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class Transcription: ObservableObject, Hashable, Identifiable, Codable {
|
||||
@Published var id = UUID()
|
||||
@Published var title: String
|
||||
@Published var timeStarted: Date = Date.now
|
||||
@Published var timeEnded: Date?
|
||||
@Published var segments: [Segment]
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case id, title, timeStarted, timeEnded, segments
|
||||
}
|
||||
|
||||
init(title: String, segments: [Segment] = []) {
|
||||
self.segments = segments
|
||||
self.title = title
|
||||
}
|
||||
|
||||
static func ==(lhs: Transcription, rhs: Transcription) -> Bool {
|
||||
return lhs.id == rhs.id
|
||||
&& lhs.title == rhs.title
|
||||
&& lhs.timeStarted == rhs.timeStarted
|
||||
&& lhs.segments == rhs.segments
|
||||
}
|
||||
|
||||
func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(id)
|
||||
hasher.combine(title)
|
||||
hasher.combine(timeStarted)
|
||||
hasher.combine(segments)
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(id, forKey: .id)
|
||||
try container.encode(title, forKey: .title)
|
||||
try container.encode(timeStarted, forKey: .timeStarted)
|
||||
try container.encode(timeEnded, forKey: .timeEnded)
|
||||
try container.encode(segments, forKey: .segments)
|
||||
}
|
||||
|
||||
required init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = try values.decode(UUID.self, forKey: .id)
|
||||
title = try values.decode(String.self, forKey: .title)
|
||||
timeStarted = try values.decode(Date.self, forKey: .timeStarted)
|
||||
timeEnded = try values.decode(Date?.self, forKey: .timeEnded)
|
||||
segments = try values.decode([Segment].self, forKey: .segments)
|
||||
}
|
||||
}
|
||||
|
||||
struct Segment: Equatable, Hashable, Codable, Identifiable {
|
||||
var id = UUID()
|
||||
var startMS: Int?
|
||||
var endMS: Int?
|
||||
let text: String
|
||||
}
|
28
Buzz.swift/Buzz/Models/TranscriptionOptions.swift
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// TranscriptionOptions.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 19/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AVFoundation
|
||||
|
||||
class TranscriptionOptions: ObservableObject {
|
||||
@Published var model: WhisperModel = .tiny
|
||||
@Published var task: WhisperTask = .transcribe
|
||||
@Published var language: WhisperLanguage = .en
|
||||
}
|
||||
|
||||
class FileTranscriptionOptions: TranscriptionOptions {
|
||||
@Published var file: URL
|
||||
|
||||
init(file: URL) {
|
||||
self.file = file
|
||||
}
|
||||
}
|
||||
|
||||
class RecordingTranscriptionOptions: TranscriptionOptions {
|
||||
@Published var microphone: AVCaptureDevice? = nil
|
||||
}
|
||||
|
151
Buzz.swift/Buzz/Models/Whisper.swift
Normal file
|
@ -0,0 +1,151 @@
|
|||
//
|
||||
// Whisper.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 20/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum WhisperModel: String, CaseIterable, Codable {
|
||||
case tiny, tiny_en, base, base_en,small, small_en, medium, medium_en, large
|
||||
|
||||
var id: String {
|
||||
displayName.lowercased()
|
||||
}
|
||||
|
||||
var displayName: String {
|
||||
switch self {
|
||||
case .tiny:
|
||||
return "Tiny"
|
||||
case .tiny_en:
|
||||
return "Tiny.en"
|
||||
case .base:
|
||||
return "Base"
|
||||
case .base_en:
|
||||
return "Base.en"
|
||||
case .small:
|
||||
return "Small"
|
||||
case .small_en:
|
||||
return "Small.en"
|
||||
case .medium:
|
||||
return "Medium"
|
||||
case .medium_en:
|
||||
return "Medium.en"
|
||||
case .large:
|
||||
return "Large"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum WhisperTask: String, CaseIterable, Codable {
|
||||
case transcribe, translate
|
||||
}
|
||||
|
||||
enum WhisperLanguage: String, CaseIterable, Codable {
|
||||
case en, zh, de, es, ru, ko, fr, ja, pt, tr, pl, ca, nl, ar, sv, it, id, hi, fi, vi, he, uk, el, ms, cs, ro, da, hu, ta, no, th, ur, hr, bg, lt, la, mi, ml, cy, sk, te, fa, lv, bn, sr, az, sl, kn, et, mk, br, eu, `is`, hy, ne, mn, bs, kk, sq, sw, gl, mr, pa, si, km, sn, yo, so, af, oc, ka, be, tg, sd, gu, am, yi, lo, uz, fo, ht, ps, tk, nn, mt, sa, lb, my, bo, tl, mg, `as`, tt, haw, ln, ha, ba, jw, su
|
||||
|
||||
var fullName: String {
|
||||
switch self {
|
||||
case .en: return "English"
|
||||
case .zh: return "Chinese"
|
||||
case .de: return "German"
|
||||
case .es: return "Spanish"
|
||||
case .ru: return "Russian"
|
||||
case .ko: return "Korean"
|
||||
case .fr: return "French"
|
||||
case .ja: return "Japanese"
|
||||
case .pt: return "Portuguese"
|
||||
case .tr: return "Turkish"
|
||||
case .pl: return "Polish"
|
||||
case .ca: return "Catalan"
|
||||
case .nl: return "Dutch"
|
||||
case .ar: return "Arabic"
|
||||
case .sv: return "Swedish"
|
||||
case .it: return "Italian"
|
||||
case .id: return "Indonesian"
|
||||
case .hi: return "Hindi"
|
||||
case .fi: return "Finnish"
|
||||
case .vi: return "Vietnamese"
|
||||
case .he: return "Hebrew"
|
||||
case .uk: return "Ukrainian"
|
||||
case .el: return "Greek"
|
||||
case .ms: return "Malay"
|
||||
case .cs: return "Czech"
|
||||
case .ro: return "Romanian"
|
||||
case .da: return "Danish"
|
||||
case .hu: return "Hungarian"
|
||||
case .ta: return "Tamil"
|
||||
case .no: return "Norwegian"
|
||||
case .th: return "Thai"
|
||||
case .ur: return "Urdu"
|
||||
case .hr: return "Croatian"
|
||||
case .bg: return "Bulgarian"
|
||||
case .lt: return "Lithuanian"
|
||||
case .la: return "Latin"
|
||||
case .mi: return "Maori"
|
||||
case .ml: return "Malayalam"
|
||||
case .cy: return "Welsh"
|
||||
case .sk: return "Slovak"
|
||||
case .te: return "Telugu"
|
||||
case .fa: return "Persian"
|
||||
case .lv: return "Latvian"
|
||||
case .bn: return "Bengali"
|
||||
case .sr: return "Serbian"
|
||||
case .az: return "Azerbaijani"
|
||||
case .sl: return "Slovenian"
|
||||
case .kn: return "Kannada"
|
||||
case .et: return "Estonian"
|
||||
case .mk: return "Macedonian"
|
||||
case .br: return "Breton"
|
||||
case .eu: return "Basque"
|
||||
case .is: return "Icelandic"
|
||||
case .hy: return "Armenian"
|
||||
case .ne: return "Nepali"
|
||||
case .mn: return "Mongolian"
|
||||
case .bs: return "Bosnian"
|
||||
case .kk: return "Kazakh"
|
||||
case .sq: return "Albanian"
|
||||
case .sw: return "Swahili"
|
||||
case .gl: return "Galician"
|
||||
case .mr: return "Marathi"
|
||||
case .pa: return "Punjabi"
|
||||
case .si: return "Sinhala"
|
||||
case .km: return "Khmer"
|
||||
case .sn: return "Shona"
|
||||
case .yo: return "Yoruba"
|
||||
case .so: return "Somali"
|
||||
case .af: return "Afrikaans"
|
||||
case .oc: return "Occitan"
|
||||
case .ka: return "Georgian"
|
||||
case .be: return "Belarusian"
|
||||
case .tg: return "Tajik"
|
||||
case .sd: return "Sindhi"
|
||||
case .gu: return "Gujarati"
|
||||
case .am: return "Amharic"
|
||||
case .yi: return "Yiddish"
|
||||
case .lo: return "Lao"
|
||||
case .uz: return "Uzbek"
|
||||
case .fo: return "Faroese"
|
||||
case .ht: return "Haitian creole"
|
||||
case .ps: return "Pashto"
|
||||
case .tk: return "Turkmen"
|
||||
case .nn: return "Nynorsk"
|
||||
case .mt: return "Maltese"
|
||||
case .sa: return "Sanskrit"
|
||||
case .lb: return "Luxembourgish"
|
||||
case .my: return "Myanmar"
|
||||
case .bo: return "Tibetan"
|
||||
case .tl: return "Tagalog"
|
||||
case .mg: return "Malagasy"
|
||||
case .as: return "Assamese"
|
||||
case .tt: return "Tatar"
|
||||
case .haw: return "Hawaiian"
|
||||
case .ln: return "Lingala"
|
||||
case .ha: return "Hausa"
|
||||
case .ba: return "Bashkir"
|
||||
case .jw: return "Javanese"
|
||||
case .su: return "Sundanese"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
173
Buzz.swift/Buzz/Recorder.swift
Normal file
|
@ -0,0 +1,173 @@
|
|||
//
|
||||
// Recorder.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 03/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AVFoundation
|
||||
|
||||
class Recorder: NSObject, AVCaptureAudioDataOutputSampleBufferDelegate {
|
||||
let alwaysMono = false
|
||||
var nChannels:UInt32 = 1
|
||||
let session : AVCaptureSession!
|
||||
static var isTranscribing = false
|
||||
static let realTimeQueue = DispatchQueue(label: "com.myapp.realtime",
|
||||
qos: DispatchQoS( qosClass:DispatchQoS.QoSClass.userInitiated, relativePriority: 0 ))
|
||||
static let transcriptionQueue = DispatchQueue(label: "transcription", qos: DispatchQoS(qosClass: DispatchQoS.QoSClass.userInitiated, relativePriority: 1))
|
||||
override init() {
|
||||
session = AVCaptureSession()
|
||||
super.init()
|
||||
}
|
||||
static var recorder:Recorder?
|
||||
static func record() ->Bool {
|
||||
if recorder == nil {
|
||||
recorder = Recorder()
|
||||
if !recorder!.setup(callback:record) {
|
||||
recorder = nil
|
||||
return false
|
||||
}
|
||||
}
|
||||
realTimeQueue.async {
|
||||
if !recorder!.session.isRunning {
|
||||
recorder!.session.startRunning()
|
||||
print("started running")
|
||||
}
|
||||
}
|
||||
transcriptionQueue.async {
|
||||
isTranscribing = true
|
||||
while isTranscribing {
|
||||
print("hello")
|
||||
sleep(5)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
static func pause() {
|
||||
recorder!.session.stopRunning()
|
||||
isTranscribing = false
|
||||
}
|
||||
func setup( callback:@escaping (()->Bool)) -> Bool {
|
||||
let device = AVCaptureDevice.default( for: AVMediaType.audio )
|
||||
if device == nil { return false }
|
||||
if let format = getActiveFormat() {
|
||||
nChannels = format.mChannelLayoutTag == kAudioChannelLayoutTag_Stereo ? 2 : 1
|
||||
print("active format is \((nChannels==2) ? "Stereo" : "Mono")")
|
||||
if alwaysMono {
|
||||
print( "Overriding to mono" )
|
||||
nChannels = 1
|
||||
}
|
||||
}
|
||||
if #available(OSX 10.14, *) {
|
||||
let status = AVCaptureDevice.authorizationStatus( for:AVMediaType.audio )
|
||||
if status == .notDetermined {
|
||||
AVCaptureDevice.requestAccess(for: AVMediaType.audio ){ granted in
|
||||
_ = callback()
|
||||
}
|
||||
return false
|
||||
} else if status != .authorized {
|
||||
return false
|
||||
}
|
||||
}
|
||||
var input : AVCaptureDeviceInput
|
||||
do {
|
||||
try device!.lockForConfiguration()
|
||||
try input = AVCaptureDeviceInput( device: device! )
|
||||
device!.unlockForConfiguration()
|
||||
} catch {
|
||||
device!.unlockForConfiguration()
|
||||
return false
|
||||
}
|
||||
let output = AVCaptureAudioDataOutput()
|
||||
output.setSampleBufferDelegate(self, queue: Recorder.realTimeQueue)
|
||||
let settings = [
|
||||
AVFormatIDKey: kAudioFormatLinearPCM,
|
||||
// AVNumberOfChannelsKey : nChannels,
|
||||
AVSampleRateKey : Recorder.SAMPLE_RATE,
|
||||
AVLinearPCMBitDepthKey : 32,
|
||||
AVLinearPCMIsFloatKey : true
|
||||
] as [String : Any]
|
||||
output.audioSettings = settings
|
||||
session.beginConfiguration()
|
||||
if !session.canAddInput( input ) {
|
||||
return false
|
||||
}
|
||||
session.addInput( input )
|
||||
if !session.canAddOutput( output ) {
|
||||
return false
|
||||
}
|
||||
session.addOutput( output )
|
||||
session.commitConfiguration()
|
||||
return true
|
||||
}
|
||||
func getActiveFormat() -> AudioFormatListItem? {
|
||||
if #available(OSX 10.15, *) {
|
||||
let device = AVCaptureDevice.default( for: AVMediaType.audio )
|
||||
if device == nil { return nil }
|
||||
let list = device!.activeFormat.formatDescription.audioFormatList
|
||||
if list.count < 1 { return nil }
|
||||
return list[0]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func captureOutput(_ captureOutput: AVCaptureOutput,
|
||||
didOutput sampleBuffer: CMSampleBuffer,
|
||||
from connection: AVCaptureConnection){
|
||||
var buffer: CMBlockBuffer? = nil
|
||||
var audioBufferList = AudioBufferList(
|
||||
mNumberBuffers: 1,
|
||||
mBuffers: AudioBuffer(mNumberChannels: nChannels, mDataByteSize: 0, mData: nil)
|
||||
)
|
||||
let status = CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(
|
||||
sampleBuffer,
|
||||
bufferListSizeNeededOut: nil,
|
||||
bufferListOut: &audioBufferList,
|
||||
bufferListSize: MemoryLayout<AudioBufferList>.size,
|
||||
blockBufferAllocator: nil,
|
||||
blockBufferMemoryAllocator: nil,
|
||||
flags: UInt32(kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment),
|
||||
blockBufferOut: &buffer
|
||||
)
|
||||
if status != 0 {
|
||||
print("got error code \(status)")
|
||||
return
|
||||
}
|
||||
|
||||
let abl = UnsafeMutableAudioBufferListPointer(&audioBufferList)
|
||||
for buff in abl {
|
||||
if buff.mData != nil {
|
||||
let count = Int(buff.mDataByteSize)/MemoryLayout<Float>.size
|
||||
let samples = UnsafeMutablePointer<Float>(OpaquePointer(buff.mData))
|
||||
process(samples:samples!, count:count)
|
||||
} else {
|
||||
print("No data!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let MAX_SECONDS_BEHIND = 10
|
||||
static let SAMPLE_RATE = 16_000
|
||||
|
||||
var circularBuffer: Array<Float> = []
|
||||
|
||||
func process( samples: UnsafeMutablePointer<Float>, count: Int ) {
|
||||
let array = (Array(UnsafeBufferPointer(start: samples, count: count)))
|
||||
print(rms(array: array), array.count)
|
||||
|
||||
if circularBuffer.count < MAX_SECONDS_BEHIND * Recorder.SAMPLE_RATE {
|
||||
print("appending")
|
||||
circularBuffer.append(contentsOf: array)
|
||||
}
|
||||
}
|
||||
|
||||
func rms(array: Array<Float>) -> Float {
|
||||
var sumSquares = Float(0)
|
||||
var count = Float(0)
|
||||
for elem in array {
|
||||
sumSquares += elem * elem
|
||||
count += 1
|
||||
}
|
||||
return (sumSquares / count).squareRoot()
|
||||
}
|
||||
}
|
113
Buzz.swift/Buzz/Transcriber/FileTranscriber.swift
Normal file
|
@ -0,0 +1,113 @@
|
|||
//
|
||||
// FileTranscriber.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 06/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import whisper
|
||||
import ffmpegkit
|
||||
import AVFoundation
|
||||
|
||||
class FileTranscriber {
|
||||
let transcriptionOptions: FileTranscriptionOptions
|
||||
|
||||
private let transcriptionQueue = DispatchQueue(label: "transcription.file", qos: DispatchQoS.userInitiated)
|
||||
private var isRunning = false
|
||||
private let SAMPLE_RATE = WHISPER_SAMPLE_RATE
|
||||
|
||||
init(transcriptionOptions: FileTranscriptionOptions) {
|
||||
self.transcriptionOptions = transcriptionOptions
|
||||
}
|
||||
|
||||
func fileToBuffer(wavFile: URL) throws -> AVAudioPCMBuffer {
|
||||
let wavAudioFile = try AVAudioFile(forReading: wavFile)
|
||||
let format = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: wavAudioFile.fileFormat.sampleRate, channels: wavAudioFile.fileFormat.channelCount, interleaved: false)!
|
||||
let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: UInt32(wavAudioFile.length))!
|
||||
try wavAudioFile.read(into: buffer)
|
||||
return buffer
|
||||
}
|
||||
|
||||
func transcribe() -> FileTranscription {
|
||||
let filePath = self.transcriptionOptions.file
|
||||
|
||||
let transcription = FileTranscription(file: filePath)
|
||||
|
||||
transcriptionQueue.async {
|
||||
let wavFile = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent(UUID().uuidString)
|
||||
.appendingPathExtension("wav")
|
||||
|
||||
guard let session = FFmpegKit.execute("""
|
||||
-i "\(filePath.path(percentEncoded: false))" -ac 1 -acodec pcm_s16le -ar \(self.SAMPLE_RATE) "\(wavFile.path(percentEncoded: false))"
|
||||
""") else {
|
||||
print("unable to create session")
|
||||
return
|
||||
}
|
||||
if (ReturnCode.isSuccess(session.getReturnCode())) {
|
||||
let buf = try! self.fileToBuffer(wavFile: wavFile)
|
||||
|
||||
let modelPath: URL
|
||||
do {
|
||||
modelPath = try ModelLoader.getModelPath(model: self.transcriptionOptions.model)
|
||||
} catch {
|
||||
fatalError(error.localizedDescription)
|
||||
}
|
||||
|
||||
let ctx = whisper_init_from_file(modelPath.path(percentEncoded: false))
|
||||
|
||||
self.isRunning = true
|
||||
|
||||
withUnsafeMutablePointer(to: &self.isRunning, {isRunning in
|
||||
var params = whisper_full_default_params(WHISPER_SAMPLING_GREEDY)
|
||||
params.print_realtime = true
|
||||
params.print_progress = false
|
||||
params.print_timestamps = false
|
||||
params.print_special = false
|
||||
params.translate = self.transcriptionOptions.task == .translate
|
||||
params.language = NSString(string: self.transcriptionOptions.language.rawValue).utf8String
|
||||
params.n_threads = 4
|
||||
params.offset_ms = 0
|
||||
params.encoder_begin_callback_user_data = UnsafeMutableRawPointer(mutating: isRunning)
|
||||
params.encoder_begin_callback = { _, userData in
|
||||
return userData?.load(as: Bool.self) ?? true
|
||||
}
|
||||
|
||||
let ret = whisper_full(ctx, params, buf.floatChannelData?.pointee, Int32(buf.frameLength))
|
||||
assert(ret == 0, "Failed to run the model")
|
||||
|
||||
let n_segments = whisper_full_n_segments(ctx)
|
||||
|
||||
for i in 0..<n_segments {
|
||||
let t0 = whisper_full_get_segment_t0(ctx, i)
|
||||
let t1 = whisper_full_get_segment_t1(ctx, i)
|
||||
|
||||
if let segment_text = whisper_full_get_segment_text(ctx, i) {
|
||||
if let ns_string = NSString(utf8String: segment_text) {
|
||||
DispatchQueue.main.async {
|
||||
transcription.segments.append(
|
||||
Segment(startMS: Int(t0), endMS: Int(t1), text: String(ns_string).trimmingCharacters(in: .whitespaces))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
whisper_print_timings(ctx)
|
||||
whisper_free(ctx)
|
||||
})
|
||||
|
||||
DispatchQueue.main.async {
|
||||
transcription.status = .completed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return transcription
|
||||
}
|
||||
|
||||
func stop() {
|
||||
isRunning = true
|
||||
}
|
||||
}
|
107
Buzz.swift/Buzz/Transcriber/RecordingTranscriber.swift
Normal file
|
@ -0,0 +1,107 @@
|
|||
//
|
||||
// RecordingTranscriber.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 06/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import whisper
|
||||
|
||||
class RecordingTranscriber {
|
||||
private let options: RecordingTranscriptionOptions
|
||||
private let recorder: AudioRecorder
|
||||
private var buffer: [Float] = []
|
||||
private var bufferSemaphore = DispatchSemaphore(value: 1)
|
||||
private let transcriptionQueue = DispatchQueue(label: "transcription.recording", qos: DispatchQoS.userInitiated)
|
||||
private var isRunning = false
|
||||
private static let SAMPLE_RATE = Int(WHISPER_SAMPLE_RATE)
|
||||
private static let STEP_SECS = 5
|
||||
private static let MAX_STEP_SIZE = RecordingTranscriber.STEP_SECS * RecordingTranscriber.SAMPLE_RATE
|
||||
private static let MAX_BACKLOG_SIZE = 2 * RecordingTranscriber.STEP_SECS * RecordingTranscriber.SAMPLE_RATE
|
||||
|
||||
init(options: RecordingTranscriptionOptions) {
|
||||
self.options = options
|
||||
self.recorder = AudioRecorder(microphoneUniqueID: options.microphone?.uniqueID)
|
||||
}
|
||||
|
||||
func start(callback: @escaping (Segment) -> Void) {
|
||||
recorder.record() { samples, sampleCount in
|
||||
self.bufferSemaphore.wait()
|
||||
if self.buffer.count < RecordingTranscriber.MAX_BACKLOG_SIZE {
|
||||
self.buffer.append(contentsOf: UnsafeBufferPointer(start: samples, count: sampleCount))
|
||||
}
|
||||
self.bufferSemaphore.signal()
|
||||
}
|
||||
|
||||
let startTime = Date.now
|
||||
var lastSegmentStartTime = startTime
|
||||
|
||||
transcriptionQueue.async {
|
||||
let modelPath: URL
|
||||
do {
|
||||
modelPath = try ModelLoader.getModelPath(model: self.options.model)
|
||||
} catch {
|
||||
fatalError(error.localizedDescription)
|
||||
}
|
||||
let ctx = whisper_init_from_file(modelPath.path(percentEncoded: false))
|
||||
|
||||
var params: whisper_full_params = whisper_full_default_params(WHISPER_SAMPLING_GREEDY)
|
||||
params.print_realtime = true
|
||||
params.print_progress = false
|
||||
params.print_timestamps = false
|
||||
params.print_special = false
|
||||
params.translate = self.options.task == .translate
|
||||
params.language = NSString(string: self.options.language.rawValue).utf8String
|
||||
params.n_threads = 4
|
||||
params.offset_ms = 0
|
||||
|
||||
self.isRunning = true
|
||||
while self.isRunning {
|
||||
if self.buffer.count < RecordingTranscriber.MAX_STEP_SIZE {
|
||||
continue
|
||||
}
|
||||
|
||||
self.bufferSemaphore.wait()
|
||||
let step_size = min(self.buffer.count, RecordingTranscriber.MAX_STEP_SIZE)
|
||||
var next_step = Array(self.buffer[0..<step_size])
|
||||
self.buffer = Array(self.buffer[step_size..<self.buffer.count])
|
||||
self.bufferSemaphore.signal()
|
||||
|
||||
let returnCode = whisper_full(ctx, params, &next_step, Int32(next_step.count))
|
||||
if returnCode != 0 {
|
||||
print("whisper model return code \(returnCode), skipping...")
|
||||
continue
|
||||
}
|
||||
|
||||
var text = ""
|
||||
|
||||
let n_segments = whisper_full_n_segments(ctx)
|
||||
for i in 0..<n_segments {
|
||||
if let segment_text = whisper_full_get_segment_text(ctx, i) {
|
||||
if let ns_string = NSString(utf8String: segment_text) {
|
||||
text += String(ns_string)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
text = text.trimmingCharacters(in: CharacterSet.whitespaces)
|
||||
|
||||
let segmentEndTime = lastSegmentStartTime.addingTimeInterval(Double(step_size) / Double(RecordingTranscriber.SAMPLE_RATE))
|
||||
let segment = Segment(
|
||||
startMS: Int(lastSegmentStartTime.timeIntervalSince(startTime)),
|
||||
endMS: Int(segmentEndTime.timeIntervalSince(startTime)),
|
||||
text: text)
|
||||
callback(segment)
|
||||
|
||||
lastSegmentStartTime = segmentEndTime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stop() {
|
||||
recorder.pause()
|
||||
isRunning = false
|
||||
}
|
||||
}
|
||||
|
80
Buzz.swift/Buzz/TranscriptionExporter.swift
Normal file
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// TranscriptionExporter.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 18/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AppKit
|
||||
|
||||
class TranscriptionExporter {
|
||||
private static let exportNameDateFormatter = {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "dd-MMM-yyyy HH-mm-ss" // 27-Dec-2022 14:11:54
|
||||
return formatter
|
||||
}()
|
||||
|
||||
static func export(transcription: Transcription, format: ExportFormat) {
|
||||
let panel = NSSavePanel()
|
||||
panel.allowedContentTypes = [.utf8PlainText]
|
||||
panel.nameFieldStringValue = getDefaultExportFilename(transcription: transcription, format: format)
|
||||
guard panel.runModal() == .OK else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let url = panel.url else {
|
||||
return
|
||||
}
|
||||
|
||||
var output = ""
|
||||
|
||||
switch (format) {
|
||||
case .TXT:
|
||||
for (index, segment) in transcription.segments.enumerated() {
|
||||
output = output.appending(segment.text)
|
||||
if index < transcription.segments.count - 1 {
|
||||
output = output.appending(" ")
|
||||
}
|
||||
}
|
||||
output = output.appending("\n")
|
||||
case .SRT:
|
||||
for (index, segment) in transcription.segments.enumerated() {
|
||||
guard let startMS = segment.startMS else {
|
||||
return
|
||||
}
|
||||
guard let endMS = segment.endMS else {
|
||||
return
|
||||
}
|
||||
output = output
|
||||
.appending("\(index + 1)\n")
|
||||
.appending("\(toTimestamp(ms: startMS, ms_separator: ",")) --> \(toTimestamp(ms: endMS, ms_separator: ","))\n")
|
||||
.appending("\(segment.text)\n\n")
|
||||
}
|
||||
case .VTT:
|
||||
output = output.appending("WEBVTT\n\n")
|
||||
transcription.segments.forEach() { segment in
|
||||
guard let startMS = segment.startMS else {
|
||||
return
|
||||
}
|
||||
guard let endMS = segment.endMS else {
|
||||
return
|
||||
}
|
||||
output = output
|
||||
.appending("\(toTimestamp(ms: startMS)) --> \(toTimestamp(ms: endMS))\n")
|
||||
.appending("\(segment.text)\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
try output.write(to: url, atomically: true, encoding: .utf8)
|
||||
NSWorkspace.shared.activateFileViewerSelecting([url])
|
||||
} catch {
|
||||
print("Failed to write output to file: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
private static func getDefaultExportFilename(transcription: Transcription, format: ExportFormat) -> String {
|
||||
return "\(transcription.title) (Transcribed on \(exportNameDateFormatter.string(from: .now)).\(format.rawValue.lowercased())"
|
||||
}
|
||||
}
|
37
Buzz.swift/Buzz/TranscriptionListRowContentView.swift
Normal file
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// TranscriptionListRowContentView.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 20/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct TranscriptionListRowContentView: View {
|
||||
@ObservedObject var transcription: Transcription
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("\(transcription.title)")
|
||||
.bold()
|
||||
Text("\(transcription.timeEnded?.formatted() ?? transcription.timeStarted.formatted())")
|
||||
.font(.caption)
|
||||
|
||||
if transcription.isInProgressFileTranscription() {
|
||||
ProgressView()
|
||||
.progressViewStyle(.linear)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TranscriptionListRowContentView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
TranscriptionListRowContentView(transcription: {
|
||||
Transcription(title: "Transcription", segments: [
|
||||
|
||||
])
|
||||
}())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// FileTranscriptionOptionsView.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 19/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct FileTranscriptionOptionsView: View {
|
||||
@ObservedObject var options: TranscriptionOptions
|
||||
|
||||
@Binding var action: SheetAction
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(header: Text("Transcription").bold()) {
|
||||
TranscriptionOptionsView(options: options)
|
||||
}
|
||||
Spacer().frame(height: 24)
|
||||
Button("Run") {
|
||||
action = .success
|
||||
dismiss()
|
||||
}.keyboardShortcut(.defaultAction)
|
||||
}
|
||||
.padding(24)
|
||||
}
|
||||
}
|
||||
|
||||
struct FileTranscriptionOptionsView_Previews: PreviewProvider {
|
||||
private static var transcriptionOptions = TranscriptionOptions()
|
||||
private static var action: SheetAction = .none
|
||||
|
||||
static var previews: some View {
|
||||
FileTranscriptionOptionsView(
|
||||
options: transcriptionOptions, action: Binding(get: {action}, set: {_,_ in}))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// ModelDownloadTask.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 28/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class ModelDownloadTask: NSObject, ObservableObject, URLSessionDownloadDelegate {
|
||||
@Published var bytesWritten: Float = 0
|
||||
@Published var bytesExpected: Float = 0
|
||||
@Published var isDownloading = false
|
||||
|
||||
private lazy var urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
|
||||
private var downloadTask: URLSessionDownloadTask?
|
||||
private var model: WhisperModel?
|
||||
|
||||
func start(model: WhisperModel) {
|
||||
isDownloading = true
|
||||
guard let downloadURL = ModelLoader.getModelDownloadURL(model: model) else { return }
|
||||
let downloadTask = urlSession.downloadTask(with: downloadURL)
|
||||
downloadTask.resume()
|
||||
self.downloadTask = downloadTask
|
||||
self.model = model
|
||||
self.bytesExpected = Float(ModelLoader.getModelByteSize(model: model))
|
||||
}
|
||||
|
||||
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
|
||||
do {
|
||||
let modelPath = try ModelLoader.getModelPath(model: model!)
|
||||
try FileManager.default.createDirectory(at: modelPath.deletingLastPathComponent(), withIntermediateDirectories: true)
|
||||
|
||||
if FileManager.default.fileExists(atPath: modelPath.path()) {
|
||||
try FileManager.default.removeItem(at: modelPath)
|
||||
}
|
||||
|
||||
try FileManager.default.moveItem(at: location, to: modelPath)
|
||||
DispatchQueue.main.async {
|
||||
self.isDownloading = false
|
||||
}
|
||||
} catch {
|
||||
fatalError(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
|
||||
DispatchQueue.main.async {
|
||||
self.bytesWritten = Float(totalBytesWritten)
|
||||
self.bytesExpected = Float(totalBytesExpectedToWrite)
|
||||
}
|
||||
}
|
||||
|
||||
func cancel() {
|
||||
downloadTask?.cancel()
|
||||
self.isDownloading = false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// LiveRecordingView.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 04/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import AVFoundation
|
||||
import whisper
|
||||
|
||||
struct RecordingTranscriptionOptionsView: View {
|
||||
@Binding var recordingAction: SheetAction
|
||||
@ObservedObject var options = RecordingTranscriptionOptions()
|
||||
|
||||
@State private var microphones: [AVCaptureDevice] = []
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
// TODO: Add visualizer from https://medium.com/swlh/swiftui-create-a-sound-visualizer-cadee0b6ad37
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(header: Text("Transcription").bold()) {
|
||||
TranscriptionOptionsView(options: options)
|
||||
}
|
||||
Spacer().frame(height: 24)
|
||||
Section(header: Text("Audio").bold()) {
|
||||
Picker("Microphone", selection: $options.microphone) {
|
||||
ForEach(microphones, id: \.uniqueID) { microphone in
|
||||
Text(microphone.localizedName).tag(microphone as AVCaptureDevice?)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer().frame(height: 24)
|
||||
Button("Record") {
|
||||
recordingAction = .success
|
||||
dismiss()
|
||||
}.keyboardShortcut(.defaultAction)
|
||||
}
|
||||
.padding(24)
|
||||
.onAppear() {
|
||||
let audioSession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInMicrophone], mediaType: .audio, position: .unspecified)
|
||||
microphones = audioSession.devices
|
||||
options.microphone = (AVCaptureDevice.default(for: .audio) ?? microphones.first)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RecordingOptionsView_Previews: PreviewProvider {
|
||||
@State private var recordingOptions = RecordingTranscriptionOptions()
|
||||
@State private var recordingAction = SheetAction.none
|
||||
|
||||
static var previews: some View {
|
||||
RecordingTranscriptionOptionsView(recordingAction: Binding(get: {SheetAction.none}, set: {_,_ in}))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// TranscriptionOptionsView.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 19/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct TranscriptionOptionsView: View {
|
||||
@ObservedObject var options: TranscriptionOptions
|
||||
@ObservedObject var downloadTask = ModelDownloadTask()
|
||||
|
||||
private let fileByteCountFormatter: ByteCountFormatter = {
|
||||
let formatter = ByteCountFormatter()
|
||||
return formatter
|
||||
}()
|
||||
|
||||
func formatByte(value: Float) -> String {
|
||||
fileByteCountFormatter.string(fromByteCount: Int64(value))
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Picker("Task:", selection: $options.task) {
|
||||
ForEach(WhisperTask.allCases, id: \.rawValue) { task in
|
||||
Text(task.rawValue.capitalized).tag(task)
|
||||
}
|
||||
}.pickerStyle(.radioGroup).horizontalRadioGroupLayout()
|
||||
HStack {
|
||||
Picker("Model:", selection: $options.model) {
|
||||
ForEach(WhisperModel.allCases, id: \.rawValue) { model in
|
||||
Text(model.displayName).tag(model)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
if ModelLoader.isAvailable(model: options.model) {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.help("Downloaded")
|
||||
}
|
||||
|
||||
if !ModelLoader.isAvailable(model: options.model) {
|
||||
if downloadTask.isDownloading {
|
||||
CircularProgressView(current: $downloadTask.bytesWritten, total: $downloadTask.bytesExpected) {
|
||||
downloadTask.cancel()
|
||||
}
|
||||
.help("\(formatByte(value: downloadTask.bytesWritten)) downloaded of \(formatByte(value: downloadTask.bytesExpected))")
|
||||
} else {
|
||||
Button(action: {
|
||||
downloadTask.start(model: options.model)
|
||||
}) {
|
||||
Image(systemName: "icloud.and.arrow.down.fill")
|
||||
}
|
||||
.help("Download model (\(formatByte(value: Float(ModelLoader.getModelByteSize(model: options.model)))))")
|
||||
}
|
||||
}
|
||||
}
|
||||
Picker("Language:", selection: $options.language) {
|
||||
ForEach(WhisperLanguage.allCases.sorted(by: { $0.fullName < $1.fullName }), id: \.rawValue) { language in
|
||||
Text(language.fullName).tag(language)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TranscriptionOptionsView_Previews: PreviewProvider {
|
||||
private static var options = TranscriptionOptions()
|
||||
|
||||
static var previews: some View {
|
||||
TranscriptionOptionsView(options: options)
|
||||
}
|
||||
}
|
86
Buzz.swift/Buzz/TranscriptionStore.swift
Normal file
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
// TranscriptionStore.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 17/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class TranscriptionStore: ObservableObject {
|
||||
private enum TranscriptionType: Codable, Hashable, Identifiable {
|
||||
var id: String { UUID().uuidString }
|
||||
|
||||
case transcription(Transcription)
|
||||
case file(FileTranscription)
|
||||
|
||||
|
||||
func unwrap() -> Transcription {
|
||||
switch self {
|
||||
case .transcription(let recording):
|
||||
return recording
|
||||
case .file(let fileTranscription):
|
||||
return fileTranscription
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Published var transcriptions: [Transcription] = []
|
||||
|
||||
private static func getFileURL() -> URL {
|
||||
try! FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
|
||||
.appending(path: "Buzz")
|
||||
.appendingPathComponent("transcriptions.data")
|
||||
}
|
||||
|
||||
static func load(completion: @escaping (Result<[Transcription], Error>) -> Void) {
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
let fileURL = getFileURL()
|
||||
guard let file = try? FileHandle(forReadingFrom: fileURL) else {
|
||||
DispatchQueue.main.async {
|
||||
completion(.success([]))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
guard let transcriptions = try? JSONDecoder().decode([TranscriptionType].self, from: file.availableData) else {
|
||||
try? FileManager.default.removeItem(at: fileURL)
|
||||
DispatchQueue.main.async {
|
||||
completion(.success([]))
|
||||
}
|
||||
return
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
completion(.success(transcriptions.map({ $0.unwrap() })))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static func wrap(transcription: Transcription) -> TranscriptionType {
|
||||
if let transcription = transcription as? FileTranscription {
|
||||
return .file(transcription)
|
||||
}
|
||||
return .transcription(transcription)
|
||||
}
|
||||
|
||||
static func save(transcriptions: [Transcription], completion: @escaping (Result<Int, Error>) -> Void) {
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
do {
|
||||
let data = try JSONEncoder().encode(transcriptions.map(wrap))
|
||||
|
||||
let outFile = getFileURL()
|
||||
|
||||
try FileManager.default.createDirectory(at: outFile.deletingLastPathComponent(), withIntermediateDirectories: true)
|
||||
|
||||
try data.write(to: outFile)
|
||||
DispatchQueue.main.async {
|
||||
completion(.success(transcriptions.count))
|
||||
}
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
106
Buzz.swift/Buzz/TranscriptionView.swift
Normal file
|
@ -0,0 +1,106 @@
|
|||
//
|
||||
// TranscriptionView.swift
|
||||
// Buzz
|
||||
//
|
||||
// Created by Chidi Williams on 06/02/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
func toTimestamp(ms: Int, ms_separator: String = ".") -> String {
|
||||
var _ms = ms
|
||||
let hr = _ms / (1000 * 60 * 60)
|
||||
_ms = _ms - hr * 1000 * 60 * 60
|
||||
let min = _ms / (1000 * 60)
|
||||
_ms = _ms - min * 1000 * 60
|
||||
let sec = _ms / 1000
|
||||
_ms = _ms - sec * 1000
|
||||
return "\(String(format: "%02d", hr)):\(String(format: "%02d", min)):\(String(format: "%02d", sec))\(ms_separator)\(String(format: "%03d", _ms))"
|
||||
}
|
||||
|
||||
extension Transcription {
|
||||
func isInProgressFileTranscription() -> Bool {
|
||||
if let transcription = self as? FileTranscription {
|
||||
switch transcription.status {
|
||||
case .inProgress(let progress):
|
||||
return progress.current != progress.total
|
||||
case .completed:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
struct TranscriptionView: View {
|
||||
@ObservedObject var transcription: Transcription
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Started: \(transcription.timeStarted.formatted())")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.padding(.top, 16)
|
||||
Text(transcription.title)
|
||||
.bold()
|
||||
.font(.title)
|
||||
.padding(.vertical, 24)
|
||||
|
||||
if transcription.isInProgressFileTranscription() {
|
||||
ProgressView()
|
||||
} else {
|
||||
ForEach(transcription.segments, id: \.self) { segment in
|
||||
VStack(alignment: .leading) {
|
||||
if let startMS = segment.startMS {
|
||||
if let endMS = segment.endMS {
|
||||
Text("\(toTimestamp(ms:startMS)) → \(toTimestamp(ms:endMS))")
|
||||
.font(.caption2)
|
||||
.padding(.bottom, 1)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
Text(segment.text)
|
||||
}
|
||||
.padding(.bottom, 24)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.textSelection(.enabled)
|
||||
}
|
||||
.padding()
|
||||
.frame(minWidth: 200)
|
||||
.toolbar() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TranscriptionView_Previews: PreviewProvider {
|
||||
private static var recordingTranscription: Transcription = {
|
||||
Transcription(title: "Test", segments: [
|
||||
Segment(
|
||||
startMS: 0,
|
||||
endMS: 2780,
|
||||
text: "Without education, we are in a horrible and deadly danger of taking educated people seriously."
|
||||
),
|
||||
Segment(
|
||||
startMS: 2781,
|
||||
endMS: 5382,
|
||||
text: "To love means loving the unlovable. To forgive means pardoning the unpardonable. Faith means believing the unbelievable. Hope means hoping when everything seems hopeless."
|
||||
)
|
||||
])
|
||||
}()
|
||||
|
||||
private static var inProgressFileTranscription: FileTranscription = {
|
||||
FileTranscription(file: URL(filePath: ""))
|
||||
}()
|
||||
|
||||
static var previews: some View {
|
||||
TranscriptionView(transcription: recordingTranscription)
|
||||
.previewDisplayName("Recording Transcription")
|
||||
TranscriptionView(transcription: inProgressFileTranscription)
|
||||
.previewDisplayName("File Transcription - In Progress")
|
||||
}
|
||||
}
|
39
Buzz.swift/BuzzTests/BuzzTests.swift
Normal file
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// BuzzTests.swift
|
||||
// BuzzTests
|
||||
//
|
||||
// Created by Chidi Williams on 29/01/2023.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Buzz
|
||||
|
||||
final class BuzzTests: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testExample() throws {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
// Any test you write for XCTest can be annotated as throws and async.
|
||||
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
|
||||
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
|
||||
let result = ModelLoader.isAvailable(model: .tiny)
|
||||
|
||||
XCTAssert(result != false)
|
||||
}
|
||||
|
||||
func testPerformanceExample() throws {
|
||||
// This is an example of a performance test case.
|
||||
self.measure {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
46
Buzz.swift/BuzzUITests/BuzzUITests.swift
Normal file
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// BuzzUITests.swift
|
||||
// BuzzUITests
|
||||
//
|
||||
// Created by Chidi Williams on 29/01/2023.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import AVFoundation
|
||||
|
||||
final class BuzzUITests: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
// In UI tests it is usually best to stop immediately when a failure occurs.
|
||||
continueAfterFailure = false
|
||||
|
||||
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testExample() throws {
|
||||
// UI tests must launch the application that they test.
|
||||
let app = XCUIApplication()
|
||||
app.launch()
|
||||
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
}
|
||||
|
||||
func testLaunchPerformance() throws {
|
||||
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
|
||||
// This measures how long it takes to launch your application.
|
||||
measure(metrics: [XCTApplicationLaunchMetric()]) {
|
||||
XCUIApplication().launch()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testReadAudioFile() {
|
||||
|
||||
}
|
||||
}
|
32
Buzz.swift/BuzzUITests/BuzzUITestsLaunchTests.swift
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// BuzzUITestsLaunchTests.swift
|
||||
// BuzzUITests
|
||||
//
|
||||
// Created by Chidi Williams on 29/01/2023.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
final class BuzzUITestsLaunchTests: XCTestCase {
|
||||
|
||||
override class var runsForEachTargetApplicationUIConfiguration: Bool {
|
||||
true
|
||||
}
|
||||
|
||||
override func setUpWithError() throws {
|
||||
continueAfterFailure = false
|
||||
}
|
||||
|
||||
func testLaunch() throws {
|
||||
let app = XCUIApplication()
|
||||
app.launch()
|
||||
|
||||
// Insert steps here to perform after app launch but before taking a screenshot,
|
||||
// such as logging into a test account or navigating somewhere in the app
|
||||
|
||||
let attachment = XCTAttachment(screenshot: app.screenshot())
|
||||
attachment.name = "Launch Screen"
|
||||
attachment.lifetime = .keepAlways
|
||||
add(attachment)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>AvailableLibraries</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>LibraryIdentifier</key>
|
||||
<string>macos-arm64_x86_64</string>
|
||||
<key>LibraryPath</key>
|
||||
<string>ffmpegkit.framework</string>
|
||||
<key>SupportedArchitectures</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
<string>x86_64</string>
|
||||
</array>
|
||||
<key>SupportedPlatform</key>
|
||||
<string>macos</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XFWK</string>
|
||||
<key>XCFrameworkFormatVersion</key>
|
||||
<string>1.0</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1 @@
|
|||
Versions/Current/Headers
|
|
@ -0,0 +1 @@
|
|||
Versions/Current/Modules
|
|
@ -0,0 +1 @@
|
|||
Versions/Current/Resources
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_ABSTRACT_SESSION_H
|
||||
#define FFMPEG_KIT_ABSTRACT_SESSION_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Session.h"
|
||||
|
||||
/**
|
||||
* Defines how long default "getAll" methods wait, in milliseconds.
|
||||
*/
|
||||
extern int const AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit;
|
||||
|
||||
/**
|
||||
* Abstract session implementation which includes common features shared by <code>FFmpeg</code>,
|
||||
* <code>FFprobe</code> and <code>MediaInformation</code> sessions.
|
||||
*/
|
||||
@interface AbstractSession : NSObject<Session>
|
||||
|
||||
/**
|
||||
* Creates a new abstract session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param logCallback session specific log callback
|
||||
* @param logRedirectionStrategy session specific log redirection strategy
|
||||
*/
|
||||
- (instancetype)init:(NSArray*)arguments withLogCallback:(LogCallback)logCallback withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy;
|
||||
|
||||
/**
|
||||
* Waits for all asynchronous messages to be transmitted until the given timeout.
|
||||
*
|
||||
* @param timeout wait timeout in milliseconds
|
||||
*/
|
||||
- (void)waitForAsynchronousMessagesInTransmit:(int)timeout;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_ABSTRACT_SESSION_H
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_ARCH_DETECT_H
|
||||
#define FFMPEG_KIT_ARCH_DETECT_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* Detects the running architecture.
|
||||
*/
|
||||
@interface ArchDetect : NSObject
|
||||
|
||||
/**
|
||||
* Returns architecture name of the cpu running.
|
||||
*
|
||||
* @return architecture name of the cpu running
|
||||
*/
|
||||
+ (NSString*)getCpuArch;
|
||||
|
||||
/**
|
||||
* Returns architecture name loaded.
|
||||
*
|
||||
* @return architecture name loaded
|
||||
*/
|
||||
+ (NSString*)getArch;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_ARCH_DETECT_H
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_ATOMIC_LONG_H
|
||||
#define FFMPEG_KIT_ATOMIC_LONG_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* Represents an atomic long data type.
|
||||
*/
|
||||
@interface AtomicLong : NSObject
|
||||
|
||||
- (instancetype)initWithValue:(long)value;
|
||||
|
||||
- (long)incrementAndGet;
|
||||
|
||||
- (long)getAndIncrement;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_ATOMIC_LONG_H
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_CHAPTER_H
|
||||
#define FFMPEG_KIT_CHAPTER_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern NSString* const ChapterKeyId;
|
||||
extern NSString* const ChapterKeyTimeBase;
|
||||
extern NSString* const ChapterKeyStart;
|
||||
extern NSString* const ChapterKeyStartTime;
|
||||
extern NSString* const ChapterKeyEnd;
|
||||
extern NSString* const ChapterKeyEndTime;
|
||||
extern NSString* const ChapterKeyTags;
|
||||
|
||||
/**
|
||||
* Chapter class.
|
||||
*/
|
||||
@interface Chapter : NSObject
|
||||
|
||||
- (instancetype)init:(NSDictionary*)chapterDictionary;
|
||||
|
||||
- (NSNumber*)getId;
|
||||
|
||||
- (NSString*)getTimeBase;
|
||||
|
||||
- (NSNumber*)getStart;
|
||||
|
||||
- (NSString*)getStartTime;
|
||||
|
||||
- (NSNumber*)getEnd;
|
||||
|
||||
- (NSString*)getEndTime;
|
||||
|
||||
- (NSDictionary*)getTags;
|
||||
|
||||
/**
|
||||
* Returns the chapter property associated with the key.
|
||||
*
|
||||
* @return chapter property as string or nil if the key is not found
|
||||
*/
|
||||
- (NSString*)getStringProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns the chapter property associated with the key.
|
||||
*
|
||||
* @return chapter property as number or nil if the key is not found
|
||||
*/
|
||||
- (NSNumber*)getNumberProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns the chapter properties associated with the key.
|
||||
*
|
||||
* @return chapter properties in a dictionary or nil if the key is not found
|
||||
*/
|
||||
- (NSDictionary*)getProperties:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns all chapter properties defined.
|
||||
*
|
||||
* @return all chapter properties in a dictionary or nil if no properties are defined
|
||||
*/
|
||||
- (NSDictionary*)getAllProperties;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_CHAPTER_H
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_H
|
||||
#define FFMPEG_KIT_H
|
||||
|
||||
#import <string.h>
|
||||
#import <stdlib.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "LogCallback.h"
|
||||
#import "FFmpegSession.h"
|
||||
#import "StatisticsCallback.h"
|
||||
|
||||
/**
|
||||
* <p>Main class to run <code>FFmpeg</code> commands. Supports executing commands both synchronously and
|
||||
* asynchronously.
|
||||
* <pre>
|
||||
* FFmpegSession *session = [FFmpegKit execute:@"-i file1.mp4 -c:v libxvid file1.avi"];
|
||||
*
|
||||
* FFmpegSession *asyncSession = [FFmpegKit executeAsync:@"-i file1.mp4 -c:v libxvid file1.avi" withCompleteCallback:completeCallback];
|
||||
* </pre>
|
||||
* <p>Provides overloaded <code>execute</code> methods to define session specific callbacks.
|
||||
* <pre>
|
||||
* FFmpegSession *asyncSession = [FFmpegKit executeAsync:@"-i file1.mp4 -c:v libxvid file1.avi" withCompleteCallback:completeCallback withLogCallback:logCallback withStatisticsCallback:statisticsCallback];
|
||||
* </pre>
|
||||
*/
|
||||
@interface FFmpegKit : NSObject
|
||||
|
||||
/**
|
||||
* <p>Synchronously executes FFmpeg with arguments provided.
|
||||
*
|
||||
* @param arguments FFmpeg command options/arguments as string array
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeWithArguments:(NSArray*)arguments;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFmpeg command options/arguments as string array
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFmpeg command options/arguments as string array
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param statisticsCallback callback that will receive statistics
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFmpeg command options/arguments as string array
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFmpeg command options/arguments as string array
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param statisticsCallback callback that will receive statistics
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Synchronously executes FFmpeg command provided. Space character is used to split command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside
|
||||
* your command.
|
||||
*
|
||||
* @param command FFmpeg command
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)execute:(NSString*)command;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFmpeg command
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeAsync:(NSString*)command withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFmpeg command
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param statisticsCallback callback that will receive statistics
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeAsync:(NSString*)command withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFmpeg command
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeAsync:(NSString*)command withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFmpeg command
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param statisticsCallback callback that will receive statistics
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFmpeg session created for this execution
|
||||
*/
|
||||
+ (FFmpegSession*)executeAsync:(NSString*)command withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Cancels all running sessions.
|
||||
*
|
||||
* <p>This method does not wait for termination to complete and returns immediately.
|
||||
*/
|
||||
+ (void)cancel;
|
||||
|
||||
/**
|
||||
* <p>Cancels the session specified with <code>sessionId</code>.
|
||||
*
|
||||
* <p>This method does not wait for termination to complete and returns immediately.
|
||||
*
|
||||
* @param sessionId id of the session that will be cancelled
|
||||
*/
|
||||
+ (void)cancel:(long)sessionId;
|
||||
|
||||
/**
|
||||
* <p>Lists all FFmpeg sessions in the session history.
|
||||
*
|
||||
* @return all FFmpeg sessions in the session history
|
||||
*/
|
||||
+ (NSArray*)listSessions;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_H
|
|
@ -0,0 +1,462 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_CONFIG_H
|
||||
#define FFMPEG_KIT_CONFIG_H
|
||||
|
||||
#import <stdio.h>
|
||||
#import <pthread.h>
|
||||
#import <unistd.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FFmpegSession.h"
|
||||
#import "FFprobeSession.h"
|
||||
#import "LogCallback.h"
|
||||
#import "MediaInformationSession.h"
|
||||
#import "StatisticsCallback.h"
|
||||
|
||||
/** Global library version */
|
||||
extern NSString* const FFmpegKitVersion;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, Signal) {
|
||||
SignalInt = 2,
|
||||
SignalQuit = 3,
|
||||
SignalPipe = 13,
|
||||
SignalTerm = 15,
|
||||
SignalXcpu = 24
|
||||
};
|
||||
|
||||
/**
|
||||
* <p>Configuration class of <code>FFmpegKit</code> library. Allows customizing the global library
|
||||
* options. Provides helper methods to support additional resources.
|
||||
*/
|
||||
@interface FFmpegKitConfig : NSObject
|
||||
|
||||
/**
|
||||
* <p>Enables log and statistics redirection.
|
||||
*
|
||||
* <p>When redirection is enabled FFmpeg/FFprobe logs are redirected to NSLog and sessions
|
||||
* collect log and statistics entries for the executions. It is possible to define global or
|
||||
* session specific log/statistics callbacks as well.
|
||||
*
|
||||
* <p>Note that redirection is enabled by default. If you do not want to use its functionality
|
||||
* please use disableRedirection method to disable it.
|
||||
*/
|
||||
+ (void)enableRedirection;
|
||||
|
||||
/**
|
||||
* <p>Disables log and statistics redirection.
|
||||
*
|
||||
* <p>When redirection is disabled logs are printed to stderr, all logs and statistics
|
||||
* callbacks are disabled and <code>FFprobe</code>'s <code>getMediaInformation</code> methods
|
||||
* do not work.
|
||||
*/
|
||||
+ (void)disableRedirection;
|
||||
|
||||
/**
|
||||
* <p>Sets and overrides <code>fontconfig</code> configuration directory.
|
||||
*
|
||||
* @param path directory that contains fontconfig configuration (fonts.conf)
|
||||
* @return zero on success, non-zero on error
|
||||
*/
|
||||
+ (int)setFontconfigConfigurationPath:(NSString*)path;
|
||||
|
||||
/**
|
||||
* <p>Registers the fonts inside the given path, so they become available to use in FFmpeg
|
||||
* filters.
|
||||
*
|
||||
* <p>Note that you need to build <code>FFmpegKit</code> with <code>fontconfig</code>
|
||||
* enabled or use a prebuilt package with <code>fontconfig</code> inside to be able to use
|
||||
* fonts in <code>FFmpeg</code>.
|
||||
*
|
||||
* @param fontDirectoryPath directory that contains fonts (.ttf and .otf files)
|
||||
* @param fontNameMapping custom font name mappings, useful to access your fonts with more
|
||||
* friendly names
|
||||
*/
|
||||
+ (void)setFontDirectory:(NSString*)fontDirectoryPath with:(NSDictionary*)fontNameMapping;
|
||||
|
||||
/**
|
||||
* <p>Registers the fonts inside the given array of font directories, so they become available
|
||||
* to use in FFmpeg filters.
|
||||
*
|
||||
* <p>Note that you need to build <code>FFmpegKit</code> with <code>fontconfig</code>
|
||||
* enabled or use a prebuilt package with <code>fontconfig</code> inside to be able to use
|
||||
* fonts in <code>FFmpeg</code>.
|
||||
*
|
||||
* @param fontDirectoryList array of directories that contain fonts (.ttf and .otf files)
|
||||
* @param fontNameMapping custom font name mappings, useful to access your fonts with more
|
||||
* friendly names
|
||||
*/
|
||||
+ (void)setFontDirectoryList:(NSArray*)fontDirectoryList with:(NSDictionary*)fontNameMapping;
|
||||
|
||||
/**
|
||||
* <p>Creates a new named pipe to use in <code>FFmpeg</code> operations.
|
||||
*
|
||||
* <p>Please note that creator is responsible of closing created pipes.
|
||||
*
|
||||
* @return the full path of the named pipe
|
||||
*/
|
||||
+ (NSString*)registerNewFFmpegPipe;
|
||||
|
||||
/**
|
||||
* <p>Closes a previously created <code>FFmpeg</code> pipe.
|
||||
*
|
||||
* @param ffmpegPipePath full path of the FFmpeg pipe
|
||||
*/
|
||||
+ (void)closeFFmpegPipe:(NSString*)ffmpegPipePath;
|
||||
|
||||
/**
|
||||
* <p>Returns the version of FFmpeg bundled within <code>FFmpegKit</code> library.
|
||||
*
|
||||
* @return the version of FFmpeg
|
||||
*/
|
||||
+ (NSString*)getFFmpegVersion;
|
||||
|
||||
/**
|
||||
* Returns FFmpegKit library version.
|
||||
*
|
||||
* @return FFmpegKit version
|
||||
*/
|
||||
+ (NSString*)getVersion;
|
||||
|
||||
/**
|
||||
* <p>Returns whether FFmpegKit release is a Long Term Release or not.
|
||||
*
|
||||
* @return true/yes or false/no
|
||||
*/
|
||||
+ (int)isLTSBuild;
|
||||
|
||||
/**
|
||||
* Returns FFmpegKit library build date.
|
||||
*
|
||||
* @return FFmpegKit library build date
|
||||
*/
|
||||
+ (NSString*)getBuildDate;
|
||||
|
||||
/**
|
||||
* <p>Sets an environment variable.
|
||||
*
|
||||
* @param variableName environment variable name
|
||||
* @param variableValue environment variable value
|
||||
* @return zero on success, non-zero on error
|
||||
*/
|
||||
+ (int)setEnvironmentVariable:(NSString*)variableName value:(NSString*)variableValue;
|
||||
|
||||
/**
|
||||
* <p>Registers a new ignored signal. Ignored signals are not handled by <code>FFmpegKit</code>
|
||||
* library.
|
||||
*
|
||||
* @param signal signal to be ignored
|
||||
*/
|
||||
+ (void)ignoreSignal:(Signal)signal;
|
||||
|
||||
/**
|
||||
* <p>Synchronously executes the FFmpeg session provided.
|
||||
*
|
||||
* @param ffmpegSession FFmpeg session which includes command options/arguments
|
||||
*/
|
||||
+ (void)ffmpegExecute:(FFmpegSession*)ffmpegSession;
|
||||
|
||||
/**
|
||||
* <p>Synchronously executes the FFprobe session provided.
|
||||
*
|
||||
* @param ffprobeSession FFprobe session which includes command options/arguments
|
||||
*/
|
||||
+ (void)ffprobeExecute:(FFprobeSession*)ffprobeSession;
|
||||
|
||||
/**
|
||||
* <p>Synchronously executes the media information session provided.
|
||||
*
|
||||
* @param mediaInformationSession media information session which includes command options/arguments
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
*/
|
||||
+ (void)getMediaInformationExecute:(MediaInformationSession*)mediaInformationSession withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution for the given session.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param ffmpegSession FFmpeg session which includes command options/arguments
|
||||
*/
|
||||
+ (void)asyncFFmpegExecute:(FFmpegSession*)ffmpegSession;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFmpeg execution for the given session.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFmpegSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param ffmpegSession FFmpeg session which includes command options/arguments
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
*/
|
||||
+ (void)asyncFFmpegExecute:(FFmpegSession*)ffmpegSession onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given session.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param ffprobeSession FFprobe session which includes command options/arguments
|
||||
*/
|
||||
+ (void)asyncFFprobeExecute:(FFprobeSession*)ffprobeSession;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given session.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param ffprobeSession FFprobe session which includes command options/arguments
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
*/
|
||||
+ (void)asyncFFprobeExecute:(FFprobeSession*)ffprobeSession onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given media information session.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param mediaInformationSession media information session which includes command options/arguments
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
*/
|
||||
+ (void)asyncGetMediaInformationExecute:(MediaInformationSession*)mediaInformationSession withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given media information session.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param mediaInformationSession media information session which includes command options/arguments
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
*/
|
||||
+ (void)asyncGetMediaInformationExecute:(MediaInformationSession*)mediaInformationSession onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Sets a global log callback to redirect FFmpeg/FFprobe logs.
|
||||
*
|
||||
* @param logCallback log callback or nil to disable a previously defined log callback
|
||||
*/
|
||||
+ (void)enableLogCallback:(LogCallback)logCallback;
|
||||
|
||||
/**
|
||||
* <p>Sets a global statistics callback to redirect FFmpeg statistics.
|
||||
*
|
||||
* @param statisticsCallback statistics callback or nil to disable a previously defined statistics callback
|
||||
*/
|
||||
+ (void)enableStatisticsCallback:(StatisticsCallback)statisticsCallback;
|
||||
|
||||
/**
|
||||
* <p>Sets a global FFmpegSessionCompleteCallback to receive execution results for FFmpeg sessions.
|
||||
*
|
||||
* @param ffmpegSessionCompleteCallback complete callback or nil to disable a previously defined callback
|
||||
*/
|
||||
+ (void)enableFFmpegSessionCompleteCallback:(FFmpegSessionCompleteCallback)ffmpegSessionCompleteCallback;
|
||||
|
||||
/**
|
||||
* <p>Returns the global FFmpegSessionCompleteCallback set.
|
||||
*
|
||||
* @return global FFmpegSessionCompleteCallback or nil if it is not set
|
||||
*/
|
||||
+ (FFmpegSessionCompleteCallback)getFFmpegSessionCompleteCallback;
|
||||
|
||||
/**
|
||||
* <p>Sets a global FFprobeSessionCompleteCallback to receive execution results for FFprobe sessions.
|
||||
*
|
||||
* @param ffprobeSessionCompleteCallback complete callback or nil to disable a previously defined callback
|
||||
*/
|
||||
+ (void)enableFFprobeSessionCompleteCallback:(FFprobeSessionCompleteCallback)ffprobeSessionCompleteCallback;
|
||||
|
||||
/**
|
||||
* <p>Returns the global FFprobeSessionCompleteCallback set.
|
||||
*
|
||||
* @return global FFprobeSessionCompleteCallback or nil if it is not set
|
||||
*/
|
||||
+ (FFprobeSessionCompleteCallback)getFFprobeSessionCompleteCallback;
|
||||
|
||||
/**
|
||||
* <p>Sets a global MediaInformationSessionCompleteCallback to receive execution results for MediaInformation sessions.
|
||||
*
|
||||
* @param mediaInformationSessionCompleteCallback complete callback or nil to disable a previously defined
|
||||
* callback
|
||||
*/
|
||||
+ (void)enableMediaInformationSessionCompleteCallback:(MediaInformationSessionCompleteCallback)mediaInformationSessionCompleteCallback;
|
||||
|
||||
/**
|
||||
* <p>Returns the global MediaInformationSessionCompleteCallback set.
|
||||
*
|
||||
* @return global MediaInformationSessionCompleteCallback or nil if it is not set
|
||||
*/
|
||||
+ (MediaInformationSessionCompleteCallback)getMediaInformationSessionCompleteCallback;
|
||||
|
||||
/**
|
||||
* Returns the current log level.
|
||||
*
|
||||
* @return current log level
|
||||
*/
|
||||
+ (int)getLogLevel;
|
||||
|
||||
/**
|
||||
* Sets the log level.
|
||||
*
|
||||
* @param level new log level
|
||||
*/
|
||||
+ (void)setLogLevel:(int)level;
|
||||
|
||||
/**
|
||||
* Converts int log level to string.
|
||||
*
|
||||
* @param level value
|
||||
* @return string value
|
||||
*/
|
||||
+ (NSString*)logLevelToString:(int)level;
|
||||
|
||||
/**
|
||||
* Returns the session history size.
|
||||
*
|
||||
* @return session history size
|
||||
*/
|
||||
+ (int)getSessionHistorySize;
|
||||
|
||||
/**
|
||||
* Sets the session history size.
|
||||
*
|
||||
* @param sessionHistorySize session history size, should be smaller than 1000
|
||||
*/
|
||||
+ (void)setSessionHistorySize:(int)sessionHistorySize;
|
||||
|
||||
/**
|
||||
* Returns the session specified with <code>sessionId</code> from the session history.
|
||||
*
|
||||
* @param sessionId session identifier
|
||||
* @return session specified with sessionId or nil if it is not found in the history
|
||||
*/
|
||||
+ (id<Session>)getSession:(long)sessionId;
|
||||
|
||||
/**
|
||||
* Returns the last session created from the session history.
|
||||
*
|
||||
* @return the last session created or nil if session history is empty
|
||||
*/
|
||||
+ (id<Session>)getLastSession;
|
||||
|
||||
/**
|
||||
* Returns the last session completed from the session history.
|
||||
*
|
||||
* @return the last session completed. If there are no completed sessions in the history this
|
||||
* method will return nil
|
||||
*/
|
||||
+ (id<Session>)getLastCompletedSession;
|
||||
|
||||
/**
|
||||
* <p>Returns all sessions in the session history.
|
||||
*
|
||||
* @return all sessions in the session history
|
||||
*/
|
||||
+ (NSArray*)getSessions;
|
||||
|
||||
/**
|
||||
* <p>Clears all, including ongoing, sessions in the session history.
|
||||
* <p>Note that callbacks cannot be triggered for deleted sessions.
|
||||
*/
|
||||
+ (void)clearSessions;
|
||||
|
||||
/**
|
||||
* <p>Returns all FFmpeg sessions in the session history.
|
||||
*
|
||||
* @return all FFmpeg sessions in the session history
|
||||
*/
|
||||
+ (NSArray*)getFFmpegSessions;
|
||||
|
||||
/**
|
||||
* <p>Returns all FFprobe sessions in the session history.
|
||||
*
|
||||
* @return all FFprobe sessions in the session history
|
||||
*/
|
||||
+ (NSArray*)getFFprobeSessions;
|
||||
|
||||
/**
|
||||
* <p>Returns all MediaInformation sessions in the session history.
|
||||
*
|
||||
* @return all MediaInformation sessions in the session history
|
||||
*/
|
||||
+ (NSArray*)getMediaInformationSessions;
|
||||
|
||||
/**
|
||||
* <p>Returns sessions that have the given state.
|
||||
*
|
||||
* @return sessions that have the given state from the session history
|
||||
*/
|
||||
+ (NSArray*)getSessionsByState:(SessionState)state;
|
||||
|
||||
/**
|
||||
* Returns the active log redirection strategy.
|
||||
*
|
||||
* @return log redirection strategy
|
||||
*/
|
||||
+ (LogRedirectionStrategy)getLogRedirectionStrategy;
|
||||
|
||||
/**
|
||||
* <p>Sets the log redirection strategy
|
||||
*
|
||||
* @param logRedirectionStrategy log redirection strategy
|
||||
*/
|
||||
+ (void)setLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy;
|
||||
|
||||
/**
|
||||
* <p>Returns the number of async messages that are not transmitted to the callbacks for
|
||||
* this session.
|
||||
*
|
||||
* @param sessionId id of the session
|
||||
* @return number of async messages that are not transmitted to the callbacks for this session
|
||||
*/
|
||||
+ (int)messagesInTransmit:(long)sessionId;
|
||||
|
||||
/**
|
||||
* Converts session state to string.
|
||||
*
|
||||
* @param state session state
|
||||
* @return string value
|
||||
*/
|
||||
+ (NSString*)sessionStateToString:(SessionState)state;
|
||||
|
||||
/**
|
||||
* <p>Parses the given command into arguments. Uses space character to split the arguments.
|
||||
* Supports single and double quote characters.
|
||||
*
|
||||
* @param command string command
|
||||
* @return array of arguments
|
||||
*/
|
||||
+ (NSArray*)parseArguments:(NSString*)command;
|
||||
|
||||
/**
|
||||
* <p>Concatenates arguments into a string adding a space character between two arguments.
|
||||
*
|
||||
* @param arguments arguments
|
||||
* @return concatenated string containing all arguments
|
||||
*/
|
||||
+ (NSString*)argumentsToString:(NSArray*)arguments;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_CONFIG_H
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_FFMPEG_SESSION_H
|
||||
#define FFMPEG_KIT_FFMPEG_SESSION_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "AbstractSession.h"
|
||||
#import "StatisticsCallback.h"
|
||||
#import "FFmpegSessionCompleteCallback.h"
|
||||
|
||||
/**
|
||||
* <p>An FFmpeg session.
|
||||
*/
|
||||
@interface FFmpegSession : AbstractSession
|
||||
|
||||
/**
|
||||
* Builds a new FFmpeg session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
*/
|
||||
- (instancetype)init:(NSArray*)arguments;
|
||||
|
||||
/**
|
||||
* Builds a new FFmpeg session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
*/
|
||||
- (instancetype)init:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* Builds a new FFmpeg session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
* @param logCallback session specific log callback
|
||||
* @param statisticsCallback session specific statistics callback
|
||||
*/
|
||||
- (instancetype)init:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback;
|
||||
|
||||
/**
|
||||
* Builds a new FFmpeg session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
* @param logCallback session specific log callback
|
||||
* @param statisticsCallback session specific statistics callback
|
||||
* @param logRedirectionStrategy session specific log redirection strategy
|
||||
*/
|
||||
- (instancetype)init:(NSArray*)arguments withCompleteCallback:(FFmpegSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withStatisticsCallback:(StatisticsCallback)statisticsCallback withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy;
|
||||
|
||||
/**
|
||||
* Returns the session specific statistics callback.
|
||||
*
|
||||
* @return session specific statistics callback
|
||||
*/
|
||||
- (StatisticsCallback)getStatisticsCallback;
|
||||
|
||||
/**
|
||||
* Returns the session specific complete callback.
|
||||
*
|
||||
* @return session specific complete callback
|
||||
*/
|
||||
- (FFmpegSessionCompleteCallback)getCompleteCallback;
|
||||
|
||||
/**
|
||||
* Returns all statistics entries generated for this session. If there are asynchronous
|
||||
* messages that are not delivered yet, this method waits for them until the given timeout.
|
||||
*
|
||||
* @param waitTimeout wait timeout for asynchronous messages in milliseconds
|
||||
* @return list of statistics entries generated for this session
|
||||
*/
|
||||
- (NSArray*)getAllStatisticsWithTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* Returns all statistics entries generated for this session. If there are asynchronous
|
||||
* messages that are not delivered yet, this method waits for them until
|
||||
* AbstractSessionDefaultTimeoutForAsynchronousMessagesInTransmit expires.
|
||||
*
|
||||
* @return list of statistics entries generated for this session
|
||||
*/
|
||||
- (NSArray*)getAllStatistics;
|
||||
|
||||
/**
|
||||
* Returns all statistics entries delivered for this session. Note that if there are
|
||||
* asynchronous messages that are not delivered yet, this method will not wait for
|
||||
* them and will return immediately.
|
||||
*
|
||||
* @return list of statistics entries received for this session
|
||||
*/
|
||||
- (NSArray*)getStatistics;
|
||||
|
||||
/**
|
||||
* Returns the last received statistics entry.
|
||||
*
|
||||
* @return the last received statistics entry or nil if there are not any statistics entries
|
||||
* received
|
||||
*/
|
||||
- (Statistics*)getLastReceivedStatistics;
|
||||
|
||||
/**
|
||||
* Adds a new statistics entry for this session. It is invoked internally by <code>FFmpegKit</code> library methods.
|
||||
* Must not be used by user applications.
|
||||
*
|
||||
* @param statistics statistics entry
|
||||
*/
|
||||
- (void)addStatistics:(Statistics*)statistics;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_FFMPEG_SESSION_H
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_FFMPEG_SESSION_COMPLETE_CALLBACK_H
|
||||
#define FFMPEG_KIT_FFMPEG_SESSION_COMPLETE_CALLBACK_H
|
||||
|
||||
@class FFmpegSession;
|
||||
|
||||
/**
|
||||
* <p>Callback function that is invoked when an asynchronous <code>FFmpeg</code> session has ended.
|
||||
* <p>Session has either SessionStateCompleted or SessionStateFailed state when
|
||||
* the callback is invoked.
|
||||
* <p>If it has SessionStateCompleted state, <code>ReturnCode</code> should be checked to
|
||||
* see the execution result.
|
||||
* <p>If <code>getState</code> returns SessionStateFailed then
|
||||
* <code>getFailStackTrace</code> should be used to get the failure reason.
|
||||
* <pre>
|
||||
* switch ([session getState]) {
|
||||
* case SessionStateCompleted:
|
||||
* ReturnCode *returnCode = [session getReturnCode];
|
||||
* break;
|
||||
* case SessionStateFailed:
|
||||
* NSString *failStackTrace = [session getFailStackTrace];
|
||||
* break;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param session session of the completed execution
|
||||
*/
|
||||
typedef void (^FFmpegSessionCompleteCallback)(FFmpegSession* session);
|
||||
|
||||
#import "FFmpegSession.h"
|
||||
|
||||
#endif // FFMPEG_KIT_FFMPEG_SESSION_COMPLETE_CALLBACK_H
|
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFPROBE_KIT_H
|
||||
#define FFPROBE_KIT_H
|
||||
|
||||
#import <string.h>
|
||||
#import <stdlib.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FFprobeSession.h"
|
||||
#import "MediaInformationJsonParser.h"
|
||||
|
||||
/**
|
||||
* <p>Main class to run <code>FFprobe</code> commands. Supports executing commands both synchronously and
|
||||
* asynchronously.
|
||||
* <pre>
|
||||
* FFprobeSession *session = [FFprobeKit execute:@"-hide_banner -v error -show_entries format=size -of default=noprint_wrappers=1 file1.mp4"];
|
||||
*
|
||||
* FFprobeSession *asyncSession = [FFprobeKit executeAsync:@"-hide_banner -v error -show_entries format=size -of default=noprint_wrappers=1 file1.mp4" withCompleteCallback:completeCallback];
|
||||
* </pre>
|
||||
* <p>Provides overloaded <code>execute</code> methods to define session specific callbacks.
|
||||
* <pre>
|
||||
* FFprobeSession *session = [FFprobeKit executeAsync:@"-hide_banner -v error -show_entries format=size -of default=noprint_wrappers=1 file1.mp4" withCompleteCallback:completeCallback withLogCallback:logCallback];
|
||||
* </pre>
|
||||
* <p>It can extract media information for a file or a url, using getMediaInformation method.
|
||||
* <pre>
|
||||
* MediaInformationSession *session = [FFprobeKit getMediaInformation:@"file1.mp4"];
|
||||
* </pre>
|
||||
*/
|
||||
@interface FFprobeKit : NSObject
|
||||
|
||||
/**
|
||||
* <p>Synchronously executes FFprobe with arguments provided.
|
||||
*
|
||||
* @param arguments FFprobe command options/arguments as string array
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeWithArguments:(NSArray*)arguments;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFprobe command options/arguments as string array
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFprobe command options/arguments as string array
|
||||
* @param completeCallback callback that will be notified when execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFprobe command options/arguments as string array
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution with arguments provided.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete.
|
||||
* You must use an FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFprobe command options/arguments as string array
|
||||
* @param completeCallback callback that will be notified when execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeWithArgumentsAsync:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Synchronously executes FFprobe command provided. Space character is used to split command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside
|
||||
* your command.
|
||||
*
|
||||
* @param command FFprobe command
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)execute:(NSString*)command;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFprobe command
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeAsync:(NSString*)command withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFprobe command
|
||||
* @param completeCallback callback that will be notified when execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeAsync:(NSString*)command withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFprobe command
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeAsync:(NSString*)command withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution for the given command. Space character is used to split the command
|
||||
* into arguments. You can use single or double quote characters to specify arguments inside your command.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* FFprobeSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFprobe command
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return FFprobe session created for this execution
|
||||
*/
|
||||
+ (FFprobeSession*)executeAsync:(NSString*)command withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Extracts media information for the file specified with path.
|
||||
*
|
||||
* @param path path or uri of a media file
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformation:(NSString*)path;
|
||||
|
||||
/**
|
||||
* <p>Extracts media information for the file specified with path.
|
||||
*
|
||||
* @param path path or uri of a media file
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformation:(NSString*)path withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution to extract the media information for the specified file.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param path path or uri of a media file
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution to extract the media information for the specified file.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param path path or uri of a media file
|
||||
* @param completeCallback callback that will be notified when execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution to extract the media information for the specified file.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param path path or uri of a media file
|
||||
* @param completeCallback callback that will be called when the execution has completed
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback onDispatchQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution to extract the media information for the specified file.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param path path or uri of a media file
|
||||
* @param completeCallback callback that will be notified when execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformationAsync:(NSString*)path withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Extracts media information using the command provided asynchronously.
|
||||
*
|
||||
* @param command FFprobe command that prints media information for a file in JSON format
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformationFromCommand:(NSString*)command;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution to extract media information using a command. The command passed to
|
||||
* this method must generate the output in JSON format in order to successfully extract media information from it.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param command FFprobe command that prints media information for a file in JSON format
|
||||
* @param completeCallback callback that will be notified when execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformationFromCommandAsync:(NSString*)command withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Starts an asynchronous FFprobe execution to extract media information using command arguments. The command
|
||||
* passed to this method must generate the output in JSON format in order to successfully extract media information
|
||||
* from it.
|
||||
*
|
||||
* <p>Note that this method returns immediately and does not wait the execution to complete. You must use an
|
||||
* MediaInformationSessionCompleteCallback if you want to be notified about the result.
|
||||
*
|
||||
* @param arguments FFprobe command that prints media information for a file in JSON format
|
||||
* @param completeCallback callback that will be notified when execution has completed
|
||||
* @param logCallback callback that will receive logs
|
||||
* @param queue dispatch queue that will be used to run this asynchronous operation
|
||||
* @param waitTimeout max time to wait until media information is transmitted
|
||||
* @return media information session created for this execution
|
||||
*/
|
||||
+ (MediaInformationSession*)getMediaInformationFromCommandArgumentsAsync:(NSArray*)arguments withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback onDispatchQueue:(dispatch_queue_t)queue withTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* <p>Lists all FFprobe sessions in the session history.
|
||||
*
|
||||
* @return all FFprobe sessions in the session history
|
||||
*/
|
||||
+ (NSArray*)listFFprobeSessions;
|
||||
|
||||
/**
|
||||
* <p>Lists all MediaInformation sessions in the session history.
|
||||
*
|
||||
* @return all MediaInformation sessions in the session history
|
||||
*/
|
||||
+ (NSArray*)listMediaInformationSessions;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFPROBE_KIT_H
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_FFPROBE_SESSION_H
|
||||
#define FFMPEG_KIT_FFPROBE_SESSION_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "AbstractSession.h"
|
||||
#import "FFprobeSessionCompleteCallback.h"
|
||||
|
||||
/**
|
||||
* <p>An FFprobe session.
|
||||
*/
|
||||
@interface FFprobeSession : AbstractSession
|
||||
|
||||
/**
|
||||
* Builds a new FFprobe session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
*/
|
||||
- (instancetype)init:(NSArray*)arguments;
|
||||
|
||||
/**
|
||||
* Builds a new FFprobe session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
*/
|
||||
- (instancetype)init:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* Builds a new FFprobe session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
* @param logCallback session specific log callback
|
||||
*/
|
||||
- (instancetype)init:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback;
|
||||
|
||||
/**
|
||||
* Builds a new FFprobe session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
* @param logCallback session specific log callback
|
||||
* @param logRedirectionStrategy session specific log redirection strategy
|
||||
*/
|
||||
- (instancetype)init:(NSArray*)arguments withCompleteCallback:(FFprobeSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback withLogRedirectionStrategy:(LogRedirectionStrategy)logRedirectionStrategy;
|
||||
|
||||
/**
|
||||
* Returns the session specific complete callback.
|
||||
*
|
||||
* @return session specific complete callback
|
||||
*/
|
||||
- (FFprobeSessionCompleteCallback)getCompleteCallback;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_FFPROBE_SESSION_H
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_FFPROBE_SESSION_COMPLETE_CALLBACK_H
|
||||
#define FFMPEG_KIT_FFPROBE_SESSION_COMPLETE_CALLBACK_H
|
||||
|
||||
@class FFprobeSession;
|
||||
|
||||
/**
|
||||
* <p>Callback function that is invoked when an asynchronous <code>FFprobe</code> session has ended.
|
||||
* <p>Session has either SessionStateCompleted or SessionStateFailed state when
|
||||
* the callback is invoked.
|
||||
* <p>If it has SessionStateCompleted state, <code>ReturnCode</code> should be checked to
|
||||
* see the execution result.
|
||||
* <p>If <code>getState</code> returns SessionStateFailed then
|
||||
* <code>getFailStackTrace</code> should be used to get the failure reason.
|
||||
* <pre>
|
||||
* switch ([session getState]) {
|
||||
* case SessionStateCompleted:
|
||||
* ReturnCode *returnCode = [session getReturnCode];
|
||||
* break;
|
||||
* case SessionStateFailed:
|
||||
* NSString *failStackTrace = [session getFailStackTrace];
|
||||
* break;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param session session of the completed execution
|
||||
*/
|
||||
typedef void (^FFprobeSessionCompleteCallback)(FFprobeSession* session);
|
||||
|
||||
#import "FFprobeSession.h"
|
||||
|
||||
#endif // FFMPEG_KIT_FFPROBE_SESSION_COMPLETE_CALLBACK_H
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_LEVEL_H
|
||||
#define FFMPEG_KIT_LEVEL_H
|
||||
|
||||
/**
|
||||
* <p>Enumeration type for log levels.
|
||||
*/
|
||||
typedef NS_ENUM(NSUInteger, Level) {
|
||||
|
||||
/**
|
||||
* This log level is defined by FFmpegKit. It is used to specify logs printed to stderr by
|
||||
* FFmpeg. Logs that has this level are not filtered and always redirected.
|
||||
*/
|
||||
LevelAVLogStdErr = -16,
|
||||
|
||||
/**
|
||||
* Print no output.
|
||||
*/
|
||||
LevelAVLogQuiet = -8,
|
||||
|
||||
/**
|
||||
* Something went really wrong and we will crash now.
|
||||
*/
|
||||
LevelAVLogPanic = 0,
|
||||
|
||||
/**
|
||||
* Something went wrong and recovery is not possible.
|
||||
* For example, no header was found for a format which depends
|
||||
* on headers or an illegal combination of parameters is used.
|
||||
*/
|
||||
LevelAVLogFatal = 8,
|
||||
|
||||
/**
|
||||
* Something went wrong and cannot losslessly be recovered.
|
||||
* However, not all future data is affected.
|
||||
*/
|
||||
LevelAVLogError = 16,
|
||||
|
||||
/**
|
||||
* Something somehow does not look correct. This may or may not
|
||||
* lead to problems. An example would be the use of '-vstrict -2'.
|
||||
*/
|
||||
LevelAVLogWarning = 24,
|
||||
|
||||
/**
|
||||
* Standard information.
|
||||
*/
|
||||
LevelAVLogInfo = 32,
|
||||
|
||||
/**
|
||||
* Detailed information.
|
||||
*/
|
||||
LevelAVLogVerbose = 40,
|
||||
|
||||
/**
|
||||
* Stuff which is only useful for libav* developers.
|
||||
*/
|
||||
LevelAVLogDebug = 48,
|
||||
|
||||
/**
|
||||
* Extremely verbose debugging, useful for libav* development.
|
||||
*/
|
||||
LevelAVLogTrace = 56
|
||||
|
||||
};
|
||||
|
||||
#endif // FFMPEG_KIT_LEVEL_H
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_LOG_H
|
||||
#define FFMPEG_KIT_LOG_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* <p>Log entry for an <code>FFmpegKit</code> session.
|
||||
*/
|
||||
@interface Log : NSObject
|
||||
|
||||
- (instancetype)init:(long)sessionId :(int)level :(NSString*)message;
|
||||
|
||||
- (long)getSessionId;
|
||||
|
||||
- (int)getLevel;
|
||||
|
||||
- (NSString*)getMessage;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_LOG_H
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_LOG_CALLBACK_H
|
||||
#define FFMPEG_KIT_LOG_CALLBACK_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Log.h"
|
||||
|
||||
/**
|
||||
* <p>Callback that receives logs generated for <code>FFmpegKit</code> sessions.
|
||||
*
|
||||
* @param log log entry
|
||||
*/
|
||||
typedef void (^LogCallback)(Log* log);
|
||||
|
||||
#endif // FFMPEG_KIT_LOG_CALLBACK_H
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_LOG_REDIRECTION_STRATEGY_H
|
||||
#define FFMPEG_KIT_LOG_REDIRECTION_STRATEGY_H
|
||||
|
||||
typedef NS_ENUM(NSUInteger, LogRedirectionStrategy) {
|
||||
LogRedirectionStrategyAlwaysPrintLogs,
|
||||
LogRedirectionStrategyPrintLogsWhenNoCallbacksDefined,
|
||||
LogRedirectionStrategyPrintLogsWhenGlobalCallbackNotDefined,
|
||||
LogRedirectionStrategyPrintLogsWhenSessionCallbackNotDefined,
|
||||
LogRedirectionStrategyNeverPrintLogs
|
||||
};
|
||||
|
||||
#endif // FFMPEG_KIT_LOG_REDIRECTION_STRATEGY_H
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_MEDIA_INFORMATION_H
|
||||
#define FFMPEG_KIT_MEDIA_INFORMATION_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Chapter.h"
|
||||
#import "StreamInformation.h"
|
||||
|
||||
extern NSString* const MediaKeyMediaProperties;
|
||||
extern NSString* const MediaKeyFilename;
|
||||
extern NSString* const MediaKeyFormat;
|
||||
extern NSString* const MediaKeyFormatLong;
|
||||
extern NSString* const MediaKeyStartTime;
|
||||
extern NSString* const MediaKeyDuration;
|
||||
extern NSString* const MediaKeySize;
|
||||
extern NSString* const MediaKeyBitRate;
|
||||
extern NSString* const MediaKeyTags;
|
||||
|
||||
/**
|
||||
* Media information class.
|
||||
*/
|
||||
@interface MediaInformation : NSObject
|
||||
|
||||
- (instancetype)init:(NSDictionary*)mediaDictionary withStreams:(NSArray*)streams withChapters:(NSArray*)chapters;
|
||||
|
||||
/**
|
||||
* Returns file name.
|
||||
*
|
||||
* @return media file name
|
||||
*/
|
||||
- (NSString*)getFilename;
|
||||
|
||||
/**
|
||||
* Returns format.
|
||||
*
|
||||
* @return media format
|
||||
*/
|
||||
- (NSString*)getFormat;
|
||||
|
||||
/**
|
||||
* Returns long format.
|
||||
*
|
||||
* @return media long format
|
||||
*/
|
||||
- (NSString*)getLongFormat;
|
||||
|
||||
/**
|
||||
* Returns duration.
|
||||
*
|
||||
* @return media duration in milliseconds
|
||||
*/
|
||||
- (NSString*)getDuration;
|
||||
|
||||
/**
|
||||
* Returns start time.
|
||||
*
|
||||
* @return media start time in milliseconds
|
||||
*/
|
||||
- (NSString*)getStartTime;
|
||||
|
||||
/**
|
||||
* Returns size.
|
||||
*
|
||||
* @return media size in bytes
|
||||
*/
|
||||
- (NSString*)getSize;
|
||||
|
||||
/**
|
||||
* Returns bitrate.
|
||||
*
|
||||
* @return media bitrate in kb/s
|
||||
*/
|
||||
- (NSString*)getBitrate;
|
||||
|
||||
/**
|
||||
* Returns all tags.
|
||||
*
|
||||
* @return tags dictionary
|
||||
*/
|
||||
- (NSDictionary*)getTags;
|
||||
|
||||
/**
|
||||
* Returns all streams.
|
||||
*
|
||||
* @return streams array
|
||||
*/
|
||||
- (NSArray*)getStreams;
|
||||
|
||||
/**
|
||||
* Returns all chapters.
|
||||
*
|
||||
* @return chapters array
|
||||
*/
|
||||
- (NSArray*)getChapters;
|
||||
|
||||
/**
|
||||
* Returns the media property associated with the key.
|
||||
*
|
||||
* @return media property as string or nil if the key is not found
|
||||
*/
|
||||
- (NSString*)getStringProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns the media property associated with the key.
|
||||
*
|
||||
* @return media property as number or nil if the key is not found
|
||||
*/
|
||||
- (NSNumber*)getNumberProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns the media properties associated with the key.
|
||||
*
|
||||
* @return media properties in a dictionary or nil if the key is not found
|
||||
*/
|
||||
- (NSDictionary*)getProperties:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns all media properties.
|
||||
*
|
||||
* @return all media properties in a dictionary or nil if no media properties are defined
|
||||
*/
|
||||
- (NSDictionary*)getMediaProperties;
|
||||
|
||||
/**
|
||||
* Returns all properties defined.
|
||||
*
|
||||
* @return all properties in a dictionary or nil if no properties are defined
|
||||
*/
|
||||
- (NSDictionary*)getAllProperties;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_MEDIA_INFORMATION_H
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_MEDIA_INFORMATION_PARSER_H
|
||||
#define FFMPEG_KIT_MEDIA_INFORMATION_PARSER_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MediaInformation.h"
|
||||
|
||||
/**
|
||||
* A parser that constructs MediaInformation from FFprobe's json output.
|
||||
*/
|
||||
@interface MediaInformationJsonParser : NSObject
|
||||
|
||||
/**
|
||||
* Extracts <code>MediaInformation</code> from the given FFprobe json output.
|
||||
*
|
||||
* @param ffprobeJsonOutput FFprobe json output
|
||||
* @return created MediaInformation instance of nil if a parsing error occurs
|
||||
*/
|
||||
+ (MediaInformation*)from:(NSString*)ffprobeJsonOutput;
|
||||
|
||||
/**
|
||||
* Extracts <code>MediaInformation</code> from the given FFprobe json output.
|
||||
*
|
||||
* @param ffprobeJsonOutput FFprobe json output
|
||||
* @param error error to save the parsing error if a parsing error occurs
|
||||
* @return created MediaInformation instance
|
||||
*/
|
||||
+ (MediaInformation*)from:(NSString*)ffprobeJsonOutput with:(NSError*)error;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_MEDIA_INFORMATION_PARSER_H
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_MEDIA_INFORMATION_SESSION_H
|
||||
#define FFMPEG_KIT_MEDIA_INFORMATION_SESSION_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "AbstractSession.h"
|
||||
#import "MediaInformation.h"
|
||||
#import "MediaInformationSessionCompleteCallback.h"
|
||||
|
||||
/**
|
||||
* <p>A custom FFprobe session, which produces a <code>MediaInformation</code> object using the
|
||||
* FFprobe output.
|
||||
*/
|
||||
@interface MediaInformationSession : AbstractSession
|
||||
|
||||
/**
|
||||
* Creates a new media information session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
*/
|
||||
- (instancetype)init:(NSArray*)arguments;
|
||||
|
||||
/**
|
||||
* Creates a new media information session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
*/
|
||||
- (instancetype)init:(NSArray*)arguments withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback;
|
||||
|
||||
/**
|
||||
* Creates a new media information session.
|
||||
*
|
||||
* @param arguments command arguments
|
||||
* @param completeCallback session specific complete callback
|
||||
* @param logCallback session specific log callback
|
||||
*/
|
||||
- (instancetype)init:(NSArray*)arguments withCompleteCallback:(MediaInformationSessionCompleteCallback)completeCallback withLogCallback:(LogCallback)logCallback;
|
||||
|
||||
/**
|
||||
* Returns the media information extracted in this session.
|
||||
*
|
||||
* @return media information extracted or nil if the command failed or the output can not be
|
||||
* parsed
|
||||
*/
|
||||
- (MediaInformation*)getMediaInformation;
|
||||
|
||||
/**
|
||||
* Sets the media information extracted in this session.
|
||||
*
|
||||
* @param mediaInformation media information extracted
|
||||
*/
|
||||
- (void)setMediaInformation:(MediaInformation*)mediaInformation;
|
||||
|
||||
/**
|
||||
* Returns the session specific complete callback.
|
||||
*
|
||||
* @return session specific complete callback
|
||||
*/
|
||||
- (MediaInformationSessionCompleteCallback)getCompleteCallback;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_MEDIA_INFORMATION_SESSION_H
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_MEDIA_INFORMATION_SESSION_COMPLETE_CALLBACK_H
|
||||
#define FFMPEG_KIT_MEDIA_INFORMATION_SESSION_COMPLETE_CALLBACK_H
|
||||
|
||||
@class MediaInformationSession;
|
||||
|
||||
/**
|
||||
* <p>Callback function that is invoked when an asynchronous <code>MediaInformation</code> session
|
||||
* has ended.
|
||||
* <p>Session has either SessionStateCompleted or SessionStateFailed state when
|
||||
* the callback is invoked.
|
||||
* <p>If it has SessionStateCompleted state, <code>ReturnCode</code> should be checked to
|
||||
* see the execution result.
|
||||
* <p>If <code>getState</code> returns SessionStateFailed then
|
||||
* <code>getFailStackTrace</code> should be used to get the failure reason.
|
||||
* <pre>
|
||||
* switch ([session getState]) {
|
||||
* case SessionStateCompleted:
|
||||
* ReturnCode *returnCode = [session getReturnCode];
|
||||
* break;
|
||||
* case SessionStateFailed:
|
||||
* NSString *failStackTrace = [session getFailStackTrace];
|
||||
* break;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param session session of the completed execution
|
||||
*/
|
||||
typedef void (^MediaInformationSessionCompleteCallback)(MediaInformationSession* session);
|
||||
|
||||
#import "MediaInformationSession.h"
|
||||
|
||||
#endif // FFMPEG_KIT_MEDIA_INFORMATION_SESSION_COMPLETE_CALLBACK_H
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_PACKAGES_H
|
||||
#define FFMPEG_KIT_PACKAGES_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* <p>Helper class to extract binary package information.
|
||||
*/
|
||||
@interface Packages : NSObject
|
||||
|
||||
/**
|
||||
* Returns the FFmpegKit binary package name.
|
||||
*
|
||||
* @return predicted FFmpegKit binary package name
|
||||
*/
|
||||
+ (NSString*)getPackageName;
|
||||
|
||||
/**
|
||||
* Returns enabled external libraries by FFmpeg.
|
||||
*
|
||||
* @return enabled external libraries
|
||||
*/
|
||||
+ (NSArray*)getExternalLibraries;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_PACKAGES_H
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_RETURN_CODE_H
|
||||
#define FFMPEG_KIT_RETURN_CODE_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM(NSUInteger, ReturnCodeEnum) {
|
||||
ReturnCodeSuccess = 0,
|
||||
ReturnCodeCancel = 255
|
||||
};
|
||||
|
||||
@interface ReturnCode : NSObject
|
||||
|
||||
- (instancetype)init:(int)value;
|
||||
|
||||
+ (BOOL)isSuccess:(ReturnCode*)value;
|
||||
|
||||
+ (BOOL)isCancel:(ReturnCode*)value;
|
||||
|
||||
- (int)getValue;
|
||||
|
||||
- (BOOL)isValueSuccess;
|
||||
|
||||
- (BOOL)isValueError;
|
||||
|
||||
- (BOOL)isValueCancel;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_RETURN_CODE_H
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_SESSION_H
|
||||
#define FFMPEG_KIT_SESSION_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Log.h"
|
||||
#import "LogCallback.h"
|
||||
#import "LogRedirectionStrategy.h"
|
||||
#import "ReturnCode.h"
|
||||
#import "SessionState.h"
|
||||
|
||||
/**
|
||||
* <p>Common interface for all <code>FFmpegKit</code> sessions.
|
||||
*/
|
||||
@protocol Session
|
||||
|
||||
@required
|
||||
|
||||
/**
|
||||
* Returns the session specific log callback.
|
||||
*
|
||||
* @return session specific log callback
|
||||
*/
|
||||
- (LogCallback)getLogCallback;
|
||||
|
||||
/**
|
||||
* Returns the session identifier.
|
||||
*
|
||||
* @return session identifier
|
||||
*/
|
||||
- (long)getSessionId;
|
||||
|
||||
/**
|
||||
* Returns session create time.
|
||||
*
|
||||
* @return session create time
|
||||
*/
|
||||
- (NSDate*)getCreateTime;
|
||||
|
||||
/**
|
||||
* Returns session start time.
|
||||
*
|
||||
* @return session start time
|
||||
*/
|
||||
- (NSDate*)getStartTime;
|
||||
|
||||
/**
|
||||
* Returns session end time.
|
||||
*
|
||||
* @return session end time
|
||||
*/
|
||||
- (NSDate*)getEndTime;
|
||||
|
||||
/**
|
||||
* Returns the time taken to execute this session.
|
||||
*
|
||||
* @return time taken to execute this session in milliseconds or zero (0) if the session is
|
||||
* not over yet
|
||||
*/
|
||||
- (long)getDuration;
|
||||
|
||||
/**
|
||||
* Returns command arguments as an array.
|
||||
*
|
||||
* @return command arguments as an array
|
||||
*/
|
||||
- (NSArray*)getArguments;
|
||||
|
||||
/**
|
||||
* Returns command arguments as a concatenated string.
|
||||
*
|
||||
* @return command arguments as a concatenated string
|
||||
*/
|
||||
- (NSString*)getCommand;
|
||||
|
||||
/**
|
||||
* Returns all log entries generated for this session. If there are asynchronous
|
||||
* messages that are not delivered yet, this method waits for them until the given timeout.
|
||||
*
|
||||
* @param waitTimeout wait timeout for asynchronous messages in milliseconds
|
||||
* @return list of log entries generated for this session
|
||||
*/
|
||||
- (NSArray*)getAllLogsWithTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* Returns all log entries generated for this session. If there are asynchronous
|
||||
* messages that are not delivered yet, this method waits for them.
|
||||
*
|
||||
* @return list of log entries generated for this session
|
||||
*/
|
||||
- (NSArray*)getAllLogs;
|
||||
|
||||
/**
|
||||
* Returns all log entries delivered for this session. Note that if there are asynchronous
|
||||
* messages that are not delivered yet, this method will not wait for them and will return
|
||||
* immediately.
|
||||
*
|
||||
* @return list of log entries received for this session
|
||||
*/
|
||||
- (NSArray*)getLogs;
|
||||
|
||||
/**
|
||||
* Returns all log entries generated for this session as a concatenated string. If there are
|
||||
* asynchronous messages that are not delivered yet, this method waits for them until
|
||||
* the given timeout.
|
||||
*
|
||||
* @param waitTimeout wait timeout for asynchronous messages in milliseconds
|
||||
* @return all log entries generated for this session as a concatenated string
|
||||
*/
|
||||
- (NSString*)getAllLogsAsStringWithTimeout:(int)waitTimeout;
|
||||
|
||||
/**
|
||||
* Returns all log entries generated for this session as a concatenated string. If there are
|
||||
* asynchronous messages that are not delivered yet, this method waits for them.
|
||||
*
|
||||
* @return all log entries generated for this session as a concatenated string
|
||||
*/
|
||||
- (NSString*)getAllLogsAsString;
|
||||
|
||||
/**
|
||||
* Returns all log entries delivered for this session as a concatenated string. Note that if
|
||||
* there are asynchronous messages that are not delivered yet, this method will not wait
|
||||
* for them and will return immediately.
|
||||
*
|
||||
* @return list of log entries received for this session
|
||||
*/
|
||||
- (NSString*)getLogsAsString;
|
||||
|
||||
/**
|
||||
* Returns the log output generated while running the session.
|
||||
*
|
||||
* @return log output generated
|
||||
*/
|
||||
- (NSString*)getOutput;
|
||||
|
||||
/**
|
||||
* Returns the state of the session.
|
||||
*
|
||||
* @return state of the session
|
||||
*/
|
||||
- (SessionState)getState;
|
||||
|
||||
/**
|
||||
* Returns the return code for this session. Note that return code is only set for sessions
|
||||
* that end with SessionStateCompleted state. If a session is not started, still running or failed then
|
||||
* this method returns nil.
|
||||
*
|
||||
* @return the return code for this session if the session has completed, nil if session is
|
||||
* not started, still running or failed
|
||||
*/
|
||||
- (ReturnCode*)getReturnCode;
|
||||
|
||||
/**
|
||||
* Returns the stack trace of the exception received while executing this session.
|
||||
* <p>
|
||||
* The stack trace is only set for sessions that end with SessionStateFailed state. For sessions that has
|
||||
* SessionStateCompleted state this method returns nil.
|
||||
*
|
||||
* @return stack trace of the exception received while executing this session, nil if session
|
||||
* is not started, still running or completed
|
||||
*/
|
||||
- (NSString*)getFailStackTrace;
|
||||
|
||||
/**
|
||||
* Returns session specific log redirection strategy.
|
||||
*
|
||||
* @return session specific log redirection strategy
|
||||
*/
|
||||
- (LogRedirectionStrategy)getLogRedirectionStrategy;
|
||||
|
||||
/**
|
||||
* Returns whether there are still asynchronous messages being transmitted for this
|
||||
* session or not.
|
||||
*
|
||||
* @return true if there are still asynchronous messages being transmitted, false
|
||||
* otherwise
|
||||
*/
|
||||
- (BOOL)thereAreAsynchronousMessagesInTransmit;
|
||||
|
||||
/**
|
||||
* Adds a new log entry for this session.
|
||||
*
|
||||
* It is invoked internally by <code>FFmpegKit</code> library methods. Must not be used by user
|
||||
* applications.
|
||||
*
|
||||
* @param log log entry
|
||||
*/
|
||||
- (void)addLog:(Log*)log;
|
||||
|
||||
/**
|
||||
* Starts running the session.
|
||||
*/
|
||||
- (void)startRunning;
|
||||
|
||||
/**
|
||||
* Completes running the session with the provided return code.
|
||||
*
|
||||
* @param returnCode return code of the execution
|
||||
*/
|
||||
- (void)complete:(ReturnCode*)returnCode;
|
||||
|
||||
/**
|
||||
* Ends running the session with a failure.
|
||||
*
|
||||
* @param exception execution received
|
||||
*/
|
||||
- (void)fail:(NSException*)exception;
|
||||
|
||||
/**
|
||||
* Returns whether it is an <code>FFmpeg</code> session or not.
|
||||
*
|
||||
* @return true if it is an <code>FFmpeg</code> session, false otherwise
|
||||
*/
|
||||
- (BOOL)isFFmpeg;
|
||||
|
||||
/**
|
||||
* Returns whether it is an <code>FFprobe</code> session or not.
|
||||
*
|
||||
* @return true if it is an <code>FFprobe</code> session, false otherwise
|
||||
*/
|
||||
- (BOOL)isFFprobe;
|
||||
|
||||
/**
|
||||
* Returns whether it is a <code>MediaInformation</code> session or not.
|
||||
*
|
||||
* @return true if it is a <code>MediaInformation</code> session, false otherwise
|
||||
*/
|
||||
- (BOOL)isMediaInformation;
|
||||
|
||||
/**
|
||||
* Cancels running the session.
|
||||
*/
|
||||
- (void)cancel;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_SESSION_H
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_SESSION_STATE_H
|
||||
#define FFMPEG_KIT_SESSION_STATE_H
|
||||
|
||||
typedef NS_ENUM(NSUInteger, SessionState) {
|
||||
SessionStateCreated,
|
||||
SessionStateRunning,
|
||||
SessionStateFailed,
|
||||
SessionStateCompleted
|
||||
};
|
||||
|
||||
#endif // FFMPEG_KIT_SESSION_STATE_H
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_STATISTICS_H
|
||||
#define FFMPEG_KIT_STATISTICS_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* Statistics entry for an FFmpeg execute session.
|
||||
*/
|
||||
@interface Statistics : NSObject
|
||||
|
||||
- (instancetype)init:(long)sessionId videoFrameNumber:(int)videoFrameNumber videoFps:(float)videoFps videoQuality:(float)videoQuality size:(int64_t)size time:(int)time bitrate:(double)bitrate speed:(double)speed;
|
||||
|
||||
- (long)getSessionId;
|
||||
|
||||
- (int)getVideoFrameNumber;
|
||||
|
||||
- (float)getVideoFps;
|
||||
|
||||
- (float)getVideoQuality;
|
||||
|
||||
- (long)getSize;
|
||||
|
||||
- (int)getTime;
|
||||
|
||||
- (double)getBitrate;
|
||||
|
||||
- (double)getSpeed;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_STATISTICS_H
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_STATISTICS_CALLBACK_H
|
||||
#define FFMPEG_KIT_STATISTICS_CALLBACK_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Statistics.h"
|
||||
|
||||
/**
|
||||
* <p>Callback that receives statistics generated for <code>FFmpegKit</code> sessions.
|
||||
*
|
||||
* @param statistics statistics entry
|
||||
*/
|
||||
typedef void (^StatisticsCallback)(Statistics* statistics);
|
||||
|
||||
#endif // FFMPEG_KIT_STATISTICS_CALLBACK_H
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_STREAM_INFORMATION_H
|
||||
#define FFMPEG_KIT_STREAM_INFORMATION_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern NSString* const StreamKeyIndex;
|
||||
extern NSString* const StreamKeyType;
|
||||
extern NSString* const StreamKeyCodec;
|
||||
extern NSString* const StreamKeyCodecLong;
|
||||
extern NSString* const StreamKeyFormat;
|
||||
extern NSString* const StreamKeyWidth;
|
||||
extern NSString* const StreamKeyHeight;
|
||||
extern NSString* const StreamKeyBitRate;
|
||||
extern NSString* const StreamKeySampleRate;
|
||||
extern NSString* const StreamKeySampleFormat;
|
||||
extern NSString* const StreamKeyChannelLayout;
|
||||
extern NSString* const StreamKeySampleAspectRatio;
|
||||
extern NSString* const StreamKeyDisplayAspectRatio;
|
||||
extern NSString* const StreamKeyAverageFrameRate;
|
||||
extern NSString* const StreamKeyRealFrameRate;
|
||||
extern NSString* const StreamKeyTimeBase;
|
||||
extern NSString* const StreamKeyCodecTimeBase;
|
||||
extern NSString* const StreamKeyTags;
|
||||
|
||||
/**
|
||||
* Stream information class.
|
||||
*/
|
||||
@interface StreamInformation : NSObject
|
||||
|
||||
- (instancetype)init:(NSDictionary*)streamDictionary;
|
||||
|
||||
/**
|
||||
* Returns stream index.
|
||||
*
|
||||
* @return stream index, starting from zero
|
||||
*/
|
||||
- (NSNumber*)getIndex;
|
||||
|
||||
/**
|
||||
* Returns stream type.
|
||||
*
|
||||
* @return stream type; audio or video
|
||||
*/
|
||||
- (NSString*)getType;
|
||||
|
||||
/**
|
||||
* Returns stream codec.
|
||||
*
|
||||
* @return stream codec
|
||||
*/
|
||||
- (NSString*)getCodec;
|
||||
|
||||
/**
|
||||
* Returns stream codec in long format.
|
||||
*
|
||||
* @return stream codec with additional profile and mode information
|
||||
*/
|
||||
- (NSString*)getCodecLong;
|
||||
|
||||
/**
|
||||
* Returns stream format.
|
||||
*
|
||||
* @return stream format
|
||||
*/
|
||||
- (NSString*)getFormat;
|
||||
|
||||
/**
|
||||
* Returns width.
|
||||
*
|
||||
* @return width in pixels
|
||||
*/
|
||||
- (NSNumber*)getWidth;
|
||||
|
||||
/**
|
||||
* Returns height.
|
||||
*
|
||||
* @return height in pixels
|
||||
*/
|
||||
- (NSNumber*)getHeight;
|
||||
|
||||
/**
|
||||
* Returns bitrate.
|
||||
*
|
||||
* @return bitrate in kb/s
|
||||
*/
|
||||
- (NSString*)getBitrate;
|
||||
|
||||
/**
|
||||
* Returns sample rate.
|
||||
*
|
||||
* @return sample rate in hz
|
||||
*/
|
||||
- (NSString*)getSampleRate;
|
||||
|
||||
/**
|
||||
* Returns sample format.
|
||||
*
|
||||
* @return sample format
|
||||
*/
|
||||
- (NSString*)getSampleFormat;
|
||||
|
||||
/**
|
||||
* Returns channel layout.
|
||||
*
|
||||
* @return channel layout
|
||||
*/
|
||||
- (NSString*)getChannelLayout;
|
||||
|
||||
/**
|
||||
* Returns sample aspect ratio.
|
||||
*
|
||||
* @return sample aspect ratio
|
||||
*/
|
||||
- (NSString*)getSampleAspectRatio;
|
||||
|
||||
/**
|
||||
* Returns display aspect ratio.
|
||||
*
|
||||
* @return display aspect ratio
|
||||
*/
|
||||
- (NSString*)getDisplayAspectRatio;
|
||||
|
||||
/**
|
||||
* Returns average frame rate.
|
||||
*
|
||||
* @return average frame rate in fps
|
||||
*/
|
||||
- (NSString*)getAverageFrameRate;
|
||||
|
||||
/**
|
||||
* Returns real frame rate.
|
||||
*
|
||||
* @return real frame rate in tbr
|
||||
*/
|
||||
- (NSString*)getRealFrameRate;
|
||||
|
||||
/**
|
||||
* Returns time base.
|
||||
*
|
||||
* @return time base in tbn
|
||||
*/
|
||||
- (NSString*)getTimeBase;
|
||||
|
||||
/**
|
||||
* Returns codec time base.
|
||||
*
|
||||
* @return codec time base in tbc
|
||||
*/
|
||||
- (NSString*)getCodecTimeBase;
|
||||
|
||||
/**
|
||||
* Returns all tags.
|
||||
*
|
||||
* @return tags dictionary
|
||||
*/
|
||||
- (NSDictionary*)getTags;
|
||||
|
||||
/**
|
||||
* Returns the stream property associated with the key.
|
||||
*
|
||||
* @return stream property as string or nil if the key is not found
|
||||
*/
|
||||
- (NSString*)getStringProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns the stream property associated with the key.
|
||||
*
|
||||
* @return stream property as number or nil if the key is not found
|
||||
*/
|
||||
- (NSNumber*)getNumberProperty:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns the stream properties associated with the key.
|
||||
*
|
||||
* @return stream properties in a dictionary or nil if the key is not found
|
||||
*/
|
||||
- (NSDictionary*)getProperties:(NSString*)key;
|
||||
|
||||
/**
|
||||
* Returns all stream properties defined.
|
||||
*
|
||||
* @return all stream properties in a dictionary or nil if no properties are defined
|
||||
*/
|
||||
- (NSDictionary*)getAllProperties;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FFMPEG_KIT_STREAM_INFORMATION_H
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2021 Taner Sener
|
||||
*
|
||||
* This file is part of FFmpegKit.
|
||||
*
|
||||
* FFmpegKit is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FFmpegKit is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FFMPEG_KIT_EXCEPTION_H
|
||||
#define FFMPEG_KIT_EXCEPTION_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
/** Holds information to implement exception handling. */
|
||||
extern __thread jmp_buf ex_buf__;
|
||||
|
||||
#endif // FFMPEG_KIT_EXCEPTION_H
|
|
@ -0,0 +1,641 @@
|
|||
/*
|
||||
* Various utilities for command line tools
|
||||
* copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* CHANGES 01.2020
|
||||
* - ffprobe support changes
|
||||
* - AV_LOG_STDERR introduced
|
||||
*
|
||||
* CHANGES 12.2019
|
||||
* - Concurrent execution support
|
||||
*
|
||||
* CHANGES 03.2019
|
||||
* --------------------------------------------------------
|
||||
* - config.h include removed
|
||||
*
|
||||
* CHANGES 08.2018
|
||||
* --------------------------------------------------------
|
||||
* - fftools_ prefix added to file name and include guards
|
||||
*
|
||||
* CHANGES 07.2018
|
||||
* --------------------------------------------------------
|
||||
* - Include guards renamed
|
||||
* - Unused headers removed
|
||||
*/
|
||||
|
||||
#ifndef FFTOOLS_CMDUTILS_H
|
||||
#define FFTOOLS_CMDUTILS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libavcodec/avcodec.h"
|
||||
#include "libavfilter/avfilter.h"
|
||||
#include "libavformat/avformat.h"
|
||||
#include "libswscale/swscale.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef main /* We don't want SDL to override our main() */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Defines logs printed to stderr by ffmpeg. They are not filtered and always redirected.
|
||||
*/
|
||||
#define AV_LOG_STDERR -16
|
||||
|
||||
/**
|
||||
* program name, defined by the program for show_version().
|
||||
*/
|
||||
extern __thread char *program_name;
|
||||
|
||||
/**
|
||||
* program birth year, defined by the program for show_banner()
|
||||
*/
|
||||
extern __thread int program_birth_year;
|
||||
|
||||
extern __thread AVCodecContext *avcodec_opts[AVMEDIA_TYPE_NB];
|
||||
extern __thread AVFormatContext *avformat_opts;
|
||||
extern __thread AVDictionary *sws_dict;
|
||||
extern __thread AVDictionary *swr_opts;
|
||||
extern __thread AVDictionary *format_opts, *codec_opts, *resample_opts;
|
||||
extern __thread int hide_banner;
|
||||
extern __thread int find_stream_info;
|
||||
|
||||
/**
|
||||
* Register a program-specific cleanup routine.
|
||||
*/
|
||||
void register_exit(void (*cb)(int ret));
|
||||
|
||||
/**
|
||||
* Wraps exit with a program-specific cleanup routine.
|
||||
*/
|
||||
void exit_program(int ret) av_noreturn;
|
||||
|
||||
/**
|
||||
* Initialize dynamic library loading
|
||||
*/
|
||||
void init_dynload(void);
|
||||
|
||||
/**
|
||||
* Initialize the cmdutils option system, in particular
|
||||
* allocate the *_opts contexts.
|
||||
*/
|
||||
void init_opts(void);
|
||||
/**
|
||||
* Uninitialize the cmdutils option system, in particular
|
||||
* free the *_opts contexts and their contents.
|
||||
*/
|
||||
void uninit_opts(void);
|
||||
|
||||
/**
|
||||
* Trivial log callback.
|
||||
* Only suitable for opt_help and similar since it lacks prefix handling.
|
||||
*/
|
||||
void log_callback_help(void* ptr, int level, const char* fmt, va_list vl);
|
||||
|
||||
/**
|
||||
* Override the cpuflags.
|
||||
*/
|
||||
int opt_cpuflags(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Override the cpucount.
|
||||
*/
|
||||
int opt_cpucount(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Fallback for options that are not explicitly handled, these will be
|
||||
* parsed through AVOptions.
|
||||
*/
|
||||
int opt_default(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Set the libav* libraries log level.
|
||||
*/
|
||||
int opt_loglevel(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
int opt_report(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
int opt_max_alloc(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
int opt_codec_debug(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Limit the execution time.
|
||||
*/
|
||||
int opt_timelimit(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Parse a string and return its corresponding value as a double.
|
||||
* Exit from the application if the string cannot be correctly
|
||||
* parsed or the corresponding value is invalid.
|
||||
*
|
||||
* @param context the context of the value to be set (e.g. the
|
||||
* corresponding command line option name)
|
||||
* @param numstr the string to be parsed
|
||||
* @param type the type (OPT_INT64 or OPT_FLOAT) as which the
|
||||
* string should be parsed
|
||||
* @param min the minimum valid accepted value
|
||||
* @param max the maximum valid accepted value
|
||||
*/
|
||||
double parse_number_or_die(const char *context, const char *numstr, int type,
|
||||
double min, double max);
|
||||
|
||||
/**
|
||||
* Parse a string specifying a time and return its corresponding
|
||||
* value as a number of microseconds. Exit from the application if
|
||||
* the string cannot be correctly parsed.
|
||||
*
|
||||
* @param context the context of the value to be set (e.g. the
|
||||
* corresponding command line option name)
|
||||
* @param timestr the string to be parsed
|
||||
* @param is_duration a flag which tells how to interpret timestr, if
|
||||
* not zero timestr is interpreted as a duration, otherwise as a
|
||||
* date
|
||||
*
|
||||
* @see av_parse_time()
|
||||
*/
|
||||
int64_t parse_time_or_die(const char *context, const char *timestr,
|
||||
int is_duration);
|
||||
|
||||
typedef struct SpecifierOpt {
|
||||
char *specifier; /**< stream/chapter/program/... specifier */
|
||||
union {
|
||||
uint8_t *str;
|
||||
int i;
|
||||
int64_t i64;
|
||||
uint64_t ui64;
|
||||
float f;
|
||||
double dbl;
|
||||
} u;
|
||||
} SpecifierOpt;
|
||||
|
||||
typedef struct OptionDef {
|
||||
const char *name;
|
||||
int flags;
|
||||
#define HAS_ARG 0x0001
|
||||
#define OPT_BOOL 0x0002
|
||||
#define OPT_EXPERT 0x0004
|
||||
#define OPT_STRING 0x0008
|
||||
#define OPT_VIDEO 0x0010
|
||||
#define OPT_AUDIO 0x0020
|
||||
#define OPT_INT 0x0080
|
||||
#define OPT_FLOAT 0x0100
|
||||
#define OPT_SUBTITLE 0x0200
|
||||
#define OPT_INT64 0x0400
|
||||
#define OPT_EXIT 0x0800
|
||||
#define OPT_DATA 0x1000
|
||||
#define OPT_PERFILE 0x2000 /* the option is per-file (currently ffmpeg-only).
|
||||
implied by OPT_OFFSET or OPT_SPEC */
|
||||
#define OPT_OFFSET 0x4000 /* option is specified as an offset in a passed optctx */
|
||||
#define OPT_SPEC 0x8000 /* option is to be stored in an array of SpecifierOpt.
|
||||
Implies OPT_OFFSET. Next element after the offset is
|
||||
an int containing element count in the array. */
|
||||
#define OPT_TIME 0x10000
|
||||
#define OPT_DOUBLE 0x20000
|
||||
#define OPT_INPUT 0x40000
|
||||
#define OPT_OUTPUT 0x80000
|
||||
union {
|
||||
void *dst_ptr;
|
||||
int (*func_arg)(void *, const char *, const char *);
|
||||
size_t off;
|
||||
} u;
|
||||
const char *help;
|
||||
const char *argname;
|
||||
} OptionDef;
|
||||
|
||||
/**
|
||||
* Print help for all options matching specified flags.
|
||||
*
|
||||
* @param options a list of options
|
||||
* @param msg title of this group. Only printed if at least one option matches.
|
||||
* @param req_flags print only options which have all those flags set.
|
||||
* @param rej_flags don't print options which have any of those flags set.
|
||||
* @param alt_flags print only options that have at least one of those flags set
|
||||
*/
|
||||
void show_help_options(const OptionDef *options, const char *msg, int req_flags,
|
||||
int rej_flags, int alt_flags);
|
||||
|
||||
/**
|
||||
* Show help for all options with given flags in class and all its
|
||||
* children.
|
||||
*/
|
||||
void show_help_children(const AVClass *class, int flags);
|
||||
|
||||
/**
|
||||
* Per-fftool specific help handler. Implemented in each
|
||||
* fftool, called by show_help().
|
||||
*/
|
||||
void show_help_default_ffmpeg(const char *opt, const char *arg);
|
||||
void show_help_default_ffprobe(const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Generic -h handler common to all fftools.
|
||||
*/
|
||||
int show_help(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Parse the command line arguments.
|
||||
*
|
||||
* @param optctx an opaque options context
|
||||
* @param argc number of command line arguments
|
||||
* @param argv values of command line arguments
|
||||
* @param options Array with the definitions required to interpret every
|
||||
* option of the form: -option_name [argument]
|
||||
* @param parse_arg_function Name of the function called to process every
|
||||
* argument without a leading option name flag. NULL if such arguments do
|
||||
* not have to be processed.
|
||||
*/
|
||||
void parse_options(void *optctx, int argc, char **argv, const OptionDef *options,
|
||||
void (* parse_arg_function)(void *optctx, const char*));
|
||||
|
||||
/**
|
||||
* Parse one given option.
|
||||
*
|
||||
* @return on success 1 if arg was consumed, 0 otherwise; negative number on error
|
||||
*/
|
||||
int parse_option(void *optctx, const char *opt, const char *arg,
|
||||
const OptionDef *options);
|
||||
|
||||
/**
|
||||
* An option extracted from the commandline.
|
||||
* Cannot use AVDictionary because of options like -map which can be
|
||||
* used multiple times.
|
||||
*/
|
||||
typedef struct Option {
|
||||
const OptionDef *opt;
|
||||
const char *key;
|
||||
const char *val;
|
||||
} Option;
|
||||
|
||||
typedef struct OptionGroupDef {
|
||||
/**< group name */
|
||||
const char *name;
|
||||
/**
|
||||
* Option to be used as group separator. Can be NULL for groups which
|
||||
* are terminated by a non-option argument (e.g. ffmpeg output files)
|
||||
*/
|
||||
const char *sep;
|
||||
/**
|
||||
* Option flags that must be set on each option that is
|
||||
* applied to this group
|
||||
*/
|
||||
int flags;
|
||||
} OptionGroupDef;
|
||||
|
||||
typedef struct OptionGroup {
|
||||
const OptionGroupDef *group_def;
|
||||
const char *arg;
|
||||
|
||||
Option *opts;
|
||||
int nb_opts;
|
||||
|
||||
AVDictionary *codec_opts;
|
||||
AVDictionary *format_opts;
|
||||
AVDictionary *resample_opts;
|
||||
AVDictionary *sws_dict;
|
||||
AVDictionary *swr_opts;
|
||||
} OptionGroup;
|
||||
|
||||
/**
|
||||
* A list of option groups that all have the same group type
|
||||
* (e.g. input files or output files)
|
||||
*/
|
||||
typedef struct OptionGroupList {
|
||||
const OptionGroupDef *group_def;
|
||||
|
||||
OptionGroup *groups;
|
||||
int nb_groups;
|
||||
} OptionGroupList;
|
||||
|
||||
typedef struct OptionParseContext {
|
||||
OptionGroup global_opts;
|
||||
|
||||
OptionGroupList *groups;
|
||||
int nb_groups;
|
||||
|
||||
/* parsing state */
|
||||
OptionGroup cur_group;
|
||||
} OptionParseContext;
|
||||
|
||||
/**
|
||||
* Parse an options group and write results into optctx.
|
||||
*
|
||||
* @param optctx an app-specific options context. NULL for global options group
|
||||
* @param g option group
|
||||
*/
|
||||
int parse_optgroup(void *optctx, OptionGroup *g);
|
||||
|
||||
/**
|
||||
* Split the commandline into an intermediate form convenient for further
|
||||
* processing.
|
||||
*
|
||||
* The commandline is assumed to be composed of options which either belong to a
|
||||
* group (those with OPT_SPEC, OPT_OFFSET or OPT_PERFILE) or are global
|
||||
* (everything else).
|
||||
*
|
||||
* A group (defined by an OptionGroupDef struct) is a sequence of options
|
||||
* terminated by either a group separator option (e.g. -i) or a parameter that
|
||||
* is not an option (doesn't start with -). A group without a separator option
|
||||
* must always be first in the supplied groups list.
|
||||
*
|
||||
* All options within the same group are stored in one OptionGroup struct in an
|
||||
* OptionGroupList, all groups with the same group definition are stored in one
|
||||
* OptionGroupList in OptionParseContext.groups. The order of group lists is the
|
||||
* same as the order of group definitions.
|
||||
*/
|
||||
int split_commandline(OptionParseContext *octx, int argc, char *argv[],
|
||||
const OptionDef *options,
|
||||
const OptionGroupDef *groups, int nb_groups);
|
||||
|
||||
/**
|
||||
* Free all allocated memory in an OptionParseContext.
|
||||
*/
|
||||
void uninit_parse_context(OptionParseContext *octx);
|
||||
|
||||
/**
|
||||
* Find the '-loglevel' option in the command line args and apply it.
|
||||
*/
|
||||
void parse_loglevel(int argc, char **argv, const OptionDef *options);
|
||||
|
||||
/**
|
||||
* Return index of option opt in argv or 0 if not found.
|
||||
*/
|
||||
int locate_option(int argc, char **argv, const OptionDef *options,
|
||||
const char *optname);
|
||||
|
||||
/**
|
||||
* Check if the given stream matches a stream specifier.
|
||||
*
|
||||
* @param s Corresponding format context.
|
||||
* @param st Stream from s to be checked.
|
||||
* @param spec A stream specifier of the [v|a|s|d]:[\<stream index\>] form.
|
||||
*
|
||||
* @return 1 if the stream matches, 0 if it doesn't, <0 on error
|
||||
*/
|
||||
int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec);
|
||||
|
||||
/**
|
||||
* Filter out options for given codec.
|
||||
*
|
||||
* Create a new options dictionary containing only the options from
|
||||
* opts which apply to the codec with ID codec_id.
|
||||
*
|
||||
* @param opts dictionary to place options in
|
||||
* @param codec_id ID of the codec that should be filtered for
|
||||
* @param s Corresponding format context.
|
||||
* @param st A stream from s for which the options should be filtered.
|
||||
* @param codec The particular codec for which the options should be filtered.
|
||||
* If null, the default one is looked up according to the codec id.
|
||||
* @return a pointer to the created dictionary
|
||||
*/
|
||||
AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
|
||||
AVFormatContext *s, AVStream *st, const AVCodec *codec);
|
||||
|
||||
/**
|
||||
* Setup AVCodecContext options for avformat_find_stream_info().
|
||||
*
|
||||
* Create an array of dictionaries, one dictionary for each stream
|
||||
* contained in s.
|
||||
* Each dictionary will contain the options from codec_opts which can
|
||||
* be applied to the corresponding stream codec context.
|
||||
*
|
||||
* @return pointer to the created array of dictionaries, NULL if it
|
||||
* cannot be created
|
||||
*/
|
||||
AVDictionary **setup_find_stream_info_opts(AVFormatContext *s,
|
||||
AVDictionary *codec_opts);
|
||||
|
||||
/**
|
||||
* Print an error message to stderr, indicating filename and a human
|
||||
* readable description of the error code err.
|
||||
*
|
||||
* If strerror_r() is not available the use of this function in a
|
||||
* multithreaded application may be unsafe.
|
||||
*
|
||||
* @see av_strerror()
|
||||
*/
|
||||
void print_error(const char *filename, int err);
|
||||
|
||||
/**
|
||||
* Print the program banner to stderr. The banner contents depend on the
|
||||
* current version of the repository and of the libav* libraries used by
|
||||
* the program.
|
||||
*/
|
||||
void show_banner(int argc, char **argv, const OptionDef *options);
|
||||
|
||||
/**
|
||||
* Print the version of the program to stdout. The version message
|
||||
* depends on the current versions of the repository and of the libav*
|
||||
* libraries.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_version(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print the build configuration of the program to stdout. The contents
|
||||
* depend on the definition of FFMPEG_CONFIGURATION.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_buildconf(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print the license of the program to stdout. The license depends on
|
||||
* the license of the libraries compiled into the program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_license(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the formats supported by the
|
||||
* program (including devices).
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_formats(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the muxers supported by the
|
||||
* program (including devices).
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_muxers(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the demuxer supported by the
|
||||
* program (including devices).
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_demuxers(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the devices supported by the
|
||||
* program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_devices(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
#if CONFIG_AVDEVICE
|
||||
/**
|
||||
* Print a listing containing autodetected sinks of the output device.
|
||||
* Device name with options may be passed as an argument to limit results.
|
||||
*/
|
||||
int show_sinks(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing autodetected sources of the input device.
|
||||
* Device name with options may be passed as an argument to limit results.
|
||||
*/
|
||||
int show_sources(void *optctx, const char *opt, const char *arg);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Print a listing containing all the codecs supported by the
|
||||
* program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_codecs(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the decoders supported by the
|
||||
* program.
|
||||
*/
|
||||
int show_decoders(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the encoders supported by the
|
||||
* program.
|
||||
*/
|
||||
int show_encoders(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the filters supported by the
|
||||
* program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_filters(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the bit stream filters supported by the
|
||||
* program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_bsfs(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the protocols supported by the
|
||||
* program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_protocols(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the pixel formats supported by the
|
||||
* program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_pix_fmts(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the standard channel layouts supported by
|
||||
* the program.
|
||||
* This option processing function does not utilize the arguments.
|
||||
*/
|
||||
int show_layouts(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the sample formats supported by the
|
||||
* program.
|
||||
*/
|
||||
int show_sample_fmts(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Print a listing containing all the color names and values recognized
|
||||
* by the program.
|
||||
*/
|
||||
int show_colors(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
/**
|
||||
* Return a positive value if a line read from standard input
|
||||
* starts with [yY], otherwise return 0.
|
||||
*/
|
||||
int read_yesno(void);
|
||||
|
||||
/**
|
||||
* Get a file corresponding to a preset file.
|
||||
*
|
||||
* If is_path is non-zero, look for the file in the path preset_name.
|
||||
* Otherwise search for a file named arg.ffpreset in the directories
|
||||
* $FFMPEG_DATADIR (if set), $HOME/.ffmpeg, and in the datadir defined
|
||||
* at configuration time or in a "ffpresets" folder along the executable
|
||||
* on win32, in that order. If no such file is found and
|
||||
* codec_name is defined, then search for a file named
|
||||
* codec_name-preset_name.avpreset in the above-mentioned directories.
|
||||
*
|
||||
* @param filename buffer where the name of the found filename is written
|
||||
* @param filename_size size in bytes of the filename buffer
|
||||
* @param preset_name name of the preset to search
|
||||
* @param is_path tell if preset_name is a filename path
|
||||
* @param codec_name name of the codec for which to look for the
|
||||
* preset, may be NULL
|
||||
*/
|
||||
FILE *get_preset_file(char *filename, size_t filename_size,
|
||||
const char *preset_name, int is_path, const char *codec_name);
|
||||
|
||||
/**
|
||||
* Realloc array to hold new_size elements of elem_size.
|
||||
* Calls exit() on failure.
|
||||
*
|
||||
* @param array array to reallocate
|
||||
* @param elem_size size in bytes of each element
|
||||
* @param size new element count will be written here
|
||||
* @param new_size number of elements to place in reallocated array
|
||||
* @return reallocated array
|
||||
*/
|
||||
void *grow_array(void *array, int elem_size, int *size, int new_size);
|
||||
|
||||
#define media_type_string av_get_media_type_string
|
||||
|
||||
#define GROW_ARRAY(array, nb_elems)\
|
||||
array = grow_array(array, sizeof(*array), &nb_elems, nb_elems + 1)
|
||||
|
||||
#define GET_PIX_FMT_NAME(pix_fmt)\
|
||||
const char *name = av_get_pix_fmt_name(pix_fmt);
|
||||
|
||||
#define GET_CODEC_NAME(id)\
|
||||
const char *name = avcodec_descriptor_get(id)->name;
|
||||
|
||||
#define GET_SAMPLE_FMT_NAME(sample_fmt)\
|
||||
const char *name = av_get_sample_fmt_name(sample_fmt)
|
||||
|
||||
#define GET_SAMPLE_RATE_NAME(rate)\
|
||||
char name[16];\
|
||||
snprintf(name, sizeof(name), "%d", rate);
|
||||
|
||||
#define GET_CH_LAYOUT_NAME(ch_layout)\
|
||||
char name[16];\
|
||||
snprintf(name, sizeof(name), "0x%"PRIx64, ch_layout);
|
||||
|
||||
#define GET_CH_LAYOUT_DESC(ch_layout)\
|
||||
char name[128];\
|
||||
av_get_channel_layout_string(name, sizeof(name), 0, ch_layout);
|
||||
|
||||
double get_rotation(AVStream *st);
|
||||
|
||||
#endif /* FFTOOLS_CMDUTILS_H */
|
|
@ -0,0 +1,791 @@
|
|||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* CHANGES 06.2020
|
||||
* - cancel_operation() method signature updated with id
|
||||
*
|
||||
* CHANGES 01.2020
|
||||
* - ffprobe support changes
|
||||
*
|
||||
* CHANGES 12.2019
|
||||
* - Concurrent execution support
|
||||
*
|
||||
* CHANGES 03.2019
|
||||
* --------------------------------------------------------
|
||||
* - config.h include removed
|
||||
*
|
||||
* CHANGES 08.2018
|
||||
* --------------------------------------------------------
|
||||
* - fftools_ prefix added to file name and include guards
|
||||
* - set_report_callback() method declared
|
||||
* - cancel_operation() method declared
|
||||
*
|
||||
* CHANGES 07.2018
|
||||
* --------------------------------------------------------
|
||||
* - Include guards renamed
|
||||
*/
|
||||
|
||||
#ifndef FFTOOLS_FFMPEG_H
|
||||
#define FFTOOLS_FFMPEG_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "fftools_cmdutils.h"
|
||||
|
||||
#include "libavformat/avformat.h"
|
||||
#include "libavformat/avio.h"
|
||||
|
||||
#include "libavcodec/avcodec.h"
|
||||
#include "libavcodec/bsf.h"
|
||||
|
||||
#include "libavfilter/avfilter.h"
|
||||
|
||||
#include "libavutil/avutil.h"
|
||||
#include "libavutil/dict.h"
|
||||
#include "libavutil/eval.h"
|
||||
#include "libavutil/fifo.h"
|
||||
#include "libavutil/hwcontext.h"
|
||||
#include "libavutil/pixfmt.h"
|
||||
#include "libavutil/rational.h"
|
||||
#include "libavutil/thread.h"
|
||||
#include "libavutil/threadmessage.h"
|
||||
|
||||
#include "libswresample/swresample.h"
|
||||
|
||||
#define VSYNC_AUTO -1
|
||||
#define VSYNC_PASSTHROUGH 0
|
||||
#define VSYNC_CFR 1
|
||||
#define VSYNC_VFR 2
|
||||
#define VSYNC_VSCFR 0xfe
|
||||
#define VSYNC_DROP 0xff
|
||||
|
||||
#define MAX_STREAMS 1024 /* arbitrary sanity check value */
|
||||
|
||||
enum HWAccelID {
|
||||
HWACCEL_NONE = 0,
|
||||
HWACCEL_AUTO,
|
||||
HWACCEL_GENERIC,
|
||||
HWACCEL_VIDEOTOOLBOX,
|
||||
};
|
||||
|
||||
typedef struct HWAccel {
|
||||
const char *name;
|
||||
int (*init)(AVCodecContext *s);
|
||||
enum HWAccelID id;
|
||||
enum AVPixelFormat pix_fmt;
|
||||
} HWAccel;
|
||||
|
||||
typedef struct HWDevice {
|
||||
const char *name;
|
||||
enum AVHWDeviceType type;
|
||||
AVBufferRef *device_ref;
|
||||
} HWDevice;
|
||||
|
||||
/* select an input stream for an output stream */
|
||||
typedef struct StreamMap {
|
||||
int disabled; /* 1 is this mapping is disabled by a negative map */
|
||||
int file_index;
|
||||
int stream_index;
|
||||
int sync_file_index;
|
||||
int sync_stream_index;
|
||||
char *linklabel; /* name of an output link, for mapping lavfi outputs */
|
||||
} StreamMap;
|
||||
|
||||
typedef struct {
|
||||
int file_idx, stream_idx, channel_idx; // input
|
||||
int ofile_idx, ostream_idx; // output
|
||||
} AudioChannelMap;
|
||||
|
||||
typedef struct OptionsContext {
|
||||
OptionGroup *g;
|
||||
|
||||
/* input/output options */
|
||||
int64_t start_time;
|
||||
int64_t start_time_eof;
|
||||
int seek_timestamp;
|
||||
const char *format;
|
||||
|
||||
SpecifierOpt *codec_names;
|
||||
int nb_codec_names;
|
||||
SpecifierOpt *audio_channels;
|
||||
int nb_audio_channels;
|
||||
SpecifierOpt *audio_sample_rate;
|
||||
int nb_audio_sample_rate;
|
||||
SpecifierOpt *frame_rates;
|
||||
int nb_frame_rates;
|
||||
SpecifierOpt *max_frame_rates;
|
||||
int nb_max_frame_rates;
|
||||
SpecifierOpt *frame_sizes;
|
||||
int nb_frame_sizes;
|
||||
SpecifierOpt *frame_pix_fmts;
|
||||
int nb_frame_pix_fmts;
|
||||
|
||||
/* input options */
|
||||
int64_t input_ts_offset;
|
||||
int loop;
|
||||
int rate_emu;
|
||||
float readrate;
|
||||
int accurate_seek;
|
||||
int thread_queue_size;
|
||||
|
||||
SpecifierOpt *ts_scale;
|
||||
int nb_ts_scale;
|
||||
SpecifierOpt *dump_attachment;
|
||||
int nb_dump_attachment;
|
||||
SpecifierOpt *hwaccels;
|
||||
int nb_hwaccels;
|
||||
SpecifierOpt *hwaccel_devices;
|
||||
int nb_hwaccel_devices;
|
||||
SpecifierOpt *hwaccel_output_formats;
|
||||
int nb_hwaccel_output_formats;
|
||||
SpecifierOpt *autorotate;
|
||||
int nb_autorotate;
|
||||
|
||||
/* output options */
|
||||
StreamMap *stream_maps;
|
||||
int nb_stream_maps;
|
||||
AudioChannelMap *audio_channel_maps; /* one info entry per -map_channel */
|
||||
int nb_audio_channel_maps; /* number of (valid) -map_channel settings */
|
||||
int metadata_global_manual;
|
||||
int metadata_streams_manual;
|
||||
int metadata_chapters_manual;
|
||||
const char **attachments;
|
||||
int nb_attachments;
|
||||
|
||||
int chapters_input_file;
|
||||
|
||||
int64_t recording_time;
|
||||
int64_t stop_time;
|
||||
uint64_t limit_filesize;
|
||||
float mux_preload;
|
||||
float mux_max_delay;
|
||||
int shortest;
|
||||
int bitexact;
|
||||
|
||||
int video_disable;
|
||||
int audio_disable;
|
||||
int subtitle_disable;
|
||||
int data_disable;
|
||||
|
||||
/* indexed by output file stream index */
|
||||
int *streamid_map;
|
||||
int nb_streamid_map;
|
||||
|
||||
SpecifierOpt *metadata;
|
||||
int nb_metadata;
|
||||
SpecifierOpt *max_frames;
|
||||
int nb_max_frames;
|
||||
SpecifierOpt *bitstream_filters;
|
||||
int nb_bitstream_filters;
|
||||
SpecifierOpt *codec_tags;
|
||||
int nb_codec_tags;
|
||||
SpecifierOpt *sample_fmts;
|
||||
int nb_sample_fmts;
|
||||
SpecifierOpt *qscale;
|
||||
int nb_qscale;
|
||||
SpecifierOpt *forced_key_frames;
|
||||
int nb_forced_key_frames;
|
||||
SpecifierOpt *force_fps;
|
||||
int nb_force_fps;
|
||||
SpecifierOpt *frame_aspect_ratios;
|
||||
int nb_frame_aspect_ratios;
|
||||
SpecifierOpt *rc_overrides;
|
||||
int nb_rc_overrides;
|
||||
SpecifierOpt *intra_matrices;
|
||||
int nb_intra_matrices;
|
||||
SpecifierOpt *inter_matrices;
|
||||
int nb_inter_matrices;
|
||||
SpecifierOpt *chroma_intra_matrices;
|
||||
int nb_chroma_intra_matrices;
|
||||
SpecifierOpt *top_field_first;
|
||||
int nb_top_field_first;
|
||||
SpecifierOpt *metadata_map;
|
||||
int nb_metadata_map;
|
||||
SpecifierOpt *presets;
|
||||
int nb_presets;
|
||||
SpecifierOpt *copy_initial_nonkeyframes;
|
||||
int nb_copy_initial_nonkeyframes;
|
||||
SpecifierOpt *copy_prior_start;
|
||||
int nb_copy_prior_start;
|
||||
SpecifierOpt *filters;
|
||||
int nb_filters;
|
||||
SpecifierOpt *filter_scripts;
|
||||
int nb_filter_scripts;
|
||||
SpecifierOpt *reinit_filters;
|
||||
int nb_reinit_filters;
|
||||
SpecifierOpt *fix_sub_duration;
|
||||
int nb_fix_sub_duration;
|
||||
SpecifierOpt *canvas_sizes;
|
||||
int nb_canvas_sizes;
|
||||
SpecifierOpt *pass;
|
||||
int nb_pass;
|
||||
SpecifierOpt *passlogfiles;
|
||||
int nb_passlogfiles;
|
||||
SpecifierOpt *max_muxing_queue_size;
|
||||
int nb_max_muxing_queue_size;
|
||||
SpecifierOpt *muxing_queue_data_threshold;
|
||||
int nb_muxing_queue_data_threshold;
|
||||
SpecifierOpt *guess_layout_max;
|
||||
int nb_guess_layout_max;
|
||||
SpecifierOpt *apad;
|
||||
int nb_apad;
|
||||
SpecifierOpt *discard;
|
||||
int nb_discard;
|
||||
SpecifierOpt *disposition;
|
||||
int nb_disposition;
|
||||
SpecifierOpt *program;
|
||||
int nb_program;
|
||||
SpecifierOpt *time_bases;
|
||||
int nb_time_bases;
|
||||
SpecifierOpt *enc_time_bases;
|
||||
int nb_enc_time_bases;
|
||||
SpecifierOpt *autoscale;
|
||||
int nb_autoscale;
|
||||
} OptionsContext;
|
||||
|
||||
typedef struct InputFilter {
|
||||
AVFilterContext *filter;
|
||||
struct InputStream *ist;
|
||||
struct FilterGraph *graph;
|
||||
uint8_t *name;
|
||||
enum AVMediaType type; // AVMEDIA_TYPE_SUBTITLE for sub2video
|
||||
|
||||
AVFifoBuffer *frame_queue;
|
||||
|
||||
// parameters configured for this input
|
||||
int format;
|
||||
|
||||
int width, height;
|
||||
AVRational sample_aspect_ratio;
|
||||
|
||||
int sample_rate;
|
||||
int channels;
|
||||
uint64_t channel_layout;
|
||||
|
||||
AVBufferRef *hw_frames_ctx;
|
||||
|
||||
int eof;
|
||||
} InputFilter;
|
||||
|
||||
typedef struct OutputFilter {
|
||||
AVFilterContext *filter;
|
||||
struct OutputStream *ost;
|
||||
struct FilterGraph *graph;
|
||||
uint8_t *name;
|
||||
|
||||
/* temporary storage until stream maps are processed */
|
||||
AVFilterInOut *out_tmp;
|
||||
enum AVMediaType type;
|
||||
|
||||
/* desired output stream properties */
|
||||
int width, height;
|
||||
AVRational frame_rate;
|
||||
int format;
|
||||
int sample_rate;
|
||||
uint64_t channel_layout;
|
||||
|
||||
// those are only set if no format is specified and the encoder gives us multiple options
|
||||
int *formats;
|
||||
uint64_t *channel_layouts;
|
||||
int *sample_rates;
|
||||
} OutputFilter;
|
||||
|
||||
typedef struct FilterGraph {
|
||||
int index;
|
||||
const char *graph_desc;
|
||||
|
||||
AVFilterGraph *graph;
|
||||
int reconfiguration;
|
||||
|
||||
InputFilter **inputs;
|
||||
int nb_inputs;
|
||||
OutputFilter **outputs;
|
||||
int nb_outputs;
|
||||
} FilterGraph;
|
||||
|
||||
typedef struct InputStream {
|
||||
int file_index;
|
||||
AVStream *st;
|
||||
int discard; /* true if stream data should be discarded */
|
||||
int user_set_discard;
|
||||
int decoding_needed; /* non zero if the packets must be decoded in 'raw_fifo', see DECODING_FOR_* */
|
||||
#define DECODING_FOR_OST 1
|
||||
#define DECODING_FOR_FILTER 2
|
||||
|
||||
AVCodecContext *dec_ctx;
|
||||
const AVCodec *dec;
|
||||
AVFrame *decoded_frame;
|
||||
AVFrame *filter_frame; /* a ref of decoded_frame, to be sent to filters */
|
||||
AVPacket *pkt;
|
||||
|
||||
int64_t start; /* time when read started */
|
||||
/* predicted dts of the next packet read for this stream or (when there are
|
||||
* several frames in a packet) of the next frame in current packet (in AV_TIME_BASE units) */
|
||||
int64_t next_dts;
|
||||
int64_t first_dts; ///< dts of the first packet read for this stream (in AV_TIME_BASE units)
|
||||
int64_t dts; ///< dts of the last packet read for this stream (in AV_TIME_BASE units)
|
||||
|
||||
int64_t next_pts; ///< synthetic pts for the next decode frame (in AV_TIME_BASE units)
|
||||
int64_t pts; ///< current pts of the decoded frame (in AV_TIME_BASE units)
|
||||
int wrap_correction_done;
|
||||
|
||||
int64_t filter_in_rescale_delta_last;
|
||||
|
||||
int64_t min_pts; /* pts with the smallest value in a current stream */
|
||||
int64_t max_pts; /* pts with the higher value in a current stream */
|
||||
|
||||
// when forcing constant input framerate through -r,
|
||||
// this contains the pts that will be given to the next decoded frame
|
||||
int64_t cfr_next_pts;
|
||||
|
||||
int64_t nb_samples; /* number of samples in the last decoded audio frame before looping */
|
||||
|
||||
double ts_scale;
|
||||
int saw_first_ts;
|
||||
AVDictionary *decoder_opts;
|
||||
AVRational framerate; /* framerate forced with -r */
|
||||
int top_field_first;
|
||||
int guess_layout_max;
|
||||
|
||||
int autorotate;
|
||||
|
||||
int fix_sub_duration;
|
||||
struct { /* previous decoded subtitle and related variables */
|
||||
int got_output;
|
||||
int ret;
|
||||
AVSubtitle subtitle;
|
||||
} prev_sub;
|
||||
|
||||
struct sub2video {
|
||||
int64_t last_pts;
|
||||
int64_t end_pts;
|
||||
AVFifoBuffer *sub_queue; ///< queue of AVSubtitle* before filter init
|
||||
AVFrame *frame;
|
||||
int w, h;
|
||||
unsigned int initialize; ///< marks if sub2video_update should force an initialization
|
||||
} sub2video;
|
||||
|
||||
int dr1;
|
||||
|
||||
/* decoded data from this stream goes into all those filters
|
||||
* currently video and audio only */
|
||||
InputFilter **filters;
|
||||
int nb_filters;
|
||||
|
||||
int reinit_filters;
|
||||
|
||||
/* hwaccel options */
|
||||
enum HWAccelID hwaccel_id;
|
||||
enum AVHWDeviceType hwaccel_device_type;
|
||||
char *hwaccel_device;
|
||||
enum AVPixelFormat hwaccel_output_format;
|
||||
|
||||
/* hwaccel context */
|
||||
void *hwaccel_ctx;
|
||||
void (*hwaccel_uninit)(AVCodecContext *s);
|
||||
int (*hwaccel_get_buffer)(AVCodecContext *s, AVFrame *frame, int flags);
|
||||
int (*hwaccel_retrieve_data)(AVCodecContext *s, AVFrame *frame);
|
||||
enum AVPixelFormat hwaccel_pix_fmt;
|
||||
enum AVPixelFormat hwaccel_retrieved_pix_fmt;
|
||||
AVBufferRef *hw_frames_ctx;
|
||||
|
||||
/* stats */
|
||||
// combined size of all the packets read
|
||||
uint64_t data_size;
|
||||
/* number of packets successfully read for this stream */
|
||||
uint64_t nb_packets;
|
||||
// number of frames/samples retrieved from the decoder
|
||||
uint64_t frames_decoded;
|
||||
uint64_t samples_decoded;
|
||||
|
||||
int64_t *dts_buffer;
|
||||
int nb_dts_buffer;
|
||||
|
||||
int got_output;
|
||||
} InputStream;
|
||||
|
||||
typedef struct InputFile {
|
||||
AVFormatContext *ctx;
|
||||
int eof_reached; /* true if eof reached */
|
||||
int eagain; /* true if last read attempt returned EAGAIN */
|
||||
int ist_index; /* index of first stream in input_streams */
|
||||
int loop; /* set number of times input stream should be looped */
|
||||
int64_t duration; /* actual duration of the longest stream in a file
|
||||
at the moment when looping happens */
|
||||
AVRational time_base; /* time base of the duration */
|
||||
int64_t input_ts_offset;
|
||||
|
||||
int64_t ts_offset;
|
||||
int64_t last_ts;
|
||||
int64_t start_time; /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */
|
||||
int seek_timestamp;
|
||||
int64_t recording_time;
|
||||
int nb_streams; /* number of stream that ffmpeg is aware of; may be different
|
||||
from ctx.nb_streams if new streams appear during av_read_frame() */
|
||||
int nb_streams_warn; /* number of streams that the user was warned of */
|
||||
int rate_emu;
|
||||
float readrate;
|
||||
int accurate_seek;
|
||||
|
||||
AVPacket *pkt;
|
||||
|
||||
#if HAVE_THREADS
|
||||
AVThreadMessageQueue *in_thread_queue;
|
||||
pthread_t thread; /* thread reading from this file */
|
||||
int non_blocking; /* reading packets from the thread should not block */
|
||||
int joined; /* the thread has been joined */
|
||||
int thread_queue_size; /* maximum number of queued packets */
|
||||
#endif
|
||||
} InputFile;
|
||||
|
||||
enum forced_keyframes_const {
|
||||
FKF_N,
|
||||
FKF_N_FORCED,
|
||||
FKF_PREV_FORCED_N,
|
||||
FKF_PREV_FORCED_T,
|
||||
FKF_T,
|
||||
FKF_NB
|
||||
};
|
||||
|
||||
#define ABORT_ON_FLAG_EMPTY_OUTPUT (1 << 0)
|
||||
#define ABORT_ON_FLAG_EMPTY_OUTPUT_STREAM (1 << 1)
|
||||
|
||||
extern const char *const forced_keyframes_const_names[];
|
||||
|
||||
typedef enum {
|
||||
ENCODER_FINISHED = 1,
|
||||
MUXER_FINISHED = 2,
|
||||
} OSTFinished ;
|
||||
|
||||
typedef struct OutputStream {
|
||||
int file_index; /* file index */
|
||||
int index; /* stream index in the output file */
|
||||
int source_index; /* InputStream index */
|
||||
AVStream *st; /* stream in the output file */
|
||||
int encoding_needed; /* true if encoding needed for this stream */
|
||||
int frame_number;
|
||||
/* input pts and corresponding output pts
|
||||
for A/V sync */
|
||||
struct InputStream *sync_ist; /* input stream to sync against */
|
||||
int64_t sync_opts; /* output frame counter, could be changed to some true timestamp */ // FIXME look at frame_number
|
||||
/* pts of the first frame encoded for this stream, used for limiting
|
||||
* recording time */
|
||||
int64_t first_pts;
|
||||
/* dts of the last packet sent to the muxer */
|
||||
int64_t last_mux_dts;
|
||||
// the timebase of the packets sent to the muxer
|
||||
AVRational mux_timebase;
|
||||
AVRational enc_timebase;
|
||||
|
||||
AVBSFContext *bsf_ctx;
|
||||
|
||||
AVCodecContext *enc_ctx;
|
||||
AVCodecParameters *ref_par; /* associated input codec parameters with encoders options applied */
|
||||
const AVCodec *enc;
|
||||
int64_t max_frames;
|
||||
AVFrame *filtered_frame;
|
||||
AVFrame *last_frame;
|
||||
AVPacket *pkt;
|
||||
int last_dropped;
|
||||
int last_nb0_frames[3];
|
||||
|
||||
void *hwaccel_ctx;
|
||||
|
||||
/* video only */
|
||||
AVRational frame_rate;
|
||||
AVRational max_frame_rate;
|
||||
int is_cfr;
|
||||
int force_fps;
|
||||
int top_field_first;
|
||||
int rotate_overridden;
|
||||
int autoscale;
|
||||
double rotate_override_value;
|
||||
|
||||
AVRational frame_aspect_ratio;
|
||||
|
||||
/* forced key frames */
|
||||
int64_t forced_kf_ref_pts;
|
||||
int64_t *forced_kf_pts;
|
||||
int forced_kf_count;
|
||||
int forced_kf_index;
|
||||
char *forced_keyframes;
|
||||
AVExpr *forced_keyframes_pexpr;
|
||||
double forced_keyframes_expr_const_values[FKF_NB];
|
||||
int dropped_keyframe;
|
||||
|
||||
/* audio only */
|
||||
int *audio_channels_map; /* list of the channels id to pick from the source stream */
|
||||
int audio_channels_mapped; /* number of channels in audio_channels_map */
|
||||
|
||||
char *logfile_prefix;
|
||||
FILE *logfile;
|
||||
|
||||
OutputFilter *filter;
|
||||
char *avfilter;
|
||||
char *filters; ///< filtergraph associated to the -filter option
|
||||
char *filters_script; ///< filtergraph script associated to the -filter_script option
|
||||
|
||||
AVDictionary *encoder_opts;
|
||||
AVDictionary *sws_dict;
|
||||
AVDictionary *swr_opts;
|
||||
AVDictionary *resample_opts;
|
||||
char *apad;
|
||||
OSTFinished finished; /* no more packets should be written for this stream */
|
||||
int unavailable; /* true if the steram is unavailable (possibly temporarily) */
|
||||
int stream_copy;
|
||||
|
||||
// init_output_stream() has been called for this stream
|
||||
// The encoder and the bitstream filters have been initialized and the stream
|
||||
// parameters are set in the AVStream.
|
||||
int initialized;
|
||||
|
||||
int inputs_done;
|
||||
|
||||
const char *attachment_filename;
|
||||
int copy_initial_nonkeyframes;
|
||||
int copy_prior_start;
|
||||
char *disposition;
|
||||
|
||||
int keep_pix_fmt;
|
||||
|
||||
/* stats */
|
||||
// combined size of all the packets written
|
||||
uint64_t data_size;
|
||||
// number of packets send to the muxer
|
||||
uint64_t packets_written;
|
||||
// number of frames/samples sent to the encoder
|
||||
uint64_t frames_encoded;
|
||||
uint64_t samples_encoded;
|
||||
|
||||
/* packet quality factor */
|
||||
int quality;
|
||||
|
||||
int max_muxing_queue_size;
|
||||
|
||||
/* the packets are buffered here until the muxer is ready to be initialized */
|
||||
AVFifoBuffer *muxing_queue;
|
||||
|
||||
/*
|
||||
* The size of the AVPackets' buffers in queue.
|
||||
* Updated when a packet is either pushed or pulled from the queue.
|
||||
*/
|
||||
size_t muxing_queue_data_size;
|
||||
|
||||
/* Threshold after which max_muxing_queue_size will be in effect */
|
||||
size_t muxing_queue_data_threshold;
|
||||
|
||||
/* packet picture type */
|
||||
int pict_type;
|
||||
|
||||
/* frame encode sum of squared error values */
|
||||
int64_t error[4];
|
||||
} OutputStream;
|
||||
|
||||
typedef struct OutputFile {
|
||||
AVFormatContext *ctx;
|
||||
AVDictionary *opts;
|
||||
int ost_index; /* index of the first stream in output_streams */
|
||||
int64_t recording_time; ///< desired length of the resulting file in microseconds == AV_TIME_BASE units
|
||||
int64_t start_time; ///< start time in microseconds == AV_TIME_BASE units
|
||||
uint64_t limit_filesize; /* filesize limit expressed in bytes */
|
||||
|
||||
int shortest;
|
||||
|
||||
int header_written;
|
||||
} OutputFile;
|
||||
|
||||
extern __thread InputStream **input_streams;
|
||||
extern __thread int nb_input_streams;
|
||||
extern __thread InputFile **input_files;
|
||||
extern __thread int nb_input_files;
|
||||
|
||||
extern __thread OutputStream **output_streams;
|
||||
extern __thread int nb_output_streams;
|
||||
extern __thread OutputFile **output_files;
|
||||
extern __thread int nb_output_files;
|
||||
|
||||
extern __thread FilterGraph **filtergraphs;
|
||||
extern __thread int nb_filtergraphs;
|
||||
|
||||
extern __thread char *vstats_filename;
|
||||
extern __thread char *sdp_filename;
|
||||
|
||||
extern __thread float audio_drift_threshold;
|
||||
extern __thread float dts_delta_threshold;
|
||||
extern __thread float dts_error_threshold;
|
||||
|
||||
extern __thread int audio_volume;
|
||||
extern __thread int audio_sync_method;
|
||||
extern __thread int video_sync_method;
|
||||
extern __thread float frame_drop_threshold;
|
||||
extern __thread int do_benchmark;
|
||||
extern __thread int do_benchmark_all;
|
||||
extern __thread int do_deinterlace;
|
||||
extern __thread int do_hex_dump;
|
||||
extern __thread int do_pkt_dump;
|
||||
extern __thread int copy_ts;
|
||||
extern __thread int start_at_zero;
|
||||
extern __thread int copy_tb;
|
||||
extern __thread int debug_ts;
|
||||
extern __thread int exit_on_error;
|
||||
extern __thread int abort_on_flags;
|
||||
extern __thread int print_stats;
|
||||
extern __thread int64_t stats_period;
|
||||
extern __thread int qp_hist;
|
||||
extern __thread int stdin_interaction;
|
||||
extern __thread int frame_bits_per_raw_sample;
|
||||
extern __thread AVIOContext *progress_avio;
|
||||
extern __thread float max_error_rate;
|
||||
extern __thread char *videotoolbox_pixfmt;
|
||||
|
||||
extern __thread int filter_nbthreads;
|
||||
extern __thread int filter_complex_nbthreads;
|
||||
extern __thread int vstats_version;
|
||||
extern __thread int auto_conversion_filters;
|
||||
|
||||
extern __thread const AVIOInterruptCB int_cb;
|
||||
|
||||
extern const HWAccel hwaccels[];
|
||||
#if CONFIG_QSV
|
||||
extern __thread char *qsv_device;
|
||||
#endif
|
||||
extern __thread HWDevice *filter_hw_device;
|
||||
|
||||
void term_init(void);
|
||||
void term_exit(void);
|
||||
|
||||
void reset_options(OptionsContext *o, int is_input);
|
||||
void show_usage(void);
|
||||
|
||||
void opt_output_file(void *optctx, const char *filename);
|
||||
|
||||
void remove_avoptions(AVDictionary **a, AVDictionary *b);
|
||||
void assert_avoptions(AVDictionary *m);
|
||||
|
||||
int guess_input_channel_layout(InputStream *ist);
|
||||
|
||||
enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *avctx, const AVCodec *codec, enum AVPixelFormat target);
|
||||
void choose_sample_fmt(AVStream *st, const AVCodec *codec);
|
||||
|
||||
int configure_filtergraph(FilterGraph *fg);
|
||||
int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out);
|
||||
void check_filter_outputs(void);
|
||||
int ist_in_filtergraph(FilterGraph *fg, InputStream *ist);
|
||||
int filtergraph_is_simple(FilterGraph *fg);
|
||||
int init_simple_filtergraph(InputStream *ist, OutputStream *ost);
|
||||
int init_complex_filtergraph(FilterGraph *fg);
|
||||
|
||||
void sub2video_update(InputStream *ist, int64_t heartbeat_pts, AVSubtitle *sub);
|
||||
|
||||
int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame);
|
||||
|
||||
int ffmpeg_parse_options(int argc, char **argv);
|
||||
|
||||
int videotoolbox_init(AVCodecContext *s);
|
||||
int qsv_init(AVCodecContext *s);
|
||||
|
||||
HWDevice *hw_device_get_by_name(const char *name);
|
||||
int hw_device_init_from_string(const char *arg, HWDevice **dev);
|
||||
void hw_device_free_all(void);
|
||||
|
||||
int hw_device_setup_for_decode(InputStream *ist);
|
||||
int hw_device_setup_for_encode(OutputStream *ost);
|
||||
int hw_device_setup_for_filter(FilterGraph *fg);
|
||||
|
||||
int hwaccel_decode_init(AVCodecContext *avctx);
|
||||
|
||||
void set_report_callback(void (*callback)(int, float, float, int64_t, int, double, double));
|
||||
|
||||
void cancel_operation(long id);
|
||||
|
||||
int opt_map(void *optctx, const char *opt, const char *arg);
|
||||
int opt_map_channel(void *optctx, const char *opt, const char *arg);
|
||||
int opt_recording_timestamp(void *optctx, const char *opt, const char *arg);
|
||||
int opt_data_frames(void *optctx, const char *opt, const char *arg);
|
||||
int opt_progress(void *optctx, const char *opt, const char *arg);
|
||||
int opt_target(void *optctx, const char *opt, const char *arg);
|
||||
int opt_vsync(void *optctx, const char *opt, const char *arg);
|
||||
int opt_abort_on(void *optctx, const char *opt, const char *arg);
|
||||
int opt_stats_period(void *optctx, const char *opt, const char *arg);
|
||||
int opt_qscale(void *optctx, const char *opt, const char *arg);
|
||||
int opt_profile(void *optctx, const char *opt, const char *arg);
|
||||
int opt_filter_complex(void *optctx, const char *opt, const char *arg);
|
||||
int opt_filter_complex_script(void *optctx, const char *opt, const char *arg);
|
||||
int opt_attach(void *optctx, const char *opt, const char *arg);
|
||||
int opt_video_frames(void *optctx, const char *opt, const char *arg);
|
||||
int opt_video_codec(void *optctx, const char *opt, const char *arg);
|
||||
int opt_sameq(void *optctx, const char *opt, const char *arg);
|
||||
int opt_timecode(void *optctx, const char *opt, const char *arg);
|
||||
|
||||
int opt_vstats_file(void *optctx, const char *opt, const char *arg);
|
||||
int opt_vstats(void *optctx, const char *opt, const char *arg);
|
||||
int opt_video_frames(void *optctx, const char *opt, const char *arg);
|
||||
int opt_old2new(void *optctx, const char *opt, const char *arg);
|
||||
int opt_streamid(void *optctx, const char *opt, const char *arg);
|
||||
int opt_bitrate(void *optctx, const char *opt, const char *arg);
|
||||
int show_hwaccels(void *optctx, const char *opt, const char *arg);
|
||||
int opt_video_filters(void *optctx, const char *opt, const char *arg);
|
||||
int opt_audio_frames(void *optctx, const char *opt, const char *arg);
|
||||
int opt_audio_qscale(void *optctx, const char *opt, const char *arg);
|
||||
int opt_audio_codec(void *optctx, const char *opt, const char *arg);
|
||||
int opt_channel_layout(void *optctx, const char *opt, const char *arg);
|
||||
int opt_preset(void *optctx, const char *opt, const char *arg);
|
||||
int opt_audio_filters(void *optctx, const char *opt, const char *arg);
|
||||
int opt_subtitle_codec(void *optctx, const char *opt, const char *arg);
|
||||
int opt_video_channel(void *optctx, const char *opt, const char *arg);
|
||||
int opt_video_standard(void *optctx, const char *opt, const char *arg);
|
||||
int opt_sdp_file(void *optctx, const char *opt, const char *arg);
|
||||
int opt_data_codec(void *optctx, const char *opt, const char *arg);
|
||||
int opt_init_hw_device(void *optctx, const char *opt, const char *arg);
|
||||
int opt_filter_hw_device(void *optctx, const char *opt, const char *arg);
|
||||
void add_input_streams(OptionsContext *o, AVFormatContext *ic);
|
||||
void assert_file_overwrite(const char *filename);
|
||||
void dump_attachment(AVStream *st, const char *filename);
|
||||
uint8_t *get_line(AVIOContext *s);
|
||||
void uninit_options(OptionsContext *o);
|
||||
void init_options(OptionsContext *o);
|
||||
AVDictionary *strip_specifiers(AVDictionary *dict);
|
||||
void parse_meta_type(char *arg, char *type, int *index, const char **stream_spec);
|
||||
int fftools_copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o);
|
||||
const AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder);
|
||||
const AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream *st);
|
||||
int open_input_file(OptionsContext *o, const char *filename);
|
||||
int get_preset_file_2(const char *preset_name, const char *codec_name, AVIOContext **s);
|
||||
int choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *ost);
|
||||
OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type, int source_index);
|
||||
void parse_matrix_coeffs(uint16_t *dest, const char *str);
|
||||
uint8_t *fftools_read_file(const char *filename);
|
||||
char *get_ost_filters(OptionsContext *o, AVFormatContext *oc, OutputStream *ost);
|
||||
void check_streamcopy_filters(OptionsContext *o, AVFormatContext *oc, const OutputStream *ost, enum AVMediaType type);
|
||||
OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, int source_index);
|
||||
OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, int source_index);
|
||||
OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc, int source_index);
|
||||
OutputStream *new_unknown_stream(OptionsContext *o, AVFormatContext *oc, int source_index);
|
||||
OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc, int source_index);
|
||||
OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc, int source_index);
|
||||
int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata);
|
||||
void init_output_filter(OutputFilter *ofilter, OptionsContext *o, AVFormatContext *oc);
|
||||
int init_complex_filters(void);
|
||||
int open_output_file(OptionsContext *o, const char *filename);
|
||||
int opt_default_new(OptionsContext *o, const char *opt, const char *arg);
|
||||
int open_files(OptionGroupList *l, const char *inout, int (*open_file)(OptionsContext*, const char*));
|
||||
|
||||
#endif /* FFTOOLS_FFMPEG_H */
|
|
@ -0,0 +1,32 @@
|
|||
framework module ffmpegkit {
|
||||
|
||||
header "AbstractSession.h"
|
||||
header "ArchDetect.h"
|
||||
header "AtomicLong.h"
|
||||
header "Chapter.h"
|
||||
header "FFmpegKit.h"
|
||||
header "FFmpegKitConfig.h"
|
||||
header "FFmpegSession.h"
|
||||
header "FFmpegSessionCompleteCallback.h"
|
||||
header "FFprobeKit.h"
|
||||
header "FFprobeSession.h"
|
||||
header "FFprobeSessionCompleteCallback.h"
|
||||
header "Level.h"
|
||||
header "Log.h"
|
||||
header "LogCallback.h"
|
||||
header "LogRedirectionStrategy.h"
|
||||
header "MediaInformation.h"
|
||||
header "MediaInformationJsonParser.h"
|
||||
header "MediaInformationSession.h"
|
||||
header "MediaInformationSessionCompleteCallback.h"
|
||||
header "Packages.h"
|
||||
header "ReturnCode.h"
|
||||
header "Session.h"
|
||||
header "SessionState.h"
|
||||
header "Statistics.h"
|
||||
header "StatisticsCallback.h"
|
||||
header "StreamInformation.h"
|
||||
header "ffmpegkit_exception.h"
|
||||
|
||||
export *
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>ffmpegkit</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.arthenica.ffmpegkit.FFmpegKit</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>ffmpegkit</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.5.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>4.5.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.15</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>MacOSX</string>
|
||||
</array>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,165 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
|
@ -0,0 +1,62 @@
|
|||
################################################################################
|
||||
#
|
||||
# Copyright 2015 Realm Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
# This script strips all non-valid architectures from dynamic libraries in
|
||||
# the application's `Frameworks` directory.
|
||||
#
|
||||
# The following environment variables are required:
|
||||
#
|
||||
# BUILT_PRODUCTS_DIR
|
||||
# FRAMEWORKS_FOLDER_PATH
|
||||
# VALID_ARCHS
|
||||
# EXPANDED_CODE_SIGN_IDENTITY
|
||||
|
||||
|
||||
# Signs a framework with the provided identity
|
||||
code_sign() {
|
||||
# Use the current code_sign_identitiy
|
||||
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
|
||||
echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements $1"
|
||||
/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements "$1"
|
||||
}
|
||||
|
||||
echo "Stripping frameworks"
|
||||
cd "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
|
||||
for file in $(find . -type f -perm +111); do
|
||||
# Skip non-dynamic libraries
|
||||
if ! [[ "$(file "$file")" == *"dynamically linked shared library"* ]]; then
|
||||
continue
|
||||
fi
|
||||
# Get architectures for current file
|
||||
archs="$(lipo -info "${file}" | rev | cut -d ':' -f1 | rev)"
|
||||
stripped=""
|
||||
for arch in $archs; do
|
||||
if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
|
||||
# Strip non-valid architectures in-place
|
||||
lipo -remove "$arch" -output "$file" "$file" || exit 1
|
||||
stripped="$stripped $arch"
|
||||
fi
|
||||
done
|
||||
if [[ "$stripped" != "" ]]; then
|
||||
echo "Stripped $file of architectures:$stripped"
|
||||
if [ "${CODE_SIGNING_REQUIRED}" == "YES" ]; then
|
||||
code_sign "${file}"
|
||||
fi
|
||||
fi
|
||||
done
|
|
@ -0,0 +1 @@
|
|||
A
|
|
@ -0,0 +1 @@
|
|||
Versions/Current/ffmpegkit
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>AvailableLibraries</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>LibraryIdentifier</key>
|
||||
<string>macos-arm64_x86_64</string>
|
||||
<key>LibraryPath</key>
|
||||
<string>libavcodec.framework</string>
|
||||
<key>SupportedArchitectures</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
<string>x86_64</string>
|
||||
</array>
|
||||
<key>SupportedPlatform</key>
|
||||
<string>macos</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XFWK</string>
|
||||
<key>XCFrameworkFormatVersion</key>
|
||||
<string>1.0</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1 @@
|
|||
Versions/Current/Headers
|
|
@ -0,0 +1 @@
|
|||
Versions/Current/Resources
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* AC-3 parser prototypes
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
* Copyright (c) 2003 Michael Niedermayer
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_AC3_PARSER_H
|
||||
#define AVCODEC_AC3_PARSER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Extract the bitstream ID and the frame size from AC-3 data.
|
||||
*/
|
||||
int av_ac3_parse_header(const uint8_t *buf, size_t size,
|
||||
uint8_t *bitstream_id, uint16_t *frame_size);
|
||||
|
||||
|
||||
#endif /* AVCODEC_AC3_PARSER_H */
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_ADTS_PARSER_H
|
||||
#define AVCODEC_ADTS_PARSER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define AV_AAC_ADTS_HEADER_SIZE 7
|
||||
|
||||
/**
|
||||
* Extract the number of samples and frames from AAC data.
|
||||
* @param[in] buf pointer to AAC data buffer
|
||||
* @param[out] samples Pointer to where number of samples is written
|
||||
* @param[out] frames Pointer to where number of frames is written
|
||||
* @return Returns 0 on success, error code on failure.
|
||||
*/
|
||||
int av_adts_header_parse(const uint8_t *buf, uint32_t *samples,
|
||||
uint8_t *frames);
|
||||
|
||||
#endif /* AVCODEC_ADTS_PARSER_H */
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* simple math operations
|
||||
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> et al
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_ARM_MATHOPS_H
|
||||
#define AVCODEC_ARM_MATHOPS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "config.h"
|
||||
#include "libavutil/common.h"
|
||||
|
||||
#if HAVE_INLINE_ASM
|
||||
|
||||
#if HAVE_ARMV6_INLINE
|
||||
#define MULH MULH
|
||||
static inline av_const int MULH(int a, int b)
|
||||
{
|
||||
int r;
|
||||
__asm__ ("smmul %0, %1, %2" : "=r"(r) : "r"(a), "r"(b));
|
||||
return r;
|
||||
}
|
||||
|
||||
#define FASTDIV FASTDIV
|
||||
static av_always_inline av_const int FASTDIV(int a, int b)
|
||||
{
|
||||
int r;
|
||||
__asm__ ("cmp %2, #2 \n\t"
|
||||
"ldr %0, [%3, %2, lsl #2] \n\t"
|
||||
"ite le \n\t"
|
||||
"lsrle %0, %1, #1 \n\t"
|
||||
"smmulgt %0, %0, %1 \n\t"
|
||||
: "=&r"(r) : "r"(a), "r"(b), "r"(ff_inverse) : "cc");
|
||||
return r;
|
||||
}
|
||||
|
||||
#else /* HAVE_ARMV6_INLINE */
|
||||
|
||||
#define FASTDIV FASTDIV
|
||||
static av_always_inline av_const int FASTDIV(int a, int b)
|
||||
{
|
||||
int r, t;
|
||||
__asm__ ("umull %1, %0, %2, %3"
|
||||
: "=&r"(r), "=&r"(t) : "r"(a), "r"(ff_inverse[b]));
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define MLS64(d, a, b) MAC64(d, -(a), b)
|
||||
|
||||
#if HAVE_ARMV5TE_INLINE
|
||||
|
||||
/* signed 16x16 -> 32 multiply add accumulate */
|
||||
# define MAC16(rt, ra, rb) \
|
||||
__asm__ ("smlabb %0, %1, %2, %0" : "+r"(rt) : "r"(ra), "r"(rb));
|
||||
|
||||
/* signed 16x16 -> 32 multiply */
|
||||
# define MUL16 MUL16
|
||||
static inline av_const int MUL16(int ra, int rb)
|
||||
{
|
||||
int rt;
|
||||
__asm__ ("smulbb %0, %1, %2" : "=r"(rt) : "r"(ra), "r"(rb));
|
||||
return rt;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define mid_pred mid_pred
|
||||
static inline av_const int mid_pred(int a, int b, int c)
|
||||
{
|
||||
int m;
|
||||
__asm__ (
|
||||
"mov %0, %2 \n\t"
|
||||
"cmp %1, %2 \n\t"
|
||||
"itt gt \n\t"
|
||||
"movgt %0, %1 \n\t"
|
||||
"movgt %1, %2 \n\t"
|
||||
"cmp %1, %3 \n\t"
|
||||
"it le \n\t"
|
||||
"movle %1, %3 \n\t"
|
||||
"cmp %0, %1 \n\t"
|
||||
"it gt \n\t"
|
||||
"movgt %0, %1 \n\t"
|
||||
: "=&r"(m), "+r"(a)
|
||||
: "r"(b), "r"(c)
|
||||
: "cc");
|
||||
return m;
|
||||
}
|
||||
|
||||
#endif /* HAVE_INLINE_ASM */
|
||||
|
||||
#endif /* AVCODEC_ARM_MATHOPS_H */
|