mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-03-15 20:13:42 +00:00
Fixed #290: improved blank diagnostics
This commit is contained in:
@@ -11,7 +11,7 @@
|
|||||||
|----------|---------------|-------------------|
|
|----------|---------------|-------------------|
|
||||||
| Multithreaded JPEG encoding | ✔ | ✘ |
|
| Multithreaded JPEG encoding | ✔ | ✘ |
|
||||||
| Hardware image encoding<br>on Raspberry Pi | ✔ | ✘ |
|
| Hardware image encoding<br>on Raspberry Pi | ✔ | ✘ |
|
||||||
| Behavior when the device<br>is disconnected while streaming | ✔ Shows a black screen<br>with ```NO SIGNAL``` on it<br>until reconnected | ✘ Stops the streaming <sup>1</sup> |
|
| Behavior when the device<br>is disconnected while streaming | ✔ Shows a black screen<br>with ```NO LIVE VIDEO``` on it<br>until reconnected | ✘ Stops the streaming <sup>1</sup> |
|
||||||
| [DV-timings](https://linuxtv.org/downloads/v4l-dvb-apis-new/userspace-api/v4l/dv-timings.html) support -<br>the ability to change resolution<br>on the fly by source signal | ✔ | ☹ Partially yes <sup>1</sup> |
|
| [DV-timings](https://linuxtv.org/downloads/v4l-dvb-apis-new/userspace-api/v4l/dv-timings.html) support -<br>the ability to change resolution<br>on the fly by source signal | ✔ | ☹ Partially yes <sup>1</sup> |
|
||||||
| Option to skip frames when streaming<br>static images by HTTP to save the traffic | ✔ <sup>2</sup> | ✘ |
|
| Option to skip frames when streaming<br>static images by HTTP to save the traffic | ✔ <sup>2</sup> | ✘ |
|
||||||
| Streaming via UNIX domain socket | ✔ | ✘ |
|
| Streaming via UNIX domain socket | ✔ | ✘ |
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
#include "threading.h"
|
#include "threading.h"
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
#include "xioctl.h"
|
#include "xioctl.h"
|
||||||
|
#include "tc358743.h"
|
||||||
|
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
@@ -200,11 +201,11 @@ int us_capture_open(us_capture_s *cap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_LOG_DEBUG("Probing DV-timings or QuerySTD ...");
|
_LOG_DEBUG("Probing DV-timings or QuerySTD ...");
|
||||||
if (_capture_open_dv_timings(cap, false) < 0) {
|
switch (_capture_open_dv_timings(cap, false)) {
|
||||||
US_ONCE_FOR(run->open_error_once, __LINE__, {
|
case 0: break;
|
||||||
_LOG_ERROR("No signal from source");
|
case US_ERROR_NO_SIGNAL: goto error_no_signal;
|
||||||
});
|
case US_ERROR_NO_SYNC: goto error_no_sync;
|
||||||
goto error_no_signal;
|
default: goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,6 +223,15 @@ int us_capture_open(us_capture_s *cap) {
|
|||||||
if (_capture_open_format(cap, true) < 0) {
|
if (_capture_open_format(cap, true) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
if (cap->dv_timings && cap->persistent) {
|
||||||
|
struct v4l2_control ctl = {.id = TC358743_CID_LANES_ENOUGH};
|
||||||
|
if (!us_xioctl(run->fd, VIDIOC_G_CTRL, &ctl)) {
|
||||||
|
if (!ctl.value) {
|
||||||
|
_LOG_ERROR("Not enough lanes, hardware can't handle this signal");
|
||||||
|
goto error_no_lanes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_capture_open_hw_fps(cap);
|
_capture_open_hw_fps(cap);
|
||||||
_capture_open_jpeg_quality(cap);
|
_capture_open_jpeg_quality(cap);
|
||||||
if (_capture_open_io_method(cap) < 0) {
|
if (_capture_open_io_method(cap) < 0) {
|
||||||
@@ -259,8 +269,18 @@ error_no_cable:
|
|||||||
return US_ERROR_NO_CABLE;
|
return US_ERROR_NO_CABLE;
|
||||||
|
|
||||||
error_no_signal:
|
error_no_signal:
|
||||||
|
US_ONCE_FOR(run->open_error_once, __LINE__, { _LOG_ERROR("No signal from source"); });
|
||||||
us_capture_close(cap);
|
us_capture_close(cap);
|
||||||
return US_ERROR_NO_DATA;
|
return US_ERROR_NO_SIGNAL;
|
||||||
|
|
||||||
|
error_no_sync:
|
||||||
|
US_ONCE_FOR(run->open_error_once, __LINE__, { _LOG_ERROR("No sync on signal"); });
|
||||||
|
us_capture_close(cap);
|
||||||
|
return US_ERROR_NO_SYNC;
|
||||||
|
|
||||||
|
error_no_lanes:
|
||||||
|
us_capture_close(cap);
|
||||||
|
return US_ERROR_NO_LANES;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
run->open_error_once = 0;
|
run->open_error_once = 0;
|
||||||
@@ -630,6 +650,10 @@ static int _capture_open_dv_timings(us_capture_s *cap, bool apply) {
|
|||||||
// TC358743 errors here (see in the kernel: drivers/media/i2c/tc358743.c):
|
// TC358743 errors here (see in the kernel: drivers/media/i2c/tc358743.c):
|
||||||
// - ENOLINK: No valid signal (SYS_STATUS & MASK_S_TMDS)
|
// - ENOLINK: No valid signal (SYS_STATUS & MASK_S_TMDS)
|
||||||
// - ENOLCK: No sync on signal (SYS_STATUS & MASK_S_SYNC)
|
// - ENOLCK: No sync on signal (SYS_STATUS & MASK_S_SYNC)
|
||||||
|
switch (errno) {
|
||||||
|
case ENOLINK: return US_ERROR_NO_SIGNAL;
|
||||||
|
case ENOLCK: return US_ERROR_NO_SYNC;
|
||||||
|
}
|
||||||
dv_errno = errno;
|
dv_errno = errno;
|
||||||
goto querystd;
|
goto querystd;
|
||||||
} else if (!apply) {
|
} else if (!apply) {
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ int us_drm_expose_stub(us_drm_s *drm, us_drm_stub_e stub, const us_capture_s *ca
|
|||||||
DRAW_MSG("=== PiKVM ===\n \n< UNSUPPORTED CAPTURE FORMAT >");
|
DRAW_MSG("=== PiKVM ===\n \n< UNSUPPORTED CAPTURE FORMAT >");
|
||||||
break;
|
break;
|
||||||
case US_DRM_STUB_NO_SIGNAL:
|
case US_DRM_STUB_NO_SIGNAL:
|
||||||
DRAW_MSG("=== PiKVM ===\n \n< NO SIGNAL >");
|
DRAW_MSG("=== PiKVM ===\n \n< NO LIVE VIDEO >");
|
||||||
break;
|
break;
|
||||||
case US_DRM_STUB_BUSY:
|
case US_DRM_STUB_BUSY:
|
||||||
DRAW_MSG("=== PiKVM ===\n \n< ONLINE IS ACTIVE >");
|
DRAW_MSG("=== PiKVM ===\n \n< ONLINE IS ACTIVE >");
|
||||||
|
|||||||
@@ -25,4 +25,7 @@
|
|||||||
#define US_ERROR_COMMON -1
|
#define US_ERROR_COMMON -1
|
||||||
#define US_ERROR_NO_DEVICE -2
|
#define US_ERROR_NO_DEVICE -2
|
||||||
#define US_ERROR_NO_CABLE -3
|
#define US_ERROR_NO_CABLE -3
|
||||||
#define US_ERROR_NO_DATA -4
|
#define US_ERROR_NO_SIGNAL -4
|
||||||
|
#define US_ERROR_NO_SYNC -5
|
||||||
|
#define US_ERROR_NO_LANES -6
|
||||||
|
#define US_ERROR_NO_DATA -7
|
||||||
|
|||||||
@@ -33,17 +33,6 @@
|
|||||||
#include "xioctl.h"
|
#include "xioctl.h"
|
||||||
|
|
||||||
|
|
||||||
#ifndef V4L2_CID_USER_TC358743_BASE
|
|
||||||
# define V4L2_CID_USER_TC358743_BASE (V4L2_CID_USER_BASE + 0x1080)
|
|
||||||
#endif
|
|
||||||
#ifndef TC358743_CID_AUDIO_PRESENT
|
|
||||||
# define TC358743_CID_AUDIO_PRESENT (V4L2_CID_USER_TC358743_BASE + 1)
|
|
||||||
#endif
|
|
||||||
#ifndef TC358743_CID_AUDIO_SAMPLING_RATE
|
|
||||||
# define TC358743_CID_AUDIO_SAMPLING_RATE (V4L2_CID_USER_TC358743_BASE + 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
int us_tc358743_xioctl_get_audio_hz(int fd, uint *audio_hz) {
|
int us_tc358743_xioctl_get_audio_hz(int fd, uint *audio_hz) {
|
||||||
*audio_hz = 0;
|
*audio_hz = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,26 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <linux/v4l2-controls.h>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef V4L2_CID_USER_TC358743_BASE
|
||||||
|
# define V4L2_CID_USER_TC358743_BASE (V4L2_CID_USER_BASE + 0x1080)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TC358743_CID_AUDIO_SAMPLING_RATE
|
||||||
|
# define TC358743_CID_AUDIO_SAMPLING_RATE (V4L2_CID_USER_TC358743_BASE + 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TC358743_CID_AUDIO_PRESENT
|
||||||
|
# define TC358743_CID_AUDIO_PRESENT (V4L2_CID_USER_TC358743_BASE + 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TC358743_CID_LANES_ENOUGH
|
||||||
|
# define TC358743_CID_LANES_ENOUGH (V4L2_CID_USER_TC358743_BASE + 2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int us_tc358743_xioctl_get_audio_hz(int fd, uint *audio_hz);
|
int us_tc358743_xioctl_get_audio_hz(int fd, uint *audio_hz);
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ us_blank_s *us_blank_init(void) {
|
|||||||
blank->ft = us_frametext_init();
|
blank->ft = us_frametext_init();
|
||||||
blank->raw = blank->ft->frame;
|
blank->raw = blank->ft->frame;
|
||||||
blank->jpeg = us_frame_init();
|
blank->jpeg = us_frame_init();
|
||||||
us_blank_draw(blank, "< NO SIGNAL >", 640, 480);
|
us_blank_draw(blank, "< NO LIVE VIDEO >", 640, 480);
|
||||||
return blank;
|
return blank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -880,7 +880,7 @@ static void _http_send_snapshot(us_server_s *server) {
|
|||||||
if (!captured_meta.online) {
|
if (!captured_meta.online) {
|
||||||
if (blank == NULL) {
|
if (blank == NULL) {
|
||||||
blank = us_blank_init();
|
blank = us_blank_init();
|
||||||
us_blank_draw(blank, "< NO SIGNAL >", captured_meta.width, captured_meta.height);
|
us_blank_draw(blank, "< NO LIVE VIDEO >", captured_meta.width, captured_meta.height);
|
||||||
}
|
}
|
||||||
frame = blank->jpeg;
|
frame = blank->jpeg;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ us_stream_s *us_stream_init(us_capture_s *cap, us_encoder_s *enc) {
|
|||||||
|
|
||||||
void us_stream_update_blank(us_stream_s *stream, const us_capture_s *cap) {
|
void us_stream_update_blank(us_stream_s *stream, const us_capture_s *cap) {
|
||||||
us_stream_runtime_s *const run = stream->run;
|
us_stream_runtime_s *const run = stream->run;
|
||||||
us_blank_draw(run->blank, "< NO SIGNAL >", cap->width, cap->height);
|
us_blank_draw(run->blank, "< NO LIVE VIDEO >", cap->width, cap->height);
|
||||||
us_fpsi_frame_to_meta(run->blank->raw, &run->notify_meta); // Initial "unchanged" meta
|
us_fpsi_frame_to_meta(run->blank->raw, &run->notify_meta); // Initial "unchanged" meta
|
||||||
_stream_update_captured_fpsi(stream, run->blank->raw, false);
|
_stream_update_captured_fpsi(stream, run->blank->raw, false);
|
||||||
}
|
}
|
||||||
@@ -529,7 +529,7 @@ static int _stream_init_loop(us_stream_s *stream) {
|
|||||||
|
|
||||||
int once = 0;
|
int once = 0;
|
||||||
while (!atomic_load(&stream->run->stop)) {
|
while (!atomic_load(&stream->run->stop)) {
|
||||||
char *blank_reason = "< NO SIGNAL >";
|
const char *blank_reason = "< NO LIVE VIDEO >";
|
||||||
|
|
||||||
# ifdef WITH_GPIO
|
# ifdef WITH_GPIO
|
||||||
us_gpio_set_stream_online(false);
|
us_gpio_set_stream_online(false);
|
||||||
@@ -556,24 +556,58 @@ static int _stream_init_loop(us_stream_s *stream) {
|
|||||||
switch (us_capture_open(stream->cap)) {
|
switch (us_capture_open(stream->cap)) {
|
||||||
case 0: break;
|
case 0: break;
|
||||||
case US_ERROR_NO_DEVICE:
|
case US_ERROR_NO_DEVICE:
|
||||||
blank_reason = "< NO CAPTURE DEVICE >";
|
blank_reason = (
|
||||||
goto known_error;
|
"< NO CAPTURE DEVICE >\n \n"
|
||||||
|
" Possible reasons: \n \n"
|
||||||
|
" - Device unplugged \n \n"
|
||||||
|
" - Bad config \n \n"
|
||||||
|
" - Malfunction "
|
||||||
|
);
|
||||||
|
goto silent_error;
|
||||||
case US_ERROR_NO_CABLE:
|
case US_ERROR_NO_CABLE:
|
||||||
blank_reason = "< NO VIDEO SOURCE >";
|
blank_reason = (
|
||||||
goto known_error;
|
"< NO VIDEO SOURCE >\n \n"
|
||||||
case US_ERROR_NO_DATA:
|
" Possible reasons: \n \n"
|
||||||
goto known_error;
|
" - Source is off \n \n"
|
||||||
|
" - Cable problems "
|
||||||
|
);
|
||||||
|
goto silent_error;
|
||||||
|
case US_ERROR_NO_SIGNAL:
|
||||||
|
blank_reason = (
|
||||||
|
"< NO SIGNAL DETECTED >\n \n"
|
||||||
|
" Possible reasons: \n \n"
|
||||||
|
" - Video suspended \n \n"
|
||||||
|
" - Cable problems "
|
||||||
|
);
|
||||||
|
goto silent_error;
|
||||||
|
case US_ERROR_NO_SYNC:
|
||||||
|
blank_reason = (
|
||||||
|
"< NO SYNC WITH SIGNAL >\n \n"
|
||||||
|
" Possible reasons: \n \n"
|
||||||
|
" - Source is crazy \n \n"
|
||||||
|
" - Cable problems "
|
||||||
|
);
|
||||||
|
goto silent_error;
|
||||||
|
case US_ERROR_NO_LANES:
|
||||||
|
blank_reason = (
|
||||||
|
"< UNSUPPORTED SIGNAL TIMINGS >\n \n"
|
||||||
|
" Possible reasons: \n \n"
|
||||||
|
" - Too high frequency \n \n"
|
||||||
|
" - Source ignores EDID \n \n"
|
||||||
|
" - Invalid EDID "
|
||||||
|
);
|
||||||
|
goto verbose_error;
|
||||||
default:
|
default:
|
||||||
goto unknown_error;
|
goto verbose_error;
|
||||||
}
|
}
|
||||||
us_encoder_open(stream->enc, stream->cap);
|
us_encoder_open(stream->enc, stream->cap);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
known_error:
|
silent_error:
|
||||||
US_ONCE({ US_LOG_INFO("Waiting for the capture device ..."); });
|
US_ONCE({ US_LOG_INFO("Waiting for the capture device ..."); });
|
||||||
goto offline_and_retry;
|
goto offline_and_retry;
|
||||||
|
|
||||||
unknown_error:
|
verbose_error:
|
||||||
once = 0;
|
once = 0;
|
||||||
goto offline_and_retry;
|
goto offline_and_retry;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user