Add Raspberry Pi Decoder (Fix #126) (#360)

This commit is contained in:
Blueroom VR 2020-11-14 10:51:08 -08:00 committed by GitHub
parent 8b6f9a5fc1
commit ea79836f0f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 543 additions and 7 deletions

View file

@ -16,6 +16,7 @@ option(CHIAKI_ENABLE_ANDROID "Enable Android (Use only as part of the Gradle Pro
option(CHIAKI_ENABLE_SWITCH "Enable Nintendo Switch (Requires devKitPro libnx)" OFF)
tri_option(CHIAKI_ENABLE_SETSU "Enable libsetsu for touchpad input from controller" AUTO)
option(CHIAKI_LIB_ENABLE_OPUS "Use Opus as part of Chiaki Lib" ON)
tri_option(CHIAKI_ENABLE_PI_DECODER "Enable Raspberry Pi-specific video decoder (requires libraspberrypi0 and libraspberrypi-doc)" AUTO)
option(CHIAKI_LIB_ENABLE_MBEDTLS "Use mbedtls instead of OpenSSL as part of Chiaki Lib" OFF)
option(CHIAKI_LIB_OPENSSL_EXTERNAL_PROJECT "Use OpenSSL as CMake external project" OFF)
option(CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER "Use SDL Gamecontroller for Input" ON)
@ -99,6 +100,27 @@ if(CHIAKI_LIB_ENABLE_MBEDTLS)
add_definitions(-DCHIAKI_LIB_ENABLE_MBEDTLS)
endif()
if(CHIAKI_ENABLE_PI_DECODER)
find_package(ILClient)
if(ILClient_FOUND)
set(CHIAKI_ENABLE_PI_DECODER ON)
else()
if(NOT CHIAKI_ENABLE_PI_DECODER STREQUAL AUTO)
message(FATAL_ERROR "
CHIAKI_ENABLE_PI_DECODER is set to ON, but its dependencies (ilclient source and libs) could not be resolved.
The Raspberry Pi Decoder is only supported on Raspberry Pi OS and requires libraspberrypi0 and libraspberrypi-doc.")
endif()
set(CHIAKI_ENABLE_PI_DECODER OFF)
endif()
endif()
if(CHIAKI_ENABLE_PI_DECODER)
message(STATUS "Pi Decoder enabled")
else()
message(STATUS "Pi Decoder disabled")
endif()
add_subdirectory(lib)
if(CHIAKI_ENABLE_CLI)

57
cmake/FindILClient.cmake Normal file
View file

@ -0,0 +1,57 @@
# Provides ILClient::ILClient
# (Raspberry Pi-specific video decoding stuff, very specific for libraspberrypi0 and libraspberrypi-doc)
set(_required_libs
/opt/vc/lib/libbcm_host.so
/opt/vc/lib/libvcilcs.a
/opt/vc/lib/libvchiq_arm.so
/opt/vc/lib/libvcos.so)
unset(_libvars)
foreach(_lib ${_required_libs})
get_filename_component(_libname "${_lib}" NAME_WE)
set(_libvar "ILClient_${_libname}_LIBRARY")
list(APPEND _libvars "${_libvar}")
if(EXISTS "${_lib}")
set("${_libvar}" "${_lib}")
else()
set("${_libvar}" "${_libvar}-NOTFOUND")
endif()
endforeach()
find_path(ILClient_INCLUDE_DIR bcm_host.h
PATHS /opt/vc/include
NO_DEFAULT_PATH)
find_path(ILClient_SOURCE_DIR ilclient.c
PATHS /opt/vc/src/hello_pi/libs/ilclient)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ILClient
FOUND_VAR ILClient_FOUND
REQUIRED_VARS
${_libvars}
ILClient_INCLUDE_DIR
ILClient_SOURCE_DIR)
if(ILClient_FOUND)
if(NOT TARGET ILClient::ILClient)
# see /opt/vc/src/hello_pi/libs/ilclient/Makefile
add_library(ilclient STATIC
"${ILClient_SOURCE_DIR}/ilclient.c"
"${ILClient_SOURCE_DIR}/ilcore.c")
target_include_directories(ilclient PUBLIC
"${ILClient_INCLUDE_DIR}"
"${ILClient_SOURCE_DIR}")
target_compile_definitions(ilclient PUBLIC
HAVE_LIBOPENMAX=2
OMX
OMX_SKIP64BIT
USE_EXTERNAL_OMX
HAVE_LIBBCM_HOST
USE_EXTERNAL_LIBBCM_HOST
USE_VCHIQ_ARM)
target_link_libraries(ilclient PUBLIC ${_required_libs})
add_library(ILClient::ILClient ALIAS ilclient)
endif()
endif()

View file

@ -30,6 +30,12 @@ enum class DisconnectAction
Ask
};
enum class Decoder
{
Ffmpeg,
Pi
};
class Settings : public QObject
{
Q_OBJECT
@ -69,6 +75,9 @@ class Settings : public QObject
unsigned int GetBitrate() const;
void SetBitrate(unsigned int bitrate);
Decoder GetDecoder() const;
void SetDecoder(Decoder decoder);
HardwareDecodeEngine GetHardwareDecodeEngine() const;
void SetHardwareDecodeEngine(HardwareDecodeEngine enabled);

View file

@ -25,6 +25,7 @@ class SettingsDialog : public QDialog
QComboBox *fps_combo_box;
QLineEdit *bitrate_edit;
QLineEdit *audio_buffer_size_edit;
QCheckBox *pi_decoder_check_box;
QComboBox *hardware_decode_combo_box;
QListWidget *registered_hosts_list_widget;
@ -41,6 +42,7 @@ class SettingsDialog : public QDialog
void BitrateEdited();
void AudioBufferSizeEdited();
void HardwareDecodeEngineSelected();
void UpdateHardwareDecodeEngineComboBox();
void UpdateRegisteredHosts();
void UpdateRegisteredHostsButtons();

View file

@ -6,6 +6,10 @@
#include <chiaki/session.h>
#include <chiaki/opusdecoder.h>
#if CHIAKI_LIB_ENABLE_PI_DECODER
#include <chiaki/pidecoder.h>
#endif
#if CHIAKI_GUI_ENABLE_SETSU
#include <setsu.h>
#endif
@ -14,6 +18,7 @@
#include "exception.h"
#include "sessionlog.h"
#include "controllermanager.h"
#include "settings.h"
#include <QObject>
#include <QImage>
@ -35,6 +40,7 @@ struct StreamSessionConnectInfo
{
Settings *settings;
QMap<Qt::Key, int> key_map;
Decoder decoder;
HardwareDecodeEngine hw_decode_engine;
uint32_t log_level_mask;
QString log_file;
@ -70,7 +76,10 @@ class StreamSession : public QObject
ChiakiControllerState keyboard_state;
VideoDecoder video_decoder;
VideoDecoder *video_decoder;
#if CHIAKI_LIB_ENABLE_PI_DECODER
ChiakiPiDecoder *pi_decoder;
#endif
unsigned int audio_buffer_size;
QAudioOutput *audio_output;
@ -101,7 +110,10 @@ class StreamSession : public QObject
void SetLoginPIN(const QString &pin);
Controller *GetController() { return controller; }
VideoDecoder *GetVideoDecoder() { return &video_decoder; }
VideoDecoder *GetVideoDecoder() { return video_decoder; }
#if CHIAKI_LIB_ENABLE_PI_DECODER
ChiakiPiDecoder *GetPiDecoder() { return pi_decoder; }
#endif
void HandleKeyboardEvent(QKeyEvent *event);
void HandleMouseEvent(QMouseEvent *event);

View file

@ -25,6 +25,7 @@ class StreamWindow: public QMainWindow
AVOpenGLWidget *av_widget;
void Init();
void UpdateVideoTransform();
protected:
void keyPressEvent(QKeyEvent *event) override;
@ -32,6 +33,9 @@ class StreamWindow: public QMainWindow
void closeEvent(QCloseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void moveEvent(QMoveEvent *event) override;
void changeEvent(QEvent *event) override;
private slots:
void SessionQuit(ChiakiQuitReason reason, const QString &reason_str);

View file

@ -3,6 +3,8 @@
#include <settings.h>
#include <QKeySequence>
#include <chiaki/config.h>
#define SETTINGS_VERSION 1
Settings::Settings(QObject *parent) : QObject(parent)
@ -79,6 +81,28 @@ unsigned int Settings::GetAudioBufferSizeRaw() const
return settings.value("settings/audio_buffer_size", 0).toUInt();
}
static const QMap<Decoder, QString> decoder_values = {
{ Decoder::Ffmpeg, "ffmpeg" },
{ Decoder::Pi, "pi" }
};
static const Decoder decoder_default = Decoder::Pi;
Decoder Settings::GetDecoder() const
{
#if CHIAKI_LIB_ENABLE_PI_DECODER
auto v = settings.value("settings/decoder", decoder_values[decoder_default]).toString();
return decoder_values.key(v, decoder_default);
#else
return Decoder::Ffmpeg;
#endif
}
void Settings::SetDecoder(Decoder decoder)
{
settings.setValue("settings/decoder", decoder_values[decoder]);
}
static const QMap<HardwareDecodeEngine, QString> hw_decode_engine_values = {
{ HW_DECODE_NONE, "none" },
{ HW_DECODE_VAAPI, "vaapi" },

View file

@ -20,6 +20,8 @@
#include <QCheckBox>
#include <QLineEdit>
#include <chiaki/config.h>
const char * const about_string =
"<h1>Chiaki</h1> by thestr4ng3r, version " CHIAKI_VERSION
""
@ -157,6 +159,18 @@ SettingsDialog::SettingsDialog(Settings *settings, QWidget *parent) : QDialog(pa
auto decode_settings_layout = new QFormLayout();
decode_settings->setLayout(decode_settings_layout);
#if CHIAKI_LIB_ENABLE_PI_DECODER
pi_decoder_check_box = new QCheckBox(this);
pi_decoder_check_box->setChecked(settings->GetDecoder() == Decoder::Pi);
connect(pi_decoder_check_box, &QCheckBox::toggled, this, [this](bool checked) {
this->settings->SetDecoder(checked ? Decoder::Pi : Decoder::Ffmpeg);
UpdateHardwareDecodeEngineComboBox();
});
decode_settings_layout->addRow(tr("Use Raspberry Pi Decoder:"), pi_decoder_check_box);
#else
pi_decoder_check_box = nullptr;
#endif
hardware_decode_combo_box = new QComboBox(this);
static const QList<QPair<HardwareDecodeEngine, const char *>> hardware_decode_engines = {
{ HW_DECODE_NONE, "none"},
@ -173,6 +187,7 @@ SettingsDialog::SettingsDialog(Settings *settings, QWidget *parent) : QDialog(pa
}
connect(hardware_decode_combo_box, SIGNAL(currentIndexChanged(int)), this, SLOT(HardwareDecodeEngineSelected()));
decode_settings_layout->addRow(tr("Hardware decode method:"), hardware_decode_combo_box);
UpdateHardwareDecodeEngineComboBox();
// Registered Consoles
@ -281,6 +296,11 @@ void SettingsDialog::HardwareDecodeEngineSelected()
settings->SetHardwareDecodeEngine((HardwareDecodeEngine)hardware_decode_combo_box->currentData().toInt());
}
void SettingsDialog::UpdateHardwareDecodeEngineComboBox()
{
hardware_decode_combo_box->setEnabled(settings->GetDecoder() == Decoder::Ffmpeg);
}
void SettingsDialog::UpdateBitratePlaceholder()
{
bitrate_edit->setPlaceholderText(tr("Automatic (%1)").arg(settings->GetVideoProfile().bitrate));

View file

@ -18,6 +18,7 @@ StreamSessionConnectInfo::StreamSessionConnectInfo(Settings *settings, QString h
: settings(settings)
{
key_map = settings->GetControllerMappingForDecoding();
decoder = settings->GetDecoder();
hw_decode_engine = settings->GetHardwareDecodeEngine();
log_level_mask = settings->GetLogLevelMask();
log_file = CreateLogFilename();
@ -42,11 +43,30 @@ StreamSession::StreamSession(const StreamSessionConnectInfo &connect_info, QObje
: QObject(parent),
log(this, connect_info.log_level_mask, connect_info.log_file),
controller(nullptr),
video_decoder(connect_info.hw_decode_engine, log.GetChiakiLog()),
video_decoder(nullptr),
#if CHIAKI_LIB_ENABLE_PI_DECODER
pi_decoder(nullptr),
#endif
audio_output(nullptr),
audio_io(nullptr)
{
connected = false;
#if CHIAKI_LIB_ENABLE_PI_DECODER
if(connect_info.decoder == Decoder::Pi)
{
pi_decoder = CHIAKI_NEW(ChiakiPiDecoder);
if(chiaki_pi_decoder_init(pi_decoder, log.GetChiakiLog()) != CHIAKI_ERR_SUCCESS)
throw ChiakiException("Failed to initialize Raspberry Pi Decoder");
}
else
{
#endif
video_decoder = new VideoDecoder(connect_info.hw_decode_engine, log.GetChiakiLog());
#if CHIAKI_LIB_ENABLE_PI_DECODER
}
#endif
chiaki_opus_decoder_init(&opus_decoder, log.GetChiakiLog());
audio_buffer_size = connect_info.audio_buffer_size;
@ -75,7 +95,17 @@ StreamSession::StreamSession(const StreamSessionConnectInfo &connect_info, QObje
chiaki_opus_decoder_get_sink(&opus_decoder, &audio_sink);
chiaki_session_set_audio_sink(&session, &audio_sink);
chiaki_session_set_video_sample_cb(&session, VideoSampleCb, this);
#if CHIAKI_LIB_ENABLE_PI_DECODER
if(pi_decoder)
chiaki_session_set_video_sample_cb(&session, chiaki_pi_decoder_video_sample_cb, pi_decoder);
else
{
#endif
chiaki_session_set_video_sample_cb(&session, VideoSampleCb, this);
#if CHIAKI_LIB_ENABLE_PI_DECODER
}
#endif
chiaki_session_set_event_cb(&session, EventCb, this);
#if CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER
@ -107,6 +137,14 @@ StreamSession::~StreamSession()
#if CHIAKI_GUI_ENABLE_SETSU
setsu_free(setsu);
#endif
#if CHIAKI_LIB_ENABLE_PI_DECODER
if(pi_decoder)
{
chiaki_pi_decoder_fini(pi_decoder);
free(pi_decoder);
}
#endif
delete video_decoder;
}
void StreamSession::Start()
@ -285,7 +323,7 @@ void StreamSession::PushAudioFrame(int16_t *buf, size_t samples_count)
void StreamSession::PushVideoSample(uint8_t *buf, size_t buf_size)
{
video_decoder.PushFrame(buf, buf_size);
video_decoder->PushFrame(buf, buf_size);
}
void StreamSession::Event(ChiakiEvent *event)

View file

@ -47,8 +47,17 @@ void StreamWindow::Init()
connect(session, &StreamSession::SessionQuit, this, &StreamWindow::SessionQuit);
connect(session, &StreamSession::LoginPINRequested, this, &StreamWindow::LoginPINRequested);
av_widget = new AVOpenGLWidget(session->GetVideoDecoder(), this);
setCentralWidget(av_widget);
if(session->GetVideoDecoder())
{
av_widget = new AVOpenGLWidget(session->GetVideoDecoder(), this);
setCentralWidget(av_widget);
}
else
{
QWidget *bg_widget = new QWidget(this);
bg_widget->setStyleSheet("background-color: black;");
setCentralWidget(bg_widget);
}
grabKeyboard();
@ -167,3 +176,34 @@ void StreamWindow::ToggleFullscreen()
av_widget->HideMouse();
}
}
void StreamWindow::resizeEvent(QResizeEvent *event)
{
UpdateVideoTransform();
QMainWindow::resizeEvent(event);
}
void StreamWindow::moveEvent(QMoveEvent *event)
{
UpdateVideoTransform();
QMainWindow::moveEvent(event);
}
void StreamWindow::changeEvent(QEvent *event)
{
if(event->type() == QEvent::ActivationChange)
UpdateVideoTransform();
QMainWindow::changeEvent(event);
}
void StreamWindow::UpdateVideoTransform()
{
#if CHIAKI_LIB_ENABLE_PI_DECODER
ChiakiPiDecoder *pi_decoder = session->GetPiDecoder();
if(pi_decoder)
{
QRect r = geometry();
chiaki_pi_decoder_set_params(pi_decoder, r.x(), r.y(), r.width(), r.height(), isActiveWindow());
}
#endif
}

View file

@ -73,6 +73,12 @@ set(SOURCE_FILES
src/regist.c
src/opusdecoder.c)
if(CHIAKI_ENABLE_PI_DECODER)
list(APPEND HEADER_FILES include/chiaki/pidecoder.h)
list(APPEND SOURCE_FILES src/pidecoder.c)
endif()
set(CHIAKI_LIB_ENABLE_PI_DECODER "${CHIAKI_ENABLE_PI_DECODER}")
add_subdirectory(protobuf)
set_source_files_properties(${CHIAKI_LIB_PROTO_SOURCE_FILES} ${CHIAKI_LIB_PROTO_HEADER_FILES} PROPERTIES GENERATED TRUE)
include_directories("${CHIAKI_LIB_PROTO_INCLUDE_DIR}")
@ -119,6 +125,10 @@ endif()
target_link_libraries(chiaki-lib Nanopb::nanopb)
target_link_libraries(chiaki-lib Jerasure::Jerasure)
if(CHIAKI_ENABLE_PI_DECODER)
target_link_libraries(chiaki-lib ILClient::ILClient)
endif()
if(CHIAKI_LIB_ENABLE_OPUS)
target_link_libraries(chiaki-lib ${Opus_LIBRARIES})
endif()

View file

@ -4,5 +4,6 @@
#define CHIAKI_CONFIG_H
#cmakedefine01 CHIAKI_LIB_ENABLE_OPUS
#cmakedefine01 CHIAKI_LIB_ENABLE_PI_DECODER
#endif // CHIAKI_CONFIG_H

View file

@ -0,0 +1,36 @@
#ifndef CHIAKI_PI_DECODER_H
#define CHIAKI_PI_DECODER_H
#include <chiaki/config.h>
#include <chiaki/log.h>
#include <ilclient.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct chiaki_pi_decoder_t
{
ChiakiLog *log;
TUNNEL_T tunnel[2];
COMPONENT_T *components[3];
ILCLIENT_T *client;
COMPONENT_T *video_decode;
COMPONENT_T *video_render;
bool port_settings_changed;
bool first_packet;
} ChiakiPiDecoder;
CHIAKI_EXPORT ChiakiErrorCode chiaki_pi_decoder_init(ChiakiPiDecoder *decoder, ChiakiLog *log);
CHIAKI_EXPORT void chiaki_pi_decoder_fini(ChiakiPiDecoder *decoder);
CHIAKI_EXPORT void chiaki_pi_decoder_set_params(ChiakiPiDecoder *decoder, int x, int y, int w, int h, bool visible);
CHIAKI_EXPORT bool chiaki_pi_decoder_video_sample_cb(uint8_t *buf, size_t buf_size, void *user);
#ifdef __cplusplus
}
#endif
#endif // CHIAKI_PI_DECODER_H

261
lib/src/pidecoder.c Normal file
View file

@ -0,0 +1,261 @@
#include <chiaki/pidecoder.h>
#include <bcm_host.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define MAX_DECODE_UNIT_SIZE 262144
CHIAKI_EXPORT ChiakiErrorCode chiaki_pi_decoder_init(ChiakiPiDecoder *decoder, ChiakiLog *log)
{
memset(decoder, 0, sizeof(ChiakiPiDecoder));
bcm_host_init();
if(!(decoder->client = ilclient_init()))
{
CHIAKI_LOGE(decoder->log, "ilclient_init failed");
chiaki_pi_decoder_fini(decoder);
return CHIAKI_ERR_UNKNOWN;
}
if(OMX_Init() != OMX_ErrorNone)
{
CHIAKI_LOGE(decoder->log, "OMX_Init failed");
chiaki_pi_decoder_fini(decoder);
return CHIAKI_ERR_UNKNOWN;
}
if(ilclient_create_component(decoder->client, &decoder->video_decode, "video_decode",
ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS) != 0)
{
CHIAKI_LOGE(decoder->log, "ilclient_create_component failed for video_decode");
chiaki_pi_decoder_fini(decoder);
return CHIAKI_ERR_UNKNOWN;
}
decoder->components[0] = decoder->video_decode;
if(ilclient_create_component(decoder->client, &decoder->video_render, "video_render", ILCLIENT_DISABLE_ALL_PORTS) != 0)
{
CHIAKI_LOGE(decoder->log, "ilclient_create_component failed for video_render");
chiaki_pi_decoder_fini(decoder);
return CHIAKI_ERR_UNKNOWN;
}
decoder->components[1] = decoder->video_render;
set_tunnel(decoder->tunnel, decoder->video_decode, 131, decoder->video_render, 90);
ilclient_change_component_state(decoder->video_decode, OMX_StateIdle);
OMX_VIDEO_PARAM_PORTFORMATTYPE format;
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(decoder->video_decode), OMX_IndexParamVideoPortFormat, &format) != OMX_ErrorNone
|| OMX_SetParameter(ILC_GET_HANDLE(decoder->video_decode), OMX_IndexParamBrcmDataUnit, &unit) != OMX_ErrorNone)
{
CHIAKI_LOGE(decoder->log, "OMX_SetParameter failed for video parameters");
chiaki_pi_decoder_fini(decoder);
return CHIAKI_ERR_UNKNOWN;
}
OMX_CONFIG_LATENCYTARGETTYPE latencyTarget;
memset(&latencyTarget, 0, sizeof(OMX_CONFIG_LATENCYTARGETTYPE));
latencyTarget.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
latencyTarget.nVersion.nVersion = OMX_VERSION;
latencyTarget.nPortIndex = 90;
latencyTarget.bEnabled = OMX_TRUE;
latencyTarget.nFilter = 2;
latencyTarget.nTarget = 4000;
latencyTarget.nShift = 3;
latencyTarget.nSpeedFactor = -135;
latencyTarget.nInterFactor = 500;
latencyTarget.nAdjCap = 20;
if(OMX_SetParameter(ILC_GET_HANDLE(decoder->video_render), OMX_IndexConfigLatencyTarget, &latencyTarget) != OMX_ErrorNone)
{
CHIAKI_LOGE(decoder->log, "OMX_SetParameter failed for render parameters");
chiaki_pi_decoder_fini(decoder);
return CHIAKI_ERR_UNKNOWN;
}
OMX_CONFIG_ROTATIONTYPE rotationType;
memset(&rotationType, 0, sizeof(OMX_CONFIG_ROTATIONTYPE));
rotationType.nSize = sizeof(OMX_CONFIG_ROTATIONTYPE);
rotationType.nVersion.nVersion = OMX_VERSION;
rotationType.nPortIndex = 90;
//rotationType.nRotation = 90; // example
if(OMX_SetParameter(ILC_GET_HANDLE(decoder->video_render), OMX_IndexConfigCommonRotate, &rotationType) != OMX_ErrorNone)
{
CHIAKI_LOGE(decoder->log, "OMX_SetParameter failed for rotation");
chiaki_pi_decoder_fini(decoder);
return CHIAKI_ERR_UNKNOWN;
}
OMX_PARAM_PORTDEFINITIONTYPE port;
memset(&port, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
port.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
port.nVersion.nVersion = OMX_VERSION;
port.nPortIndex = 130;
if(OMX_GetParameter(ILC_GET_HANDLE(decoder->video_decode), OMX_IndexParamPortDefinition, &port) != OMX_ErrorNone)
{
CHIAKI_LOGE(decoder->log, "Failed to get decoder port definition\n");
chiaki_pi_decoder_fini(decoder);
return CHIAKI_ERR_UNKNOWN;
}
// Increase the buffer size to fit the largest possible frame
port.nBufferSize = MAX_DECODE_UNIT_SIZE;
if(OMX_SetParameter(ILC_GET_HANDLE(decoder->video_decode), OMX_IndexParamPortDefinition, &port) != OMX_ErrorNone)
{
CHIAKI_LOGE(decoder->log, "OMX_SetParameter failed for port");
chiaki_pi_decoder_fini(decoder);
return CHIAKI_ERR_UNKNOWN;
}
if(ilclient_enable_port_buffers(decoder->video_decode, 130, NULL, NULL, NULL) != 0)
{
CHIAKI_LOGE(decoder->log, "ilclient_enable_port_buffers failed");
chiaki_pi_decoder_fini(decoder);
return CHIAKI_ERR_UNKNOWN;
}
decoder->port_settings_changed = false;
decoder->first_packet = true;
ilclient_change_component_state(decoder->video_decode, OMX_StateExecuting);
CHIAKI_LOGI(decoder->log, "Raspberry Pi Decoder initialized");
return CHIAKI_ERR_SUCCESS;
}
CHIAKI_EXPORT void chiaki_pi_decoder_fini(ChiakiPiDecoder *decoder)
{
if(decoder->video_decode)
{
OMX_BUFFERHEADERTYPE *buf;
if((buf = ilclient_get_input_buffer(decoder->video_decode, 130, 1)))
{
buf->nFilledLen = 0;
buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS;
OMX_EmptyThisBuffer(ILC_GET_HANDLE(decoder->video_decode), buf);
}
// need to flush the renderer to allow video_decode to disable its input port
ilclient_flush_tunnels(decoder->tunnel, 0);
ilclient_disable_port_buffers(decoder->video_decode, 130, NULL, NULL, NULL);
ilclient_disable_tunnel(decoder->tunnel);
ilclient_teardown_tunnels(decoder->tunnel);
ilclient_state_transition(decoder->components, OMX_StateIdle);
ilclient_state_transition(decoder->components, OMX_StateLoaded);
ilclient_cleanup_components(decoder->components);
}
OMX_Deinit();
if(decoder->client)
ilclient_destroy(decoder->client);
}
static bool push_buffer(ChiakiPiDecoder *decoder, uint8_t *buf, size_t buf_size)
{
OMX_BUFFERHEADERTYPE *omx_buf = ilclient_get_input_buffer(decoder->video_decode, 130, 1);
if(!omx_buf)
{
CHIAKI_LOGE(decoder->log, "ilclient_get_input_buffer failed");
return false;
}
if(omx_buf->nAllocLen < buf_size)
{
CHIAKI_LOGE(decoder->log, "Buffer from omx is too small for frame");
return false;
}
omx_buf->nFilledLen = 0;
omx_buf->nOffset = 0;
omx_buf->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
if(decoder->first_packet)
{
omx_buf->nFlags |= OMX_BUFFERFLAG_STARTTIME;
decoder->first_packet = false;
}
memcpy(omx_buf->pBuffer + omx_buf->nFilledLen, buf, buf_size);
omx_buf->nFilledLen += buf_size;
if(!decoder->port_settings_changed
&& ((omx_buf->nFilledLen > 0 && ilclient_remove_event(decoder->video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0)
|| (omx_buf->nFilledLen == 0 && ilclient_wait_for_event(decoder->video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1, ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10000) == 0)))
{
decoder->port_settings_changed = true;
if(ilclient_setup_tunnel(decoder->tunnel, 0, 0) != 0)
{
CHIAKI_LOGE(decoder->log, "ilclient_setup_tunnel failed");
return false;
}
ilclient_change_component_state(decoder->video_render, OMX_StateExecuting);
}
if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(decoder->video_decode), omx_buf) != OMX_ErrorNone)
{
CHIAKI_LOGE(decoder->log, "OMX_EmptyThisBuffer failed");
return false;
}
return true;
}
#define OMX_INIT_STRUCTURE(a) \
memset(&(a), 0, sizeof(a)); \
(a).nSize = sizeof(a); \
(a).nVersion.s.nVersionMajor = OMX_VERSION_MAJOR; \
(a).nVersion.s.nVersionMinor = OMX_VERSION_MINOR; \
(a).nVersion.s.nRevision = OMX_VERSION_REVISION; \
(a).nVersion.s.nStep = OMX_VERSION_STEP
CHIAKI_EXPORT void chiaki_pi_decoder_set_params(ChiakiPiDecoder *decoder, int x, int y, int w, int h, bool visible)
{
OMX_CONFIG_DISPLAYREGIONTYPE configDisplay;
OMX_INIT_STRUCTURE(configDisplay);
configDisplay.nPortIndex = 90;
configDisplay.set = (OMX_DISPLAYSETTYPE)(OMX_DISPLAY_SET_NOASPECT | OMX_DISPLAY_SET_MODE | OMX_DISPLAY_SET_FULLSCREEN | OMX_DISPLAY_SET_PIXEL | OMX_DISPLAY_SET_DEST_RECT | OMX_DISPLAY_SET_ALPHA);
configDisplay.mode = OMX_DISPLAY_MODE_LETTERBOX;
configDisplay.fullscreen = OMX_FALSE;
configDisplay.noaspect = OMX_FALSE;
configDisplay.dest_rect.x_offset = x;
configDisplay.dest_rect.y_offset = y;
configDisplay.dest_rect.width = w;
configDisplay.dest_rect.height = h;
configDisplay.alpha = visible ? 255 : 0;
if(OMX_SetParameter(ILC_GET_HANDLE(decoder->video_render), OMX_IndexConfigDisplayRegion, &configDisplay) != OMX_ErrorNone)
CHIAKI_LOGE(decoder->log, "OMX_SetParameter failed for display params");
}
CHIAKI_EXPORT bool chiaki_pi_decoder_video_sample_cb(uint8_t *buf, size_t buf_size, void *user)
{
return push_buffer(user, buf, buf_size);
}