vb.net 通过 .NET HTML5 流式传输 MP4 视频
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16421255/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Streaming MP4 video through .NET HTML5
提问by JLo
I am trying to create a test page which will contain a HTML5 VIDEO tag which will allow converted videos to be played. I am successfully able to convert the videos and store these locally on the server but I'd like to be able to stream all videos through another .aspx page.
我正在尝试创建一个测试页面,其中将包含一个 HTML5 VIDEO 标签,该标签将允许播放转换后的视频。我能够成功转换视频并将它们本地存储在服务器上,但我希望能够通过另一个 .aspx 页面流式传输所有视频。
Assuming I have a player.aspx page which will contain the HTML code and getvideo.aspx page which will do nothing except provide the video binary, I thought that the following code would work fine in my player.aspx page:
假设我有一个包含 HTML 代码的 player.aspx 页面和除了提供视频二进制文件什么都不做的 getvideo.aspx 页面,我认为以下代码在我的 player.aspx 页面中可以正常工作:
<div style="text-align:center">
<video controls autoplay id="video1" width="920">
<source src="http://www.mywebsite.com/getvideo.aspx?getvideo=1" type="video/mp4">
Your browser does not support HTML5 video.
</video>
The getvideo.aspx page contains the following vb.net code:
getvideo.aspx 页面包含以下 vb.net 代码:
Response.clearheaders
Response.AddHeader("Content-Type", "video/mp4")
Response.AddHeader("Content-Disposition", "inline;filename=""newvideo.mp4""")
dim Err as string = ""
Dim iStream As System.IO.Stream
' Buffer to read 10K bytes in chunk:
Dim buffer(buffersize) As Byte
' Length of the file:
Dim length As Integer
' Total bytes to read:
Dim dataToRead As Long
' Identify the file to download including its path.
Dim filepath As String = "./outout/videos/newvideo.mp4"
' Identify the file name.
Dim filename As String = System.IO.Path.GetFileName(filepath)
' Open the file.
try
iStream = New System.IO.FileStream(filepath, System.IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)
catch ex as exception
throw new exception("Could not create FileStream for [" & filepath & "], error follows." & vbcrlf & ex.toString)
end try
Try
' Total bytes to read:
dataToRead = iStream.Length
' Read the bytes.
While dataToRead > 0
' Verify that the client is connected.
If system.web.httpcontext.current.Response.IsClientConnected Then
' Read the data in buffer
length = iStream.Read(buffer, 0, buffersize)
' Write the data to the current output stream.
system.web.httpcontext.current.Response.OutputStream.Write(buffer, 0, length)
' Flush the data to the HTML output.
system.web.httpcontext.current.Response.Flush()
ReDim buffer(buffersize) ' Clear the buffer
dataToRead = dataToRead - length
Else
'prevent infinite loop if user disconnects
dataToRead = -1
End If
End While
Catch ex As Exception
' Trap the error, if any.
err = "Error accessing " & filepath & " : " & ex.tostring
Finally
If IsNothing(iStream) = False Then
' Close the file.
iStream.Close()
End If
End Try
if err<>"" then throw new exception( err )
All I get on my page output is a HTML video player (chrome's basic player) which seems to time out and the PLAY button goes grey. The Network tool in the Chrome Developer tools shows that it's downloading 45mb and gets a 200 response code. This suggests to me that it is working fine. Although I get a second GET request with the status of "Cancelled"?
我在页面输出上得到的只是一个 HTML 视频播放器(chrome 的基本播放器),它似乎超时并且 PLAY 按钮变灰。Chrome 开发人员工具中的网络工具显示它正在下载 45mb 并获得 200 响应代码。这向我表明它运行良好。虽然我收到了状态为“已取消”的第二个 GET 请求?
If I visit www.mywebsite.com/output/videos/myvideo.mp4 then this plays in the browser fine so I know IIS is configured to correctly stream video.
如果我访问 www.mywebsite.com/output/videos/myvideo.mp4,那么它可以在浏览器中正常播放,因此我知道 IIS 已配置为正确流式传输视频。
Also if I change the response content disposition to "attachment" then the browser correctly forces a download of the video when going to my ASPX page, but this also doesn't correctly play on the HTML player. Is there something 'clever' going on with the HTML5 VIDEO tag which is stopping a .aspx file from serving up video via .net? Or am I missing a response header?
此外,如果我将响应内容配置更改为“附件”,则浏览器会在转到我的 ASPX 页面时正确强制下载视频,但这也无法在 HTML 播放器上正确播放。HTML5 VIDEO 标签是否有一些“聪明”的东西会阻止 .aspx 文件通过 .net 提供视频?还是我缺少响应标头?
Thanks!
谢谢!
采纳答案by JLo
FIXED!
固定的!
The problem here is presumably something to do with the HTML5 video implementation of range-requests. Without supporting range-requests in the page being used to SERVE the video, they just won't work.
这里的问题大概与范围请求的 HTML5 视频实现有关。如果不支持用于 SERVE 视频的页面中的范围请求,它们将无法工作。
It was this very helpful post from Scott Mitchell which set me on the case: http://dotnetslackers.com/articles/aspnet/Range-Specific-Requests-in-ASP-NET.aspx
正是 Scott Mitchell 的这篇非常有帮助的帖子让我了解了这个案例:http: //dotnetslackers.com/articles/aspnet/Range-Specific-Requests-in-ASP-NET.aspx
And another helpful post from Chris Coulson which provided the implementation in C# for the solution! http://blogs.visigo.com/chriscoulson/easy-handling-of-http-range-requests-in-asp-net/
Chris Coulson 的另一篇有用的帖子提供了 C# 中的解决方案实现! http://blogs.visigo.com/chriscoulson/easy-handling-of-http-range-requests-in-asp-net/
My vb.net port of the code Chris found is below, to implement it simply put this in your page:
我的 Chris 找到的代码的 vb.net 端口在下面,要实现它,只需将它放在您的页面中:
system.web.httpcontext.current.Response.ContentType = "video/" & convertFormat.toString
RangeDownload(convertedVideo, system.web.httpcontext.current)
VB.NET CODE:
VB.NET 代码:
private sub RangeDownload( fullpath as string, context as HttpContext)
dim size as long
dim start as long
dim theend as long
dim length as long
dim fp as long =0
using reader as new StreamReader(fullpath)
size = reader.BaseStream.Length
start = 0
theend = size - 1
length = size
'/ Now that we've gotten so far without errors we send the accept range header
'* At the moment we only support single ranges.
'* Multiple ranges requires some more work to ensure it works correctly
'* and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
'*
'* Multirange support annouces itself with:
'* header('Accept-Ranges: bytes');
'*
'* Multirange content must be sent with multipart/byteranges mediatype,
'* (mediatype = mimetype)
'* as well as a boundry header to indicate the various chunks of data.
'*/
context.Response.AddHeader("Accept-Ranges", "0-" + size)
'// header('Accept-Ranges: bytes')
'// multipart/byteranges
'// http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
if (not String.IsNullOrEmpty(context.Request.ServerVariables("HTTP_RANGE"))) then
dim anotherStart as long = start
dim anotherEnd as long = theend
dim arr_split as string() = context.Request.ServerVariables("HTTP_RANGE").Split("=") 'new char[] { Convert.ToChar("=") })
dim range as string = arr_split(1)
'// Make sure the client hasn't sent us a multibyte range
if (range.IndexOf(",") > -1) then
'// (?) Shoud this be issued here, or should the first
'// range be used? Or should the header be ignored and
'// we output the whole content?
context.Response.AddHeader("Content-Range", "bytes " & start & "-" & theend & "/" & size)
throw new HttpException(416, "Requested Range Not Satisfiable")
end if
'// If the range starts with an '-' we start from the beginning
'// If not, we forward the file pointer
'// And make sure to get the end byte if spesified
if (range.StartsWith("-")) then
'// The n-number of the last bytes is requested
anotherStart = size - Convert.ToInt64(range.Substring(1))
else
arr_split = range.Split("-")
anotherStart = Convert.ToInt64(arr_split(0))
dim temp as long = 0
if (arr_split.Length > 1 andalso Int64.TryParse(arr_split(1).ToString(), temp)) then
anotherEnd = Convert.ToInt64(arr_split(1))
else
anotherEnd = size
end if
end if
'/* Check the range and make sure it's treated according to the specs.
' * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
' */
'// End bytes can not be larger than $end.
if (anotherEnd > theend) then
anotherEnd = theend
else
anotherEnd = anotherEnd
end if
'// Validate the requested range and return an error if it's not correct.
if (anotherStart > anotherEnd or anotherStart > size - 1 or anotherEnd >= size) then
context.Response.AddHeader("Content-Range", "bytes " + start + "-" + theend + "/" + size)
throw new HttpException(416, "Requested Range Not Satisfiable")
end if
start = anotherStart
theend = anotherEnd
length = theend - start + 1 '// Calculate new content length
fp = reader.BaseStream.Seek(start, SeekOrigin.Begin)
context.Response.StatusCode = 206
end if
end using
'// Notify the client the byte range we'll be outputting
context.Response.AddHeader("Content-Range", "bytes " & start & "-" & theend & "/" & size)
context.Response.AddHeader("Content-Length", length.ToString())
'// Start buffered download
context.Response.WriteFile(fullpath, fp, length)
context.Response.End()
end sub

