• Tags
  • Documentation
  • Order
  • Register
  • Login
Duet3D Logo Duet3D
  • Tags
  • Documentation
  • Order
  • Register
  • Login

Setting up video streaming using raspberry pi

Scheduled Pinned Locked Moved
Third-party software
3
7
414
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • undefined
    OwenD
    last edited by OwenD 29 Mar 2024, 03:51

    Recently I had to set up a Raspberry Pi is camera to use as a monitoring device for my printer.
    I found that pretty much all the online information was outdated and had no end trouble getting it to work on the current version of Pi OS (Bullseye Bookworm).
    The entire camera and video handling system has changed over the years.
    So I decided to document what worked for me.
    In the end it was relatively easy (once you knew the correct steps0

    I must first point out I know bugger all about Linux.
    All this work is taken from bits and pieces I found on various sites and cobbled together, so my apologies for not crediting the original author(s)

    NOTE: These instructions were done using a Raspberry Pi 4 running Bullseye Bookworm 64 bit and an official Pi camera
    Also if you're running RRF in SBC mode, you don't need to do this as I believe it has a built in camera setup.

    The first step is to install the OS using the Pi Imager
    https://www.raspberrypi.com/software/

    step1.png

    When prompted, choose your user name, password and Wifi details.
    NOTE: The current version no longer uses the default user pi and password raspberry

    when you get to this point, click on "edit settings"
    step2.png

    Enable SSH so that you can connect to the Pi via PUTTY rather than always needing a monitor and keyboard.
    If you installed a Pi OS that has a desktop you can use the inbuilt command line terminal for all the steps listed below.

    Then click on YES to apply the settings.

    Once the image has been loaded onto the SD card, insert the card in your Pi and start it up.

    Start Putty (or some other terminal) and SSH into the Pi
    If you used the default settings, you should be able to go to
    raspberrypi.local
    step4.png

    You should see something like this
    putty.png

    You may get any updates/upgrade by using these commands

    sudo apt update
    
    sudo apt upgrade
    
    sudo apt install

    Change directory

    cd /usr/local/bin/

    Open a text edior

    sudo nano streamVideo.py

    Paste in the following code

    #!/usr/bin/python3
    # This is the same as mjpeg_server.py, but uses the h/w MJPEG encoder.
    import io
    import logging
    import socketserver
    from http import server
    from threading import Condition
    from picamera2 import Picamera2
    from picamera2.encoders import MJPEGEncoder
    from picamera2.outputs import FileOutput
    PAGE = """\
    <html>
    <head>
    <title>3D Printer Camera</title>
    </head>
    <body>
    <img src="stream.mjpg" width="800" height="600" />
    </body>
    </html>
    """
    class StreamingOutput(io.BufferedIOBase):
    def __init__(self):
    self.frame = None
    self.condition = Condition()
    def write(self, buf):
    with self.condition:
    self.frame = buf
    self.condition.notify_all()
    class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
    if self.path == '/':
    self.send_response(301)
    self.send_header('Location', '/index.html')
    self.end_headers()
    elif self.path == '/index.html':
    content = PAGE.encode('utf-8')
    self.send_response(200)
    self.send_header('Content-Type', 'text/html')
    self.send_header('Content-Length', len(content))
    self.end_headers()
    self.wfile.write(content)
    elif self.path == '/stream.mjpg':
    self.send_response(200)
    self.send_header('Age', 0)
    self.send_header('Cache-Control', 'no-cache, private')
    self.send_header('Pragma', 'no-cache')
    self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
    self.end_headers()
    try:
    while True:
    with output.condition:
    output.condition.wait()
    frame = output.frame
    self.wfile.write(b'--FRAME\r\n')
    self.send_header('Content-Type', 'image/jpeg')
    self.send_header('Content-Length', len(frame))
    self.end_headers()
    self.wfile.write(frame)
    self.wfile.write(b'\r\n')
    except Exception as e:
    logging.warning(
    'Removed streaming client %s: %s',
    self.client_address, str(e))
    else:
    self.send_error(404)
    self.end_headers()
    class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True
    picam2 = Picamera2()
    picam2.configure(picam2.create_video_configuration(main={"size": (640, 480)}))
    output = StreamingOutput()
    picam2.start_recording(MJPEGEncoder(), FileOutput(output))
    try:
    address = ('', 8888)
    server = StreamingServer(address, StreamingHandler)
    server.serve_forever()
    finally:
    picam2.stop_recording()

    Press CTRL + X to exit and choose Y to save file

    change directory

    cd /etc/systemd/system
    

    Open the text editor to create a system service file

    sudo nano streamVideo.service

    Paste in the following code

    [Unit]
    Description=A script for straming video to http
    After=syslog.target network.target
    [Service]
    WorkingDirectory=/usr/local/bin/
    ExecStart=/usr/bin/python3 /usr/local/bin/streamVideo.py
    Restart=always
    RestartSec=120
    [Install]
    WantedBy=multi-user.target

    PRess CTRL + X
    press Y and enter to save

    Enter the following to reload the daemon

    sudo systemctl daemon-reload

    Enable the service

    sudo systemctl enable streamVideo.service

    You should see something like
    Created symlink /etc/systemd/system/multi-user.target.wants/streamVideo.service → /etc/systemd/system/streamVideo.service.

    Restart the Pi

    sudo shutdown -r now

    After the Pi has rebooted, you should be able to access the stream by going to the following URL in your browser

    http://raspberrypi.local:8888/index.html

    In DWC you need to enter this URL on order to get the stream

    http://raspberrypi.local:8888/stream.mjpg

    dwc.png

    Your video stream should now be visible in the Webcam tab
    webcam.png

    I hope this saves someone some frustration.

    undefined 1 Reply Last reply 30 Mar 2024, 07:23 Reply Quote 4
    • undefined
      OwenD @OwenD
      last edited by OwenD 30 Mar 2024, 07:23

      I have done a bit more tinkering in an effort to get a high and low resolution stream.

      I'm not sure it's the "right" way to go about this as I have no python or Pi experience, but it appears to work.
      CPU usage doesn't appear high in use.
      Perhaps someone more knowledgeable than I can correct or enhance it.

      This is the main file that replaces streamVideo.py above

      #!/usr/bin/python3
      # This is the same as mjpeg_server.py, but uses the h/w MJPEG encoder.
      import io
      import logging
      import socketserver
      import libcamera
      from http import server
      from threading import Condition
      from libcamera import controls
      from picamera2 import Picamera2
      from picamera2.encoders import MJPEGEncoder
      from picamera2.outputs import FileOutput
      PAGE = """\
      <html>
      <head>
      <title>3D Printer Camera</title>
      </head>
      <body>
      <H2> Camera Feed Low Res</H2>
      <img src="lores.mjpg" width="640" height="480" />
      <H2> Camera Feed Hi Res</H2>
      <img src="stream.mjpg" width="1280" height="720" />
      </body>
      </html>
      """
      class StreamingOutput(io.BufferedIOBase):
      def __init__(self):
      self.frame = None
      self.condition = Condition()
      def write(self, buf):
      with self.condition:
      self.frame = buf
      self.condition.notify_all()
      class StreamingHandler(server.BaseHTTPRequestHandler):
      def do_GET(self):
      if self.path == '/':
      self.send_response(301)
      self.send_header('Location', '/index.html')
      self.end_headers()
      elif self.path == '/index.html':
      content = PAGE.encode('utf-8')
      self.send_response(200)
      self.send_header('Content-Type', 'text/html')
      self.send_header('Content-Length', len(content))
      self.end_headers()
      self.wfile.write(content)
      elif self.path == '/stream.mjpg':
      self.send_response(200)
      self.send_header('Age', 0)
      self.send_header('Cache-Control', 'no-cache, private')
      self.send_header('Pragma', 'no-cache')
      self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
      self.end_headers()
      try:
      while True:
      with output1.condition:
      output1.condition.wait()
      frame = output1.frame
      self.wfile.write(b'--FRAME\r\n')
      self.send_header('Content-Type', 'image/jpeg')
      self.send_header('Content-Length', len(frame))
      self.end_headers()
      self.wfile.write(frame)
      self.wfile.write(b'\r\n')
      except Exception as e:
      logging.warning(
      'Removed streaming client %s: %s',
      self.client_address, str(e))
      elif self.path == '/lores.mjpg':
      self.send_response(200)
      self.send_header('Age', 0)
      self.send_header('Cache-Control', 'no-cache, private')
      self.send_header('Pragma', 'no-cache')
      self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
      self.end_headers()
      try:
      while True:
      with output2.condition:
      output2.condition.wait()
      frame = output2.frame
      self.wfile.write(b'--FRAME\r\n')
      self.send_header('Content-Type', 'image/jpeg')
      self.send_header('Content-Length', len(frame))
      self.end_headers()
      self.wfile.write(frame)
      self.wfile.write(b'\r\n')
      except Exception as e:
      logging.warning(
      'Removed streaming client %s: %s',
      self.client_address, str(e))
      else:
      self.send_error(404)
      self.end_headers()
      class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
      allow_reuse_address = True
      daemon_threads = True
      picam2 = Picamera2()
      picam2.video_configuration.enable_lores()
      #adjust resolution as required
      main_resolution = (1280, 720)
      low_resolution= (640, 480)
      #adjust hflip/vflip to 0 or 1 to flip horizontally or vertically
      orientation=libcamera.Transform(hflip=1, vflip=1)
      video_config = picam2.create_video_configuration(main={"size": main_resolution, "format": "RGB888"},
      lores={"size": low_resolution, "format": "YUV420"},
      transform=orientation)
      picam2.configure(video_config)
      output1 = StreamingOutput()
      output2 = StreamingOutput()
      output = [output1,output2]
      encoder1=MJPEGEncoder()
      encoder2=MJPEGEncoder()
      picam2.start_recording(encoder1, FileOutput(output1))
      picam2.start_recording(encoder2, FileOutput(output2),name="lores")
      picam2.set_controls({"AfMode": controls.AfModeEnum.Continuous}) # set autofocus
      try:
      address = ('', 8888)
      server = StreamingServer(address, StreamingHandler)
      server.serve_forever()
      finally:
      picam2.stop_recording()

      Then change the DWC setup so that the standard view is the low res stream and clicking on that opens the high res stream

      Low res link
      http://raspberrypi.local:8888/lores.mjpg

      Hi Res link
      http://raspberrypi.local:8888/stream.mjpg

      hilow.png

      droftartsundefined 1 Reply Last reply 30 Mar 2024, 08:50 Reply Quote 2
      • droftartsundefined
        droftarts administrators @OwenD
        last edited by 30 Mar 2024, 08:50

        @OwenD thanks for this! I guess this is mainly for a RPi running NOT as an SBC connected to a Duet? Though I’d imagine it could work like that too.

        You say this is on Bullseye, but Bookworm is the latest RPi OS, see https://www.raspberrypi.com/software/operating-systems/
        I think there were quite a few changes to the camera sub-system, so may be worth updating and running through your instructions and see if they still work. I’m going to do the same thing next week with the instructions here: https://docs.duet3d.com/en/User_manual/Reference/DWC_webcam#motion-on-a-raspberry-pi-running-dsf

        Ian

        Bed-slinger - Mini5+ WiFi/1LC | RRP Fisher v1 - D2 WiFi | Polargraph - D2 WiFi | TronXY X5S - 6HC/Roto | CNC router - 6HC | Tractus3D T1250 - D2 Eth

        undefined 1 Reply Last reply 30 Mar 2024, 09:00 Reply Quote 0
        • oliofundefined
          oliof
          last edited by 30 Mar 2024, 08:55

          very good write up.

          In the Klipper world the solution to camera streaming is crowsnest but since that's a mountain of shell scripts I am not super convinced it's something I would recommend people to use unless prepackaged. It does have some nice features like multiple camera support for nozzle cams and the likes, so maybe it's worth looking at for inspiration.

          <>RatRig V-Minion Fly Super5Pro RRF<> V-Core 3.1 IDEX k*****r <> RatRig V-Minion SKR 2 Marlin<>

          1 Reply Last reply Reply Quote 0
          • undefined
            OwenD @droftarts
            last edited by 30 Mar 2024, 09:00

            @droftarts said in Setting up video streaming using raspberry pi:

            @OwenD thanks for this! I guess this is mainly for a RPi running NOT as an SBC connected to a Duet? Though I’d imagine it could work like that too.

            Yes, it's for those of us that choose not to run SBC

            You say this is on Bullseye, but Bookworm is the latest RPi OS, see https://www.raspberrypi.com/software/operating-systems/

            My mistake!
            It's actually Bookworm that I'm running.

            cat /etc/os-release
            PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
            NAME="Debian GNU/Linux"
            VERSION_ID="12"
            VERSION="12 (bookworm)"
            VERSION_CODENAME=bookworm
            ID=debian
            HOME_URL="https://www.debian.org/"
            SUPPORT_URL="https://www.debian.org/support"
            BUG_REPORT_URL="https://bugs.debian.org/"

            I think there were quite a few changes to the camera sub-system, so may be worth updating and running through your instructions and see if they still work. I’m going to do the same thing next week with the instructions here: https://docs.duet3d.com/en/User_manual/Reference/DWC_webcam#motion-on-a-raspberry-pi-running-dsf

            Ian

            Yes, there have been many changes which rendered most of the tutorials online useless.
            I had to try to cobble this together from various documents in the picamera documentation.

            droftartsundefined 1 Reply Last reply 30 Mar 2024, 09:18 Reply Quote 0
            • droftartsundefined
              droftarts administrators @OwenD
              last edited by 30 Mar 2024, 09:18

              @OwenD great! I was wondering if you meant Bookworm, as there were parts I didn’t recognise from previous times I’d messed around with it on Buster and Bullseye.

              According to @chrishamm Motion at least provides 32 and 64 bit versions.

              Ian

              Bed-slinger - Mini5+ WiFi/1LC | RRP Fisher v1 - D2 WiFi | Polargraph - D2 WiFi | TronXY X5S - 6HC/Roto | CNC router - 6HC | Tractus3D T1250 - D2 Eth

              1 Reply Last reply Reply Quote 0
              • undefined
                OwenD
                last edited by OwenD 31 Mar 2024, 22:53

                I found another application that works quite easily and has the benefit of being able to adjust all the settings from the web interface.

                It's called picamera2-WebUI-Lite

                webui-lite-screen.png

                There's a slight error on the instructions to install and it doesn't tell you how to set it up as a service, so I've listed thesteps.

                To install.

                SSH into your PI (or open a terminal if using a desktop)

                Change directory

                cd /usr/local/bin/

                Clone the repositry

                 sudo git clone https://github.com/monkeymademe/picamera2-WebUI-Lite.git
                

                Change directory

                cd /usr/local/bin/picamera2-WebUI-Lite 
                

                Test that it's running

                 python3 app.py 
                

                Open your browser and go to
                http://raspberrypi.local:8080/

                To see just the video feed go to
                http://raspberrypi.local:8080/video_feed

                Go back to the terminal and hot CTRL + C to shut the app down

                To set it up as a service
                Change directory

                cd /etc/systemd/system
                

                Open a text editor to create a system service file

                sudo nano webui-lite.service

                Paste in the following

                [Unit]
                Description=Start script for WebUi-Lite as a service
                After=syslog.target network.target
                [Service]
                WorkingDirectory=/usr/local/bin/picamera2-WebUI-Lite/
                ExecStart=/usr/bin/python3 /usr/local/bin//picamera2-WebUI-Lite/app.py
                Restart=always
                RestartSec=120
                [Install]
                WantedBy=multi-user.target

                Press CTRL + X to exit and Y to save

                Reload the daemon

                sudo systemctl daemon-reload

                Enable the service

                sudo systemctl enable webui-lite.service

                NOTE that if you already have the other streamVideo service I listed above using Picamera you will have to disable it as you can't run both.

                sudo systemctl disable streamVideo.service
                

                Reboot the system to make sure the service starts

                sudo shutdown -r now

                Adjust your DWC settings as follows
                webui.png

                This will allow you to easily get to the settings page by clicking on the webcam image in DWC
                From there adjust your resolution and you can also zoom in a particular area using the scaler crop settings.

                Full view
                fullscreen.png

                Cropped view
                zoomed.png

                1 Reply Last reply Reply Quote 4
                1 out of 7
                • First post
                  1/7
                  Last post
                Unless otherwise noted, all forum content is licensed under CC-BY-SA