Преглед на файлове

add second stream to rtsp

Alfonso Gamboa преди 3 години
родител
ревизия
ad42670438
променени са 6 файла, в които са добавени 168 реда и са изтрити 30 реда
  1. 18 9
      README.md
  2. 13 3
      SD_ROOT/wz_mini/etc/init.d/v3_post.sh
  3. BIN
      SD_ROOT/wz_mini/lib/libcallback.so
  4. 61 14
      SD_ROOT/wz_mini/run_mmc.sh
  5. BIN
      libcallback_wz_mod/libcallback.so
  6. 76 4
      libcallback_wz_mod/video_callback.c

+ 18 - 9
README.md

@@ -183,23 +183,31 @@ ENABLE_NFSv4="true"
 
 ---
 RTSP streaming:
-You can choose to enable or disable audio.  Set your login credentials here, server listening port, and the stream bitrate.
-(RTSP_ENC_PARAMETER variable accepts numbers only.  0=FIXQP, 1=CBR, 2=VBR, 4=CAPPED VBR, 8=CAPPED QUALITY.  Currently only 2, 4, and 8 are working)
+The RTSP server outputs the two supported video streams from the camera, 1080p/360p (1296p/480p for the DB3).  You can choose to enable a single stream of your choice, or both.  Audio is also available.  Set your login credentials here, server listening port, and the stream bitrate.
+(ENC_PARAMETER variable accepts numbers only.  0=FIXQP, 1=CBR, 2=VBR, 4=CAPPED VBR, 8=CAPPED QUALITY.  Currently only 2, 4, and 8 are working)
 
 ```
-RTSP_ENABLED="true"
-RTSP_ENABLE_AUDIO="true"
 RTSP_LOGIN="admin"
 RTSP_PASSWORD=""
-RTSP_PORT="8554"
-RTSP_MAX_BITRATE="2048"
-RTSP_TARGET_BITRATE="1024"
-RTSP_ENC_PARAMETER="2"
+
+RTSP_HI_RES_ENABLED="true"
+RTSP_HI_RES_ENABLE_AUDIO="true"
+RTSP_HI_RES_PORT="8554"
+RTSP_HI_RES_MAX_BITRATE="2048"
+RTSP_HI_RES_TARGET_BITRATE="1024"
+RTSP_HI_RES_ENC_PARAMETER="2"
+
+RTSP_LOW_RES_ENABLED="false"
+RTSP_LOW_RES_ENABLE_AUDIO="false"
+RTSP_LOW_RES_PORT="8555"
+RTSP_LOW_RES_MAX_BITRATE=""
+RTSP_LOW_RES_TARGET_BITRATE=""
+RTSP_LOW_RES_ENC_PARAMETER=""
 
 ```
 the stream will be located at ```rtsp://login:password@IP_ADDRESS:8554/unicast```
 
-Notes:  If you don't set the password, then the password will be the unique MAC address of the camera, in all uppercase, including the colons... for example:. AA:BB:CC:00:11:22.  It's typically printed on the camera.  VLC seems to work fine for playback, ffmpeg and others have severe artifacts in the stream during playback.
+Notes:  If you don't set the password, then the password will be the unique MAC address of the camera, in all uppercase, including the colons... for example:. AA:BB:CC:00:11:22.  It's typically printed on the camera.  Higher video bitrates may overload your Wi-Fi connection, so a wired connection is recommended.
 
 Huge credit to @mnakada for his libcallback library: [https://github.com/mnakada/atomcam_tools](https://github.com/mnakada/atomcam_tools)
 
@@ -207,6 +215,7 @@ Huge credit to @mnakada for his libcallback library: [https://github.com/mnakada
 
 ## Latest Updates
 
+* 05-15-22:  patched libcallback to support both video streams from the camera.  Added support for them in run_mmc.sh.
 * 05-14-22:  Added ability to specify RTSP bitrate parameters.  Note that changing bitrate in the mobile app will briefly reset the bitrate for the RTSP stream.
 * 05-14-22:  Update v4l2rtspserver, tinyalsa, alsa-lib.  Patch busybox for older official FW's failing to run scripts, fix choppy/static audio in libcallback
 * 05-09-22:  fix bug in run_mmc.sh that did not store the wlan mac when using a wired usb or ethernet connection for the rtsp server

+ 13 - 3
SD_ROOT/wz_mini/etc/init.d/v3_post.sh

@@ -11,11 +11,21 @@ set -x
 
 echo "v3_post.sh exec"
 
-if [[ $(cat /opt/wz_mini/run_mmc.sh | grep "RTSP_ENABLED\=") == "RTSP_ENABLED\=\"true\"" ]] && ! [[ -e /tmp/dbgflag ]]; then
+
+if [[ $(cat /opt/wz_mini/run_mmc.sh | grep "RTSP_HI_RES_ENABLED\=") == "RTSP_HI_RES_ENABLED\=\"true\"" ]] ||  [[ $(cat /opt/wz_mini/run_mmc.sh | grep "RTSP_LOW_RES_ENABLED\=") == "RTSP_LOW_RES_ENABLED\=\"true\"" ]] && ! [[ -e /tmp/dbgflag ]]; then
+	if [[ $(cat /opt/wz_mini/run_mmc.sh | grep "RTSP_LOW_RES_ENABLED\=") == "RTSP_LOW_RES_ENABLED\=\"true\"" ]] && [[ $(cat /opt/wz_mini/run_mmc.sh | grep "RTSP_HI_RES_ENABLED\=") == "RTSP_HI_RES_ENABLED\=\"true\"" ]]; then
+	        echo "load video loopback driver at video1 video2"
+	        insmod /opt/wz_mini/lib/modules/v4l2loopback.ko video_nr=1,2
+	elif [[ $(cat /opt/wz_mini/run_mmc.sh | grep "RTSP_LOW_RES_ENABLED\=") == "RTSP_LOW_RES_ENABLED\=\"true\"" ]]; then
+	        echo "load video loopback driver at video2"
+	        insmod /opt/wz_mini/lib/modules/v4l2loopback.ko video_nr=2
+	elif [[ $(cat /opt/wz_mini/run_mmc.sh | grep "RTSP_HI_RES_ENABLED\=") == "RTSP_HI_RES_ENABLED\=\"true\"" ]]; then
+	        echo "load video loopback driver at video1"
+	        insmod /opt/wz_mini/lib/modules/v4l2loopback.ko video_nr=1
+	fi
+
         cp /system/bin/iCamera /opt/wz_mini/tmp/.storage/
         mount -o ro,bind /opt/wz_mini/usr/bin/iCamera /system/bin/iCamera
-        echo "load video loopback driver at video1"
-        insmod /opt/wz_mini/lib/modules/v4l2loopback.ko video_nr=1
 fi
 
 ##LIBRARY DEBUG

BIN
SD_ROOT/wz_mini/lib/libcallback.so


+ 61 - 14
SD_ROOT/wz_mini/run_mmc.sh

@@ -30,14 +30,22 @@ REMOTE_SPOTLIGHT="false"
 REMOTE_SPOTLIGHT_HOST="0.0.0.0"
 
 #####VIDEO STREAM#####
-RTSP_ENABLED="false"
-RTSP_ENABLE_AUDIO="false"
 RTSP_LOGIN="admin"
 RTSP_PASSWORD=""
-RTSP_PORT="8554"
-RTSP_MAX_BITRATE=""
-RTSP_TARGET_BITRATE=""
-RTSP_ENC_PARAMETER=""
+
+RTSP_HI_RES_ENABLED="false"
+RTSP_HI_RES_ENABLE_AUDIO="false"
+RTSP_HI_RES_PORT="8554"
+RTSP_HI_RES_MAX_BITRATE=""
+RTSP_HI_RES_TARGET_BITRATE=""
+RTSP_HI_RES_ENC_PARAMETER=""
+
+RTSP_LOW_RES_ENABLED="false"
+RTSP_LOW_RES_ENABLE_AUDIO="false"
+RTSP_LOW_RES_PORT="8555"
+RTSP_LOW_RES_MAX_BITRATE=""
+RTSP_LOW_RES_TARGET_BITRATE=""
+RTSP_LOW_RES_ENC_PARAMETER=""
 
 #####GENERAL#####
 ENABLE_SWAP="true"
@@ -345,7 +353,7 @@ else
 	echo "remote accessory disabled"
 fi
 
-if [[ "$RTSP_ENABLED" == "true" ]]; then
+if [[ "$RTSP_HI_RES_ENABLED" == "true" ]]; then
 
 	if [[ "$ENABLE_SWAP" == "true" ]]; then
 	echo "swap already enabled"
@@ -361,23 +369,22 @@ if [[ "$RTSP_ENABLED" == "true" ]]; then
 	RTSP_PASSWORD=$(cat /opt/wz_mini/tmp/wlan0_mac)
 	fi
 
-        if [[ "$RTSP_ENABLE_AUDIO" == "true" ]]; then
-                LD_LIBRARY_PATH=/media/mmc/wz_mini/lib /media/mmc/wz_mini/bin/v4l2rtspserver -C 1 -a S16_LE  /dev/video1,hw:Loopback,0 -U $RTSP_LOGIN:$RTSP_PASSWORD -P $RTSP_PORT &
+        if [[ "$RTSP_HI_RES_ENABLE_AUDIO" == "true" ]]; then
+                LD_LIBRARY_PATH=/media/mmc/wz_mini/lib /media/mmc/wz_mini/bin/v4l2rtspserver -C 1 -a S16_LE  /dev/video1,hw:Loopback,0 -U $RTSP_LOGIN:$RTSP_PASSWORD -P $RTSP_HI_RES_PORT &
         else
                 echo "rtsp audio disabled"
-                LD_LIBRARY_PATH=/media/mmc/wz_mini/lib /media/mmc/wz_mini/bin/v4l2rtspserver -s /dev/video1 -U $RTSP_LOGIN:$RTSP_PASSWORD -P $RTSP_PORT &
+                LD_LIBRARY_PATH=/media/mmc/wz_mini/lib /media/mmc/wz_mini/bin/v4l2rtspserver -s /dev/video1 -U $RTSP_LOGIN:$RTSP_PASSWORD -P $RTSP_HI_RES_PORT &
         fi
 
-
-	if [[ "$RTSP_ENC_PARAMETER" != "" ]]; then
+	if [[ "$RTSP_HI_RES_ENC_PARAMETER" != "" ]]; then
 	watch -n5 -t "/system/bin/impdbg --enc_rc_s 0:44:4:$RTSP_ENC_PARAMETER" > /dev/null 2>&1 &
 	fi
 
-	if [[ "$RTSP_MAX_BITRATE" != "" ]]; then
+	if [[ "$RTSP_HI_RES_MAX_BITRATE" != "" ]]; then
 	watch -n5 -t "/system/bin/impdbg --enc_rc_s 0:48:4:$RTSP_MAX_BITRATE" > /dev/null 2>&1 &
 	fi
 
-	if [[ "$RTSP_TARGET_BITRATE" != "" ]]; then
+	if [[ "$RTSP_HI_RES_TARGET_BITRATE" != "" ]]; then
 	watch -n5 -t "/system/bin/impdbg --enc_rc_s 0:52:4:$RTSP_TARGET_BITRATE" > /dev/null 2>&1 &
 	fi
 
@@ -386,6 +393,46 @@ if [[ "$RTSP_ENABLED" == "true" ]]; then
 
 fi
 
+if [[ "$RTSP_LOW_RES_ENABLED" == "true" ]]; then
+
+	if [[ "$ENABLE_SWAP" == "true" ]]; then
+	echo "swap already enabled"
+	else
+	swap_enable
+	fi
+
+	/opt/wz_mini/bin/cmd video on1
+	/opt/wz_mini/bin/cmd audio on
+
+
+	if [[ "$RTSP_PASSWORD" = "" ]]; then
+	RTSP_PASSWORD=$(cat /opt/wz_mini/tmp/wlan0_mac)
+	fi
+
+        if [[ "$RTSP_LOW_RES_ENABLE_AUDIO" == "true" ]]; then
+                LD_LIBRARY_PATH=/media/mmc/wz_mini/lib /media/mmc/wz_mini/bin/v4l2rtspserver -C 1 -a S16_LE  /dev/video2,hw:Loopback,0 -U $RTSP_LOGIN:$RTSP_PASSWORD -P $RTSP_LOW_RES_PORT &
+        else
+                echo "rtsp audio disabled"
+                LD_LIBRARY_PATH=/media/mmc/wz_mini/lib /media/mmc/wz_mini/bin/v4l2rtspserver -s /dev/video2 -U $RTSP_LOGIN:$RTSP_PASSWORD -P $RTSP_LOW_RES_PORT &
+        fi
+
+	if [[ "$RTSP_LOW_RES_ENC_PARAMETER" != "" ]]; then
+	watch -n5 -t "/system/bin/impdbg --enc_rc_s 1:44:4:$RTSP_ENC_PARAMETER" > /dev/null 2>&1 &
+	fi
+
+	if [[ "$RTSP_LOW_RES_MAX_BITRATE" != "" ]]; then
+	watch -n5 -t "/system/bin/impdbg --enc_rc_s 1:48:4:$RTSP_MAX_BITRATE" > /dev/null 2>&1 &
+	fi
+
+	if [[ "$RTSP_LOW_RES_TARGET_BITRATE" != "" ]]; then
+	watch -n5 -t "/system/bin/impdbg --enc_rc_s 1:52:4:$RTSP_TARGET_BITRATE" > /dev/null 2>&1 &
+	fi
+
+        else
+        echo "rtsp disabled"
+
+fi
+
 touch /opt/wz_mini/tmp/.run_mmc_firstrun
 sync;echo 3 > /proc/sys/vm/drop_caches
 sleep 3

BIN
libcallback_wz_mod/libcallback.so


+ 76 - 4
libcallback_wz_mod/video_callback.c

@@ -19,7 +19,9 @@ typedef int (* framecb)(struct frames_st *);
 
 static int (*real_local_sdk_video_set_encode_frame_callback)(int ch, void *callback);
 static void *video_encode_cb = NULL;
+static void *video_encode_cb1 = NULL;
 static int VideoCaptureEnable = 0;
+static int VideoCaptureEnable1 = 0;
 
 char *VideoCapture(int fd, char *tokenPtr) {
 
@@ -27,12 +29,22 @@ char *VideoCapture(int fd, char *tokenPtr) {
   if(!p) return VideoCaptureEnable ? "on" : "off";
   if(!strcmp(p, "on")) {
     VideoCaptureEnable = 1;
-    fprintf(stderr, "[command] video capute on\n", p);
+    fprintf(stderr, "[command] video capture ch0 on\n", p);
+    return "ok";
+  }
+  if(!strcmp(p, "on1")) {
+    VideoCaptureEnable1 = 1;
+    fprintf(stderr, "[command] video capture ch1 on\n", p);
     return "ok";
   }
   if(!strcmp(p, "off")) {
     VideoCaptureEnable = 0;
-    fprintf(stderr, "[command] video capute off\n", p);
+    fprintf(stderr, "[command] video capture ch0 off\n", p);
+    return "ok";
+  }
+  if(!strcmp(p, "off1")) {
+    VideoCaptureEnable1 = 0;
+    fprintf(stderr, "[command] video capture ch1 off\n", p);
     return "ok";
   }
   return "error";
@@ -43,6 +55,7 @@ static uint32_t video_encode_capture(struct frames_st *frames) {
   static int firstEntry = 0;
   static int v4l2Fd = -1;
 
+//primary stream 0
   if(!firstEntry) {
     firstEntry++;
     int err;
@@ -86,19 +99,78 @@ static uint32_t video_encode_capture(struct frames_st *frames) {
   return ((framecb)video_encode_cb)(frames);
 }
 
+//secondary stream 1
+static uint32_t video_encode_capture1(struct frames_st *frames) {
+
+  static int firstEntry = 0;
+  static int v4l2Fd = -1;
+
+  if(!firstEntry) {
+    firstEntry++;
+    int err;
+    const char *v4l2_device_path = "/dev/video2";
+    const char *productf="/configs/.product_db3";
+    fprintf(stderr,"Opening V4L2 device: %s \n", v4l2_device_path);
+    v4l2Fd = open(v4l2_device_path, O_WRONLY, 0777);
+    if(v4l2Fd < 0) fprintf(stderr,"Failed to open V4L2 device: %s\n", v4l2_device_path);
+    struct v4l2_format vid_format;
+    memset(&vid_format, 0, sizeof(vid_format));
+    vid_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+    if( access( productf, F_OK ) == 0 ) {
+                /* doorbell resolution */
+                printf("[command] video product 640x480");
+                vid_format.fmt.pix.width = 640;
+                vid_format.fmt.pix.height = 480;
+    } else {
+                /* v3 and panv2 res */
+                printf("[command] video product 640x320");
+                vid_format.fmt.pix.width = 640;
+                vid_format.fmt.pix.height = 320;
+    }
+
+    vid_format.fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
+    vid_format.fmt.pix.sizeimage = 0;
+    vid_format.fmt.pix.field = V4L2_FIELD_NONE;
+    vid_format.fmt.pix.bytesperline = 0;
+    vid_format.fmt.pix.colorspace = V4L2_PIX_FMT_YUV420;
+    err = ioctl(v4l2Fd, VIDIOC_S_FMT, &vid_format);
+    if(err < 0) fprintf(stderr,"Unable to set V4L2 device video format: %d\n", err);
+    err = ioctl(v4l2Fd, VIDIOC_STREAMON, &vid_format);
+    if(err < 0) fprintf(stderr,"Unable to perform VIDIOC_STREAMON: %d\n", err);
+  }
+
+  if( (v4l2Fd >= 0) && VideoCaptureEnable) {
+    uint32_t *buf = frames->buf;
+    int size = write(v4l2Fd, frames->buf, frames->length);
+    if(size != frames->length) fprintf(stderr,"Stream write error: %s\n", size);
+  }
+  return ((framecb)video_encode_cb1)(frames);
+}
+
+
+
 int local_sdk_video_set_encode_frame_callback(int ch, void *callback) {
 
   fprintf(stderr, "local_sdk_video_set_encode_frame_callback streamChId=%d, callback=0x%x\n", ch, callback);
   static int ch_count = 0;
 
-/* two callbacks typically detected, unknown what the difference is between them, but if they are both hooked, the app breaks. grab just one of them. */
-
+/* two callbacks for video stream 0 are typically detected, unknown what the difference is between them, but if they are both hooked, the app breaks. grab just one of them. */
+  //stream 0
   if( (ch == 0) && ch_count == 2) {
     video_encode_cb = callback;
     fprintf(stderr,"enc func injection save video_encode_cb=0x%x\n", video_encode_cb);
     callback = video_encode_capture;
   }
     fprintf(stderr,"ch count is %x\n", ch_count);
+
+  //stream 1
+  if( (ch == 1) && ch_count == 1) {
+    video_encode_cb1 = callback;
+    fprintf(stderr,"enc func injection save video_encode_cb=0x%x\n", video_encode_cb1);
+    callback = video_encode_capture1;
+  }
+
     ch_count=ch_count+1;
 
   return real_local_sdk_video_set_encode_frame_callback(ch, callback);