add second stream to rtsp

This commit is contained in:
Alfonso Gamboa 2022-05-15 18:36:36 -07:00
parent 94b2aad718
commit ad42670438
6 changed files with 168 additions and 30 deletions

View File

@ -183,23 +183,31 @@ ENABLE_NFSv4="true"
--- ---
RTSP streaming: RTSP streaming:
You can choose to enable or disable audio. Set your login credentials here, server listening port, and the stream bitrate. 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.
(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) (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_LOGIN="admin"
RTSP_PASSWORD="" RTSP_PASSWORD=""
RTSP_PORT="8554"
RTSP_MAX_BITRATE="2048" RTSP_HI_RES_ENABLED="true"
RTSP_TARGET_BITRATE="1024" RTSP_HI_RES_ENABLE_AUDIO="true"
RTSP_ENC_PARAMETER="2" 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``` 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) 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 ## 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: 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-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 * 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

View File

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

Binary file not shown.

View File

@ -30,14 +30,22 @@ REMOTE_SPOTLIGHT="false"
REMOTE_SPOTLIGHT_HOST="0.0.0.0" REMOTE_SPOTLIGHT_HOST="0.0.0.0"
#####VIDEO STREAM##### #####VIDEO STREAM#####
RTSP_ENABLED="false"
RTSP_ENABLE_AUDIO="false"
RTSP_LOGIN="admin" RTSP_LOGIN="admin"
RTSP_PASSWORD="" RTSP_PASSWORD=""
RTSP_PORT="8554"
RTSP_MAX_BITRATE="" RTSP_HI_RES_ENABLED="false"
RTSP_TARGET_BITRATE="" RTSP_HI_RES_ENABLE_AUDIO="false"
RTSP_ENC_PARAMETER="" 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##### #####GENERAL#####
ENABLE_SWAP="true" ENABLE_SWAP="true"
@ -345,7 +353,7 @@ else
echo "remote accessory disabled" echo "remote accessory disabled"
fi fi
if [[ "$RTSP_ENABLED" == "true" ]]; then if [[ "$RTSP_HI_RES_ENABLED" == "true" ]]; then
if [[ "$ENABLE_SWAP" == "true" ]]; then if [[ "$ENABLE_SWAP" == "true" ]]; then
echo "swap already enabled" echo "swap already enabled"
@ -361,23 +369,22 @@ if [[ "$RTSP_ENABLED" == "true" ]]; then
RTSP_PASSWORD=$(cat /opt/wz_mini/tmp/wlan0_mac) RTSP_PASSWORD=$(cat /opt/wz_mini/tmp/wlan0_mac)
fi fi
if [[ "$RTSP_ENABLE_AUDIO" == "true" ]]; then 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_PORT & 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 else
echo "rtsp audio disabled" 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 fi
if [[ "$RTSP_HI_RES_ENC_PARAMETER" != "" ]]; then
if [[ "$RTSP_ENC_PARAMETER" != "" ]]; then
watch -n5 -t "/system/bin/impdbg --enc_rc_s 0:44:4:$RTSP_ENC_PARAMETER" > /dev/null 2>&1 & watch -n5 -t "/system/bin/impdbg --enc_rc_s 0:44:4:$RTSP_ENC_PARAMETER" > /dev/null 2>&1 &
fi 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 & watch -n5 -t "/system/bin/impdbg --enc_rc_s 0:48:4:$RTSP_MAX_BITRATE" > /dev/null 2>&1 &
fi 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 & watch -n5 -t "/system/bin/impdbg --enc_rc_s 0:52:4:$RTSP_TARGET_BITRATE" > /dev/null 2>&1 &
fi fi
@ -386,6 +393,46 @@ if [[ "$RTSP_ENABLED" == "true" ]]; then
fi 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 touch /opt/wz_mini/tmp/.run_mmc_firstrun
sync;echo 3 > /proc/sys/vm/drop_caches sync;echo 3 > /proc/sys/vm/drop_caches
sleep 3 sleep 3

Binary file not shown.

View File

@ -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 int (*real_local_sdk_video_set_encode_frame_callback)(int ch, void *callback);
static void *video_encode_cb = NULL; static void *video_encode_cb = NULL;
static void *video_encode_cb1 = NULL;
static int VideoCaptureEnable = 0; static int VideoCaptureEnable = 0;
static int VideoCaptureEnable1 = 0;
char *VideoCapture(int fd, char *tokenPtr) { char *VideoCapture(int fd, char *tokenPtr) {
@ -27,12 +29,22 @@ char *VideoCapture(int fd, char *tokenPtr) {
if(!p) return VideoCaptureEnable ? "on" : "off"; if(!p) return VideoCaptureEnable ? "on" : "off";
if(!strcmp(p, "on")) { if(!strcmp(p, "on")) {
VideoCaptureEnable = 1; 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"; return "ok";
} }
if(!strcmp(p, "off")) { if(!strcmp(p, "off")) {
VideoCaptureEnable = 0; 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 "ok";
} }
return "error"; return "error";
@ -43,6 +55,7 @@ static uint32_t video_encode_capture(struct frames_st *frames) {
static int firstEntry = 0; static int firstEntry = 0;
static int v4l2Fd = -1; static int v4l2Fd = -1;
//primary stream 0
if(!firstEntry) { if(!firstEntry) {
firstEntry++; firstEntry++;
int err; int err;
@ -86,19 +99,78 @@ static uint32_t video_encode_capture(struct frames_st *frames) {
return ((framecb)video_encode_cb)(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) { 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); fprintf(stderr, "local_sdk_video_set_encode_frame_callback streamChId=%d, callback=0x%x\n", ch, callback);
static int ch_count = 0; 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) { if( (ch == 0) && ch_count == 2) {
video_encode_cb = callback; video_encode_cb = callback;
fprintf(stderr,"enc func injection save video_encode_cb=0x%x\n", video_encode_cb); fprintf(stderr,"enc func injection save video_encode_cb=0x%x\n", video_encode_cb);
callback = video_encode_capture; callback = video_encode_capture;
} }
fprintf(stderr,"ch count is %x\n", ch_count); 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; ch_count=ch_count+1;
return real_local_sdk_video_set_encode_frame_callback(ch, callback); return real_local_sdk_video_set_encode_frame_callback(ch, callback);