raspberrypi / picamera2

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

[HOW-TO] Don't take a photo after record #988

Open tranhien1612 opened 5 months ago

tranhien1612 commented 5 months ago

Hi, i am using picame2 to write a simple code to take a photo and record video. Receiver the data from TCPClient and capture or record.

import time
import os
import socket
import threading
from datetime import datetime

from picamera2 import Picamera2
from picamera2.encoders import H264Encoder
from picamera2.outputs import FfmpegOutput
from picamera2.outputs import FileOutput

picam2 = Picamera2();
isRecord = False;
isPhoto = False;

def camera():
  global picam2;
  global isRecord;
  global isPhoto;

  print("Start Camera")
  picam2.configure(picam2.create_video_configuration())
  picam2.start()

  try:
    while True:

      if(isPhoto):
        print("Start Photo")
        filename = "/home/raspi/img/"+ datetime.now().strftime("%d-%m-%Y-%H-%M-%S") + ".jpg";
        #picam2.start_and_capture_file(filename)

        #cfg = picam2.create_still_configuration()
        #picam2.switch_mode_and_capture_file(cfg, filename)

        picam2.capture_file(filename)
        isPhoto = False;

      if(isRecord):
        print("Start Video")
        filename = "/home/raspi/video/"+ datetime.now().strftime("%d-%m-%Y-%H-%M-%S") + ".mp4";
        #picam2.video_configuration.format = 'BGR888';
        picam2.start_and_record_video(filename, duration=900); #15p

  except Exception as e:
    print(f"Error: {str(e)}")

def handle_client(client_socket, client_addr):
    print(f"Connection from {client_addr}")
    thread = threading.Thread(target=camera, name='camera')
    thread.start()

    global picam2;
    global isRecord;
    global isPhoto;
    try:
        while True:
            # Receive data from the client
            data = client_socket.recv(1024)

            if not data:
                break  # No more data received, exit loop
            dataHexa = data.hex();
            #print(dataHexa)
            if(dataHexa == '01'):
              isPhoto = True;
            elif(dataHexa == '02' and isRecord == False):
              isRecord = True;
            elif(dataHexa == '03' and isRecord == True):
              print("Stop Video")
              picam2.stop_recording()
              isRecord = False;

            # Echo back the received data
            #client_socket.sendall(data)
    except Exception as e:
        print(f"Error: {str(e)}")
    finally:
        # Close the client socket
        client_socket.close()
        print(f"Connection with {client_addr} closed")
        thread.join()

def start_server(host, port):
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind((host, port))
    server_socket.listen(5)  # Accept up to 5 connections
    print(f"TCP server started on {host}:{port}")
    while True:
        # Wait for a client to connect
        print("Waiting for connection...")
        client_socket, client_addr = server_socket.accept()

        # Start a new thread to handle the client connection
        client_thread = threading.Thread(target=handle_client, args=(client_socket, client_addr))
        client_thread.start()

if __name__ == "__main__":
    start_server('0.0.0.0', 5765) 

when I record, then stop recording. After that I couldn't record or take photos. It seems that when using the recording command and stopping recording, subsequent commands cannot be executed pls support me to fix it.

davidplowman commented 5 months ago

Hi, it would be easier if you could condense your example to maybe a dozen lines or so, basically the simplest thing you can manage that shows the problem. Otherwise we have to spend time working out how to run your code and figure out exactly what the code is doing. Would that be possible?

Having said that, I see you're using the start_and_... methods. I really would avoid that - they were put on only for folks who "just want to call one function" and don't really want any control over it. But if you can create a very short standalone script that demonstrates the problem, then that would be great and would make it obvious how to reproduce the issue. I'm thinking something like:

from picamera2 import Picamera2

picam2 = Picamera2()
picam2.start_and_record_video("test.h264", duration=10)
picam2.start_and_capture_file("test.jpg")

Thanks!

tranhien1612 commented 5 months ago

@davidplowman I have a simple code. But when i run code, i only record one time (don't take photo and record after first time)

from picamera2 import Picamera2 from picamera2.encoders import H264Encoder from picamera2.outputs import FfmpegOutput

picam2 = Picamera2() picam2.configure(picam2.create_video_configuration())

print("Start Record1") picam2.start_and_record_video("test.mp4", duration=5);

print("Photo2") picam2.capture_file("test1.jpg") time.sleep(1) print("Start Record2") picam2.start_and_record_video("test1.mp4", duration=5);

print("Photo3") picam2.capture_file("test2.jpg") time.sleep(1) print("Start Record3") picam2.start_and_record_video("test2.mp4", duration=5);

davidplowman commented 5 months ago

Hi again, and thanks for the simplified script. I just wanted to check that you know that start_and_record_video will wait for the recording to finish, and then stop the camera. After that, I expect picam2.capture_file("test1.jpg") will lock up because it's waiting for the camera which is no longer running.

Are you wanting to take pictures simultaneously with video, or one after the other?

tranhien1612 commented 5 months ago

@davidplowman Yes, I want to test the functions when taking pictures and recording videos sequentially. I have a question: when executing the start_and_record_video function, if I call stop_recording while the start_and_record_video function is being executed, will I still take photos or record videos afterward?

tranhien1612 commented 5 months ago

@davidplowman I want to be able to take photos, record and stop video recording at any time. Can you suggest me a list of functions to perform this task? In addition, I also want to stream video through rtsp, but I still haven't found an example for this idea

davidplowman commented 5 months ago

I think you'd do better to avoid the start_and_... functions. I would configure and start the camera, and then just leave it running. Then you can use start_encoder and stop_encoder at any time to start recording. You can also use capture_file at any time if the camera is running.

Here are some examples that might help:

tranhien1612 commented 5 months ago

@davidplowman Thanks, I wnat to record with .mp4 file and take photos. I went through your instructions and i have a simple code like below. Is this code what you mean?

import time
from picamera2 import Picamera2
from picamera2.outputs import FfmpegOutput
from picamera2.encoders import H264Encoder

picam2 = Picamera2()
video_config = picam2.create_video_configuration()
picam2.configure(video_config)

encoder = H264Encoder(10000000)
output = FfmpegOutput("test.mp4", audio=True)
# Start Record
picam2.start_recording(encoder, output)
time.sleep(10)
picam2.stop_recording()

# Take Photos
picam2.capture_file("test.jpg")
davidplowman commented 5 months ago

Hi, I think that's close. stop_recording will stop the camera, so either:

tranhien1612 commented 5 months ago

@davidplowman thank you!. tomorrow, i will test this code. Thank you for your support!

tranhien1612 commented 5 months ago

@davidplowman i tried the example capture_stream_udp.py, i change ip to my ip latop and received data. i want to change the file format "mkv" or "mov" or "mp4" . Can i change it by code?

davidplowman commented 5 months ago

I think the FfmpegOutput detects the format from the filename, so many formats other than mp4 should work. Have you tried this?

tranhien1612 commented 5 months ago

@davidplowman I want to record video twice with the command start_recording, but when I stop with the command stop_record, both stop. I want to stop one of the two, how do I do that?

tranhien1612 commented 5 months ago

Tôi nghĩ rằng nó FfmpegOutputphát hiện định dạng từ tên tệp, vì vậy nhiều định dạng khác ngoài mp4 sẽ hoạt động. Bạn đã thử cái này chưa? i don`t try this command.

davidplowman commented 5 months ago

If you have started two encoders then use stop_encoder. You should be able to stop one encoder and leave the other running. See for example https://github.com/raspberrypi/picamera2/blob/main/examples/capture_video_multiple_2.py.

tranhien1612 commented 5 months ago

@davidplowman how can i increase the fps when streaming and recording video? Currently, the fps is 11 when i use the picam2.start_encoder for recording and picam2.start_recording(H264Encoder(bitrate=1000000), output=FfmpegOutput( "-f rtp udp://192.168.1.27:10001")); for streaming. I want to increase the fps to 30fps.

tranhien1612 commented 5 months ago

@davidplowman i am using :

        video_config = self.picam2.create_video_configuration(
                    main   ={"size": (1920, 1080)}, 
                    lores  ={"size": (1280, 720)}, 
                    raw    ={"size": (4056, 3040)}, 
                    controls = {"FrameRate": 30.0},
                ); 

main, lorse for recording and streaming and raw for taking photos. with size windows of raw, i see the fps max is 14 fps. i changed the size windows of raw to (1920, 1080), then the fps is 30fps. But i want to take photos with max resolution, but with max resolution of taking photo, the fps is slow. Can you give me some suggestion?

davidplowman commented 5 months ago

Hi, I'm afraid that's a physical limitation of the hardware. At full resolution there are too many pixels to achieve 30fps so you have to choose either resolution or framerate.

scoles10 commented 1 month ago

Hi, I think that's close. stop_recording will stop the camera, so either:

  • Use stop_encoder instead. That should leave the camera running.
  • Or start the camera again (picam2.start()) before calling capture_file. There will be a short delay while the camera restarts.

Correct solution! Thanks!