Java 在ExoPlayer2上找不到同步字节m3u8
我有一个AES 128位加密的m3u8播放列表。我试着在电视上主持这个节目Java 在ExoPlayer2上找不到同步字节m3u8,java,android,flutter,http-live-streaming,m3u8,Java,Android,Flutter,Http Live Streaming,M3u8,我有一个AES 128位加密的m3u8播放列表。我试着在电视上主持这个节目 通过Cloudflare的Google云存储桶 本地Xampp服务器 播放列表在HTML5网络播放器上工作。然后我尝试在Android应用程序中播放m3u8文件。我试过了,一个flatter应用程序,一个React Native应用程序和一个Native Java应用程序 我已经尝试了几乎所有适用于Flutter和React Native的HLS库。但在最后,每个玩家都显示了关于谷歌ExoPlayer的相同错误。我正在努
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:12
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="http://192.168.1.2/key/video.key",IV=0x00000000000000000000000000000000
#EXTINF:10.666667,
playlist0.ts
#EXTINF:11.666667,
playlist1.ts
#EXT-X-ENDLIST
我发现问题出在TS
文件上,因为错误消息在TsExtractor.java
文件中显示了错误。在这里,我还尝试使用curl查看其中一个TS文件的HTTP响应头
C:\Users\mdils>curl -D - http://localhost/key/playlist0.ts
HTTP/1.1 200 OK
Date: Fri, 23 Apr 2021 16:01:24 GMT
Server: Apache/2.4.46 (Win64) OpenSSL/1.1.1g PHP/7.4.11
Last-Modified: Sun, 28 Feb 2021 15:29:09 GMT
ETag: "239f80-5bc6729a3ba75"
Accept-Ranges: bytes
Content-Length: 2334592
Access-Control-Allow-Origin: *
任何关于这方面的帮助都非常感谢
更新
播放列表示例-
用于编码的FFMPEG命令
ffmpeg -i input.mp4 -c copy -bsf:v h264_mp4toannexb -hls_list_size 0 -hls_time 10 -hls_key_info_file key_info.txt playback.m3u8
更新-2021-04-25 这是一个工作的m3u8文件(从ExoPlayer演示应用程序复制) 将此m3u8文件与上述文件进行比较,唯一的区别是出现错误的文件具有aes-128位加密播放列表 然后,当我检查源代码时,我在ExoPlayer源代码上找到了这个方法
/**
* Returns the position of the end of the first TS packet (exclusive) in the packet buffer.
*
* <p>This may be a position beyond the buffer limit if the packet has not been read fully into
* the buffer, or if no packet could be found within the buffer.
*/
private int findEndOfFirstTsPacketInBuffer() throws ParserException {
int searchStart = tsPacketBuffer.getPosition();
int limit = tsPacketBuffer.limit();
int syncBytePosition =
TsUtil.findSyncBytePosition(tsPacketBuffer.getData(), searchStart, limit);
// Discard all bytes before the sync byte.
// If sync byte is not found, this means discard the whole buffer.
tsPacketBuffer.setPosition(syncBytePosition);
int endOfPacket = syncBytePosition + TS_PACKET_SIZE;
if (endOfPacket > limit) {
bytesSinceLastSync += syncBytePosition - searchStart;
if (mode == MODE_HLS && bytesSinceLastSync > TS_PACKET_SIZE * 2) {
throw new ParserException("Cannot find sync byte. Most likely not a Transport Stream.");
}
} else {
// We have found a packet within the buffer.
bytesSinceLastSync = 0;
}
return endOfPacket;
}
/**
*返回第一个TS数据包(独占)在数据包缓冲区中的结束位置。
*
*如果数据包未完全读入,则该位置可能超出缓冲区限制
*缓冲区,或者如果在缓冲区内找不到数据包。
*/
private int findEndOfFirstTsPacketInBuffer()引发ParserException{
int searchStart=tsPacketBuffer.getPosition();
int limit=tsPacketBuffer.limit();
int syncBytePosition=
TsUtil.findSyncBytePosition(tsPacketBuffer.getData(),searchStart,limit);
//放弃同步字节之前的所有字节。
//如果找不到同步字节,这意味着丢弃整个缓冲区。
tsPacketBuffer.setPosition(syncBytePosition);
int endOfPacket=syncBytePosition+TS\u数据包大小;
如果(endOfPacket>limit){
ByTessinclastSync+=syncBytePosition-searchStart;
if(mode==mode_HLS&&bytessinclastsync>TS_数据包大小*2){
抛出新的ParserException(“找不到同步字节。很可能不是传输流”);
}
}否则{
//我们在缓冲区内发现了一个数据包。
ByTessinclastSync=0;
}
返回endOfPacket;
}
根据上述函数的注释,当无法找到同步字节时,会抛出上述错误消息。因此,我唯一可以假设的是,可能播放器未能用提供的密钥解密第一个TS文件?(密钥是正确的,因为它在HLS web播放器上工作)您的密钥文件无效,在解密TS段时会收到垃圾。
hls\u key\u info\u文件的FFmpeg文档说明:
密钥文件以二进制格式读取为16个八位字节的单个压缩数组
您的密钥文件有32个字节。如果您获取当前密钥文件的前16个字节并以二进制形式输出,它将正确解密。例如:
xxd-p-l 16 video.key | xxd-r-p-video\u bin.key
在播放列表中使用video\u bin.key
。当然,最好首先生成一个有效的密钥。听起来段(.ts
文件)的内容有问题。你能在stackoverflow上分享吗?@jmsn谢谢你的评论。我已经更新了问题,非常感谢你的回答。我不明白为什么它与hls.js一起工作。因为我没有找到解决方案,所以我添加了一个带有hls.js的WebView作为临时解决方案。使用32字节长的密钥(不是问题中的同一个,而是一个类似的密钥),它可以完美地工作。@Dilshan它可能会像我一样截断密钥。如果玩家验证了钥匙,你就有麻烦了。例如,您的播放列表在使用SafariOh的macOS上无法正常工作。再次感谢你。您保存了整个项目:)我刚刚用16字节的键进行了测试。它工作得很好。
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:9.97667,
fileSequence0.ts
#EXTINF:9.97667,
fileSequence1.ts
#EXTINF:9.97667,
...
/**
* Returns the position of the end of the first TS packet (exclusive) in the packet buffer.
*
* <p>This may be a position beyond the buffer limit if the packet has not been read fully into
* the buffer, or if no packet could be found within the buffer.
*/
private int findEndOfFirstTsPacketInBuffer() throws ParserException {
int searchStart = tsPacketBuffer.getPosition();
int limit = tsPacketBuffer.limit();
int syncBytePosition =
TsUtil.findSyncBytePosition(tsPacketBuffer.getData(), searchStart, limit);
// Discard all bytes before the sync byte.
// If sync byte is not found, this means discard the whole buffer.
tsPacketBuffer.setPosition(syncBytePosition);
int endOfPacket = syncBytePosition + TS_PACKET_SIZE;
if (endOfPacket > limit) {
bytesSinceLastSync += syncBytePosition - searchStart;
if (mode == MODE_HLS && bytesSinceLastSync > TS_PACKET_SIZE * 2) {
throw new ParserException("Cannot find sync byte. Most likely not a Transport Stream.");
}
} else {
// We have found a packet within the buffer.
bytesSinceLastSync = 0;
}
return endOfPacket;
}