summaryrefslogtreecommitdiff
path: root/dxr3multichannelaudio.c
diff options
context:
space:
mode:
authoraustriancoder <austriancoder>2005-08-15 17:18:40 +0000
committeraustriancoder <austriancoder>2005-08-15 17:18:40 +0000
commit8955b4dfa419698ecb853bb8f1cdc1fe96d206d6 (patch)
tree2ec35c50a4c8feb54f6c6fe48710d6a48bfc2ea6 /dxr3multichannelaudio.c
parente4c44acfc5421d0794dcbc777202378f35a187e8 (diff)
downloadvdr-plugin-dxr3-8955b4dfa419698ecb853bb8f1cdc1fe96d206d6.tar.gz
vdr-plugin-dxr3-8955b4dfa419698ecb853bb8f1cdc1fe96d206d6.tar.bz2
HEAD should have files of 0.2.3 release
Diffstat (limited to 'dxr3multichannelaudio.c')
-rw-r--r--dxr3multichannelaudio.c651
1 files changed, 0 insertions, 651 deletions
diff --git a/dxr3multichannelaudio.c b/dxr3multichannelaudio.c
deleted file mode 100644
index 9a12d70..0000000
--- a/dxr3multichannelaudio.c
+++ /dev/null
@@ -1,651 +0,0 @@
-/*
-* dxr3multichannelaudio.c:
-*
-* taken from the AC3overDVB Patch maintained by Stefan Huelswitt
-*
-*
-*/
-
-#include <malloc.h>
-#include "dxr3multichannelaudio.h"
-#include "dxr3log.h"
-#include <vdr/ringbuffer.h>
-
-//#define DEBUG(x...) printf(x)
-#define DEBUG(x...)
-
-//#define ED(x...) printf(x)
-#define ED(x...)
-
-#define aAC3 0x80
-#define aDTS 0x88
-#define aLPCM 0xA0
-#define aMPEG 0xC0
-
-#define aVDR 0x0B // VDR specific audio substream
-#define aSPU 0x20 // SPU stream
-
-#define PES_HDR_SIZE 6 // length of PES header
-#define PTS_SIZE 5 // length of PTS data
-#define MAX_FRAMECOUNT 1536 // max. LPCM payload size
-
-#define SYNC_SIZE 7 // how many bytes we need to sync on a audio header
-
-#define AC3_SIZE 6144 // size of AC3 IEC paket
-#define DTS_SIZE 2048 // size of DTS IEC paket
-#define IEC_HDR_SIZE 8 // size of IEC header
-
-// --- cAudioEncapsulator ------------------------------------------------------
-
-class cAudioEncapsulator {
-private:
- int totalSize, frameCount;
- cFrame *frame;
- uchar *frameData;
- //
- uchar syncBuff[SYNC_SIZE];
- int have, length, skipped;
- //
- uchar ptsFlags;
- const uchar *ptsData;
- int ptsDelay;
- //
- void NewFrame(uchar PTSflags, const uchar *PTSdata);
- void SyncFound(const uchar *data);
-protected:
- int streamType;
- cRingBufferFrame *ringBuffer;
- int fillup, firstBurst;
- bool mute, muteData;
- //
- void StartFrame(int size, uchar PTSflags, const uchar *PTSdata);
- void FinishFrame(void);
- void PutData(const uchar *data, int len);
- void SendIECpause(int type, uchar PTSflags, const uchar *PTSdata);
- //
- virtual int SyncInfo(const uchar *data)=0;
- virtual void StartIECFrame(const uchar *buf, int length, uchar PTSflags, const uchar *PTSdata)=0;
- virtual void FinishIECFrame(void);
-public:
- cAudioEncapsulator(cRingBufferFrame *rb, int StreamType);
- virtual ~cAudioEncapsulator();
- void Clear(void);
- void Decode(const uchar *data, int len, uchar PTSflags, int PTSdelay, const uchar *PTSdata);
- int StreamType() { return streamType; }
- void Mute(bool Mute) { mute=Mute; }
- };
-
-cAudioEncapsulator::cAudioEncapsulator(cRingBufferFrame *rb, int StreamType)
-{
- ringBuffer=rb;
- streamType=StreamType;
- frame=0; firstBurst=1;
- Clear();
-}
-
-cAudioEncapsulator::~cAudioEncapsulator()
-{
- delete frame;
-}
-
-void cAudioEncapsulator::Clear(void)
-{
- delete frame;
- frame=0; frameCount=0; fillup=0; mute=muteData=false;
- have=length=skipped=0;
-}
-
-void cAudioEncapsulator::StartFrame(int size, uchar PTSflags, const uchar *PTSdata)
-{
- if(frame) {
- DEBUG("StartFrame() with unfinished frame!\n");
- FinishFrame();
- }
- ED("StartFrame: size=%d ptsFlags=%d\n",size,PTSflags);
- totalSize=size;
- NewFrame(PTSflags,PTSdata);
-}
-
-void cAudioEncapsulator::NewFrame(uchar PTSflags, const uchar *PTSdata)
-{
- if(!totalSize) {
- DEBUG("NewFrame: new frame requested, but totalSize=0\n");
- return;
- }
- static const int ptslen[] = { 0,0,PTS_SIZE,PTS_SIZE*2 };
- const int plen = ptslen[PTSflags];
- int len = std::min(totalSize, MAX_FRAMECOUNT);
- ED("NewFrame: totalSize=%d frameCount=%d PTSflags=%d",totalSize,len,PTSflags);
- totalSize -= len;
- ED(" new totalSize=%d\n",totalSize);
- len += (plen + 3 + 7);
- frameCount = len+PES_HDR_SIZE;
- frameData = MALLOC(uchar,frameCount);
- if (frameData) {
- frame = new cFrame(frameData, -frameCount, ftUnknown);
- if (frame) {
- uchar buf[10];
- // build the PES header
- buf[0] = 0x00;
- buf[1] = 0x00;
- buf[2] = 0x01;
- buf[3] = 0xBD; // PRIVATE_STREAM1
- buf[4] = (len >> 8) & 0xFF;
- buf[5] = len & 0xFF;
- buf[6] = 0x84;
- buf[7] = plen ? (PTSflags << 6) : 0;
- buf[8] = plen;
- PutData(buf,9);
-
- if (plen) PutData(PTSdata,plen);
-
- // build LPCM header
- buf[0] = aLPCM; // substream ID
- buf[1] = 0xFF;
- buf[2] = 0x00;
- buf[3] = 0x00;
- buf[4] = 0x00;
- buf[5] = 0x00;
- buf[6] = 0x81;
- PutData(buf,7);
- return;
- }
- else { free(frameData); frameData=0; }
- }
- esyslog("Failed to build frame for audio encapsulation");
-}
-
-void cAudioEncapsulator::FinishFrame(void)
-{
- if (frameCount) {
- DEBUG("FinishFrame() with frameCount>0\n");
- PutData(0,frameCount);
- }
- if (frame && frameData) {
- ED("FinishFrame: totalSize=%d\n",totalSize);
- if (!ringBuffer->Put(frame)) {
- esyslog("Ringbuffer overflow. Encapsulated audio frame lost");
- delete frame;
- }
- }
- frame=0; frameData=0; frameCount=0;
-}
-
-void cAudioEncapsulator::PutData(const uchar *data, int len)
-{
- if(!muteData) {
- if(!frameData) DEBUG("PutData() without frame\n");
- while (frameData && len > 0) {
- int l = std::min(len,frameCount);
- if(data) {
- memcpy(frameData,data,l);
- data += l;
- }
- else memset(frameData,0,l);
- frameData += l; len -= l; frameCount -= l;
-
- ED("PutData: %s=%d len=%d frameCount=%d\n",data?"put":"zero",l,len,frameCount);
- if (!frameCount) {
- FinishFrame();
- if (totalSize > 0) NewFrame(0,0);
- }
- }
- }
-}
-
-void cAudioEncapsulator::SendIECpause(int type, uchar PTSflags, const uchar *PTSdata)
-{
- StartFrame(AC3_SIZE,PTSflags,PTSdata);
- uchar burst[IEC_HDR_SIZE];
- // prepare IEC 60958 data frame
- burst[0] = 0xF8;
- burst[1] = 0x72;
- burst[2] = 0x4E;
- burst[3] = 0x1F;
-
- switch (type) {
- default:
- case 0:
- burst[4] = 7 << 5; // null frame, stream = 7
- burst[5] = 0x00;
- burst[6] = 0x00; // No data therein
- burst[7] = 0x00;
- break;
- case 1:
- burst[4] = 0x00; // Audio ES Channel empty, wait
- burst[5] = 0x03; // for DD Decoder or pause
- burst[6] = 0x00; // Trailing frame size is 32 bits payload
- burst[7] = 0x20;
- break;
- case -1:
- burst[4] = 0x01; // User stop, skip or error
- burst[5] = 0x03;
- burst[6] = 0x08; // Trailing frame size is zero
- burst[7] = 0x00;
- break;
- }
- PutData(burst,sizeof(burst));
- PutData(0,AC3_SIZE-sizeof(burst));
- FinishFrame();
- muteData = true;
-}
-
-void cAudioEncapsulator::FinishIECFrame(void)
-{
- if(!muteData) {
- ED("FinishIECFrame: fillup=%d\n",fillup);
- if (fillup) PutData(0,fillup);
- FinishFrame();
- }
- muteData=false; fillup=0;
-}
-
-void cAudioEncapsulator::SyncFound(const uchar *data)
-{
- if(skipped) {
- DEBUG("Decode: skipped %d bytes\n",skipped);
- ED("skipped: "); for(int k=-skipped ; k<0 ; k++) ED("%02x ",data[k]);
- ED("\ndata: "); for(int k=0 ; k<24 ; k++) ED("%02x ",data[k]);
- ED("\n");
- skipped=0;
- }
- uchar pf=0;
- ED("Decode: sync found ptsFlags=%d ptsDelay=%d\n",ptsFlags,ptsDelay);
- if(ptsFlags && ptsDelay<=1) {
- pf=ptsFlags; ptsFlags=0;
- }
- if(firstBurst || mute) {
- SendIECpause(1,pf,ptsData);
- if(firstBurst && ++firstBurst>10) firstBurst=0;
- }
- else StartIECFrame(data,length,pf,ptsData);
- PutData(data,SYNC_SIZE);
- have = SYNC_SIZE;
-}
-
-void cAudioEncapsulator::Decode(const uchar *data, int len, uchar PTSflags, int PTSdelay, const uchar *PTSdata)
-{
- ED("Decode: enter length=%d have=%d len=%d PTSflags=%d PTSdelay=%d\n",length,have,len,PTSflags,PTSdelay);
- if(PTSflags) {
- // if we are close to the end of an audio frame, but are already receiving
- // the start of the next frame, assume a corrupted stream and finish the
- // incomplete frame.
- if(length && length-have<20 && !PTSdelay && SyncInfo(data)) {
- int miss=length-have;
- DEBUG("Decode: incomplete frame (stream corrupt?). syncing to next. miss=%d\n",miss);
- PutData(0,miss);
- FinishIECFrame();
- length=have=0;
- }
-/*
- // we only send PTS info if we're nearly at frame start, except
- // if we're signaled to delay the PTS
- if(length && have>40) {
- if(PTSdelay) ED("Decode: PTS delayed\n");
- else {
- DEBUG("Decode: PTS info dropped length=%d have=%d\n",length,have);
- PTSflags=0;
- }
- }
-*/
- ptsFlags=PTSflags; ptsData=PTSdata; ptsDelay=PTSdelay;
-// ED("Decode: saved PTS flags=%d delay=%d\n",ptsFlags,ptsDelay);
- }
-
-#if 0
- {
- printf("Decode: len=%d\n",len);
- for(int i=0 ; i<len ; ) {
- printf("%04x:",i);
- for(int j=0 ; j<16 && i<len ; j++) {
- printf(" %02x",data[i++]);
- }
- printf("\n");
- }
- }
-#endif
-
- int used=0;
- while (used < len) {
- if (!length) { // we are still searching for a header sync
- if (!have) { // buffer is empty, work without buffering
- if (used+SYNC_SIZE < len) {
- length=SyncInfo(&data[used]);
- if (length) {
- ED("Decode: sync found at offset %d (len=%d)\n",used,length);
- SyncFound(&data[used]);
- used += SYNC_SIZE; ptsDelay -= SYNC_SIZE;
- continue;
- }
- else { used++; skipped++; }
- }
- else { // not enough data to try a sync, buffer the rest
- ED("Decode: buffering started\n");
- have = len-used;
- memcpy(syncBuff,&data[used],have);
- used += have; ptsDelay -= have;
- }
- }
- else { // unfortunaly buffer is not empty, so continue with buffering until sync found
- int need=std::min(SYNC_SIZE-have,len-used);
- if (need) {
- memcpy(&syncBuff[have],&data[used],need);
- have += need; used += need; ptsDelay -= need;
- }
- if (have==SYNC_SIZE) {
- length=SyncInfo(syncBuff);
- if (length) {
- ED("Decode: (buffered) sync found at offset %d (len=%d)\n",used-7,length);
- SyncFound(syncBuff);
- continue;
- }
- else {
- memmove(syncBuff,syncBuff+1,SYNC_SIZE-1);
- have--; skipped++;
- }
- }
- }
- }
- else { // we have a header sync and are copying data
- int need = std::min(length-have,len-used);
- if(need) {
- ED("Decode: writing %d\n",need);
- PutData(&data[used],need);
- have += need; used += need; ptsDelay -= need;
- if (have == length) {
- FinishIECFrame();
- length = have = 0;
- continue;
- }
- }
- }
- }
- ED("Decode: leave length=%d have=%d len=%d used=%d\n",length,have,len,used);
-}
-
-// --- cAudioEncapsulatorAC3 ---------------------------------------------------
-
-class cAudioEncapsulatorAC3 : public cAudioEncapsulator {
-private:
- virtual int SyncInfo(const uchar *buf);
- virtual void StartIECFrame(const uchar *buf, int length, uchar PTSflags, const uchar *PTSdata);
-public:
- cAudioEncapsulatorAC3(cRingBufferFrame *rb, int StreamType);
- };
-
-cAudioEncapsulatorAC3::cAudioEncapsulatorAC3(cRingBufferFrame *rb, int StreamType)
-:cAudioEncapsulator(rb, StreamType)
-{}
-
-int cAudioEncapsulatorAC3::SyncInfo(const uchar *buf)
-{
- static const int rate[] = { 32, 40, 48, 56, 64, 80, 96, 112,
- 128, 160, 192, 224, 256, 320, 384, 448,
- 512, 576, 640};
-
- if ((buf[0] != 0x0B) || (buf[1] != 0x77)) /* syncword */
- return 0;
- if (buf[5] >= 0x60) /* bsid >= 12 */
- return 0;
-
- int frmsizecod = buf[4] & 63;
- if (frmsizecod >= 38)
- return 0;
- int bitrate = rate[frmsizecod >> 1];
-
- switch (buf[4] & 0xC0) {
- case 0:
- return 4 * bitrate;
- case 0x40:
- return 2 * (320 * bitrate / 147 + (frmsizecod & 1));
- case 0x80:
- return 6 * bitrate;
- default:
- return 0;
- }
-}
-
-void cAudioEncapsulatorAC3::StartIECFrame(const uchar *buf, int length, uchar PTSflags, const uchar *PTSdata)
-{
- StartFrame(AC3_SIZE,PTSflags,PTSdata);
- fillup = AC3_SIZE-IEC_HDR_SIZE-length;
-
- // prepare IEC 60958 data frame
- uchar burst[IEC_HDR_SIZE];
- burst[0] = 0xF8;
- burst[1] = 0x72;
- burst[2] = 0x4E;
- burst[3] = 0x1F;
- burst[4] = (buf[5] & 0x07); // Pc1
- burst[5] = 0x01; // Pc2 AC-3
- burst[6] = ((length * 8) >> 8 ) & 0xFF; // Pd1
- burst[7] = (length * 8) & 0xFF; // Pd2
- PutData(burst,sizeof(burst));
-}
-
-// --- cAudioEncapsulatorDTS ---------------------------------------------------
-
-class cAudioEncapsulatorDTS : public cAudioEncapsulator {
-private:
- virtual int SyncInfo(const uchar *buf);
- virtual void StartIECFrame(const uchar *buf, int length, uchar PTSflags, const uchar *PTSdata);
-public:
- cAudioEncapsulatorDTS(cRingBufferFrame *rb, int StreamType);
- };
-
-cAudioEncapsulatorDTS::cAudioEncapsulatorDTS(cRingBufferFrame *rb, int StreamType)
-: cAudioEncapsulator(rb, StreamType)
-{}
-
-int cAudioEncapsulatorDTS::SyncInfo(const uchar *buf)
-{
- if ((buf[0] != 0x7F) ||
- (buf[1] != 0xfE) ||
- (buf[2] != 0x80) ||
- (buf[3] != 0x01)) return 0;
-
- int length = ((buf[5] & 0x03) << 12) |
- ((buf[6] & 0xFF) << 4) |
- ((buf[7] & 0xF0) >> 4);
-
- return length + 1;
-}
-
-void cAudioEncapsulatorDTS::StartIECFrame(const uchar *buf, int length, uchar PTSflags, const uchar *PTSdata)
-{
- uchar ac5_type = ((buf[4] & 0x01) << 6) | ((buf[5] >>2) & 0x3F);
- uchar ac5_spdif_type;
- switch(ac5_type) {
- case 0x0F:
- ac5_spdif_type = 0x0B; /* DTS */
- break;
- case 0x1F:
- ac5_spdif_type = 0x0C; /* DTS */
- break;
- case 0x3F:
- ac5_spdif_type = 0x0D; /* DTS */
- break;
- default:
- ac5_spdif_type = 0x00; /* DTS */
- esyslog("DTS: SPDIF type not detected: ac5 type = %X!\n", ac5_type);
- break;
- }
-
- if (length > DTS_SIZE-IEC_HDR_SIZE) {
- DEBUG("DTS: length too long %d\n",length);
- return;
- }
-
- StartFrame(DTS_SIZE,PTSflags,PTSdata);
- fillup = DTS_SIZE-IEC_HDR_SIZE-length;
-
- // prepare IEC 60958 data frame
- uchar burst[IEC_HDR_SIZE];
- burst[0] = 0xF8;
- burst[1] = 0x72;
- burst[2] = 0x4E;
- burst[3] = 0x1F;
- burst[4] = 0x00;
- burst[5] = ac5_spdif_type; /* DTS data */
- burst[6] = ((length * 8) >> 8 ) & 0xFF; /* ac5_length * 8 */
- burst[7] = (length * 8) & 0xFF;
- PutData(burst,sizeof(burst));
-}
-
-// --- cMultichannelAudio ------------------------------------------------------
-
-cMultichannelAudio::cMultichannelAudio(cRingBufferFrame *rb)
-{
- encapsulator=0; ringBuffer=rb;
- fixed=false;
- if(!ringBuffer) DEBUG("multichannel: no ringbuffer!");
-}
-
-cMultichannelAudio::~cMultichannelAudio()
-{
- delete encapsulator;
-}
-
-void cMultichannelAudio::Clear()
-{
- Lock();
- if(encapsulator) encapsulator->Clear();
- Unlock();
-}
-
-void cMultichannelAudio::Reset()
-{
- Lock();
- delete encapsulator; encapsulator=0;
- fixed=false;
- Unlock();
-}
-
-/*
-void cMultichannelAudio::Mute(bool Mute)
-{
- Lock();
- if(encapsulator) encapsulator->Mute(Mute);
- Unlock();
-}
-*/
-
-int cMultichannelAudio::Check(uchar *b, int length, uchar *header)
-{
- Lock();
- int res=0;
- ptsDelay=0; offset=0; ptsData=0;
-
- // get PTS information
- ptsFlags=header[7]>>6;
- if(ptsFlags) ptsData=&header[9];
-
- // AC3 frames may span over multiple PES packets. Unfortunaly the continuation
- // packets start with the aLPCM code sometimes. Some magic here to detect
- // this case.
- uchar subStreamType=b[0];
- if(subStreamType!=aVDR) subStreamType&=0xF8;
- bool aligned=header[6]&4;
- if(!aligned) {
- uchar ost=encapsulator ? encapsulator->StreamType() : 0;
- if(!ptsFlags) {
- if((subStreamType!=aLPCM && subStreamType!=aSPU) || fixed) {
- if(ost>0) {
- ED("multichannel: crossing -> keep encapsulator\n");
- subStreamType=ost;
- }
- else {
- ED("multichannel: crossing -> skip\n");
- res=1; goto out; // skip
- }
- }
- }
- else if(fixed && ost>0) {
- ED("multichannel: fixed unaligned -> keep encapsulator\n");
- subStreamType=ost;
- }
- }
- fixed=false;
-
- switch(subStreamType) {
- case aDTS:
- case aAC3:
- offset=4; // skip the DVD stream infos
- break;
- default:
- if(aligned || !ptsFlags) {
- if(encapsulator) {
- Reset();
- DEBUG("multichannel: interrupted encapsulator stream (unknown)\n");
- }
- DEBUG("multichannel: unknown substream type %x (skipped)\n",subStreamType);
- res=1; goto out; // skip
- }
- subStreamType=aVDR;
- ED("multichannel: assuming aVDR for unknown substream type\n");
- // fall through
- case aVDR:
- fixed=true;
- break;
- case aLPCM:
- if(encapsulator) {
- Reset();
- DEBUG("multichannel: interrupted encapsulator stream (LPCM)\n");
- }
- ED("multichannel: LPCM\n");
- res=2; goto out; // pass
- case aSPU:
- ED("multichannel: SPU stream (skipped)\n");
- res=1; goto out; // skip
- }
-
- // If the SubStreamType has changed then select the right encapsulator
- if(!encapsulator || encapsulator->StreamType()!=subStreamType) {
- DEBUG("multichannel: new encapsulator %x\n",subStreamType);
- Reset();
- switch(subStreamType) {
- case aAC3:
- case aVDR: // AC3
- encapsulator=new cAudioEncapsulatorAC3(ringBuffer,subStreamType);
- break;
- case aDTS: // Dts
- encapsulator=new cAudioEncapsulatorDTS(ringBuffer,subStreamType);
- break;
- }
- if(!encapsulator) {
- DEBUG("multichannel: no encapsulator\n");
- res=1; goto out; // skip
- }
- }
-
-out:
- ED("HEADER type=%x sub=%x ptsflags=%d length=%d\n",header[3],subStreamType,ptsFlags,length);
- ED("head: "); for(int k=0 ; k<24 ; k++) ED("%02x ",header[k]);
- ED("\ndata: "); for(int k=0 ; k<24 ; k++) ED("%02x ",b[k]);
- ED("\n");
-
- Unlock(); return res;
-}
-
-void cMultichannelAudio::Encapsulate(uchar *b, int length)
-{
- Lock();
- if(offset && ptsFlags) { // get start of the packet to which the PTS belong (DVD only)
- if(offset>=2 && length>offset-2) ptsDelay|=b[offset-2]*256;
- if(offset>=1 && length>offset-1) ptsDelay|=b[offset-1];
- }
- if(length>=offset) {
- if(encapsulator)
- encapsulator->Decode(b+offset,length-offset,ptsFlags,ptsDelay,ptsData);
- ptsFlags=0; ptsDelay=0; offset=0; ptsData=0;
- }
- else offset-=length;
- Unlock();
-}
-
-// Local variables:
-// mode: c++
-// c-file-style: "stroustrup"
-// c-file-offsets: ((inline-open . 0))
-// indent-tabs-mode: t
-// End: