php - attribute - playsinline video html5
MP4 se reproduce cuando se accede directamente, pero no cuando se lee a través de PHP, en iOS (6)
Utilizo un script PHP para validar las solicitudes de video antes de servirlas. Este script funciona como se espera en el escritorio, con Safari y Chrome. Pero en iOS, me sale un botón de reproducción roto.
Estoy seguro de que el video está codificado correctamente para iPhone / iPad, porque cuando lo accedo directamente, funciona como se esperaba.
El código PHP relevante:
$file_name = ''test-video.mp4'';
$file_size = (string)(filesize($file_name));
header(''Content-Type: video/mp4'');
header(''Content-Length: ''.$file_size);
readfile_chunked($file_name);
exit;
( readfile_chunked()
es similar a readfile()
pero para archivos muy grandes, que se encuentran en los comentarios en la página del manual de PHP: http://php.net/manual/en/function.readfile.php . En cualquier caso, test-video.mp4
es solo de ~ 5 MB, que es menor que el límite de memoria, y en este caso realmente puedo sustituirlo en el readfile()
normal readfile()
y producir el mismo comportamiento.
Los encabezados que obtengo cuando test-video.mp4
directamente son:
Accept-Ranges:bytes
Connection:Keep-Alive
Content-Length:5558749
Content-Type:video/mp4
Date:Sun, 27 Jun 2010 21:02:09 GMT
Etag:"1c04757-54d1dd-489944c5a6400"
Keep-Alive:timeout=10, max=30
Last-Modified:Tue, 22 Jun 2010 01:25:36 GMT
Server:Apache/2.2.15 (CentOS) mod_ssl/2.2.15 0.9.8l DAV/2 mod_auth_passthrough/2.1 FrontPage/5.0.2.2635
Los encabezados del script PHP son:
Connection:Keep-Alive
Content-Disposition:inline; filename="test-video.mp4"
Content-Length:5558749
Content-Type:video/mp4
Date:Sun, 27 Jun 2010 21:03:32 GMT
Keep-Alive:timeout=10, max=15
Server:Apache/2.2.15 (CentOS) mod_ssl/2.2.15 0.9.8l DAV/2 mod_auth_passthrough/2.1 FrontPage/5.0.2.2635
X-Powered-By:PHP/5.2.13
He intentado muchas permutaciones diferentes de encabezados, incluso comparándolos exactamente con los de una solicitud directa, sin éxito.
¿Alguien ha tenido éxito sirviendo video HTML5 a través de PHP, en iOS?
[Nota: probaría usar X-Sendfile, pero el sitio está en un host compartido con acceso muy limitado.]
EDITAR: estaba leyendo que iOS puede ser sensible acerca de las extensiones de archivo, así que intenté configurar una RewriteRule que vuelve a escribir las solicitudes de MP4 en mi script PHP original, pero eso tampoco ayudó.
Como se indicó anteriormente para transmitir o reproducir videos MP4 usando PHP, deberá manejar los rangos de bytes si desea una reproducción adecuada en Safari y iOS.
rangeDownload()
función rangeDownload()
mencionada en las respuestas anteriores hace el trabajo bastante bien.
Quiero mencionar otra pieza de este rompecabezas: asegúrese de que la fuente en el video termine con .mp4
como en <video source="url/yourfile.php/referenceForFile.mp4">
. Esto hace que el navegador sea un archivo de video, y comienza a tratarlo como uno solo.
Dentro de yourfile.php
, puede tomar la referencia entrante para su archivo usando $_SERVER[''PATH_INFO'']
o dentro de REQUEST_URI
. No es necesario pasarlo como un ?id=someId.mp4
, el enfoque de barra directa se parece más a un archivo real.
En resumen, desde mi experiencia para servir un archivo de video desde PHP correctamente, necesitará:
- Soporte de rango de bytes. El navegador le dice al servidor qué parte del archivo necesita, y el servidor necesita responder con ese contenido de rango de bytes.
- Tenga su
moov atom
al principio del archivo (puede usar ffmpeg''s-movflags +faststart
oMP4Box
) -
<video source="...file.mp4">
El atributo de origen de la etiqueta de video debe verse como un archivo.mp4
. Sin esto, mis videos solo se reproducían en Chrome y no en Safari / iOS. - Reproductor HTML5 directo, o puedes usar una biblioteca como
videojs
Escribí esto en base a mi experiencia con la publicación de miles de videos en mi sitio web de videos musicales. Si bien este podría no ser el caso para todos, pero encontré que esta configuración de navegador cruzado y dispositivo funcionó como se esperaba.
Si lees el archivo de la URL de http, en lugar de filsize (), la función de tu usuario debajo del código para obtener el tamaño del archivo
function getFileSize($file) {
$ch = curl_init($file);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$data = curl_exec($ch);
curl_close($ch);
$contentLength=0;
if (preg_match(''/Content-Length: (/d+)/'', $data, $matches)) {
// Contains file size in bytes
$contentLength = (int)$matches[1];
}
return $contentLength;
}
Si lo maneja usted mismo, entonces también deberá manejar las solicitudes de rango de bytes.
Tenga en cuenta que este es el código ( https://mobiforge.com/design-development/content-delivery-mobile-devices ) es un salvavidas. Sin embargo estar en la búsqueda de la línea
"if ($ range {0} == ''-'') {" o "if ($ range0 == ''-'') {"
debería ser
if ($ range [0] == ''-'') {
Este error tipográfico resultó en un tiempo muy largo para descubrir por qué no funcionó.
Tratar:
$arquivo_caminho = ''path/file''
if (is_file($arquivo_caminho)){
header("Content-type: video/mp4"); // change mimetype
if (isset($_SERVER[''HTTP_RANGE''])){ // do it for any device that supports byte-ranges not only iPhone
rangeDownload($arquivo_caminho);
} else {
header("Content-length: " . filesize($arquivo_caminho));
readfile($arquivo_caminho);
} // fim do if
} // fim do if
function rangeDownload($file){
$fp = @fopen($file, ''rb'');
$size = filesize($file); // File size
$length = $size; // Content length
$start = 0; // Start byte
$end = $size - 1; // End byte
// Now that we''ve gotten so far without errors we send the accept range header
/* At the moment we only support single ranges.
* Multiple ranges requires some more work to ensure it works correctly
* and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
*
* Multirange support annouces itself with:
* header(''Accept-Ranges: bytes'');
*
* Multirange content must be sent with multipart/byteranges mediatype,
* (mediatype = mimetype)
* as well as a boundry header to indicate the various chunks of data.
*/
header("Accept-Ranges: 0-$length");
// header(''Accept-Ranges: bytes'');
// multipart/byteranges
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
if (isset($_SERVER[''HTTP_RANGE''])){
$c_start = $start;
$c_end = $end;
// Extract the range string
list(, $range) = explode(''='', $_SERVER[''HTTP_RANGE''], 2);
// Make sure the client hasn''t sent us a multibyte range
if (strpos($range, '','') !== false){
// (?) Shoud this be issued here, or should the first
// range be used? Or should the header be ignored and
// we output the whole content?
header(''HTTP/1.1 416 Requested Range Not Satisfiable'');
header("Content-Range: bytes $start-$end/$size");
// (?) Echo some info to the client?
exit;
} // fim do if
// If the range starts with an ''-'' we start from the beginning
// If not, we forward the file pointer
// And make sure to get the end byte if spesified
if ($range{0} == ''-''){
// The n-number of the last bytes is requested
$c_start = $size - substr($range, 1);
} else {
$range = explode(''-'', $range);
$c_start = $range[0];
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
} // fim do if
/* Check the range and make sure it''s treated according to the specs.
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
*/
// End bytes can not be larger than $end.
$c_end = ($c_end > $end) ? $end : $c_end;
// Validate the requested range and return an error if it''s not correct.
if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size){
header(''HTTP/1.1 416 Requested Range Not Satisfiable'');
header("Content-Range: bytes $start-$end/$size");
// (?) Echo some info to the client?
exit;
} // fim do if
$start = $c_start;
$end = $c_end;
$length = $end - $start + 1; // Calculate new content length
fseek($fp, $start);
header(''HTTP/1.1 206 Partial Content'');
} // fim do if
// Notify the client the byte range we''ll be outputting
header("Content-Range: bytes $start-$end/$size");
header("Content-Length: $length");
// Start buffered download
$buffer = 1024 * 8;
while(!feof($fp) && ($p = ftell($fp)) <= $end){
if ($p + $buffer > $end){
// In case we''re only outputtin a chunk, make sure we don''t
// read past the length
$buffer = $end - $p + 1;
} // fim do if
set_time_limit(0); // Reset time limit for big files
echo fread($fp, $buffer);
flush(); // Free up memory. Otherwise large files will trigger PHP''s memory limit.
} // fim do while
fclose($fp);
} // fim do function
Tuve un problema con ese código.
Fijar:
set_time_limit(0); // Reset time limit for big files
ob_clean(); //added
echo fread($fp, $buffer);
flush(); // Free up memory. Otherwise large files will trigger PHP''s memory limit.