diff --git a/HISTORY b/HISTORY index d8cdc39..c04ad77 100644 --- a/HISTORY +++ b/HISTORY @@ -381,3 +381,4 @@ VDR Plugin 'femon' Revision History - Changed H.264 parser to show display aspect ratio. - Removed error logging from unimplemented ioctl functions. +- Removed bitstream parsing from Receive() method. diff --git a/femonosd.c b/femonosd.c index fa04b98..fe88f7d 100644 --- a/femonosd.c +++ b/femonosd.c @@ -28,6 +28,7 @@ #define OSDSPACING 5 #define OSDROUNDING 10 #define IS_OSDROUNDING (femonConfig.skin == eFemonSkinElchi) +#define IS_OSDRESOLUTION(r1, r2) (abs(r1 - r2) < 20) #define OSDINFOWIN_Y(offset) (femonConfig.position ? (OSDHEIGHT - OSDINFOHEIGHT + offset) : offset) #define OSDINFOWIN_X(col) ((col == 4) ? int(round(OSDWIDTH * 0.76)) : \ (col == 3) ? int(round(OSDWIDTH * 0.51)) : \ @@ -66,7 +67,7 @@ #define OSDDRAWSTATUSBAR(value) \ if (value > 0) { \ - int32_t barvalue = OSDBARWIDTH(value); \ + int barvalue = OSDBARWIDTH(value); \ m_Osd->DrawRectangle(0, OSDSTATUSWIN_Y(offset) + 3, min(OSDBARWIDTH(femonConfig.redlimit), barvalue), OSDSTATUSWIN_Y(offset) + OSDROWHEIGHT - 3, femonTheme[femonConfig.theme].clrRed); \ if (barvalue > OSDBARWIDTH(femonConfig.redlimit)) \ m_Osd->DrawRectangle(OSDBARWIDTH(femonConfig.redlimit), OSDSTATUSWIN_Y(offset) + 3, min((OSDWIDTH * femonConfig.greenlimit / 100), barvalue), OSDSTATUSWIN_Y(offset) + OSDROWHEIGHT - 3, femonTheme[femonConfig.theme].clrYellow); \ @@ -168,10 +169,15 @@ cFemonOsd::cFemonOsd() m_SvdrpPlugin(NULL), m_Number(0), m_OldNumber(0), - m_SNR(-1), - m_Signal(-1), - m_BER(-1), - m_UNC(-1), + m_SNR(0), + m_SNRValid(false), + m_Signal(0), + m_SignalValid(false), + m_BER(0), + m_BERValid(false), + m_UNC(0), + m_UNCValid(false), + m_FrontendStatusValid(false), m_DisplayMode(femonConfig.displaymode), m_OsdWidth(cOsd::OsdWidth()), m_OsdHeight(cOsd::OsdHeight()), @@ -181,8 +187,8 @@ cFemonOsd::cFemonOsd() { int tmp; Dprintf("%s()\n", __PRETTY_FUNCTION__); - memset(&m_FrontendInfo, 0, sizeof(m_FrontendInfo)); memset(&m_FrontendStatus, 0, sizeof(m_FrontendStatus)); + memset(&m_FrontendInfo, 0, sizeof(m_FrontendInfo)); m_SvdrpConnection.handle = -1; m_Font = cFont::CreateFont(Setup.FontSml, min(max(Setup.FontSmlSize, MINFONTSIZE), MAXFONTSIZE)); if (!m_Font || !m_Font->Height()) { @@ -284,13 +290,13 @@ void cFemonOsd::DrawStatusWindow(void) OSDDRAWSTATUSBM(OSDSPACING); } if (m_Receiver) { - if (abs(m_Receiver->VideoVerticalSize() - 1080) < 20) + if (IS_OSDRESOLUTION(m_Receiver->VideoVerticalSize(), 1080)) bm = &bmSymbol[SYMBOL_FORMAT_1080]; - else if (abs(m_Receiver->VideoVerticalSize() - 720) < 20) + else if (IS_OSDRESOLUTION(m_Receiver->VideoVerticalSize(), 720)) bm = &bmSymbol[SYMBOL_FORMAT_720]; - else if (abs(m_Receiver->VideoVerticalSize() - 576) < 20) + else if (IS_OSDRESOLUTION(m_Receiver->VideoVerticalSize(), 576)) bm = &bmSymbol[SYMBOL_FORMAT_576]; - else if (abs(m_Receiver->VideoVerticalSize() - 480) < 20) + else if (IS_OSDRESOLUTION(m_Receiver->VideoVerticalSize(), 480)) bm = &bmSymbol[SYMBOL_FORMAT_480]; else bm = NULL; @@ -321,28 +327,30 @@ void cFemonOsd::DrawStatusWindow(void) OSDDRAWSTATUSBM(OSDSPACING); } offset += OSDROWHEIGHT; - if (m_Signal >= 0) + if (m_SignalValid) OSDDRAWSTATUSBAR(m_Signal / 655); offset += OSDROWHEIGHT; - if (m_SNR >= 0) + if (m_SNRValid) OSDDRAWSTATUSBAR(m_SNR / 655); offset += OSDROWHEIGHT; - OSDDRAWSTATUSVALUES("STR:", (m_Signal >= 0) ? *cString::sprintf("%04" PRIu32, m_Signal) : "---", (m_Signal >= 0) ? *cString::sprintf("(%2d%%)", m_Signal / 655) : "", - "BER:", (m_BER >= 0) ? *cString::sprintf("%08" PRIx64, m_BER) : "---", *cString::sprintf("%s:", tr("Video")), + OSDDRAWSTATUSVALUES("STR:", m_SignalValid ? *cString::sprintf("%04x", m_Signal) : "", m_SignalValid ? *cString::sprintf("(%2d%%)", m_Signal / 655) : "", + "BER:", m_BERValid ? *cString::sprintf("%08x", m_BER) : "", *cString::sprintf("%s:", tr("Video")), *getBitrateMbits(m_Receiver ? m_Receiver->VideoBitrate() : (m_SvdrpFrontend >= 0 ? m_SvdrpVideoBitrate : -1.0))); offset += OSDROWHEIGHT; - OSDDRAWSTATUSVALUES("SNR:", (m_SNR >= 0) ? *cString::sprintf("%04" PRIu32, m_SNR) : "---", (m_SNR >= 0) ? *cString::sprintf("(%2d%%)", m_SNR / 655) : "", - "UNC:", (m_UNC >= 0) ? *cString::sprintf("%08" PRIx64, m_UNC) : "---", + OSDDRAWSTATUSVALUES("SNR:", m_SNRValid ? *cString::sprintf("%04x", m_SNR) : "", m_SNRValid ? *cString::sprintf("(%2d%%)", m_SNR / 655) : "", + "UNC:", m_UNCValid ? *cString::sprintf("%08x", m_UNC) : "", *cString::sprintf("%s:", (m_Receiver && m_Receiver->AC3Valid() && IS_DOLBY_TRACK(track)) ? tr("AC-3") : tr("Audio")), *getBitrateKbits(m_Receiver ? ((m_Receiver->AC3Valid() && IS_DOLBY_TRACK(track)) ? m_Receiver->AC3Bitrate() : m_Receiver->AudioBitrate()) : (m_SvdrpFrontend >= 0 ? m_SvdrpAudioBitrate : -1.0))); offset += OSDROWHEIGHT; x = bmSymbol[SYMBOL_LOCK].Width(); y = (OSDROWHEIGHT - bmSymbol[SYMBOL_LOCK].Height()) / 2; - OSDDRAWSTATUSFRONTEND(1, bmSymbol[SYMBOL_LOCK], FE_HAS_LOCK); - OSDDRAWSTATUSFRONTEND(2, bmSymbol[SYMBOL_SIGNAL], FE_HAS_SIGNAL); - OSDDRAWSTATUSFRONTEND(3, bmSymbol[SYMBOL_CARRIER], FE_HAS_CARRIER); - OSDDRAWSTATUSFRONTEND(4, bmSymbol[SYMBOL_VITERBI], FE_HAS_VITERBI); - OSDDRAWSTATUSFRONTEND(5, bmSymbol[SYMBOL_SYNC], FE_HAS_SYNC); + if (m_FrontendStatusValid) { + OSDDRAWSTATUSFRONTEND(1, bmSymbol[SYMBOL_LOCK], FE_HAS_LOCK); + OSDDRAWSTATUSFRONTEND(2, bmSymbol[SYMBOL_SIGNAL], FE_HAS_SIGNAL); + OSDDRAWSTATUSFRONTEND(3, bmSymbol[SYMBOL_CARRIER], FE_HAS_CARRIER); + OSDDRAWSTATUSFRONTEND(4, bmSymbol[SYMBOL_VITERBI], FE_HAS_VITERBI); + OSDDRAWSTATUSFRONTEND(5, bmSymbol[SYMBOL_SYNC], FE_HAS_SYNC); + } OSDDRAWSTATUSBOTTOMBAR(); m_Osd->Flush(); } @@ -505,16 +513,11 @@ void cFemonOsd::Action(void) m_SvdrpVideoBitrate = -1.0; m_SvdrpAudioBitrate = -1.0; if (m_Frontend != -1) { - if (ioctl(m_Frontend, FE_READ_STATUS, &m_FrontendStatus) < 0) - memset(&m_FrontendStatus, 0, sizeof(m_FrontendStatus)); - if (ioctl(m_Frontend, FE_READ_SIGNAL_STRENGTH, &m_Signal) < 0) - m_Signal = -1; - if (ioctl(m_Frontend, FE_READ_SNR, &m_SNR) < 0) - m_SNR = -1; - if (ioctl(m_Frontend, FE_READ_BER, &m_BER) < 0) - m_BER = -1; - if (ioctl(m_Frontend, FE_READ_UNCORRECTED_BLOCKS, &m_UNC) < 0) - m_UNC = -1; + m_FrontendStatusValid = (ioctl(m_Frontend, FE_READ_STATUS, &m_FrontendStatus) >= 0); + m_SignalValid = (ioctl(m_Frontend, FE_READ_SIGNAL_STRENGTH, &m_Signal) >= 0); + m_SNRValid = (ioctl(m_Frontend, FE_READ_SNR, &m_SNR) >= 0); + m_BERValid = (ioctl(m_Frontend, FE_READ_BER, &m_BER) >= 0); + m_UNCValid = (ioctl(m_Frontend, FE_READ_UNCORRECTED_BLOCKS, &m_UNC) >= 0); DrawInfoWindow(); DrawStatusWindow(); } @@ -522,24 +525,40 @@ void cFemonOsd::Action(void) cmd.handle = m_SvdrpConnection.handle; m_SvdrpPlugin->Service("SvdrpCommand-v1.0", &cmd); if (cmd.responseCode == 900) { + m_FrontendStatusValid = false; + m_SignalValid = false; + m_SNRValid = false; + m_BERValid = false; + m_UNCValid = false; for (cLine *line = cmd.reply.First(); line; line = cmd.reply.Next(line)) { const char *s = line->Text(); if (!strncasecmp(s, "CARD:", 5)) m_SvdrpFrontend = (int)strtol(s + 5, NULL, 10); else if (!strncasecmp(s, "TYPE:", 5)) m_FrontendInfo.type = (fe_type_t)strtol(s + 5, NULL, 10); - else if (!strncasecmp(s, "NAME:", 5)) + else if (!strncasecmp(s, "NAME:", 5)) { strn0cpy(m_FrontendInfo.name, s + 5, sizeof(m_FrontendInfo.name)); - else if (!strncasecmp(s, "STAT:", 5)) + } + else if (!strncasecmp(s, "STAT:", 5)) { m_FrontendStatus = (fe_status_t)strtol(s + 5, NULL, 16); - else if (!strncasecmp(s, "SGNL:", 5)) - m_Signal = (int32_t)strtol(s + 5, NULL, 16); - else if (!strncasecmp(s, "SNRA:", 5)) - m_SNR = (int32_t)strtol(s + 5, NULL, 16); - else if (!strncasecmp(s, "BERA:", 5)) - m_BER = (int64_t)strtol(s + 5, NULL, 16); - else if (!strncasecmp(s, "UNCB:", 5)) - m_UNC = (int64_t)strtol(s + 5, NULL, 16); + m_FrontendStatusValid = true; + } + else if (!strncasecmp(s, "SGNL:", 5)) { + m_Signal = (uint16_t)strtol(s + 5, NULL, 16); + m_SignalValid = true; + } + else if (!strncasecmp(s, "SNRA:", 5)) { + m_SNR = (uint16_t)strtol(s + 5, NULL, 16); + m_SNRValid = true; + } + else if (!strncasecmp(s, "BERA:", 5)) { + m_BER = (uint32_t)strtol(s + 5, NULL, 16); + m_BERValid = true; + } + else if (!strncasecmp(s, "UNCB:", 5)) { + m_UNC = (uint32_t)strtol(s + 5, NULL, 16); + m_UNCValid = true; + } else if (!strncasecmp(s, "VIBR:", 5)) m_SvdrpVideoBitrate = (double)strtol(s + 5, NULL, 10); else if (!strncasecmp(s, "AUBR:", 5)) diff --git a/femonosd.h b/femonosd.h index b85beca..58ff428 100644 --- a/femonosd.h +++ b/femonosd.h @@ -34,14 +34,19 @@ private: double m_SvdrpAudioBitrate; SvdrpConnection_v1_0 m_SvdrpConnection; cPlugin *m_SvdrpPlugin; - dvb_frontend_info m_FrontendInfo; int m_Number; int m_OldNumber; - int32_t m_SNR; - int32_t m_Signal; - int64_t m_BER; - int64_t m_UNC; + uint16_t m_SNR; + bool m_SNRValid; + uint16_t m_Signal; + bool m_SignalValid; + uint32_t m_BER; + bool m_BERValid; + uint32_t m_UNC; + bool m_UNCValid; fe_status_t m_FrontendStatus; + bool m_FrontendStatusValid; + dvb_frontend_info m_FrontendInfo; int m_DisplayMode; int m_OsdWidth; int m_OsdHeight; diff --git a/femonreceiver.c b/femonreceiver.c index 99f87e6..caa7fc6 100644 --- a/femonreceiver.c +++ b/femonreceiver.c @@ -20,15 +20,18 @@ cFemonReceiver::cFemonReceiver(tChannelID ChannelID, int Ca, int Vtype, int Vpid m_DetectMPEG(this, this), m_DetectAAC(this), m_DetectAC3(this), + m_VideoBuffer(KILOBYTE(256), TS_SIZE, false, "Femon video"), m_VideoType(Vtype), m_VideoPid(Vpid), m_VideoPacketCount(0), m_VideoBitrate(0.0), m_VideoValid(false), + m_AudioBuffer(KILOBYTE(256), TS_SIZE, false, "Femon audio"), m_AudioPid(Apid[0]), m_AudioPacketCount(0), m_AudioBitrate(0.0), m_AudioValid(false), + m_AC3Buffer(KILOBYTE(256), TS_SIZE, false, "Femon AC3"), m_AC3Pid(Dpid[0]), m_AC3PacketCount(0), m_AC3Bitrate(0), @@ -36,6 +39,10 @@ cFemonReceiver::cFemonReceiver(tChannelID ChannelID, int Ca, int Vtype, int Vpid { Dprintf("%s()\n", __PRETTY_FUNCTION__); + m_VideoBuffer.SetTimeouts(0, 0); + m_AudioBuffer.SetTimeouts(0, 0); + m_AC3Buffer.SetTimeouts(0, 0); + m_VideoInfo.codec = VIDEO_CODEC_INVALID; m_VideoInfo.format = VIDEO_FORMAT_INVALID; m_VideoInfo.scan = VIDEO_SCAN_INVALID; @@ -89,46 +96,31 @@ void cFemonReceiver::Activate(bool On) void cFemonReceiver::Receive(uchar *Data, int Length) { // TS packet length: TS_SIZE - if (Length == TS_SIZE) { + if ((*Data == TS_SYNC_BYTE) || (Length == TS_SIZE)) { int len, pid = TsPid(Data); if (pid == m_VideoPid) { - 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); + ++m_VideoPacketCount; + len = m_VideoBuffer.Put(Data, Length); + if (len != Length) { + m_VideoBuffer.ReportOverflow(Length - len); + m_VideoBuffer.Clear(); + } } else if (pid == m_AudioPid) { - m_AudioPacketCount++; - 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_AudioPacketCount; + len = m_AudioBuffer.Put(Data, Length); + if (len != Length) { + m_AudioBuffer.ReportOverflow(Length - len); + m_AudioBuffer.Clear(); } - m_AudioAssembler.PutTs(Data, Length); } else if (pid == m_AC3Pid) { - m_AC3PacketCount++; - if (const uint8_t *p = m_AC3Assembler.GetPes(len)) { - if (m_DetectAC3.processAudio(p, len)) - m_AC3Valid = true; - m_AC3Assembler.Reset(); + ++m_AC3PacketCount; + len = m_AC3Buffer.Put(Data, Length); + if (len != Length) { + m_AC3Buffer.ReportOverflow(Length - len); + m_AC3Buffer.Clear(); } - m_AC3Assembler.PutTs(Data, Length); } } } @@ -136,17 +128,116 @@ void cFemonReceiver::Receive(uchar *Data, int Length) void cFemonReceiver::Action(void) { Dprintf("%s()\n", __PRETTY_FUNCTION__); - cTimeMs t; + cTimeMs calcPeriod(0); m_Active = true; + while (Running() && m_Active) { - t.Set(0); - // TS packet 188 bytes - 4 byte header; MPEG standard defines 1Mbit = 1000000bit - m_VideoBitrate = (10.0 * 8.0 * 184.0 * m_VideoPacketCount) / femonConfig.calcinterval; - m_VideoPacketCount = 0; - m_AudioBitrate = (10.0 * 8.0 * 184.0 * m_AudioPacketCount) / femonConfig.calcinterval; - m_AudioPacketCount = 0; - m_AC3Bitrate = (10.0 * 8.0 * 184.0 * m_AC3PacketCount) / femonConfig.calcinterval; - m_AC3PacketCount = 0; - m_Sleep.Wait(max((int)(100 * femonConfig.calcinterval - t.Elapsed()), 3)); + uint8_t *Data; + double timeout; + int len, Length; + bool processed = false; + + // process available video data + while (Data = m_VideoBuffer.Get(Length)) { + if (!m_Active || (Length < TS_SIZE)) + break; + Length = TS_SIZE; + if (*Data != TS_SYNC_BYTE) { + for (int i = 1; i < Length; ++i) { + if (Data[i] == TS_SYNC_BYTE) { + Length = i; + break; + } + } + m_VideoBuffer.Del(Length); + continue; + } + processed = true; + if (TsPayloadStart(Data)) { + 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); + m_VideoBuffer.Del(Length); + } + + // process available audio data + while (Data = m_AudioBuffer.Get(Length)) { + if (!m_Active || (Length < TS_SIZE)) + break; + Length = TS_SIZE; + if (*Data != TS_SYNC_BYTE) { + for (int i = 1; i < Length; ++i) { + if (Data[i] == TS_SYNC_BYTE) { + Length = i; + break; + } + } + m_AudioBuffer.Del(Length); + continue; + } + processed = true; + 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); + m_AudioBuffer.Del(Length); + } + + // process available dolby data + while (Data = m_AC3Buffer.Get(Length)) { + if (!m_Active || (Length < TS_SIZE)) + break; + Length = TS_SIZE; + if (*Data != TS_SYNC_BYTE) { + for (int i = 1; i < Length; ++i) { + if (Data[i] == TS_SYNC_BYTE) { + Length = i; + break; + } + } + m_AC3Buffer.Del(Length); + continue; + } + processed = true; + if (const uint8_t *p = m_AC3Assembler.GetPes(len)) { + if (m_DetectAC3.processAudio(p, len)) + m_AC3Valid = true; + m_AC3Assembler.Reset(); + } + m_AC3Assembler.PutTs(Data, Length); + m_AudioBuffer.Del(Length); + } + + // calculate bitrates + timeout = double(calcPeriod.Elapsed()); + if (m_Active && (timeout >= (100.0 * femonConfig.calcinterval))) { + // TS packet 188 bytes - 4 byte header; MPEG standard defines 1Mbit = 1000000bit + m_VideoBitrate = (1000.0 * 8.0 * 184.0 * m_VideoPacketCount) / timeout; + m_VideoPacketCount = 0; + m_AudioBitrate = (1000.0 * 8.0 * 184.0 * m_AudioPacketCount) / timeout; + m_AudioPacketCount = 0; + m_AC3Bitrate = (1000.0 * 8.0 * 184.0 * m_AC3PacketCount) / timeout; + m_AC3PacketCount = 0; + calcPeriod.Set(0); + } + + if (!processed) + m_Sleep.Wait(10); // to avoid busy loop and reduce cpu load } } diff --git a/femonreceiver.h b/femonreceiver.h index 6218dba..99f4309 100644 --- a/femonreceiver.h +++ b/femonreceiver.h @@ -21,36 +21,39 @@ class cFemonReceiver : public cReceiver, public cThread, public cFemonVideoIf, public cFemonAudioIf, public cFemonAC3If { private: - cMutex m_Mutex; - cCondWait m_Sleep; - bool m_Active; + cMutex m_Mutex; + cCondWait m_Sleep; + bool m_Active; - cFemonH264 m_DetectH264; - cFemonMPEG m_DetectMPEG; - cFemonAAC m_DetectAAC; - cFemonAC3 m_DetectAC3; + cFemonH264 m_DetectH264; + cFemonMPEG m_DetectMPEG; + cFemonAAC m_DetectAAC; + cFemonAC3 m_DetectAC3; - cTsToPes m_VideoAssembler; - int m_VideoType; - int m_VideoPid; - int m_VideoPacketCount; - double m_VideoBitrate; - bool m_VideoValid; - video_info_t m_VideoInfo; + cRingBufferLinear m_VideoBuffer; + cTsToPes m_VideoAssembler; + int m_VideoType; + int m_VideoPid; + int m_VideoPacketCount; + double m_VideoBitrate; + bool m_VideoValid; + video_info_t m_VideoInfo; - cTsToPes m_AudioAssembler; - int m_AudioPid; - int m_AudioPacketCount; - double m_AudioBitrate; - bool m_AudioValid; - audio_info_t m_AudioInfo; + cRingBufferLinear m_AudioBuffer; + cTsToPes m_AudioAssembler; + int m_AudioPid; + int m_AudioPacketCount; + double m_AudioBitrate; + bool m_AudioValid; + audio_info_t m_AudioInfo; - cTsToPes m_AC3Assembler; - int m_AC3Pid; - int m_AC3PacketCount; - double m_AC3Bitrate; - bool m_AC3Valid; - ac3_info_t m_AC3Info; + cRingBufferLinear m_AC3Buffer; + cTsToPes m_AC3Assembler; + int m_AC3Pid; + int m_AC3PacketCount; + double m_AC3Bitrate; + bool m_AC3Valid; + ac3_info_t m_AC3Info; protected: virtual void Activate(bool On); diff --git a/femontools.c b/femontools.c index 08bcc79..888ef25 100644 --- a/femontools.c +++ b/femontools.c @@ -99,13 +99,13 @@ cString getFrontendInfo(int cardIndex) if (ioctl(fe, FE_READ_STATUS, &status) >= 0) info = cString::sprintf("%s\nSTAT:%02X", *info, status); if (ioctl(fe, FE_READ_SIGNAL_STRENGTH, &signal) >= 0) - info = cString::sprintf("%s\nSGNL:%04" PRIX16, *info, signal); + info = cString::sprintf("%s\nSGNL:%04X", *info, signal); if (ioctl(fe, FE_READ_SNR, &snr) >= 0) - info = cString::sprintf("%s\nSNRA:%04" PRIX16, *info, snr); + info = cString::sprintf("%s\nSNRA:%04X", *info, snr); if (ioctl(fe, FE_READ_BER, &ber) >= 0) - info = cString::sprintf("%s\nBERA:%08" PRIX32, *info, ber); + info = cString::sprintf("%s\nBERA:%08X", *info, ber); if (ioctl(fe, FE_READ_UNCORRECTED_BLOCKS, &unc) >= 0) - info = cString::sprintf("%s\nUNCB:%08" PRIX32, *info, unc); + info = cString::sprintf("%s\nUNCB:%08X", *info, unc); close(fe); if (cFemonOsd::Instance())