mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-27 20:26:31 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e7d8da407 | ||
|
|
1c862b21e9 | ||
|
|
b202438a4d | ||
|
|
50ee2ba964 | ||
|
|
9f40713ee1 | ||
|
|
5f393ae972 | ||
|
|
aca3ee9e23 |
@@ -1,7 +1,7 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
commit = True
|
commit = True
|
||||||
tag = True
|
tag = True
|
||||||
current_version = 5.53
|
current_version = 5.55
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)
|
parse = (?P<major>\d+)\.(?P<minor>\d+)
|
||||||
serialize =
|
serialize =
|
||||||
{major}.{minor}
|
{major}.{minor}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Manpage for ustreamer-dump.
|
.\" Manpage for ustreamer-dump.
|
||||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||||
.TH USTREAMER-DUMP 1 "version 5.53" "January 2021"
|
.TH USTREAMER-DUMP 1 "version 5.55" "January 2021"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ustreamer-dump \- Dump uStreamer's memory sink to file
|
ustreamer-dump \- Dump uStreamer's memory sink to file
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Manpage for ustreamer.
|
.\" Manpage for ustreamer.
|
||||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||||
.TH USTREAMER 1 "version 5.53" "November 2020"
|
.TH USTREAMER 1 "version 5.55" "November 2020"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ustreamer \- stream MJPEG video from any V4L2 device to the network
|
ustreamer \- stream MJPEG video from any V4L2 device to the network
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
pkgname=ustreamer
|
pkgname=ustreamer
|
||||||
pkgver=5.53
|
pkgver=5.55
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
|
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
|
||||||
url="https://github.com/pikvm/ustreamer"
|
url="https://github.com/pikvm/ustreamer"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=ustreamer
|
PKG_NAME:=ustreamer
|
||||||
PKG_VERSION:=5.53
|
PKG_VERSION:=5.55
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ def _find_sources(suffix: str) -> list[str]:
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
setup(
|
setup(
|
||||||
name="ustreamer",
|
name="ustreamer",
|
||||||
version="5.53",
|
version="5.55",
|
||||||
description="uStreamer tools",
|
description="uStreamer tools",
|
||||||
author="Maxim Devaev",
|
author="Maxim Devaev",
|
||||||
author_email="mdevaev@gmail.com",
|
author_email="mdevaev@gmail.com",
|
||||||
|
|||||||
@@ -94,11 +94,11 @@ all: $(_TARGETS)
|
|||||||
|
|
||||||
install: all
|
install: all
|
||||||
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||||
for i in $(_TARGETS); do install -m755 $$i $(DESTDIR)$(PREFIX)/bin/$(subst .bin,,$$i); done
|
for i in $(subst .bin,,$(_TARGETS)); do install -m755 $$i.bin $(DESTDIR)$(PREFIX)/bin/$$i; done
|
||||||
|
|
||||||
|
|
||||||
install-strip: install
|
install-strip: install
|
||||||
for i in $(_TARGETS); do strip $(DESTDIR)$(PREFIX)/bin/$(subst .bin,,$$i); done
|
for i in $(subst .bin,,$(_TARGETS)); do strip $(DESTDIR)$(PREFIX)/bin/$$i; done
|
||||||
|
|
||||||
|
|
||||||
$(_USTR): $(_USTR_SRCS:%.c=$(_BUILD)/%.o)
|
$(_USTR): $(_USTR_SRCS:%.c=$(_BUILD)/%.o)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define US_VERSION_MAJOR 5
|
#define US_VERSION_MAJOR 5
|
||||||
#define US_VERSION_MINOR 53
|
#define US_VERSION_MINOR 55
|
||||||
|
|
||||||
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
|
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
|
||||||
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)
|
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)
|
||||||
|
|||||||
427
src/v4p/drm.c
427
src/v4p/drm.c
@@ -27,6 +27,8 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/sysmacros.h>
|
||||||
|
|
||||||
#include <xf86drm.h>
|
#include <xf86drm.h>
|
||||||
#include <xf86drmMode.h>
|
#include <xf86drmMode.h>
|
||||||
@@ -44,10 +46,11 @@
|
|||||||
static void _drm_vsync_callback(int fd, uint n_frame, uint sec, uint usec, void *v_run);
|
static void _drm_vsync_callback(int fd, uint n_frame, uint sec, uint usec, void *v_run);
|
||||||
static int _drm_expose_raw(us_drm_s *drm, const us_frame_s *frame);
|
static int _drm_expose_raw(us_drm_s *drm, const us_frame_s *frame);
|
||||||
static void _drm_cleanup(us_drm_s *drm);
|
static void _drm_cleanup(us_drm_s *drm);
|
||||||
static void _drm_ensure(us_drm_s *drm, const us_frame_s *frame, float hz);
|
static int _drm_ensure(us_drm_s *drm, const us_frame_s *frame, float hz);
|
||||||
static int _drm_init_video(us_drm_s *drm);
|
static int _drm_check_status(us_drm_s *drm);
|
||||||
static int _drm_init_buffers(us_drm_s *drm);
|
|
||||||
static int _drm_find_sink(us_drm_s *drm, uint width, uint height, float hz);
|
static int _drm_find_sink(us_drm_s *drm, uint width, uint height, float hz);
|
||||||
|
static int _drm_init_buffers(us_drm_s *drm);
|
||||||
|
static int _drm_start_video(us_drm_s *drm);
|
||||||
|
|
||||||
static u32 _find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, u32 *taken_crtcs);
|
static u32 _find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, u32 *taken_crtcs);
|
||||||
static const char *_connector_type_to_string(u32 type);
|
static const char *_connector_type_to_string(u32 type);
|
||||||
@@ -65,8 +68,7 @@ us_drm_s *us_drm_init(void) {
|
|||||||
us_drm_runtime_s *run;
|
us_drm_runtime_s *run;
|
||||||
US_CALLOC(run, 1);
|
US_CALLOC(run, 1);
|
||||||
run->fd = -1;
|
run->fd = -1;
|
||||||
run->conn_type = -1;
|
run->status_fd = -1;
|
||||||
run->conn_type_id = -1;
|
|
||||||
run->ft = us_ftext_init();
|
run->ft = us_ftext_init();
|
||||||
run->state = US_DRM_STATE_CLOSED;
|
run->state = US_DRM_STATE_CLOSED;
|
||||||
|
|
||||||
@@ -90,8 +92,7 @@ void us_drm_destroy(us_drm_s *drm) {
|
|||||||
int us_drm_wait_for_vsync(us_drm_s *drm) {
|
int us_drm_wait_for_vsync(us_drm_s *drm) {
|
||||||
us_drm_runtime_s *const run = drm->run;
|
us_drm_runtime_s *const run = drm->run;
|
||||||
|
|
||||||
_drm_ensure(drm, NULL, 0);
|
if (_drm_ensure(drm, NULL, 0) < 0) {
|
||||||
if (run->state != US_DRM_STATE_OK) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (run->has_vsync) {
|
if (run->has_vsync) {
|
||||||
@@ -133,8 +134,7 @@ error:
|
|||||||
int us_drm_expose(us_drm_s *drm, us_drm_expose_e ex, const us_frame_s *frame, float hz) {
|
int us_drm_expose(us_drm_s *drm, us_drm_expose_e ex, const us_frame_s *frame, float hz) {
|
||||||
us_drm_runtime_s *const run = drm->run;
|
us_drm_runtime_s *const run = drm->run;
|
||||||
|
|
||||||
_drm_ensure(drm, frame, hz);
|
if (_drm_ensure(drm, frame, hz) < 0) {
|
||||||
if (run->state != US_DRM_STATE_OK) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,21 +203,18 @@ static int _drm_expose_raw(us_drm_s *drm, const us_frame_s *frame) {
|
|||||||
_D_LOG_DEBUG("Exposing%s framebuffer n_buf=%u, vsync=%d ...",
|
_D_LOG_DEBUG("Exposing%s framebuffer n_buf=%u, vsync=%d ...",
|
||||||
(frame == NULL ? " EMPTY" : ""), run->next_n_buf, run->has_vsync);
|
(frame == NULL ? " EMPTY" : ""), run->next_n_buf, run->has_vsync);
|
||||||
|
|
||||||
run->has_vsync = false;
|
|
||||||
|
|
||||||
if (frame == NULL) {
|
if (frame == NULL) {
|
||||||
memset(buf->data, 0, buf->allocated);
|
memset(buf->data, 0, buf->allocated);
|
||||||
} else {
|
} else {
|
||||||
memcpy(buf->data, frame->data, US_MIN(frame->used, buf->allocated));
|
memcpy(buf->data, frame->data, US_MIN(frame->used, buf->allocated));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
run->has_vsync = false;
|
||||||
const int retval = drmModePageFlip(
|
const int retval = drmModePageFlip(
|
||||||
run->fd, run->crtc_id, buf->id,
|
run->fd, run->crtc_id, buf->id,
|
||||||
DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_ASYNC,
|
DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_ASYNC,
|
||||||
run);
|
run);
|
||||||
if (retval == 0) {
|
run->next_n_buf = (run->next_n_buf + 1) % run->n_bufs;
|
||||||
run->next_n_buf = (run->next_n_buf + 1) % run->n_bufs;
|
|
||||||
}
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +228,7 @@ static void _drm_cleanup(us_drm_s *drm) {
|
|||||||
run->saved_crtc->crtc_id, run->saved_crtc->buffer_id,
|
run->saved_crtc->crtc_id, run->saved_crtc->buffer_id,
|
||||||
run->saved_crtc->x, run->saved_crtc->y,
|
run->saved_crtc->x, run->saved_crtc->y,
|
||||||
&run->conn_id, 1, &run->saved_crtc->mode
|
&run->conn_id, 1, &run->saved_crtc->mode
|
||||||
) < 0) {
|
) < 0 && errno != ENOENT) {
|
||||||
_D_LOG_PERROR("Can't restore CRTC");
|
_D_LOG_PERROR("Can't restore CRTC");
|
||||||
}
|
}
|
||||||
drmModeFreeCrtc(run->saved_crtc);
|
drmModeFreeCrtc(run->saved_crtc);
|
||||||
@@ -258,57 +255,52 @@ static void _drm_cleanup(us_drm_s *drm) {
|
|||||||
run->n_bufs = 0;
|
run->n_bufs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (run->fd >= 0) {
|
US_CLOSE_FD(run->status_fd, close);
|
||||||
if (close(run->fd) < 0) {
|
US_CLOSE_FD(run->fd, close);
|
||||||
_D_LOG_PERROR("Can't close device");
|
|
||||||
}
|
|
||||||
run->fd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
run->crtc_id = 0;
|
run->crtc_id = 0;
|
||||||
run->next_n_buf = 0;
|
run->next_n_buf = 0;
|
||||||
run->has_vsync = false;
|
run->has_vsync = false;
|
||||||
|
|
||||||
if (run->state == US_DRM_STATE_OK) {
|
if (run->state == US_DRM_STATE_OK) {
|
||||||
_D_LOG_INFO("Stopped");
|
_D_LOG_INFO("Stopped");
|
||||||
run->state = US_DRM_STATE_CLOSED;
|
|
||||||
}
|
}
|
||||||
|
run->state = US_DRM_STATE_CLOSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _drm_ensure(us_drm_s *drm, const us_frame_s *frame, float hz) {
|
static int _drm_ensure(us_drm_s *drm, const us_frame_s *frame, float hz) {
|
||||||
us_drm_runtime_s *const run = drm->run;
|
us_drm_runtime_s *const run = drm->run;
|
||||||
|
|
||||||
if (frame == NULL) {
|
switch (_drm_check_status(drm)) {
|
||||||
if (run->state == US_DRM_STATE_OK) {
|
case 0: break;
|
||||||
return;
|
case -2: goto unplugged;
|
||||||
}
|
default: goto error;
|
||||||
} else {
|
|
||||||
if (
|
|
||||||
run->p_width == frame->width
|
|
||||||
&& run->p_height == frame->height
|
|
||||||
&& run->p_hz == hz
|
|
||||||
&& run->state <= US_DRM_STATE_RETRY
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frame == NULL && run->state == US_DRM_STATE_OK) {
|
||||||
|
return 0;
|
||||||
|
} else if (
|
||||||
|
frame != NULL
|
||||||
|
&& run->p_width == frame->width
|
||||||
|
&& run->p_height == frame->height
|
||||||
|
&& run->p_hz == hz
|
||||||
|
&& run->state <= US_DRM_STATE_CLOSED
|
||||||
|
) {
|
||||||
|
return (run->state == US_DRM_STATE_OK ? 0 : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const us_drm_state_e saved_state = run->state;
|
||||||
_drm_cleanup(drm);
|
_drm_cleanup(drm);
|
||||||
|
if (saved_state > US_DRM_STATE_CLOSED) {
|
||||||
if (run->state <= US_DRM_STATE_RETRY) {
|
run->state = saved_state;
|
||||||
_D_LOG_INFO("Configuring DRM device ...");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame == NULL) {
|
run->p_width = (frame != NULL ? frame->width : 0); // 0 for find the native resolution
|
||||||
run->p_width = 0; // Find the native resolution
|
run->p_height = (frame != NULL ? frame->height : 0);
|
||||||
run->p_height = 0;
|
|
||||||
} else {
|
|
||||||
run->p_width = frame->width;
|
|
||||||
run->p_height = frame->height;
|
|
||||||
}
|
|
||||||
run->p_hz = hz;
|
run->p_hz = hz;
|
||||||
|
|
||||||
if ((run->fd = open(drm->path, O_RDWR|O_CLOEXEC|O_NONBLOCK)) < 0) {
|
_D_LOG_INFO("Configuring DRM device ...");
|
||||||
|
|
||||||
|
if ((run->fd = open(drm->path, O_RDWR | O_CLOEXEC | O_NONBLOCK)) < 0) {
|
||||||
_D_LOG_PERROR("Can't open DRM device");
|
_D_LOG_PERROR("Can't open DRM device");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@@ -328,59 +320,178 @@ static void _drm_ensure(us_drm_s *drm, const us_frame_s *frame, float hz) {
|
|||||||
// CHECK_CAP(DRM_CAP_PRIME);
|
// CHECK_CAP(DRM_CAP_PRIME);
|
||||||
# undef CHECK_CAP
|
# undef CHECK_CAP
|
||||||
|
|
||||||
if (_drm_find_sink(drm, run->p_width, run->p_height, run->p_hz) < 0) {
|
switch (_drm_find_sink(drm, run->p_width, run->p_height, run->p_hz)) {
|
||||||
goto error;
|
case 0: break;
|
||||||
|
case -2: goto unplugged;
|
||||||
|
default: goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (run->crtc_id == 0) {
|
const float mode_hz = _get_refresh_rate(&run->mode);
|
||||||
if (run->state != US_DRM_STATE_NO_DISPLAY) {
|
if (frame == NULL) {
|
||||||
_D_LOG_INFO("Using %s mode: Display unplugged", drm->port);
|
run->p_width = run->mode.hdisplay;
|
||||||
run->state = US_DRM_STATE_NO_DISPLAY;
|
run->p_height = run->mode.vdisplay;
|
||||||
}
|
run->p_hz = mode_hz;
|
||||||
goto error;
|
|
||||||
} else {
|
|
||||||
const float mode_hz = _get_refresh_rate(&run->mode);
|
|
||||||
if (frame == NULL) {
|
|
||||||
run->p_width = run->mode.hdisplay;
|
|
||||||
run->p_height = run->mode.vdisplay;
|
|
||||||
run->p_hz = mode_hz;
|
|
||||||
}
|
|
||||||
_D_LOG_INFO("Using %s mode: %ux%up%.02f",
|
|
||||||
drm->port, run->mode.hdisplay, run->mode.vdisplay, mode_hz);
|
|
||||||
}
|
}
|
||||||
|
_D_LOG_INFO("Using %s mode: %ux%up%.02f",
|
||||||
|
drm->port, run->mode.hdisplay, run->mode.vdisplay, mode_hz);
|
||||||
|
|
||||||
if (_drm_init_buffers(drm) < 0) {
|
if (_drm_init_buffers(drm) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_drm_init_video(drm) < 0) {
|
if (_drm_start_video(drm) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
_D_LOG_INFO("Showing ...");
|
_D_LOG_INFO("Showing ...");
|
||||||
run->state = US_DRM_STATE_OK;
|
run->state = US_DRM_STATE_OK;
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (run->state == US_DRM_STATE_CLOSED) {
|
_drm_cleanup(drm);
|
||||||
_D_LOG_ERROR("Device destroyed due an error (prepare)");
|
_D_LOG_ERROR("Device destroyed due an error (ensure)");
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
unplugged:
|
||||||
|
if (run->state != US_DRM_STATE_NO_DISPLAY) {
|
||||||
|
_D_LOG_INFO("Display %s is not plugged", drm->port);
|
||||||
}
|
}
|
||||||
_drm_cleanup(drm);
|
_drm_cleanup(drm);
|
||||||
|
run->state = US_DRM_STATE_NO_DISPLAY;
|
||||||
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _drm_init_video(us_drm_s *drm) {
|
static int _drm_check_status(us_drm_s *drm) {
|
||||||
|
us_drm_runtime_s *run = drm->run;
|
||||||
|
|
||||||
|
if (run->status_fd < 0) {
|
||||||
|
struct stat st;
|
||||||
|
if (stat(drm->path, &st) < 0) {
|
||||||
|
_D_LOG_PERROR("Can't stat() DRM device");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
const uint mi = minor(st.st_rdev);
|
||||||
|
|
||||||
|
char path[128];
|
||||||
|
US_SNPRINTF(path, 127, "/sys/class/drm/card%u-%s/status", mi, drm->port);
|
||||||
|
if ((run->status_fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) {
|
||||||
|
_D_LOG_PERROR("Can't open DRM device status file: %s", path);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char status_ch;
|
||||||
|
if (read(run->status_fd, &status_ch, 1) != 1) {
|
||||||
|
_D_LOG_PERROR("Can't read connector status");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (lseek(run->status_fd, 0, SEEK_SET) != 0) {
|
||||||
|
_D_LOG_PERROR("Can't rewind connector status");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
return (status_ch == 'd' ? -2 : 0);
|
||||||
|
|
||||||
|
error:
|
||||||
|
US_CLOSE_FD(run->status_fd, close);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _drm_find_sink(us_drm_s *drm, uint width, uint height, float hz) {
|
||||||
us_drm_runtime_s *const run = drm->run;
|
us_drm_runtime_s *const run = drm->run;
|
||||||
run->saved_crtc = drmModeGetCrtc(run->fd, run->crtc_id);
|
|
||||||
_D_LOG_DEBUG("Setting up CRTC ...");
|
run->crtc_id = 0;
|
||||||
if (drmModeSetCrtc(run->fd, run->crtc_id, run->bufs[0].id, 0, 0, &run->conn_id, 1, &run->mode) < 0) {
|
|
||||||
_D_LOG_PERROR("Can't set CRTC");
|
_D_LOG_DEBUG("Trying to find the appropriate sink ...");
|
||||||
return -1;
|
|
||||||
|
drmModeRes *res = drmModeGetResources(run->fd);
|
||||||
|
if (res == NULL) {
|
||||||
|
_D_LOG_PERROR("Can't get resources info");
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
if (_drm_expose_raw(drm, NULL) < 0) {
|
if (res->count_connectors <= 0) {
|
||||||
_D_LOG_PERROR("Can't flip the first page");
|
_D_LOG_ERROR("Can't find any connectors");
|
||||||
return -1;
|
goto done;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
for (int ci = 0; ci < res->count_connectors; ++ci) {
|
||||||
|
drmModeConnector *conn = drmModeGetConnector(run->fd, res->connectors[ci]);
|
||||||
|
if (conn == NULL) {
|
||||||
|
_D_LOG_PERROR("Can't get connector index=%d", ci);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
char port[32];
|
||||||
|
US_SNPRINTF(port, 31, "%s-%u",
|
||||||
|
_connector_type_to_string(conn->connector_type),
|
||||||
|
conn->connector_type_id);
|
||||||
|
if (strcmp(port, drm->port) != 0) {
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_D_LOG_DEBUG("Found connector for port %s: conn_type=%d, conn_type_id=%d",
|
||||||
|
drm->port, conn->connector_type, conn->connector_type_id);
|
||||||
|
|
||||||
|
if (conn->connection != DRM_MODE_CONNECTED) {
|
||||||
|
_D_LOG_DEBUG("Display is not connected");
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeModeInfo *best = NULL;
|
||||||
|
drmModeModeInfo *closest = NULL;
|
||||||
|
drmModeModeInfo *pref = NULL;
|
||||||
|
for (int mi = 0; mi < conn->count_modes; ++mi) {
|
||||||
|
drmModeModeInfo *const mode = &conn->modes[mi];
|
||||||
|
if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
|
||||||
|
continue; // Paranoia for size and discard interlaced
|
||||||
|
}
|
||||||
|
const float mode_hz = _get_refresh_rate(mode);
|
||||||
|
if (mode->hdisplay == width && mode->vdisplay == height) {
|
||||||
|
best = mode; // Any mode with exact resolution
|
||||||
|
if (hz > 0 && mode_hz == hz) {
|
||||||
|
break; // Exact mode with same freq
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mode->hdisplay == width && mode->vdisplay < height) {
|
||||||
|
if (closest == NULL || _get_refresh_rate(closest) != hz) {
|
||||||
|
closest = mode; // Something like 1920x1080p60 for 1920x1200p60 source
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pref == NULL && (mode->type & DRM_MODE_TYPE_PREFERRED)) {
|
||||||
|
pref = mode; // Preferred mode if nothing is found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (best == NULL) { best = closest; }
|
||||||
|
if (best == NULL) { best = pref; }
|
||||||
|
if (best == NULL) { best = (conn->count_modes > 0 ? &conn->modes[0] : NULL); }
|
||||||
|
if (best == NULL) {
|
||||||
|
_D_LOG_ERROR("Can't find any appropriate resolutions");
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
goto unplugged;
|
||||||
|
}
|
||||||
|
assert(best->hdisplay > 0);
|
||||||
|
assert(best->vdisplay > 0);
|
||||||
|
|
||||||
|
u32 taken_crtcs = 0; // Unused here
|
||||||
|
if ((run->crtc_id = _find_crtc(run->fd, res, conn, &taken_crtcs)) == 0) {
|
||||||
|
_D_LOG_ERROR("Can't find CRTC");
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
run->conn_id = conn->connector_id;
|
||||||
|
memcpy(&run->mode, best, sizeof(drmModeModeInfo));
|
||||||
|
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
drmModeFreeResources(res);
|
||||||
|
return (run->crtc_id > 0 ? 0 : -1);
|
||||||
|
|
||||||
|
unplugged:
|
||||||
|
drmModeFreeResources(res);
|
||||||
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _drm_init_buffers(us_drm_s *drm) {
|
static int _drm_init_buffers(us_drm_s *drm) {
|
||||||
@@ -432,119 +543,25 @@ static int _drm_init_buffers(us_drm_s *drm) {
|
|||||||
_D_LOG_PERROR("Can't map buffer=%u", n_buf);
|
_D_LOG_PERROR("Can't map buffer=%u", n_buf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
memset(buf->data, 0, create.size);
|
||||||
buf->allocated = create.size;
|
buf->allocated = create.size;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _drm_find_sink(us_drm_s *drm, uint width, uint height, float hz) {
|
static int _drm_start_video(us_drm_s *drm) {
|
||||||
us_drm_runtime_s *const run = drm->run;
|
us_drm_runtime_s *const run = drm->run;
|
||||||
|
run->saved_crtc = drmModeGetCrtc(run->fd, run->crtc_id);
|
||||||
int retval = -1;
|
_D_LOG_DEBUG("Setting up CRTC ...");
|
||||||
|
if (drmModeSetCrtc(run->fd, run->crtc_id, run->bufs[0].id, 0, 0, &run->conn_id, 1, &run->mode) < 0) {
|
||||||
run->crtc_id = 0;
|
_D_LOG_PERROR("Can't set CRTC");
|
||||||
|
return -1;
|
||||||
_D_LOG_DEBUG("Trying to find the appropriate sink ...");
|
|
||||||
|
|
||||||
drmModeRes *res = drmModeGetResources(run->fd);
|
|
||||||
if (res == NULL) {
|
|
||||||
_D_LOG_PERROR("Can't get resources info");
|
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
_D_LOG_DEBUG("Found %u connectors", res->count_connectors);
|
if (_drm_expose_raw(drm, NULL) < 0) {
|
||||||
|
_D_LOG_PERROR("Can't flip the first page");
|
||||||
for (int ci = 0; ci < res->count_connectors; ++ci) {
|
return -1;
|
||||||
drmModeConnector *conn = drmModeGetConnector(run->fd, res->connectors[ci]);
|
|
||||||
if (conn == NULL) {
|
|
||||||
_D_LOG_PERROR("Can't get connector index=%d", ci);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (run->conn_type < 0) {
|
|
||||||
char port[32];
|
|
||||||
US_SNPRINTF(port, 31, "%s-%u",
|
|
||||||
_connector_type_to_string(conn->connector_type),
|
|
||||||
conn->connector_type_id);
|
|
||||||
if (!strcmp(port, drm->port)) {
|
|
||||||
run->conn_type = conn->connector_type;
|
|
||||||
run->conn_type_id = conn->connector_type_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
(int)conn->connector_type != run->conn_type
|
|
||||||
|| (int)conn->connector_type_id != run->conn_type_id
|
|
||||||
) {
|
|
||||||
drmModeFreeConnector(conn);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_D_LOG_DEBUG("Found requested connector for port %s: conn_type=%d, conn_type_id=%d",
|
|
||||||
drm->port, run->conn_type, run->conn_type_id);
|
|
||||||
|
|
||||||
if (conn->connection != DRM_MODE_CONNECTED) {
|
|
||||||
_D_LOG_DEBUG("Display is not connected");
|
|
||||||
drmModeFreeConnector(conn);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
drmModeModeInfo *best = NULL;// (conn->count_modes > 0 ? &conn->modes[0] : NULL);
|
|
||||||
drmModeModeInfo *closest = NULL;
|
|
||||||
drmModeModeInfo *pref = NULL;
|
|
||||||
for (int mi = 0; mi < conn->count_modes; ++mi) {
|
|
||||||
drmModeModeInfo *const mode = &conn->modes[mi];
|
|
||||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
|
|
||||||
continue; // Paranoia for size and discard interlaced
|
|
||||||
}
|
|
||||||
const float mode_hz = _get_refresh_rate(mode);
|
|
||||||
if (mode->hdisplay == width && mode->vdisplay == height) {
|
|
||||||
best = mode; // Any mode with exact resolution
|
|
||||||
if (hz > 0 && mode_hz == hz) {
|
|
||||||
break; // Exact mode with same freq
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mode->hdisplay == width && mode->vdisplay < height) {
|
|
||||||
if (closest == NULL || _get_refresh_rate(closest) != hz) {
|
|
||||||
closest = mode; // Something like 1920x1080p60 for 1920x1200p60 source
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pref == NULL && (mode->type & DRM_MODE_TYPE_PREFERRED)) {
|
|
||||||
pref = mode; // Preferred mode if nothing is found
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (best == NULL) {
|
|
||||||
best = closest;
|
|
||||||
}
|
|
||||||
if (best == NULL) {
|
|
||||||
best = pref;
|
|
||||||
}
|
|
||||||
if (best == NULL) {
|
|
||||||
best = (conn->count_modes > 0 ? &conn->modes[0] : NULL);
|
|
||||||
}
|
|
||||||
if (best == NULL) {
|
|
||||||
_D_LOG_ERROR("Can't find any resolutions");
|
|
||||||
drmModeFreeConnector(conn);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
assert(best->hdisplay > 0);
|
|
||||||
assert(best->vdisplay > 0);
|
|
||||||
|
|
||||||
u32 taken_crtcs = 0; // Unused here
|
|
||||||
if ((run->crtc_id = _find_crtc(run->fd, res, conn, &taken_crtcs)) == 0) {
|
|
||||||
_D_LOG_ERROR("Can't find CRTC");
|
|
||||||
drmModeFreeConnector(conn);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
memcpy(&run->mode, best, sizeof(drmModeModeInfo));
|
|
||||||
run->conn_id = conn->connector_id;
|
|
||||||
|
|
||||||
drmModeFreeConnector(conn);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
retval = 0;
|
|
||||||
|
|
||||||
error:
|
|
||||||
drmModeFreeResources(res);
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 _find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, u32 *taken_crtcs) {
|
static u32 _find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, u32 *taken_crtcs) {
|
||||||
@@ -574,22 +591,26 @@ static const char *_connector_type_to_string(u32 type) {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
# define CASE_NAME(x_suffix, x_name) \
|
# define CASE_NAME(x_suffix, x_name) \
|
||||||
case DRM_MODE_CONNECTOR_##x_suffix: return x_name;
|
case DRM_MODE_CONNECTOR_##x_suffix: return x_name;
|
||||||
CASE_NAME(VGA, "VGA");
|
CASE_NAME(VGA, "VGA");
|
||||||
CASE_NAME(DVII, "DVI-I");
|
CASE_NAME(DVII, "DVI-I");
|
||||||
CASE_NAME(DVID, "DVI-D");
|
CASE_NAME(DVID, "DVI-D");
|
||||||
CASE_NAME(DVIA, "DVI-A");
|
CASE_NAME(DVIA, "DVI-A");
|
||||||
CASE_NAME(Composite, "Composite");
|
CASE_NAME(Composite, "Composite");
|
||||||
CASE_NAME(SVIDEO, "SVIDEO");
|
CASE_NAME(SVIDEO, "SVIDEO");
|
||||||
CASE_NAME(LVDS, "LVDS");
|
CASE_NAME(LVDS, "LVDS");
|
||||||
CASE_NAME(Component, "Component");
|
CASE_NAME(Component, "Component");
|
||||||
CASE_NAME(9PinDIN, "DIN");
|
CASE_NAME(9PinDIN, "DIN");
|
||||||
CASE_NAME(DisplayPort, "DP");
|
CASE_NAME(DisplayPort, "DP");
|
||||||
CASE_NAME(HDMIA, "HDMI-A");
|
CASE_NAME(HDMIA, "HDMI-A");
|
||||||
CASE_NAME(HDMIB, "HDMI-B");
|
CASE_NAME(HDMIB, "HDMI-B");
|
||||||
CASE_NAME(TV, "TV");
|
CASE_NAME(TV, "TV");
|
||||||
CASE_NAME(eDP, "eDP");
|
CASE_NAME(eDP, "eDP");
|
||||||
CASE_NAME(VIRTUAL, "Virtual");
|
CASE_NAME(VIRTUAL, "Virtual");
|
||||||
CASE_NAME(DSI, "DSI");
|
CASE_NAME(DSI, "DSI");
|
||||||
|
CASE_NAME(DPI, "DPI");
|
||||||
|
CASE_NAME(WRITEBACK, "Writeback");
|
||||||
|
CASE_NAME(SPI, "SPI");
|
||||||
|
CASE_NAME(USB, "USB");
|
||||||
case DRM_MODE_CONNECTOR_Unknown: break;
|
case DRM_MODE_CONNECTOR_Unknown: break;
|
||||||
# undef CASE_NAME
|
# undef CASE_NAME
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ typedef enum {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
US_DRM_STATE_OK = 0,
|
US_DRM_STATE_OK = 0,
|
||||||
US_DRM_STATE_CLOSED,
|
US_DRM_STATE_CLOSED,
|
||||||
US_DRM_STATE_RETRY, // Not used directly
|
|
||||||
US_DRM_STATE_NO_DISPLAY,
|
US_DRM_STATE_NO_DISPLAY,
|
||||||
} us_drm_state_e;
|
} us_drm_state_e;
|
||||||
|
|
||||||
@@ -54,12 +53,12 @@ typedef struct {
|
|||||||
} us_drm_buffer_s;
|
} us_drm_buffer_s;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
int status_fd;
|
||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
int conn_type;
|
|
||||||
int conn_type_id;
|
|
||||||
u32 crtc_id;
|
u32 crtc_id;
|
||||||
drmModeModeInfo mode;
|
|
||||||
u32 conn_id;
|
u32 conn_id;
|
||||||
|
drmModeModeInfo mode;
|
||||||
us_drm_buffer_s *bufs;
|
us_drm_buffer_s *bufs;
|
||||||
uint n_bufs;
|
uint n_bufs;
|
||||||
drmModeCrtc *saved_crtc;
|
drmModeCrtc *saved_crtc;
|
||||||
|
|||||||
Reference in New Issue
Block a user