Page 1 of 1

rv1106_ipc例程中录制视频的时长错误

Posted: 2024-05-30 3:03
by PWRJOY
你好,我在rv1106_ipc的基础上做二次开发,主要功能是录制视频生成.mp4文件。
我需要在特定时刻触发视频录制功能,而原有的例程是在.ini文件中固定录制时长duration.
虽然修改代码后也能在特定时刻生成.mp4文件,但是由于信号量rk_storage_muxer_group[id].g_storage_signal没有获取,录制视频流异常结束导致文件时长错误,录制了15分钟但文件信息只有2秒。
2024-05-30_111508.png
storage.c中修改的函数如下:

Code: Select all

//每小时0,15,30,45分钟触发录制
static void *rk_storage_record(void *arg) {
	int *id_ptr = arg;
	int id = *id_ptr;
	printf("id: %d, #Start %s thread, arg:%p\n", id, __func__, arg);

	//设置进程名 rk_storage_record
	prctl(PR_SET_NAME, "rk_storage_record", 0, 0, 0);

	// 如果开启存储
	while (g_storage_record_flag[id] && record_flag[id] == 1) {
		//获取当前时间
		time_t t = time(NULL);
		struct tm tm = *localtime(&t);
		//生成文件名
		snprintf(rk_storage_muxer_group[id].file_name, 512, "%s/%d%02d%02d%02d%02d%02d.%s",
		         rk_storage_muxer_group[id].record_path, tm.tm_year + 1900, tm.tm_mon + 1,
		         tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
		         rk_storage_muxer_group[id].file_format);
		// 打印文件名
		LOG_INFO("[%d], file_name is %s\n", id, rk_storage_muxer_group[id].file_name);
		// 互斥锁
		pthread_mutex_lock(&g_rkmuxer_mutex);
		// 停止旧的muxer
		rk_storage_muxer_group[0].g_record_run_ = 0;
		rkmuxer_deinit(id);
		// 开始新的录制(文件名、视频帧、音频帧)
		rkmuxer_init(id, NULL, rk_storage_muxer_group[id].file_name,
		             &rk_storage_muxer_group[id].g_video_param,
		             &rk_storage_muxer_group[id].g_audio_param);
		rk_storage_muxer_group[0].g_record_run_ = 1;
		pthread_mutex_unlock(&g_rkmuxer_mutex);
		// 等待 file_duration
//		rk_signal_wait(rk_storage_muxer_group[id].g_storage_signal,
//		               rk_storage_muxer_group[id].file_duration * 1000);

        // 等待直到下一个触发点(0, 15, 30, 45分钟) 
        int next_minute = (tm.tm_min / 15 + 1) * 15; 
        if (next_minute >= 60) { 
            next_minute = 0; 
            tm.tm_hour += 1; 
        } 
        tm.tm_min = next_minute; 
        tm.tm_sec = 0; 
        time_t next_trigger_time = mktime(&tm); 
        time_t current_time; 
        
        do { 
            current_time = time(NULL); 
            sleep(1); 
        } while (current_time < next_trigger_time);

	}
	pthread_mutex_lock(&g_rkmuxer_mutex);
	rk_storage_muxer_group[0].g_record_run_ = 0;
	rkmuxer_deinit(id);
	pthread_mutex_unlock(&g_rkmuxer_mutex);

	return NULL;
}
结合开发手册的结构框图,所涉及的部分用红圈全出。
2024-05-30_105818.png
在修改storage.c代码过程中多次看到程序使用muxer复用器相关功能,但是却没有找到#include "rkmuxer.h"这个头文件的位置,麻烦告知下。

想找到复用器muxer生成.mp4部分的源码,排查问题,或者您有别的解决方式。

Re: rv1106_ipc例程中录制视频的时长错误

Posted: 2024-05-30 4:01
by Crocodile
Crocodile wrote: 2024-05-30 3:59
PWRJOY wrote: 2024-05-30 3:03 你好,我在rv1106_ipc的基础上做二次开发,主要功能是录制视频生成.mp4文件。
我需要在特定时刻触发视频录制功能,而原有的例程是在.ini文件中固定录制时长duration.
虽然修改代码后也能在特定时刻生成.mp4文件,但是由于信号量rk_storage_muxer_group[id].g_storage_signal没有获取,录制视频流异常结束导致文件时长错误,录制了15分钟但文件信息只有2秒。
2024-05-30_111508.png
storage.c中修改的函数如下:

Code: Select all

//每小时0,15,30,45分钟触发录制
static void *rk_storage_record(void *arg) {
	int *id_ptr = arg;
	int id = *id_ptr;
	printf("id: %d, #Start %s thread, arg:%p\n", id, __func__, arg);

	//设置进程名 rk_storage_record
	prctl(PR_SET_NAME, "rk_storage_record", 0, 0, 0);

	// 如果开启存储
	while (g_storage_record_flag[id] && record_flag[id] == 1) {
		//获取当前时间
		time_t t = time(NULL);
		struct tm tm = *localtime(&t);
		//生成文件名
		snprintf(rk_storage_muxer_group[id].file_name, 512, "%s/%d%02d%02d%02d%02d%02d.%s",
		         rk_storage_muxer_group[id].record_path, tm.tm_year + 1900, tm.tm_mon + 1,
		         tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
		         rk_storage_muxer_group[id].file_format);
		// 打印文件名
		LOG_INFO("[%d], file_name is %s\n", id, rk_storage_muxer_group[id].file_name);
		// 互斥锁
		pthread_mutex_lock(&g_rkmuxer_mutex);
		// 停止旧的muxer
		rk_storage_muxer_group[0].g_record_run_ = 0;
		rkmuxer_deinit(id);
		// 开始新的录制(文件名、视频帧、音频帧)
		rkmuxer_init(id, NULL, rk_storage_muxer_group[id].file_name,
		             &rk_storage_muxer_group[id].g_video_param,
		             &rk_storage_muxer_group[id].g_audio_param);
		rk_storage_muxer_group[0].g_record_run_ = 1;
		pthread_mutex_unlock(&g_rkmuxer_mutex);
		// 等待 file_duration
//		rk_signal_wait(rk_storage_muxer_group[id].g_storage_signal,
//		               rk_storage_muxer_group[id].file_duration * 1000);

        // 等待直到下一个触发点(0, 15, 30, 45分钟) 
        int next_minute = (tm.tm_min / 15 + 1) * 15; 
        if (next_minute >= 60) { 
            next_minute = 0; 
            tm.tm_hour += 1; 
        } 
        tm.tm_min = next_minute; 
        tm.tm_sec = 0; 
        time_t next_trigger_time = mktime(&tm); 
        time_t current_time; 
        
        do { 
            current_time = time(NULL); 
            sleep(1); 
        } while (current_time < next_trigger_time);

	}
	pthread_mutex_lock(&g_rkmuxer_mutex);
	rk_storage_muxer_group[0].g_record_run_ = 0;
	rkmuxer_deinit(id);
	pthread_mutex_unlock(&g_rkmuxer_mutex);

	return NULL;
}
结合开发手册的结构框图,所涉及的部分用红圈全出。
2024-05-30_105818.png
在修改storage.c代码过程中多次看到程序使用muxer复用器相关功能,但是却没有找到#include "rkmuxer.h"这个头文件的位置,麻烦告知下。

想找到复用器muxer生成.mp4部分的源码,排查问题,或者您有别的解决方式。
您好,rkmuxer.h和相关的库在<SDK>/media/common_algorithm/common_algorithm/misc 下,rkmuxer部分的源码Rockchip是没有公开的.
根据rkipc的文档来看,rkmuxer的作用应该是结合音频和视频编码为mp4文件,而 VENC 目前能支持硬件编码的格式MJPEG和H264,如果您对音频没有需求的话可以考虑单独走视频录制,rkmuxer对原始视频流的封装部分可以自己实现(比如调用ffmpeg库,比较耗时的编码交给VENC实现了),这样的话需求就好实现很多,RKMPI的资料比较完善且灵活性更高,这样可以跳过对rkmuxer可能存在的问题。
mp4的使用需求之前也有其它论坛成员提到,后续我也会测试一下rkmuxer的使用,如果有新的进展我会在wiki进行更新。

Re: rv1106_ipc例程中录制视频的时长错误

Posted: 2024-05-30 4:21
by PWRJOY
感谢您的回复!
能够再解释下“单独走视频录制”这个是什么意思,有什么资料可以参考吗?

Re: rv1106_ipc例程中录制视频的时长错误

Posted: 2024-05-30 5:24
by PWRJOY
把storage.c中修改的代码还原,只配置.ini文件,生成mp4仍然会出现视频时长只有2秒的问题。
所以rkipc的例程本身还是有bug的,您可以复现下。

Re: rv1106_ipc例程中录制视频的时长错误

Posted: 2024-05-30 6:30
by Crocodile
PWRJOY wrote: 2024-05-30 4:21 感谢您的回复!
能够再解释下“单独走视频录制”这个是什么意思,有什么资料可以参考吗?
单独走视频录制就是不要使用rkipc中的那套结构,使用新的框架来实现
rkipc_MP4.jpg
如果您打算保存的视频对分辨率还是格式有需求可另外绑定一套VENC,不需要的话就从原本的输出作处理即可。
实现方法可以参考Rockchip_Developer_Guide_Linux_RKIPC_CN.pdf 中的内容,添加新的参数并实现相关业务代码(方便后续管理)。当然rkipc的框架比较复杂,您也可以重新构建工程,这样在很多组件的调控上更加直观一点,不依赖ini文件可以大大简化工程,wiki中的RKMPI章节也提供了基础框架,您可以在上面的基础上作修改。
rkipc虽然作为rv1106的核心功能,但是本身的完成度有限,很多功能或许是实现有问题或者文档没有说明清楚,在测试过程中不能实现。由于rkipc使用的控制框架比较独特,我们不确定进行维护后会不会和后续Rockchip更新的冲突,所以短期内没有对rkipc进行深入维护的打算。在Rockchip下一个更新后我们会系统性地测试rkipc并更新SDK中的版本,确保rkipc能够正常使用。