1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Recording both audio tracks

This commit is contained in:
Klaus Schmidinger 2001-06-14 15:57:30 +02:00
parent 4b8968f7e1
commit 9de548ee59
8 changed files with 174 additions and 98 deletions

View File

@ -128,3 +128,12 @@ Video Disk Recorder File Formats
- marks must have a frame number, and that frame MUST be an I-frame (this
means that only marks generated by VDR itself can be used, since they
will always be guaranteed to mark I-frames).
* 001.vdr ... 255.vdr
These are the actual recorded MPEG data files. In order to keep the size of
an individual file below a given limit, a recording is split into several
files. The contents of these files is "Packetized Elementary Stream" (PES)
and contains ES packets with ids 0xE0 for video, 0xC0 for audio 1 and 0xC1
for audio 2 (if available).

17
HISTORY
View File

@ -510,3 +510,20 @@ Video Disk Recorder Revision History
- Increased timeout until reporting "broken video data stream" when recording.
- Modified method of turning off PIDs when switching channel.
- Increased amount of non-useful data received by cRemux before assuming the
recording will fail.
- If there are two audio PIDs defined for a channel, both audio tracks will
now be recorded and can be selectively replayed later. See the FORMATS file
for details on how these different audio tracks are stored in the recorded
files. In order for this to work properly you need to make sure that the
StartHWFilter() function in the driver's 'dvb.c' has
u16 mode=0x0320;
instead of the default
u16 mode=0x0820;
This will create packets for the second audio track that are small enough
to multiplex smoothly with the video data.

2
MANUAL
View File

@ -122,6 +122,8 @@ Video Disk Recorder User's Manual
to toggle between these. There can be two different audio PIDs per channel,
assuming that typically a channel broadcasts a country specific language
plus the movie's original soundtrack.
Recordings made form such channels will contain both audio tracks, and when
replaying the desired audio track can be selected the same way.
* Switching through channel groups

121
dvbapi.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbapi.c 1.72 2001/06/14 08:19:43 kls Exp $
* $Id: dvbapi.c 1.73 2001/06/14 15:10:16 kls Exp $
*/
#include "dvbapi.h"
@ -451,14 +451,14 @@ protected:
virtual void Input(void);
virtual void Output(void);
public:
cRecordBuffer(cDvbApi *DvbApi, const char *FileName, dvb_pid_t VPid, dvb_pid_t APid);
cRecordBuffer(cDvbApi *DvbApi, const char *FileName, dvb_pid_t VPid, dvb_pid_t APid1, dvb_pid_t APid2);
virtual ~cRecordBuffer();
};
cRecordBuffer::cRecordBuffer(cDvbApi *DvbApi, const char *FileName, dvb_pid_t VPid, dvb_pid_t APid)
cRecordBuffer::cRecordBuffer(cDvbApi *DvbApi, const char *FileName, dvb_pid_t VPid, dvb_pid_t APid1, dvb_pid_t APid2)
:cRingBuffer(VIDEOBUFSIZE, true)
,fileName(FileName, true)
,remux(VPid, APid, true)
,remux(VPid, APid1, APid2, true)
{
dvbApi = DvbApi;
index = NULL;
@ -608,12 +608,14 @@ private:
bool eof;
int blockInput, blockOutput;
bool paused, fastForward, fastRewind;
int lastIndex, stillIndex;
int lastIndex, stillIndex, playIndex;
bool canToggleAudioTrack;
uchar audioTrack;
bool NextFile(uchar FileNumber = 0, int FileOffset = -1);
void Clear(bool Block = false);
void Close(void);
int ReadFrame(uchar *b, int Length, int Max);
void StripAudioPackets(uchar *b, int Length);
void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00);
void DisplayFrame(uchar *b, int Length);
int Resume(void);
bool Save(void);
@ -631,6 +633,8 @@ public:
void SkipSeconds(int Seconds);
void Goto(int Position, bool Still = false);
void GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
bool CanToggleAudioTrack(void) { return canToggleAudioTrack; }
void ToggleAudioTrack(void);
};
cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const char *FileName)
@ -646,7 +650,9 @@ cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const
eof = false;
blockInput = blockOutput = false;
paused = fastForward = fastRewind = false;
lastIndex = stillIndex = -1;
lastIndex = stillIndex = playIndex = -1;
canToggleAudioTrack = false;
audioTrack = 0xC0;
if (!fileName.Name())
return;
// Create the index file:
@ -701,12 +707,19 @@ void cReplayBuffer::Input(void)
continue;
}
lastIndex = Index;
playIndex = -1;
r = ReadFrame(b, Length, sizeof(b));
StripAudioPackets(b, Length);
StripAudioPackets(b, r);
}
else {
lastIndex = -1;
r = read(replayFile, b, sizeof(b));
playIndex = (playIndex >= 0) ? playIndex + 1 : index->Get(fileName.Number(), fileOffset);
uchar FileNumber;
int FileOffset, Length;
if (!(index->Get(playIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset)))
break;
r = ReadFrame(b, Length, sizeof(b));
StripAudioPackets(b, r, audioTrack);
}
if (r > 0) {
uchar *p = b;
@ -778,13 +791,16 @@ int cReplayBuffer::ReadFrame(uchar *b, int Length, int Max)
return -1;
}
void cReplayBuffer::StripAudioPackets(uchar *b, int Length)
void cReplayBuffer::StripAudioPackets(uchar *b, int Length, uchar Except)
{
for (int i = 0; i < Length - 6; i++) {
if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) {
switch (b[i + 3]) {
uchar c = b[i + 3];
switch (c) {
case 0xC0 ... 0xDF: // audio
{
if (c == 0xC1)
canToggleAudioTrack = true;
if (!Except || c != Except) {
int n = b[i + 4] * 256 + b[i + 5];
for (int j = i; j < Length && n--; j++)
b[j] = 0x00;
@ -816,6 +832,7 @@ void cReplayBuffer::Clear(bool Block)
usleep(1);
Lock();
cRingBuffer::Clear();
playIndex = -1;
CHECK(ioctl(videoDev, VIDEO_FREEZE));
CHECK(ioctl(videoDev, VIDEO_CLEAR_BUFFER));
CHECK(ioctl(audioDev, AUDIO_CLEAR_BUFFER));
@ -969,6 +986,7 @@ void cReplayBuffer::Goto(int Index, bool Still)
Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length);
if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) {
stillIndex = Index;
playIndex = -1;
uchar b[MAXFRAMESIZE];
int r = ReadFrame(b, Length, sizeof(b));
if (r > 0)
@ -977,7 +995,7 @@ void cReplayBuffer::Goto(int Index, bool Still)
paused = true;
}
else
stillIndex = -1;
stillIndex = playIndex = -1;
Clear(false);
}
}
@ -1015,6 +1033,14 @@ bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset)
return replayFile >= 0;
}
void cReplayBuffer::ToggleAudioTrack(void)
{
if (CanToggleAudioTrack()) {
audioTrack = (audioTrack == 0xC0) ? 0xC1 : 0xC0;
Clear();
}
}
// --- cTransferBuffer -------------------------------------------------------
class cTransferBuffer : public cRingBuffer {
@ -1336,7 +1362,8 @@ cDvbApi::cDvbApi(int n)
// Devices that all DVB cards must have:
fd_demuxv = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true);
fd_demuxa = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true);
fd_demuxa1 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true);
fd_demuxa2 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true);
fd_demuxt = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true);
// Devices not present on "budget" cards:
@ -1355,7 +1382,7 @@ cDvbApi::cDvbApi(int n)
// We only check the devices that must be present - the others will be checked before accessing them:
if (((fd_qpskfe >= 0 && fd_sec >= 0) || fd_qamfe >= 0) && fd_demuxv >= 0 && fd_demuxa >= 0 && fd_demuxt >= 0) {
if (((fd_qpskfe >= 0 && fd_sec >= 0) || fd_qamfe >= 0) && fd_demuxv >= 0 && fd_demuxa1 >= 0 && fd_demuxa2 >= 0 && fd_demuxt >= 0) {
siProcessor = new cSIProcessor(OstName(DEV_OST_DEMUX, n));
if (!dvbApi[0]) // only the first one shall set the system time
siProcessor->SetUseTSTime(Setup.SetSystemTime);
@ -2026,7 +2053,8 @@ bool cDvbApi::SetPid(int fd, dmxPesType_t PesType, dvb_pid_t Pid, dmxOutput_t Ou
bool cDvbApi::SetPids(bool ForRecording)
{
return SetVpid(vPid, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) &&
SetApid(aPid1, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER);
SetApid1(aPid1, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) &&
SetApid2(ForRecording ? aPid2 : 0, DMX_OUT_TS_TAP);
}
bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Tpid, int Ca, int Pnr)
@ -2048,9 +2076,10 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
// Turn off current PIDs:
SetVpid(0, DMX_OUT_DECODER);
SetApid(0, DMX_OUT_DECODER);
SetTpid(0, DMX_OUT_DECODER);
SetVpid( 0, DMX_OUT_DECODER);
SetApid1(0, DMX_OUT_DECODER);
SetApid2(0, DMX_OUT_DECODER);
SetTpid( 0, DMX_OUT_DECODER);
bool ChannelSynced = false;
@ -2110,7 +2139,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
esyslog(LOG_ERR, "ERROR %d in qpsk get event", res);
}
else
fprintf(stderr, "ERROR: timeout while tuning\n");
esyslog(LOG_ERR, "ERROR: timeout while tuning\n");
}
else if (fd_qamfe >= 0) { // DVB-C
@ -2137,7 +2166,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
esyslog(LOG_ERR, "ERROR %d in qam get event", res);
}
else
fprintf(stderr, "ERROR: timeout while tuning\n");
esyslog(LOG_ERR, "ERROR: timeout while tuning\n");
}
else {
esyslog(LOG_ERR, "ERROR: attempt to set channel without DVB-S or DVB-C device");
@ -2187,28 +2216,6 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
return true;
}
bool cDvbApi::CanToggleAudioPid(void)
{
return aPid1 && aPid2 && aPid1 != aPid2;
}
bool cDvbApi::ToggleAudioPid(void)
{
if (CanToggleAudioPid()) {
int a = aPid2;
aPid2 = aPid1;
aPid1 = a;
if (transferringFromDvbApi)
return transferringFromDvbApi->ToggleAudioPid();
else {
if (transferBuffer)
transferBuffer->SetAudioPid(aPid1);
return SetPids(transferBuffer != NULL);
}
}
return false;
}
bool cDvbApi::Transferring(void)
{
return transferBuffer;
@ -2278,7 +2285,7 @@ bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority)
// Create recording buffer:
recordBuffer = new cRecordBuffer(this, FileName, vPid, aPid1);
recordBuffer = new cRecordBuffer(this, FileName, vPid, aPid1, aPid2);
if (recordBuffer) {
ca = Ca;
@ -2390,6 +2397,32 @@ void cDvbApi::Goto(int Position, bool Still)
replayBuffer->Goto(Position, Still);
}
bool cDvbApi::CanToggleAudioTrack(void)
{
return replayBuffer ? replayBuffer->CanToggleAudioTrack() : (aPid1 && aPid2 && aPid1 != aPid2);
}
bool cDvbApi::ToggleAudioTrack(void)
{
if (replayBuffer) {
replayBuffer->ToggleAudioTrack();
return true;
}
else {
int a = aPid2;
aPid2 = aPid1;
aPid1 = a;
if (transferringFromDvbApi)
return transferringFromDvbApi->ToggleAudioTrack();
else {
if (transferBuffer)
transferBuffer->SetAudioPid(aPid1);
return SetPids(transferBuffer != NULL);
}
}
return false;
}
// --- cEITScanner -----------------------------------------------------------
cEITScanner::cEITScanner(void)

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbapi.h 1.37 2001/06/03 11:51:30 kls Exp $
* $Id: dvbapi.h 1.38 2001/06/14 14:54:25 kls Exp $
*/
#ifndef __DVBAPI_H
@ -66,11 +66,12 @@ class cDvbApi {
friend class cTransferBuffer;
private:
int videoDev;
int fd_osd, fd_qpskfe, fd_qamfe, fd_sec, fd_dvr, fd_audio, fd_video, fd_demuxa, fd_demuxv, fd_demuxt;
int fd_osd, fd_qpskfe, fd_qamfe, fd_sec, fd_dvr, fd_audio, fd_video, fd_demuxa1, fd_demuxa2, fd_demuxv, fd_demuxt;
int vPid, aPid1, aPid2;
bool SetPid(int fd, dmxPesType_t PesType, dvb_pid_t Pid, dmxOutput_t Output);
bool SetVpid(int Vpid, dmxOutput_t Output) { return SetPid(fd_demuxv, DMX_PES_VIDEO, Vpid, Output); }
bool SetApid(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa, DMX_PES_AUDIO, Apid, Output); }
bool SetApid1(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa1, DMX_PES_AUDIO, Apid, Output); }
bool SetApid2(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa2, DMX_PES_OTHER, Apid, Output); }
bool SetTpid(int Tpid, dmxOutput_t Output) { return SetPid(fd_demuxt, DMX_PES_TELETEXT, Tpid, Output); }
bool SetPids(bool ForRecording);
cDvbApi(int n);
@ -180,8 +181,6 @@ public:
bool SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Tpid, int Ca, int Pnr);
static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; }
int Channel(void) { return currentChannel; }
bool CanToggleAudioPid(void);
bool ToggleAudioPid(void);
// Transfer facilities
@ -262,6 +261,14 @@ public:
void Goto(int Index, bool Still = false);
// Positions to the given index and displays that frame as a still picture
// if Still is true.
// Audio track facilities
bool CanToggleAudioTrack(void);
// Returns true if we are currently replaying and this recording has two
// audio tracks, or if the current channel has two audio PIDs.
bool ToggleAudioTrack(void);
// Toggles the audio track if possible.
};
class cEITScanner {

8
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.c 1.72 2001/06/02 13:51:28 kls Exp $
* $Id: menu.c 1.73 2001/06/14 14:55:16 kls Exp $
*/
#include "menu.h"
@ -1726,7 +1726,7 @@ cMenuMain::cMenuMain(bool Replaying)
}
if (cVideoCutter::Active())
Add(new cOsdItem(tr(" Cancel editing"), osCancelEdit));
SetHelp(tr("Record"), cDvbApi::PrimaryDvbApi->CanToggleAudioPid() ? tr("Language") : NULL, NULL, cReplayControl::LastReplayed() ? tr("Resume") : NULL);
SetHelp(tr("Record"), cDvbApi::PrimaryDvbApi->CanToggleAudioTrack() ? tr("Language") : NULL, NULL, cReplayControl::LastReplayed() ? tr("Resume") : NULL);
Display();
lastActivity = time(NULL);
SetHasHotkeys();
@ -1761,9 +1761,9 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
case kRed: if (!HasSubMenu())
state = osRecord;
break;
case kGreen: if (cDvbApi::PrimaryDvbApi->CanToggleAudioPid()) {
case kGreen: if (cDvbApi::PrimaryDvbApi->CanToggleAudioTrack()) {
Interface->Clear();
cDvbApi::PrimaryDvbApi->ToggleAudioPid();
cDvbApi::PrimaryDvbApi->ToggleAudioTrack();
state = osEnd;
}
break;

47
remux.c
View File

@ -8,7 +8,7 @@
* the Linux DVB driver's 'tuxplayer' example and were rewritten to suit
* VDR's needs.
*
* $Id: remux.c 1.3 2001/06/02 15:39:16 kls Exp $
* $Id: remux.c 1.4 2001/06/14 15:30:09 kls Exp $
*/
/* The calling interface of the 'cRemux::Process()' function is defined
@ -107,6 +107,11 @@
#define IPACKS 2048
// Start codes:
#define SC_PICTURE 0x00 // "picture header"
#define MAXNONUSEFULDATA (10*1024*1024)
class cTS2PES {
private:
int size;
@ -114,6 +119,7 @@ private:
int count;
uint8_t *buf;
uint8_t cid;
uint8_t audioCid;
int plength;
uint8_t plen[2];
uint8_t flag1;
@ -132,7 +138,7 @@ private:
void write_ipack(const uint8_t *Data, int Count);
void instant_repack(const uint8_t *Buf, int Count);
public:
cTS2PES(uint8_t *ResultBuffer, int *ResultCount, int Size);
cTS2PES(uint8_t *ResultBuffer, int *ResultCount, int Size, uint8_t AudioCid = 0x00);
~cTS2PES();
void ts_to_pes(const uint8_t *Buf); // don't need count (=188)
void Clear(void);
@ -140,11 +146,12 @@ public:
uint8_t cTS2PES::headr[] = { 0x00, 0x00, 0x01 };
cTS2PES::cTS2PES(uint8_t *ResultBuffer, int *ResultCount, int Size)
cTS2PES::cTS2PES(uint8_t *ResultBuffer, int *ResultCount, int Size, uint8_t AudioCid)
{
resultBuffer = ResultBuffer;
resultCount = ResultCount;
size = Size;
audioCid = AudioCid;
if (!(buf = new uint8_t[size]))
esyslog(LOG_ERR, "Not enough memory for ts_transform");
@ -164,7 +171,10 @@ void cTS2PES::Clear(void)
void cTS2PES::store(uint8_t *Data, int Count)
{
//XXX overflow check???
if (*resultCount + Count > RESULTBUFFERSIZE) {
esyslog(LOG_ERR, "ERROR: result buffer overflow (%d + %d > %d)", *resultCount, Count, RESULTBUFFERSIZE);
Count = RESULTBUFFERSIZE - *resultCount;
}
memcpy(resultBuffer + *resultCount, Data, Count);
*resultCount += Count;
}
@ -188,7 +198,7 @@ void cTS2PES::send_ipack(void)
{
if (count < 10)
return;
buf[3] = cid;
buf[3] = (AUDIO_STREAM_S <= cid && cid <= AUDIO_STREAM_E && audioCid) ? audioCid : cid;
buf[4] = (uint8_t)(((count - 6) & 0xFF00) >> 8);
buf[5] = (uint8_t)((count - 6) & 0x00FF);
store(buf, count);
@ -409,22 +419,25 @@ void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188)
// --- cRemux ----------------------------------------------------------------
cRemux::cRemux(dvb_pid_t VPid, dvb_pid_t APid, bool ExitOnFailure)
cRemux::cRemux(dvb_pid_t VPid, dvb_pid_t APid1, dvb_pid_t APid2, bool ExitOnFailure)
{
vPid = VPid;
aPid = APid;
aPid1 = APid1;
aPid2 = APid2;
exitOnFailure = ExitOnFailure;
synced = false;
skipped = 0;
resultCount = resultDelivered = 0;
vTS2PES = new cTS2PES(resultBuffer, &resultCount, IPACKS);
aTS2PES = new cTS2PES(resultBuffer, &resultCount, IPACKS);
aTS2PES1 = new cTS2PES(resultBuffer, &resultCount, IPACKS, 0xC0);
aTS2PES2 = aPid2 ? new cTS2PES(resultBuffer, &resultCount, IPACKS, 0xC1) : NULL;
}
cRemux::~cRemux()
{
delete vTS2PES;
delete aTS2PES;
delete aTS2PES1;
delete aTS2PES2;
}
int cRemux::GetPid(const uchar *Data)
@ -463,9 +476,9 @@ int cRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &Pic
void cRemux::SetAudioPid(int APid)
{
aPid = APid;
aPid1 = APid;
vTS2PES->Clear();
aTS2PES->Clear();
aTS2PES1->Clear();
resultCount = resultDelivered = 0;
}
@ -501,8 +514,10 @@ XXX*/
if (Data[i + 3] & 0x10) { // got payload
if (pid == vPid)
vTS2PES->ts_to_pes(Data + i);
else if (pid == aPid)
aTS2PES->ts_to_pes(Data + i);
else if (pid == aPid1)
aTS2PES1->ts_to_pes(Data + i);
else if (pid == aPid2 && aTS2PES2)
aTS2PES2->ts_to_pes(Data + i);
}
used += TS_SIZE;
if (resultCount > (int)sizeof(resultBuffer) / 2)
@ -520,7 +535,7 @@ XXX*/
// Check if we're getting anywhere here:
if (!synced && skipped >= 0) {
if (skipped > 1024*1024) {
if (skipped > MAXNONUSEFULDATA) {
esyslog(LOG_ERR, "ERROR: no useful data seen within %d byte of video stream", skipped);
skipped = -1;
if (exitOnFailure)
@ -538,7 +553,7 @@ XXX*/
for (int i = 0; i < resultCount; i++) {
if (resultBuffer[i] == 0 && resultBuffer[i + 1] == 0 && resultBuffer[i + 2] == 1) {
switch (resultBuffer[i + 3]) {
case SC_VIDEO:
case VIDEO_STREAM_S ... VIDEO_STREAM_E:
{
uchar pt = NO_PICTURE;
int l = ScanVideoPacket(resultBuffer, resultCount, i, pt);
@ -572,7 +587,7 @@ XXX*/
}
}
break;
case SC_AUDIO:
case AUDIO_STREAM_S ... AUDIO_STREAM_E:
{
int l = GetPacketLength(resultBuffer, resultCount, i);
if (l < 0)

21
remux.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: remux.h 1.3 2001/06/02 15:15:43 kls Exp $
* $Id: remux.h 1.4 2001/06/14 15:27:07 kls Exp $
*/
#ifndef __REMUX_H
@ -19,18 +19,11 @@
#define P_FRAME 2
#define B_FRAME 3
//XXX -> remux.c???
// Start codes:
#define SC_PICTURE 0x00 // "picture header"
#define SC_SEQU 0xB3 // "sequence header"
#define SC_PHEAD 0xBA // "pack header"
#define SC_SHEAD 0xBB // "system header"
#define SC_AUDIO 0xC0
#define SC_VIDEO 0xE0
// The minimum amount of video data necessary to identify frames:
#define MINVIDEODATA (16*1024) // just a safe guess (max. size of any frame block, plus some safety)
#define RESULTBUFFERSIZE (MINVIDEODATA * 4)
typedef unsigned char uchar;
class cTS2PES;
@ -39,16 +32,16 @@ private:
bool exitOnFailure;
bool synced;
int skipped;
dvb_pid_t vPid, aPid;
cTS2PES *vTS2PES, *aTS2PES;
uchar resultBuffer[MINVIDEODATA * 4];//XXX
dvb_pid_t vPid, aPid1, aPid2;
cTS2PES *vTS2PES, *aTS2PES1, *aTS2PES2;
uchar resultBuffer[RESULTBUFFERSIZE];
int resultCount;
int resultDelivered;
int GetPid(const uchar *Data);
int GetPacketLength(const uchar *Data, int Count, int Offset);
int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType);
public:
cRemux(dvb_pid_t VPid, dvb_pid_t APid, bool ExitOnFailure = false);
cRemux(dvb_pid_t VPid, dvb_pid_t APid1, dvb_pid_t APid2 = 0, bool ExitOnFailure = false);
~cRemux();
void SetAudioPid(int APid);
const uchar *Process(const uchar *Data, int &Count, int &Result, uchar *PictureType = NULL);