/* * mpeg.c: Frontend Status Monitor plugin for the Video Disk Recorder * * See the README file for copyright information and how to reach the author. * */ #include "tools.h" #include "mpeg.h" #define IS_EXTENSION_START(buf) (((buf)[0] == 0x00) && ((buf)[1] == 0x00) && ((buf)[2] == 0x01) && ((buf)[3] == 0xB5)) int cFemonMPEG::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 } }; int cFemonMPEG::sampleRateS[2][4] = { {22050, 24000, 16000, -1}, // MPEG-2 {44100, 48000, 32000, -1} // MPEG-1 }; eAudioCodec cFemonMPEG::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 }; cFemonMPEG::cFemonMPEG(cFemonVideoIf *videoHandlerP, cFemonAudioIf *audioHandlerP) : videoHandlerM(videoHandlerP), audioHandlerM(audioHandlerP) { } cFemonMPEG::~cFemonMPEG() { } bool cFemonMPEG::processAudio(const uint8_t *bufP, int lenP) { cFemonBitStream bs(bufP, lenP * 8); if (!audioHandlerM) return false; // skip PES header if (!PesLongEnough(lenP)) return false; bs.SkipBits(8 * PesPayloadOffset(bufP)); // MPEG audio detection if (bs.GetBits(12) != 0xFFF) // syncword return false; 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 audioHandlerM->SetAudioCodec(formatS[id][layer]); switch (mode) { case 0: audioHandlerM->SetAudioChannel(AUDIO_CHANNEL_MODE_STEREO); break; case 1: audioHandlerM->SetAudioChannel(AUDIO_CHANNEL_MODE_JOINT_STEREO); break; case 2: audioHandlerM->SetAudioChannel(AUDIO_CHANNEL_MODE_DUAL); break; case 3: audioHandlerM->SetAudioChannel(AUDIO_CHANNEL_MODE_SINGLE); break; default: audioHandlerM->SetAudioChannel(AUDIO_CHANNEL_MODE_INVALID); break; } switch (bit_rate_index) { case 0: audioHandlerM->SetAudioBitrate(AUDIO_BITRATE_FREE); break; case 0xF: audioHandlerM->SetAudioBitrate(AUDIO_BITRATE_RESERVED); break; default: audioHandlerM->SetAudioBitrate(1000 * bitrateS[id][layer][bit_rate_index]); break; } switch (sampling_frequency) { case 3: audioHandlerM->SetAudioSamplingFrequency(AUDIO_SAMPLING_FREQUENCY_RESERVED); break; default: audioHandlerM->SetAudioSamplingFrequency(sampleRateS[id][sampling_frequency]); break; } return true; } bool cFemonMPEG::processVideo(const uint8_t *bufP, int lenP) { cFemonBitStream bs(bufP, lenP * 8); if (!videoHandlerM) return false; // skip PES header if (!PesLongEnough(lenP)) return false; bs.SkipBits(8 * PesPayloadOffset(bufP)); // MPEG-2 video detection, search for start code if (bs.GetBits(32) != 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: aspect = VIDEO_ASPECT_RATIO_1_1; break; case 2: aspect = VIDEO_ASPECT_RATIO_4_3; break; case 3: aspect = VIDEO_ASPECT_RATIO_16_9; break; case 4: aspect = VIDEO_ASPECT_RATIO_2_21_1; break; case 5 ... 15: default: aspect = VIDEO_ASPECT_RATIO_RESERVED; break; } double frame_rate = 0; switch (bs.GetBits(4)) { // frame rate code case 1: frame_rate = 24000 / 1001.0; format = VIDEO_FORMAT_UNKNOWN; break; case 2: frame_rate = 24.0; format = VIDEO_FORMAT_UNKNOWN; break; case 3: frame_rate = 25.0; format = VIDEO_FORMAT_PAL; break; case 4: frame_rate = 30000 / 1001.0; format = VIDEO_FORMAT_NTSC; break; case 5: frame_rate = 30.0; format = VIDEO_FORMAT_NTSC; break; case 6: frame_rate = 50.0; format = VIDEO_FORMAT_PAL; break; case 7: frame_rate = 60.0; format = VIDEO_FORMAT_NTSC; break; case 8: frame_rate = 60000 / 1001.0; format = VIDEO_FORMAT_NTSC; break; case 9 ... 15: default: frame_rate = 0; format = VIDEO_FORMAT_UNKNOWN; break; } 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.GetBits(32) != 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.GetBits(32) != 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; } } } videoHandlerM->SetVideoCodec(VIDEO_CODEC_MPEG2); videoHandlerM->SetVideoSize(horizontal_size, vertical_size); videoHandlerM->SetVideoBitrate(400.0 * (double)(bit_rate)); videoHandlerM->SetVideoFramerate(frame_rate); videoHandlerM->SetVideoScan(eVideoScan(scan)); videoHandlerM->SetVideoAspectRatio(eVideoAspectRatio(aspect)); videoHandlerM->SetVideoFormat(eVideoFormat(format)); return true; }