mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Added PTS to the converted PCM audio when replaying a DVD
This commit is contained in:
parent
57bd015bcb
commit
d78d555b27
@ -115,6 +115,7 @@ Helmut Sch
|
|||||||
Andreas Schultz <aschultz@warp10.net>
|
Andreas Schultz <aschultz@warp10.net>
|
||||||
for adding support for replaying DVDs (much of this was derived from
|
for adding support for replaying DVDs (much of this was derived from
|
||||||
dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si>)
|
dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si>)
|
||||||
|
for adding PTS to the converted PCM audio when replaying a DVD
|
||||||
|
|
||||||
Aaron Holtzman
|
Aaron Holtzman
|
||||||
for writing 'ac3dec'
|
for writing 'ac3dec'
|
||||||
|
5
HISTORY
5
HISTORY
@ -831,7 +831,7 @@ Video Disk Recorder Revision History
|
|||||||
- Fixed handling trick modes near the beginning and end of a recording.
|
- Fixed handling trick modes near the beginning and end of a recording.
|
||||||
- Pressing the "Back" button while replaying a DVD now leads to the DVD menu.
|
- Pressing the "Back" button while replaying a DVD now leads to the DVD menu.
|
||||||
|
|
||||||
2001-10-28: Version 0.98
|
2001-11-03: Version 0.98
|
||||||
|
|
||||||
- Completed storing the current audio volume in the setup.conf file (thanks
|
- Completed storing the current audio volume in the setup.conf file (thanks
|
||||||
to Andy Grobb).
|
to Andy Grobb).
|
||||||
@ -851,3 +851,6 @@ Video Disk Recorder Revision History
|
|||||||
on an other free DVB card (if one is free at the moment). See MANUAL for
|
on an other free DVB card (if one is free at the moment). See MANUAL for
|
||||||
details.
|
details.
|
||||||
- Added some missing teletext PIDs (thanks to Norbert Schmidt).
|
- Added some missing teletext PIDs (thanks to Norbert Schmidt).
|
||||||
|
- Added PTS to the converted PCM audio when replaying a DVD (thanks to Andreas
|
||||||
|
Schultz). Now the audio and video of a DVD replayed over the DVB card's A/V
|
||||||
|
out should always be in sync.
|
||||||
|
415
dvbapi.c
415
dvbapi.c
@ -7,7 +7,7 @@
|
|||||||
* DVD support initially written by Andreas Schultz <aschultz@warp10.net>
|
* DVD support initially written by Andreas Schultz <aschultz@warp10.net>
|
||||||
* based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si>
|
* based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si>
|
||||||
*
|
*
|
||||||
* $Id: dvbapi.c 1.133 2001/10/27 13:00:29 kls Exp $
|
* $Id: dvbapi.c 1.134 2001/11/03 10:59:34 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//#define DVDDEBUG 1
|
//#define DVDDEBUG 1
|
||||||
@ -713,7 +713,10 @@ protected:
|
|||||||
void TrickSpeed(int Increment);
|
void TrickSpeed(int Increment);
|
||||||
virtual void Empty(bool Block = false);
|
virtual void Empty(bool Block = false);
|
||||||
virtual void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00) {}
|
virtual void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00) {}
|
||||||
|
virtual void PlayExternalDolby(const uchar *b, int MaxLength);
|
||||||
virtual void Output(void);
|
virtual void Output(void);
|
||||||
|
void putFrame(cFrame *Frame);
|
||||||
|
void putFrame(unsigned char *Data, int Length, eFrameType Type = ftUnknown);
|
||||||
public:
|
public:
|
||||||
cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev);
|
cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev);
|
||||||
virtual ~cPlayBuffer();
|
virtual ~cPlayBuffer();
|
||||||
@ -759,6 +762,28 @@ cPlayBuffer::~cPlayBuffer()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cPlayBuffer::PlayExternalDolby(const uchar *b, int MaxLength)
|
||||||
|
{
|
||||||
|
if (dolbyDev) {
|
||||||
|
if (b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01) {
|
||||||
|
if (b[3] == 0xBD) { // dolby
|
||||||
|
int l = b[4] * 256 + b[5] + 6;
|
||||||
|
int written = b[8] + 9; // skips the PES header
|
||||||
|
int n = min(l - written, MaxLength);
|
||||||
|
while (n > 0) {
|
||||||
|
int w = fwrite(&b[written], 1, n, dolbyDev);
|
||||||
|
if (w < 0) {
|
||||||
|
LOG_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n -= w;
|
||||||
|
written += w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void cPlayBuffer::Output(void)
|
void cPlayBuffer::Output(void)
|
||||||
{
|
{
|
||||||
dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid());
|
dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid());
|
||||||
@ -771,6 +796,9 @@ void cPlayBuffer::Output(void)
|
|||||||
}
|
}
|
||||||
const cFrame *frame = Get();
|
const cFrame *frame = Get();
|
||||||
if (frame) {
|
if (frame) {
|
||||||
|
if (frame->Type() == ftDolby)
|
||||||
|
PlayExternalDolby(frame->Data(), frame->Count());
|
||||||
|
else {
|
||||||
StripAudioPackets((uchar *)frame->Data(), frame->Count(), (playMode == pmFast || playMode == pmSlow) ? 0x00 : audioTrack);//XXX
|
StripAudioPackets((uchar *)frame->Data(), frame->Count(), (playMode == pmFast || playMode == pmSlow) ? 0x00 : audioTrack);//XXX
|
||||||
const uchar *p = frame->Data();
|
const uchar *p = frame->Data();
|
||||||
int r = frame->Count();
|
int r = frame->Count();
|
||||||
@ -789,6 +817,7 @@ void cPlayBuffer::Output(void)
|
|||||||
}
|
}
|
||||||
writeIndex = frame->Index();
|
writeIndex = frame->Index();
|
||||||
backTrace.Add(frame->Index(), frame->Count());
|
backTrace.Add(frame->Index(), frame->Count());
|
||||||
|
}
|
||||||
Drop(frame);
|
Drop(frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -796,6 +825,20 @@ void cPlayBuffer::Output(void)
|
|||||||
dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid());
|
dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cPlayBuffer::putFrame(cFrame *Frame)
|
||||||
|
{
|
||||||
|
while (Busy() && !blockInput) {
|
||||||
|
if (Put(Frame))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete Frame; // caller relies on frame being put, otherwise this would be a memory leak!
|
||||||
|
}
|
||||||
|
|
||||||
|
void cPlayBuffer::putFrame(unsigned char *Data, int Length, eFrameType Type)
|
||||||
|
{
|
||||||
|
putFrame(new cFrame(Data, Length, Type));
|
||||||
|
}
|
||||||
|
|
||||||
void cPlayBuffer::TrickSpeed(int Increment)
|
void cPlayBuffer::TrickSpeed(int Increment)
|
||||||
{
|
{
|
||||||
int nts = trickSpeed + Increment;
|
int nts = trickSpeed + Increment;
|
||||||
@ -1089,11 +1132,8 @@ void cReplayBuffer::Input(void)
|
|||||||
}
|
}
|
||||||
else // allows replay even if the index file is missing
|
else // allows replay even if the index file is missing
|
||||||
r = read(replayFile, b, sizeof(b));
|
r = read(replayFile, b, sizeof(b));
|
||||||
if (r > 0) {
|
if (r > 0)
|
||||||
cFrame *frame = new cFrame(b, r, readIndex);
|
putFrame(new cFrame(b, r, ftUnknown, readIndex));
|
||||||
while (Busy() && !blockInput && !Put(frame))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
else if (r == 0)
|
else if (r == 0)
|
||||||
eof = true;
|
eof = true;
|
||||||
else if (r < 0 && FATALERRNO) {
|
else if (r < 0 && FATALERRNO) {
|
||||||
@ -1117,19 +1157,8 @@ void cReplayBuffer::StripAudioPackets(uchar *b, int Length, uchar Except)
|
|||||||
int l = b[i + 4] * 256 + b[i + 5] + 6;
|
int l = b[i + 4] * 256 + b[i + 5] + 6;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 0xBD: // dolby
|
case 0xBD: // dolby
|
||||||
if (Except && dolbyDev) {
|
if (Except && dolbyDev)
|
||||||
int written = b[i + 8] + 9; // skips the PES header
|
PlayExternalDolby(&b[i], Length - i);
|
||||||
int n = l - written;
|
|
||||||
while (n > 0) {
|
|
||||||
int w = fwrite(&b[i + written], 1, n, dolbyDev);
|
|
||||||
if (w < 0) {
|
|
||||||
LOG_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
n -= w;
|
|
||||||
written += w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// continue with deleting the data - otherwise it disturbs DVB replay
|
// continue with deleting the data - otherwise it disturbs DVB replay
|
||||||
case 0xC0 ... 0xC1: // audio
|
case 0xC0 ... 0xC1: // audio
|
||||||
if (c == 0xC1)
|
if (c == 0xC1)
|
||||||
@ -1290,10 +1319,166 @@ bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DVDSUPPORT
|
#ifdef DVDSUPPORT
|
||||||
|
|
||||||
|
#define SYSTEM_HEADER 0xBB
|
||||||
|
#define PROG_STREAM_MAP 0xBC
|
||||||
|
#ifndef PRIVATE_STREAM1
|
||||||
|
#define PRIVATE_STREAM1 0xBD
|
||||||
|
#endif
|
||||||
|
#define PADDING_STREAM 0xBE
|
||||||
|
#ifndef PRIVATE_STREAM2
|
||||||
|
#define PRIVATE_STREAM2 0xBF
|
||||||
|
#endif
|
||||||
|
#define AUDIO_STREAM_S 0xC0
|
||||||
|
#define AUDIO_STREAM_E 0xDF
|
||||||
|
#define VIDEO_STREAM_S 0xE0
|
||||||
|
#define VIDEO_STREAM_E 0xEF
|
||||||
|
#define ECM_STREAM 0xF0
|
||||||
|
#define EMM_STREAM 0xF1
|
||||||
|
#define DSM_CC_STREAM 0xF2
|
||||||
|
#define ISO13522_STREAM 0xF3
|
||||||
|
#define PROG_STREAM_DIR 0xFF
|
||||||
|
|
||||||
|
#define cOPENDVD 0
|
||||||
|
#define cOPENTITLE 1
|
||||||
|
#define cOPENCHAPTER 2
|
||||||
|
#define cOUTCELL 3
|
||||||
|
#define cREADFRAME 4
|
||||||
|
#define cOUTPACK 5
|
||||||
|
#define cOUTFRAMES 6
|
||||||
|
|
||||||
|
#define aAC3 0x80
|
||||||
|
#define aLPCM 0xA0
|
||||||
|
|
||||||
|
// --- cAC3toPCM -------------------------------------------------------------
|
||||||
|
|
||||||
|
class cAC3toPCM {
|
||||||
|
private:
|
||||||
|
enum { AC3_STOP, AC3_START, AC3_PLAY } ac3stat;
|
||||||
|
uchar *ac3data;
|
||||||
|
int ac3inp;
|
||||||
|
int ac3outp;
|
||||||
|
public:
|
||||||
|
cAC3toPCM(void);
|
||||||
|
~cAC3toPCM();
|
||||||
|
void Clear(void);
|
||||||
|
void Put(unsigned char *sector, int length);
|
||||||
|
cFrame *Get(int size, uchar PTSflags = 0, uchar *PTSdata = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
cAC3toPCM::cAC3toPCM(void)
|
||||||
|
{
|
||||||
|
ac3dec_init();
|
||||||
|
ac3data = new uchar[AC3_BUFFER_SIZE];
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
cAC3toPCM::~cAC3toPCM()
|
||||||
|
{
|
||||||
|
delete ac3data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cAC3toPCM::Clear(void)
|
||||||
|
{
|
||||||
|
ac3stat = AC3_START;
|
||||||
|
ac3outp = ac3inp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cAC3toPCM::Put(unsigned char *sector, int length)
|
||||||
|
{
|
||||||
|
ac3dec_decode_data(sector, sector + length, ac3stat == AC3_START, &ac3inp, &ac3outp, (char *)ac3data);
|
||||||
|
ac3stat = AC3_PLAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// data=PCM samples, 16 bit, LSB first, 48kHz, stereo
|
||||||
|
cFrame *cAC3toPCM::Get(int size, uchar PTSflags, uchar *PTSdata)
|
||||||
|
{
|
||||||
|
if (ac3inp == ac3outp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
#define MAXSIZE 2022
|
||||||
|
|
||||||
|
uchar buffer[2048];
|
||||||
|
uchar *data;
|
||||||
|
|
||||||
|
if (size > 0) {
|
||||||
|
int p_size = (size > MAXSIZE) ? MAXSIZE : size;
|
||||||
|
int length = 10; // default header bytes
|
||||||
|
int header = 0;
|
||||||
|
int stuffb = 0;
|
||||||
|
|
||||||
|
switch (PTSflags) {
|
||||||
|
case 2: header = 5; // additional header bytes
|
||||||
|
stuffb = 1;
|
||||||
|
break;
|
||||||
|
case 3: header = 10;
|
||||||
|
break;
|
||||||
|
default: header = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// header = 0; //XXX ???
|
||||||
|
stuffb = 0; //XXX ???
|
||||||
|
|
||||||
|
length += header;
|
||||||
|
length += stuffb;
|
||||||
|
|
||||||
|
buffer[0] = 0x00;
|
||||||
|
buffer[1] = 0x00;
|
||||||
|
buffer[2] = 0x01;
|
||||||
|
buffer[3] = PRIVATE_STREAM1;
|
||||||
|
|
||||||
|
buffer[6] = 0x80;
|
||||||
|
buffer[7] = PTSflags << 6;
|
||||||
|
buffer[8] = header + stuffb;
|
||||||
|
|
||||||
|
if (header)
|
||||||
|
memcpy(&buffer[9], (void *)PTSdata, header);
|
||||||
|
|
||||||
|
// add stuffing
|
||||||
|
data = buffer + 9 + header;
|
||||||
|
for (int cnt = 0; cnt < stuffb; cnt++)
|
||||||
|
data[cnt] = 0xff;
|
||||||
|
length += stuffb;
|
||||||
|
|
||||||
|
// add data
|
||||||
|
data = buffer + 9 + header + stuffb + 7;
|
||||||
|
int cnt = 0;
|
||||||
|
while (p_size) {
|
||||||
|
if (ac3outp != ac3inp) { // data in the buffer
|
||||||
|
data[cnt ^ 1] = ac3data[ac3outp]; // swab because ac3dec delivers wrong byteorder (the "xor" (^) is a swab!)
|
||||||
|
p_size--;
|
||||||
|
cnt++;
|
||||||
|
length++;
|
||||||
|
ac3outp = (ac3outp + 1) % AC3_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = buffer + 9 + header + stuffb;
|
||||||
|
data[0] = aLPCM; // substream ID
|
||||||
|
data[1] = 0x00; // other stuff (see DVB specs), ignored by driver
|
||||||
|
data[2] = 0x00;
|
||||||
|
data[3] = 0x00;
|
||||||
|
data[4] = 0x00;
|
||||||
|
data[5] = 0x00;
|
||||||
|
data[6] = 0x00;
|
||||||
|
|
||||||
|
buffer[4] = (length >> 8) & 0xff;
|
||||||
|
buffer[5] = length & 0xff;
|
||||||
|
|
||||||
|
length += 6;
|
||||||
|
|
||||||
|
return new cFrame(buffer, length);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// --- cDVDplayBuffer --------------------------------------------------------
|
// --- cDVDplayBuffer --------------------------------------------------------
|
||||||
|
|
||||||
class cDVDplayBuffer : public cPlayBuffer {
|
class cDVDplayBuffer : public cPlayBuffer {
|
||||||
private:
|
private:
|
||||||
|
cAC3toPCM AC3toPCM;
|
||||||
uchar audioTrack;
|
uchar audioTrack;
|
||||||
|
|
||||||
cDVD *dvd;//XXX necessary???
|
cDVD *dvd;//XXX necessary???
|
||||||
@ -1308,7 +1493,6 @@ private:
|
|||||||
int doplay;
|
int doplay;
|
||||||
int cyclestate;
|
int cyclestate;
|
||||||
int prevcycle;
|
int prevcycle;
|
||||||
int brakeCounter;
|
|
||||||
int skipCnt;
|
int skipCnt;
|
||||||
|
|
||||||
tt_srpt_t *tt_srpt;
|
tt_srpt_t *tt_srpt;
|
||||||
@ -1335,11 +1519,6 @@ private:
|
|||||||
int logAudioTrack;
|
int logAudioTrack;
|
||||||
int maxAudioTrack;
|
int maxAudioTrack;
|
||||||
|
|
||||||
enum { AC3_STOP, AC3_START, AC3_PLAY } ac3stat;
|
|
||||||
uchar *ac3data;
|
|
||||||
int ac3inp;
|
|
||||||
int ac3outp;
|
|
||||||
int lpcm_count;
|
|
||||||
int is_nav_pack(unsigned char *buffer);
|
int is_nav_pack(unsigned char *buffer);
|
||||||
void Close(void);
|
void Close(void);
|
||||||
virtual void Empty(bool Block = false);
|
virtual void Empty(bool Block = false);
|
||||||
@ -1350,10 +1529,7 @@ private:
|
|||||||
int GetStuffingLen(const uchar *Data);
|
int GetStuffingLen(const uchar *Data);
|
||||||
int GetPacketLength(const uchar *Data);
|
int GetPacketLength(const uchar *Data);
|
||||||
int GetPESHeaderLength(const uchar *Data);
|
int GetPESHeaderLength(const uchar *Data);
|
||||||
int SendPCM(int size);
|
void handleAC3(unsigned char *sector, int length, uchar PTSflags, uchar *PTSdata);
|
||||||
void playDecodedAC3(void);
|
|
||||||
void handleAC3(unsigned char *sector, int length);
|
|
||||||
void putFrame(unsigned char *sector, int length);
|
|
||||||
unsigned int getAudioStream(unsigned int StreamId);
|
unsigned int getAudioStream(unsigned int StreamId);
|
||||||
void setChapid(void);
|
void setChapid(void);
|
||||||
void NextState(int State) { prevcycle = cyclestate; cyclestate = State; }
|
void NextState(int State) { prevcycle = cyclestate; cyclestate = State; }
|
||||||
@ -1369,17 +1545,6 @@ public:
|
|||||||
virtual void ToggleAudioTrack(void);
|
virtual void ToggleAudioTrack(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define cOPENDVD 0
|
|
||||||
#define cOPENTITLE 1
|
|
||||||
#define cOPENCHAPTER 2
|
|
||||||
#define cOUTCELL 3
|
|
||||||
#define cREADFRAME 4
|
|
||||||
#define cOUTPACK 5
|
|
||||||
#define cOUTFRAMES 6
|
|
||||||
|
|
||||||
#define aAC3 0x80
|
|
||||||
#define aLPCM 0xA0
|
|
||||||
|
|
||||||
cDVDplayBuffer::cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title)
|
cDVDplayBuffer::cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title)
|
||||||
:cPlayBuffer(DvbApi, VideoDev, AudioDev)
|
:cPlayBuffer(DvbApi, VideoDev, AudioDev)
|
||||||
{
|
{
|
||||||
@ -1389,15 +1554,10 @@ cDVDplayBuffer::cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD
|
|||||||
angle = 0;
|
angle = 0;
|
||||||
cyclestate = cOPENDVD;
|
cyclestate = cOPENDVD;
|
||||||
prevcycle = 0;
|
prevcycle = 0;
|
||||||
brakeCounter = 0;
|
|
||||||
skipCnt = 0;
|
skipCnt = 0;
|
||||||
logAudioTrack = 0;
|
logAudioTrack = 0;
|
||||||
canToggleAudioTrack = true;//XXX determine from cDVD!
|
canToggleAudioTrack = true;//XXX determine from cDVD!
|
||||||
ac3dec_init();
|
|
||||||
data = new uchar[1024 * DVD_VIDEO_LB_LEN];
|
data = new uchar[1024 * DVD_VIDEO_LB_LEN];
|
||||||
ac3data = new uchar[AC3_BUFFER_SIZE];
|
|
||||||
ac3inp = ac3outp = 0;
|
|
||||||
ac3stat = AC3_START;
|
|
||||||
canDoTrickMode = true;
|
canDoTrickMode = true;
|
||||||
dvbApi->SetModeReplay();
|
dvbApi->SetModeReplay();
|
||||||
Start();
|
Start();
|
||||||
@ -1408,7 +1568,6 @@ cDVDplayBuffer::~cDVDplayBuffer()
|
|||||||
Stop();
|
Stop();
|
||||||
Close();
|
Close();
|
||||||
dvbApi->SetModeNormal(false);
|
dvbApi->SetModeNormal(false);
|
||||||
delete ac3data;
|
|
||||||
delete data;
|
delete data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1449,8 +1608,7 @@ void cDVDplayBuffer::ToggleAudioTrack(void)
|
|||||||
#ifdef DVDDEBUG
|
#ifdef DVDDEBUG
|
||||||
dsyslog(LOG_INFO, "DVB: Audio Stream ID changed to: %x", audioTrack);
|
dsyslog(LOG_INFO, "DVB: Audio Stream ID changed to: %x", audioTrack);
|
||||||
#endif
|
#endif
|
||||||
ac3stat = AC3_START;
|
AC3toPCM.Clear();
|
||||||
ac3outp = ac3inp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1869,141 +2027,21 @@ int cDVDplayBuffer::ScanVideoPacket(const uchar *Data, int Count, uchar *Picture
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SYSTEM_HEADER 0xBB
|
void cDVDplayBuffer::handleAC3(unsigned char *sector, int length, uchar PTSflags, uchar *PTSdata)
|
||||||
#define PROG_STREAM_MAP 0xBC
|
|
||||||
#ifndef PRIVATE_STREAM1
|
|
||||||
#define PRIVATE_STREAM1 0xBD
|
|
||||||
#endif
|
|
||||||
#define PADDING_STREAM 0xBE
|
|
||||||
#ifndef PRIVATE_STREAM2
|
|
||||||
#define PRIVATE_STREAM2 0xBF
|
|
||||||
#endif
|
|
||||||
#define AUDIO_STREAM_S 0xC0
|
|
||||||
#define AUDIO_STREAM_E 0xDF
|
|
||||||
#define VIDEO_STREAM_S 0xE0
|
|
||||||
#define VIDEO_STREAM_E 0xEF
|
|
||||||
#define ECM_STREAM 0xF0
|
|
||||||
#define EMM_STREAM 0xF1
|
|
||||||
#define DSM_CC_STREAM 0xF2
|
|
||||||
#define ISO13522_STREAM 0xF3
|
|
||||||
#define PROG_STREAM_DIR 0xFF
|
|
||||||
|
|
||||||
// data=PCM samples, 16 bit, LSB first, 48kHz, stereo
|
|
||||||
int cDVDplayBuffer::SendPCM(int size)
|
|
||||||
{
|
{
|
||||||
|
#define PCM_FRAME_SIZE 1536
|
||||||
#define MAXSIZE 2032
|
AC3toPCM.Put(sector, length);
|
||||||
|
cFrame *frame;
|
||||||
uchar buffer[MAXSIZE + 16];
|
if ((frame = AC3toPCM.Get(PCM_FRAME_SIZE, PTSflags, PTSdata)) != NULL)
|
||||||
int length = 0;
|
putFrame(frame);
|
||||||
int p_size;
|
while ((frame = AC3toPCM.Get(PCM_FRAME_SIZE)) != NULL)
|
||||||
|
putFrame(frame);
|
||||||
if (ac3inp == ac3outp)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
while (size > 0) {
|
|
||||||
if (size >= MAXSIZE)
|
|
||||||
p_size = MAXSIZE;
|
|
||||||
else
|
|
||||||
p_size = size;
|
|
||||||
length = 10;
|
|
||||||
|
|
||||||
while (p_size) {
|
|
||||||
if (ac3outp != ac3inp) { // data in the buffer
|
|
||||||
buffer[(length + 6) ^ 1] = ac3data[ac3outp]; // swab because ac3dec delivers wrong byteorder
|
|
||||||
// XXX there is no 'swab' here??? (kls)
|
|
||||||
p_size--;
|
|
||||||
length++;
|
|
||||||
ac3outp = (ac3outp + 1) % AC3_BUFFER_SIZE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[0] = 0x00;
|
|
||||||
buffer[1] = 0x00;
|
|
||||||
buffer[2] = 0x01;
|
|
||||||
buffer[3] = PRIVATE_STREAM1;
|
|
||||||
|
|
||||||
buffer[4] = (length >> 8) & 0xff;
|
|
||||||
buffer[5] = length & 0xff;
|
|
||||||
|
|
||||||
buffer[6] = 0x80;
|
|
||||||
buffer[7] = 0x00;
|
|
||||||
buffer[8] = 0x00;
|
|
||||||
|
|
||||||
buffer[9] = aLPCM; // substream ID
|
|
||||||
buffer[10] = 0x00; // other stuff (see DVD specs), ignored by driver
|
|
||||||
buffer[11] = 0x00;
|
|
||||||
buffer[12] = 0x00;
|
|
||||||
buffer[13] = 0x00;
|
|
||||||
buffer[14] = 0x00;
|
|
||||||
buffer[15] = 0x00;
|
|
||||||
|
|
||||||
length += 6;
|
|
||||||
|
|
||||||
putFrame(buffer, length);
|
|
||||||
size -= MAXSIZE;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cDVDplayBuffer::playDecodedAC3(void)
|
|
||||||
{
|
|
||||||
int ac3_datasize = (AC3_BUFFER_SIZE + ac3inp - ac3outp) % AC3_BUFFER_SIZE;
|
|
||||||
|
|
||||||
if (ac3_datasize) {
|
|
||||||
if (ac3_datasize > 1024 * 48)
|
|
||||||
SendPCM(3096);
|
|
||||||
else if (ac3_datasize > 1024 * 32)
|
|
||||||
SendPCM(1536);
|
|
||||||
else if (ac3_datasize > 1024 * 16 && !(lpcm_count % 2))
|
|
||||||
SendPCM(1536);
|
|
||||||
else if (ac3_datasize && !(lpcm_count % 4))
|
|
||||||
SendPCM(1536);
|
|
||||||
lpcm_count++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
lpcm_count=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cDVDplayBuffer::handleAC3(unsigned char *sector, int length)
|
|
||||||
{
|
|
||||||
if (dolbyDev) {
|
|
||||||
while (length > 0) {
|
|
||||||
int w = fwrite(sector, 1, length , dolbyDev);
|
|
||||||
if (w < 0) {
|
|
||||||
LOG_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
length -= w;
|
|
||||||
sector += w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (ac3stat == AC3_PLAY)
|
|
||||||
ac3dec_decode_data(sector, sector + length, 0, &ac3inp, &ac3outp, (char *)ac3data);
|
|
||||||
else if (ac3stat == AC3_START) {
|
|
||||||
ac3dec_decode_data(sector, sector + length, 1, &ac3inp, &ac3outp, (char *)ac3data);
|
|
||||||
ac3stat = AC3_PLAY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//playDecodedAC3();
|
|
||||||
}
|
|
||||||
|
|
||||||
void cDVDplayBuffer::putFrame(unsigned char *sector, int length)
|
|
||||||
{
|
|
||||||
cFrame *frame = new cFrame(sector, length);
|
|
||||||
while (Busy() && !blockInput && !Put(frame))
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode)
|
int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode)
|
||||||
{
|
{
|
||||||
|
//XXX kls 2001-11-03: do we really need all these different return values?
|
||||||
uchar pt = 1;
|
uchar pt = 1;
|
||||||
#if 0
|
|
||||||
uchar *osect = sector;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//make sure we got a PS packet header
|
//make sure we got a PS packet header
|
||||||
if (!PacketStart(§or, DVD_VIDEO_LB_LEN) && GetPacketType(sector) != 0xBA) {
|
if (!PacketStart(§or, DVD_VIDEO_LB_LEN) && GetPacketType(sector) != 0xBA) {
|
||||||
@ -2017,6 +2055,8 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode)
|
|||||||
int datalen = r;
|
int datalen = r;
|
||||||
|
|
||||||
sector[6] &= 0x8f;
|
sector[6] &= 0x8f;
|
||||||
|
uchar PTSflags = sector[7] >> 6;
|
||||||
|
uchar *PTSdata = sector + 9;
|
||||||
uchar *data = sector;
|
uchar *data = sector;
|
||||||
|
|
||||||
switch (GetPacketType(sector)) {
|
switch (GetPacketType(sector)) {
|
||||||
@ -2025,6 +2065,7 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode)
|
|||||||
ScanVideoPacket(sector, r, &pt);
|
ScanVideoPacket(sector, r, &pt);
|
||||||
if (trickMode && pt != 1)
|
if (trickMode && pt != 1)
|
||||||
return pt;
|
return pt;
|
||||||
|
putFrame(sector, r, ftVideo);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AUDIO_STREAM_S ... AUDIO_STREAM_E: {
|
case AUDIO_STREAM_S ... AUDIO_STREAM_E: {
|
||||||
@ -2033,6 +2074,7 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode)
|
|||||||
return 1;
|
return 1;
|
||||||
if (audioTrack != GetPacketType(sector))
|
if (audioTrack != GetPacketType(sector))
|
||||||
return 5;
|
return 5;
|
||||||
|
putFrame(sector, r, ftAudio);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PRIVATE_STREAM1:
|
case PRIVATE_STREAM1:
|
||||||
@ -2060,14 +2102,15 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode)
|
|||||||
if (audioTrack == *data) {
|
if (audioTrack == *data) {
|
||||||
switch (audioTrack & 0xF8) {
|
switch (audioTrack & 0xF8) {
|
||||||
case aAC3:
|
case aAC3:
|
||||||
|
if (dolbyDev)
|
||||||
|
putFrame(sector, r, ftDolby);
|
||||||
data += 4;
|
data += 4;
|
||||||
// correct a3 data lenght - FIXME: why 13 ???
|
datalen -= 13; // 3 (mandatory header) + 6 (PS header) + 4 (AC3 header) = 13
|
||||||
datalen -= 13;
|
handleAC3(data, datalen, PTSflags, PTSdata);
|
||||||
handleAC3(data, datalen);
|
|
||||||
break;
|
break;
|
||||||
case aLPCM:
|
case aLPCM:
|
||||||
// write(audio, sector+14 , sector[19]+(sector[18]<<8)+6);
|
// write(audio, sector+14 , sector[19]+(sector[18]<<8)+6);
|
||||||
putFrame(sector, GetPacketLength(sector));
|
putFrame(sector, GetPacketLength(sector), ftAudio);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -2096,9 +2139,6 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode)
|
|||||||
return pt;
|
return pt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
putFrame(sector, r);
|
|
||||||
if ((audioTrack & 0xF8) == aAC3)
|
|
||||||
playDecodedAC3();
|
|
||||||
return pt;
|
return pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2106,8 +2146,7 @@ void cDVDplayBuffer::Empty(bool Block)
|
|||||||
{
|
{
|
||||||
if (!(blockInput || blockOutput)) {
|
if (!(blockInput || blockOutput)) {
|
||||||
cPlayBuffer::Empty(true);
|
cPlayBuffer::Empty(true);
|
||||||
ac3stat = AC3_START;
|
AC3toPCM.Clear();
|
||||||
ac3outp = ac3inp;
|
|
||||||
}
|
}
|
||||||
if (!Block)
|
if (!Block)
|
||||||
cPlayBuffer::Empty(false);
|
cPlayBuffer::Empty(false);
|
||||||
@ -2149,9 +2188,7 @@ void cDVDplayBuffer::SkipSeconds(int Seconds)
|
|||||||
Empty(true);
|
Empty(true);
|
||||||
chapid = newchapid;
|
chapid = newchapid;
|
||||||
NextState(cOPENCHAPTER);
|
NextState(cOPENCHAPTER);
|
||||||
if (ac3stat != AC3_STOP)
|
AC3toPCM.Clear();
|
||||||
ac3stat = AC3_START;
|
|
||||||
ac3outp = ac3inp;
|
|
||||||
Empty(false);
|
Empty(false);
|
||||||
Play();
|
Play();
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Parts of this file were inspired by the 'ringbuffy.c' from the
|
* Parts of this file were inspired by the 'ringbuffy.c' from the
|
||||||
* LinuxDVB driver (see linuxtv.org).
|
* LinuxDVB driver (see linuxtv.org).
|
||||||
*
|
*
|
||||||
* $Id: ringbuffer.c 1.4 2001/08/05 12:17:45 kls Exp $
|
* $Id: ringbuffer.c 1.5 2001/11/03 09:50:46 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
@ -215,9 +215,10 @@ int cRingBufferLinear::Get(uchar *Data, int Count)
|
|||||||
|
|
||||||
// --- cFrame ----------------------------------------------------------------
|
// --- cFrame ----------------------------------------------------------------
|
||||||
|
|
||||||
cFrame::cFrame(const uchar *Data, int Count, int Index)
|
cFrame::cFrame(const uchar *Data, int Count, eFrameType Type, int Index)
|
||||||
{
|
{
|
||||||
count = Count;
|
count = Count;
|
||||||
|
type = Type;
|
||||||
index = Index;
|
index = Index;
|
||||||
data = new uchar[count];
|
data = new uchar[count];
|
||||||
if (data)
|
if (data)
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: ringbuffer.h 1.4 2001/08/05 11:12:06 kls Exp $
|
* $Id: ringbuffer.h 1.5 2001/11/03 10:41:33 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __RINGBUFFER_H
|
#ifndef __RINGBUFFER_H
|
||||||
@ -75,18 +75,22 @@ public:
|
|||||||
virtual ~cRingBufferLinear();
|
virtual ~cRingBufferLinear();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum eFrameType { ftUnknown, ftVideo, ftAudio, ftDolby };
|
||||||
|
|
||||||
class cFrame {
|
class cFrame {
|
||||||
friend class cRingBufferFrame;
|
friend class cRingBufferFrame;
|
||||||
private:
|
private:
|
||||||
cFrame *next;
|
cFrame *next;
|
||||||
uchar *data;
|
uchar *data;
|
||||||
int count;
|
int count;
|
||||||
|
eFrameType type;
|
||||||
int index;
|
int index;
|
||||||
public:
|
public:
|
||||||
cFrame(const uchar *Data, int Count, int Index = -1);
|
cFrame(const uchar *Data, int Count, eFrameType = ftUnknown, int Index = -1);
|
||||||
~cFrame();
|
~cFrame();
|
||||||
const uchar *Data(void) const { return data; }
|
const uchar *Data(void) const { return data; }
|
||||||
int Count(void) const { return count; }
|
int Count(void) const { return count; }
|
||||||
|
eFrameType Type(void) const { return type; }
|
||||||
int Index(void) const { return index; }
|
int Index(void) const { return index; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user