我正在创建一个Java应用程序,它通过http将视频文件“流式传输”到浏览器(目前是Chrome v24.x)。此视频发送到FFmpeg,其输出通过HTTP发送。
现在,一旦文件被完全编码,就会使用分块传输来提供文件,并响应范围请求。示例标题:
GET /file/9fe6b502-c127-47c2-b6d2-83ea58676a8d HTTP/1.1 : Host: localhost:1234 : Connection: keep-alive : Accept-Encoding: identity;q=1, *;q=0 : User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17 : Accept: */* : Referer: http://localhost:1234/media/9fe6b502-c127-47c2-b6d2-83ea58676a8d : Accept-Language: en-US,en;q=0.8 : Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 : Cookie: plushContainerWidth=100%25; plushNoTopMenu=0 : Range: bytes=0- :
HTTP/1.1 206 Partial Content : Connection: close : Date: Mon, 28 Jan 2013 14:51:52 GMT : Content-Type: video/mp4 : Etag: "9fe6b502-c127-47c2-b6d2-83ea58676a8d" : Accept-Ranges: bytes : Content-Range: bytes 0-625825/625826 : Content-Length: 625826 : Transfer-Encoding: chunked :
发送的数据为625826字节,不包括头数据和分块开销。
现在,这很好用!
问题是在文件编码完成之前发生GET请求。我试图通过HTTP直接发送文件,只使用没有内容长度属性或范围的分块传输,因为它们目前还不知道。这会导致浏览器等待完整文件(并且在传输完成之前不会开始播放)。此外,文件传输完成后,浏览器会报告无法播放文件的视频错误。示例标题:
Request : GET /file/9fe6b502-c127-47c2-b6d2-83ea58676a8d HTTP/1.1 : Host: localhost:1234 : Connection: keep-alive : Accept-Encoding: identity;q=1, *;q=0 : User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17 : Accept: */* : Referer: http://localhost:1234/media/9fe6b502-c127-47c2-b6d2-83ea58676a8d : Accept-Language: en-US,en;q=0.8 : Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 : Cookie: plushContainerWidth=100%25; plushNoTopMenu=0 : Range: bytes=0-
HTTP/1.1 200 OK : Connection: close : Date: Mon, 28 Jan 2013 14:51:29 GMT : Content-Type: video/mp4 : Transfer-Encoding: chunked
发送的数据为625826字节,不包括头数据和分块开销。
有没有人知道出了什么问题,或者如何在不知道文件全长的情况下开始播放视频?
感谢您的时间,
詹姆斯。
// EDIT
由于对不完整文件的请求状态'Range:bytes = 0-' - 我可以使用Content-Range:bytes 0-999 / *回复部分'n'字节(例如,1000字节)的内容吗?
//编辑2 根据要求,这是我输出文件的代码。由于代码实际上跨越了几个类,所以这是精简的。
File f = new File(_filename);
RandomAccessFile raf = new RandomAccessFile(f, "r");
ChunkedOutputStream cos = new ChunkedOutputStream(_out, 1024 * 100);
byte[] bytes;
while (true){
lBufferSizeMax = Math.min(lBufferSize, fc.length() - lCompleted);
bytes = new byte[(int)lBufferSizeMax];
lCurrentRead = fc.read(bytes);
if (lCurrentRead == 0){
break;
}
cos.write(bytes);
}
答案 0 :(得分:2)
请注意,ffmpeg
可能会在编码结束时重写部分文件。这意味着视频文件中的元数据在最后才会完整,因此在此之前尝试流式传输文件的开头是没有用的。您可以使用单个破折号替换ffmpeg
命令行中的输出文件名,并将stdout重定向到文件。而不是ffmpeg ... out.mov
做ffmpeg ... - > out.mov
。如果您收到错误消息,说明格式需要可搜索输出,则会受到影响。
我几乎完全按照你要做的去做,结果在我Git repo。我使用的容器格式是FLV,我可以用元数据玩游戏。不幸的是,这不是iPad / iPhone设备所希望看到的。