鹰潭北京网站建设,深圳网站设计机构,ui界面设计包括哪些内容,男女做那个的的视频网站实现思路 #x1f914; 基于ffmpeg#xff0c;画布的方式#xff0c;创建画布 - 水印 - 旋转 - 抠图 - 叠加到图像上基于ffmpeg#xff0c;旋转图片的方式#xff0c;填充 - 水印 - 顺时针旋转 - 逆时针旋转 - 截图基于opencv#xff…
实现思路 基于ffmpeg画布的方式创建画布 - 水印 - 旋转 - 抠图 - 叠加到图像上基于ffmpeg旋转图片的方式填充 - 水印 - 顺时针旋转 - 逆时针旋转 - 截图基于opencv创建画布 - 水印 - 仿射变换 - 水平垂直拼接 - 叠加图片上 经测试比对opencv实现方式效率是最快的 代码实现
FFmpeg 旋转画布方式 这种方式相对实现简单一些但经过试验对于一个2k的视频实现全屏文字倾斜效率太慢了 。不知道是我代码问题还是什么问题。如果有大佬能提高效率方便指导一二抱拳了.实现参考 https://blog.csdn.net/qq_38722827/article/details/121549999 https://blog.csdn.net/qq_23282479/article/details/119904850 旋转图片方式 思路: 首先将图片填充放大然后计算出水印位置叠加水印再逆时针将图片旋转回来字体就变斜了。然后通过剪裁将图片剪切成原图大小。 基于 ffmpeg filter 实现 // 填充// [in]scale原图宽:原图高,pad填充后宽:填充后高:填充左右大小:填充上下大小:black[out]// 四周填充, pad 输入尺寸的一半char dtext[512];snprintf(dtext, sizeof(dtext), [in]scale%d:%d,pad%d:%d:%d:%d:black[out],frameWidth, frameHeight, expandFrameWidth, expandFrameHeight, expandSize, expandSize);// 水印// inxxxx[a];[a]xxx[a];[a]xxx[out] 中间传的文字标签首位对应([a] [a]). 结束没有;. char dtext[1000];snprintf(dtext, sizeof(dtext), [in]drawtextfontfile%s:text%s:x%d:y%d:fontsize%d:fontcolor%s:alpha%.1f[a];,kFont, txt.c_str(), start_x, start_y, kFontSize, kFontColor, italicTextInfo_.alpha);// 翻转// [in]rotatePI* angel /180[out] char dtext[512];snprintf(dtext, sizeof(dtext), [in]rotatePI* %d /180[out], angel);// 截取 // [in]crop原图宽:原图高:截取x:截取y[out]char dtext[512];snprintf(dtext, sizeof(dtext), [in]crop%d:%d:%d:%d[out], frameWidth, frameHeight, startx, starty);创建 AVFilterGraph int init_filter_graph(const std::string filter) {filterGraph_ avfilter_graph_alloc();const AVFilter* buffersrc avfilter_get_by_name(buffer);const AVFilter* buffersink avfilter_get_by_name(buffersink);char args[512];snprintf(args, sizeof(args), video_size%dx%d:pix_fmt%d:time_base%d/%d:pixel_aspect%d/%d, frameWidth_, frameHeight_, frameFormat_, 1, videoFps_, 1, 1);int ret avfilter_graph_create_filter(buffersrcCtx_, buffersrc, in, args, NULL, filterGraph_);if (ret 0){avfilter_graph_free(filterGraph_);filterGraph_ NULL;return -1;}// buffer video sink: to terminate the filter chain.enum AVPixelFormat pix_fmts[] { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12, AV_PIX_FMT_NONE };AVBufferSinkParams* buffersink_params av_buffersink_params_alloc();buffersink_params-pixel_fmts pix_fmts;ret avfilter_graph_create_filter(buffersinkCtx_, buffersink, out, NULL, buffersink_params, filterGraph_);av_free(buffersink_params);if (ret 0){avfilter_graph_free(filterGraph_);filterGraph_ NULL;return -1;}AVFilterInOut* outputs avfilter_inout_alloc();/* Endpoints for the filter graph. */outputs-name av_strdup(in);outputs-filter_ctx buffersrcCtx_;outputs-pad_idx 0;outputs-next NULL;AVFilterInOut* inputs avfilter_inout_alloc();inputs-name av_strdup(out);inputs-filter_ctx buffersinkCtx_;inputs-pad_idx 0;inputs-next NULL;if ((ret avfilter_graph_parse_ptr(filterGraph_, filter.c_str(), inputs, outputs, NULL)) 0)goto end;ret avfilter_graph_config(filterGraph_, NULL);if (ret 0)goto end;
end:avfilter_inout_free(inputs);avfilter_inout_free(outputs);return ret;
}向滤波输入帧, 然后从FilterGraph中取出一个AVFrame AVFrame* overlay(AVFrame* in) {if (!isInit_)return nullptr;int ret av_buffersrc_add_frame(buffersrcCtx_, in);if (ret 0)return nullptr;ret av_buffersink_get_frame(buffersinkCtx_, out_);if (ret 0){av_frame_unref(out_);return nullptr;}return out_;}生成对应 filter , 然后 向滤波中输入帧 // 大概流程思路
void xxxxx(){...// 生成对应filterstd::string filter 对应filter;init_filter_graph(filter);...while (true){ret av_read_frame(ifmtCtx, pkt);if (ret 0)goto end;// audioif (pkt-stream_index aistream) {av_packet_unref(pkt);continue;}// decode encode pktret avcodec_send_packet(deCodecCtx, pkt);if (ret 0)goto end;while (ret 0) {ret avcodec_receive_frame(deCodecCtx, frame);if (ret AVERROR(EAGAIN) || ret AVERROR_EOF) {break;}else if (ret 0) {goto end;}// solove [libx264 0x34b88a0] specified frame type (3) at 0 is not compatible with keyframe intervalframe-pict_type AV_PICTURE_TYPE_NONE;// overlay italic txt infoAVFrame* overlay_frame overlay(frame);if (overlay_frame nullptr)goto end;ret encode_frame_to_write_file(enCodecCtx, overlay_frame, pkt, ifmtCtx-streams[vistream]-time_base, ofmtCtx-streams[vostream]-time_base, ofmtCtx);if (ret 0) {av_frame_free(overlay_frame);goto end;}av_packet_unref(pkt);av_frame_unref(frame);av_frame_unref(overlay_frame);}#pragma endregionav_packet_unref(pkt);}...}Opencv 思路 先创建一张斜体水印的画布然后重复叠加到每一张图片上这样可以提高很大的效率。 代码 创建斜体水印int init_water_mark(const std::string txt, cv::Mat water) {// 原图宽高int imageW italicTextInfo_.frameWidth / italicTextInfo_.col;int imageH italicTextInfo_.frameHeight / italicTextInfo_.row;cv::Mat canvasMat cv::Mat::zeros(cv::Size(imageW, imageH), CV_8UC3);// 水印使用 Times New Roman 字体VTText::putTextHuskyC(canvasMat, txt.c_str(), cv::Scalar(255, 255, 255), kFontSize, Times New Roman, false, false);// 实际显示的水印行列数int w_count italicTextInfo_.col * 2 - 1;int h_count italicTextInfo_.row * 2;// 垂直拼接水印std::vectorcv::Mat vImgs;cv::Mat vResult;for (int vi 0; vi h_count; vi)vImgs.push_back(canvasMat);vconcat(vImgs, vResult);// 水平拼接水印std::vectorcv::Mat hImgs;cv::Mat hResult;for (int hi 0; hi w_count; hi)hImgs.push_back(vResult);hconcat(hImgs, hResult);cv::Point2f center(hResult.cols / 2.0, hResult.rows / 2.0);// 通过仿射变换将水印旋转45度,实现全屏斜体效果cv::Mat rotation_matix getRotationMatrix2D(center, italicTextInfo_.italicAngel, 1.0);cv::Mat rotated_image;warpAffine(hResult, rotated_image, rotation_matix, hResult.size());// 然后将水印图裁剪成原图大小用于后续叠加到原图上.water rotated_image(cv::Rect((hResult.cols - italicTextInfo_.frameWidth) / 2, (hResult.rows - italicTextInfo_.frameHeight) / 2, italicTextInfo_.frameWidth, italicTextInfo_.frameHeight));return 0;}// 将水印图叠加到原图上// frame: 解码帧 avframe AVFrame* overlayItalicTextInfoCVCanvas(AVFrame* frame) {//cv::Mat src_mat;//frame_to_mat(frame, src_mat);int pktSize;uint8_t* buffer_rgb convertRgb(frame, frame-width, frame-height, AV_PIX_FMT_YUV420P, frame-width, frame-height, AV_PIX_FMT_BGR24, pktSize);cv::Mat src_mat cv::Mat(frame-height, frame-width, CV_8UC3, buffer_rgb);cv::Mat roi;roi src_mat(cv::Rect(0, 0, watermark_.cols, watermark_.rows));cv::addWeighted(roi, 1.0, watermark_, italicTextInfo_.alpha, 0, roi);AVFrame* dst mat_to_frame(src_mat, src_mat.cols, src_mat.rows, AV_PIX_FMT_YUV420P);if (buffer_rgb ! nullptr)av_free(buffer_rgb);return dst;}大概流程 void xxxxx(){...// 先创建个带有斜体水印的matcv::Mat water;const std::string txt 12321321;init_water_mark(txt, water)...while (true){ret av_read_frame(ifmtCtx, pkt);if (ret 0)goto end;// audioif (pkt-stream_index aistream) {av_packet_unref(pkt);continue;}// decode encode pktret avcodec_send_packet(deCodecCtx, pkt);if (ret 0)goto end;while (ret 0) {ret avcodec_receive_frame(deCodecCtx, frame);if (ret AVERROR(EAGAIN) || ret AVERROR_EOF) {break;}else if (ret 0) {goto end;}// solove [libx264 0x34b88a0] specified frame type (3) at 0 is not compatible with keyframe intervalframe-pict_type AV_PICTURE_TYPE_NONE;// overlay italic txt infoAVFrame* overlay_frame overlayItalicTextInfo(frame);if (overlay_frame nullptr)goto end;ret encode_frame_to_write_file(enCodecCtx, overlay_frame, pkt, ifmtCtx-streams[vistream]-time_base, ofmtCtx-streams[vostream]-time_base, ofmtCtx);if (ret 0) {av_frame_free(overlay_frame);goto end;}av_packet_unref(pkt);av_frame_unref(frame);av_frame_unref(overlay_frame);}#pragma endregionav_packet_unref(pkt);}...}整理个demo基于opencv实现的。demo中 需依赖 opencv ffmpeg 自己搭建个环境即可运行。
demo: https://download.csdn.net/download/haiyangyunbao813/87499341 参考文章 ✨
https://blog.csdn.net/qq_23282479/article/details/119904850https://blog.csdn.net/qq_38722827/article/details/121549999 总结
经测试基于opencv方式相比较ffmpeg filter 效率至少能提升2倍。(1920 * 1080 i7 6代u) opencv : 平均一帧 20msffmpeg : 平均一帧 50ms 基于ffmpeg filter, 我感觉应该是可以提升效率的我的想法先创建出来水印然后重复叠加到每一张frame上就行但效率总是提升不了希望哪位大佬有时间能帮忙试试或者有什么别的好的方式抱拳了。以上就是我分享的全部内容了有不对的地方好欢迎留言指正。有需要的小伙伴可以参考参考。
最后来个三连今年就属你最牛逼了