2013-05-08 13 views
9

Wir haben Probleme beim Versenden von mp4s, die auf einem iPad mit einer Standard-App "rails 3" wiedergegeben werden. Der mp4 wird korrekt wiedergegeben, wenn die Route in Chrome und anderen Browsern auf einem Desktop angezeigt wird.Was ist der richtige Weg, um mp4-Dateien über Schienen zu einem Ipad zu dienen?

Hier ist unser Code:

file_path = File.join(Rails.root, 'test.mp4') 
send_file(file_path, :disposition => "inline", :type => "video/mp4") 

Wir 0.0.0.0:3000/video/test.mp4 schlagen das Video anzusehen und präsentiert mit nicht-Symbol auf dem ipad spielen. Wir haben versucht, verschiedene Header "Content-Length", "Content-Range" usw. zu ändern, aber sie scheinen das Endergebnis nicht zu beeinflussen.

Wir haben versucht, auch send_data zu einem gewissen Grad

heißt

File.open(file_path, "r") do |f| 
    send_data f.read, :type => "video/mp4" 
end 

Das gleiche Video serviert feine aus dem öffentlichen Ordner verwenden, wenn auf dem iPad gesehen.

Was ist der richtige Weg, um mp4-Dateien über Schienen zu einem Ipad zu dienen?

Antwort

15

Das Problem scheint zu sein, dass Rails nicht http-Bereich Anfragen, die IOS für Streaming MP4s benötigt behandelt.

Dies war unsere Lösung für die Entwicklung, (dünn wie unsere Server):

if(request.headers["HTTP_RANGE"]) && Rails.env.development? 

    size = File.size(file_path) 
    bytes = Rack::Utils.byte_ranges(request.headers, size)[0] 
    offset = bytes.begin 
    length = bytes.end - bytes.begin + 1 

    response.header["Accept-Ranges"]= "bytes" 
    response.header["Content-Range"] = "bytes #{bytes.begin}-#{bytes.end}/#{size}" 
    response.header["Content-Length"] = "#{length}" 

    send_data IO.binread(file_path,length, offset), :type => "video/mp4", :stream => true, :disposition => 'inline', 
       :file_name => file_name 

    else 
    send_file(file_path, :disposition => 'inline', :stream => true, :file_name => file_name) 
    end 

Letztlich werden wir nginx mit werden XSendfile die Vermögenswerte in der Produktionsumgebung wie die obige Lösung zu dienen ist viel langsamer als das, was wir brauchen.

+2

Ich denke, es gibt einen Zaunpfosten Fehler im Code. Ich glaube, die Länge sollte "bytes.end - bytes.begin + 1" sein - wenn der Bytebereich von Byte 10 bis 12 ist, sollte dies 3 Byte sein. Wenn Sie 'send_data' aus irgendeinem Grund verwenden, stellen Sie sicher, dass' Content-Length' in den Antwortheadern steht. – tovodeverett

+0

Vielen Dank für diese Lösung! Ich habe Korrekturen basierend auf @tovodeverett Kommentar hinzugefügt. Mit Sinatra (anstelle von Rails) für die Entwicklung konnte ich das send_data-Verhalten mit sinatra/streaming contrib wie folgt replizieren: 'stream {| out | out.write IO.binread (Dateipfad, Länge, Offset); out.flush} ' –

+1

Danke für die Lösung! Uns ist aufgefallen, dass der Reaktionsstatus explizit auf '206' gesetzt werden muss, damit dieser Ansatz in Chrome funktioniert. –

Verwandte Themen