Open hoxily opened 3 years ago
I ran into the same problem. In addition, the black screen file generated by this tool is larger than the normal file before.
Using the hexadecimal viewer, I found that the black screen video has some extra characters, and there are many google logos, which are not in the previous videos. I guess this piece of data will be added in front of every picture.
修改 whammy.js
,移除这行代码:
var webp = parseWebP(parseRIFF(atob(frame.image.slice(23))))
替换为
var str = atob(frame.image.slice(23))
// Process for WEBPVP8X encoding
if(str.includes('WEBPVP8X')){
// save 0-15
// The length to be removed in the middle is 562 B, which is to remove 16-577
// save 578-end
var p1 = str.substr(0,15)
var p2 = str.substr(577)
str = p1 + p2
}
var webp = parseWebP(parseRIFF(str))
问题解决。
如果你需要使用其下方的 fromImageArray
函数,那么在 fromImageArray
函数里也需要这样修改。
解决的原理:
Chrome 最近的更新修改了 webp 图片的编码方法,从 WEBPVP8
改为了 WEBPVP8X
。
WEBPVP8X
编码的图片多出了一些内容,我们需要移除这些内容,否则生成的 webm 视频是不能使用的。
以前的版本:WEBPVP8
新版本:WEBPVP8X
移除选中的部分,图片就变得和旧版本 Chrome 相同了。所以视频也恢复正常了。
非常感谢。 基于RIFF的Chunk规则,我写了一个更好的方法,忽略其他不需要的Chunk,仅提取出VP8 Bit Stream Chunk数据。相比 @xuejianxianzun 使用写死的常量 [0,15], [577, end] ,会更健壮一些。
/**
* 读取指定偏移量处的小端模式的32位无符号整数
* @param buffer - 数据缓冲区
* @param offset - 起始偏移量
* @returns 32位无符号整数
*/
function readUint32LittleEndian(buffer: string, offset: number): number {
let val = parseInt(
buffer
.substr(offset, 4)
.split("")
.map(function(i) {
var unpadded = i.charCodeAt(0).toString(2);
return new Array(8 - unpadded.length + 1).join("0") + unpadded;
})
.reverse() // 注意需要翻转字节序才是小端编码
.join(""),
2
);
return val;
}
/**
* 对于 VP8X,需要提取出其中的 VP8 或 VP8L bit stream chunk。
* 关于 VP8X 格式,参见 Extended file format: https://developers.google.com/speed/webp/docs/riff_container#extended_file_format
* @param buffer VP8X Chunk数据,不含 "VP8X" tag
*/
function extractBitStreamFromVp8x(buffer: string): ChunkSizeAndBinaryData {
//console.log("VP8X buffer:", buffer);
/*
跳过以下VP8X头:
32bit VP8X Chunk size
8bit Flags: Rsv I L E X A R
24bit Reserved
24bit Canvas Width Minus One
24bit Canvas Height Minus One
*/
let offset = 4 + 1 + 3 + 3 + 3;
// 搜索第一个"VP8 "或"VP8L" bit stream chunk
while (offset < buffer.length) {
let chunkTag = buffer.substr(offset, 4);
//console.log(`chunkTag: \"${chunkTag}\"`);
offset += 4;
let chunkSize = readUint32LittleEndian(buffer, offset);
//console.log("chunkSize:", chunkSize);
offset += 4;
switch (chunkTag) {
case "VP8 ":
case "VP8L":
const size = buffer.substr(offset - 4, 4);
const body = buffer.substr(offset, chunkSize);
return size + body;
default:
// 跳过不关心的数据块
offset += chunkSize;
break;
}
}
console.error("VP8X format error: missing VP8/VP8L chunk.");
}
function parseRIFF(string: string): RiffChunk {
//console.log("binary string:", string);
var offset = 0;
var chunks: RiffChunk = {};
while (offset < string.length) {
var id = string.substr(offset, 4);
chunks[id] = chunks[id] || [];
if (id == "RIFF" || id == "LIST") {
var len = readUint32LittleEndian(string, offset + 4)
var data = string.substr(offset + 4 + 4, len);
// console.log(data);
offset += 4 + 4 + len;
chunks[id].push(parseRIFF(data));
} else if (id == "WEBP") {
let vpVersion = string.substr(offset + 4, 4);
switch (vpVersion) {
case "VP8X":
chunks[id].push(extractBitStreamFromVp8x(string.substr(offset + 8)));
break;
case "VP8 ":
case "VP8L":
// Use (offset + 8) to skip past "VP8 " / "VP8L" field after "WEBP"
chunks[id].push(string.substr(offset + 8));
break;
default:
console.error(`not supported webp version: \"${vpVersion}\"`);
break;
}
offset = string.length;
} else {
// Unknown chunk type; push entire payload
chunks[id].push(string.substr(offset + 4));
offset = string.length;
}
}
return chunks;
}
type ChunkSizeAndBinaryData = string;
interface RiffChunk {
[tag: string]: (ChunkSizeAndBinaryData | RiffChunk)[];
}
厉害了
Update on the https://github.com/Akimyou/ts-whammy/issues/29 Please try the ts-whammy.
A modern typescript version of whammy. You can use it to encode images(webp) to webm video.
ts-whammy only include the core function of whammy then with modern frontend technology stack.
Backgrounds
We used whammy for about 1 year, and it works well. Recently, some customers report that the generated video is black screen.
Google Chrome Versions
I have checked an older version of Google Chrome 90.0.4430.212 (64-bit),it works well. But whammy gives black screen when on latest Google Chrome 92.0.4515.107 (64-bit)。
Guessing Cause
The lastest Google Chrome updated webp image format, and whammy parse latest webp incorrectly, then it get a black screen webm video file.
Can anyone help on webp and webm format? webm-ok.zip webm-blackscreen.zip