作者:RS迷途小书童
博客地址:https://rsran.blog.csdn.net/
标签:
大疆DJIPythonffmpegSRT字幕无人机遥测M3TD航测
文章目录
- 前言
- 原理说明
- 环境与依赖准备
- 完整Python源码
- 代码运行输出示例
- nb_frames元数据字段说明
- [流索引说明,‑map 0:3含义](#流索引说明,‑map 0:3含义)
- 适用范围与局限性
- 总结
1. 前言
大疆M3TD、M300等工业无人机录制MP4视频时,文件内部封装多路数据流:H.264视频流、djmd元数据流、dbgi二进制遥测流、mov_text(tx3g)内嵌字幕流。
mov_text字幕轨道存储可读SRT格式遥测信息,包含GPS经纬度、相对/绝对海拔、云台姿态、焦距、变焦系数等传感器数据。在航测、摄影测量、无人机航迹解算、视频‑POS匹配场景中经常需要导出该字幕。
直接使用ffmpeg可以导出SRT,但很多使用者无法判断导出后的SRT文件是否完整。本套Python脚本基于ffprobe+ffmpeg实现三件事:
- 读取MP4容器、视频流元信息:时长、平均帧率;
- 获取元数据中标注的视频总帧数、字幕轨道总帧数
nb_frames; - 导出SRT字幕,统计磁盘上SRT真实字幕条目,与元数据标注帧数做比对,完成完整性校验。
校验逻辑:当元数据字幕轨道帧数 = SRT实际条目数,代表字幕完整导出。
2. 原理说明
- 调用
ffprobe(ffmpeg自带工具)读取MP4元数据,输出JSON结构化结果,解析得到容器时长、视频流时长、帧率、nb_frames; - 调用
ffmpeg,通过‑map指定mov_text字幕流,直接输出标准SRT字幕文件; - 遍历生成的SRT文件,统计字幕序号行数量,得到真实字幕条目;
- 将元数据标注帧数与实际SRT条目对比,完成完整性校验。
nb_frames:Number of frames,存储在MP4 moov盒子内的元数据字段,仅读取文件头部即可获取,不需要解码整个视频。
3. 环境与依赖准备
- Python 3.7+(Conda虚拟环境同样支持,仅使用标准库
json、subprocess,无需pip安装第三方包) - FFmpeg完整构建包,必须同时包含
ffmpeg.exe与ffprobe.exe
下载地址:https://www.gyan.dev/ffmpeg/builds/
解压后使用bin目录下可执行文件,填写完整绝对路径到代码。
测试机型:DJI M3TD,其他支持内嵌mov_text字幕的大疆工业机型均可适配。
4. 完整Python源码
python
# -*- coding: utf-8 -*-
"""
@Time:2026/10/07 20:02
@Auth:RS迷途小书童
@File:DJ SRT Extracting.py
@IDE:PyCharm
@Purpose:大疆无人机视频 SRT字幕日志提取
@Web:博客地址: [https://rsran.blog.csdn.net/](https://rsran.blog.csdn.net/)
@Attention:
1.依赖ffmpeg.exe,下载地址:[https://www.gyan.dev/ffmpeg/builds/](https://www.gyan.dev/ffmpeg/builds/)
2.注意核对视频帧数和SRT字幕轨道帧数是否一致
"""
import json
import subprocess
def parse_fraction(s: str):
if s is None or str(s).strip() in ("", "N/A"):
return None
s = str(s).strip()
if "/" in s:
a, b = s.split("/")
return float(a) / float(b)
else:
return float(s)
def get_video_info(ffmpeg_exe: str, video_path: str):
ffprobe_exe = ffmpeg_exe.replace("ffmpeg.exe", "ffprobe.exe")
cmd = [
ffprobe_exe,
"-v", "error",
"-print_format", "json",
"-show_format",
"-show_streams",
video_path
]
proc = subprocess.run(cmd, capture_output=True, encoding="utf-8", errors="ignore")
if proc.returncode != 0:
print("⚠️获取视频元信息失败:", proc.stderr)
return None
try:
raw = json.loads(proc.stdout)
except json.JSONDecodeError:
print("⚠️ffprobe JSON解析失败")
return None
streams = raw.get("streams", [])
video_stream = None
subtitle_stream = None
for st in streams:
idx = st.get("index")
codec_type = st.get("codec_type")
tag_string = st.get("codec_tag_string", "")
if idx == 0 and codec_type == "video":
video_stream = st
if codec_type == "subtitle" and tag_string == "tx3g":
subtitle_stream = st
if video_stream is None:
return None
container_dur = parse_fraction(raw["format"].get("duration"))
video_dur = parse_fraction(video_stream.get("duration"))
avg_fps = parse_fraction(video_stream.get("avg_frame_rate"))
video_meta_frames = None
sub_meta_frames = None
nbf_vid = video_stream.get("nb_frames")
if nbf_vid and nbf_vid != "N/A":
video_meta_frames = int(nbf_vid)
if subtitle_stream is not None:
nbf_sub = subtitle_stream.get("nb_frames")
if nbf_sub and nbf_sub != "N/A":
sub_meta_frames = int(nbf_sub)
return {
"container_duration_sec": round(container_dur, 3) if container_dur else None,
"video_stream_duration_sec": round(video_dur, 3) if video_dur else None,
"avg_fps": round(avg_fps, 3) if avg_fps else None,
"video_meta_total_frames": video_meta_frames,
"subtitle_meta_nb_frames": sub_meta_frames
}
def count_srt_entries(srt_file_path: str) -> int:
count = 0
try:
with open(srt_file_path, "r", encoding="utf-8") as f:
for line in f:
line_strip = line.strip()
if line_strip.isdigit():
count += 1
except FileNotFoundError:
return 0
return count
# SRT提取主函数:视频信息、提取、验证
def extract_dji_mov_text_srt(ffmpeg_exe: str, video_path: str, out_srt: str):
vid_info = get_video_info(ffmpeg_exe, video_path)
if vid_info is not None:
print("-----------------视频元数据信息【ffprobe读取】-----------------")
print(f"MP4容器总时长(sec): {vid_info['container_duration_sec']}")
print(f"视频流实际时长(sec): {vid_info['video_stream_duration_sec']}")
print(f"平均帧率(fps): {vid_info['avg_fps']}")
print(f"元数据标注视频总帧数: {vid_info['video_meta_total_frames']}")
print(f"元数据标注字幕轨道帧数: {vid_info['subtitle_meta_nb_frames']}")
print("-----------------视频元数据信息【ffprobe读取】-----------------\n")
cmd = [
ffmpeg_exe,
"-i", video_path,
"-map", "0:3",
"-y",
out_srt
]
proc = subprocess.run(cmd, capture_output=True)
if proc.returncode == 0:
print(f"✅ 执行完毕,输出文件路径:{out_srt}")
real_srt_count = count_srt_entries(out_srt)
print(f"📄 磁盘上srt文件实际字幕条目数:{real_srt_count} 条")
else:
print("❌ ffmpeg执行出错")
print(proc.stderr.decode("utf8", errors="ignore"))
if __name__ == "__main__":
# 修改为你本机实际路径
FFMPEG_EXE = r"D:\ffmpeg-9.0-full_build\bin\ffmpeg.exe"
INPUT_VIDEO = r"D:\Work Data\DJI_video.mp4"
OUTPUT_SRT = r"D:\Work Data\output.srt"
extract_dji_mov_text_srt(FFMPEG_EXE, INPUT_VIDEO, OUTPUT_SRT)
5. 代码运行输出示例
-----------------视频元数据信息【ffprobe读取】-----------------
MP4容器总时长(sec): 343.777
视频流实际时长(sec): 343.777
平均帧率(fps): 29.97
元数据标注视频总帧数: 10303
元数据标注字幕轨道帧数: 10303
-----------------视频元数据信息【ffprobe读取】-----------------
✅ 执行完毕,输出文件路径:D:\Work Data\无人机视频三维可视化\示例数据\ffmpeg_python_out.srt
📄 磁盘上srt文件实际字幕条目数:10303 条
当元数据字幕轨道帧数与SRT实际条目相等,代表字幕完整导出。
6. nb_frames元数据字段说明
nb_frames是MP4文件moov盒子内记录的帧计数字段:
- ffprobe仅读取文件头部元数据,不需要解码视频即可拿到该数值;
- 视频流
nb_frames代表元数据记录的视频总帧; - 字幕流
nb_frames代表元数据记录的mov_text字幕总帧; - 本脚本把元数据值和磁盘SRT真实条目做比对,作为完整性校验依据。
注意:部分固件、部分视频,元数据中
nb_frames字段可能为空,此时无法依靠该字段校验。
7. 流索引说明,‑map 0:3含义
DJI M3TD生成MP4内部流排布:
| 索引 | 流类型 | 说明 |
|---|---|---|
| 0:0 | video | H.264主视频流 |
| 0:1 | data | djmd大疆元数据 |
| 0:2 | data | dbgi完整二进制遥测流 |
| 0:3 | subtitle | mov_text(tx3g)内嵌字幕流,提取目标 |
| 0:4 | video | MJPEG缩略图流 |
‑map 0:3:选取输入文件0的索引为3的字幕流输出。
⚠️不同机型、固件版本流索引可能发生变化。如果报错找不到字幕流,执行下面命令查看全部流信息,确认tx3g字幕流真实index。
cmd
ffprobe -v error -print_format json -show_streams "你的视频.mp4"
8. 适用范围与局限性
✅ 适用场景
- 大疆工业无人机录制、开启内嵌字幕的MP4视频;
- 需要导出mov_text内嵌SRT遥测,用于航迹分析、视频POS匹配、摄影测量预处理;
- 需要对导出SRT做自动化完整性校验。
❌ 局限性
- mov_text字幕的采样率受机型固件设置决定;
- ffmpeg无法解析dbgi私有二进制遥测流;
- 个别固件版本MP4,字幕流索引不是0:3,需要手动修改map参数;
- 部分视频元数据不存在
nb_frames字段,无法做帧数比对校验。
9. 总结
- 脚本完成:读取MP4元信息、ffmpeg导出mov_text字幕、统计SRT真实条目、元数据‑实际条目比对校验;
- 完整性判断标准:字幕轨道元数据帧数等于SRT实际条目数,说明字幕完整;
- mov_text字幕提供可读的GPS、姿态、焦距信息,适合快速解析;如需更高频率原始遥测,可使用SD卡原始日志或研究dbgi流解析。
如果文章对你有帮助,欢迎点赞收藏,问题可在评论区交流。
CSDN标签:
大疆 DJI Python ffmpeg SRT字幕 无人机遥测 M3TD 航测