Skip to content

Commit 2444817

Browse files
ymadamshiervanithinkafterbefore
authored
chore: disable sleep mode when detecting video format (#887)
Co-authored-by: Adam Shiervani <adam.shiervani@gmail.com> Co-authored-by: Adam Shiervani <adamshiervani@fastmail.com>
1 parent 74e64f6 commit 2444817

File tree

11 files changed

+257
-69
lines changed

11 files changed

+257
-69
lines changed

config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ type Config struct {
106106
NetworkConfig *types.NetworkConfig `json:"network_config"`
107107
DefaultLogLevel string `json:"default_log_level"`
108108
VideoSleepAfterSec int `json:"video_sleep_after_sec"`
109+
VideoQualityFactor float64 `json:"video_quality_factor"`
109110
}
110111

111112
func (c *Config) GetDisplayRotation() uint16 {

internal/native/cgo/ctrl.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,8 +405,8 @@ char *jetkvm_video_log_status() {
405405
return (char *)videoc_log_status();
406406
}
407407

408-
int jetkvm_video_init() {
409-
return video_init();
408+
int jetkvm_video_init(float factor) {
409+
return video_init(factor);
410410
}
411411

412412
void jetkvm_video_shutdown() {

internal/native/cgo/ctrl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const char *jetkvm_ui_get_lvgl_version();
5252

5353
const char *jetkvm_ui_event_code_to_name(int code);
5454

55-
int jetkvm_video_init();
55+
int jetkvm_video_init(float quality_factor);
5656
void jetkvm_video_shutdown();
5757
void jetkvm_video_start();
5858
void jetkvm_video_stop();

internal/native/cgo/video.c

Lines changed: 143 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#define VIDEO_DEV "/dev/video0"
3131
#define SUB_DEV "/dev/v4l-subdev2"
32+
#define SLEEP_MODE_FILE "/sys/devices/platform/ff470000.i2c/i2c-4/4-000f/sleep_mode"
3233

3334
#define RK_ALIGN(x, a) (((x) + (a)-1) & ~((a)-1))
3435
#define RK_ALIGN_2(x) RK_ALIGN(x, 2)
@@ -39,6 +40,7 @@ int sub_dev_fd = -1;
3940
#define VENC_CHANNEL 0
4041
MB_POOL memPool = MB_INVALID_POOLID;
4142

43+
bool sleep_mode_available = false;
4244
bool should_exit = false;
4345
float quality_factor = 1.0f;
4446

@@ -51,6 +53,45 @@ RK_U64 get_us()
5153
return (RK_U64)time.tv_sec * 1000000 + (RK_U64)time.tv_nsec / 1000; /* microseconds */
5254
}
5355

56+
static void ensure_sleep_mode_disabled()
57+
{
58+
if (!sleep_mode_available)
59+
{
60+
return;
61+
}
62+
63+
int fd = open(SLEEP_MODE_FILE, O_RDWR);
64+
if (fd < 0)
65+
{
66+
log_error("Failed to open sleep mode file: %s", strerror(errno));
67+
return;
68+
}
69+
lseek(fd, 0, SEEK_SET);
70+
char buffer[1];
71+
read(fd, buffer, 1);
72+
if (buffer[0] == '0') {
73+
close(fd);
74+
return;
75+
}
76+
log_warn("HDMI sleep mode is not disabled, disabling it");
77+
lseek(fd, 0, SEEK_SET);
78+
write(fd, "0", 1);
79+
close(fd);
80+
81+
usleep(1000); // give some time to the system to disable the sleep mode
82+
return;
83+
}
84+
85+
static void detect_sleep_mode()
86+
{
87+
if (access(SLEEP_MODE_FILE, F_OK) != 0) {
88+
sleep_mode_available = false;
89+
return;
90+
}
91+
sleep_mode_available = true;
92+
ensure_sleep_mode_disabled();
93+
}
94+
5495
double calculate_bitrate(float bitrate_factor, int width, int height)
5596
{
5697
const int32_t base_bitrate_high = 2000;
@@ -190,8 +231,15 @@ static int32_t buf_init()
190231

191232
pthread_t *format_thread = NULL;
192233

193-
int video_init()
234+
int video_init(float factor)
194235
{
236+
detect_sleep_mode();
237+
238+
if (factor < 0 || factor > 1) {
239+
factor = 1.0f;
240+
}
241+
quality_factor = factor;
242+
195243
if (RK_MPI_SYS_Init() != RK_SUCCESS)
196244
{
197245
log_error("RK_MPI_SYS_Init failed");
@@ -301,11 +349,29 @@ static void *venc_read_stream(void *arg)
301349
}
302350

303351
uint32_t detected_width, detected_height;
304-
bool detected_signal = false, streaming_flag = false;
352+
bool detected_signal = false, streaming_flag = false, streaming_stopped = true;
305353

306354
pthread_t *streaming_thread = NULL;
307355
pthread_mutex_t streaming_mutex = PTHREAD_MUTEX_INITIALIZER;
308356

357+
bool get_streaming_flag()
358+
{
359+
log_info("getting streaming flag");
360+
pthread_mutex_lock(&streaming_mutex);
361+
bool flag = streaming_flag;
362+
pthread_mutex_unlock(&streaming_mutex);
363+
return flag;
364+
}
365+
366+
void set_streaming_flag(bool flag)
367+
{
368+
log_info("setting streaming flag to %d", flag);
369+
370+
pthread_mutex_lock(&streaming_mutex);
371+
streaming_flag = flag;
372+
pthread_mutex_unlock(&streaming_mutex);
373+
}
374+
309375
void write_buffer_to_file(const uint8_t *buffer, size_t length, const char *filename)
310376
{
311377
FILE *file = fopen(filename, "wb");
@@ -319,6 +385,8 @@ void *run_video_stream(void *arg)
319385

320386
log_info("running video stream");
321387

388+
streaming_stopped = false;
389+
322390
while (streaming_flag)
323391
{
324392
if (detected_signal == false)
@@ -401,7 +469,7 @@ void *run_video_stream(void *arg)
401469
{
402470
log_error("get mb blk failed!");
403471
close(video_dev_fd);
404-
return ;
472+
return (void *)errno;
405473
}
406474
log_info("Got memory block for buffer %d", i);
407475

@@ -538,6 +606,18 @@ void *run_video_stream(void *arg)
538606
log_error("VIDIOC_STREAMOFF failed: %s", strerror(errno));
539607
}
540608

609+
// Explicitly free V4L2 buffer queue
610+
struct v4l2_requestbuffers req_free;
611+
memset(&req_free, 0, sizeof(req_free));
612+
req_free.count = 0;
613+
req_free.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
614+
req_free.memory = V4L2_MEMORY_DMABUF;
615+
616+
if (ioctl(video_dev_fd, VIDIOC_REQBUFS, &req_free) < 0)
617+
{
618+
log_error("Failed to free V4L2 buffers: %s", strerror(errno));
619+
}
620+
541621
venc_stop();
542622

543623
for (int i = 0; i < input_buffer_count; i++)
@@ -553,6 +633,9 @@ void *run_video_stream(void *arg)
553633
}
554634

555635
log_info("video stream thread exiting");
636+
637+
streaming_stopped = true;
638+
556639
return NULL;
557640
}
558641

@@ -577,61 +660,80 @@ void video_shutdown()
577660
RK_MPI_MB_DestroyPool(memPool);
578661
}
579662
log_info("Destroyed memory pool");
580-
663+
581664
pthread_mutex_destroy(&streaming_mutex);
582665
log_info("Destroyed streaming mutex");
583666
}
584667

585-
586668
void video_start_streaming()
587669
{
588-
pthread_mutex_lock(&streaming_mutex);
670+
log_info("starting video streaming");
589671
if (streaming_thread != NULL)
590672
{
673+
if (streaming_stopped == true) {
674+
log_error("video streaming already stopped but streaming_thread is not NULL");
675+
assert(streaming_stopped == true);
676+
}
591677
log_warn("video streaming already started");
592-
goto cleanup;
678+
return;
593679
}
594-
680+
595681
pthread_t *new_thread = malloc(sizeof(pthread_t));
596682
if (new_thread == NULL)
597683
{
598684
log_error("Failed to allocate memory for streaming thread");
599-
goto cleanup;
685+
return;
600686
}
601-
602-
streaming_flag = true;
687+
688+
set_streaming_flag(true);
603689
int result = pthread_create(new_thread, NULL, run_video_stream, NULL);
604690
if (result != 0)
605691
{
606692
log_error("Failed to create streaming thread: %s", strerror(result));
607-
streaming_flag = false;
693+
set_streaming_flag(false);
608694
free(new_thread);
609-
goto cleanup;
695+
return;
610696
}
611-
612-
// Only set streaming_thread after successful creation, and before unlocking the mutex
697+
698+
// Only set streaming_thread after successful creation
613699
streaming_thread = new_thread;
614-
cleanup:
615-
pthread_mutex_unlock(&streaming_mutex);
616-
return;
617700
}
618701

619702
void video_stop_streaming()
620703
{
621-
pthread_mutex_lock(&streaming_mutex);
622-
if (streaming_thread != NULL)
704+
if (streaming_thread == NULL) {
705+
log_info("video streaming already stopped");
706+
return;
707+
}
708+
709+
log_info("stopping video streaming");
710+
set_streaming_flag(false);
711+
712+
log_info("waiting for video streaming thread to exit");
713+
int attempts = 0;
714+
while (!streaming_stopped && attempts < 30) {
715+
usleep(100000); // 100ms
716+
attempts++;
717+
}
718+
if (!streaming_stopped) {
719+
log_error("video streaming thread did not exit after 30s");
720+
}
721+
722+
pthread_join(*streaming_thread, NULL);
723+
free(streaming_thread);
724+
streaming_thread = NULL;
725+
726+
log_info("video streaming stopped");
727+
}
728+
729+
void video_restart_streaming()
730+
{
731+
if (get_streaming_flag() == true)
623732
{
624-
streaming_flag = false;
625-
log_info("stopping video streaming");
626-
// wait 100ms for the thread to exit
627-
usleep(1000000);
628-
log_info("waiting for video streaming thread to exit");
629-
pthread_join(*streaming_thread, NULL);
630-
free(streaming_thread);
631-
streaming_thread = NULL;
632-
log_info("video streaming stopped");
733+
log_info("restarting video streaming");
734+
video_stop_streaming();
633735
}
634-
pthread_mutex_unlock(&streaming_mutex);
736+
video_start_streaming();
635737
}
636738

637739
void *run_detect_format(void *arg)
@@ -650,6 +752,8 @@ void *run_detect_format(void *arg)
650752

651753
while (!should_exit)
652754
{
755+
ensure_sleep_mode_disabled();
756+
653757
memset(&dv_timings, 0, sizeof(dv_timings));
654758
if (ioctl(sub_dev_fd, VIDIOC_QUERY_DV_TIMINGS, &dv_timings) != 0)
655759
{
@@ -689,21 +793,17 @@ void *run_detect_format(void *arg)
689793
(dv_timings.bt.width + dv_timings.bt.hfrontporch + dv_timings.bt.hsync +
690794
dv_timings.bt.hbackporch));
691795
log_info("Frames per second: %.2f fps", frames_per_second);
796+
797+
bool should_restart = dv_timings.bt.width != detected_width || dv_timings.bt.height != detected_height || !detected_signal;
798+
692799
detected_width = dv_timings.bt.width;
693800
detected_height = dv_timings.bt.height;
694801
detected_signal = true;
695802
video_report_format(true, NULL, detected_width, detected_height, frames_per_second);
696-
pthread_mutex_lock(&streaming_mutex);
697-
if (streaming_flag == true)
698-
{
699-
pthread_mutex_unlock(&streaming_mutex);
700-
log_info("restarting on going video streaming");
701-
video_stop_streaming();
702-
video_start_streaming();
703-
}
704-
else
705-
{
706-
pthread_mutex_unlock(&streaming_mutex);
803+
804+
if (should_restart) {
805+
log_info("restarting video streaming due to format change");
806+
video_restart_streaming();
707807
}
708808
}
709809

@@ -731,21 +831,9 @@ void video_set_quality_factor(float factor)
731831
quality_factor = factor;
732832

733833
// TODO: update venc bitrate without stopping streaming
734-
735-
pthread_mutex_lock(&streaming_mutex);
736-
if (streaming_flag == true)
737-
{
738-
pthread_mutex_unlock(&streaming_mutex);
739-
log_info("restarting on going video streaming due to quality factor change");
740-
video_stop_streaming();
741-
video_start_streaming();
742-
}
743-
else
744-
{
745-
pthread_mutex_unlock(&streaming_mutex);
746-
}
834+
video_restart_streaming();
747835
}
748836

749837
float video_get_quality_factor() {
750838
return quality_factor;
751-
}
839+
}

internal/native/cgo/video.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
* @return int 0 on success, -1 on failure
88
*/
9-
int video_init();
9+
int video_init(float quality_factor);
1010

1111
/**
1212
* @brief Shutdown the video subsystem

internal/native/cgo_linux.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,13 @@ func uiTick() {
129129
C.jetkvm_ui_tick()
130130
}
131131

132-
func videoInit() error {
132+
func videoInit(factor float64) error {
133133
cgoLock.Lock()
134134
defer cgoLock.Unlock()
135135

136-
ret := C.jetkvm_video_init()
136+
factorC := C.float(factor)
137+
138+
ret := C.jetkvm_video_init(factorC)
137139
if ret != 0 {
138140
return fmt.Errorf("failed to initialize video: %d", ret)
139141
}

0 commit comments

Comments
 (0)