从Grails Controller中流式传输MP4,无法在iPhone上工作



我正在尝试从Grails Controller中将MP4文件传输到iOS设备(iPhone和iPad):

def streamContent() {
    def contentPath = "/path/to/file"
    File f = new File(contentPath)
    if(f.exists()) {
        response.setContentType("video/mp4")
        response.outputStream << f.newInputStream()
        response.outputStream.flush()
        response.outputStream.close()
    } else {
        render status: 404
    }
}

此代码在Safari(我看到的视频)等桌面浏览器上运行良好,但是当我使用iPhone或iPad访问同一页面时,视频将无法播放。请注意,如果我将相同的视频放在Apache HTTPD上,并且我从iOS设备请求它,那就没有问题了。因此,它必须是流媒体问题。

在HTML页面上使用HTML5视频标签嵌入视频:

<video width="360" height="200" controls>
    <source src="http://localhost:8080/myapp/controller/streamContent" type='video/mp4'>
</video>

我通过处理部分内容和范围请求(HTTP 206状态)解决了此问题。移动浏览器/媒体播放器似乎正在使用部分请求,一次避免了一次数据传输。因此,而不是做一个简单的

response.outputStream << f.newInputStream()

我仅读取请求的字节,当时是一系列字节的请求:

if (isRange) {
    //start and end are requested bytes offsets
    def bytes = new byte[end-start]
    f.newInputStream().read(bytes, start, bytes.length)
    response.outputStream << bytes
    response.status = 206
} else {
    response.outputStream << f.newInputStream()
    response.status = 200
}

我还没有足够的声誉来发表评论,但是我只想指出上面的答案不完整,具体是您需要包括其他标题,并且使用情况 f.newInputStream().read()的使用尚未准确使用,因为它不仅在输入流的任何起点上读取了一个块,而且还将读取当前位置的块,因此您必须使用"保存输入流",然后使用inputStream.skip()来跳转到正确的位置。

我在这里有一个更完整的答案(我回答了自己的类似问题)https://stackoverflow.com/a/23137725/2601060

最新更新