Commit 4c91576

benny-dou <60535774+benny-dou@users.noreply.github.com>
2025-10-23 07:17:53
fix(ffmpeg): use re-encoding for ffmpeg cut to improve accuracy
1 parent 6bc8844
Changed files (1)
src
others
src/others/ffmpeg.py
@@ -36,9 +36,6 @@ async def ffmpeg_cut(client: Client, message: Message, **kwargs):
 - `{PREFIX.FFMPEG_CUT} 10 20`: 第10秒至第20秒
 - `{PREFIX.FFMPEG_CUT} 10 1:30`: 第10秒至1分30秒
 - `{PREFIX.FFMPEG_CUT} 1:30.25 300`: 第1分30秒250豪秒至300秒
-
-⚠️注意: 切片使用ffmpeg对视频流或音频流进行copy, 不会重新进行编码
-copy操作使用关键帧作为分割点, 因此切片的开始或结束位置并非精确匹配请求时间点
 """
     if not startswith_prefix(message.content, prefix=PREFIX.FFMPEG_CUT):
         return
@@ -64,16 +61,18 @@ copy操作使用关键帧作为分割点, 因此切片的开始或结束位置
     if not Path(fpath).is_file():
         await modify_progress(text="❌媒体文件下载失败", force_update=True, **kwargs)
         return
+    vinfo = await parse_media_info(fpath)
     ext = Path(fpath).suffix
     start_time = sanitize_time(times[0])
     out_path = Path(DOWNLOAD_DIR).joinpath(f"ffmpeg-cut-{info['file_name']}").as_posix()
     if len(times) == 1:
-        cmd = f"✅文件下载完成 ({readable_size(path=fpath)})\n✂️执行切片命令:\n`ffmpeg -ss {start_time} -i input{ext} -c copy output{ext}`"
-        ffmpeg = FFmpeg().option("y").input(fpath, ss=start_time).output(out_path, acodec="copy", vcodec="copy")
+        end_time = sanitize_time(vinfo["duration"])
+        cmd = f"✅文件下载完成 ({readable_size(path=fpath)})\n✂️执行切片命令:\n`ffmpeg -ss {start_time} -i input{ext} -c:v libx264 -c:a aac output{ext}`"
+        ffmpeg = FFmpeg().option("y").input(fpath, ss=start_time).output(out_path, acodec="aac", vcodec="libx264")
     else:
         end_time = sanitize_time(times[1])
-        cmd = f"✅文件下载完成 ({readable_size(path=fpath)})\n✂️执行切片命令:\n`ffmpeg -ss {start_time} -to {end_time} -i input{ext} -c copy output{ext}`"
-        ffmpeg = FFmpeg().option("y").input(fpath, ss=start_time, to=end_time).output(out_path, acodec="copy", vcodec="copy")
+        cmd = f"✅文件下载完成 ({readable_size(path=fpath)})\n✂️执行切片命令:\n`ffmpeg -ss {start_time} -to {end_time} -i input{ext} -c:v libx264 -c:a aac output{ext}`"
+        ffmpeg = FFmpeg().option("y").input(fpath, ss=start_time, to=end_time).output(out_path, acodec="aac", vcodec="libx264")
 
     await modify_progress(text=cmd, force_update=True, **kwargs)
 
@@ -103,7 +102,10 @@ copy操作使用关键帧作为分割点, 因此切片的开始或结束位置
     """
     minfo = await parse_media_info(out_path)
     media = [{"video": out_path, "thumb": generate_cover(fpath)}] if info["mtype"] == "video" else [{"audio": out_path, "thumb": generate_cover(fpath)}]
-    caption = f"✂️切片大小: {minfo['filesize']}\n⏳切片时长: {seconds_to_time(minfo['duration'])}\n🎬视频编码: {minfo['video_codec']}\n🎧音频编码: {minfo['audio_codec']}"
+    start = start_time.removeprefix("00:")
+    end = end_time.removeprefix("00:")
+    duration = f"{minfo['raw_duration']:.3f}".rstrip("0").rstrip(".")
+    caption = f"✂️切片时间: {start} - {end}\n⏳切片时长: {duration}秒\n💾切片大小: {minfo['filesize']}"
     logger.success("✅切片完成\n" + caption)
     await send2tg(client, message, texts=caption, media=media, **kwargs)
     await modify_progress(del_status=True, **kwargs)
@@ -120,7 +122,7 @@ def sanitize_time(t: str) -> str:
     ctx = getcontext()
     ctx.prec = 3
     ctx.rounding = ROUND_DOWN
-    parts = t.split(":")
+    parts = t.replace(":", ":").split(":")  # noqa: RUF001
     hours = 0
     minutes = 0
     seconds = Decimal(0)