因此,在我的web服务器上,我想使用FFMPEG对媒体文件进行代码转换,以便与HTML <audio>
或<video>
标签一起使用。很简单,对吧?
转换需要在HTTP客户端请求转换后的文件时实时进行。理想情况下,文件应该在代码转换时流回HTTP客户端(而不是在代码转换结束后,因为这可能需要一段时间才能开始发送回任何数据)。
这很好,除了在今天的浏览器中,HTML5音频或视频标签使用Range
头在多个HTTP请求中请求媒体文件。See this question for details。
在上面链接的问题中,您可以看到Safari请求奇怪的文件块,包括结尾的几个字节。这带来了一个问题,即web服务器将不得不等待转换完成,以便传递文件的最后字节以符合Range
请求。
所以我的问题是,我的思路是正确的吗?有没有一种更好的方法来将代码转换内容传递到<audio>
或<video>
标签,而不需要等待整个转换完成?提前感谢!
发布于 2014-05-08 13:26:41
我最近遇到了同样的问题,因为我想为浏览器提供我的库。令人惊讶的是,通过ffmpeg发送流并即时交付的想法运行得很好。主要的问题是支持寻求……
下面,你可以使用Flask在Python中找到代码片段来解决这个问题:
我们需要一个函数来流式传输内容:
@app.route('/media/<path:path>.ogv')
def media_content_ogv(path):
d= os.path.abspath( os.path.join( config.media_folder, path ) )
if not os.path.isfile( d ): abort(404)
start= request.args.get("start") or 0
def generate():
cmdline= list()
cmdline.append( config.ffmpeg )
cmdline.append( "-i" )
cmdline.append( d );
cmdline.append( "-ss" )
cmdline.append( str(start) );
cmdline.extend( config.ffmpeg_args )
print cmdline
FNULL = open(os.devnull, 'w')
proc= subprocess.Popen( cmdline, stdout=subprocess.PIPE, stderr=FNULL )
try:
f= proc.stdout
byte = f.read(512)
while byte:
yield byte
byte = f.read(512)
finally:
proc.kill()
return Response(response=generate(),status=200,mimetype='video/ogg',headers={'Access-Control-Allow-Origin': '*', "Content-Type":"video/ogg","Content-Disposition":"inline","Content-Transfer-Enconding":"binary"})
然后我们需要一个函数来返回持续时间:
@app.route('/media/<path:path>.js')
def media_content_js(path):
d= os.path.abspath( os.path.join( config.media_folder, path ) )
if not os.path.isfile( d ): abort(404)
cmdline= list()
cmdline.append( config.ffmpeg )
cmdline.append( "-i" )
cmdline.append( d );
duration= -1
FNULL = open(os.devnull, 'w')
proc= subprocess.Popen( cmdline, stderr=subprocess.PIPE, stdout=FNULL )
try:
for line in iter(proc.stderr.readline,''):
line= line.rstrip()
#Duration: 00:00:45.13, start: 0.000000, bitrate: 302 kb/s
m = re.search('Duration: (..):(..):(..)\...', line)
if m is not None: duration= int(m.group(1)) * 3600 + int(m.group(2)) * 60 + int(m.group(3)) + 1
finally:
proc.kill()
return jsonify(duration=duration)
最后,我们使用videojs将其嵌入HTML5:
<!DOCTYPE html>
<html>
<head>
<link href="//vjs.zencdn.net/4.5/video-js.css" rel="stylesheet">
<script src="//vjs.zencdn.net/4.5/video.js"></script>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
</head>
<body>
<video id="video" class="video-js vjs-default-skin" controls preload="auto" width="640" height="264">
</video>
<script>
var video= videojs('video');
video.src("media/testavi.avi.ogv");
// hack duration
video.duration= function() { return video.theDuration; };
video.start= 0;
video.oldCurrentTime= video.currentTime;
video.currentTime= function(time)
{
if( time == undefined )
{
return video.oldCurrentTime() + video.start;
}
console.log(time)
video.start= time;
video.oldCurrentTime(0);
video.src("media/testavi.avi.ogv?start=" + time);
video.play();
return this;
};
$.getJSON( "media/testavi.avi.js", function( data )
{
video.theDuration= data.duration;
});
</script>
</body>
在https://github.com/derolf/transcoder上可以找到一个有效的例子。
dero
发布于 2020-05-14 00:12:08
我知道这是一个老帖子,但如果有人发现它并需要帮助,我无论如何都会把它贴出来。
'user3612643‘答案是正确的,这解决了寻道问题。然而,这引入了一个新的问题。当前时间不再正确。要解决这个问题,我们必须复制原始的currentTime
函数。
现在,每次video.js调用currentTime
(没有参数)时,它都会调用oldCurrentTime
,这是原始的currentTime
函数。其余部分与‘user3612643’的答案相同(谢谢!)。这适用于最新的video.js (7.7.6)。
video = videojs("video");
video.src({
src: 'http://localhost:4000/api/video/sdf',
type: 'video/webm'
});
// hack duration
video.duration= function() {return video.theDuration; };
video.start= 0;
// The original code for "currentTime"
video.oldCurrentTime = function currentTime(seconds) {
if (typeof seconds !== 'undefined') {
if (seconds < 0) {
seconds = 0;
}
this.techCall_('setCurrentTime', seconds);
return;
}
this.cache_.currentTime = this.techGet_('currentTime') || 0;
return this.cache_.currentTime;
}
// Our modified currentTime
video.currentTime= function(time)
{
if( time == undefined )
{
return video.oldCurrentTime() + video.start;
}
video.start= time;
video.oldCurrentTime(0);
video.src({
src: "http://localhost:4000/api/video/sdf?start=" + time,
type: 'video/webm'
});
video.play();
return this;
};
// Get the dureation of the movie
$.getJSON( "http://localhost:4000/api/video/sdf/getDuration", function( data )
{
video.theDuration= data.duration;
});
发布于 2011-08-12 04:21:36
这应该可以通过VLC来实现,我可以通过设置VLC来托管一个大的avi文件并将其转码为OGG,然后我的html5引用了这个流:
<source src="http://localhost:8081/stream.ogg">
它可以在vlc中进行转码,在我的chrome浏览器和我的android手机上渲染也很好,但我最终选择了一个different solution,而不是创建自己的webapp来托管我的媒体收藏和为所请求的文件创建流-我寻找并找不到一个已经存在的免费应用程序,它以我需要/喜欢的方式做到了这一点。
https://stackoverflow.com/questions/3639604
复制相似问题