Участник:Clint/Черновики4

Материал из Xgu.ru

Перейти к: навигация, поиск

Содержание

[править] Door cam on RPi

основная идея: web camera подключена к usb порту Rasberry Pi, данные из устройства /dev/video0 с помощью gstreamer копируются с некоторыми изменениями налету в /dev/video1, /dev/video2 и /dev/video3.

Затем на /dev/video1 запускается motion, который детектит движение и оправляет на почту соответствующие ролики.
На /dev/video2 запускается gstreamer, который пишет ролики по 60 sec.
На /dev/video3 запускается mjpegstreamer, который используется для простомтра с мобильного телефона или удаленного компьютера.

[править] Оборудование

  1. 046d:081b Logitech, Inc. Webcam C310
  2. Raspberry Pi 3 Model B+
  3. Корпус к Raspberry Pi
  4. USB Modem Huawei E3372h-153 переделанный под STICK (чтобы была возможность принимать или отправлять смс при помощи gammu) (https://4pda.ru/forum/index.php?showtopic=582284)
  5. Реле напряжения
  6. Источник бесперебойного питания, подключается к 220В через Реле напряжения, батарея на 7Ah - обеспечивает работу всего стенда ~7 часов.
  7. Понижающий преобразователь 5А, ток откручен на максимум, напряжение - 5,64 Вольт.
  8. Кабель питания от понижающего преобразователя к Raspberry Pi - не следует экономить на проводах, их сопротивление важно, может потребоваться много времени чтобы понять, что причина сбоев - некачественное питание.


Более подробно о камере c310:

список поддерживаемых форматов:

pi@rpi3:~ $ v4l2-ctl --list-formats -d /dev/video0
ioctl: VIDIOC_ENUM_FMT
        Index       : 0
        Type        : Video Capture
        Pixel Format: 'YUYV'
        Name        : YUYV 4:2:2

        Index       : 1
        Type        : Video Capture
        Pixel Format: 'MJPG' (compressed)
        Name        : Motion-JPEG

Есть в наличии Logitech, Inc. HD Pro Webcam C920 и есть желание переделать пайплайны для gstreamer-а, так как:

pi@rpi3:~ $ v4l2-ctl --list-formats -d /dev/video0
ioctl: VIDIOC_ENUM_FMT
        Index       : 0
        Type        : Video Capture
        Pixel Format: 'YUYV'
        Name        : YUV 4:2:2 (YUYV)

        Index       : 1
        Type        : Video Capture
        Pixel Format: 'H264' (compressed)
        Name        : H.264

        Index       : 2
        Type        : Video Capture
        Pixel Format: 'MJPG' (compressed)
        Name        : MJPEG

эта камера может на аппаратном уровне сразу отдавать в H.264, тодга процессорные ресурсы RPi будут использоваться меньше. Ниже будет описан пайплайн для gstreamer и указано что может быть перенесено на камеру.

[править] Копирование из /dev/video0 в /dev/video{1,2,3}

Для выполнения этой задачи необходимо установить gstreamer-1.0 и собрать v4l2loopback модуль ядра (если его нет).

Затем, для упрощения конторля за запущенными процессами gstreamer сделаны sym links:

pi@rpi3:~ $ ls -l /usr/bin/gst-launch-1.0-*
lrwxrwxrwx 1 root root 29 Jun 17  2017 /usr/bin/gst-launch-1.0-LOOP -> /usr/local/bin/gst-launch-1.0
lrwxrwxrwx 1 root root 29 Jun 17  2017 /usr/bin/gst-launch-1.0-MY -> /usr/local/bin/gst-launch-1.0

Скрипт /home/pi/bin/v4l2Mysink.sh для запуска gstreamer для копирования данных из /dev/video0 в /dev/video{1,2,3}:

#!/bin/bash
#set -x
export LD_LIBRARY_PATH=/usr/local/lib
export GST_PLUGIN_PATH=/usr/local/lib/gstreamer-1.0/
export GST_OMX_CONFIG_DIR=/usr/local/etc/xdg/
BIN='/usr/bin/gst-launch-1.0-MY'
DEB='/tmp/v4l2Mysink_deb.log'

ps -ef | grep -q uvcdynctrl && (kill -9 $(ps -ef | grep uvcdynctrl | grep -v grep | awk '{print $2}'))

lsmod | grep -q ^v4l2loopback  && (modprobe -r uvcvideo; modprobe -r videodev; modprobe -r meida; modprobe -r v4l2loopback; modprobe videodev; modprobe uvcvideo; modprobe media)

sourceDEV="$(ls -tr1 /dev/video* | tail -1)"
if [ "x${sourceDEV}" == "x" ]
then
 echo "sourceDEV empty, exit 0 now" >> ${DEB}
 exit 0
fi

modprobe -v v4l2loopback devices=3
v4l2-ctl --set-parm=10/1  -d /dev/video1
v4l2-ctl --set-parm=10/1  -d /dev/video2
v4l2-ctl --set-parm=10/1  -d /dev/video3

MY_CLOCKOVERLAY='clockoverlay time-format="%d/%m/%Y %H:%M:%S" halignment=left valignment=top font-desc="Terminus bold 30px"  wrap-mode=-1'
MY_VIDEO_CROP='videocrop left=268 right=372 top=42 bottom=30' 

nice -n-5 ${BIN} --gst-debug-level=3 --gst-debug-no-color -e v4l2src device="${sourceDEV}" ! \
 'video/x-raw,format=(string)YUY2,width=(int)1024,height=(int)576,pixel-aspect-ratio=(fraction)1/1,interlace-mode=(string)progressive,framerate=(fraction)10/1' ! \
  queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 leaky=2 ! \
  ${MY_VIDEO_CROP} ! \
  tee name=tp ! queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 leaky=2 ! v4l2sink device=/dev/video1 sync=false \
          tp. ! queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 leaky=2 ! v4l2sink device=/dev/video2 sync=false \
          tp. ! ${MY_CLOCKOVERLAY} ! queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 leaky=2 ! v4l2sink device=/dev/video3 sync=false \
      2>>${DEB}&


в результате выполнения будет запущен процесс:

pi@rpi3:~ $ ps -ef | grep gst-launch-1.0-MY | grep -v grep
root      5870     1  5 Mar24 ?        11:16:35 /usr/bin/gst-launch-1.0-MY --gst-debug-level=3 --gst-debug-no-color -e v4l2src device=/dev/video0 ! video/x-raw,format=(string)YUY2,width=(int)1024,height=(int)576,pixel-aspect-ratio=(fraction)1/1,interlace-mode=(string)progressive,framerate=(fraction)10/1 ! queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 leaky=2 ! videocrop left=268 right=372 top=42 bottom=30 ! tee name=tp ! queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 leaky=2 ! v4l2sink device=/dev/video1 sync=false tp. ! queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 leaky=2 ! v4l2sink device=/dev/video2 sync=false tp. ! clockoverlay time-format="%d/%m/%Y %H:%M:%S" halignment=left valignment=top font-desc="Terminus bold 30px" wrap-mode=-1 ! queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 leaky=2 ! v4l2sink device=/dev/video3 sync=false

и лог файл для этого процесса будет /tmp/v4l2Mysink_deb.log

Замечено, что ошибок в логфайле гораздо меньше, если использовать следующие параметры к модулю uvcvideo:

pi@rpi3:~ $ cat /etc/modprobe.d/uvcvideo.conf 
options uvcvideo nodrop=1 timeout=100 


gstreamer в данном случае собирался из исходных текстов:

pi@rpi3:~ $ ls -lhtra gstreamer_src_10.1.4/
total 25M
-rw-r--r--  1 pi pi 455K Aug 31  2016 orc-0.4.26.tar.xz
-rw-r--r--  1 pi pi 8.2M Feb 23  2017 gst-libav-1.10.4.tar.xz
-rw-r--r--  1 pi pi 492K Feb 23  2017 gst-omx-1.10.4.tar.xz
-rw-r--r--  1 pi pi 4.6M Feb 23  2017 gst-plugins-bad-1.10.4.tar.xz
-rw-r--r--  1 pi pi 3.0M Feb 23  2017 gst-plugins-base-1.10.4.tar.xz
-rw-r--r--  1 pi pi 3.3M Feb 23  2017 gst-plugins-good-1.10.4.tar.xz
-rw-r--r--  1 pi pi 888K Feb 23  2017 gst-plugins-ugly-1.10.4.tar.xz
-rw-r--r--  1 pi pi 3.7M Feb 23  2017 gstreamer-1.10.4.tar.xz
drwxr-xr-x 10 pi pi 4.0K Mar  3  2017 orc-0.4.26
drwxr-xr-x 15 pi pi 4.0K Mar  3  2017 gst-plugins-base-1.10.4
drwxr-xr-x 14 pi pi 4.0K Mar  3  2017 gst-plugins-good-1.10.4
drwxr-xr-x 13 pi pi 4.0K Mar  3  2017 gst-plugins-ugly-1.10.4
drwxr-xr-x 10 pi pi 4.0K Mar  3  2017 gst-libav-1.10.4
drwxr-xr-x 15 pi pi 4.0K Mar  3  2017 gst-plugins-bad-1.10.4
drwxr-xr-x 10 pi pi 4.0K May  6  2017 .
drwxr-xr-x 16 pi pi 4.0K Jun 16  2017 gstreamer-1.10.4
drwxr-xr-x  9 pi pi 4.0K Jun 16  2017 gst-omx-1.10.4
drwxr-xr-x 32 pi pi 4.0K Apr  2 11:43 ..

но лучше сначала попробовать apt-get install вместо сборки. Архивы получены по ссылке https://gstreamer.freedesktop.org/src/


Запуск gstreamer-а для копирования данных камеры выполняется на этапе старта ОС:

pi@rpi3:~ $ ls -lhtr /etc/rcS.d/S17v4l2MYsink 
lrwxrwxrwx 1 root root 20 Oct  4 18:11 /etc/rcS.d/S17v4l2MYsink -> ../init.d/v4l2MYsink


pi@rpi3:~ $ cat /etc/init.d/v4l2MYsink 
#! /bin/sh

### BEGIN INIT INFO
# Provides:             v4l2Mysink
# Required-Start:       $remote_fs $syslog
# Required-Stop:        $remote_fs $syslog
# Default-Start:        2 3 4 5
# Default-Stop:
# Short-Description:    v4l2Mysink Enabler
### END INIT INFO

set -e

export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"

case "$1" in
  start)
        if [ -L /dev/doorcam ]
         then
           /bin/bash /home/pi/bin/v4l2Mysink.sh &
         fi
#       log_end_msg 0 
;;
  stop)
        ;;

  reload|force-reload)
        ;;

  restart)
        ;;

  try-restart)
        ;;

  status)
        ;;

  *)
        log_action_msg "Usage: /etc/init.d/v4l2MYsink start"
esac

exit 0


Ссылка /dev/doorcam создается демоном udev:

pi@rpi3:~ $ cat /etc/udev/rules.d/11-mycam.rules
SUBSYSTEM=="video4linux", ATTR{name}=="UVC Camera (046d:081b)", SYMLINK+="doorcam", RUN+="/etc/udev/rules.d/11-mycam.rules.sh"

pi@rpi3:~ $ cat /etc/udev/rules.d/11-mycam.rules.sh
#!/bin/bash
/bin/chgrp video /dev/video*
/bin/chmod g+rw /dev/video*
/bin/chgrp video /dev/media*
/bin/chmod g+rw /dev/media*



[править] Запись 60 sec видео файлов

Запуск gstreamer для создания видео файлов по 60 сек выполняется скриптом /home/pi/bin/my_writer.sh:


#!/bin/bash

export GST_PLUGIN_PATH=/usr/local/lib/gstreamer-1.0/
export GST_OMX_CONFIG_DIR=/usr/local/etc/xdg/
export LD_LIBRARY_PATH=/usr/local/lib/

TARGETDIR="/camera/video/lastMins"
STOPfILE="/var/lib/motion/stop_sms"
LOOPFILE='/tmp/writer_loop_file'

if [ ! -f /tmp/writer_loop_file ]
then
 touch /tmp/writer_loop_file
 LASTLOOP=0
else
 LASTLOOP=$(cat ${LOOPFILE})
fi

CURRLOOP=$((LASTLOOP+1))
echo ${CURRLOOP} > ${LOOPFILE}
seq=${CURRLOOP}

#MANDATORY, or see my_writer_controller.sh
fileMask="writer"

dateMask="$(date +%Y%m%d%H%M%S)"
fileName="${fileMask}_${dateMask}.avi"
fileNameNew="${fileMask}_${dateMask}_[0-9][0-9][0-9][0-9].avi"
fileName_0="${fileMask}_${dateMask}"

DEBUG_DIR='/dev/shm/writer'

if [ ! -d ${DEBUG_DIR} ]
then
 mkdir ${DEBUG_DIR}
fi

pid_file="${DEBUG_DIR}/myAVIpid-${seq}"

GSTDEB="${DEBUG_DIR}/my_gst_handler-${seq}"

SKIP_LINES='No\ corresponding\ frame\ found\|Creating\ random\ stream-id\|Consider\ implementing\ group-id\ handling'

DEB="/tmp/writer_deb.log"

echo "" >> ${DEB}
echo "======================= START ${seq} $(date +%Y/%m/%d_%H:%M:%S)=====================" >> ${DEB}
echo "" >> ${DEB}


MYQUEUE='queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 leaky=2'

MY_VIDEO_SETTINGS='video/x-raw,format=I420,width=384,height=504,framerate=10/1'

MY_AUDIO_SETTINGS='audio/x-raw,rate=48000,channels=1'

MY_AUDIO_ENC='voaacenc  bitrate=64000'

MY_MUXSplit="splitmuxsink muxer=avimux name=my1avimux max-size-time=60000000000 location=${TARGETDIR}/${fileMask}_${dateMask}_%04d.avi"

MY_MUX='avimux'

MY_PULSE_SETTINGS='do-timestamp=true device="alsa_input.usb-046d_081b_0FE0F1A0-02-U0x46d0x81b.analog-mono" provide-clock=true buffer-time=30000 latency-time=1000 '

MY_CLOCKOVERLAY='clockoverlay time-format="%H:%M:%S" halignment=left valignment=top xpad=5 ypad=65 font-desc="Terminus bold 30px" ! clockoverlay time-format="%d/%m/%Y" halignment=right valignment=top xpad=0 ypad=65 font-desc="Terminus bold 30px"'

MY_VIDEO_CROP='videocrop top=95 bottom=50'

CARDNUM=$(/usr/bin/arecord -l  | /bin/grep '0x46d:0x81b' | /bin/sed 's/card\ \([0-9]\):.*$/\1/')
/usr/bin/amixer -q -c ${CARDNUM} sset Mic 26dB cap unmute

MY_OMX_ENC_SETTINGS='omxh264enc target-bitrate=400000 control-rate=variable '

BIN='/usr/bin/gst-launch-1.0-LOOP'

function gstCMDsplit {
${BIN} --gst-debug-level=3 --gst-debug-no-color -e v4l2src device=/dev/video2 do-timestamp=true ! ${MY_VIDEO_SETTINGS} ! ${MY_CLOCKOVERLAY} ! ${MYQUEUE} ! ${MY_OMX_ENC_SETTINGS} ! video/x-h264,profile=high ! h264parse config-interval=2 ! ${MYQUEUE} ! ${MY_MUXSplit} pulsesrc ${MY_PULSE_SETTINGS} ! audioconvert qos=true ! ${MY_AUDIO_SETTINGS} ! ${MY_AUDIO_ENC} ! ${MYQUEUE} ! my1avimux.audio_%u 2>${GSTDEB} &
}

gstCMDsplit

echo "pid:${!}" > ${pid_file}
echo "file:${fileName_0}" >> ${pid_file}

echo "file $(echo $pid_file): " >> ${DEB}
cat "${pid_file}" >> ${DEB}
echo "" >> ${DEB}

echo "ls -l ${DEBUG_DIR}" >> ${DEB}
ls -l ${DEBUG_DIR} >> ${DEB}
echo "----------------" >> ${DEB}

echo "cat ${GSTDEB}" >> ${DEB}
cat ${GSTDEB} >> ${DEB}
echo "----------------" >> ${DEB}

echo "sleep 1 started" >> ${DEB}

sleep 1

echo "sleep 1 ended" >> ${DEB}

echo "ls -l ${DEBUG_DIR}" >> ${DEB}
ls -l ${DEBUG_DIR} >> ${DEB}
echo "----------------" >> ${DEB}

echo "cat ${GSTDEB}" >> ${DEB}
cat ${GSTDEB} >> ${DEB}
echo "----------------" >> ${DEB}

echo "ls -lh ${TARGETDIR}/${fileNameNew}" >> ${DEB}
ls -lh ${TARGETDIR}/${fileNameNew} >> ${DEB} 2>&1
echo "----------------" >> ${DEB}

gst_restart_needed="NO"
pulse_restart_needed="NO"

errorString='Caught\ SIGSEGV|busy|no\ buffers\ have\ been\ allocated\ yet|codec_data\ is\ not\ expected|Failed\ to\ allocate\ a\ buffer|could\ not\ link\ my1avimux\ to\ pulsesrc0|streaming\ stopped\,\ reason\ not\-negotiated'
PulseErrorString='Internal\ data\ flow\ error|streaming\ task\ paused|gst_pulsesrc_is_dead|Failed\ to\ connect\ stream\:\ No\ such\ entity|Failed\ to\ connect\:\ Connection\ refused|Connection\ terminated'

egrep -qi "${errorString}" ${GSTDEB} && gst_restart_needed="YES"
egrep -qi "${PulseErrorString}" ${GSTDEB} && pulse_restart_needed="YES"


echo "" >> ${DEB}
echo "                                                 gstreamer for sequence ${seq} restart needed: ${gst_restart_needed}" >> ${DEB}
echo "" >> ${DEB}

if [ "${pulse_restart_needed}" == "YES" ]
then
 echo "                                              pulseaudio for sequence ${seq} restart needed: ${pulse_restart_needed}" >> ${DEB}
 gst_restart_needed="YES"
 kill -9 $(pgrep pulseaudio)
 pulseaudio --system=true -D&

  if [ -f "${STOPfILE}" ]
  then :
  else
    message="RK2 ${seq} pulse restarted: $(date +%d/%m/%y\ %H:%M:%S)"
    LOG='/tmp/smsd.log'
    NUMBER="+380XXXXXXXXX"
    /usr/bin/sudo /usr/bin/gammu-smsd-inject TEXT "${NUMBER}" -text "${message}" 1>>$LOG 2>&1
    /bin/rm -f $LOG
  fi
fi

echo "sleep 1 started" >> ${DEB}

sleep 1

echo "sleep 1 ended" >> ${DEB}

echo "ls -lh ${TARGETDIR}/${fileNameNew}" >> ${DEB}
ls -lh ${TARGETDIR}/${fileNameNew} >> ${DEB} 2>&1
echo "----------------" >> ${DEB}


if [ "${gst_restart_needed}" == "YES" ]
then

  if [ -f "${STOPfILE}" ]
   then :
  else
   message="RK2 ${seq} gst restart needed: $(date +%d/%m/%y\ %H:%M:%S)"
   #LOG='/tmp/smsd.log'
   #NUMBER="+380XXXXXXXXX"
   #/usr/bin/sudo /usr/bin/gammu-smsd-inject TEXT "${NUMBER}" -text "${message}" 1>>$LOG 2>&1
   #/bin/rm -f $LOG
  fi


echo "cat ${GSTDEB}" >> ${DEB}
cat ${GSTDEB} >> ${DEB}
echo "----------------" >> ${DEB}

echo "ps -auxww | grep gst-launch-1.0 | grep LOOP | grep -v grep" >> ${DEB}
ps -auxww | grep gst-launch-1.0 | grep LOOP | grep -v grep >> ${DEB}
echo "----------------" >> ${DEB}

 b=0
 while [ $b -lt 21 ]
  do
   killRegEx='ps -auxww | grep gst-launch-1.0 | grep LOOP | grep -v grep'
   b=$((b+1))
   echo "gstreamer SIGSEGV loop: $b" >> ${DEB}
   currpid=$(grep pid: ${pid_file} | sed 's/^.*://g')
   echo "trying killall by regex ${killRegEx} " >> ${DEB}
   sudo kill -9 $(ps -auxww | grep gst-launch-1.0 | grep LOOP | grep -v grep | awk '{print $2}')

   gstCMDsplit

   lastPID=${!}

   sed -i -e "s/^pid:.*$/pid:${lastPID}/g" ${pid_file}
   echo "Pid chnaged to ${lastPID} in ${pid_file}" >> ${DEB}

   echo "ps -auxww | grep gst-launch-1.0 | grep LOOP | grep -v grep" >> ${DEB}
   ps -auxww | grep gst-launch-1.0 | grep LOOP | grep -v grep >> ${DEB}
   echo "----------------" >> ${DEB}
   
   echo "ps -auxww | grep ${lastPID}" >> ${DEB}
   ps -auxww | grep ${lastPID} >> ${DEB}
   echo "----------------" >> ${DEB}

   echo "ls -l ${DEBUG_DIR}" >> ${DEB}
   ls -l ${DEBUG_DIR} >> ${DEB}
   echo "----------------" >> ${DEB}

   echo "cat ${GSTDEB}" >> ${DEB}
   cat ${GSTDEB} >> ${DEB}
   echo "----------------" >> ${DEB}

   echo "ls -lh ${TARGETDIR}/${fileNameNew}" >> ${DEB}
   ls -lh ${TARGETDIR}/${fileNameNew} >> ${DEB} 2>&1
   echo "----------------" >> ${DEB}

   echo "sleep 1 started" >> ${DEB}
   sleep 1
   echo "sleep 1 ended" >> ${DEB}

   echo "ls -l ${DEBUG_DIR}" >> ${DEB}
   ls -l ${DEBUG_DIR} >> ${DEB}
   echo "----------------" >> ${DEB}

   echo "cat ${GSTDEB}" >> ${DEB}
   cat ${GSTDEB} >> ${DEB}
   echo "----------------" >> ${DEB}

   echo "ls -lh ${TARGETDIR}/${fileNameNew}" >> ${DEB}
   ls -lh ${TARGETDIR}/${fileNameNew} >> ${DEB} 2>&1
   echo "----------------" >> ${DEB}

   egrep -qi "${errorString}" ${GSTDEB} && gst_restarted="NO" || gst_restarted="YES"
   echo "gst_restarted seq: ${seq}: ${gst_restarted}" >> ${DEB}
   if [ "${gst_restarted}" == "YES" ]
    then
     if [ -f "${STOPfILE}" ]
      then :
     else
        if [ $b -gt 1 ]
        #if [ $b -gt 5 ]
         then
             message="RK2 ${seq} gst restarted,loop: ${b}, $(date +%d/%m/%y\ %H:%M:%S)"
             LOG='/tmp/smsd.log'
             NUMBER="+380XXXXXXXXX"
             /usr/bin/sudo /usr/bin/gammu-smsd-inject TEXT "${NUMBER}" -text "${message}" 1>>$LOG 2>&1
             /bin/rm -f $LOG
        fi
     fi
     break
   fi
  sleep 2
  done

 if [ "${gst_restarted}" == "NO" ]
    then
     if [ -f "${STOPfILE}" ]
      then :
     else
      message="RK2 ${seq} gst NOT restartied,loop ${b}, $(date +%d/%m/%y\ %H:%M:%S)"
      LOG='/tmp/smsd.log'
      NUMBER="+380XXXXXXXXX"
      /usr/bin/sudo /usr/bin/gammu-smsd-inject TEXT "${NUMBER}" -text "${message}" 1>>$LOG 2>&1
      /bin/rm -f $LOG
     fi
   fi
fi

Запуск этого скрипта происходит из /etc/rc.local:

#!/bin/sh -e


/bin/bash /home/pi/bin/set_performance_cpu.sh &

if [ -L /dev/doorcam ]
then 
    /home/pi/bin/disable_green_led_on_cam.sh &
    mkdir /var/run/motion
    chown motion:motion /var/run/motion
fi

/etc/init.d/dbus stop
/etc/init.d/cgmanager stop
/etc/init.d/cgproxy stop
/etc/init.d/triggerhappy stop

if [ -L /dev/doorcam ]
then
    sudo -u motion sh -c 'sleep 4; /home/pi/motion-main/motion -c /etc/motion/motion.conf'
    pulseaudio --system=true -D
    sleep 2
    /bin/bash /home/pi/bin/my_writer.sh &
    /bin/bash /home/pi/bin/myMicrophoneStartupSound.sh &
    /bin/bash /home/pi/bin/myPidMon.sh &
    /bin/bash /home/pi/bin/my_mjpg_streamer_starter.sh &
fi
/bin/bash /home/pi/bin/myStartupSMS.sh &

if [ ! -L /dev/doorcam ]
then
 MailFile=/tmp/$$_$$_log.txt
 echo "" >> "${MailFile}"
 echo "/dev/doorcam not found at startup: $(date)" >> "${MailFile}"
 echo "" >> "${MailFile}"
 echo "" >> "${MailFile}"
 RCPTTO='email@gmail.com'
 /usr/bin/mutt -e 'my_hdr From:email@gmail.com' $RCPTTO -s DOORcam_Not_Found_at_RPI3 < ${MailFile} 
 /bin/rm -rf ${MailFile}
fi

exit 0

Перед тем как запускать /home/pi/bin/my_writer.sh скрипт pulseaudio демон должен быть запущен (pulseaudio --system=true -D).

Процесс, который появится в результате работы скрипта:

pi@rpi3:~ $ ps -ef | grep LOOP | grep -v grep
root     30202     1  8 Apr01 ?        01:43:22 /usr/bin/gst-launch-1.0-LOOP --gst-debug-level=3 --gst-debug-no-color -e v4l2src device=/dev/video2 do-timestamp=true ! video/x-raw,format=I420,width=384,height=504,framerate=10/1 ! clockoverlay time-format="%H:%M:%S" halignment=left valignment=top xpad=5 ypad=65 font-desc="Terminus bold 30px" ! clockoverlay time-format="%d/%m/%Y" halignment=right valignment=top xpad=0 ypad=65 font-desc="Terminus bold 30px" ! queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 leaky=2 ! omxh264enc target-bitrate=400000 control-rate=variable ! video/x-h264,profile=high ! h264parse config-interval=2 ! queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 leaky=2 ! splitmuxsink muxer=avimux name=my1avimux max-size-time=60000000000 location=/camera/video/lastMins/writer_20190401173004_%04d.avi pulsesrc do-timestamp=true device="alsa_input.usb-046d_081b_0FE0F1A0-02-U0x46d0x81b.analog-mono" provide-clock=true buffer-time=30000 latency-time=1000 ! audioconvert qos=true ! audio/x-raw,rate=48000,channels=1 ! voaacenc bitrate=64000 ! queue max-size-buffers=0 max-size-time=0 max-size-bytes=0 leaky=2 ! my1avimux.audio_%u

Обратите внимание на

omxh264enc target-bitrate=400000 control-rate=variable

То есть, если камера может на аппаратном уровне отдавать h264 - то все что в пайплайне gstreamer-a до omxh264enc target-bitrate=400000 control-rate=variable ! video/x-h264,profile=high ! может быть опущено - надо проверить!!

В результате в $TARGETDIR начнут появляться видео файлы:

pi@rpi3:~ $ ls -lhtr /camera/video/lastMins/ | tail -5
-rw-r--r-- 1 root root 3.1M Apr  2 12:53 writer_20190401173004_1231.avi
-rw-r--r-- 1 root root 3.1M Apr  2 12:54 writer_20190401173004_1232.avi
-rw-r--r-- 1 root root 3.1M Apr  2 12:55 writer_20190401173004_1233.avi
-rw-r--r-- 1 root root 3.1M Apr  2 12:56 writer_20190401173004_1234.avi
-rw-r--r-- 1 root root 1.4M Apr  2 12:56 writer_20190401173004_1235.avi
pi@rpi3:~ $ mediainfo /camera/video/lastMins/writer_20190401173004_1234.avi 
General
Complete name                            : /camera/video/lastMins/writer_20190401173004_1234.avi
Format                                   : AVI
Format/Info                              : Audio Video Interleave
File size                                : 3.06 MiB
Duration                                 : 55s 0ms
Overall bit rate                         : 467 Kbps

Video
ID                                       : 0
Format                                   : AVC
Format/Info                              : Advanced Video Codec
Format profile                           : High@L4.0
Format settings, CABAC                   : Yes
Format settings, ReFrames                : 1 frame
Format settings, GOP                     : M=1, N=60
Codec ID                                 : H264
Duration                                 : 55s 0ms
Bit rate                                 : 393 Kbps
Width                                    : 384 pixels
Height                                   : 504 pixels
Display aspect ratio                     : 0.762
Frame rate                               : 10.000 fps
Color space                              : YUV
Chroma subsampling                       : 4:2:0
Bit depth                                : 8 bits
Scan type                                : Progressive
Bits/(Pixel*Frame)                       : 0.203
Stream size                              : 2.58 MiB (84%)

Audio
ID                                       : 1
Format                                   : AAC
Format/Info                              : Advanced Audio Codec
Format profile                           : LC
Codec ID                                 : FF
Duration                                 : 54s 400ms
Bit rate                                 : 64.0 Kbps
Channel(s)                               : 1 channel
Channel positions                        : Front: C
Sampling rate                            : 48.0 KHz
Compression mode                         : Lossy
Stream size                              : 425 KiB (14%)
Alignment                                : Split accross interleaves
Interleave, duration                     : 22 ms (0.22 video frame)

[править] Motion

В данный момент используется motion версии:

pi@rpi3:~/motion-main $ ./version.sh 
3.4.1+git7692717

из https://github.com/Motion-Project/motion

но лучше начать с apt-get install motion.

Запуск демона motion в данном случае выполнен из /etc/rc.local:

...
...
...
if [ -L /dev/doorcam ]
then 
    /home/pi/bin/disable_green_led_on_cam.sh &
    mkdir /var/run/motion
    chown motion:motion /var/run/motion
fi
...
...
sudo -u motion sh -c 'sleep 4; /home/pi/motion-main/motion -c /etc/motion/motion.conf'
...
...

Конфигурационный файл motion.conf:


sudo egrep -v '^#|^$|^;' /etc/motion/motion.conf
daemon on 
process_id_file /var/run/motion/motion.pid
setup_mode off
logfile /tmp/motion.log
log_level 6
log_type all
videodevice /dev/video1
v4l2_palette 15
input -1
norm 0
frequency 0
rotate 0
width 384
height 448
framerate 5
minimum_frame_time 0
netcam_keepalive off
netcam_tolerant_check off
auto_brightness off
brightness 0
contrast 0
saturation 0
hue 0
roundrobin_frames 1
roundrobin_skip 1
switchfilter off
threshold 15
threshold_tune off
noise_level 10
noise_tune off
despeckle_filter EedDl
smart_mask_speed 0
lightswitch 0
minimum_motion_frames 2
pre_capture 0
post_capture 0
event_gap 33
max_movie_time 0
emulate_motion off
output_pictures off
output_debug_pictures off
quality 75
picture_type jpeg
ffmpeg_output_movies off
ffmpeg_output_debug_movies off
ffmpeg_timelapse 0
ffmpeg_timelapse_mode daily
ffmpeg_bps 9999999
ffmpeg_variable_bitrate 0
ffmpeg_video_codec mpeg4
ffmpeg_deinterlace off
use_extpipe off
snapshot_interval 0
locate_motion_mode off
locate_motion_style box
text_right %Y-%m-%d\n%T-%q
text_changes on
text_event %Y%m%d%H%M%S
text_double on
target_dir /var/lib/motion
snapshot_filename %v-%Y%m%d%H%M%S-snapshot
picture_filename %Y%m%d/%v-%Y%m%d%H%M%S-%q
movie_filename %Y%m%d/%v-%Y%m%d%H%M%S
timelapse_filename %Y%m%d-timelapse
ipv6_enabled off
stream_port 0
stream_quality 50
stream_motion on
stream_maxrate 2
stream_localhost off
stream_limit 0
stream_auth_method 1
stream_authentication user:password
webcontrol_port 0
webcontrol_localhost on
webcontrol_html_output on
track_type 0
track_auto off
track_iomojo_id 0
track_step_angle_x 10
track_step_angle_y 10
track_move_wait 10
track_speed 255
track_stepsize 40
quiet on
on_event_start /var/lib/motion/bin/myrec_start.sh %v %v-%Y%m%d%H%M%S
on_event_end /var/lib/motion/bin/myrec_stop.sh %v %v-%Y%m%d%H%M%S

тут много лишних опций, основная задача motion - определить начало/конец движения и запустить on_event_start/on_event_end скрипт с параметрами.


Скрипт /var/lib/motion/bin/myrec_start.sh:

#!/bin/bash
#set -x 
if [ -z "${1}" ]
then
 exit 0
fi

if [ -z "${2}" ]
then
 exit 0
fi

STOPfILE="/var/lib/motion/stop_sms"
SEQ="${1}"

if [ -f "${STOPfILE}" ]
then :
else
 message="+ $(date +%d/%m/%y\ %H:%M:%S) ${SEQ}"
 LOG='/tmp/smsd.log'
 NUMBER="+380XXXXXXXXX"
 /usr/bin/sudo /usr/bin/gammu-smsd-inject TEXT "${NUMBER}" -text "${message}" 1>>$LOG 2>&1
 /bin/rm -f $LOG
fi

stopTELEGRAMMfILE='/var/lib/motion/stop_telegramm'
if [ -f "$stopTELEGRAMMfILE" ]
then :
else
    message="+ $(date +%d/%m/%y\ %H:%M:%S) ${SEQ}"
    /home/pi/bin/notify_me.sh "${message}" &
fi

MOTION_OLD_INFO_FILE='/tmp/motion_info_file_old'
/bin/rm -f $MOTION_OLD_INFO_FILE

MOTION_LOG_FILE=/var/log/motion_history.log
echo "+ $(date +%d/%m/%y\ %H:%M:%S) ${SEQ}" >> /var/log/motion_history.log

/usr/bin/logger -p info -n 192.168.7.254 -d -t MOTION_UP "test"
/bin/bash /home/pi/bin/popup_android-start.sh &
/usr/bin/touch /tmp/motion_start_file_${SEQ}
/bin/bash /home/pi/bin/my_motion_watcher.sh "${SEQ}" &
/bin/bash /home/pi/bin/5min_mon.sh start "${SEQ}" &

основная задача этого скрипта - оповестить по смс или telegram о начале движения и запустить /home/pi/bin/my_motion_watcher.sh, который начнет отправлять ролики на почту до окончания движения.

В нем используется /usr/src/ffmpeg-2.7.2/ffmpeg для пересбора avi в mp4 контейнер, так как мощности raspberry pi не хватает налету сразу mp4 собирать, avi - еле еле получается собрать... - это еще один костыль, который надо исправить, есть надежда на c920 камеру с h264 на борту...


Скрипт /home/pi/bin/my_motion_watcher.sh:

#!/bin/bash
#set -x
MOTION_HISTORY_LOG=/var/log/motion_history.log
mailFile="/tmp/$$_1_$$_email_file"
PROCEEDED_FILES_LOG=/var/log/motion_watcher_files_sent_log
OWN_LOG=/var/log/motion_watcher_log
RCPTTO='email@gmail.com'
CURRENT_SEQ_OF_MOTION="$1"
eval $(grep ^TARGETDIR /home/pi/bin/my_writer.sh)
echo "$(date)::${CURRENT_SEQ_OF_MOTION}::$0::TARGETDIR: ${TARGETDIR}" >> ${OWN_LOG}
AGE_DIFF_TRESHOLD=20
MOTION_STOP_FILE="/tmp/motion_stop_file_${CURRENT_SEQ_OF_MOTION}"
LOW_TIME_STAMP=''
HIGH_TIME_STAMP=$(date "+%Y-%m-%d %H:%M:%S")
echo "$(date)::${CURRENT_SEQ_OF_MOTION}::HIGH_TIME_STAMP: ${HIGH_TIME_STAMP}" >> ${OWN_LOG}

file_cnt=0
while true
do
  echo "$(date)::${CURRENT_SEQ_OF_MOTION}::Inside while loop"  >> ${OWN_LOG}
  for file in $(find ${TARGETDIR} -type f -newermt "${HIGH_TIME_STAMP}")
  # -a -not -newermt '-5 seconds')
  do
  echo "$(date)::${CURRENT_SEQ_OF_MOTION}::file to work: $file" >> ${OWN_LOG}
   PROCEEDED_FILE="NO"
   grep -q "${file}" ${PROCEEDED_FILES_LOG} && PROCEEDED_FILE="YES" || PROCEEDED_FILE="NO"
   echo "$(date)::${CURRENT_SEQ_OF_MOTION}::PROCEEDED: ${PROCEEDED_FILE}" >> ${OWN_LOG}
    
   if [ "x${PROCEEDED_FILE}" == "xNO" ]
     then
       echo "$(date)::${CURRENT_SEQ_OF_MOTION}::file to work: ${file}" >> ${OWN_LOG}
     
        AGE_DIFF=0
        AGE_DIFF=$(expr `date +%s` - `stat -c %Y "${file}"`)
        
        if [ ${AGE_DIFF} -le ${AGE_DIFF_TRESHOLD} ]
          then
           echo "$(date)::${CURRENT_SEQ_OF_MOTION}::diff for file ${file} now is ${AGE_DIFF}, treshold is ${AGE_DIFF_TRESHOLD}" >> ${OWN_LOG}
        fi
        
        if [ ${AGE_DIFF} -ne 0 -a ${AGE_DIFF} -gt ${AGE_DIFF_TRESHOLD} ]
         then
           file_cnt=$((file_cnt+1))
           echo "$(date)::${CURRENT_SEQ_OF_MOTION}::                                    FILE IS READY TO BE SENT: ${file}, FILE COUNT: ${file_cnt}" >> ${OWN_LOG}
           echo "$file" >> ${PROCEEDED_FILES_LOG}
           tail -3 ${MOTION_HISTORY_LOG} | grep ${CURRENT_SEQ_OF_MOTION}$ >> ${mailFile}
           human_name=''
           human_name=$(/bin/ls ${file} | sed 's/.*writer_\([0-9][0-9][0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\)/\4:\5:\6_\3-\2-\1/g')
           /bin/cp ${file} "${TARGETDIR}/../${CURRENT_SEQ_OF_MOTION}_${human_name}" 
           ( mp4_human_name=$(echo ${human_name} | sed 's/\.avi/\.mp4/');\
           nice -n19 /usr/src/ffmpeg-2.7.2/ffmpeg -threads 1 -i ${file} -c:a copy "${TARGETDIR}/../${CURRENT_SEQ_OF_MOTION}_${mp4_human_name}" -hide_banner -loglevel panic -y & (sleep 2; cpulimit -z -P /usr/src/ffmpeg-2.7.2/ffmpeg -l 50; /usr/bin/mutt ${RCPTTO} -s Motion_${CURRENT_SEQ_OF_MOTION}_${file_cnt}_Finished -a "${TARGETDIR}/../${CURRENT_SEQ_OF_MOTION}_${mp4_human_name}" < ${mailFile});\
           (sleep 3; /home/pi/bin/my_black_frame_detector.sh "${TARGETDIR}/../${CURRENT_SEQ_OF_MOTION}_${mp4_human_name}")&
           (sleep 1; /usr/bin/sudo /usr/sbin/exim4 -q -v 1>/dev/null 2>&1)&
           rm -f ${mailFile};\
           )&
           if [ ! -z ${file_cnt} ]
           then
             if [ ${file_cnt} -gt 15 ]
              then
               echo "$(date)::${CURRENT_SEQ_OF_MOTION}::SOMETHING WRONG WITH Start/Stop sequences, trying to fix now. :: FILE COUNT: ${file_cnt}" >> ${OWN_LOG}
               # grep 518 /tmp/motion.log 
               # [1] [NTC] [ALL] [Jul 23 18:14:25] motion_detected: Motion detected - starting event 518
               # [1] [NTC] [ALL] [Jul 23 18:15:08] motion_loop: End of event 518
               MOTION_LOG_LINES="$(grep ${CURRENT_SEQ_OF_MOTION} /tmp/motion.log)"
               log_start_found="NO"
               log_finish_found="NO"
               echo "$MOTION_LOG_LINES" | grep -q "Motion detected - starting event ${CURRENT_SEQ_OF_MOTION}" && log_start_found="YES"
               echo "$MOTION_LOG_LINES" | grep -q "motion_loop: End of event ${CURRENT_SEQ_OF_MOTION}" && log_finish_found="YES"
                if [ "x${log_start_found}" == "xYES" -a "x${log_finish_found}" == "xYES" ]
                 then
                   echo "$(date)::${CURRENT_SEQ_OF_MOTION}::SOMETHING WRONG WITH Start/Stop sequences, start/stop found in motion.log. :: FILE COUNT: ${file_cnt}" >> ${OWN_LOG}
                   echo "$(date)::${CURRENT_SEQ_OF_MOTION}::SOMETHING WRONG WITH Start/Stop sequences, part of motion.log. :: FILE COUNT: ${file_cnt}" >> ${OWN_LOG}
                   echo "${MOTION_LOG_LINES}" >> ${OWN_LOG}
                   echo "$(date)::${CURRENT_SEQ_OF_MOTION}::SOMETHING WRONG WITH Start/Stop sequences, end of part of motion.log. :: FILE COUNT: ${file_cnt}" >> ${OWN_LOG}
                   echo "$(date)::${CURRENT_SEQ_OF_MOTION}::SOMETHING WRONG WITH Start/Stop sequences, working_here.. kill bash with ${CURRENT_SEQ_OF_MOTION} in cmdline.. :: FILE COUNT: ${file_cnt}" >> ${OWN_LOG}
                   currentPID=$$
                   pid_to_kill=$(ps -ef | grep bash | grep my_motion_watcher | grep ${CURRENT_SEQ_OF_MOTION} | awk '{print $2}')
                   echo "$(date)::${CURRENT_SEQ_OF_MOTION}::SOMETHING WRONG WITH Start/Stop sequences, Current PID: $currentPID; Determinated PID to kill: $pid_to_kill"  >> ${OWN_LOG}
                   echo "$(date)::${CURRENT_SEQ_OF_MOTION}::SOMETHING WRONG WITH Start/Stop sequences, Killing Determinated PID to kill: $pid_to_kill"  >> ${OWN_LOG}
                   kill -9 $pid_to_kill
                   
                fi
             fi
          fi
       fi
    else
      continue
    fi
  done

if [ -f "${MOTION_STOP_FILE}" ] 
  then
   echo "$(date)::${CURRENT_SEQ_OF_MOTION}::Motion finished" >> ${OWN_LOG}
   if [ -z $LOW_TIME_STAMP ]
    then 
     LOW_TIME_STAMP=$(date "+%Y-%m-%d %H:%M:%S" -d '+ 65 seconds' )
     echo "$(date)::${CURRENT_SEQ_OF_MOTION}::LOW TIME STAMP REMEMBERED: ${LOW_TIME_STAMP}, high timestamp: ${HIGH_TIME_STAMP}" >> ${OWN_LOG}
   else
     echo "$(date)::${CURRENT_SEQ_OF_MOTION}::LOW TIME STAMP ALREADY REMEMBERED: ${LOW_TIME_STAMP}" ${OWN_LOG}
   fi
   ALL_FILES_SENT="START"
   for filesLast in $(find ${TARGETDIR} -type f -newermt "${HIGH_TIME_STAMP}" -not -newermt "${LOW_TIME_STAMP}")
    do
     grep -q "${filesLast}" ${PROCEEDED_FILES_LOG} && ALL_FILES_SENT="${ALL_FILES_SENT}:YES" || ALL_FILES_SENT="${ALL_FILES_SENT}:NO"
     echo "$(date)::${CURRENT_SEQ_OF_MOTION}::File: ${filesLast} " >> ${OWN_LOG}
     echo "$(date)::${CURRENT_SEQ_OF_MOTION}::LOW TIME STAMP: ${LOW_TIME_STAMP}, high timestamp: ${HIGH_TIME_STAMP}" >> ${OWN_LOG}
     echo "$(date)::${CURRENT_SEQ_OF_MOTION}::$(ls -l ${filesLast}) " >> ${OWN_LOG}
    done
   
   echo "$(date)::${CURRENT_SEQ_OF_MOTION}::ALL FILES SENT: ${ALL_FILES_SENT}" >> ${OWN_LOG} 
   READY_TO_EXIT="NO"
   echo "${ALL_FILES_SENT}" | grep -q "NO" && READY_TO_EXIT="NO" || READY_TO_EXIT="YES"
   if [ "x${READY_TO_EXIT}" == "xYES" ]
    then
    echo "$(date)::${CURRENT_SEQ_OF_MOTION}::ALL FILE SENT. EXIT" >> ${OWN_LOG} 
    rm -f ${MOTION_STOP_FILE}
    sleep 5
    break
   fi
  fi
echo "$(date)::${CURRENT_SEQ_OF_MOTION}::Sleep 15 in  while loop"  >> ${OWN_LOG}
sleep 15
done


Скрипт /var/lib/motion/bin/myrec_stop.sh:

#!/bin/bash
DEB="/tmp/deb.log"

if [ -z ${1} ]
then
exit 0
fi

if [ -z ${2} ]
then
exit 0
fi

TARGETDIR="/tmp"
STOPfILE="/var/lib/motion/stop_sms"
if [ -f "${STOPfILE}" ]
then :
else
 SEQ=${1}
 message="- $(date +%d/%m/%y\ %H:%M:%S) ${SEQ}"
 LOG='/tmp/smsd.log'
 NUMBER="+380XXXXXXXXX"
 /usr/bin/sudo /usr/bin/gammu-smsd-inject TEXT "${NUMBER}" -text "${message}" 1>>$LOG 2>&1
 /bin/rm -f $LOG
fi


stopTELEGRAMMfILE='/var/lib/motion/stop_telegramm'
if [ -f "$stopTELEGRAMMfILE" ]
then :
else
    SEQ=${1}
    message="- $(date +%d/%m/%y\ %H:%M:%S) ${SEQ}"
    /home/pi/bin/notify_me.sh "${message}" &
fi


SEQ="${1}"
FILE="${2}"

if [ -f /tmp/motion_start_file_${SEQ} ]
 then
  /usr/bin/touch /tmp/motion_stop_file_${SEQ}
  /bin/rm -f /tmp/motion_start_file_${SEQ}
fi

/bin/bash /home/pi/bin/popup_android-stop.sh &
/bin/bash /home/pi/bin/5min_mon.sh stop "${SEQ}" &

MOTION_LOG_FILE=/var/log/motion_history.log
echo "- $(date +%d/%m/%y\ %H:%M:%S) ${SEQ}" >> ${MOTION_LOG_FILE}

[править] mjpg_streamer

В данный момент используется версия:

pi@rpi3:~/mjpg-streamer/mjpg-streamer $ ./mjpg_streamer -v
MJPG Streamer Version: 3:172M
Compilation Date.....: Sep 27 2016
Compilation Time.....: 05:24:36

Источник: https://sourceforge.net/projects/mjpg-streamer/

mjpg_streamer запускается при старте ОС из /etc/rc.local:

...
...
if [ -L /dev/doorcam ]
then
    sudo -u motion sh -c 'sleep 4; /home/pi/motion-main/motion -c /etc/motion/motion.conf'
    pulseaudio --system=true -D
    sleep 2
    /bin/bash /home/pi/bin/my_writer.sh &
    /bin/bash /home/pi/bin/myMicrophoneStartupSound.sh &
    /bin/bash /home/pi/bin/myPidMon.sh &
    /bin/bash /home/pi/bin/my_mjpg_streamer_starter.sh &
fi
...
...

скриптом /home/pi/bin/my_mjpg_streamer_starter.sh:

#!/bin/bash
#set -x
UPTIME=0
UPTIME=$(/bin/cat /proc/uptime  | /usr/bin/cut -f1 -d' ' | /bin/sed 's/\..*//g')
if [ ${UPTIME} -lt 80 ]
then
 sleep 12
fi

(/usr/local/bin/mjpg_streamer -i "/usr/local/lib/input_uvc.so -q 100 -d /dev/video3 -r 384x504 -f 3 -y" -o "/usr/local/lib/output_http.so -n -w /home/pi/my_tmp_www" 2>>/tmp/v4l2Mysink_deb.log)&

В итоге будет процесс:

pi@rpi3:~ $ ps -ef | grep mjp
root      5977     1  9 Mar24 ?        20:24:41 /usr/local/bin/mjpg_streamer -i /usr/local/lib/input_uvc.so -q 100 -d /dev/video3 -r 384x504 -f 3 -y -o /usr/local/lib/output_http.so -n -w /home/pi/my_tmp_www

И доступ к стриму по url http://RPi_ip:8080/?action=stream