Search code examples
videoffmpegclip

With ffmpeg print onto clipped video hh:mm:ss time *from original* and hh:mm:ss total duration from original


I am using arch linux and bash and ffmpeg, all are up to date and the latest versions.

I am clipping a video that is 30 seconds long and wish to clip from 5 secs to 10 seconds to a new file, from the original.

In the bottom right hand corner of the clip I wish to show timestamps from the original video as follows

  • in the 5th second "00:00:05/ 00:00:30"
  • in the 6th second "00:00:06/ 00:00:30"
    etc
  • in the 10th second "00:00:10/ 00:00:30"

This is an apparentley simple question(?) but the syntax of the command is not at all obvious and I am hoping an expert may shed some light on this.

All I have so far for the drawtext part, which does not do what I want as it only counts the elapsed time from t=0 of the new clip, whereas I want it to show the timestamp and total duration of the original clip

drawtext I started with

"drawtext=text='%{pts\:gmtime\:0\:%M\\\\\:%S}':fontsize=24:fontcolor=black:x=(w-text_w-10):y=(h-text_h-10)"

ffmpeg line with drawtext I have started with

ffmpeg -ss 00:00:05 -i  "$in_file" -filter_complex "drawtext=fontfile=font.ttf:text='sample text':x=10:y=10:fontsize=12:fontcolor=white:box=1:[email protected]:boxborderw=5,drawtext=text='%{duration\:hms}':fontsize=12:fontcolor=black:x=(w-text_w-10):y=(h-text_h-10)" -t 5 -c:a copy -c:v libx264 out_file.mp4

Solution

  • Here is the solution.

    The ffmpeg presentation timestamp %{pts} can only be zeroed and offest, as far as I know, using the C gmtime function, with the time set to 1st Jan 2000 in unix time seconds, ie 946684800 seconds, or some other arbitrary time at midnight.

    946684800 seconds in UNIX time gives midnight 00:00:00 on 01/01/2000 as a starting point for our calculations, to which we can add our own offset, in this case 5 seconds, as follows.

    We don't display the %d-%m-%Y portion of the date, so our method is not seen. Works very well. Took a bit of figuring out though.

    # set file names
    in_file="my_video_file.mp4"
    out_file="my_video__clipped.mp4"
    
    # set start and end times of the clip to be made
    start_time_z="00:00:05"
    end_time_z="00:00:10"   
    
    ######################################################################
    ##########                                                  ########## 
    ##########       get the duration of the                    ##########
    ##########          input video in hh:mm:ss format          ##########
    ##########        and convert it to seconds                 ##########
    ##########                                                  ########## 
    ######################################################################
    
    
    total_duration=$(ffprobe -v error -show_entries format=duration \
      -of default=noprint_wrappers=1:nokey=1 "$in_file" \
      | awk '{printf("%02d:%02d:%02d\n", ($1/3600), ($1%3600)/60, $1%60)}')
    
    # escape the ":" in the time stamp so that they can be printed by ffmpeg
    total_duration="$(echo $total_duration | sed 's@:@\\:@g')"
    
    # display the duration of the original video. Check we have captured it correctly
    ####    yad --text="\n\n$total_duration\n\n" --button="Submit":0
    
    
    ######################################################################
    ##########                                                  ########## 
    ##########       convert the variable                       ##########
    ##########             $start_time_z   which                ##########
    ##########                    = 00:00:05                    ##########
    ##########                                                  ##########
    ##########    into seconds and add to it unix time for      ##########
    ##########           00:00:00 on 1st Jan 2000               ##########
    ##########                                                  ########## 
    ######################################################################
    
    
    # convert the clip start time from hh:mm:ss to seconds
    start_secs=$(echo "$start_time_z" | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')
    
    # convert the clip end time from hh:mm:ss to seconds
    end_secs=$(echo "$end_time_z" | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')
    
    # duration of the clip
    duration_z=$((end_secs-start_secs))
    
    
    # Add start time to 946684800 which is 00:00:00 on 1st Jan 2000
    total_z=$(echo "$start_secs + 946684800" | bc)
    echo $total
    
    
    ######################################################################
    ##########                                                  ########## 
    ##########   run the command to create the MAIN  clip       ##########
    ##########                                                  ########## 
    ######################################################################
    
    
    #   below string shows unix time in action
    #     by removing the %d-%m-%Y portion we remove the 01-01-2000 part
    #       this appears to be the only way to shift pts and add a time shift onto it
    
    # drawtext=fontfile=font.ttf:text='%{pts\:gmtime\:$total_z\:%d-%m-%Y %T} / "$total_duration"':fontsize=$main_clip_font_size:fontcolor=white:x=(w-text_w-10):y=(h-text_h-10)" \
    
    ffmpeg -ss "$start_time_z" \
        -i "$in_file_name" \
        -filter_complex \
    "drawtext=fontfile=font.ttf:text='%{pts\:gmtime\:$total_z\:%T} / "$total_duration"':fontsize=$main_clip_font_size:fontcolor=white:x=(w-text_w-10):y=(h-text_h-10)" \
           -t  $duration_z \
           -c:a copy -c:v libx264 \
           "$out_file"