1
0
mirror of https://github.com/rofafor/vdr-plugin-femon.git synced 2023-10-10 11:36:53 +00:00

Compare commits

..

16 Commits

Author SHA1 Message Date
Rolf Ahrenberg
daf823435b Changed to use VDR's core translations. 2009-08-29 21:01:20 +03:00
Rolf Ahrenberg
53b42a2d4a Fixed H.264 parser. 2009-08-28 20:54:34 +03:00
Rolf Ahrenberg
167da08ab3 Silenced compiler warnings. 2009-08-26 22:44:49 +03:00
Rolf Ahrenberg
61ff96556e Fixed bitstream parser for H.264. 2009-08-26 16:24:49 +03:00
Rolf Ahrenberg
a06ae6f6ff Added PES assembler. 2009-08-25 20:22:06 +03:00
Rolf Ahrenberg
2e6a236a56 Removed OSD offset and height options. 2009-07-08 23:14:19 +03:00
Rolf Ahrenberg
6086c135c7 Added missing MINFONTSIZE and MAXFONTSIZE defines. 2009-06-18 23:08:25 +03:00
Rolf Ahrenberg
db9735b80b Cleaned up compilation warnings. 2009-06-18 17:38:27 +03:00
Rolf Ahrenberg
84878bd1b9 Cleaned up compilation warnings. 2009-06-18 17:35:35 +03:00
Rolf Ahrenberg
afd72642e9 Fixed font handling to be thread-safe. 2009-06-18 12:16:11 +03:00
Rolf Ahrenberg
0a162a9a8c Cleaned up compilation warnings. 2009-03-24 12:51:51 +02:00
Rolf Ahrenberg
2e2aacd573 Fixed end of sequence NAL unit. 2009-02-11 14:51:55 +02:00
Rolf Ahrenberg
4e8fdaf99f Fixed closing of frontend file handles. 2009-01-06 23:10:02 +02:00
Rolf Ahrenberg
eb2da4721c Added whitespace cleanups. 2008-12-16 12:51:59 +02:00
Rolf Ahrenberg
5cf9b4af0b Updated for vdr-1.7.2.
Removed the "Show CA system" setup option.
2008-12-16 12:26:46 +02:00
Rolf Ahrenberg
83556bf2d3 Added whitespace cleanups.
Changed info window to use the channel source instead of the frontend type.
2008-12-13 22:25:26 +02:00
28 changed files with 1149 additions and 919 deletions

View File

@@ -364,3 +364,9 @@ VDR Plugin 'femon' Revision History
- Cleaned up compilation warnings. - Cleaned up compilation warnings.
- Fixed font handling to be thread-safe. - Fixed font handling to be thread-safe.
2009-08-29: Version 1.7.3
- Removed OSD offset and height options.
- Added PES assembler.
- Added bitstream parsers for all codecs.

10
README
View File

@@ -26,10 +26,7 @@ transponder and stream information are also available in advanced display modes.
The plugin is based on a neat console frontend status monitor application The plugin is based on a neat console frontend status monitor application
called 'femon' by Johannes Stezenbach (see DVB-apps/szap/femon.c for further called 'femon' by Johannes Stezenbach (see DVB-apps/szap/femon.c for further
information). The bitrate calculation trick originates from the 'dvbstream' information).
application by Dave Chapman and the stream information routines are taken from
the 'libdvb' library by Metzler Brothers. The H.264 parsing routines are taken
from vdr-xineliboutput plugin by Petri Hintukainen.
Terminology: Terminology:
@@ -110,9 +107,8 @@ Notes:
specifications those values cannot be calculated into any real units. specifications those values cannot be calculated into any real units.
- If the OSD isn't visible, you've configured the OSD height too big or too - If the OSD isn't visible, you've configured the OSD height too big or too
small. Please, try to adjust the variable on the setup page before writing small. Please, try to adjust the variable on the OSD setup page before
any bug reports. NTSC users should use a shrinked default OSD height by writing any bug reports.
modifying VDR's setup.conf: femon.OSDHeight = 420
- If the SVDRP service is used: femon won't notice if the server is tuned - If the SVDRP service is used: femon won't notice if the server is tuned
to a different channel and tuning the channel on the server might annoy to a different channel and tuning the channel on the server might annoy

16
femon.c
View File

@@ -14,11 +14,11 @@
#include "femonservice.h" #include "femonservice.h"
#include "femontools.h" #include "femontools.h"
#if defined(APIVERSNUM) && APIVERSNUM < 10600 #if defined(APIVERSNUM) && APIVERSNUM < 10700
#error "VDR-1.6.0 API version or greater is required!" #error "VDR-1.7.0 API version or greater is required!"
#endif #endif
static const char VERSION[] = "1.6.7"; static const char VERSION[] = "1.7.3";
static const char DESCRIPTION[] = trNOOP("DVB Signal Information Monitor (OSD)"); static const char DESCRIPTION[] = trNOOP("DVB Signal Information Monitor (OSD)");
static const char MAINMENUENTRY[] = trNOOP("Signal Information"); static const char MAINMENUENTRY[] = trNOOP("Signal Information");
@@ -110,8 +110,6 @@ bool cPluginFemon::SetupParse(const char *Name, const char *Value)
if (!strcasecmp(Name, "HideMenu")) femonConfig.hidemenu = atoi(Value); if (!strcasecmp(Name, "HideMenu")) femonConfig.hidemenu = atoi(Value);
else if (!strcasecmp(Name, "DisplayMode")) femonConfig.displaymode = atoi(Value); else if (!strcasecmp(Name, "DisplayMode")) femonConfig.displaymode = atoi(Value);
else if (!strcasecmp(Name, "Position")) femonConfig.position = atoi(Value); else if (!strcasecmp(Name, "Position")) femonConfig.position = atoi(Value);
else if (!strcasecmp(Name, "OSDHeight")) femonConfig.osdheight = atoi(Value);
else if (!strcasecmp(Name, "OSDOffset")) femonConfig.osdoffset = atoi(Value);
else if (!strcasecmp(Name, "Skin")) femonConfig.skin = atoi(Value); else if (!strcasecmp(Name, "Skin")) femonConfig.skin = atoi(Value);
else if (!strcasecmp(Name, "Theme")) femonConfig.theme = atoi(Value); else if (!strcasecmp(Name, "Theme")) femonConfig.theme = atoi(Value);
else if (!strcasecmp(Name, "RedLimit")) femonConfig.redlimit = atoi(Value); else if (!strcasecmp(Name, "RedLimit")) femonConfig.redlimit = atoi(Value);
@@ -321,12 +319,6 @@ void cMenuFemonSetup::Setup(void)
Add(new cMenuEditBoolItem(tr("Position"), &data.position, trVDR("bottom"), trVDR("top"))); Add(new cMenuEditBoolItem(tr("Position"), &data.position, trVDR("bottom"), trVDR("top")));
help.Append(tr("Define the position of OSD.")); help.Append(tr("Define the position of OSD."));
Add(new cMenuEditIntItem(trVDR("Setup.OSD$Height"), &data.osdheight, 400, 500));
help.Append(tr("Define the height of OSD."));
Add(new cMenuEditIntItem(tr("Horizontal offset"), &data.osdoffset, -50, 50));
help.Append(tr("Define the horizontal offset of OSD."));
Add(new cMenuEditIntItem(tr("Red limit [%]"), &data.redlimit, 1, 50)); Add(new cMenuEditIntItem(tr("Red limit [%]"), &data.redlimit, 1, 50));
help.Append(tr("Define a limit for red bar, which is used to indicate a bad signal.")); help.Append(tr("Define a limit for red bar, which is used to indicate a bad signal."));
@@ -368,8 +360,6 @@ void cMenuFemonSetup::Store(void)
SetupStore("Skin", femonConfig.skin); SetupStore("Skin", femonConfig.skin);
SetupStore("Theme", femonConfig.theme); SetupStore("Theme", femonConfig.theme);
SetupStore("Position", femonConfig.position); SetupStore("Position", femonConfig.position);
SetupStore("OSDHeight", femonConfig.osdheight);
SetupStore("OSDOffset", femonConfig.osdoffset);
SetupStore("RedLimit", femonConfig.redlimit); SetupStore("RedLimit", femonConfig.redlimit);
SetupStore("GreenLimit", femonConfig.greenlimit); SetupStore("GreenLimit", femonConfig.greenlimit);
SetupStore("UpdateInterval", femonConfig.updateinterval); SetupStore("UpdateInterval", femonConfig.updateinterval);

View File

@@ -10,15 +10,25 @@
#define IS_HEAAC_AUDIO(buf) (((buf)[0] == 0xFF) && (((buf)[1] & 0xF6) == 0xF0)) #define IS_HEAAC_AUDIO(buf) (((buf)[0] == 0xFF) && (((buf)[1] & 0xF6) == 0xF0))
static unsigned int samplerates[16] = unsigned int cFemonAAC::s_Samplerates[16] =
{ {
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, -1, -1, -1, -1 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, -1, -1, -1, -1
}; };
bool getAACAudioInfo(uint8_t *buf, int len, audio_info_t *info) cFemonAAC::cFemonAAC(cFemonAudioIf *audiohandler)
: m_AudioHandler(audiohandler)
{ {
// HE-AAC audio detection, search for syncword with layer set to 0 }
if ((len < 4) || !IS_HEAAC_AUDIO(buf))
cFemonAAC::~cFemonAAC()
{
}
bool cFemonAAC::processAudio(const uint8_t *buf, int len)
{
cBitStream bs(buf, len * 8);
if (!m_AudioHandler)
return false; return false;
/* ADTS Fixed Header: /* ADTS Fixed Header:
@@ -35,41 +45,59 @@ bool getAACAudioInfo(uint8_t *buf, int len, audio_info_t *info)
* emphasis 2b only if ID == 0 (ie MPEG-4) * emphasis 2b only if ID == 0 (ie MPEG-4)
*/ */
int sampling_frequency_index = (buf[2] & 0x03C) >> 2; // skip PES header
int channel_configuration = ((buf[2] & 0x01) << 2) | ((buf[3] & 0xC0) >> 6); if (!PesLongEnough(len))
return false;
bs.skipBits(8 * PesPayloadOffset(buf));
info->codec = AUDIO_CODEC_HEAAC; // HE-AAC audio detection
info->bitrate = AUDIO_BITRATE_RESERVED; if (bs.getBits(12) != 0xFFF) // syncword
return false;
bs.skipBit(); // id
// layer must be 0
if (bs.getBits(2)) // layer
return false;
bs.skipBit(); // protection_absent
bs.skipBits(2); // profile
int sampling_frequency_index = bs.getBits(4); // sampling_frequency_index
bs.skipBit(); // private pid
int channel_configuration = bs.getBits(3); // channel_configuration
m_AudioHandler->SetAudioCodec(AUDIO_CODEC_HEAAC);
m_AudioHandler->SetAudioBitrate(AUDIO_BITRATE_RESERVED);
switch (channel_configuration) { switch (channel_configuration) {
case 0: case 0:
info->channelMode = AUDIO_CHANNEL_MODE_STEREO; m_AudioHandler->SetAudioChannel(AUDIO_CHANNEL_MODE_STEREO);
break; break;
case 1: case 1:
info->channelMode = AUDIO_CHANNEL_MODE_JOINT_STEREO; m_AudioHandler->SetAudioChannel(AUDIO_CHANNEL_MODE_JOINT_STEREO);
break; break;
case 2: case 2:
info->channelMode = AUDIO_CHANNEL_MODE_DUAL; m_AudioHandler->SetAudioChannel(AUDIO_CHANNEL_MODE_DUAL);
break; break;
case 3: case 3:
info->channelMode = AUDIO_CHANNEL_MODE_SINGLE; m_AudioHandler->SetAudioChannel(AUDIO_CHANNEL_MODE_SINGLE);
break; break;
default: default:
info->channelMode = AUDIO_CHANNEL_MODE_INVALID; m_AudioHandler->SetAudioChannel(AUDIO_CHANNEL_MODE_INVALID);
break; break;
} }
switch (sampling_frequency_index) { switch (sampling_frequency_index) {
case 0xC ... 0xF: case 0xC ... 0xF:
info->samplingFrequency = AUDIO_SAMPLING_FREQUENCY_RESERVED; m_AudioHandler->SetAudioSamplingFrequency(AUDIO_SAMPLING_FREQUENCY_RESERVED);
break; break;
default: default:
info->samplingFrequency = samplerates[sampling_frequency_index]; m_AudioHandler->SetAudioSamplingFrequency(s_Samplerates[sampling_frequency_index]);
break; break;
} }

View File

@@ -10,6 +10,17 @@
#include "femonaudio.h" #include "femonaudio.h"
bool getAACAudioInfo(uint8_t *buf, int len, audio_info_t *info); class cFemonAAC {
private:
cFemonAudioIf *m_AudioHandler;
static unsigned int s_Samplerates[16];
public:
cFemonAAC(cFemonAudioIf *audiohandler);
virtual ~cFemonAAC();
bool processAudio(const uint8_t *buf, int len);
};
#endif //__FEMONAAC_H #endif //__FEMONAAC_H

View File

@@ -9,107 +9,85 @@
#include "femontools.h" #include "femontools.h"
#include "femonac3.h" #include "femonac3.h"
#define IS_AC3_DATA(buf) (((buf)[0] == 0x0b) && ((buf)[1] == 0x77)) unsigned int cFemonAC3::s_Bitrates[32] =
static unsigned int ac3_bitrates[32] =
{ {
32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}; };
static unsigned int ac3_freq[4] = unsigned int cFemonAC3::s_Frequencies[4] =
{ {
480, 441, 320, 0 480, 441, 320, 0
}; };
//static unsigned int ac3_frames[3][32] = unsigned int cFemonAC3::s_Frames[3][32] =
//{
// {64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 640, 768, 896, 1024, 1152, 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// {69, 87, 104, 121, 139, 174, 208, 243, 278, 348, 417, 487, 557, 696, 835, 975, 1114, 1253, 1393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// {96, 120, 144, 168, 192, 240, 288, 336, 384, 480, 576, 672, 768, 960, 1152, 1344, 1536, 1728, 1920, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
//};
bool getAC3AudioInfo(uint8_t *buf, int len, ac3_info_t *info)
{ {
if (!IS_AC3_DATA(buf) || (len < 8)) {64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 640, 768, 896, 1024, 1152, 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{69, 87, 104, 121, 139, 174, 208, 243, 278, 348, 417, 487, 557, 696, 835, 975, 1114, 1253, 1393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{96, 120, 144, 168, 192, 240, 288, 336, 384, 480, 576, 672, 768, 960, 1152, 1344, 1536, 1728, 1920, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
cFemonAC3::cFemonAC3(cFemonAC3If *audiohandler)
: m_AudioHandler(audiohandler)
{
}
cFemonAC3::~cFemonAC3()
{
}
bool cFemonAC3::processAudio(const uint8_t *buf, int len)
{
int fscod, frmsizcod, bsmod, acmod;
int centermixlevel = AUDIO_CENTER_MIX_LEVEL_INVALID;
int surroundmixlevel = AUDIO_SURROUND_MIX_LEVEL_INVALID;
int dolbysurroundmode = AUDIO_DOLBY_SURROUND_MODE_INVALID;
cBitStream bs(buf, len * 8);
if (!m_AudioHandler)
return false; return false;
uint8_t *data = buf + 2; // skip PES header
uint8_t frame = (uint8_t)(data[2] & 0x3f); if (!PesLongEnough(len))
info->bitrate = 1000 * ac3_bitrates[frame >> 1]; return false;
uint8_t fr = (data[2] & 0xc0 ) >> 6; bs.skipBits(8 * PesPayloadOffset(buf));
//uint8_t sz = ac3_frames[fr][frame >> 1];
//if ((frame & 1) && (fr == 1)) // http://rmworkshop.com/dvd_info/related_info/ac3hdr.htm
// sz++;
//sz <<= 1; // AC3 audio detection
info->samplingFrequency = 100 * ac3_freq[fr]; if (bs.getU16() != 0x0B77) // syncword
info->bitstreamMode = (data[3] & 7); return false;
int acm = (data[4] & 0xE0) >> 5;
info->audioCodingMode = acm; bs.skipBits(16); // CRC1
if ((acm & 0x01) && (acm != 0x01)) {
// 3 front channels fscod = bs.getBits(2); // sampling rate values
info->centerMixLevel = (data[4] & 0x18) >> 3; frmsizcod = bs.getBits(6); // frame size code
if (acm & 0x04) {
// a surround channel exists bs.skipBits(5); // bitstream id
info->surroundMixLevel = (data[4] & 0x06) >> 1; bsmod = bs.getBits(3); // bitstream mode
if (acm == 0x02) { acmod = bs.getBits(3); // audio coding mode
// if in 2/0 mode
info->dolbySurroundMode = ((data[4] & 0x01) << 1) | ((data[5] & 0x80) >> 7); // 3 front channels
info->lfe = (data[5] & 0x40) >> 6; if ((acmod & 0x01) && (acmod != 0x01))
info->dialogLevel = (data[5] & 0x3e) >> 1; centermixlevel = bs.getBits(2);
}
else { // if a surround channel exists
info->dolbySurroundMode = AUDIO_DOLBY_SURROUND_MODE_INVALID; if (acmod & 0x04)
info->lfe = (data[4] & 0x01); surroundmixlevel = bs.getBits(2);
info->dialogLevel = (data[5] & 0xF8) >> 3;
} // if in 2/0 mode
} if (acmod == 0x02)
else { dolbysurroundmode = bs.getBits(2);
info->surroundMixLevel = AUDIO_SURROUND_MIX_LEVEL_INVALID;
if (acm == 0x02) { m_AudioHandler->SetAC3Bitrate(1000 * s_Bitrates[frmsizcod >> 1]);
// if in 2/0 mode m_AudioHandler->SetAC3SamplingFrequency(100 * s_Frequencies[fscod]);
info->dolbySurroundMode = (data[4] & 0x06) >> 1; m_AudioHandler->SetAC3Bitstream(bsmod);
info->lfe = (data[4] & 0x01); m_AudioHandler->SetAC3AudioCoding(acmod);
info->dialogLevel = (data[5] & 0xF8) >> 3; m_AudioHandler->SetAC3CenterMix(centermixlevel);
} m_AudioHandler->SetAC3SurroundMix(surroundmixlevel);
else { m_AudioHandler->SetAC3DolbySurround(dolbysurroundmode);
info->dolbySurroundMode = AUDIO_DOLBY_SURROUND_MODE_INVALID;
info->lfe = (data[4] & 0x04) >> 2; m_AudioHandler->SetAC3LFE(bs.getBit()); // low frequency effects on
info->dialogLevel = (data[4] & 0x03) << 3 | ((data[5] & 0xE0) >> 5); m_AudioHandler->SetAC3Dialog(bs.getBits(5)); // dialog normalization
}
}
}
else {
info->centerMixLevel = AUDIO_CENTER_MIX_LEVEL_INVALID;
if (acm & 0x04) {
// a surround channel exists
info->surroundMixLevel = (data[4] & 0x18) >> 3;
if (acm == 0x02) {
// if in 2/0 mode
info->dolbySurroundMode = (data[4] & 0x06) >> 1;
info->lfe = (data[4] & 0x01);
info->dialogLevel = (data[5] & 0xF8) >> 3;
}
else {
info->dolbySurroundMode = AUDIO_DOLBY_SURROUND_MODE_INVALID;
info->lfe = (data[4] & 0x04) >> 2;
info->dialogLevel = (data[4] & 0x03) << 3 | ((data[5] & 0xE0) >> 5);
}
}
else {
info->surroundMixLevel = AUDIO_SURROUND_MIX_LEVEL_INVALID;
if (acm == 0x02) {
// if in 2/0 mode
info->dolbySurroundMode = (data[4] & 0x18) >> 3;
info->lfe = (data[4] & 0x04) >> 2;
info->dialogLevel = (data[4] & 0x03) << 3 | ((data[5] & 0xE0) >> 5);
}
else {
info->dolbySurroundMode = AUDIO_DOLBY_SURROUND_MODE_INVALID;
info->lfe = (data[4] & 0x10) >> 4;
info->dialogLevel = ((data[4] & 0x0F) << 1) | ((data[5] & 0x80) >> 7);
}
}
}
return true; return true;
} }

View File

@@ -10,6 +10,19 @@
#include "femonaudio.h" #include "femonaudio.h"
bool getAC3AudioInfo(uint8_t *buf, int len, ac3_info_t *info); class cFemonAC3 {
private:
cFemonAC3If *m_AudioHandler;
static unsigned int s_Bitrates[32];
static unsigned int s_Frequencies[4];
static unsigned int s_Frames[3][32];
public:
cFemonAC3(cFemonAC3If *audiohandler);
virtual ~cFemonAC3();
bool processAudio(const uint8_t *buf, int len);
};
#endif //__FEMONAC3_H #endif //__FEMONAC3_H

View File

@@ -106,4 +106,44 @@ typedef struct ac3_info {
bool lfe; // boolean bool lfe; // boolean
} ac3_info_t; } ac3_info_t;
class cFemonAudioIf {
public:
cFemonAudioIf() {}
virtual ~cFemonAudioIf() {}
// enum
virtual void SetAudioCodec(eAudioCodec codec) = 0;
// kbit/s or eAudioBitrate
virtual void SetAudioBitrate(double bitrate) = 0;
// Hz or eAudioSamplingFrequency
virtual void SetAudioSamplingFrequency(int sampling) = 0;
// eAudioChannelMode
virtual void SetAudioChannel(eAudioChannelMode mode) = 0;
};
class cFemonAC3If {
public:
cFemonAC3If() {}
virtual ~cFemonAC3If() {}
// bit/s or eAudioBitrate
virtual void SetAC3Bitrate(int bitrate) = 0;
// Hz or eAudioSamplingFrequency
virtual void SetAC3SamplingFrequency(int sampling) = 0;
// 0..7 or eAudioBitstreamMode
virtual void SetAC3Bitstream(int mode) = 0;
// 0..7 or eAudioCodingMode
virtual void SetAC3AudioCoding(int mode) = 0;
// eAudioDolbySurroundMode
virtual void SetAC3DolbySurround(int mode) = 0;
// eAudioCenterMixLevel
virtual void SetAC3CenterMix(int level) = 0;
// eAudioSurroundMixLevel
virtual void SetAC3SurroundMix(int level) = 0;
// -dB
virtual void SetAC3Dialog(int level) = 0;
// boolean
virtual void SetAC3LFE(bool onoff) = 0;
};
#endif //__FEMONAUDIO_H #endif //__FEMONAUDIO_H

View File

@@ -22,8 +22,6 @@ cFemonConfig::cFemonConfig(void)
updateinterval = 5; updateinterval = 5;
analyzestream = 1; analyzestream = 1;
calcinterval = 20; calcinterval = 20;
osdheight = 480;
osdoffset = 0;
usesvdrp = 0; usesvdrp = 0;
svdrpport = 2001; svdrpport = 2001;
strncpy(svdrpip, "0.0.0.0", sizeof(svdrpip)); strncpy(svdrpip, "0.0.0.0", sizeof(svdrpip));

View File

@@ -33,8 +33,6 @@ public:
int updateinterval; int updateinterval;
int analyzestream; int analyzestream;
int calcinterval; int calcinterval;
int osdheight;
int osdoffset;
int usesvdrp; int usesvdrp;
int svdrpport; int svdrpport;
char svdrpip[MaxSvdrpIp + 1]; // must end with additional null char svdrpip[MaxSvdrpIp + 1]; // must end with additional null

View File

@@ -10,23 +10,7 @@
#include "femontools.h" #include "femontools.h"
#include "femonh264.h" #include "femonh264.h"
#define NAL_SEI 0x06 // Supplemental Enhancement Information const eVideoAspectRatio cFemonH264::s_AspectRatios[] =
#define NAL_SPS 0x07 // Sequence Parameter Set
#define NAL_AUD 0x09 // Access Unit Delimiter
#define NAL_END_SEQ 0x0A // End of Sequence
#define IS_NAL_SEI(buf) (((buf)[0] == 0x00) && ((buf)[1] == 0x00) && ((buf)[2] == 0x01) && ((buf)[3] == NAL_SEI))
#define IS_NAL_SPS(buf) (((buf)[0] == 0x00) && ((buf)[1] == 0x00) && ((buf)[2] == 0x01) && ((buf)[3] == NAL_SPS))
#define IS_NAL_AUD(buf) (((buf)[0] == 0x00) && ((buf)[1] == 0x00) && ((buf)[2] == 0x01) && ((buf)[3] == NAL_AUD))
#define IS_NAL_END_SEQ(buf) (((buf)[0] == 0x00) && ((buf)[1] == 0x00) && ((buf)[2] == 0x01) && ((buf)[3] == NAL_END_SEQ))
// Picture types
#define NO_PICTURE 0
#define I_FRAME 1
#define P_FRAME 2
#define B_FRAME 3
static const eVideoAspectRatio aspect_ratios[] =
{ {
VIDEO_ASPECT_RATIO_INVALID, VIDEO_ASPECT_RATIO_INVALID,
VIDEO_ASPECT_RATIO_1_1, VIDEO_ASPECT_RATIO_1_1,
@@ -47,7 +31,7 @@ static const eVideoAspectRatio aspect_ratios[] =
VIDEO_ASPECT_RATIO_2_1 VIDEO_ASPECT_RATIO_2_1
}; };
static const eVideoFormat video_formats[] = const eVideoFormat cFemonH264::s_VideoFormats[] =
{ {
VIDEO_FORMAT_COMPONENT, VIDEO_FORMAT_COMPONENT,
VIDEO_FORMAT_PAL, VIDEO_FORMAT_PAL,
@@ -58,281 +42,128 @@ static const eVideoFormat video_formats[] =
VIDEO_FORMAT_RESERVED VIDEO_FORMAT_RESERVED
}; };
typedef struct { const uint8_t cFemonH264::s_SeiNumClockTsTable[9] =
int width; {
int height; 1, 1, 1, 2, 2, 3, 3, 2, 3
eVideoAspectRatio aspect_ratio; };
eVideoFormat format;
} h264_sps_data_t; cFemonH264::cFemonH264(cFemonVideoIf *videohandler)
: m_VideoHandler(videohandler),
typedef struct { m_Width(0),
double frame_rate; m_Height(0),
double bitrate; m_AspectRatio(VIDEO_ASPECT_RATIO_INVALID),
eVideoScan scan; m_Format(VIDEO_FORMAT_INVALID),
} h264_sei_data_t; m_FrameRate(0),
m_BitRate(0),
typedef struct { m_Scan(VIDEO_SCAN_INVALID),
const uint8_t *data; m_CpbDpbDelaysPresentFlag(false),
int count; // bits m_PicStructPresentFlag(false),
int index; // bits m_TimeOffsetLength(0)
} br_state;
#define BR_INIT(data, bytes) { (data), 8 * (bytes), 0 }
#define BR_EOF(br) ((br)->index >= (br)->count)
#define br_skip_bit(br) br_skip_bits(br,1)
#define br_get_u8(br) br_get_bits(br, 8)
#define br_get_u16(br) ((br_get_bits(br, 8) << 8) | br_get_bits(br, 8))
#define br_skip_ue_golomb(br) br_skip_golomb(br)
#define br_skip_se_golomb(br) br_skip_golomb(br)
static inline void br_init(br_state *br, const uint8_t *data, int bytes)
{ {
br->data = data;
br->count = 8 * bytes;
br->index = 0;
} }
static inline int br_get_bit(br_state *br) cFemonH264::~cFemonH264()
{ {
if (br->index >= br->count)
return 1; // -> no infinite colomb's ...
int r = (br->data[br->index >> 3] >> (7 - (br->index & 7))) & 1;
br->index++;
return r;
} }
static inline uint32_t br_get_bits(br_state *br, uint32_t n) bool cFemonH264::processVideo(const uint8_t *buf, int len)
{ {
uint32_t r = 0; uint8_t nal_data[len];
while (n--) bool aud_found = false, sps_found = false, sei_found = false;
r = r | (br_get_bit(br) << n); const uint8_t *start = buf;
return r; const uint8_t *end = start + len;
}
static inline void br_skip_bits(br_state *br, int n) if (!m_VideoHandler)
{
br->index += n;
}
static inline uint32_t br_get_ue_golomb(br_state *br)
{
int n = 0;
while (!br_get_bit(br) && (n < 32))
n++;
return n ? ((1 << n) - 1) + br_get_bits(br, n) : 0;
}
static inline int32_t br_get_se_golomb(br_state *br)
{
uint32_t r = br_get_ue_golomb(br) + 1;
return (r & 1) ? -(r >> 1) : (r >> 1);
}
static inline void br_skip_golomb(br_state *br)
{
int n = 0;
while (!br_get_bit(br) && (n < 32))
n++;
br_skip_bits(br, n);
}
static inline void br_byte_align(br_state *br)
{
int n = br->index % 8;
if (n > 0)
br_skip_bits(br, 8 - n);
}
static bool h264_parse_sps(const uint8_t *buf, int len, h264_sps_data_t *sps)
{
br_state br = BR_INIT(buf, len);
int profile_idc, pic_order_cnt_type;
int frame_mbs_only;
int i, j;
profile_idc = br_get_u8(&br);
//Dprintf("H.264 SPS: profile_idc %d", profile_idc);
br_skip_bits(&br, 16);
br_skip_ue_golomb(&br); // seq_parameter_set_id
if (profile_idc >= 100) {
if (br_get_ue_golomb(&br) == 3) // chroma_format_idc
br_skip_bit(&br); // residual_colour_transform_flag
br_skip_ue_golomb(&br); // bit_depth_luma - 8
br_skip_ue_golomb(&br); // bit_depth_chroma - 8
br_skip_bit(&br); // transform_bypass
if (br_get_bit(&br)) { // seq_scaling_matrix_present
for (i = 0; i < 8; i++) {
if (br_get_bit(&br)) { // seq_scaling_list_present
int last = 8, next = 8, size = (i < 6) ? 16 : 64;
for (j = 0; j < size; j++) {
if (next)
next = (last + br_get_se_golomb(&br)) & 0xff;
last = next ?: last;
}
}
}
}
}
br_skip_ue_golomb(&br); // log2_max_frame_num - 4
pic_order_cnt_type = br_get_ue_golomb(&br);
if (pic_order_cnt_type == 0)
br_skip_ue_golomb(&br); // log2_max_poc_lsb - 4
else if (pic_order_cnt_type == 1) {
br_skip_bit(&br); // delta_pic_order_always_zero
br_skip_se_golomb(&br); // offset_for_non_ref_pic
br_skip_se_golomb(&br); // offset_for_top_to_bottom_field
j = br_get_ue_golomb(&br); // num_ref_frames_in_pic_order_cnt_cycle
for (i = 0; i < j; i++)
br_skip_se_golomb(&br); // offset_for_ref_frame[i]
}
br_skip_ue_golomb(&br); // ref_frames
br_skip_bit(&br); // gaps_in_frame_num_allowed
sps->width = br_get_ue_golomb(&br) + 1; // mbs
sps->height = br_get_ue_golomb(&br) + 1; // mbs
frame_mbs_only = br_get_bit(&br);
//Dprintf("H.264 SPS: pic_width: %u mbs", (unsigned int)sps->width);
//Dprintf("H.264 SPS: pic_height: %u mbs", (unsigned int)sps->height);
//Dprintf("H.264 SPS: frame only flag: %d", frame_mbs_only);
sps->width *= 16;
sps->height *= 16 * (2 - frame_mbs_only);
if (!frame_mbs_only) {
if (br_get_bit(&br)) { // mb_adaptive_frame_field_flag
//Dprintf("H.264 SPS: MBAFF");
}
}
br_skip_bit(&br); // direct_8x8_inference_flag
if (br_get_bit(&br)) { // frame_cropping_flag
uint32_t crop_left = br_get_ue_golomb(&br);
uint32_t crop_right = br_get_ue_golomb(&br);
uint32_t crop_top = br_get_ue_golomb(&br);
uint32_t crop_bottom = br_get_ue_golomb(&br);
//Dprintf("H.264 SPS: cropping %d %d %d %d", crop_left, crop_top, crop_right, crop_bottom);
sps->width -= 2 * (crop_left + crop_right);
if (frame_mbs_only)
sps->height -= 2 * (crop_top + crop_bottom);
else
sps->height -= 4 * (crop_top + crop_bottom);
}
// VUI parameters
sps->aspect_ratio = VIDEO_ASPECT_RATIO_INVALID;
sps->format = VIDEO_FORMAT_INVALID;
if (br_get_bit(&br)) { // vui_parameters_present_flag
if (br_get_bit(&br)) { // aspect_ratio_info_present
uint32_t aspect_ratio_idc = br_get_u8(&br);
//Dprintf("H.264 SPS: aspect_ratio_idc %d", aspect_ratio_idc);
if (aspect_ratio_idc == 255) { // extended sar
br_skip_bit(&br); // sar_width
br_skip_bit(&br); // sar_height
sps->aspect_ratio = VIDEO_ASPECT_RATIO_EXTENDED;
//Dprintf("H.264 SPS: aspect ratio extended");
}
else if (aspect_ratio_idc < sizeof(aspect_ratios) / sizeof(aspect_ratios[0])) {
sps->aspect_ratio = aspect_ratios[aspect_ratio_idc];
//Dprintf("H.264 SPS: -> aspect ratio %d", sps->aspect_ratio);
}
}
if (br_get_bit(&br)) // overscan_info_present_flag
br_skip_bit(&br); // overscan_approriate_flag
if (br_get_bit(&br)) { // video_signal_type_present_flag
uint32_t video_format = br_get_bits(&br, 3);
if (video_format < sizeof(video_formats) / sizeof(video_formats[0])) {
sps->format = video_formats[video_format];
//Dprintf("H.264 SPS: -> video format %d", sps->format);
}
}
}
//Dprintf("H.264 SPS: -> video size %dx%d, aspect %d", sps->width, sps->height, sps->aspect_ratio);
if (BR_EOF(&br)) {
//Dprintf("H.264 SPS: not enough data ?");
return false; return false;
}
return true; // skip PES header
} if (!PesLongEnough(len))
return false;
buf += PesPayloadOffset(buf);
start = buf;
static bool h264_parse_sei(const uint8_t *buf, int len, h264_sei_data_t *sei) for (;;) {
{ int consumed = 0;
int num_referenced_subseqs, i;
br_state br = BR_INIT(buf, len);
while (!BR_EOF(&br)) { // sei_message buf = nextStartCode(buf, end);
int lastByte, payloadSize = 0, payloadType = 0; if (buf >= end)
break;
// last_payload_type_byte switch (buf[3] & 0x1F) {
do { case NAL_AUD:
lastByte = br_get_u8(&br) & 0xFF; if (!aud_found) {
payloadType += lastByte; switch (buf[4] >> 5) {
} while (lastByte == 0xFF); case 0: case 3: case 5: // I_FRAME
//Dprintf("H.264: Found NAL AUD at offset %d/%d", buf - start, len);
aud_found = true;
break;
case 1: case 4: case 6: // P_FRAME;
case 2: case 7: // B_FRAME;
default: // NO_PICTURE;
break;
}
}
break;
// last_payload_size_byte case NAL_SPS:
do { if (!sps_found) {
lastByte = br_get_u8(&br) & 0xFF; //Dprintf("H.264: Found NAL SPS at offset %d/%d", buf - start, len);
payloadSize += lastByte; int nal_len = nalUnescape(nal_data, buf + 4, int(end - buf - 4));
} while (lastByte == 0xFF); consumed = parseSPS(nal_data, nal_len);
if (consumed > 0)
sps_found = true;
}
break;
#if 0
case NAL_SEI:
if (!sei_found) {
//Dprintf("H.264: Found NAL SEI at offset %d/%d", buf - start, len);
int nal_len = nalUnescape(nal_data, buf + 4, int(end - buf - 4));
consumed = parseSEI(nal_data, nal_len);
if (consumed > 0)
sei_found = true;
}
break;
#endif
default:
break;
}
switch (payloadType) { // sei_payload if (aud_found && sps_found && sei_found)
//case 1: // pic_timing break;
// ...
// switch (br_get_bits(&br, 2)) { // ct_type
// case 0:
// sei->scan = VIDEO_SCAN_PROGRESSIVE;
// break;
// case 1:
// sei->scan = VIDEO_SCAN_INTERLACED;
// break;
// case 2:
// sei->scan = VIDEO_SCAN_UNKNOWN;
// break;
// default:
// sei->scan = VIDEO_SCAN_RESERVED;
// break;
// }
// break;
case 12: // sub_seq_characteristics buf += consumed + 4;
br_skip_ue_golomb(&br); // sub_seq_layer_num
br_skip_ue_golomb(&br); // sub_seq_id
if (br_get_bit(&br)) // duration_flag
br_skip_bits(&br, 32); // sub_seq_duration
if (br_get_bit(&br)) { // average_rate_flag
br_skip_bit(&br); // accurate_statistics_flag
sei->bitrate = br_get_u16(&br); // average_bit_rate
sei->frame_rate = br_get_u16(&br); // average_frame_rate
//Dprintf("H.264 SEI: -> stream bitrate %.1f, frame rate %.1f", sei->bitrate, sei->frame_rate);
}
num_referenced_subseqs = br_get_ue_golomb(&br); // num_referenced_subseqs
for (i = 0; i < num_referenced_subseqs; ++i) {
br_skip_ue_golomb(&br); // ref_sub_seq_layer_num
br_skip_ue_golomb(&br); // ref_sub_seq_id
br_get_bit(&br); // ref_sub_seq_direction
}
break;
default:
br_skip_bits(&br, payloadSize);
break;
} }
// force byte align if (aud_found) {
br_byte_align(&br); m_VideoHandler->SetVideoCodec(VIDEO_CODEC_H264);
} if (sps_found) {
//Dprintf("H.264 SPS: -> video size %dx%d, aspect %d format %d", m_Width, m_Height, m_AspectRatio, m_Format);
m_VideoHandler->SetVideoFormat(m_Format);
m_VideoHandler->SetVideoSize(m_Width, m_Height);
m_VideoHandler->SetVideoAspectRatio(m_AspectRatio);
}
if (sei_found) {
//Dprintf("H.264 SEI: -> stream bitrate %.1f, frame rate %.1f scan %d", m_BitRate, m_FrameRate, m_Scan);
m_VideoHandler->SetVideoFramerate(m_FrameRate);
m_VideoHandler->SetVideoBitrate(m_BitRate);
m_VideoHandler->SetVideoScan(m_Scan);
}
}
return true; return aud_found;
} }
static int h264_nal_unescape(uint8_t *dst, const uint8_t *src, int len) const uint8_t *cFemonH264::nextStartCode(const uint8_t *start, const uint8_t *end)
{
for (end -= 3; start < end; ++start) {
if ((start[0] == 0x00) && (start[1] == 0x00) && (start[2] == 0x01))
return start;
}
return (end + 3);
}
int cFemonH264::nalUnescape(uint8_t *dst, const uint8_t *src, int len)
{ {
int s = 0, d = 0; int s = 0, d = 0;
@@ -354,72 +185,302 @@ static int h264_nal_unescape(uint8_t *dst, const uint8_t *src, int len)
return d; return d;
} }
static int h264_get_picture_type(const uint8_t *buf, int len) int cFemonH264::parseSPS(const uint8_t *buf, int len)
{ {
for (int i = 0; i < (len - 5); ++i) { int profile_idc, pic_order_cnt_type, frame_mbs_only, i, j;
if (buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1 && buf[i + 3] == NAL_AUD) { cBitStream bs(buf, len);
uint8_t type = (uint8_t)(buf[i + 4] >> 5);
switch (type) { unsigned int width = m_Width;
case 0: case 3: case 5: return I_FRAME; unsigned int height = m_Height;
case 1: case 4: case 6: return P_FRAME; eVideoAspectRatio aspect_ratio = m_AspectRatio;
case 2: case 7: return B_FRAME; eVideoFormat format = m_Format;
default:; bool cpb_dpb_delays_present_flag = m_CpbDpbDelaysPresentFlag;
bool pic_struct_present_flag = m_PicStructPresentFlag;
unsigned int time_offset_length = m_TimeOffsetLength;
profile_idc = bs.getU8();
//Dprintf("H.264 SPS: profile_idc %d", profile_idc);
bs.skipBits(16);
bs.skipUeGolomb(); // seq_parameter_set_id
if (profile_idc >= 100) {
if (bs.getUeGolomb() == 3) // chroma_format_idc
bs.skipBit(); // residual_colour_transform_flag
bs.skipUeGolomb(); // bit_depth_luma - 8
bs.skipUeGolomb(); // bit_depth_chroma - 8
bs.skipBit(); // transform_bypass
if (bs.getBit()) { // seq_scaling_matrix_present
for (i = 0; i < 8; i++) {
if (bs.getBit()) { // seq_scaling_list_present
int last = 8, next = 8, size = (i < 6) ? 16 : 64;
for (j = 0; j < size; j++) {
if (next)
next = (last + bs.getSeGolomb()) & 0xff;
last = next ?: last;
}
}
}
}
}
bs.skipUeGolomb(); // log2_max_frame_num - 4
pic_order_cnt_type = bs.getUeGolomb();
if (pic_order_cnt_type == 0)
bs.skipUeGolomb(); // log2_max_poc_lsb - 4
else if (pic_order_cnt_type == 1) {
bs.skipBit(); // delta_pic_order_always_zero
bs.skipSeGolomb(); // offset_for_non_ref_pic
bs.skipSeGolomb(); // offset_for_top_to_bottom_field
j = bs.getUeGolomb(); // num_ref_frames_in_pic_order_cnt_cycle
for (i = 0; i < j; i++)
bs.skipSeGolomb(); // offset_for_ref_frame[i]
}
bs.skipUeGolomb(); // ref_frames
bs.skipBit(); // gaps_in_frame_num_allowed
width = bs.getUeGolomb() + 1; // mbs
height = bs.getUeGolomb() + 1; // mbs
frame_mbs_only = bs.getBit();
//Dprintf("H.264 SPS: pic_width: %u mbs", width);
//Dprintf("H.264 SPS: pic_height: %u mbs", height);
//Dprintf("H.264 SPS: frame only flag: %d", frame_mbs_only);
width *= 16;
height *= 16 * (2 - frame_mbs_only);
if (!frame_mbs_only) {
if (bs.getBit()) { // mb_adaptive_frame_field_flag
//Dprintf("H.264 SPS: MBAFF");
}
}
bs.skipBit(); // direct_8x8_inference_flag
if (bs.getBit()) { // frame_cropping_flag
uint32_t crop_left = bs.getUeGolomb();
uint32_t crop_right = bs.getUeGolomb();
uint32_t crop_top = bs.getUeGolomb();
uint32_t crop_bottom = bs.getUeGolomb();
//Dprintf("H.264 SPS: cropping %d %d %d %d", crop_left, crop_top, crop_right, crop_bottom);
width -= 2 * (crop_left + crop_right);
if (frame_mbs_only)
height -= 2 * (crop_top + crop_bottom);
else
height -= 4 * (crop_top + crop_bottom);
}
// VUI parameters
if (bs.getBit()) { // vui_parameters_present_flag
if (bs.getBit()) { // aspect_ratio_info_present
uint32_t aspect_ratio_idc = bs.getU8();
//Dprintf("H.264 SPS: aspect_ratio_idc %d", aspect_ratio_idc);
if (aspect_ratio_idc == 255) { // extended sar
bs.skipBit(); // sar_width
bs.skipBit(); // sar_height
aspect_ratio = VIDEO_ASPECT_RATIO_EXTENDED;
//Dprintf("H.264 SPS: aspect ratio extended");
} }
} else if (aspect_ratio_idc < sizeof(s_AspectRatios) / sizeof(s_AspectRatios[0])) {
} aspect_ratio = s_AspectRatios[aspect_ratio_idc];
return NO_PICTURE; //Dprintf("H.264 SPS: -> aspect ratio %d", aspect_ratio);
}
}
if (bs.getBit()) // overscan_info_present_flag
bs.skipBit(); // overscan_approriate_flag
if (bs.getBit()) { // video_signal_type_present_flag
uint32_t video_format;
video_format = bs.getBits(3); // video_format
if (video_format < sizeof(s_VideoFormats) / sizeof(s_VideoFormats[0])) {
format = s_VideoFormats[video_format];
//Dprintf("H.264 SPS: -> video format %d", format);
}
bs.skipBit(); // video_full_range_flag
bs.skipBit(); // video_full_range_flag
if (bs.getBit()) { // colour_description_present_flag
bs.skipBits(8); // colour_primaries
bs.skipBits(8); // transfer_characteristics
bs.skipBits(8); // matrix_coefficients
}
}
if (bs.getBit()) { // chroma_loc_info_present_flag
bs.skipUeGolomb(); // chroma_sample_loc_type_top_field
bs.skipUeGolomb(); // chroma_sample_loc_type_bottom_field
}
if (bs.getBit()) { // timing_info_present_flag
bs.skipBits(32); // num_units_in_tick
bs.skipBits(32); // time_scale
bs.skipBit(); // fixed_frame_rate_flag
}
int nal_hrd_parameters_present_flag = bs.getBit(); // nal_hrd_parameters_present_flag
if (nal_hrd_parameters_present_flag) {
int cpb_cnt_minus1;
cpb_cnt_minus1 = bs.getUeGolomb(); // cpb_cnt_minus1
bs.skipBits(4); // bit_rate_scale
bs.skipBits(4); // cpb_size_scale
for (int i = 0; i < cpb_cnt_minus1; ++i) {
bs.skipUeGolomb(); // bit_rate_value_minus1[i]
bs.skipUeGolomb(); // cpb_size_value_minus1[i]
bs.skipBit(); // cbr_flag[i]
}
bs.skipBits(5); // initial_cpb_removal_delay_length_minus1
bs.skipBits(5); // cpb_removal_delay_length_minus1
bs.skipBits(5); // dpb_output_delay_length_minus1
time_offset_length = bs.getBits(5); // time_offset_length
}
int vlc_hrd_parameters_present_flag = bs.getBit(); // vlc_hrd_parameters_present_flag
if (vlc_hrd_parameters_present_flag) {
int cpb_cnt_minus1;
cpb_cnt_minus1 = bs.getUeGolomb(); // cpb_cnt_minus1
bs.skipBits(4); // bit_rate_scale
bs.skipBits(4); // cpb_size_scale
for (int i = 0; i < cpb_cnt_minus1; ++i) {
bs.skipUeGolomb(); // bit_rate_value_minus1[i]
bs.skipUeGolomb(); // cpb_size_value_minus1[i]
bs.skipBit(); // cbr_flag[i]
}
bs.skipBits(5); // initial_cpb_removal_delay_length_minus1
bs.skipBits(5); // cpb_removal_delay_length_minus1
bs.skipBits(5); // dpb_output_delay_length_minus1
time_offset_length = bs.getBits(5); // time_offset_length
}
cpb_dpb_delays_present_flag = (nal_hrd_parameters_present_flag | vlc_hrd_parameters_present_flag);
if (cpb_dpb_delays_present_flag)
bs.skipBit(); // low_delay_hrd_flag
pic_struct_present_flag = bs.getBit(); // pic_struct_present_flag
if (bs.getBit()) { // bitstream_restriction_flag
bs.skipBit(); // motion_vectors_over_pic_boundaries_flag
bs.skipUeGolomb(); // max_bytes_per_pic_denom
bs.skipUeGolomb(); // max_bits_per_mb_denom
bs.skipUeGolomb(); // log2_max_mv_length_horizontal
bs.skipUeGolomb(); // log2_max_mv_length_vertical
bs.skipUeGolomb(); // num_reorder_frames
bs.skipUeGolomb(); // max_dec_frame_buffering
}
}
m_Width = width;
m_Height = height;
m_AspectRatio = aspect_ratio;
m_Format = format;
m_CpbDpbDelaysPresentFlag = cpb_dpb_delays_present_flag;
m_PicStructPresentFlag = pic_struct_present_flag;
m_TimeOffsetLength = time_offset_length;
return (bs.getIndex() / 8);
} }
bool getH264VideoInfo(uint8_t *buf, int len, video_info_t *info) int cFemonH264::parseSEI(const uint8_t *buf, int len)
{ {
bool sps_found = false, sei_found = true; // sei currently disabled int num_referenced_subseqs, i;
cBitStream bs(buf, len);
// H.264 detection, search for NAL AUD double frame_rate = m_FrameRate;
if (!IS_NAL_AUD(buf)) double bit_rate = m_BitRate;
return false; eVideoScan scan = m_Scan;
// If I-frame, search for NAL SPS while ((bs.getIndex() * 8 + 16) < len) { // sei_message
if (h264_get_picture_type(buf, len) != I_FRAME) int lastByte, payloadSize = 0, payloadType = 0;
return false;
info->codec = VIDEO_CODEC_H264; // last_payload_type_byte
do {
lastByte = bs.getU8() & 0xFF;
payloadType += lastByte;
} while (lastByte == 0xFF);
// Scan video packet ... // last_payload_size_byte
for (int i = 5; i < len - 4; i++) { do {
// ... for sequence parameter set lastByte = bs.getU8() & 0xFF;
if (!sps_found && (buf[i] == 0x00) && (buf[i + 1] == 0x00) && (buf[i + 2] == 0x01) && (buf[i + 3] & 0x1f) == NAL_SPS) { payloadSize += lastByte;
uint8_t nal_data[len]; } while (lastByte == 0xFF);
int nal_len;
//Dprintf("H.264: Found NAL SPS at offset %d/%d", i, len); switch (payloadType) { // sei_payload
if (0 < (nal_len = h264_nal_unescape(nal_data, buf + i + 4, len - i - 4))) { case 1: // pic_timing
h264_sps_data_t sps = { 0, 0, VIDEO_ASPECT_RATIO_INVALID, VIDEO_FORMAT_INVALID }; if (m_CpbDpbDelaysPresentFlag) { // cpb_dpb_delays_present_flag
if (h264_parse_sps(nal_data, nal_len, &sps)) { bs.skipUeGolomb(); // cpb_removal_delay
info->format = sps.format; bs.skipUeGolomb(); // dpb_output_delay
info->width = sps.width; }
info->height = sps.height; if (m_PicStructPresentFlag) { // pic_struct_present_flag
info->aspectRatio = sps.aspect_ratio; unsigned int pic_struct = bs.getBits(4); // pic_struct
sps_found = true; if (pic_struct >= (sizeof(s_SeiNumClockTsTable) ) / sizeof(s_SeiNumClockTsTable[0]))
return 0;
for (int i = 0; i < s_SeiNumClockTsTable[pic_struct]; ++i) {
if (bs.getBit()) { // clock_timestamp_flag[i]
int full_timestamp_flag;
switch (bs.getBits(2)) { // ct_type
case 0:
scan = VIDEO_SCAN_PROGRESSIVE;
break;
case 1:
scan = VIDEO_SCAN_INTERLACED;
break;
case 2:
scan = VIDEO_SCAN_UNKNOWN;
break;
default:
scan = VIDEO_SCAN_RESERVED;
break;
}
//Dprintf("\nH.264 SEI: -> scan type %d", bit_rate, scan);
bs.skipBit(); // nuit_field_based_flag
bs.skipBits(5); // counting_type
full_timestamp_flag = bs.getBit(); // full_timestamp_flag
bs.skipBit(); // discontinuity_flag
bs.skipBit(); // cnt_dropped_flag
bs.skipBits(8); // n_frames
if (full_timestamp_flag) {
bs.skipBits(6); // seconds_value
bs.skipBits(6); // minutes_value
bs.skipBits(5); // hours_value
}
else {
if (bs.getBit()) { // seconds_flag
bs.skipBits(6); // seconds_value
if (bs.getBit()) { // minutes_flag
bs.skipBits(6); // minutes_value
if (bs.getBit()) // hours_flag
bs.skipBits(5); // hours_value
}
}
}
if (m_TimeOffsetLength > 0)
bs.skipBits(m_TimeOffsetLength); // time_offset
}
}
}
break;
case 12: // sub_seq_characteristics
bs.skipUeGolomb(); // sub_seq_layer_num
bs.skipUeGolomb(); // sub_seq_id
if (bs.getBit()) // duration_flag
bs.skipBits(32); // sub_seq_duration
if (bs.getBit()) { // average_rate_flag
bs.skipBit(); // accurate_statistics_flag
bit_rate = bs.getU16() / 1048.51; // average_bit_rate (1000 bit/s -> Mbit/s)
frame_rate = bs.getU16() / 256.0; // average_frame_rate (frames/256s)
//Dprintf("\nH.264 SEI: -> stream bitrate %.1f, frame rate %.1f", bit_rate, frame_rate);
}
num_referenced_subseqs = bs.getUeGolomb(); // num_referenced_subseqs
for (i = 0; i < num_referenced_subseqs; ++i) {
bs.skipUeGolomb(); // ref_sub_seq_layer_num
bs.skipUeGolomb(); // ref_sub_seq_id
bs.getBit(); // ref_sub_seq_direction
} }
} break;
}
// ... for supplemental enhancement information default:
if (!sei_found && (buf[i] == 0x00) && (buf[i + 1] == 0x00) && (buf[i + 2] == 0x01) && (buf[i + 3] & 0x1f) == NAL_SEI) { bs.skipBits(payloadSize * 8);
uint8_t nal_data[len]; break;
int nal_len;
//Dprintf("H.264: Found NAL SEI at offset %d/%d", i, len);
if (0 < (nal_len = h264_nal_unescape(nal_data, buf + i + 4, len - i - 4))) {
h264_sei_data_t sei = { 0, 0, VIDEO_SCAN_INVALID };
if (h264_parse_sei(nal_data, nal_len, &sei)) {
info->frameRate = sei.frame_rate;
info->bitrate = sei.bitrate;
info->scan = sei.scan;
sei_found = true;
}
}
}
if (sps_found && sei_found)
break;
} }
return true; // force byte align
bs.byteAlign();
}
m_FrameRate = frame_rate;
m_BitRate = bit_rate;
m_Scan = scan;
return (bs.getIndex() / 8);
} }

View File

@@ -10,6 +10,41 @@
#include "femonvideo.h" #include "femonvideo.h"
bool getH264VideoInfo(uint8_t *buf, int len, video_info_t *info); class cFemonH264 {
private:
enum {
NAL_SEI = 0x06, // Supplemental Enhancement Information
NAL_SPS = 0x07, // Sequence Parameter Set
NAL_AUD = 0x09, // Access Unit Delimiter
NAL_END_SEQ = 0x0A // End of Sequence
};
cFemonVideoIf *m_VideoHandler;
unsigned int m_Width;
unsigned int m_Height;
eVideoAspectRatio m_AspectRatio;
eVideoFormat m_Format;
double m_FrameRate;
double m_BitRate;
eVideoScan m_Scan;
bool m_CpbDpbDelaysPresentFlag;
bool m_PicStructPresentFlag;
unsigned int m_TimeOffsetLength;
const uint8_t *nextStartCode(const uint8_t *start, const uint8_t *end);
int nalUnescape(uint8_t *dst, const uint8_t *src, int len);
int parseSPS(const uint8_t *buf, int len);
int parseSEI(const uint8_t *buf, int len);
static const eVideoAspectRatio s_AspectRatios[];
static const eVideoFormat s_VideoFormats[];
static const uint8_t s_SeiNumClockTsTable[9];
public:
cFemonH264(cFemonVideoIf *videohandler);
virtual ~cFemonH264();
bool processVideo(const uint8_t *buf, int len);
};
#endif //__FEMONH264_H #endif //__FEMONH264_H

View File

@@ -8,10 +8,9 @@
#include "femontools.h" #include "femontools.h"
#include "femonmpeg.h" #include "femonmpeg.h"
#define IS_MPEG_AUDIO(buf) (((buf)[0] == 0xFF) && ((buf)[1] & 0xF0)) #define IS_EXTENSION_START(buf) (((buf)[0] == 0x00) && ((buf)[1] == 0x00) && ((buf)[2] == 0x01) && ((buf)[3] == 0xB5))
#define IS_SEQUENCE_HEADER(buf) (((buf)[0] == 0x00) && ((buf)[1] == 0x00) && ((buf)[2] == 0x01) && ((buf)[3] == 0xB3))
static unsigned int bitrates[2][3][16] = unsigned int cFemonMPEG::s_Bitrates[2][3][16] =
{ {
{ {
{0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1}, // MPEG-2 Layer I {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1}, // MPEG-2 Layer I
@@ -25,160 +24,263 @@ static unsigned int bitrates[2][3][16] =
} }
}; };
static unsigned int samplerates[2][4] = unsigned int cFemonMPEG::s_Samplerates[2][4] =
{ {
{22050, 24000, 16000, -1}, // MPEG-2 {22050, 24000, 16000, -1}, // MPEG-2
{44100, 48000, 32000, -1} // MPEG-1 {44100, 48000, 32000, -1} // MPEG-1
}; };
static eAudioCodec formats[2][4] = eAudioCodec cFemonMPEG::s_Formats[2][4] =
{ {
{AUDIO_CODEC_MPEG2_I, AUDIO_CODEC_MPEG2_II, AUDIO_CODEC_MPEG2_III, AUDIO_CODEC_UNKNOWN}, // MPEG-2 {AUDIO_CODEC_MPEG2_I, AUDIO_CODEC_MPEG2_II, AUDIO_CODEC_MPEG2_III, AUDIO_CODEC_UNKNOWN}, // MPEG-2
{AUDIO_CODEC_MPEG1_I, AUDIO_CODEC_MPEG1_II, AUDIO_CODEC_MPEG1_III, AUDIO_CODEC_UNKNOWN} // MPEG-1 {AUDIO_CODEC_MPEG1_I, AUDIO_CODEC_MPEG1_II, AUDIO_CODEC_MPEG1_III, AUDIO_CODEC_UNKNOWN} // MPEG-1
}; };
bool getMPEGAudioInfo(uint8_t *buf, int len, audio_info_t *info) cFemonMPEG::cFemonMPEG(cFemonVideoIf *videohandler, cFemonAudioIf *audiohandler)
: m_VideoHandler(videohandler),
m_AudioHandler(audiohandler)
{ {
// MPEG audio detection, search for syncword }
if ((len < 4) || !IS_MPEG_AUDIO(buf))
cFemonMPEG::~cFemonMPEG()
{
}
bool cFemonMPEG::processAudio(const uint8_t *buf, int len)
{
cBitStream bs(buf, len * 8);
if (!m_AudioHandler)
return false; return false;
int mpegIndex = (buf[1] & 0x08) >> 3; // MPEG-2=0, MPEG-1=1 // skip PES header
int layerIndex = 3 - ((buf[1] & 0x06) >> 1); // I=11, II=10, III=01 if (!PesLongEnough(len))
int bitrateIndex = (buf[2] & 0xF0) >> 4; return false;
int frequency = (buf[2] & 0x0C) >> 2; bs.skipBits(8 * PesPayloadOffset(buf));
int channelMode = (buf[3] & 0xC0) >> 6;
info->codec = formats[mpegIndex][layerIndex]; // MPEG audio detection
if (bs.getBits(12) != 0xFFF) // syncword
return false;
switch (channelMode) { int id = bs.getBit(); // id: MPEG-2=0, MPEG-1=1
int layer = 3 - bs.getBits(2); // layer: I=11, II=10, III=01
bs.skipBit(); // protection bit
int bit_rate_index = bs.getBits(4); // bitrate index
int sampling_frequency = bs.getBits(2); // sampling frequency
bs.skipBit(); // padding bit
bs.skipBit(); // private pid
int mode = bs.getBits(2); // mode
m_AudioHandler->SetAudioCodec(s_Formats[id][layer]);
switch (mode) {
case 0: case 0:
info->channelMode = AUDIO_CHANNEL_MODE_STEREO; m_AudioHandler->SetAudioChannel(AUDIO_CHANNEL_MODE_STEREO);
break; break;
case 1: case 1:
info->channelMode = AUDIO_CHANNEL_MODE_JOINT_STEREO; m_AudioHandler->SetAudioChannel(AUDIO_CHANNEL_MODE_JOINT_STEREO);
break; break;
case 2: case 2:
info->channelMode = AUDIO_CHANNEL_MODE_DUAL; m_AudioHandler->SetAudioChannel(AUDIO_CHANNEL_MODE_DUAL);
break; break;
case 3: case 3:
info->channelMode = AUDIO_CHANNEL_MODE_SINGLE; m_AudioHandler->SetAudioChannel(AUDIO_CHANNEL_MODE_SINGLE);
break; break;
default: default:
info->channelMode = AUDIO_CHANNEL_MODE_INVALID; m_AudioHandler->SetAudioChannel(AUDIO_CHANNEL_MODE_INVALID);
break; break;
} }
switch (bitrateIndex) { switch (bit_rate_index) {
case 0: case 0:
info->bitrate = AUDIO_BITRATE_FREE; m_AudioHandler->SetAudioBitrate(AUDIO_BITRATE_FREE);
break; break;
case 0xF: case 0xF:
info->bitrate = AUDIO_BITRATE_RESERVED; m_AudioHandler->SetAudioBitrate(AUDIO_BITRATE_RESERVED);
break; break;
default: default:
info->bitrate = 1000 * bitrates[mpegIndex][layerIndex][bitrateIndex]; m_AudioHandler->SetAudioBitrate(1000 * s_Bitrates[id][layer][bit_rate_index]);
break; break;
} }
switch (frequency) { switch (sampling_frequency) {
case 3: case 3:
info->samplingFrequency = AUDIO_SAMPLING_FREQUENCY_RESERVED; m_AudioHandler->SetAudioSamplingFrequency(AUDIO_SAMPLING_FREQUENCY_RESERVED);
break; break;
default: default:
info->samplingFrequency = samplerates[mpegIndex][frequency]; m_AudioHandler->SetAudioSamplingFrequency(s_Samplerates[id][sampling_frequency]);
break; break;
} }
return true; return true;
} }
bool getMPEGVideoInfo(uint8_t *buf, int len, video_info_t *info) bool cFemonMPEG::processVideo(const uint8_t *buf, int len)
{ {
// MPEG-2 video detection, search for sequence header cBitStream bs(buf, len * 8);
if ((len < 7) || !IS_SEQUENCE_HEADER(buf))
if (!m_VideoHandler)
return false; return false;
// Parse header // skip PES header
uint8_t *data = buf + 4; if (!PesLongEnough(len))
info->codec = VIDEO_CODEC_MPEG2; return false;
info->width = ((data[1] & 0xF0) >> 4) | (data[0] << 4); bs.skipBits(8 * PesPayloadOffset(buf));
info->height = ((data[1] & 0x0F) << 8) | (data[2]);
switch ((data[3] & 0xF0) >> 4) { // MPEG-2 video detection, search for start code
if (bs.getU32() != 0x000001B3) // sequence header
return false;
int scan = VIDEO_SCAN_UNKNOWN;
int format = VIDEO_FORMAT_UNKNOWN;
int aspect = VIDEO_ASPECT_RATIO_RESERVED;
int horizontal_size = bs.getBits(12); // horizontal size value
int vertical_size = bs.getBits(12); // vertical size value
switch (bs.getBits(4)) { // aspect ratio information
case 1: case 1:
info->aspectRatio = VIDEO_ASPECT_RATIO_1_1; aspect = VIDEO_ASPECT_RATIO_1_1;
break; break;
case 2: case 2:
info->aspectRatio = VIDEO_ASPECT_RATIO_4_3; aspect = VIDEO_ASPECT_RATIO_4_3;
break; break;
case 3: case 3:
info->aspectRatio = VIDEO_ASPECT_RATIO_16_9; aspect = VIDEO_ASPECT_RATIO_16_9;
break; break;
case 4: case 4:
info->aspectRatio = VIDEO_ASPECT_RATIO_2_21_1; aspect = VIDEO_ASPECT_RATIO_2_21_1;
break; break;
case 5 ... 15: case 5 ... 15:
default: default:
info->aspectRatio = VIDEO_ASPECT_RATIO_RESERVED; aspect = VIDEO_ASPECT_RATIO_RESERVED;
break; break;
} }
// Video scan should be read from progressive_sequence field in sequence extension
switch (data[3] & 0x0F) { double frame_rate = 0;
switch (bs.getBits(4)) { // frame rate code
case 1: case 1:
info->frameRate = 24000 / 1001.0; frame_rate = 24000 / 1001.0;
info->scan = VIDEO_SCAN_PROGRESSIVE; format = VIDEO_FORMAT_UNKNOWN;
info->format = VIDEO_FORMAT_UNKNOWN; break;
break;
case 2: case 2:
info->frameRate = 24.0; frame_rate = 24.0;
info->scan = VIDEO_SCAN_PROGRESSIVE; format = VIDEO_FORMAT_UNKNOWN;
info->format = VIDEO_FORMAT_UNKNOWN; break;
break;
case 3: case 3:
info->frameRate = 25.0; frame_rate = 25.0;
info->scan = VIDEO_SCAN_UNKNOWN; // interlaced or progressive format = VIDEO_FORMAT_PAL;
info->format = VIDEO_FORMAT_PAL; break;
break;
case 4: case 4:
info->frameRate = 30000 / 1001.0; frame_rate = 30000 / 1001.0;
info->scan = VIDEO_SCAN_UNKNOWN; // interlaced or progressive format = VIDEO_FORMAT_NTSC;
info->format = VIDEO_FORMAT_NTSC; break;
break;
case 5: case 5:
info->frameRate = 30.0; frame_rate = 30.0;
info->scan = VIDEO_SCAN_UNKNOWN; // interlaced or progressive format = VIDEO_FORMAT_NTSC;
info->format = VIDEO_FORMAT_NTSC; break;
break;
case 6: case 6:
info->frameRate = 50.0; frame_rate = 50.0;
info->scan = VIDEO_SCAN_PROGRESSIVE; format = VIDEO_FORMAT_PAL;
info->format = VIDEO_FORMAT_PAL; break;
break;
case 7: case 7:
info->frameRate = 60.0; frame_rate = 60.0;
info->scan = VIDEO_SCAN_PROGRESSIVE; format = VIDEO_FORMAT_NTSC;
info->format = VIDEO_FORMAT_NTSC; break;
break;
case 8: case 8:
info->frameRate = 60000 / 1001.0; frame_rate = 60000 / 1001.0;
info->scan = VIDEO_SCAN_PROGRESSIVE; format = VIDEO_FORMAT_NTSC;
info->format = VIDEO_FORMAT_NTSC; break;
break;
case 9 ... 15: case 9 ... 15:
default: default:
info->frameRate = 0; frame_rate = 0;
info->scan = VIDEO_SCAN_UNKNOWN; format = VIDEO_FORMAT_UNKNOWN;
info->format = VIDEO_FORMAT_UNKNOWN; break;
break;
} }
info->bitrate = 400.0 * (double)(((data[4] << 10) & 0x0003FC00UL) | ((data[5] << 2) & 0x000003FCUL) | (((data[6] & 0xC0) >> 6) & 0x00000003UL));
int bit_rate = bs.getBits(18); // bit rate value
bs.skipBit(); // marker bit
bs.skipBits(10); // vbv buffer size value
bs.skipBit(); // constrained parameters value
if (bs.getBit()) // load intra quantizer matrix
bs.skipBits(8 * 64); // intra quantizer matrix
if (bs.getBit()) // load non-intra quantizer matrix
bs.skipBits(8 * 64); // non-intra quantizer matrix
if (bs.getU32() != 0x000001B5) { // extension start
bs.skipBits(4); // extension start code identifier
bs.skipBits(8); // profile and level indicator
scan = bs.getBit() ? VIDEO_SCAN_PROGRESSIVE :
VIDEO_SCAN_INTERLACED; // progressive sequence
bs.skipBits(2); // chroma format
horizontal_size |= (bs.getBits(2) << 12); // horizontal size extension
vertical_size |= (bs.getBits(2) << 12); // vertical size extension
bit_rate |= (bs.getBits(12) << 18); // bit rate extension
bs.skipBit(); // marker bit
bs.skipBits(8); // vpv buffer size extension
bs.skipBit(); // low delay
bs.skipBits(2); // frame rate extension n
bs.skipBits(5); // frame rate extension d
if ((bs.getU32() != 0x000001B5) && // extension start code
(bs.getBits(4) == 0x0010)) { // sequence display extension id
switch (bs.getBits(3)) { // video format
case 0x000:
format = VIDEO_FORMAT_COMPONENT;
break;
case 0x001:
format = VIDEO_FORMAT_PAL;
break;
case 0x010:
format = VIDEO_FORMAT_NTSC;
break;
case 0x011:
format = VIDEO_FORMAT_SECAM;
break;
case 0x100:
format = VIDEO_FORMAT_MAC;
break;
case 0x101:
format = VIDEO_FORMAT_UNKNOWN;
break;
case 0x110:
case 0x111:
format = VIDEO_FORMAT_RESERVED;
break;
default:
format = VIDEO_FORMAT_INVALID;
break;
}
}
}
m_VideoHandler->SetVideoCodec(VIDEO_CODEC_MPEG2);
m_VideoHandler->SetVideoSize(horizontal_size, vertical_size);
m_VideoHandler->SetVideoBitrate(400.0 * (double)(bit_rate));
m_VideoHandler->SetVideoFramerate(frame_rate);
m_VideoHandler->SetVideoScan(eVideoScan(scan));
m_VideoHandler->SetVideoAspectRatio(eVideoAspectRatio(aspect));
m_VideoHandler->SetVideoFormat(eVideoFormat(format));
return true; return true;
} }

View File

@@ -8,10 +8,24 @@
#ifndef __FEMONMPEG_H #ifndef __FEMONMPEG_H
#define __FEMONMPEG_H #define __FEMONMPEG_H
#include "femonaudio.h"
#include "femonvideo.h" #include "femonvideo.h"
#include "femonaudio.h"
bool getMPEGAudioInfo(uint8_t *buf, int len, audio_info_t *info); class cFemonMPEG {
bool getMPEGVideoInfo(uint8_t *buf, int len, video_info_t *info); private:
cFemonVideoIf *m_VideoHandler;
cFemonAudioIf *m_AudioHandler;
static unsigned int s_Bitrates[2][3][16];
static unsigned int s_Samplerates[2][4];
static eAudioCodec s_Formats[2][4];
public:
cFemonMPEG(cFemonVideoIf *videohandler, cFemonAudioIf *audiohandler);
virtual ~cFemonMPEG();
bool processVideo(const uint8_t *buf, int len);
bool processAudio(const uint8_t *buf, int len);
};
#endif //__FEMONMPEG_H #endif //__FEMONMPEG_H

View File

@@ -6,6 +6,7 @@
*/ */
#include <ctype.h> #include <ctype.h>
#include <math.h>
#include "femoncfg.h" #include "femoncfg.h"
#include "femonreceiver.h" #include "femonreceiver.h"
#include "femontools.h" #include "femontools.h"
@@ -15,19 +16,27 @@
#define CHANNELINPUT_TIMEOUT 1000 #define CHANNELINPUT_TIMEOUT 1000
#define SVDRPPLUGIN "svdrpservice" #define SVDRPPLUGIN "svdrpservice"
#define OSDHEIGHT femonConfig.osdheight // in pixels #define OSDWIDTH m_OsdWidth // in pixels
#define OSDWIDTH 600 // in pixels #define OSDHEIGHT m_OsdHeight // in pixels
#define OSDROWHEIGHT m_Font->Height() // in pixels #define OSDROWHEIGHT m_Font->Height() // in pixels
#define OSDINFOHEIGHT (OSDROWHEIGHT * 13) // in pixels (13 rows) #define OSDINFOHEIGHT (OSDROWHEIGHT * 13) // in pixels (13 rows)
#define OSDSTATUSHEIGHT (OSDROWHEIGHT * 6) // in pixels (6 rows) #define OSDSTATUSHEIGHT (OSDROWHEIGHT * 6) // in pixels (6 rows)
#define OSDSPACING 5 #define OSDSPACING 5
#define OSDROUNDING 10 #define OSDROUNDING 10
#define IS_OSDROUNDING (femonConfig.skin == eFemonSkinElchi) #define IS_OSDROUNDING (femonConfig.skin == eFemonSkinElchi)
#define OSDINFOWIN_Y(offset) (femonConfig.position ? (OSDHEIGHT - OSDINFOHEIGHT + offset) : offset) #define OSDINFOWIN_Y(offset) (femonConfig.position ? (OSDHEIGHT - OSDINFOHEIGHT + offset) : offset)
#define OSDINFOWIN_X(col) ((col == 4) ? 455 : (col == 3) ? 305 : (col == 2) ? 155 : 15) #define OSDINFOWIN_X(col) ((col == 4) ? int(round(OSDWIDTH * 0.76)) : \
(col == 3) ? int(round(OSDWIDTH * 0.51)) : \
(col == 2) ? int(round(OSDWIDTH * 0.26)) : \
int(round(OSDWIDTH * 0.025)))
#define OSDSTATUSWIN_Y(offset) (femonConfig.position ? offset : (OSDHEIGHT - OSDSTATUSHEIGHT + offset)) #define OSDSTATUSWIN_Y(offset) (femonConfig.position ? offset : (OSDHEIGHT - OSDSTATUSHEIGHT + offset))
#define OSDSTATUSWIN_X(col) ((col == 7) ? 475 : (col == 6) ? 410 : (col == 5) ? 275 : (col == 4) ? 220 : (col == 3) ? 125 : (col == 2) ? 70 : 15) #define OSDSTATUSWIN_X(col) ((col == 7) ? int(round(OSDWIDTH * 0.79)) : \
(col == 6) ? int(round(OSDWIDTH * 0.68)) : \
(col == 5) ? int(round(OSDWIDTH * 0.46)) : \
(col == 4) ? int(round(OSDWIDTH * 0.37)) : \
(col == 3) ? int(round(OSDWIDTH * 0.21)) : \
(col == 2) ? int(round(OSDWIDTH * 0.12)) : \
int(round(OSDWIDTH * 0.025)))
#define OSDSTATUSWIN_XSYMBOL(c,w) (c * ((OSDWIDTH - (5 * w)) / 6) + ((c - 1) * w)) #define OSDSTATUSWIN_XSYMBOL(c,w) (c * ((OSDWIDTH - (5 * w)) / 6) + ((c - 1) * w))
#define OSDBARWIDTH(x) (OSDWIDTH * x / 100) #define OSDBARWIDTH(x) (OSDWIDTH * x / 100)
@@ -160,10 +169,13 @@ cFemonOsd::cFemonOsd()
m_BER(0), m_BER(0),
m_UNC(0), m_UNC(0),
m_DisplayMode(femonConfig.displaymode), m_DisplayMode(femonConfig.displaymode),
m_OsdWidth(cOsd::OsdWidth()),
m_OsdHeight(cOsd::OsdHeight()),
m_InputTime(0), m_InputTime(0),
m_Sleep(), m_Sleep(),
m_Mutex() m_Mutex()
{ {
int tmp;
Dprintf("%s()\n", __PRETTY_FUNCTION__); Dprintf("%s()\n", __PRETTY_FUNCTION__);
m_SvdrpConnection.handle = -1; m_SvdrpConnection.handle = -1;
m_Font = cFont::CreateFont(Setup.FontSml, min(max(Setup.FontSmlSize, MINFONTSIZE), MAXFONTSIZE)); m_Font = cFont::CreateFont(Setup.FontSml, min(max(Setup.FontSmlSize, MINFONTSIZE), MAXFONTSIZE));
@@ -171,8 +183,16 @@ cFemonOsd::cFemonOsd()
m_Font = new cFemonDummyFont; m_Font = new cFemonDummyFont;
esyslog("ERROR: cFemonOsd::cFemonOsd() cannot create required font."); esyslog("ERROR: cFemonOsd::cFemonOsd() cannot create required font.");
} }
if (OSDHEIGHT < (OSDINFOHEIGHT + OSDROWHEIGHT + OSDSTATUSHEIGHT)) tmp = 5 * bmSymbol[SYMBOL_LOCK].Width() + 6 * OSDSPACING;
OSDHEIGHT = (OSDINFOHEIGHT + OSDROWHEIGHT + OSDSTATUSHEIGHT); if (OSDWIDTH < tmp) {
esyslog("ERROR: cFemonOsd::cFemonOsd() OSD width (%d) smaller than required (%d).", OSDWIDTH, tmp);
OSDWIDTH = tmp;
}
tmp = OSDINFOHEIGHT + OSDROWHEIGHT + OSDSTATUSHEIGHT;
if (OSDHEIGHT < tmp) {
esyslog("ERROR: cFemonOsd::cFemonOsd() OSD height (%d) smaller than required (%d).", OSDHEIGHT, tmp);
OSDHEIGHT = tmp;
}
} }
cFemonOsd::~cFemonOsd(void) cFemonOsd::~cFemonOsd(void)
@@ -338,7 +358,7 @@ void cFemonOsd::DrawInfoWindow(void)
offset += OSDROWHEIGHT; offset += OSDROWHEIGHT;
switch (channel->Source() & cSource::st_Mask) { switch (channel->Source() & cSource::st_Mask) {
case cSource::stSat: case cSource::stSat:
OSDDRAWINFOLINE(*cString::sprintf("DVB-S #%d - %s", (m_SvdrpFrontend >= 0) ? m_SvdrpFrontend : cDevice::ActualDevice()->CardIndex(), m_FrontendInfo.name)); OSDDRAWINFOLINE(*cString::sprintf("DVB-S%s #%d - %s", (m_FrontendInfo.caps & 0x10000000) ? "2" : "", (m_SvdrpFrontend >= 0) ? m_SvdrpFrontend : cDevice::ActualDevice()->CardIndex(), m_FrontendInfo.name));
offset += OSDROWHEIGHT; offset += OSDROWHEIGHT;
OSDDRAWINFOLEFT( trVDR("Frequency"), *getFrequencyMHz(channel->Frequency())); OSDDRAWINFOLEFT( trVDR("Frequency"), *getFrequencyMHz(channel->Frequency()));
OSDDRAWINFORIGHT(trVDR("Source"), *cSource::ToString(channel->Source())); OSDDRAWINFORIGHT(trVDR("Source"), *cSource::ToString(channel->Source()));
@@ -348,6 +368,9 @@ void cFemonOsd::DrawInfoWindow(void)
offset += OSDROWHEIGHT; offset += OSDROWHEIGHT;
OSDDRAWINFOLEFT( trVDR("Inversion"), *getInversion(channel->Inversion())); OSDDRAWINFOLEFT( trVDR("Inversion"), *getInversion(channel->Inversion()));
OSDDRAWINFORIGHT(trVDR("CoderateH"), *getCoderate(channel->CoderateH())); OSDDRAWINFORIGHT(trVDR("CoderateH"), *getCoderate(channel->CoderateH()));
offset += OSDROWHEIGHT;
OSDDRAWINFOLEFT( trVDR("System"), *getSystem(channel->System()));
OSDDRAWINFORIGHT(trVDR("RollOff"), *getRollOff(channel->RollOff()));
break; break;
case cSource::stCable: case cSource::stCable:
@@ -434,7 +457,7 @@ void cFemonOsd::DrawInfoWindow(void)
offset += OSDROWHEIGHT; offset += OSDROWHEIGHT;
OSDDRAWINFOINACTIVE(tr("Dolby Surround Mode"), *getAC3DolbySurroundMode(m_Receiver->AC3DolbySurroundMode())); OSDDRAWINFOINACTIVE(tr("Dolby Surround Mode"), *getAC3DolbySurroundMode(m_Receiver->AC3DolbySurroundMode()));
offset += OSDROWHEIGHT; offset += OSDROWHEIGHT;
OSDDRAWINFOINACTIVE(tr("Low Frequency Effects"), *cString::sprintf("%s", m_Receiver->AC3Lfe() ? tr("on") : tr("off"))); OSDDRAWINFOINACTIVE(tr("Low Frequency Effects"), *cString::sprintf("%s", m_Receiver->AC3Lfe() ? trVDR("on") : trVDR("off")));
offset += OSDROWHEIGHT; offset += OSDROWHEIGHT;
OSDDRAWINFOINACTIVE(tr("Dialogue Normalization"), *getAC3DialogLevel(m_Receiver->AC3DialogLevel())); OSDDRAWINFOINACTIVE(tr("Dialogue Normalization"), *getAC3DialogLevel(m_Receiver->AC3DialogLevel()));
} }
@@ -529,7 +552,7 @@ void cFemonOsd::Show(void)
return; return;
} }
m_Osd = cOsdProvider::NewOsd(((cOsd::OsdWidth() - OSDWIDTH) / 2) + cOsd::OsdLeft() + femonConfig.osdoffset, ((cOsd::OsdHeight() - OSDHEIGHT) / 2) + cOsd::OsdTop()); m_Osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop());
if (m_Osd) { if (m_Osd) {
tArea Areas1[] = { { 0, 0, OSDWIDTH - 1, OSDHEIGHT - 1, 8 } }; tArea Areas1[] = { { 0, 0, OSDWIDTH - 1, OSDHEIGHT - 1, 8 } };
if (Setup.AntiAlias && m_Osd->CanHandleAreas(Areas1, sizeof(Areas1) / sizeof(tArea)) == oeOk) { if (Setup.AntiAlias && m_Osd->CanHandleAreas(Areas1, sizeof(Areas1) / sizeof(tArea)) == oeOk) {
@@ -553,7 +576,7 @@ void cFemonOsd::Show(void)
if (channel) { if (channel) {
IS_AUDIO_TRACK(track) ? apid[0] = channel->Apid(int(track - ttAudioFirst)) : apid[0] = channel->Apid(0); IS_AUDIO_TRACK(track) ? apid[0] = channel->Apid(int(track - ttAudioFirst)) : apid[0] = channel->Apid(0);
IS_DOLBY_TRACK(track) ? dpid[0] = channel->Dpid(int(track - ttDolbyFirst)) : dpid[0] = channel->Dpid(0); IS_DOLBY_TRACK(track) ? dpid[0] = channel->Dpid(int(track - ttDolbyFirst)) : dpid[0] = channel->Dpid(0);
m_Receiver = new cFemonReceiver(channel->GetChannelID(), channel->Ca(), channel->Vpid(), apid, dpid); m_Receiver = new cFemonReceiver(channel->GetChannelID(), channel->Ca(), channel->Vtype(), channel->Vpid(), apid, dpid);
cDevice::ActualDevice()->AttachReceiver(m_Receiver); cDevice::ActualDevice()->AttachReceiver(m_Receiver);
} }
} }
@@ -598,7 +621,7 @@ void cFemonOsd::ChannelSwitch(const cDevice * device, int channelNumber)
if (channel) { if (channel) {
IS_AUDIO_TRACK(track) ? apid[0] = channel->Apid(int(track - ttAudioFirst)) : apid[0] = channel->Apid(0); IS_AUDIO_TRACK(track) ? apid[0] = channel->Apid(int(track - ttAudioFirst)) : apid[0] = channel->Apid(0);
IS_DOLBY_TRACK(track) ? dpid[0] = channel->Dpid(int(track - ttDolbyFirst)) : dpid[0] = channel->Dpid(0); IS_DOLBY_TRACK(track) ? dpid[0] = channel->Dpid(int(track - ttDolbyFirst)) : dpid[0] = channel->Dpid(0);
m_Receiver = new cFemonReceiver(channel->GetChannelID(), channel->Ca(), channel->Vpid(), apid, dpid); m_Receiver = new cFemonReceiver(channel->GetChannelID(), channel->Ca(), channel->Vtype(), channel->Vpid(), apid, dpid);
cDevice::ActualDevice()->AttachReceiver(m_Receiver); cDevice::ActualDevice()->AttachReceiver(m_Receiver);
} }
} }
@@ -619,7 +642,7 @@ void cFemonOsd::SetAudioTrack(int Index, const char * const *Tracks)
if (channel) { if (channel) {
IS_AUDIO_TRACK(track) ? apid[0] = channel->Apid(int(track - ttAudioFirst)) : apid[0] = channel->Apid(0); IS_AUDIO_TRACK(track) ? apid[0] = channel->Apid(int(track - ttAudioFirst)) : apid[0] = channel->Apid(0);
IS_DOLBY_TRACK(track) ? dpid[0] = channel->Dpid(int(track - ttDolbyFirst)) : dpid[0] = channel->Dpid(0); IS_DOLBY_TRACK(track) ? dpid[0] = channel->Dpid(int(track - ttDolbyFirst)) : dpid[0] = channel->Dpid(0);
m_Receiver = new cFemonReceiver(channel->GetChannelID(), channel->Ca(), channel->Vpid(), apid, dpid); m_Receiver = new cFemonReceiver(channel->GetChannelID(), channel->Ca(), channel->Vtype(), channel->Vpid(), apid, dpid);
cDevice::ActualDevice()->AttachReceiver(m_Receiver); cDevice::ActualDevice()->AttachReceiver(m_Receiver);
} }
} }

View File

@@ -43,6 +43,8 @@ private:
uint32_t m_UNC; uint32_t m_UNC;
fe_status_t m_FrontendStatus; fe_status_t m_FrontendStatus;
int m_DisplayMode; int m_DisplayMode;
int m_OsdWidth;
int m_OsdHeight;
cFont *m_Font; cFont *m_Font;
cTimeMs m_InputTime; cTimeMs m_InputTime;
cCondWait m_Sleep; cCondWait m_Sleep;

View File

@@ -8,38 +8,30 @@
#include <unistd.h> #include <unistd.h>
#include "femontools.h" #include "femontools.h"
#include "femoncfg.h" #include "femoncfg.h"
#include "femonmpeg.h"
#include "femonaac.h"
#include "femonac3.h"
#include "femonh264.h"
#include "femonreceiver.h" #include "femonreceiver.h"
#define TS_SIZE 188 cFemonReceiver::cFemonReceiver(tChannelID ChannelID, int Ca, int Vtype, int Vpid, int Apid[], int Dpid[])
#define PAY_START 0x40
#define ADAPT_FIELD 0x20
#define PAYLOAD 0x10
#define PTS_DTS_FLAGS 0xC0
cFemonReceiver::cFemonReceiver(tChannelID ChannelID, int Ca, int Vpid, int Apid[], int Dpid[])
: cReceiver(ChannelID, -1, Vpid, Apid, Dpid, NULL), : cReceiver(ChannelID, -1, Vpid, Apid, Dpid, NULL),
cThread("femon receiver"), cThread("femon receiver"),
m_Sleep(), m_Sleep(),
m_Active(false), m_Active(false),
m_DetectH264(this),
m_DetectMPEG(this, this),
m_DetectAAC(this),
m_DetectAC3(this),
m_VideoType(Vtype),
m_VideoPid(Vpid), m_VideoPid(Vpid),
m_VideoPacketCount(0), m_VideoPacketCount(0),
m_VideoBitrate(0.0), m_VideoBitrate(0.0),
m_VideoValid(false), m_VideoValid(false),
m_VideoInfoBufferIndex(0),
m_AudioPid(Apid[0]), m_AudioPid(Apid[0]),
m_AudioPacketCount(0), m_AudioPacketCount(0),
m_AudioBitrate(0.0), m_AudioBitrate(0.0),
m_AudioValid(false), m_AudioValid(false),
m_AudioInfoBufferIndex(0),
m_AC3Pid(Dpid[0]), m_AC3Pid(Dpid[0]),
m_AC3PacketCount(0), m_AC3PacketCount(0),
m_AC3Bitrate(0), m_AC3Bitrate(0),
m_AC3Valid(false), m_AC3Valid(false)
m_AC3InfoBufferIndex(0)
{ {
Dprintf("%s()\n", __PRETTY_FUNCTION__); Dprintf("%s()\n", __PRETTY_FUNCTION__);
@@ -51,16 +43,10 @@ cFemonReceiver::cFemonReceiver(tChannelID ChannelID, int Ca, int Vpid, int Apid[
m_VideoInfo.height = 0; m_VideoInfo.height = 0;
m_VideoInfo.frameRate = 0; m_VideoInfo.frameRate = 0;
m_VideoInfo.bitrate = AUDIO_BITRATE_INVALID; m_VideoInfo.bitrate = AUDIO_BITRATE_INVALID;
for (unsigned int i = 0; i < ELEMENTS(m_VideoInfoBuffer); ++i)
memcpy(&m_VideoInfoBuffer[i], &m_VideoInfo, sizeof(video_info_t));
m_AudioInfo.codec = AUDIO_CODEC_UNKNOWN; m_AudioInfo.codec = AUDIO_CODEC_UNKNOWN;
m_AudioInfo.bitrate = AUDIO_BITRATE_INVALID; m_AudioInfo.bitrate = AUDIO_BITRATE_INVALID;
m_AudioInfo.samplingFrequency = AUDIO_SAMPLING_FREQUENCY_INVALID; m_AudioInfo.samplingFrequency = AUDIO_SAMPLING_FREQUENCY_INVALID;
m_AudioInfo.channelMode = AUDIO_CHANNEL_MODE_INVALID; m_AudioInfo.channelMode = AUDIO_CHANNEL_MODE_INVALID;
for (unsigned int i = 0; i < ELEMENTS(m_AudioInfoBuffer); ++i)
memcpy(&m_AudioInfoBuffer[i], &m_AudioInfo, sizeof(audio_info_t));
m_AC3Info.bitrate = AUDIO_BITRATE_INVALID; m_AC3Info.bitrate = AUDIO_BITRATE_INVALID;
m_AC3Info.samplingFrequency = AUDIO_SAMPLING_FREQUENCY_INVALID; m_AC3Info.samplingFrequency = AUDIO_SAMPLING_FREQUENCY_INVALID;
m_AC3Info.bitstreamMode = AUDIO_BITSTREAM_MODE_INVALID; m_AC3Info.bitstreamMode = AUDIO_BITSTREAM_MODE_INVALID;
@@ -70,8 +56,6 @@ cFemonReceiver::cFemonReceiver(tChannelID ChannelID, int Ca, int Vpid, int Apid[
m_AC3Info.surroundMixLevel = AUDIO_SURROUND_MIX_LEVEL_INVALID; m_AC3Info.surroundMixLevel = AUDIO_SURROUND_MIX_LEVEL_INVALID;
m_AC3Info.dialogLevel = 0; m_AC3Info.dialogLevel = 0;
m_AC3Info.lfe = false; m_AC3Info.lfe = false;
for (unsigned int i = 0; i < ELEMENTS(m_AC3InfoBuffer); ++i)
memcpy(&m_AC3InfoBuffer[i], &m_AC3Info, sizeof(ac3_info_t));
} }
cFemonReceiver::~cFemonReceiver(void) cFemonReceiver::~cFemonReceiver(void)
@@ -92,84 +76,6 @@ void cFemonReceiver::Deactivate(void)
} }
} }
void cFemonReceiver::GetVideoInfo(uint8_t *buf, int len)
{
int c = 0;
while (c < len) {
video_info_t tmp;
uint8_t *b = buf + c;
if (getMPEGVideoInfo(b, len - c, &tmp) || getH264VideoInfo(b, len - c, &tmp)) {
bool coherent = true;
memcpy(&m_VideoInfoBuffer[m_VideoInfoBufferIndex], &tmp, sizeof(video_info_t));
m_VideoInfoBufferIndex = (m_VideoInfoBufferIndex + 1) % ELEMENTS(m_VideoInfoBuffer);
for (unsigned int i = 1; i < ELEMENTS(m_VideoInfoBuffer); ++i) {
if (memcmp(&m_VideoInfoBuffer[0], &m_VideoInfoBuffer[i], sizeof(video_info_t)))
coherent = false;
break;
}
if (!m_VideoValid || coherent) {
m_VideoValid = true;
memcpy(&m_VideoInfo, &m_VideoInfoBuffer[0], sizeof(video_info_t));
}
return;
}
c++;
}
}
void cFemonReceiver::GetAudioInfo(uint8_t *buf, int len)
{
int c = 0;
while (c < len) {
audio_info_t tmp;
uint8_t *b = buf + c;
if (getAACAudioInfo(b, len - c, &tmp) || getMPEGAudioInfo(b, len - c, &tmp)) {
bool coherent = true;
memcpy(&m_AudioInfoBuffer[m_AudioInfoBufferIndex], &tmp, sizeof(audio_info_t));
m_AudioInfoBufferIndex = (m_AudioInfoBufferIndex + 1) % ELEMENTS(m_AudioInfoBuffer);
for (unsigned int i = 1; i < ELEMENTS(m_AudioInfoBuffer); ++i) {
if (memcmp(&m_AudioInfoBuffer[0], &m_AudioInfoBuffer[i], sizeof(audio_info_t)))
coherent = false;
break;
}
if (!m_AudioValid || coherent) {
m_AudioValid = true;
memcpy(&m_AudioInfo, &m_AudioInfoBuffer[0], sizeof(audio_info_t));
}
return;
}
c++;
}
}
void cFemonReceiver::GetAC3Info(uint8_t *buf, int len)
{
int c = 0;
while (c < len) {
ac3_info_t tmp;
uint8_t *b = buf + c;
if (getAC3AudioInfo(b, len - c, &tmp)) {
bool coherent = true;
memcpy(&m_AC3InfoBuffer[m_AC3InfoBufferIndex], &tmp, sizeof(ac3_info_t));
m_AC3InfoBufferIndex = (m_AC3InfoBufferIndex + 1) % ELEMENTS(m_AC3InfoBuffer);
for (unsigned int i = 1; i < ELEMENTS(m_AC3InfoBuffer); ++i) {
if (memcmp(&m_AC3InfoBuffer[0], &m_AC3InfoBuffer[i], sizeof(ac3_info_t)))
coherent = false;
break;
}
if (!m_AC3Valid || coherent) {
m_AC3Valid = true;
memcpy(&m_AC3Info, &m_AC3InfoBuffer[0], sizeof(ac3_info_t));
}
return;
}
c++;
}
}
void cFemonReceiver::Activate(bool On) void cFemonReceiver::Activate(bool On)
{ {
Dprintf("%s(%d)\n", __PRETTY_FUNCTION__, On); Dprintf("%s(%d)\n", __PRETTY_FUNCTION__, On);
@@ -183,41 +89,46 @@ void cFemonReceiver::Receive(uchar *Data, int Length)
{ {
// TS packet length: TS_SIZE // TS packet length: TS_SIZE
if (Length == TS_SIZE) { if (Length == TS_SIZE) {
int pid = ((Data[1] & 0x1f) << 8) | (Data[2]); int len, pid = TsPid(Data);
if (pid == m_VideoPid) { if (pid == m_VideoPid) {
m_VideoPacketCount++; m_VideoPacketCount++;
if (TsPayloadStart(Data)) {
while (const uint8_t *p = m_VideoAssembler.GetPes(len)) {
if (m_VideoType == 0x1B) { // MPEG4
if (m_DetectH264.processVideo(p, len)) {
m_VideoValid = true;
break;
}
}
else {
if (m_DetectMPEG.processVideo(p, len)) {
m_VideoValid = true;
break;
}
}
}
m_VideoAssembler.Reset();
}
m_VideoAssembler.PutTs(Data, Length);
} }
else if (pid == m_AudioPid) { else if (pid == m_AudioPid) {
m_AudioPacketCount++; m_AudioPacketCount++;
if (const uint8_t *p = m_AudioAssembler.GetPes(len)) {
if (m_DetectAAC.processAudio(p, len) || m_DetectMPEG.processAudio(p, len))
m_AudioValid = true;
m_AudioAssembler.Reset();
}
m_AudioAssembler.PutTs(Data, Length);
} }
else if (pid == m_AC3Pid) { else if (pid == m_AC3Pid) {
m_AC3PacketCount++; m_AC3PacketCount++;
} if (const uint8_t *p = m_AC3Assembler.GetPes(len)) {
/* the following originates from libdvbmpeg: */ if (m_DetectAC3.processAudio(p, len))
if (!(Data[3] & PAYLOAD)) { m_AC3Valid = true;
return; m_AC3Assembler.Reset();
}
uint8_t off = 0;
if (Data[3] & ADAPT_FIELD) {
off = (uint8_t)(Data[4] + 1);
}
if (Data[1] & PAY_START) {
uint8_t *sb = Data + 4 + off;
if (sb[7] & PTS_DTS_FLAGS) {
uint8_t *pay = sb + sb[8] + 9;
int l = TS_SIZE - 13 - off - sb[8];
if (pid == m_VideoPid) {
GetVideoInfo(pay, l);
}
else if (pid == m_AudioPid) {
GetAudioInfo(pay, l);
}
else if (pid == m_AC3Pid) {
GetAC3Info(pay, l);
}
} }
m_AC3Assembler.PutTs(Data, Length);
} }
/* end */
} }
} }

View File

@@ -11,41 +11,45 @@
#include <vdr/thread.h> #include <vdr/thread.h>
#include <vdr/receiver.h> #include <vdr/receiver.h>
#include "femonh264.h"
#include "femonmpeg.h"
#include "femonaac.h"
#include "femonac3.h"
#include "femonaudio.h" #include "femonaudio.h"
#include "femonvideo.h" #include "femonvideo.h"
#include "femontools.h"
class cFemonReceiver : public cReceiver, public cThread { class cFemonReceiver : public cReceiver, public cThread, public cFemonVideoIf, public cFemonAudioIf, public cFemonAC3If {
private: private:
cCondWait m_Sleep; cCondWait m_Sleep;
bool m_Active; bool m_Active;
cFemonH264 m_DetectH264;
cFemonMPEG m_DetectMPEG;
cFemonAAC m_DetectAAC;
cFemonAC3 m_DetectAC3;
cTsToPes m_VideoAssembler;
int m_VideoType;
int m_VideoPid; int m_VideoPid;
int m_VideoPacketCount; int m_VideoPacketCount;
double m_VideoBitrate; double m_VideoBitrate;
bool m_VideoValid; bool m_VideoValid;
video_info_t m_VideoInfo; video_info_t m_VideoInfo;
video_info_t m_VideoInfoBuffer[3];
unsigned int m_VideoInfoBufferIndex;
cTsToPes m_AudioAssembler;
int m_AudioPid; int m_AudioPid;
int m_AudioPacketCount; int m_AudioPacketCount;
double m_AudioBitrate; double m_AudioBitrate;
bool m_AudioValid; bool m_AudioValid;
audio_info_t m_AudioInfo; audio_info_t m_AudioInfo;
audio_info_t m_AudioInfoBuffer[3];
unsigned int m_AudioInfoBufferIndex;
cTsToPes m_AC3Assembler;
int m_AC3Pid; int m_AC3Pid;
int m_AC3PacketCount; int m_AC3PacketCount;
double m_AC3Bitrate; double m_AC3Bitrate;
bool m_AC3Valid; bool m_AC3Valid;
ac3_info_t m_AC3Info; ac3_info_t m_AC3Info;
ac3_info_t m_AC3InfoBuffer[3];
unsigned int m_AC3InfoBufferIndex;
void GetVideoInfo(uint8_t *buf, int len);
void GetAudioInfo(uint8_t *buf, int len);
void GetAC3Info(uint8_t *buf, int len);
protected: protected:
virtual void Activate(bool On); virtual void Activate(bool On);
@@ -53,7 +57,32 @@ protected:
virtual void Action(void); virtual void Action(void);
public: public:
cFemonReceiver(tChannelID ChannelID, int Ca, int Vpid, int Apid[], int Dpid[]); virtual void SetVideoCodec(eVideoCodec codec) { m_VideoInfo.codec = codec; }
virtual void SetVideoFormat(eVideoFormat format) { m_VideoInfo.format = format; }
virtual void SetVideoScan(eVideoScan scan) { m_VideoInfo.scan = scan; }
virtual void SetVideoAspectRatio(eVideoAspectRatio aspectratio) { m_VideoInfo.aspectRatio = aspectratio; }
virtual void SetVideoSize(int width, int height) { m_VideoInfo.width = width;
m_VideoInfo.height = height; }
virtual void SetVideoFramerate(double framerate) { m_VideoInfo.frameRate = framerate; }
virtual void SetVideoBitrate(double bitrate) { m_VideoInfo.bitrate = bitrate; }
virtual void SetAudioCodec(eAudioCodec codec) { m_AudioInfo.codec = codec; }
virtual void SetAudioBitrate(double bitrate) { m_AudioInfo.bitrate = bitrate; }
virtual void SetAudioSamplingFrequency(int sampling) { m_AudioInfo.samplingFrequency = sampling; }
virtual void SetAudioChannel(eAudioChannelMode mode) { m_AudioInfo.channelMode = mode; }
virtual void SetAC3Bitrate(int bitrate) { m_AC3Info.bitrate = bitrate; }
virtual void SetAC3SamplingFrequency(int sampling) { m_AC3Info.samplingFrequency = sampling; }
virtual void SetAC3Bitstream(int mode) { m_AC3Info.bitstreamMode = mode; }
virtual void SetAC3AudioCoding(int mode) { m_AC3Info.audioCodingMode = mode; }
virtual void SetAC3DolbySurround(int mode) { m_AC3Info.dolbySurroundMode = mode; }
virtual void SetAC3CenterMix(int level) { m_AC3Info.centerMixLevel = level; }
virtual void SetAC3SurroundMix(int level) { m_AC3Info.surroundMixLevel = level; }
virtual void SetAC3Dialog(int level) { m_AC3Info.dialogLevel = level; }
virtual void SetAC3LFE(bool onoff) { m_AC3Info.lfe = onoff; }
public:
cFemonReceiver(tChannelID ChannelID, int Ca, int Vtype, int Vpid, int Apid[], int Dpid[]);
virtual ~cFemonReceiver(); virtual ~cFemonReceiver();
void Deactivate(void); void Deactivate(void);
@@ -81,8 +110,8 @@ public:
int AC3SamplingFreq(void) { return m_AC3Info.samplingFrequency; }; // Hz or eAudioSamplingFrequency int AC3SamplingFreq(void) { return m_AC3Info.samplingFrequency; }; // Hz or eAudioSamplingFrequency
int AC3BitStreamMode(void) { return m_AC3Info.bitstreamMode; }; // 0..7 or eAudioBitstreamMode int AC3BitStreamMode(void) { return m_AC3Info.bitstreamMode; }; // 0..7 or eAudioBitstreamMode
int AC3AudioCodingMode(void) { return m_AC3Info.audioCodingMode; }; // 0..7 or eAudioCodingMode int AC3AudioCodingMode(void) { return m_AC3Info.audioCodingMode; }; // 0..7 or eAudioCodingMode
bool AC3_2_0(void) { return m_AC3Info.audioCodingMode == AUDIO_CODING_MODE_2_0; }; // boolean bool AC3_2_0(void) { return (m_AC3Info.audioCodingMode == AUDIO_CODING_MODE_2_0); }; // boolean
bool AC3_5_1(void) { return m_AC3Info.audioCodingMode == AUDIO_CODING_MODE_3_2; }; // boolean bool AC3_5_1(void) { return (m_AC3Info.audioCodingMode == AUDIO_CODING_MODE_3_2); }; // boolean
int AC3DolbySurroundMode(void) { return m_AC3Info.dolbySurroundMode; }; // eAudioDolbySurroundMode int AC3DolbySurroundMode(void) { return m_AC3Info.dolbySurroundMode; }; // eAudioDolbySurroundMode
int AC3CenterMixLevel(void) { return m_AC3Info.centerMixLevel; }; // eAudioCenterMixLevel int AC3CenterMixLevel(void) { return m_AC3Info.centerMixLevel; }; // eAudioCenterMixLevel
int AC3SurroundMixLevel(void) { return m_AC3Info.surroundMixLevel; }; // eAudioSurroundMixLevel int AC3SurroundMixLevel(void) { return m_AC3Info.surroundMixLevel; }; // eAudioSurroundMixLevel

View File

@@ -60,6 +60,17 @@ static cString getCA(int value)
return cString::sprintf("%X", value); return cString::sprintf("%X", value);
} }
static const char *getUserString(int Value, const tChannelParameterMap *Map)
{
const tChannelParameterMap *map = Map;
while (map && map->userValue != -1) {
if (map->driverValue == Value)
return map->userString ? trVDR(map->userString) : "---";
map++;
}
return "---";
}
cString getFrontendInfo(int cardIndex) cString getFrontendInfo(int cardIndex)
{ {
cString info; cString info;
@@ -288,95 +299,47 @@ cString getAudioChannelMode(int value)
cString getCoderate(int value) cString getCoderate(int value)
{ {
switch (value) { return cString::sprintf("%s", getUserString(value, CoderateValues));
case FEC_NONE: return cString::sprintf("%s", trVDR("none"));
case FEC_1_2: return cString::sprintf("1/2");
case FEC_2_3: return cString::sprintf("2/3");
case FEC_3_4: return cString::sprintf("3/4");
case FEC_4_5: return cString::sprintf("4/5");
case FEC_5_6: return cString::sprintf("5/6");
case FEC_6_7: return cString::sprintf("6/7");
case FEC_7_8: return cString::sprintf("7/8");
case FEC_8_9: return cString::sprintf("8/9");
case FEC_AUTO: return cString::sprintf("%s", trVDR("auto"));
default: break;
}
return cString::sprintf("---");
} }
cString getTransmission(int value) cString getTransmission(int value)
{ {
switch (value) { return cString::sprintf("%s", getUserString(value, TransmissionValues));
case TRANSMISSION_MODE_2K: return cString::sprintf("2K");
case TRANSMISSION_MODE_8K: return cString::sprintf("8K");
case TRANSMISSION_MODE_AUTO: return cString::sprintf("%s", trVDR("auto"));
default: break;
}
return cString::sprintf("---");
} }
cString getBandwidth(int value) cString getBandwidth(int value)
{ {
switch (value) { return cString::sprintf("%s", getUserString(value, BandwidthValues));
case BANDWIDTH_8_MHZ: return cString::sprintf("8 %s", tr("MHz"));
case BANDWIDTH_7_MHZ: return cString::sprintf("7 %s", tr("MHz"));
case BANDWIDTH_6_MHZ: return cString::sprintf("6 %s", tr("MHz"));
case BANDWIDTH_AUTO: return cString::sprintf("%s", trVDR("auto"));
default: break;
}
return cString::sprintf("---");
} }
cString getInversion(int value) cString getInversion(int value)
{ {
switch (value) { return cString::sprintf("%s", getUserString(value, InversionValues));
case INVERSION_OFF: return cString::sprintf("%s", tr("off"));
case INVERSION_ON: return cString::sprintf("%s", tr("on"));
case INVERSION_AUTO: return cString::sprintf("%s", trVDR("auto"));
default: break;
}
return cString::sprintf("---");
} }
cString getHierarchy(int value) cString getHierarchy(int value)
{ {
switch (value) { return cString::sprintf("%s", getUserString(value, HierarchyValues));
case HIERARCHY_NONE: return cString::sprintf("%s", trVDR("none"));
case HIERARCHY_1: return cString::sprintf("1");
case HIERARCHY_2: return cString::sprintf("2");
case HIERARCHY_4: return cString::sprintf("4");
case HIERARCHY_AUTO: return cString::sprintf("%s", trVDR("auto"));
default: break;
}
return cString::sprintf("---");
} }
cString getGuard(int value) cString getGuard(int value)
{ {
switch (value) { return cString::sprintf("%s", getUserString(value, GuardValues));
case GUARD_INTERVAL_1_32: return cString::sprintf("1/32");
case GUARD_INTERVAL_1_16: return cString::sprintf("1/16");
case GUARD_INTERVAL_1_8: return cString::sprintf("1/8");
case GUARD_INTERVAL_1_4: return cString::sprintf("1/4");
case GUARD_INTERVAL_AUTO: return cString::sprintf("%s", trVDR("auto"));
default: break;
}
return cString::sprintf("---");
} }
cString getModulation(int value) cString getModulation(int value)
{ {
switch (value) { return cString::sprintf("%s", getUserString(value, ModulationValues));
case QPSK: return cString::sprintf("QPSK"); }
case QAM_16: return cString::sprintf("QAM 16");
case QAM_32: return cString::sprintf("QAM 32"); cString getSystem(int value)
case QAM_64: return cString::sprintf("QAM 64"); {
case QAM_128: return cString::sprintf("QAM 128"); return cString::sprintf("%s", getUserString(value, SystemValues));
case QAM_256: return cString::sprintf("QAM 256"); }
case QAM_AUTO: return cString::sprintf("QAM %s", trVDR("auto"));
default: break; cString getRollOff(int value)
} {
return cString::sprintf("---"); return cString::sprintf("%s", getUserString(value, RollOffValues));
} }
cString getResolution(int width, int height, int scan) cString getResolution(int width, int height, int scan)
@@ -563,3 +526,85 @@ cString getBitrateKbits(double value)
return cString::sprintf("%.0f %s", value / 1000.0, tr("kbit/s")); return cString::sprintf("%.0f %s", value / 1000.0, tr("kbit/s"));
return cString::sprintf("---"); return cString::sprintf("---");
} }
cBitStream::cBitStream(const uint8_t *buf, const int len)
: data(buf),
count(len),
index(0)
{
}
cBitStream::~cBitStream()
{
}
int cBitStream::getBit()
{
if (index >= count)
return (1); // -> no infinite colomb's ...
int r = (data[index >> 3] >> (7 - (index & 7))) & 1;
++index;
return (r);
}
uint32_t cBitStream::getBits(uint32_t n)
{
uint32_t r = 0;
while (n--)
r = (r | (getBit() << n));
return (r);
}
void cBitStream::skipBits(uint32_t n)
{
index += n;
}
uint32_t cBitStream::getUeGolomb()
{
int n = 0;
while (!getBit() && (n < 32))
n++;
return (n ? ((1 << n) - 1) + getBits(n) : 0);
}
int32_t cBitStream::getSeGolomb()
{
uint32_t r = getUeGolomb() + 1;
return ((r & 1) ? -(r >> 1) : (r >> 1));
}
void cBitStream::skipGolomb()
{
int n = 0;
while (!getBit() && (n < 32))
n++;
skipBits(n);
}
void cBitStream::skipUeGolomb()
{
skipGolomb();
}
void cBitStream::skipSeGolomb()
{
skipGolomb();
}
void cBitStream::byteAlign()
{
int n = index % 8;
if (n > 0)
skipBits(8 - n);
}

View File

@@ -10,6 +10,7 @@
#include <stdint.h> #include <stdint.h>
#include <vdr/channels.h> #include <vdr/channels.h>
#include <vdr/remux.h>
#include <vdr/tools.h> #include <vdr/tools.h>
#ifdef DEBUG #ifdef DEBUG
@@ -48,6 +49,8 @@ cString getInversion(int value);
cString getHierarchy(int value); cString getHierarchy(int value);
cString getGuard(int value); cString getGuard(int value);
cString getModulation(int value); cString getModulation(int value);
cString getSystem(int value);
cString getRollOff(int value);
cString getResolution(int width, int height, int scan); cString getResolution(int width, int height, int scan);
cString getAspectRatio(int value); cString getAspectRatio(int value);
cString getVideoFormat(int value); cString getVideoFormat(int value);
@@ -66,4 +69,35 @@ cString getVideoBitrate(double value, double stream);
cString getBitrateMbits(double value); cString getBitrateMbits(double value);
cString getBitrateKbits(double value); cString getBitrateKbits(double value);
class cBitStream {
private:
const uint8_t *data;
int count; // in bits
int index; // in bits
public:
cBitStream(const uint8_t *buf, const int len);
~cBitStream();
int getBit();
uint32_t getBits(uint32_t n);
void skipBits(uint32_t n);
uint32_t getUeGolomb();
int32_t getSeGolomb();
void skipGolomb();
void skipUeGolomb();
void skipSeGolomb();
void byteAlign();
void skipBit() { skipBits(1); }
uint32_t getU8() { return getBits(8); }
uint32_t getU16() { return ((getBits(8) << 8) | getBits(8)); }
uint32_t getU24() { return ((getBits(8) << 16) | (getBits(8) << 8) | getBits(8)); }
uint32_t getU32() { return ((getBits(8) << 24) | (getBits(8) << 16) | (getBits(8) << 8) | getBits(8)); }
bool isEOF() { return (index >= count); }
void reset() { index = 0; }
int getIndex() { return (isEOF() ? count : index); }
const uint8_t *getData() { return (isEOF() ? NULL : data + (index / 8)); }
};
#endif // __FEMONTOOLS_H #endif // __FEMONTOOLS_H

View File

@@ -69,4 +69,25 @@ typedef struct video_info {
double bitrate; // Mbit/s double bitrate; // Mbit/s
} video_info_t; } video_info_t;
class cFemonVideoIf {
public:
cFemonVideoIf() {}
virtual ~cFemonVideoIf() {}
// eVideoCodec
virtual void SetVideoCodec(eVideoCodec codec) = 0;
// eVideoFormat
virtual void SetVideoFormat(eVideoFormat format) = 0;
// eVideoScan
virtual void SetVideoScan(eVideoScan scan) = 0;
// eVideoAspectRatio
virtual void SetVideoAspectRatio(eVideoAspectRatio aspectratio) = 0;
// pixels
virtual void SetVideoSize(int width, int height) = 0;
// Hz
virtual void SetVideoFramerate(double framerate) = 0;
// Mbit/s
virtual void SetVideoBitrate(double bitrate) = 0;
};
#endif //__FEMONVIDEO_H #endif //__FEMONVIDEO_H

View File

@@ -7,9 +7,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: femon 1.6.5\n" "Project-Id-Version: femon 1.7.3\n"
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n" "Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
"POT-Creation-Date: 2008-12-16 12:08+0200\n" "POT-Creation-Date: 2009-08-29 20:57+0300\n"
"PO-Revision-Date: 2007-08-12 23:22+0300\n" "PO-Revision-Date: 2007-08-12 23:22+0300\n"
"Last-Translator: Christian Wieninger\n" "Last-Translator: Christian Wieninger\n"
"Language-Team: <vdr@linuxtv.org>\n" "Language-Team: <vdr@linuxtv.org>\n"
@@ -89,15 +89,6 @@ msgstr "Position"
msgid "Define the position of OSD." msgid "Define the position of OSD."
msgstr "" msgstr ""
msgid "Define the height of OSD."
msgstr ""
msgid "Horizontal offset"
msgstr "Horizontaler Offset"
msgid "Define the horizontal offset of OSD."
msgstr ""
msgid "Red limit [%]" msgid "Red limit [%]"
msgstr "Grenze Rot [%]" msgstr "Grenze Rot [%]"
@@ -233,12 +224,6 @@ msgstr "Dolby Surround Modus"
msgid "Low Frequency Effects" msgid "Low Frequency Effects"
msgstr "Tieft<66>ner Effekte" msgstr "Tieft<66>ner Effekte"
msgid "on"
msgstr "Ein"
msgid "off"
msgstr "Aus"
msgid "Dialogue Normalization" msgid "Dialogue Normalization"
msgstr "Dialog Normalisierung" msgstr "Dialog Normalisierung"
@@ -287,9 +272,6 @@ msgstr ""
msgid "mono" msgid "mono"
msgstr "" msgstr ""
msgid "MHz"
msgstr "MHz"
msgid "interlaced" msgid "interlaced"
msgstr "" msgstr ""
@@ -380,6 +362,9 @@ msgstr "dB"
msgid "not indicated" msgid "not indicated"
msgstr "nicht angegeben" msgstr "nicht angegeben"
msgid "MHz"
msgstr "MHz"
msgid "free" msgid "free"
msgstr "frei" msgstr "frei"

View File

@@ -5,9 +5,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: femon 1.6.5\n" "Project-Id-Version: femon 1.7.3\n"
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n" "Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
"POT-Creation-Date: 2008-12-16 12:08+0200\n" "POT-Creation-Date: 2009-08-29 20:57+0300\n"
"PO-Revision-Date: 2007-08-12 23:22+0300\n" "PO-Revision-Date: 2007-08-12 23:22+0300\n"
"Last-Translator: Luis Palacios\n" "Last-Translator: Luis Palacios\n"
"Language-Team: <vdr@linuxtv.org>\n" "Language-Team: <vdr@linuxtv.org>\n"
@@ -87,15 +87,6 @@ msgstr "Posici
msgid "Define the position of OSD." msgid "Define the position of OSD."
msgstr "" msgstr ""
msgid "Define the height of OSD."
msgstr ""
msgid "Horizontal offset"
msgstr "Desplazamiento horizontal"
msgid "Define the horizontal offset of OSD."
msgstr ""
msgid "Red limit [%]" msgid "Red limit [%]"
msgstr "L<>mite de rojo [%s]" msgstr "L<>mite de rojo [%s]"
@@ -231,12 +222,6 @@ msgstr "Nivel sonoro Dolby Surround"
msgid "Low Frequency Effects" msgid "Low Frequency Effects"
msgstr "Efectos de baja frecuencia" msgstr "Efectos de baja frecuencia"
msgid "on"
msgstr "on"
msgid "off"
msgstr "off"
msgid "Dialogue Normalization" msgid "Dialogue Normalization"
msgstr "Normalizaci<63>n del di<64>logo" msgstr "Normalizaci<63>n del di<64>logo"
@@ -285,9 +270,6 @@ msgstr ""
msgid "mono" msgid "mono"
msgstr "o" msgstr "o"
msgid "MHz"
msgstr "MHz"
msgid "interlaced" msgid "interlaced"
msgstr "" msgstr ""
@@ -378,6 +360,9 @@ msgstr "dB"
msgid "not indicated" msgid "not indicated"
msgstr "no indicado" msgstr "no indicado"
msgid "MHz"
msgstr "MHz"
msgid "free" msgid "free"
msgstr "libre" msgstr "libre"

View File

@@ -5,9 +5,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: femon 1.6.5\n" "Project-Id-Version: femon 1.7.3\n"
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n" "Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
"POT-Creation-Date: 2008-12-16 12:08+0200\n" "POT-Creation-Date: 2009-08-29 20:57+0300\n"
"PO-Revision-Date: 2007-08-12 23:22+0300\n" "PO-Revision-Date: 2007-08-12 23:22+0300\n"
"Last-Translator: Arthur Konovalov\n" "Last-Translator: Arthur Konovalov\n"
"Language-Team: <vdr@linuxtv.org>\n" "Language-Team: <vdr@linuxtv.org>\n"
@@ -87,15 +87,6 @@ msgstr "Positsioon"
msgid "Define the position of OSD." msgid "Define the position of OSD."
msgstr "" msgstr ""
msgid "Define the height of OSD."
msgstr ""
msgid "Horizontal offset"
msgstr "Horisontaalne nihe"
msgid "Define the horizontal offset of OSD."
msgstr ""
msgid "Red limit [%]" msgid "Red limit [%]"
msgstr "Punase limiit [%]" msgstr "Punase limiit [%]"
@@ -231,12 +222,6 @@ msgstr "Dolby Surround'i t
msgid "Low Frequency Effects" msgid "Low Frequency Effects"
msgstr "LFE kanal" msgstr "LFE kanal"
msgid "on"
msgstr "Sees"
msgid "off"
msgstr "V<>ljas"
msgid "Dialogue Normalization" msgid "Dialogue Normalization"
msgstr "Dialoogi normalisatsioon" msgstr "Dialoogi normalisatsioon"
@@ -285,9 +270,6 @@ msgstr ""
msgid "mono" msgid "mono"
msgstr "" msgstr ""
msgid "MHz"
msgstr "MHz"
msgid "interlaced" msgid "interlaced"
msgstr "" msgstr ""
@@ -378,6 +360,9 @@ msgstr "dB"
msgid "not indicated" msgid "not indicated"
msgstr "m<>rkimata" msgstr "m<>rkimata"
msgid "MHz"
msgstr "MHz"
msgid "free" msgid "free"
msgstr "vaba" msgstr "vaba"

View File

@@ -5,9 +5,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: femon 1.6.5\n" "Project-Id-Version: femon 1.7.3\n"
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n" "Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
"POT-Creation-Date: 2008-12-16 12:08+0200\n" "POT-Creation-Date: 2009-08-29 20:57+0300\n"
"PO-Revision-Date: 2007-08-12 23:22+0300\n" "PO-Revision-Date: 2007-08-12 23:22+0300\n"
"Last-Translator: Rolf Ahrenberg\n" "Last-Translator: Rolf Ahrenberg\n"
"Language-Team: <vdr@linuxtv.org>\n" "Language-Team: <vdr@linuxtv.org>\n"
@@ -87,15 +87,6 @@ msgstr "Sijainti"
msgid "Define the position of OSD." msgid "Define the position of OSD."
msgstr "Määrittele näytön sijainti." msgstr "Määrittele näytön sijainti."
msgid "Define the height of OSD."
msgstr "Määrittele näytön korkeus."
msgid "Horizontal offset"
msgstr "Vaakakeskitys"
msgid "Define the horizontal offset of OSD."
msgstr "Määrittele näytön vaakakeskitys."
msgid "Red limit [%]" msgid "Red limit [%]"
msgstr "Punaisen taso [%]" msgstr "Punaisen taso [%]"
@@ -231,12 +222,6 @@ msgstr "Dolby Surround -tehoste"
msgid "Low Frequency Effects" msgid "Low Frequency Effects"
msgstr "LFE-kanava" msgstr "LFE-kanava"
msgid "on"
msgstr "päällä"
msgid "off"
msgstr "poissa"
msgid "Dialogue Normalization" msgid "Dialogue Normalization"
msgstr "Dialogin normalisointi" msgstr "Dialogin normalisointi"
@@ -285,9 +270,6 @@ msgstr "kaksikanavainen"
msgid "mono" msgid "mono"
msgstr "mono" msgstr "mono"
msgid "MHz"
msgstr "MHz"
msgid "interlaced" msgid "interlaced"
msgstr "lomiteltu" msgstr "lomiteltu"
@@ -378,6 +360,9 @@ msgstr "dB"
msgid "not indicated" msgid "not indicated"
msgstr "ei ilmaistu" msgstr "ei ilmaistu"
msgid "MHz"
msgstr "MHz"
msgid "free" msgid "free"
msgstr "vapaa" msgstr "vapaa"

View File

@@ -5,9 +5,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: femon 1.6.5\n" "Project-Id-Version: femon 1.7.3\n"
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n" "Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
"POT-Creation-Date: 2008-12-16 12:08+0200\n" "POT-Creation-Date: 2009-08-29 20:57+0300\n"
"PO-Revision-Date: 2008-01-26 09:59+0100\n" "PO-Revision-Date: 2008-01-26 09:59+0100\n"
"Last-Translator: NIVAL Micha<68>l <mnival@club-internet.fr>\n" "Last-Translator: NIVAL Micha<68>l <mnival@club-internet.fr>\n"
"Language-Team: <vdr@linuxtv.org>\n" "Language-Team: <vdr@linuxtv.org>\n"
@@ -87,15 +87,6 @@ msgstr "Position"
msgid "Define the position of OSD." msgid "Define the position of OSD."
msgstr "D<>finit la position de l'OSD." msgstr "D<>finit la position de l'OSD."
msgid "Define the height of OSD."
msgstr "D<>finit l'hauteur de l'OSD."
msgid "Horizontal offset"
msgstr "D<>placement horizontal"
msgid "Define the horizontal offset of OSD."
msgstr "D<>finit le d<>placement horizontal de l'OSD."
msgid "Red limit [%]" msgid "Red limit [%]"
msgstr "Limite du rouge (%)" msgstr "Limite du rouge (%)"
@@ -231,12 +222,6 @@ msgstr "Mode Dolby Surround"
msgid "Low Frequency Effects" msgid "Low Frequency Effects"
msgstr "Effets de basses" msgstr "Effets de basses"
msgid "on"
msgstr "Oui"
msgid "off"
msgstr "Non"
msgid "Dialogue Normalization" msgid "Dialogue Normalization"
msgstr "Normalisation des dialogues" msgstr "Normalisation des dialogues"
@@ -285,9 +270,6 @@ msgstr ""
msgid "mono" msgid "mono"
msgstr "" msgstr ""
msgid "MHz"
msgstr "MHz"
msgid "interlaced" msgid "interlaced"
msgstr "" msgstr ""
@@ -378,6 +360,9 @@ msgstr "dB"
msgid "not indicated" msgid "not indicated"
msgstr "non indiqu<71>" msgstr "non indiqu<71>"
msgid "MHz"
msgstr "MHz"
msgid "free" msgid "free"
msgstr "libre" msgstr "libre"

View File

@@ -6,9 +6,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: femon 1.6.5\n" "Project-Id-Version: femon 1.7.3\n"
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n" "Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
"POT-Creation-Date: 2008-12-16 12:08+0200\n" "POT-Creation-Date: 2009-08-29 20:57+0300\n"
"PO-Revision-Date: 2008-11-10 23:37+0100\n" "PO-Revision-Date: 2008-11-10 23:37+0100\n"
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n" "Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
"Language-Team: <vdr@linuxtv.org>\n" "Language-Team: <vdr@linuxtv.org>\n"
@@ -88,15 +88,6 @@ msgstr "Posizione"
msgid "Define the position of OSD." msgid "Define the position of OSD."
msgstr "Definisci la posizione dell'OSD." msgstr "Definisci la posizione dell'OSD."
msgid "Define the height of OSD."
msgstr "Definisci l'altezza dell'OSD."
msgid "Horizontal offset"
msgstr "Limite orizzontale"
msgid "Define the horizontal offset of OSD."
msgstr "Definisci il limite orizzontale dell'OSD."
msgid "Red limit [%]" msgid "Red limit [%]"
msgstr "Limite rosso [%]" msgstr "Limite rosso [%]"
@@ -232,12 +223,6 @@ msgstr "Modalit
msgid "Low Frequency Effects" msgid "Low Frequency Effects"
msgstr "Effetti bassa frequenza" msgstr "Effetti bassa frequenza"
msgid "on"
msgstr "Attivo"
msgid "off"
msgstr "Disattivo"
msgid "Dialogue Normalization" msgid "Dialogue Normalization"
msgstr "Normalizzazione dialoghi" msgstr "Normalizzazione dialoghi"
@@ -286,9 +271,6 @@ msgstr "dual"
msgid "mono" msgid "mono"
msgstr "mono" msgstr "mono"
msgid "MHz"
msgstr "MHz"
msgid "interlaced" msgid "interlaced"
msgstr "interlacciato" msgstr "interlacciato"
@@ -379,6 +361,9 @@ msgstr "dB"
msgid "not indicated" msgid "not indicated"
msgstr "non indicato" msgstr "non indicato"
msgid "MHz"
msgstr "MHz"
msgid "free" msgid "free"
msgstr "libero" msgstr "libero"

View File

@@ -5,9 +5,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: femon 1.6.5\n" "Project-Id-Version: femon 1.7.3\n"
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n" "Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
"POT-Creation-Date: 2008-12-16 12:08+0200\n" "POT-Creation-Date: 2009-08-29 20:57+0300\n"
"PO-Revision-Date: 2007-08-12 23:22+0300\n" "PO-Revision-Date: 2007-08-12 23:22+0300\n"
"Last-Translator: Vyacheslav Dikonov\n" "Last-Translator: Vyacheslav Dikonov\n"
"Language-Team: <vdr@linuxtv.org>\n" "Language-Team: <vdr@linuxtv.org>\n"
@@ -87,15 +87,6 @@ msgstr "
msgid "Define the position of OSD." msgid "Define the position of OSD."
msgstr "" msgstr ""
msgid "Define the height of OSD."
msgstr ""
msgid "Horizontal offset"
msgstr ""
msgid "Define the horizontal offset of OSD."
msgstr ""
msgid "Red limit [%]" msgid "Red limit [%]"
msgstr "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> (%)" msgstr "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> (%)"
@@ -231,12 +222,6 @@ msgstr ""
msgid "Low Frequency Effects" msgid "Low Frequency Effects"
msgstr "" msgstr ""
msgid "on"
msgstr "<22><><EFBFBD>"
msgid "off"
msgstr "<22><><EFBFBD><EFBFBD>"
msgid "Dialogue Normalization" msgid "Dialogue Normalization"
msgstr "" msgstr ""
@@ -285,9 +270,6 @@ msgstr ""
msgid "mono" msgid "mono"
msgstr "" msgstr ""
msgid "MHz"
msgstr "<22><><EFBFBD>"
msgid "interlaced" msgid "interlaced"
msgstr "" msgstr ""
@@ -378,6 +360,9 @@ msgstr "dB"
msgid "not indicated" msgid "not indicated"
msgstr "" msgstr ""
msgid "MHz"
msgstr "<22><><EFBFBD>"
msgid "free" msgid "free"
msgstr "" msgstr ""