亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Flutter開發(fā)Mac桌面應用實現(xiàn)自動提取生成視頻字幕文件

 更新時間:2023年03月29日 14:41:57   作者:loongwind  
這篇文章主要為大家介紹了Flutter開發(fā)Mac桌面應用實現(xiàn)自動提取生成視頻字幕文件示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

前段時間準備做一個視頻,最后需要添加字幕,手動添加太麻煩了就想在網(wǎng)上找一個能自動提取字幕的軟件或服務,確實是找到了,但是免費版基本上都有諸多限制,比如現(xiàn)在視頻時長等等,后來在 Github 找到一個開源的版本是使用云平臺的語音識別實現(xiàn)的,云服務的語音識別是有免費的額度的,對于個人使用來說一般是夠用了,項目地址:video-srt-windows ,大致實現(xiàn)流程如下:

  • 使用 ffmpeg 提取視頻的音頻文件
  • 將音頻文件上傳到云平臺的對象存儲
  • 調(diào)用云平臺的語音識別 api 進行文字識別
  • 生成字幕文件

下載 release 版本測試了一下效果還可以,只需要修改個別識別有誤的詞就行,功能完全滿足我的需求;但是遺憾的是該項目只提供了 Windows 版本,而沒有 Mac 版本的 ,雖然作者也提供了一個 CLI 命令行版本可以在 Mac 上使用,但是對于普通用戶來說使用起來還是不是很方便,于是產(chǎn)生了開發(fā)一個 Mac 版。

思路

該開源項目作者是用 Go 語言寫的,我本人擅長的是 Flutter 開發(fā),所以首先想到的就是通過 Flutter 開發(fā)一個 Mac 版的桌面應用,將 CLI 項目通過 Go 編譯成 Mac 的可執(zhí)行文件內(nèi)置到 Flutter 項目中,再通過 Dart 調(diào)用 shell 命令進行執(zhí)行從而實現(xiàn)軟件的功能。

效果

實現(xiàn)

下面就來看看整個項目是如何一步步最終實現(xiàn)上面的效果的。

編譯 Mac 版可執(zhí)行文件

首先將 CLI 項目 clone 到本地,然后使用 go build命令編譯對應平臺的可執(zhí)行文件,如下:

# Mac M1/M2 Arm 架構 CPU
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o video-srt-arm64 main.go
# Mac Amd 架構 CPU
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o video-srt-amd64 main.go

執(zhí)行以上文件分別生成 armamd 架構的可執(zhí)行文件 video-srt-arm64 和 video-srt-amd64。

內(nèi)置可執(zhí)行文件和 ffmpeg

將上一步生成的對應平臺的可執(zhí)行文件修改為 video-srt 和配置文件 config.ini以及 ffmpeg文件放到一個文件夾中打包成 video-srt.zip壓縮包減少包體積。

因為項目需要使用到 ffmpeg ,所以需要把 ffmpeg 也內(nèi)置到項目中

通過 Xcode 將 video-srt.zip文件添加到項目的 Resources 文件夾下

然后就是通過代碼在程序啟動時將內(nèi)置的壓縮包解壓到指定位置,這里解壓使用了 archive庫,核心代碼如下:

// 目錄名稱
const String VIDEO_SRT = "video-srt";
class ZipRepository{
  static Future<void> unzip(String zipFile, String targetDir) async{
    final inputStream = InputFileStream(zipFile);
    final archive = ZipDecoder().decodeBuffer(inputStream);
    extractArchiveToDisk(archive, targetDir);
    return;
  }
  static Future<void> unzipVideoSrt() async{
    var workDirPath = await PathUtils.getWorkDirPath();
    // 創(chuàng)建工作目錄下的 video-srt 目錄
    var videoSrtFile = Directory("$workDirPath/$VIDEO_SRT");
    // 如果已經(jīng)存在則不重復解壓
    if(await videoSrtFile.exists()){
      return;
    }
    // 解壓
    await unzip(VIDEO_SRT_ZIP_PATH, "$workDirPath");
    return;
  }
}

這里還用到了 path_provider庫用于獲取相關目錄:

// 工作目錄名稱
const String WORK_DIR_NAME = "videoSrt";
class PathUtils{
  static String? workDirPath;
  static Future<String> getWorkDirPath() async{
    if(workDirPath != null){
      return workDirPath!;
    }
    // 獲取 library 目錄
    Directory tempDir = await getLibraryDirectory();
    var workDir = "${tempDir.path}/$WORK_DIR_NAME";
    var dir = Directory(workDir);
    if(! (await dir.exists())){
      await dir.create();
    }
    workDirPath = workDir;
    return workDir;
  }
}

在應用啟動時調(diào)用解壓將內(nèi)置的 video-srt.zip 內(nèi)容解壓到系統(tǒng) library 下的 videoSrt 目錄下。

設置配置信息

video-srt的配置是用的 config.ini文件存儲的,所以在代碼里需要讀寫 ini 文件,這里使用了一個 ini的三方庫,config.ini里包含如下配置內(nèi)容:

#字幕相關設置
[srt]
#智能分段處理:true(開啟) false(關閉)
intelligent_block=true
#阿里云Oss對象服務配置
#文檔:https://help.aliyun.com/document_detail/31827.html?spm=a2c4g.11186623.6.582.4e7858a85Dr5pA
[aliyunOss]
# OSS 對外服務的訪問域名
endpoint=
# 存儲空間(Bucket)名稱
bucketName=
# 存儲空間(Bucket 域名)地址
bucketDomain=
accessKeyId=
accessKeySecret=
#阿里云語音識別配置
#文檔:
[aliyunClound]
# 在管控臺中創(chuàng)建的項目Appkey,項目的唯一標識
appKey=
accessKeyId=
accessKeySecret=

這里創(chuàng)建一個 ConfigModel用于存放相關配置,然后使用 ini 庫的 Config 進行讀寫封裝,代碼如下 :

// 讀取配置數(shù)據(jù)
static Future<ConfigModel> readIniData() async{
  var workDir = await PathUtils.getWorkDirPath();
  var iniPath = "$workDir/$VIDEO_SRT/$CONFIG_NAME";
  Completer<ConfigModel> completer = Completer();
  File(iniPath).readAsLines()
      .then((lines) => Config.fromStrings(lines))
      .then((Config config){
        var iniModel = ConfigModel();
        iniModel.intelligent_block = (config.get("srt", "intelligent_block") ?? "true").toLowerCase() == "true";
        iniModel.oss_endpoint = config.get("aliyunOss", "endpoint");
        iniModel.oss_bucketName = config.get("aliyunOss", "bucketName") ;
        iniModel.oss_bucketDomain = config.get("aliyunOss", "bucketDomain") ;
        iniModel.oss_accessKeyId = config.get("aliyunOss", "accessKeyId") ;
        iniModel.oss_accessKeySecret = config.get("aliyunOss", "accessKeySecret") ;
        iniModel.voice_appKey = config.get("aliyunClound", "appKey") ;
        iniModel.voice_accessKeyId = config.get("aliyunClound", "accessKeyId") ;
        iniModel.voice_accessKeySecret = config.get("aliyunClound", "accessKeySecret") ;
        iniModel.go_path = config.get("go", "goPath") ;
        completer.complete(iniModel);
  });
  return completer.future;
}
// 寫配置數(shù)據(jù)
static Future<void> writeIniData(ConfigModel iniModel) async{
  Config config = Config();
  config.addSection("srt");
  config.set("srt", "intelligent_block", iniModel.intelligent_block.toString());
  config.addSection("aliyunOss");
  config.set("aliyunOss", "endpoint", iniModel.oss_endpoint ?? "");
  config.set("aliyunOss", "bucketName", iniModel.oss_bucketName ?? "");
  config.set("aliyunOss", "bucketDomain", iniModel.oss_bucketDomain ?? "");
  config.set("aliyunOss", "accessKeyId", iniModel.oss_accessKeyId ?? "");
  config.set("aliyunOss", "accessKeySecret", iniModel.oss_accessKeySecret ?? "");
  config.addSection("aliyunClound");
  config.set("aliyunClound", "appKey", iniModel.voice_appKey ?? "");
  config.set("aliyunClound", "accessKeyId", iniModel.voice_accessKeyId ?? "");
  config.set("aliyunClound", "accessKeySecret", iniModel.voice_accessKeySecret ?? "");
  config.addSection("go");
  config.set("go", "goPath", iniModel.go_path ?? "");
  var workDir = await PathUtils.getWorkDirPath();
  var iniPath = "$workDir/$VIDEO_SRT/$CONFIG_NAME";
  await File(iniPath).writeAsString(config.toString());
  return;
}

執(zhí)行命令

配置也寫好了,接下來就需要執(zhí)行編譯好的 video-srt 命令來提取視頻字幕,這里使用 shell 命令來執(zhí)行,用到了 process_run庫,核心代碼如下:

static Future<void> runVideoSrt(String targetFilePath, Function(String) callback) async{
  if(targetFilePath.isEmpty){
    return;
  }
  // 獲取工作目錄
  var workDir = await PathUtils.getWorkDirPath();
  var controller = ShellLinesController();
  var shell = Shell(stdout: controller.sink, verbose: false);
  // 切換路徑到工作目錄下的 video-srt 下
  shell = shell.pushd("$workDir/$VIDEO_SRT");
  try {
    // 給 ffmpeg 添加執(zhí)行權限
    await shell.run("chmod +x ffmpeg");
    // 給 video-srt 添加執(zhí)行權限
    await shell.run("chmod +x video-srt");
  } on ShellException catch (_) {
    // We might get a shell exception
  }
  // 監(jiān)聽執(zhí)行結果
  controller.stream.listen((event) {
    callback(event);
  });
  try {
    // 執(zhí)行視頻提取字幕命令
    await shell.run("./video-srt $targetFilePath");
  } on ShellException catch (_) {
    // We might get a shell exception
  }
  shell = shell.popd();
  return;
}

UI 實現(xiàn)

核心功能實現(xiàn)了,接下來就是完成界面的開發(fā),讓我們可以方便的進行相關配置和選擇要生成字幕的視頻文件。

為了實現(xiàn) Mac 風格的界面,這里使用了 macos_ui庫,可以讓我們更快捷的實現(xiàn)相關界面。

界面分成兩部分,左邊菜單和右邊內(nèi)容展示區(qū)域,效果如下:

代碼如下:

class MainView extends StatefulWidget {
  const MainView({super.key});
  @override
  State<MainView> createState() => _MainViewState();
}
class _MainViewState extends State<MainView> {
  int _pageIndex = 0;
  @override
  Widget build(BuildContext context) {
    return PlatformMenuBar(
      menus: const [
        PlatformMenu(
          label: 'VideoSrtMacos',
          menus: [
            // 狀態(tài)欄左上角退出按鈕
            PlatformProvidedMenuItem(
              type: PlatformProvidedMenuItemType.quit,
            ),
          ],
        ),
      ],
      child:  MacosWindow(
        sidebar: Sidebar(
          minWidth: 200,
          builder: (context, scrollController) => SidebarItems(
            currentIndex: _pageIndex,
            onChanged: (index) {
              setState(() => _pageIndex = index);
            },
            items: const [
              SidebarItem(leading: MacosIcon(CupertinoIcons.home),label: Text('首頁'),),
              SidebarItem(leading: MacosIcon(CupertinoIcons.settings),label: Text('配置'),),
              SidebarItem(leading: MacosIcon(CupertinoIcons.helm),label: Text('幫助'),),
              SidebarItem(leading: MacosIcon(CupertinoIcons.info),label: Text('關于'),),
            ],
          ),
        ),
        child: IndexedStack(
          index: _pageIndex,
          children: const [
            // 主頁
            HomePage(),
            // 配置頁面
            ConfigView(),
            HelpView(),
            AboutView()
          ],
        ),
      ),
    );
  }
}

然后分別實現(xiàn)對應的子界面即可實現(xiàn)整個完整的功能,這部分就是純粹的 flutter 界面開發(fā)的內(nèi)容了,這里就不過多贅述了。

最后

雖然使用 Flutter 進行開發(fā)已經(jīng)很久了,但是更多還是進行 Android、iOS 的開發(fā),桌面端雖然也寫過一些Demo,但是還未真正使用 Flutter 去開發(fā)一個桌面應用,雖然這個項目功能很簡單但也算是一個不錯的練手項目。

Github 地址:video-srt-mac

以上就是Flutter開發(fā)Mac桌面應用實現(xiàn)自動提取生成視頻字幕文件的詳細內(nèi)容,更多關于Flutter Mac提取視頻字幕的資料請關注腳本之家其它相關文章!

相關文章

最新評論