双路录像利用静态变量做多对象之间简单写互斥
笔者目前在研的项目是基于android6.0的智能后视镜产品,目前存在前视录像跟后视录像的功能,存储的文件路径都是保持到外部的同一张SD卡上的。我们都有一个这样的经验:比如往SD卡拷文件,比如2个文件都是50M,先拷贝第一个50M文件完成后,再拷贝另外一个50M的文件,这样拷贝这2个总共100M文件花费的时间比会先拷贝一个50M文件,在还没有完成拷贝第一个文件的时候就复制拷贝第二个50M的文件到SD卡上等它完成拷贝花费的总时间要少。:
/*****************************************************************************************************/
声明:本博内容均由http://blog.csdn.net/edsam49原创,转载请注明出处,谢谢!
/*****************************************************************************************************/
因为都有这样的体验,确实两个任务在操作同一个卡的时候,总是需要一些协调管理的开销,还会造成写不连续分配簇的问题;那跟我们双路录像有什么关系呢,理论上也是一样的,两个任务会操作同一个SD卡,从效率上看,把两个任务协调成一个任务肯定是更好的效率、性能。
两个不同的任务实际上是两个不同的对象,但是又是同一个类的,因为都要封装成一样的视频格式,因此写卡就在封装格式完成后的接收对象里面。可能很多人会说,在这两个任务里面有很多方法来把他们互相开,理论上确实是这样。做二次开发,很多时候还得看原厂提供的大框架,改动太大出问题了原厂还不一定支持你,另外真改动太大了耗费的人力物力也大,我们想以较小的代价来实现这个功能。
笔者前视录像的码率固定在6M,后视固定在2.2M左右,因此按照编码缓存达到2M阀值后一次写入2M,效率确实会好很多,但是难免会出现两个任务同时写的时候。通过分析,前视的每一次写之间的间隔在2.6~2.8秒之间,后视的在7秒左右,这样留给我们的操作空间就是很大的。
首先我们来看一个打印,笔者加了一个静态变量【cun】,打印如下
09-05 10:13:14.757 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:17.146 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 71,fd = 83
09-05 10:13:17.285 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:20.045 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 72,fd = 83
09-05 10:13:20.176 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:20.387 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 73,fd = 65
09-05 10:13:20.523 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=65
09-05 10:13:22.694 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 74,fd = 83
09-05 10:13:22.839 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:25.453 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 75,fd = 83
09-05 10:13:25.583 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:27.631 D/V4L2CameraDevice( 1677): Mic TVIN framerate = 29fps@720x480
09-05 10:13:28.045 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 76,fd = 65
09-05 10:13:28.178 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=65
09-05 10:13:28.218 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 77,fd = 83
09-05 10:13:28.368 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:30.859 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 78,fd = 83
09-05 10:13:31.030 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:33.700 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 79,fd = 83
09-05 10:13:33.836 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:35.495 D/MvwPcmRecordListener( 4465): ---> length=8000,ret = 0
09-05 10:13:35.502 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 80,fd = 65
09-05 10:13:35.646 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=65
09-05 10:13:36.419 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 81,fd = 83
09-05 10:13:36.551 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:38.976 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 82,fd = 83
09-05 10:13:39.127 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:41.856 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 83,fd = 83
09-05 10:13:41.996 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:43.222 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 84,fd = 65
09-05 10:13:43.363 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=65
09-05 10:13:43.993 D/V4L2CameraDevice( 1677): Mic CSI framerate = 24fps@1280x720
09-05 10:13:44.626 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 85,fd = 83
09-05 10:13:44.758 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:47.304 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 86,fd = 83
09-05 10:13:47.445 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:50.021 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 87,fd = 83
09-05 10:13:50.157 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:50.846 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 88,fd = 65
09-05 10:13:51.013 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=65
09-05 10:13:52.704 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 89,fd = 83
09-05 10:13:52.840 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:55.544 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 90,fd = 83
09-05 10:13:55.681 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:58.223 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 91,fd = 83
09-05 10:13:58.357 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=83
09-05 10:13:58.461 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 92,fd = 65
09-05 10:13:58.602 D/MPEG2TSWriter( 1677): 2##2writeAwCache sfd=65
09-05 10:14:00.822 D/MPEG2TSWriter( 1677): ####judgCouldWrite 1 flag =49,cun = 93,fd = 83
从打印上,存在两个fd,一个是65一个是83,这是两个不同的文件句柄,跟随两个对象里打印出的cun变量确实是线性增长的。那么机会就来了,可以使用这个静态变量来做简单互斥。
static int writingNow =0;
else if((writingNow != 0) && (0 == mForceWrite)){
/*other process has write, so need delay a short time*/
ALOGD("1## writeAwCache sfd=%d, writingNow=%d", sfd, writingNow);
memcpy(mAwCache.mCacheData + mAwCache.mValidCacheSize, (uint8_t *)write_data, needWriteSize);
mAwCache.mValidCacheSize += needWriteSize;
mAwCache.mCacheSize = mAwCache.mCacheSize + 200*1024;
mForceWrite = 1;
}
大概思路是这样的,在写之前都判断一下【cun】是不是为0,如果是0,那就说明还没有人写,那就可以立马先把【cun】置一,然后再写,因为笔者使用的是class10的卡,因此2M的写入基本在200ms之内就解决了;因此笔者就定了一个能兼容两个人任务的时间缓冲,也就是保障一个任务完全写完成后才开始另外一个写任务。考虑到了这一点,实施起来就简单了,笔者想得比较简单一点,就是在写阀值稍微调大一点,在将触发老阀值2M的时候先判断一下是否有任务写,如果有就把阀值临时调大一点,缓存会继续接受编码数据,得到达到新阀值的时候,先前的那个写任务早就完成了。这样就可以岔开这个写动作,这个修改从总的来说,改善还是蛮多的。另外还得考虑一下,下次万一还是没写完的情况,也得做一个强制启动写,不能一直这样缓存下去。考虑问题还是尽量要闭环思维。
这个思路套路不深,浅显易懂。笔者通过批量机器试验,证明还是行之有效的。