summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Reufer <thomas@reufer.ch>2016-03-20 21:42:51 +0100
committerThomas Reufer <thomas@reufer.ch>2016-03-20 21:42:51 +0100
commitb0fe61c70c862afcb5defb2cede3dac32587f475 (patch)
treecebb2b673d55f020b6143bd2c8e7fac6385a4f3a
parent10cf387b03d2431e7e152aee08fef0b91c9b7de1 (diff)
downloadvdr-plugin-amlhddevice-b0fe61c70c862afcb5defb2cede3dac32587f475.tar.gz
vdr-plugin-amlhddevice-b0fe61c70c862afcb5defb2cede3dac32587f475.tar.bz2
switched back to ES mode and fixed replayHEADmaster
-rw-r--r--HISTORY1
-rw-r--r--amldevice.c476
-rw-r--r--amldevice.h67
-rw-r--r--amlhddevice.c14
4 files changed, 404 insertions, 154 deletions
diff --git a/HISTORY b/HISTORY
index edc42cf..57ba801 100644
--- a/HISTORY
+++ b/HISTORY
@@ -2,6 +2,7 @@ VDR Plugin 'amlhddevice' Revision History
-----------------------------------------
- fixed:
+ - replay and fast trick speeds
- A/V sync
2015-08-23: Version 0.0.1
diff --git a/amldevice.c b/amldevice.c
index c4ab07e..0ac2ab9 100644
--- a/amldevice.c
+++ b/amldevice.c
@@ -5,11 +5,6 @@
*/
#include <stdio.h>
-
-extern "C" {
-#include <codec.h>
-}
-
#include <libsi/si.h>
#include "tools.h"
@@ -17,142 +12,109 @@ extern "C" {
#define INVALID_PTS (-1)
-/* ------------------------------------------------------------------------- */
+#define TRICKMODE_NONE (0)
+#define TRICKMODE_I (1)
+#define TRICKMODE_FFFB (2)
-class cAmlDecoder
-{
-public:
+#define EXTERNAL_PTS (1)
+#define SYNC_OUTSIDE (2)
- cAmlDecoder() :
- m_initialized(false)
- {
- Reset();
- }
+#define PTS_FREQ 90000
+#define PTS_FREQ_MS PTS_FREQ / 1000
+#define AV_SYNC_THRESH PTS_FREQ * 30
- virtual ~cAmlDecoder()
- {
- Stop();
- }
+/* ------------------------------------------------------------------------- */
- virtual void Reset(void)
- {
- Stop();
- memset(&m_param, 0, sizeof(codec_para_t));
- m_param.stream_type = STREAM_TYPE_TS;
- }
+const int cScheduler::s_speeds[eNumSpeeds] = {
+ 0, PTS_FREQ_MS / 12, PTS_FREQ_MS / 8, PTS_FREQ_MS / 4,
+ PTS_FREQ_MS, PTS_FREQ_MS * 4, PTS_FREQ_MS * 8, PTS_FREQ_MS * 12
+};
- virtual int WriteTs(const uchar *data, int length)
- {
- int ret = length;
+cScheduler::cScheduler() :
+ m_pts(INVALID_PTS),
+ m_timestamp(),
+ m_speed(eNormal),
+ m_forward(true)
+{ }
- while (length)
- {
- int written = codec_write(&m_param, (void *)data, length);
- if (written > 0)
- {
- length -= written;
- data += written;
- }
- else
- {
- ELOG("failed to write codec data, ret=0x%x", written);
- ret = 0;
- break;
- }
- }
- return ret;
- }
+void cScheduler::SetSpeed(int speed, bool forward)
+{
+ m_speed =
- void SetAudioPid(int pid, int streamType)
- {
- Stop();
-
- m_param.has_audio = 1;
- m_param.audio_pid = pid;
- m_param.audio_type =
- streamType == 0x03 ? AFORMAT_MPEG :
- streamType == 0x04 ? AFORMAT_MPEG :
- streamType == SI::AC3DescriptorTag ? AFORMAT_AC3 :
- streamType == SI::EnhancedAC3DescriptorTag ? AFORMAT_EAC3 :
- streamType == 0x0f ? AFORMAT_AAC :
- streamType == 0x11 ? AFORMAT_AAC : AFORMAT_UNKNOWN;
-
- m_param.audio_channels = 0;
- m_param.audio_samplerate = 0;
- m_param.audio_info.channels = 0;
- m_param.audio_info.sample_rate = 0;
-
- Start();
- }
+ // slow forward
+ speed == 8 ? eSlowest :
+ speed == 4 ? eSlower :
+ speed == 2 ? eSlow :
- void SetVideoPid(int pid, int streamType)
- {
- Stop();
+ // fast for-/backward
+ speed == 6 ? eFast :
+ speed == 3 ? eFaster :
+ speed == 1 ? eFastest :
- m_param.has_video = 1;
- m_param.video_pid = pid;
- m_param.video_type =
- streamType == 0x01 ? VFORMAT_MPEG12 :
- streamType == 0x02 ? VFORMAT_MPEG12 :
- streamType == 0x1b ? VFORMAT_H264 : VFORMAT_UNKNOWN;
+ // slow backward
+ speed == 63 ? eSlowest :
+ speed == 48 ? eSlower :
+ speed == 24 ? eSlow : eNormal;
- m_param.am_sysinfo.format = m_param.video_type == VFORMAT_H264 ?
- VIDEO_DEC_FORMAT_H264 : VIDEO_DEC_FORMAT_UNKNOW;
+ m_forward = forward;
+}
- Start();
- }
+void cScheduler::Reset()
+{
+ m_pts = INVALID_PTS;
+ m_speed = eNormal;
+}
-protected:
+bool cScheduler::Check(int64_t pts)
+{
+ // no scheduling
+ if (m_speed == eNormal || pts == INVALID_PTS)
+ return true;
- virtual void Stop(void)
+ // first packet
+ if (m_pts == INVALID_PTS)
{
- if (!m_initialized || (!m_param.has_audio && !m_param.has_video))
- return;
-
- if (codec_close(&m_param) != CODEC_ERROR_NONE)
- ELOG("failed to close codec!");
- else
- m_initialized = false;
+ m_timestamp.Set(0);
+ m_pts = pts;
+ return true;
}
- virtual void Start(void)
+ if ((int64_t)m_timestamp.Elapsed() * s_speeds[m_speed] >
+ (m_forward ? PtsDiff(m_pts, pts) : PtsDiff(pts, m_pts)))
{
- if (m_initialized || (!m_param.has_audio && !m_param.has_video))
- return;
-
- cSysFs::Write("/sys/class/tsdemux/stb_source", 2);
- cSysFs::Write("/sys/class/tsync/pts_pcrscr", "0x0");
-
- if (codec_init(&m_param) != CODEC_ERROR_NONE)
- ELOG("failed to init codec!");
- else
- {
- m_initialized = true;
- cSysFs::Write("/sys/class/tsync/enable",
- m_param.has_audio && m_param.has_video ? 1 : 0);
- }
+ m_pts = pts;
+ m_timestamp.Set(0);
+ return true;
}
+ return false;
+}
- codec_para_t m_param;
- bool m_initialized;
-};
+int64_t cScheduler::GetPts(void)
+{
+ return m_pts;
+}
/* ------------------------------------------------------------------------- */
cAmlDevice::cAmlDevice(void (*onPrimaryDevice)(void)) :
cDevice(),
m_onPrimaryDevice(onPrimaryDevice),
- m_decoder(new cAmlDecoder()),
- m_audioPid(0),
- m_videoPid(0)
+ m_audioId(0),
+ m_trickMode(false),
+ m_scheduler()
{
+ memset(&m_videoCodec, 0, sizeof(codec_para_t));
+ memset(&m_audioCodec, 0, sizeof(codec_para_t));
+
+ m_videoCodec.stream_type = STREAM_TYPE_ES_VIDEO;
+ m_audioCodec.stream_type = STREAM_TYPE_ES_AUDIO;
+
+ codec_audio_basic_init();
}
cAmlDevice::~cAmlDevice()
{
DeInit();
-
- delete m_decoder;
}
int cAmlDevice::Init(void)
@@ -180,8 +142,6 @@ void cAmlDevice::MakePrimaryDevice(bool On)
if (On && m_onPrimaryDevice)
m_onPrimaryDevice();
cDevice::MakePrimaryDevice(On);
-
- codec_audio_basic_init();
}
void cAmlDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect)
@@ -191,6 +151,12 @@ void cAmlDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect)
PixelAspect = (double)Width / Height;
}
+int64_t cAmlDevice::GetSTC(void)
+{
+ return m_trickMode ? m_scheduler.GetPts() : (m_audioCodec.has_audio ?
+ codec_get_apts(&m_audioCodec) : codec_get_vpts(&m_videoCodec));
+}
+
bool cAmlDevice::SetPlayMode(ePlayMode PlayMode)
{
DBG("%s(%s)", __FUNCTION__,
@@ -203,15 +169,15 @@ bool cAmlDevice::SetPlayMode(ePlayMode PlayMode)
switch (PlayMode)
{
case pmNone:
- m_decoder->Reset();
- m_audioPid = 0;
- m_videoPid = 0;
+ cSysFs::Write("/sys/class/video/blackout_policy", 1);
+ Clear();
break;
case pmAudioVideo:
case pmAudioOnly:
case pmAudioOnlyBlack:
case pmVideoOnly:
+ cSysFs::Write("/sys/class/video/blackout_policy", 0);
break;
default:
@@ -221,50 +187,275 @@ bool cAmlDevice::SetPlayMode(ePlayMode PlayMode)
return true;
}
-int cAmlDevice::PlayTsVideo(const uchar *Data, int Length)
+int cAmlDevice::PlayVideo(const uchar *Data, int Length)
+{
+ int ret = Length;
+ int payloadLen = Length - PesPayloadOffset(Data);
+ const uchar *payload = Data + PesPayloadOffset(Data);
+
+ if (!m_videoCodec.has_video)
+ {
+ int streamType = PatPmtParser()->Vtype();
+
+ m_videoCodec.has_video = 1;
+ m_videoCodec.am_sysinfo.param = m_trickMode ? 0 : (void *)(EXTERNAL_PTS);
+ m_videoCodec.video_type =
+ streamType == 0x01 ? VFORMAT_MPEG12 :
+ streamType == 0x02 ? VFORMAT_MPEG12 :
+ streamType == 0x1b ? VFORMAT_H264 : VFORMAT_UNKNOWN;
+
+ m_videoCodec.am_sysinfo.format =
+ m_videoCodec.video_type == VFORMAT_H264 ?
+ VIDEO_DEC_FORMAT_H264 : VIDEO_DEC_FORMAT_UNKNOW;
+
+ if (codec_init(&m_videoCodec) != CODEC_ERROR_NONE)
+ {
+ ELOG("failed to init video codec!");
+ m_videoCodec.has_video = 0;
+ }
+ else
+ {
+ DLOG("set video codec to: %s",
+ m_videoCodec.video_type == VFORMAT_MPEG12 ? "MPEG2" :
+ m_videoCodec.video_type == VFORMAT_H264 ? "H264" : "UNKNOWN");
+
+ if (!m_trickMode)
+ {
+ codec_set_cntl_avthresh(&m_videoCodec, AV_SYNC_THRESH);
+ codec_set_cntl_syncthresh(&m_videoCodec, 0);
+
+ cSysFs::Write("/sys/class/tsync/mode", m_audioCodec.has_audio ? 1 : 0);
+ cSysFs::Write("/sys/class/tsync/enable", 1);
+ cSysFs::Write("/sys/class/tsync/pts_pcrscr", "0x0");
+ }
+ }
+ }
+ if (m_videoCodec.has_video)
+ {
+ uint64_t pts = PesHasPts(Data) ? PesGetPts(Data) : INVALID_PTS;
+ if (m_scheduler.Check(pts))
+ {
+ if (!m_trickMode)
+ codec_checkin_pts(&m_videoCodec, pts);
+ }
+ else
+ ret = 0;
+
+ while (ret && m_videoCodec.has_video && payloadLen > 0)
+ {
+ int written = codec_write(&m_videoCodec, (void *)payload, payloadLen);
+ if (written > 0)
+ {
+ payloadLen -= written;
+ payload += written;
+ }
+ else
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+int cAmlDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
{
- int pid = TsPid(Data);
- if (pid != m_videoPid)
+ int ret = Length;
+ const uchar *payload = Data + PesPayloadOffset(Data);
+ int payloadLen = Length - PesPayloadOffset(Data);
+
+ if (!m_audioCodec.has_audio || m_audioId != Id)
{
- PatPmtParser();
- if (pid == PatPmtParser()->Vpid())
+ bool reset = m_audioCodec.has_audio > 0;
+
+ m_audioId = Id;
+ m_audioCodec.has_audio = 1;
+ m_audioCodec.am_sysinfo.param = (void *)(EXTERNAL_PTS);
+ m_audioCodec.audio_channels = 0;
+ m_audioCodec.audio_samplerate = 0;
+ m_audioCodec.audio_info.channels = 0;
+ m_audioCodec.audio_info.sample_rate = 0;
+ m_audioCodec.audio_type = AFORMAT_UNKNOWN;
+
+ if (Data[3] >= 0xc0 && Data[3] <= 0xdf)
+ m_audioCodec.audio_type = AFORMAT_MPEG;
+ else
{
- m_decoder->SetVideoPid(pid, PatPmtParser()->Vtype());
- m_videoPid = pid;
+ if ((payload[0] & 0xf8) == 0x88)
+ m_audioCodec.audio_type = AFORMAT_DTS;
+ else if ((payload[0] & 0xf8) == 0x80)
+ m_audioCodec.audio_type = AFORMAT_AC3;
+ }
+
+ if ((reset ? codec_reset_audio(&m_audioCodec) :
+ codec_init(&m_audioCodec)) != CODEC_ERROR_NONE)
+ {
+ ELOG("failed to init audio codec!");
+ m_audioCodec.has_audio = 0;
+ }
+ else
+ {
+ DLOG("set audio codec to: %s",
+ m_audioCodec.audio_type == AFORMAT_MPEG ? "MPEG" :
+ m_audioCodec.audio_type == AFORMAT_AC3 ? "AC-3" :
+ m_audioCodec.audio_type == AFORMAT_DTS ? "DTS" : "UNKNOWN");
+
+ if (m_trickMode)
+ codec_set_cntl_mode(&m_videoCodec, TRICKMODE_I);
+ else
+ {
+ cSysFs::Write("/sys/class/tsync/mode", 1);
+ cSysFs::Write("/sys/class/tsync/enable", 1);
+ cSysFs::Write("/sys/class/tsync/pts_pcrscr", "0x0");
+ }
}
}
- return m_decoder->WriteTs(Data, Length);
+ if (m_audioCodec.has_audio)
+ {
+ uint64_t pts = PesHasPts(Data) ? PesGetPts(Data) : INVALID_PTS;
+ if (m_scheduler.Check(pts))
+ {
+ if (!m_trickMode)
+ codec_checkin_pts(&m_audioCodec, pts);
+ }
+ else
+ ret = 0;
+
+ while (ret && m_audioCodec.has_audio && payloadLen > 0)
+ {
+ int written = codec_write(&m_audioCodec, (void *)payload, payloadLen);
+ if (written > 0)
+ {
+ payloadLen -= written;
+ payload += written;
+ }
+ else
+ ret = 0;
+ }
+ }
+ return ret;
}
-int cAmlDevice::PlayTsAudio(const uchar *Data, int Length)
+void cAmlDevice::StillPicture(const uchar *Data, int Length)
{
- int pid = TsPid(Data);
- if (pid != m_audioPid)
+ if (Data[0] == 0x47)
+ cDevice::StillPicture(Data, Length);
+ else
{
- int streamType = -1;
- for (int i = 0; PatPmtParser()->Apid(i); i++)
- if (pid == PatPmtParser()->Apid(i))
+ DBG("%s", __FUNCTION__);
+ if (!m_videoCodec.has_video)
+ {
+ int streamType = PatPmtParser()->Vtype();
+
+ m_videoCodec.has_video = 1;
+ m_videoCodec.am_sysinfo.param = 0;//(void *)(EXTERNAL_PTS);
+ m_videoCodec.video_type =
+ streamType == 0x01 ? VFORMAT_MPEG12 :
+ streamType == 0x02 ? VFORMAT_MPEG12 :
+ streamType == 0x1b ? VFORMAT_H264 : VFORMAT_UNKNOWN;
+
+ m_videoCodec.am_sysinfo.format =
+ m_videoCodec.video_type == VFORMAT_H264 ?
+ VIDEO_DEC_FORMAT_H264 : VIDEO_DEC_FORMAT_UNKNOW;
+
+ if (codec_init(&m_videoCodec) != CODEC_ERROR_NONE)
{
- streamType = PatPmtParser()->Atype(i);
- break;
+ ELOG("failed to init video codec!");
+ m_videoCodec.has_video = 0;
}
- if (streamType < 0)
- for (int i = 0; PatPmtParser()->Dpid(i); i++)
- if (pid == PatPmtParser()->Dpid(i))
+ else
+ {
+ codec_set_cntl_mode(&m_videoCodec, TRICKMODE_I);
+ m_trickMode = true;
+ }
+ }
+ if (m_videoCodec.has_video)
+ {
+ int repeat = m_videoCodec.video_type == VFORMAT_H264 ? 12 : 4;
+ while (repeat--)
+ {
+ int length = Length;
+ const uchar *data = Data;
+
+ while (PesLongEnough(length))
{
- streamType = PatPmtParser()->Dtype(i);
- break;
+ int pktLen = PesHasLength(data) ? PesLength(data) : length;
+
+ if ((data[3] & 0xf0) == 0xe0)
+ PlayVideo(data, pktLen);
+
+ data += pktLen;
+ length -= pktLen;
}
+ }
+ }
+ }
+}
- m_decoder->SetAudioPid(pid, streamType);
- m_audioPid = pid;
+void cAmlDevice::Clear(void)
+{
+ DBG("%s", __FUNCTION__);
+
+ cSysFs::Write("/sys/class/tsync/enable", 0);
+ cSysFs::Write("/sys/class/tsync/mode", 0);
+
+ if (m_audioCodec.has_audio)
+ codec_close(&m_audioCodec);
+
+ if (m_videoCodec.has_video)
+ {
+ if (m_trickMode)
+ {
+ m_trickMode = false;
+ codec_resume(&m_videoCodec);
+ codec_set_cntl_mode(&m_videoCodec, TRICKMODE_NONE);
+ }
+ codec_close(&m_videoCodec);
}
- return m_decoder->WriteTs(Data, Length);
+ m_audioCodec.has_audio = 0;
+ m_videoCodec.has_video = 0;
+
+ m_scheduler.Reset();
+}
+
+void cAmlDevice::Play(void)
+{
+ DBG("%s", __FUNCTION__);
+
+ if (m_videoCodec.has_video)
+ {
+ codec_resume(&m_videoCodec);
+ codec_set_cntl_mode(&m_videoCodec, TRICKMODE_NONE);
+ }
+ if (m_audioCodec.has_audio)
+ codec_resume(&m_audioCodec);
+}
+
+void cAmlDevice::Freeze(void)
+{
+ DBG("%s", __FUNCTION__);
+
+ if (m_videoCodec.has_video)
+ codec_pause(&m_videoCodec);
+
+ if (m_audioCodec.has_audio)
+ codec_pause(&m_audioCodec);
+}
+
+void cAmlDevice::TrickSpeed(int Speed, bool Forward)
+{
+ DBG("%s", __FUNCTION__);
+ m_trickMode = true;
+ m_scheduler.SetSpeed(Speed, Forward);
}
bool cAmlDevice::Poll(cPoller &Poller, int TimeoutMs)
{
- return true;
+ if (m_videoCodec.has_video)
+ Poller.Add(m_videoCodec.handle, true);
+
+ if (m_audioCodec.has_audio)
+ Poller.Add(m_audioCodec.handle, true);
+
+ return Poller.Poll(TimeoutMs);
}
bool cAmlDevice::Flush(int TimeoutMs)
@@ -272,3 +463,8 @@ bool cAmlDevice::Flush(int TimeoutMs)
DBG("%s", __FUNCTION__);
return true;
}
+
+void cAmlDevice::SetVolumeDevice(int Volume)
+{
+ DBG("%s(%d)", __FUNCTION__, Volume);
+}
diff --git a/amldevice.h b/amldevice.h
index 35f38dc..6554392 100644
--- a/amldevice.h
+++ b/amldevice.h
@@ -8,10 +8,48 @@
#define AML_DEVICE_H
#include <vdr/device.h>
-
#include "tools.h"
-class cAmlDecoder;
+extern "C" {
+#include <codec.h>
+}
+
+class cScheduler
+{
+
+public:
+
+ cScheduler();
+ virtual ~cScheduler() { }
+
+ void SetSpeed(int speed, bool forward);
+ void Reset();
+
+ bool Check(int64_t pts);
+ int64_t GetPts(void);
+
+ enum eSpeed {
+ ePause,
+ eSlowest,
+ eSlower,
+ eSlow,
+ eNormal,
+ eFast,
+ eFaster,
+ eFastest,
+ eNumSpeeds
+ };
+
+private:
+
+ int64_t m_pts;
+ cTimeMs m_timestamp;
+
+ eSpeed m_speed;
+ bool m_forward;
+
+ static const int s_speeds[eNumSpeeds];
+};
class cAmlDevice : cDevice
{
@@ -35,21 +73,36 @@ public:
virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect);
+ virtual int64_t GetSTC(void);
+
protected:
virtual void MakePrimaryDevice(bool On);
- virtual int PlayTsVideo(const uchar *Data, int Length);
- virtual int PlayTsAudio(const uchar *Data, int Length);
+ virtual int PlayVideo(const uchar *Data, int Length);
+ virtual int PlayAudio(const uchar *Data, int Length, uchar Id);
+
+ void StillPicture(const uchar *Data, int Length);
+
+ virtual void Clear(void);
+ virtual void Play(void);
+ virtual void Freeze(void);
+
+ virtual void TrickSpeed(int Speed, bool Forward);
+
+ virtual void SetVolumeDevice(int Volume);
private:
void (*m_onPrimaryDevice)(void);
- cAmlDecoder *m_decoder;
+ codec_para_t m_videoCodec;
+ codec_para_t m_audioCodec;
+
+ uchar m_audioId;
+ bool m_trickMode;
- int m_audioPid;
- int m_videoPid;
+ cScheduler m_scheduler;
};
#endif
diff --git a/amlhddevice.c b/amlhddevice.c
index d83208a..f2e5105 100644
--- a/amlhddevice.c
+++ b/amlhddevice.c
@@ -17,11 +17,11 @@ class cPluginAmlHdDevice : public cPlugin
{
private:
- class cAmlDevice *m_device;
+ cAmlDevice *m_device;
static void OnPrimaryDevice(void)
{
- new cFbOsdProvider("/dev/fb0");
+ new cFbOsdProvider("/dev/fb1");
}
public:
@@ -60,9 +60,9 @@ bool cPluginAmlHdDevice::Initialize(void)
if (m_device->Init())
return false;
- cSysFs::Write("/sys/class/graphics/fb0/mode", "U:1280x720p-0\n");
- cSysFs::Write("/sys/class/graphics/fb0/blank", 0);
- cSysFs::Write("/sys/class/graphics/fb1/blank", 1);
+ cSysFs::Write("/sys/class/graphics/fb1/mode", "U:1280x720p-0\n");
+ cSysFs::Write("/sys/class/graphics/fb1/blank", 0);
+ cSysFs::Write("/sys/class/graphics/fb0/blank", 1);
}
return true;
}
@@ -74,8 +74,8 @@ bool cPluginAmlHdDevice::Start(void)
void cPluginAmlHdDevice::Stop(void)
{
- cSysFs::Write("/sys/class/graphics/fb0/blank", 1);
- cSysFs::Write("/sys/class/graphics/fb1/blank", 0);
+ cSysFs::Write("/sys/class/graphics/fb1/blank", 1);
+ cSysFs::Write("/sys/class/graphics/fb0/blank", 0);
}
VDRPLUGINCREATOR(cPluginAmlHdDevice); // Don't touch this! okay.