如何提取MVIMG文件中的照片/视频组件?

16
谷歌Pixel 2和可能其他手机都可以拍摄"动态照片"。这些照片保存为MVIMG格式并且相对较大。
我正在寻找一种方法来删除/提取视频。
到目前为止,我找到了一个有希望的exif标签。
$ exiftool -xmp:all MVIMG_123.jpg
XMP Toolkit                     : Adobe XMP Core 5.1.0-jc003
Micro Video                     : 1
Micro Video Version             : 1
Micro Video Offset              : 4032524

我以为视频会出现在指定的偏移量处,但这行不通:

$ dd if=MVIMG_123.jpg of=video.mp4 bs=4032524 skip=1
$ file video.mp4
video.mp4: data

是否有任何记录嵌入的资源的资料? 是否有任何工具可以移除/提取视频吗?


稍微相关:任何Linux GUI图像查看器可以显示这些视频吗? - Joachim Breitner
4个回答

17

我找到了https://github.com/cliveontoast/GoMoPho,该工具可以扫描mp4头并转储视频。

我们也可以通过扫描MP4头(实际文件开始4个字节之前)中的ftypmp4来执行相同的操作:

因此,要提取视频:

for i in MVIMG*.jpg; do \
  ofs=$(grep -F --byte-offset --only-matching --text ftypmp4 "$i"); \
  ofs=${ofs%:*}; \
  [[ $ofs ]] && dd "if=$i" "of=${i%.jpg}.mp4" bs=$((ofs-4)) skip=1; \
done

删除视频:

for i in MVIMG*.jpg; do \
  ofs=$(grep -F --byte-offset --only-matching --text ftypmp4 "$i"); \
  ofs=${ofs%:*}; \
  [[ $ofs ]] && truncate -s $((ofs-4)) "$i"; \
done

1
很好地使用了 grepdd :-) - Mark Setchell
我已经尝试了上面提到的GoMoPho开源控制台应用程序,并且它可以完美地处理由Google Pixel 2 XL捕获的移动图像。谢谢! - Adrian Ciura
5
似乎 Android 12 中有所变化。我的 Pixel 4a 生成的动态图像,MP4 的偏移量为 ftypisom - aorth
4
为了兼容两种情况,请使用 for i in PXL*.MP.jpg MVIMG*.jpg;grep --byte-offset --only-matching --text "ftypmp4\|ftypisom" "$i"(由于or模式,不要使用-F)。 - Perseids

6

EXIF标签很有用,但偏移量是相对于文件结尾的。mp4文件嵌入在以下位置:

[file_size-micro_video_offset, file_size)

例如:

$ exiftool -xmp:all MVIMG_123.jpg
XMP Toolkit                     : Adobe XMP Core 5.1.0-jc003
Micro Video                     : 1
Micro Video Version             : 1
Micro Video Offset              : 2107172
Micro Video Presentation Timestamp Us: 966280
$ python -c 'import os; print os.path.getsize("MVIMG_123.jpg") - 2107172'
3322791
$ dd if=MVIMG_123.jpg of=video.mp4 bs=3322791 skip=1
$ file video.mp4 
video.mp4: ISO Media, MP4 v2 [ISO 14496-14]

6

这篇文章开头的非Perl脚本在我的Linux系统上运行良好。我将它们合并成一个单一的脚本,保留了输入文件(例如MVIMG_20191216_153039.jpg),并创建了两个输出文件(例如IMG_20191216_153039.jpg和IMG_20191216_153039.mp4):

#!/bin/bash
# extract-mvimg: Extract .mp4 video and .jpg still image from a Pixel phone
# camera "motion video" file with a name like MVIMG_20191216_153039.jpg
# to make files like IMG_20191216_153039.jpg and IMG_20191216_153039.mp4
#
# Usage: extract-mvimg MVIMG*.jpg [MVIMG*.jpg...]

for srcfile
do
  case "$srcfile" in
  MVIMG_*_*.jpg) ;;
  *)
    echo "extract-mvimg: skipping '$srcfile': not an MVIMG*.jpg file?" 2>&1
    continue
    ;;
  esac

  # Get base filename: strip leading MV and trailing .jpg
  # Example: MVIMG_20191216_153039.jpg becomes IMG_20191216_153039
  basefile=${srcfile#MV}
  basefile=${basefile%.jpg}

  # Get byte offset. Example output: 2983617:ftypmp4
  offset=$(grep -F --byte-offset --only-matching --text ftypmp4 "$srcfile")
  # Strip trailing text. Example output: 2983617
  offset=${offset%:*}

  # If $offset isn't an empty string, create .mp4 file and
  # truncate a copy of input file to make .jpg file.
  if [[ $offset ]]
  then
    dd status=none "if=$srcfile" "of=${basefile}.mp4" bs=$((offset-4)) skip=1
    cp -ip "$srcfile" "${basefile}.jpg" || exit 1
    truncate -s $((offset-4)) "${basefile}.jpg"
  else
    echo "extract-mvimg: can't find ftypmp4 in $srcfile; skipping..." 2>&1
  fi
done

使用 status=none 参数可以抑制 dd 命令输出 "1+1 records in" 和 "1+1 records out" 状态信息。如果您的 dd 不支持此参数,可以将其删除。


1
针对Android 12,将“ftypmp4”更改为“ftypisom”。或者只需使用“ftyp”以获得最大兼容性。 - pucky124
有趣的是,我正在检查来自Android 9的一些MVIMG文件,其头部是“ftypiso6”。也许使用“ftyp”是一个好建议。 - aorth

4

上述建议使用grep -F --byte-offset ...dd在macOS High Sierra上对我不起作用,因为/usr/bin/grep输出了错误的偏移量——我猜它产生了包含单词ftypmp4的"行"的偏移量,即上一个LF字符加一的位置。我可能猜错了,但无论如何,这是我的解决方案:

for i in MVIMG*.jpg; do \
    perl -0777 -ne 's/^.*(....ftypmp4.*)$/$1/s && print' "$i" >"${i%.jpg}.mp4"; \
done

这里利用了perl一次读取整个文件并将其视为一个大字符串的能力。如果没有至少四个前导字节的ftypmp4存在,则会创建一个空文件;如果有多个,则提取最后一个。
类似地,要从所有文件中删除视频:
for i in MVIMG*.jpg; do \
    perl -0777 -pi -e 's/^(.*?)....ftypmp4.*$/$1/s' "$i"; \
done

这个功能使用了perl的原地编辑特性。在第一次出现ftypmp4及其前四个字节后的所有内容都被剪切掉。如果没有出现,文件将被重写为原样。

(可能需要在环境中设置PERLIO=raw和/或取消区域设置相关变量以避免UTF-8解释,因为二进制文件可能包含违反UTF-8组成规则的字节序列。但是,在我对各种MVIMG文件进行测试时,没有出现任何此类问题。)


我在我的Vagrant Ubuntu Buster盒子上也遇到了“grep”建议的同样问题。这个答案对我有用,使用了“perl”命令。谢谢! - ChrisPrime

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接