roleoroleo / yi-hack-Allwinner-v2

Custom firmware for Yi 1080p camera based on Allwinner platform
MIT License
794 stars 91 forks source link

Support for new YiCamera #528

Closed DGA45 closed 1 year ago

DGA45 commented 1 year ago

Hi, I bought a camera (https://fr.aliexpress.com/item/1005004622553546.html) which is finally a Yi camera. It is based on a FH8632 SoC, so the YiHack does not work as it is. I succeeded to log using serial connection, and then to modify a debug.sh on /tmp/sd to get root access and ftp. I found a similar file structure than your hack, as well as a /dev/shm/fshare_frame_buf file. I used BuildRoot to recompile your tools and try them. Unfortunately, the frames format is not the same (I tried all the existing models). The closest model seems to be the "QG311R" one. With this one, I am able to make a snapshot with "imggrabber" but only in low resolution. The high resolution is crashing in the first "avcodec_send_packet" function call ("Killed" is reported in the bash). With the same configuration (low resolution QG311R), rRTSPServer is not finding any frames (frozen on "Waiting for stream type (autodetection)...).

I attached 4 copies of my fshare_frame_buf file: fshare_frame_buf_YiCam A35I.zip Would you mind having a look to it ? Maybe you will find which "buffer offset" and "frame header size" I should change so that this camera is supported ? I tried by myself but I still have not enough knowledge on the H264/HEVC formats and the tools I found were not able to decode also the fshare_frame_buf file :(

Thanks a lot for your help, best regards

roleoroleo commented 1 year ago

Codec is h264. SPS are different from Allwinner and Allwinner-v2. 00 00 00 01 67 4D 00 32 8D 8D 40 12 00 51 D0 80 00 05 DC 00 00 AF C8 02 <--- 2304 x 1296 00 00 00 01 67 4D 00 16 8D 8D 40 50 17 FC B0 80 00 05 DC 00 00 AF C8 02 <--- 640 x 368 PPS: 00 00 00 01 68 EE 38 80 The frame header is 26 bytes length, for example: 08 00 00 00 30 10 00 00 10 35 52 63 26 C5 A7 01 CD 46 1F F9 04 04 8B 05 00 00 Probably the buffer offset is 300. But there is a "big" difference: SPS and PPS are repeated twice. The parser should consider it. So the source code must be adapted.

imggrabber should work because it doesn't search a fixed byte sequence. Probably it fails with high res due to a memory problem.

DGA45 commented 1 year ago

Thanks a lot ! Regarding the imggrabber, you were right, it was a memory issue. I had the whole Yi application running, plus a ftpd and I compiler with static libraries, thus it was remaining about only 3-4MB of memory. I killed all the Yi application, except the rmm, and then imggrabber is working in high resolution mode.

I updated rRTSPServer to remove the auto-detection (it was not working) and to not update the SPS timing info (since the SPS/PPS headers are only used here). Unfortunately, now I have a "segmentation fault" when VLC is connecting on it (low or high resolution). This might be related to the fact that "SPS and PPS are repeated twice" as you noted. You said that the source code must be adapted, could you tell me more ? Should I skip repeated frames or is there other things to do ?

roleoroleo commented 1 year ago

You should re-enable autodetect adding a definition for your SPSs. For example, for high res:

unsigned char SPS4_4_2304X1296[]    = {0x00, 0x00, 0x00, 0x01, 0x67 0x4D, 0x00, 0x32,
                0x8D, 0x8D, 0x40, 0x12, 0x00, 0x51, 0xD0, 0x80,
                0x00, 0x05, 0xDC, 0x00, 0x00, 0xAF, 0xC8, 0x02};

And disable sps_timing_info. Finally, when the frame is an IDR (fhs[i].type & 0x0001) you have to skip 59 bytes to skip the repetion of the SPS and PPS. The IDR frame must start with 00 00 00 01 65.

DGA45 commented 1 year ago

I did the previous actions, but I was getting a segmentation fault at VLC connection :( I finally build up also a full gdb for the FH8632 and was able to catch the faulty line, located in live555:

5 0x00042bf8 in snprintf (s=, n=,

fmt=0x53818 "v=0\r\no=- %ld%06ld %d IN %s %s\r\ns=%s\r\ni=%s\r\nt=0 0\r\na=tool:%s%s\r\na=type:broadcast\r\na=control:*\r\n%s%sa=x-qt-text-nam:%s\r\na=x-qt-text-inf:%s\r\n%s") at src/stdio/snprintf.c:9

6 0x00022e2c in ServerMediaSession::generateSDPDescription(int) ()

7 0x0001e3c4 in RTSPServer::RTSPClientConnection::handleCmd_DESCRIBE_afterLookup(ServerMediaSession*) ()

8 0x0001da78 in RTSPServer::RTSPClientConnection::handleCmd_DESCRIBE(char const, char const, char const*) ()

9 0x0001f708 in RTSPServer::RTSPClientConnection::handleRequestBytes(int) ()

10 0x00030e98 in BasicTaskScheduler::SingleStep(unsigned int) ()

11 0x00032130 in BasicTaskScheduler0::doEventLoop(char volatile*) ()

12 0x00010ca8 in main ()

What happens actually is that the time_t structure is defined as a 64 bits (long long int) on my target, while live555 assumes it is a 32bits (long int), since they use %ld. The compiler is also not casting automatically, thus the snprintf of %ld%06ld for fCreationTime.tv_sec and fCreationTime.tv_usec is passing wrong things on the stack (ie pushing 64bits values, instead of 32bits one).

I solved the segmentation fault by adding explicit casts in the snprintf call of ServerMediaSession.cpp: (long int)fCreationTime.tv_sec, (long int)fCreationTime.tv_usec, // o=

However, VLC is looping forever trying to connect but nothing is displayed, no error message... I am wondering if there could have other similar 64/32bits issue elsewhere in the code....

Is this something you already faced or due to my buildroot setup (I am using libmusl, and binaries statically linked) ?

roleoroleo commented 1 year ago

If you are not able to find somewhere the cross toolchain for FH8632 platform, you should try to create your own toolchain as close as possible to what you find inside the cam. You should check:

If I'm not wrong FH8632 is based on ARM1176, a 32 bit arm platform. So, if your cross-tolchain is ok, it must build a 32 bit application. I think that something is not ok on your buildroot. You could try to create the toolchain with crosstool-NG.

roleoroleo commented 1 year ago

Do you want to share with me a backup of the flash?

DGA45 commented 1 year ago

Yes, I got 32bits application. I noticed there were compiler warnings on the %ld (long int) time_t value (long long int) issue, thus I tried to cast all of them, but same result. There must have something else, I continue investigation :) Here is a backup of this camera

roleoroleo commented 1 year ago

Ok, you can remove it, if you want.

roleoroleo commented 1 year ago

There are 2 different versions of uClibc: 0.9.32.1 and 0.9.33.2. I don't know why. A lot of libs:

ld-uClibc-0.9.32.1.so
ld-uClibc-0.9.33.2.so
ld-uClibc.so.0 -> ld-uClibc-0.9.32.1.so
libatomic.so -> libatomic.so.1.2.0
libatomic.so.1 -> libatomic.so.1.2.0
libatomic.so.1.2.0
libcrypt-0.9.32.1.so
libcrypt-0.9.33.2.so
libcrypt.so.0 -> libcrypt-0.9.32.1.so
libc.so.0 -> libuClibc-0.9.32.1.so
libdl-0.9.32.1.so
libdl-0.9.33.2.so
libdl.so.0 -> libdl-0.9.32.1.so
libgcc_s.so -> libgcc_s.so.1
libgcc_s.so.1
libitm.so -> libitm.so.1.0.0
libitm.so.1 -> libitm.so.1.0.0
libitm.so.1.0.0
libm-0.9.32.1.so
libm-0.9.33.2.so
libm.so.0 -> libm-0.9.32.1.so
libnsl-0.9.33.2.so
libnsl.so.0 -> libnsl-0.9.33.2.so
libpthread-0.9.32.1.so
libpthread-0.9.33.2.so
libpthread.so.0 -> libpthread-0.9.32.1.so
libresolv-0.9.33.2.so
libresolv.so.0 -> libresolv-0.9.33.2.so
librt-0.9.32.1.so
librt-0.9.33.2.so
librt.so.0 -> librt-0.9.32.1.so
libthread_db-0.9.32.1.so
libthread_db-0.9.33.2.so
libthread_db.so.1 -> libthread_db-0.9.32.1.so
libuClibc-0.9.32.1.so
libuClibc-0.9.33.2.so
libutil-0.9.33.2.so
libutil.so.0 -> libutil-0.9.33.2.so

crosstool-NG 1.19.0

Many different gcc used: gcc 3.3.2 gcc 4.3.2 gcc 6.5.0

roleoroleo commented 1 year ago

Try this: https://airtake-public-data-1254153901.cos.ap-shanghai.myqcloud.com/smart/embed/pruduct/arm-fullhan-linux-uclibcgnueabi_0.0.3.zip

DGA45 commented 1 year ago

What is the host for this one ? I am using Ubuntu on Windows 11. The C++ located in toolchain\arm-fullhan-linux-uclibcgnueabi\bin is a 32bits one and I got a message when trying to execute (seems a dynamic library is missing/not found)

DGA45 commented 1 year ago

I attach also a log of the rRTSPServer with -d3 (rRTSPServer -d3 -rlow -s ). It seems that frames are detected, and when VLC is connecting, there are a few messages "RTSP doGetNextFrame()". But it stops quite quickly and this is probably why I have nothing on my VLC.

I send you the log if you have some clue rRTSPServer.log

roleoroleo commented 1 year ago

What is the host for this one ? I am using Ubuntu on Windows 11. The C++ located in toolchain\arm-fullhan-linux-uclibcgnueabi\bin is a 32bits one and I got a message when trying to execute (seems a dynamic library is missing/not found)

Check Makefile.rRTSPServer and compile.rRTSPServer: rRTSPServer.tar.gz Build process works on my debian.

roleoroleo commented 1 year ago

I send you the log if you have some clue rRTSPServer.log

After the last doGetNextFrame() there are no error. But it seems that the process is locked.

DGA45 commented 1 year ago

I finally understood the problem. The used socket number was always -1, thus nothing was really sent. After other investigation, I came to the root-cause: setting the option SO_REUSEPORT with setsockopt was failing, thus closing the socket. I just patched the function setupDatagramSocket in GroupsockHelper.cpp to not close the socket in case of error:

  if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT,
         (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
  #if 1  /* DGA PATCH */
    //fprintf(stderr, "DGA: newSocket=%d setopt SO_REUSEPORT reuseFlag %d ERROR\n", newSocket, reuseFlag);
    /* DGA: Do not close the socket, keep using it */
  #else 
    socketErr(env, "setsockopt(SO_REUSEPORT) error: ");
    closeSocket(newSocket);
    return -1;
  #endif
  }

and now this is working fine !

Not easy to debug the live555 library :( It seems there is no easy way to know if the connection is opened/closed/error state so that the application could handle it ?

roleoroleo commented 1 year ago

I don't remember the kernel version of your cam, but probably SO_REUSEPORT is not supported. Maybe SO_REUSEADDR could work.

and now this is working fine !

Can you see the stream?

Not easy to debug the live555 library :( It seems there is no easy way to know if the connection is opened/closed/error state so that the application could handle it ?

I agree, is very complex.

DGA45 commented 1 year ago

Yes, SO_REUSEADDR is working. I will see to create a change/improvement ticket in the live555 library to avoid closing the socket in case this option is not supported. Especially, they already managed the WIN32 case by doing nothing, thus the option seems not mandatory. Yes, I can see perfectly the streams now, both low and high res. The low resolution has a lower FPS (about 1-2 FPS), while the high res is much better, I am a bit surprised with that or is it due to some additional rescaling performed by the live555 library ?

roleoroleo commented 1 year ago

Other cams have 20 fps for both, high and low resolution. 1-2 fps is strange but live555 should not rescale the stream.

DGA45 commented 1 year ago

Hi ! I try now to add the IPC command on my camera. The ipc_cmd is compiling fine, but nothing happens (dispatch process is still running). I modified it to act as a sniffer of /dev/mqueue/IPC_dispatch but nothing is reported :( I think that dispatch process is getting the message before my sniffer. I saw that you implemented a shared library to redispatch the IPC message in multiple queues, but I do not see how you "inject" this library ? Is it in the original dispatch process or in the rmm one ? Do you use LD_PRELOAD trick ? If so, you have to set if before launching the executable ? I got segmentation fault every time I tried something similar :/

redphx commented 1 year ago

Hi @DGA45, how is the progress so far? I'm also trying to hack my Y4 camera with FH8632v2 SoC. Thanks.

roleoroleo commented 1 year ago

Yes, dispatch is started with LD_PRELOAD: https://github.com/roleoroleo/yi-hack-Allwinner-v2/blob/2880d36b8fa0e078679e3b046a0345048422bce0/sysroot/y21ga/lower_half_init.sh#L132

And, if you want, I have the source code of a sniffer.

DGA45 commented 1 year ago

Hi, I got initial access using serial connexion on the internal PCB. Then I was able to read the init.sh and lower_half_init.sh scripts. I found that the script /tmp/sd/debug.sh is executed at the end of the init.sh. I did not want to recreate a complete customized image as the YiHack, since I only wanted RTSP, PTZ and motion events. Thus I try adding things step-by-step in my own debug.sh: 1/ get root access:

passwd -d root

Be careful, this set no password for root (this is the only command working with the existing commands)

2/ get FTP access using inetd:

echo "22    stream  tcp nowait  root    /sbin/ftpd  /sbin/ftpd -w  / " >> /etc/inetd.conf
kill $(ps | grep inetd | grep -v "grep" | awk -F " " '{print $1}')

3/ kill unrequired programs:

kill $(ps | grep watch_process | grep -v "grep" | awk -F " " '{print $1}')
sleep 1
kill $(ps | grep p2p_tnp | grep -v "grep" | awk -F " " '{print $1}')
kill $(ps | grep cloud | grep -v "grep" | awk -F " " '{print $1}')
kill $(ps | grep oss | grep -v "grep" | awk -F " " '{print $1}')
kill $(ps | grep log_server | grep -v "grep" | awk -F " " '{print $1}')
kill $(ps | grep mp4record | grep -v "grep" | awk -F " " '{print $1}')
# Do not kill dispatch required to manage IPC events
#kill $(ps | grep dispatch | grep -v "grep" | awk -F " " '{print $1}')
# Do not kill rmm  required to generate the /dev/shm/fshare_frame_buf file (video frames)

4/ recompile some binaries using BuildRoot and lib musl:

It's about one month I did not continue working on it since RTSP was working and I wanted to use this stream on my Raspberry Pi3 to make some human detection with OpenCV (security system), but struggling with low memory (again) :(

redphx commented 1 year ago

@DGA45 correct me if I'm wrong, but I think you could load your own lower_half_init.sh file on SD card by modifying the last line in /backup/init.sh. You can see roleo did the same in Factory/config.sh, but it didn't work for this camera because the last line didn't match.

So the process should be:

  1. Use debug.sh to patch /backup/init.sh, then remove it + reboot.
  2. From now on it will load the lower_half_init.sh file on your SD card instead. You should able to fix your problem with IPC injection.

What do you think?

I only want RTSP & to be able to take screenshot with this camera and use it for creating timelapse in OctoPrint.

DGA45 commented 1 year ago

Yes, but I did not want to change the original firmware, that's why I did everything from the debug.sh. Regarding your goal to take screenshot, I also recompiled the imggrabber binary and it is working fine. So with a basic httpd/cgi-bin + imggrabber, that could do the job

redphx commented 1 year ago

@DGA45 thank you! Any requirements for the build process (SDK, host, build script...)? Sorry I'm new to this. I'll try to work on this this weekend.

DGA45 commented 1 year ago

Here is my current project: SDCard.tar.gz Just unzip the content in your SDCard and reboot your cam. If this is working, you should be able to log on it using telnet or FTP with user "root" and no password, and to connect to the Httpd server (port 8080) with cgi-bin and imggrabber. If not working, you can have a look on the SD Card (with your computer) if you have a debug_log.txt file on it. If so, it means that the debug.sh is starting, if not this means that my "hack" is not working on your cam.

redphx commented 1 year ago

@DGA45 thanks so much!

pmariett commented 1 year ago

@DGA45 Thanks for sharing your work. On mine the rtsp works but not the PTZ commands. I tried handling @redphx to patch the init.sh but bad idea, the camera is KO now. No more boot, no more sounds. I continue in standalone mode on the second.

DGA45 commented 1 year ago

Yes, this was my fear to kill my only cam :(, hence the trick thru the debug.sh. Regarding the PTZ not working, do you mean by using the WWW interface (cgi-bin) ? Actually, the binary ipc_cmd binary is working on mine, but I did not updated all the WWW pages/scripts to have it working thru the web server (typically the paths are not the same between the www server and my SD card). You can try if the ipc_cmd is working on yours, and then I can have a look to update the www server

stale[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

dingiso commented 2 months ago

Hi @DGA45 and @roleoroleo,

Thank you for your contribution. I have extracted the SDcard.tar.gz file onto the SD card and inserted it into my camera. The telnet connection works fine. However, I'm encountering an issue with the RTSP debug log, which outputs the following error:

RTSP doGetNextFrame() error - wrong frame header

I'm unsure how to resolve this problem. Any tips or suggestions would be greatly appreciated.

While I'm not certain if we have the same camera model, it seems we share the same chipset - FH8632.

Processor       : ARMv6-compatible processor rev 7 (v6l)
BogoMIPS        : 479.23
Features        : swp half thumb fastmult vfp edsp java 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xb76
CPU revision    : 7

Hardware        : FH8632
Revision        : 0000
Serial          : 0000000000000000

Thank you, Dingisoul