Al acondicionar una transmisión para la reproducción DASH, los puntos de acceso aleatorio deben estar exactamente al mismo tiempo de transmisión de la fuente en todas las transmisiones. La forma habitual de hacer esto es forzar una velocidad de cuadro fija y una longitud de GOP fija (es decir, un fotograma clave cada N cuadros).
En FFmpeg, la velocidad de fotogramas fija es fácil (-r NÚMERO).
Pero para ubicaciones de fotogramas clave fijos (longitud de GOP), hay tres métodos ... ¿cuál es "correcto"? La documentación de FFmpeg es frustrantemente vaga al respecto.
Método 1: jugar con los argumentos de libx264
-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1
Parece haber cierto debate sobre si el corte de escena debe desactivarse o no, ya que no está claro si el "contador" de fotogramas clave se reinicia cuando ocurre un corte de escena.
Método 2: establecer un tamaño de GOP fijo:
-g GOP_LEN_IN_FRAMES
Desafortunadamente, esto solo se documenta al pasar la documentación de FFMPEG y, por lo tanto, el efecto de este argumento es muy poco claro.
Método 3: inserte un fotograma clave cada N segundos ( ¿Quizás? ):
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
Esto está explícitamente documentado. Pero aún no está claro de inmediato si el "contador de tiempo" se reinicia después de cada fotograma clave. Por ejemplo, en un GOP esperado de 5 segundos, si scenecut
libx264 inyecta un fotograma clave en 3 segundos, ¿sería el siguiente fotograma clave 5 segundos más tarde o 2 segundos más tarde?
De hecho, la documentación de FFmpeg diferencia entre esta y la -g
opción, pero en realidad no dice cómo estas dos opciones anteriores son un poco diferentes (obviamente, -g
va a requerir una velocidad de cuadro fija).
¿Lo cual está bien?
Parecería que -force_key_frames
sería superior , ya que no requeriría una velocidad de cuadro fija. Sin embargo, esto requiere que
- cumple con las especificaciones de GOP en H.264 ( si corresponde )
- GARANTIZA que habría un fotograma clave en cadencia fija, independientemente de los
scenecut
fotogramas clave libx264 .
También parece que -g
no podría funcionar sin forzar una velocidad de cuadro fija ( -r
) , ya que no hay garantía de que múltiples ejecuciones ffmpeg
con diferentes argumentos de códec proporcionen la misma velocidad de cuadro instantánea en cada resolución. Las velocidades de cuadro fijas pueden reducir el rendimiento de compresión (¡IMPORTANTE en un escenario DASH!).
Finalmente, el keyint
método parece un truco . Espero contra esperanza que esta no sea la respuesta correcta.
Referencias
Un ejemplo usando el -force_key_frames
método
fuente
ffprobe -i input.mp4 -select_streams v -show_frames -of csv -show_entries frame=pict_type
y luego coloreando las celdas. Me temo que no hay discusiones públicas, pero veré si puedo desenterrar algunos de los enlaces que encontré en ese momento.-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
formulario? Acabo de probarlo y descubrí que si bien había marcos I adicionales en la transmisión, parecía acatar mi regla. Un programa PERL seguirá como una "respuesta", ya que aparentemente no puede usar el marcado en los comentarios.-force_key_frames
no funcionó para mí, por lo que nunca lo volví a intentar. Eso fue hace mas de un año. Quizás fue un error. Lo intentaré de nuevo pronto.Aquí están mis cincuenta centavos para el caso.
Genere iframes solo en los intervalos deseados.
Ejemplo 1:
Genere iframes como se espera así:
El método 2 se deprecia. Omitido
Ejemplo 2
Genere un iframes de una manera ligeramente diferente:
Como puede ver, coloca iframes cada 2 segundos Y en el corte de escena (segundos con parte flotante), lo cual es importante para la complejidad de la transmisión de video en mi opinión.
Los tamaños de archivo geneada son bastante iguales. Muy extraño que incluso con más fotogramas clave en el Método 3 , a veces genera menos archivos que el algoritmo de biblioteca estándar x264.
Para generar múltiples archivos de bitrate para HLS, elegimos el método tres. Se alineó perfectamente con 2 segundos entre fragmentos, tienen un iframe al comienzo de cada fragmento y tienen iframes adicionales en escenas complejas que brindan una mejor experiencia para los usuarios que tienen dispositivos obsoletos y no pueden reproducir perfiles de alto x264.
Espero que ayude a alguien.
fuente
La respuesta, por lo tanto, parece ser:
libx264
específico y tiene el costo de eliminar lascenecut
opción muy útil enlibx264
.-g
parece estar en desuso. Parece que no funciona, ni está explícitamente definido en la documentación, ni se encuentra en la ayuda, ni parece estar usado en el código. La inspección de código muestra que la-g
opción probablemente esté destinada a transmisiones MPEG-2 (¡incluso hay estrofas de código que se refieren a PAL y NTSC!).También:
Script para la
-force_key_frames
opciónAquí hay un breve programa PERL que utilicé para verificar la cadencia de trama I basada en el resultado de la sugerencia ffprobe de slhck. Parece verificar que el
-force_key_frames
método también funcionará y tiene el beneficio adicional de permitirscenecut
marcos. No tengo ni idea de cómo FFMPEG hace que esto funcione, o si tuve suerte de alguna manera porque mis transmisiones están bien condicionadas.En mi caso, codifiqué a 30 fps con un tamaño GOP esperado de 6 segundos, o 180 fotogramas. Usé 180 como el argumento gopsize para este programa verificó un marco I en cada múltiplo de 180, pero establecerlo en 181 (o cualquier otro número que no sea un múltiplo de 180) hizo que se quejara.
fuente
force_key_frames
, confunde el algoritmo de asignación de bits x264, por lo que puede darle una peor calidad que simplemente establecer un intervalo fijo de fotogramas clave.-g
, usted dice, "Parece que no funciona, ... ni parece estar usado en el código". Lo comprobé y la entrada de lag
se almacena enavctx->gop_size
y eso hace que libx264 uso de ella:x4->params.i_keyint_max = avctx->gop_size;
. Cuando sondeo este archivo de prueba generado:ffmpeg -i a-test-file.mp4 -g 37 -t 15 gtest.mp4
obtengo fotogramas clave exactamente0,37,74,111,148,185,222,259,296,333,370
. Un GOP podría interrumpirse si se activa el cambio de escena, y para eso-sc_threshold
podría establecerse, lo que también es recogido por x264.Quería agregar información aquí, ya que mi búsqueda en Google sacó bastante de esta discusión en mi búsqueda para encontrar información sobre cómo tratar de encontrar una forma de segmentar mi codificación DASH de la manera que quería, y ninguna de la información que encontré era totalmente correcta.
Primero varios conceptos erróneos para deshacerse de:
No todos los cuadros I son iguales. Hay grandes cuadros "I" y pequeños cuadros "i". O para utilizar la terminología correcta, IDR I-Frames y no IDR I-Frames. IDR I-frames (a veces llamados "fotogramas clave") creará un nuevo GOP. Las tramas no IDR no lo harán. Son útiles para tener dentro de un Partido Republicano donde hay un cambio de escena.
-x264opts keyint=GOPSIZE:min-keyint=GOPSIZE
← Esto no hace lo que crees que hace. Esto me llevó un tiempo darme cuenta. Resulta quemin-keyint
está limitado en el código. No está permitido ser mayor que(keyint / 2) + 1
. Por lo tanto, asignar el mismo valor a estas dos variables da como resultado el valor demin-keyint
ser derribado a la mitad al codificar.Aquí está la cosa: el corte de escena es realmente genial, especialmente en videos que tienen cortes duros rápidos. Lo mantiene agradable y nítido, por lo que no quiero deshabilitarlo, pero al mismo tiempo no pude obtener un tamaño de GOP fijo mientras estaba habilitado. Quería habilitar el corte de escena, pero solo para que use marcos I que no sean IDR. Pero no estaba funcionando. Hasta que descubrí (de muchas lecturas) sobre el concepto erróneo # 2.
Resulta que necesitaba configurar el
keyint
doble del tamaño deseado de GOP. Esto significa quemin-keyint
se puede establecer en mi tamaño de GOP deseado (sin que el código interno lo corte por la mitad), lo que evita que la detección de corte de escena use fotogramas IDR I dentro del tamaño de GOP porque el recuento de fotogramas desde el último fotograma I de IDR es siempre menos quemin-keyinit
.Y finalmente, configurar la
force_key_frame
opción anula el tamaño doblekeyint
. Entonces, esto es lo que funciona:Prefiero segmentos en fragmentos de 2 segundos, por lo que mi GOPSIZE = Framerate * 2
Puede verificar usando ffprobe:
En el archivo CSV generado, cada línea le dirá
frame, [is_an_IDR_?], [frame_type], [frame_number]
:El resultado es que solo debería ver marcos I IDR a
GOPSIZE
intervalos fijos , mientras que todos los demás cuadros I son cuadros I sin IDR insertados según sea necesario para la detección de corte de escena.fuente
Parece que esta sintaxis no funciona siempre. He probado bastante en nuestro contenido de VOD, así como en el contenido en vivo (volcados de archivos) y, a veces, el corte de escena no funciona y desencadena un iframe intermedio:
Sintaxis para una conversión ascendente i50-> p50, gop / segmento de 2 segundos, IDR al inicio, marcos intermedios si es necesario
fuente
Twitch tiene una publicación sobre esto. Explican que decidieron usar su propio programa por varias razones; Una de ellas fue que ffmpeg no le permite ejecutar diferentes instancias x264 en diferentes subprocesos, sino que dedica todos los subprocesos especificados a un cuadro en una salida antes de pasar a la siguiente salida.
Si no estás haciendo streaming en tiempo real, tienes más lujo. La forma 'correcta' es probablemente codificar en una resolución con solo el tamaño de GOP especificado con -g, y luego codificar las otras resoluciones forzando fotogramas clave en los mismos lugares.
Si desea hacer eso, puede usar ffprobe para obtener los tiempos de fotogramas clave y luego usar un script de shell o un lenguaje de programación real para convertirlo en un comando ffmpeg.
Pero para la mayoría del contenido, hay muy poca diferencia entre tener un fotograma clave cada 5 segundos y dos fotogramas clave cada 5 segundos (uno forzado y otro de corte de escena). Esto es aproximadamente el tamaño promedio de I-frame versus el tamaño de P-frames y B-frames. Si usa x264 con configuraciones típicas (la única razón por la que creo que debería hacer algo para afectarlas es si configura -qmin, como una forma pobre de evitar que x264 use bitrate en contenido fácil; esto limita todos los tipos de cuadros al mismo valor , Creo) y obtener un resultado como el tamaño promedio del cuadro I de 46 kB, cuadro P 24 kB, cuadro B 17 kB (la mitad de frecuente que los cuadros P), luego un cuadro I adicional cada segundo a 30 fps es solo un aumento del 3% en el tamaño del archivo La diferencia entre h264 y h263 podría estar compuesta por un montón de disminuciones del 3%, pero una sola no es muy importante.
En otros tipos de contenido, los tamaños de los cuadros serán diferentes. Para ser justos, se trata de la complejidad temporal y no de la complejidad espacial, por lo que no se trata solo de contenido fácil frente a contenido duro. Pero en general, los sitios de transmisión de video tienen un límite de velocidad de bits, y el contenido con fotogramas I relativamente grandes es un contenido fácil que se codificará en alta calidad sin importar cuántos fotogramas clave adicionales se agreguen. Es un desperdicio, pero este desperdicio generalmente no se notará. El caso más derrochador es probablemente un video que es solo una imagen estática que acompaña a una canción, donde cada fotograma clave es exactamente el mismo.
Una cosa de la que no estoy seguro es de cómo los fotogramas clave forzados interactúan con el limitador de velocidad establecido con -maxrate y -bufsize. Creo que incluso YouTube ha tenido problemas recientes al configurar correctamente los ajustes del búfer para brindar una calidad constante. Si solo está utilizando la configuración de velocidad de bits promedio como puede verse en algunos sitios (ya que puede inspeccionar las opciones de x264 en el encabezado / mov atom? Con un editor hexadecimal), entonces el modelo de búfer no es un problema, pero si Al ofrecer contenido generado por el usuario, la tasa de bits promedio alienta a los usuarios a agregar una pantalla en negro al final de su video.
La opción -g de Ffmpeg, o cualquier otra opción de codificador que utilice, se asigna a la opción específica del codificador. Entonces '-x264-params keyint = GOPSIZE' es equivalente a '-g GOPSIZE'.
Un problema con el uso de la detección de escenas es si prefiere fotogramas clave cerca de números específicos por cualquier razón. Si especifica fotogramas clave cada 5 segundos y utiliza la detección de escena, y hay un cambio de escena en 4.5, entonces debería detectarse, pero el siguiente fotograma clave será en 9.5. Si el tiempo se acelera de esta manera, podría terminar con fotogramas clave en 42.5, 47.5, 52.5, etc., en lugar de 40, 45, 50, 55. Por el contrario, si hay un cambio de escena en 5.5, habrá un fotograma clave en 5 y 5.5 será demasiado temprano para otro. Ffmpeg no le permite especificar "hacer un fotograma clave aquí si no hay cambio de escena en los próximos 30 fotogramas". Sin embargo, alguien que entienda C podría agregar esa opción.
Para el video de velocidad de cuadro variable, cuando no está transmitiendo en vivo como Twitch, debería poder usar los cambios de escena sin convertir permanentemente a una velocidad de cuadro constante. Si usa el filtro 'select' en ffmpeg y usa la constante 'escena' en la expresión, entonces la salida de depuración (-v debug o presione '+' varias veces mientras codifica) muestra el número de cambio de escena. Esto es probablemente diferente y no tan útil como el número utilizado por x264, pero aún podría ser útil.
El procedimiento, entonces, probablemente sería hacer un video de prueba que sea solo para cambios de fotogramas clave, pero tal vez podría usarse para datos de control de velocidad si se usa 2 pasos. (No estoy seguro de si los datos generados son útiles para diferentes resoluciones y configuraciones; los datos del árbol de macrobloques no lo serán). Conviértalo a video de velocidad de fotogramas constante, pero vea este error sobre la tartamudez de salida al reducir a la mitad la velocidad de fotogramas si alguna vez decide usar el filtro fps para otros fines. Ejecútelo a través de x264 con el fotograma clave deseado y la configuración de GOP.
Luego, solo use estos tiempos de fotogramas clave con el video original de velocidad de cuadro variable.
Si permite contenido generado por el usuario completamente loco con un espacio de 20 segundos entre fotogramas, entonces para la codificación de velocidad de fotogramas variable, podría dividir la salida, usar el filtro fps, de alguna manera usar el filtro select (tal vez construir una expresión realmente larga que tenga cada tiempo de fotograma clave) ... o tal vez podría usar el video de prueba como entrada y decodificar solo fotogramas clave, si esa opción ffmpeg funciona, o usar el filtro de selección para seleccionar fotogramas clave. Luego escale al tamaño correcto (incluso hay un filtro scale2ref para esto) y superponga el video original en él. Luego use el filtro de intercalación para combinar estos fotogramas clave destinados a ser forzados con el video original. Si esto resulta en dos cuadros separados por 0.001 segundos que el filtro de intercalación no previene, entonces resuelva este problema usted mismo con otro filtro de selección. Tratar con los límites de la memoria intermedia de trama para el filtro intercalado podría ser el principal problema aquí. Todo esto podría funcionar: use algún tipo de filtro para amortiguar el flujo más denso (¿filtro de quince?); consulte el archivo de entrada varias veces para que se decodifique más de una vez y los marcos no tengan que almacenarse; use el filtro 'streamselect', que nunca he hecho, exactamente en el momento de los fotogramas clave; mejorar el filtro de intercalación cambiando su comportamiento predeterminado o agregando una opción para generar el marco más antiguo en un búfer en lugar de soltar un marco. que nunca he hecho, exactamente en los tiempos de los fotogramas clave; mejorar el filtro de intercalación cambiando su comportamiento predeterminado o agregando una opción para generar el marco más antiguo en un búfer en lugar de soltar un marco. que nunca he hecho, exactamente en los tiempos de los fotogramas clave; mejore el filtro de intercalación cambiando su comportamiento predeterminado o agregando una opción para generar el fotograma más antiguo en un búfer en lugar de soltar un fotograma.
fuente