3
votes

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!

1
Thank you for the reply. I don't think the issue is wrong mimetype. I'm using "video/mp4", which Google Chrome is able to handle. Inspecting the HTTP traffic, it looks like the issue may be that Google Chrome needs support for range requests before it will stream over HTTP. I will probably work around this issue with mod_xsendfile, but would still like to find out why the code above breaks.Roger Dahl
Sorry to revive an old problem but were you able to solved this?hakura
@alper: The issue was that Chrome needs HTTP byte-range for video streaming. I worked around it with mod_xsendfile.Roger Dahl

1 Answers

0
votes

For those who're stumbling across this question in 2019 (and beyond), the answer has been posted here.