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:
parent
4b8968f7e1
commit
9de548ee59
9
FORMATS
9
FORMATS
@ -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
17
HISTORY
@ -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
2
MANUAL
@ -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
|
||||
|
||||
|
149
dvbapi.c
149
dvbapi.c
@ -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,17 +791,20 @@ 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
|
||||
{
|
||||
int n = b[i + 4] * 256 + b[i + 5];
|
||||
for (int j = i; j < Length && n--; j++)
|
||||
b[j] = 0x00;
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case 0xE0 ... 0xEF: // video
|
||||
i += b[i + 4] * 256 + b[i + 5];
|
||||
@ -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 {
|
||||
@ -1329,33 +1355,34 @@ cDvbApi::cDvbApi(int n)
|
||||
|
||||
// Devices that are only present on DVB-C or DVB-S cards:
|
||||
|
||||
fd_qamfe = OstOpen(DEV_OST_QAMFE, n, O_RDWR);
|
||||
fd_qpskfe = OstOpen(DEV_OST_QPSKFE, n, O_RDWR);
|
||||
fd_sec = OstOpen(DEV_OST_SEC, n, O_RDWR);
|
||||
fd_qamfe = OstOpen(DEV_OST_QAMFE, n, O_RDWR);
|
||||
fd_qpskfe = OstOpen(DEV_OST_QPSKFE, n, O_RDWR);
|
||||
fd_sec = OstOpen(DEV_OST_SEC, n, O_RDWR);
|
||||
|
||||
// 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_demuxt = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true);
|
||||
fd_demuxv = 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:
|
||||
|
||||
fd_osd = OstOpen(DEV_OST_OSD, n, O_RDWR);
|
||||
fd_video = OstOpen(DEV_OST_VIDEO, n, O_RDWR | O_NONBLOCK);
|
||||
fd_audio = OstOpen(DEV_OST_AUDIO, n, O_RDWR | O_NONBLOCK);
|
||||
fd_osd = OstOpen(DEV_OST_OSD, n, O_RDWR);
|
||||
fd_video = OstOpen(DEV_OST_VIDEO, n, O_RDWR | O_NONBLOCK);
|
||||
fd_audio = OstOpen(DEV_OST_AUDIO, n, O_RDWR | O_NONBLOCK);
|
||||
|
||||
// Devices that may not be available, and are not necessary for normal operation:
|
||||
|
||||
videoDev = OstOpen(DEV_VIDEO, n, O_RDWR);
|
||||
videoDev = OstOpen(DEV_VIDEO, n, O_RDWR);
|
||||
|
||||
// Devices that will be dynamically opened and closed when necessary:
|
||||
|
||||
fd_dvr = -1;
|
||||
fd_dvr = -1;
|
||||
|
||||
// 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)
|
||||
|
17
dvbapi.h
17
dvbapi.h
@ -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
8
menu.c
@ -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;
|
||||
|
49
remux.c
49
remux.c
@ -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);
|
||||
vTS2PES = 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
21
remux.h
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user