start_recording Function

private function start_recording(self, file, fps, quality, codec, scale, options, watermark, watermark_width, watermark_opacity, ffmpeg) result(ok)

Start recording the frames drawn to the video file (see the module documentation), fps frames per second (default 30). Encoded by codec (an ffmpeg encoder; default libx264, H.264) at quality (for libx264, libx265 and libvpx-vp9 the CRF: 0 lossless to 51, default 18, visually lossless), scaled by scale (default 1; e.g. 0.5 for half the size of a Retina window's pixels), the size made even. options replaces the encoder options (codec, quality; and the scale, unless there is a watermark), e.g. '-c:v prores_ks -profile:v 3'. watermark: an image (e.g. a logo; PNG, SVG, ... with transparency) drawn over the video's bottom right corner by ffmpeg, watermark_width of the video's width (default 0.2), watermark_opacity opaque (default 0.6). ffmpeg: the program (default: VKFRAMES_FFMPEG, else ffmpeg on the path). Returns false if the window isn't open, is already recording or the watermark doesn't exist; ffmpeg's errors (e.g. an unknown encoder) show when it starts, at the next frame, and end the recording.

Ten seconds of video, at 30 frames per second:

if (.not. window%start_recording('orbit.mp4', fps=30.0_wp)) error stop 'could not record'
do k = 1, 300
    if (.not. window%frame()) exit
end do
if (.not. window%stop_recording()) write(*, '(a)') 'the recording failed'

Type Bound

WindowProxy

Arguments

Type IntentOptional Attributes Name
class(WindowProxy), intent(inout) :: self
character(len=*), intent(in) :: file

the video file (e.g. .mp4, .mov, .webm)

real(kind=wp), intent(in), optional :: fps

frames per second of the video (default 30)

integer, intent(in), optional :: quality

the CRF (default 18; lower is better)

character(len=*), intent(in), optional :: codec

an ffmpeg encoder (default libx264)

real(kind=wp), intent(in), optional :: scale

of the window's pixels (default 1)

character(len=*), intent(in), optional :: options

ffmpeg's encoder options, instead of those above

character(len=*), intent(in), optional :: watermark

an image file drawn at the bottom right

real(kind=wp), intent(in), optional :: watermark_width

its width, of the video's (default 0.2)

real(kind=wp), intent(in), optional :: watermark_opacity

0 to 1 (default 0.6)

character(len=*), intent(in), optional :: ffmpeg

the ffmpeg program

Return Value logical


Calls

proc~~start_recording~~CallsGraph proc~start_recording WindowProxy%start_recording interface~vkf_viewer_record_start vkf_viewer_record_start proc~start_recording->interface~vkf_viewer_record_start proc~encoder_options encoder_options proc~start_recording->proc~encoder_options proc~is_open WindowProxy%is_open proc~start_recording->proc~is_open proc~wall_time wall_time proc~start_recording->proc~wall_time

Source Code

    logical function start_recording(self, file, fps, quality, codec, scale, options, watermark, watermark_width, &
                                     watermark_opacity, ffmpeg) result(ok)
        class(WindowProxy), intent(inout) :: self
        character(len=*), intent(in) :: file                !! the video file (e.g. .mp4, .mov, .webm)
        real(wp), intent(in), optional :: fps               !! frames per second of the video (default 30)
        integer, intent(in), optional :: quality            !! the CRF (default 18; lower is better)
        character(len=*), intent(in), optional :: codec     !! an ffmpeg encoder (default libx264)
        real(wp), intent(in), optional :: scale             !! of the window's pixels (default 1)
        character(len=*), intent(in), optional :: options   !! ffmpeg's encoder options, instead of those above
        character(len=*), intent(in), optional :: watermark !! an image file drawn at the bottom right
        real(wp), intent(in), optional :: watermark_width   !! its width, of the video's (default 0.2)
        real(wp), intent(in), optional :: watermark_opacity !! 0 to 1 (default 0.6)
        character(len=*), intent(in), optional :: ffmpeg    !! the ffmpeg program
        character(len=:), allocatable :: output, program, filter
        character(len=1024) :: env
        character(len=32) :: f, w, a
        integer :: n, status
        logical :: exists
        ok = .false.
        if (.not. self%is_open() .or. self%recording_) return
        write(f, '(g0)') 1.0_wp
        if (present(scale)) write(f, '(g0)') max(scale, 0.01_wp)
        filter = 'scale=trunc(iw*'//trim(f)//'/2)*2:trunc(ih*'//trim(f)//'/2)*2'     ! (an even size)
        output = ''
        if (present(watermark)) then
            inquire(file=watermark, exist=exists)
            if (.not. exists) then
                write(*, '(a)') 'vkframes: recording: no watermark file '//trim(watermark)
                return
            end if
            output = '-i "'//trim(watermark)//'" '                   ! (ffmpeg's second input)
        end if
        if (present(options)) then
            output = output//trim(options)
        else
            output = output//encoder_options(codec, quality)
        end if
        if (present(watermark)) then
            ! the video scaled; the image scaled to its width and made translucent, over its bottom right corner
            write(w, '(g0)') 0.2_wp
            if (present(watermark_width)) write(w, '(g0)') max(0.01_wp, min(1.0_wp, watermark_width))
            write(a, '(g0)') 0.6_wp
            if (present(watermark_opacity)) write(a, '(g0)') max(0.0_wp, min(1.0_wp, watermark_opacity))
            output = output//' -filter_complex "[0:v]'//filter//'[v];[1:v][v]scale=w=rw*'//trim(w)// &
                     ':h=-1,format=rgba,colorchannelmixer=aa='//trim(a)//'[w];[v][w]overlay=W-w-H*0.03:H-h-H*0.03"'
        else if (.not. present(options)) then
            output = output//' -vf "'//filter//'"'
        end if
        output = output//' "'//trim(file)//'"'
        if (present(ffmpeg)) then
            program = '"'//trim(ffmpeg)//'"'
        else
            call get_environment_variable('VKFRAMES_FFMPEG', env, n, status)
            program = 'ffmpeg'
            if (status == 0 .and. n > 0) program = '"'//trim(env)//'"'
        end if
        self%record_fps = 30.0_wp
        if (present(fps)) self%record_fps = fps
        if (self%record_fps <= 0.0_wp) return
        if (vkf_viewer_record_start(self%viewer_, program, len(program, kind=c_int), output, len(output, kind=c_int), &
                                    real(self%record_fps, c_double)) /= 0) return
        self%record_wall = wall_time()               ! (the window's time goes on from now, at the video's pace)
        self%record_frames = 0_int64
        self%recording_ = .true.
        ok = .true.
    end function start_recording