mirror of
https://github.com/rofafor/vdr-plugin-femon.git
synced 2023-10-10 13:36:53 +02:00
241 lines
7.1 KiB
C
241 lines
7.1 KiB
C
/*
|
|
* Frontend Status Monitor plugin for the Video Disk Recorder
|
|
*
|
|
* See the README file for copyright information and how to reach the author.
|
|
*
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include "femontools.h"
|
|
#include "femoncfg.h"
|
|
#include "femonmpeg.h"
|
|
#include "femonaac.h"
|
|
#include "femonac3.h"
|
|
#include "femonh264.h"
|
|
#include "femonreceiver.h"
|
|
|
|
#define TS_SIZE 188
|
|
#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),
|
|
cThread("femon receiver"),
|
|
m_Sleep(),
|
|
m_Active(false),
|
|
m_VideoPid(Vpid),
|
|
m_VideoPacketCount(0),
|
|
m_VideoBitrate(0.0),
|
|
m_VideoValid(false),
|
|
m_VideoInfoBufferIndex(0),
|
|
m_AudioPid(Apid[0]),
|
|
m_AudioPacketCount(0),
|
|
m_AudioBitrate(0.0),
|
|
m_AudioValid(false),
|
|
m_AudioInfoBufferIndex(0),
|
|
m_AC3Pid(Dpid[0]),
|
|
m_AC3PacketCount(0),
|
|
m_AC3Bitrate(0),
|
|
m_AC3Valid(false),
|
|
m_AC3InfoBufferIndex(0)
|
|
{
|
|
Dprintf("%s()\n", __PRETTY_FUNCTION__);
|
|
|
|
m_VideoInfo.codec = VIDEO_CODEC_INVALID;
|
|
m_VideoInfo.format = VIDEO_FORMAT_INVALID;
|
|
m_VideoInfo.scan = VIDEO_SCAN_INVALID;
|
|
m_VideoInfo.aspectRatio = VIDEO_ASPECT_RATIO_INVALID;
|
|
m_VideoInfo.width = 0;
|
|
m_VideoInfo.height = 0;
|
|
m_VideoInfo.frameRate = 0;
|
|
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.bitrate = AUDIO_BITRATE_INVALID;
|
|
m_AudioInfo.samplingFrequency = AUDIO_SAMPLING_FREQUENCY_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.samplingFrequency = AUDIO_SAMPLING_FREQUENCY_INVALID;
|
|
m_AC3Info.bitstreamMode = AUDIO_BITSTREAM_MODE_INVALID;
|
|
m_AC3Info.audioCodingMode = AUDIO_CODING_MODE_INVALID;
|
|
m_AC3Info.dolbySurroundMode = AUDIO_DOLBY_SURROUND_MODE_INVALID;
|
|
m_AC3Info.centerMixLevel = AUDIO_CENTER_MIX_LEVEL_INVALID;
|
|
m_AC3Info.surroundMixLevel = AUDIO_SURROUND_MIX_LEVEL_INVALID;
|
|
m_AC3Info.dialogLevel = 0;
|
|
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)
|
|
{
|
|
Dprintf("%s()\n", __PRETTY_FUNCTION__);
|
|
Deactivate();
|
|
}
|
|
|
|
void cFemonReceiver::Deactivate(void)
|
|
{
|
|
Dprintf("%s()\n", __PRETTY_FUNCTION__);
|
|
if (m_Active) {
|
|
m_Active = false;
|
|
m_Sleep.Signal();
|
|
if (Running())
|
|
Cancel(3);
|
|
Detach();
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
Dprintf("%s(%d)\n", __PRETTY_FUNCTION__, On);
|
|
if (On)
|
|
Start();
|
|
else
|
|
Deactivate();
|
|
}
|
|
|
|
void cFemonReceiver::Receive(uchar *Data, int Length)
|
|
{
|
|
// TS packet length: TS_SIZE
|
|
if (Length == TS_SIZE) {
|
|
int pid = ((Data[1] & 0x1f) << 8) | (Data[2]);
|
|
if (pid == m_VideoPid) {
|
|
m_VideoPacketCount++;
|
|
}
|
|
else if (pid == m_AudioPid) {
|
|
m_AudioPacketCount++;
|
|
}
|
|
else if (pid == m_AC3Pid) {
|
|
m_AC3PacketCount++;
|
|
}
|
|
/* the following originates from libdvbmpeg: */
|
|
if (!(Data[3] & PAYLOAD)) {
|
|
return;
|
|
}
|
|
uint8_t off = 0;
|
|
if (Data[3] & ADAPT_FIELD) {
|
|
off = 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);
|
|
}
|
|
}
|
|
}
|
|
/* end */
|
|
}
|
|
}
|
|
|
|
void cFemonReceiver::Action(void)
|
|
{
|
|
Dprintf("%s()\n", __PRETTY_FUNCTION__);
|
|
cTimeMs t;
|
|
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));
|
|
}
|
|
}
|