raspberrypi / picamera2

New libcamera based python library
BSD 2-Clause "Simplified" License
824 stars 176 forks source link

[HOW-TO] Use Hardware JPEG encoder #752

Open julled opened 1 year ago

julled commented 1 year ago

Describe what it is that you want to accomplish I want to use the hardware JPEG encoder to encode single images (in contrast to MJPEG) which is used in the former picamera1 stack.

Describe alternatives you've considered I thought of using the MJPEG encoder which claims to use the hardware encoders, but i want to use it for single frames instead of video frames.

Additional context

davidplowman commented 1 year ago

Unfortunately we haven't written code that uses the MJPEG encoder for still images. With things like bitrates and framerates it's not an ideal match. That said, would a workaround like this be any use?

import io
import threading

from picamera2 import Picamera2
from picamera2.encoders import MJPEGEncoder
from picamera2.outputs import FileOutput

picam2 = Picamera2()
picam2.start()
main_stream = picam2.stream_map["main"]

class MyOutput(io.BufferedIOBase):
    def __init__(self, filename):
        self.filename = filename
        self.event = threading.Event()

    def write(self, buf):
        with open(self.filename, 'wb') as f:
            f.write(buf)
        self.event.set()

    def wait_for_frame(self):
        self.event.wait()
        self.event.clear()

mjpeg_encoder = MJPEGEncoder()
mjpeg_encoder.framerate = 30
mjpeg_encoder.size = config["main"]["size"]
mjpeg_encoder.format = config["main"]["format"]
mjpeg_encoder.bitrate = 5000000
my_output = MyOutput("out.jpg")
mjpeg_encoder.output = FileOutput(my_output)
mjpeg_encoder.start()

request = picam2.capture_request()
mjpeg_encoder.encode(main_stream, request)
request.release()
my_output.wait_for_frame()

It's a little tricky because the video encoders run asynchronously, so we have to find a way to get a signal from them when it's all finished. Though once it's set up, you should be able just to repeat those last 4 lines every time you want to do a capture.