introducción
Ubuntu
Continuando con "Mejora de la reproducción de video del motor axmol: compatibilidad con la reproducción de video de Android", este artículo describe principalmente cómo admitir la representación de video para la reproducción de texturas en la famosa distribución de Linux . A menos que se especifique lo contrario, Linux
todas las referencias en las siguientes descripciones se refieren a Ubuntu Linux
la versión Ubuntu 22.04+
.
¿Por qué desarrollar?
Después de que el autor completó con éxito la renderización de texturas de video de Android, la única plataforma compatible con el motor axmol (macos, windows, ios/tvos, android, linux) fue Linux, así que pensé, por cierto, ¿por qué no admitir Linux?
Investigación
Después de la investigación, se descubrió que entre los mejores reproductores en Linux, VLC proporciona libvlc
autorización LGPL-2.1 (uso comercial gratuito en forma de biblioteca dinámica sin modificar el código fuente), por lo que la integración libvlc
es una mejor solución.
Como alcanzar
Sigue siendo la interfaz que implementa axmol MediaEngine
, pero usamos libvlc
como backend
.
-
Instalar el paquete de desarrollo libvlc
sudo apt install libvlc-dev libvlccore-dev vlc
Entre ellos
libvlc-dev
, ylibvlccore-dev
son necesarios para la compilación y la conexión, y la instalaciónvlc
es en realidad instalar el reproductor y el complemento. Entonces, el reproductor no lo necesita y el complemento es necesario para ejecutarse. De lo contrario, el video no se podrá ver. descifrado.
CONSEJOS: Reglas ocultas para la carga de complementos:- De forma predeterminada, al llamar
libvlc_new
a la API, libvlc buscará el complemento de decodificación necesario para reproducir el video desde el directoriolibvlc.so
dondelibvlccore.so
se encuentra la biblioteca .plugins
La instalaciónvlc
pondrá el complemento en la ruta correcta. - A través de variables de entorno:
VLC_PLUGIN_PATH
especifiquelibvlc
la ruta para cargar el complemento- Linux
setenv
se puede configurar dinámicamente a través de API:setenv("VLC_PLUGIN_PATH", "/path/to/vlc/plugins", true);
- Windows se puede configurar a través de API
_putenv_s
, pero se debe prestar especial atención en función de la biblioteca de tiempo de ejecución de clibvlc.dll
ylibvlccore.dll
. La biblioteca oficial precompilada libvlc usa libvlcmsvcrt
, lo que significa que en el sistema win10, las llamadas directas_putenv_s
no son válidas. Las llamadas directas_putenv_s
generalmente se configuranucrt
en Cuando las variables de entorno coexistenmsvcrt
conucrtbased/ucrtbase
diferentes bibliotecas de tiempo de ejecución de C, la memoria está aislada. Si desea que ambas bibliotecas de tiempo de ejecución surtan efecto, puede configurarlas de la siguiente manera:_putenv_s("VLC_PLUGIN_PATH", R"(D:\dev\axmol\thirdparty\vlc\win\lib\plugins)"); HMODULE hmsvcrt = GetModuleHandleW(L"msvcrt.dll"); auto msvcrt_getenv = (decltype(getenv)*)GetProcAddress(hmsvcrt, "getenv"); if (msvcrt_getenv) { auto msvcrt_putenv_s = (decltype(_putenv_s)*)GetProcAddress(hmsvcrt, "_putenv_s"); if (msvcrt_putenv_s) msvcrt_putenv_s("VLC_PLUGIN_PATH", R"(D:\dev\axmol\thirdparty\vlc\win\lib\plugins)"); }
- Linux
- De forma predeterminada, al llamar
-
Escriba código para implementar
MediaEngine
funciones principales, como reproducir, pausar, etc., registrar devoluciones de llamadas (eventos multimedia, eventos de fotograma NV12 de video) y otras funciones. -
Con respecto a cómo obtener datos de video NV12 decodificados por VLC (principalmente RGBA en Internet), este artículo solo publica el código clave
libvlc
En la devolución de llamada de bloqueo, bloquee la memoria de este cuadro de datos de video para escribir:static constexpr auto VLC_OUTPUT_FORMAT = ax::MEVideoPixelFormat::NV12; void* VlcMediaEngine::libvlc_video_lock(void* data, void** p_pixels) { VlcMediaEngine* mediaEngine = static_cast<VlcMediaEngine*>(data); auto& bufferDim = mediaEngine->_videoDim; auto& outputBuffer = mediaEngine->_frameBuffer1; mediaEngine->_frameBuffer1Mtx.lock(); if constexpr (VLC_OUTPUT_FORMAT == ax::MEVideoPixelFormat::NV12) { outputBuffer.resize_fit(bufferDim.x * bufferDim.y + (bufferDim.x * bufferDim.y >> 1)); // NV12 p_pixels[0] = outputBuffer.data(); p_pixels[1] = outputBuffer.data() + (bufferDim.x * bufferDim.y); } else if constexpr (VLC_OUTPUT_FORMAT == ax::MEVideoPixelFormat::YUY2) { outputBuffer.resize_fit(bufferDim.x * bufferDim.y + ((bufferDim.x >> 1) * bufferDim.y * 4)); // YUY2 p_pixels[0] = outputBuffer.data(); } else { outputBuffer.resize_fit(bufferDim.x * bufferDim.y * 4); // RGBA32 p_pixels[0] = outputBuffer.data(); } return nullptr; } void VlcMediaEngine::libvlc_video_unlock(void* data, void* id, void* const* p_pixels) { VlcMediaEngine* mediaEngine = static_cast<VlcMediaEngine*>(data); mediaEngine->_frameBuffer1Mtx.unlock(); ++mediaEngine->_frameIndex; assert(id == nullptr); }
libvlc
Al utilizar el formato del modo de devolución de llamada, vale la pena señalar que NV12 necesita especificar el segundoplane
(pitch
bytesPorfila) ylines
(altura de representación esperada del video/2)unsigned int VlcMediaEngine::libvlc_video_format_setup(void** opaque, char* chroma, // forcc, refer to:vlc_fourcc.h unsigned* width, unsigned* height, unsigned* pitches, unsigned* lines) { // refer to: vmem.c:Open https://github.com/videolan/vlc/blob/3.0.18/modules/video_output/vmem.c#L150 // future: 4.0: will be widths, heights: // https://github.com/videolan/vlc/blob/master/modules/video_output/vmem.c#L156 VlcMediaEngine* mediaEngine = static_cast<VlcMediaEngine*>(*opaque); // vlc tell us the original codecDim(ALIGNED) mediaEngine->_codecDim.set(width[0], height[0]); // tell vlc we want render as video size width[0] = mediaEngine->_videoDim.x; height[0] = mediaEngine->_videoDim.y; // plane0 pitches[0] = width[0]; // bytesPerRow lines[0] = height[0]; // rows # if LIBVLC_VERSION_MAJOR >= 4 mediaEngine->_videoDim.set(width[1], height[1]); # endif int num_of_plane = 1; if constexpr (VLC_OUTPUT_FORMAT == ax::MEVideoPixelFormat::NV12) { memcpy(chroma, "NV12", 4); // plane1 pitches[1] = mediaEngine->_videoDim.x; // bytesPerRow lines[1] = mediaEngine->_videoDim.y >> 1; // rows num_of_plane = 2; } else if constexpr (VLC_OUTPUT_FORMAT == ax::MEVideoPixelFormat::YUY2) { memcpy(chroma, "YUY2", 4); pitches[0] = width[0] * 2; // bytesPerRow } else { memcpy(chroma, "RGBA", 4); pitches[0] = width[0] * 4; // bytesPerRow } // return the number of picture buffers allocated, 0 indicates failure return num_of_plane; }
Operación y precauciones
Descargue el código fuente más reciente del motor axmolUbuntu 22.04+
para compilarlo y ejecutarlo en el sistema. Si encuentra el problema de no poder decodificar al reproducir un video, instálelo con ubuntu扩展组件
el siguiente comando:
sudo apt install ubuntu-restricted-extras
Conclusión
Desde entonces, el motor axmol ui::MediaPlayer
ha admitido la representación y reproducción de texturas de video en todas las plataformas, lo que también se ha beneficiado del MediaEngine
marco rediseñado, que no solo puede axmol
funcionar en el motor, sino que también se puede compilar de forma independiente, como el ejemplo escrito de reproducción de video bgfx. por el autor: bgfx -axplay .
Además: libvlc
es multiplataforma en sí, por lo que la implementación de este artículo VlcMediaEngine
también puede ejecutarse en otras plataformas después de una configuración simple, comoWindows