mirror of
https://github.com/moonlight-stream/moonlight-embedded.git
synced 2025-07-01 15:25:35 +00:00
Add MMAL video decoder
This commit is contained in:
parent
70e54ef300
commit
922cd29adc
@ -85,9 +85,16 @@ if(BROADCOM_FOUND)
|
||||
aux_source_directory(./third_party/ilclient ILCLIENT_SRC_LIST)
|
||||
add_library(moonlight-pi SHARED ./src/video/pi.c ./src/audio/omx.c ${ILCLIENT_SRC_LIST})
|
||||
target_include_directories(moonlight-pi PRIVATE ./third_party/ilclient ${BROADCOM_INCLUDE_DIRS} ${GAMESTREAM_INCLUDE_DIR} ${MOONLIGHT_COMMON_INCLUDE_DIR} ${OPUS_INCLUDE_DIRS})
|
||||
target_link_libraries(moonlight-pi gamestream ${BROADCOM_LIBRARIES} ${OPUS_LIBRARY})
|
||||
set_property(TARGET moonlight-pi PROPERTY COMPILE_DEFINITIONS ${BROADCOM_DEFINITIONS})
|
||||
target_link_libraries(moonlight-pi gamestream ${BROADCOM_OMX_LIBRARIES} ${OPUS_LIBRARY})
|
||||
set_property(TARGET moonlight-pi PROPERTY COMPILE_DEFINITIONS ${BROADCOM_OMX_DEFINITIONS})
|
||||
install(TARGETS moonlight-pi DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
list(APPEND MOONLIGHT_DEFINITIONS HAVE_MMAL)
|
||||
list(APPEND MOONLIGHT_OPTIONS MMAL)
|
||||
add_library(moonlight-mmal SHARED ./src/video/mmal.c)
|
||||
target_include_directories(moonlight-mmal PRIVATE ${BROADCOM_INCLUDE_DIRS} ${GAMESTREAM_INCLUDE_DIR} ${MOONLIGHT_COMMON_INCLUDE_DIR})
|
||||
target_link_libraries(moonlight-mmal gamestream ${BROADCOM_MMAL_LIBRARIES})
|
||||
install(TARGETS moonlight-mmal DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
|
||||
if(FREESCALE_FOUND)
|
||||
|
@ -28,9 +28,28 @@ find_library(BCM_HOST_LIBRARY
|
||||
PATHS /opt/vc/lib)
|
||||
mark_as_advanced(BCM_HOST_LIBRARY)
|
||||
|
||||
find_library(MMAL_CORE_LIBRARY
|
||||
NAMES libmmal_core.so
|
||||
DOC "Path to MMAL Core Library"
|
||||
PATHS /opt/vc/lib)
|
||||
mark_as_advanced(MMAL_CORE_LIBRARY)
|
||||
|
||||
find_library(MMAL_UTIL_LIBRARY
|
||||
NAMES libmmal_util.so
|
||||
DOC "Path to MMAL Util Library"
|
||||
PATHS /opt/vc/lib)
|
||||
mark_as_advanced(MMAL_UTIL_LIBRARY)
|
||||
|
||||
find_library(MMAL_VC_CLIENT_LIBRARY
|
||||
NAMES libmmal_vc_client.so
|
||||
DOC "Path to MMAL Client Library"
|
||||
PATHS /opt/vc/lib)
|
||||
mark_as_advanced(MMAL_VC_CLIENT_LIBRARY)
|
||||
|
||||
include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Broadcom DEFAULT_MSG BROADCOM_INCLUDE_DIR VCOS_LIBRARY VCHIQ_LIBRARY OPENMAXIL_LIBRARY BCM_HOST_LIBRARY)
|
||||
|
||||
set(BROADCOM_LIBRARIES ${BCM_HOST_LIBRARY} ${OPENMAXIL_LIBRARY} ${VCHIQ_LIBRARY} ${VCOS_LIBRARY})
|
||||
set(BROADCOM_OMX_LIBRARIES ${BCM_HOST_LIBRARY} ${OPENMAXIL_LIBRARY} ${VCHIQ_LIBRARY} ${VCOS_LIBRARY})
|
||||
set(BROADCOM_MMAL_LIBRARIES ${BCM_HOST_LIBRARY} ${VCOS_LIBRARY} ${MMAL_CORE_LIBRARY} ${MMAL_UTIL_LIBRARY} ${MMAL_VC_CLIENT_LIBRARY})
|
||||
set(BROADCOM_INCLUDE_DIRS ${BROADCOM_INCLUDE_DIR} ${BROADCOM_INCLUDE_DIR}/interface/vmcs_host/linux ${BROADCOM_INCLUDE_DIR}/interface/vcos/pthreads)
|
||||
set(BROADCOM_DEFINITIONS USE_VCHIQ_ARM HAVE_LIBOPENMAX=2 OMX OMX_SKIP64BIT USE_EXTERNAL_OMX HAVE_LIBBCM_HOST USE_EXTERNAL_LIBBCM_HOST)
|
||||
set(BROADCOM_OMX_DEFINITIONS USE_VCHIQ_ARM HAVE_LIBOPENMAX=2 OMX OMX_SKIP64BIT USE_EXTERNAL_OMX HAVE_LIBBCM_HOST USE_EXTERNAL_LIBBCM_HOST)
|
||||
|
@ -52,6 +52,13 @@ enum platform platform_check(char* name) {
|
||||
return PI;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_MMAL
|
||||
if (std || strcmp(name, "mmal") == 0) {
|
||||
void *handle = dlopen("libmoonlight-mmal.so", RTLD_NOW | RTLD_GLOBAL);
|
||||
if (handle != NULL && dlsym(RTLD_DEFAULT, "bcm_host_init") != NULL)
|
||||
return MMAL;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_AML
|
||||
if (std || strcmp(name, "aml") == 0) {
|
||||
void *handle = dlopen("libmoonlight-aml.so", RTLD_NOW | RTLD_GLOBAL);
|
||||
@ -101,7 +108,7 @@ void platform_start(enum platform system) {
|
||||
blank_fb("/sys/class/graphics/fb1/blank", true);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_PI
|
||||
#if defined(HAVE_PI) | defined(HAVE_MMAL)
|
||||
case PI:
|
||||
blank_fb("/sys/class/graphics/fb0/blank", true);
|
||||
break;
|
||||
@ -117,7 +124,7 @@ void platform_stop(enum platform system) {
|
||||
blank_fb("/sys/class/graphics/fb1/blank", false);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_PI
|
||||
#if defined(HAVE_PI) | defined(HAVE_MMAL)
|
||||
case PI:
|
||||
blank_fb("/sys/class/graphics/fb0/blank", false);
|
||||
break;
|
||||
@ -151,6 +158,10 @@ DECODER_RENDERER_CALLBACKS* platform_get_video(enum platform system) {
|
||||
case PI:
|
||||
return (PDECODER_RENDERER_CALLBACKS) dlsym(RTLD_DEFAULT, "decoder_callbacks_pi");
|
||||
#endif
|
||||
#ifdef HAVE_MMAL
|
||||
case MMAL:
|
||||
return (PDECODER_RENDERER_CALLBACKS) dlsym(RTLD_DEFAULT, "decoder_callbacks_mmal");
|
||||
#endif
|
||||
#ifdef HAVE_AML
|
||||
case AML:
|
||||
return (PDECODER_RENDERER_CALLBACKS) dlsym(RTLD_DEFAULT, "decoder_callbacks_aml");
|
||||
@ -199,6 +210,8 @@ char* platform_name(enum platform system) {
|
||||
switch(system) {
|
||||
case PI:
|
||||
return "Raspberry Pi (Broadcom)";
|
||||
case MMAL:
|
||||
return "Raspberry Pi (Broadcom) MMAL";
|
||||
case IMX:
|
||||
return "i.MX6 (MXC Vivante)";
|
||||
case AML:
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
#define IS_EMBEDDED(SYSTEM) SYSTEM != SDL
|
||||
|
||||
enum platform { NONE, SDL, X11, X11_VDPAU, X11_VAAPI, PI, IMX, AML, RK, FAKE };
|
||||
enum platform { NONE, SDL, X11, X11_VDPAU, X11_VAAPI, PI, MMAL, IMX, AML, RK, FAKE };
|
||||
|
||||
enum platform platform_check(char*);
|
||||
PDECODER_RENDERER_CALLBACKS platform_get_video(enum platform system);
|
||||
|
280
src/video/mmal.c
Normal file
280
src/video/mmal.c
Normal file
@ -0,0 +1,280 @@
|
||||
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Video decode on Raspberry Pi using MMAL
|
||||
// Based upon example code from the Raspberry Pi
|
||||
|
||||
#include <Limelight.h>
|
||||
|
||||
#include <sps.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <bcm_host.h>
|
||||
#include <interface/mmal/mmal.h>
|
||||
#include <interface/mmal/util/mmal_default_components.h>
|
||||
#include <interface/mmal/util/mmal_util_params.h>
|
||||
#include <interface/mmal/util/mmal_util.h>
|
||||
#include <interface/mmal/vc/mmal_vc_api.h>
|
||||
#include <interface/vcos/vcos.h>
|
||||
|
||||
#define MAX_DECODE_UNIT_SIZE 262144
|
||||
|
||||
#define ALIGN(x, a) (((x)+(a)-1)&~((a)-1))
|
||||
|
||||
static VCOS_SEMAPHORE_T semaphore;
|
||||
static MMAL_COMPONENT_T *decoder = NULL, *renderer = NULL;
|
||||
static MMAL_POOL_T *pool_in = NULL, *pool_out = NULL;
|
||||
|
||||
static void input_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf) {
|
||||
mmal_buffer_header_release(buf);
|
||||
|
||||
if (port == decoder->input[0])
|
||||
vcos_semaphore_post(&semaphore);
|
||||
}
|
||||
|
||||
static void control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf) {
|
||||
if (buf->cmd == MMAL_EVENT_ERROR) {
|
||||
MMAL_STATUS_T status = *(uint32_t *) buf->data;
|
||||
fprintf(stderr, "Video decode error MMAL_EVENT_ERROR:%d\n", status);
|
||||
}
|
||||
|
||||
mmal_buffer_header_release(buf);
|
||||
}
|
||||
|
||||
static void output_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf) {
|
||||
if (mmal_port_send_buffer(renderer->input[0], buf) != MMAL_SUCCESS) {
|
||||
fprintf(stderr, "Can't display decoded frame\n");
|
||||
mmal_buffer_header_release(buf);
|
||||
}
|
||||
}
|
||||
|
||||
static int decoder_renderer_setup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
|
||||
MMAL_STATUS_T status;
|
||||
|
||||
if (videoFormat != VIDEO_FORMAT_H264) {
|
||||
fprintf(stderr, "Video format not supported\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bcm_host_init();
|
||||
mmal_vc_init();
|
||||
gs_sps_init(width, height);
|
||||
|
||||
vcos_semaphore_create(&semaphore, "video_decoder", 1);
|
||||
if (mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &decoder) != MMAL_SUCCESS) {
|
||||
fprintf(stderr, "Can't create decoder\n");
|
||||
return -2;
|
||||
}
|
||||
|
||||
MMAL_ES_FORMAT_T *format_in = decoder->input[0]->format;
|
||||
format_in->type = MMAL_ES_TYPE_VIDEO;
|
||||
format_in->encoding = MMAL_ENCODING_H264;
|
||||
format_in->es->video.width = ALIGN(width, 32);
|
||||
format_in->es->video.height = ALIGN(height, 16);
|
||||
format_in->es->video.crop.width = width;
|
||||
format_in->es->video.crop.height = height;
|
||||
format_in->es->video.frame_rate.num = redrawRate;
|
||||
format_in->es->video.frame_rate.den = 1;
|
||||
format_in->es->video.par.num = 1;
|
||||
format_in->es->video.par.den = 1;
|
||||
format_in->flags = MMAL_ES_FORMAT_FLAG_FRAMED;
|
||||
|
||||
if (mmal_port_format_commit(decoder->input[0]) != MMAL_SUCCESS) {
|
||||
fprintf(stderr, "Can't commit input format to decoder\n");
|
||||
return -3;
|
||||
}
|
||||
|
||||
decoder->input[0]->buffer_num = 5;
|
||||
decoder->input[0]->buffer_size = MAX_DECODE_UNIT_SIZE;
|
||||
pool_in = mmal_port_pool_create(decoder->input[0], decoder->input[0]->buffer_num, decoder->output[0]->buffer_size);
|
||||
|
||||
MMAL_ES_FORMAT_T *format_out = decoder->output[0]->format;
|
||||
format_out->encoding = MMAL_ENCODING_OPAQUE;
|
||||
if (mmal_port_format_commit(decoder->output[0]) != MMAL_SUCCESS) {
|
||||
fprintf(stderr, "Can't commit output format to decoder\n");
|
||||
return -3;
|
||||
}
|
||||
|
||||
decoder->output[0]->buffer_num = 3;
|
||||
decoder->output[0]->buffer_size = decoder->output[0]->buffer_size_recommended;
|
||||
pool_out = mmal_port_pool_create(decoder->output[0], decoder->output[0]->buffer_num, decoder->output[0]->buffer_size);
|
||||
|
||||
if (mmal_port_enable(decoder->control, control_callback) != MMAL_SUCCESS) {
|
||||
fprintf(stderr, "Can't enable control port\n");
|
||||
return -4;
|
||||
}
|
||||
|
||||
if (mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &renderer) != MMAL_SUCCESS) {
|
||||
fprintf(stderr, "Can't create renderer\n");
|
||||
return -5;
|
||||
}
|
||||
|
||||
format_in = renderer->input[0]->format;
|
||||
format_in->encoding = MMAL_ENCODING_OPAQUE;
|
||||
format_in->es->video.width = width;
|
||||
format_in->es->video.height = height;
|
||||
format_in->es->video.crop.x = 0;
|
||||
format_in->es->video.crop.y = 0;
|
||||
format_in->es->video.crop.width = width;
|
||||
format_in->es->video.crop.height = height;
|
||||
if (mmal_port_format_commit(renderer->input[0]) != MMAL_SUCCESS) {
|
||||
fprintf(stderr, "Can't set output format\n");
|
||||
return -6;
|
||||
}
|
||||
|
||||
MMAL_DISPLAYREGION_T param;
|
||||
param.hdr.id = MMAL_PARAMETER_DISPLAYREGION;
|
||||
param.hdr.size = sizeof(MMAL_DISPLAYREGION_T);
|
||||
param.set = MMAL_DISPLAY_SET_LAYER | MMAL_DISPLAY_SET_NUM | MMAL_DISPLAY_SET_FULLSCREEN;
|
||||
param.layer = 128;
|
||||
param.display_num = 0;
|
||||
param.fullscreen = true;
|
||||
|
||||
if (mmal_port_parameter_set(renderer->input[0], ¶m.hdr) != MMAL_SUCCESS) {
|
||||
fprintf(stderr, "Can't set parameters\n");
|
||||
return -7;
|
||||
}
|
||||
|
||||
if (mmal_port_enable(renderer->control, control_callback) != MMAL_SUCCESS) {
|
||||
fprintf(stderr, "Can't enable control port\n");
|
||||
return -8;
|
||||
}
|
||||
|
||||
if (mmal_component_enable(renderer) != MMAL_SUCCESS) {
|
||||
fprintf(stderr, "Can't enable renderer\n");
|
||||
return -9;
|
||||
}
|
||||
|
||||
if (mmal_port_enable(renderer->input[0], input_callback) != MMAL_SUCCESS) {
|
||||
fprintf(stderr, "Can't enable renderer input port\n");
|
||||
return -10;
|
||||
}
|
||||
|
||||
if (mmal_port_enable(decoder->input[0], input_callback) != MMAL_SUCCESS) {
|
||||
fprintf(stderr, "Can't enable decoder input port\n");
|
||||
return -11;
|
||||
}
|
||||
|
||||
if (mmal_port_enable(decoder->output[0], output_callback) != MMAL_SUCCESS) {
|
||||
fprintf(stderr, "Can't enable decoder output port\n");
|
||||
return -12;
|
||||
}
|
||||
|
||||
if (mmal_component_enable(decoder) != MMAL_SUCCESS) {
|
||||
fprintf(stderr, "Can't enable decoder\n");
|
||||
return -13;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void decoder_renderer_cleanup() {
|
||||
if (decoder)
|
||||
mmal_component_destroy(decoder);
|
||||
|
||||
if (renderer)
|
||||
mmal_component_destroy(renderer);
|
||||
|
||||
if (pool_in)
|
||||
mmal_pool_destroy(pool_in);
|
||||
|
||||
if (pool_out)
|
||||
mmal_pool_destroy(pool_out);
|
||||
|
||||
vcos_semaphore_delete(&semaphore);
|
||||
}
|
||||
|
||||
static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) {
|
||||
MMAL_STATUS_T status;
|
||||
MMAL_BUFFER_HEADER_T *buf = NULL;
|
||||
PLENTRY entry = decodeUnit->bufferList;
|
||||
bool first_entry = false;
|
||||
|
||||
while (entry != NULL) {
|
||||
if (buf == NULL) {
|
||||
vcos_semaphore_wait(&semaphore);
|
||||
if ((buf = mmal_queue_get(pool_in->queue)) != NULL) {
|
||||
buf->flags = 0;
|
||||
buf->offset = 0;
|
||||
buf->pts = buf->dts = MMAL_TIME_UNKNOWN;
|
||||
} else {
|
||||
fprintf(stderr, "Video buffer full\n");
|
||||
return DR_NEED_IDR;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry->bufferType != BUFFER_TYPE_PICDATA)
|
||||
buf->flags |= MMAL_BUFFER_HEADER_FLAG_CONFIG;
|
||||
else if (!first_entry) {
|
||||
buf->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_START;
|
||||
first_entry = true;
|
||||
}
|
||||
|
||||
if (entry->bufferType == BUFFER_TYPE_SPS)
|
||||
gs_sps_fix(entry, GS_SPS_BITSTREAM_FIXUP, buf->data, &buf->length);
|
||||
else {
|
||||
if (entry->length + buf->length > buf->alloc_size) {
|
||||
fprintf(stderr, "Video decoder buffer too small\n");
|
||||
mmal_buffer_header_release(buf);
|
||||
return DR_NEED_IDR;
|
||||
}
|
||||
memcpy(buf->data + buf->length, entry->data, entry->length);
|
||||
buf->length += entry->length;
|
||||
}
|
||||
|
||||
if (entry->bufferType != BUFFER_TYPE_PICDATA || entry->next == NULL || entry->next->bufferType != BUFFER_TYPE_PICDATA) {
|
||||
buf->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END;
|
||||
if ((status = mmal_port_send_buffer(decoder->input[0], buf)) != MMAL_SUCCESS) {
|
||||
mmal_buffer_header_release(buf);
|
||||
return DR_NEED_IDR;
|
||||
}
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
//Send available output buffers to decoder
|
||||
while ((buf = mmal_queue_get(pool_out->queue))) {
|
||||
if ((status = mmal_port_send_buffer(decoder->output[0], buf)) != MMAL_SUCCESS)
|
||||
mmal_buffer_header_release(buf);
|
||||
}
|
||||
|
||||
return DR_OK;
|
||||
}
|
||||
|
||||
DECODER_RENDERER_CALLBACKS decoder_callbacks_mmal = {
|
||||
.setup = decoder_renderer_setup,
|
||||
.cleanup = decoder_renderer_cleanup,
|
||||
.submitDecodeUnit = decoder_renderer_submit_decode_unit,
|
||||
.capabilities = CAPABILITY_DIRECT_SUBMIT,
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user