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 | Intent | Optional | 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 |
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