diff --git a/Makefile b/Makefile index e8c20c1..929de4a 100644 --- a/Makefile +++ b/Makefile @@ -230,6 +230,7 @@ SRC = $(SRCDIR)/dm_ansi.f90 \ $(SRCDIR)/dm_beat.f90 \ $(SRCDIR)/dm_block.f90 \ $(SRCDIR)/dm_c.f90 \ + $(SRCDIR)/dm_camera.f90 \ $(SRCDIR)/dm_cgi.f90 \ $(SRCDIR)/dm_cgi_router.f90 \ $(SRCDIR)/dm_config.f90 \ @@ -324,6 +325,7 @@ OBJ = dm_ansi.o \ dm_beat.o \ dm_block.o \ dm_c.o \ + dm_camera.o \ dm_cgi.o \ dm_cgi_router.o \ dm_config.o \ @@ -638,6 +640,7 @@ $(OBJ): $(SRC) $(FC) $(FFLAGS) $(LDFLAGS) -c src/dm_crypto.f90 $(FC) $(FFLAGS) $(LDFLAGS) -c src/dm_im.f90 $(FC) $(FFLAGS) $(LDFLAGS) -c src/dm_image.f90 + $(FC) $(FFLAGS) $(LDFLAGS) -c src/dm_camera.f90 $(FC) $(FFLAGS) $(LDFLAGS) -c src/dmpack.f90 # Static library `libdmpack.a`. diff --git a/src/dm_camera.f90 b/src/dm_camera.f90 new file mode 100644 index 0000000..a91aa6e --- /dev/null +++ b/src/dm_camera.f90 @@ -0,0 +1,55 @@ +! Author: Philipp Engel +! Licence: ISC +module dm_camera + !! Module for handling IP cameras and webcams using FFmpeg. + !! + !! On Linux, install the packages `ffmpeg` and `v4l-utils`: + !! + !! ``` + !! $ sudo apt-get install ffmpeg v4l-utils + !! ``` + !! + !! List connected USB cameras: + !! + !! ``` + !! $ v4l2-ctl --list-devices + !! UVC Camera (046d:0825) (usb-0000:00:1d.7-1): + !! /dev/video0 + !! /dev/video1 + !! /dev/media0 + !! ``` + !! + !! Capture a still image from the camera attached to `/dev/video0`, add a + !! timestamp to the bottom right corner, and save it to `/tmp/image.jpg`: + !! + !! ``` + !! $ ffmpeg -f video4linux2 -i /dev/video0 -vframes 1 -video_size 640x480 \ + !! -vf "drawtext=fontfile=DejaVuMono.ttf:fontsize=12:fontcolor=white:box=1:boxcolor=black:text='%{localtime}':x=(w-text_w):y=(h-text_h)" \ + !! -hide_banner -loglevel error -nostats -y \ + !! /tmp/image.jpg + !! ``` + use :: dm_file, only: FILE_PATH_LEN + use :: dm_mime, only: MIME_LEN, MIME_GIF, MIME_PNG, MIME_JPEG + implicit none (type, external) + private + + ! FFmpeg devices/formats. + integer, parameter, public :: CAMERA_DEVICE_NONE = 0 !! No device selected. + integer, parameter, public :: CAMERA_DEVICE_V4L = 1 !! Video4Linux2. + integer, parameter, public :: CAMERA_DEVICE_RTSP = 2 !! RTSP stream. + + integer, parameter, public :: CAMERA_FONT_LEN = 128 !! Max. length of font name or path. + + type, public :: camera_type + !! Camera context type. + integer :: device = CAMERA_DEVICE_NONE !! Input device. + character(len=FILE_PATH_LEN) :: input = ' ' !! Input path. + character(len=FILE_PATH_LEN) :: output = ' ' !! Output path. + character(len=MIME_LEN) :: mime = ' ' !! Output format (MIME type). + character(len=CAMERA_FONT_LEN) :: font = ' ' !! Overlay font name. + integer :: font_size = 12 !! Overlay font size + integer :: width = 0 !! Image width in pixels. + integer :: height = 0 !! Image size in pixels. + logical :: overlay = .false. !! Overlay flag. + end type camera_type +end module dm_camera diff --git a/src/dm_image.f90 b/src/dm_image.f90 index 8b78e69..d5898b5 100644 --- a/src/dm_image.f90 +++ b/src/dm_image.f90 @@ -1,33 +1,7 @@ ! Author: Philipp Engel ! Licence: ISC module dm_image - !! Module for handling images of IP cameras and webcams. - !! - !! On Linux, install the packages `ffmpeg` and `v4l-utils`: - !! - !! ``` - !! $ sudo apt-get install ffmpeg v4l-utils - !! ``` - !! - !! List connected USB cameras: - !! - !! ``` - !! $ v4l2-ctl --list-devices - !! UVC Camera (046d:0825) (usb-0000:00:1d.7-1): - !! /dev/video0 - !! /dev/video1 - !! /dev/media0 - !! ``` - !! - !! Capture a still image from the camera attached to `/dev/video0`, add a - !! timestamp to the bottom right corner, and save it to `/tmp/image.jpg`: - !! - !! ``` - !! $ ffmpeg -f video4linux2 -i /dev/video0 -vframes 1 -video_size 640x480 \ - !! -vf "drawtext=fontfile=DejaVuMono.ttf:fontsize=12:fontcolor=white:box=1:boxcolor=black:text='%{localtime}':x=(w-text_w):y=(h-text_h)" \ - !! -hide_banner -loglevel error -nostats -y \ - !! /tmp/image.jpg - !! ``` + !! Image type module. use :: dm_id, only: ID_LEN use :: dm_mime, only: MIME_LEN, MIME_GIF, MIME_PNG, MIME_JPEG use :: dm_node, only: NODE_ID_LEN @@ -36,11 +10,10 @@ module dm_image implicit none (type, external) private - integer, parameter, public :: IMAGE_DEVICE_LEN = 512 !! Max. image device path length. - integer, parameter, public :: IMAGE_BASE64_LEN = int(z'800000') !! Max. base64-encoded image data size in bytes (8 MiB). + integer, parameter, public :: IMAGE_DEVICE_LEN = 512 !! Max. image device path length. - type, public :: image_meta_type - !! Image meta type. + type, public :: image_type + !! Image type. character(len=ID_LEN) :: id = ' ' !! Image id (UUIDv4). character(len=NODE_ID_LEN) :: node_id = ' ' !! Node id. character(len=SENSOR_ID_LEN) :: sensor_id = ' ' !! Sensor id. @@ -49,16 +22,5 @@ module dm_image character(len=MIME_LEN) :: mime = ' ' !! Image format (MIME type). integer :: width = 0 !! Image width in pixels. integer :: height = 0 !! Image height in pixels. - end type image_meta_type - - type, public :: image_data_type - !! Image data type. - character(len=IMAGE_BASE64_LEN) :: base64 = ' ' !! Base64-encoded image data. - end type image_data_type - - type, public :: image_type - !! Image compound type. - type(image_meta_type) :: meta !! Image meta data. - type(image_data_type) :: data !! Image data. end type image_type end module dm_image diff --git a/src/dm_plot.f90 b/src/dm_plot.f90 index d0a95df..cdbd0aa 100644 --- a/src/dm_plot.f90 +++ b/src/dm_plot.f90 @@ -5,6 +5,7 @@ module dm_plot use, intrinsic :: iso_c_binding use :: dm_dp use :: dm_error + use :: dm_file use :: dm_kind use :: dm_pipe use :: dm_string @@ -46,30 +47,30 @@ module dm_plot character(len=*), parameter, public :: PLOT_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S' !! Datetime format. type, public :: plot_type - !! Plot type of plot settings. - integer :: terminal = PLOT_TERMINAL_NONE !! Output terminal. - integer :: style = PLOT_STYLE_LINES !! Plot line style. - integer :: width = 800 !! Plot width. - integer :: height = 300 !! Plot height. - character(len=1024) :: output = ' ' !! Output file name. - character(len=8) :: background = ' ' !! Background colour (optional). - character(len=8) :: foreground = '#3b4cc0' !! Foreground colour (optional). - character(len=8) :: graph = '#ffffff' !! Graph background colour. - character(len=1024) :: font = ' ' !! Font name or file path (optional). - character(len=128) :: title = ' ' !! Plot title (optional). - character(len=128) :: xlabel = ' ' !! X label (optional). - character(len=128) :: ylabel = ' ' !! Y label (optional). - character(len=TIME_LEN) :: xrange(2) = ' ' !! X axis range. - real(kind=r8) :: yrange(2) = 0.0_r8 !! Y axis range. - logical :: bidirect = .false. !! Bi-directional anonymous pipe. - logical :: persist = .false. !! Persistent Gnuplot process (use only with X11). - logical :: xautoscale = .true. !! Auto-scale X axis. - logical :: yautoscale = .true. !! Auto-scale Y axis. - logical :: grid = .true. !! Show grid. - logical :: legend = .false. !! Show legend. - type(pipe_type), private :: stdin !! Gnuplot’s standard input. - type(pipe_type), private :: stdout !! Gnuplot’s standard output. - type(pipe_type), private :: stderr !! Gnuplot’s standard error. + !! Plot context type. + integer :: terminal = PLOT_TERMINAL_NONE !! Output terminal. + integer :: style = PLOT_STYLE_LINES !! Plot line style. + integer :: width = 800 !! Plot width. + integer :: height = 300 !! Plot height. + character(len=FILE_PATH_LEN) :: output = ' ' !! Output file name. + character(len=8) :: background = ' ' !! Background colour (optional). + character(len=8) :: foreground = '#3b4cc0' !! Foreground colour (optional). + character(len=8) :: graph = '#ffffff' !! Graph background colour. + character(len=FILE_PATH_LEN) :: font = ' ' !! Font name or file path (optional). + character(len=128) :: title = ' ' !! Plot title (optional). + character(len=128) :: xlabel = ' ' !! X label (optional). + character(len=128) :: ylabel = ' ' !! Y label (optional). + character(len=TIME_LEN) :: xrange(2) = ' ' !! X axis range. + real(kind=r8) :: yrange(2) = 0.0_r8 !! Y axis range. + logical :: bidirect = .false. !! Bi-directional anonymous pipe. + logical :: persist = .false. !! Persistent Gnuplot process (use only with X11). + logical :: xautoscale = .true. !! Auto-scale X axis. + logical :: yautoscale = .true. !! Auto-scale Y axis. + logical :: grid = .true. !! Show grid. + logical :: legend = .false. !! Show legend. + type(pipe_type), private :: stdin !! Gnuplot’s standard input. + type(pipe_type), private :: stdout !! Gnuplot’s standard output. + type(pipe_type), private :: stderr !! Gnuplot’s standard error. end type plot_type public :: dm_plot_error diff --git a/src/dmpack.f90 b/src/dmpack.f90 index 1defd77..1fe2b80 100644 --- a/src/dmpack.f90 +++ b/src/dmpack.f90 @@ -36,6 +36,7 @@ module dmpack use :: dm_beat use :: dm_block use :: dm_c + use :: dm_camera use :: dm_cgi use :: dm_cgi_router use :: dm_config