Great thanks for your feedback.
I assume I do the wrong order.
I first want to see how camera connected to anything in a graph-component structure is working find to see that I understood connection and zero copying correctly.
I thought encoder , having a single input and single output port and having mostly default settings will be simple enough.
Here is a high-level view on what I am running now. I have cleared the code from error checking.In this versions I use still port to go for only a single capture tryign to simplify and this does not work
Camera component is created hereCreate encoder
Apply buffers:Same code kind of works if I remove encoder comlpetely from the formula and make camera output port as raw RGB24, zero copy.
Ok, but I go for very basic functionality that was in raspberry pi for years. Raspberry PI has cameras have been on the marker for a really long time and I always wanted to use them in my projects. My baremetal code can handle vchiq communication. And I go for a pretty standard functionality simple graphs, used in raspivid.c and elsewhere, advertising graph structure of mmal components. It should work I thing there are no bugs or issues in mmal itself that someone has to "support". The issue is that although the birds eye view on MMAL architecture is nice the details - such as in which order to enable components and ports, provide buffers is not clear.Sorry, MMAL is deprecated, and trying to support anything under bare metal is just too time consuming to be practical.
I assume I do the wrong order.
I first want to see how camera connected to anything in a graph-component structure is working find to see that I understood connection and zero copying correctly.
I thought encoder , having a single input and single output port and having mostly default settings will be simple enough.
Ok, but I dont see where is the flaw with my current logic. Encoder output upon creation requires only one buffer from me - 0x10000 (64k), which I provide, then it sends me this buffer with 0x1024 flags - END_OF_FRAME, CONFIG, END_OF_NAL. I don't know what that is , just release this back to mmal server with BUFFER_FROM_HOST command. If I submit more buffers that requested in port info, I receive this much "3" errors in the follow up EVENT_TO_HOST. So I figured I can not provide moreMESS:00:00:33.235649:0: mmalsrv: mmal_server_do_buffer_from_host: pool exhausted, recyling bust, on comp 56 port 2
Would be the clue I'd work with first. The port has a buffer ready to send to the host, went to collect a buffer header from the pool and found it empty. That pool is allocated at port_enable as a size of port->buffer_num.
Here is a high-level view on what I am running now. I have cleared the code from error checking.
Code:
static int vchiq_startup_camera(struct vchiq_service_common *mmal_service, struct vchiq_service_common *mems_service, int frame_width, int frame_height) { int err; struct mmal_cam_info cam_info = {0}; struct vchiq_mmal_port *cam_preview, *cam_video, *cam_still; struct vchiq_mmal_port *encoder_input, *encoder_output; err = vchiq_mmal_get_cam_info(mmal_service, &cam_info); err = create_camera_component(mmal_service, frame_width, frame_height, &cam_info.cameras[0], &cam_preview, &cam_video, &cam_still); err = create_encoder(mmal_service, &encoder_input, &encoder_output, frame_width, frame_height); err = vchiq_mmal_port_connect(cam_still, encoder_input); err = vchiq_mmal_port_enable(encoder_output); err = vchiq_mmal_port_enable(encoder_input); err = mmal_port_set_zero_copy(encoder_output); err = mmal_port_set_zero_copy(encoder_input); err = mmal_port_set_zero_copy(cam_still); /* This is just to try and create a bigger buffer for encoding purposes, but this does not help */ encoder_output->minimum_buffer.num = 1; encoder_output->minimum_buffer.size = 512 * 1024; err = mmal_apply_buffers(mems_service, encoder_output, true, 1); /* this is a set port paramter CAPTURE wrapper */ err = mmal_camera_capture_frames(cam_still); while(1) { asm volatile ("wfe"); } out_err: return err; }
Camera component is created here
Code:
static int create_camera_component(struct vchiq_service_common *mmal_service, int frame_width ,int frame_height, struct mmal_parameter_camera_info_camera_t *cam_info, struct vchiq_mmal_port **out_preview, struct vchiq_mmal_port **out_video, struct vchiq_mmal_port **out_still) { uint32_t param; uint32_t supported_encodings[MAX_SUPPORTED_ENCODINGS]; int num_encodings; struct vchiq_mmal_port *still, *video, *preview; int err; /* mmal_init start */ struct vchiq_mmal_component *cam = component_create(mmal_service, "ril.camera"); param = 0; err = vchiq_mmal_port_parameter_set(&cam->control, MMAL_PARAMETER_CAMERA_NUM, ¶m, sizeof(param)); err = vchiq_mmal_port_parameter_set(&cam->control, MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, ¶m, sizeof(param)); err = vchiq_mmal_port_enable(&cam->control); err = mmal_set_camera_parameters(cam, cam_info, frame_width, frame_height); preview = &cam->output[CAM_PORT_PREVIEW]; video = &cam->output[CAM_PORT_VIDEO]; still = &cam->output[CAM_PORT_CAPTURE]; err = mmal_port_get_supp_encodings(still, supported_encodings, sizeof(supported_encodings), &num_encodings); vchiq_mmal_local_format_fill(&preview->format, MMAL_ENCODING_OPAQUE, MMAL_ENCODING_I420, frame_width, frame_height, 3); err = vchiq_mmal_port_set_format(preview); vchiq_mmal_local_format_fill(&video->format, MMAL_ENCODING_OPAQUE, 0, frame_width, frame_height, 0); err = vchiq_mmal_port_set_format(video); vchiq_mmal_local_format_fill(&still->format, MMAL_ENCODING_OPAQUE, MMAL_ENCODING_I420, frame_width, frame_height, 0); err = vchiq_mmal_port_set_format(still); err = mmal_component_enable(cam); *out_preview = preview; *out_video = video; *out_still = still; out_err: return err; }
Code:
static int create_encoder(struct vchiq_service_common *mmal_service, struct vchiq_mmal_port **encoder_input, struct vchiq_mmal_port **encoder_output, int width, int height) { bool bool_arg; int err = SUCCESS; struct vchiq_mmal_component *encoder; struct mmal_parameter_video_profile video_profile; encoder = component_create(mmal_service, "ril.video_encode"); CHECK_ERR_PTR(encoder, "Failed to create component 'ril.video_encode'"); if (!encoder->inputs || !encoder->outputs) { MMAL_ERR("err: encoder has 0 outputs or inputs"); return ERR_GENERIC; } err = mmal_component_enable(encoder); CHECK_ERR("Failed to enable encoder"); *encoder_input = &encoder->input[0]; *encoder_output = &encoder->output[0]; err = vchiq_mmal_port_enable(&encoder->control); mmal_format_copy(&encoder->output[0].format, &encoder->input[0].format); encoder->output[0].format.encoding = MMAL_ENCODING_H264; encoder->output[0].format.encoding_variant = 0; encoder->output[0].format.bitrate = 25000000; encoder->output[0].format.es->video.frame_rate.num = 1; encoder->output[0].format.es->video.frame_rate.den = 0; encoder->output[0].format.es->video.width = width; encoder->output[0].format.es->video.height = height; encoder->output[0].format.es->video.crop.x = 0; encoder->output[0].format.es->video.crop.y = 0; encoder->output[0].format.es->video.crop.width = width; encoder->output[0].format.es->video.crop.height = height; err = vchiq_mmal_port_set_format(&encoder->output[0]); encoder->input[0].format.encoding = MMAL_ENCODING_OPAQUE; encoder->input[0].format.encoding_variant = MMAL_ENCODING_I420; encoder->input[0].format.es->video.frame_rate.num = 1; encoder->input[0].format.es->video.frame_rate.den = 0; encoder->input[0].format.es->video.width = width; encoder->input[0].format.es->video.height = height; encoder->input[0].format.es->video.crop.x = 0; encoder->input[0].format.es->video.crop.y = 0; encoder->input[0].format.es->video.crop.width = width; encoder->input[0].format.es->video.crop.height = height; err = vchiq_mmal_port_set_format(&encoder->input[0]); CHECK_ERR("Failed to set format for preview capture port"); video_profile.profile = MMAL_VIDEO_PROFILE_H264_HIGH; video_profile.level = MMAL_VIDEO_LEVEL_H264_4; err = vchiq_mmal_port_parameter_set(&encoder->output[0], MMAL_PARAMETER_PROFILE, &video_profile, sizeof(video_profile)); CHECK_ERR("Failed to set h264 encoder parameter");
Apply buffers:
Code:
static int mmal_apply_buffers(struct vchiq_service_common *mems_service, struct vchiq_mmal_port *p, bool zero_copy, size_t min_buffers) { err = mmal_alloc_port_buffers(mems_service, p, min_buffers); err = mmal_port_buffer_send_all(p); } static int mmal_alloc_port_buffers(struct vchiq_service_common *mems_service, struct vchiq_mmal_port *p, size_t min_buffers) { int err; size_t i; struct mmal_buffer *buf; size_t num_buffers = p->minimum_buffer.num; if (num_buffers < min_buffers) num_buffers = min_buffers; for (i = 0; i < num_buffers; ++i) { buf = dma_alloc(sizeof(*buf)); buf->buffer_size = p->minimum_buffer.size; buf->buffer = dma_alloc(buf->buffer_size); if (p->zero_copy) err = vc_sm_cma_import_dmabuf(mems_service, buf, &buf->vcsm_handle); list_add_tail(&buf->list, &p->buffers); } }static int mmal_port_buffer_send_all(struct vchiq_mmal_port *p) { int err; struct mmal_buffer *b; list_for_each_entry(b, &p->buffers, list) err = vchiq_mmal_buffer_from_host(p, b); }
Statistics: Posted by valc — Fri May 10, 2024 5:00 am