mirror of
https://github.com/rofafor/vdr-plugin-femon.git
synced 2023-10-10 13:36:53 +02:00
185 lines
5.4 KiB
C
185 lines
5.4 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 "femontools.h"
|
||
|
#include "femonmpeg.h"
|
||
|
|
||
|
#define IS_MPEG_AUDIO(buf) (((buf)[0] == 0xFF) && ((buf)[1] & 0xF0))
|
||
|
#define IS_SEQUENCE_HEADER(buf) (((buf)[0] == 0x00) && ((buf)[1] == 0x00) && ((buf)[2] == 0x01) && ((buf)[3] == 0xB3))
|
||
|
|
||
|
static unsigned int 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, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1}, // MPEG-2 Layer II/III
|
||
|
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1} // MPEG-2 Layer II/III
|
||
|
},
|
||
|
{
|
||
|
{0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1}, // MPEG-1 Layer I
|
||
|
{0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1}, // MPEG-1 Layer II
|
||
|
{0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1} // MPEG-1 Layer III
|
||
|
}
|
||
|
};
|
||
|
|
||
|
static unsigned int samplerates[2][4] =
|
||
|
{
|
||
|
{22050, 24000, 16000, -1}, // MPEG-2
|
||
|
{44100, 48000, 32000, -1} // MPEG-1
|
||
|
};
|
||
|
|
||
|
static eAudioCodec formats[2][4] =
|
||
|
{
|
||
|
{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
|
||
|
};
|
||
|
|
||
|
bool getMPEGAudioInfo(uint8_t *buf, int len, audio_info_t *info)
|
||
|
{
|
||
|
// MPEG audio detection, search for syncword
|
||
|
if ((len < 4) || !IS_MPEG_AUDIO(buf))
|
||
|
return false;
|
||
|
|
||
|
int mpegIndex = (buf[1] & 0x08) >> 3; // MPEG-2=0, MPEG-1=1
|
||
|
int layerIndex = 3 - ((buf[1] & 0x06) >> 1); // I=11, II=10, III=01
|
||
|
int bitrateIndex = (buf[2] & 0xF0) >> 4;
|
||
|
int frequency = (buf[2] & 0x0C) >> 2;
|
||
|
int channelMode = (buf[3] & 0xC0) >> 6;
|
||
|
|
||
|
info->codec = formats[mpegIndex][layerIndex];
|
||
|
|
||
|
switch (channelMode) {
|
||
|
case 0:
|
||
|
info->channelMode = AUDIO_CHANNEL_MODE_STEREO;
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
info->channelMode = AUDIO_CHANNEL_MODE_JOINT_STEREO;
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
info->channelMode = AUDIO_CHANNEL_MODE_DUAL;
|
||
|
break;
|
||
|
|
||
|
case 3:
|
||
|
info->channelMode = AUDIO_CHANNEL_MODE_SINGLE;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
info->channelMode = AUDIO_CHANNEL_MODE_INVALID;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (bitrateIndex) {
|
||
|
case 0:
|
||
|
info->bitrate = AUDIO_BITRATE_FREE;
|
||
|
break;
|
||
|
|
||
|
case 0xF:
|
||
|
info->bitrate = AUDIO_BITRATE_RESERVED;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
info->bitrate = 1000 * bitrates[mpegIndex][layerIndex][bitrateIndex];
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (frequency) {
|
||
|
case 3:
|
||
|
info->samplingFrequency = AUDIO_SAMPLING_FREQUENCY_RESERVED;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
info->samplingFrequency = samplerates[mpegIndex][frequency];
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool getMPEGVideoInfo(uint8_t *buf, int len, video_info_t *info)
|
||
|
{
|
||
|
// MPEG-2 video detection, search for sequence header
|
||
|
if ((len < 7) || !IS_SEQUENCE_HEADER(buf))
|
||
|
return false;
|
||
|
|
||
|
// Parse header
|
||
|
uint8_t *data = buf + 4;
|
||
|
info->codec = VIDEO_CODEC_MPEG2;
|
||
|
info->width = ((data[1] & 0xF0) >> 4) | (data[0] << 4);
|
||
|
info->height = ((data[1] & 0x0F) << 8) | (data[2]);
|
||
|
switch ((data[3] & 0xF0) >> 4) {
|
||
|
case 1:
|
||
|
info->aspectRatio = VIDEO_ASPECT_RATIO_1_1;
|
||
|
break;
|
||
|
case 2:
|
||
|
info->aspectRatio = VIDEO_ASPECT_RATIO_4_3;
|
||
|
break;
|
||
|
case 3:
|
||
|
info->aspectRatio = VIDEO_ASPECT_RATIO_16_9;
|
||
|
break;
|
||
|
case 4:
|
||
|
info->aspectRatio = VIDEO_ASPECT_RATIO_2_21_1;
|
||
|
break;
|
||
|
case 5 ... 15:
|
||
|
default:
|
||
|
info->aspectRatio = VIDEO_ASPECT_RATIO_RESERVED;
|
||
|
break;
|
||
|
}
|
||
|
// Video scan should be read from progressive_sequence field in sequence extension
|
||
|
switch (data[3] & 0x0F) {
|
||
|
case 1:
|
||
|
info->frameRate = 24000 / 1001.0;
|
||
|
info->scan = VIDEO_SCAN_PROGRESSIVE;
|
||
|
info->format = VIDEO_FORMAT_UNKNOWN;
|
||
|
break;
|
||
|
case 2:
|
||
|
info->frameRate = 24.0;
|
||
|
info->scan = VIDEO_SCAN_PROGRESSIVE;
|
||
|
info->format = VIDEO_FORMAT_UNKNOWN;
|
||
|
break;
|
||
|
case 3:
|
||
|
info->frameRate = 25.0;
|
||
|
info->scan = VIDEO_SCAN_UNKNOWN; // interlaced or progressive
|
||
|
info->format = VIDEO_FORMAT_PAL;
|
||
|
break;
|
||
|
case 4:
|
||
|
info->frameRate = 30000 / 1001.0;
|
||
|
info->scan = VIDEO_SCAN_UNKNOWN; // interlaced or progressive
|
||
|
info->format = VIDEO_FORMAT_NTSC;
|
||
|
break;
|
||
|
case 5:
|
||
|
info->frameRate = 30.0;
|
||
|
info->scan = VIDEO_SCAN_UNKNOWN; // interlaced or progressive
|
||
|
info->format = VIDEO_FORMAT_NTSC;
|
||
|
break;
|
||
|
case 6:
|
||
|
info->frameRate = 50.0;
|
||
|
info->scan = VIDEO_SCAN_PROGRESSIVE;
|
||
|
info->format = VIDEO_FORMAT_PAL;
|
||
|
break;
|
||
|
case 7:
|
||
|
info->frameRate = 60.0;
|
||
|
info->scan = VIDEO_SCAN_PROGRESSIVE;
|
||
|
info->format = VIDEO_FORMAT_NTSC;
|
||
|
break;
|
||
|
case 8:
|
||
|
info->frameRate = 60000 / 1001.0;
|
||
|
info->scan = VIDEO_SCAN_PROGRESSIVE;
|
||
|
info->format = VIDEO_FORMAT_NTSC;
|
||
|
break;
|
||
|
case 9 ... 15:
|
||
|
default:
|
||
|
info->frameRate = 0;
|
||
|
info->scan = VIDEO_SCAN_UNKNOWN;
|
||
|
info->format = VIDEO_FORMAT_UNKNOWN;
|
||
|
break;
|
||
|
}
|
||
|
info->bitrate = 400.0 * (((data[4] << 10) & 0x0003FC00UL) | ((data[5] << 2) & 0x000003FCUL) | (((data[6] & 0xC0) >> 6) & 0x00000003UL));
|
||
|
|
||
|
return true;
|
||
|
}
|