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
4041MB_POOL memPool = MB_INVALID_POOLID ;
4142
43+ bool sleep_mode_available = false;
4244bool should_exit = false;
4345float 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+
5495double 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
191232pthread_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
303351uint32_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
306354pthread_t * streaming_thread = NULL ;
307355pthread_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+
309375void 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-
586668void 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
619702void 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
637739void * 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
749837float video_get_quality_factor () {
750838 return quality_factor ;
751- }
839+ }
0 commit comments