You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在R中通过reticulate调用guano-py完成WAV的GUANO元数据写入?

批量处理相机陷阱MP4:提取WAV音频并嵌入GUANO元数据

需求概述

  • 批量处理数千个相机陷阱生成的.MP4文件
  • 提取音频为WAV格式(适配Kaleidoscope lite等声学分析软件)
  • 生成GUANO标准元数据并嵌入WAV,核心是提取MP4的创建日期作为元数据字段
  • 优先用R实现自动化,Python方案也可

已尝试的操作

  1. FFmpeg批量提取音频:用命令复制元数据,但存在编码适配隐患
system(sprintf("ffmpeg -i  ./data/input/my_file.MP4  -map_metadata 0 -acodec copy -y ./data/output/my_file.wav"))
  1. R的guano包:仅支持读取含GUANO元数据的文件,无编辑/写入能力
read.guano('my_file.WAV')
  1. R中通过reticulate调用guano-py:可读取并编辑GUANO对象,但无法完成写入操作。Python中gfile.write()可正常保存,但R中尝试py_run_string("gfile.write()")和guano$write("gfile")均报错。

解决方案

1. 修复R中reticulate调用guano-py的写入问题

问题出在reticulate的对象引用方式——不能用字符串引用Python对象,要直接调用R中已创建的GUANO对象的方法。具体步骤:

第一步:安装依赖

  • R中安装文件操作和Python交互工具:
install.packages(c("reticulate", "fs"))
  • 通过reticulate安装Python的guano包:
reticulate::py_install("guano")

第二步:正确的读取/编辑/写入代码

library(reticulate)
library(fs)

# 导入Python的guano模块
guano <- import("guano")

# 读取已提取的WAV文件
wav_path <- "./data/output/my_file.wav"
gfile <- guano$GuanoFile(wav_path)

# 编辑元数据(示例:添加备注)
gfile$__setitem__("Note", "Camera trap audio extract")

# 关键:直接调用对象的write方法保存修改
gfile$write()

提示:如果不想覆盖原文件,可传入新路径:gfile$write("./data/output/my_file_guano.wav")

2. 完整自动化流程(含MP4创建日期提取)

步骤1:FFmpeg正确提取WAV音频

原命令中-acodec copy可能导致编码不兼容(MP4音频多为AAC,WAV需要PCM编码),替换为标准PCM参数:

# 单文件示例
input_mp4 <- "./data/input/my_file.MP4"
output_wav <- "./data/output/my_file.wav"
system(sprintf(
  "ffmpeg -i %s -vn -acodec pcm_s16le -ar 44100 -ac 2 -map_metadata 0 -y %s",
  shQuote(input_mp4), shQuote(output_wav)
))

参数说明:

  • -vn:忽略视频流
  • -acodec pcm_s16le:指定WAV标准的PCM 16位小端编码
  • -ar 44100:采样率44.1kHz(可按需调整)
  • -ac 2:双声道(单声道用-ac 1)

步骤2:提取MP4的创建日期

优先用exiftool提取MP4原始创建时间(比系统文件时间更准确):

# 确保系统已安装exiftool,然后提取日期
creation_date <- system(sprintf('exiftool -CreateDate -d "%%Y-%%m-%%dT%%H:%%M:%%SZ" -s3 %s', shQuote(input_mp4)), intern = TRUE)

步骤3:嵌入GUANO元数据

将提取的日期写入GUANO标准字段Recording Start:

# 读取WAV的GUANO对象
gfile <- guano$GuanoFile(output_wav)

# 设置GUANO标准元数据
gfile$__setitem__("Recording Start", creation_date)
gfile$__setitem__("Device Type", "Camera Trap")
gfile$__setitem__("Source File", path_file(input_mp4))

# 保存修改
gfile$write()

步骤4:批量处理脚本

将上述步骤封装为函数,批量处理整个文件夹的MP4:

library(reticulate)
library(fs)

# 初始化Python环境
guano <- import("guano")

# 批量处理函数
process_camera_trap_mp4 <- function(input_dir, output_dir) {
  # 创建输出目录
  dir_create(output_dir, recurse = TRUE)
  
  # 获取所有MP4文件(忽略大小写)
  mp4_files <- dir_ls(input_dir, regexp = "\\.MP4$", ignore.case = TRUE)
  
  for (mp4_path in mp4_files) {
    # 生成输出WAV路径
    wav_filename <- path_ext_set(path_file(mp4_path), "wav")
    wav_path <- path(output_dir, wav_filename)
    
    # 1. FFmpeg提取WAV
    system(sprintf(
      "ffmpeg -i %s -vn -acodec pcm_s16le -ar 44100 -ac 2 -map_metadata 0 -y %s",
      shQuote(mp4_path), shQuote(wav_path)
    ))
    
    # 2. 提取MP4创建日期
    creation_date <- system(sprintf('exiftool -CreateDate -d "%%Y-%%m-%%dT%%H:%%M:%%SZ" -s3 %s', shQuote(mp4_path)), intern = TRUE)
    
    # 3. 嵌入GUANO元数据
    gfile <- guano$GuanoFile(wav_path)
    gfile$__setitem__("Recording Start", creation_date)
    gfile$__setitem__("Device Type", "Camera Trap")
    gfile$__setitem__("Source File", path_file(mp4_path))
    gfile$write()
    
    cat(sprintf("处理完成:%s\n", path_file(mp4_path)))
  }
}

# 调用函数
process_camera_trap_mp4("./data/input", "./data/output")

备选Python方案

如果R的reticulate调用仍有问题,可直接用Python实现完整流程:

import os
import guano
import subprocess

def process_mp4(input_path, output_dir):
    # 生成WAV路径
    wav_filename = os.path.splitext(os.path.basename(input_path))[0] + ".wav"
    wav_path = os.path.join(output_dir, wav_filename)
    
    # FFmpeg提取WAV
    ffmpeg_cmd = [
        "ffmpeg", "-i", input_path,
        "-vn", "-acodec", "pcm_s16le", "-ar", "44100", "-ac", "2",
        "-map_metadata", "0", "-y", wav_path
    ]
    subprocess.run(ffmpeg_cmd, check=True)
    
    # 提取创建日期
    exif_cmd = [
        "exiftool", "-CreateDate", "-d", "%Y-%m-%dT%H:%M:%SZ", "-s3", input_path
    ]
    creation_date = subprocess.run(exif_cmd, capture_output=True, text=True).stdout.strip()
    
    # 嵌入GUANO元数据
    with guano.GuanoFile(wav_path, mode="r+") as gfile:
        gfile["Recording Start"] = creation_date
        gfile["Device Type"] = "Camera Trap"
        gfile["Source File"] = os.path.basename(input_path)

# 批量处理
input_dir = "./data/input"
output_dir = "./data/output"
os.makedirs(output_dir, exist_ok=True)

for filename in os.listdir(input_dir):
    if filename.lower().endswith(".mp4"):
        input_path = os.path.join(input_dir, filename)
        process_mp4(input_path, output_dir)
        print(f"处理完成:{filename}")

内容的提问来源于stack exchange,提问作者Quentin Dubois

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 11:20:58