omx audio backend, and dispmanx window

This commit is contained in:
Preston Smith 2016-03-02 00:48:34 -05:00
parent e5d8851316
commit 6f1fa1ab08
11 changed files with 479 additions and 0 deletions

View File

@ -160,6 +160,24 @@ s32 cfgLoadInt(const wchar * Section, const wchar * Key,s32 Default)
return cfgdb.get_int(string(Section), string(Key), Default);
}
void cfgSaveBool(const wchar * Section, const wchar * Key, bool Bool)
{
cfgdb.set_bool(string(Section), string(Key), Bool);
if(save_config)
{
savecfgf();
}
}
bool cfgLoadBool(const wchar * Section, const wchar * Key,bool Default)
{
if(!cfgdb.has_entry(string(Section), string(Key)))
{
cfgSaveBool(Section, Key, Default);
}
return cfgdb.get_bool(string(Section), string(Key), Default);
}
void cfgSetVirtual(const wchar * Section, const wchar * Key, const wchar * String)
{
cfgdb.set(string(Section), string(Key), string(String), true);

View File

@ -15,6 +15,8 @@ void cfgSaveInt(const wchar * lpSection, const wchar * lpKey, s32 Int);
void cfgLoadStr(const wchar * lpSection, const wchar * lpKey, wchar * lpReturn,const wchar* lpDefault);
string cfgLoadStr(const wchar * Section, const wchar * Key, const wchar* Default);
void cfgSaveStr(const wchar * lpSection, const wchar * lpKey, const wchar * lpString);
void cfgSaveBool(const wchar * Section, const wchar * Key, bool Bool);
bool cfgLoadBool(const wchar * Section, const wchar * Key,bool Default);
s32 cfgExists(const wchar * Section, const wchar * Key);
void cfgSetVirtual(const wchar * lpSection, const wchar * lpKey, const wchar * lpString);

View File

@ -0,0 +1,81 @@
#if defined(SUPPORT_DISPMANX)
#include "linux-dist/dispmanx.h"
#include "linux-dist/main.h"
#include <bcm_host.h>
#include <EGL/egl.h>
void dispmanx_window_create()
{
DISPMANX_DISPLAY_HANDLE_T dispman_display;
DISPMANX_UPDATE_HANDLE_T dispman_update;
DISPMANX_ELEMENT_HANDLE_T dispman_element;
VC_RECT_T src_rect;
VC_RECT_T dst_rect;
VC_DISPMANX_ALPHA_T dispman_alpha;
uint32_t screen_width;
uint32_t screen_height;
uint32_t window_width;
uint32_t window_height;
dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
dispman_alpha.opacity = 0xFF;
dispman_alpha.mask = 0;
graphics_get_display_size(0 /* LCD */, &screen_width, &screen_height);
window_width = settings.dispmanx.Width;
window_height = settings.dispmanx.Height;
if(window_width < 1)
window_width = screen_width;
if(window_height < 1)
window_height = screen_height;
src_rect.x = 0;
src_rect.y = 0;
src_rect.width = window_width << 16;
src_rect.height = window_height << 16;
if(settings.dispmanx.Maintain_Aspect)
{
float screen_aspect = (float)screen_width / screen_height;
float window_aspect = (float)window_width / window_height;
if(screen_aspect > window_aspect)
{
dst_rect.width = window_width * screen_height / window_height;
dst_rect.height = screen_height;
}
else
{
dst_rect.width = screen_width;
dst_rect.height = window_height * screen_width / window_width;
}
dst_rect.x = (screen_width - dst_rect.width) / 2;
dst_rect.y = (screen_height - dst_rect.height) / 2;
}
else
{
dst_rect.x = 0;
dst_rect.y = 0;
dst_rect.width = screen_width;
dst_rect.height = screen_height;
}
dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
dispman_update = vc_dispmanx_update_start( 0 );
dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display,
0 /*layer*/, &dst_rect, 0 /*src*/,
&src_rect, DISPMANX_PROTECTION_NONE,
&dispman_alpha /*alpha*/, 0 /*clamp*/, 0 /*transform*/);
static EGL_DISPMANX_WINDOW_T native_window;
native_window.element = dispman_element;
native_window.width = window_width;
native_window.height = window_height;
vc_dispmanx_update_submit_sync( dispman_update );
x11_disp = (void*)dispman_display;
x11_win = (void*)&native_window;
}
#endif

View File

@ -0,0 +1,3 @@
#pragma once
extern void dispmanx_window_create();

View File

@ -19,6 +19,10 @@
#include <emscripten.h>
#endif
#if defined(SUPPORT_DISPMANX)
#include "linux-dist/dispmanx.h"
#endif
#if defined(SUPPORT_X11)
#include "linux-dist/x11.h"
#endif
@ -235,6 +239,9 @@ void os_SetWindowText(const char * text)
void os_CreateWindow()
{
#if defined(SUPPORT_DISPMANX)
dispmanx_window_create();
#endif
#if defined(SUPPORT_X11)
x11_window_create();
#endif

View File

@ -263,12 +263,23 @@ void LoadSettings()
settings.pvr.HashLogFile = cfgLoadStr("testing", "ta.HashLogFile", "");
settings.pvr.HashCheckFile = cfgLoadStr("testing", "ta.HashCheckFile", "");
#if SUPPORT_DISPMANX
settings.dispmanx.Width = cfgLoadInt("dispmanx","width",640);
settings.dispmanx.Height = cfgLoadInt("dispmanx","height",480);
settings.dispmanx.Maintain_Aspect = cfgLoadBool("dispmanx","maintain_aspect",true);
#endif
#if (HOST_OS != OS_LINUX || defined(_ANDROID) || defined(TARGET_PANDORA))
settings.aica.BufferSize=2048;
#else
settings.aica.BufferSize=1024;
#endif
#if USE_OMX
settings.omx.Audio_Latency = cfgLoadInt("omx","audio_latency",100);
settings.omx.Audio_HDMI = cfgLoadBool("omx","audio_hdmi",true);
#endif
/*
//make sure values are valid
settings.dreamcast.cable = min(max(settings.dreamcast.cable, 0),3);

View File

@ -0,0 +1,319 @@
#include "oslib/audiobackend_omx.h"
#if USE_OMX
#include <IL/OMX_Broadcom.h>
#include <unistd.h>
#define PORT_INDEX 100
#define OUTPUT_FREQ 44100
static OMX_HANDLETYPE omx_handle;
static OMX_STATETYPE omx_state = OMX_StateInvalid;
static size_t audio_buffer_idx;
static OMX_BUFFERHEADERTYPE** audio_buffers = NULL;
static u32 latency_max;
static u32 buffer_count;
static u32 buffer_size;
static u32 buffer_length;
static pthread_mutex_t audio_lock;
static pthread_cond_t omx_state_cond;
OMX_ERRORTYPE EventHandler(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_PTR pAppData,
OMX_IN OMX_EVENTTYPE eEvent,
OMX_IN OMX_U32 nData1,
OMX_IN OMX_U32 nData2,
OMX_IN OMX_PTR pEventData)
{
pthread_mutex_lock(&audio_lock);
if(eEvent == OMX_EventCmdComplete && nData1 == OMX_CommandStateSet)
{
omx_state = (OMX_STATETYPE)nData2;
pthread_cond_signal(&omx_state_cond);
}
pthread_mutex_unlock(&audio_lock);
return OMX_ErrorNone;
}
OMX_ERRORTYPE EmptyBufferDone(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_PTR pAppData,
OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
{
return OMX_ErrorNone;
}
OMX_ERRORTYPE FillBufferDone(
OMX_OUT OMX_HANDLETYPE hComponent,
OMX_OUT OMX_PTR pAppData,
OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer)
{
return OMX_ErrorNone;
}
void omx_wait_for_state(OMX_STATETYPE state)
{
pthread_mutex_lock(&audio_lock);
while(omx_state != state)
pthread_cond_wait(&omx_state_cond, &audio_lock);
pthread_mutex_unlock(&audio_lock);
}
static u32 omx_get_latency()
{
OMX_PARAM_U32TYPE param;
memset(&param, 0, sizeof(OMX_PARAM_U32TYPE));
param.nSize = sizeof(OMX_PARAM_U32TYPE);
param.nVersion.nVersion = OMX_VERSION;
param.nPortIndex = PORT_INDEX;
OMX_ERRORTYPE error = OMX_GetConfig(omx_handle, OMX_IndexConfigAudioRenderingLatency, &param);
if(error != OMX_ErrorNone)
fprintf(stderr, "OMX: failed to get OMX configuration (OMX_IndexConfigAudioRenderingLatency). Error 0x%X\n", error);
return param.nU32 * 1000 / OUTPUT_FREQ;
}
static void omx_init()
{
OMX_ERRORTYPE error;
error = OMX_Init();
if(error != OMX_ErrorNone)
{
fprintf(stderr, "OMX: OMX_Init() failed. Error 0x%X\n", error);
return;
}
// Initialize settings
latency_max = settings.omx.Audio_Latency;
buffer_size = settings.aica.BufferSize * 4;
buffer_count = 2 + OUTPUT_FREQ * latency_max / (buffer_size * 1000);
OMX_CALLBACKTYPE callbacks;
callbacks.EventHandler = EventHandler;
callbacks.EmptyBufferDone = EmptyBufferDone;
callbacks.EmptyBufferDone = FillBufferDone;
error = OMX_GetHandle(&omx_handle, (OMX_STRING)"OMX.broadcom.audio_render", NULL, &callbacks);
if(error != OMX_ErrorNone)
{
fprintf(stderr, "OMX: OMX_GetHandle() failed. Error 0x%X\n", error);
return;
}
OMX_PARAM_PORTDEFINITIONTYPE param;
memset(&param, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
param.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
param.nVersion.nVersion = OMX_VERSION;
param.nPortIndex = PORT_INDEX;
param.nBufferSize = buffer_size;
param.nBufferCountActual = buffer_count;
param.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
error = OMX_SetParameter(omx_handle, OMX_IndexParamPortDefinition, &param);
if(error != OMX_ErrorNone)
fprintf(stderr, "OMX: failed to set OMX_IndexParamPortDefinition. Error 0x%X\n", error);
OMX_AUDIO_PARAM_PCMMODETYPE pcm;
memset(&pcm, 0, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE));
pcm.nSize = sizeof(OMX_AUDIO_PARAM_PCMMODETYPE);
pcm.nVersion.nVersion = OMX_VERSION;
pcm.nPortIndex = PORT_INDEX;
pcm.nChannels = 2;
pcm.eNumData = OMX_NumericalDataSigned;
pcm.eEndian = OMX_EndianLittle;
pcm.nSamplingRate = OUTPUT_FREQ;
pcm.bInterleaved = OMX_TRUE;
pcm.nBitPerSample = 16;
pcm.ePCMMode = OMX_AUDIO_PCMModeLinear;
pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
error = OMX_SetParameter(omx_handle, OMX_IndexParamAudioPcm, &pcm);
if(error != OMX_ErrorNone)
fprintf(stderr, "OMX: failed to set OMX_IndexParamAudioPcm. Error 0x%X\n", error);
// Disable all ports
error = OMX_SendCommand(omx_handle, OMX_CommandPortDisable, PORT_INDEX, NULL);
if(error != OMX_ErrorNone)
fprintf(stderr, "OMX: failed to do OMX_CommandPortDisable. Error 0x%X\n", error);
OMX_PORT_PARAM_TYPE param2;
memset(&param2, 0, sizeof(OMX_PORT_PARAM_TYPE));
param2.nSize = sizeof(OMX_PORT_PARAM_TYPE);
param2.nVersion.nVersion = OMX_VERSION;
error = OMX_GetParameter(omx_handle, OMX_IndexParamOtherInit, &param2);
if(error != OMX_ErrorNone)
{
fprintf(stderr, "OMX: failed to get OMX_IndexParamOtherInit. Error 0x%X\n", error);
}
else
{
for(u32 i = 0; i < param2.nPorts; i++)
{
u32 port = param2.nStartPortNumber + i;
error = OMX_SendCommand(omx_handle, OMX_CommandPortDisable, port, NULL);
if(error != OMX_ErrorNone)
fprintf(stderr, "OMX: failed to do OMX_CommandPortDisable on port %u. Error 0x%X\n", port, error);
}
}
// Go into idle state
error = OMX_SendCommand(omx_handle, OMX_CommandStateSet, OMX_StateIdle, NULL);
if(error != OMX_ErrorNone)
{
fprintf(stderr, "OMX: failed to set OMX_CommandStateSet. Error 0x%X\n", error);
return;
}
omx_wait_for_state(OMX_StateIdle);
// Check if we're in a state able to recieve buffers
OMX_STATETYPE state;
error = OMX_GetState(omx_handle, &state);
if(error != OMX_ErrorNone || !(state == OMX_StateIdle || state == OMX_StateExecuting || state == OMX_StatePause))
{
fprintf(stderr, "OMX: state is incorrect. State 0x%X; Error 0x%X\n", state, error);
return;
}
// Create audio buffers
fprintf(stderr, "OMX: creating %u buffers\n", buffer_count);
// Enable port
error = OMX_SendCommand(omx_handle, OMX_CommandPortEnable, PORT_INDEX, NULL);
if(error != OMX_ErrorNone)
fprintf(stderr, "OMX: failed to do OMX_CommandPortEnable. Error 0x%X\n", error);
// Free audio buffers if they're allocated
if(audio_buffers != NULL)
delete[] audio_buffers;
// Allocate buffers
audio_buffers = new OMX_BUFFERHEADERTYPE*[buffer_count];
for(size_t i = 0; i < buffer_count; i++)
{
error = OMX_AllocateBuffer(omx_handle, &audio_buffers[i], PORT_INDEX, NULL, buffer_size);
if(error != OMX_ErrorNone)
{
fprintf(stderr, "OMX: failed to allocate buffer[%u]. Error 0x%X\n", i, error);
return;
}
}
// Set state to executing
error = OMX_SendCommand(omx_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL);
if(error != OMX_ErrorNone)
{
fprintf(stderr, "OMX: failed to do OMX_CommandStateSet. Error 0x%X\n", error);
return;
}
omx_wait_for_state(OMX_StateExecuting);
// Empty buffers
for(size_t i = 0; i < buffer_count; i++)
{
memset(audio_buffers[i]->pBuffer, 0, buffer_size);
audio_buffers[i]->nOffset = 0;
audio_buffers[i]->nFilledLen = buffer_size;
error = OMX_EmptyThisBuffer(omx_handle, audio_buffers[i]);
if(error != OMX_ErrorNone)
fprintf(stderr, "OMX: failed to empty buffer[%u]. Error 0x%X\n", i, error);
}
char* output_device = "local";
if(settings.omx.Audio_HDMI)
output_device = (char*)"hdmi";
// Set audio destination
OMX_CONFIG_BRCMAUDIODESTINATIONTYPE ar_dest;
memset(&ar_dest, 0, sizeof(ar_dest));
ar_dest.nSize = sizeof(OMX_CONFIG_BRCMAUDIODESTINATIONTYPE);
ar_dest.nVersion.nVersion = OMX_VERSION;
strcpy((char *)ar_dest.sName, output_device);
error = OMX_SetConfig(omx_handle, OMX_IndexConfigBrcmAudioDestination, &ar_dest);
if(error != OMX_ErrorNone)
{
fprintf(stderr, "OMX: failed to set OMX configuration (OMX_IndexConfigBrcmAudioDestination). Error 0x%X\n", error);
return;
}
audio_buffer_idx = 0;
buffer_length = 0;
fprintf(stderr, "OMX: audio output to '%s'\n", ar_dest.sName);
}
static u32 omx_push(void* frame, u32 samples, bool wait)
{
if(audio_buffers == NULL)
return 1;
size_t data_size = samples * 4;
while(data_size > 0)
{
size_t copy_size = std::min(buffer_size, data_size);
// Don't have more than maximum audio latency
u32 latency = omx_get_latency();
if(latency > latency_max)
{
usleep((latency - latency_max) * 1000);
}
else if(latency == 0)
{
fprintf(stderr, "OMX: underrun occurred\n");
}
memcpy(audio_buffers[audio_buffer_idx]->pBuffer + buffer_length, frame, copy_size);
buffer_length += copy_size;
// Flush buffer and swap
if(buffer_length >= buffer_size)
{
audio_buffers[audio_buffer_idx]->nOffset = 0;
audio_buffers[audio_buffer_idx]->nFilledLen = buffer_size;
OMX_ERRORTYPE error = OMX_EmptyThisBuffer(omx_handle, audio_buffers[audio_buffer_idx]);
if(error != OMX_ErrorNone)
fprintf(stderr, "OMX: failed to empty buffer[%u]. Error 0x%X\n", audio_buffer_idx, error);
audio_buffer_idx = (audio_buffer_idx + 1) % buffer_count;
buffer_length = 0;
}
data_size -= copy_size;
}
return 1;
}
static void omx_term()
{
OMX_ERRORTYPE error;
// Is there anything else that needs to be done for omx?
error = OMX_Deinit();
if(error != OMX_ErrorNone)
fprintf(stderr, "OMX: OMX_Deinit() failed. Error 0x%X\n", error);
if(audio_buffers != NULL)
{
delete[] audio_buffers;
audio_buffers = NULL;
}
}
audiobackend_t audiobackend_omx = {
"omx", // Slug
"OpenMAX IL", // Name
&omx_init,
&omx_push,
&omx_term
};
#endif

View File

@ -0,0 +1,4 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_omx;

View File

@ -8,6 +8,7 @@
#include "oslib/audiobackend_oss.h"
#include "oslib/audiobackend_pulseaudio.h"
#include "oslib/audiobackend_coreaudio.h"
#include "oslib/audiobackend_omx.h"
struct SoundFrame { s16 l;s16 r; };
#define SAMPLE_COUNT 512
@ -77,6 +78,9 @@ void RegisterAllAudioBackends() {
#if ANDROID
RegisterAudioBackend(&audiobackend_android);
#endif
#if USE_OMX
RegisterAudioBackend(&audiobackend_omx);
#endif
#if USE_ALSA
RegisterAudioBackend(&audiobackend_alsa);
#endif

View File

@ -652,6 +652,23 @@ struct settings_t
u32 NoSound; //0 ->sound, 1 -> no sound
} aica;
#if USE_OMX
struct
{
u32 Audio_Latency;
bool Audio_HDMI;
} omx;
#endif
#if SUPPORT_DISPMANX
struct
{
u32 Width;
u32 Height;
bool Maintain_Aspect;
} dispmanx;
#endif
struct
{
bool PatchRegion;

View File

@ -124,7 +124,10 @@ else ifneq (,$(findstring rpi2,$(platform)))
CFLAGS += -D TARGET_BEAGLE -D TARGET_LINUX_ARMELv7 -DARM_HARDFP -fsingle-precision-constant
INCS += -I/opt/vc/include/ -I/opt/vc/include/interface/vmcs_host/linux -I/opt/vc/include/interface/vcos/pthreads -I../linux-deps/include
LIBS += -L/opt/vc/lib/ -L../linux-deps/lib -lbcm_host
USE_OMX := 1
USE_DISPMANX := 1
USE_GLES := 1
undefine USE_X11
# BeagleBone Black
else ifneq (,$(findstring beagle,$(platform)))
@ -233,6 +236,11 @@ ifdef LTO_TEST
LDFLAGS +=-flto -fwhole-program
endif
ifdef USE_DISPMANX
CFLAGS += -D SUPPORT_DISPMANX
CXXFLAGS += -D SUPPORT_DISPMANX
endif
ifdef USE_X11
CFLAGS += -D SUPPORT_X11
CXXFLAGS += -D SUPPORT_X11
@ -247,6 +255,11 @@ ifdef USE_JOYSTICK
CXXFLAGS += -D USE_JOYSTICK
endif
ifdef USE_OMX
CXXFLAGS += -D USE_OMX
LIBS += -lopenmaxil
endif
ifdef USE_ALSA
CXXFLAGS += -D USE_ALSA
LIBS += -lasound