以前是要這樣,現在不用那麼麻煩,可以直接從視頻中提取文字了,你可以看下微信的【微轉寫】小程序,複製你原視頻的鏈接到這個小程序就可以一鍵提取視頻裏的文案了,對我來說還挺好用的,安利給大家,附上了操作教程,喜歡的話點個贊同喲~

如何一鍵提取短視頻的文案|視頻轉寫神器|視頻轉文字微配音的視頻 · 907 播放發佈於 2020-11-07繼續瀏覽內容知乎發現更大的世界打開Chrome繼續微轉寫微轉寫?

已認證的官方帳號

這個問題很簡單,不用提取視頻的音頻,現在微信的【微轉寫】小程序已經支持直接把視頻轉換成文字了,直接複製視頻地址或者是上傳本地的視頻就可以一鍵轉文本了,是不是很方便?對了,現在還可以免費看廣告領取時長哦

如何將錄音轉文字|音頻視頻語音轉文字 ,教程來了微轉寫的視頻 · 1056 播放視頻裏的音頻如何轉換成文字?看這個一鍵提取文案的神工具微轉寫的視頻 · 1372 播放發佈於 2020-12-12繼續瀏覽內容知乎發現更大的世界打開Chrome繼續科技口袋科技口袋?

已認證的官方帳號

使用微信小程序「微轉寫」,不需要提取音頻即可一鍵轉視頻為文字,且抖音、快手等平臺的視頻無需下載,支持在線一鍵轉寫,使用非常方便

編輯於 2020-12-16繼續瀏覽內容知乎發現更大的世界打開Chrome繼續黑狐提詞-手機提詞器黑狐提詞-手機提詞器?

已認證的官方帳號

其實這個問題很好解決,我們這款黑狐提詞手機提詞器就可以幫到你啦。我們不用提取視頻中的音頻再轉成文字,只需將視頻上傳至平臺上來,一鍵就可以提取視頻裏的文字了,識別準確率高達 97%。有了實用性AI工具輔助,音視頻轉文字操作簡單便捷,給大家大大節省時間,提高工作效率,在平時的創作中你也不妨用用看哦~

黑狐提詞?

a.app.qq.com

如何一鍵提取音視頻文案?智能操作,識別準確度高!黑狐提詞-手機提詞器的視頻 · 100 播放編輯於 2020-12-17繼續瀏覽內容知乎發現更大的世界打開Chrome繼續黑狐提詞-短視頻智能創作平臺黑狐提詞-短視頻智能創作平臺?

已認證的官方帳號

這個問題也太簡單了。用黑狐提詞APP就可以。

我教你,你在黑狐提詞APP裏打開視頻,一鍵就能轉為文字,如有神助。傻瓜式操作,你可以看看下面這個視頻。

黑狐提詞APP黑狐提詞-短視頻智能創作平臺的視頻 · 522 播放發佈於 2020-12-24繼續瀏覽內容知乎發現更大的世界打開Chrome繼續雲貓轉碼雲貓轉碼?

已認證的官方帳號

視頻轉文本的落地場景有很多:課程視頻做筆記、會議視頻整理、演講視頻學習等等。視頻直接轉文字,可以節省很多時間,大大提高工作學習的效率。按照傳統的方法,將視頻轉為文字,需要先將音頻提取出來,再轉為文字。使用 AI 技術自動轉文本,可以大大節省時間,提高工作效率。

推薦使用雲貓轉碼的【轉文本】功能,可以直接將視頻轉為文字。支持幾乎所有視頻格式,兼容多種外語和方言,識別準確率高達 97%:

轉文本 - 雲貓轉碼 | 簡單智能、功能齊備的在線視頻工具?

yunmaovideo.com

手機端可以使用小程序雲貓轉碼,微信登錄可與電腦端實時同步所有數據,十分方便:

雲貓轉碼,是一款簡單智能、功能齊備的在線視頻處理工具,擁有智能字幕、轉文字、配音、消音(消除人聲、背景音樂)等視頻處理和 AI 功能。

編輯於 03-12繼續瀏覽內容知乎發現更大的世界打開Chrome繼續技術路漫漫技術路漫漫技術路漫漫兮,吾將上下而求索

本系列將介紹如何一步步實現將mp4視頻中的語音對話,自動轉換為文本,並輸出到word文檔中。這裡第一篇,先完成視頻轉音頻處理。本項目全部代碼也已經全部開源到碼雲(https://gitee.com/coolpine/thomas),可直接下載試用。

總體技術架構

下圖是整體轉換流程:

  1. 先將mp4視頻文件,通過ffmpeg工具庫,批量轉換為pcm音頻文件(語音識別服務僅支持該格式)
  2. 基於百度雲的技術,將pcm文件上傳到百度對象存儲BOS中,並將日誌等記錄到本地mysql資料庫。
  3. pcm文件上傳完畢後,調用免費的語音識別(錄音轉寫)服務,創建離線錄音轉寫任務。
  4. 查詢轉寫成功的任務,並將相關轉寫結果存儲到本地mysql庫中。
  5. 基於docx4j庫,將資料庫中的錄音轉寫結果,導出為規範化的word文檔。

轉換結果示例

我們這裡實現的是將 《託馬斯和他的朋友們第18季》20集MP4視頻,最終轉換為一個word故事文檔:

下面是第一集具體對話文本表格:

視頻轉音頻

視頻轉音頻基於ffmpeg庫來實現。ffmpeg是一個強大的跨平臺音視頻記錄、轉換方案(官網說法:A complete, cross-platform solution to record, convert and stream audio and video)

ffmpeg主要是以命令行模式來實現音視頻轉換和處理,我們這裡實現的功能有:

  • 將mp4文件中片頭和片尾音樂剔除,截取中間片段。
  • 將截取後的mp4文件,轉換為pcm文件。
  • 基於ffplay驗證pcm可播放情況。

截取mp4文件中間片段的命令基本格式為:

ffmpeg -ss [start] -i [input] -t [duration] -c copy [output]
ffmpeg -ss [start] -i [input] -to [end] -c copy [output]
?
# 例如,以下是將t1801.mp4文件,截取從第30秒開始,截止到524秒,並保存為c1-1801.mp4文件:
ffmpeg -y -ss 30 -i t1801.mp4 -to 524 -c copy c1-1801.mp4

將mp4文件轉換為pcm音頻文件命令參數:

-i 輸入文件
-an 去除音頻流
-vn 去除視頻流
-acodec 設置音頻編碼
-f 強制指定輸入或輸出文件的編碼
-ac 設置音頻軌道數
-ar 設置音頻採用頻率
-y 不經過確認,直接覆蓋同名文件
?
# 例如,以下是將t1801.mp4文件,去除視頻流並用pcm_s16le進行音頻編碼,輸出文件也採用s16le編碼,同時音軌為1且採樣頻率為16000:
ffmpeg -i t1801.mp4 -vn -acodec pcm_s16le -f s16le -ac 1 -ar 16000 t1801.pcm

用ffplay播放pcm文件:

ffplay -ar 16000 -ac 1 -f s16le -i t1801.pcm

更多ffmpeg命令使用,參見官方文檔:https://ffmpeg.org/ffmpeg.html

Java音視頻處理

以上只是驗證了在命令行模式下,基於ffmpeg進行基本音視頻操作。因為要進行批量處理,我們還需要用編程的方式來調用ffmpeg:

  1. 基於org.bytedeco的ffmpeg和ffmpeg-platform來實現用java調用ffmpeg。
  2. 因為每集視頻的片頭和片尾歌曲時長基本固定,但每集視頻總時長不一樣,通過org.mp4parser的isoparser庫實現讀取每集總時長,動態拼裝轉換命令。

以下是引入的基本依賴:

&
&
&org.mp4parser&
&isoparser&
&1.9.41&
&
&
&
&org.bytedeco&
&ffmpeg&
&4.2.2-1.5.3&
&
&
&org.bytedeco&
&ffmpeg-platform&
&4.2.2-1.5.3&
&

以下是基於isoparser,讀取MP4文件的總時長(秒數):

public long readDuration(Path mp4Path) {
if (Files.notExists(mp4Path) || !Files.isReadable(mp4Path)) {
log.warn("文件路徑不存在或不可讀 {}", mp4Path);
return 0;
}
try {
IsoFile isoFile = new IsoFile(mp4Path.toFile());
long duration = isoFile.getMovieBox().getMovieHeaderBox().getDuration();
long timescale = isoFile.getMovieBox().getMovieHeaderBox().getTimescale();
return duration / timescale;
} catch (IOException e) {
log.error("讀取MP4文件時長出錯", e);
return 0;
}
}

以下是將MP4文件進行截取,並轉換為PCM文件:

/**
* 將單個PM4文件進行片頭和片尾歌曲刪除後,轉換為PCM文件
*
* @param mp4Path
* @param pcmDir
* @return 轉換完成後的pcm文件路徑
*/
public Optional& convertMP4toPCM(Path mp4Path, Path pcmDir) {
long seconds = readDuration(mp4Path);
if (seconds == 0) {
log.warn("文件總時長為0");
return Optional.empty();
}
String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
String endTime = String.valueOf(seconds - 100 - 30);
File src = mp4Path.toFile();
//在當前源mp4文件目錄下生成臨時文件
String mp4TempFile = src.getParent() + "" + System.currentTimeMillis() + ".mp4";
//基於ffmpeg進行截取
ProcessBuilder cutBuilder = new ProcessBuilder(ffmpeg, "-ss", "30", "-i", mp4Path.toAbsolutePath().toString(),
"-to", endTime, "-c", "copy", mp4TempFile);
try {
cutBuilder.inheritIO().start().waitFor();
} catch (InterruptedException | IOException e) {
log.error("ffmpeg截取MP4文件出錯", e);
return Optional.empty();
}
// 基於ffmpeg進行pcm轉換
// 基於輸入路徑的md5值來命名,也可以基於系統時間戳來命名
String pcmFile = pcmDir.resolve(DigestUtils.md5Hex(mp4Path.toString()) + ".pcm").toString();
ProcessBuilder pcmBuilder = new ProcessBuilder(ffmpeg, "-y", "-i", mp4TempFile, "-vn", "-acodec", "pcm_s16le",
"-f", "s16le", "-ac", "1", "-ar", "16000", pcmFile);
try {
//inheritIO是指將 子流程的IO與當前java流程的IO設置為相同
pcmBuilder.inheritIO().start().waitFor();
} catch (InterruptedException | IOException e) {
log.error("ffmpeg將mp4轉換為pcm時出錯", e);
return Optional.empty();
}
// 刪除MP4臨時文件
try {
Files.deleteIfExists(Paths.get(mp4TempFile));
} catch (IOException e) {
log.error("刪除mp4臨時文件出錯", e);
}
//返回pcm文件路徑
return Optional.of(pcmFile);
}

調用上述單個文件的處理方法,實現批量文件處理和轉換:

/**
* 批量將MP4文件轉換為PCM文件
*
* @param rootDir
* @param pcmDir
* @return 成功轉換的PCM文件數
*/
public int batchConvertMP4toPCM(Path rootDir, Path pcmDir) {
if (Files.notExists(rootDir) || !Files.isDirectory(rootDir)) {
log.warn("mp4文件目錄{}不存在", rootDir);
return 0;
}
?
if (Files.notExists(pcmDir)) {
//級聯創建目錄
try {
Files.createDirectories(pcmDir);
} catch (IOException e) {
log.error("創建文件夾出錯", e);
}
}
AtomicInteger pcmCount = new AtomicInteger(0);
//遍歷rootdir,獲取所有目錄下子目錄和文件
try {
Files.list(rootDir).forEach(path -&> {
if (Files.isDirectory(path)) {
//遞歸遍歷下級目錄
pcmCount.getAndAdd(batchConvertMP4toPCM(path, pcmDir));
}
if (Files.isRegularFile(path) Files.isReadable(path) path.getFileName()
.toString()
.endsWith("mp4")) {
Optional& pcmFile = this.convertMP4toPCM(path, pcmDir);
if (pcmFile.isPresent()) {
pcmCount.getAndIncrement();
}
}
});
} catch (IOException e) {
log.error("批量將MP4文件轉換為PCM文件出錯", e);
}
?
return pcmCount.get();
}

單個文件轉換調用測試:

@Test
void cutTest() {
String file = "D:\dev2\project\thomas\local\videos\t1801.mp4";
String pcmdir = "D:\dev2\project\thomas\local\videos\pcm";
Path path = Paths.get(file);
util.convertMP4toPCM(path, Paths.get(pcmdir));
}

批量文件轉換測試:

@Test
void batchTest() {
Path root = Paths.get("D:\dev2\project\thomas\local\videos\第18季");
Path pcmDir = Paths.get("D:\dev2\project\thomas\local\videos\pcm");
int pcmFiles = util.batchConvertMP4toPCM(root, pcmDir);
log.info("轉換出PCM文件數{}", pcmFiles);
}

至此,讀取mp4文件,轉換為pcm文件並剔除片頭和片尾,就基本完成了,接下來將為你介紹如何基於百度雲SDK和API實現語音轉錄。


這個問題很簡單,不用提取視頻的音頻,現在微信的【微轉寫】小程序已經支持直接把視頻轉換成文字了,直接複製視頻地址或者是上傳本地的視頻就可以一鍵轉文本了,是不是很方便?對了,現在還可以免費看廣告領取時長哦

如何將錄音轉文字|音頻視頻語音轉文字 ,教程來了微轉寫的視頻 · 1056 播放視頻裏的音頻如何轉換成文字?看這個一鍵提取文案的神工具微轉寫的視頻 · 1372 播放發佈於 2020-12-12繼續瀏覽內容知乎發現更大的世界打開Chrome繼續科技口袋科技口袋?

已認證的官方帳號

使用微信小程序「微轉寫」,不需要提取音頻即可一鍵轉視頻為文字,且抖音、快手等平臺的視頻無需下載,支持在線一鍵轉寫,使用非常方便

編輯於 2020-12-16繼續瀏覽內容知乎發現更大的世界打開Chrome繼續黑狐提詞-手機提詞器黑狐提詞-手機提詞器?

已認證的官方帳號

其實這個問題很好解決,我們這款黑狐提詞手機提詞器就可以幫到你啦。我們不用提取視頻中的音頻再轉成文字,只需將視頻上傳至平臺上來,一鍵就可以提取視頻裏的文字了,識別準確率高達 97%。有了實用性AI工具輔助,音視頻轉文字操作簡單便捷,給大家大大節省時間,提高工作效率,在平時的創作中你也不妨用用看哦~

黑狐提詞?

a.app.qq.com

如何一鍵提取音視頻文案?智能操作,識別準確度高!黑狐提詞-手機提詞器的視頻 · 100 播放編輯於 2020-12-17繼續瀏覽內容知乎發現更大的世界打開Chrome繼續黑狐提詞-短視頻智能創作平臺黑狐提詞-短視頻智能創作平臺?

已認證的官方帳號

這個問題也太簡單了。用黑狐提詞APP就可以。

我教你,你在黑狐提詞APP裏打開視頻,一鍵就能轉為文字,如有神助。傻瓜式操作,你可以看看下面這個視頻。

黑狐提詞APP黑狐提詞-短視頻智能創作平臺的視頻 · 522 播放發佈於 2020-12-24繼續瀏覽內容知乎發現更大的世界打開Chrome繼續雲貓轉碼雲貓轉碼?

已認證的官方帳號

視頻轉文本的落地場景有很多:課程視頻做筆記、會議視頻整理、演講視頻學習等等。視頻直接轉文字,可以節省很多時間,大大提高工作學習的效率。按照傳統的方法,將視頻轉為文字,需要先將音頻提取出來,再轉為文字。使用 AI 技術自動轉文本,可以大大節省時間,提高工作效率。

推薦使用雲貓轉碼的【轉文本】功能,可以直接將視頻轉為文字。支持幾乎所有視頻格式,兼容多種外語和方言,識別準確率高達 97%:

轉文本 - 雲貓轉碼 | 簡單智能、功能齊備的在線視頻工具?

yunmaovideo.com

手機端可以使用小程序雲貓轉碼,微信登錄可與電腦端實時同步所有數據,十分方便:

雲貓轉碼,是一款簡單智能、功能齊備的在線視頻處理工具,擁有智能字幕、轉文字、配音、消音(消除人聲、背景音樂)等視頻處理和 AI 功能。

編輯於 03-12繼續瀏覽內容知乎發現更大的世界打開Chrome繼續技術路漫漫技術路漫漫技術路漫漫兮,吾將上下而求索

本系列將介紹如何一步步實現將mp4視頻中的語音對話,自動轉換為文本,並輸出到word文檔中。這裡第一篇,先完成視頻轉音頻處理。本項目全部代碼也已經全部開源到碼雲(https://gitee.com/coolpine/thomas),可直接下載試用。

總體技術架構

下圖是整體轉換流程:

  1. 先將mp4視頻文件,通過ffmpeg工具庫,批量轉換為pcm音頻文件(語音識別服務僅支持該格式)
  2. 基於百度雲的技術,將pcm文件上傳到百度對象存儲BOS中,並將日誌等記錄到本地mysql資料庫。
  3. pcm文件上傳完畢後,調用免費的語音識別(錄音轉寫)服務,創建離線錄音轉寫任務。
  4. 查詢轉寫成功的任務,並將相關轉寫結果存儲到本地mysql庫中。
  5. 基於docx4j庫,將資料庫中的錄音轉寫結果,導出為規範化的word文檔。

轉換結果示例

我們這裡實現的是將 《託馬斯和他的朋友們第18季》20集MP4視頻,最終轉換為一個word故事文檔:

下面是第一集具體對話文本表格:

視頻轉音頻

視頻轉音頻基於ffmpeg庫來實現。ffmpeg是一個強大的跨平臺音視頻記錄、轉換方案(官網說法:A complete, cross-platform solution to record, convert and stream audio and video)

ffmpeg主要是以命令行模式來實現音視頻轉換和處理,我們這裡實現的功能有:

  • 將mp4文件中片頭和片尾音樂剔除,截取中間片段。
  • 將截取後的mp4文件,轉換為pcm文件。
  • 基於ffplay驗證pcm可播放情況。

截取mp4文件中間片段的命令基本格式為:

ffmpeg -ss [start] -i [input] -t [duration] -c copy [output]
ffmpeg -ss [start] -i [input] -to [end] -c copy [output]
?
# 例如,以下是將t1801.mp4文件,截取從第30秒開始,截止到524秒,並保存為c1-1801.mp4文件:
ffmpeg -y -ss 30 -i t1801.mp4 -to 524 -c copy c1-1801.mp4

將mp4文件轉換為pcm音頻文件命令參數:

-i 輸入文件
-an 去除音頻流
-vn 去除視頻流
-acodec 設置音頻編碼
-f 強制指定輸入或輸出文件的編碼
-ac 設置音頻軌道數
-ar 設置音頻採用頻率
-y 不經過確認,直接覆蓋同名文件
?
# 例如,以下是將t1801.mp4文件,去除視頻流並用pcm_s16le進行音頻編碼,輸出文件也採用s16le編碼,同時音軌為1且採樣頻率為16000:
ffmpeg -i t1801.mp4 -vn -acodec pcm_s16le -f s16le -ac 1 -ar 16000 t1801.pcm

用ffplay播放pcm文件:

ffplay -ar 16000 -ac 1 -f s16le -i t1801.pcm

更多ffmpeg命令使用,參見官方文檔:https://ffmpeg.org/ffmpeg.html

Java音視頻處理

以上只是驗證了在命令行模式下,基於ffmpeg進行基本音視頻操作。因為要進行批量處理,我們還需要用編程的方式來調用ffmpeg:

  1. 基於org.bytedeco的ffmpeg和ffmpeg-platform來實現用java調用ffmpeg。
  2. 因為每集視頻的片頭和片尾歌曲時長基本固定,但每集視頻總時長不一樣,通過org.mp4parser的isoparser庫實現讀取每集總時長,動態拼裝轉換命令。

以下是引入的基本依賴:

&
&
&org.mp4parser&
&isoparser&
&1.9.41&
&
&
&
&org.bytedeco&
&ffmpeg&
&4.2.2-1.5.3&
&
&
&org.bytedeco&
&ffmpeg-platform&
&4.2.2-1.5.3&
&

以下是基於isoparser,讀取MP4文件的總時長(秒數):

public long readDuration(Path mp4Path) {
if (Files.notExists(mp4Path) || !Files.isReadable(mp4Path)) {
log.warn("文件路徑不存在或不可讀 {}", mp4Path);
return 0;
}
try {
IsoFile isoFile = new IsoFile(mp4Path.toFile());
long duration = isoFile.getMovieBox().getMovieHeaderBox().getDuration();
long timescale = isoFile.getMovieBox().getMovieHeaderBox().getTimescale();
return duration / timescale;
} catch (IOException e) {
log.error("讀取MP4文件時長出錯", e);
return 0;
}
}

以下是將MP4文件進行截取,並轉換為PCM文件:

/**
* 將單個PM4文件進行片頭和片尾歌曲刪除後,轉換為PCM文件
*
* @param mp4Path
* @param pcmDir
* @return 轉換完成後的pcm文件路徑
*/
public Optional& convertMP4toPCM(Path mp4Path, Path pcmDir) {
long seconds = readDuration(mp4Path);
if (seconds == 0) {
log.warn("文件總時長為0");
return Optional.empty();
}
String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
String endTime = String.valueOf(seconds - 100 - 30);
File src = mp4Path.toFile();
//在當前源mp4文件目錄下生成臨時文件
String mp4TempFile = src.getParent() + "" + System.currentTimeMillis() + ".mp4";
//基於ffmpeg進行截取
ProcessBuilder cutBuilder = new ProcessBuilder(ffmpeg, "-ss", "30", "-i", mp4Path.toAbsolutePath().toString(),
"-to", endTime, "-c", "copy", mp4TempFile);
try {
cutBuilder.inheritIO().start().waitFor();
} catch (InterruptedException | IOException e) {
log.error("ffmpeg截取MP4文件出錯", e);
return Optional.empty();
}
// 基於ffmpeg進行pcm轉換
// 基於輸入路徑的md5值來命名,也可以基於系統時間戳來命名
String pcmFile = pcmDir.resolve(DigestUtils.md5Hex(mp4Path.toString()) + ".pcm").toString();
ProcessBuilder pcmBuilder = new ProcessBuilder(ffmpeg, "-y", "-i", mp4TempFile, "-vn", "-acodec", "pcm_s16le",
"-f", "s16le", "-ac", "1", "-ar", "16000", pcmFile);
try {
//inheritIO是指將 子流程的IO與當前java流程的IO設置為相同
pcmBuilder.inheritIO().start().waitFor();
} catch (InterruptedException | IOException e) {
log.error("ffmpeg將mp4轉換為pcm時出錯", e);
return Optional.empty();
}
// 刪除MP4臨時文件
try {
Files.deleteIfExists(Paths.get(mp4TempFile));
} catch (IOException e) {
log.error("刪除mp4臨時文件出錯", e);
}
//返回pcm文件路徑
return Optional.of(pcmFile);
}

調用上述單個文件的處理方法,實現批量文件處理和轉換:

/**
* 批量將MP4文件轉換為PCM文件
*
* @param rootDir
* @param pcmDir
* @return 成功轉換的PCM文件數
*/
public int batchConvertMP4toPCM(Path rootDir, Path pcmDir) {
if (Files.notExists(rootDir) || !Files.isDirectory(rootDir)) {
log.warn("mp4文件目錄{}不存在", rootDir);
return 0;
}
?
if (Files.notExists(pcmDir)) {
//級聯創建目錄
try {
Files.createDirectories(pcmDir);
} catch (IOException e) {
log.error("創建文件夾出錯", e);
}
}
AtomicInteger pcmCount = new AtomicInteger(0);
//遍歷rootdir,獲取所有目錄下子目錄和文件
try {
Files.list(rootDir).forEach(path -&> {
if (Files.isDirectory(path)) {
//遞歸遍歷下級目錄
pcmCount.getAndAdd(batchConvertMP4toPCM(path, pcmDir));
}
if (Files.isRegularFile(path) Files.isReadable(path) path.getFileName()
.toString()
.endsWith("mp4")) {
Optional& pcmFile = this.convertMP4toPCM(path, pcmDir);
if (pcmFile.isPresent()) {
pcmCount.getAndIncrement();
}
}
});
} catch (IOException e) {
log.error("批量將MP4文件轉換為PCM文件出錯", e);
}
?
return pcmCount.get();
}

單個文件轉換調用測試:

@Test
void cutTest() {
String file = "D:\dev2\project\thomas\local\videos\t1801.mp4";
String pcmdir = "D:\dev2\project\thomas\local\videos\pcm";
Path path = Paths.get(file);
util.convertMP4toPCM(path, Paths.get(pcmdir));
}

批量文件轉換測試:

@Test
void batchTest() {
Path root = Paths.get("D:\dev2\project\thomas\local\videos\第18季");
Path pcmDir = Paths.get("D:\dev2\project\thomas\local\videos\pcm");
int pcmFiles = util.batchConvertMP4toPCM(root, pcmDir);
log.info("轉換出PCM文件數{}", pcmFiles);
}

至此,讀取mp4文件,轉換為pcm文件並剔除片頭和片尾,就基本完成了,接下來將為你介紹如何基於百度雲SDK和API實現語音轉錄。


使用微信小程序「微轉寫」,不需要提取音頻即可一鍵轉視頻為文字,且抖音、快手等平臺的視頻無需下載,支持在線一鍵轉寫,使用非常方便

編輯於 2020-12-16繼續瀏覽內容知乎發現更大的世界打開Chrome繼續黑狐提詞-手機提詞器黑狐提詞-手機提詞器?

已認證的官方帳號

其實這個問題很好解決,我們這款黑狐提詞手機提詞器就可以幫到你啦。我們不用提取視頻中的音頻再轉成文字,只需將視頻上傳至平臺上來,一鍵就可以提取視頻裏的文字了,識別準確率高達 97%。有了實用性AI工具輔助,音視頻轉文字操作簡單便捷,給大家大大節省時間,提高工作效率,在平時的創作中你也不妨用用看哦~

黑狐提詞?

a.app.qq.com

如何一鍵提取音視頻文案?智能操作,識別準確度高!黑狐提詞-手機提詞器的視頻 · 100 播放編輯於 2020-12-17繼續瀏覽內容知乎發現更大的世界打開Chrome繼續黑狐提詞-短視頻智能創作平臺黑狐提詞-短視頻智能創作平臺?

已認證的官方帳號

這個問題也太簡單了。用黑狐提詞APP就可以。

我教你,你在黑狐提詞APP裏打開視頻,一鍵就能轉為文字,如有神助。傻瓜式操作,你可以看看下面這個視頻。

黑狐提詞APP黑狐提詞-短視頻智能創作平臺的視頻 · 522 播放發佈於 2020-12-24繼續瀏覽內容知乎發現更大的世界打開Chrome繼續雲貓轉碼雲貓轉碼?

已認證的官方帳號

視頻轉文本的落地場景有很多:課程視頻做筆記、會議視頻整理、演講視頻學習等等。視頻直接轉文字,可以節省很多時間,大大提高工作學習的效率。按照傳統的方法,將視頻轉為文字,需要先將音頻提取出來,再轉為文字。使用 AI 技術自動轉文本,可以大大節省時間,提高工作效率。

推薦使用雲貓轉碼的【轉文本】功能,可以直接將視頻轉為文字。支持幾乎所有視頻格式,兼容多種外語和方言,識別準確率高達 97%:

轉文本 - 雲貓轉碼 | 簡單智能、功能齊備的在線視頻工具?

yunmaovideo.com

手機端可以使用小程序雲貓轉碼,微信登錄可與電腦端實時同步所有數據,十分方便:

雲貓轉碼,是一款簡單智能、功能齊備的在線視頻處理工具,擁有智能字幕、轉文字、配音、消音(消除人聲、背景音樂)等視頻處理和 AI 功能。

編輯於 03-12繼續瀏覽內容知乎發現更大的世界打開Chrome繼續技術路漫漫技術路漫漫技術路漫漫兮,吾將上下而求索

本系列將介紹如何一步步實現將mp4視頻中的語音對話,自動轉換為文本,並輸出到word文檔中。這裡第一篇,先完成視頻轉音頻處理。本項目全部代碼也已經全部開源到碼雲(https://gitee.com/coolpine/thomas),可直接下載試用。

總體技術架構

下圖是整體轉換流程:

  1. 先將mp4視頻文件,通過ffmpeg工具庫,批量轉換為pcm音頻文件(語音識別服務僅支持該格式)
  2. 基於百度雲的技術,將pcm文件上傳到百度對象存儲BOS中,並將日誌等記錄到本地mysql資料庫。
  3. pcm文件上傳完畢後,調用免費的語音識別(錄音轉寫)服務,創建離線錄音轉寫任務。
  4. 查詢轉寫成功的任務,並將相關轉寫結果存儲到本地mysql庫中。
  5. 基於docx4j庫,將資料庫中的錄音轉寫結果,導出為規範化的word文檔。

轉換結果示例

我們這裡實現的是將 《託馬斯和他的朋友們第18季》20集MP4視頻,最終轉換為一個word故事文檔:

下面是第一集具體對話文本表格:

視頻轉音頻

視頻轉音頻基於ffmpeg庫來實現。ffmpeg是一個強大的跨平臺音視頻記錄、轉換方案(官網說法:A complete, cross-platform solution to record, convert and stream audio and video)

ffmpeg主要是以命令行模式來實現音視頻轉換和處理,我們這裡實現的功能有:

  • 將mp4文件中片頭和片尾音樂剔除,截取中間片段。
  • 將截取後的mp4文件,轉換為pcm文件。
  • 基於ffplay驗證pcm可播放情況。

截取mp4文件中間片段的命令基本格式為:

ffmpeg -ss [start] -i [input] -t [duration] -c copy [output]
ffmpeg -ss [start] -i [input] -to [end] -c copy [output]
?
# 例如,以下是將t1801.mp4文件,截取從第30秒開始,截止到524秒,並保存為c1-1801.mp4文件:
ffmpeg -y -ss 30 -i t1801.mp4 -to 524 -c copy c1-1801.mp4

將mp4文件轉換為pcm音頻文件命令參數:

-i 輸入文件
-an 去除音頻流
-vn 去除視頻流
-acodec 設置音頻編碼
-f 強制指定輸入或輸出文件的編碼
-ac 設置音頻軌道數
-ar 設置音頻採用頻率
-y 不經過確認,直接覆蓋同名文件
?
# 例如,以下是將t1801.mp4文件,去除視頻流並用pcm_s16le進行音頻編碼,輸出文件也採用s16le編碼,同時音軌為1且採樣頻率為16000:
ffmpeg -i t1801.mp4 -vn -acodec pcm_s16le -f s16le -ac 1 -ar 16000 t1801.pcm

用ffplay播放pcm文件:

ffplay -ar 16000 -ac 1 -f s16le -i t1801.pcm

更多ffmpeg命令使用,參見官方文檔:https://ffmpeg.org/ffmpeg.html

Java音視頻處理

以上只是驗證了在命令行模式下,基於ffmpeg進行基本音視頻操作。因為要進行批量處理,我們還需要用編程的方式來調用ffmpeg:

  1. 基於org.bytedeco的ffmpeg和ffmpeg-platform來實現用java調用ffmpeg。
  2. 因為每集視頻的片頭和片尾歌曲時長基本固定,但每集視頻總時長不一樣,通過org.mp4parser的isoparser庫實現讀取每集總時長,動態拼裝轉換命令。

以下是引入的基本依賴:

&
&
&org.mp4parser&
&isoparser&
&1.9.41&
&
&
&
&org.bytedeco&
&ffmpeg&
&4.2.2-1.5.3&
&
&
&org.bytedeco&
&ffmpeg-platform&
&4.2.2-1.5.3&
&

以下是基於isoparser,讀取MP4文件的總時長(秒數):

public long readDuration(Path mp4Path) {
if (Files.notExists(mp4Path) || !Files.isReadable(mp4Path)) {
log.warn("文件路徑不存在或不可讀 {}", mp4Path);
return 0;
}
try {
IsoFile isoFile = new IsoFile(mp4Path.toFile());
long duration = isoFile.getMovieBox().getMovieHeaderBox().getDuration();
long timescale = isoFile.getMovieBox().getMovieHeaderBox().getTimescale();
return duration / timescale;
} catch (IOException e) {
log.error("讀取MP4文件時長出錯", e);
return 0;
}
}

以下是將MP4文件進行截取,並轉換為PCM文件:

/**
* 將單個PM4文件進行片頭和片尾歌曲刪除後,轉換為PCM文件
*
* @param mp4Path
* @param pcmDir
* @return 轉換完成後的pcm文件路徑
*/
public Optional& convertMP4toPCM(Path mp4Path, Path pcmDir) {
long seconds = readDuration(mp4Path);
if (seconds == 0) {
log.warn("文件總時長為0");
return Optional.empty();
}
String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
String endTime = String.valueOf(seconds - 100 - 30);
File src = mp4Path.toFile();
//在當前源mp4文件目錄下生成臨時文件
String mp4TempFile = src.getParent() + "" + System.currentTimeMillis() + ".mp4";
//基於ffmpeg進行截取
ProcessBuilder cutBuilder = new ProcessBuilder(ffmpeg, "-ss", "30", "-i", mp4Path.toAbsolutePath().toString(),
"-to", endTime, "-c", "copy", mp4TempFile);
try {
cutBuilder.inheritIO().start().waitFor();
} catch (InterruptedException | IOException e) {
log.error("ffmpeg截取MP4文件出錯", e);
return Optional.empty();
}
// 基於ffmpeg進行pcm轉換
// 基於輸入路徑的md5值來命名,也可以基於系統時間戳來命名
String pcmFile = pcmDir.resolve(DigestUtils.md5Hex(mp4Path.toString()) + ".pcm").toString();
ProcessBuilder pcmBuilder = new ProcessBuilder(ffmpeg, "-y", "-i", mp4TempFile, "-vn", "-acodec", "pcm_s16le",
"-f", "s16le", "-ac", "1", "-ar", "16000", pcmFile);
try {
//inheritIO是指將 子流程的IO與當前java流程的IO設置為相同
pcmBuilder.inheritIO().start().waitFor();
} catch (InterruptedException | IOException e) {
log.error("ffmpeg將mp4轉換為pcm時出錯", e);
return Optional.empty();
}
// 刪除MP4臨時文件
try {
Files.deleteIfExists(Paths.get(mp4TempFile));
} catch (IOException e) {
log.error("刪除mp4臨時文件出錯", e);
}
//返回pcm文件路徑
return Optional.of(pcmFile);
}

調用上述單個文件的處理方法,實現批量文件處理和轉換:

/**
* 批量將MP4文件轉換為PCM文件
*
* @param rootDir
* @param pcmDir
* @return 成功轉換的PCM文件數
*/
public int batchConvertMP4toPCM(Path rootDir, Path pcmDir) {
if (Files.notExists(rootDir) || !Files.isDirectory(rootDir)) {
log.warn("mp4文件目錄{}不存在", rootDir);
return 0;
}
?
if (Files.notExists(pcmDir)) {
//級聯創建目錄
try {
Files.createDirectories(pcmDir);
} catch (IOException e) {
log.error("創建文件夾出錯", e);
}
}
AtomicInteger pcmCount = new AtomicInteger(0);
//遍歷rootdir,獲取所有目錄下子目錄和文件
try {
Files.list(rootDir).forEach(path -&> {
if (Files.isDirectory(path)) {
//遞歸遍歷下級目錄
pcmCount.getAndAdd(batchConvertMP4toPCM(path, pcmDir));
}
if (Files.isRegularFile(path) Files.isReadable(path) path.getFileName()
.toString()
.endsWith("mp4")) {
Optional& pcmFile = this.convertMP4toPCM(path, pcmDir);
if (pcmFile.isPresent()) {
pcmCount.getAndIncrement();
}
}
});
} catch (IOException e) {
log.error("批量將MP4文件轉換為PCM文件出錯", e);
}
?
return pcmCount.get();
}

單個文件轉換調用測試:

@Test
void cutTest() {
String file = "D:\dev2\project\thomas\local\videos\t1801.mp4";
String pcmdir = "D:\dev2\project\thomas\local\videos\pcm";
Path path = Paths.get(file);
util.convertMP4toPCM(path, Paths.get(pcmdir));
}

批量文件轉換測試:

@Test
void batchTest() {
Path root = Paths.get("D:\dev2\project\thomas\local\videos\第18季");
Path pcmDir = Paths.get("D:\dev2\project\thomas\local\videos\pcm");
int pcmFiles = util.batchConvertMP4toPCM(root, pcmDir);
log.info("轉換出PCM文件數{}", pcmFiles);
}

至此,讀取mp4文件,轉換為pcm文件並剔除片頭和片尾,就基本完成了,接下來將為你介紹如何基於百度雲SDK和API實現語音轉錄。


其實這個問題很好解決,我們這款黑狐提詞手機提詞器就可以幫到你啦。我們不用提取視頻中的音頻再轉成文字,只需將視頻上傳至平臺上來,一鍵就可以提取視頻裏的文字了,識別準確率高達 97%。有了實用性AI工具輔助,音視頻轉文字操作簡單便捷,給大家大大節省時間,提高工作效率,在平時的創作中你也不妨用用看哦~

黑狐提詞?

a.app.qq.com

如何一鍵提取音視頻文案?智能操作,識別準確度高!黑狐提詞-手機提詞器的視頻 · 100 播放編輯於 2020-12-17繼續瀏覽內容知乎發現更大的世界打開Chrome繼續黑狐提詞-短視頻智能創作平臺黑狐提詞-短視頻智能創作平臺?

已認證的官方帳號

這個問題也太簡單了。用黑狐提詞APP就可以。

我教你,你在黑狐提詞APP裏打開視頻,一鍵就能轉為文字,如有神助。傻瓜式操作,你可以看看下面這個視頻。

黑狐提詞APP黑狐提詞-短視頻智能創作平臺的視頻 · 522 播放發佈於 2020-12-24繼續瀏覽內容知乎發現更大的世界打開Chrome繼續雲貓轉碼雲貓轉碼?

已認證的官方帳號

視頻轉文本的落地場景有很多:課程視頻做筆記、會議視頻整理、演講視頻學習等等。視頻直接轉文字,可以節省很多時間,大大提高工作學習的效率。按照傳統的方法,將視頻轉為文字,需要先將音頻提取出來,再轉為文字。使用 AI 技術自動轉文本,可以大大節省時間,提高工作效率。

推薦使用雲貓轉碼的【轉文本】功能,可以直接將視頻轉為文字。支持幾乎所有視頻格式,兼容多種外語和方言,識別準確率高達 97%:

轉文本 - 雲貓轉碼 | 簡單智能、功能齊備的在線視頻工具?

yunmaovideo.com

手機端可以使用小程序雲貓轉碼,微信登錄可與電腦端實時同步所有數據,十分方便:

雲貓轉碼,是一款簡單智能、功能齊備的在線視頻處理工具,擁有智能字幕、轉文字、配音、消音(消除人聲、背景音樂)等視頻處理和 AI 功能。

編輯於 03-12繼續瀏覽內容知乎發現更大的世界打開Chrome繼續技術路漫漫技術路漫漫技術路漫漫兮,吾將上下而求索

本系列將介紹如何一步步實現將mp4視頻中的語音對話,自動轉換為文本,並輸出到word文檔中。這裡第一篇,先完成視頻轉音頻處理。本項目全部代碼也已經全部開源到碼雲(https://gitee.com/coolpine/thomas),可直接下載試用。

總體技術架構

下圖是整體轉換流程:

  1. 先將mp4視頻文件,通過ffmpeg工具庫,批量轉換為pcm音頻文件(語音識別服務僅支持該格式)
  2. 基於百度雲的技術,將pcm文件上傳到百度對象存儲BOS中,並將日誌等記錄到本地mysql資料庫。
  3. pcm文件上傳完畢後,調用免費的語音識別(錄音轉寫)服務,創建離線錄音轉寫任務。
  4. 查詢轉寫成功的任務,並將相關轉寫結果存儲到本地mysql庫中。
  5. 基於docx4j庫,將資料庫中的錄音轉寫結果,導出為規範化的word文檔。

轉換結果示例

我們這裡實現的是將 《託馬斯和他的朋友們第18季》20集MP4視頻,最終轉換為一個word故事文檔:

下面是第一集具體對話文本表格:

視頻轉音頻

視頻轉音頻基於ffmpeg庫來實現。ffmpeg是一個強大的跨平臺音視頻記錄、轉換方案(官網說法:A complete, cross-platform solution to record, convert and stream audio and video)

ffmpeg主要是以命令行模式來實現音視頻轉換和處理,我們這裡實現的功能有:

  • 將mp4文件中片頭和片尾音樂剔除,截取中間片段。
  • 將截取後的mp4文件,轉換為pcm文件。
  • 基於ffplay驗證pcm可播放情況。

截取mp4文件中間片段的命令基本格式為:

ffmpeg -ss [start] -i [input] -t [duration] -c copy [output]
ffmpeg -ss [start] -i [input] -to [end] -c copy [output]
?
# 例如,以下是將t1801.mp4文件,截取從第30秒開始,截止到524秒,並保存為c1-1801.mp4文件:
ffmpeg -y -ss 30 -i t1801.mp4 -to 524 -c copy c1-1801.mp4

將mp4文件轉換為pcm音頻文件命令參數:

-i 輸入文件
-an 去除音頻流
-vn 去除視頻流
-acodec 設置音頻編碼
-f 強制指定輸入或輸出文件的編碼
-ac 設置音頻軌道數
-ar 設置音頻採用頻率
-y 不經過確認,直接覆蓋同名文件
?
# 例如,以下是將t1801.mp4文件,去除視頻流並用pcm_s16le進行音頻編碼,輸出文件也採用s16le編碼,同時音軌為1且採樣頻率為16000:
ffmpeg -i t1801.mp4 -vn -acodec pcm_s16le -f s16le -ac 1 -ar 16000 t1801.pcm

用ffplay播放pcm文件:

ffplay -ar 16000 -ac 1 -f s16le -i t1801.pcm

更多ffmpeg命令使用,參見官方文檔:https://ffmpeg.org/ffmpeg.html

Java音視頻處理

以上只是驗證了在命令行模式下,基於ffmpeg進行基本音視頻操作。因為要進行批量處理,我們還需要用編程的方式來調用ffmpeg:

  1. 基於org.bytedeco的ffmpeg和ffmpeg-platform來實現用java調用ffmpeg。
  2. 因為每集視頻的片頭和片尾歌曲時長基本固定,但每集視頻總時長不一樣,通過org.mp4parser的isoparser庫實現讀取每集總時長,動態拼裝轉換命令。

以下是引入的基本依賴:

&
&
&org.mp4parser&
&isoparser&
&1.9.41&
&
&
&
&org.bytedeco&
&ffmpeg&
&4.2.2-1.5.3&
&
&
&org.bytedeco&
&ffmpeg-platform&
&4.2.2-1.5.3&
&

以下是基於isoparser,讀取MP4文件的總時長(秒數):

public long readDuration(Path mp4Path) {
if (Files.notExists(mp4Path) || !Files.isReadable(mp4Path)) {
log.warn("文件路徑不存在或不可讀 {}", mp4Path);
return 0;
}
try {
IsoFile isoFile = new IsoFile(mp4Path.toFile());
long duration = isoFile.getMovieBox().getMovieHeaderBox().getDuration();
long timescale = isoFile.getMovieBox().getMovieHeaderBox().getTimescale();
return duration / timescale;
} catch (IOException e) {
log.error("讀取MP4文件時長出錯", e);
return 0;
}
}

以下是將MP4文件進行截取,並轉換為PCM文件:

/**
* 將單個PM4文件進行片頭和片尾歌曲刪除後,轉換為PCM文件
*
* @param mp4Path
* @param pcmDir
* @return 轉換完成後的pcm文件路徑
*/
public Optional& convertMP4toPCM(Path mp4Path, Path pcmDir) {
long seconds = readDuration(mp4Path);
if (seconds == 0) {
log.warn("文件總時長為0");
return Optional.empty();
}
String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
String endTime = String.valueOf(seconds - 100 - 30);
File src = mp4Path.toFile();
//在當前源mp4文件目錄下生成臨時文件
String mp4TempFile = src.getParent() + "" + System.currentTimeMillis() + ".mp4";
//基於ffmpeg進行截取
ProcessBuilder cutBuilder = new ProcessBuilder(ffmpeg, "-ss", "30", "-i", mp4Path.toAbsolutePath().toString(),
"-to", endTime, "-c", "copy", mp4TempFile);
try {
cutBuilder.inheritIO().start().waitFor();
} catch (InterruptedException | IOException e) {
log.error("ffmpeg截取MP4文件出錯", e);
return Optional.empty();
}
// 基於ffmpeg進行pcm轉換
// 基於輸入路徑的md5值來命名,也可以基於系統時間戳來命名
String pcmFile = pcmDir.resolve(DigestUtils.md5Hex(mp4Path.toString()) + ".pcm").toString();
ProcessBuilder pcmBuilder = new ProcessBuilder(ffmpeg, "-y", "-i", mp4TempFile, "-vn", "-acodec", "pcm_s16le",
"-f", "s16le", "-ac", "1", "-ar", "16000", pcmFile);
try {
//inheritIO是指將 子流程的IO與當前java流程的IO設置為相同
pcmBuilder.inheritIO().start().waitFor();
} catch (InterruptedException | IOException e) {
log.error("ffmpeg將mp4轉換為pcm時出錯", e);
return Optional.empty();
}
// 刪除MP4臨時文件
try {
Files.deleteIfExists(Paths.get(mp4TempFile));
} catch (IOException e) {
log.error("刪除mp4臨時文件出錯", e);
}
//返回pcm文件路徑
return Optional.of(pcmFile);
}

調用上述單個文件的處理方法,實現批量文件處理和轉換:

/**
* 批量將MP4文件轉換為PCM文件
*
* @param rootDir
* @param pcmDir
* @return 成功轉換的PCM文件數
*/
public int batchConvertMP4toPCM(Path rootDir, Path pcmDir) {
if (Files.notExists(rootDir) || !Files.isDirectory(rootDir)) {
log.warn("mp4文件目錄{}不存在", rootDir);
return 0;
}
?
if (Files.notExists(pcmDir)) {
//級聯創建目錄
try {
Files.createDirectories(pcmDir);
} catch (IOException e) {
log.error("創建文件夾出錯", e);
}
}
AtomicInteger pcmCount = new AtomicInteger(0);
//遍歷rootdir,獲取所有目錄下子目錄和文件
try {
Files.list(rootDir).forEach(path -&> {
if (Files.isDirectory(path)) {
//遞歸遍歷下級目錄
pcmCount.getAndAdd(batchConvertMP4toPCM(path, pcmDir));
}
if (Files.isRegularFile(path) Files.isReadable(path) path.getFileName()
.toString()
.endsWith("mp4")) {
Optional& pcmFile = this.convertMP4toPCM(path, pcmDir);
if (pcmFile.isPresent()) {
pcmCount.getAndIncrement();
}
}
});
} catch (IOException e) {
log.error("批量將MP4文件轉換為PCM文件出錯", e);
}
?
return pcmCount.get();
}

單個文件轉換調用測試:

@Test
void cutTest() {
String file = "D:\dev2\project\thomas\local\videos\t1801.mp4";
String pcmdir = "D:\dev2\project\thomas\local\videos\pcm";
Path path = Paths.get(file);
util.convertMP4toPCM(path, Paths.get(pcmdir));
}

批量文件轉換測試:

@Test
void batchTest() {
Path root = Paths.get("D:\dev2\project\thomas\local\videos\第18季");
Path pcmDir = Paths.get("D:\dev2\project\thomas\local\videos\pcm");
int pcmFiles = util.batchConvertMP4toPCM(root, pcmDir);
log.info("轉換出PCM文件數{}", pcmFiles);
}

至此,讀取mp4文件,轉換為pcm文件並剔除片頭和片尾,就基本完成了,接下來將為你介紹如何基於百度雲SDK和API實現語音轉錄。


這個問題也太簡單了。用黑狐提詞APP就可以。

我教你,你在黑狐提詞APP裏打開視頻,一鍵就能轉為文字,如有神助。傻瓜式操作,你可以看看下面這個視頻。

黑狐提詞APP黑狐提詞-短視頻智能創作平臺的視頻 · 522 播放發佈於 2020-12-24繼續瀏覽內容知乎發現更大的世界打開Chrome繼續雲貓轉碼雲貓轉碼?

已認證的官方帳號

視頻轉文本的落地場景有很多:課程視頻做筆記、會議視頻整理、演講視頻學習等等。視頻直接轉文字,可以節省很多時間,大大提高工作學習的效率。按照傳統的方法,將視頻轉為文字,需要先將音頻提取出來,再轉為文字。使用 AI 技術自動轉文本,可以大大節省時間,提高工作效率。

推薦使用雲貓轉碼的【轉文本】功能,可以直接將視頻轉為文字。支持幾乎所有視頻格式,兼容多種外語和方言,識別準確率高達 97%:

轉文本 - 雲貓轉碼 | 簡單智能、功能齊備的在線視頻工具?

yunmaovideo.com

手機端可以使用小程序雲貓轉碼,微信登錄可與電腦端實時同步所有數據,十分方便:

雲貓轉碼,是一款簡單智能、功能齊備的在線視頻處理工具,擁有智能字幕、轉文字、配音、消音(消除人聲、背景音樂)等視頻處理和 AI 功能。

編輯於 03-12繼續瀏覽內容知乎發現更大的世界打開Chrome繼續技術路漫漫技術路漫漫技術路漫漫兮,吾將上下而求索

本系列將介紹如何一步步實現將mp4視頻中的語音對話,自動轉換為文本,並輸出到word文檔中。這裡第一篇,先完成視頻轉音頻處理。本項目全部代碼也已經全部開源到碼雲(https://gitee.com/coolpine/thomas),可直接下載試用。

總體技術架構

下圖是整體轉換流程:

  1. 先將mp4視頻文件,通過ffmpeg工具庫,批量轉換為pcm音頻文件(語音識別服務僅支持該格式)
  2. 基於百度雲的技術,將pcm文件上傳到百度對象存儲BOS中,並將日誌等記錄到本地mysql資料庫。
  3. pcm文件上傳完畢後,調用免費的語音識別(錄音轉寫)服務,創建離線錄音轉寫任務。
  4. 查詢轉寫成功的任務,並將相關轉寫結果存儲到本地mysql庫中。
  5. 基於docx4j庫,將資料庫中的錄音轉寫結果,導出為規範化的word文檔。

轉換結果示例

我們這裡實現的是將 《託馬斯和他的朋友們第18季》20集MP4視頻,最終轉換為一個word故事文檔:

下面是第一集具體對話文本表格:

視頻轉音頻

視頻轉音頻基於ffmpeg庫來實現。ffmpeg是一個強大的跨平臺音視頻記錄、轉換方案(官網說法:A complete, cross-platform solution to record, convert and stream audio and video)

ffmpeg主要是以命令行模式來實現音視頻轉換和處理,我們這裡實現的功能有:

  • 將mp4文件中片頭和片尾音樂剔除,截取中間片段。
  • 將截取後的mp4文件,轉換為pcm文件。
  • 基於ffplay驗證pcm可播放情況。

截取mp4文件中間片段的命令基本格式為:

ffmpeg -ss [start] -i [input] -t [duration] -c copy [output]
ffmpeg -ss [start] -i [input] -to [end] -c copy [output]
?
# 例如,以下是將t1801.mp4文件,截取從第30秒開始,截止到524秒,並保存為c1-1801.mp4文件:
ffmpeg -y -ss 30 -i t1801.mp4 -to 524 -c copy c1-1801.mp4

將mp4文件轉換為pcm音頻文件命令參數:

-i 輸入文件
-an 去除音頻流
-vn 去除視頻流
-acodec 設置音頻編碼
-f 強制指定輸入或輸出文件的編碼
-ac 設置音頻軌道數
-ar 設置音頻採用頻率
-y 不經過確認,直接覆蓋同名文件
?
# 例如,以下是將t1801.mp4文件,去除視頻流並用pcm_s16le進行音頻編碼,輸出文件也採用s16le編碼,同時音軌為1且採樣頻率為16000:
ffmpeg -i t1801.mp4 -vn -acodec pcm_s16le -f s16le -ac 1 -ar 16000 t1801.pcm

用ffplay播放pcm文件:

ffplay -ar 16000 -ac 1 -f s16le -i t1801.pcm

更多ffmpeg命令使用,參見官方文檔:https://ffmpeg.org/ffmpeg.html

Java音視頻處理

以上只是驗證了在命令行模式下,基於ffmpeg進行基本音視頻操作。因為要進行批量處理,我們還需要用編程的方式來調用ffmpeg:

  1. 基於org.bytedeco的ffmpeg和ffmpeg-platform來實現用java調用ffmpeg。
  2. 因為每集視頻的片頭和片尾歌曲時長基本固定,但每集視頻總時長不一樣,通過org.mp4parser的isoparser庫實現讀取每集總時長,動態拼裝轉換命令。

以下是引入的基本依賴:

&
&
&org.mp4parser&
&isoparser&
&1.9.41&
&
&
&
&org.bytedeco&
&ffmpeg&
&4.2.2-1.5.3&
&
&
&org.bytedeco&
&ffmpeg-platform&
&4.2.2-1.5.3&
&

以下是基於isoparser,讀取MP4文件的總時長(秒數):

public long readDuration(Path mp4Path) {
if (Files.notExists(mp4Path) || !Files.isReadable(mp4Path)) {
log.warn("文件路徑不存在或不可讀 {}", mp4Path);
return 0;
}
try {
IsoFile isoFile = new IsoFile(mp4Path.toFile());
long duration = isoFile.getMovieBox().getMovieHeaderBox().getDuration();
long timescale = isoFile.getMovieBox().getMovieHeaderBox().getTimescale();
return duration / timescale;
} catch (IOException e) {
log.error("讀取MP4文件時長出錯", e);
return 0;
}
}

以下是將MP4文件進行截取,並轉換為PCM文件:

/**
* 將單個PM4文件進行片頭和片尾歌曲刪除後,轉換為PCM文件
*
* @param mp4Path
* @param pcmDir
* @return 轉換完成後的pcm文件路徑
*/
public Optional& convertMP4toPCM(Path mp4Path, Path pcmDir) {
long seconds = readDuration(mp4Path);
if (seconds == 0) {
log.warn("文件總時長為0");
return Optional.empty();
}
String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
String endTime = String.valueOf(seconds - 100 - 30);
File src = mp4Path.toFile();
//在當前源mp4文件目錄下生成臨時文件
String mp4TempFile = src.getParent() + "" + System.currentTimeMillis() + ".mp4";
//基於ffmpeg進行截取
ProcessBuilder cutBuilder = new ProcessBuilder(ffmpeg, "-ss", "30", "-i", mp4Path.toAbsolutePath().toString(),
"-to", endTime, "-c", "copy", mp4TempFile);
try {
cutBuilder.inheritIO().start().waitFor();
} catch (InterruptedException | IOException e) {
log.error("ffmpeg截取MP4文件出錯", e);
return Optional.empty();
}
// 基於ffmpeg進行pcm轉換
// 基於輸入路徑的md5值來命名,也可以基於系統時間戳來命名
String pcmFile = pcmDir.resolve(DigestUtils.md5Hex(mp4Path.toString()) + ".pcm").toString();
ProcessBuilder pcmBuilder = new ProcessBuilder(ffmpeg, "-y", "-i", mp4TempFile, "-vn", "-acodec", "pcm_s16le",
"-f", "s16le", "-ac", "1", "-ar", "16000", pcmFile);
try {
//inheritIO是指將 子流程的IO與當前java流程的IO設置為相同
pcmBuilder.inheritIO().start().waitFor();
} catch (InterruptedException | IOException e) {
log.error("ffmpeg將mp4轉換為pcm時出錯", e);
return Optional.empty();
}
// 刪除MP4臨時文件
try {
Files.deleteIfExists(Paths.get(mp4TempFile));
} catch (IOException e) {
log.error("刪除mp4臨時文件出錯", e);
}
//返回pcm文件路徑
return Optional.of(pcmFile);
}

調用上述單個文件的處理方法,實現批量文件處理和轉換:

/**
* 批量將MP4文件轉換為PCM文件
*
* @param rootDir
* @param pcmDir
* @return 成功轉換的PCM文件數
*/
public int batchConvertMP4toPCM(Path rootDir, Path pcmDir) {
if (Files.notExists(rootDir) || !Files.isDirectory(rootDir)) {
log.warn("mp4文件目錄{}不存在", rootDir);
return 0;
}
?
if (Files.notExists(pcmDir)) {
//級聯創建目錄
try {
Files.createDirectories(pcmDir);
} catch (IOException e) {
log.error("創建文件夾出錯", e);
}
}
AtomicInteger pcmCount = new AtomicInteger(0);
//遍歷rootdir,獲取所有目錄下子目錄和文件
try {
Files.list(rootDir).forEach(path -&> {
if (Files.isDirectory(path)) {
//遞歸遍歷下級目錄
pcmCount.getAndAdd(batchConvertMP4toPCM(path, pcmDir));
}
if (Files.isRegularFile(path) Files.isReadable(path) path.getFileName()
.toString()
.endsWith("mp4")) {
Optional& pcmFile = this.convertMP4toPCM(path, pcmDir);
if (pcmFile.isPresent()) {
pcmCount.getAndIncrement();
}
}
});
} catch (IOException e) {
log.error("批量將MP4文件轉換為PCM文件出錯", e);
}
?
return pcmCount.get();
}

單個文件轉換調用測試:

@Test
void cutTest() {
String file = "D:\dev2\project\thomas\local\videos\t1801.mp4";
String pcmdir = "D:\dev2\project\thomas\local\videos\pcm";
Path path = Paths.get(file);
util.convertMP4toPCM(path, Paths.get(pcmdir));
}

批量文件轉換測試:

@Test
void batchTest() {
Path root = Paths.get("D:\dev2\project\thomas\local\videos\第18季");
Path pcmDir = Paths.get("D:\dev2\project\thomas\local\videos\pcm");
int pcmFiles = util.batchConvertMP4toPCM(root, pcmDir);
log.info("轉換出PCM文件數{}", pcmFiles);
}

至此,讀取mp4文件,轉換為pcm文件並剔除片頭和片尾,就基本完成了,接下來將為你介紹如何基於百度雲SDK和API實現語音轉錄。


視頻轉文本的落地場景有很多:課程視頻做筆記、會議視頻整理、演講視頻學習等等。視頻直接轉文字,可以節省很多時間,大大提高工作學習的效率。按照傳統的方法,將視頻轉為文字,需要先將音頻提取出來,再轉為文字。使用 AI 技術自動轉文本,可以大大節省時間,提高工作效率。

推薦使用雲貓轉碼的【轉文本】功能,可以直接將視頻轉為文字。支持幾乎所有視頻格式,兼容多種外語和方言,識別準確率高達 97%:

轉文本 - 雲貓轉碼 | 簡單智能、功能齊備的在線視頻工具?

yunmaovideo.com

手機端可以使用小程序雲貓轉碼,微信登錄可與電腦端實時同步所有數據,十分方便:

雲貓轉碼,是一款簡單智能、功能齊備的在線視頻處理工具,擁有智能字幕、轉文字、配音、消音(消除人聲、背景音樂)等視頻處理和 AI 功能。

編輯於 03-12繼續瀏覽內容知乎發現更大的世界打開Chrome繼續技術路漫漫技術路漫漫技術路漫漫兮,吾將上下而求索

本系列將介紹如何一步步實現將mp4視頻中的語音對話,自動轉換為文本,並輸出到word文檔中。這裡第一篇,先完成視頻轉音頻處理。本項目全部代碼也已經全部開源到碼雲(https://gitee.com/coolpine/thomas),可直接下載試用。

總體技術架構

下圖是整體轉換流程:

  1. 先將mp4視頻文件,通過ffmpeg工具庫,批量轉換為pcm音頻文件(語音識別服務僅支持該格式)
  2. 基於百度雲的技術,將pcm文件上傳到百度對象存儲BOS中,並將日誌等記錄到本地mysql資料庫。
  3. pcm文件上傳完畢後,調用免費的語音識別(錄音轉寫)服務,創建離線錄音轉寫任務。
  4. 查詢轉寫成功的任務,並將相關轉寫結果存儲到本地mysql庫中。
  5. 基於docx4j庫,將資料庫中的錄音轉寫結果,導出為規範化的word文檔。

轉換結果示例

我們這裡實現的是將 《託馬斯和他的朋友們第18季》20集MP4視頻,最終轉換為一個word故事文檔:

下面是第一集具體對話文本表格:

視頻轉音頻

視頻轉音頻基於ffmpeg庫來實現。ffmpeg是一個強大的跨平臺音視頻記錄、轉換方案(官網說法:A complete, cross-platform solution to record, convert and stream audio and video)

ffmpeg主要是以命令行模式來實現音視頻轉換和處理,我們這裡實現的功能有:

  • 將mp4文件中片頭和片尾音樂剔除,截取中間片段。
  • 將截取後的mp4文件,轉換為pcm文件。
  • 基於ffplay驗證pcm可播放情況。

截取mp4文件中間片段的命令基本格式為:

ffmpeg -ss [start] -i [input] -t [duration] -c copy [output]
ffmpeg -ss [start] -i [input] -to [end] -c copy [output]
?
# 例如,以下是將t1801.mp4文件,截取從第30秒開始,截止到524秒,並保存為c1-1801.mp4文件:
ffmpeg -y -ss 30 -i t1801.mp4 -to 524 -c copy c1-1801.mp4

將mp4文件轉換為pcm音頻文件命令參數:

-i 輸入文件
-an 去除音頻流
-vn 去除視頻流
-acodec 設置音頻編碼
-f 強制指定輸入或輸出文件的編碼
-ac 設置音頻軌道數
-ar 設置音頻採用頻率
-y 不經過確認,直接覆蓋同名文件
?
# 例如,以下是將t1801.mp4文件,去除視頻流並用pcm_s16le進行音頻編碼,輸出文件也採用s16le編碼,同時音軌為1且採樣頻率為16000:
ffmpeg -i t1801.mp4 -vn -acodec pcm_s16le -f s16le -ac 1 -ar 16000 t1801.pcm

用ffplay播放pcm文件:

ffplay -ar 16000 -ac 1 -f s16le -i t1801.pcm

更多ffmpeg命令使用,參見官方文檔:https://ffmpeg.org/ffmpeg.html

Java音視頻處理

以上只是驗證了在命令行模式下,基於ffmpeg進行基本音視頻操作。因為要進行批量處理,我們還需要用編程的方式來調用ffmpeg:

  1. 基於org.bytedeco的ffmpeg和ffmpeg-platform來實現用java調用ffmpeg。
  2. 因為每集視頻的片頭和片尾歌曲時長基本固定,但每集視頻總時長不一樣,通過org.mp4parser的isoparser庫實現讀取每集總時長,動態拼裝轉換命令。

以下是引入的基本依賴:

&
&
&org.mp4parser&
&isoparser&
&1.9.41&
&
&
&
&org.bytedeco&
&ffmpeg&
&4.2.2-1.5.3&
&
&
&org.bytedeco&
&ffmpeg-platform&
&4.2.2-1.5.3&
&

以下是基於isoparser,讀取MP4文件的總時長(秒數):

public long readDuration(Path mp4Path) {
if (Files.notExists(mp4Path) || !Files.isReadable(mp4Path)) {
log.warn("文件路徑不存在或不可讀 {}", mp4Path);
return 0;
}
try {
IsoFile isoFile = new IsoFile(mp4Path.toFile());
long duration = isoFile.getMovieBox().getMovieHeaderBox().getDuration();
long timescale = isoFile.getMovieBox().getMovieHeaderBox().getTimescale();
return duration / timescale;
} catch (IOException e) {
log.error("讀取MP4文件時長出錯", e);
return 0;
}
}

以下是將MP4文件進行截取,並轉換為PCM文件:

/**
* 將單個PM4文件進行片頭和片尾歌曲刪除後,轉換為PCM文件
*
* @param mp4Path
* @param pcmDir
* @return 轉換完成後的pcm文件路徑
*/
public Optional& convertMP4toPCM(Path mp4Path, Path pcmDir) {
long seconds = readDuration(mp4Path);
if (seconds == 0) {
log.warn("文件總時長為0");
return Optional.empty();
}
String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
String endTime = String.valueOf(seconds - 100 - 30);
File src = mp4Path.toFile();
//在當前源mp4文件目錄下生成臨時文件
String mp4TempFile = src.getParent() + "" + System.currentTimeMillis() + ".mp4";
//基於ffmpeg進行截取
ProcessBuilder cutBuilder = new ProcessBuilder(ffmpeg, "-ss", "30", "-i", mp4Path.toAbsolutePath().toString(),
"-to", endTime, "-c", "copy", mp4TempFile);
try {
cutBuilder.inheritIO().start().waitFor();
} catch (InterruptedException | IOException e) {
log.error("ffmpeg截取MP4文件出錯", e);
return Optional.empty();
}
// 基於ffmpeg進行pcm轉換
// 基於輸入路徑的md5值來命名,也可以基於系統時間戳來命名
String pcmFile = pcmDir.resolve(DigestUtils.md5Hex(mp4Path.toString()) + ".pcm").toString();
ProcessBuilder pcmBuilder = new ProcessBuilder(ffmpeg, "-y", "-i", mp4TempFile, "-vn", "-acodec", "pcm_s16le",
"-f", "s16le", "-ac", "1", "-ar", "16000", pcmFile);
try {
//inheritIO是指將 子流程的IO與當前java流程的IO設置為相同
pcmBuilder.inheritIO().start().waitFor();
} catch (InterruptedException | IOException e) {
log.error("ffmpeg將mp4轉換為pcm時出錯", e);
return Optional.empty();
}
// 刪除MP4臨時文件
try {
Files.deleteIfExists(Paths.get(mp4TempFile));
} catch (IOException e) {
log.error("刪除mp4臨時文件出錯", e);
}
//返回pcm文件路徑
return Optional.of(pcmFile);
}

調用上述單個文件的處理方法,實現批量文件處理和轉換:

/**
* 批量將MP4文件轉換為PCM文件
*
* @param rootDir
* @param pcmDir
* @return 成功轉換的PCM文件數
*/
public int batchConvertMP4toPCM(Path rootDir, Path pcmDir) {
if (Files.notExists(rootDir) || !Files.isDirectory(rootDir)) {
log.warn("mp4文件目錄{}不存在", rootDir);
return 0;
}
?
if (Files.notExists(pcmDir)) {
//級聯創建目錄
try {
Files.createDirectories(pcmDir);
} catch (IOException e) {
log.error("創建文件夾出錯", e);
}
}
AtomicInteger pcmCount = new AtomicInteger(0);
//遍歷rootdir,獲取所有目錄下子目錄和文件
try {
Files.list(rootDir).forEach(path -&> {
if (Files.isDirectory(path)) {
//遞歸遍歷下級目錄
pcmCount.getAndAdd(batchConvertMP4toPCM(path, pcmDir));
}
if (Files.isRegularFile(path) Files.isReadable(path) path.getFileName()
.toString()
.endsWith("mp4")) {
Optional& pcmFile = this.convertMP4toPCM(path, pcmDir);
if (pcmFile.isPresent()) {
pcmCount.getAndIncrement();
}
}
});
} catch (IOException e) {
log.error("批量將MP4文件轉換為PCM文件出錯", e);
}
?
return pcmCount.get();
}

單個文件轉換調用測試:

@Test
void cutTest() {
String file = "D:\dev2\project\thomas\local\videos\t1801.mp4";
String pcmdir = "D:\dev2\project\thomas\local\videos\pcm";
Path path = Paths.get(file);
util.convertMP4toPCM(path, Paths.get(pcmdir));
}

批量文件轉換測試:

@Test
void batchTest() {
Path root = Paths.get("D:\dev2\project\thomas\local\videos\第18季");
Path pcmDir = Paths.get("D:\dev2\project\thomas\local\videos\pcm");
int pcmFiles = util.batchConvertMP4toPCM(root, pcmDir);
log.info("轉換出PCM文件數{}", pcmFiles);
}

至此,讀取mp4文件,轉換為pcm文件並剔除片頭和片尾,就基本完成了,接下來將為你介紹如何基於百度雲SDK和API實現語音轉錄。


本系列將介紹如何一步步實現將mp4視頻中的語音對話,自動轉換為文本,並輸出到word文檔中。這裡第一篇,先完成視頻轉音頻處理。本項目全部代碼也已經全部開源到碼雲(https://gitee.com/coolpine/thomas),可直接下載試用。

總體技術架構

下圖是整體轉換流程:

  1. 先將mp4視頻文件,通過ffmpeg工具庫,批量轉換為pcm音頻文件(語音識別服務僅支持該格式)
  2. 基於百度雲的技術,將pcm文件上傳到百度對象存儲BOS中,並將日誌等記錄到本地mysql資料庫。
  3. pcm文件上傳完畢後,調用免費的語音識別(錄音轉寫)服務,創建離線錄音轉寫任務。
  4. 查詢轉寫成功的任務,並將相關轉寫結果存儲到本地mysql庫中。
  5. 基於docx4j庫,將資料庫中的錄音轉寫結果,導出為規範化的word文檔。

轉換結果示例

我們這裡實現的是將 《託馬斯和他的朋友們第18季》20集MP4視頻,最終轉換為一個word故事文檔:

下面是第一集具體對話文本表格:

視頻轉音頻

視頻轉音頻基於ffmpeg庫來實現。ffmpeg是一個強大的跨平臺音視頻記錄、轉換方案(官網說法:A complete, cross-platform solution to record, convert and stream audio and video)

ffmpeg主要是以命令行模式來實現音視頻轉換和處理,我們這裡實現的功能有:

  • 將mp4文件中片頭和片尾音樂剔除,截取中間片段。
  • 將截取後的mp4文件,轉換為pcm文件。
  • 基於ffplay驗證pcm可播放情況。

截取mp4文件中間片段的命令基本格式為:

ffmpeg -ss [start] -i [input] -t [duration] -c copy [output]
ffmpeg -ss [start] -i [input] -to [end] -c copy [output]
?
# 例如,以下是將t1801.mp4文件,截取從第30秒開始,截止到524秒,並保存為c1-1801.mp4文件:
ffmpeg -y -ss 30 -i t1801.mp4 -to 524 -c copy c1-1801.mp4

將mp4文件轉換為pcm音頻文件命令參數:

-i 輸入文件
-an 去除音頻流
-vn 去除視頻流
-acodec 設置音頻編碼
-f 強制指定輸入或輸出文件的編碼
-ac 設置音頻軌道數
-ar 設置音頻採用頻率
-y 不經過確認,直接覆蓋同名文件
?
# 例如,以下是將t1801.mp4文件,去除視頻流並用pcm_s16le進行音頻編碼,輸出文件也採用s16le編碼,同時音軌為1且採樣頻率為16000:
ffmpeg -i t1801.mp4 -vn -acodec pcm_s16le -f s16le -ac 1 -ar 16000 t1801.pcm

用ffplay播放pcm文件:

ffplay -ar 16000 -ac 1 -f s16le -i t1801.pcm

更多ffmpeg命令使用,參見官方文檔:https://ffmpeg.org/ffmpeg.html

Java音視頻處理

以上只是驗證了在命令行模式下,基於ffmpeg進行基本音視頻操作。因為要進行批量處理,我們還需要用編程的方式來調用ffmpeg:

  1. 基於org.bytedeco的ffmpeg和ffmpeg-platform來實現用java調用ffmpeg。
  2. 因為每集視頻的片頭和片尾歌曲時長基本固定,但每集視頻總時長不一樣,通過org.mp4parser的isoparser庫實現讀取每集總時長,動態拼裝轉換命令。

以下是引入的基本依賴:

&
&
&org.mp4parser&
&isoparser&
&1.9.41&
&
&
&
&org.bytedeco&
&ffmpeg&
&4.2.2-1.5.3&
&
&
&org.bytedeco&
&ffmpeg-platform&
&4.2.2-1.5.3&
&

以下是基於isoparser,讀取MP4文件的總時長(秒數):

public long readDuration(Path mp4Path) {
if (Files.notExists(mp4Path) || !Files.isReadable(mp4Path)) {
log.warn("文件路徑不存在或不可讀 {}", mp4Path);
return 0;
}
try {
IsoFile isoFile = new IsoFile(mp4Path.toFile());
long duration = isoFile.getMovieBox().getMovieHeaderBox().getDuration();
long timescale = isoFile.getMovieBox().getMovieHeaderBox().getTimescale();
return duration / timescale;
} catch (IOException e) {
log.error("讀取MP4文件時長出錯", e);
return 0;
}
}

以下是將MP4文件進行截取,並轉換為PCM文件:

/**
* 將單個PM4文件進行片頭和片尾歌曲刪除後,轉換為PCM文件
*
* @param mp4Path
* @param pcmDir
* @return 轉換完成後的pcm文件路徑
*/
public Optional& convertMP4toPCM(Path mp4Path, Path pcmDir) {
long seconds = readDuration(mp4Path);
if (seconds == 0) {
log.warn("文件總時長為0");
return Optional.empty();
}
String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
String endTime = String.valueOf(seconds - 100 - 30);
File src = mp4Path.toFile();
//在當前源mp4文件目錄下生成臨時文件
String mp4TempFile = src.getParent() + "" + System.currentTimeMillis() + ".mp4";
//基於ffmpeg進行截取
ProcessBuilder cutBuilder = new ProcessBuilder(ffmpeg, "-ss", "30", "-i", mp4Path.toAbsolutePath().toString(),
"-to", endTime, "-c", "copy", mp4TempFile);
try {
cutBuilder.inheritIO().start().waitFor();
} catch (InterruptedException | IOException e) {
log.error("ffmpeg截取MP4文件出錯", e);
return Optional.empty();
}
// 基於ffmpeg進行pcm轉換
// 基於輸入路徑的md5值來命名,也可以基於系統時間戳來命名
String pcmFile = pcmDir.resolve(DigestUtils.md5Hex(mp4Path.toString()) + ".pcm").toString();
ProcessBuilder pcmBuilder = new ProcessBuilder(ffmpeg, "-y", "-i", mp4TempFile, "-vn", "-acodec", "pcm_s16le",
"-f", "s16le", "-ac", "1", "-ar", "16000", pcmFile);
try {
//inheritIO是指將 子流程的IO與當前java流程的IO設置為相同
pcmBuilder.inheritIO().start().waitFor();
} catch (InterruptedException | IOException e) {
log.error("ffmpeg將mp4轉換為pcm時出錯", e);
return Optional.empty();
}
// 刪除MP4臨時文件
try {
Files.deleteIfExists(Paths.get(mp4TempFile));
} catch (IOException e) {
log.error("刪除mp4臨時文件出錯", e);
}
//返回pcm文件路徑
return Optional.of(pcmFile);
}

調用上述單個文件的處理方法,實現批量文件處理和轉換:

/**
* 批量將MP4文件轉換為PCM文件
*
* @param rootDir
* @param pcmDir
* @return 成功轉換的PCM文件數
*/
public int batchConvertMP4toPCM(Path rootDir, Path pcmDir) {
if (Files.notExists(rootDir) || !Files.isDirectory(rootDir)) {
log.warn("mp4文件目錄{}不存在", rootDir);
return 0;
}
?
if (Files.notExists(pcmDir)) {
//級聯創建目錄
try {
Files.createDirectories(pcmDir);
} catch (IOException e) {
log.error("創建文件夾出錯", e);
}
}
AtomicInteger pcmCount = new AtomicInteger(0);
//遍歷rootdir,獲取所有目錄下子目錄和文件
try {
Files.list(rootDir).forEach(path -&> {
if (Files.isDirectory(path)) {
//遞歸遍歷下級目錄
pcmCount.getAndAdd(batchConvertMP4toPCM(path, pcmDir));
}
if (Files.isRegularFile(path) Files.isReadable(path) path.getFileName()
.toString()
.endsWith("mp4")) {
Optional& pcmFile = this.convertMP4toPCM(path, pcmDir);
if (pcmFile.isPresent()) {
pcmCount.getAndIncrement();
}
}
});
} catch (IOException e) {
log.error("批量將MP4文件轉換為PCM文件出錯", e);
}
?
return pcmCount.get();
}

單個文件轉換調用測試:

@Test
void cutTest() {
String file = "D:\dev2\project\thomas\local\videos\t1801.mp4";
String pcmdir = "D:\dev2\project\thomas\local\videos\pcm";
Path path = Paths.get(file);
util.convertMP4toPCM(path, Paths.get(pcmdir));
}

批量文件轉換測試:

@Test
void batchTest() {
Path root = Paths.get("D:\dev2\project\thomas\local\videos\第18季");
Path pcmDir = Paths.get("D:\dev2\project\thomas\local\videos\pcm");
int pcmFiles = util.batchConvertMP4toPCM(root, pcmDir);
log.info("轉換出PCM文件數{}", pcmFiles);
}

至此,讀取mp4文件,轉換為pcm文件並剔除片頭和片尾,就基本完成了,接下來將為你介紹如何基於百度雲SDK和API實現語音轉錄。


視頻編輯軟體或者播放器工具 提取音頻文件

再用類似的音轉文軟體或者網站轉

極簡字幕 語音轉字幕 視頻轉字幕 自動字幕 語音轉文字 視頻轉文字 字幕轉配音 字幕翻譯 自動時間軸?

www.yinzhuanwen.com圖標

大概用途是做字幕之類吧


推薦閱讀:
相關文章