2013-05-08 8 views
9

Stiamo riscontrando problemi nella pubblicazione di mp4 che verranno riprodotti su un ipad utilizzando un'app predefinita di rails 3. L'mp4 viene pubblicato correttamente quando si visualizza il percorso in Chrome e altri browser su un desktop.Qual è il modo corretto di servire i file mp4 attraverso i binari su un Ipad?

Ecco il nostro codice:

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

abbiamo colpito 0.0.0.0:3000/video/test.mp4 per visualizzare il video e sono rappresentati con non può giocare icona sulla ipad. Abbiamo provato a modificare varie intestazioni "Content-Length", "Content-Range", ecc. Ma non sembrano influenzare il risultato finale.

Abbiamo provato anche utilizzando Send_Data in una certa misura

cioè

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

Lo stesso video serve una raffinata dalla cartella pubblica quando viene visualizzato sul Ipad.

Qual è il modo corretto di servire i file mp4 attraverso i binari su un Ipad?

risposta

15

Il problema sembra essere che i binari non gestiscono le richieste di portata http di cui ios ha bisogno per lo streaming di mp4s.

Questa era la nostra soluzione per lo sviluppo, (utilizzando sottile come il nostro 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 

definitiva useremo nginx XSendfile a servire i beni nel nostro ambiente di produzione, come la soluzione di cui sopra è molto più lento di quello che abbiamo bisogno.

+2

Penso che ci sia un errore fencepost nel codice. Credo che la lunghezza dovrebbe essere 'bytes.end - bytes.begin + 1' - se l'intervallo di byte è dal byte 10 al 12, dovrebbe essere 3 byte. Inoltre, se stai usando 'send_data' per qualche motivo, assicurati di impostare' Content-Length' nelle intestazioni di risposta. – tovodeverett

+0

Grazie per questa soluzione! Ho aggiunto correzioni basate sul commento di @tovodeverett. Usando Sinatra (invece di Rails) per lo sviluppo, sono riuscito a replicare il comportamento send_data usando contrib come sinatra/streaming come segue: 'stream {| out | out.write IO.binread (percorso_file, lunghezza, offset); out.flush} ' –

+1

Grazie per la soluzione! Abbiamo notato che per fare in modo che questo approccio funzioni in Chrome, è necessario impostare esplicitamente lo stato della risposta su '206'. –

Problemi correlati