mirror of
https://github.com/moonlight-stream/moonlight-embedded.git
synced 2025-07-01 23:35:47 +00:00
Add: initial ODROID-N1 Rockchip hardware decoder support
This commit is contained in:
parent
d452411428
commit
c0cc20733b
@ -14,6 +14,7 @@ find_package(Opus REQUIRED)
|
|||||||
find_package(Broadcom)
|
find_package(Broadcom)
|
||||||
find_package(Freescale)
|
find_package(Freescale)
|
||||||
find_package(Amlogic)
|
find_package(Amlogic)
|
||||||
|
find_package(Rockchip)
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(EVDEV REQUIRED libevdev)
|
pkg_check_modules(EVDEV REQUIRED libevdev)
|
||||||
@ -97,6 +98,16 @@ if(FREESCALE_FOUND)
|
|||||||
install(TARGETS moonlight-imx DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
install(TARGETS moonlight-imx DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(ROCKCHIP_FOUND)
|
||||||
|
list(APPEND MOONLIGHT_DEFINITIONS HAVE_ROCKCHIP)
|
||||||
|
list(APPEND MOONLIGHT_OPTIONS ROCKCHIP)
|
||||||
|
add_library(moonlight-rk SHARED ./src/video/rk.c)
|
||||||
|
target_include_directories(moonlight-rk PRIVATE ${ROCKCHIP_INCLUDE_DIRS} ${GAMESTREAM_INCLUDE_DIR} ${MOONLIGHT_COMMON_INCLUDE_DIR})
|
||||||
|
target_link_libraries(moonlight-rk gamestream ${ROCKCHIP_LIBRARIES})
|
||||||
|
set_property(TARGET moonlight-rk PROPERTY COMPILE_DEFINITIONS ${ROCKCHIP_DEFINITIONS})
|
||||||
|
install(TARGETS moonlight-rk DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
if (SOFTWARE_FOUND)
|
if (SOFTWARE_FOUND)
|
||||||
target_sources(moonlight PRIVATE ./src/video/ffmpeg.c)
|
target_sources(moonlight PRIVATE ./src/video/ffmpeg.c)
|
||||||
target_include_directories(moonlight PRIVATE ${AVCODEC_INCLUDE_DIRS} ${AVUTIL_INCLUDE_DIRS})
|
target_include_directories(moonlight PRIVATE ${AVCODEC_INCLUDE_DIRS} ${AVUTIL_INCLUDE_DIRS})
|
||||||
@ -147,12 +158,12 @@ if (PULSE_FOUND)
|
|||||||
target_link_libraries(moonlight ${PULSE_LIBRARIES})
|
target_link_libraries(moonlight ${PULSE_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (AMLOGIC_FOUND OR BROADCOM_FOUND OR FREESCALE_FOUND OR X11_FOUND)
|
if (AMLOGIC_FOUND OR BROADCOM_FOUND OR FREESCALE_FOUND OR ROCKCHIP_FOUND OR X11_FOUND)
|
||||||
list(APPEND MOONLIGHT_DEFINITIONS HAVE_EMBEDDED)
|
list(APPEND MOONLIGHT_DEFINITIONS HAVE_EMBEDDED)
|
||||||
list(APPEND MOONLIGHT_OPTIONS EMBEDDED)
|
list(APPEND MOONLIGHT_OPTIONS EMBEDDED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT AMLOGIC_FOUND AND NOT BROADCOM_FOUND AND NOT FREESCALE_FOUND AND NOT SOFTWARE_FOUND)
|
if(NOT AMLOGIC_FOUND AND NOT BROADCOM_FOUND AND NOT FREESCALE_FOUND AND NOT ROCKCHIP_FOUND AND NOT SOFTWARE_FOUND)
|
||||||
message(FATAL_ERROR "No video output available")
|
message(FATAL_ERROR "No video output available")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
29
cmake/FindRockchip.cmake
Normal file
29
cmake/FindRockchip.cmake
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
find_path(DRM_INCLUDE_DIR
|
||||||
|
NAMES drm.h
|
||||||
|
DOC "libdrm include directory"
|
||||||
|
PATHS /usr/local/include/libdrm /usr/include/libdrm /usr/include)
|
||||||
|
mark_as_advanced(DRM_INCLUDE_DIR)
|
||||||
|
|
||||||
|
find_path(DRM_LIBRARY
|
||||||
|
NAMES libdrm.so
|
||||||
|
DOC "Path to libdrm Library"
|
||||||
|
PATHS /usr/local/lib /usr/lib /usr/lib/aarch64-linux-gnu /usr/lib/arm-linux-gnueabihf)
|
||||||
|
mark_as_advanced(DRM_INCLUDE_DIR)
|
||||||
|
|
||||||
|
find_path(ROCKCHIP_INCLUDE_DIR
|
||||||
|
NAMES rk_mpi.h
|
||||||
|
DOC "Rockchip include directory"
|
||||||
|
PATHS /usr/local/include/rockchip /usr/include/rockchip /usr/include)
|
||||||
|
mark_as_advanced(ROCKCHIP_INCLUDE_DIR)
|
||||||
|
|
||||||
|
find_library(ROCKCHIP_LIBRARY
|
||||||
|
NAMES librockchip_mpp.so
|
||||||
|
DOC "Path to Rockchip Media Process Platform Library"
|
||||||
|
PATHS /usr/local/lib /usr/lib /usr/lib/aarch64-linux-gnu /usr/lib/arm-linux-gnueabihf)
|
||||||
|
mark_as_advanced(ROCKCHIP_LIBRARY)
|
||||||
|
|
||||||
|
include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Rockchip DEFAULT_MSG ROCKCHIP_INCLUDE_DIR ROCKCHIP_LIBRARY)
|
||||||
|
|
||||||
|
set(ROCKCHIP_INCLUDE_DIRS ${ROCKCHIP_INCLUDE_DIR} ${DRM_INCLUDE_DIR})
|
||||||
|
set(ROCKCHIP_LIBRARIES ${ROCKCHIP_LIBRARY} ${DRM_LIBRARY})
|
@ -46,6 +46,7 @@
|
|||||||
## Select the audio and video decoder to use
|
## Select the audio and video decoder to use
|
||||||
## default - autodetect
|
## default - autodetect
|
||||||
## aml - hardware video decoder for ODROID-C1/C2
|
## aml - hardware video decoder for ODROID-C1/C2
|
||||||
|
## rk - hardware video decoder for ODROID-N1 Rockchip
|
||||||
## omx - hardware video decoder for Raspberry Pi
|
## omx - hardware video decoder for Raspberry Pi
|
||||||
## imx - hardware video decoder for i.MX6 devices
|
## imx - hardware video decoder for i.MX6 devices
|
||||||
## x11 - software decoder
|
## x11 - software decoder
|
||||||
|
@ -163,7 +163,7 @@ static void help() {
|
|||||||
printf("\t-surround\t\tStream 5.1 surround sound (requires GFE 2.7)\n");
|
printf("\t-surround\t\tStream 5.1 surround sound (requires GFE 2.7)\n");
|
||||||
printf("\t-keydir <directory>\tLoad encryption keys from directory\n");
|
printf("\t-keydir <directory>\tLoad encryption keys from directory\n");
|
||||||
printf("\t-mapping <file>\t\tUse <file> as gamepad mappings configuration file\n");
|
printf("\t-mapping <file>\t\tUse <file> as gamepad mappings configuration file\n");
|
||||||
printf("\t-platform <system>\tSpecify system used for audio, video and input: pi/imx/aml/x11/x11_vdpau/sdl/fake (default auto)\n");
|
printf("\t-platform <system>\tSpecify system used for audio, video and input: pi/imx/aml/rk/x11/x11_vdpau/sdl/fake (default auto)\n");
|
||||||
printf("\t-unsupported\t\tTry streaming if GFE version or options are unsupported\n");
|
printf("\t-unsupported\t\tTry streaming if GFE version or options are unsupported\n");
|
||||||
#if defined(HAVE_SDL) || defined(HAVE_X11)
|
#if defined(HAVE_SDL) || defined(HAVE_X11)
|
||||||
printf("\n WM options (SDL and X11 only)\n\n");
|
printf("\n WM options (SDL and X11 only)\n\n");
|
||||||
|
@ -59,6 +59,13 @@ enum platform platform_check(char* name) {
|
|||||||
return AML;
|
return AML;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_ROCKCHIP
|
||||||
|
if (std || strcmp(name, "rk") == 0) {
|
||||||
|
void *handle = dlopen("libmoonlight-rk.so", RTLD_NOW | RTLD_GLOBAL);
|
||||||
|
if (handle != NULL && dlsym(RTLD_DEFAULT, "mpp_init") != NULL)
|
||||||
|
return RK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef HAVE_X11
|
#ifdef HAVE_X11
|
||||||
bool x11 = strcmp(name, "x11") == 0;
|
bool x11 = strcmp(name, "x11") == 0;
|
||||||
bool vdpau = strcmp(name, "x11_vdpau") == 0;
|
bool vdpau = strcmp(name, "x11_vdpau") == 0;
|
||||||
@ -148,6 +155,10 @@ DECODER_RENDERER_CALLBACKS* platform_get_video(enum platform system) {
|
|||||||
case AML:
|
case AML:
|
||||||
return (PDECODER_RENDERER_CALLBACKS) dlsym(RTLD_DEFAULT, "decoder_callbacks_aml");
|
return (PDECODER_RENDERER_CALLBACKS) dlsym(RTLD_DEFAULT, "decoder_callbacks_aml");
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_ROCKCHIP
|
||||||
|
case RK:
|
||||||
|
return (PDECODER_RENDERER_CALLBACKS) dlsym(RTLD_DEFAULT, "decoder_callbacks_rk");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -178,6 +189,7 @@ AUDIO_RENDERER_CALLBACKS* platform_get_audio(enum platform system, char* audio_d
|
|||||||
bool platform_supports_hevc(enum platform system) {
|
bool platform_supports_hevc(enum platform system) {
|
||||||
switch (system) {
|
switch (system) {
|
||||||
case AML:
|
case AML:
|
||||||
|
case RK:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -191,6 +203,8 @@ char* platform_name(enum platform system) {
|
|||||||
return "i.MX6 (MXC Vivante)";
|
return "i.MX6 (MXC Vivante)";
|
||||||
case AML:
|
case AML:
|
||||||
return "AMLogic VPU";
|
return "AMLogic VPU";
|
||||||
|
case RK:
|
||||||
|
return "Rockchip VPU";
|
||||||
case X11:
|
case X11:
|
||||||
return "X Window System (software decoding)";
|
return "X Window System (software decoding)";
|
||||||
case X11_VAAPI:
|
case X11_VAAPI:
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
#define IS_EMBEDDED(SYSTEM) SYSTEM != SDL
|
#define IS_EMBEDDED(SYSTEM) SYSTEM != SDL
|
||||||
|
|
||||||
enum platform { NONE, SDL, X11, X11_VDPAU, X11_VAAPI, PI, IMX, AML, FAKE };
|
enum platform { NONE, SDL, X11, X11_VDPAU, X11_VAAPI, PI, IMX, AML, RK, FAKE };
|
||||||
|
|
||||||
enum platform platform_check(char*);
|
enum platform platform_check(char*);
|
||||||
PDECODER_RENDERER_CALLBACKS platform_get_video(enum platform system);
|
PDECODER_RENDERER_CALLBACKS platform_get_video(enum platform system);
|
||||||
|
484
src/video/rk.c
Normal file
484
src/video/rk.c
Normal file
@ -0,0 +1,484 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Moonlight Embedded.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015-2018 Iwan Timmer
|
||||||
|
* Copyright (C) 2018 Martin Cerveny, Daniel Mehrwald
|
||||||
|
*
|
||||||
|
* Moonlight is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Moonlight is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Limelight.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <xf86drm.h>
|
||||||
|
#include <xf86drmMode.h>
|
||||||
|
#include <libdrm/drm_fourcc.h>
|
||||||
|
|
||||||
|
#include <rockchip/rk_mpi.h>
|
||||||
|
|
||||||
|
#define READ_BUF_SIZE (SZ_1M)
|
||||||
|
#define MAX_FRAMES 16
|
||||||
|
#define RK_H264 7
|
||||||
|
#define RK_H265 16777220
|
||||||
|
|
||||||
|
void *pkt_buf = NULL;
|
||||||
|
int fd;
|
||||||
|
int fb_id;
|
||||||
|
uint32_t plane_id, crtc_id;
|
||||||
|
int frm_eos;
|
||||||
|
int crtc_width;
|
||||||
|
int crtc_height;
|
||||||
|
RK_U32 frm_width;
|
||||||
|
RK_U32 frm_height;
|
||||||
|
int fb_x, fb_y, fb_width, fb_height;
|
||||||
|
|
||||||
|
pthread_t tid_frame, tid_display;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
pthread_cond_t cond;
|
||||||
|
|
||||||
|
drmModePlane *ovr = NULL;
|
||||||
|
drmModeEncoder *encoder = NULL;
|
||||||
|
drmModeConnector *connector = NULL;
|
||||||
|
drmModeRes *resources = NULL;
|
||||||
|
drmModePlaneRes *plane_resources = NULL;
|
||||||
|
drmModeCrtcPtr crtc = {0};
|
||||||
|
|
||||||
|
MppCtx mpi_ctx;
|
||||||
|
MppApi *mpi_api;
|
||||||
|
MppPacket mpi_packet;
|
||||||
|
MppBufferGroup mpi_frm_grp;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int prime_fd;
|
||||||
|
int fb_id;
|
||||||
|
uint32_t handle;
|
||||||
|
} frame_to_drm[MAX_FRAMES];
|
||||||
|
|
||||||
|
void *display_thread(void *param) {
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
while (!frm_eos) {
|
||||||
|
int _fb_id;
|
||||||
|
|
||||||
|
ret = pthread_mutex_lock(&mutex);
|
||||||
|
assert(!ret);
|
||||||
|
while (fb_id == 0) {
|
||||||
|
pthread_cond_wait(&cond, &mutex);
|
||||||
|
assert(!ret);
|
||||||
|
if (fb_id == 0 && frm_eos) {
|
||||||
|
ret = pthread_mutex_unlock(&mutex);
|
||||||
|
assert(!ret);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_fb_id = fb_id;
|
||||||
|
|
||||||
|
fb_id = 0;
|
||||||
|
ret = pthread_mutex_unlock(&mutex);
|
||||||
|
assert(!ret);
|
||||||
|
|
||||||
|
// show DRM FB in overlay plane (auto vsynced/atomic !)
|
||||||
|
ret = drmModeSetPlane(fd, plane_id, crtc_id, _fb_id, 0,
|
||||||
|
fb_x, fb_y, fb_width, fb_height,
|
||||||
|
0, 0, frm_width << 16, frm_height << 16);
|
||||||
|
assert(!ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *frame_thread(void *param) {
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
MppFrame frame = NULL;
|
||||||
|
|
||||||
|
while (!frm_eos) {
|
||||||
|
|
||||||
|
ret = mpi_api->decode_get_frame(mpi_ctx, &frame);
|
||||||
|
if (ret != MPP_OK && ret != MPP_ERR_TIMEOUT) {
|
||||||
|
if (count < 3) {
|
||||||
|
fprintf(stderr, "Waiting for Frame (return code = %d, retry count = %d)\n", ret, count);
|
||||||
|
usleep(10000);
|
||||||
|
count++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (frame) {
|
||||||
|
if (mpp_frame_get_info_change(frame)) {
|
||||||
|
// new resolution
|
||||||
|
assert(!mpi_frm_grp);
|
||||||
|
|
||||||
|
frm_width = mpp_frame_get_width(frame);
|
||||||
|
frm_height = mpp_frame_get_height(frame);
|
||||||
|
RK_U32 hor_stride = mpp_frame_get_hor_stride(frame);
|
||||||
|
RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
|
||||||
|
MppFrameFormat fmt = mpp_frame_get_fmt(frame);
|
||||||
|
assert((fmt == MPP_FMT_YUV420SP) || (fmt == MPP_FMT_YUV420SP_10BIT));
|
||||||
|
|
||||||
|
// position overlay, scale to ratio
|
||||||
|
float crt_ratio = (float)crtc_width/crtc_height;
|
||||||
|
float frame_ratio = (float)frm_width/frm_height;
|
||||||
|
|
||||||
|
if (crt_ratio>frame_ratio) {
|
||||||
|
fb_width = frame_ratio/crt_ratio*crtc_width;
|
||||||
|
fb_height = crtc_height;
|
||||||
|
fb_x = (crtc_width-fb_width)/2;
|
||||||
|
fb_y = 0;
|
||||||
|
} else {
|
||||||
|
fb_width = crtc_width;
|
||||||
|
fb_height = crt_ratio/frame_ratio*crtc_height;
|
||||||
|
fb_x = 0;
|
||||||
|
fb_y = (crtc_height-fb_height)/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create new external frame group and allocate (commit flow) new DRM buffers and DRM FB
|
||||||
|
assert(!mpi_frm_grp);
|
||||||
|
ret = mpp_buffer_group_get_external(&mpi_frm_grp, MPP_BUFFER_TYPE_DRM);
|
||||||
|
assert(!ret);
|
||||||
|
for (i = 0; i < MAX_FRAMES; i++) {
|
||||||
|
|
||||||
|
// new DRM buffer
|
||||||
|
struct drm_mode_create_dumb dmcd = {0};
|
||||||
|
dmcd.bpp = fmt == MPP_FMT_YUV420SP ? 8:10;
|
||||||
|
dmcd.width = hor_stride;
|
||||||
|
dmcd.height = ver_stride * 2; // documentation say not v*2/3 but v*2 (additional info included)
|
||||||
|
do {
|
||||||
|
ret = ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &dmcd);
|
||||||
|
} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
|
||||||
|
assert(!ret);
|
||||||
|
assert(dmcd.pitch == (fmt == MPP_FMT_YUV420SP?hor_stride:hor_stride * 10 / 8));
|
||||||
|
assert(dmcd.size == (fmt == MPP_FMT_YUV420SP?hor_stride:hor_stride * 10 / 8) * ver_stride * 2);
|
||||||
|
frame_to_drm[i].handle = dmcd.handle;
|
||||||
|
|
||||||
|
// commit DRM buffer to frame group
|
||||||
|
struct drm_prime_handle dph = {0};
|
||||||
|
dph.handle = dmcd.handle;
|
||||||
|
dph.fd = -1;
|
||||||
|
do {
|
||||||
|
ret = ioctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &dph);
|
||||||
|
} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
|
||||||
|
assert(!ret);
|
||||||
|
MppBufferInfo info = {0};
|
||||||
|
info.type = MPP_BUFFER_TYPE_DRM;
|
||||||
|
info.size = dmcd.width * dmcd.height;
|
||||||
|
info.fd = dph.fd;
|
||||||
|
ret = mpp_buffer_commit(mpi_frm_grp, &info);
|
||||||
|
assert(!ret);
|
||||||
|
frame_to_drm[i].prime_fd = info.fd; // dups fd
|
||||||
|
|
||||||
|
// allocate DRM FB from DRM buffer
|
||||||
|
uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
|
||||||
|
handles[0] = frame_to_drm[i].handle;
|
||||||
|
offsets[0] = 0;
|
||||||
|
pitches[0] = hor_stride;
|
||||||
|
handles[1] = frame_to_drm[i].handle;
|
||||||
|
offsets[1] = hor_stride * ver_stride;
|
||||||
|
pitches[1] = hor_stride;
|
||||||
|
ret = drmModeAddFB2(fd, frm_width, frm_height, fmt == MPP_FMT_YUV420SP ? DRM_FORMAT_NV12:DRM_FORMAT_NV12_10, handles, pitches, offsets, &frame_to_drm[i].fb_id, 0);
|
||||||
|
assert(!ret);
|
||||||
|
}
|
||||||
|
// register external frame group
|
||||||
|
ret = mpi_api->control(mpi_ctx, MPP_DEC_SET_EXT_BUF_GROUP, mpi_frm_grp);
|
||||||
|
ret = mpi_api->control(mpi_ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// regular frame received
|
||||||
|
|
||||||
|
MppBuffer buffer = mpp_frame_get_buffer(frame);
|
||||||
|
if (buffer) {
|
||||||
|
// find fb_id by frame prime_fd
|
||||||
|
MppBufferInfo info;
|
||||||
|
ret = mpp_buffer_info_get(buffer, &info);
|
||||||
|
assert(!ret);
|
||||||
|
for (i = 0; i < MAX_FRAMES; i++) {
|
||||||
|
if (frame_to_drm[i].prime_fd == info.fd) break;
|
||||||
|
}
|
||||||
|
assert(i != MAX_FRAMES);
|
||||||
|
// send DRM FB to display thread
|
||||||
|
ret = pthread_mutex_lock(&mutex);
|
||||||
|
assert(!ret);
|
||||||
|
fb_id = frame_to_drm[i].fb_id;
|
||||||
|
ret = pthread_cond_signal(&cond);
|
||||||
|
assert(!ret);
|
||||||
|
ret = pthread_mutex_unlock(&mutex);
|
||||||
|
assert(!ret);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Frame no buff\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frm_eos = mpp_frame_get_eos(frame);
|
||||||
|
mpp_frame_deinit(&frame);
|
||||||
|
frame = NULL;
|
||||||
|
} else {
|
||||||
|
if (!frm_eos) {
|
||||||
|
fprintf(stderr, "Didn't get frame from MPP (return code = %d)\n", ret);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rk_setup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
int format = 0;
|
||||||
|
|
||||||
|
switch (videoFormat) {
|
||||||
|
case VIDEO_FORMAT_H264:
|
||||||
|
format = RK_H264;
|
||||||
|
break;
|
||||||
|
case VIDEO_FORMAT_H265:
|
||||||
|
format = RK_H265;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Video format not supported\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MppCodingType mpp_type = (MppCodingType)format;
|
||||||
|
ret = mpp_check_support_format(MPP_CTX_DEC, mpp_type);
|
||||||
|
assert(!ret);
|
||||||
|
|
||||||
|
fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
|
||||||
|
assert(fd >= 0);
|
||||||
|
|
||||||
|
resources = drmModeGetResources(fd);
|
||||||
|
assert(resources);
|
||||||
|
|
||||||
|
// find active monitor
|
||||||
|
for (i = 0; i < resources->count_connectors; ++i) {
|
||||||
|
connector = drmModeGetConnector(fd, resources->connectors[i]);
|
||||||
|
if (!connector) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (connector->connection == DRM_MODE_CONNECTED && connector->count_modes > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
drmModeFreeConnector(connector);
|
||||||
|
}
|
||||||
|
assert(i < resources->count_connectors);
|
||||||
|
|
||||||
|
for (i = 0; i < resources->count_encoders; ++i) {
|
||||||
|
encoder = drmModeGetEncoder(fd, resources->encoders[i]);
|
||||||
|
if (!encoder) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (encoder->encoder_id == connector->encoder_id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
drmModeFreeEncoder(encoder);
|
||||||
|
}
|
||||||
|
assert(i < resources->count_encoders);
|
||||||
|
|
||||||
|
for (i = 0; i < resources->count_crtcs; ++i) {
|
||||||
|
if (resources->crtcs[i] == encoder->crtc_id) {
|
||||||
|
crtc = drmModeGetCrtc(fd, resources->crtcs[i]);
|
||||||
|
assert(crtc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(i < resources->count_crtcs);
|
||||||
|
crtc_id = crtc->crtc_id;
|
||||||
|
crtc_width = crtc->width;
|
||||||
|
crtc_height = crtc->height;
|
||||||
|
uint32_t crtc_bit = (1 << i);
|
||||||
|
|
||||||
|
ret = drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
|
||||||
|
assert(!ret);
|
||||||
|
plane_resources = drmModeGetPlaneResources(fd);
|
||||||
|
assert(plane_resources);
|
||||||
|
|
||||||
|
// search for OVERLAY (for active connector, unused, NV12 support)
|
||||||
|
for (i = 0; i < plane_resources->count_planes; i++) {
|
||||||
|
ovr = drmModeGetPlane(fd, plane_resources->planes[i]);
|
||||||
|
if (!ovr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (j = 0; j < ovr->count_formats; j++) {
|
||||||
|
if (ovr->formats[j] == DRM_FORMAT_NV12) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j == ovr->count_formats) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((ovr->possible_crtcs & crtc_bit) && !ovr->crtc_id) {
|
||||||
|
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(fd, plane_resources->planes[i], DRM_MODE_OBJECT_PLANE);
|
||||||
|
if (!props) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < props->count_props && !plane_id; j++) {
|
||||||
|
drmModePropertyPtr prop = drmModeGetProperty(fd, props->props[j]);
|
||||||
|
if (!prop) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(prop->name, "type") && props->prop_values[j] == DRM_PLANE_TYPE_OVERLAY) {
|
||||||
|
plane_id = ovr->plane_id;
|
||||||
|
}
|
||||||
|
drmModeFreeProperty(prop);
|
||||||
|
}
|
||||||
|
drmModeFreeObjectProperties(props);
|
||||||
|
if (plane_id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drmModeFreePlane(ovr);
|
||||||
|
}
|
||||||
|
assert(plane_id);
|
||||||
|
|
||||||
|
// disable cursor
|
||||||
|
drmModeSetCursor(fd, crtc_id, 0, 0, 0);
|
||||||
|
|
||||||
|
// MPI SETUP
|
||||||
|
|
||||||
|
pkt_buf = malloc(READ_BUF_SIZE);
|
||||||
|
assert(pkt_buf);
|
||||||
|
ret = mpp_packet_init(&mpi_packet, pkt_buf, READ_BUF_SIZE);
|
||||||
|
assert(!ret);
|
||||||
|
|
||||||
|
ret = mpp_create(&mpi_ctx, &mpi_api);
|
||||||
|
assert(!ret);
|
||||||
|
|
||||||
|
// decoder split mode (multi-data-input) need to be set before init
|
||||||
|
int param = 1;
|
||||||
|
ret = mpi_api->control(mpi_ctx, MPP_DEC_SET_PARSER_SPLIT_MODE, ¶m);
|
||||||
|
assert(!ret);
|
||||||
|
|
||||||
|
ret = mpp_init(mpi_ctx, MPP_CTX_DEC, mpp_type);
|
||||||
|
assert(!ret);
|
||||||
|
|
||||||
|
// set blocked read on Frame Thread
|
||||||
|
param = MPP_POLL_BLOCK;
|
||||||
|
ret = mpi_api->control(mpi_ctx, MPP_SET_OUTPUT_BLOCK, ¶m);
|
||||||
|
assert(!ret);
|
||||||
|
|
||||||
|
ret = pthread_mutex_init(&mutex, NULL);
|
||||||
|
assert(!ret);
|
||||||
|
ret = pthread_cond_init(&cond, NULL);
|
||||||
|
assert(!ret);
|
||||||
|
|
||||||
|
ret = pthread_create(&tid_frame, NULL, frame_thread, NULL);
|
||||||
|
assert(!ret);
|
||||||
|
ret = pthread_create(&tid_display, NULL, display_thread, NULL);
|
||||||
|
assert(!ret);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk_cleanup() {
|
||||||
|
|
||||||
|
int i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
frm_eos = 1;
|
||||||
|
ret = pthread_mutex_lock(&mutex);
|
||||||
|
assert(!ret);
|
||||||
|
ret = pthread_cond_signal(&cond);
|
||||||
|
assert(!ret);
|
||||||
|
ret = pthread_mutex_unlock(&mutex);
|
||||||
|
assert(!ret);
|
||||||
|
|
||||||
|
ret = pthread_join(tid_display, NULL);
|
||||||
|
assert(!ret);
|
||||||
|
|
||||||
|
ret = pthread_cond_destroy(&cond);
|
||||||
|
assert(!ret);
|
||||||
|
ret = pthread_mutex_destroy(&mutex);
|
||||||
|
assert(!ret);
|
||||||
|
|
||||||
|
ret = mpi_api->reset(mpi_ctx);
|
||||||
|
assert(!ret);
|
||||||
|
|
||||||
|
ret = pthread_join(tid_frame, NULL);
|
||||||
|
assert(!ret);
|
||||||
|
|
||||||
|
if (mpi_frm_grp) {
|
||||||
|
ret = mpp_buffer_group_put(mpi_frm_grp);
|
||||||
|
assert(!ret);
|
||||||
|
mpi_frm_grp = NULL;
|
||||||
|
for (i = 0; i < MAX_FRAMES; i++) {
|
||||||
|
ret = drmModeRmFB(fd, frame_to_drm[i].fb_id);
|
||||||
|
assert(!ret);
|
||||||
|
struct drm_mode_destroy_dumb dmdd = {0};
|
||||||
|
dmdd.handle = frame_to_drm[i].handle;
|
||||||
|
do {
|
||||||
|
ret = ioctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dmdd);
|
||||||
|
} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
|
||||||
|
assert(!ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mpp_packet_deinit(&mpi_packet);
|
||||||
|
mpp_destroy(mpi_ctx);
|
||||||
|
free(pkt_buf);
|
||||||
|
|
||||||
|
drmModeFreePlane(ovr);
|
||||||
|
drmModeFreePlaneResources(plane_resources);
|
||||||
|
drmModeFreeEncoder(encoder);
|
||||||
|
drmModeFreeConnector(connector);
|
||||||
|
drmModeFreeCrtc(crtc);
|
||||||
|
drmModeFreeResources(resources);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rk_submit_decode_unit(PDECODE_UNIT decodeUnit) {
|
||||||
|
|
||||||
|
int result = DR_OK;
|
||||||
|
|
||||||
|
if (decodeUnit->fullLength < READ_BUF_SIZE) {
|
||||||
|
PLENTRY entry = decodeUnit->bufferList;
|
||||||
|
int length = 0;
|
||||||
|
while (entry != NULL) {
|
||||||
|
memcpy(pkt_buf+length, entry->data, entry->length);
|
||||||
|
length += entry->length;
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
if (length) {
|
||||||
|
mpp_packet_set_pos(mpi_packet, pkt_buf);
|
||||||
|
mpp_packet_set_length(mpi_packet, length);
|
||||||
|
|
||||||
|
while (MPP_OK != mpi_api->decode_put_packet(mpi_ctx, mpi_packet))
|
||||||
|
;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DECODER_RENDERER_CALLBACKS decoder_callbacks_rk = {
|
||||||
|
.setup = rk_setup,
|
||||||
|
.cleanup = rk_cleanup,
|
||||||
|
.submitDecodeUnit = rk_submit_decode_unit,
|
||||||
|
.capabilities = CAPABILITY_DIRECT_SUBMIT,
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user