mirror of
https://github.com/moonlight-stream/moonlight-embedded.git
synced 2025-07-02 07:45:48 +00:00
Output video using OMX Raspberry Pi
This commit is contained in:
parent
de74c11828
commit
f231f0a8e0
@ -5,9 +5,12 @@ SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
|||||||
|
|
||||||
aux_source_directory(./common/limelight-common SRC_LIST)
|
aux_source_directory(./common/limelight-common SRC_LIST)
|
||||||
aux_source_directory(./common/limelight-common/OpenAES SRC_LIST)
|
aux_source_directory(./common/limelight-common/OpenAES SRC_LIST)
|
||||||
|
aux_source_directory(./ilclient SRC_LIST)
|
||||||
|
|
||||||
aux_source_directory(./src SRC_LIST)
|
aux_source_directory(./src SRC_LIST)
|
||||||
|
|
||||||
include_directories(./common)
|
include_directories(./common)
|
||||||
|
include_directories(./ilclient)
|
||||||
|
|
||||||
add_executable(moonlight ${SRC_LIST})
|
add_executable(moonlight ${SRC_LIST})
|
||||||
set_property(TARGET moonlight PROPERTY C_STANDARD 11)
|
set_property(TARGET moonlight PROPERTY C_STANDARD 11)
|
||||||
@ -18,9 +21,11 @@ find_package(OpenSSL)
|
|||||||
find_package(EXPAT)
|
find_package(EXPAT)
|
||||||
find_package(ALSA)
|
find_package(ALSA)
|
||||||
find_package(Opus)
|
find_package(Opus)
|
||||||
|
find_package(Broadcom)
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(EVDEV libevdev)
|
pkg_check_modules(EVDEV libevdev)
|
||||||
|
|
||||||
include_directories(./moonlight-common-c ${OPUS_INCLUDE_DIRS} ${EVDEV_INCLUDE_DIRS})
|
include_directories(./moonlight-common-c ${OPUS_INCLUDE_DIRS} ${EVDEV_INCLUDE_DIRS} ${BROADCOM_INCLUDE_DIRS})
|
||||||
target_link_libraries (moonlight PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${EVDEV_LIBRARIES} ${ALSA_LIBRARY} ${OPUS_LIBRARY})
|
target_link_libraries (moonlight PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${EVDEV_LIBRARIES} ${ALSA_LIBRARY} ${OPUS_LIBRARY} ${BROADCOM_LIBRARIES})
|
||||||
|
set_property(TARGET moonlight PROPERTY COMPILE_DEFINITIONS ${BROADCOM_DEFINITIONS})
|
||||||
|
36
cmake/FindBroadcom.cmake
Normal file
36
cmake/FindBroadcom.cmake
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
find_path(BROADCOM_INCLUDE_DIR
|
||||||
|
NAMES bcm_host.h
|
||||||
|
DOC "Broadcom include directory"
|
||||||
|
PATHS /opt/vc/include)
|
||||||
|
mark_as_advanced(BCM_INCLUDE_DIR)
|
||||||
|
|
||||||
|
find_library(VCOS_LIBRARY
|
||||||
|
NAMES libvcos.so
|
||||||
|
DOC "Path to VCOS Library"
|
||||||
|
PATHS /opt/vc/lib)
|
||||||
|
mark_as_advanced(VCOS_LIBRARY)
|
||||||
|
|
||||||
|
find_library(VCHIQ_LIBRARY
|
||||||
|
NAMES libvchiq_arm.so
|
||||||
|
DOC "Path to VCHIQ Library"
|
||||||
|
PATHS /opt/vc/lib)
|
||||||
|
mark_as_advanced(VCHIQ_LIBRARY)
|
||||||
|
|
||||||
|
find_library(OPENMAXIL_LIBRARY
|
||||||
|
NAMES libopenmaxil.so
|
||||||
|
DOC "Path to OpenMAX IL Library"
|
||||||
|
PATHS /opt/vc/lib)
|
||||||
|
mark_as_advanced(OPENMAXIL_LIBRARY)
|
||||||
|
|
||||||
|
find_library(BCM_HOST_LIBRARY
|
||||||
|
NAMES libbcm_host.so
|
||||||
|
DOC "Path to Broadcom Host Library"
|
||||||
|
PATHS /opt/vc/lib)
|
||||||
|
mark_as_advanced(BCM_HOST_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_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)
|
1836
ilclient/ilclient.c
Normal file
1836
ilclient/ilclient.c
Normal file
File diff suppressed because it is too large
Load Diff
1039
ilclient/ilclient.h
Normal file
1039
ilclient/ilclient.h
Normal file
File diff suppressed because it is too large
Load Diff
308
ilclient/ilcore.c
Normal file
308
ilclient/ilcore.c
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* \file
|
||||||
|
*
|
||||||
|
* \brief Host core implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
//includes
|
||||||
|
#include <memory.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "IL/OMX_Component.h"
|
||||||
|
#include "interface/vcos/vcos.h"
|
||||||
|
|
||||||
|
#include "interface/vmcs_host/vcilcs.h"
|
||||||
|
#include "interface/vmcs_host/vchost.h"
|
||||||
|
#include "interface/vmcs_host/vcilcs_common.h"
|
||||||
|
|
||||||
|
static int coreInit = 0;
|
||||||
|
static int nActiveHandles = 0;
|
||||||
|
static ILCS_SERVICE_T *ilcs_service = NULL;
|
||||||
|
static VCOS_MUTEX_T lock;
|
||||||
|
static VCOS_ONCE_T once = VCOS_ONCE_INIT;
|
||||||
|
|
||||||
|
/* Atomic creation of lock protecting shared state */
|
||||||
|
static void initOnce(void)
|
||||||
|
{
|
||||||
|
VCOS_STATUS_T status;
|
||||||
|
status = vcos_mutex_create(&lock, VCOS_FUNCTION);
|
||||||
|
vcos_demand(status == VCOS_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OMX_Init */
|
||||||
|
OMX_ERRORTYPE OMX_APIENTRY OMX_Init(void)
|
||||||
|
{
|
||||||
|
VCOS_STATUS_T status;
|
||||||
|
OMX_ERRORTYPE err = OMX_ErrorNone;
|
||||||
|
|
||||||
|
status = vcos_once(&once, initOnce);
|
||||||
|
vcos_demand(status == VCOS_SUCCESS);
|
||||||
|
|
||||||
|
vcos_mutex_lock(&lock);
|
||||||
|
|
||||||
|
if(coreInit == 0)
|
||||||
|
{
|
||||||
|
// we need to connect via an ILCS connection to VideoCore
|
||||||
|
VCHI_INSTANCE_T initialise_instance;
|
||||||
|
VCHI_CONNECTION_T *connection;
|
||||||
|
ILCS_CONFIG_T config;
|
||||||
|
|
||||||
|
vc_host_get_vchi_state(&initialise_instance, &connection);
|
||||||
|
|
||||||
|
vcilcs_config(&config);
|
||||||
|
|
||||||
|
ilcs_service = ilcs_init((VCHIQ_INSTANCE_T) initialise_instance, (void **) &connection, &config, 0);
|
||||||
|
|
||||||
|
if(ilcs_service == NULL)
|
||||||
|
{
|
||||||
|
err = OMX_ErrorHardware;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
coreInit = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
coreInit++;
|
||||||
|
|
||||||
|
end:
|
||||||
|
vcos_mutex_unlock(&lock);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OMX_Deinit */
|
||||||
|
OMX_ERRORTYPE OMX_APIENTRY OMX_Deinit(void)
|
||||||
|
{
|
||||||
|
if(coreInit == 0) // || (coreInit == 1 && nActiveHandles > 0))
|
||||||
|
return OMX_ErrorNotReady;
|
||||||
|
|
||||||
|
vcos_mutex_lock(&lock);
|
||||||
|
|
||||||
|
coreInit--;
|
||||||
|
|
||||||
|
if(coreInit == 0)
|
||||||
|
{
|
||||||
|
// we need to teardown the ILCS connection to VideoCore
|
||||||
|
ilcs_deinit(ilcs_service);
|
||||||
|
ilcs_service = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
vcos_mutex_unlock(&lock);
|
||||||
|
|
||||||
|
return OMX_ErrorNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* OMX_ComponentNameEnum */
|
||||||
|
OMX_ERRORTYPE OMX_APIENTRY OMX_ComponentNameEnum(
|
||||||
|
OMX_OUT OMX_STRING cComponentName,
|
||||||
|
OMX_IN OMX_U32 nNameLength,
|
||||||
|
OMX_IN OMX_U32 nIndex)
|
||||||
|
{
|
||||||
|
if(ilcs_service == NULL)
|
||||||
|
return OMX_ErrorBadParameter;
|
||||||
|
|
||||||
|
return vcil_out_component_name_enum(ilcs_get_common(ilcs_service), cComponentName, nNameLength, nIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* OMX_GetHandle */
|
||||||
|
OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle(
|
||||||
|
OMX_OUT OMX_HANDLETYPE* pHandle,
|
||||||
|
OMX_IN OMX_STRING cComponentName,
|
||||||
|
OMX_IN OMX_PTR pAppData,
|
||||||
|
OMX_IN OMX_CALLBACKTYPE* pCallBacks)
|
||||||
|
{
|
||||||
|
OMX_ERRORTYPE eError;
|
||||||
|
OMX_COMPONENTTYPE *pComp;
|
||||||
|
OMX_HANDLETYPE hHandle = 0;
|
||||||
|
|
||||||
|
if (pHandle == NULL || cComponentName == NULL || pCallBacks == NULL || ilcs_service == NULL)
|
||||||
|
{
|
||||||
|
if(pHandle)
|
||||||
|
*pHandle = NULL;
|
||||||
|
return OMX_ErrorBadParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
pComp = (OMX_COMPONENTTYPE *)malloc(sizeof(OMX_COMPONENTTYPE));
|
||||||
|
if (!pComp)
|
||||||
|
{
|
||||||
|
vcos_assert(0);
|
||||||
|
return OMX_ErrorInsufficientResources;
|
||||||
|
}
|
||||||
|
memset(pComp, 0, sizeof(OMX_COMPONENTTYPE));
|
||||||
|
hHandle = (OMX_HANDLETYPE)pComp;
|
||||||
|
pComp->nSize = sizeof(OMX_COMPONENTTYPE);
|
||||||
|
pComp->nVersion.nVersion = OMX_VERSION;
|
||||||
|
eError = vcil_out_create_component(ilcs_get_common(ilcs_service), hHandle, cComponentName);
|
||||||
|
|
||||||
|
if (eError == OMX_ErrorNone) {
|
||||||
|
// Check that all function pointers have been filled in.
|
||||||
|
// All fields should be non-zero.
|
||||||
|
int i;
|
||||||
|
uint32_t *p = (uint32_t *) pComp;
|
||||||
|
for(i=0; i<sizeof(OMX_COMPONENTTYPE)>>2; i++)
|
||||||
|
if(*p++ == 0)
|
||||||
|
eError = OMX_ErrorInvalidComponent;
|
||||||
|
|
||||||
|
if(eError != OMX_ErrorNone && pComp->ComponentDeInit)
|
||||||
|
pComp->ComponentDeInit(hHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eError == OMX_ErrorNone) {
|
||||||
|
eError = pComp->SetCallbacks(hHandle,pCallBacks,pAppData);
|
||||||
|
if (eError != OMX_ErrorNone)
|
||||||
|
pComp->ComponentDeInit(hHandle);
|
||||||
|
}
|
||||||
|
if (eError == OMX_ErrorNone) {
|
||||||
|
*pHandle = hHandle;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*pHandle = NULL;
|
||||||
|
free(pComp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eError == OMX_ErrorNone) {
|
||||||
|
vcos_mutex_lock(&lock);
|
||||||
|
nActiveHandles++;
|
||||||
|
vcos_mutex_unlock(&lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return eError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OMX_FreeHandle */
|
||||||
|
OMX_ERRORTYPE OMX_APIENTRY OMX_FreeHandle(
|
||||||
|
OMX_IN OMX_HANDLETYPE hComponent)
|
||||||
|
{
|
||||||
|
OMX_ERRORTYPE eError = OMX_ErrorNone;
|
||||||
|
OMX_COMPONENTTYPE *pComp;
|
||||||
|
|
||||||
|
if (hComponent == NULL || ilcs_service == NULL)
|
||||||
|
return OMX_ErrorBadParameter;
|
||||||
|
|
||||||
|
pComp = (OMX_COMPONENTTYPE*)hComponent;
|
||||||
|
|
||||||
|
if (ilcs_service == NULL)
|
||||||
|
return OMX_ErrorBadParameter;
|
||||||
|
|
||||||
|
eError = (pComp->ComponentDeInit)(hComponent);
|
||||||
|
if (eError == OMX_ErrorNone) {
|
||||||
|
vcos_mutex_lock(&lock);
|
||||||
|
--nActiveHandles;
|
||||||
|
vcos_mutex_unlock(&lock);
|
||||||
|
free(pComp);
|
||||||
|
}
|
||||||
|
|
||||||
|
vcos_assert(nActiveHandles >= 0);
|
||||||
|
|
||||||
|
return eError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OMX_SetupTunnel */
|
||||||
|
OMX_ERRORTYPE OMX_APIENTRY OMX_SetupTunnel(
|
||||||
|
OMX_IN OMX_HANDLETYPE hOutput,
|
||||||
|
OMX_IN OMX_U32 nPortOutput,
|
||||||
|
OMX_IN OMX_HANDLETYPE hInput,
|
||||||
|
OMX_IN OMX_U32 nPortInput)
|
||||||
|
{
|
||||||
|
OMX_ERRORTYPE eError = OMX_ErrorNone;
|
||||||
|
OMX_COMPONENTTYPE *pCompIn, *pCompOut;
|
||||||
|
OMX_TUNNELSETUPTYPE oTunnelSetup;
|
||||||
|
|
||||||
|
if ((hOutput == NULL && hInput == NULL) || ilcs_service == NULL)
|
||||||
|
return OMX_ErrorBadParameter;
|
||||||
|
|
||||||
|
oTunnelSetup.nTunnelFlags = 0;
|
||||||
|
oTunnelSetup.eSupplier = OMX_BufferSupplyUnspecified;
|
||||||
|
|
||||||
|
pCompOut = (OMX_COMPONENTTYPE*)hOutput;
|
||||||
|
|
||||||
|
if (hOutput){
|
||||||
|
eError = pCompOut->ComponentTunnelRequest(hOutput, nPortOutput, hInput, nPortInput, &oTunnelSetup);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eError == OMX_ErrorNone && hInput) {
|
||||||
|
pCompIn = (OMX_COMPONENTTYPE*)hInput;
|
||||||
|
eError = pCompIn->ComponentTunnelRequest(hInput, nPortInput, hOutput, nPortOutput, &oTunnelSetup);
|
||||||
|
|
||||||
|
if (eError != OMX_ErrorNone && hOutput) {
|
||||||
|
/* cancel tunnel request on output port since input port failed */
|
||||||
|
pCompOut->ComponentTunnelRequest(hOutput, nPortOutput, NULL, 0, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return eError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OMX_GetComponentsOfRole */
|
||||||
|
OMX_ERRORTYPE OMX_GetComponentsOfRole (
|
||||||
|
OMX_IN OMX_STRING role,
|
||||||
|
OMX_INOUT OMX_U32 *pNumComps,
|
||||||
|
OMX_INOUT OMX_U8 **compNames)
|
||||||
|
{
|
||||||
|
OMX_ERRORTYPE eError = OMX_ErrorNone;
|
||||||
|
|
||||||
|
*pNumComps = 0;
|
||||||
|
return eError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OMX_GetRolesOfComponent */
|
||||||
|
OMX_ERRORTYPE OMX_GetRolesOfComponent (
|
||||||
|
OMX_IN OMX_STRING compName,
|
||||||
|
OMX_INOUT OMX_U32 *pNumRoles,
|
||||||
|
OMX_OUT OMX_U8 **roles)
|
||||||
|
{
|
||||||
|
OMX_ERRORTYPE eError = OMX_ErrorNone;
|
||||||
|
|
||||||
|
*pNumRoles = 0;
|
||||||
|
return eError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OMX_GetDebugInformation */
|
||||||
|
OMX_ERRORTYPE OMX_GetDebugInformation (
|
||||||
|
OMX_OUT OMX_STRING debugInfo,
|
||||||
|
OMX_INOUT OMX_S32 *pLen)
|
||||||
|
{
|
||||||
|
if(ilcs_service == NULL)
|
||||||
|
return OMX_ErrorBadParameter;
|
||||||
|
|
||||||
|
return vcil_out_get_debug_information(ilcs_get_common(ilcs_service), debugInfo, pLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* File EOF */
|
||||||
|
|
206
src/video.c
206
src/video.c
@ -1,32 +1,123 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of Moonlight Embedded.
|
Copyright (c) 2012, Broadcom Europe Ltd
|
||||||
*
|
All rights reserved.
|
||||||
* Copyright (C) 2015 Iwan Timmer
|
|
||||||
*
|
Redistribution and use in source and binary forms, with or without
|
||||||
* Moonlight is free software; you can redistribute it and/or modify
|
modification, are permitted provided that the following conditions are met:
|
||||||
* it under the terms of the GNU General Public License as published by
|
* Redistributions of source code must retain the above copyright
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
notice, this list of conditions and the following disclaimer.
|
||||||
* (at your option) any later version.
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
*
|
notice, this list of conditions and the following disclaimer in the
|
||||||
* Moonlight is distributed in the hope that it will be useful,
|
documentation and/or other materials provided with the distribution.
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* Neither the name of the copyright holder nor the
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
names of its contributors may be used to endorse or promote products
|
||||||
* GNU General Public License for more details.
|
derived from this software without specific prior written permission.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
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 OpenMAX IL though the ilcient helper library
|
||||||
|
// Based upon video decode example from the Raspberry Pi firmware
|
||||||
|
|
||||||
#include "video.h"
|
#include "video.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "bcm_host.h"
|
||||||
|
#include "ilclient.h"
|
||||||
|
|
||||||
static FILE* fd;
|
#include <stdio.h>
|
||||||
static const char* fileName = "fake.h264";
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static TUNNEL_T tunnel[2];
|
||||||
|
static COMPONENT_T *list[3];
|
||||||
|
static ILCLIENT_T *client;
|
||||||
|
|
||||||
|
static COMPONENT_T *video_decode = NULL, *video_scheduler = NULL, *video_render = NULL;
|
||||||
|
|
||||||
|
static OMX_BUFFERHEADERTYPE *buf;
|
||||||
|
static unsigned char *dest;
|
||||||
|
|
||||||
|
static int port_settings_changed;
|
||||||
|
static int first_packet;
|
||||||
|
|
||||||
static void decoder_renderer_setup(int width, int height, int redrawRate, void* context, int drFlags) {
|
static void decoder_renderer_setup(int width, int height, int redrawRate, void* context, int drFlags) {
|
||||||
printf("decoder_renderer_setup %dx%d %dfps\n", width, height, redrawRate);
|
bcm_host_init();
|
||||||
fd = fopen(fileName, "w");
|
|
||||||
|
OMX_VIDEO_PARAM_PORTFORMATTYPE format;
|
||||||
|
OMX_TIME_CONFIG_CLOCKSTATETYPE cstate;
|
||||||
|
COMPONENT_T *clock = NULL;
|
||||||
|
unsigned int data_len = 0;
|
||||||
|
int packet_size = 80<<10;
|
||||||
|
|
||||||
|
memset(list, 0, sizeof(list));
|
||||||
|
memset(tunnel, 0, sizeof(tunnel));
|
||||||
|
|
||||||
|
if((client = ilclient_init()) == NULL) {
|
||||||
|
fprintf(stderr, "Can't initialize video\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(OMX_Init() != OMX_ErrorNone) {
|
||||||
|
fprintf(stderr, "Can't initialize OMX\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create video_decode
|
||||||
|
if(ilclient_create_component(client, &video_decode, "video_decode", ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS) != 0){
|
||||||
|
fprintf(stderr, "Can't create video decode\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
list[0] = video_decode;
|
||||||
|
|
||||||
|
// create video_render
|
||||||
|
if(ilclient_create_component(client, &video_render, "video_render", ILCLIENT_DISABLE_ALL_PORTS) != 0){
|
||||||
|
fprintf(stderr, "Can't create video renderer\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
list[1] = video_render;
|
||||||
|
|
||||||
|
set_tunnel(tunnel, video_decode, 131, video_render, 90);
|
||||||
|
|
||||||
|
ilclient_change_component_state(video_decode, OMX_StateIdle);
|
||||||
|
|
||||||
|
memset(&format, 0, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
|
||||||
|
format.nSize = sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE);
|
||||||
|
format.nVersion.nVersion = OMX_VERSION;
|
||||||
|
format.nPortIndex = 130;
|
||||||
|
format.eCompressionFormat = OMX_VIDEO_CodingAVC;
|
||||||
|
|
||||||
|
OMX_PARAM_DATAUNITTYPE unit;
|
||||||
|
|
||||||
|
memset(&unit, 0, sizeof(OMX_PARAM_DATAUNITTYPE));
|
||||||
|
unit.nSize = sizeof(OMX_PARAM_DATAUNITTYPE);
|
||||||
|
unit.nVersion.nVersion = OMX_VERSION;
|
||||||
|
unit.nPortIndex = 130;
|
||||||
|
unit.eUnitType = OMX_DataUnitCodedPicture;
|
||||||
|
unit.eEncapsulationType = OMX_DataEncapsulationElementaryStream;
|
||||||
|
|
||||||
|
if(OMX_SetParameter(ILC_GET_HANDLE(video_decode), OMX_IndexParamVideoPortFormat, &format) == OMX_ErrorNone &&
|
||||||
|
OMX_SetParameter(ILC_GET_HANDLE(video_decode), OMX_IndexParamBrcmDataUnit, &unit) == OMX_ErrorNone &&
|
||||||
|
ilclient_enable_port_buffers(video_decode, 130, NULL, NULL, NULL) == 0) {
|
||||||
|
|
||||||
|
port_settings_changed = 0;
|
||||||
|
first_packet = 1;
|
||||||
|
|
||||||
|
ilclient_change_component_state(video_decode, OMX_StateExecuting);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Can't setup video\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void decoder_renderer_start() {
|
static void decoder_renderer_start() {
|
||||||
@ -34,20 +125,83 @@ static void decoder_renderer_start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void decoder_renderer_stop() {
|
static void decoder_renderer_stop() {
|
||||||
printf("decoder_renderer_stop\n");
|
int status = 0;
|
||||||
|
|
||||||
|
buf->nFilledLen = 0;
|
||||||
|
buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS;
|
||||||
|
|
||||||
|
if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(list[0]), buf) != OMX_ErrorNone){
|
||||||
|
fprintf(stderr, "Can't empty video buffer\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// need to flush the renderer to allow video_decode to disable its input port
|
||||||
|
ilclient_flush_tunnels(tunnel, 0);
|
||||||
|
|
||||||
|
ilclient_disable_port_buffers(list[0], 130, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void decoder_renderer_release() {
|
static void decoder_renderer_release() {
|
||||||
printf("decoder_renderer_release\n");
|
ilclient_disable_tunnel(tunnel);
|
||||||
fclose(fd);
|
ilclient_teardown_tunnels(tunnel);
|
||||||
|
|
||||||
|
ilclient_state_transition(list, OMX_StateIdle);
|
||||||
|
ilclient_state_transition(list, OMX_StateLoaded);
|
||||||
|
|
||||||
|
ilclient_cleanup_components(list);
|
||||||
|
|
||||||
|
OMX_Deinit();
|
||||||
|
|
||||||
|
ilclient_destroy(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) {
|
static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) {
|
||||||
|
if((buf = ilclient_get_input_buffer(video_decode, 130, 1)) == NULL){
|
||||||
|
fprintf(stderr, "Can't get video buffer\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// feed data and wait until we get port settings changed
|
||||||
|
dest = buf->pBuffer;
|
||||||
|
|
||||||
|
buf->nFilledLen = 0;
|
||||||
|
|
||||||
|
buf->nOffset = 0;
|
||||||
|
|
||||||
|
buf->nFlags = OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS;
|
||||||
|
|
||||||
|
if(first_packet) {
|
||||||
|
buf->nFlags = OMX_BUFFERFLAG_STARTTIME;
|
||||||
|
first_packet = 0;
|
||||||
|
}
|
||||||
|
|
||||||
PLENTRY entry = decodeUnit->bufferList;
|
PLENTRY entry = decodeUnit->bufferList;
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
fwrite(entry->data, entry->length, 1, fd);
|
memcpy(dest, entry->data, entry->length);
|
||||||
|
buf->nFilledLen += entry->length;
|
||||||
|
dest += entry->length;
|
||||||
entry = entry->next;
|
entry = entry->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(port_settings_changed == 0 &&
|
||||||
|
((buf->nFilledLen > 0 && ilclient_remove_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0) ||
|
||||||
|
(buf->nFilledLen == 0 && ilclient_wait_for_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1,
|
||||||
|
ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10000) == 0))) {
|
||||||
|
port_settings_changed = 1;
|
||||||
|
|
||||||
|
if(ilclient_setup_tunnel(tunnel, 0, 0) != 0){
|
||||||
|
fprintf(stderr, "Can't setup video\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ilclient_change_component_state(video_render, OMX_StateExecuting);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone){
|
||||||
|
fprintf(stderr, "Can't empty video buffer\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
return DR_OK;
|
return DR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user