Android NDK开发之如何实现FFmpeg视频添加水印
发表于:2024-10-22 作者:千家信息网编辑
千家信息网最后更新 2024年10月22日,这篇文章主要介绍Android NDK开发之如何实现FFmpeg视频添加水印,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!前言Android也是利用FFmpeg命令行的形式(混
千家信息网最后更新 2024年10月22日Android NDK开发之如何实现FFmpeg视频添加水印
这篇文章主要介绍Android NDK开发之如何实现FFmpeg视频添加水印,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
前言
Android也是利用FFmpeg命令行的形式(混编),进行视频转码压缩。
1.FFmpeg添加水印命令
1.1.水印命令
ffmpeg -iWildlife.wmv-vf "movie=panda.png[watermark];[in][watermark] overlay=10:10[out]"Marked.wmv
原始视频文件路径:Wildlife.wmv
水印图片路径:panda.png
水印位置:(x,y)=(10,10)<=(left,top)距离左侧、顶部各10像素;
输出文件路径:Marked.wmv
注意事项
问题:FFmpeg 3.0之前-vf "movie=绝对路径存在问题
从3.0开始就支持了
解决的方案:过滤器
ffmpeg -i /Users/yangshaohong/Desktop/Test.mov -i /Desktop/watermark.png -filter_complex overlay=480:10 /Desktop/Test_out.mp4
1.2.命令补充说明
水印位置参数的第一个数值是水印图片的左上角的x轴像素值,第二个数值是水印图片的左上角的y轴像素值。
水印位置参数除了使用数值外,还可以使用以下几个参数:
对应地可以将overlay参数设置成如下值来改变水印图片的位置:
2.Android 核心代码
2.1.jni Java声明
//添加水印 public native void addWatermark(int argc,String[] argv);
2.2.核心代码ffmpeg.c
#include "jni.h"#include "ffmpeg.h"//视频转码压缩主函数入口//SDL(main)//ffmpeg_mod.c有一个FFmpeg视频转码主函数入口//标记(声明有一个这样的函数提供给我调用)//参数含义分析//首先分析:String str = "ffmpeg -i input.mov -b:v 640k output.mp4"// argc = str.split(" ").length()// argv = str.split(" ") 字符串数组//参数一:命令行字符串命令个数//参数二:命令行字符串数组int ffmpegmain(int argc, char **argv);JNIEXPORT void JNICALL Java_com_haocai_ffmpegtest_util_VideoPlayer_transcodingCompress (JNIEnv *env, jobject jobj,jint jlen,jobjectArray jobjArray){ //转码 //将java的字符串数组转成C字符串 int argc = jlen; //开辟内存空间 char **argv = (char**)malloc(sizeof(char*) * argc); //填充内容 for (int i = 0; i < argc; ++i) { jstring str = (*env)->GetObjectArrayElement(env,jobjArray,i); const char* tem = (*env)->GetStringUTFChars(env,str,0); argv[i] = (char*)malloc(sizeof(char)*1024); strcpy(argv[i],tem); } //开始转码(底层实现就是只需命令) ffmpegmain(argc,argv); //释放内存空间 for (int i = 0; i < argc; ++i) { free(argv[i]); } //释放数组 free(argv);}
调用ffmpeg_mod.c中ffmpegmain函数入口
//ffmpeg主函数入口int ffmpegmain(int argc, char **argv){ int ret; int64_t ti; //av_log_set_callback(av_log_callback); register_exit(ffmpeg_cleanup); setvbuf(stderr,NULL,_IONBF,0); /* win32 runtime needs this */ av_log_set_flags(AV_LOG_SKIP_REPEATED); parse_loglevel(argc, argv, options); if(argc>1 && !strcmp(argv[1], "-d")){ run_as_daemon=1; av_log_set_callback(log_callback_null); argc--; argv++; } avcodec_register_all();#if CONFIG_AVDEVICE avdevice_register_all();#endif avfilter_register_all(); av_register_all(); avformat_network_init(); show_banner(argc, argv, options); term_init(); /* parse options and open all input/output files */ ret = ffmpeg_parse_options(argc, argv); if (ret < 0) { ffmpeg_cleanup(1); return 1;} if (nb_output_files <= 0 && nb_input_files == 0) { show_usage(); av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run 'man %s'\n", program_name); ffmpeg_cleanup(1); return 1; } /* file converter / grab */ if (nb_output_files <= 0) { av_log(NULL, AV_LOG_FATAL, "At least one output file must be specified\n"); ffmpeg_cleanup(1); return 1; }// if (nb_input_files == 0) {// av_log(NULL, AV_LOG_FATAL, "At least one input file must be specified\n");// exit_program(1);// } current_time = ti = getutime(); if (transcode() < 0) { ffmpeg_cleanup(1); return 1;} ti = getutime() - ti; av_log(NULL, AV_LOG_FATAL, "Transcode has Finished\n"); // if (do_benchmark) { // printf("bench: utime=%0.3fs\n", ti / 1000000.0); // } // av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" frames successfully decoded, %"PRIu64" decoding errors\n", // decode_error_stat[0], decode_error_stat[1]); //if ((decode_error_stat[0] + decode_error_stat[1]) * max_error_rate < decode_error_stat[1]) // { exit_program(69); return 69;} ///exit_program(received_nb_signals ? 255 : main_return_code); ffmpeg_cleanup(0); return main_return_code;}
2.3调用程序
public void addWatermark(){ File ipFile = new File(Environment.getExternalStorageDirectory(),"告白气球.avi"); File opFile = new File(Environment.getExternalStorageDirectory(),"告白气球_out.mp4"); File wmFile = new File(Environment.getExternalStorageDirectory(),"watermark.png"); String str = "ffmpeg -i "+ipFile.getAbsolutePath()+" -i "+wmFile.getAbsolutePath()+" -filter_complex overlay=480:10 "+opFile.getAbsolutePath(); final String[] argv = str.split(" "); final int argc = argv.length; new Thread(){ public void run() { player.ffmpegCmdUtil(argc,argv); Log.i("main","------加水印完成-------"); } }.start(); }
3.运行结果
3.1原视频播放
3.2添加水印
注意:
视频质量 下降是因为没有设置-b bitrate 比特率,缺省200kb/s
所以质量会下降,在参数中添加设置 如:-b 1024k 会提高视频质量
以上是"Android NDK开发之如何实现FFmpeg视频添加水印"这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注行业资讯频道!
水印
视频
参数
命令
函数
字符
字符串
位置
入口
图片
数组
路径
像素
内容
数值
质量
开发
代码
内存
告白
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
水校高职扩招计算机网络技术
网络技术中的分组
仿真推演软件开发
辰风互联网科技
ptc数据库
2020网络安全宣传周视频
网络技术DHCP报文中大写
武山网络安全培训会
灵寿品牌软件开发专业服务
服务器校验授权码在哪里
网络技术专业方向是什么
混凝土公司软件开发
方舟进化怎么建专用服务器
数据库技术与应用的论文
服务器管理器里面角色没有了
公安部网络安全保卫局口号
幼儿园网络安全班会图片
mc服务器软件
三校生计算机网络技术高考
闪电十一人王牙 数据库
并行处理软件开发环境
360解压软件开发
数据库变量的类型
思科最新网络技术测试题答案
毕业论文上传数据库后还能投稿么
协议自动投注软件开发
天宫服务器代理商
网络安全要学一些什么
数据库主主复制
网络安全技术四大类