Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AML] HEVC, S805 and S812 board support #5533

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
173 changes: 170 additions & 3 deletions xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.cpp
Expand Up @@ -274,6 +274,9 @@ class DllLibAmCodec : public DllDynamic, DllLibamCodecInterface
#define CODEC_TAG_mjpeg (0x47504a4c)
#define CODEC_TAG_jpeg (0x6765706a)
#define CODEC_TAG_mjpa (0x61706a6d)
#define CODEC_TAG_HEVC (0x43564548)
#define CODEC_TAG_hvc1 (0x31637668)
#define CODEC_TAG_hev1 (0x31766568)

#define RW_WAIT_TIME (20 * 1000) // 20ms

Expand Down Expand Up @@ -450,6 +453,9 @@ static vformat_t codecid_to_vformat(enum AVCodecID id)
case AV_CODEC_ID_H264:
format = VFORMAT_H264;
break;
case AV_CODEC_ID_HEVC:
format = VFORMAT_HEVC;
break;
/*
case AV_CODEC_ID_H264MVC:
// H264 Multiview Video Coding (3d blurays)
Expand Down Expand Up @@ -576,6 +582,10 @@ static vdec_type_t codec_tag_to_vdec_type(unsigned int codec_tag)
// avs
dec_type = VIDEO_DEC_FORMAT_AVS;
break;
case AV_CODEC_ID_HEVC:
// h265
dec_type = VIDEO_DEC_FORMAT_HEVC;
break;
default:
dec_type = VIDEO_DEC_FORMAT_UNKNOW;
break;
Expand Down Expand Up @@ -775,6 +785,58 @@ int write_av_packet(am_private_t *para, am_packet_t *pkt)
}

/*************************************************************************/

static int check_size_in_buffer(unsigned char *p, int len)

This comment was marked as spam.

{
unsigned int size;
unsigned char *q = p;
while ((q + 4) < (p + len)) {
size = (*q << 24) | (*(q + 1) << 16) | (*(q + 2) << 8) | (*(q + 3));
if (size & 0xff000000) {
return 0;
}

if (q + size + 4 == p + len) {
return 1;
}

q += size + 4;
}
return 0;
}

static int check_size_in_buffer3(unsigned char *p, int len)
{
unsigned int size;
unsigned char *q = p;
while ((q + 3) < (p + len)) {
size = (*q << 16) | (*(q + 1) << 8) | (*(q + 2));

if (q + size + 3 == p + len) {
return 1;
}

q += size + 3;
}
return 0;
}

static int check_size_in_buffer2(unsigned char *p, int len)
{
unsigned int size;
unsigned char *q = p;
while ((q + 2) < (p + len)) {
size = (*q << 8) | (*(q + 1));

if (q + size + 2 == p + len) {
return 1;
}

q += size + 2;
}
return 0;
}

static int m4s2_dx50_mp4v_add_header(unsigned char *buf, int size, am_packet_t *pkt)
{
if (size > pkt->hdr->size) {
Expand Down Expand Up @@ -895,6 +957,98 @@ static int divx3_data_prefeeding(am_packet_t *pkt, unsigned w, unsigned h)
return PLAYER_SUCCESS;
}

static int h264_update_frame_header(am_packet_t *pkt)

This comment was marked as spam.

{
int nalsize, size = pkt->data_size;
unsigned char *data = pkt->data;
unsigned char *p = data;
if (p != NULL) {
if (check_size_in_buffer(p, size)) {
while ((p + 4) < (data + size)) {
nalsize = (*p << 24) | (*(p + 1) << 16) | (*(p + 2) << 8) | (*(p + 3));
*p = 0;
*(p + 1) = 0;
*(p + 2) = 0;
*(p + 3) = 1;
p += (nalsize + 4);
}
return PLAYER_SUCCESS;
} else if (check_size_in_buffer3(p, size)) {
while ((p + 3) < (data + size)) {
nalsize = (*p << 16) | (*(p + 1) << 8) | (*(p + 2));
*p = 0;
*(p + 1) = 0;
*(p + 2) = 1;
p += (nalsize + 3);
}
return PLAYER_SUCCESS;
} else if (check_size_in_buffer2(p, size)) {
unsigned char *new_data;
int new_len = 0;

new_data = (unsigned char *)malloc(size + 2 * 1024);
if (!new_data) {
return PLAYER_NOMEM;
}

while ((p + 2) < (data + size)) {
nalsize = (*p << 8) | (*(p + 1));
*(new_data + new_len) = 0;
*(new_data + new_len + 1) = 0;
*(new_data + new_len + 2) = 0;
*(new_data + new_len + 3) = 1;
memcpy(new_data + new_len + 4, p + 2, nalsize);
p += (nalsize + 2);
new_len += nalsize + 4;
}

free(pkt->buf);

pkt->buf = new_data;
pkt->buf_size = size + 2 * 1024;
pkt->data = pkt->buf;
pkt->data_size = new_len;
}
} else {
CLog::Log(LOGERROR, "[%s]invalid pointer!\n", __FUNCTION__);
return PLAYER_FAILED;
}
return PLAYER_SUCCESS;
}

static int hevc_update_frame_header(am_packet_t * pkt)
{
unsigned char *p = pkt->data;
// NAL has been formatted already, no need to update
if (p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 1) {
return PLAYER_SUCCESS;
}
// process like h264 for now.
return h264_update_frame_header(pkt);
}

static int hevc_add_header(unsigned char *buf, int size, am_packet_t *pkt)
{
memcpy(pkt->hdr->data, buf, size);
pkt->hdr->size = size;
return PLAYER_SUCCESS;
}

static int hevc_write_header(am_private_t *para, am_packet_t *pkt)
{
int ret = -1;

if (para->extradata) {
ret = hevc_add_header(para->extradata, para->extrasize, pkt);
}
if (ret == PLAYER_SUCCESS) {
pkt->codec = &para->vcodec;
pkt->newflag = 1;
ret = write_av_packet(para, pkt);
}
return ret;
}

static int divx3_write_header(am_private_t *para, am_packet_t *pkt)
{
CLog::Log(LOGDEBUG, "divx3_write_header");
Expand Down Expand Up @@ -1074,6 +1228,11 @@ int pre_header_feeding(am_private_t *para, am_packet_t *pkt)
if (ret != PLAYER_SUCCESS) {
return ret;
}
} else if (VFORMAT_HEVC == para->video_format) {
ret = hevc_write_header(para, pkt);
if (ret != PLAYER_SUCCESS) {
return ret;
}
} else if ((VFORMAT_MPEG4 == para->video_format) && (VIDEO_DEC_FORMAT_MPEG4_3 == para->video_codec_type)) {
ret = divx3_write_header(para, pkt);
if (ret != PLAYER_SUCCESS) {
Expand Down Expand Up @@ -1399,6 +1558,8 @@ int set_header_info(am_private_t *para)
pkt->hdr->size = 4;
pkt->newflag = 1;
}
} else if (para->video_format == VFORMAT_HEVC) {
hevc_update_frame_header(pkt);
}
}
return PLAYER_SUCCESS;
Expand Down Expand Up @@ -1580,7 +1741,7 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints)
am_private->gcodec.param = (void*)(EXTERNAL_PTS | SYNC_OUTSIDE);
break;
case VFORMAT_H264_4K2K:
if (aml_get_device_type() == AML_DEVICE_TYPE_M8) {
if ((aml_get_device_type() == AML_DEVICE_TYPE_M8) || (aml_get_device_type() == AML_DEVICE_TYPE_M8M2)) {
am_private->gcodec.format = VIDEO_DEC_FORMAT_H264_4K2K;
am_private->gcodec.param = (void*)EXTERNAL_PTS;
// h264 in an avi file
Expand All @@ -1590,7 +1751,7 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints)
CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder codec init failed, 4K supported only on Meson8.");
return false;
}
break;
break;
case VFORMAT_REAL:
am_private->stream_type = AM_STREAM_RM;
am_private->vcodec.noblock = 1;
Expand Down Expand Up @@ -1619,6 +1780,12 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints)
if (m_hints.ptsinvalid)
am_private->gcodec.param = (void*)EXTERNAL_PTS;
break;
case VFORMAT_HEVC:
am_private->gcodec.format = VIDEO_DEC_FORMAT_HEVC;
am_private->gcodec.param = (void*)EXTERNAL_PTS;
if (m_hints.ptsinvalid)
am_private->gcodec.param = (void*)(EXTERNAL_PTS | SYNC_OUTSIDE);
break;
}
am_private->gcodec.param = (void *)((unsigned int)am_private->gcodec.param | (am_private->video_rotation_degree << 16));

Expand Down Expand Up @@ -1653,7 +1820,7 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints)
g_renderManager.RegisterRenderFeaturesCallBack((const void*)this, RenderFeaturesCallBack);

m_display_rect = g_graphicsContext.GetViewWindow();
if (aml_get_device_type() == AML_DEVICE_TYPE_M8)
if ((aml_get_device_type() == AML_DEVICE_TYPE_M8) || (aml_get_device_type() == AML_DEVICE_TYPE_M8B) || (aml_get_device_type() == AML_DEVICE_TYPE_M8M2))
{
char mode[256] = {0};
aml_get_sysfs_str("/sys/class/display/mode", mode, 255);
Expand Down
21 changes: 21 additions & 0 deletions xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAmlogic.cpp
Expand Up @@ -24,6 +24,7 @@
#include "DVDClock.h"
#include "DVDStreamInfo.h"
#include "AMLCodec.h"
#include "utils/AMLUtils.h"
#include "utils/BitstreamConverter.h"
#include "utils/log.h"

Expand Down Expand Up @@ -138,6 +139,26 @@ bool CDVDVideoCodecAmlogic::Open(CDVDStreamInfo &hints, CDVDCodecOptions &option
case AV_CODEC_ID_CAVS:
m_pFormatName = "am-avs";
break;
case AV_CODEC_ID_HEVC:
if ((aml_get_device_type() == AML_DEVICE_TYPE_M8B) || (aml_get_device_type() == AML_DEVICE_TYPE_M8M2)) {
if ((aml_get_device_type() == AML_DEVICE_TYPE_M8B) && ((m_hints.width > 1920) || (m_hints.height > 1088)))
{
// 4K HEVC is supported only on Amlogic S812 chip
return false;
}
} else {
// HEVC supported only on S805 and S812.
return false;
}
m_pFormatName = "am-h265";
m_bitstream = new CBitstreamConverter();
m_bitstream->Open(m_hints.codec, (uint8_t*)m_hints.extradata, m_hints.extrasize, true);
// make sure we do not leak the existing m_hints.extradata
free(m_hints.extradata);
m_hints.extrasize = m_bitstream->GetExtraSize();
m_hints.extradata = malloc(m_hints.extrasize);
memcpy(m_hints.extradata, m_bitstream->GetExtraData(), m_hints.extrasize);
break;
default:
CLog::Log(LOGDEBUG, "%s: Unknown hints.codec(%d", __MODULE_NAME__, m_hints.codec);
return false;
Expand Down
27 changes: 24 additions & 3 deletions xbmc/utils/AMLUtils.cpp
Expand Up @@ -159,6 +159,21 @@ void aml_permissions()
}
}

bool aml_support_hevc()
{
char valstr[1024];
if(aml_get_sysfs_str("/sys/class/amstream/vcodec_profile", valstr, 1024) != 0)
{
return false;
}
char* p = strstr(valstr, "hevc:");
if(p == NULL)
{
return false;
}
return true;
}

enum AML_DEVICE_TYPE aml_get_device_type()
{
static enum AML_DEVICE_TYPE aml_device_type = AML_DEVICE_TYPE_UNINIT;
Expand All @@ -173,8 +188,14 @@ enum AML_DEVICE_TYPE aml_get_device_type()
aml_device_type = AML_DEVICE_TYPE_M3;
else if (cpu_hardware.find("Meson6") != std::string::npos)
aml_device_type = AML_DEVICE_TYPE_M6;
else if (cpu_hardware.find("Meson8") != std::string::npos)
aml_device_type = AML_DEVICE_TYPE_M8;
else if ((cpu_hardware.find("Meson8") != std::string::npos) && (cpu_hardware.find("Meson8B") == std::string::npos))
{
if (aml_support_hevc())
aml_device_type = AML_DEVICE_TYPE_M8M2;
else
aml_device_type = AML_DEVICE_TYPE_M8;
} else if (cpu_hardware.find("Meson8B") != std::string::npos)
aml_device_type = AML_DEVICE_TYPE_M8B;
else
aml_device_type = AML_DEVICE_TYPE_UNKNOWN;
}
Expand Down Expand Up @@ -218,7 +239,7 @@ void aml_set_audio_passthrough(bool passthrough)
{
if ( aml_present()
&& aml_get_device_type() != AML_DEVICE_TYPE_UNKNOWN
&& aml_get_device_type() <= AML_DEVICE_TYPE_M8)
&& aml_get_device_type() <= AML_DEVICE_TYPE_M8M2)
{
// m1 uses 1, m3 and above uses 2
int raw = aml_get_device_type() == AML_DEVICE_TYPE_M1 ? 1:2;
Expand Down
5 changes: 4 additions & 1 deletion xbmc/utils/AMLUtils.h
Expand Up @@ -28,7 +28,9 @@ enum AML_DEVICE_TYPE
AML_DEVICE_TYPE_M1,
AML_DEVICE_TYPE_M3,
AML_DEVICE_TYPE_M6,
AML_DEVICE_TYPE_M8
AML_DEVICE_TYPE_M8,
AML_DEVICE_TYPE_M8B,
AML_DEVICE_TYPE_M8M2
};

int aml_set_sysfs_str(const char *path, const char *val);
Expand All @@ -40,6 +42,7 @@ bool aml_present();
void aml_permissions();
bool aml_hw3d_present();
bool aml_wired_present();
bool aml_support_hevc();
enum AML_DEVICE_TYPE aml_get_device_type();
void aml_cpufreq_min(bool limit);
void aml_cpufreq_max(bool limit);
Expand Down