Snapshot 2010-09-15

This commit is contained in:
Frank Schmirler 2010-12-02 09:39:01 +01:00 committed by Mikko Matilainen
parent db3274c046
commit 635ccc479f
18 changed files with 257 additions and 56 deletions

View File

@ -132,6 +132,10 @@ Norman Thiel
vel_tins vel_tins
for reporting that externremux x264 uses value of ABR for VBR for reporting that externremux x264 uses value of ABR for VBR
for various suggestions to improve externremux.sh
Matthias Prill Matthias Prill
for reporting a compiler error with older libstdc++ versions for reporting a compiler error with older libstdc++ versions
Timothy D. Lenz
for reporting missing support for invisible channel groups in HTTP menu

23
HISTORY
View File

@ -1,6 +1,29 @@
VDR Plugin 'streamdev' Revision History VDR Plugin 'streamdev' Revision History
--------------------------------------- ---------------------------------------
- VTP no longer uses a static priority value for its server-side receivers.
The server stores channel and priority requested with the PROV command and
re-uses these values in a subsequent TUNE for the same channel. The new
PRIO command is used to update the receiver's priority if necessary.
- added parameter HEIGHT to externremux.sh
- fixed syslog messages reporting local instead of remote IP and port
- log an error if externremux.sh is missing or not executable
- added dsyslog messages to help troubleshouting channel switch issues
- VTP command SUSP didn't attach the player to the primary device
- replacing a connections receiver is now an atomic operation. Solves
stuttering audio/video due to lost TS packets when adding/removing PIDs
- fixed missing support for invisible channel groups (groups without name)
in HTTP menu (reported by Timothy D. Lenz)
- don't quote actual program call in externremux.sh, so you can run th
program through e.g. nice or taskset just by extending the variable
which holds the program name
- in externremux.sh each mencoder audio and video codec has a dedicated
variable for a default option string now. Still you can override each
default option with an URL parameter
- externremux.sh mencoder now uses scale parameter with negative height
instead of -xy for scaling (suggested by vel_tins@vdrportal)
- added FPS (frames per second) parameter to externremux.sh (suggested by
vel_tins@vdrportal)
- don't use std::map.at(). It's not available in older libstdc++ version - don't use std::map.at(). It's not available in older libstdc++ version
(reported by Matthias Prill) (reported by Matthias Prill)
- fixed extremux x264 using value of ABR for VBR (thanks to vel_tins@vdrportal) - fixed extremux x264 using value of ABR for VBR (thanks to vel_tins@vdrportal)

View File

@ -1,5 +1,5 @@
/* /*
* $Id: device.c,v 1.18.2.3 2010/06/08 05:56:15 schmirl Exp $ * $Id: device.c,v 1.18.2.4 2010/08/18 10:26:18 schmirl Exp $
*/ */
#include "client/device.h" #include "client/device.h"
@ -8,6 +8,7 @@
#include "tools/select.h" #include "tools/select.h"
#include <vdr/config.h>
#include <vdr/channels.h> #include <vdr/channels.h>
#include <vdr/ringbuffer.h> #include <vdr/ringbuffer.h>
#include <vdr/eit.h> #include <vdr/eit.h>
@ -32,6 +33,7 @@ cStreamdevDevice::cStreamdevDevice(void) {
m_Device = this; m_Device = this;
m_Pids = 0; m_Pids = 0;
m_Priority = -1;
m_DvrClosed = true; m_DvrClosed = true;
} }
@ -119,6 +121,9 @@ bool cStreamdevDevice::SetChannelDevice(const cChannel *Channel,
bool LiveView) { bool LiveView) {
Dprintf("SetChannelDevice Channel: %s, LiveView: %s\n", Channel->Name(), Dprintf("SetChannelDevice Channel: %s, LiveView: %s\n", Channel->Name(),
LiveView ? "true" : "false"); LiveView ? "true" : "false");
LOCK_THREAD;
m_UpdatePriority = ClientSocket.SupportsPrio();
if (LiveView) if (LiveView)
return false; return false;
@ -139,6 +144,8 @@ bool cStreamdevDevice::SetPid(cPidHandle *Handle, int Type, bool On) {
Handle->used); Handle->used);
LOCK_THREAD; LOCK_THREAD;
m_UpdatePriority = ClientSocket.SupportsPrio();
if (On && !m_TSBuffer) { if (On && !m_TSBuffer) {
Dprintf("SetPid: no data connection -> OpenDvr()"); Dprintf("SetPid: no data connection -> OpenDvr()");
OpenDvrInt(); OpenDvrInt();
@ -305,3 +312,16 @@ bool cStreamdevDevice::ReInit(void) {
return StreamdevClientSetup.StartClient ? Init() : true; return StreamdevClientSetup.StartClient ? Init() : true;
} }
void cStreamdevDevice::UpdatePriority(void) {
if (m_Device) {
m_Device->Lock();
if (m_Device->m_UpdatePriority && ClientSocket.DataSocket(siLive)) {
int Priority = m_Device->Priority();
if (m_Device == cDevice::ActualDevice() && Priority < Setup.PrimaryLimit)
Priority = Setup.PrimaryLimit;
if (m_Device->m_Priority != Priority && ClientSocket.SetPriority(Priority))
m_Device->m_Priority = Priority;
}
m_Device->Unlock();
}
}

View File

@ -1,5 +1,5 @@
/* /*
* $Id: device.h,v 1.7.2.1 2008/04/07 15:07:39 schmirl Exp $ * $Id: device.h,v 1.7.2.2 2010/08/18 10:26:18 schmirl Exp $
*/ */
#ifndef VDR_STREAMDEV_DEVICE_H #ifndef VDR_STREAMDEV_DEVICE_H
@ -15,13 +15,14 @@ class cTBString;
#define CMD_LOCK_OBJ(x) cMutexLock CmdLock((cMutex*)&(x)->m_Mutex) #define CMD_LOCK_OBJ(x) cMutexLock CmdLock((cMutex*)&(x)->m_Mutex)
class cStreamdevDevice: public cDevice { class cStreamdevDevice: public cDevice {
friend class cRemoteRecordings;
private: private:
const cChannel *m_Channel; const cChannel *m_Channel;
cTSBuffer *m_TSBuffer; cTSBuffer *m_TSBuffer;
cStreamdevFilters *m_Filters; cStreamdevFilters *m_Filters;
int m_Pids; int m_Pids;
int m_Priority;
bool m_UpdatePriority;
bool m_DvrClosed; bool m_DvrClosed;
static cStreamdevDevice *m_Device; static cStreamdevDevice *m_Device;
@ -56,6 +57,7 @@ public:
bool *NeedsDetachReceivers = NULL) const; bool *NeedsDetachReceivers = NULL) const;
virtual bool IsTunedToTransponder(const cChannel *Channel); virtual bool IsTunedToTransponder(const cChannel *Channel);
static void UpdatePriority(void);
static bool Init(void); static bool Init(void);
static bool ReInit(void); static bool ReInit(void);

View File

@ -1,5 +1,5 @@
/* /*
* $Id: socket.c,v 1.11.2.1 2010/06/08 05:56:15 schmirl Exp $ * $Id: socket.c,v 1.11.2.3 2010/08/18 10:26:18 schmirl Exp $
*/ */
#include <tools/select.h> #include <tools/select.h>
@ -21,6 +21,7 @@ cClientSocket ClientSocket;
cClientSocket::cClientSocket(void) cClientSocket::cClientSocket(void)
{ {
memset(m_DataSockets, 0, sizeof(cTBSocket*) * si_Count); memset(m_DataSockets, 0, sizeof(cTBSocket*) * si_Count);
m_Prio = false;
Reset(); Reset();
} }
@ -143,8 +144,14 @@ bool cClientSocket::CheckConnection(void) {
if(Command("CAPS FILTERS", 220)) if(Command("CAPS FILTERS", 220))
Filters = ",FILTERS"; Filters = ",FILTERS";
isyslog("Streamdev: Connected to server %s:%d using capabilities TSPIDS%s", const char *Prio = "";
RemoteIp().c_str(), RemotePort(), Filters); if(Command("CAPS PRIO", 220)) {
Prio = ",PRIO";
m_Prio = true;
}
isyslog("Streamdev: Connected to server %s:%d using capabilities TSPIDS%s%s",
RemoteIp().c_str(), RemotePort(), Filters, Prio);
return true; return true;
} }
@ -252,6 +259,21 @@ bool cClientSocket::SetChannelDevice(const cChannel *Channel) {
return true; return true;
} }
bool cClientSocket::SetPriority(int Priority) {
if (!CheckConnection()) return false;
CMD_LOCK;
std::string command = (std::string)"PRIO " + (const char*)itoa(Priority);
if (!Command(command, 220)) {
if (errno == 0)
esyslog("Streamdev: Failed to update priority on %s:%d", RemoteIp().c_str(),
RemotePort());
return false;
}
return true;
}
bool cClientSocket::SetPid(int Pid, bool On) { bool cClientSocket::SetPid(int Pid, bool On) {
if (!CheckConnection()) return false; if (!CheckConnection()) return false;
@ -260,8 +282,8 @@ bool cClientSocket::SetPid(int Pid, bool On) {
std::string command = (std::string)(On ? "ADDP " : "DELP ") + (const char*)itoa(Pid); std::string command = (std::string)(On ? "ADDP " : "DELP ") + (const char*)itoa(Pid);
if (!Command(command, 220)) { if (!Command(command, 220)) {
if (errno == 0) if (errno == 0)
esyslog("Streamdev: Pid %d not available from %s:%d", Pid, LocalIp().c_str(), esyslog("Streamdev: Pid %d not available from %s:%d", Pid, RemoteIp().c_str(),
LocalPort()); RemotePort());
return false; return false;
} }
return true; return true;
@ -277,7 +299,7 @@ bool cClientSocket::SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On) {
if (!Command(command, 220)) { if (!Command(command, 220)) {
if (errno == 0) if (errno == 0)
esyslog("Streamdev: Filter %hu, %hhu, %hhu not available from %s:%d", esyslog("Streamdev: Filter %hu, %hhu, %hhu not available from %s:%d",
Pid, Tid, Mask, LocalIp().c_str(), LocalPort()); Pid, Tid, Mask, RemoteIp().c_str(), RemotePort());
return false; return false;
} }
return true; return true;

View File

@ -1,5 +1,5 @@
/* /*
* $Id: socket.h,v 1.6.2.1 2010/06/08 05:56:15 schmirl Exp $ * $Id: socket.h,v 1.6.2.2 2010/08/18 10:26:18 schmirl Exp $
*/ */
#ifndef VDR_STREAMDEV_CLIENT_CONNECTION_H #ifndef VDR_STREAMDEV_CLIENT_CONNECTION_H
@ -20,6 +20,7 @@ private:
cTBSocket *m_DataSockets[si_Count]; cTBSocket *m_DataSockets[si_Count];
cMutex m_Mutex; cMutex m_Mutex;
char m_Buffer[BUFSIZ + 1]; // various uses char m_Buffer[BUFSIZ + 1]; // various uses
bool m_Prio; // server supports command PRIO
protected: protected:
/* Send Command, and return true if the command results in Expected. /* Send Command, and return true if the command results in Expected.
@ -45,6 +46,8 @@ public:
bool CreateDataConnection(eSocketId Id); bool CreateDataConnection(eSocketId Id);
bool CloseDataConnection(eSocketId Id); bool CloseDataConnection(eSocketId Id);
bool SetChannelDevice(const cChannel *Channel); bool SetChannelDevice(const cChannel *Channel);
bool SupportsPrio() { return m_Prio; }
bool SetPriority(int Priority);
bool SetPid(int Pid, bool On); bool SetPid(int Pid, bool On);
bool SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On); bool SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On);
bool CloseDvr(void); bool CloseDvr(void);

2
i18n.h
View File

@ -1,5 +1,5 @@
/* /*
* $Id: i18n.h,v 1.1 2004/12/30 22:43:58 lordjaxom Exp $ * $Id: i18n.h,v 1.1.1.1 2004/12/30 22:43:58 lordjaxom Exp $
*/ */
#ifndef VDR_STREAMDEV_I18N_H #ifndef VDR_STREAMDEV_I18N_H

View File

@ -191,6 +191,11 @@ cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, const cServerConnection *Connect
if (setpgid(0, 0) == -1) if (setpgid(0, 0) == -1)
esyslog("streamdev-server: externremux setpgid failed: %m"); esyslog("streamdev-server: externremux setpgid failed: %m");
if (access(opt_remux, X_OK) == -1) {
esyslog("streamdev-server %s: %m", opt_remux);
_exit(-1);
}
if (execle("/bin/sh", "sh", "-c", opt_remux, NULL, env) == -1) { if (execle("/bin/sh", "sh", "-c", opt_remux, NULL, env) == -1) {
esyslog("streamdev-server: externremux script '%s' execution failed: %m", opt_remux); esyslog("streamdev-server: externremux script '%s' execution failed: %m", opt_remux);
_exit(-1); _exit(-1);

View File

@ -1,5 +1,5 @@
/* /*
* $Id: connection.c,v 1.10.2.3 2010/07/19 13:50:14 schmirl Exp $ * $Id: connection.c,v 1.10.2.4 2010/08/03 10:56:58 schmirl Exp $
*/ */
#include "server/connection.h" #include "server/connection.h"
@ -254,12 +254,16 @@ cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority)
} }
Dprintf(" * Found device for live tv: %p (%d)\n", newdev, Dprintf(" * Found device for live tv: %p (%d)\n", newdev,
newdev ? newdev->CardIndex() + 1 : 0); newdev ? newdev->CardIndex() + 1 : 0);
if (newdev == NULL || newdev == device) if (newdev == NULL || newdev == device) {
// no suitable device to continue live TV, giving up... // no suitable device to continue live TV, giving up...
device = NULL; device = NULL;
dsyslog("streamdev: Not providing channel %s at priority %d - live TV not suspended", Channel->Name(), Priority);
}
else else
newdev->SwitchChannel(current, true); newdev->SwitchChannel(current, true);
} }
else if (!device)
dsyslog("streamdev: No device provides channel %s at priority %d", Channel->Name(), Priority);
} }
return device; return device;

View File

@ -1,5 +1,5 @@
/* /*
* $Id: connectionVTP.c,v 1.18.2.7 2010/07/19 13:50:14 schmirl Exp $ * $Id: connectionVTP.c,v 1.18.2.9 2010/08/18 10:26:19 schmirl Exp $
*/ */
#include "server/connectionVTP.h" #include "server/connectionVTP.h"
@ -726,6 +726,8 @@ cConnectionVTP::cConnectionVTP(void):
m_StreamType(stTSPIDS), m_StreamType(stTSPIDS),
m_FiltersSupport(false), m_FiltersSupport(false),
m_RecPlayer(NULL), m_RecPlayer(NULL),
m_TuneChannel(NULL),
m_TunePriority(0),
m_LSTEHandler(NULL), m_LSTEHandler(NULL),
m_LSTCHandler(NULL), m_LSTCHandler(NULL),
m_LSTTHandler(NULL), m_LSTTHandler(NULL),
@ -816,6 +818,7 @@ bool cConnectionVTP::Command(char *Cmd)
else if (strcasecmp(Cmd, "READ") == 0) return CmdREAD(param); else if (strcasecmp(Cmd, "READ") == 0) return CmdREAD(param);
else if (strcasecmp(Cmd, "TUNE") == 0) return CmdTUNE(param); else if (strcasecmp(Cmd, "TUNE") == 0) return CmdTUNE(param);
else if (strcasecmp(Cmd, "PLAY") == 0) return CmdPLAY(param); else if (strcasecmp(Cmd, "PLAY") == 0) return CmdPLAY(param);
else if (strcasecmp(Cmd, "PRIO") == 0) return CmdPRIO(param);
else if (strcasecmp(Cmd, "ADDP") == 0) return CmdADDP(param); else if (strcasecmp(Cmd, "ADDP") == 0) return CmdADDP(param);
else if (strcasecmp(Cmd, "DELP") == 0) return CmdDELP(param); else if (strcasecmp(Cmd, "DELP") == 0) return CmdDELP(param);
else if (strcasecmp(Cmd, "ADDF") == 0) return CmdADDF(param); else if (strcasecmp(Cmd, "ADDF") == 0) return CmdADDF(param);
@ -874,6 +877,11 @@ bool cConnectionVTP::CmdCAPS(char *Opts)
return Respond(220, "Capability \"%s\" accepted", Opts); return Respond(220, "Capability \"%s\" accepted", Opts);
} }
// Command PRIO is known
if (strcasecmp(Opts, "PRIO") == 0) {
return Respond(220, "Capability \"%s\" accepted", Opts);
}
return Respond(561, "Capability \"%s\" not known", Opts); return Respond(561, "Capability \"%s\" not known", Opts);
} }
@ -891,9 +899,15 @@ bool cConnectionVTP::CmdPROV(char *Opts)
if ((chan = ChannelFromString(Opts)) == NULL) if ((chan = ChannelFromString(Opts)) == NULL)
return Respond(550, "Undefined channel \"%s\"", Opts); return Respond(550, "Undefined channel \"%s\"", Opts);
return GetDevice(chan, prio) != NULL if (GetDevice(chan, prio)) {
? Respond(220, "Channel available") m_TuneChannel = chan;
: Respond(560, "Channel not available"); m_TunePriority = prio;
return Respond(220, "Channel available");
}
else {
m_TuneChannel = NULL;
return Respond(560, "Channel not available");
}
} }
bool cConnectionVTP::CmdPORT(char *Opts) bool cConnectionVTP::CmdPORT(char *Opts)
@ -1047,18 +1061,23 @@ bool cConnectionVTP::CmdTUNE(char *Opts)
{ {
const cChannel *chan; const cChannel *chan;
cDevice *dev; cDevice *dev;
int prio = m_TunePriority;
if ((chan = ChannelFromString(Opts)) == NULL) if ((chan = ChannelFromString(Opts)) == NULL)
return Respond(550, "Undefined channel \"%s\"", Opts); return Respond(550, "Undefined channel \"%s\"", Opts);
if ((dev = GetDevice(chan, 0)) == NULL) if (chan != m_TuneChannel) {
esyslog("streamdev-server TUNE %s: Priority unknown - using 0", Opts);
prio = 0;
}
if ((dev = GetDevice(chan, prio)) == NULL)
return Respond(560, "Channel not available"); return Respond(560, "Channel not available");
if (!dev->SwitchChannel(chan, false)) if (!dev->SwitchChannel(chan, false))
return Respond(560, "Channel not available"); return Respond(560, "Channel not available");
delete m_LiveStreamer; delete m_LiveStreamer;
m_LiveStreamer = new cStreamdevLiveStreamer(1, this); m_LiveStreamer = new cStreamdevLiveStreamer(prio, this);
m_LiveStreamer->SetChannel(chan, m_StreamType); m_LiveStreamer->SetChannel(chan, m_StreamType);
m_LiveStreamer->SetDevice(dev); m_LiveStreamer->SetDevice(dev);
if(m_LiveSocket) if(m_LiveSocket)
@ -1099,6 +1118,22 @@ bool cConnectionVTP::CmdPLAY(char *Opts)
} }
} }
bool cConnectionVTP::CmdPRIO(char *Opts)
{
int prio;
char *end;
prio = strtoul(Opts, &end, 10);
if (end == Opts || (*end != '\0' && *end != ' '))
return Respond(500, "Use: PRIO Priority");
if (m_LiveStreamer) {
m_LiveStreamer->SetPriority(prio);
return Respond(220, "Priority changed to %d", prio);
}
return Respond(550, "Priority not applicable");
}
bool cConnectionVTP::CmdADDP(char *Opts) bool cConnectionVTP::CmdADDP(char *Opts)
{ {
int pid; int pid;
@ -1223,6 +1258,7 @@ bool cConnectionVTP::CmdSUSP(void)
else if (StreamdevServerSetup.SuspendMode == smOffer else if (StreamdevServerSetup.SuspendMode == smOffer
&& StreamdevServerSetup.AllowSuspend) { && StreamdevServerSetup.AllowSuspend) {
cControl::Launch(new cSuspendCtl); cControl::Launch(new cSuspendCtl);
cControl::Attach();
return Respond(220, "Server is suspended"); return Respond(220, "Server is suspended");
} else } else
return Respond(550, "Client may not suspend server"); return Respond(550, "Client may not suspend server");

View File

@ -31,6 +31,11 @@ private:
bool m_FiltersSupport; bool m_FiltersSupport;
RecPlayer *m_RecPlayer; RecPlayer *m_RecPlayer;
// Priority is only known in PROV command
// Store in here for later use in TUNE call
const cChannel *m_TuneChannel;
int m_TunePriority;
// Members adopted for SVDRP // Members adopted for SVDRP
cLSTEHandler *m_LSTEHandler; cLSTEHandler *m_LSTEHandler;
cLSTCHandler *m_LSTCHandler; cLSTCHandler *m_LSTCHandler;
@ -59,6 +64,7 @@ public:
bool CmdREAD(char *Opts); bool CmdREAD(char *Opts);
bool CmdTUNE(char *Opts); bool CmdTUNE(char *Opts);
bool CmdPLAY(char *Opts); bool CmdPLAY(char *Opts);
bool CmdPRIO(char *Opts);
bool CmdADDP(char *Opts); bool CmdADDP(char *Opts);
bool CmdDELP(char *Opts); bool CmdDELP(char *Opts);
bool CmdADDF(char *Opts); bool CmdADDF(char *Opts);

View File

@ -297,7 +297,7 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
if (written != TS_SIZE) if (written != TS_SIZE)
siBuffer.ReportOverflow(TS_SIZE - written); siBuffer.ReportOverflow(TS_SIZE - written);
if (pmtPid != prevPmtPid) { if (pmtPid != prevPmtPid) {
m_Streamer->SetPids(pmtPid); m_Streamer->SetPid(pmtPid, true);
Add(pmtPid, 0x02); Add(pmtPid, 0x02);
pmtVersion = -1; pmtVersion = -1;
} }
@ -442,21 +442,28 @@ bool cStreamdevLiveStreamer::SetPids(int Pid, const int *Pids1, const int *Pids2
return true; return true;
} }
void cStreamdevLiveStreamer::SetPriority(int Priority)
{
m_Priority = Priority;
StartReceiver();
}
void cStreamdevLiveStreamer::StartReceiver(void) void cStreamdevLiveStreamer::StartReceiver(void)
{ {
DELETENULL(m_Receiver); if (m_Device != NULL && m_NumPids > 0 && IsRunning()) {
if (m_NumPids > 0) {
Dprintf("Creating Receiver to respect changed pids\n"); Dprintf("Creating Receiver to respect changed pids\n");
cReceiver *current = m_Receiver;
#if VDRVERSNUM < 10500 #if VDRVERSNUM < 10500
m_Receiver = new cStreamdevLiveReceiver(this, m_Channel->Ca(), m_Priority, m_Pids); m_Receiver = new cStreamdevLiveReceiver(this, m_Channel->Ca(), m_Priority, m_Pids);
#else #else
m_Receiver = new cStreamdevLiveReceiver(this, m_Channel->GetChannelID(), m_Priority, m_Pids); m_Receiver = new cStreamdevLiveReceiver(this, m_Channel->GetChannelID(), m_Priority, m_Pids);
#endif #endif
if (IsRunning() && m_Device != NULL) { cThreadLock ThreadLock(m_Device);
Dprintf("Attaching new receiver\n");
Attach(); Attach();
delete current;
} }
} else
DELETENULL(m_Receiver);
} }
bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType StreamType, const int* Apid, const int *Dpid) bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType StreamType, const int* Apid, const int *Dpid)

View File

@ -38,6 +38,7 @@ public:
bool SetPid(int Pid, bool On); bool SetPid(int Pid, bool On);
bool SetPids(int Pid, const int *Pids1 = NULL, const int *Pids2 = NULL, const int *Pids3 = NULL); bool SetPids(int Pid, const int *Pids1 = NULL, const int *Pids2 = NULL, const int *Pids3 = NULL);
bool SetChannel(const cChannel *Channel, eStreamType StreamType, const int* Apid = NULL, const int* Dpid = NULL); bool SetChannel(const cChannel *Channel, eStreamType StreamType, const int* Apid = NULL, const int* Dpid = NULL);
void SetPriority(int Priority);
virtual int Put(const uchar *Data, int Count); virtual int Put(const uchar *Data, int Count);
virtual uchar *Get(int &Count); virtual uchar *Get(int &Count);

View File

@ -2,7 +2,7 @@
#include "server/menuHTTP.h" #include "server/menuHTTP.h"
//**************************** cChannelIterator ************** //**************************** cChannelIterator **************
cChannelIterator::cChannelIterator(cChannel *First): channel(First) cChannelIterator::cChannelIterator(const cChannel *First): channel(First)
{} {}
const cChannel* cChannelIterator::Next() const cChannel* cChannelIterator::Next()
@ -19,7 +19,7 @@ cListAll::cListAll(): cChannelIterator(Channels.First())
const cChannel* cListAll::NextChannel(const cChannel *Channel) const cChannel* cListAll::NextChannel(const cChannel *Channel)
{ {
if (Channel) if (Channel)
Channel = Channels.Next(Channel); Channel = SkipFakeGroups(Channels.Next(Channel));
return Channel; return Channel;
} }
@ -46,14 +46,19 @@ const cChannel* cListGroups::NextChannel(const cChannel *Channel)
} }
// //
// ********************* cListGroup **************** // ********************* cListGroup ****************
cListGroup::cListGroup(const cChannel *Group): cChannelIterator((Group && Group->GroupSep() && Channels.Next(Group) && !Channels.Next(Group)->GroupSep()) ? Channels.Next(Group) : NULL) cListGroup::cListGroup(const cChannel *Group): cChannelIterator(GetNextChannelInGroup(Group))
{} {}
const cChannel* cListGroup::GetNextChannelInGroup(const cChannel *Channel)
{
if (Channel)
Channel = SkipFakeGroups(Channels.Next(Channel));
return Channel && !Channel->GroupSep() ? Channel : NULL;
}
const cChannel* cListGroup::NextChannel(const cChannel *Channel) const cChannel* cListGroup::NextChannel(const cChannel *Channel)
{ {
if (Channel) return GetNextChannelInGroup(Channel);
Channel = Channels.Next(Channel);
return (Channel && !Channel->GroupSep()) ? Channel : NULL;
} }
// //
// ********************* cListTree **************** // ********************* cListTree ****************
@ -68,7 +73,7 @@ const cChannel* cListTree::NextChannel(const cChannel *Channel)
if (currentGroup == selectedGroup) if (currentGroup == selectedGroup)
{ {
if (Channel) if (Channel)
Channel = Channels.Next(Channel); Channel = SkipFakeGroups(Channels.Next(Channel));
if (Channel && Channel->GroupSep()) if (Channel && Channel->GroupSep())
currentGroup = Channel; currentGroup = Channel;
} }

View File

@ -13,9 +13,10 @@ class cChannelIterator
const cChannel *channel; const cChannel *channel;
protected: protected:
virtual const cChannel* NextChannel(const cChannel *Channel) = 0; virtual const cChannel* NextChannel(const cChannel *Channel) = 0;
static inline const cChannel* SkipFakeGroups(const cChannel *Channel);
public: public:
const cChannel* Next(); const cChannel* Next();
cChannelIterator(cChannel *First); cChannelIterator(const cChannel *First);
virtual ~cChannelIterator() {}; virtual ~cChannelIterator() {};
}; };
@ -48,6 +49,8 @@ class cListGroups: public cChannelIterator
class cListGroup: public cChannelIterator class cListGroup: public cChannelIterator
{ {
private:
static const cChannel* GetNextChannelInGroup(const cChannel *Channel);
protected: protected:
virtual const cChannel* NextChannel(const cChannel *Channel); virtual const cChannel* NextChannel(const cChannel *Channel);
public: public:
@ -155,4 +158,11 @@ class cM3uChannelList: public cChannelList
virtual ~cM3uChannelList(); virtual ~cM3uChannelList();
}; };
inline const cChannel* cChannelIterator::SkipFakeGroups(const cChannel* Group)
{
while (Group && Group->GroupSep() && !*Group->Name())
Group = Channels.Next(Group);
return Group;
}
#endif #endif

View File

@ -3,7 +3,7 @@
* *
* See the README file for copyright information and how to reach the author. * See the README file for copyright information and how to reach the author.
* *
* $Id: streamdev-client.c,v 1.5.2.1 2010/06/08 05:56:14 schmirl Exp $ * $Id: streamdev-client.c,v 1.5.2.2 2010/08/18 10:26:18 schmirl Exp $
*/ */
#include "streamdev-client.h" #include "streamdev-client.h"
@ -56,4 +56,8 @@ bool cPluginStreamdevClient::SetupParse(const char *Name, const char *Value) {
return StreamdevClientSetup.SetupParse(Name, Value); return StreamdevClientSetup.SetupParse(Name, Value);
} }
void cPluginStreamdevClient::MainThreadHook(void) {
cStreamdevDevice::UpdatePriority();
}
VDRPLUGINCREATOR(cPluginStreamdevClient); // Don't touch this! VDRPLUGINCREATOR(cPluginStreamdevClient); // Don't touch this!

View File

@ -1,5 +1,5 @@
/* /*
* $Id: streamdev-client.h,v 1.1.1.1.2.1 2010/06/08 05:56:14 schmirl Exp $ * $Id: streamdev-client.h,v 1.1.1.1.2.2 2010/08/18 10:26:18 schmirl Exp $
*/ */
#ifndef VDR_STREAMDEVCLIENT_H #ifndef VDR_STREAMDEVCLIENT_H
@ -23,6 +23,7 @@ public:
virtual cOsdObject *MainMenuAction(void); virtual cOsdObject *MainMenuAction(void);
virtual cMenuSetupPage *SetupMenu(void); virtual cMenuSetupPage *SetupMenu(void);
virtual bool SetupParse(const char *Name, const char *Value); virtual bool SetupParse(const char *Name, const char *Value);
virtual void MainThreadHook(void);
}; };
#endif // VDR_STREAMDEVCLIENT_H #endif // VDR_STREAMDEVCLIENT_H

View File

@ -16,6 +16,8 @@
# VBR video bitrate (kbit) # VBR video bitrate (kbit)
# VOPTS custom video options # VOPTS custom video options
# WIDTH scale video to width # WIDTH scale video to width
# HEIGHT scale video to height
# FPS output frames per second
# AC audio codec # AC audio codec
# ABR audio bitrate (kbit) # ABR audio bitrate (kbit)
# AOPTS custom audio options # AOPTS custom audio options
@ -42,14 +44,22 @@ ABR_MONO=64
### ###
# mencoder binary # mencoder binary
MENCODER=mencoder MENCODER=mencoder
### video part
# Default video codec (e.g. lavc/x264/copy) # Default video codec (e.g. lavc/x264/copy)
MENCODER_VC=lavc MENCODER_VC=lavc
# Default video options if lavc is used (-ovc lavc -lavcopts ...)
MENCODER_LAVC_VOPTS=vcodec=mpeg4
# Default video options if x264 is used (-ovc x264 -x264encopts ...)
MENCODER_X264_VOPTS=threads=auto
### audio part
# Default audio codec (e.g. lavc/mp3lame/faac/copy) # Default audio codec (e.g. lavc/mp3lame/faac/copy)
MENCODER_AC=mp3lame MENCODER_AC=mp3lame
# Default video codec if lavc is used (-ovc lavc -lavcopts vcodec=) # Default audio options if lavc is used (-oac lavc -lavcopts ...)
MENCODER_LAVC_VC=mpeg4 MENCODER_LAVC_AOPTS=acodec=mp2
# Default audio codec if lavc is used (-oac lavc -lavcopts acodec=) # Default audio options if mp3lame is used (-oac mp3lame -lameopts ...)
MENCODER_LAVC_AC=mp2 MENCODER_LAME_AOPTS=
# Default audio options if faac is used (-oac faac -faacopts ...)
MENCODER_FAAC_AOPTS=
### ###
### MENCODER CONFIG END ### MENCODER CONFIG END
@ -63,6 +73,8 @@ OGG_SPEED=1
OGG_VQUALITY=0 OGG_VQUALITY=0
# audioquality - higher value gives better quality but is slower (0..10) # audioquality - higher value gives better quality but is slower (0..10)
OGG_AQUALITY=0 OGG_AQUALITY=0
# aspect ratio used for scaling if only one of HEIGHT/WIDTH given (16/9 or 4/3)
OGG_ASPECT='4 / 3'
### ###
### OGG CONFIG END ### OGG CONFIG END
@ -70,7 +82,19 @@ OGG_AQUALITY=0
function hasOpt { echo "$1" | grep -q "\b${2}\b"; } function hasOpt { echo "$1" | grep -q "\b${2}\b"; }
function isNumeric() { echo "$@" | grep -q '^[0-9]\{1,\}$'; } # $1: concatenation of already set option=value pairs
# $2-$n: option=value pairs to be echod if the option is not present in $1
function addOpts
{
local opts="$1"
shift
while [ $# -gt 0 ]; do
hasOpt "$opts" ${1%%=*}= || echo $1
shift
done
}
function isNumeric() { echo "$@" | grep -q '^-\?[0-9]\{1,\}$'; }
function remux_cat function remux_cat
{ {
@ -87,20 +111,31 @@ function remux_mencoder
# Assemble video options # Assemble video options
VC=${REMUX_PARAM_VC:-$MENCODER_VC} VC=${REMUX_PARAM_VC:-$MENCODER_VC}
VOPTS=${REMUX_PARAM_VOPTS} VOPTS=${REMUX_PARAM_VOPTS}
WIDTH=${REMUX_PARAM_WIDTH:-$WIDTH} FPS=${REMUX_PARAM_FPS:-$FPS}
# if only one of HEIGHT/WIDTH given:
# have mencoder calculate other value depending on actual aspect ratio
if [ "$HEIGHT" -a -z "$WIDTH" ]; then
WIDTH=-3
elif [ "$WIDTH" -a -z "$HEIGHT" ]; then
HEIGHT=-3
fi
case "$VC" in case "$VC" in
lavc) lavc)
LAVCOPTS=( LAVCOPTS=(
${VOPTS} ${VOPTS}
$(hasOpt "$VOPTS" vcodec || echo "vcodec=$MENCODER_LAVC_VC") $(IFS=$IFS:; addOpts "$VOPTS" $MENCODER_LAVC_VOPTS)
${VBR:+vbitrate=$VBR} ${VBR:+vbitrate=$VBR}
) )
[ ${#LAVCOPTS[*]} -gt 0 ] && VOPTS=$(IFS=:; echo -lavcopts "${LAVCOPTS[*]}") [ ${#LAVCOPTS[*]} -gt 0 ] && VOPTS=$(IFS=:; echo -lavcopts "${LAVCOPTS[*]}")
;; ;;
x264) x264)
isNumeric "$HEIGHT" && [ $HEIGHT -lt 0 -a $HEIGHT -gt -8 ] && ((HEIGHT-=8))
isNumeric "$WIDTH" && [ $WIDTH -lt 0 -a $WIDTH -gt -8 ] && ((WIDTH-=8))
X264OPTS=( X264OPTS=(
${VOPTS} ${VOPTS}
$(hasOpt "$VOPTS" threads || echo "threads=auto") $(IFS=$IFS:; addOpts "$VOPTS" $MENCODER_X264_VOPTS)
${VBR:+bitrate=$VBR} ${VBR:+bitrate=$VBR}
) )
[ ${#X264OPTS[*]} -gt 0 ] && VOPTS=$(IFS=:; echo -x264encopts "${X264OPTS[*]}") [ ${#X264OPTS[*]} -gt 0 ] && VOPTS=$(IFS=:; echo -x264encopts "${X264OPTS[*]}")
@ -121,7 +156,7 @@ function remux_mencoder
LAVCOPTS=( LAVCOPTS=(
${LAVCOPTS[*]} ${LAVCOPTS[*]}
${AOPTS} ${AOPTS}
$(hasOpt "$AOPTS" acodec || echo "acodec=$MENCODER_LAVC_AC") $(IFS=$IFS:; addOpts "$AOPTS" $MENCODER_LAVC_AOPTS)
${ABR:+abitrate=$ABR} ${ABR:+abitrate=$ABR}
) )
@ -133,6 +168,7 @@ function remux_mencoder
LAMEOPTS=( LAMEOPTS=(
${AOPTS} ${AOPTS}
$(isNumeric "${ABR}" && [ "${ABR}" -lt "$ABR_MONO" ] && ! hasOpt "${AOPTS}" mode ] && echo 'mode=3') $(isNumeric "${ABR}" && [ "${ABR}" -lt "$ABR_MONO" ] && ! hasOpt "${AOPTS}" mode ] && echo 'mode=3')
$(IFS=$IFS:; addOpts "$AOPTS" $MENCODER_LAME_AOPTS)
${ABR:+preset=$ABR} ${ABR:+preset=$ABR}
) )
[ ${#LAMEOPTS[*]} -gt 0 ] && AOPTS=$(IFS=:; echo -lameopts "${LAMEOPTS[*]}") [ ${#LAMEOPTS[*]} -gt 0 ] && AOPTS=$(IFS=:; echo -lameopts "${LAMEOPTS[*]}")
@ -140,6 +176,7 @@ function remux_mencoder
faac) faac)
FAACOPTS=( FAACOPTS=(
${AOPTS} ${AOPTS}
$(IFS=$IFS:; addOpts "$AOPTS" $MENCODER_FAAC_AOPTS)
${ABR:+br=$ABR} ${ABR:+br=$ABR}
) )
[ ${#FAACOPTS[*]} -gt 0 ] && AOPTS=$(IFS=:; echo -faacopts "${FAACOPTS[*]}") [ ${#FAACOPTS[*]} -gt 0 ] && AOPTS=$(IFS=:; echo -faacopts "${FAACOPTS[*]}")
@ -155,15 +192,17 @@ function remux_mencoder
startReply startReply
exec 3<&0 exec 3<&0
echo "$MENCODER" \ echo $MENCODER \
-ovc $VC $VOPTS \ -ovc $VC $VOPTS \
-oac $AC $AOPTS \ -oac $AC $AOPTS \
${WIDTH:+-vf scale -zoom -xy $WIDTH} \ ${WIDTH:+-vf scale=$WIDTH:$HEIGHT -zoom} \
${FPS:+-ofps $FPS} \
-o "$FIFO" -- - >&2 -o "$FIFO" -- - >&2
"$MENCODER" \ $MENCODER \
-ovc $VC $VOPTS \ -ovc $VC $VOPTS \
-oac $AC $AOPTS \ -oac $AC $AOPTS \
${WIDTH:+-vf scale -zoom -xy $WIDTH} \ ${WIDTH:+-vf scale=$WIDTH:$HEIGHT -zoom} \
${FPS:+-ofps $FPS} \
-o "$FIFO" -- - 0<&3 >/dev/null & -o "$FIFO" -- - 0<&3 >/dev/null &
} }
@ -171,7 +210,15 @@ function remux_ogg
{ {
VOPTS=${REMUX_PARAM_VOPTS//[:=]/ } VOPTS=${REMUX_PARAM_VOPTS//[:=]/ }
AOPTS=${REMUX_PARAM_AOPTS//[:=]/ } AOPTS=${REMUX_PARAM_AOPTS//[:=]/ }
WIDTH=${REMUX_PARAM_WIDTH:-$WIDTH}
# if only one of HEIGHT/WIDTH given:
# calculate other value depending on configured aspect ratio
# trim to multiple of 8
if [ "$HEIGHT" -a -z "$WIDTH" ]; then
WIDTH=$((HEIGHT * $OGG_ASPECT / 8 * 8))
elif [ "$WIDTH" -a -z "$HEIGHT" ]; then
HEIGHT=$(($WIDTH * $( echo $OGG_ASPECT | sed 's#^\([0-9]\+\) */ *\([0-9]\+\)$#\2 / \1#') / 8 * 8))
fi
OGGOPTS=( OGGOPTS=(
${VOPTS} ${VOPTS}
@ -187,14 +234,14 @@ function remux_ogg
startReply startReply
exec 3<&0 exec 3<&0
echo "$OGG" --format ts \ echo $OGG --format ts \
${OGGOPTS[*]} \ ${OGGOPTS[*]} \
${WIDTH:+--width $WIDTH --height $(($WIDTH * 3 / 4 / 8 * 8))} \ ${WIDTH:+--width $WIDTH --height $HEIGHT} \
--title "VDR Streamdev: ${REMUX_CHANNEL_NAME}" \ --title "VDR Streamdev: ${REMUX_CHANNEL_NAME}" \
--output "$FIFO" -- - 0<&3 >&2 --output "$FIFO" -- - 0<&3 >&2
"$OGG" --format ts \ $OGG --format ts \
${OGGOPTS[*]} \ ${OGGOPTS[*]} \
${WIDTH:+--width $WIDTH --height $(($WIDTH * 3 / 4 / 8 * 8))} \ ${WIDTH:+--width $WIDTH --height $HEIGHT} \
--title "VDR Streamdev: ${REMUX_CHANNEL_NAME}" \ --title "VDR Streamdev: ${REMUX_CHANNEL_NAME}" \
--output "$FIFO" -- - 0<&3 >/dev/null & --output "$FIFO" -- - 0<&3 >/dev/null &
} }
@ -254,6 +301,7 @@ esac
ABR=${REMUX_PARAM_ABR:-$ABR} ABR=${REMUX_PARAM_ABR:-$ABR}
VBR=${REMUX_PARAM_VBR:-$VBR} VBR=${REMUX_PARAM_VBR:-$VBR}
WIDTH=${REMUX_PARAM_WIDTH:-$WIDTH} WIDTH=${REMUX_PARAM_WIDTH:-$WIDTH}
HEIGHT=${REMUX_PARAM_HEIGHT:-$HEIGHT}
PROG=${REMUX_PARAM_PROG:-$PROG} PROG=${REMUX_PARAM_PROG:-$PROG}
case "$PROG" in case "$PROG" in