ffmpeg编解码中,给本地视频加上时间水印,并保存到本地,使用到的技术是ffmpeg中的avfilter库;

具体效果如下

yuv:

mp4

本方法不适合摄像头解码,解码出来糊得不行,本地视频的话会好得多;

具体代码如下:

int video::waterMark(AVFrame *frame_in,AVFrame *frame_out,int w,int h,const char *str)
{int ret;/*根据名字获取ffmegding定义的filter*/const AVFilter *buffersrc=avfilter_get_by_name("buffer");//原始数据const AVFilter *buffersink=avfilter_get_by_name("buffersink");//处理后的数据/*动态分配AVFilterInOut空间*/outputs=avfilter_inout_alloc();inputs=avfilter_inout_alloc();/*创建AVFilterGraph,分配空间*/filter_graph = avfilter_graph_alloc();enum AVPixelFormat pix_fmts[]={AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE};//设置格式/*过滤器参数:解码器的解码帧将被插入这里。*/char args[256];snprintf(args, sizeof(args),"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",w,h,AV_PIX_FMT_YUV420P,1,25,1,1);//图像宽高,格式,帧率,画面横纵比qDebug()<<args;/*创建过滤器上下文,源数据AVFilterContext*/AVFilterContext *buffersrc_ctx = nullptr;ret=avfilter_graph_create_filter(&buffersrc_ctx,buffersrc,"in",args,NULL,filter_graph);if(ret<0){qDebug()<<"创建过滤器上下文失败AVFilterContext";return -1;}/*创建过滤器上下文,处理后数据buffersink_params*/AVBufferSinkParams *buffersink_params;buffersink_params=av_buffersink_params_alloc();buffersink_params->pixel_fmts=pix_fmts;//设置格式AVFilterContext *buffersink_ctx;ret=avfilter_graph_create_filter(&buffersink_ctx,buffersink,"out",NULL,buffersink_params,filter_graph);av_free(buffersink_params);if(ret<0){qDebug()<<"创建sink过滤器上下文失败AVFilterContext";return -2;}/*过滤器链输入/输出链接列表*/outputs->name       =av_strdup("in");outputs->filter_ctx =buffersrc_ctx;outputs->pad_idx    =0;outputs->next       =NULL;inputs->name      =av_strdup("out");inputs->filter_ctx  =buffersink_ctx;inputs->pad_idx    =0;inputs->next      =NULL;char filter_desrc[200]={0};//要添加的水印数据snprintf(filter_desrc,sizeof(filter_desrc),"drawtext=fontfile=arial.ttf:fontcolor=green:fontsize=20:x=450:y=50:text='%s'",str);qDebug()<<filter_desrc;if(avfilter_graph_parse_ptr(filter_graph,filter_desrc,&inputs,&outputs, NULL)<0)//设置过滤器数据内容{qDebug()<<avfilter_graph_parse_ptr(filter_graph,filter_desrc,&inputs,&outputs, NULL);qDebug()<<"添加字符串信息失败";return -3;}qDebug()<<"添加字符串信息成功";/*检测配置信息是否正常*/if(avfilter_graph_config(filter_graph,NULL)<0){qDebug()<<"配置信息有误";return -4;}qDebug()<<"配置信息成功";/*往源滤波器buffer中输入待处理数据*/if(av_buffersrc_add_frame(buffersrc_ctx,frame_in)<0){qDebug()<<"往源滤波器buffer中输入待处理数据有误";return -5;}qDebug()<<"往源滤波器buffer中输入待处理数据成功";/*从滤波器中输出处理数据*/if(av_buffersink_get_frame(buffersink_ctx, frame_out)<0){qDebug()<<"从滤波器中输出处理数据失败";return -6;}qDebug()<<"从滤波器中输出处理数据成功";avfilter_inout_free(&outputs);avfilter_inout_free(&inputs);avfilter_graph_free(&filter_graph);return 0;}

上述的函数我是放入解码线程中进行循环操作,解码部分可以参考我之前的【Qt+FFmpeg】解码播放本地视频(一)_logani的博客-CSDN博客

部分有些出入,所以这边还是贴一下代码

void video::run()
{   in_width=avcodec_context->width;in_height=avcodec_context->height;qDebug()<<"6.循环解码";//packet开空间av_packet = (AVPacket*)av_malloc(sizeof(AVPacket));//输入->环境一帧数据->缓冲区->类似于一张图pFramein = av_frame_alloc();//输出->帧数据->数据格式->RGBpFrameRGB = av_frame_alloc();pictureYUV=av_frame_alloc();pFrameOUT=av_frame_alloc();pictureYUV->format = avcodec_context->pix_fmt;    //获取像素格式pFrameRGB->format = avcodec_context->pix_fmt;    //获取像素格式//只有指定了AVFrame的像素格式、画面大小才能真正分配内存//缓冲区分配内存RGBpOutbuffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_RGB32, avcodec_context->width, avcodec_context->height));//缓冲区分配内存YUVbuffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, avcodec_context->width, avcodec_context->height));bufferOUT= (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, avcodec_context->width, avcodec_context->height));//初始化缓冲区 类似于memsetavpicture_fill((AVPicture *)pFrameRGB, pOutbuffer,AV_PIX_FMT_RGB32, avcodec_context->width, avcodec_context->height);//初始化缓冲区 类似于memsetavpicture_fill((AVPicture *)pictureYUV, buffer,AV_PIX_FMT_YUV420P, avcodec_context->width, avcodec_context->height);avpicture_fill((AVPicture *)pFrameOUT, bufferOUT,AV_PIX_FMT_YUV420P, avcodec_context->width, avcodec_context->height);//解码的状态类型(0:表示解码完毕,非0:表示正在解码)int y_size, u_size, v_size=0;//用于转码(缩放)的参数,转之前的宽高,转之后的宽高,格式等//准备一个视频像素数据格式上下文//参数一:输入帧数据宽//参数二:输入帧数据高//参数三:输入帧数据格式//参数四:输出帧数据宽//参数五:输出帧数据高//参数六:输出帧数据格式->AV_PIX_FMT_RGB32//参数七:视频像素数据格式转换算法类型//参数八:字节对齐类型(C/C++里面)->提高读取效率SwsContext* pSwsContext = sws_getContext(avcodec_context->width,avcodec_context->height,avcodec_context->pix_fmt,avcodec_context->width,avcodec_context->height,AV_PIX_FMT_RGB32,SWS_BICUBIC,NULL,NULL,NULL);SwsContext* ySwsContent = sws_getContext(avcodec_context->width,avcodec_context->height,avcodec_context->pix_fmt,avcodec_context->width,avcodec_context->height,AV_PIX_FMT_YUV420P,SWS_BICUBIC,NULL,NULL,NULL);//保存 yuv 像素数据的文件FILE *fpyuv=fopen("../videofile/saveYUV.yuv","wb+");int ret=0;while (m_stop == false){//>=0:说明有数据,继续读取   <0:说明读取完毕,结束//从视频文件上下文中读取包--- 有数据就一直读取if (av_read_frame(avformat_context,av_packet) >= 0){//解码什么类型流(视频流、音频流、字幕流等等...)if (av_packet->stream_index == av_stream_index){//发送一个包数据进行解码avcodec_send_packet(avcodec_context, av_packet);//接收一个包数据,解压成一帧ret = avcodec_receive_frame(avcodec_context,pFramein);if (ret == 0){sws_scale(ySwsContent,(const unsigned char* const*)pFramein->data,pFramein->linesize, 0,avcodec_context->height,pictureYUV->data, pictureYUV->linesize);sws_scale(ySwsContent,(const unsigned char* const*)pFramein->data,pFramein->linesize, 0,avcodec_context->height,pFrameOUT->data, pictureYUV->linesize);pictureYUV->width=in_width;pictureYUV->height=in_height;pictureYUV->format=AV_PIX_FMT_YUV420P;//图片格式的转换  输入 输出sws_scale(pSwsContext, (const unsigned char* const*)pFramein->data, pFramein->linesize, 0, avcodec_context->height,pFrameRGB->data,  pFrameRGB->linesize);QImage image(pOutbuffer,avcodec_context->width,avcodec_context->height,QImage::Format_RGB32);qDebug()<<"接收图片信号"<<image;sec=time(NULL);if(sec!=sec2){sec2=sec;struct tm* today = localtime(&sec2);strftime(sys_time, sizeof(sys_time), "%Y/%m/%d %H\\:%M\\:%S", today);}waterMark(pictureYUV,pFrameOUT,in_width,in_height,sys_time);//添加水印//yuv420规则一:Y结构表示一个像素点//yuv420规则二:四个Y对应一个U和一个V(也就是四个像素点,对应一个U和一个V)// y = 宽 * 高// u = y / 4// v = y / 4y_size = avcodec_context->width * avcodec_context->height;u_size = y_size / 4;v_size = y_size / 4;fwrite(pFrameOUT->data[0],1,y_size,fpyuv);//Y  UV 个数是 Y 的 1/4fwrite(pFrameOUT->data[1],1,u_size,fpyuv);//Ufwrite(pFrameOUT->data[2],1,v_size,fpyuv);//V//计数第几张图片current_frame_index++;//发送图片信号emit sigGetOneFrame(image);emit SendOneData(current_frame_index);video::YUVQueue.enqueue(pFrameOUT);//YUV像素数据存入队列中video::ImageQueue.enqueue(image);//RGB存入队列//pCoding->codingFrame(pFramein);//发送YUV//延时操作  1秒显示25帧--1000/25=40QThread::msleep(timeSpeed);//获取的视频信息qDebug()<<QString("当前遍历第 %1 帧").arg(current_frame_index);}}}else{qDebug()<<"播放完毕";emit sigPlayOver();//读取完视频发出信号this->current_frame_index=0;//清空计数this->stop();//关闭文件fclose(fpyuv);}av_free_packet(av_packet);}
}

做完这些,可能会存在的一些问题:

1. avfilter_graph_create_filter返回值小于0,打印值为-22;

原因:没有注册avfilter组件

解决方法:注册一下环境

2. avfilter_graph_parse_ptr返回值小于0,添加字符信息失败;

红字字体错误:[Parsed_drawtext_0 @ 0x70fc22fe00] Cannot find a valid font for the family Sans

[AVFilterGraph @ 0x71031fc980] Error initializing filter 'drawtext'

原因:没有本地字体文件

解决方法:网上下载一个

3. 红色字体错误Changing video/audio frame properties on the fly is not supported by all filters

原因:可能是输入流没有初始化大小和格式?

添加了下面代码就没有报错

本文参考了

基于FFMPEG水印添加---avfilter库_IT_阿水的博客-CSDN博客_ffmpeg 动态水印

感谢观看!!!!

以上就是全部内容,如果对您有帮助,欢迎点赞评论,或者发现有哪里写错的,欢迎指正!

【Qt+FFmpeg】给视频添加时间水印相关推荐

  1. ffmpeg给视频添加时间水印

    ffmpeg给视频添加时间水印 通过 drawtext 滤镜模块给视频添加时间水印 给视频添加时间水印 用来做片源调试,非常方便的查找和定位处理的哪一帧视频片源: 1. 添加本地时间水印 ffmpeg ...

  2. Android视频添加时间水印

    由于需要在高通平台上做行车记录的功能,需要给视频加上时间水印. 网上搜索了一下方案,发现有在MTK平台做过类似功能的,参考: http://blog.csdn.net/jimbo_lee/articl ...

  3. ffmpeg实现视频实时动态时间水印

    首先看下效果 左上角的实时当前时间,纯c完成.下面的是hello ffmpeg字样是avfilter的drawtext实现. 动态时间水印,其实ffmpeg有命令可以实现,不过我在windows下发现 ...

  4. Android 录制视频添加时间水印,不吃透都对不起自己

    mStopVideoRecording = true; Log.d(TAG, "stopVideoRecordingAsync() mMediaRecorderRecording=" ...

  5. Android录像时添加时间水印

    在网上搜索整理了下,有三篇有用的文章,原理也是一样. 实现步骤说明在这里Android 录制视频添加时间水印 上面也仅给出了步骤,具体代码在增加录像时间戳水印. camera框架介绍 可以找到.从博客 ...

  6. 使用ffmpeg给视频添加图片及文字水印

    1. 准备工具 MacBook Pro homebrew ffmpeg 2.工具安装 homebrew安装 说起homebrew确实是Mac上非常好用的一个工具,像什么CocoPods,node,ff ...

  7. 用Java为视频添加图片水印(类似直播)

    文章目录 1.首先[下载nginx](http://nginx-win.ecsds.eu/download/) 2.[下载ffmpeg](https://pan.baidu.com/s/1LUWeVn ...

  8. PHP实现给视频加图片水印,怎么在视频画面上加图片?如何给视频添加自己的图片作为水印?视频添加图片水印的方法...

    今天就是周一啦,昨天周末大家有没有跟好友去玩呢~反正小编是跟同学聚会去了,聚会主题:胖.哈哈哈,不过小编可不跟他们一样只会长胖,小编可是瘦瘦瘦的呢,偷偷的告诉你们,小编减肥瘦了三十斤哦,嘻嘻.好啦,废 ...

  9. Moviepy模块之视频添加图片水印

    文章目录 前言 视频添加图片水印 1.引入库 2.加载视频文件 3.加载水印图片 4.缩放水印图片大小 5.设置水印的位置 5.1 相对于视频的左上角 5.2 相对于视频的左下角 5.3 相对于视频的 ...

最新文章

  1. nginx+tomcat的负载均衡
  2. python:装饰器
  3. ML之sklearn:sklearn.metrics中常用的函数参数(比如confusion_matrix等 )解释及其用法说明之详细攻略
  4. Hyperopt中文文档:Cite引用
  5. BZOJ2301: [HAOI2011]Problem b
  6. 【排错】net::ERR_ABORTED 404
  7. 点乘叉乘坐标公式_点积与叉乘的运算与物理意义
  8. SQLServer数据库文件组相关知识笔记
  9. 【经典回放】多种语言系列数据结构算法:二叉树(C#版)
  10. mapper mysql 主键_实现通用mapper主键策略兼容mysql和oracle
  11. printf函数输出格式汇总
  12. 写磁盘太慢导致服务超时问题分析
  13. idea的Database导出导入表操作
  14. H3CNE综合小实验
  15. Hinton 2006 science 文章 RBM 预训练 AutoEncoder
  16. 六种礼仪帮助你赢得面试
  17. java实现高斯日记
  18. 在Linux中安装JKD(详细教学)
  19. 2020.10.7--PS--填充图层、调整图层、调整图层与剪贴蒙版
  20. vue 数字动画递增_数字滚动动画效果 vue组件化

热门文章

  1. bugku never give up
  2. 量子近似优化算法QAOA——解读与代码实现
  3. 合作对策模型的简单实现
  4. Android Studio 星座查询系统
  5. 网络学习(第十八篇-HSRP协议讲解以及配置思路)
  6. python 股票交易接口 github_GitHub - xiongyixiaoyang/vnpy: 基于python的开源量化交易平台开发框架...
  7. ABAP CDS View
  8. php 发送邮箱验证怎么做,PHP 实现 注册等的邮箱验证 (二)—— 使用 PHPMailer 发送邮件...
  9. matlab 端点检测 能零比法_基于短时能量与过零率的端点检测的matlab分析
  10. 南京外企100万,杭州阿里p8 150万,怎么选?