Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Reference: https://www.bluebill.net/timestamps.html


Table of Contents

Install Pre-Requisits

Install ffmpeg, coreutils and jq.

Code Block
brew install ffmpeg
brew install coreutils
brew install jq

Revise Scripts

Using the scripts from https://www.bluebill.net/timestamps.html

Revise timestamp.sh and correctTime.sh to use 'gdate' instead of 'date'.  

See below for revised scripts. 

Fixing GoPro Video Creation Time

Check Creation Time

Code Block
./correctTime.sh DIVE_2_1_GH010089.MP4 
DIVE_2_1_GH010089.MP4

Video Create Time (Zulu):  2023-06-13T19:12:11.000000Z
Video Create Time (local): 2023-06-13T15:12:11 -0400 (EDT)
--------
Video Create Time (without timezone):2023-06-13T19:12:11
Video Create Time (to local):2023-06-13T19:12:11 -0400 (EDT)
--------
Video Create Time (to UTC):2023-06-13T23:12:11.000000Z

To update the metadata use --update

In the above output we see that the local time was recorded as Zulu time.  The local time was 19:12:11.

Fix Creation Time

Code Block
./correctTime.sh DIVE_2_1_GH010089.MP4 --update

Verify Creation Time

Code Block
./correctTime.sh DIVE_2_1_GH010089.corrected.MP4 
DIVE_2_1_GH010089.corrected.MP4

Video Create Time (Zulu):  2023-06-13T23:12:11.000000Z
Video Create Time (local): 2023-06-13T19:12:11 -0400 (EDT)
--------
Video Create Time (without timezone):2023-06-13T23:12:11
Video Create Time (to local):2023-06-13T23:12:11 -0400 (EDT)
--------
Video Create Time (to UTC):2023-06-14T03:12:11.000000Z

To update the metadata use --update

Command to Update Creation Time:

Code Block
ffmpeg -I <MOVIE> -c copy -metadata creation_time=2023-06-13-23:12:11.000000Z <OUTPUT>

Add Timestamp to Video

Code Block
./timestamp.sh DIVE_2_1_GH010089.corrected.MP4

Changes to the timestamp.sh script:

  • Removed -vcodec libx265
  • Changed location of timestamp to top right corner
Code Block
...
#ffmpeg -i "${INPUT}" -vf drawtext="fontsize=30:fontcolor=yellow:text='%{pts\:localtime\:${EPOCH}}':x=(w-text_w) - 10:y=(h-text_h) - 10" -vcodec libx265 -crf 28 "${OUTPUT}"

ffmpeg -i "${INPUT}" -vf drawtext="fontsize=30:fontcolor=white:text='%{pts\:localtime\:${EPOCH}}':x=(w-text_w) - 10:y=10" -crf 28 "${OUTPUT}"
...

Joining Video Files

Code Block
echo file DIVE_2_1_GH010089.corrected.MP4 >  mylist.txt 
echo file DIVE_2_2_GH020089.corrected.MP4 >>  mylist.txt 

ffmpeg -f concat -i mylist.txt -c copy output.mp4

Get Video File Information

Code Block
ffprobe -loglevel 0 -print_format json -show_format -show_streams "${INPUT}" | jq -r .format.tags.creation_time


Joining the Videos While Preserving Metadata

First create a text file (e.g. filesToMerge.txt) with all the chaptered video files that you want to merge into a single video e.g.

Code Block
file GH010097.MP4
file GH020097.MP4
file GH030097.MP4
file GH040097.MP4 


Next, check the streams in the video files.

Code Block
themeEmacs
ffprobe -show_format GH010097.MP4
Code Block
  Stream #0:0[0x1](eng): Video: h264 (High) (avc1 / 0x31637661), yuvj420p(pc, bt709, progressive), 2704x1520 [SAR 1:1 DAR 169:95], 60002 kb/s, 59.94 fps, 59.94 tbr, 60k tbn (default)
    Metadata:
      creation_time   : 2023-08-09T17:39:29.000000Z
      handler_name    : GoPro AVC  
      vendor_id       : [0][0][0][0]
      encoder         : GoPro AVC encoder
      timecode        : 17:38:25:34
  Stream #0:1[0x2](eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 189 kb/s (default)
    Metadata:
      creation_time   : 2023-08-09T17:39:29.000000Z
      handler_name    : GoPro AAC  
      vendor_id       : [0][0][0][0]
      timecode        : 17:38:25:34
  Stream #0:2[0x3](eng): Data: none (tmcd / 0x64636D74) (default)
    Metadata:
      creation_time   : 2023-08-09T17:39:29.000000Z
      handler_name    : GoPro TCD  
      timecode        : 17:38:25:34
  Stream #0:3[0x4](eng): Data: bin_data (gpmd / 0x646D7067), 49 kb/s (default)
    Metadata:
      creation_time   : 2023-08-09T17:39:29.000000Z
      handler_name    : GoPro MET  
  Stream #0:4[0x5](eng): Data: none (fdsc / 0x63736466), 13 kb/s (default)
    Metadata:
      creation_time   : 2023-08-09T17:39:29.000000Z
      handler_name    : GoPro SOS 


The above video has 4 streams. Lets try to join streams 0,1 and 3.

Code Block
themeEmacs
ffmpeg -f concat -safe 0 -i filesToMerge.txt -c copy -map 0:0 -map 0:1 -map 0:3 -c:v libx264 -pix_fmt yuv420p video-merged.mp4


Revise Scripts

Using the scripts from https://www.bluebill.net/timestamps.html

Revise timestamp.sh and correctTime.sh to use 'gdate' instead of 'date'.  

See below for revised scripts. 


Fixing GoPro Video Creation Time


Check Creation Time

Code Block
./correctTime.sh DIVE_2_1_GH010089.MP4 
DIVE_2_1_GH010089.MP4

Video Create Time (Zulu):  2023-06-13T19:12:11.000000Z
Video Create Time (local): 2023-06-13T15:12:11 -0400 (EDT)
--------
Video Create Time (without timezone):2023-06-13T19:12:11
Video Create Time (to local):2023-06-13T19:12:11 -0400 (EDT)
--------
Video Create Time (to UTC):2023-06-13T23:12:11.000000Z

To update the metadata use --update

In the above output we see that the local time was recorded as Zulu time.  The local time was 19:12:11.


Fix Creation Time

Code Block
./correctTime.sh DIVE_2_1_GH010089.MP4 --update


Verify Creation Time

Code Block
./correctTime.sh DIVE_2_1_GH010089.corrected.MP4 
DIVE_2_1_GH010089.corrected.MP4

Video Create Time (Zulu):  2023-06-13T23:12:11.000000Z
Video Create Time (local): 2023-06-13T19:12:11 -0400 (EDT)
--------
Video Create Time (without timezone):2023-06-13T23:12:11
Video Create Time (to local):2023-06-13T23:12:11 -0400 (EDT)
--------
Video Create Time (to UTC):2023-06-14T03:12:11.000000Z

To update the metadata use --update


Command to Update Creation Time:

Code Block
ffmpeg -I <MOVIE> -c copy -metadata creation_time=2023-06-13-23:12:11.000000Z <OUTPUT>


Add Timestamp to Video

Code Block
./timestamp.sh DIVE_2_1_GH010089.corrected.MP4


Changes to the timestamp.sh script:

  • Removed -vcodec libx265
  • Changed location of timestamp to top right corner


Code Block
...
#ffmpeg -i "${INPUT}" -vf drawtext="fontsize=30:fontcolor=yellow:text='%{pts\:localtime\:${EPOCH}}':x=(w-text_w) - 10:y=(h-text_h) - 10" -vcodec libx265 -crf 28 "${OUTPUT}"

ffmpeg -i "${INPUT}" -vf drawtext="fontsize=30:fontcolor=white:text='%{pts\:localtime\:${EPOCH}}':x=(w-text_w) - 10:y=10" -crf 28 "${OUTPUT}"
...


Get Video File Information

Code Block
ffprobe -loglevel 0 -print_format json -show_format -show_streams <VIDEO_FILE> 
Code Block
{
    "streams": [
        {
            "index": 0,
            "codec_name": "aac",
            "codec_long_name": "AAC (Advanced Audio Coding)",
            "profile": "LC",
            "codec_type": "audio",
            "codec_time_base": "1/48000",
            "codec_tag_string": "mp4a",
            "codec_tag": "
Code Block
{
    "streams": [
        {
            "index": 0,
            "codec_name": "aac",
            "codec_long_name": "AAC (Advanced Audio Coding)",
            "profile": "LC",
            "codec_type": "audio",
            "codec_time_base": "1/48000",
            "codec_tag_string": "mp4a",
            "codec_tag": "0x6134706d",
            "sample_fmt": "fltp",
            "sample_rate": "48000",
            "channels": 2,
            "channel_layout": "stereo",
            "bits_per_sample": 0,
            "r_frame_rate": "0/0",
            "avg_frame_rate": "0/0",
            "time_base": "1/48000",
            "start_pts": 0,
            "start_time": "0.000000",
            "duration_ts": 35213578,
            "duration": "733.616208",
            "bit_rate": "119736",
            "max_bit_rate": "128000",
            "nb_frames": "34391",
            "disposition": {
                "default": 1,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0
            },
            "tags": {
                "creation_time": "2023-07-16T15:22:49.000000Z",
                "language": "eng",
                "handler_name": "Core Media Audio"
            }
        },
        {
            "index": 1,
            "codec_name": "h264",
            "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
            "profile": "High",
            "codec_type": "video",
            "codec_time_base": "1001/120000",
            "codec_tag_string": "avc1",
            "codec_tag": "0x31637661",
            "width": 1280,
            "height": 720,
            "coded_width": 1280,
            "coded_height": 720,
            "has_b_frames": 0,
            "sample_aspect_ratio": "1:1",
            "display_aspect_ratio": "16:9",
            "pix_fmt": "yuv420p",
            "level": 32,
            "color_range": "tv",
            "color_space": "bt709",
            "color_transfer": "bt709",
            "color_primaries": "bt709",
            "chroma_location": "left",
            "field_order": "progressive",
            "refs": 1,
            "is_avc": "true",
            "nal_length_size": "4",
            "r_frame_rate": "60000/1001",
            "avg_frame_rate": "60000/1001",
            "time_base": "1/60000",
            "start_pts": 0,
            "start_time": "0.000000",
            "duration_ts": 44016973,
            "duration": "733.616217",
            "bit_rate": "8069838",
            "bits_per_raw_sample": "8",
            "nb_frames": "43973",
            "disposition": {
                "default": 1,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0
            },
            "tags": {
                "creation_time": "2023-07-16T15:22:49.000000Z",
                "language": "und",
                "handler_name": "Core Media Video"
            }
        }
    ],
    "format": {
        "filename": "Dive2.mp4",
        "nb_streams": 2,
        "nb_programs": 0,
        "format_name": "mov,mp4,m4a,3gp,3g2,mj2",
        "format_long_name": "QuickTime / MOV",
        "start_time": "0.000000",
        "duration": "733.616217",
        "size": "751679577",
        "bit_rate": "8196978",
        "probe_score": 100,
        "tags": {
            "major_brand": "mp42",
            "minor_version": "1",
            "compatible_brands": "isommp41mp42","isommp41mp42",
            "creation_time": "2023-07-16T15:22:49.000000Z"
            "creation_time": "2023-07-16T15:22:49.000000Z"
        }
    }
}

Scripts

}
    }
}


Scripts

ScriptDescription 

This script extracts the creation_time, removes the timezone and assigns the local timezone. It then converts this back to UTC and write it back to the video. This fixes issue with GoPro Videos.

USAGE: ./correct_time.sh video.mp4 --update 

Adds Timestamp in the top right hand corner of the video.

USAGE: ./timestamp.sh video.mp4

Sets the time to the local time specified and stores in the video as UTC.

USAGE: ./setTime.sh video.mp4 '2023-06-13T19:23:59' --update


References

ReferenceURL
Add Timestamp to Videos

https://www.bluebill.net/timestamps.html

Merging Chaptered GoPro Videos Whilst Preserving Telemetry | Trek View
ScriptDescription This script extracts the creation_time, removes the timezone and assigns the local timezone. It then converts this back to UTC and write it back to the video. This fixes issue with GoPro Videos.Adds Timestamp in the top right hand corner of the video.