/* * _ _ _ _ _____ * __ ____| |_ __ _ __ | |_ _ __ _(_)_ __ __| |_ ___ _|___ / * \ \ / / _` | '__|____| '_ \| | | | |/ _` | | '_ \ _____ / _` \ \/ / '__||_ \ * \ V / (_| | | |_____| |_) | | |_| | (_| | | | | |_____| (_| |> <| | ___) | * \_/ \__,_|_| | .__/|_|\__,_|\__, |_|_| |_| \__,_/_/\_\_| |____/ * |_| |___/ * * Copyright (C) 2002-2004 Kai Möller * Copyright (C) 2004-2010 Christian Gmeiner * * This file is part of vdr-plugin-dxr3. * * vdr-plugin-dxr3 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2. * * vdr-plugin-dxr3 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with dxr3-plugin. If not, see . * */ #include #include "decoder.h" #include "dxr3pesframe.h" #include "dxr3audio.h" #include "settings.h" // ================================== const int LPCM_HEADER_LENGTH = 7; // ================================== //! constructor cDecoder::cDecoder() : rbuf(50000), ac3dtsDecoder(&rbuf) { // setup ffmpeg avcodec_init(); avcodec_register_all(); // look for audio decoder audio = avcodec_find_decoder(CODEC_ID_MP3); if (!audio) { esyslog("[dxr3-decoder] no suitable audio codec found."); esyslog("[dxr3-decoder] check your ffmpeg installation."); exit(-1); } // create a new codec context contextAudio = avcodec_alloc_context(); int ret = avcodec_open(contextAudio, audio); if (ret < 0) { esyslog("[dxr3-decoder] failed to open codec %s.", audio->name); exit(-1); } lastBitrate = 0xff; // init with an invalid value - see checkMpegAudioHdr; } // ================================== //! deconst. cDecoder::~cDecoder() { // close codec, if it is open avcodec_close(contextAudio); } // ================================== //! (re)init ffmpeg codec void cDecoder::Init() { avcodec_close(contextAudio); // create a new codec context contextAudio = avcodec_alloc_context(); int ret = avcodec_open(contextAudio, audio); if (ret < 0) { esyslog("[dxr3-decoder] failed to open codec %s.", audio->name); exit(-1); } } void cDecoder::decode(cDxr3PesFrame *frame, iAudio *audio) { int len, out_size; const uint8_t *buf = frame->payload(); int length = frame->payloadSize(); if (checkMpegAudioHdr(buf)) { // look if Bitrate or samplerate has changed if ((buf[2] & 0xFC) != (lastBitrate & 0xFC)) { dsyslog("[dxr3-audiodecoder] found new audio header"); // recalculate used framesize frameSize = calcFrameSize(buf); dsyslog("[dxr3-audiodecoder] calculated frame size %d", frameSize); // we need now to reinit the deocder and to store the new // part from the audio header Init(); lastBitrate = buf[2]; } } // setup AVPacket avpkt.data = const_cast(buf); avpkt.size = frameSize; while (length > 0) { out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(51, 29, 0) len = avcodec_decode_audio(contextAudio, (short *)(&pcmbuf), &out_size, avpkt.data, frameSize); #elif LIBAVCODEC_VERSION_INT < AV_VERSION_INT(52, 26, 0) len = avcodec_decode_audio2(contextAudio, (short *)(&pcmbuf), &out_size, avpkt.data, frameSize); #else len = avcodec_decode_audio3(contextAudio, (short *)(&pcmbuf), &out_size, &avpkt); #endif if (len <= 0) { esyslog("[dxr3-decoder] failed to decode audio"); return; } if (out_size) { audio->setup(contextAudio->channels, contextAudio->sample_rate); audio->changeVolume((short *)pcmbuf, out_size); audio->write(pcmbuf, out_size); } length -= len; avpkt.data += len; } } void cDecoder::ac3dts(cDxr3PesFrame *frame, iAudio *audio) { if (cSettings::instance()->ac3AudioMode() == PCM_ENCAPSULATION) { uint8_t *buf = (uint8_t *)frame->payload(); int length = frame->payloadSize(); ac3dtsDecoder.Check(buf, length, (uint8_t *)frame->pesStart()); ac3dtsDecoder.Encapsulate(buf, length); cFrame* pFrame = 0; while ((pFrame = rbuf.Get())) { if (pFrame && pFrame->Count()) { cDxr3PesFrame tempPes; tempPes.parse(pFrame->Data(), pFrame->Count()); int pesHeaderLength = (int) (tempPes.payload() - tempPes.pesStart()); uint8_t* pData = pFrame->Data() + pesHeaderLength + LPCM_HEADER_LENGTH; for (int i = 0; i < pFrame->Count() - pesHeaderLength - LPCM_HEADER_LENGTH; i += 2) { std::swap(pData[i], pData[i + 1]); } audio->write(pFrame->Data() + pesHeaderLength + LPCM_HEADER_LENGTH, pFrame->Count() - pesHeaderLength - 7); rbuf.Drop(pFrame); } } } } // ================================== //! checking routine bool cDecoder::checkMpegAudioHdr(const uint8_t *head) { // all informations about the mpeg audio header // can be found at http://www.datavoyage.com/mpgscript/mpeghdr.htm // the header conists of four 8bit elements, described as // AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM // all As must be set to 1 if (head[0] != 0xff || (head[1] & 0xe0) != 0xe0) { return false; } // B is not allowed to be 01 (bits), as it is a reserved value if ((head[1] & 0x18) == 0x8) { return false; } // C is not allowed to be 00 (bits), as it is a reserved value if ((head[1] & 0x6) == 0x0) { return false; } // all Es are not allowed to be 1 if ((head[2] & 0xf0) == 0xf0) { return false; } // all Fs are not allowed to be 1 if ((head[2] & 0xc) == 0xc) { return false; } return true; } int cDecoder::calcFrameSize(const uint8_t *header) { static const int bitrates[2][3][15] = { { // MPEG 1 {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,}, // Layer1 {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,}, // Layer2 {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} // Layer3 }, { // MPEG 2, 2.5 {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,}, // Layer1 {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,}, // Layer2 {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} // Layer3 } }; static const int samplingRates[4][3] = { {11025, 12000, 8000, }, // MPEG 2.5 {0, 0, 0, }, // reserved {22050, 24000, 16000, }, // MPEG 2 {44100, 48000, 32000 } // MPEG 1 }; static const int MPEG1 = 0x3; // in B the version is stored int ver = (header[1] >> 3) & 0x03; int version = 1; // default to MPEG2 // determine index into arrays based on ver if (ver == MPEG1) { version = 0; } // in C the layer version is stored int layer = 3 - ((header[1] >> 1) & 0x03); // in E the bitrate index is stored int bitrateIndex = (header[2] >> 4) & 0x0f; // in F the sampling rate frequency index is stored int samplingIndex = (header[2] >> 2) & 0x03; // in G the padding bit is stored int padding = (header[2] >> 1) & 0x01; int bitrate = bitrates[version][layer][bitrateIndex]; // kbit bitrate *= 1000; // kbit -> bit int samplesrate = samplingRates[ver][samplingIndex]; // formulars used to calculate frame size // layer I // FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4 // layer II & III // FrameLengthInBytes = 144 * BitRate / SampleRate + Padding if (layer == 0) { return (12 * bitrate / samplesrate + padding) * 4; } else { return 144 * bitrate / samplesrate + padding; } } // Local variables: // mode: c++ // c-file-style: "stroustrup" // c-file-offsets: ((inline-open . 0)) // tab-width: 4; // indent-tabs-mode: nil // End: