HTML5 <audio>/<video> y vivir de transcodificación con FFMPEG

Por lo que desde mi servidor web, me gustaría usar FFMPEG para transcodificar un archivo multimedia para su uso con un HTML <audio> o <video> etiqueta. Bastante fácil de derecho?

La conversión tendría que tienen lugar en tiempo real, cuando un cliente HTTP solicitado el archivo convertido. Lo ideal es que el archivo se retiraban para el cliente HTTP como es de transcodificación (y no después, en el final, ya que podría tomar un tiempo antes de que los datos comienza a ser enviado de vuelta).

Esto estaría bien, excepto que en el día de hoy los navegadores HTML5 audio o de vídeo de la etiqueta de las solicitudes de los medios de comunicación de archivos en múltiples peticiones HTTP con el Range encabezado. Ver esta pregunta para obtener más detalles.

En esa pregunta enlazado más arriba, usted puede ver que el Safari solicitudes extraño trozos del archivo, incluyendo el final que pocos bytes. Esto plantea un problema en el que el servidor web TENDRÍA que esperar a la conversión para terminar, con el fin de entregar la final de bytes del archivo para cumplir la Range solicitud.

Así que mi pregunta es, es mi tren de pensamiento de la derecha? Existe una mejor forma de entregar la transcodificación de contenido a un <audio> o <video> etiqueta que no involucrar a la espera de la totalidad de la conversión a terminar? Gracias de antemano!

  • Entonces, ¿qué pasa si 50 personas tratan de ver su vídeo al mismo tiempo (o si puedo actualizar de prensa 100 veces)? La transcodificación en tiempo real podría funcionar para un vídeo en una estación de trabajo, pero sospecho que es demasiado intensivo de los recursos para hacer de cada solicitud en un servidor. Tal vez un «por favor, espere mientras tratamos de convertir-entonces-cache» estrategia de trabajo?
  • El almacenamiento en caché el archivo convertido es lo que yo ya estaba pensando en este momento. Pero mis aplicaciones está destinado a ser bloqueado a un par de usuarios de todos modos, como abiertamente que permita el acceso HTTP a tu biblioteca de iTunes no es tanto una buena idea en mi opinión.
  • Me gustaría ir con YouTube enfoque (Seth sugerencia)– supongo que esta pregunta en algún momento 🙂
InformationsquelleAutor TooTallNate | 2010-09-03

4 Kommentare

  1. 10

    Recientemente he quedado en el mismo problema ya que quiero servir a mi biblioteca a los navegadores. Sorprendentemente, la idea de enviar la corriente a través de ffmpeg y entregar en la mosca funciona bastante bien. El problema principal era apoyar la búsqueda de…

    Siguientes, encontrará el código de sniplets en Python usando el Matraz de resolver el problema:

    Necesitamos una función para el contenido de la secuencia:

    @app.route('/media/<path:path>.ogv')
    def media_content_ogv(path):
        d= os.path.abspath( os.path.join( config.media_folder, path ) )
        if not os.path.isfile( d ): abort(404)
        start= request.args.get("start") or 0
        def generate():
            cmdline= list()
            cmdline.append( config.ffmpeg )
            cmdline.append( "-i" )
            cmdline.append( d );
            cmdline.append( "-ss" )
            cmdline.append( str(start) );
            cmdline.extend( config.ffmpeg_args )
            print cmdline
            FNULL = open(os.devnull, 'w')
            proc= subprocess.Popen( cmdline, stdout=subprocess.PIPE, stderr=FNULL )
            try:
                f= proc.stdout
                byte = f.read(512)
                while byte:
                    yield byte
                    byte = f.read(512)
            finally:
                proc.kill()
    
        return Response(response=generate(),status=200,mimetype='video/ogg',headers={'Access-Control-Allow-Origin': '*', "Content-Type":"video/ogg","Content-Disposition":"inline","Content-Transfer-Enconding":"binary"})

    Entonces tenemos una función para devolver la duración:

    @app.route('/media/<path:path>.js')
    def media_content_js(path):
        d= os.path.abspath( os.path.join( config.media_folder, path ) )
        if not os.path.isfile( d ): abort(404)
        cmdline= list()
        cmdline.append( config.ffmpeg )
        cmdline.append( "-i" )
        cmdline.append( d );
        duration= -1
        FNULL = open(os.devnull, 'w')
        proc= subprocess.Popen( cmdline, stderr=subprocess.PIPE, stdout=FNULL )
        try:
            for line in iter(proc.stderr.readline,''):
                line= line.rstrip()
                #Duration: 00:00:45.13, start: 0.000000, bitrate: 302 kb/s
                m = re.search('Duration: (..):(..):(..)\...', line)
                if m is not None: duration= int(m.group(1)) * 3600 + int(m.group(2)) * 60 + int(m.group(3)) + 1
        finally:
            proc.kill()
    
        return jsonify(duration=duration)

    Y por último, nos hack que en HTML5 utilizando videojs:

    <!DOCTYPE html>
    <html>
    <head>
        <link href="//vjs.zencdn.net/4.5/video-js.css" rel="stylesheet">
        <script src="//vjs.zencdn.net/4.5/video.js"></script>
        <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    </head>
    <body>
        <video id="video" class="video-js vjs-default-skin" controls preload="auto" width="640" height="264">
        </video>
        <script>
            var video= videojs('video');
            video.src("media/testavi.avi.ogv");
    
            //hack duration
            video.duration= function() { return video.theDuration; };
            video.start= 0;
            video.oldCurrentTime= video.currentTime;
            video.currentTime= function(time) 
            { 
                if( time == undefined )
                {
                    return video.oldCurrentTime() + video.start;
                }
                console.log(time)
                video.start= time;
                video.oldCurrentTime(0);
                video.src("media/testavi.avi.ogv?start=" + time);
                video.play();
                return this;
            };
    
            $.getJSON( "media/testavi.avi.js", function( data ) 
            {
                video.theDuration= data.duration;
            });
        </script>
    </body>

    Un ejemplo de trabajo se puede encontrar en la https://github.com/derolf/transcoder .

    dero

  2. 3

    Gracias por la respuesta Camilo. Me tomó un vistazo más de cerca a la HTTP especificaciones con respecto a la solicitud de Rango y se encontró:

    The header SHOULD indicate the total length of the full entity-body, unless
    this length is unknown or difficult to determine. The asterisk "*" character
    means that the instance-length is unknown at the time when the response was
    generated.

    Por lo que es realmente sólo una cuestión de prueba de cómo los navegadores reaccionar al responder con un Content-Range: bytes 0-1/*, por ejemplo. Voy a dejar que usted sabe lo que sucede.

    • ¿Cómo encontrar la compatibilidad con este enfoque? Funcionó bien en todos los navegadores? La última vez que hice esto me di cuenta que era mejor tomar una «conjetura» en la longitud y el cero de llenar el resto de adivinar grande. Esto parece funcionar con constante tasa de bits decentemente.
    • Nunca me terminó tratando de ser honesto. Nadie más sabe? Desde la especificación, se especifica que los de trabajo, pero es un nicho de la parte de la especificación que podríamos necesitar para abrir temas en los diversos navegadores de insectos » trackers para que funcione correctamente.
  3. 0

    AFAIK puede codificar a stdout en ffmpeg. Así que usted puede configurar su servidor HTTP a:

    • iniciar la codificación a la caché cuando se CONSIGUE recibido.
    • corriente solicitada rango de bytes al cliente.
    • llenado el buffer y el uso de ella para su posterior rangos.

    Estoy despistado, pero yo creo que puede llegar lejos sin saber el final de la secuencia de longitud.

    En una nota de lado, creo que este es propensa a los DoS.

  4. -1

    Este debe ser factible a través de VLC, yo era capaz de conseguir que funcione mediante la configuración de VLC para alojar un gran archivo avi y codificar a OGG, entonces mi html5 hace referencia a la secuencia:

    <source src="http://localhost:8081/stream.ogg">

    Fue capaz de transcodificar en vlc, y hacer bien en mi navegador chrome y en mi teléfono android, pero terminé tomando un solución diferente en lugar de ir a través de la labor de crear mi propia web para alojar mi colección de medios y crear flujos de los archivos solicitados – me miró y no pude encontrar uno gratis ya que lo hizo de una manera que me necesitan o les gustó.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea