Add: Amlogic hardware video decoder backend

This commit is contained in:
Daniel Mehrwald 2016-03-13 11:09:59 -04:00 committed by Iwan Timmer
parent 3943ba8cd8
commit c1f5a2a30e
10 changed files with 225 additions and 6 deletions

View File

@ -17,6 +17,7 @@ find_package(ALSA REQUIRED)
find_package(Opus REQUIRED)
find_package(Broadcom)
find_package(Freescale)
find_package(Amlogic)
find_package(PkgConfig REQUIRED)
pkg_check_modules(EVDEV REQUIRED libevdev)
@ -47,10 +48,17 @@ if(CMAKE_BUILD_TYPE MATCHES Debug)
list(APPEND SRC_LIST ./src/video/fake.c)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_FAKE LC_DEBUG)
list(APPEND MOONLIGHT_OPTIONS FAKE DEBUG)
elseif(NOT BROADCOM_FOUND AND NOT FREESCALE_FOUND AND NOT SOFTWARE_FOUND)
elseif(NOT AMLOGIC_FOUND AND NOT BROADCOM_FOUND AND NOT FREESCALE_FOUND AND NOT SOFTWARE_FOUND)
message(FATAL_ERROR "No video output available")
endif()
if (AMLOGIC_FOUND)
set(SOFTWARE_FOUND FALSE)
list(APPEND SRC_LIST ./src/video/aml.c)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_AML)
list(APPEND MOONLIGHT_OPTIONS AML)
endif()
if (SOFTWARE_FOUND)
list(APPEND SRC_LIST ./src/video/ffmpeg.c ./src/video/sdl.c ./src/audio/sdl.c)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_SDL)
@ -62,7 +70,7 @@ if (SOFTWARE_FOUND)
endif()
endif()
if (BROADCOM_FOUND OR FREESCALE_FOUND OR CMAKE_BUILD_TYPE MATCHES Debug)
if (AMLOGIC_FOUND OR BROADCOM_FOUND OR FREESCALE_FOUND OR CMAKE_BUILD_TYPE MATCHES Debug)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_EMBEDDED)
list(APPEND MOONLIGHT_OPTIONS EMBEDDED)
endif()
@ -90,6 +98,15 @@ if (CEC_FOUND)
target_link_libraries(moonlight ${CEC_LIBRARIES})
endif()
if(AMLOGIC_FOUND)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_AML)
list(APPEND MOONLIGHT_OPTIONS AML)
target_include_directories(moonlight PRIVATE ${AMLOGIC_INCLUDE_DIRS} ${GAMESTREAM_INCLUDE_DIR} ${MOONLIGHT_COMMON_INCLUDE_DIR})
target_link_libraries(moonlight gamestream ${AMLOGIC_LIBRARIES})
set_property(TARGET moonlight PROPERTY COMPILE_DEFINITIONS ${AMLOGIC_DEFINITIONS})
install(TARGETS moonlight DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
if(BROADCOM_FOUND)
list(APPEND MOONLIGHT_DEFINITIONS HAVE_PI)
list(APPEND MOONLIGHT_OPTIONS PI)

View File

@ -3,7 +3,7 @@
Moonlight Embedded is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield, but built for Linux.
Moonlight Embedded allows you to stream your full collection of Steam games from
your powerful Windows desktop to your (embedded) Linux system, like Raspberry Pi, CuBox-i and Hummingboard.
your powerful Windows desktop to your (embedded) Linux system, like ODROID, Raspberry Pi, CuBox-i and Hummingboard.
## Documentation
@ -14,7 +14,8 @@ More information about installing and runnning Moonlight Embedded is available o
* Streams Steam and all of your games from your PC to your embedded system.
* Use mDNS to scan for compatible GeForce Experience (GFE) machines on the network.
* Qwerty Keyboard, Mouse and Gamepad support
* Support hardware video decoding on Raspberry Pi and i.MX 6 devices
* Support H264 hardware video decoding on ODROID, Raspberry Pi and i.MX 6 devices
* Support HEVC hardware video decoding on ODROID C1/C2
## Requirements

29
cmake/FindAmlogic.cmake Normal file
View File

@ -0,0 +1,29 @@
find_path(AMLOGIC_INCLUDE_DIR
NAMES codec.h
DOC "Amlogic include directory"
PATHS /usr/local/include/amcodec /usr/include/amcodec)
mark_as_advanced(AMLOGIC_INCLUDE_DIR)
find_library(AMAVUTILS_LIBRARY
NAMES libamavutils.so
DOC "Path to Amlogic Audio Video Utils Library"
PATHS /usr/lib/aml_libs /usr/local/lib /usr/lib)
mark_as_advanced(AMAVUTILS_LIBRARY)
find_library(AMADEC_LIBRARY
NAMES libamadec.so
DOC "Path to Amlogic Audio Decoder Library"
PATHS /usr/lib/aml_libs /usr/local/lib /usr/lib)
mark_as_advanced(AMADEC_LIBRARY)
find_library(AMCODEC_LIBRARY
NAMES libamcodec.so
DOC "Path to Amlogic Video Codec Library"
PATHS /usr/lib/aml_libs /usr/local/lib /usr/lib)
mark_as_advanced(AMCODEC_LIBRARY)
include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Amlogic DEFAULT_MSG AMLOGIC_INCLUDE_DIR AMCODEC_LIBRARY AMADEC_LIBRARY AMAVUTILS_LIBRARY)
set(AMLOGIC_LIBRARIES ${AMCODEC_LIBRARY} ${AMADEC_LIBRARY} ${AMAVUTILS_LIBRARY})
set(AMLOGIC_INCLUDE_DIRS ${AMLOGIC_INCLUDE_DIR})

View File

@ -42,6 +42,7 @@
## Select the audio and video decoder to use
## default - autodetect
## aml - hardware video decoder for ODROID-C1/C2
## omx - hardware video decoder for Raspberry Pi
## imx - hardware video decoder for i.MX6 devices
## sdl - software decoder

View File

@ -63,6 +63,9 @@ static struct option long_options[] = {
{"surround", no_argument, NULL, 'u'},
{"fps", required_argument, NULL, 'v'},
{"forcehw", no_argument, NULL, 'w'},
#ifdef HAVE_AML
{"hevc", no_argument, NULL, 'x'},
#endif
{0, 0, 0, 0},
};
@ -199,6 +202,12 @@ static void parse_argument(int c, char* value, PCONFIGURATION config) {
break;
case 'w':
config->forcehw = true;
break;
#ifdef HAVE_AML
case 'x':
config->hevc = true;
break;
#endif
case 1:
if (config->action == NULL)
config->action = value;
@ -289,6 +298,7 @@ void config_parse(int argc, char* argv[], PCONFIGURATION config) {
config->sops = true;
config->localaudio = false;
config->fullscreen = true;
config->hevc = false;
config->inputsCount = 0;
config->mapping = get_path("mappings/default.conf", getenv("XDG_DATA_DIRS"));
@ -306,7 +316,7 @@ void config_parse(int argc, char* argv[], PCONFIGURATION config) {
} else {
int option_index = 0;
int c;
while ((c = getopt_long_only(argc, argv, "-abc:d:efg:h:i:j:k:lm:no:p:q:r:stuv:w", long_options, &option_index)) != -1) {
while ((c = getopt_long_only(argc, argv, "-abc:d:efg:h:i:j:k:lm:no:p:q:r:stuv:w:x", long_options, &option_index)) != -1) {
parse_argument(c, optarg, config);
}
}

View File

@ -43,6 +43,9 @@ typedef struct _CONFIGURATION {
bool forcehw;
struct input_config inputs[MAX_INPUTS];
int inputsCount;
#ifdef HAVE_AML
bool hevc;
#endif
} CONFIGURATION, *PCONFIGURATION;
bool inputAdded;

View File

@ -83,6 +83,11 @@ static void stream(PSERVER_DATA server, PCONFIGURATION config, enum platform sys
exit(-1);
}
// h265
if (config->hevc) {
config->stream.supportsHevc = 1;
}
int ret = gs_start_app(server, &config->stream, appId, config->sops, config->localaudio);
if (ret < 0) {
if (ret == GS_NOT_SUPPORTED_4K)
@ -154,6 +159,10 @@ static void help() {
printf("\t-audio <device>\t\tUse <device> as ALSA audio output device (default sysdefault)\n");
printf("\t-forcehw \t\tTry to use video hardware acceleration\n");
#endif
#ifdef HAVE_AML
printf("\n Amlogic Codec options\n\n");
printf("\t-hevc \t\tUse high efficiency video decoding (HEVC)\n");
#endif
printf("\nUse Ctrl+Alt+Shift+Q to exit streaming session\n\n");
exit(0);
}

View File

@ -52,6 +52,10 @@ enum platform platform_check(char* name) {
if (std || strcmp(name, "sdl") == 0)
return SDL;
#endif
#ifdef HAVE_AML
if (std || strcmp(name, "aml") == 0)
return AML;
#endif
#ifdef HAVE_FAKE
if (std || strcmp(name, "fake") == 0)
return FAKE;
@ -73,6 +77,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_AML
case AML:
return &decoder_callbacks_aml;
#endif
#ifdef HAVE_FAKE
case FAKE:
return &decoder_callbacks_fake;

View File

@ -25,12 +25,15 @@
#define IS_EMBEDDED(SYSTEM) SYSTEM != SDL
enum platform { NONE, SDL, PI, IMX, FAKE };
enum platform { NONE, SDL, PI, IMX, AML, FAKE };
enum platform platform_check(char*);
PDECODER_RENDERER_CALLBACKS platform_get_video(enum platform system);
PAUDIO_RENDERER_CALLBACKS platform_get_audio(enum platform system);
#ifdef HAVE_AML
extern DECODER_RENDERER_CALLBACKS decoder_callbacks_aml;
#endif
#ifdef HAVE_FAKE
extern DECODER_RENDERER_CALLBACKS decoder_callbacks_fake;
#endif

138
src/video/aml.c Normal file
View File

@ -0,0 +1,138 @@
/*
* This file is part of Moonlight Embedded.
*
* Copyright (C) 2015 Iwan Timmer
* Copyright (C) 2016 OtherCrashOverride, 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-common/Limelight.h"
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <amcodec/codec.h>
static codec_para_t codecParam = { 0 };
const size_t EXTERNAL_PTS = (1);
const size_t SYNC_OUTSIDE = (2);
int osd_blank(char *path,int cmd) {
int fd;
char bcmd[16];
fd = open(path, O_CREAT|O_RDWR | O_TRUNC, 0644);
if(fd>=0) {
sprintf(bcmd,"%d",cmd);
if (write(fd,bcmd,strlen(bcmd)) < 0) {
printf("osd_blank error during write.\n");
}
close(fd);
return 0;
}
return -1;
}
void init_display() {
osd_blank("/sys/class/graphics/fb0/blank",1);
osd_blank("/sys/class/graphics/fb1/blank",0);
}
void restore_display() {
osd_blank("/sys/class/graphics/fb0/blank",0);
osd_blank("/sys/class/graphics/fb1/blank",0);
}
void aml_setup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
fprintf(stderr, "\nvideoFormat=%d nwidth=%d, height=%d, redrawRate=%d, context=%p, drFlags=%x\n",
videoFormat, width, height, redrawRate, context, drFlags);
init_display();
codecParam.stream_type = STREAM_TYPE_ES_VIDEO;
codecParam.has_video = 1;
codecParam.noblock = 0;
switch (videoFormat) {
case VIDEO_FORMAT_H264: // 1
if (width > 1920 || height > 1080) {
codecParam.video_type = VFORMAT_H264_4K2K;
codecParam.am_sysinfo.format = VIDEO_DEC_FORMAT_H264_4K2K; ///< video format, such as H264, MPEG2...
} else {
codecParam.video_type = VFORMAT_H264;
codecParam.am_sysinfo.format = VIDEO_DEC_FORMAT_H264; ///< video format, such as H264, MPEG2...
}
fprintf(stdout, "Decoding H264 video.\n");
break;
case VIDEO_FORMAT_H265: // 2
codecParam.video_type = VFORMAT_HEVC;
codecParam.am_sysinfo.format = VIDEO_DEC_FORMAT_HEVC; ///< video format, such as H264, MPEG2...
fprintf(stdout, "Decoding HEVC video.\n");
break;
default:
printf("Unsupported video format.\n");
exit(1);
}
codecParam.am_sysinfo.width = width; //< video source width
codecParam.am_sysinfo.height = height; //< video source height
codecParam.am_sysinfo.rate = (96000 / (redrawRate)); //< video source frame duration
codecParam.am_sysinfo.param = (void *)(EXTERNAL_PTS | SYNC_OUTSIDE); //< other parameters for video decoder
int api = codec_init(&codecParam);
fprintf(stdout, "codec_init=%x\n", api);
if (api != 0) {
fprintf(stderr, "codec_init failed.\n");
exit(1);
}
}
void aml_cleanup() {
int api = codec_close(&codecParam);
restore_display();
}
int aml_submit_decode_unit(PDECODE_UNIT decodeUnit) {
int result = DR_OK;
PLENTRY entry = decodeUnit->bufferList;
while (entry != NULL) {
int api = codec_write(&codecParam, entry->data, entry->length);
if (api != entry->length) {
fprintf(stderr, "codec_write error: %x\n", api);
codec_reset(&codecParam);
result = DR_NEED_IDR;
break;
}
entry = entry->next;
}
return result;
}
DECODER_RENDERER_CALLBACKS decoder_callbacks_aml = {
.setup = aml_setup,
.cleanup = aml_cleanup,
.submitDecodeUnit = aml_submit_decode_unit,
.capabilities = CAPABILITY_DIRECT_SUBMIT | CAPABILITY_SLICES_PER_FRAME(8),
};