3

I want to extract the last few seconds of a GoPro video losslessly with FFmpeg so that it keeps telemetry info and keeps the original stream order.

A GoPro video has 4 streams, in that order:

  1. Stream #0:0[0x1](eng): Video
  2. Stream #0:1[0x2](eng): Audio
  3. Stream #0:2[0x3](eng): Data: none (tmcd / 0x64636D74) (default)
  4. Stream #0:3[0x4](eng): Data: bin_data (gpmd / 0x646D7067), 59 kb/s (default)

Details (using the commandffmpeg -i gopro_video.mp4):

 Stream #0:0[0x1](eng): Video: hevc (Main) (hvc1 / 0x31637668), yuvj420p(pc, bt709), 3840x2160 [SAR 1:1 DAR 16:9], 59703 kb/s, 59.94 fps, 59.94 tbr, 60k tbn (default)
      Metadata:
        creation_time   : 2024-11-23T23:10:03.000000Z
        handler_name    : GoPro H.265
        vendor_id       : [0][0][0][0]
        encoder         : GoPro H.265 encoder
        timecode        : 23:26:28:23
  Stream #0:1[0x2](eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 189 kb/s (default)
      Metadata:
        creation_time   : 2024-11-23T23:10:03.000000Z
        handler_name    : GoPro AAC
        vendor_id       : [0][0][0][0]
        timecode        : 23:26:28:23
  Stream #0:2[0x3](eng): Data: none (tmcd / 0x64636D74) (default)
      Metadata:
        creation_time   : 2024-11-23T23:10:03.000000Z
        handler_name    : GoPro TCD
        timecode        : 23:26:28:23
  Stream #0:3[0x4](eng): Data: bin_data (gpmd / 0x646D7067), 59 kb/s (default)
      Metadata:
        creation_time   : 2024-11-23T23:10:03.000000Z
        handler_name    : GoPro MET

I try to use this command to extract the last few seconds of a GoPro video with ffmpeg so that it keeps telemetry info and keeps the original stream order:

ffmpeg -sseof -10 -i input.MP4 -map 0:v -map 0:a -map 0:3 -c copy -copy_unknown output.MP4

However, it inverses the order of Stream #0:2[0x3](eng) and Stream #0:3[0x4](eng), i.e. the output file output.MP4 has 4 streams, in that order:

  1. Stream #0:0[0x1](eng): Video
  2. Stream #0:1[0x2](eng): Audio
  3. Stream #0:3[0x3](eng): Data: bin_data (gpmd / 0x646D7067), 59 kb/s (default)
  4. Stream #0:2[0x4](eng): Data: none (tmcd / 0x64636D74) (default)

Stream details of the output file output.MP4:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'output.MP4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2mp41
    encoder         : Lavf61.7.100
  Duration: 00:00:10.24, start: 0.000000, bitrate: 60393 kb/s
  Stream #0:0[0x1](eng): Video: hevc (Main) (hvc1 / 0x31637668), yuvj420p(pc, bt709), 3840x2160 [SAR 1:1 DAR 16:9], 60132 kb/s, 59.94 fps, 59.94 tbr, 60k tbn (default)
      Metadata:
        handler_name    : GoPro H.265
        vendor_id       : [0][0][0][0]
        encoder         : GoPro H.265 encoder
        timecode        : 23:26:28:23
  Stream #0:1[0x2](eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 189 kb/s (default)
      Metadata:
        handler_name    : GoPro AAC
        vendor_id       : [0][0][0][0]
  Stream #0:2[0x3](eng): Data: bin_data (gpmd / 0x646D7067), 60 kb/s (default)
      Metadata:
        handler_name    : GoPro MET
  Stream #0:3[0x4](eng): Data: none (tmcd / 0x64636D74), 0 kb/s
      Metadata:
        handler_name    : GoPro H.265
        timecode        : 23:26:28:23

It is tempting to instead use the following command, since, as slhck wrote, "the order of the -map options determines the order of the streams in the output file":

ffmpeg -sseof -10 -i input.MP4 -map 0:v -map 0:a -map 0:2 -map 0:3 -c copy output.MP4

However, one can't use -map on streams that FFmpeg doesn't understand, and as a result, one gets this error:

[mp4 @ 00000292a73dd140] You requested a copy of the original timecode track so timecode metadata are now ignored
[mp4 @ 00000292a73dd140] Could not find tag for codec none in stream #2, codec not currently supported in container
[out#0/mp4 @ 00000292a793ec40] Could not write header (incorrect codec parameters ?): Invalid argument
Conversion failed!

One may otherwise try to move -copy_unknown in front of -map 0:3, i.e.:

ffmpeg -sseof -10 -i input.MP4 -map 0:v -map 0:a -copy_unknown -map 0:3 -c copy  output.MP4

But FFmpeg doesn't care about the order of -copy_unknown relative to -map so that doesn't change the stream order.

I'm out of ideas. For testing convenience, here is an example of a GoPro video file (18.5 MiB). Rename it as input.MP4 to try the aforementioned commands and use -sseof -1 instead of -sseof -10 since the video is only 2-second long.

How can I extract the last few seconds of a GoPro video losslessly with ffmpeg so that it keeps telemetry info and keeps the original stream order?

Franck Dernoncourt
  • 24,246
  • 64
  • 231
  • 400

1 Answers1

1

I tried a simple copy, and it worked without error...

ffmpeg -i GoPro_file_example.MP4 -map 0:2 -c copy -f data stream3_map0:2.bin
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'GoPro_file_example.MP4':
  Metadata:
    major_brand     : mp41
    minor_version   : 538120216
    compatible_brands: mp41
    creation_time   : 2022-07-13T08:46:54.000000Z
    firmware        : H21.01.01.42.00
  Duration: 00:00:02.90, start: 0.000000, bitrate: 53612 kb/s
  Stream #0:0[0x1](eng): Video: hevc (Main) (hvc1 / 0x31637668), yuvj420p(pc, bt709), 5312x2988 [SAR 1:1 DAR 16:9], 53273 kb/s, 29.97 fps, 29.97 tbr, 30k tbn (default)
    Metadata:
      creation_time   : 2022-07-13T08:46:54.000000Z
      handler_name    : GoPro H.265
      vendor_id       : [0][0][0][0]
      encoder         : GoPro H.265 encoder
      timecode        : 08:46:23:01
  Stream #0:1[0x2](eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 189 kb/s (default)
    Metadata:
      creation_time   : 2022-07-13T08:46:54.000000Z
      handler_name    : GoPro AAC  
      vendor_id       : [0][0][0][0]
      timecode        : 08:46:23:01
  Stream #0:2[0x3](eng): Data: none (tmcd / 0x64636D74), 0 kb/s (default)
    Metadata:
      creation_time   : 2022-07-13T08:46:54.000000Z
      handler_name    : GoPro TCD  
      timecode        : 08:46:23:01
  Stream #0:3[0x4](eng): Data: bin_data (gpmd / 0x646D7067), 55 kb/s (default)
    Metadata:
      creation_time   : 2022-07-13T08:46:54.000000Z
      handler_name    : GoPro MET  
Output #0, data, to 'stream3_map0:2.bin':
  Metadata:
    major_brand     : mp41
    minor_version   : 538120216
    compatible_brands: mp41
    firmware        : H21.01.01.42.00
    encoder         : Lavf60.16.100
  Stream #0:0(eng): Data: none (tmcd / 0x64636D74), 0 kb/s (default)
    Metadata:
      creation_time   : 2022-07-13T08:46:54.000000Z
      handler_name    : GoPro TCD  
      timecode        : 08:46:23:01
Stream mapping:
  Stream #0:2 -> #0:0 (copy)
Press [q] to stop, [?] for help
[out#0/data @ 0x55b8d8f02280] video:0kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000000%
size=       0kB time=00:00:00.00 bitrate=N/A speed=   0x    

But, it doesn't look like it contains any data, saying 0 kb/s, yet the file shows 4 bytes. The data looks strange in different encodings, so it's likely binary interpretation.

So, I opened the file in a hex editor. This shows hex, binary and little endian:

fedora@/dev/pts/2:$ xxd stream3_map0:2.bin
00000000: 000e 7523                                ..u#
fedora@/dev/pts/2:$ xxd -b stream3_map0:2.bin
00000000: 00000000 00001110 01110101 00100011                    ..u#
fedora@/dev/pts/2:$ xxd -e stream3_map0:2.bin
00000000: 23750e00                              ..u#

Binary shows us each byte: A null byte, control character (0E), the character u and #.

Control characters and padding indicates a specific protocol or encoding scheme, i.e. GoPro is looking very proprietary in their encoding. At this point, I needed info on GoPro... I found: https://trac.ffmpeg.org/ticket/8338

Which is an interesting read! The takeaway: you need to compile a version of ffmpeg with the modifications on that thread, or GPMF-parser.

The main metadata file, just inspecting with cat, it is the file GPMF-parser is referring to (Accelerometer, Gyroscope etc.):

DEVC��DVIDLDVNMc
AccelerometerORINcZXYSIUNcm/Y���`���R���[���[���\���U���[���\��~^���^���d���^���\���Y���b���h���m���a���d���^��{b��`���d���b���]���c���]���`���^���V���T���]��Z���T���W���R���[���W���X���]���[���e���R���[���e���_���]���\���Y���\���c���h���^���Z���_���\���V���Z���W���\���Y���U���i���X���[���V��\��yU���e���d���]���V���^���X���S���`���c��a���b��a���S���STRM$STMP�TSMPL�STNMc    GyroscopeORINcZXYSIUNcrad/sSCALs�TMPCfB="GYROs���

Hopefully this will lead to a solution for you!