Estoy creando tutoriales cortos grabando mi pantalla (720p30fps). El contenido es solo una grabación del uso de algún software de escritorio, por lo que se mueve el mouse y se abren cuadros de diálogo, se escribe, se dibujan formas, etc. Después de la edición básica de la grabación de pantalla original, quiero codificar los videos en formatos webm y mp4 con exactamente la misma resolución y velocidad de fotogramas que grabé y quiero que la calidad de reproducción sea lo más cercana posible a la calidad de grabación original. Por lo tanto, no debería haber artefactos de compresión visibles después de la codificación final.
Respecto a la grabación original: La resolución es de 1280x720 píxeles. La velocidad de fotogramas es de 30 fotogramas por segundo. El software de grabación es Simple Screen Recorder. La codificación es H.264 con un factor de velocidad constante de 10 (lo suficientemente cerca como para no tener pérdidas) en un contenedor Matroska. La reproducción del original no muestra artefactos en absoluto.
Luego agrego algunos efectos muy básicos como fundidos cruzados y superposiciones de texto al MKV original usando Blender. Luego renderice en una secuencia de imágenes (formato PNG). Utilizo la exportación de imágenes de alta calidad desde Blender y, nuevamente, las imágenes de salida no muestran signos de artefactos de compresión.
El problema ocurre después de codificar la secuencia de imágenes en un video mp4 usando el codificador x264 con ffmpeg. A veces, algunas partes de algunos de los bordes duros/contornos de formas parpadean. Estos no son objetos en movimiento. Están inmóviles en el fondo en comparación con el lugar donde se mueve el mouse. Parece aleatorio. Por ejemplo, podría tener dos rectángulos amarillos uno al lado del otro, cada uno con un contorno negro y solo la parte superior de uno de los contornos del rectángulo parpadea durante algunos fotogramas y luego se detiene. Distrae un poco y es feo para lo que debería ser una codificación realmente limpia/fácil basada en una grabación de pantalla.
Generalmente veo esto por las líneas oscuras horizontales / bordes duros. De vez en cuando he visto similares para los bordes verticales.
Todavía no he notado este problema con los archivos webm de salida producidos por ffmpeg, solo con los archivos mp4 codificados x264. El comando ffmpeg que uso es así:
ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -pix_fmt yuv420p -movflags +faststart -crf 22 -r 30 -g 300 -y myvideo.mp4
Para webm, uso el mismo comando básico y el mismo valor crf, pero obviamente un codificador diferente (libvpx-vp9). El archivo webm tiene aproximadamente 9 MB o más por 2 minutos de metraje. El mp4 es de unos 3,5 MB. Generalmente, la calidad entre los dos es imposible de distinguir, solo en aquellos momentos en los que el mp4 tiene algunos segmentos de líneas duras que parpadean.
He ilustrado aproximadamente el problema a continuación usando arte ASCII, donde estoy tratando de mostrar un rectángulo en cuatro marcos. Al principio está bien, luego para algunos marcos, parte del contorno del rectángulo se dibuja con un poco de grosor adicional en algunas partes, lo que hace que parezca parpadear o moverse un poco. Luego vuelve a ser perfecto de nuevo.
-----------------
| |
-----------------
------=====------
| |
-----------------
______=====______
| |
-----------------
-----------------
| |
-----------------
Compara las siguientes imágenes. Observe en la segunda imagen que los 2 rectángulos inferiores tienen una línea gris adicional arriba o debajo de parte de su borde negro. Capturé estas imágenes mientras VLC estaba reproduciendo mi mp4 codificado x264 al 100% (sin escala). Este no es un ejemplo realmente dramático, pero es de esperar que sea suficiente para mostrar lo que está pasando. Debido a que las líneas adicionales aparecen y desaparecen, se crea una especie de efecto de parpadeo.
Notas:
ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -coder ac -pix_fmt yuv420p -movflags +faststart -crf 22 -bf 16 -b_strategy 2 -refs 16 -direct-pred spatial -me_method umh -me_range 16 -r 30 -g 300 -y myvideo.mp4
(Es más fácil notar los artefactos si alterna entre las dos imágenes en tamaño original)
¿Cómo se llama este tipo de artefacto de compresión?
¿Qué indicador puedo pasar ffmpeg para intentar suprimirlo?
Mucha experimentación con el CRF y los valores de velocidad. Para CRF he bajado a 18 y eso parece reducir un poco el parpadeo, pero no eliminarlo. Pero ese factor de velocidad parece demasiado bajo para obtener una codificación decente de contenido tan simple como una grabación de pantalla de acción baja en 720p.
También intenté establecer manualmente marcos b y marcos de referencia en valores entre 1 y 16, varí el tamaño de gop entre 30 y 300 y probé diferentes valores para la opción -me_method. Y probé un par de configuraciones de desentrelazado a través de la opción yadif, pero estoy bastante seguro de que eso no es relevante para este problema y solo parece empeorar la calidad del video de salida. Terminé con comandos ffmpeg que se parecen más a esto:
ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -coder ac -pix_fmt yuv420p -movflags +faststart -crf 22 -bf 16 -b_strategy 2 -refs 16 -direct-pred spatial -me_method umh -me_range 16 -r 30 -g 300 -y myvideo.mp4
Pero hasta ahora, solo variar el valor CRF ha tenido un efecto notable. No quiero bajar mucho más, porque va a aumentar demasiado el tamaño del video.
Usé el ejemplo anterior con LibreOffice Draw y una pantalla de 1280x720p para grabar un clip de aproximadamente 47 segundos en un archivo MKV codificado en H.264. Importé esto a Blender y lo exporté directamente como una secuencia de imágenes PNG, sin efectos ni ediciones. Luego ejecuté la secuencia de imágenes a través de ffmpeg con el codificador x264 para producir el archivo de video mp4.
Empecé a variar mi comando ffmpeg original un parámetro a la vez para ver la diferencia. Me concentré principalmente en el valor CRF, porque esa era la única forma en que definitivamente podía ver una reducción en los artefactos de compresión. Incluso con el CRF establecido en 10, todavía podía ver el extraño parpadeo/bandas en los bordes en un par de lugares. Finalmente, bajé el valor a 5 y no noté ningún artefacto en absoluto. El valor ideal es posiblemente entre 5 y 10 para este contenido.
Eso me dejó con un video que es demasiado grande para lo que es. Después de jugar con los valores del marco B y del marco de referencia para lograr reducciones marginales en el tamaño del archivo, finalmente volví a variar el valor de gop y eso tuvo un impacto relativamente grande. Establecer el gop en 300 en lugar de 30, básicamente redujo a la mitad el tamaño del archivo. Así que mi último comando ffmpeg fue este:
ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 5 -bf 16 -refs 16 -r 30 -g 300 -me_method umh -me_range 16 -y myvideo.mp4
(Actualización: originalmente publiqué el comando anterior como -crf 10... ahora corregido a -crf 5)
Los principales parámetros que eliminé fueron:
-pix_fmt yuv420p
(podría degradar la calidad)-coder ac
(No pude ver ningún impacto positivo con o sin esto)-b_strategy 2
(esto en realidad aumentó ligeramente el tamaño del archivo en algunos casos)-direct-pred spatial
(Absolutamente ningún impacto en la calidad/tamaño del archivo de salida que pude observar)Si estuviera entregando el archivo de salida a YouTube, consideraría volver a colocar -pix_fmt yuv420p
and -coder ac
y -flags cgop
, solo porque los recomiendan.
Estos parámetros produjeron una mejora/disminución marginal en el tamaño del archivo (como en fracciones de 1 MB):
-bf 16
-refs 16
-me_method umh -me_range 16
Puede ver la variación en el tamaño del archivo en la pantalla a continuación, donde nombré cada archivo de salida según los parámetros de ffmpeg que varié. Cualquier cosa que no tenga crf05 en el nombre manifiesta el problema de los artefactos.
Como comparación, ejecuté un comando similar para producir un archivo webm, pero con un valor CRF mucho peor/más alto. Con un valor CRF de 22, el archivo mp4 resultante tenía 1,4 MB sin artefactos de compresión perceptibles en absoluto. El comando ffmpeg que usé fue:
ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libvpx-vp9 -b:v 0 -tile-columns 2 -crf 22 -r 30 -g 300 -y myvideo.webm
Siguiendo las sugerencias de stib y Mulvya, probé las opciones y y varí el -tune
valor entre 5 y 10. Hice lo mismo para mis propios experimentos con las opciones y . La salida mp4, basada en mi video mkv de entrada, tenía artefactos de compresión visibles y parpadeantes en el mismo lugar hasta que bajé el crf a 6 cuando usaba , y a 5 con las opciones o cuando usaba-trellis
crf
-me_method
-bf
-trellis
-bf -refs
-tune
. Aquí hay capturas de pantalla que muestran la parte final de los artefactos que estoy tratando de eliminar mientras uso valores de CRF más altos. La primera pantalla es el video mkv de entrada, la segunda es un video mp4 codificado de muestra creado con la opción -trellis 0. Puede ver los artefactos en el borde superior de uno de los rectángulos. (También hay una banda gris gruesa en el fondo negro; sin embargo, eso no es un artefacto de compresión, creo que es un diálogo en proceso de desaparecer después de hacer clic en cancelar en mi grabación de demostración / muestra).
Aquí están los comandos y los tamaños de archivo resultantes
-tune animación:
ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 5 -tune animation -r 30 -g 300 -y myvideo.mp4
Tamaño: 2.757.370
Artefactos visibles: No
ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 6 -tune animation -r 30 -g 300 -y myvideo.mp4
Tamaño: 2,593,711
Artefactos visibles: Sí
-enrejado 0:
ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 6 -pix_fmt yuv420p -x264opts trellis=0 -r 30 -g 300 -y myvideo.mp4
Tamaño: 2.214.534 bytes
Artefactos visibles: No
ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 7 -pix_fmt yuv420p -x264opts trellis=0 -r 30 -g 300 -y myvideo.mp4
Tamaño: 2 074 544 bytes
Artefactos visibles: sí (aunque una cantidad minúscula, literalmente, unos pocos píxeles en una fracción de segundo)
-fast_skip 0:
ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 7 -pix_fmt yuv420p -x264opts fast_pskip=0 -r 30 -g 300 -y myvideo.mp4
Tamaño: 2.012.596 bytes
Artefactos visibles: No
ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 8 -pix_fmt yuv420p -x264opts fast_pskip=0 -r 30 -g 300 -y myvideo.mp4
Tamaño: 1.883.919 bytes
Artefactos visibles: Sí (cantidad muy pequeña/breve)
-psy 0 -fast_pskip 0:
ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 7 -pix_fmt yuv420p -x264opts psy=0:fast_pskip=0 -r 30 -g 300 -y myvideo.mp4
Tamaño: 1 886 919 bytes
Artefactos visibles: No
ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 8 -pix_fmt yuv420p -x264opts psy=0:fast_pskip=0 -r 30 -g 300 -y myvideo.mp4
Tamaño: 1.764.771 bytes
Artefactos visibles: Sí
-bf -refs:
ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 5 -bf 16 -refs 16 -r 30 -g 300 -me_method umh -me_range 16 -y myvideo.mp4
Tamaño: 2.257.420 bytes
Artefactos visibles: No
ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 6 -bf 16 -refs 16 -r 30 -g 300 -me_method umh -me_range 16 -y myvideo.mp4
Tamaño: 2 106 439 bytes
Artefactos visibles: Sí (aunque una cantidad minúscula)
-desbloquear:
ffmpeg -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -preset veryslow -crf 14 -pix_fmt yuv420p -x264opts fast_pskip=0:psy=0:deblock=-3,-3 -r 30 -g 300 -y myvideo.mp4
Tamaño: 982.549 bytes
Artefactos visibles: No
ffmpeg -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -preset veryslow -crf 14 -pix_fmt yuv420p -x264opts fast_pskip=0:psy=0:deblock=-3,-3 -bf 16 -refs 16 -me_method umh -me_range 64 -r 30 -g 300 -y myvideo.mp4
Tamaño: 961.460 bytes
Artefactos visibles: No
O el codificador vp9 es mucho mejor para manejar este tipo de contenido de video, o hay algún parámetro x264 que no conozco que mejoraría las cosas. ¿Alguien tiene alguna idea sobre una opción que pueda darle a ffmpeg para obtener un mejor resultado con x264/mp4? (Y no estoy tratando de iniciar una guerra de códecs, ¡necesito publicar en ambos formatos!)
El parámetro que parece tener el mayor impacto en la eliminación de este artefacto (por el tipo de contenido en la publicación original), al tiempo que permite valores de CRF más altos, es deblock
. El uso -deblock -3,-3
permitió un valor CRF de 14 con los artefactos completamente eliminados. El uso de valores CRF de 15 y 16 vuelve a introducir el artefacto, aunque en pequeñas cantidades y no se nota mucho a menos que lo esté buscando específicamente. También los valores de desbloqueo de -3 -1 y -3 -0 funcionaron razonablemente bien, pero no eliminaron el artefacto por completo en CRF 14.
El comando final fue:
ffmpeg -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -preset veryslow -crf 14 -pix_fmt yuv420p -x264opts fast_pskip=0:psy=0:deblock=-3,-3 -r 30 -g 300 -y myvideo.mp4
Para exprimir un poco más de kb de compresión, puede leer bf
refs
me_method umh
y agregar los me_range
parámetros. Pero descubrí que necesitaba el me_range
conjunto en 64. Los valores menores reintroducirían el artefacto de compresión.
Nota: Tuve cierto éxito con la variación aq-mode
y aq-strength
, pero eso no fue tan bueno como el desbloqueo para eliminar los artefactos.
Varíe el valor de CRF hacia abajo hasta que no vea artefactos de compresión. Vaya ridículamente bajo si es necesario, como CRF = 5.
Varíe el valor de GOP para compensar el mayor tamaño del archivo de salida. Por ejemplo, para video a 30 cuadros por segundo, intente gop=300
Su comando ffmpeg podría verse así:ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 5 -bf 16 -refs 16 -r 30 -g 300 -me_method umh -me_range 16 -y myvideo.mp4
Editar: (Usando la opción de velocidad correcta para x264, agregando pix_fmt y otras opciones x264)
ffmpeg -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -preset veryslow -crf 5 -pix_fmt yuv420p -x264opts fast_pskip=0:psy=0 -bf 16 -refs 16 -me_method umh -me_range 16 -r 30 -g 300 -y myvideo.mp4
-pix_fmt yuv420p -x264opts fast_pskip=0:psy=0
Respuesta actualizada en consecuencia.
Dr. Mayhem