192 lines
5.9 KiB
C
192 lines
5.9 KiB
C
#include "camera.h"
|
|
|
|
#include "device/buffer.h"
|
|
#include "device/buffer_list.h"
|
|
#include "device/device.h"
|
|
#include "device/device_list.h"
|
|
#include "device/links.h"
|
|
#include "util/opts/log.h"
|
|
#include "util/opts/fourcc.h"
|
|
#include "device/buffer_list.h"
|
|
#include "util/http/http.h"
|
|
#include "output/rtsp/rtsp.h"
|
|
#include "output/output.h"
|
|
|
|
static const char *jpeg_names[2] = {
|
|
"JPEG",
|
|
"JPEG-LOW"
|
|
};
|
|
|
|
static link_callbacks_t jpeg_callbacks[2] = {
|
|
{ "JPEG-CAPTURE", http_jpeg_capture, http_jpeg_needs_buffer },
|
|
{ "JPEG-LOW-CAPTURE", http_jpeg_lowres_capture, http_jpeg_needs_buffer }
|
|
};
|
|
|
|
static const char *h264_names[2] = {
|
|
"H264",
|
|
"H264-LOW"
|
|
};
|
|
|
|
static void h264_capture(buffer_t *buf)
|
|
{
|
|
http_h264_capture(buf);
|
|
rtsp_h264_capture(buf);
|
|
}
|
|
|
|
static void h264_lowres_capture(buffer_t *buf)
|
|
{
|
|
http_h264_lowres_capture(buf);
|
|
rtsp_h264_low_res_capture(buf);
|
|
}
|
|
|
|
static bool h264_needs_buffer()
|
|
{
|
|
return http_h264_needs_buffer() | rtsp_h264_needs_buffer();
|
|
}
|
|
|
|
static link_callbacks_t h264_callbacks[2] = {
|
|
{ "H264-CAPTURE", h264_capture, h264_needs_buffer },
|
|
{ "H264-LOW-CAPTURE", h264_lowres_capture, h264_needs_buffer }
|
|
};
|
|
|
|
static int camera_configure_h264_output(camera_t *camera, buffer_list_t *src_capture, int res)
|
|
{
|
|
if (src_capture->fmt.format == V4L2_PIX_FMT_H264) {
|
|
camera_capture_set_callbacks(camera, src_capture, h264_callbacks[res]);
|
|
return 0;
|
|
}
|
|
|
|
device_info_t *device = device_list_find_m2m_format(camera->device_list, src_capture->fmt.format, V4L2_PIX_FMT_H264);
|
|
|
|
if (!device) {
|
|
LOG_INFO(camera, "Cannot find H264 encoder to convert from '%s'", fourcc_to_string(src_capture->fmt.format).buf);
|
|
return -1;
|
|
}
|
|
|
|
camera->codec_h264[res] = device_v4l2_open(h264_names[res], device->path);
|
|
|
|
buffer_list_t *output = device_open_buffer_list_output(camera->codec_h264[res], src_capture);
|
|
buffer_list_t *capture = device_open_buffer_list_capture(camera->codec_h264[res], output, 1.0, V4L2_PIX_FMT_H264, true);
|
|
|
|
if (!capture) {
|
|
return -1;
|
|
}
|
|
|
|
camera_capture_add_output(camera, src_capture, output);
|
|
camera_capture_set_callbacks(camera, capture, h264_callbacks[res]);
|
|
return 0;
|
|
}
|
|
|
|
static int camera_configure_jpeg_output(camera_t *camera, buffer_list_t *src_capture, int res)
|
|
{
|
|
if (src_capture->fmt.format == V4L2_PIX_FMT_MJPEG || src_capture->fmt.format == V4L2_PIX_FMT_JPEG) {
|
|
camera_capture_set_callbacks(camera, src_capture, jpeg_callbacks[res]);
|
|
return 0;
|
|
}
|
|
|
|
device_info_t *device = device_list_find_m2m_format(camera->device_list, src_capture->fmt.format, V4L2_PIX_FMT_JPEG);
|
|
|
|
if (!device) {
|
|
device = device_list_find_m2m_format(camera->device_list, src_capture->fmt.format, V4L2_PIX_FMT_MJPEG);
|
|
}
|
|
|
|
if (!device) {
|
|
LOG_INFO(camera, "Cannot find JPEG encoder to convert from '%s'", fourcc_to_string(src_capture->fmt.format).buf);
|
|
return -1;
|
|
}
|
|
|
|
camera->codec_jpeg[res] = device_v4l2_open(jpeg_names[res], device->path);
|
|
|
|
buffer_list_t *output = device_open_buffer_list_output(camera->codec_jpeg[res], src_capture);
|
|
buffer_list_t *capture = device_open_buffer_list_capture(camera->codec_jpeg[res], output, 1.0, V4L2_PIX_FMT_JPEG, true);
|
|
|
|
if (!capture) {
|
|
return -1;
|
|
}
|
|
|
|
camera_capture_add_output(camera, src_capture, output);
|
|
camera_capture_set_callbacks(camera, capture, jpeg_callbacks[res]);
|
|
return 0;
|
|
}
|
|
|
|
int camera_configure_output(camera_t *camera, buffer_list_t *src_capture, int res)
|
|
{
|
|
if (camera_configure_h264_output(camera, src_capture, res) < 0 ||
|
|
camera_configure_jpeg_output(camera, src_capture, res) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int camera_configure_output_rescaler2(camera_t *camera, buffer_list_t *src_capture, float div, int res)
|
|
{
|
|
if (div > 1) {
|
|
return camera_configure_legacy_isp(camera, src_capture, div, res);
|
|
} else if (div > 0) {
|
|
return camera_configure_output(camera, src_capture, 0);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int camera_configure_output_rescaler(camera_t *camera, buffer_list_t *src_capture, float high_div, float low_div)
|
|
{
|
|
if (camera_configure_output_rescaler2(camera, src_capture, high_div, 0) < 0 ||
|
|
camera_configure_output_rescaler2(camera, src_capture, low_div, 1) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int camera_configure_decoder(camera_t *camera, buffer_list_t *src_capture)
|
|
{
|
|
unsigned decode_formats[] = {
|
|
V4L2_PIX_FMT_YUYV,
|
|
V4L2_PIX_FMT_YUV420,
|
|
V4L2_PIX_FMT_YVU420,
|
|
V4L2_PIX_FMT_NV12,
|
|
V4L2_PIX_FMT_NV21,
|
|
0
|
|
};
|
|
unsigned chosen_format = 0;
|
|
device_info_t *device = device_list_find_m2m_formats(camera->device_list, src_capture->fmt.format, decode_formats, &chosen_format);
|
|
|
|
if (!device) {
|
|
LOG_INFO(camera, "Cannot find '%s' decoder", fourcc_to_string(src_capture->fmt.format).buf);
|
|
return -1;
|
|
}
|
|
|
|
device_video_force_key(camera->camera);
|
|
|
|
camera->decoder = device_v4l2_open("DECODER", device->path);
|
|
|
|
buffer_list_t *decoder_output = device_open_buffer_list_output(
|
|
camera->decoder, src_capture);
|
|
buffer_list_t *decoder_capture = device_open_buffer_list_capture(
|
|
camera->decoder, decoder_output, 1.0, 0, true);
|
|
|
|
camera_capture_add_output(camera, src_capture, decoder_output);
|
|
|
|
if (camera->options.high_res_factor <= 1 && (src_capture->fmt.format == V4L2_PIX_FMT_JPEG || src_capture->fmt.format == V4L2_PIX_FMT_MJPEG)) {
|
|
camera_capture_set_callbacks(camera, src_capture, jpeg_callbacks[0]);
|
|
|
|
if (camera_configure_h264_output(camera, decoder_capture, 0) < 0)
|
|
return -1;
|
|
} else if (camera->options.high_res_factor <= 1 && src_capture->fmt.format == V4L2_PIX_FMT_H264) {
|
|
camera_capture_set_callbacks(camera, src_capture, h264_callbacks[0]);
|
|
|
|
if (camera_configure_jpeg_output(camera, decoder_capture, 0) < 0)
|
|
return -1;
|
|
} else if (camera_configure_output_rescaler2(camera, decoder_capture, camera->options.high_res_factor, 0) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (camera->options.low_res_factor > 1 && camera_configure_output_rescaler2(camera, decoder_capture, camera->options.low_res_factor, 1) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|