2

One may losslessly concatenate two MP4 files using FFmpeg as follows:

ffmpeg -safe 0 -f concat -i list.txt -c copy output.mp4

with list.txt:

file 'C:\file1.mp4'
file 'C:\file2.mp4'

However, if the input files C:\file1.mp4 and C:\file2.mp4 have telemetry information, output.mp4 won't have it, as ffprobe can confirm. In my case, C:\file1.mp4 and C:\file2.mp4 have GPMF™ formatted telemetry data used within GoPro® cameras.

How can I losslessly concatenate two MP4 files and keep the telemetry information using FFmpeg?


ffprobe ouput for one of the input file with telemetry information:

C:\>ffprobe GX010013.MP4
ffprobe version 5.0.1-full_build-www.gyan.dev Copyright (c) 2007-2022 the FFmpeg developers
  built with gcc 11.2.0 (Rev7, Built by MSYS2 project)
  configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-bzlib --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libdav1d --enable-libdavs2 --enable-libuavs3d --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-mediafoundation --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-liblensfun --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libshaderc --enable-vulkan --enable-libplacebo --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint
  libavutil      57. 17.100 / 57. 17.100
  libavcodec     59. 18.100 / 59. 18.100
  libavformat    59. 16.100 / 59. 16.100
  libavdevice    59.  4.100 / 59.  4.100
  libavfilter     8. 24.100 /  8. 24.100
  libswscale      6.  4.100 /  6.  4.100
  libswresample   4.  3.100 /  4.  3.100
  libpostproc    56.  3.100 / 56.  3.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'GX010013.MP4':
  Metadata:
    major_brand     : mp41
    minor_version   : 538120216
    compatible_brands: mp41
    creation_time   : 2022-07-16T20:36:19.000000Z
    firmware        : H21.01.01.42.00
  Duration: 00:08:54.55, start: 0.000000, bitrate: 59971 kb/s
  Stream #0:0[0x1](eng): Video: hevc (Main) (hvc1 / 0x31637668), yuvj420p(pc, bt709), 5312x2988 [SAR 1:1 DAR 16:9], 59702 kb/s, 59.94 fps, 59.94 tbr, 60k tbn (default)
    Metadata:
      creation_time   : 2022-07-16T20:36:19.000000Z
      handler_name    : GoPro H.265
      vendor_id       : [0][0][0][0]
      encoder         : GoPro H.265 encoder
      timecode        : 20:35:05:32
  Stream #0:1[0x2](eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 189 kb/s (default)
    Metadata:
      creation_time   : 2022-07-16T20:36:19.000000Z
      handler_name    : GoPro AAC
      vendor_id       : [0][0][0][0]
      timecode        : 20:35:05:32
  Stream #0:2[0x3](eng): Data: none (tmcd / 0x64636D74) (default)
    Metadata:
      creation_time   : 2022-07-16T20:36:19.000000Z
      handler_name    : GoPro TCD
      timecode        : 20:35:05:32
  Stream #0:3[0x4](eng): Data: bin_data (gpmd / 0x646D7067), 60 kb/s (default)
    Metadata:
      creation_time   : 2022-07-16T20:36:19.000000Z
      handler_name    : GoPro MET
Unsupported codec with id 0 for input stream 2
Unsupported codec with id 98314 for input stream 3

https://github.com/gopro/gpmf-parser gives an overview of the GoPro's MP4 structure:

Telemetry carrying MP4 files will have a minimum of four tracks: Video, audio, timecode and telemetry (GPMF). A fifth track ('SOS') is used in file recovery in HERO4 and HERO5, can be ignored.

File structure:

  ftyp [type ‘mp41’]
  mdat [all the data for all tracks are interleaved]
  moov [all the header/index info]
    ‘trak’ subtype ‘vide’, name “GoPro AVC”, H.264 video data 
    ‘trak’ subtype ‘soun’, name “GoPro AAC”, to AAC audio data
    ‘trak’ subtype ‘tmcd’, name “GoPro TCD”, starting timecode (time of day as frame since midnight)
    ‘trak’ subtype ‘meta’, name “GoPro MET”, GPMF telemetry
Franck Dernoncourt
  • 20,384
  • 48
  • 186
  • 322

1 Answers1

1

From this SO post by Andrew, one has to add the attributes: -map 0:v -map 0:a -map 0:3 -copy_unknown -tag:2 gpmd

Full command:

ffmpeg -safe 0 -f concat -i list.txt -map 0:v -map 0:a -map 0:3 -copy_unknown -tag:2 gpmd -c copy output.mp4

Note that https://community.gopro.com/s/question/0D53b00008BtrlQCAR/merge-files-and-keep-telemetry?language=en_US reports some issues:

ReelSteady Go refuses to read the data.

I assume that's because ffmpeg is merging the gpmd stream roughly, since we use -copy_unknown because ffmpeg has no clue what gpmd is.

However, https://goprotelemetryextractor.com/free/ seems to be able to properly extract the GPX information.

Franck Dernoncourt
  • 20,384
  • 48
  • 186
  • 322