I am trying to use WebAPI within an MVC site to stream video with a PushStreamContent object. I have read several how tos on this (including this frequently cited post @ strathweb.com and still can't seem to get this working.
Currently, the video does not play in the browser. As soon as the user moves their mouse over the video controls, they become disabled. There are two odd issues/symptoms occurring on the server:
First, on page load, the server seems to stream back the entire file immediately even though the user has not tried to actually play the video yet (they are merely seeing the standard HTML5 video placeholder - they should click play to view the video). Autoplay is not specified in the video tag. I can see this happening via the debug.writeline call within the streaming loop.
Second, when the user does actually click play, this error occurs: The remote host closed the connection. The error code is 0x800704CD.
Here is my code:
public class VideoController : ApiController
{
[ActionName("Get")]
public System.Net.Http.HttpResponseMessage Get(string fsoId)
{
var videoFullPath = GetPathToVideo(fsoId);
var response = Request.CreateResponse();
response.Content = new System.Net.Http.PushStreamContent( async (outputStream, context, transport) =>
{
try
{
var buffer = new byte[65536];
using (var videoFile = System.IO.File.Open(videoFullPath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
var length = (int)videoFile.Length;
var bytesRead = 1;
while (length > 0 && bytesRead > 0)
{
bytesRead = videoFile.Read(buffer, 0, Math.Min(length, buffer.Length));
System.Diagnostics.Debug.WriteLine(string.Format("Length at Start: {0}; bytesread: {1}", length, bytesRead));
await
outputStream.WriteAsync(buffer, 0, bytesRead);
length -= bytesRead;
}
}
}
catch (System.Web.HttpException httpEx)
{
System.Diagnostics.Debug.WriteLine(httpEx.GetBaseException().Message);
if (httpEx.ErrorCode == -2147023667) // The remote host closed the connection.
return;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.GetBaseException().Message);
return;
}
finally
{
outputStream.Close();
}
},
new System.Net.Http.Headers.MediaTypeHeaderValue("video/mp4"));
return response;
}
}
And here is my video tag:
<video width="320" height="240" controls>
<source src="api/video/12345" type="video/mp4">
Your browser does not support the video tag.
</video>
I figured out what was wrong: it was the video. The video had not been formatted for fast start (with metadata at the beginning of the file). So, regenerating the video using this ffmpeg command did the trick:
ffmpeg -1 MyVideo.mp4 -movflags faststart MyNewVideo.mp4
Essentially, the browser was requesting/downloading the whole video file in order to read the metadata embedded at the end.
Once I fixed that, no more download of the whole file and no more "Remote host closed connection" error. Not the most intuitive error message.
If someone knows how to determine if an existing video has it's metadata at the beginning already, I'd love to hear how to do it.
I hope this helps someone.
User contributions licensed under CC BY-SA 3.0