Android视频添加时间水印
由于需要在高通平台上做行车记录的功能,需要给视频加上时间水印。
网上搜索了一下方案,发现有在MTK平台做过类似功能的,参考:
http://blog.csdn.net/jimbo_lee/article/details/27545193
最直接的想法就是获取到视频编码前每一帧YUV数据,将时间水印覆盖到对应的像素点上,然后再进行视频编码。
效果图:
主要实现过程:
1.准备0-9数字以及- / 等符号(时间水印中包含的元素)的Bitmap图片,如果是灰度的时间水印,8位深度的Bitmap就可以。Bitmap图片转换成对应的字节数组可以借助工具实现,当然也可以自己解析Bitmap文件(参考http://blog.csdn.net/smileorcryps/article/details/60756967),获取到时间对应的字节数组后,直接覆盖YUV中相应位置的Y分量就可以了;
2.找到相机中video数据流后处理的位置,高通平台hardware/qcom/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp(具体的位置参考后面贴的patch),在这里先根据当前时间获取到具体的水印字节数组,然后修改YUV数据中Y分量(NV21格式,Y单独存储,修改起来也相对简单),这样最后生成的视频中就会包含时间水印了。
问题:时间水印闪烁跳动
之前是修改的frameworks中CameraSource.cpp
void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
int32_t msgType, const sp &data) {
…
这种方式会造成水印不规则闪烁,怀疑是内存缓存的问题,函数是有同步控制的,for循环中的值直接跑乱了。
后来换成在hardware的video流处理阶段进行处理就可以了。
只针对720p视频修改的patch:
diff --git a/hardware/qcom/camera/QCamera2/HAL/QCamera2HWI.cpp b/hardware/qcom/camera/QCamera2/HAL/QCamera2HWI.cpp
old mode 100644
new mode 100755
index 60f7191..891d743
--- a/hardware/qcom/camera/QCamera2/HAL/QCamera2HWI.cpp
+++ b/hardware/qcom/camera/QCamera2/HAL/QCamera2HWI.cpp
@@ -1022,6 +1022,7 @@ QCamera2HardwareInterface::QCamera2HardwareInterface(uint32_t cameraId)mAdvancedCaptureConfigured(false),mFPSReconfigure(false){
+ mWatermarkBuf = NULL;#ifdef TARGET_TS_MAKEUPmMakeUpBuf = NULL;memset(&mFaceRect, -1, sizeof(mFaceRect));
@@ -2222,6 +2223,13 @@ int QCamera2HardwareInterface::startRecording()if (rc == NO_ERROR) {rc = startChannel(QCAMERA_CH_TYPE_VIDEO);}
+
+ if (mWatermarkBuf == NULL) {+ int vid_width, vid_height;
+ mParameters.getVideoSize(&vid_width, &vid_height);
+ mWatermarkBuf = new unsigned char[vid_width*vid_height*3/2];
+ CDBG_HIGH("vid_width=%d,vid_height=%d",vid_width, vid_height);
+ }#ifdef HAS_MULTIMEDIA_HINTSif (rc == NO_ERROR) {
@@ -2259,6 +2267,11 @@ int QCamera2HardwareInterface::stopRecording()}}#endif
+
+ if (mWatermarkBuf) {+ delete []mWatermarkBuf;
+ mWatermarkBuf=NULL;
+ }CDBG_HIGH("%s: X", __func__);return rc;}
diff --git a/hardware/qcom/camera/QCamera2/HAL/QCamera2HWI.h b/hardware/qcom/camera/QCamera2/HAL/QCamera2HWI.h
old mode 100644
new mode 100755
index 236908e..d7b0f92
--- a/hardware/qcom/camera/QCamera2/HAL/QCamera2HWI.h
+++ b/hardware/qcom/camera/QCamera2/HAL/QCamera2HWI.h
@@ -656,6 +656,11 @@ private:int32_t mNumPreviewFaces;bool mAdvancedCaptureConfigured;bool mFPSReconfigure;
+
+ unsigned char *mWatermarkBuf;
+ bool WatermarkProcess_Video(mm_camera_buf_def_t *pFrame,QCameraStream * pStream);
+ bool WatermarkProcess(mm_camera_buf_def_t *pFrame,QCameraStream * pStream,unsigned char *pOutBuf);
+ //ts add for makeup#ifdef TARGET_TS_MAKEUPTSRect mFaceRect;
diff --git a/hardware/qcom/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp b/hardware/qcom/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp
old mode 100644
new mode 100755
index 9065e33..5bb2abc
--- a/hardware/qcom/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp
+++ b/hardware/qcom/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp
@@ -37,6 +37,7 @@#include <utils/Trace.h>#include <utils/Timers.h>#include "QCamera2HWI.h"
+#include "digital_data.h"namespace qcamera {@@ -552,6 +553,87 @@ bool QCamera2HardwareInterface::TsMakeupProcess(mm_camera_buf_def_t *pFrame,return bRet;}#endif
+
+bool QCamera2HardwareInterface::WatermarkProcess_Video(mm_camera_buf_def_t *pFrame,
+ QCameraStream * pStream) {+ CDBG("%s begin",__func__);
+ bool bRet = false;
+ if (pStream == NULL || pFrame == NULL) {+ bRet = false;
+ CDBG_HIGH("%s pStream == NULL || pFrame == NULL",__func__);
+ } else {+ bRet = WatermarkProcess(pFrame,pStream,mWatermarkBuf);
+ }
+ CDBG("%s end bRet = %d ",__func__,bRet);
+ return bRet;
+}
+
+bool QCamera2HardwareInterface::WatermarkProcess(mm_camera_buf_def_t *pFrame,
+ QCameraStream * pStream,unsigned char *pOutBuf) {+ bool bRet = false;
+ CDBG("%s begin",__func__);
+ if (pStream == NULL || pFrame == NULL || pOutBuf == NULL) {+ bRet = false;
+ CDBG_HIGH("%s pStream == NULL || pFrame == NULL || pMakeupOutBuf == NULL",__func__);
+ }
+
+ cam_dimension_t dim;
+ pStream->getFrameDimension(dim);
+
+ int width = dim.width;
+ int height = dim.height;
+ unsigned char *_ptr;
+ _ptr = (unsigned char*)pFrame->buffer;
+
+ if (NULL != _ptr) {
+ char dateTime[] = "2016-12-22 09:00:00";
+ time_t timer;
+ struct tm* t_tm;
+
+ time(&timer);
+ t_tm = localtime(&timer);
+ memset(dateTime, 0, sizeof(dateTime));
+ sprintf(dateTime,"%4d-%02d-%02d %02d:%02d:%02d", t_tm->tm_year+1900, t_tm->tm_mon+1, t_tm->tm_mday, t_tm->tm_hour, t_tm->tm_min, t_tm->tm_sec);
+
+ //ALOGE("========== timestampUs:%d, systemTime():%d, dateTime:%s",timestampUs, systemTime()/1000, dateTime);
+ int digitalNums[10+8+1+ 1] = {-1}; // 10:- 11 :: 12:blank
+ memset(digitalNums, -1, sizeof(digitalNums));
+ for(int i = 0; i<19; i++){
+ char num = dateTime[i];
+ if(('0' <= num) && (num <= '9'))
+ {
+ digitalNums[i] = num - '0';
+ }else if(num == '-'){
+ digitalNums[i] = 10;
+ }else if(num == ':'){
+ digitalNums[i] = 11;
+ }else if(num == ' '){
+ digitalNums[i] = 12;
+ }
+ }
+
+ //for 1280 x 720
+ int left_offset = 776; // width - digital_width * srtlen(dateTime) - digital_width * 2
+ int top_offset = 620; // height - 100
+ for(int j = 0; j<digital_height; j++) {
+ for(volatile int k=0; k<19; k++) {
+ const unsigned char* str = (digitalNums[k] < 12 && digitalNums[k] != -1) ? DigitalArray[digitalNums[k]] : NULL;
+ if(str != NULL) {
+ for(volatile int h=0; h<digital_width; h++) {
+ if(*(str+(digital_height - 1 - j)*digital_width + h) != 0x00) {
+ *(_ptr+top_offset*width + left_offset + j*width + k*(gap_width+digital_width) + h) = *(str+(digital_height - 1 - j)*digital_width + h);
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ CDBG("%s end bRet = %d ",__func__,bRet);
+ return bRet;
+}
+/*===========================================================================* FUNCTION : postproc_channel_cb_routine*
@@ -1119,6 +1201,9 @@ void QCamera2HardwareInterface::video_stream_cb_routine(mm_camera_super_buf_t *sreturn;}mm_camera_buf_def_t *frame = super_frame->bufs[0];
+
+ //ysm
+ pme->WatermarkProcess_Video(frame,stream);if (pme->needDebugFps()) {pme->debugShowVideoFPS();
代码链接:
http://download.csdn.net/detail/smileorcryps/9773313
Android视频添加时间水印相关推荐
- ffmpeg给视频添加时间水印
ffmpeg给视频添加时间水印 通过 drawtext 滤镜模块给视频添加时间水印 给视频添加时间水印 用来做片源调试,非常方便的查找和定位处理的哪一帧视频片源: 1. 添加本地时间水印 ffmpeg ...
- 【Qt+FFmpeg】给视频添加时间水印
ffmpeg编解码中,给本地视频加上时间水印,并保存到本地,使用到的技术是ffmpeg中的avfilter库: 具体效果如下 yuv: mp4 本方法不适合摄像头解码,解码出来糊得不行,本地视频的话会 ...
- Android 拍照添加时间水印
效果如下图 : 1.拍照 // 非空判断 拍照if (mCamera0 != null){mCamera0.takePicture(null, null, jpeg0); // 1 front} 2. ...
- Android 录制视频添加时间水印,不吃透都对不起自己
mStopVideoRecording = true; Log.d(TAG, "stopVideoRecordingAsync() mMediaRecorderRecording=" ...
- Android录像时添加时间水印
在网上搜索整理了下,有三篇有用的文章,原理也是一样. 实现步骤说明在这里Android 录制视频添加时间水印 上面也仅给出了步骤,具体代码在增加录像时间戳水印. camera框架介绍 可以找到.从博客 ...
- android利用EpMedia给录像添加时间水印
做出来的例子效果如下: 第一步:集成EpMedia, 步骤在大神的github上都有,地址如下: https://github.com/yangjie10930/EpMedia 添加时间水印,我的方法 ...
- Android 录像添加时间戳水印
最近项目中需要后台录像并添加时间戳,就类似监控视频,直接放效果图了, demo界面功能如图:跑的时候注意自己到设置加相机权限 这个demo主要做到了两点,一.添加时间戳水印.二.暂停,继续录像.git ...
- PHP实现给视频加图片水印,怎么在视频画面上加图片?如何给视频添加自己的图片作为水印?视频添加图片水印的方法...
今天就是周一啦,昨天周末大家有没有跟好友去玩呢~反正小编是跟同学聚会去了,聚会主题:胖.哈哈哈,不过小编可不跟他们一样只会长胖,小编可是瘦瘦瘦的呢,偷偷的告诉你们,小编减肥瘦了三十斤哦,嘻嘻.好啦,废 ...
- Moviepy模块之视频添加图片水印
文章目录 前言 视频添加图片水印 1.引入库 2.加载视频文件 3.加载水印图片 4.缩放水印图片大小 5.设置水印的位置 5.1 相对于视频的左上角 5.2 相对于视频的左下角 5.3 相对于视频的 ...
最新文章
- golang go-sql-driver 数据库报错 bad connection
- UA MATH564 概率论IV 次序统计量例题2
- python 将excel文件转换为txt文件_python利用pandas将excel文件转换为txt文件的方法
- docker容器的本地局域网yum源优化
- [PyJs系列介绍]三、编译与上线
- Android开发之通过反射获取全局的application
- java mybatis 代码生成器_Java MyBatis-Plus 代码生成器
- oracle 次月,Oracle日期查询:季度、月份、星期等时间信息
- BSD配置SSH服务
- python 最快 因式分解_Python实现的对一个数进行因式分解操作示例
- 研究CV、研究美,MMFashion开源库升级~
- VxWorks程序一下载就停住了
- CodeForces 785C Anton and Fairy Tale 二分
- linux mysql ssh通道_通过SSH通道来访问MySQL
- 删除文件显示正在使用无法删除该怎么办?
- 如何用Jupyter中文集成版画一个图表
- 【挖矿程式】oCam 萤幕录影软体竟然藏有挖矿程式 (BRTSvc)(转)
- 交换两个变量的值的swap函数
- Windows 系统文件资源管理器的命令行参数(如何降权打开程序,如何选择文件)
- 2020“智创未来 · 精彩平度”创新创业大赛阶段性成果概览
热门文章
- 射频识别系统及WMS仓库管理系统功能介绍
- linux键盘符号错乱,Ubuntu14.04 键盘错位小问题
- 专访中科云创周北川:用AI来做工业设备的故障诊断,目前还停留在“鸡尾酒疗法”阶段
- python-生产者消费者模型_线程_线程互斥锁_GIL全局解释器锁
- 怎样学好英语?(多年英语学习经验总结)
- java中任何变量都可以被赋值为null,java中当给一个对象赋值为null时发生了什么...
- FPGA电源设计方案
- cfg格式文件在服务器哪里,cfg文件,小编教你怎么打开cfg文件
- 四川一度智信|小白卖家不懂选品?
- # Sql语句过长报错、查询慢优化方案探索