motion photo的压缩
# motion photo/ live photo的压缩
# 判断是否为动态图
# 文件格式标准:
https://developer.android.com/media/platform/motion-photo-format?hl=zh-cn
# by xmp
按谷歌的标准,判断xmp里是否有关键标签,有了之后,提取其中关键的字段:视频文件的大小
String androidXmp = "xmlns:GCamera=";
String iosXmp = "iosxxx";
if (!xmp.contains(androidXmp) && !xmp.contains(iosXmp)) {
return false;
}
if (xmp.contains(androidXmp)) {
LogUtils.d("读取xmp",xmp);
String regex0 = "GCamera:MicroVideoOffset=\"(\\d+)\"";
// 创建 Pattern 对象
Pattern pattern0 = Pattern.compile(regex0);
// 创建 matcher 对象
Matcher matcher0 = pattern0.matcher(xmp);
// 查找并提取数字
if (matcher0.find()) {
String number = matcher0.group(1);
int length = Integer.parseInt(number);
System.out.println("提取到的数字是: " + number);
if (wholeFileLength <= length) {
System.out.println("文件大小小于视频文件大小, xmp显示是动态图,但实际不是 " + fileOrUriPath);
return false;
}
//提取视频文件
if (extractVideo) {
extractMp4FromMotionPhoto(fileOrUriPath, motion.mp4CacheFile(fileOrUriPath), wholeFileLength - length, length);
}
return true;
} else {
String regex = "<Container:Item\\s+Item:Mime=\"video/mp4\"\\s+Item:Semantic=\"MotionPhoto\"\\s+Item:Length=\"(\\d+)\"\\s+Item:Padding=\"(\\d+)\"\\s*/>";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(xmp);
if (matcher.find()) {
String length = matcher.group(1);
String padding = matcher.group(2);
System.out.println("length: " + length + ", padding:" + padding);
int len = Integer.parseInt(length);
int pad = Integer.parseInt(padding);
if (wholeFileLength <= len + pad) {
System.out.println("文件大小小于视频文件大小2, xmp显示是动态图,但实际不是 " + fileOrUriPath);
return false;
}
//提取视频文件
if (extractVideo) {
extractMp4FromMotionPhoto(fileOrUriPath, motion.mp4CacheFile(fileOrUriPath), wholeFileLength - (len + pad), len);
}
return true;
} else {
LogUtils.w("没有找到xmp里匹配的模式。");
}
}
}else {
LogUtils.w("没有找到xmp里匹配的模式2");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# by byte:
最准确,且不受于不同版本的协议差异影响
但是需要逐个比对字节,io耗时较多
文件结尾:
mp4文件头格式:
# 压缩前后:
分别对图片和视频都做了压缩,rotation/orientation不为0的,还对原图和原视频做了旋转处理并将rotation//orientation置为0
xmp为空的,将视频文件大小写入到motion photo模板中:
public static final String xmpTmplate = "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"Adobe XMP Core 5.1.0-jc003\">" +
" <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">" +
"<rdf:Description rdf:about=\"\"" +
"xmlns:GCamera=\"http://ns.google.com/photos/1.0/camera/\"" +
"xmlns:MiCamera=\"http://ns.xiaomi.com/photos/1.0/camera/\"" +
"GCamera:MicroVideoVersion=\"1\"" +
"GCamera:MicroVideo=\"1\"" +
"GCamera:MicroVideoOffset=\"xxxxxx\"" +
"GCamera:MicroVideoPresentationTimestampUs=\"900999\"" +
"MiCamera:XMPMeta=\"<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>\"/>" +
" </rdf:RDF>" +
"</x:xmpmeta>";
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
原图:
压缩后:
# 兼容性
荣耀手机没有按谷歌的motion photo协议来,是自己瞎搞的.压缩后,系统相册无法识别图片为动态图. 小米相册没有这个问题.
将荣耀手机拍的动态图,无xmp,只能通过字节比对来判断
移除图片中的视频,荣耀相册依然识别为动态图,可见荣耀相册是在数据库增加一个字段的方式记录一张图片是否为动态图,而非根据xmp或字节规律来判断.他们的这种方式是比较初级的,鲁棒性不够,没有任何兼容性.
# 代码
编辑 (opens new window)