I'm having a strange issue trying stream H.264 video with Django using the FileWrapper class. I'm using the following view function:
def mp4(request, path):
wrapper = FileWrapper(open(path, 'rb'))
content_type = mimetypes.guess_type(path)[0]
response = HttpResponse(wrapper, content_type=content_type)
response['Content-Length'] = os.path.getsize(path)
return response
The function is mapped to this URL:
(r'^/mp4/(.*)$', 'mp4'),
And I'm referencing the URL inside an HTML5 video tag:
<video width="560" height="340" controls>
<source src='/video/mp4//tmp/test.mp4' type='video/mp4 codecs="avc1.42E01E, mp4a.40.2"'>
</video>
However, when I open the page containing the video, the video does NOT play and the Django development server issues the following errors:
Traceback (most recent call last): File "/usr/lib/pymodules/python2.6/django/core/servers/basehttp.py", line 280, in run self.finish_response() File "/usr/lib/pymodules/python2.6/django/core/servers/basehttp.py", line 320, in finish_response self.write(data) File "/usr/lib/pymodules/python2.6/django/core/servers/basehttp.py", line 416, in write self._write(data) File "/usr/lib/python2.6/socket.py", line 300, in write self.flush() File "/usr/lib/python2.6/socket.py", line 286, in flush self._sock.sendall(buffer) error: [Errno 104] Connection reset by peer [05/Dec/2010 13:08:00] "GET /video/mp4//tmp/test.mp4 HTTP/1.1" 200 384329753 Traceback (most recent call last): File "/usr/lib/pymodules/python2.6/django/core/servers/basehttp.py", line 280, in run self.finish_response() File "/usr/lib/pymodules/python2.6/django/core/servers/basehttp.py", line 320, in finish_response self.write(data) File "/usr/lib/pymodules/python2.6/django/core/servers/basehttp.py", line 416, in write self._write(data) File "/usr/lib/python2.6/socket.py", line 300, in write self.flush() File "/usr/lib/python2.6/socket.py", line 286, in flush self._sock.sendall(buffer) error: [Errno 104] Connection reset by peer Traceback (most recent call last): File "/usr/lib/pymodules/python2.6/django/core/servers/basehttp.py", line 280, in run self.finish_response() File "/usr/lib/pymodules/python2.6/django/core/servers/basehttp.py", line 320, in finish_response self.write(data) File "/usr/lib/pymodules/python2.6/django/core/servers/basehttp.py", line 416, in write self._write(data) File "/usr/lib/python2.6/socket.py", line 300, in write self.flush() File "/usr/lib/python2.6/socket.py", line 286, in flush self._sock.sendall(buffer) error: [Errno 32] Broken pipe
The browser, Google Chrome, appears to try to retrieve the video multiple times, the first two times reseting the connection and the last time dropping the connection. Notice that Django returns a 200 OK response together with the correct size of the video.
Here is the strange part: Even though the video does not play, I can right click the player control, select Save Video As... and Google Chrome will happily download the entire video and store it locally. I can then, still in Google Chrome, play the saved video by opening it with a file:// URL.
I have also tried putting the video file in a local web server and referencing it there in the video tag, and that works as well.
So I think the issue is related to FileWrapper and/or the way Django handles HttpResponse with an iterator. The data is there, it can be saved with Save Video As..., so why won't it play?
Thanks!