您当前的位置: 首页 > 慢生活 > 程序人生 网站首页程序人生
(安卓)ffmpeg添加文字水印中文乱码的解决(非终极方案)
发布时间:2021-07-21 22:58:02编辑:雪饮阅读()
对于视频的处理,那个一般都是用ffmpeg,像是大名鼎鼎的格式工厂,他还是用的ffmpeg为核心。
那么如果在windows上面使用ffmpeg是非常的easy的,也是非常的稳定的。
那么移植到安卓中,就没有那么好用了,你比如像是基于jni的ndk就可以用于移植ffmpeg到安卓中,但是实际使用上,你会发现,有诸多问题。
那么今天这里主要是针对文字水印添加于视频时在安卓中ffmpeg使用的问题。
那么具体的问题呢,就是中文乱码,在这个ffmpeg它的那个添加文字水印的时候字体文件是必须要指定的,那么这个字体文件,一般指定绝对路径如:
那么假如你指定一个路径
-i "/storage/emulated/0/qqmusic/mv/银临 - 流光记_k0029xmzbzk_4_0 [mqms].mp4" -vf "drawtext=fontfile='/storage/emulated/0/penguinVideoEdit/fonts/msyh': text='咯哦哦':x=1:y=2:fontsize=24:fontcolor=white" –y
当然了,这里我指定的一个字体路径是在sdcard中的,这个字体是从windows上面拷贝过来的微软雅黑字体,该字体亦可用于安卓中对中文的兼容。
但是除了自定义这些字体以外,那么安卓自带的这些系统的字体,像是上图中/system/fonts中的这些字体路径也可以用的。
但是这些字体啊一般都是不兼容中文的,另外就是说好像并不是在windows中比如你看到一个英文的字体名称,在windows中它可以使用,并且对于中文也兼容,比如常见的狸窝视频编辑器就是这样的,但是当你找到该狸窝视频编辑器所用到的这个英文名称的字体拷贝到安卓中,你会发现,人家用这个字体不会中文乱码,但是在你安卓中就会出现中文乱码,所以具体还是要亲自实践一下啊。
那么这里分享下,笔者找到的这30款字体是人家网上的资源,据说是完全可以在安卓中对中文的兼容
这里笔者目前也在探索使用着。
为什么说这种方案不是最终方案,其实我想要的最终方案是能够调用系统的像是直接安卓sdk的api那样优雅的实现字体选择,并且能够返回字体的绝对路径,并且这些路径是常规路径并非是安卓资产文件那样的路径,因为对于资产文件,你要传递给像是jni实现的c语言接口,人家是接收标准的磁盘文件路径,而不是安卓特有的这种路径。
那么,其实有想过用图片来代替的,就是可以用安卓canvas绘制透明背景的图片,上面写上文字,然后以图片水印的方式添加到视频中,这样其实也可以实现目标任务。
但这样其实有点曲折,关键还是遇到了ffmpeg缩放对于图片后无法保存图片的原有alpha通道,导致缩放之后图片会出现黑色背景,那么明显是不可以的。或者笔者目前为止没有找到缩放并保留alpha通道的方法(必须是命令行的形式,因为虽然我们可以直接去修改c文件,但是对于像是ffmpeg这种鼎鼎大名的软件来说,建议不要轻易修改源文件,咱们能在java端实现,就尽量在java端实现)。
所以,最后就选择了通过网上找到的这一大堆兼容安卓中文字符的字体,目前看到是有30款。
其实这种方案对比于上面用图片来实现(如果能实现的话),其实图片那种方案更成熟,毕竟安卓sdk就有相关api,对于textView的优雅实现(我觉得,毕竟textView还有安卓api里面有图形库里面有font,这样是很切近的,毕竟都是安卓,而我们ffmpeg的实现是c,而不是安卓的java,就有点远了。)因为你最后一般肯定都是像textView中显示或者回显。
而目前这种通过网上找到的兼容安卓中文的字体库毕竟是第三方的,那么就我目录了解到,是不能完全优雅的像系统字体那样直接一个路径就加载了。
目前我的实现方式是,先将这些第三方字体放到安卓的资产目录中,然后我们通过获取资产目录的输入流,写入到sdcard目录中,那么我们就可以通过像是内容提供者,或者安卓早先那样直接普暴漏文件路径的方式。
那么从资产文件到sdcard的具体实现可以参考代码片段如:
/**
* 复制res/raw中的文件到指定目录
* @param context 上下文
* @param id 资源ID
* @param fileName 文件名
* @param storagePath 目标文件夹的路径
*/
public static void copyFilesFromRaw(Context context, int id, String fileName,String storagePath){
InputStream inputStream=context.getResources().openRawResource(id);
File file = new File(storagePath);
if (!file.exists()) {//如果文件夹不存在,则创建新的文件夹
file.mkdirs();
}
readInputStream(storagePath + File.separator + fileName, inputStream);
}
public static void readInputStream(String storagePath, InputStream inputStream) {
File file = new File(storagePath);
try {
if (!file.exists()) {
// 1.建立通道对象
FileOutputStream fos = new FileOutputStream(file);
// 2.定义存储空间
byte[] buffer = new byte[inputStream.available()];
// 3.开始读文件
int lenght = 0;
while ((lenght = inputStream.read(buffer)) != -1) {// 循环从输入流读取buffer字节
// 将Buffer中的数据写到outputStream对象中
fos.write(buffer, 0, lenght);
}
fos.flush();// 刷新缓冲区
// 4.关闭流
fos.close();
inputStream.close();
}
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
* 复制res/raw中的文件到指定目录
* @param context 上下文
* @param id 资源ID
* @param fileName 文件名
* @param storagePath 目标文件夹的路径
*/
public static void copyFilesFromRaw(Context context, int id, String fileName,String storagePath){
InputStream inputStream=context.getResources().openRawResource(id);
File file = new File(storagePath);
if (!file.exists()) {//如果文件夹不存在,则创建新的文件夹
file.mkdirs();
}
readInputStream(storagePath + File.separator + fileName, inputStream);
}
public static void readInputStream(String storagePath, InputStream inputStream) {
File file = new File(storagePath);
try {
if (!file.exists()) {
// 1.建立通道对象
FileOutputStream fos = new FileOutputStream(file);
// 2.定义存储空间
byte[] buffer = new byte[inputStream.available()];
// 3.开始读文件
int lenght = 0;
while ((lenght = inputStream.read(buffer)) != -1) {// 循环从输入流读取buffer字节
// 将Buffer中的数据写到outputStream对象中
fos.write(buffer, 0, lenght);
}
fos.flush();// 刷新缓冲区
// 4.关闭流
fos.close();
inputStream.close();
}
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
那么对于从资产文件中复制这些文件到sdcard中,对于调用者,则如:
关键字词:ffmpeg,安卓,文字水印,中文乱码