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

253 lines
7.1 KiB
C
Raw Normal View History

/*
2015-03-07 21:32:58 +01:00
* receiver.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>
2015-03-07 21:32:58 +01:00
#include "config.h"
2015-03-07 21:09:18 +01:00
#include "log.h"
2015-03-07 21:32:58 +01:00
#include "tools.h"
#include "receiver.h"
2015-03-07 17:22:02 +01:00
cFemonReceiver::cFemonReceiver(const cChannel *channelP, int aTrackP, int dTrackP)
: cReceiver(channelP),
2012-03-31 10:47:57 +02:00
cThread("femon receiver"),
2015-03-07 17:22:02 +01:00
mutexM(),
sleepM(),
activeM(false),
detectH264M(this),
detectMpegM(this, this),
detectAacM(this),
detectLatmM(this),
detectAc3M(this),
videoBufferM(KILOBYTE(512), TS_SIZE, false, "Femon video"),
videoTypeM(channelP ? channelP->Vtype(): 0),
videoPidM(channelP ? channelP->Vpid() : 0),
videoPacketCountM(0),
videoBitRateM(0.0),
videoValidM(false),
audioBufferM(KILOBYTE(256), TS_SIZE, false, "Femon audio"),
audioPidM(channelP ? channelP->Apid(aTrackP) : 0),
audioPacketCountM(0),
audioBitRateM(0.0),
audioValidM(false),
ac3BufferM(KILOBYTE(256), TS_SIZE, false, "Femon AC3"),
ac3PidM(channelP ? channelP->Dpid(dTrackP) : 0),
ac3PacketCountM(0),
ac3BitRateM(0),
ac3ValidM(false)
{
2015-03-07 21:09:18 +01:00
debug1("%s (, %d, %d)", __PRETTY_FUNCTION__, aTrackP, dTrackP);
2012-03-31 10:47:57 +02:00
SetPids(NULL);
2015-03-07 17:22:02 +01:00
AddPid(videoPidM);
AddPid(audioPidM);
AddPid(ac3PidM);
videoBufferM.SetTimeouts(0, 100);
audioBufferM.SetTimeouts(0, 100);
ac3BufferM.SetTimeouts(0, 100);
videoInfoM.codec = VIDEO_CODEC_INVALID;
videoInfoM.format = VIDEO_FORMAT_INVALID;
videoInfoM.scan = VIDEO_SCAN_INVALID;
videoInfoM.aspectRatio = VIDEO_ASPECT_RATIO_INVALID;
videoInfoM.width = 0;
videoInfoM.height = 0;
videoInfoM.frameRate = 0;
videoInfoM.bitrate = AUDIO_BITRATE_INVALID;
audioInfoM.codec = AUDIO_CODEC_UNKNOWN;
audioInfoM.bitrate = AUDIO_BITRATE_INVALID;
audioInfoM.samplingFrequency = AUDIO_SAMPLING_FREQUENCY_INVALID;
audioInfoM.channelMode = AUDIO_CHANNEL_MODE_INVALID;
ac3InfoM.bitrate = AUDIO_BITRATE_INVALID;
ac3InfoM.samplingFrequency = AUDIO_SAMPLING_FREQUENCY_INVALID;
ac3InfoM.bitstreamMode = AUDIO_BITSTREAM_MODE_INVALID;
ac3InfoM.audioCodingMode = AUDIO_CODING_MODE_INVALID;
ac3InfoM.dolbySurroundMode = AUDIO_DOLBY_SURROUND_MODE_INVALID;
ac3InfoM.centerMixLevel = AUDIO_CENTER_MIX_LEVEL_INVALID;
ac3InfoM.surroundMixLevel = AUDIO_SURROUND_MIX_LEVEL_INVALID;
ac3InfoM.dialogLevel = 0;
ac3InfoM.lfe = false;
}
cFemonReceiver::~cFemonReceiver(void)
{
2015-03-07 21:09:18 +01:00
debug1("%s", __PRETTY_FUNCTION__);
2008-11-23 21:26:48 +01:00
Deactivate();
}
void cFemonReceiver::Deactivate(void)
{
2015-03-07 21:09:18 +01:00
debug1("%s", __PRETTY_FUNCTION__);
Detach();
2015-03-07 17:22:02 +01:00
if (activeM) {
activeM = false;
sleepM.Signal();
2008-11-23 21:26:48 +01:00
if (Running())
Cancel(3);
}
}
2015-03-07 17:22:02 +01:00
void cFemonReceiver::Activate(bool onP)
{
2015-03-07 21:09:18 +01:00
debug1("%s (%d)", __PRETTY_FUNCTION__, onP);
2015-03-07 17:22:02 +01:00
if (onP)
2005-08-15 03:20:00 +02:00
Start();
else
2008-11-23 21:26:48 +01:00
Deactivate();
}
2015-03-07 17:22:02 +01:00
void cFemonReceiver::Receive(uchar *dataP, int lengthP)
{
// TS packet length: TS_SIZE
2015-03-07 17:22:02 +01:00
if (Running() && (*dataP == TS_SYNC_BYTE) && (lengthP == TS_SIZE)) {
int len, pid = TsPid(dataP);
if (pid == videoPidM) {
++videoPacketCountM;
len = videoBufferM.Put(dataP, lengthP);
if (len != lengthP) {
videoBufferM.ReportOverflow(lengthP - len);
videoBufferM.Clear();
}
}
2015-03-07 17:22:02 +01:00
else if (pid == audioPidM) {
++audioPacketCountM;
len = audioBufferM.Put(dataP, lengthP);
if (len != lengthP) {
audioBufferM.ReportOverflow(lengthP - len);
audioBufferM.Clear();
}
}
2015-03-07 17:22:02 +01:00
else if (pid == ac3PidM) {
++ac3PacketCountM;
len = ac3BufferM.Put(dataP, lengthP);
if (len != lengthP) {
ac3BufferM.ReportOverflow(lengthP - len);
ac3BufferM.Clear();
}
}
}
}
void cFemonReceiver::Action(void)
{
2015-03-07 21:09:18 +01:00
debug1("%s", __PRETTY_FUNCTION__);
cTimeMs calcPeriod(0);
2015-03-07 17:22:02 +01:00
activeM = true;
2015-03-07 17:22:02 +01:00
while (Running() && activeM) {
2012-02-05 17:21:07 +01:00
uint8_t *Data;
double timeout;
int len, Length;
bool processed = false;
// process available video data
2015-03-07 17:22:02 +01:00
while ((Data = videoBufferM.Get(Length))) {
if (!activeM || (Length < TS_SIZE))
break;
2010-06-23 11:16:17 +02:00
Length = TS_SIZE;
if (*Data != TS_SYNC_BYTE) {
for (int i = 1; i < Length; ++i) {
if (Data[i] == TS_SYNC_BYTE) {
Length = i;
break;
}
}
2015-03-07 17:22:02 +01:00
videoBufferM.Del(Length);
continue;
}
processed = true;
if (TsPayloadStart(Data)) {
2015-03-07 17:22:02 +01:00
while (const uint8_t *p = videoAssemblerM.GetPes(len)) {
if (videoTypeM == 0x1B) { // MPEG4
if (detectH264M.processVideo(p, len)) {
videoValidM = true;
break;
}
}
else {
2015-03-07 17:22:02 +01:00
if (detectMpegM.processVideo(p, len)) {
videoValidM = true;
break;
}
}
}
2015-03-07 17:22:02 +01:00
videoAssemblerM.Reset();
}
2015-03-07 17:22:02 +01:00
videoAssemblerM.PutTs(Data, Length);
videoBufferM.Del(Length);
}
// process available audio data
2015-03-07 17:22:02 +01:00
while ((Data = audioBufferM.Get(Length))) {
if (!activeM || (Length < TS_SIZE))
break;
2010-06-23 11:16:17 +02:00
Length = TS_SIZE;
if (*Data != TS_SYNC_BYTE) {
for (int i = 1; i < Length; ++i) {
if (Data[i] == TS_SYNC_BYTE) {
Length = i;
break;
}
}
2015-03-07 17:22:02 +01:00
audioBufferM.Del(Length);
continue;
}
processed = true;
2015-03-07 17:22:02 +01:00
if (const uint8_t *p = audioAssemblerM.GetPes(len)) {
if (detectAacM.processAudio(p, len) || detectLatmM.processAudio(p, len) || detectMpegM.processAudio(p, len))
audioValidM = true;
audioAssemblerM.Reset();
}
2015-03-07 17:22:02 +01:00
audioAssemblerM.PutTs(Data, Length);
audioBufferM.Del(Length);
}
// process available dolby data
2015-03-07 17:22:02 +01:00
while ((Data = ac3BufferM.Get(Length))) {
if (!activeM || (Length < TS_SIZE))
break;
2010-06-23 11:16:17 +02:00
Length = TS_SIZE;
if (*Data != TS_SYNC_BYTE) {
for (int i = 1; i < Length; ++i) {
if (Data[i] == TS_SYNC_BYTE) {
Length = i;
break;
}
}
2015-03-07 17:22:02 +01:00
ac3BufferM.Del(Length);
continue;
}
processed = true;
2015-03-07 17:22:02 +01:00
if (const uint8_t *p = ac3AssemblerM.GetPes(len)) {
if (detectAc3M.processAudio(p, len))
ac3ValidM = true;
ac3AssemblerM.Reset();
}
2015-03-07 17:22:02 +01:00
ac3AssemblerM.PutTs(Data, Length);
ac3BufferM.Del(Length);
}
// calculate bitrates
timeout = double(calcPeriod.Elapsed());
2015-03-07 20:37:46 +01:00
if (activeM && (timeout >= (100.0 * FemonConfig.GetCalcInterval()))) {
// TS packet 188 bytes - 4 byte header; MPEG standard defines 1Mbit = 1000000bit
// PES headers should be compensated!
2015-03-07 17:22:02 +01:00
videoBitRateM = (1000.0 * 8.0 * 184.0 * videoPacketCountM) / timeout;
videoPacketCountM = 0;
audioBitRateM = (1000.0 * 8.0 * 184.0 * audioPacketCountM) / timeout;
audioPacketCountM = 0;
ac3BitRateM = (1000.0 * 8.0 * 184.0 * ac3PacketCountM) / timeout;
ac3PacketCountM = 0;
calcPeriod.Set(0);
}
if (!processed)
2015-03-07 17:22:02 +01:00
sleepM.Wait(10); // to avoid busy loop and reduce cpu load
}
}