added tokens for current video and audio bitrate in displaychannel

This commit is contained in:
louis 2014-10-28 16:39:42 +01:00
parent c53dbf7cd6
commit abd8fd8db0
17 changed files with 402 additions and 10 deletions

View File

@ -42,6 +42,8 @@ Version 0.0.2
Version 0.0.3
- added tokens for current video and audio bitrate in displaychannel. Thx @rofafor for the original code
in the femon plugin and _Martin_ for extracting the code in skinflatplus
- changed skin metrixHD to display bitrate infos

View File

@ -78,6 +78,7 @@ OBJS = $(PLUGIN).o \
libcore/recfolderinfo.o \
libcore/extrecinfo.o \
libcore/timers.o \
libcore/femonreceiver.o \
libtemplate/globals.o \
libtemplate/parameter.o \
libtemplate/template.o \

View File

@ -23,6 +23,8 @@ cDesignerConfig::cDesignerConfig() {
//menu display style, display menu items
//one after each other or in one step
blockFlush = 1;
//interval for femon receiver to recalculate bitrates in tenth of a second
bitrateCalcInterval = 10;
//remember current skin and theme, osd size and osd fonts
SetSkin();
SetOSDSize();

View File

@ -61,6 +61,7 @@ public:
int rerunDistance;
int rerunMaxChannel;
int blockFlush;
int bitrateCalcInterval;
};
#ifdef DEFINE_CONFIG

View File

@ -186,12 +186,14 @@ void cSDDisplayChannel::Flush(void) {
channelView->DrawSignal();
channelView->DrawAudioInfo();
channelView->DrawDevices(initial);
channelView->DrawBitrates();
} else {
channelView->ClearStatusIcons();
channelView->ClearScreenResolution();
channelView->ClearSignal();
channelView->ClearSignalBackground();
channelView->ClearDevices();
channelView->DrawBitrates();
}
if (initial) {

View File

@ -4,7 +4,7 @@
<!ELEMENT displaychannel (background | channelinfo | epginfo | progressbar | progressbarback |
statusinfo | audioinfo | screenresolution | channelgroup |
signalquality | signalqualityback | devices | scrapercontent |
signalquality | signalqualityback | devices | bitrate | scrapercontent |
datetime | message | customtokens)* >
<!ATTLIST displaychannel
x CDATA #REQUIRED
@ -78,6 +78,11 @@
debug CDATA #IMPLIED
>
<!ELEMENT bitrate (area|areascroll)*>
<!ATTLIST bitrate
debug CDATA #IMPLIED
>
<!ELEMENT scrapercontent (area|areascroll)*>
<!ATTLIST scrapercontent
debug CDATA #IMPLIED

184
libcore/femonreceiver.c Normal file
View File

@ -0,0 +1,184 @@
#include <unistd.h>
#include "../config.h"
#include "femonreceiver.h"
cFemonReceiver::cFemonReceiver(const cChannel *Channel, int ATrack, int DTrack)
: cReceiver(Channel),
cThread("femon receiver"),
m_Mutex(),
m_Sleep(),
m_Active(false),
m_VideoBuffer(KILOBYTE(512), TS_SIZE, false, "Femon video"),
m_VideoType(Channel ? Channel->Vtype(): 0),
m_VideoPid(Channel ? Channel->Vpid() : 0),
m_VideoPacketCount(0),
m_AudioBuffer(KILOBYTE(256), TS_SIZE, false, "Femon audio"),
m_AudioPid(Channel ? Channel->Apid(ATrack) : 0),
m_AudioPacketCount(0),
m_AC3Buffer(KILOBYTE(256), TS_SIZE, false, "Femon AC3"),
m_AC3Pid(Channel ? Channel->Dpid(DTrack) : 0),
m_AC3PacketCount(0)
{
SetPids(NULL);
AddPid(m_VideoPid);
AddPid(m_AudioPid);
AddPid(m_AC3Pid);
m_VideoBuffer.SetTimeouts(0, 100);
m_AudioBuffer.SetTimeouts(0, 100);
m_AC3Buffer.SetTimeouts(0, 100);
m_VideoBitrate = 0.0;
m_AudioBitrate = 0.0;
m_AC3Bitrate = 0.0;
}
cFemonReceiver::~cFemonReceiver(void)
{
Deactivate();
}
void cFemonReceiver::Deactivate(void)
{
Detach();
if (m_Active) {
m_Active = false;
m_Sleep.Signal();
if (Running())
Cancel(3);
}
}
void cFemonReceiver::Activate(bool On)
{
if (On)
Start();
else
Deactivate();
}
void cFemonReceiver::Receive(uchar *Data, int Length)
{
// TS packet length: TS_SIZE
if (Running() && (*Data == TS_SYNC_BYTE) && (Length == TS_SIZE)) {
int len, pid = TsPid(Data);
if (pid == m_VideoPid) {
++m_VideoPacketCount;
len = m_VideoBuffer.Put(Data, Length);
if (len != Length) {
m_VideoBuffer.ReportOverflow(Length - len);
m_VideoBuffer.Clear();
}
}
else if (pid == m_AudioPid) {
++m_AudioPacketCount;
len = m_AudioBuffer.Put(Data, Length);
if (len != Length) {
m_AudioBuffer.ReportOverflow(Length - len);
m_AudioBuffer.Clear();
}
}
else if (pid == m_AC3Pid) {
++m_AC3PacketCount;
len = m_AC3Buffer.Put(Data, Length);
if (len != Length) {
m_AC3Buffer.ReportOverflow(Length - len);
m_AC3Buffer.Clear();
}
}
}
}
void cFemonReceiver::Action(void)
{
cTimeMs calcPeriod(0);
m_Active = true;
bool init = true;
while (Running() && m_Active) {
uint8_t *Data;
double timeout;
int Length;
bool processed = false;
// process available video data
while ((Data = m_VideoBuffer.Get(Length))) {
if (!m_Active || (Length < TS_SIZE))
break;
Length = TS_SIZE;
if (*Data != TS_SYNC_BYTE) {
for (int i = 1; i < Length; ++i) {
if (Data[i] == TS_SYNC_BYTE) {
Length = i;
break;
}
}
m_VideoBuffer.Del(Length);
continue;
}
processed = true;
if (TsPayloadStart(Data)) {
m_VideoAssembler.Reset();
}
m_VideoAssembler.PutTs(Data, Length);
m_VideoBuffer.Del(Length);
}
// process available audio data
while ((Data = m_AudioBuffer.Get(Length))) {
if (!m_Active || (Length < TS_SIZE))
break;
Length = TS_SIZE;
if (*Data != TS_SYNC_BYTE) {
for (int i = 1; i < Length; ++i) {
if (Data[i] == TS_SYNC_BYTE) {
Length = i;
break;
}
}
m_AudioBuffer.Del(Length);
continue;
}
processed = true;
m_AudioAssembler.PutTs(Data, Length);
m_AudioBuffer.Del(Length);
}
// process available dolby data
while ((Data = m_AC3Buffer.Get(Length))) {
if (!m_Active || (Length < TS_SIZE))
break;
Length = TS_SIZE;
if (*Data != TS_SYNC_BYTE) {
for (int i = 1; i < Length; ++i) {
if (Data[i] == TS_SYNC_BYTE) {
Length = i;
break;
}
}
m_AC3Buffer.Del(Length);
continue;
}
processed = true;
m_AC3Assembler.PutTs(Data, Length);
m_AC3Buffer.Del(Length);
}
// calculate bitrates
timeout = double(calcPeriod.Elapsed());
if (m_Active && (init || (timeout >= (100.0 * config.bitrateCalcInterval )))) {
// TS packet 188 bytes - 4 byte header; MPEG standard defines 1Mbit = 1000000bit
// PES headers should be compensated!
m_VideoBitrate = (1000.0 * 8.0 * 184.0 * m_VideoPacketCount) / timeout;
m_VideoPacketCount = 0;
m_AudioBitrate = (1000.0 * 8.0 * 184.0 * m_AudioPacketCount) / timeout;
m_AudioPacketCount = 0;
m_AC3Bitrate = (1000.0 * 8.0 * 184.0 * m_AC3PacketCount) / timeout;
m_AC3PacketCount = 0;
calcPeriod.Set(0);
init = false;
}
if (!processed)
m_Sleep.Wait(10); // to avoid busy loop and reduce cpu load
}
}

53
libcore/femonreceiver.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef __FEMONRECEIVER_H
#define __FEMONRECEIVER_H
#include <vdr/thread.h>
#include <vdr/receiver.h>
class cFemonReceiver : public cReceiver, public cThread {
private:
cMutex m_Mutex;
cCondWait m_Sleep;
bool m_Active;
cRingBufferLinear m_VideoBuffer;
cTsToPes m_VideoAssembler;
int m_VideoType;
int m_VideoPid;
int m_VideoPacketCount;
double m_VideoBitrate;
cRingBufferLinear m_AudioBuffer;
cTsToPes m_AudioAssembler;
int m_AudioPid;
int m_AudioPacketCount;
double m_AudioBitrate;
bool m_AudioValid;
cRingBufferLinear m_AC3Buffer;
cTsToPes m_AC3Assembler;
int m_AC3Pid;
int m_AC3PacketCount;
double m_AC3Bitrate;
bool m_AC3Valid;
protected:
virtual void Activate(bool On);
virtual void Receive(uchar *Data, int Length);
virtual void Action(void);
public:
cFemonReceiver(const cChannel* Channel, int ATrack, int DTrack);
virtual ~cFemonReceiver();
void Deactivate(void);
double VideoBitrate(void) { cMutexLock MutexLock(&m_Mutex);
return m_VideoBitrate; }; // bit/s
double AudioBitrate(void) { cMutexLock MutexLock(&m_Mutex);
return m_AudioBitrate; }; // bit/s
double AC3Bitrate(void) { cMutexLock MutexLock(&m_Mutex);
return m_AC3Bitrate; }; // bit/s
};
#endif //__FEMONRECEIVER_H

View File

@ -613,6 +613,7 @@ void cTemplateViewChannel::SetViewElements(void) {
viewElementsAllowed.insert("signalquality");
viewElementsAllowed.insert("signalqualityback");
viewElementsAllowed.insert("devices");
viewElementsAllowed.insert("bitrate");
viewElementsAllowed.insert("scrapercontent");
viewElementsAllowed.insert("datetime");
viewElementsAllowed.insert("message");
@ -655,6 +656,9 @@ string cTemplateViewChannel::GetViewElementName(eViewElement ve) {
case veSignalQualityBack:
name = "Signal Quality Background";
break;
case veBitRate:
name = "Bit Rate";
break;
case veDevices:
name = "Devices";
break;
@ -702,6 +706,8 @@ void cTemplateViewChannel::AddPixmap(string sViewElement, cTemplatePixmap *pix,
ve = veSignalQuality;
} else if (!sViewElement.compare("signalqualityback")) {
ve = veSignalQualityBack;
} else if (!sViewElement.compare("bitrate")) {
ve = veBitRate;
} else if (!sViewElement.compare("devices")) {
ve = veDevices;
} else if (!sViewElement.compare("scrapercontent")) {

View File

@ -37,6 +37,7 @@ enum eViewElement {
veScreenResolution,
veSignalQuality,
veSignalQualityBack,
veBitRate,
veScraperContent,
//DisplayMenu ViewElements
veHeader,

View File

@ -19,7 +19,7 @@
#endif
static const char *VERSION = "0.0.3";
static const char *VERSION = "0.0.4dev";
static const char *DESCRIPTION = "SkinDesigner";
static const char *MAINMENUENTRY = "Skin Designer";

View File

@ -164,8 +164,9 @@
{signalquality} SNR value of currently displayed channel
-->
<signalquality>
<area x="22%" y="94%" width="76%" height="6%" layer="3">
<drawtext x="0" valign="center" font="{light}" fontsize="70%" color="{clrWhite}" text="STR: {signalstrength}% SNR: {signalquality}%" />
<area x="22%" y="94%" width="10%" height="6%" layer="3">
<drawtext x="0" y="0" font="{light}" fontsize="50%" color="{clrWhite}" text="STR: {signalstrength}%" />
<drawtext x="0" y="50%" font="{light}" fontsize="50%" color="{clrWhite}" text="SNR: {signalquality}%" />
</area>
</signalquality>
@ -208,6 +209,19 @@
</area>
</devices>
<!-- Available Variables scrapercontent:
{bitratevideo} bitrate of currently displayed video track in MBit/s (with two decimal places)
{bitrateaudio} bitrate of currently displayed stereo audio track in KBit/s
{bitratedolby} bitrate of currently displayed ac3 audio track in KBit/s
{isdolby} true if bitrate of ac3 stream is > 0
-->
<bitrate>
<area x="32%" y="94%" width="15%" height="6%" layer="3">
<drawtext x="0" y="0" font="{light}" fontsize="50%" color="{clrWhite}" text="Video: {bitratevideo} MBit/s" />
<drawtext condition="not{isdolby}" x="0" y="50%" font="{light}" fontsize="50%" color="{clrWhite}" text="Stereo: {bitrateaudio} KBit/s" />
<drawtext condition="{isdolby}" x="0" y="50%" font="{light}" fontsize="50%" color="{clrWhite}" text="AC3: {bitratedolby} KBit/s" />
</area>
</bitrate>
<!-- Available Variables scrapercontent:
{mediapath} Full Path of Poster or Banner to use in image path attribute
{mediawidth} width of image in pixel

View File

@ -125,6 +125,15 @@
<devices>
</devices>
<!-- Available Variables scrapercontent:
{bitratevideo} bitrate of currently displayed video track in MBit/s (with two decimal places)
{bitrateaudio} bitrate of currently displayed stereo audio track in KBit/s
{bitratedolby} bitrate of currently displayed ac3 audio track in KBit/s
{isdolby} true if bitrate of ac3 stream is > 0
-->
<bitrate>
</bitrate>
<!-- Available Variables scrapercontent:
{mediapath} Full Path of Poster or Banner to use in image path attribute
{mediawidth} width of image in pixel

View File

@ -5,7 +5,6 @@
#include "../libcore/timers.h"
#include "../libcore/helpers.h"
cDisplayChannelView::cDisplayChannelView(cTemplateView *tmplView) : cView(tmplView) {
lastDate = "";
lastScreenWidth = 0;
@ -18,6 +17,7 @@ cDisplayChannelView::cDisplayChannelView(cTemplateView *tmplView) : cView(tmplVi
lastTracDesc = "";
lastTrackLang = "";
InitDevices();
InitFemonReceiver();
DeleteOsdOnExit();
SetFadeTime(tmplView->GetNumericParameter(ptFadeTime));
}
@ -424,6 +424,33 @@ void cDisplayChannelView::ClearDevices(void) {
ClearViewElement(veDevices);
}
void cDisplayChannelView::DrawBitrates(void) {
if (!ViewElementImplemented(veBitRate)) {
return;
}
double bitrateVideo;
double bitrateAudio;
double bitrateDolby;
bool changed = GetBitrates(bitrateVideo, bitrateAudio, bitrateDolby);
if (!changed) {
return;
}
map < string, string > stringTokens;
map < string, int > intTokens;
stringTokens.insert(pair<string,string>("bitratevideo", *cString::sprintf("%.2f", bitrateVideo)));
intTokens.insert(pair<string,int>("bitrateaudio", bitrateAudio));
intTokens.insert(pair<string,int>("bitratedolby", bitrateDolby));
intTokens.insert(pair<string,int>("isdolby", (bitrateDolby > 0) ? true : false));
ClearBitrates();
DrawViewElement(veBitRate, &stringTokens, &intTokens);
}
void cDisplayChannelView::ClearBitrates(void) {
ClearViewElement(veBitRate);
}
void cDisplayChannelView::DrawChannelGroups(const cChannel *Channel, cString ChannelName) {
if (!ViewElementImplemented(veChannelGroup)) {
return;

View File

@ -47,6 +47,8 @@ public:
void ClearSignalBackground(void);
void DrawDevices(bool initial);
void ClearDevices(void);
void DrawBitrates(void);
void ClearBitrates(void);
void DrawChannelGroups(const cChannel *Channel, cString ChannelName);
void ClearChannelGroups(void);
void DisplayMessage(eMessageType Type, const char *Text);

View File

@ -4,6 +4,8 @@
cViewHelpers::cViewHelpers(void) {
devicesInit = false;
femonReceiver = NULL;
bitrateVideoLast = bitrateAudioLast = bitrateDolbyLast = 0.0;
}
cViewHelpers::~cViewHelpers() {
@ -12,6 +14,10 @@ cViewHelpers::~cViewHelpers() {
delete[] lastSignalQuality;
delete[] recDevices;
}
if (femonReceiver) {
femonReceiver->Deactivate();
delete femonReceiver;
}
}
void cViewHelpers::InitDevices(void) {
@ -132,3 +138,69 @@ bool cViewHelpers::SetDevices(bool initial, map<string,int> *intTokens, vector<m
return true;
}
void cViewHelpers::InitFemonReceiver(void) {
const cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel());
eTrackType track = cDevice::PrimaryDevice()->GetCurrentAudioTrack();
if (channel) {
femonReceiver = new cFemonReceiver(channel,
IS_AUDIO_TRACK(track) ? int(track - ttAudioFirst) : 0,
IS_DOLBY_TRACK(track) ? int(track - ttDolbyFirst) : 0);
cDevice::ActualDevice()->AttachReceiver(femonReceiver);
}
}
void cViewHelpers::ChannelSwitch(const cDevice * device, int channelNumber, bool liveView) {
if (!femonReceiver)
return;
bitrateVideoLast = bitrateAudioLast = bitrateDolbyLast = 0.0;
eTrackType track = cDevice::PrimaryDevice()->GetCurrentAudioTrack();
const cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel());
if (!liveView || !channelNumber || !channel || channel->Number() != channelNumber)
return;
if (femonReceiver) {
femonReceiver->Deactivate();
delete femonReceiver;
femonReceiver = NULL;
}
if (channel) {
femonReceiver = new cFemonReceiver(channel,
IS_AUDIO_TRACK(track) ? int(track - ttAudioFirst) : 0,
IS_DOLBY_TRACK(track) ? int(track - ttDolbyFirst) : 0);
cDevice::ActualDevice()->AttachReceiver(femonReceiver);
}
}
void cViewHelpers::SetAudioTrack(int Index, const char * const *Tracks) {
if (!femonReceiver)
return;
bitrateVideoLast = bitrateAudioLast = bitrateDolbyLast = 0.0;
eTrackType track = cDevice::PrimaryDevice()->GetCurrentAudioTrack();
if (femonReceiver) {
femonReceiver->Deactivate();
delete femonReceiver;
femonReceiver = NULL;
}
const cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel());
if (channel) {
femonReceiver = new cFemonReceiver(channel,
IS_AUDIO_TRACK(track) ? int(track - ttAudioFirst) : 0,
IS_DOLBY_TRACK(track) ? int(track - ttDolbyFirst) : 0);
cDevice::ActualDevice()->AttachReceiver(femonReceiver);
}
}
bool cViewHelpers::GetBitrates(double &bitrateVideo, double &bitrateAudio, double &bitrateDolby) {
bitrateVideo = (int)(femonReceiver->VideoBitrate() / 1024 / 1024 * 100 + 0.5) / 100.0;
bitrateAudio = (int)(femonReceiver->AudioBitrate() / 1024 * 100 + 0.5) / 100.0;
bitrateDolby = (int)(femonReceiver->AC3Bitrate() / 1024 * 100 + 0.5) / 100.0;
if (bitrateVideo != bitrateVideoLast || bitrateAudio != bitrateAudioLast || bitrateDolby != bitrateDolbyLast) {
bitrateVideoLast = bitrateVideo;
bitrateAudioLast = bitrateAudio;
bitrateDolbyLast = bitrateDolby;
return true;
}
return false;
}

View File

@ -1,18 +1,29 @@
#ifndef __VIEWHELPERS_H
#define __VIEWHELPERS_H
class cViewHelpers {
#include <vdr/status.h>
#include "../libcore/femonreceiver.h"
class cViewHelpers : public cStatus {
private:
bool devicesInit;
int* lastSignalStrength;
int* lastSignalQuality;
bool* recDevices;
cFemonReceiver *femonReceiver;
double bitrateVideoLast;
double bitrateAudioLast;
double bitrateDolbyLast;
protected:
virtual void ChannelSwitch(const cDevice *device, int channelNumber, bool liveView);
virtual void SetAudioTrack(int Index, const char * const *Tracks);
void InitDevices(void);
bool SetDevices(bool initial, map<string,int> *intTokens, vector<map<string,string> > *devices);
void InitFemonReceiver(void);
bool GetBitrates(double &bitrateVideo, double &bitrateAudio, double &bitrateDolby);
public:
cViewHelpers(void);
virtual ~cViewHelpers(void);
void InitDevices(void);
bool SetDevices(bool initial, map<string,int> *intTokens, vector<map<string,string> > *devices);
};
#endif //__VIEWHELPERS_H