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] Use amlvideo driver for audio/video sync #9896

Merged
merged 1 commit into from Jun 13, 2016
Merged
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
220 changes: 150 additions & 70 deletions xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.cpp
Expand Up @@ -54,12 +54,49 @@ extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>

// amcodec include
extern "C" {
#include <amcodec/codec.h>
} // extern "C"

class PosixFile
{
public:
PosixFile() :
m_fd(-1)
{
}

PosixFile(int fd) :
m_fd(fd)
{
}

~PosixFile()
{
if (m_fd >= 0)
close(m_fd);
}

bool Open(const std::string &pathName, int flags)
{
m_fd = open(pathName.c_str(), flags);
return m_fd >= 0;
}

int GetDescriptor() const { return m_fd; }

int IOControl(unsigned long request, void *param)
{
return ioctl(m_fd, request, param);
}

private:
int m_fd;
};

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

typedef struct {
bool noblock;
int video_pid;
Expand Down Expand Up @@ -364,27 +401,6 @@ void dumpfile_write(am_private_t *para, void* buf, int bufsiz)
write(para->dumpfile, buf, bufsiz);
}

/*************************************************************************/
/*************************************************************************/
static int64_t get_pts_video()
{
int fd = open("/sys/class/tsync/pts_video", O_RDONLY);
if (fd >= 0)
{
char pts_str[16];
int size = read(fd, pts_str, sizeof(pts_str));
close(fd);
if (size > 0)
{
unsigned long pts = strtoul(pts_str, NULL, 16);
return pts;
}
}

CLog::Log(LOGERROR, "get_pts_video: open /tsync/event error");
return -1;
}

static int set_pts_pcrscr(int64_t value)
{
int fd = open("/sys/class/tsync/pts_pcrscr", O_WRONLY);
Expand Down Expand Up @@ -1418,9 +1434,6 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints)
m_speed = DVD_PLAYSPEED_NORMAL;
m_1st_pts = 0;
m_cur_pts = 0;
m_player_pts = 0;
m_cur_pictcnt = 0;
m_old_pictcnt = 0;
m_dst_rect.SetRect(0, 0, 0, 0);
m_zoom = -1;
m_contrast = -1;
Expand All @@ -1430,6 +1443,12 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints)
m_start_pts = 0;
m_hints = hints;

if (!OpenAmlVideo(hints))
{
CLog::Log(LOGERROR, "CAMLCodec::OpenDecoder - cannot open amlvideo device");
return false;
}

ShowMainVideo(false);

am_packet_init(&am_private->am_pkt);
Expand Down Expand Up @@ -1657,6 +1676,53 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints)
return true;
}

bool CAMLCodec::OpenAmlVideo(const CDVDStreamInfo &hints)
{
PosixFilePtr amlVideoFile = std::make_shared<PosixFile>();

This comment was marked as spam.

This comment was marked as spam.

if (!amlVideoFile->Open("/dev/video10", O_RDONLY | O_NONBLOCK))
{
CLog::Log(LOGERROR, "CAMLCodec::OpenAmlVideo - cannot open V4L amlvideo device /dev/video10: %s", strerror(errno));
return false;
}

m_amlVideoFile = amlVideoFile;

m_defaultVfmMap = GetVfmMap("default");
SetVfmMap("default", "decoder ppmgr deinterlace amlvideo amvideo");

SysfsUtils::SetInt("/sys/module/amlvideodri/parameters/freerun_mode", 1);

This comment was marked as spam.

This comment was marked as spam.


return true;
}

std::string CAMLCodec::GetVfmMap(const std::string &name)
{
std::string vfmMap;
SysfsUtils::GetString("/sys/class/vfm/map", vfmMap);
std::vector<std::string> sections = StringUtils::Split(vfmMap, '\n');
std::string sectionMap;
for (size_t i = 0; i < sections.size(); ++i)
{
if (StringUtils::StartsWith(sections[i], name + " {"))
{
sectionMap = sections[i];
break;
}
}

int openingBracePos = sectionMap.find('{') + 1;
sectionMap = sectionMap.substr(openingBracePos, sectionMap.size() - openingBracePos - 1);
StringUtils::Replace(sectionMap, "(0)", "");

This comment was marked as spam.


return sectionMap;
}

void CAMLCodec::SetVfmMap(const std::string &name, const std::string &map)
{
SysfsUtils::SetString("/sys/class/vfm/map", "rm " + name);
SysfsUtils::SetString("/sys/class/vfm/map", "add " + name + " " + map);
}

void CAMLCodec::CloseDecoder()
{
CLog::Log(LOGDEBUG, "CAMLCodec::CloseDecoder");
Expand All @@ -1679,6 +1745,14 @@ void CAMLCodec::CloseDecoder()
SysfsUtils::SetInt("/sys/class/tsync/enable", 1);

ShowMainVideo(false);

CloseAmlVideo();
}

void CAMLCodec::CloseAmlVideo()
{
m_amlVideoFile.reset();
SetVfmMap("default", m_defaultVfmMap);
}

void CAMLCodec::Reset()
Expand Down Expand Up @@ -1716,8 +1790,7 @@ void CAMLCodec::Reset()
// reset some interal vars
m_1st_pts = 0;
m_cur_pts = 0;
m_cur_pictcnt = 0;
m_old_pictcnt = 0;
m_ptsQueue.clear();
SetSpeed(m_speed);
}

Expand All @@ -1728,7 +1801,6 @@ int CAMLCodec::Decode(uint8_t *pData, size_t iSize, double dts, double pts)

if (pData)
{
m_player_pts = pts;
am_private->am_pkt.data = pData;
am_private->am_pkt.data_size = iSize;

Expand All @@ -1749,7 +1821,6 @@ int CAMLCodec::Decode(uint8_t *pData, size_t iSize, double dts, double pts)
if (am_private->am_pkt.avpts != (int64_t)AV_NOPTS_VALUE)
am_private->am_pkt.avpts -= m_start_pts;


// handle dts, including 31bit wrap, aml can only handle 31
// bit dts as it uses an int in kernel.
if (dts == DVD_NOPTS_VALUE)
Expand Down Expand Up @@ -1806,28 +1877,22 @@ int CAMLCodec::Decode(uint8_t *pData, size_t iSize, double dts, double pts)
if (iSize < 20)
target_timesize = 2.0;

int rtn = 0;

// keep hw buffered demux above 1 second
if (GetTimeSize() < target_timesize && m_speed == DVD_PLAYSPEED_NORMAL)
return VC_BUFFER;
if (GetTimeSize() < target_timesize)
rtn |= VC_BUFFER;

// wait until we get a new frame or 25ms,
if (m_old_pictcnt == m_cur_pictcnt)
if (m_ptsQueue.size() == 0)
m_ready_event.WaitMSec(25);

// we must return VC_BUFFER or VC_PICTURE,
// default to VC_BUFFER.
int rtn = VC_BUFFER;
m_player_pts = DVD_NOPTS_VALUE;
if (m_old_pictcnt != m_cur_pictcnt)
if (m_ptsQueue.size() > 0)
{
m_old_pictcnt++;
rtn = VC_PICTURE;
m_player_pts = pts;
// we got a new pict, try and keep hw buffered demux above 2 seconds.
// this, combined with the above 1 second check, keeps hw buffered demux between 1 and 2 seconds.
// we also check to make sure we keep from filling hw buffer.
if (GetTimeSize() < 2.0 && GetDataSize() < m_vbufsize/3)
rtn |= VC_BUFFER;
CSingleLock lock(m_ptsQueueMutex);
m_cur_pts = m_ptsQueue.front();
m_ptsQueue.pop_front();
rtn |= VC_PICTURE;
}
/*
CLog::Log(LOGDEBUG, "CAMLCodec::Decode: "
Expand All @@ -1837,6 +1902,36 @@ int CAMLCodec::Decode(uint8_t *pData, size_t iSize, double dts, double pts)
return rtn;
}

int CAMLCodec::DequeueBuffer(int &pts)
{
v4l2_buffer vbuf = { 0 };
vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

if (m_amlVideoFile->IOControl(VIDIOC_DQBUF, &vbuf) < 0)
{
if (errno != EAGAIN)
CLog::Log(LOGERROR, "CAMLCodec::DequeueBuffer - VIDIOC_DQBUF failed: %s", strerror(errno));
return -errno;
}

// Since kernel 3.14 Amlogic changed length and units of PTS values reported here.
// To differentiate such PTS values we check for existence of omx_pts_interval_lower
// parameter, because it was introduced since kernel 3.14.
if (access("/sys/module/amvideo/parameters/omx_pts_interval_lower", F_OK) != -1)
{
int64_t pts64 = vbuf.timestamp.tv_sec & 0xFFFFFFFF;
pts64 <<= 32;
pts64 += vbuf.timestamp.tv_usec & 0xFFFFFFFF;
pts = (int)((pts64 * PTS_FREQ) / DVD_TIME_BASE);
}
else
{
pts = vbuf.timestamp.tv_usec;
}

return 0;
}

bool CAMLCodec::GetPicture(DVDVideoPicture *pDvdVideoPicture)
{
if (!m_opened)
Expand All @@ -1848,7 +1943,7 @@ bool CAMLCodec::GetPicture(DVDVideoPicture *pDvdVideoPicture)

pDvdVideoPicture->dts = DVD_NOPTS_VALUE;
if (m_speed == DVD_PLAYSPEED_NORMAL)
pDvdVideoPicture->pts = m_player_pts;
pDvdVideoPicture->pts = (double)m_cur_pts / PTS_FREQ * DVD_TIME_BASE;
else
{
if (m_cur_pts == 0)
Expand Down Expand Up @@ -1931,40 +2026,25 @@ void CAMLCodec::Process()
{
CLog::Log(LOGDEBUG, "CAMLCodec::Process Started");

// bump our priority to be level with SoftAE
SetPriority(THREAD_PRIORITY_ABOVE_NORMAL);
while (!m_bStop)
{
int64_t pts_video = 0;
if (am_private->am_pkt.lastpts > 0)
if (m_dll->codec_poll_cntl(&am_private->vcodec) < 0)
{
// this is a blocking poll that returns every vsync.
// since we are running at a higher priority, make sure
// we sleep if the call fails or does a timeout.
if (m_dll->codec_poll_cntl(&am_private->vcodec) < 0)
{
CLog::Log(LOGDEBUG, "CAMLCodec::Process: codec_poll_cntl failed");
Sleep(10);
}
CLog::Log(LOGDEBUG, "CAMLCodec::Process: codec_poll_cntl failed");
Sleep(10);
}

pts_video = get_pts_video();
if (m_cur_pts != pts_video)
{
CSingleLock lock(m_ptsQueueMutex);
int pts = 0;
if (DequeueBuffer(pts) == 0)
{
//CLog::Log(LOGDEBUG, "CAMLCodec::Process: pts_video(%lld), pts_video/PTS_FREQ(%f), duration(%f)",
// pts_video, (double)pts_video/PTS_FREQ, 1.0/((double)(pts_video - m_cur_pts)/PTS_FREQ));

// other threads look at these, do them first
m_cur_pts = pts_video;
m_cur_pictcnt++;
m_ptsQueue.push_back(pts);
m_ready_event.Set();
}
}
else
{
Sleep(100);
}
}
SetPriority(THREAD_PRIORITY_NORMAL);

CLog::Log(LOGDEBUG, "CAMLCodec::Process Stopped");
}

Expand Down
17 changes: 14 additions & 3 deletions xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.h
Expand Up @@ -25,11 +25,15 @@
#include "guilib/Geometry.h"
#include "rendering/RenderSystem.h"
#include "threads/Thread.h"
#include <deque>

typedef struct am_private_t am_private_t;

class DllLibAmCodec;

class PosixFile;
typedef std::shared_ptr<PosixFile> PosixFilePtr;

class CAMLCodec : public CThread
{
public:
Expand All @@ -47,6 +51,7 @@ class CAMLCodec : public CThread
int GetDataSize();
double GetTimeSize();
void SetVideoRect(const CRect &SrcRect, const CRect &DestRect);
int64_t GetCurPts() const { return m_cur_pts; }

protected:
virtual void Process();
Expand All @@ -60,6 +65,11 @@ class CAMLCodec : public CThread
void SetVideoSaturation(const int saturation);
void SetVideo3dMode(const int mode3d);
std::string GetStereoMode();
bool OpenAmlVideo(const CDVDStreamInfo &hints);
void CloseAmlVideo();
std::string GetVfmMap(const std::string &name);
void SetVfmMap(const std::string &name, const std::string &map);
int DequeueBuffer(int &pts);

DllLibAmCodec *m_dll;
bool m_opened;
Expand All @@ -68,8 +78,6 @@ class CAMLCodec : public CThread
volatile int m_speed;
volatile int64_t m_1st_pts;
volatile int64_t m_cur_pts;
volatile int64_t m_cur_pictcnt;
volatile int64_t m_old_pictcnt;
volatile double m_timesize;
volatile int64_t m_vbufsize;
int64_t m_start_dts;
Expand All @@ -86,5 +94,8 @@ class CAMLCodec : public CThread
int m_contrast;
int m_brightness;

double m_player_pts;
PosixFilePtr m_amlVideoFile;
std::string m_defaultVfmMap;
std::deque<int> m_ptsQueue;
CCriticalSection m_ptsQueueMutex;
};