62 Commits
master ... v0_4

Author SHA1 Message Date
Frank Schmirler
17c22dc7ee increased client side timeout for TUNE command 2011-01-27 16:17:07 +01:00
Frank Schmirler
fe9a58b88c fixed regression: no receiver created for ES/PS/PES
(reported by Gavin Hamill)
2010-12-10 16:38:10 +01:00
Frank Schmirler
635ccc479f Snapshot 2010-09-15 2011-03-24 19:20:05 +02:00
schmirl
db3274c046 don't use std::map.at(). It's not available in older libstdc++ version
Modified Files:
 Tag: v0_4
	CONTRIBUTORS HISTORY remux/extern.c server/connectionHTTP.c
2010-07-22 14:18:36 +00:00
schmirl
b2f30affa9 fixed extremux x264 using value of ABR for VBR 2010-07-22 06:30:36 +00:00
schmirl
6f3b081dd0 fixed wrong URL path in m3u playlists 2010-07-20 12:26:09 +00:00
schmirl
ab4fc57879 - set externremux.sh executable in distribution archive
- externremux quality value should be wlan54, not wlan45
2010-07-20 06:24:04 +00:00
schmirl
fa578940f7 - using SIGINT in externremux to kill mencoder works better than SIGTERM;
especially x264 still needs a SIGKILL sometimes
- added --remove-destination to cp commands installing plugins
- updated Italian translation (thanks to Diego Pierotto)
- config option "client may suspend" hidden if not applicable
- updated and enhanced README
- added support for HTTP method HEAD
- rewrite of externremux.sh, including support for various URL parameters,
  logging and improved shutdown
- start externremux script in a separate process group
- changed HTTP URL path for externremux from EXTERN to EXT (suggested by
  Rolf Ahrenberg)
- HTTP headers now have to be emitted by externremux script
- pass channel related information and URL parameters to externremux script
  through environment
- implement CGI like interface for externremux script
Modified Files:
 Tag: v0_4
	CONTRIBUTORS HISTORY Makefile README common.c common.h i18n.c
	remux/extern.c remux/extern.h server/connection.c
	server/connection.h server/connectionHTTP.c
	server/connectionHTTP.h server/connectionIGMP.c
	server/connectionVTP.c server/livestreamer.c
	server/livestreamer.h server/menuHTTP.c server/setup.c
	server/setup.h server/streamer.c server/streamer.h
	streamdev/externremux.sh streamdev/streamdevhosts.conf
2010-07-19 13:50:11 +00:00
schmirl
a43455f660 dropped "Synchronize EPG" feature
Modified Files:
 Tag: v0_4
	HISTORY README i18n.c streamdev-client.c streamdev-client.h
	client/device.c client/setup.c client/setup.h client/socket.c
	client/socket.h
2010-06-08 05:56:14 +00:00
schmirl
fc99a72467 fixed a memory leak in cStreamdevPatFilter::GetPid (thanks to lhanisch) 2010-02-20 23:05:20 +00:00
schmirl
ccbc738202 - length -1 is the correct value for streams in M3U playlists 2010-02-20 22:19:31 +00:00
schmirl
25f287f5b1 added DELT FORCE option to delete running timers (#554) 2010-01-29 12:02:44 +00:00
schmirl
913e6164b6 fixed missing virtual destructor for cTSRemux 2009-12-03 07:26:19 +00:00
schmirl
1eb9b85681 Capitalized languages 2009-11-03 11:20:04 +00:00
schmirl
98d20a98bb improved PARENTALRATING patch detection was missing in this branch 2009-10-13 06:48:23 +00:00
schmirl
824a192579 silenced warnings concerning asprintf (requested by Rolf Ahrenberg)
Modified Files:
 Tag: v0_4
	CONTRIBUTORS HISTORY server/connectionVTP.c server/setup.c
2009-10-13 06:38:58 +00:00
schmirl
900af77de7 don't update recordings list on CmdPLAY (reported by BBlack) 2009-09-30 10:10:53 +00:00
schmirl
e0f60bbd81 adapted and included xmbc patch for VDR 1.4.x
Modified Files:
 Tag: v0_4
	CONTRIBUTORS HISTORY Makefile common.h server/connectionVTP.c
	server/connectionVTP.h
Added Files:
 Tag: v0_4
	server/recplayer.c server/recplayer.h
2009-09-30 10:02:26 +00:00
schmirl
7ea2353728 - cleaned up common.h / common.c
- dropped cStreamdevMenuSetupPage
2009-09-18 10:41:11 +00:00
schmirl
7acdfe7428 Added defines for getting charset in VDR 1.5.3+ 2009-09-17 10:12:11 +00:00
schmirl
f4e9cc1de9 report charset in HTTP replies (suggested by Rolf Ahrenberg) 2009-09-15 10:39:09 +00:00
schmirl
d5f0744f4b use SO_KEEPALIVE option on all sockets do detect dead sockets 2009-09-04 13:24:34 +00:00
schmirl
22ff6d0801 Fixed sysctl command 2009-09-04 13:19:31 +00:00
schmirl
53a07a9dfa enable PatFilter for externremux, so VLC can be used as remuxer or client 2009-08-05 09:33:07 +00:00
schmirl
b099df3011 fixed insecure format strings in LSTX handlers (thanks to Anssi Hannula) 2009-07-17 06:25:55 +00:00
schmirl
06e1bb7976 updated Finish translation (thanks to Rolf Ahrenberg) 2009-07-07 10:50:13 +00:00
schmirl
47b4dc48fc removed redefinitions in includes - caused problems in older compilers 2009-07-06 06:23:36 +00:00
schmirl
458bb84ea7 fixed ts2ps.h defines 2009-07-06 06:14:14 +00:00
schmirl
cf1d2b9f6b fixed missing virtual for cTS2PESRemux destructor 2009-07-06 06:13:41 +00:00
schmirl
d7760f78fa silenced format mismatch warning on 64bit OS 2009-07-03 21:42:08 +00:00
schmirl
6feef574e9 file recplayer.h was added on branch v0_4 on 2009-09-30 10:02:27 +0000 2009-07-01 11:00:49 +00:00
schmirl
bc945caca2 file recplayer.c was added on branch v0_4 on 2009-09-30 10:02:27 +0000 2009-07-01 11:00:49 +00:00
schmirl
abb8e80033 now there's a common baseclass for all remuxers, make use of it
Modified Files:
 Tag: v0_4
	HISTORY remux/ts2pes.c remux/ts2pes.h remux/tsremux.h
	server/livestreamer.c server/livestreamer.h
2009-06-30 06:03:15 +00:00
schmirl
412c6982b6 - added namespace to remuxers
- increased WRITERBUFSIZE - buffer was too small for high bandwidth content
- removed cStreamdevStreamer::m_Running
- eliminated potential busy waits in remuxers
- updated cTSRemux static helpers to code of their VDR 1.6.0 counterparts
- use a copy of VDR 1.6.0's cRemux for TS to PES remuxing.
- make sure that only complete TS packets are written to ringbuffers
- use signaling instead of sleeps when writing to ringbuffers
- optimized cStreamdevPatFilter PAT packet initialization
- fixed cStreamdevPatFilter not processing PATs with length > TS_SIZE - 5
- use a small ringbuffer for cStreamdevPatFilter instead of writing to
  cStreamdevStreamers SendBuffer as two threads mustn't write to the same
  ringbuffer
Modified Files:
 Tag: v0_4
	CONTRIBUTORS HISTORY Makefile streamdev-server.c
	libdvbmpeg/transform.h remux/extern.c remux/extern.h
	remux/ts2es.c remux/ts2es.h remux/ts2ps.c remux/ts2ps.h
	remux/tsremux.c remux/tsremux.h server/livestreamer.c
	server/livestreamer.h server/streamer.c server/streamer.h
Added Files:
 Tag: v0_4
	remux/ts2pes.c remux/ts2pes.h
2009-06-29 06:25:27 +00:00
schmirl
cacd4b73d5 file ts2pes.h was added on branch v0_4 on 2009-06-29 06:25:28 +0000 2009-06-29 06:23:33 +00:00
schmirl
40fa22bba4 file ts2pes.c was added on branch v0_4 on 2009-06-29 06:25:28 +0000 2009-06-19 06:32:40 +00:00
schmirl
421a0e113a added comments to indicate that the VTP filter stream is proprietary forma
Modified Files:
 Tag: v0_4
	client/filter.c server/livefilter.c
2009-02-13 13:02:33 +00:00
schmirl
3bd1dc556f Typo 2009-02-13 12:31:03 +00:00
schmirl
e3599df308 Added IGMP Multicast server
Modified Files:
 Tag: v0_4
	CONTRIBUTORS HISTORY Makefile README i18n.c server/component.c
	server/component.h server/connection.c server/connection.h
	server/livefilter.c server/server.c server/setup.c
	server/setup.h server/streamer.c server/streamer.h
	streamdev/streamdevhosts.conf tools/socket.c tools/socket.h
Added Files:
 Tag: v0_4
	patches/vdr-cap_net_raw.diff server/componentIGMP.c
	server/componentIGMP.h server/connectionIGMP.c
	server/connectionIGMP.h
2009-02-13 10:39:40 +00:00
schmirl
fa06a6068b file connectionIGMP.h was added on branch v0_4 on 2009-02-13 10:39:42 +0000 2009-02-13 10:39:22 +00:00
schmirl
a0c4b3aa6d file connectionIGMP.c was added on branch v0_4 on 2009-02-13 10:39:42 +0000 2009-02-13 10:39:22 +00:00
schmirl
d14ae6829f file componentIGMP.h was added on branch v0_4 on 2009-02-13 10:39:42 +0000 2009-02-13 10:39:22 +00:00
schmirl
df27143a81 file componentIGMP.c was added on branch v0_4 on 2009-02-13 10:39:42 +0000 2009-02-13 10:39:22 +00:00
schmirl
486238595f file vdr-cap_net_raw.diff was added on branch v0_4 on 2009-02-13 10:39:41 +0000 2009-02-13 10:39:21 +00:00
schmirl
c000d1d50b ignore trailing blank lines in HTTP requests 2009-02-13 07:02:25 +00:00
schmirl
64ac6278bf Fixed parsing Min/MaxPriority from config 2009-02-03 10:26:23 +00:00
schmirl
507365d16e Updated Finnish translations 2009-02-02 11:53:05 +00:00
schmirl
f8002f7e31 Added min/max priority (#508)
Modified Files:
 Tag: v0_4
	HISTORY README i18n.c client/device.c client/setup.c
	client/setup.h
2009-01-29 07:49:04 +00:00
schmirl
46b8104cd2 added Network Media Tank browser support to HTML pages (#494) 2008-12-08 11:37:36 +00:00
schmirl
d716532d8c Compatiblity to Network Media Tank (#496)
- minor fixes of PAT repacker
- repack and send every PAT packet we receive
2008-11-24 12:10:29 +00:00
schmirl
6c620ea756 - fixed null pointer in server.c when cConnection::Accept() failes 2008-10-31 12:20:06 +00:00
schmirl
4d4f39f8cd consider Pids from channels.conf when HTTP TS streaming. Section filtering
is an optional feature for VDR devices, so we must not rely on the PMT
alone (#473)
2008-10-31 11:59:55 +00:00
schmirl
30ebb2dad1 Improved externremux script termination (#455) 2008-10-31 11:41:06 +00:00
schmirl
84f994384a - use cThread::Running()/Active() instead of private members
- replaced the last usleep by cCondWait
thanks to Rolf Ahrenberg (#383)
Modified Files:
 Tag: v0_4
	CONTRIBUTORS HISTORY server/server.c server/server.h
	server/streamer.c server/streamer.h server/suspend.c
	server/suspend.h
2008-10-22 11:59:35 +00:00
schmirl
5c24a13075 - fixed output format of some debug messages (thanks to Rolf Ahrenberg) 2008-10-22 11:17:25 +00:00
schmirl
52b4bfcd8c - added HTTP authentication (#475)
Modified Files:
 Tag: v0_4
	HISTORY README streamdev-server.c server/connection.h
	server/connectionHTTP.c server/connectionHTTP.h
	server/server.c server/server.h
2008-10-14 11:05:57 +00:00
schmirl
9258019e0f - added preprocessor directive for ancient gcc 2008-07-16 05:59:45 +00:00
schmirl
4e9c967872 - added Russian translation (thanks to Oleg Roitburd) 2008-06-26 14:17:10 +00:00
schmirl
90ae937018 - Fixed assignment of externremux.sh's default location
cPlugin::ConfigDirectory() cannot be used directly after the plugin has
been loaded. The return value of AddDirectory() must be allocated.
2008-04-29 07:00:57 +00:00
schmirl
9e46f86686 - added French translation (thanks to micky979) 2008-04-14 13:42:50 +00:00
schmirl
5788cd92b2 - updated Italian translation (thanks to Diego Pierotto)
- removed some unused translations
- added missing German translations
2008-04-14 07:12:34 +00:00
schmirl
c6c2344fef Applied and removed respect_ca patch 2008-04-07 15:07:38 +00:00
109 changed files with 4612 additions and 7153 deletions

25
.gitignore vendored
View File

@@ -1,25 +0,0 @@
# Compiled Object files
*.slo
*.lo
*.o
# Compiled Dynamic libraries
*.so
*.dylib
# Compiled Static libraries
*.lai
*.la
*.a
# Eclipse project files
.project
.cproject
.settings
# Generated dependency file
.dependencies
# translations
*.mo
*.pot

View File

@@ -29,19 +29,12 @@ Rolf Ahrenberg
for a TS PAT repacker based on Petri Laine's VDR TS recording patch
for making it possible to pass parameters to externremux.sh
for removing pre VDR 1.4 legacy code
for adding gettext support
for fixing output format of some debug messages
for replacing private members by cThread::Running()/Active()
for improving externremux script termination
for fixing PAT repacker version field
for improving LIMIKUUTIO and PARENTALRATING patch detection
for suggesting to include the charset in HTTP replies
for requesting replacement of asprintf calls
for suggesting to change the URL path from EXTERN to EXT
for suggesting increased thread priorities for cStreamdevWriter/Streamer
for adding "Hide mainmenu entry" option
for polishing po file headers
for adding the special meaning "show current channel" to channel 0
Rantanen Teemu
for providing vdr-incompletesections.diff
@@ -60,8 +53,6 @@ Udo Richter
for fixing streamdev-server shutdown
for speeding up cPluginStreamdevServer::Active()
for adapting to VDR 1.5.0 API
for adapting to VDR 1.7.1
for proper tsplay-0.2 patch detection
greenman
for reporting that the log could get flooded on connection failures.
@@ -101,28 +92,18 @@ Diego Pierotto
micky979
for providing French language texts
Tiroler
for reporting a problem when switching between encrypted channels
Pixelpeter
for an initial fix to the "switching between ecncrypted channels" problem
Anssi Hannula
for the vdr-1.6.0-intcamdevices patch
for fixing insecure format strings in LSTX handlers
wirbel
for pointing out that section filtering is optional for VDR devices
for reporting a problem with Makefile defines in VDR 1.7.4+
Jori Hamalainen
for extensive testing while making stream compatible to Network Media Tank
for adding Network Media Tank browser support to HTML pages
Oliver Wagner
for pointing out a problem with the encrypted channel switching fix
owagner
for suggesting use of SO_KEEPALIVE socket option to detect dead sockets
for making cStatus::ChannelChange re-tune only if CA IDs changed
Joachim König-Baltes
for fixing Min/MaxPriority parsing
@@ -132,31 +113,16 @@ Artem Makhutov
Alwin Esch
for adding XBMC support by extending VTP capabilities
for adding VDR 1.7.11 parental rating support for VTP LSTE command
for adding the DELT FORCE option to delete running timers
BBlack
for reporting that updating recordings list on CmdPLAY is a bad idea
Milan Hrala
for providing Slovak language texts
Valdemaras Pipiras
for providing Lithuanian language texts
sk8ter
for fixing failures when switching between two encrypted channels
lhanisch
for fixing a memory leak in cStreamdevPatFilter::GetPid
Eric Valette
for adding support for EnhancedAC3
carel
for reporting "plugin doesn't honor APIVERSION" error in new Makefile
for helping to find a way to cleanly shutdown externremux with mencoder
for reporting that GetClippedNumProvidedSystems is no longer up-to-date
wolfi.m
for reporting a typo in externremux quality parameter value
@@ -174,88 +140,5 @@ Matthias Prill
Timothy D. Lenz
for reporting missing support for invisible channel groups in HTTP menu
Rainer Blickle
for reporting that channel switches may interrupt live TV on the server
Gavin Hamill
for reporting that ES/PS/PES no longer works
Michal Novotny
for reporting that switching away live TV fails when "always suspended"
wtor
for reporting that a client may interrupt replaying on FF cards
for helping to debug channel switch issues on FF cards
Javier Bradineras
for providing Spanish language texts
Pekko Tiitto
for providing a git mirror of streamdev's lost CVS repository
for suggesting to use mencoder params -alang and -msglevel in externremux
Lubo¨ Dole¸el
for suggesting higher buffer sizes to fix some ringbuffer overflows
Ville Skyttä
for updating the outdated COPYING file and FSF address
for restricting VTP command RENR to liemikuutio patch < 1.32
for fixing memory and filedescriptor leaks in libdvbmpeg
for code cleanup and optimization
for correcting typos
Methodus
for suggesting to use HTTP code 503 for unavailable channels
Uwe
for reporting a compiler error in client/device.c with VDR < 1.7.22
Chris Tallon
for his kind permission to use VOMP's recplayer for replaying recordings
macmenot
for adapting Makefiles to VDR 1.7.36+
thomasjfox
for fixing cSuspendCtl preventing idle shutdown
hivdr
for adding the pos= parameter for replaying recordings from a certain position
for suggesting to add the HTTP "Server" header
hummel99
for reporting and helping to debug channel switch issues with priority > 0
for reporting a race condition when switching the server's LiveTV device
Henrik Niehaus
for fixing replay of large TS files on 32-bit systems
Guy Martin
for adding SVDRP commands to list and disconnect clients
Martin1234
for suggesting a service call, returning the number of clients
for implementing GetCurrentlyTunedTransponder() on client
Toerless Eckert
for converting suspend.dat into proper PES format
for investigating and fixing problems caused by filter streaming
for fixing TimedWrite() so it doesn't fail after a slow but successful write
for suggesting to double the size of client's filter buffer
Tomasz Maciej Nowak
for providing Polish language texts
Christopher Reimer
for providing an initial compatibility patch for VDR 2.3.1
Matthias Senzel
for refining the compatibility patch for VDR 2.3.1
David Binderman
for fixing an lseek error check in libdvbmpeg
Jasmin J
for fixing some warnings in libdvbmpeg
for adding .gitignore
for fixing compilation for VDR 2.3.7

39
COPYING
View File

@@ -1,12 +1,12 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
@@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
@@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
@@ -225,7 +225,7 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
@@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
@@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
@@ -303,9 +303,10 @@ the "copyright" line and a pointer to where the full notice is found.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
@@ -335,5 +336,5 @@ necessary. Here is a sample; alter the names:
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

238
HISTORY
View File

@@ -1,184 +1,7 @@
VDR Plugin 'streamdev' Revision History
---------------------------------------
- fixed compilation for VDR 2.3.7 (thanks to Jasmin J)
- added .gitignore (thanks to Jasmin J)
- fixed some warnings in libdvbmpeg (thanks to Jasmin J)
- fixed lseek error check in libdvbmpeg (thanks to David Binderman)
- server compatibility with VDR 2.3.1 (thanks to Christopher Reimer and
Matthias Senzel)
- client compatibility with VDR 2.3.1
- use cReceiver::SetPriority(...) in VDR 2.1.4+
- doubled size of client's filter buffer (suggested by Toerless Eckert)
- make sure TimedWrite(...) doesn't return failure after a slow but successful
write operation (thanks to Toerless Eckert)
- fixed problems related to VTP filter streaming like ringbuffer overflows,
stuttering or aborting video stream (thanks to Toerless Eckert)
- added Polish translation (thanks to Tomasz Maciej Nowak)
- converted suspend.dat into proper PES format (thanks to Toerless Eckert)
- implemented GetCurrentlyTunedTransponder() on client (thanks to Martin1234)
- added service call returning the number of clients (suggested by Martin1234)
- added SVDRP commands to list and disconnect clients (thanks to Guy Martin)
- fixed recplayer issues with large TS files (>4GB)
- Don't abort externremux when internal read buffer is empty
- Implemented remuxing of recordings
- Make ChannelChange retune only if CA IDs changed (thanks to Oliver Wagner)
- Implemented VDR 2.1.4 cStatus::ChannelChange(...)
- Call detach only if receiver is attached
- Try changing to other device when receiver got detached
- In TSPIDS mode, create and attach receiver with empty pid list to occupy dev
- Restructured server classes
- New option for server side live TV buffer to prevent buffer underruns
2013-11-28: Version 0.6.1
- Updated Slovak translation (thanks to Milan Hrala)
- Updated Finnish translation (thanks to Rolf Ahrenberg)
- Disabled PS remuxer which is said to produce anything but PS
- The patches intcamdevices and ignore_missing_cam are no longer required
on VDR >= 1.7.30. The localchannelprovide patch became obsolete with VDR
1.7.21.
- Added option to suspend live TV when the server starts
- Set device occupied when streamdev switches away LiveTV on the server, to
reduce the risk that the VDR main loop immediately switches back, resulting
in a black screen on the client (reported by hummel99)
- Fixed channel switch issues with priority > 0 (reported by hummel99)
- Removed noisy debug messages
- Fixed HTTP menu destruction
- API change of VDR 2.1.2
- Fixed priority handling, messed up when adding multi-device support
- Added HTTP "Server" header (suggested by hivdr)
- Ignore dummy file extensions (.ts, .vob, .vdr) when parsing HTTP URIs
- Select start position for replaying a recording by parameter pos=. Supported
values are resume, mark.#, time.#, frame.# or a plain # representing a
percentage if < 100 or a byte position otherwise (thanks to hivdr)
- Start cSuspendCtl hidden or it will prevent idle shutdown (thanks to
thomasjfox)
- Fixed recordings menu inode numbers: ino_t is a long long on some systems
- Updated Slovak translation (thanks to Milan Hrala)
- Adapted Makefiles to VDR 1.7.36+ (thanks to macmenot). Old makefiles have
been renamed to Makefile-1.7.33.
- API changes of VDR 1.7.38 (thanks to mal@vdr-developer)
- Added simple recordings menu in HTTP server
- Restructured menuHTTP classes
- Added RSS format for HTTP menus
- Recordings can now also be selected by struct stat "st_dev:st_ino.rec"
- Implemented multi-device support for streamdev client (suggested by johns)
- Basic support for HTTP streaming of recordings
- Close writer when streamer is finished
- Don't abort VTP connection if filter stream is broken
- Restructured cStreamdevStreamer: Moved inbound buffer into actual subclass.
- In cStreamdevStreamer dropped Activate(bool) and moved its code into Start().
- Moved cStreamdevFilterStreamer to livefilter.[hc]
- Return HTTP/1.1 compliant response headers plus some always useful headers
- Return HTTP URL parameters ending with ".dlna.org" as response headers
- Store HTTP URL parameters in a map
- Support HTTP HEAD requests with external remuxer
- Fixed always using priority 0 for HTTP HEAD requests
- Start writer right after creating it
- Corrected typos (thanks to Ville Skyttä)
- Fixed compiler error in client/device.c with VDR < 1.7.22 (reported by
Uwe@vdrportal)
- Updated Italian translation (thanks to Diego Pierotto)
- Added DeviceName() and DeviceType() to client device. The server IP and the
number of the device used on the server are returned respectively.
2012-05-29: Version 0.6.0
- Reimplemented some client device methods
- Proper fix for "client sends ABRT after TUNE". Obsoletes many hacks in client
- Added CLOCK_MONOTONIC timestamp and thread id to Dprintf
- Silenced warning (thanks to Rolf Ahrenberg)
- Updated Finnish translation (thanks to Rolf Ahrenberg)
- Replaced server-side suspend modes with priority based precedence handling
- Client-side priority handling for VDR >= 1.7.25 and servers running VTP > 1.0
- Introduced VTP protocol version numbering for easier compatibility handling
between different client and server versions. The server includes the protocol
version in its greeting string, the client reports its version with the new
command "VERS".
- Dropped compatibility of streamdev-server with VDR < 1.7.25
2012-05-12: Version 0.5.2
- Use fileno() to retrieve the fd from a FILE structure (submitted by an
anonymous user)
- New special meaning "show current channel" when channel 0 is requested.
Applies to HTTP streaming only (thanks to Rolf Ahrenberg)
- Fixed ProvidesChannel() on client always returning true since the new timeout
option has been added.
- Updated Finnish translation (thanks to Rolf Ahrenberg)
- With VDR 1.7.25 priorities down to -99 will be used. Please update
"Minimum Priority" in streamdev-client setup.
- Use the new streamdev-client setup option "Live TV Priority" to control
precedence among multiple clients. The VDR option "Primary Limit" which
has previouly been used for this purpose has been dropped in VDR 1.7.25.
- Timout for network operations now configurable in streamdev-client setup
- Added timeout to Connect()
- Report the server-side HTTP status "503 Service unavailable" instead of
the client-side error "409 Conflict" when a channel is unavailable
(suggested by Methodus)
- Update of po headers and Finnish translation (thanks to Rolf Ahrenberg)
- support for non-cycle-free setups (e.g. where two VDRs mutually share
their DVB cards through streamdev-client/-server). Must be enabled in
streamdev-server setup. Obsoletes recursion patches.
- API change of VDR 1.7.22
- VDR 1.7.22 obsoletes cap_net_raw patch. Added cap_net_raw patch for VDR
1.7.5 - 1.7.21.
- Update and UTF-8 conversion of Finnish po files (thanks to Rolf Ahrenberg)
- Added "Hide mainmenu entry" option on server (thanks to Rolf Ahrenberg)
- Added server menu with list of clients. Connections can be terminated
with the "red" key. The former main menu action of suspending live TV
moved to the "blue" key.
- code cleanup and optimization (thanks to Ville Skyttä)
- properly shutdown IGMP timeout handler thread when the plugin is stopped.
Fixes occasional segfaults on VDR exit.
- fixed memory leak in libdvbmpeg read_pes (thanks to Ville Skyttä)
- dropped several unused functions in libdvbmpeg
- restricted VTP command RENR to liemikuutio patch < 1.32. Build fails with
newer versions of this patch (thanks to Ville Skyttä)
- updated outdated COPYING file and FSF address (thanks to Ville Skyttä)
- include SDT and TDT in TS streams
- the icy-name HTTP header sent with radio streams makes VLC pick the wrong
demuxer. Send icy-name only for ES audio streams.
- fixed regression of "live TV must be switched in VDR main thread" change:
deadlock in IGMP streaming server when switching live TV.
- streamdev-client returns true in its AvoidRecording() method introduced
with VDR 1.7.19. Note however that the impact of NumProvidedSystems is
higher.
- updated device selection to code of VDR 1.7.19
- adaption to VDR 1.7.12 cReceiver API change
- increased WRITERBUFSIZE. Has been reported to fix some ringbuffer
overflows (thanks to Lubo¨ Dole¸el)
- check availability of channel if VTP command TUNE is called without
prior PROV call (e.g. client side EPG scan)
- added support for VDR 1.7.19 SignalStrength/SignalQuality
- analog video channels use the same transponder and pid for different
channels, so streamdev-client must always issue TUNE command
- server must close the VTP connection also if filter stream is broken
- fixed missing #ifdefs for new NumProvidedSystems setup option
- new externremux.sh mencoder config options: audio pid by language code
(-alang) and verbosity (-msglevel) (thanks to Pekko Tiitto)
- writer must not spend too much time waiting in select() without checking
if the thread has been cancelled
- added Spanish translation (thanks to Javier Bradineras)
- live TV must be switched in VDR main thread
- dropped compatibility with VDR < 1.5.16
- return value of streamdev-clients cDevice::NumProvidedSystems() now
configurable in plugin setup
2011-02-11: Version 0.5.1
- updated copy of GetClippedNumProvidedSystems to the version used since
VDR 1.7.15 (reported by carel@vdrportal)
- fixed the code deciding if a device is in use for live TV or not. It did
not work as expected for FF cards (reported by wtor@vdrportal)
- increased client side timeout for TUNE command
- more dsyslog messages to help troubleshouting channel switch issues
- improved the channel switch code trying to move live TV to different card
- make sure that a client doesn't interrupt replaying on server's FF card
(reported by wtor@vdrportal)
- switching away live TV failed even when "always suspended" (reported by
Michal Novotny)
- fixed regression: no receiver created for ES/PS/PES (reported by Gavin
Hamill)
- VTP no longer uses a static priority value for its server-side receivers.
@@ -187,25 +10,14 @@ VDR Plugin 'streamdev' Revision History
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
- fixed regression of the GetDevice(...) change. Filter streaming to clients
with a recent VDR version no longer worked.
- log an error if externremux.sh is missing or not executable
- since VDR 1.5.0 cDevice::GetDevice(...) is no longer a query only method.
It detaches all receivers of the device it returns. So it is no longer
suitable for testing the availability of a device. Added a copy of VDR's
cDevice::GetDevice(...) without the detach receivers part as a workaround
until a better solution is available
- added dsyslog messages to help troubleshouting channel switch issues
- VTP command SUSP didn't attach the player to the primary device
- fixed incompatibilities with older make versions
- replacing a connections receiver is now an atomic operation. Solves
stuttering audio/video due to lost TS packets when adding/removing PIDs
- disabled attribute warn_unused_result in libdvbmpeg
- slightly increased thread priorities of cStreamdevWriter/Streamer
(suggested by Rolf Ahrenberg)
- 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 the
- 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
@@ -219,27 +31,24 @@ VDR Plugin 'streamdev' Revision History
(reported by Matthias Prill)
- fixed extremux x264 using value of ABR for VBR (thanks to vel_tins@vdrportal)
2010-07-20: Version 0.5.0b
2010-07-20: Version 0.4.0b
- fixed wrong URL path in m3u playlists (reported by Norman Thiel)
2010-07-20: Version 0.5.0a
2010-07-20: Version 0.4.0a
- set externremux.sh executable in distribution archive
- externremux quality value should be wlan54, not wlan45 (reported by
wolfi.m@vdrportal)
2010-07-19: Version 0.5.0
2010-07-19: Version 0.4.0
- using SIGINT in externremux to kill mencoder works better than SIGTERM;
especially x264 still needs a SIGKILL sometimes
- added --remove-destination to cp commands installing plugins
- fixed "plugin doesn't honor APIVERSION" (reported by carel@vdrportal)
- updated Italian translation (thanks to Diego Pierotto)
- config option "client may suspend" hidden if not applicable
- updated and enhanced README
- separated language resources of client and server
- restructured build process
- added support for HTTP method HEAD
- rewrite of externremux.sh, including support for various URL parameters,
logging and improved shutdown
@@ -252,27 +61,14 @@ VDR Plugin 'streamdev' Revision History
- implement CGI like interface for externremux script
- dropped "Synchronize EPG" feature. Please use epgsync-plugin instead
(available from http://vdr.schmirler.de)
- proper tsplay-0.2 patch detection. tsplay-0.1 is no longer recognized
(thanks to Udo Richter)
- added compatibility with VDR 1.6 tsplay-0.1 patch
- added support for EnhancedAC3 (thanks to Eric Valette)
- fixed a memory leak in cStreamdevPatFilter::GetPid (thanks to lhanisch)
- length -1 is the correct value for streams in M3U playlists
- switching between two encrypted channels on the same transponder didn't
always work (thanks to sk8ter@vdrportal)
- added DELT FORCE option to delete running timers (thanks to Alwin Esch)
- added VDR 1.7.11 parental rating support for VTP LSTE command (thanks to
Alwin Esch)
- added Lithuanian translation (thanks to Valdemaras Pipiras)
- fixed missing virtual destructor for cTSRemux
- added defines for large file support to Makefile as required by VDR 1.7.4+
(reported by wirbel@vdrportal)
- added Slovak translation (thanks to Milan Hrala)
- fixed regression from fix for switching between encrypted channels. It was
no longer possible to receive multiple (FTA) streams from the same
transponder
- improved PARENTALRATING patch detection was missing in this branch
- silenced warnings concerning asprintf (requested by Rolf Ahrenberg)
- don't update recordings list on CmdPLAY (reported by BBlack)
- adapted and included xmbc patch for VDR 1.4.x
- cleaned up common.h / common.c
- dropped cStreamdevMenuSetupPage
- report charset in HTTP replies (suggested by Rolf Ahrenberg)
@@ -285,16 +81,13 @@ VDR Plugin 'streamdev' Revision History
- fixed ts2ps.h defines
- fixed missing virtual for cTS2PESRemux destructor
- silenced format mismatch warning on 64bit OS
- added XBMC support by extending VTP capabilities (thanks to Alwin Esch)
- now there's a common baseclass for all remuxers, make use of it
- added cDevice::NumProvidedSystems() which was introduced in VDR 1.7.0
- added namespace to remuxers
- increased WRITERBUFSIZE - buffer was too small for high bandwidth content
- removed cStreamdevStreamer::m_Running
- eliminated potential busy waits in remuxers
- updated cTSRemux static helpers to code of their VDR 1.6.0 counterparts
- re-enabled PES vor VDR 1.7.3+. Streamdev now uses a copy of VDR 1.6.0's
cRemux for TS to PES remuxing.
- use a copy of VDR 1.6.0's cRemux for TS to PES remuxing.
- make sure that only complete TS packets are written to ringbuffers
- use signaling instead of sleeps when writing to ringbuffers
- optimized cStreamdevPatFilter PAT packet initialization
@@ -302,15 +95,12 @@ VDR Plugin 'streamdev' Revision History
- use a small ringbuffer for cStreamdevPatFilter instead of writing to
cStreamdevStreamers SendBuffer as two threads mustn't write to the same
ringbuffer
- added missing call to StopSectionHandler which could cause crashes when
shutting down VDR
- added IGMP based multicast streaming
- ignore trailing blank lines in HTTP requests
- fixed parsing Min/MaxPriority from config (thanks to Joachim König-Baltes)
- updated Finnish translation (thanks to Rolf Ahrenberg)
- added Min/MaxPriority parameters. Can be used to keep client VDR from
using streamdev e.g. when recording
- disabled PES for VDR 1.7.3+
- added Network Media Tank browser support to HTML pages (thanks to Jori
Hamalainen)
- minor fixes of PAT repacker
@@ -324,20 +114,14 @@ VDR Plugin 'streamdev' Revision History
Rolf Ahrenberg)
- fixed output format of some debug messages (thanks to Rolf Ahrenberg)
- added HTTP authentication
- compatibility for VDR 1.7.1 (thanks to Udo Richter)
- added vdr-1.6.0-intcamdevices.patch (thanks to Anssi Hannula)
- fixed problem when switching from one encrypted channel to an other
(reported by Tiroler@vdrportal, initial bugfix by pixelpeter@vdrportal,
another fix by owagner@vdrportal)
- added preprocessor directive for ancient gcc
- added Russian translation (thanks to Oleg Roitburd)
- fixed assignment of externremux.sh's default location (reported by plautze)
- added French translation (thanks to micky979)
- added Italian translation (thanks to Diego Pierotto)
- added gettext support (thanks to Rolf Ahrenberg)
- added vdr-1.6.0-ignore_missing_cam patch
- dropped obsolete respect_ca patch
- removed legacy code for < VDR 1.5.9 (thanks to Rolf Ahrenberg)
- updated Italian translation (thanks to Diego Pierotto)
- removed some unused translations
- added missing German translations
- applied and removed respect_ca patch
2008-04-07: Branched v0_4

127
Makefile
View File

@@ -1,46 +1,36 @@
#
# Makefile for a Video Disk Recorder plugin
#
# $Id: $
# $Id: Makefile,v 1.15.2.4 2010/07/19 13:50:11 schmirl Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
# By default the main source file also carries this name.
#
PLUGIN = streamdev
### The version number of this plugin (taken from the main source file):
VERSION = $(shell grep 'const char \*VERSION *=' common.c | awk '{ print $$5 }' | sed -e 's/[";]//g')
### The C++ compiler and options:
CXX ?= g++
CXXFLAGS ?= -fPIC -g -O2 -Wall -Woverloaded-virtual -Wno-parentheses
### The directory environment:
# Use package data if installed...otherwise assume we're under the VDR source directory:
PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc))
LIBDIR = $(call PKGCFG,libdir)
LOCDIR = $(call PKGCFG,locdir)
PLGCFG = $(call PKGCFG,plgcfg)
#
TMPDIR ?= /tmp
### The compiler options:
export CFLAGS = $(call PKGCFG,cflags)
export CXXFLAGS = $(call PKGCFG,cxxflags)
### The version number of VDR's plugin API:
APIVERSION = $(call PKGCFG,apiversion)
VDRDIR = ../../..
LIBDIR = ../../lib
TMPDIR = /tmp
### Allow user defined options to overwrite defaults:
-include $(PLGCFG)
-include $(VDRDIR)/Make.config
### export all vars for sub-makes, using absolute paths
LIBDIR := $(shell cd $(LIBDIR) >/dev/null 2>&1 && pwd)
LOCDIR := $(shell cd $(LOCDIR) >/dev/null 2>&1 && pwd)
export
unexport PLUGIN
### The version number of VDR (taken from VDR's "config.h"):
APIVERSION = $(shell grep 'define APIVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g')
### The name of the distribution archive:
@@ -49,56 +39,83 @@ PACKAGE = vdr-$(ARCHIVE)
### Includes and Defines (add further entries here):
INCLUDES += -I$(VDRDIR)/include -I..
export INCLUDES
INCLUDES += -I$(VDRDIR)/include -I.
DEFINES += -D_GNU_SOURCE
DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
### The object files (add further files here):
COMMONOBJS = common.o i18n.o \
\
tools/source.o tools/select.o tools/socket.o tools/tools.o
CLIENTOBJS = $(PLUGIN)-client.o \
\
client/socket.o client/device.o client/setup.o \
client/filter.o
SERVEROBJS = $(PLUGIN)-server.o \
\
server/server.o server/component.o server/connection.o \
server/componentVTP.o server/componentHTTP.o server/componentIGMP.o \
server/connectionVTP.o server/connectionHTTP.o server/connectionIGMP.o \
server/streamer.o server/livestreamer.o server/livefilter.o \
server/suspend.o server/setup.o server/menuHTTP.o server/recplayer.o \
remux/tsremux.o remux/ts2pes.o remux/ts2ps.o remux/ts2es.o remux/extern.o
ifdef DEBUG
DEFINES += -DDEBUG
endif
ifdef STREAMDEV_DEBUG
DEFINES += -DDEBUG
DEFINES += -DDEBUG
endif
### The main target:
.PHONY: all client server install install-client install-server dist clean
all: client server
.PHONY: all dist clean
all: libvdr-$(PLUGIN)-client.so libvdr-$(PLUGIN)-server.so
### Implicit rules:
%.o: %.c
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
# Dependencies:
MAKEDEP = $(CXX) -MM -MG
DEPFILE = .dependencies
ifdef GCC3
$(DEPFILE): Makefile
@rm -f $@
@for i in $(CLIENTOBJS:%.o=%.c) $(SERVEROBJS:%.o=%.c) $(COMMONOBJS:%.o=%.c) ; do \
$(MAKEDEP) $(DEFINES) $(INCLUDES) -MT "`dirname $$i`/`basename $$i .c`.o" $$i >>$@ ; \
done
else
$(DEPFILE): Makefile
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(CLIENTOBJS:%.o=%.c) $(SERVEROBJS:%.o=%.c) \
$(COMMONOBJS:%.o=%.c) > $@
endif
-include $(DEPFILE)
### Targets:
client:
$(MAKE) -C ./tools
$(MAKE) -C ./client
libdvbmpeg/libdvbmpegtools.a: libdvbmpeg/*.c libdvbmpeg/*.h
$(MAKE) -C ./libdvbmpeg libdvbmpegtools.a
server:
$(MAKE) -C ./tools
$(MAKE) -C ./libdvbmpeg
$(MAKE) -C ./remux
$(MAKE) -C ./server
libvdr-$(PLUGIN)-client.so: $(CLIENTOBJS) $(COMMONOBJS) libdvbmpeg/libdvbmpegtools.a
libvdr-$(PLUGIN)-server.so: $(SERVEROBJS) $(COMMONOBJS) libdvbmpeg/libdvbmpegtools.a
install-client: client
$(MAKE) -C ./client install
# installs to $(LIBDIR)/libvdr-streamdev-client.so.$(APIVERSION)
install-server: server
$(MAKE) -C ./server install
# installs to $(LIBDIR)/libvdr-streamdev-server.so.$(APIVERSION)
install: install-client install-server
%.so:
$(CXX) $(CXXFLAGS) -shared $^ -o $@
@cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
dist: clean
@-rm -rf $(TMPDIR)/$(ARCHIVE)
@mkdir $(TMPDIR)/$(ARCHIVE)
@cp -a * $(TMPDIR)/$(ARCHIVE)
@tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE)
@tar czf $(PACKAGE).tgz --exclude CVS -C $(TMPDIR) $(ARCHIVE)
@-rm -rf $(TMPDIR)/$(ARCHIVE)
@echo Distribution package created as $(PACKAGE).tgz
clean:
$(MAKE) -C ./tools clean
@-rm -f $(COMMONOBJS) $(CLIENTOBJS) $(SERVEROBJS) $(DEPFILE) *.so *.tgz core* *~
$(MAKE) -C ./libdvbmpeg clean
$(MAKE) -C ./remux clean
$(MAKE) -C ./client clean
$(MAKE) -C ./server clean

View File

@@ -1,108 +0,0 @@
#
# Makefile for a Video Disk Recorder plugin
#
# $Id: Makefile,v 1.23 2010/08/02 10:36:59 schmirl Exp $
# The main source file name.
#
PLUGIN = streamdev
### The C/C++ compiler and options:
CC ?= gcc
CFLAGS ?= -g -O2 -Wall
CXX ?= g++
CXXFLAGS ?= -g -O2 -Wall -Woverloaded-virtual -Wno-parentheses
### The version number of this plugin (taken from the main source file):
VERSION = $(shell grep 'const char \*VERSION *=' common.c | awk '{ print $$5 }' | sed -e 's/[";]//g')
### The directory environment:
VDRDIR = ../../..
LIBDIR = ../../lib
TMPDIR = /tmp
### The version number of VDR (taken from VDR's "config.h"):
APIVERSION = $(shell grep 'define APIVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g')
APIVERSNUM = $(shell grep 'define APIVERSNUM ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g')
TSPLAYVERSNUM = $(shell grep 'define TSPLAY_PATCH_VERSION ' $(VDRDIR)/device.h | awk '{ print $$3 }')
### Allow user defined options to overwrite defaults:
ifeq ($(shell test $(APIVERSNUM) -ge 10713; echo $$?),0)
include $(VDRDIR)/Make.global
else
ifeq ($(shell test $(APIVERSNUM) -ge 10704 -o -n "$(TSPLAYVERSNUM)" ; echo $$?),0)
DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
CFLAGS += -fPIC
CXXFLAGS += -fPIC
else
CFLAGS += -fPIC
CXXFLAGS += -fPIC
endif
endif
-include $(VDRDIR)/Make.config
### export all vars for sub-makes, using absolute paths
VDRDIR := $(shell cd $(VDRDIR) >/dev/null 2>&1 && pwd)
LIBDIR := $(shell cd $(LIBDIR) >/dev/null 2>&1 && pwd)
export
unexport PLUGIN
### The name of the distribution archive:
ARCHIVE = $(PLUGIN)-$(VERSION)
PACKAGE = vdr-$(ARCHIVE)
### Includes and Defines (add further entries here):
INCLUDES += -I$(VDRDIR)/include -I..
DEFINES += -D_GNU_SOURCE
ifdef DEBUG
DEFINES += -DDEBUG
endif
ifdef STREAMDEV_DEBUG
DEFINES += -DDEBUG
endif
### The main target:
.PHONY: all client server dist clean
all: client server
### Targets:
client:
$(MAKE) -C ./tools
$(MAKE) -C ./client
# installs to $(LIBDIR)/libvdr-streamdev-client.so.$(APIVERSION)
server:
$(MAKE) -C ./tools
$(MAKE) -C ./libdvbmpeg
$(MAKE) -C ./remux
$(MAKE) -C ./server
# installs to $(LIBDIR)/libvdr-streamdev-server.so.$(APIVERSION)
dist: clean
@-rm -rf $(TMPDIR)/$(ARCHIVE)
@mkdir $(TMPDIR)/$(ARCHIVE)
@cp -a * $(TMPDIR)/$(ARCHIVE)
@tar czf $(PACKAGE).tgz --exclude CVS -C $(TMPDIR) $(ARCHIVE)
@-rm -rf $(TMPDIR)/$(ARCHIVE)
@echo Distribution package created as $(PACKAGE).tgz
clean:
$(MAKE) -C ./tools clean
$(MAKE) -C ./libdvbmpeg clean
$(MAKE) -C ./remux clean
$(MAKE) -C ./client clean
$(MAKE) -C ./server clean

286
README
View File

@@ -63,7 +63,7 @@ the PROTOCOL file.
2. Installation:
----------------
Let's say streamdev's version is 0.5.0 and vdr's version is 1.X.X. If you
Let's say streamdev's version is 0.4.0 and vdr's version is 1.X.X. If you
use anything else please exchange the version numbers appropriately (this
way I don't have to update this section all the times;) ).
@@ -80,11 +80,11 @@ If you want to drive additional Input-Devices (with different sources) on the
client, you can merge the channels.conf files. VDR will detect if the local
device or the network device can receive the channels.
Last, but not least you have to copy the streamdev-server folder into the
"plugins/streamdev-server" subfolder of VDR's config-directory (which is equal
to your video-directory if not specified otherwise). For example, if you didn't
specify a separate config-directory, and set your video directory to "/video0",
the directory has to be copied to /video0/plugins/streamdev-server.
Last, but not least you have to copy the streamdev folder into the
"plugins/streamdev" subfolder of VDR's config-directory (which is equal to your
video-directory if not specified otherwise). For example, if you didn't specify
a separate config-directory, and specified your video directory as "/video0",
the directory has to be copied to /video0/plugins/streamdev.
The directory contains a file named streamdevhosts.conf which you must adjust
to your needs. The syntax is the same as for svdrphosts.conf, so please consult
@@ -101,20 +101,16 @@ as otherwise -r will be passed to VDR and not to streamdev.
2.1 Compatibility:
------------------
This version is not compatible to VDR releases older than 1.7.25. Use one of
the streamdev-0.5.x releases for older versions.
This version is compatible to VDR releases 1.4.x and 1.5 upto 1.5.8. If you are
running some older VDR release, streamdev-0.3.4 is your friend. Check higher
streamdev releases if you are running a more recent VDR.
2.2 Compiling:
--------------
The Makefiles are for VDR 1.7.36 and above. For VDR 1.7.33 and below, please
replace the Makefiles in the main directory and in the client/ and server/
subdirectories with the corresponding Makefile-1.7.33 files. With VDR 1.7.34 and
1.7.35 YMMV ;)
cd vdr-1.X.X/PLUGINS/src
tar xvfz vdr-streamdev-0.5.0.tgz
ln -s streamdev-0.5.0 streamdev
tar xvfz vdr-streamdev-0.4.0.tgz
ln -s streamdev-0.4.0 streamdev
cp -r streamdev/streamdev-server VDRCONFDIR/plugins/
cd ../..
make [options, if necessary] vdr
@@ -123,10 +119,6 @@ subdirectories with the corresponding Makefile-1.7.33 files. With VDR 1.7.34 and
To build only the plugin, change into the streamdev source folder and issue
make
To build only streamdev-server or only streamdev-client, use
make server
make client
2.3 Updating:
--------------
@@ -134,39 +126,17 @@ If you are updating streamdev from an earlier release, you might have to
perform some additional steps. Check which version you've been running before,
then read below for the necessary changes.
* Priorities:
-------------
(Affected: 0.5.x and older)
The server-side setting "Suspend behaviour" has been dropped in 0.6.0 in favour
of priority based precedence. A priority of 0 and above means that clients
have precedence. A negative priority gives precedence to local live TV on the
server. So if "Suspend behaviour" was previously set to "Client may suspend" or
"Never suspended", you will have to configure a negative priority. If the
"Suspend behaviour" was set to "Always suspended", the default values should do.
Configure the desired priorities for HTTP and IGMP Multicast streaming in the
settings of streamdev-server. If you haven't updated all your streamdev-clients
to at least 0.5.2, configure "Legacy Client Priority", too.
In streamdev-client, you should set "Minimum Priority" to -99. Adjust "Live TV
Priority" if necessary.
* Location of files:
--------------------
(Affected: 0.3.x, 0.4.x, 0.4.0pre, 0.5.0pre)
(Affected: 0.3.x)
Starting with streamdev 0.5.0, all additional files are kept in a directory
called "streamdev-server" inside VDR's plugin config directory. It is the new
default location of externremux.sh and the new place where streamdev-server
expects the file "streamdevhosts.conf". You will have to move this file to its
new location:
Starting with streamdev 0.4.0, all additional files are kept in a directory
called "streamdev" inside VDR's plugin config directory. It is the new default
location of externremux.sh and the new place where streamdev-server expects
the file "streamdevhosts.conf". You will have to move this file to its new
location:
streamdev 0.3.x:
mv VDRCONFDIR/plugins/streamdevhosts.conf VDRCONFDIR/plugins/streamdev-server/
streamdev 0.4.x, 0.4.0pre and 0.5.0pre:
mv VDRCONFDIR/plugins/streamdev VDRCONFDIR/plugins/streamdev-server/
mv VDRCONFDIR/plugins/streamdevhosts.conf VDRCONFDIR/plugins/streamdev/
Now check the contents of streamdevhosts.conf. Does it contain a "0.0.0.0/0"
entry? If your VDR machine is connected to the Internet, this line gives
@@ -176,7 +146,7 @@ HTTP authentication instead.
* Handling of externremux script:
---------------------------------
(Affected: 0.3.x, 0.4.0pre, 0.5.0pre)
(Affected: 0.3.x, 0.4.0pre)
Streamdev server's externremux script became responsible for emitting all HTTP
headers. A quick and dirty extension to your current script would be:
@@ -197,41 +167,25 @@ Start the server core itself by specifying -Pstreamdev-server on your VDR
commandline. To use the client core, specify -Pstreamdev-client. Both parts
can run in one VDR instance, if necessary.
Precedence between multiple clients and between client and server is controlled
with priorities. For HTTP and IGMP Multicast, the priority is configured in
streamdev-server's setup menu. A negative priority gives precedence to local
live TV on the server. Zero and positive values give precedence to the client.
The parameter "Suspend behaviour" allows you to specify how the server should
react in case the client requests a channel that would require switching the
primary device (i.e. disrupt live-tv). If set to "Offer suspend mode", you will
have a new entry in the main menu. Activating that will put the server into
"Suspend Mode" (a picture is displayed on TV). Then, a client may switch the
primary card to wherever it likes to. While watching TV (Suspend deactivated),
the client may not switch the transponder on the primary device. If you set
the behaviour to "Always suspended" (the default), there will be normal live-tv
on the server, but whenever a client decides to switch the transponder, the
server will lose it's live-tv. Set to "Never suspended", the server always
prevents the client from switching transponders. If you set "Client may
suspend" to yes, the client can suspend the server remotely (this only applies
if "Offer suspend mode" is selected).
The priority for VDR clients watching live TV is configured in the plugin setup
of streamdev-client. For other client tasks (e.g. recording a client side timer)
the same priority as on the client is used. With the parameter "Legacy client
Priority" in streamdev-server's setup menu you can configure the priority for
clients which cannot be configured to use negative priorities. It is used
when an old client is detected an it requests priority "0".
On the server, the main menu entry "Streamdev Connections" gives you a list
of currently connected clients. Use the "red" key to terminate a connection.
Note that depending on connection type and client, the client might re-connect
sooner or later.
The "blue" key in the server's main menu will suspend live TV on server. An
image is displayed instead. This would allow a low priority client to switch
to a different transponder. Enable "Client may suspend" in the server setup
to allow VDR clients to suspend live TV remotely.
In the server's setup there's also an option to suspend live TV when starting
the server. The "auto" option will suspend live TV if there's no device with
an MPEG decoder available which is typically the case on a headless server.
NOTE: Precedence is mainly an issue on One-Card-Systems, since with multiple
cards there is no need to switch transponders on the primary interface, if one
of the other cards is idle (i.e. if it is not blocked by a recording). If all
cards are in use (i.e. when something is recorded, or by multiple clients), this
applies to Multiple-Card-Systems as well.
If your client suffers from buffer underruns while watching live TV, you can
configure buffering on the server side. Enter a reasonable value (e.g. 300ms)
as "Live TV buffer delay (ms)" in the server setup.
NOTE: This mainly applies to One-Card-Systems, since with multiple cards there
is no need to switch transponders on the primary interface, if the secondary
can stream a given channel (i.e. if it is not blocked by a recording). If both
cards are in use (i.e. when something is recorded, or by multiple clients),
this applies to Multiple-Card-Systems as well.
3.1 Usage HTTP server:
----------------------
@@ -245,6 +199,7 @@ has been requested in the URL (see below). The supported stream types are:
TS Transport Stream (i.e. a dump from the device)
PES Packetized Elemetary Stream (VDR's native recording format)
PS Program Stream (SVCD, DVD like stream)
ES Elementary Stream (only Video, if available, otherwise only Audio)
EXT Pass stream through external script (e.g. for converting with mencoder)
@@ -262,18 +217,16 @@ streams directly like this:
http://hostname:3000/S19.2E-0-12480-898
The first one will deliver a channel by number on the server, the second one
will request the channel by unique channel id. Use the special channel number 0
to see the server's current live TV channel.
In addition, you can specify the desired stream type as a path to the channel.
will request the channel by unique channel id. In addition, you can specify
the desired stream type as a path to the channel.
http://hostname:3000/TS/3
http://hostname:3000/PES/S19.2E-0-12480-898
The first one would deliver the stream in TS, the second one in PES format.
Possible values are 'PES', 'TS', 'ES' and 'EXT'. You need to specify the ES
format explicitly if you want to listen to radio channels. Play them back i.e.
with mpg123.
Possible values are 'PES', 'TS', 'PS', 'ES' and 'EXT'. You need to specify
the ES format explicitly if you want to listen to radio channels. Play them
back i.e. with mpg123.
mpg123 http://hostname:3000/ES/200
@@ -309,7 +262,7 @@ For multicast streaming over the public Internet you would even need to register
for your own IP range. So don't even think of multicasting via Internet with
streamdev! Streamdev will send the stream only to one local ethernet segment and
all clients must be connected to this same segment. There must not be a router
in between. Also note that the client must not run on the streamdev-server
inbetween. Also note that the client must not run on the streamdev-server
machine.
Each channel is offered on a different multicast IP. Channel 1 is available from
@@ -319,11 +272,16 @@ reserved according to RFC-2365).
Before you can use streamdev's multicast server, you might need to patch VDR.
Binding an IGMP socket is a privileged operation, so you must start VDR as root.
If you pass the -u option to VDR, it will drop almost all priviledges before
streamdev is even loaded. Apply vdr-cap_net_raw.diff to keep VDR from dropping
the CAP_NET_RAW capability required to bind the IGMP socket. The patch is part
of streamdev's source distribution. Check the patches subdirectory. There's no
need to patch VDR if it is kept running as root (not recommended).
The multicast server is disabled by default. Enter the streamdev-server setup
menu to enable it and - IMPORTANT - bind the multicast server to the IP of your
VDR server's LAN ethernet card. The multicast server will refuse to start with
the default bind address "0.0.0.0".
the default bind adresse "0.0.0.0".
Now edit your streamdevhosts.conf. To allow streaming of all channels, it must
contain "239.255.0.0/16". Note that you cannot limit connections by client IP
@@ -339,12 +297,7 @@ You might want to increase this up to "number_of_channels + 1". Note that it's
#All channels:
bash# COUNT=$(grep -c '^[^:]' PATH_TO_YOUR/channels.conf)
bash# sysctl -w net.ipv4.igmp_max_memberships=$((COUNT + 1))
You need to run the sysctl command *before* VDR is started. The setting is lost
after the next reboot. Check the documentation of your Linux distro on how to
make the setting persist (i.e. have your distro change the value for you as
part of the boot procedure). Most likely /etc/sysctl.conf is your friend.
bash# sysctl -w net.ipv4.igmp_max_memberships=$COUNT
A multicast server never knows how many clients are actually receiving a stream.
If a client signals that it leaves a multicast group, the server has to query
@@ -363,13 +316,6 @@ port where you want the server to listen for incoming connections. The server
will be activated when you push the OK button inside the setup menu, so there's
no need to restart VDR.
If both, streamdev-client and streamdev-server are installed, the additional
option "Loop prevention" will show up in the streamdev-server setup. If enabled,
streamdev-client won't be considered when streamdev-server is looking for a
device which is able to receive some channel. This is required if two or more
VDRs mutually share their DVB devices through streamdev. Otherwise you would
end up in a loop.
3.4 Usage VDR-to-VDR client:
----------------------------
@@ -378,9 +324,9 @@ setup parameter "Hide Mainmenu Entry" you can hide this menu item if you don't
need it. "Suspend Server" is only useful if the server runs in "Offer suspend
mode" with "Client may suspend" enabled.
The parameter "Remote IP" uses an IP-Address-Editor, where you can just enter
The parameter "Remote IP" uses an IP-Adress-Editor, where you can just enter
the IP number with the number keys on your remote. After three digits (or if
the next digit would result in an invalid IP address, or if the first digit is
the next digit would result in an invalid IP adress, or if the first digit is
0), the current position jumps to the next one. You can change positions with
the left and right buttons, and you can cycle the current position using up
and down. To confirm the entered address, press OK. So, if you want to enter
@@ -389,83 +335,50 @@ type "127001<OK>" on your remote. If you want to enter "192.168.1.12", type
"1921681<Right>12<OK>".
The parameters "Remote IP" and "Remote Port" in the client's setup specify the
address of the remote VDR-to-VDR server to connect to. The client is disabled
by default, because it wouldn't make much sense to start the client without
specifying a server anyway. Activate the client by setting "Simultaneously used
Devices" to at least 1. Streamdev-client will allocate as many VDR devices as
you configure here. Each of these devices opens one connection to the server
and becomes associated with one of the server's devices (typically a DVB card)
on demand.
address of the remote VDR-to-VDR server to connect to. Activate the client by
setting "Start Client" to yes. It is disabled by default, because it wouldn't
make much sense to start the client without specifying a server anyway. The
client is activated after you push the OK button, so there's no need to restart
VDR. Deactivation on-the-fly is not possible, so in order to deactivate the
client, you will have to restart VDR. However requests to switch channels will
be refused by streamdev-client once it has been deactivated. All other settings
can be changed without restarting VDR.
The client will try to connect to the server (in case it isn't yet) whenever
a remote channel is requested. Just activate the client and switch to a
channel that's not available by local devices. If anything goes wrong with the
connection between the two, you will see it in the logfile instantly. If you
now switch the client to a channel which isn't covered by it's own local
devices, it will ask the server for it. If the server can (currently) receive
that channel, the client will show it until you switch again, or until the
server needs that card (if no other is free) for a recording on a different
transponder.
Only the needed PIDs are transferred, and additional PIDs can be turned on
during an active transfer. This makes it possible to switch languages, receive
additional channels on the same transponder and use plugins that use receivers
themselves (like osdteletext).
So for viewing live TV a single device is sufficient. But if the client needs
to receive channels from different transponders simultaneously (e.g. for PiP or
client side recordings) a second device becomes necessary.
To allocate additional devices, just increase the number and push the OK button.
There's no need to restart VDR. Deleting VDR devices on-the-fly is not possible.
However requests to switch channels will be refused by redundant devices.
The default timeout of 2 seconds for network operations should be sufficient in
most cases. Increase "Timeout" if you get frequent timeout errors in the log.
additional channels (for recording on the client) and use plugins that use
receivers themselves (like osdteletext).
With "Filter Streaming" enabled, the client will receive meta information like
EPG data and service information, just as if the client had its own DVB card.
Link channels and even a client-side EPG scan have been reported to work.
If you have TV programs with dynamically changing PIDs (such as some german
regional programs like NDR), then you need to enable "Filter Streaming" to
correctly receive them. You also need to set in VDRs DVB setup the option
"Update channels" to at least "PIDs only" (or "names and PIDs") for this
to work.
"Filter streaming" uses internally a socketpair(2) to copy meta data to
VDR. This socketpair may require larger than default buffering. If
you see a mesage like the following in syslog,
cStreamdevFilter::PutSection(Pid:18 Tid: 64): Dropped 2995 bytes, max queue: 328640
then you should increase the streamdev client "FilterSockBufSize" value. A
good value is 3072000. You will need to first configure your linux to
permit such a large buffer size:
sysctl net.core.wmem_max=3072000
The precedence among multiple client VDRs receiving live TV from the same
server is controlled with "Live TV Priority".
With "Maximum Priority" and "Minimum Priority" you can keep VDR from considering
Finally with the maximum and minimum priority, you can keep VDR from considering
streamdev in certain cases. If for instance you have a streamdev client with its
own DVB card, VDR might use streamdev for recording. If this is not what you
want, you could set the maximum priority to 0. As recordings usually have a much
higher priority (default 50), streamdev is now no longer used for recordings.
The two parameters define the inclusive range of priorities for which streamdev
will accept to tune. Setting the minimum priority to a higher value than the
maximum, you will get two ranges: "up to maximum" and "minimum and above".
own DVB card, VDR would normally use streamdev for recording. If this is not
what you want, you could set the maximum priority to 0. As recordings usually
have a much higher priority (default 50), streamdev is now no longer used for
recordings. The two parameters define the inclusive range of priorities for
which streamdev will accept to tune. Setting the minimum priority to a higher
value than the maximum, you will get two ranges: "up to maximum" and "minimum
and above".
You can also configure the "Broadcast Systems / Cost" of the streamdev-client
device. On a pure streamdev-client only system it doesn't matter what you
configure here. But if your client is equipped with a DVB card, you should read
on. VDR always prefers the cheapest device in terms of supported broadcast
systems and modulations. A DVB-S2 card supports two broadcast systems (DVB-S and
DVB-S2). The supported modulations are counted as well (QPSK, QAM32/64/128/256,
VSB8/16, TURBO_FEC). So for a DVB-S2 card which does QPSK you'll get a total
cost of three. A DVB-C card (one broadcast system) which can do QAM32, QAM64,
QAM128, QAM256 would give you a total of five. Check your log for "frontend ...
provides ... with ..." messages to find out the cost of your DVB cards. Then
pick a suitable value for streamdev-client. With equal costs, VDR will usually
prefer the DVB card and take streamdev for recordings. If streamdev's costs are
higher, live TV will use your DVB card until a recordings kicks in. Then the
recording will take the DVB card and live TV will be shifted to streamdev
(you'll notice a short interruption of live TV).
To receive channels from multiple servers, create additional instances of the
streamdev-client plugin. Simply copy (don't link!) the binary to a different
name (e.g. streamdev-client2):
Note that streamdev-client acts similar to a DVB card. It is possible to receive
multiple channels simultaneously, but only from the same transponder. Just add
additional instances of streamdev-client and you will be able to receive as many
transponders at a time. The same trick allows a client to receive channels from
different servers. To create an additional instance, copy the streamdev-client
binary to a different name (e.g. streamdev-client2):
cd VDRPLUGINLIBDIR
cp libvdr-streamdev-client.so.1.X.X libvdr-streamdev-client2.so.1.X.X
@@ -567,26 +480,11 @@ The script should perform the following steps (pseudocode):
onSIGINT/SIGKILL: cleanup and exit
6. Known Problems:
------------------
* In VDR before 1.7.30 viewing encrypted channels is an issue as Streamdev
doesn't provide a (dummy) CAM. So out of the box, VDR won't ever try to receive
encrypted channels from streamdev. Pick one of the following solutions to work
around the problem:
1. Force VDR to use streamdev. Open the channels menu on the client (or edit its
channels.conf if you know how to do this) and set the CA field of all channels
that only the server can decrypt to streamdev's device index. Usually streamdev
will get number 9 or 10. Streamdev logs the actual device number when starting
up. So please consider the logs for the correct value. Remember to fill in
hexadecimal values if you are using an editor to modify your channels.conf
(number 10 becomes an "a", number 11 a "b", ...).
2. Apply either patch "patches/vdr-1.6.0-1.7.29-intcamdevices.patch" or patch
"patches/vdr-1.6.0-1.7.29-ignore_missing_cam.diff" to your client VDR.
Intcamdevices is the clean solution, but it modifies the VDR API. So you will
need to recompile all of your plugins. The ignore_missing_cam patch is trivial,
no need to recompile other plugins. However it is not suitable for clients with
a DVB card of their own.
* In VDR-to-VDR setup, the availability of a channel is checked with a different
priority than the actual channel switch. The later always uses priority 0.
Usually a channel switch for live TV has priority 0 anyway, so it is not a
problem here. However timers usually have a higher priority. Either avoid
client side recordings or set the priority of client side timers to 0.

View File

@@ -1,83 +0,0 @@
#
# Makefile for a Video Disk Recorder plugin
#
# $Id: $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
# By default the main source file also carries this name.
PLUGIN = streamdev-client
### The name of the shared object file:
SOFILE = libvdr-$(PLUGIN).so
### Includes and Defines (add further entries here):
DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
### The object files (add further files here):
COMMONOBJS = ../common.o
CLIENTOBJS = $(PLUGIN).o \
device.o filter.o setup.o socket.o
### The main target:
all: $(SOFILE) i18n
### Implicit rules:
%.o: %.c
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
MAKEDEP = $(CXX) -MM -MG
DEPFILE = .dependencies
$(DEPFILE): Makefile
@$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(CLIENTOBJS:%.o=%.c) $(COMMONOBJS:%.o=%.c) > $@
-include $(DEPFILE)
### Internationalization (I18N):
PODIR = po
I18Npo = $(wildcard $(PODIR)/*.po)
I18Nmo = $(addsuffix .mo, $(foreach file, $(I18Npo), $(basename $(file))))
I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
I18Npot = $(PODIR)/$(PLUGIN).pot
%.mo: %.po
msgfmt -c -o $@ $<
$(I18Npot): $(CLIENTOBJS:%.o=%.c)
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<vdrdev@schmirler.de>' -o $@ `ls $^`
%.po: $(I18Npot)
msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
@touch $@
$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
install -D -m644 $< $@
.PHONY: i18n
i18n: $(I18Nmo) $(I18Npot)
install-i18n: $(I18Nmsgs)
### Targets:
$(SOFILE): $(CLIENTOBJS) $(COMMONOBJS) ../tools/sockettools.a
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $^ -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
install: install-lib install-i18n
clean:
@-rm -f $(PODIR)/*.mo $(PODIR)/*.pot
@-rm -f $(COMMONOBJS) $(CLIENTOBJS) $(DEPFILE) *.so *.tgz core* *~

View File

@@ -1,84 +0,0 @@
#
# Makefile for a Video Disk Recorder plugin
#
# $Id: Makefile,v 1.2 2010/07/19 13:49:25 schmirl Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
# By default the main source file also carries this name.
#
PLUGIN = streamdev-client
### Includes and Defines (add further entries here):
DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
### The object files (add further files here):
COMMONOBJS = ../common.o
CLIENTOBJS = $(PLUGIN).o \
device.o filter.o setup.o socket.o
### The main target:
.PHONY: all i18n dist clean
all: libvdr-$(PLUGIN).so i18n
### Implicit rules:
%.o: %.c
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
MAKEDEP = $(CXX) -MM -MG
DEPFILE = .dependencies
$(DEPFILE): Makefile
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(CLIENTOBJS:%.o=%.c) $(COMMONOBJS:%.o=%.c) > $@
-include $(DEPFILE)
### Internationalization (I18N):
PODIR = po
LOCALEDIR = $(VDRDIR)/locale
I18Npo = $(wildcard $(PODIR)/*.po)
I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
I18Npot = $(PODIR)/$(PLUGIN).pot
%.mo: %.po
msgfmt -c -o $@ $<
$(I18Npot): $(CLIENTOBJS:%.o=%.c)
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='<http://www.vdr-developer.org/mantisbt/>' -o $@ $^
%.po: $(I18Npot)
msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
@touch $@
$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
@mkdir -p $(dir $@)
cp $< $@
i18n: $(I18Nmsgs)
### Targets:
libvdr-$(PLUGIN).so: $(CLIENTOBJS) $(COMMONOBJS) ../tools/sockettools.a
%.so:
$(CXX) $(CXXFLAGS) -shared $^ -o $@
@cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
dist: clean
@-rm -rf $(TMPDIR)/$(ARCHIVE)
@mkdir $(TMPDIR)/$(ARCHIVE)
@cp -a * $(TMPDIR)/$(ARCHIVE)
@tar czf $(PACKAGE).tgz --exclude CVS -C $(TMPDIR) $(ARCHIVE)
@-rm -rf $(TMPDIR)/$(ARCHIVE)
@echo Distribution package created as $(PACKAGE).tgz
clean:
@-rm -f $(COMMONOBJS) $(CLIENTOBJS) $(DEPFILE) $(PODIR)/*.mo $(PODIR)/*.pot *.so *.tgz core* *~

View File

@@ -1,5 +1,5 @@
/*
* $Id: device.c,v 1.27 2010/08/18 10:26:55 schmirl Exp $
* $Id: device.c,v 1.18.2.4 2010/08/18 10:26:18 schmirl Exp $
*/
#include "client/device.h"
@@ -19,52 +19,45 @@
using namespace std;
#ifndef LIVEPRIORITY
#define LIVEPRIORITY 0
#endif
#ifndef TRANSFERPRIORITY
#define TRANSFERPRIORITY -1
#endif
#define VIDEOBUFSIZE MEGABYTE(3)
const cChannel *cStreamdevDevice::m_DenyChannel = NULL;
cStreamdevDevice *cStreamdevDevice::m_Device = NULL;
cStreamdevDevice::cStreamdevDevice(void) {
m_Disabled = false;
m_ClientSocket = new cClientSocket();
m_Channel = NULL;
m_TSBuffer = NULL;
m_Channel = NULL;
m_TSBuffer = NULL;
m_Filters = new cStreamdevFilters(m_ClientSocket);
m_Filters = new cStreamdevFilters;
StartSectionHandler();
isyslog("streamdev-client: got device number %d", CardIndex() + 1);
m_Device = this;
m_Pids = 0;
m_Priority = -1;
m_DvrClosed = true;
}
cStreamdevDevice::~cStreamdevDevice() {
Dprintf("Device gets destructed\n");
Lock();
m_Device = NULL;
m_Filters->SetConnection(-1);
m_ClientSocket->Quit();
m_ClientSocket->Reset();
ClientSocket.Quit();
ClientSocket.Reset();
Unlock();
Cancel(3);
StopSectionHandler();
DELETENULL(m_Filters);
DELETENULL(m_TSBuffer);
delete m_ClientSocket;
}
#if APIVERSNUM >= 10700
int cStreamdevDevice::NumProvidedSystems(void) const
{ return StreamdevClientSetup.NumProvidedSystems; }
#endif
int cStreamdevDevice::ProvidesCa(const cChannel *Channel) const
{
// Encrypted is acceptable for now. Will ask the server later.
return Channel->Ca() <= CA_DVB_MAX ? cDevice::ProvidesCa(Channel) : 1;
}
bool cStreamdevDevice::ProvidesSource(int Source) const {
Dprintf("ProvidesSource, Source=%d\n", Source);
@@ -77,29 +70,25 @@ bool cStreamdevDevice::ProvidesTransponder(const cChannel *Channel) const
return true;
}
#if APIVERSNUM >= 10722
bool cStreamdevDevice::IsTunedToTransponder(const cChannel *Channel) const
#else
bool cStreamdevDevice::IsTunedToTransponder(const cChannel *Channel)
#endif
{
return m_ClientSocket->DataSocket(siLive) != NULL &&
m_Channel != NULL &&
Channel->Transponder() == m_Channel->Transponder();
}
const cChannel *cStreamdevDevice::GetCurrentlyTunedTransponder(void) const {
if (m_ClientSocket->DataSocket(siLive) != NULL)
return m_Channel;
return NULL;
bool res = false;
if (ClientSocket.DataSocket(siLive) != NULL
&& TRANSPONDER(Channel, m_Channel))
res = true;
return res;
}
bool cStreamdevDevice::ProvidesChannel(const cChannel *Channel, int Priority,
bool *NeedsDetachReceivers) const {
if (m_Disabled || Channel == m_DenyChannel)
bool res = false;
bool prio = Priority < 0 || Priority > this->Priority();
bool ndr = false;
if (!StreamdevClientSetup.StartClient)
return false;
Dprintf("ProvidesChannel, Channel=%s, Priority=%d, SocketPrio=%d\n", Channel->Name(), Priority, m_ClientSocket->Priority());
Dprintf("ProvidesChannel, Channel=%s, Prio=%d\n", Channel->Name(), Priority);
if (StreamdevClientSetup.MinPriority <= StreamdevClientSetup.MaxPriority)
{
@@ -114,41 +103,12 @@ bool cStreamdevDevice::ProvidesChannel(const cChannel *Channel, int Priority,
return false;
}
int newPrio = Priority;
if (Priority == LIVEPRIORITY) {
if (m_ClientSocket->ServerVersion() >= 100 || StreamdevClientSetup.LivePriority >= 0)
newPrio = StreamdevClientSetup.LivePriority;
}
#if APIVERSNUM >= 10725
bool prio = Priority == IDLEPRIORITY || newPrio >= m_ClientSocket->Priority();
#else
bool prio = Priority < 0 || newPrio > m_ClientSocket->Priority();
#endif
bool res = prio;
bool ndr = false;
#if APIVERSNUM >= 10722
if (IsTunedToTransponder(Channel)) {
#else
if (const_cast<cStreamdevDevice*>(this)->IsTunedToTransponder(Channel)) {
#endif
if (Channel->Ca() < CA_ENCRYPTED_MIN ||
(Channel->Vpid() && HasPid(Channel->Vpid())) ||
(Channel->Apid(0) && HasPid(Channel->Apid(0))))
res = true;
else
ndr = true;
}
else if (prio) {
if (Priority == LIVEPRIORITY && m_ClientSocket->ServerVersion() >= 100)
UpdatePriority(true);
res = m_ClientSocket->ProvidesChannel(Channel, newPrio);
ndr = Receiving();
if (m_ClientSocket->ServerVersion() >= 100)
UpdatePriority(false);
if (ClientSocket.DataSocket(siLive) != NULL
&& TRANSPONDER(Channel, m_Channel))
res = true;
else if (ProvidesCa(Channel)) {
res = prio && ClientSocket.ProvidesChannel(Channel, Priority);
ndr = true;
}
if (NeedsDetachReceivers)
@@ -159,93 +119,142 @@ bool cStreamdevDevice::ProvidesChannel(const cChannel *Channel, int Priority,
bool cStreamdevDevice::SetChannelDevice(const cChannel *Channel,
bool LiveView) {
bool res;
Dprintf("SetChannelDevice Channel: %s, LiveView: %s\n", Channel->Name(),
LiveView ? "true" : "false");
LOCK_THREAD;
m_UpdatePriority = ClientSocket.SupportsPrio();
if (LiveView)
return false;
if (Receiving() && IsTunedToTransponder(Channel) && (
Channel->Ca() < CA_ENCRYPTED_MIN ||
(Channel->Vpid() && HasPid(Channel->Vpid())) ||
(Channel->Apid(0) && HasPid(Channel->Apid(0))))) {
res = true;
}
else {
DetachAllReceivers();
m_Channel = Channel;
// Old servers delete cStreamdevLiveStreamer in ABRT.
// Delete it now or it will happen after we tuned to new channel
if (m_ClientSocket->ServerVersion() < 100)
CloseDvr();
res = m_ClientSocket->SetChannelDevice(m_Channel);
}
Dprintf("setchanneldevice res=%d\n", res);
return res;
if (ClientSocket.DataSocket(siLive) != NULL
&& TRANSPONDER(Channel, m_Channel))
return true;
DetachAllReceivers();
m_Channel = Channel;
bool r = ClientSocket.SetChannelDevice(m_Channel);
Dprintf("setchanneldevice r=%d\n", r);
return r;
}
bool cStreamdevDevice::SetPid(cPidHandle *Handle, int Type, bool On) {
Dprintf("SetPid, Pid=%d, Type=%d, On=%d, used=%d\n", Handle->pid, Type, On, Handle->used);
Dprintf("SetPid, Pid=%d, Type=%d, On=%d, used=%d\n", Handle->pid, Type, On,
Handle->used);
LOCK_THREAD;
m_UpdatePriority = ClientSocket.SupportsPrio();
if (On && !m_TSBuffer) {
Dprintf("SetPid: no data connection -> OpenDvr()");
OpenDvrInt();
}
bool res = true;
if (Handle->pid && (On || !Handle->used)) {
res = m_ClientSocket->SetPid(Handle->pid, On);
res = ClientSocket.SetPid(Handle->pid, On);
m_Pids += (!res) ? 0 : On ? 1 : -1;
if (m_Pids < 0)
m_Pids = 0;
if(m_Pids < 1 && m_DvrClosed) {
Dprintf("SetPid: 0 pids left -> CloseDvr()");
CloseDvrInt();
}
}
return res;
}
bool cStreamdevDevice::OpenDvrInt(void) {
Dprintf("OpenDvrInt\n");
LOCK_THREAD;
CloseDvrInt();
if (m_TSBuffer) {
Dprintf("cStreamdevDevice::OpenDvrInt(): DVR connection already open\n");
return true;
}
Dprintf("cStreamdevDevice::OpenDvrInt(): Connecting ...\n");
if (ClientSocket.CreateDataConnection(siLive)) {
m_TSBuffer = new cTSBuffer(*ClientSocket.DataSocket(siLive), MEGABYTE(2), CardIndex() + 1);
return true;
}
esyslog("cStreamdevDevice::OpenDvrInt(): DVR connection FAILED");
return false;
}
bool cStreamdevDevice::OpenDvr(void) {
Dprintf("OpenDvr\n");
LOCK_THREAD;
CloseDvr();
if (m_ClientSocket->CreateDataConnection(siLive)) {
m_TSBuffer = new cTSBuffer(*m_ClientSocket->DataSocket(siLive), MEGABYTE(2), CardIndex() + 1);
}
else {
esyslog("cStreamdevDevice::OpenDvr(): DVR connection FAILED");
}
return m_TSBuffer != NULL;
m_DvrClosed = false;
return OpenDvrInt();
}
void cStreamdevDevice::CloseDvrInt(void) {
Dprintf("CloseDvrInt\n");
LOCK_THREAD;
if (ClientSocket.CheckConnection()) {
if (!m_DvrClosed) {
Dprintf("cStreamdevDevice::CloseDvrInt(): m_DvrClosed=false -> not closing yet\n");
return;
}
if (m_Pids > 0) {
Dprintf("cStreamdevDevice::CloseDvrInt(): %d active pids -> not closing yet\n", m_Pids);
return;
}
} else {
Dprintf("cStreamdevDevice::CloseDvrInt(): Control connection gone !\n");
}
Dprintf("cStreamdevDevice::CloseDvrInt(): Closing DVR connection\n");
#if VDRVERSNUM < 10500
DELETENULL(m_TSBuffer);
ClientSocket.CloseDvr();
#else
// Hack for VDR 1.5.x clients (sometimes sending ABRT after TUNE)
// TODO: Find a clean solution to fix this
ClientSocket.SetChannelDevice(m_Channel);
ClientSocket.CloseDvr();
DELETENULL(m_TSBuffer);
#endif
}
void cStreamdevDevice::CloseDvr(void) {
Dprintf("CloseDvr\n");
LOCK_THREAD;
m_ClientSocket->CloseDvr();
DELETENULL(m_TSBuffer);
m_DvrClosed = true;
CloseDvrInt();
}
bool cStreamdevDevice::GetTSPacket(uchar *&Data) {
if (m_TSBuffer) {
if (m_TSBuffer && m_Device) {
Data = m_TSBuffer->Get();
#if 1 // TODO: this should be fixed in vdr cTSBuffer
// simple disconnect detection
static int m_TSFails = 0;
if (!Data) {
LOCK_THREAD;
if(!m_ClientSocket->DataSocket(siLive)) {
if(!ClientSocket.DataSocket(siLive)) {
return false; // triggers CloseDvr() + OpenDvr() in cDevice
}
cPoller Poller(*m_ClientSocket->DataSocket(siLive));
cPoller Poller(*ClientSocket.DataSocket(siLive));
errno = 0;
if (Poller.Poll() && !errno) {
char tmp[1];
if (recv(*m_ClientSocket->DataSocket(siLive), tmp, 1, MSG_PEEK) == 0 && !errno) {
if (recv(*ClientSocket.DataSocket(siLive), tmp, 1, MSG_PEEK) == 0 && !errno) {
esyslog("cStreamDevice::GetTSPacket: GetChecked: NOTHING (%d)", m_TSFails);
m_TSFails++;
if (m_TSFails > 10) {
isyslog("cStreamdevDevice::GetTSPacket(): disconnected");
m_Pids = 0;
CloseDvr();
CloseDvrInt();
m_TSFails = 0;
return false;
}
@@ -267,89 +276,52 @@ int cStreamdevDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask) {
return -1;
if (!m_ClientSocket->DataSocket(siLiveFilter)) {
if (m_ClientSocket->CreateDataConnection(siLiveFilter)) {
m_Filters->SetConnection(*m_ClientSocket->DataSocket(siLiveFilter));
if (!ClientSocket.DataSocket(siLiveFilter)) {
if (ClientSocket.CreateDataConnection(siLiveFilter)) {
m_Filters->SetConnection(*ClientSocket.DataSocket(siLiveFilter));
} else {
isyslog("cStreamdevDevice::OpenFilter: connect failed: %m");
return -1;
}
}
if (m_ClientSocket->SetFilter(Pid, Tid, Mask, true))
if (ClientSocket.SetFilter(Pid, Tid, Mask, true))
return m_Filters->OpenFilter(Pid, Tid, Mask);
return -1;
}
void cStreamdevDevice::CloseFilter(int Handle) {
if(m_Filters)
m_Filters->CloseFilter(Handle);
else
esyslog("cStreamdevDevice::CloseFilter called while m_Filters is null");
}
bool cStreamdevDevice::ReInit(bool Disable) {
LOCK_THREAD;
m_Disabled = Disable;
m_Filters->SetConnection(-1);
m_Pids = 0;
m_ClientSocket->Quit();
m_ClientSocket->Reset();
//DELETENULL(m_TSBuffer);
bool cStreamdevDevice::Init(void) {
if (m_Device == NULL && StreamdevClientSetup.StartClient)
new cStreamdevDevice;
return true;
}
void cStreamdevDevice::UpdatePriority(bool SwitchingChannels) const {
if (!m_Disabled) {
//LOCK_THREAD;
const_cast<cStreamdevDevice*>(this)->Lock();
if (m_ClientSocket->SupportsPrio() && m_ClientSocket->DataSocket(siLive)) {
int Priority = this->Priority();
// override TRANSFERPRIORITY (-1) with live TV priority from setup
if (Priority == TRANSFERPRIORITY && this == cDevice::ActualDevice()) {
Priority = StreamdevClientSetup.LivePriority;
// temporarily lower priority
if (SwitchingChannels)
Priority--;
if (Priority < 0 && m_ClientSocket->ServerVersion() < 100)
Priority = 0;
}
m_ClientSocket->SetPriority(Priority);
bool cStreamdevDevice::ReInit(void) {
if(m_Device) {
m_Device->Lock();
m_Device->m_Filters->SetConnection(-1);
m_Device->m_Pids = 0;
}
ClientSocket.Quit();
ClientSocket.Reset();
if (m_Device != NULL) {
//DELETENULL(m_Device->m_TSBuffer);
m_Device->Unlock();
}
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;
}
const_cast<cStreamdevDevice*>(this)->Unlock();
m_Device->Unlock();
}
}
cString cStreamdevDevice::DeviceName(void) const {
return StreamdevClientSetup.RemoteIp;
}
cString cStreamdevDevice::DeviceType(void) const {
static int dev = -1;
static cString devType("STRDev");
int d = -1;
if (m_ClientSocket->DataSocket(siLive) != NULL)
m_ClientSocket->GetSignal(NULL, NULL, &d);
if (d != dev) {
dev = d;
devType = d < 0 ? "STRDev" : *cString::sprintf("STRD%2d", d);
}
return devType;
}
int cStreamdevDevice::SignalStrength(void) const {
int strength = -1;
if (m_ClientSocket->DataSocket(siLive) != NULL)
m_ClientSocket->GetSignal(&strength, NULL, NULL);
return strength;
}
int cStreamdevDevice::SignalQuality(void) const {
int quality = -1;
if (m_ClientSocket->DataSocket(siLive) != NULL)
m_ClientSocket->GetSignal(NULL, &quality, NULL);
return quality;
}

View File

@@ -1,5 +1,5 @@
/*
* $Id: device.h,v 1.10 2010/08/18 10:26:55 schmirl Exp $
* $Id: device.h,v 1.7.2.2 2010/08/18 10:26:18 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_DEVICE_H
@@ -17,22 +17,22 @@ class cTBString;
class cStreamdevDevice: public cDevice {
private:
bool m_Disabled;
cClientSocket *m_ClientSocket;
const cChannel *m_Channel;
cTSBuffer *m_TSBuffer;
cStreamdevFilters *m_Filters;
int m_Pids;
int m_Priority;
bool m_UpdatePriority;
bool m_DvrClosed;
static const cChannel *m_DenyChannel;
static cStreamdevDevice *m_Device;
bool OpenDvrInt(void);
void CloseDvrInt(void);
protected:
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
#if APIVERSNUM >= 10738
virtual bool HasLock(int TimeoutMs) const
#else
virtual bool HasLock(int TimeoutMs)
#endif
{
//printf("HasLock is %d\n", (ClientSocket.DataSocket(siLive) != NULL));
//return ClientSocket.DataSocket(siLive) != NULL;
@@ -45,38 +45,23 @@ protected:
virtual bool GetTSPacket(uchar *&Data);
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
virtual void CloseFilter(int Handle);
public:
cStreamdevDevice(void);
virtual ~cStreamdevDevice();
virtual bool HasInternalCam(void) { return true; }
virtual int ProvidesCa(const cChannel *Channel) const;
virtual bool ProvidesSource(int Source) const;
virtual bool ProvidesTransponder(const cChannel *Channel) const;
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1,
bool *NeedsDetachReceivers = NULL) const;
#if APIVERSNUM >= 10700
virtual int NumProvidedSystems(void) const;
#endif
#if APIVERSNUM >= 10719
virtual bool AvoidRecording(void) const { return true; }
#endif
#if APIVERSNUM >= 10722
virtual bool IsTunedToTransponder(const cChannel *Channel) const;
#else
virtual bool IsTunedToTransponder(const cChannel *Channel);
#endif
virtual const cChannel *GetCurrentlyTunedTransponder(void) const;
virtual cString DeviceName(void) const;
virtual cString DeviceType(void) const;
virtual int SignalStrength(void) const;
virtual int SignalQuality(void) const;
bool ReInit(bool Disable);
void UpdatePriority(bool SwitchingChannels = false) const;
bool SuspendServer() { return m_ClientSocket->SuspendServer(); }
static void DenyChannel(const cChannel *Channel) { m_DenyChannel = Channel; }
static void UpdatePriority(void);
static bool Init(void);
static bool ReInit(void);
static cStreamdevDevice *GetDevice(void) { return m_Device; }
};
#endif // VDR_STREAMDEV_DEVICE_H

View File

@@ -1,33 +1,24 @@
/*
* $Id: filter.c,v 1.14 2009/02/13 13:02:39 schmirl Exp $
* $Id: filter.c,v 1.12.2.1 2009/02/13 13:02:33 schmirl Exp $
*/
#include "client/filter.h"
#include "client/socket.h"
#include "tools/select.h"
#include "common.h"
#include <sys/ioctl.h>
#include <string.h>
#include <vdr/device.h>
#define PID_MASK_HI 0x1F
// --- cStreamdevFilter ------------------------------------------------------
static int FilterSockBufSize_warn = 0;
class cStreamdevFilter: public cListObject {
private:
uchar m_Buffer[8192];
uchar m_Buffer[4096];
int m_Used;
int m_Pipe[2];
u_short m_Pid;
u_char m_Tid;
u_char m_Mask;
#ifdef TIOCOUTQ
unsigned long m_maxq;
unsigned long m_flushed;
#endif
public:
cStreamdevFilter(u_short Pid, u_char Tid, u_char Mask);
@@ -37,6 +28,7 @@ public:
bool PutSection(const uchar *Data, int Length, bool Pusi);
int ReadPipe(void) const { return m_Pipe[0]; }
bool IsClosed(void);
void Reset(void);
u_short Pid(void) const { return m_Pid; }
@@ -54,10 +46,6 @@ cStreamdevFilter::cStreamdevFilter(u_short Pid, u_char Tid, u_char Mask) {
m_Tid = Tid;
m_Mask = Mask;
m_Pipe[0] = m_Pipe[1] = -1;
#ifdef TIOCOUTQ
m_flushed = 0;
m_maxq = 0;
#endif
#ifdef SOCK_SEQPACKET
// SOCK_SEQPACKET (since kernel 2.6.4)
@@ -69,46 +57,7 @@ cStreamdevFilter::cStreamdevFilter(u_short Pid, u_char Tid, u_char Mask) {
esyslog("streamdev-client: couldn't open section filter socket: %m");
}
// Set buffer for socketpair. During certain situations, such as startup, channel/transponder
// change, VDR may lag in reading data. Instead of discarding it, we can buffer it.
// Buffer size required may be up to 4MByte.
if(StreamdevClientSetup.FilterSockBufSize) {
int sbs = StreamdevClientSetup.FilterSockBufSize;
int sbs2;
unsigned int sbss = sizeof(sbs);
int r;
r = setsockopt(m_Pipe[1], SOL_SOCKET, SO_SNDBUF, (char *)&sbs, sbss);
if(r < 0) {
isyslog("streamdev-client: setsockopt(SO_SNDBUF, %d) = %s", sbs, strerror(errno));
}
sbs2 = 0;
r = getsockopt(m_Pipe[1], SOL_SOCKET, SO_SNDBUF, (char *)&sbs2, &sbss);
if(r < 0 || !sbss || !sbs2) {
isyslog("streamdev-client: getsockopt(SO_SNDBUF, &%d, &%d) = %s", sbs2, sbss, strerror(errno));
} else {
// Linux actually returns double the requested size
// if everything works fine. And it actually buffers up to that double amount
// as can be seen from observing TIOCOUTQ (kernel 3.7/2014).
if(sbs2 > sbs)
sbs2 /= 2;
if(sbs2 < sbs) {
if(FilterSockBufSize_warn != sbs2) {
isyslog("streamdev-client: ******************************************************");
isyslog("streamdev-client: getsockopt(SO_SNDBUF) = %d < %d (configured).", sbs2, sbs);
isyslog("streamdev-client: Consider increasing system buffer size:");
isyslog("streamdev-client: 'sysctl net.core.wmem_max=%d'", sbs);
isyslog("streamdev-client: ******************************************************");
FilterSockBufSize_warn = sbs2;
}
}
}
}
if(fcntl(m_Pipe[0], F_SETFL, O_NONBLOCK) != 0 ||
else if(fcntl(m_Pipe[0], F_SETFL, O_NONBLOCK) != 0 ||
fcntl(m_Pipe[1], F_SETFL, O_NONBLOCK) != 0) {
esyslog("streamdev-client: couldn't set section filter socket to non-blocking mode: %m");
}
@@ -117,12 +66,11 @@ cStreamdevFilter::cStreamdevFilter(u_short Pid, u_char Tid, u_char Mask) {
cStreamdevFilter::~cStreamdevFilter() {
Dprintf("~cStreamdevFilter %p\n", this);
if (m_Pipe[0] >= 0) {
close(m_Pipe[0]);
}
if (m_Pipe[1] >= 0) {
// ownership of handle m_Pipe[0] has been transferred to VDR section handler
//if (m_Pipe[0] >= 0)
// close(m_Pipe[0]);
if (m_Pipe[1] >= 0)
close(m_Pipe[1]);
}
}
bool cStreamdevFilter::PutSection(const uchar *Data, int Length, bool Pusi) {
@@ -145,42 +93,13 @@ bool cStreamdevFilter::PutSection(const uchar *Data, int Length, bool Pusi) {
int length = (((m_Buffer[1] & 0x0F) << 8) | m_Buffer[2]) + 3;
if (m_Used == length) {
m_Used = 0;
#ifdef TIOCOUTQ
// If we can determine the queue size of the socket,
// we flush rather then let the socket drop random packets.
// This ensures that we have more contiguous set of packets
// on the receiver side.
if(m_flushed) {
unsigned long queue = 0;
ioctl(m_Pipe[1], TIOCOUTQ, &queue);
if(queue > m_maxq)
m_maxq = queue;
if(queue * 2 < m_maxq) {
dsyslog("cStreamdevFilter::PutSection(Pid:%d Tid: %d): "
"Flushed %ld bytes, max queue: %ld",
m_Pid, m_Tid, m_flushed, m_maxq);
m_flushed = m_maxq = 0;
if (write(m_Pipe[1], m_Buffer, length) < 0) {
if(errno == EAGAIN || errno == EWOULDBLOCK)
dsyslog("cStreamdevFilter::PutSection socket overflow, "
"Pid %4d Tid %3d", m_Pid, m_Tid);
} else {
m_flushed += length;
}
}
if(!m_flushed)
#endif
if(write(m_Pipe[1], m_Buffer, length) < 0) {
if(errno != EAGAIN && errno != EWOULDBLOCK) {
dsyslog("cStreamdevFilter::PutSection(Pid:%d Tid: %d): error: %s",
m_Pid, m_Tid, strerror(errno));
else
return false;
} else {
#ifdef TIOCOUTQ
m_flushed += length;
#else
dsyslog("cStreamdevFilter::PutSection(Pid:%d Tid: %d): "
"Dropping packet %ld bytes (queue overflow)",
m_Pid, m_Tid, length);
#endif
}
}
}
@@ -203,11 +122,29 @@ void cStreamdevFilter::Reset(void) {
m_Used = 0;
}
bool cStreamdevFilter::IsClosed(void) {
char m_Buffer[3] = {0,0,0}; /* tid 0, 0 bytes */
// Test if pipe/socket has been closed by writing empty section
if (write(m_Pipe[1], m_Buffer, 3) < 0 &&
errno != EAGAIN &&
errno != EWOULDBLOCK) {
if (errno != ECONNREFUSED &&
errno != ECONNRESET &&
errno != EPIPE)
esyslog("cStreamdevFilter::IsClosed failed: %m");
return true;
}
return false;
}
// --- cStreamdevFilters -----------------------------------------------------
cStreamdevFilters::cStreamdevFilters(cClientSocket *ClientSocket):
cStreamdevFilters::cStreamdevFilters(void):
cThread("streamdev-client: sections assembler") {
m_ClientSocket = ClientSocket;
m_TSBuffer = NULL;
}
@@ -216,27 +153,43 @@ cStreamdevFilters::~cStreamdevFilters() {
}
int cStreamdevFilters::OpenFilter(u_short Pid, u_char Tid, u_char Mask) {
CarbageCollect();
cStreamdevFilter *f = new cStreamdevFilter(Pid, Tid, Mask);
int fh = f->ReadPipe();
LOCK_THREAD;
Lock();
Add(f);
Unlock();
return fh;
}
void cStreamdevFilters::CloseFilter(int Handle) {
void cStreamdevFilters::CarbageCollect(void) {
LOCK_THREAD;
for (cStreamdevFilter *fi = First(); fi;) {
if (fi->IsClosed()) {
if (errno == ECONNREFUSED ||
errno == ECONNRESET ||
errno == EPIPE) {
ClientSocket.SetFilter(fi->Pid(), fi->Tid(), fi->Mask(), false);
Dprintf("cStreamdevFilters::CarbageCollector: filter closed: Pid %4d, Tid %3d, Mask %2x (%d filters left)",
(int)fi->Pid(), (int)fi->Tid(), fi->Mask(), Count()-1);
for (cStreamdevFilter *fi = First(); fi; fi = Next(fi)) {
if(fi->ReadPipe() == Handle) {
// isyslog("cStreamdevFilters::CloseFilter(%d): Pid %4d, Tid %3d, Mask %2x (%d filters left)\n",
// Handle, (int)fi->Pid(), (int)fi->Tid(), fi->Mask(), Count()-1);
Del(fi);
return;
cStreamdevFilter *next = Prev(fi);
Del(fi);
fi = next ? Next(next) : First();
} else {
esyslog("cStreamdevFilters::CarbageCollector() error: "
"Pid %4d, Tid %3d, Mask %2x (%d filters left) failed",
(int)fi->Pid(), (int)fi->Tid(), fi->Mask(), Count()-1);
LOG_ERROR;
fi = Next(fi);
}
} else {
fi = Next(fi);
}
}
esyslog("cStreamdevFilters::CloseFilter(%d): failed (%d filters left)\n", Handle, Count()-1);
}
bool cStreamdevFilters::ReActivateFilters(void)
@@ -244,8 +197,9 @@ bool cStreamdevFilters::ReActivateFilters(void)
LOCK_THREAD;
bool res = true;
CarbageCollect();
for (cStreamdevFilter *fi = First(); fi; fi = Next(fi)) {
res = m_ClientSocket->SetFilter(fi->Pid(), fi->Tid(), fi->Mask(), true) && res;
res = ClientSocket.SetFilter(fi->Pid(), fi->Tid(), fi->Mask(), true) && res;
Dprintf("ReActivateFilters(%d, %d, %d) -> %s", fi->Pid(), fi->Tid(), fi->Mask(), res ? "Ok" :"FAIL");
}
return res;
@@ -296,7 +250,7 @@ void cStreamdevFilters::Action(void) {
Dprintf("FATAL ERROR: %m\n");
esyslog("streamdev-client: couldn't send section packet: %m");
}
m_ClientSocket->SetFilter(f->Pid(), f->Tid(), f->Mask(), false);
ClientSocket.SetFilter(f->Pid(), f->Tid(), f->Mask(), false);
Del(f);
// Filter was closed.
// - need to check remaining filters for another match
@@ -306,7 +260,7 @@ void cStreamdevFilters::Action(void) {
} else {
#if 1 // TODO: this should be fixed in vdr cTSBuffer
// Check disconnection
int fd = *m_ClientSocket->DataSocket(siLiveFilter);
int fd = *ClientSocket.DataSocket(siLiveFilter);
if(fd < 0)
break;
cPoller Poller(fd);
@@ -318,7 +272,7 @@ void cStreamdevFilters::Action(void) {
++fails;
if (fails >= 10) {
esyslog("cStreamdevFilters::Action(): stream disconnected ?");
m_ClientSocket->CloseDataConnection(siLiveFilter);
ClientSocket.CloseDataConnection(siLiveFilter);
break;
}
} else {

View File

@@ -11,24 +11,23 @@
class cTSBuffer;
class cStreamdevFilter;
class cClientSocket;
class cStreamdevFilters: public cList<cStreamdevFilter>, public cThread {
private:
cClientSocket *m_ClientSocket;
cTSBuffer *m_TSBuffer;
protected:
virtual void Action(void);
void CarbageCollect(void);
bool ReActivateFilters(void);
public:
cStreamdevFilters(cClientSocket *ClientSocket);
cStreamdevFilters(void);
virtual ~cStreamdevFilters();
void SetConnection(int Handle);
int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
void CloseFilter(int Handle);
};
#endif // VDR_STREAMDEV_FILTER_H

View File

@@ -1,62 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Frank Schmirler <vdrdev@schmirler.de>, 2008
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2014-10-20 22:57+0200\n"
"PO-Revision-Date: 2008-03-30 02:11+0200\n"
"Last-Translator: Frank Schmirler <vdrdev@schmirler.de>\n"
"Language-Team: German <vdr@linuxtv.org>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-15\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Hide Mainmenu Entry"
msgstr "Hauptmenüeintrag verstecken"
msgid "Simultaneously used Devices"
msgstr "Gleichzeitig genutzte DVB-Karten"
msgid "Remote IP"
msgstr "IP der Gegenseite"
msgid "Remote Port"
msgstr "Port der Gegenseite"
msgid "Timeout (s)"
msgstr "Timeout (s)"
msgid "Filter Streaming"
msgstr "Filter-Daten streamen"
msgid "Filter SockBufSize"
msgstr "Filter Socket Puffergröße"
msgid "Live TV Priority"
msgstr "Live TV Priorität"
msgid "Minimum Priority"
msgstr "Minimale Priorität"
msgid "Maximum Priority"
msgstr "Maximale Priorität"
msgid "Broadcast Systems / Cost"
msgstr "Empfangssysteme / Kosten"
msgid "VTP Streaming Client"
msgstr "VTP Streaming Client"
msgid "Suspend Server"
msgstr "Server pausieren"
msgid "Server is suspended"
msgstr "Server ist pausiert"
msgid "Couldn't suspend Server!"
msgstr "Konnte Server nicht pausieren!"

View File

@@ -1,62 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Javier Bradineras <jbradi@hotmail.com>, 2011
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2015-01-16 22:32+0100\n"
"PO-Revision-Date: 2010-06-19 03:58+0100\n"
"Last-Translator: Javier Bradineras <jbradi@hotmail.com>\n"
"Language-Team: Spanish <vdr@linuxtv.org>\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-15\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Hide Mainmenu Entry"
msgstr "Ocultar entrada en menú principal"
msgid "Simultaneously used Devices"
msgstr ""
msgid "Remote IP"
msgstr "Indicar IP del Servidor"
msgid "Remote Port"
msgstr "Indicar puerto remoto del Servidor"
msgid "Timeout (s)"
msgstr ""
msgid "Filter Streaming"
msgstr "Filtrar transmisión"
msgid "Filter SockBufSize"
msgstr ""
msgid "Live TV Priority"
msgstr ""
msgid "Minimum Priority"
msgstr "Prioridad mínima"
msgid "Maximum Priority"
msgstr "Prioridad máxima"
msgid "Broadcast Systems / Cost"
msgstr ""
msgid "VTP Streaming Client"
msgstr "Cliente trasmisión VTP"
msgid "Suspend Server"
msgstr "Suspender servidor"
msgid "Server is suspended"
msgstr "Servidor en suspensión"
msgid "Couldn't suspend Server!"
msgstr "Imposible suspender el servidor!"

View File

@@ -1,62 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Rolf Ahrenberg, 2008-
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2015-01-16 22:32+0100\n"
"PO-Revision-Date: 2008-03-30 02:11+0200\n"
"Last-Translator: Rolf Ahrenberg\n"
"Language-Team: Finnish <vdr@linuxtv.org>\n"
"Language: fi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Hide Mainmenu Entry"
msgstr "Piilota valinta päävalikosta"
msgid "Simultaneously used Devices"
msgstr "Yhtäaikaiset laitteet"
msgid "Remote IP"
msgstr "Etäkoneen IP-osoite"
msgid "Remote Port"
msgstr "Etäkoneen portti"
msgid "Timeout (s)"
msgstr "Yhteyden aikakatkaisu (s)"
msgid "Filter Streaming"
msgstr "Suodatetun tiedon suoratoisto"
msgid "Filter SockBufSize"
msgstr ""
msgid "Live TV Priority"
msgstr "Live-katselun prioriteetti"
msgid "Minimum Priority"
msgstr "Pienin prioriteetti"
msgid "Maximum Priority"
msgstr "Suurin prioriteetti"
msgid "Broadcast Systems / Cost"
msgstr "Lähetysjärjestelmien suhdeluku"
msgid "VTP Streaming Client"
msgstr "VTP-suoratoistoasiakas"
msgid "Suspend Server"
msgstr "Pysäytä palvelin"
msgid "Server is suspended"
msgstr "Palvelin on pysäytetty"
msgid "Couldn't suspend Server!"
msgstr "Palvelinta ei onnistuttu pysäyttämään!"

View File

@@ -1,62 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Frank Schmirler <vdrdev@schmirler.de>, 2008
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2015-01-16 22:32+0100\n"
"PO-Revision-Date: 2008-03-30 02:11+0200\n"
"Last-Translator: micky979 <micky979@free.fr>\n"
"Language-Team: French <vdr@linuxtv.org>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-15\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Hide Mainmenu Entry"
msgstr "Masquer dans le menu principal"
msgid "Simultaneously used Devices"
msgstr ""
msgid "Remote IP"
msgstr "Adresse IP du serveur"
msgid "Remote Port"
msgstr "Port du serveur"
msgid "Timeout (s)"
msgstr ""
msgid "Filter Streaming"
msgstr "Filtre streaming"
msgid "Filter SockBufSize"
msgstr ""
msgid "Live TV Priority"
msgstr ""
msgid "Minimum Priority"
msgstr ""
msgid "Maximum Priority"
msgstr ""
msgid "Broadcast Systems / Cost"
msgstr ""
msgid "VTP Streaming Client"
msgstr "Client de streaming VTP"
msgid "Suspend Server"
msgstr "Suspendre le serveur"
msgid "Server is suspended"
msgstr "Le serveur est suspendu"
msgid "Couldn't suspend Server!"
msgstr "Impossible de suspendre le serveur!"

View File

@@ -1,64 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Alberto Carraro <bertocar@tin.it>, 2001
# Antonio Ospite <ospite@studenti.unina.it>, 2003
# Sean Carlos <seanc@libero.it>, 2005
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2015-01-16 22:32+0100\n"
"PO-Revision-Date: 2012-06-10 20:34+0100\n"
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
"Language-Team: Italian <vdr@linuxtv.org>\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Hide Mainmenu Entry"
msgstr "Nascondi voce menu principale"
msgid "Simultaneously used Devices"
msgstr ""
msgid "Remote IP"
msgstr "Indirizzo IP del Server"
msgid "Remote Port"
msgstr "Porta Server Remoto"
msgid "Timeout (s)"
msgstr "Scadenza (s)"
msgid "Filter Streaming"
msgstr "Filtra trasmissione"
msgid "Filter SockBufSize"
msgstr ""
msgid "Live TV Priority"
msgstr "Priorità TV dal vivo"
msgid "Minimum Priority"
msgstr "Priorità minima"
msgid "Maximum Priority"
msgstr "Priorità massima"
msgid "Broadcast Systems / Cost"
msgstr "Costo / sistemi trasmissione"
msgid "VTP Streaming Client"
msgstr "Client trasmissione VTP"
msgid "Suspend Server"
msgstr "Sospendi Server"
msgid "Server is suspended"
msgstr "Server sospeso"
msgid "Couldn't suspend Server!"
msgstr "Impossibile sospendere il server!"

View File

@@ -1,62 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Frank Schmirler <vdrdev@schmirler.de>, 2008
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2015-01-16 22:32+0100\n"
"PO-Revision-Date: 2009-11-26 21:57+0200\n"
"Last-Translator: Valdemaras Pipiras <varas@ambernet.lt>\n"
"Language-Team: Lithuanian <vdr@linuxtv.org>\n"
"Language: lt\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Hide Mainmenu Entry"
msgstr "Paslėpti pagrindinio meniu įrašą"
msgid "Simultaneously used Devices"
msgstr ""
msgid "Remote IP"
msgstr "Nuotolinis IP adresas"
msgid "Remote Port"
msgstr "Nuotolinis portas"
msgid "Timeout (s)"
msgstr ""
msgid "Filter Streaming"
msgstr "Filtruoti transliavimą"
msgid "Filter SockBufSize"
msgstr ""
msgid "Live TV Priority"
msgstr ""
msgid "Minimum Priority"
msgstr "Minimalus prioritetas"
msgid "Maximum Priority"
msgstr "Maksimalus prioritetas"
msgid "Broadcast Systems / Cost"
msgstr ""
msgid "VTP Streaming Client"
msgstr "VTP transliavimo standartas"
msgid "Suspend Server"
msgstr "Sustabdyti serverį"
msgid "Server is suspended"
msgstr "Serveris sustabdytas"
msgid "Couldn't suspend Server!"
msgstr "Negali sustabdyti serverio!"

View File

@@ -1,63 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See
# This file is distributed under the same license as the VDR streamdev package.
# Tomasz Maciej Nowak, 2014
#
msgid ""
msgstr ""
"Project-Id-Version: vdr-streamdev-client 0.6.1-git\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2015-01-16 22:32+0100\n"
"PO-Revision-Date: 2014-11-24 18:07+0100\n"
"Last-Translator: Tomasz Maciej Nowak <tomek_n@o2.pl>\n"
"Language-Team: Polish <vdr@linuxtv.org>\n"
"Language: pl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-2\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.6.10\n"
msgid "Hide Mainmenu Entry"
msgstr "Ukryj pozycjê w g³ównym menu"
msgid "Simultaneously used Devices"
msgstr "Jednocze¶nie u¿ywane urz±dzenia"
msgid "Remote IP"
msgstr "Adres serwera"
msgid "Remote Port"
msgstr "Port serwera"
msgid "Timeout (s)"
msgstr "Czas oczekiwania (s)"
msgid "Filter Streaming"
msgstr "Filtruj strumieñ"
msgid "Filter SockBufSize"
msgstr ""
msgid "Live TV Priority"
msgstr "Priorytet lokalnych ur±dzeñ"
msgid "Minimum Priority"
msgstr "Minimalny priorytet"
msgid "Maximum Priority"
msgstr "Maksymalny priorytet"
msgid "Broadcast Systems / Cost"
msgstr "Koszt / systemy transmisji"
msgid "VTP Streaming Client"
msgstr "Klient strumieniowania VTP"
msgid "Suspend Server"
msgstr "Wstrzymaj serwer"
msgid "Server is suspended"
msgstr "Serwer jest wstrzymany"
msgid "Couldn't suspend Server!"
msgstr "Nie mo¿na wstrzymaæ serwera!"

View File

@@ -1,62 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Frank Schmirler <vdrdev@schmirler.de>, 2008
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2015-01-16 22:32+0100\n"
"PO-Revision-Date: 2008-06-26 15:36+0100\n"
"Last-Translator: Oleg Roitburd <oleg@roitburd.de>\n"
"Language-Team: Russian <vdr@linuxtv.org>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-5\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Hide Mainmenu Entry"
msgstr "ÁßàïâÐâì Ò ÓÛÐÒÝÞÜ ÜÕÝî"
msgid "Simultaneously used Devices"
msgstr ""
msgid "Remote IP"
msgstr "ÃÔÐÛÕÝÝëÙ IP"
msgid "Remote Port"
msgstr "ÃÔÐÛÕÝÝëÙ ßÞàâ"
msgid "Timeout (s)"
msgstr ""
msgid "Filter Streaming"
msgstr "ÄØÛìâà ßÞâÞÚÐ"
msgid "Filter SockBufSize"
msgstr ""
msgid "Live TV Priority"
msgstr ""
msgid "Minimum Priority"
msgstr ""
msgid "Maximum Priority"
msgstr ""
msgid "Broadcast Systems / Cost"
msgstr ""
msgid "VTP Streaming Client"
msgstr "VTP Streaming ÚÛØÕÝâ"
msgid "Suspend Server"
msgstr "¾áâÐÝÞÒØâì áÕàÒÕà"
msgid "Server is suspended"
msgstr "ÁÕàÒÕà ÞáâÐÝÞÒÛÕÝ"
msgid "Couldn't suspend Server!"
msgstr "ÝÕ ÜÞÓã ÞáâÐÝÞÒØâì áÕàÒÕà"

View File

@@ -1,64 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2009 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Milan Hrala <hrala.milan@gmail.com>, 2009
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev_SK\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2015-01-16 22:32+0100\n"
"PO-Revision-Date: \n"
"Last-Translator: Milan Hrala <hrala.milan@gmail.com>\n"
"Language-Team: Slovak <hrala.milan@gmail.com>\n"
"Language: sk\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-2\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-Language: Slovak\n"
"X-Poedit-Country: SLOVAKIA\n"
msgid "Hide Mainmenu Entry"
msgstr "Schova» polo¾ku v hlavnom menu"
msgid "Simultaneously used Devices"
msgstr "Súbe¾ne pou¾íva» zariadenia"
msgid "Remote IP"
msgstr "Vzdialená IP"
msgid "Remote Port"
msgstr "Vzdialený port"
msgid "Timeout (s)"
msgstr "Èasový limit (s)"
msgid "Filter Streaming"
msgstr "Filtrova» dátový prúd"
msgid "Filter SockBufSize"
msgstr ""
msgid "Live TV Priority"
msgstr "Priorita ¾ivého vysielania"
msgid "Minimum Priority"
msgstr "Minimálna priorita"
msgid "Maximum Priority"
msgstr "Maximálna priorita"
msgid "Broadcast Systems / Cost"
msgstr "Systémy vysielania / Hodnota"
msgid "VTP Streaming Client"
msgstr "VDR klient streamovania"
msgid "Suspend Server"
msgstr "Pozastavi» server"
msgid "Server is suspended"
msgstr "Server je doèasne pozastavený"
msgid "Couldn't suspend Server!"
msgstr "Server sa nepodarilo pozastavi»!"

View File

@@ -1,32 +1,23 @@
/*
* $Id: setup.c,v 1.10 2010/06/08 05:55:17 schmirl Exp $
* $Id: setup.c,v 1.5.2.4 2010/06/08 05:56:15 schmirl Exp $
*/
#include <vdr/menuitems.h>
#include "client/setup.h"
#include "client/streamdev-client.h"
#ifndef MINPRIORITY
#define MINPRIORITY -MAXPRIORITY
#endif
#include "client/device.h"
#include "i18n.h"
cStreamdevClientSetup StreamdevClientSetup;
cStreamdevClientSetup::cStreamdevClientSetup(void) {
StartClient = false;
RemotePort = 2004;
Timeout = 2;
StreamFilters = false;
HideMenuEntry = false;
LivePriority = 0;
MinPriority = MINPRIORITY;
MinPriority = -1;
MaxPriority = MAXPRIORITY;
#if APIVERSNUM >= 10700
NumProvidedSystems = 1;
#endif
strcpy(RemoteIp, "");
FilterSockBufSize = 0;
}
bool cStreamdevClientSetup::SetupParse(const char *Name, const char *Value) {
@@ -38,40 +29,24 @@ bool cStreamdevClientSetup::SetupParse(const char *Name, const char *Value) {
strcpy(RemoteIp, Value);
}
else if (strcmp(Name, "RemotePort") == 0) RemotePort = atoi(Value);
else if (strcmp(Name, "Timeout") == 0) Timeout = atoi(Value);
else if (strcmp(Name, "StreamFilters") == 0) StreamFilters = atoi(Value);
else if (strcmp(Name, "HideMenuEntry") == 0) HideMenuEntry = atoi(Value);
else if (strcmp(Name, "LivePriority") == 0) LivePriority = atoi(Value);
else if (strcmp(Name, "MinPriority") == 0) MinPriority = atoi(Value);
else if (strcmp(Name, "MaxPriority") == 0) MaxPriority = atoi(Value);
else if (strcmp(Name, "FilterSockBufSize") == 0) FilterSockBufSize = atoi(Value);
#if APIVERSNUM >= 10700
else if (strcmp(Name, "NumProvidedSystems") == 0) NumProvidedSystems = atoi(Value);
#endif
else return false;
return true;
}
cStreamdevClientMenuSetupPage::cStreamdevClientMenuSetupPage(cPluginStreamdevClient *Plugin) {
m_Plugin = Plugin;
cStreamdevClientMenuSetupPage::cStreamdevClientMenuSetupPage(void) {
m_NewSetup = StreamdevClientSetup;
Add(new cMenuEditBoolItem(tr("Hide Mainmenu Entry"), &m_NewSetup.HideMenuEntry));
Add(new cMenuEditIntItem (tr("Simultaneously used Devices"), &m_NewSetup.StartClient, 0, STREAMDEV_MAXDEVICES));
Add(new cMenuEditBoolItem(tr("Start Client"), &m_NewSetup.StartClient));
Add(new cMenuEditIpItem (tr("Remote IP"), m_NewSetup.RemoteIp));
Add(new cMenuEditIntItem (tr("Remote Port"), &m_NewSetup.RemotePort, 0, 65535));
Add(new cMenuEditIntItem (tr("Timeout (s)"), &m_NewSetup.Timeout, 1, 15));
Add(new cMenuEditBoolItem(tr("Filter Streaming"), &m_NewSetup.StreamFilters));
if(m_NewSetup.StreamFilters)
Add(new cMenuEditIntItem (tr("Filter SockBufSize"), &m_NewSetup.FilterSockBufSize, 0, 8192000));
Add(new cMenuEditIntItem (tr("Live TV Priority"), &m_NewSetup.LivePriority, MINPRIORITY, MAXPRIORITY));
Add(new cMenuEditIntItem (tr("Minimum Priority"), &m_NewSetup.MinPriority, MINPRIORITY, MAXPRIORITY));
Add(new cMenuEditIntItem (tr("Maximum Priority"), &m_NewSetup.MaxPriority, MINPRIORITY, MAXPRIORITY));
#if APIVERSNUM >= 10715
Add(new cMenuEditIntItem (tr("Broadcast Systems / Cost"), &m_NewSetup.NumProvidedSystems, 1, 15));
#elif APIVERSNUM >= 10700
Add(new cMenuEditIntItem (tr("Broadcast Systems / Cost"), &m_NewSetup.NumProvidedSystems, 1, 4));
#endif
Add(new cMenuEditIntItem (tr("Minimum Priority"), &m_NewSetup.MinPriority, -1, MAXPRIORITY));
Add(new cMenuEditIntItem (tr("Maximum Priority"), &m_NewSetup.MaxPriority, -1, MAXPRIORITY));
SetCurrent(Get(0));
}
@@ -79,25 +54,24 @@ cStreamdevClientMenuSetupPage::~cStreamdevClientMenuSetupPage() {
}
void cStreamdevClientMenuSetupPage::Store(void) {
if (m_NewSetup.StartClient != StreamdevClientSetup.StartClient) {
if (m_NewSetup.StartClient)
cStreamdevDevice::Init();
}
SetupStore("StartClient", m_NewSetup.StartClient);
if (strcmp(m_NewSetup.RemoteIp, "") == 0)
SetupStore("RemoteIp", "-none-");
else
SetupStore("RemoteIp", m_NewSetup.RemoteIp);
SetupStore("RemotePort", m_NewSetup.RemotePort);
SetupStore("Timeout", m_NewSetup.Timeout);
SetupStore("StreamFilters", m_NewSetup.StreamFilters);
SetupStore("HideMenuEntry", m_NewSetup.HideMenuEntry);
SetupStore("LivePriority", m_NewSetup.LivePriority);
SetupStore("MinPriority", m_NewSetup.MinPriority);
SetupStore("MaxPriority", m_NewSetup.MaxPriority);
#if APIVERSNUM >= 10700
SetupStore("NumProvidedSystems", m_NewSetup.NumProvidedSystems);
#endif
SetupStore("FilterSockBufSize", m_NewSetup.FilterSockBufSize);
StreamdevClientSetup = m_NewSetup;
m_Plugin->Initialize();
cStreamdevDevice::ReInit();
}

View File

@@ -1,5 +1,5 @@
/*
* $Id: setup.h,v 1.7 2010/06/08 05:55:17 schmirl Exp $
* $Id: setup.h,v 1.4.2.3 2010/06/08 05:56:15 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_SETUPCLIENT_H
@@ -15,32 +15,23 @@ struct cStreamdevClientSetup {
int StartClient;
char RemoteIp[20];
int RemotePort;
int Timeout;
int StreamFilters;
int FilterSockBufSize;
int HideMenuEntry;
int LivePriority;
int MinPriority;
int MaxPriority;
#if APIVERSNUM >= 10700
int NumProvidedSystems;
#endif
};
extern cStreamdevClientSetup StreamdevClientSetup;
class cPluginStreamdevClient;
class cStreamdevClientMenuSetupPage: public cMenuSetupPage {
private:
cPluginStreamdevClient *m_Plugin;
cStreamdevClientSetup m_NewSetup;
cStreamdevClientSetup m_NewSetup;
protected:
virtual void Store(void);
public:
cStreamdevClientMenuSetupPage(cPluginStreamdevClient *Plugin);
cStreamdevClientMenuSetupPage(void);
virtual ~cStreamdevClientMenuSetupPage();
};

View File

@@ -1,5 +1,5 @@
/*
* $Id: socket.c,v 1.15 2010/08/18 10:26:55 schmirl Exp $
* $Id: socket.c,v 1.11.2.3 2010/08/18 10:26:18 schmirl Exp $
*/
#include <tools/select.h>
@@ -11,24 +11,17 @@
#define MINLOGREPEAT 10 //don't log connect failures too often (seconds)
// timeout for writing to command socket
#define WRITE_TIMEOUT_MS 200
#define QUIT_TIMEOUT_MS 500
#include "client/socket.h"
#include "client/setup.h"
#include "common.h"
#include "i18n.h"
cClientSocket ClientSocket;
cClientSocket::cClientSocket(void)
{
memset(m_DataSockets, 0, sizeof(cTBSocket*) * si_Count);
m_ServerVersion = 0;
m_Priority = -100;
m_Prio = false;
m_Abort = false;
m_LastSignalUpdate = 0;
m_LastSignalStrength = -1;
m_LastSignalQuality = -1;
m_LastDev = -1;
Reset();
}
@@ -40,62 +33,53 @@ cClientSocket::~cClientSocket()
void cClientSocket::Reset(void)
{
for (int it = 0; it < si_Count; ++it)
DELETENULL(m_DataSockets[it]);
m_Priority = -100;
for (int it = 0; it < si_Count; ++it) {
if (m_DataSockets[it] != NULL)
DELETENULL(m_DataSockets[it]);
}
}
cTBSocket *cClientSocket::DataSocket(eSocketId Id) const {
return m_DataSockets[Id];
}
bool cClientSocket::Command(const std::string &Command, uint Expected)
bool cClientSocket::Command(const std::string &Command, uint Expected, uint TimeoutMs)
{
uint code = 0;
std::string buffer;
if (Send(Command) && Receive(Command, &code, &buffer)) {
if (code == Expected)
return true;
errno = 0;
dsyslog("streamdev-client: Command '%s' rejected by %s:%d: %s",
Command.c_str(), RemoteIp().c_str(), RemotePort(), buffer.c_str());
}
return false;
}
bool cClientSocket::Send(const std::string &Command)
{
std::string pkt = Command + "\015\012";
Dprintf("OUT: |%s|\n", Command.c_str());
errno = 0;
if (!TimedWrite(pkt.c_str(), pkt.size(), WRITE_TIMEOUT_MS)) {
esyslog("ERROR: streamdev-client: Failed sending command '%s' to %s:%d: %s",
Command.c_str(), RemoteIp().c_str(), RemotePort(), strerror(errno));
cTimeMs starttime;
if (!TimedWrite(pkt.c_str(), pkt.size(), TimeoutMs)) {
esyslog("Streamdev: Lost connection to %s:%d: %s", RemoteIp().c_str(), RemotePort(),
strerror(errno));
Close();
return false;
}
uint64_t elapsed = starttime.Elapsed();
if (Expected != 0) { // XXX+ What if elapsed > TimeoutMs?
TimeoutMs -= elapsed;
return Expect(Expected, NULL, TimeoutMs);
}
return true;
}
#define TIMEOUT_MS 1000
bool cClientSocket::Receive(const std::string &Command, uint *Code, std::string *Result, uint TimeoutMs) {
bool cClientSocket::Expect(uint Expected, std::string *Result, uint TimeoutMs) {
char *endptr;
int bufcount;
do
{
errno = 0;
bufcount = ReadUntil(m_Buffer, sizeof(m_Buffer) - 1, "\012", TimeoutMs < TIMEOUT_MS ? TimeoutMs : TIMEOUT_MS);
if (bufcount == -1) {
if (m_Abort)
return false;
if (errno != ETIMEDOUT || TimeoutMs <= TIMEOUT_MS) {
esyslog("ERROR: streamdev-client: Failed reading reply to '%s' from %s:%d: %s",
Command.c_str(), RemoteIp().c_str(), RemotePort(), strerror(errno));
Close();
return false;
}
TimeoutMs -= TIMEOUT_MS;
}
} while (bufcount == -1);
bool res;
errno = 0;
if ((bufcount = ReadUntil(m_Buffer, sizeof(m_Buffer) - 1, "\012", TimeoutMs)) == -1) {
esyslog("Streamdev: Lost connection to %s:%d: %s", RemoteIp().c_str(), RemotePort(),
strerror(errno));
Close();
return false;
}
if (m_Buffer[bufcount - 1] == '\015')
--bufcount;
m_Buffer[bufcount] = '\0';
@@ -103,9 +87,9 @@ bool cClientSocket::Receive(const std::string &Command, uint *Code, std::string
if (Result != NULL)
*Result = m_Buffer;
if (Code != NULL)
*Code = strtoul(m_Buffer, NULL, 10);
return true;
res = strtoul(m_Buffer, &endptr, 10) == Expected;
return res;
}
bool cClientSocket::CheckConnection(void) {
@@ -114,22 +98,25 @@ bool cClientSocket::CheckConnection(void) {
if (IsOpen()) {
cTBSelect select;
Dprintf("connection open\n");
// XXX+ check if connection is still alive (is there a better way?)
// There REALLY shouldn't be anything readable according to PROTOCOL here
// If there is, assume it's an eof signal (subseq. read would return 0)
select.Add(*this, false);
int res;
if ((res = select.Select(0)) == 0) {
Dprintf("select said nothing happened\n");
return true;
}
Dprintf("closing connection (res was %d)\n", res);
Dprintf("closing connection (res was %d)", res);
Close();
}
if (!Connect(StreamdevClientSetup.RemoteIp, StreamdevClientSetup.RemotePort, StreamdevClientSetup.Timeout * 1000)){
if (!Connect(StreamdevClientSetup.RemoteIp, StreamdevClientSetup.RemotePort)){
static time_t lastTime = 0;
if (time(NULL) - lastTime > MINLOGREPEAT) {
esyslog("ERROR: streamdev-client: Couldn't connect to %s:%d: %s",
esyslog("ERROR: Streamdev: Couldn't connect to %s:%d: %s",
(const char*)StreamdevClientSetup.RemoteIp,
StreamdevClientSetup.RemotePort, strerror(errno));
lastTime = time(NULL);
@@ -137,51 +124,34 @@ bool cClientSocket::CheckConnection(void) {
return false;
}
uint code = 0;
std::string buffer;
if (!Receive("<connect>", &code, &buffer)) {
Close();
return false;
}
if (code != 220) {
esyslog("ERROR: streamdev-client: Didn't receive greeting from %s:%d: %s",
RemoteIp().c_str(), RemotePort(), buffer.c_str());
if (!Expect(220)) {
if (errno == 0)
esyslog("ERROR: Streamdev: Didn't receive greeting from %s:%d",
RemoteIp().c_str(), RemotePort());
Close();
return false;
}
unsigned int major, minor;
if (sscanf(buffer.c_str(), "%*u VTP/%u.%u", &major, &minor) == 2)
m_ServerVersion = major * 100 + minor;
if (m_ServerVersion == 0) {
if (!Command("CAPS TSPIDS", 220)) {
Close();
return false;
}
const char *Filters = "";
if(Command("CAPS FILTERS", 220))
Filters = ",FILTERS";
const char *Prio = "";
if(Command("CAPS PRIO", 220)) {
Prio = ",PRIO";
m_Prio = true;
}
isyslog("streamdev-client: Connected to server %s:%d using capabilities TSPIDS%s%s",
RemoteIp().c_str(), RemotePort(), Filters, Prio);
if (!Command("CAPS TSPIDS", 220)) {
if (errno == 0)
esyslog("ERROR: Streamdev: Couldn't negotiate capabilities on %s:%d",
RemoteIp().c_str(), RemotePort());
Close();
return false;
}
else {
if(!Command("VERS 1.0", 220)) {
Close();
return false;
}
const char *Filters = "";
if(Command("CAPS FILTERS", 220))
Filters = ",FILTERS";
const char *Prio = "";
if(Command("CAPS PRIO", 220)) {
Prio = ",PRIO";
m_Prio = true;
isyslog("streamdev-client: Connected to server %s:%d using protocol version %u.%u",
RemoteIp().c_str(), RemotePort(), major, minor);
}
isyslog("Streamdev: Connected to server %s:%d using capabilities TSPIDS%s%s",
RemoteIp().c_str(), RemotePort(), Filters, Prio);
return true;
}
@@ -192,19 +162,17 @@ bool cClientSocket::ProvidesChannel(const cChannel *Channel, int Priority) {
std::string command = (std::string)"PROV " + (const char*)itoa(Priority) + " "
+ (const char*)Channel->GetChannelID().ToString();
if (!Send(command))
if (!Command(command))
return false;
uint code;
std::string buffer;
if (!Receive(command, &code, &buffer))
return false;
if (code != 220 && code != 560) {
esyslog("streamdev-client: Unexpected reply to '%s' from %s:%d: %s",
command.c_str(), RemoteIp().c_str(), RemotePort(), buffer.c_str());
if (!Expect(220, &buffer)) {
if (buffer.substr(0, 3) != "560" && errno == 0)
esyslog("ERROR: Streamdev: Couldn't check if %s:%d provides channel %s",
RemoteIp().c_str(), RemotePort(), Channel->Name());
return false;
}
return code == 220;
return true;
}
bool cClientSocket::CreateDataConnection(eSocketId Id) {
@@ -216,7 +184,7 @@ bool cClientSocket::CreateDataConnection(eSocketId Id) {
DELETENULL(m_DataSockets[Id]);
if (!listen.Listen(LocalIp(), 0, 1)) {
esyslog("ERROR: streamdev-client: Couldn't create data connection: %s",
esyslog("ERROR: Streamdev: Couldn't create data connection: %s",
strerror(errno));
return false;
}
@@ -231,8 +199,13 @@ bool cClientSocket::CreateDataConnection(eSocketId Id) {
CMD_LOCK;
if (!Command(command, 220))
if (!Command(command, 220)) {
Dprintf("error: %m\n");
if (errno == 0)
esyslog("ERROR: Streamdev: Couldn't establish data connection to %s:%d",
RemoteIp().c_str(), RemotePort());
return false;
}
/* The server SHOULD do the following:
* - get PORT command
@@ -242,7 +215,7 @@ bool cClientSocket::CreateDataConnection(eSocketId Id) {
m_DataSockets[Id] = new cTBSocket;
if (!m_DataSockets[Id]->Accept(listen)) {
esyslog("ERROR: streamdev-client: Couldn't establish data connection to %s:%d%s%s",
esyslog("ERROR: Streamdev: Couldn't establish data connection to %s:%d%s%s",
RemoteIp().c_str(), RemotePort(), errno == 0 ? "" : ": ",
errno == 0 ? "" : strerror(errno));
DELETENULL(m_DataSockets[Id]);
@@ -253,12 +226,18 @@ bool cClientSocket::CreateDataConnection(eSocketId Id) {
}
bool cClientSocket::CloseDataConnection(eSocketId Id) {
//if (!CheckConnection()) return false;
CMD_LOCK;
if(Id == siLive || Id == siLiveFilter)
if (m_DataSockets[Id] != NULL) {
std::string command = (std::string)"ABRT " + (const char*)itoa(Id);
Command(command, 220);
if (!Command(command, 220)) {
if (errno == 0)
esyslog("ERROR: Streamdev: Couldn't cleanly close data connection");
//return false;
}
DELETENULL(m_DataSockets[Id]);
}
return true;
@@ -271,53 +250,28 @@ bool cClientSocket::SetChannelDevice(const cChannel *Channel) {
std::string command = (std::string)"TUNE "
+ (const char*)Channel->GetChannelID().ToString();
if (!Command(command, 220))
if (!Command(command, 220, 10000)) {
if (errno == 0)
esyslog("ERROR: Streamdev: Couldn't tune %s:%d to channel %s",
RemoteIp().c_str(), RemotePort(), Channel->Name());
return false;
m_LastSignalUpdate = 0;
}
return true;
}
bool cClientSocket::SetPriority(int Priority) {
if (Priority == m_Priority)
return true;
if (!CheckConnection()) return false;
CMD_LOCK;
std::string command = (std::string)"PRIO " + (const char*)itoa(Priority);
if (!Command(command, 220))
if (!Command(command, 220)) {
if (errno == 0)
esyslog("Streamdev: Failed to update priority on %s:%d", RemoteIp().c_str(),
RemotePort());
return false;
m_Priority = Priority;
return true;
}
bool cClientSocket::GetSignal(int *SignalStrength, int *SignalQuality, int *Dev) {
if (!CheckConnection()) return -1;
CMD_LOCK;
if (m_LastSignalUpdate != time(NULL)) {
uint code = 0;
std::string buffer;
std::string command("SGNL");
if (!Send(command) || !Receive(command, &code, &buffer) || code != 220
|| sscanf(buffer.c_str(), "%*d %d %d:%d", &m_LastDev, &m_LastSignalStrength, &m_LastSignalQuality) != 3) {
m_LastDev = -1;
m_LastSignalStrength = -1;
m_LastSignalQuality = -1;
}
m_LastSignalUpdate = time(NULL);
}
if (SignalStrength)
*SignalStrength = m_LastSignalStrength;
if (SignalQuality)
*SignalQuality = m_LastSignalQuality;
if (Dev)
*Dev = m_LastDev;
return 0;
return true;
}
bool cClientSocket::SetPid(int Pid, bool On) {
@@ -326,7 +280,13 @@ bool cClientSocket::SetPid(int Pid, bool On) {
CMD_LOCK;
std::string command = (std::string)(On ? "ADDP " : "DELP ") + (const char*)itoa(Pid);
return Command(command, 220);
if (!Command(command, 220)) {
if (errno == 0)
esyslog("Streamdev: Pid %d not available from %s:%d", Pid, RemoteIp().c_str(),
RemotePort());
return false;
}
return true;
}
bool cClientSocket::SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On) {
@@ -336,7 +296,13 @@ bool cClientSocket::SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On) {
std::string command = (std::string)(On ? "ADDF " : "DELF ") + (const char*)itoa(Pid)
+ " " + (const char*)itoa(Tid) + " " + (const char*)itoa(Mask);
return Command(command, 220);
if (!Command(command, 220)) {
if (errno == 0)
esyslog("Streamdev: Filter %hu, %hhu, %hhu not available from %s:%d",
Pid, Tid, Mask, RemoteIp().c_str(), RemotePort());
return false;
}
return true;
}
bool cClientSocket::CloseDvr(void) {
@@ -346,20 +312,27 @@ bool cClientSocket::CloseDvr(void) {
if (m_DataSockets[siLive] != NULL) {
std::string command = (std::string)"ABRT " + (const char*)itoa(siLive);
if (!Command(command, 220))
if (!Command(command, 220)) {
if (errno == 0)
esyslog("ERROR: Streamdev: Couldn't cleanly close data connection");
return false;
}
DELETENULL(m_DataSockets[siLive]);
}
return true;
}
bool cClientSocket::Quit(void) {
m_Abort = true;
if (!IsOpen()) return false;
bool res;
CMD_LOCK;
std::string command("QUIT");
bool res = Send(command) && Receive(command, NULL, NULL, QUIT_TIMEOUT_MS);
if (!CheckConnection()) return false;
if (!(res = Command("QUIT", 221))) {
if (errno == 0)
esyslog("ERROR: Streamdev: Couldn't quit command connection to %s:%d",
RemoteIp().c_str(), RemotePort());
}
Close();
return res;
}
@@ -369,5 +342,10 @@ bool cClientSocket::SuspendServer(void) {
CMD_LOCK;
return Command("SUSP", 220);
if (!Command("SUSP", 220)) {
if (errno == 0)
esyslog("ERROR: Streamdev: Couldn't suspend server");
return false;
}
return true;
}

View File

@@ -1,5 +1,5 @@
/*
* $Id: socket.h,v 1.8 2010/08/18 10:26:55 schmirl Exp $
* $Id: socket.h,v 1.6.2.2 2010/08/18 10:26:18 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_CLIENT_CONNECTION_H
@@ -8,7 +8,6 @@
#include <tools/socket.h>
#include "common.h"
#include "client/setup.h"
#include <string>
@@ -21,27 +20,20 @@ private:
cTBSocket *m_DataSockets[si_Count];
cMutex m_Mutex;
char m_Buffer[BUFSIZ + 1]; // various uses
unsigned int m_ServerVersion;
bool m_Prio; // server supports command PRIO
int m_Priority; // current device priority
bool m_Abort; // quit command pending
time_t m_LastSignalUpdate;
int m_LastSignalStrength;
int m_LastSignalQuality;
int m_LastDev;
protected:
/* Send Command, and return true if the command results in Expected.
Returns false on failure. */
bool Command(const std::string &Command, uint Expected);
Returns false on failure, setting errno appropriately if it has been
a system failure. If Expected is zero, returns immediately after
sending the command. */
bool Command(const std::string &Command, uint Expected = 0, uint TimeoutMs = 1500);
/* Send the given command. Returns false on failure. */
bool Send(const std::string &Command);
/* Fetch results from an ongoing Command. The status code and the
buffer holding the server's response are stored in Code and Result
if non-NULL. Returns false on failure. */
bool Receive(const std::string &Command, uint *Code = NULL, std::string *Result = NULL, uint TimeoutMs = StreamdevClientSetup.Timeout * 1000);
/* Fetch results from an ongoing Command called with Expected == 0. Returns
true if the response has the code Expected, returning an internal buffer
in the array pointer pointed to by Result. Returns false on failure,
setting errno appropriately if it has been a system failure. */
bool Expect(uint Expected, std::string *Result = NULL, uint TimeoutMs = 1500);
public:
cClientSocket(void);
@@ -55,12 +47,9 @@ public:
bool CloseDataConnection(eSocketId Id);
bool SetChannelDevice(const cChannel *Channel);
bool SupportsPrio() { return m_Prio; }
unsigned int ServerVersion() { return m_ServerVersion; }
int Priority() const { return m_Priority; }
bool SetPriority(int Priority);
bool SetPid(int Pid, bool On);
bool SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On);
bool GetSignal(int *SignalStrength, int *SignalQuality, int *Dev);
bool CloseDvr(void);
bool SuspendServer(void);
bool Quit(void);
@@ -68,4 +57,6 @@ public:
cTBSocket *DataSocket(eSocketId Id) const;
};
extern class cClientSocket ClientSocket;
#endif // VDR_STREAMDEV_CLIENT_CONNECTION_H

View File

@@ -1,5 +1,5 @@
/*
* $Id: common.c,v 1.12 2010/07/19 13:49:24 schmirl Exp $
* $Id: common.c,v 1.7.2.2 2010/07/19 13:50:11 schmirl Exp $
*/
#include <vdr/channels.h>
@@ -10,7 +10,7 @@
using namespace std;
const char *VERSION = "0.6.1-git";
const char *VERSION = "0.4.0-CVS";
const char cMenuEditIpItem::IpCharacters[] = "0123456789.";

View File

@@ -1,5 +1,5 @@
/*
* $Id: common.h,v 1.16 2010/07/19 13:49:24 schmirl Exp $
* $Id: common.h,v 1.11.2.3 2010/07/19 13:50:11 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_COMMON_H
@@ -17,22 +17,15 @@
#include "tools/socket.h"
#ifdef DEBUG
#include <stdio.h>
#include <time.h>
#define Dprintf(fmt, x...) {\
struct timespec ts;\
clock_gettime(CLOCK_MONOTONIC, &ts);\
fprintf(stderr, "%ld.%.3ld [%d] "fmt,\
ts.tv_sec, ts.tv_nsec / 1000000, cThread::ThreadId(), ##x);\
}
# include <stdio.h>
# define Dprintf(x...) fprintf(stderr, x)
#else
#define Dprintf(x...)
# define Dprintf(x...)
#endif
#define MAXPARSEBUFFER KILOBYTE(16)
#define TRANSPONDER(c1, c2) (c1->Transponder() == c2->Transponder())
/* Service ID for loop prevention */
#define LOOP_PREVENTION_SERVICE "StreamdevLoopPrevention"
#define MAXPARSEBUFFER KILOBYTE(16)
/* Check if a channel is a radio station. */
#define ISRADIO(x) ((x)->Vpid()==0||(x)->Vpid()==1||(x)->Vpid()==0x1fff)
@@ -49,6 +42,13 @@ enum eStreamType {
st_Count
};
enum eSuspendMode {
smOffer,
smAlways,
smNever,
sm_Count
};
enum eSocketId {
siLive,
siReplay,

836
i18n.c Normal file
View File

@@ -0,0 +1,836 @@
/*
* $Id: i18n.c,v 1.8.2.9 2010/07/19 13:50:11 schmirl Exp $
*/
#include "i18n.h"
const char *i18n_name = NULL;
const tI18nPhrase Phrases[] = {
{ "VDR Streaming Server", // English
"VDR Streaming Server", // Deutsch
"", // Slovenski
"Server trasmissione VDR", // Italiano
"", // Nederlands
"", // Português
"Serveur de streaming VDR", // Français
"", // Norsk
"VDR-suoratoistopalvelin", // suomi
"", // Polski
"", // Español
"", // Ellinika / Greek
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"VDR Streaming áÕàÒÕà", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "VTP Streaming Client", // English
"VTP Streaming Client", // Deutsch
"", // Slovenski
"Client trasmissione VTP", // Italiano
"", // Nederlands
"", // Português
"Client de streaming VTP", // Français
"", // Norsk
"VTP-suoratoistoasiakas ", // suomi
"", // Polski
"", // Español
"", // Ellinika / Greek
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"VTP Streaming ÚÛØÕÝâ", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Start VDR-to-VDR Server", // English
"VDR-zu-VDR Server starten", // Deutsch
"", // Slovenski
"Avvia Server VDR-a-VDR", // Italiano
"", // Nederlands
"", // Português
"Démarrer le serveur VDR-to-VDR", // Français
"", // Norsk
"Käynnistä VDR-palvelin", // suomi
"", // Polski
"", // Español
"", // Ellinika / Greek
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"ÁâÐàâ VDR-to-VDR áÕàÒÕà", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Start HTTP Server", // English
"HTTP Server starten", // Deutsch
"", // Slovenski
"Avvia Server HTTP", // Italiano
"", // Nederlands
"", // Português
"Démarrer le serveur HTTP", // Français
"", // Norsk
"Käynnistä HTTP-palvelin", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"ÁâÐàâ HTTP áÕàÒÕàÐ", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "HTTP Streamtype", // English
"HTTP Streamtyp", // Deutsch
"", // Slovenski
"Tipo flusso HTTP", // Italiano
"", // Nederlands
"", // Português
"Type de Streaming HTTP", // Français
"", // Norsk
"HTTP-lähetysmuoto", // Suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"ÂØß HTTP ßÞâÞÚÐ", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Start Client", // English
"Client starten", // Deutsch
"", // Slovenski
"Avvia Client", // Italiano
"", // Nederlands
"", // Português
"Démarrage du client", // Français
"", // Norsk
"Käynnistä VDR-asiakas", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"ÁâÐàâ ÚÛØÕÝâÐ", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "VDR-to-VDR Server Port", // English
"Port des VDR-zu-VDR Servers", // Deutsch
"", // Slovenski
"Porta Server VDR-a-VDR", // Italiano
"", // Nederlands
"", // Português
"Port du serveur VDR-to-VDR", // Français
"", // Norsk
"VDR-palvelimen portti", // Suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"VDR-to-VDR ßÞàâ áÕàÒÕàÐ", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "HTTP Server Port", // English
"Port des HTTP Servers", // Deutsch
"", // Slovenski
"Porta Server HTTP", // Italiano
"", // Nederlands
"", // Português
"Port du serveur HTTP", // Français
"", // Norsk
"HTTP-palvelimen portti", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"HTTP áÕàÒÕà ¿Þàâ", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Maximum Number of Clients", // English
"Maximalanzahl an Clients", // Deutsch
"", // Slovenski
"Numero massimo di Client", // Italiano
"", // Nederlands
"", // Português
"Nombre maximun de clients", // Français
"", // Norsk
"Suurin sallittu asiakkaiden määrä", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"¼ÐÚá. ÚÞÛØçÕáâÒÞ ÚÛØÕÝâÞÒ", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Remote IP", // English
"IP der Gegenseite", // Deutsch
"", // Slovenski
"Indirizzo IP del Server", // Italiano
"", // Nederlands
"", // Português
"Adresse IP du serveur", // Français
"", // Norsk
"Etäkoneen IP-osoite", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"ÃÔÐÛÕÝÝëÙ IP", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Remote Port", // English
"Port der Gegenseite", // Deutsch
"", // Slovenski
"Porta Server Remoto", // Italiano
"", // Nederlands
"", // Português
"Port du serveur", // Français
"", // Norsk
"Etäkoneen portti", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"ÃÔÐÛÕÝÝëÙ ßÞàâ", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Common Settings", // English
"Allgemeines", // Deutsch
"", // Slovenski
"Impostazioni comuni", // Italiano
"", // Nederlands
"", // Português
"Paramètres communs", // Français
"", // Norsk
"Yleiset asetukset", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"½ÐáâàÞÙÚØ", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "VDR-to-VDR Server", // English
"VDR-zu-VDR Server", // Deutsch
"", // Slovenski
"Server VDR-a-VDR", // Italiano
"", // Nederlands
"", // Português
"VDR-to-VDR Serveur", // Français
"", // Norsk
"VDR-palvelin", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"VDR-to-VDR áÕàÒÕà", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "HTTP Server", // English
"HTTP Server", // Deutsch
"", // Slovenski
"Server HTTP", // Italiano
"", // Nederlands
"", // Português
"Serveur HTTP", // Français
"", // Norsk
"HTTP-palvelin", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"HTTP áÕàÒÕà", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Minimum Priority", // English
"Minimale Priorität", // Deutsch
"", // Slovenski
"Priorità minima", // Italiano
"", // Nederlands
"", // Português
"", // Français
"", // Norsk
"Pienin prioriteetti", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Maximum Priority", // English
"Maximale Priorität", // Deutsch
"", // Slovenski
"Priorità massima", // Italiano
"", // Nederlands
"", // Português
"", // Français
"", // Norsk
"Suurin prioriteetti", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Suspend Live TV", // English
"Live-TV pausieren", // Deutsch
"", // Slovenski
"Sospendi TV dal vivo", // Italiano
"", // Nederlands
"", // Português
"Suspendre Live TV", // Français
"", // Norsk
"Pysäytä suora TV-lähetys", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"¾áâÐÝÞÒÚÐ Live TV", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Suspend behaviour", // English
"Pausierverhalten", // Deutsch
"", // Slovenski
"Tipo sospensione", // Italiano
"", // Nederlands
"", // Português
"Suspendre", // Français
"", // Norsk
"Pysäytystoiminto", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"¿ÞÒÕÔÕÝØÕ ÞáâÐÝÞÒÚØ", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Offer suspend mode", // English
"Pausieren anbieten", // Deutsch
"", // Slovenski
"Offri mod. sospensione", // Italiano
"", // Nederlands
"", // Português
"Offrir le mode suspendre", // Français
"", // Norsk
"tyrkytä", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"¿àÕÔÛÐÓÐâì ÞáâÐÝÞÒÚã", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Always suspended", // English
"Immer pausiert", // Deutsch
"", // Slovenski
"Sempre sospeso", // Italiano
"", // Nederlands
"", // Português
"Toujours suspendre", // Français
"", // Norsk
"aina", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"²áÕÓÔÐ ÞáâÐÝÞÒÛÕÝ", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Never suspended", // English
"Nie pausiert", // Deutsch
"", // Slovenski
"Mai sospeso", // Italiano
"", // Nederlands
"", // Português
"Jamais suspendre", // Français
"", // Norsk
"ei koskaan", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"½ØÚÞÓÔÐ ÝÕ ÞáâÐÝÞÒÛÕÝ", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Suspend Server", // English
"Server pausieren", // Deutsch
"", // Slovenski
"Sospendi Server", // Italiano
"", // Nederlands
"", // Português
"Suspendre le serveur", // Français
"", // Norsk
"Pysäytä palvelin", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"¾áâÐÝÞÒØâì áÕàÒÕà", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Server is suspended", // English
"Server ist pausiert", // Deutsch
"", // Slovenski
"Server sospeso", // Italiano
"", // Nederlands
"", // Português
"Le serveur est suspendu", // Français
"", // Norsk
"Palvelin on pysäytetty", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"ÁÕàÒÕà ÞáâÐÝÞÒÛÕÝ", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Couldn't suspend Server!", // English
"Konnte Server nicht pausieren!", // Deutsch
"", // Slovenski
"Impossibile sospendere il server!", // Italiano
"", // Nederlands
"", // Português
"Impossible de suspendre le serveur!", // Français
"", // Norsk
"Palvelinta ei onnistuttu pysäyttämään!", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"ÝÕ ÜÞÓã ÞáâÐÝÞÒØâì áÕàÒÕà", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Client may suspend", // English
"Client darf pausieren", // Deutsch
"", // Slovenski
"Permetti sospensione al Client", // Italiano
"", // Nederlands
"", // Português
"Le client peut suspendre", // Français
"", // Norsk
"Asiakas saa pysäyttää palvelimen", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"ºÛØÕÝâ ÜÞÖÕâ ÞáâÐÝÐÒÛØÒÐâì", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Bind to IP", // English
"Binde an IP", // Deutsch
"", // Slovenski
"IP associati", // Italiano
"", // Nederlands
"", // Português
"Attacher aux IP", // Français
"", // Norsk
"Sido osoitteeseen", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"¿àØáÞÕÔØÝØâìáï Ú IP", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Filter Streaming", // English
"Filter-Daten streamen", // Deutsch
"", // Slovenski
"Filtra trasmissione", // Italiano
"", // Nederlands
"", // Português
"Filtre streaming", // Français
"", // Norsk
"Suodatetun tiedon suoratoisto", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"ÄØÛìâà ßÞâÞÚÐ", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Streaming active", // English
"Streamen im Gange", // Deutsch
"", // Slovenski
"Trasmissione attiva", // Italiano
"", // Nederlands
"", // Português
"Streaming actif", // Français
"", // Norsk
"Suoratoistopalvelin aktiivinen", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"ÁâàØÜØÝÓ ÐÚâØÒÕÝ", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Hide Mainmenu Entry", // English
"Hauptmenüeintrag verstecken", // Deutsch
"", // Slovenski
"Nascondi voce menu principale", // Italiano
"", // Nederlands
"", // Português
"Masquer dans le menu principal", // Français
"", // Norsk
"Piilota valinta päävalikosta", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"ÁßàïâÐâì Ò ÓÛÐÒÝÞÜ ÜÕÝî", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Multicast Streaming Server", // English
"Multicast Streaming Server", // Deutsch
"", // Slovenski
"Server trasmissione Multicast", // Italiano
"", // Nederlands
"", // Português
"", // Français
"", // Norsk
"Multicast-suoratoistopalvelin", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Start IGMP Server", // English
"IGMP Server starten", // Deutsch
"", // Slovenski
"Avvia Server IGMP", // Italiano
"", // Nederlands
"", // Português
"", // Français
"", // Norsk
"Käynnistä IGMP-palvelin", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Multicast Client Port", // English
"Port des Multicast Clients", // Deutsch
"", // Slovenski
"Porta Client Multicast", // Italiano
"", // Nederlands
"", // Português
"", // Français
"", // Norsk
"Multicast-portti", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ "Multicast Streamtype", // English
"Multicast Streamtyp", // Deutsch
"", // Slovenski
"Tipo flusso Multicast", // Italiano
"", // Nederlands
"", // Português
"", // Français
"", // Norsk
"Multicast-lähetysmuoto", // suomi
"", // Polski
"", // Español
"", // Ellinika
"", // Svenska
"", // Romaneste
"", // Magyar
"", // Catala
"", // Russian
"", // Hrvatski
"", // Eesti
"", // Dansk
"", // Czech
#if VDRVERSNUM >= 10502
"", // Türkçe
#endif
},
{ NULL }
};

16
i18n.h Normal file
View File

@@ -0,0 +1,16 @@
/*
* $Id: i18n.h,v 1.1.1.1 2004/12/30 22:43:58 lordjaxom Exp $
*/
#ifndef VDR_STREAMDEV_I18N_H
#define VDR_STREAMDEV_I18N_H
#include <vdr/i18n.h>
extern const char *i18n_name;
extern const tI18nPhrase Phrases[];
#undef tr
#define tr(s) I18nTranslate(s, i18n_name)
#endif // VDR_STREAMDEV_I18N_H

View File

@@ -1,38 +1,25 @@
#
# Makefile for a Video Disk Recorder plugin
#
# $Id: Makefile,v 1.5 2010/07/30 10:49:28 schmirl Exp $
INCS = -I.
CFLAGS = -g -Wall -O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -fPIC
MFLAG = -M
OBJS = ctools.o ringbuffy.o remux.o transform.o
SRC = $(wildcard *.c)
### The object files (add further files here):
OBJS = ctools.o remux.o ringbuffy.o transform.o
### Disable attribute warn_unused_result
DEFINES += -U_FORTIFY_SOURCE
### The main target:
DESTDIR = /usr/local
.PHONY: clean
clean:
- rm -f *.o *~ *.a .depend
libdvbmpegtools.a: $(OBJS)
ar -rcs libdvbmpegtools.a $(OBJS)
### Implicit rules:
%.o: %.c
$(CC) -c $(CFLAGS) $(INCS) $(DEFINES) $<
%.o: %.c
$(CC) $(CFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
.depend:
$(CXX) $(DEFINES) $(MFLAG) $(SRC) $(INCS)> .depend
### Dependencies:
MAKEDEP = $(CC) -MM -MG
DEPFILE = .dependencies
$(DEPFILE): Makefile
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
-include $(DEPFILE)
### Targets:
clean:
@-rm -f $(OBJS) $(DEPFILE) *.a core* *~
-include .depend

View File

@@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
@@ -298,6 +298,7 @@ void write_pes(int fd, pes_packet *p){
}
static unsigned int find_length(int f){
uint64_t p = 0;
uint64_t start = 0;
uint64_t q = 0;
int found = 0;
@@ -308,7 +309,7 @@ static unsigned int find_length(int f){
start -=2;
lseek(f,start,SEEK_SET);
while ( neof > 0 && !found ){
lseek(f,0,SEEK_CUR);
p = lseek(f,0,SEEK_CUR);
neof = save_read(f,&sync4,4);
if (sync4[0] == 0x00 && sync4[1] == 0x00 && sync4[2] == 0x01) {
switch ( sync4[3] ) {
@@ -557,7 +558,7 @@ int read_pes(int f, pes_packet *p){
while (neof > 0 && !found) {
po = lseek(f,0,SEEK_CUR);
if (po == (off_t) -1) return -1;
if (po < 0) return -1;
if ((neof = save_read(f,&sync4,4)) < 4) return -1;
if (sync4[0] == 0x00 && sync4[1] == 0x00 && sync4[2] == 0x01) {
p->stream_id = sync4[3];
@@ -595,10 +596,7 @@ int read_pes(int f, pes_packet *p){
if (p->length >0){
buf = (uint8_t *) malloc(p->length);
if((neof = save_read(f,buf,p->length))< p->length){
free(buf);
return -1;
}
if((neof = save_read(f,buf,p->length))< p->length) return -1;
cread_pes((char *)buf,p);
free(buf);
} else return 0;
@@ -1333,7 +1331,7 @@ void tfilter(trans *p)
{
int l,c;
int tpid;
uint8_t flags;
uint8_t flag,flags;
uint8_t adapt_length = 0;
uint8_t cpid[2];
@@ -1349,6 +1347,7 @@ void tfilter(trans *p)
tpid);
}
flag = cpid[0];
flags = p->packet[3];
if ( flags & ADAPT_FIELD ) {
@@ -1877,3 +1876,528 @@ int write_ps_header(uint8_t *buf,
}
}
#define MAX_BASE 80
#define MAX_PATH 256
#define MAX_EXT 10
int break_up_filename(char *name, char *base_name, char *path, char *ext)
{
int l,i,sstop,sstart;
l = strlen(name);
sstop = l;
sstart = -1;
for( i= l-1; i >= 0; i--){
if (sstop == l && name[i] == '.') sstop = i;
if (sstart<0 && name[i] == '/') sstart = i+1;
}
if (sstart < 0) sstart = 0;
if (sstop-sstart < MAX_BASE){
strncpy(base_name, name+sstart, sstop-sstart);
base_name[sstop-sstart]=0;
if(sstart > 0){
if( l - sstop + sstart < MAX_PATH){
strncpy(path, name, sstart);
path[sstart] = 0;
} else {
fprintf(stderr,"PATH too long\n");
return -1;
}
} else {
strcpy(path, "./");
}
if(sstop < l){
if( l - sstop -1 < MAX_EXT){
strncpy(ext, name+sstop+1, l-sstop-1);
ext[l-sstop-1]=0;
} else {
fprintf(stderr,"Extension too long\n");
return -1;
}
} else {
strcpy(ext, "");
}
} else {
fprintf(stderr,"Name too long\n");
return -1;
}
/*
printf("%d %d\n",sstart, sstop);
printf("%s %d\n",name, strlen(name));
printf("%s %d\n",base_name, strlen(base_name));
printf("%s %d\n",path,strlen(path));
printf("%s %d\n",ext,strlen(ext));
*/
return 0;
}
int seek_mpg_start(uint8_t *buf, int size)
{
int found = 0;
int c=0;
int seq = 0;
int mpeg = 0;
int mark = 0;
while ( !seq ){
while (found != 4){
switch (found) {
case 0:
if ( buf[c] == 0x00 ) found++;
c++;
break;
case 1:
if ( buf[c] == 0x00 ) found++;
else found = 0;
c++;
break;
case 2:
if ( buf[c] == 0x01 ) found++;
else found = 0;
if ( buf[c] == 0x00 ) found = 2;
c++;
break;
case 3:
if ( (buf[c] & 0xe0) == 0xe0 ) found++;
else found = 0;
c++;
break;
}
if (c >= size) return -1;
}
if (found == 4){
mark = c-4;
c+=2;
if (c >= size) return -1;
if ( (buf[c] & 0xC0) == 0x80 ){
mpeg = 2;
c += 2;
if (c >= size) return -1;
c += buf[c]+1;
if (c >= size) return -1;
} else {
mpeg = 1;
while( buf[c] == 0xFF ) {
c++;
if (c >= size) return -1;
}
if ( (buf[c] & 0xC0) == 0x40) c+=2;
if (c >= size) return -1;
if ( (buf[c] & 0x30) ){
if ( (buf[c] & 0x30) == 0x20) c+=5;
else c+=10;
} else c++;
if (c >= size) return -1;
}
if ( buf[c] == 0x00 &&
buf[c+1] == 0x00 &&
buf[c+2] == 0x01 &&
buf[c+3] == 0xB3 )
seq = 1;
}
found = 0;
}
return size-mark;
}
void write_mpg(int fstart, uint64_t length, int fdin, int fdout)
{
// uint8_t mpeg_end[4] = { 0x00, 0x00, 0x01, 0xB9 };
uint8_t *buf;
uint64_t l=0;
uint64_t count = 0;
struct stat sb;
int buf_size;
fstat (fdout, &sb);
buf_size = sb.st_blksize;
buf = (uint8_t *) alloca (buf_size + sizeof (int));
lseek(fdin, fstart, SEEK_SET);
while ( count < length && (l = read(fdin,buf,buf_size)) >= 0){
if (l > 0) count+=l;
write(fdout,buf,l);
printf("written %02.2f%%\r",(100.*count)/length);
}
printf("\n");
//write( fdout, mpeg_end, 4);
}
#define CHECKBUF (1024*1024)
#define ONE_GIG (1024UL*1024UL*1024UL)
void split_mpg(char *name, uint64_t size)
{
char base_name[MAX_BASE];
char path[MAX_PATH];
char ext[MAX_EXT];
char new_name[256];
uint8_t buf[CHECKBUF];
int fdin;
int fdout;
uint64_t length = 0;
uint64_t last;
int i;
int mark, csize;
struct stat sb;
if (break_up_filename(name,base_name,path,ext) < 0) exit(1);
#ifdef __FreeBSD__
if ( (fdin = open(name, O_RDONLY)) < 0){
#else
if ( (fdin = open(name, O_RDONLY|O_LARGEFILE)) < 0){
#endif
fprintf(stderr,"Can't open %s\n",name);
exit(1);
}
fstat (fdin, &sb);
length = sb.st_size;
if ( length < ONE_GIG )
printf("Filelength = %2.2f MB\n", length/1024./1024.);
else
printf("Filelength = %2.2f GB\n", length/1024./1024./1024.);
if ( length < size ) length = size;
printf("Splitting %s into Files with size <= %2.2f MB\n",name,
size/1024./1024.);
csize = CHECKBUF;
read(fdin, buf, csize);
if ( (mark = seek_mpg_start(buf,csize)) < 0){
fprintf(stderr,"Couldn't find sequence header\n");
exit(1);
}
last = csize-mark;
for ( i = 0 ; i < length/size; i++){
csize = CHECKBUF;
if (csize > length-last) csize = length-last;
lseek(fdin, last+size-csize, SEEK_SET);
read(fdin, buf, csize);
if ( (mark = seek_mpg_start(buf,csize)) < 0){
fprintf(stderr,"Couldn't find sequence header\n");
exit(1);
}
sprintf(new_name,"%s-%03d.%s",base_name,i,ext);
printf("writing %s\n",new_name);
#ifdef __FreeBSD__
if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC,
#else
if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC
|O_LARGEFILE,
#endif
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|
S_IROTH|S_IWOTH)) < 0){
fprintf(stderr,"Can't open %s\n",new_name);
exit(1);
}
write_mpg(last, size-mark, fdin, fdout);
last = last + size - mark;
}
sprintf(new_name,"%s-%03d.%s",base_name,i,ext);
printf("writing %s\n",new_name);
#ifdef __FreeBSD__
if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC,
#else
if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC
|O_LARGEFILE,
#endif
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|
S_IROTH|S_IWOTH)) < 0){
fprintf(stderr,"Can't open %s\n",new_name);
exit(1);
}
write_mpg(last, length-last, fdin, fdout);
}
void cut_mpg(char *name, uint64_t size)
{
char base_name[MAX_BASE];
char path[MAX_PATH];
char ext[MAX_EXT];
char new_name[256];
uint8_t buf[CHECKBUF];
int fdin;
int fdout;
uint64_t length = 0;
uint64_t last;
int mark, csize;
struct stat sb;
if (break_up_filename(name,base_name,path,ext) < 0) exit(1);
#ifdef __FreeBSD__
if ( (fdin = open(name, O_RDONLY)) < 0){
#else
if ( (fdin = open(name, O_RDONLY|O_LARGEFILE)) < 0){
#endif
fprintf(stderr,"Can't open %s\n",name);
exit(1);
}
fstat (fdin, &sb);
length = sb.st_size;
if ( length < ONE_GIG )
printf("Filelength = %2.2f MB\n", length/1024./1024.);
else
printf("Filelength = %2.2f GB\n", length/1024./1024./1024.);
if ( length < size ) length = size;
printf("Splitting %s into 2 Files with length %.2f MB and %.2f MB\n",
name, size/1024./1024., (length-size)/1024./1024.);
csize = CHECKBUF;
read(fdin, buf, csize);
if ( (mark = seek_mpg_start(buf,csize)) < 0){
fprintf(stderr,"Couldn't find sequence header\n");
exit(1);
}
last = csize-mark;
if (csize > length-last) csize = length-last;
lseek(fdin, last+size-csize, SEEK_SET);
read(fdin, buf, csize);
if ( (mark = seek_mpg_start(buf,csize)) < 0){
fprintf(stderr,"Couldn't find sequence header\n");
exit(1);
}
sprintf(new_name,"%s-1.%s",base_name,ext);
printf("writing %s\n",new_name);
#ifdef __FreeBSD__
if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC,
#else
if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC
|O_LARGEFILE,
#endif
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|
S_IROTH|S_IWOTH)) < 0){
fprintf(stderr,"Can't open %s\n",new_name);
exit(1);
}
write_mpg(last, size-mark, fdin, fdout);
last = last + size - mark;
sprintf(new_name,"%s-2.%s",base_name,ext);
printf("writing %s\n",new_name);
#ifdef __FreeBSD__
if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC,
#else
if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC
|O_LARGEFILE,
#endif
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|
S_IROTH|S_IWOTH)) < 0){
fprintf(stderr,"Can't open %s\n",new_name);
exit(1);
}
write_mpg(last, length-last, fdin, fdout);
}
void write_all (int fd, const char *data, int length)
{
int r;
while (length) {
if ((r = write(fd, data, length)) > 0) {
data += r;
length -= r;
}
}
}
void read_all (int fd, char *data, int length)
{
int c = 0;
while(1) {
if( read(fd, data+c, 1) == 1) {
c++;
if(data[c-1] == '\n') {
data[c] = 0;
break;
}
}
else {
fprintf (stderr, "Error reading socket\n");
exit(1);
}
}
}
char *url2host (char *url, char **name, uint32_t *ip, uint32_t *port)
{
char *murl;
struct hostent *hoste;
struct in_addr haddr;
int found_ip = 1;
if (!(strncmp(url, "http://", 7)))
url += 7;
*name = strdup(url);
if (!(*name)) {
*name = NULL;
return (NULL);
}
murl = url;
while (*murl && *murl != ':' && *murl != '/') {
if ((*murl < '0' || *murl > '9') && *murl != '.')
found_ip = 0;
murl++;
}
(*name)[murl - url] = 0;
if (found_ip) {
if ((*ip = inet_addr(*name)) == INADDR_NONE)
return (NULL);
} else {
if (!(hoste = gethostbyname(*name)))
return (NULL);
memcpy (&haddr, hoste->h_addr, sizeof(haddr));
*ip = haddr.s_addr;
}
if (!*murl || *murl == '/') {
*port = 80;
return (murl);
}
*port = atoi(++murl);
while (*murl && *murl != '/')
murl++;
return (murl);
}
#define ACCEPT "Accept: video/mpeg, video/x-mpegurl, */*\r\n"
int http_open (char *url)
{
char purl[1024], *host, req[1024], *sptr;
uint32_t ip;
uint32_t port;
int sock;
int reloc, relocnum = 0;
struct sockaddr_in server;
int mfd;
strncpy (purl, url, 1023);
purl[1023] = '\0';
do {
host = NULL;
strcpy (req, "GET ");
if (!(sptr = url2host(purl, &host, &ip, &port))) {
fprintf (stderr, "Unknown host\n");
exit (1);
}
strcat (req, sptr);
sprintf (req + strlen(req),
" HTTP/1.0\r\nUser-Agent: %s/%s\r\n",
"whatever", "you want");
if (host) {
sprintf(req + strlen(req),
"Host: %s:%u\r\n", host, port);
free (host);
}
strcat (req, ACCEPT);
strcat (req, "\r\n");
server.sin_port = htons(port);
server.sin_family = AF_INET;
server.sin_addr.s_addr = ip;
if ((sock = socket(PF_INET, SOCK_STREAM, 6)) < 0) {
perror ("socket");
exit (1);
}
if (connect(sock, (struct sockaddr *)&server,
sizeof(server))) {
perror ("connect");
exit (1);
}
write_all (sock, req, strlen(req));
if (!(mfd = fileno(fdopen(sock, "rb")))) {
perror ("open");
exit (1);
}
reloc = 0;
purl[0] = '\0';
read_all (mfd, req, 1023);
if ((sptr = strchr(req, ' '))) {
switch (sptr[1]) {
case '2':
break;
case '3':
reloc = 1;
default:
fprintf (stderr, "HTTP req failed:%s",
sptr+1);
exit (1);
}
}
do {
read_all (mfd,req, 1023);
if (!strncmp(req, "Location:", 9))
strncpy (purl, req+10, 1023);
} while (req[0] != '\r' && req[0] != '\n');
} while (reloc && purl[0] && relocnum++ < 3);
if (reloc) {
fprintf (stderr, "Too many HTTP relocations.\n");
exit (1);
}
return sock;
}
extern int errno;
const char * strerrno (void)
{
return strerror(errno);
}

View File

@@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
@@ -387,7 +387,16 @@ extern "C" {
uint8_t buffer2_scale,
uint32_t buffer2_size);
int seek_mpg_start(uint8_t *buf, int size);
void split_mpg(char *name, uint64_t size);
void cut_mpg(char *name, uint64_t size);
int http_open (char *url);
ssize_t save_read(int fd, void *buf, size_t count);
const char * strerrno(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
@@ -388,9 +388,10 @@ int refill_buffy(Remux *rem)
while ( acount > MAX_PLENGTH && vcount > MAX_PLENGTH && count < 10){
int neof;
count++;
init_pes(&pes);
if (read_pes(fin,&pes) <= 0) return -1;
if ((neof = read_pes(fin,&pes)) <= 0) return -1;
switch(pes.stream_id){
case AUDIO_STREAM_S ... AUDIO_STREAM_E:
rem->apes++;
@@ -701,6 +702,22 @@ void init_remux(Remux *rem, int fin, int fout, int mult)
rem->time_off = 0;
}
uint32_t bytes2pts(int bytes, int rate)
{
if (bytes < 0xFFFFFFFFUL/720000UL)
return (uint32_t)(bytes*720000UL/rate);
else
return (uint32_t)(bytes/rate*720000UL);
}
long pts2bytes( uint32_t pts, int rate)
{
if (pts < 0xEFFFFFFFUL/rate)
return (pts*rate/720000);
else
return (pts* (rate/720000));
}
int write_audio_pes( Remux *rem, uint8_t *buf, int *alength)
{
int add;
@@ -756,6 +773,7 @@ int write_video_pes( Remux *rem, uint8_t *buf, int *vlength)
int pos = 0;
int p = 0;
uint32_t pts = 0;
uint32_t dts = 0;
int stuff = 0;
int length = *vlength;
long diff = 0;
@@ -786,6 +804,7 @@ int write_video_pes( Remux *rem, uint8_t *buf, int *vlength)
if (add < 0) return -1;
pos += add;
rem->vpts_old = rem->vpts;
dts = rem->vdts;
rem->vpts = rem->vpts_list[0].PTS;
rem->vdts = rem->vpts_list[0].dts;
if ( diff > 0) rem->SCR += diff;
@@ -1069,6 +1088,12 @@ struct remux_s{
} REMUX;
void init_REMUX(REMUX *rem)
{
rem->num_pbuf = 0;
}
#define REPACK 2048
#define ABUF_SIZE REPACK*1024

View File

@@ -20,7 +20,7 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*

View File

@@ -15,8 +15,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA.
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "ringbuffy.h"
@@ -192,8 +191,9 @@ int ring_read_file(ringbuffy *rbuf, int fd, int count)
}
int ring_rest(ringbuffy *rbuf){
int diff, free, pos;
int diff, free, pos, rest;
pos = rbuf->read_pos;
rest = rbuf->size - pos;
diff = rbuf->write_pos - pos;
free = (diff >= 0) ? diff : rbuf->size+diff;

View File

@@ -15,8 +15,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA.
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef RINGBUFFY_H

View File

@@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*

View File

@@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*

View File

@@ -0,0 +1,85 @@
# If you have two or more VDRs and you like them to mutually share
# there DVB cards you might need to apply this patch first.
#
# IMPORTANT: As this patch does not only modify streamdev-server but
# also an exported method of VDR, you will need to
#
# !!!!! RECOMPILE VDR AND ALL PLUGINS !!!!!
#
# Why do I need the patch?
# --------------------------
# Before switching channels VDR will consider all of its devices to
# find the one with the least impact. This includes the device provided
# by the streamdev-client plugin. Streamdev-client will forward the
# request to its server which in turn checks all of its devices. Now if
# the server is running streamdev-client, too, the request will again
# be forwarded to its server and finally you will endup in a loop.
#
# What does the patch do?
# -----------------------
# The patch adds the additional parameter "bool DVBCardsOnly" to VDR's
# device selection method cDevice::GetDevice(...). The parameter
# defaults to false which gives you the standard behaviour of GetDevice.
# When set to true, GetDevice will use only those devices with a card
# index < MAXDVBDEVICES, so only real DVB cards will be considered.
# Other devices like streamdev-client or DVB cards provided by plugin
# (Hauppauge PVR) won't be used.
#
# Author: Frank Schmirler (http://vdr.schmirler.de)
#
--- device.h.orig 2006-11-15 12:01:34.000000000 +0100
+++ device.h 2006-11-15 12:02:15.000000000 +0100
@@ -128,7 +128,7 @@
///< Gets the device with the given Index.
///< \param Index must be in the range 0..numDevices-1.
///< \return A pointer to the device, or NULL if the Index was invalid.
- static cDevice *GetDevice(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL);
+ static cDevice *GetDevice(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL, bool DVBCardsOnly = false);
///< Returns a device that is able to receive the given Channel at the
///< given Priority, with the least impact on active recordings and
///< live viewing.
--- device.c.orig 2006-11-15 12:01:30.000000000 +0100
+++ device.c 2006-11-22 12:28:05.000000000 +0100
@@ -8,6 +8,7 @@
*/
#include "device.h"
+#include "dvbdevice.h"
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
@@ -278,11 +279,13 @@
return (0 <= Index && Index < numDevices) ? device[Index] : NULL;
}
-cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers)
+cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers, bool DVBCardsOnly)
{
cDevice *d = NULL;
uint Impact = 0xFFFFFFFF; // we're looking for a device with the least impact
for (int i = 0; i < numDevices; i++) {
+ if (DVBCardsOnly && device[i]->CardIndex() >= MAXDVBDEVICES)
+ continue;
bool ndr;
if (device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basicly able to do the job
// Put together an integer number that reflects the "impact" using
--- PLUGINS/src/streamdev/server/connection.c.orig 2006-11-15 12:10:11.000000000 +0100
+++ PLUGINS/src/streamdev/server/connection.c 2006-11-15 12:10:59.000000000 +0100
@@ -132,7 +132,7 @@
Dprintf(" * GetDevice(const cChannel*, int)\n");
Dprintf(" * -------------------------------\n");
- device = cDevice::GetDevice(Channel, Priority);
+ device = cDevice::GetDevice(Channel, Priority, NULL, true);
Dprintf(" * Found following device: %p (%d)\n", device,
device ? device->CardIndex() + 1 : 0);
@@ -150,7 +150,7 @@
const cChannel *current = Channels.GetByNumber(cDevice::CurrentChannel());
isyslog("streamdev-server: Detaching current receiver");
Detach();
- device = cDevice::GetDevice(Channel, Priority);
+ device = cDevice::GetDevice(Channel, Priority, NULL, true);
Attach();
Dprintf(" * Found following device: %p (%d)\n", device,
device ? device->CardIndex() + 1 : 0);

View File

@@ -0,0 +1,88 @@
# If you have two or more VDRs and you like them to mutually share
# there DVB cards you might need to apply this patch first.
#
# This is a modified version of the patch for VDRs with BIGPATCH.
# Thanks to p_body@vdrportal.
#
# IMPORTANT: As this patch does not only modify streamdev-server but
# also an exported method of VDR, you will need to
#
# !!!!! RECOMPILE VDR AND ALL PLUGINS !!!!!
#
# Why do I need the patch?
# --------------------------
# Before switching channels VDR will consider all of its devices to
# find the one with the least impact. This includes the device provided
# by the streamdev-client plugin. Streamdev-client will forward the
# request to its server which in turn checks all of its devices. Now if
# the server is running streamdev-client, too, the request will again
# be forwarded to its server and finally you will endup in a loop.
#
# What does the patch do?
# -----------------------
# The patch adds the additional parameter "bool DVBCardsOnly" to VDR's
# device selection method cDevice::GetDevice(...). The parameter
# defaults to false which gives you the standard behaviour of GetDevice.
# When set to true, GetDevice will use only those devices with a card
# index < MAXDVBDEVICES, so only real DVB cards will be considered.
# Other devices like streamdev-client or DVB cards provided by plugin
# (Hauppauge PVR) won't be used.
#
# Author: Frank Schmirler (http://vdr.schmirler.de)
#
--- device.h.orig 2006-11-15 12:01:34.000000000 +0100
+++ device.h 2006-11-15 12:02:15.000000000 +0100
@@ -128,7 +128,7 @@
///< Gets the device with the given Index.
///< \param Index must be in the range 0..numDevices-1.
///< \return A pointer to the device, or NULL if the Index was invalid.
- static cDevice *GetDevice(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL, bool LiveView = false);
+ static cDevice *GetDevice(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL, bool LiveView = false, bool DVBCardsOnly = false);
///< Returns a device that is able to receive the given Channel at the
///< given Priority, with the least impact on active recordings and
///< live viewing.
--- device.c.orig 2006-11-15 12:01:30.000000000 +0100
+++ device.c 2006-11-22 12:28:05.000000000 +0100
@@ -8,6 +8,7 @@
*/
#include "device.h"
+#include "dvbdevice.h"
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
@@ -278,11 +279,13 @@
return (0 <= Index && Index < numDevices) ? device[Index] : NULL;
}
-cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers, bool LiveView)
+cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers, bool LiveView, bool DVBCardsOnly)
{
cDevice *d = NULL;
uint Impact = 0xFFFFFFFF; // we're looking for a device with the least impact
for (int i = 0; i < numDevices; i++) {
+ if (DVBCardsOnly && device[i]->CardIndex() >= MAXDVBDEVICES)
+ continue;
bool ndr;
if (device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basicly able to do the job
// Put together an integer number that reflects the "impact" using
--- PLUGINS/src/streamdev/server/connection.c.orig 2006-11-15 12:10:11.000000000 +0100
+++ PLUGINS/src/streamdev/server/connection.c 2006-11-15 12:10:59.000000000 +0100
@@ -132,7 +132,7 @@
Dprintf(" * GetDevice(const cChannel*, int)\n");
Dprintf(" * -------------------------------\n");
- device = cDevice::GetDevice(Channel, Priority);
+ device = cDevice::GetDevice(Channel, Priority, NULL, NULL, true);
Dprintf(" * Found following device: %p (%d)\n", device,
device ? device->CardIndex() + 1 : 0);
@@ -150,7 +150,7 @@
const cChannel *current = Channels.GetByNumber(cDevice::CurrentChannel());
isyslog("streamdev-server: Detaching current receiver");
Detach();
- device = cDevice::GetDevice(Channel, Priority);
+ device = cDevice::GetDevice(Channel, Priority, NULL, NULL, true);
Attach();
Dprintf(" * Found following device: %p (%d)\n", device,
device ? device->CardIndex() + 1 : 0);

View File

@@ -0,0 +1,102 @@
# Apply this patch to VDR if you want to use a fullfeatured DVB card
# as pure output device. Infact the patch will keep VDR from using the
# tuner of any local DVB card (also budget cards). It will not affect
# other input devices like e.g. streamdev-client or DVB cards provided
# by plugins (e.g. Hauppauge PVR).
#
# By default the patch is DISABLED. There will be a new OSD menu entry
# in Setup->DVB which allows you to enable or disable the patch at any
# time.
diff -ru vdr-1.4.3.orig/config.c vdr-1.4.3/config.c
--- vdr-1.4.3.orig/config.c 2006-07-22 13:57:51.000000000 +0200
+++ vdr-1.4.3/config.c 2006-11-16 08:16:37.000000000 +0100
@@ -273,6 +273,7 @@
CurrentChannel = -1;
CurrentVolume = MAXVOLUME;
CurrentDolby = 0;
+ LocalChannelProvide = 1;
InitialChannel = 0;
InitialVolume = -1;
}
@@ -434,6 +435,7 @@
else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value);
else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value);
else if (!strcasecmp(Name, "CurrentDolby")) CurrentDolby = atoi(Value);
+ else if (!strcasecmp(Name, "LocalChannelProvide")) LocalChannelProvide = atoi(Value);
else if (!strcasecmp(Name, "InitialChannel")) InitialChannel = atoi(Value);
else if (!strcasecmp(Name, "InitialVolume")) InitialVolume = atoi(Value);
else
@@ -502,6 +504,7 @@
Store("CurrentChannel", CurrentChannel);
Store("CurrentVolume", CurrentVolume);
Store("CurrentDolby", CurrentDolby);
+ Store("LocalChannelProvide",LocalChannelProvide);
Store("InitialChannel", InitialChannel);
Store("InitialVolume", InitialVolume);
diff -ru vdr-1.4.3.orig/config.h vdr-1.4.3/config.h
--- vdr-1.4.3.orig/config.h 2006-09-23 15:56:08.000000000 +0200
+++ vdr-1.4.3/config.h 2006-11-16 08:16:57.000000000 +0100
@@ -250,6 +250,7 @@
int CurrentChannel;
int CurrentVolume;
int CurrentDolby;
+ int LocalChannelProvide;
int InitialChannel;
int InitialVolume;
int __EndData__;
diff -ru vdr-1.4.3.orig/dvbdevice.c vdr-1.4.3/dvbdevice.c
--- vdr-1.4.3.orig/dvbdevice.c 2006-08-14 11:38:32.000000000 +0200
+++ vdr-1.4.3/dvbdevice.c 2006-11-16 08:17:58.000000000 +0100
@@ -766,6 +766,8 @@
bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
{
+ if (Setup.LocalChannelProvide != 1)
+ return false;
bool result = false;
bool hasPriority = Priority < 0 || Priority > this->Priority();
bool needsDetachReceivers = false;
diff -ru vdr-1.4.3.orig/i18n.c vdr-1.4.3/i18n.c
--- vdr-1.4.3.orig/i18n.c 2006-09-16 11:08:30.000000000 +0200
+++ vdr-1.4.3/i18n.c 2006-11-16 08:36:53.000000000 +0100
@@ -3546,6 +3546,28 @@
"Foretrukket sprog",
"Preferovaný jazyk",
},
+ { "Setup.DVB$Use DVB receivers",
+ "DVB Empfangsteile benutzen",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ },
{ "Setup.DVB$Primary DVB interface",
"Primäres DVB-Interface",
"Primarna naprava",
diff -ru vdr-1.4.3.orig/menu.c vdr-1.4.3/menu.c
--- vdr-1.4.3.orig/menu.c 2006-07-23 11:23:11.000000000 +0200
+++ vdr-1.4.3/menu.c 2006-11-16 08:37:27.000000000 +0100
@@ -2354,6 +2354,7 @@
Clear();
+ Add(new cMenuEditBoolItem(tr("Setup.DVB$Use DVB receivers"), &data.LocalChannelProvide));
Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices()));
Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9"));
if (data.VideoFormat == 0)

View File

@@ -1,13 +0,0 @@
--- device.c.orig 2008-03-28 11:47:25.000000000 +0100
+++ device.c 2008-03-28 11:47:09.000000000 +0100
@@ -375,8 +375,8 @@
}
}
}
- if (!NumUsableSlots)
- return NULL; // no CAM is able to decrypt this channel
+// if (!NumUsableSlots)
+// return NULL; // no CAM is able to decrypt this channel
}
bool NeedsDetachReceivers = false;

View File

@@ -1,78 +0,0 @@
Index: vdr-1.6.0-nocamdevices/device.c
===================================================================
--- vdr-1.6.0-nocamdevices/device.c
+++ vdr-1.6.0-nocamdevices/device.c 2008-04-27 18:55:37.000000000 +0300
@@ -363,6 +363,7 @@
int NumCamSlots = CamSlots.Count();
int SlotPriority[NumCamSlots];
int NumUsableSlots = 0;
+ bool InternalCamNeeded = false;
if (Channel->Ca() >= CA_ENCRYPTED_MIN) {
for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
SlotPriority[CamSlot->Index()] = MAXPRIORITY + 1; // assumes it can't be used
@@ -376,7 +377,7 @@
}
}
if (!NumUsableSlots)
- return NULL; // no CAM is able to decrypt this channel
+ InternalCamNeeded = true; // no CAM is able to decrypt this channel
}
bool NeedsDetachReceivers = false;
@@ -392,11 +393,13 @@
continue; // this device shall be temporarily avoided
if (Channel->Ca() && Channel->Ca() <= CA_DVB_MAX && Channel->Ca() != device[i]->CardIndex() + 1)
continue; // a specific card was requested, but not this one
- if (NumUsableSlots && !CamSlots.Get(j)->Assign(device[i], true))
+ if (InternalCamNeeded && !device[i]->HasInternalCam())
+ continue; // no CAM is able to decrypt this channel and the device uses vdr handled CAMs
+ if (NumUsableSlots && !device[i]->HasInternalCam() && !CamSlots.Get(j)->Assign(device[i], true))
continue; // CAM slot can't be used with this device
bool ndr;
if (device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basicly able to do the job
- if (NumUsableSlots && device[i]->CamSlot() && device[i]->CamSlot() != CamSlots.Get(j))
+ if (NumUsableSlots && !device[i]->HasInternalCam() && device[i]->CamSlot() && device[i]->CamSlot() != CamSlots.Get(j))
ndr = true; // using a different CAM slot requires detaching receivers
// Put together an integer number that reflects the "impact" using
// this device would have on the overall system. Each condition is represented
@@ -410,18 +413,18 @@
imp <<= 1; imp |= device[i]->Receiving(); // avoid devices that are receiving
imp <<= 1; imp |= device[i] == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device
imp <<= 8; imp |= min(max(device[i]->Priority() + MAXPRIORITY, 0), 0xFF); // use the device with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
- imp <<= 8; imp |= min(max((NumUsableSlots ? SlotPriority[j] : 0) + MAXPRIORITY, 0), 0xFF); // use the CAM slot with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
+ imp <<= 8; imp |= min(max(((NumUsableSlots && !device[i]->HasInternalCam()) ? SlotPriority[j] : 0) + MAXPRIORITY, 0), 0xFF); // use the CAM slot with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
imp <<= 1; imp |= ndr; // avoid devices if we need to detach existing receivers
imp <<= 1; imp |= device[i]->IsPrimaryDevice(); // avoid the primary device
- imp <<= 1; imp |= NumUsableSlots ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels
+ imp <<= 1; imp |= (NumUsableSlots || InternalCamNeeded) ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels
imp <<= 1; imp |= device[i]->HasDecoder(); // avoid full featured cards
- imp <<= 1; imp |= NumUsableSlots ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel
+ imp <<= 1; imp |= (NumUsableSlots && !device[i]->HasInternalCam()) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel
if (imp < Impact) {
// This device has less impact than any previous one, so we take it.
Impact = imp;
d = device[i];
NeedsDetachReceivers = ndr;
- if (NumUsableSlots)
+ if (NumUsableSlots && !device[i]->HasInternalCam())
s = CamSlots.Get(j);
}
}
Index: vdr-1.6.0-nocamdevices/device.h
===================================================================
--- vdr-1.6.0-nocamdevices/device.h
+++ vdr-1.6.0-nocamdevices/device.h 2008-04-27 18:55:49.000000000 +0300
@@ -335,6 +335,12 @@
public:
virtual bool HasCi(void);
///< Returns true if this device has a Common Interface.
+ virtual bool HasInternalCam(void) { return false; }
+ ///< Returns true if this device handles encrypted channels itself
+ ///< without VDR assistance. This can be e.g. when the device is a
+ ///< client that gets the stream from another VDR instance that has
+ ///< already decrypted the stream. In this case ProvidesChannel()
+ ///< shall check whether the channel can be decrypted.
void SetCamSlot(cCamSlot *CamSlot);
///< Sets the given CamSlot to be used with this device.
cCamSlot *CamSlot(void) const { return camSlot; }

View File

@@ -0,0 +1,11 @@
--- vdr.c.orig 2009-02-13 09:45:55.000000000 +0100
+++ vdr.c 2009-02-13 09:46:24.000000000 +0100
@@ -115,7 +115,7 @@
static bool SetCapSysTime(void)
{
// drop all capabilities except cap_sys_time
- cap_t caps = cap_from_text("= cap_sys_time=ep");
+ cap_t caps = cap_from_text("= cap_sys_time,cap_net_raw=ep");
if (!caps) {
fprintf(stderr, "vdr: cap_from_text failed: %s\n", strerror(errno));
return false;

View File

@@ -1,34 +0,0 @@
#
# Makefile for a Video Disk Recorder plugin
#
# $Id: Makefile,v 1.2 2010/07/19 13:49:28 schmirl Exp $
### The object files (add further files here):
OBJS = tsremux.o ts2es.o ts2pes.o ts2ps.o extern.o
### The main target:
.PHONY: clean
remux.a: $(OBJS)
ar -rcs remux.a $^
### Implicit rules:
%.o: %.c
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
MAKEDEP = $(CXX) -MM -MG
DEPFILE = .dependencies
$(DEPFILE): Makefile
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
-include $(DEPFILE)
### Targets:
clean:
@-rm -f $(OBJS) $(DEPFILE) *.a core* *~

View File

@@ -3,7 +3,6 @@
#include "server/connection.h"
#include "server/streamer.h"
#include <vdr/channels.h>
#include <vdr/remux.h>
#include <vdr/tools.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -26,7 +25,7 @@ protected:
virtual void Action(void);
public:
cTSExt(cRingBufferLinear *ResultBuffer, const cServerConnection *Connection, const cChannel *Channel, const cPatPmtParser *PatPmt, const int *Apids, const int *Dpids);
cTSExt(cRingBufferLinear *ResultBuffer, const cServerConnection *Connection, const cChannel *Channel, const int *Apids, const int *Dpids);
virtual ~cTSExt();
void Put(const uchar *Data, int Count);
@@ -35,7 +34,7 @@ public:
} // namespace Streamdev
using namespace Streamdev;
cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, const cServerConnection *Connection, const cChannel *Channel, const cPatPmtParser *PatPmt, const int *Apids, const int *Dpids):
cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, const cServerConnection *Connection, const cChannel *Channel, const int *Apids, const int *Dpids):
m_ResultBuffer(ResultBuffer),
m_Active(false),
m_Process(-1),
@@ -74,24 +73,17 @@ cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, const cServerConnection *Connect
#define ADDENV(x...) if (asprintf(&env[i++], x) < 0) i--
// add channel ID, name and pids to environment
if (Channel) {
ADDENV("REMUX_CHANNEL_ID=%s", *Channel->GetChannelID().ToString());
ADDENV("REMUX_CHANNEL_NAME=%s", Channel->Name());
ADDENV("REMUX_VTYPE=%d", Channel->Vtype());
if (Channel->Vpid())
ADDENV("REMUX_VPID=%d", Channel->Vpid());
if (Channel->Ppid() != Channel->Vpid())
ADDENV("REMUX_PPID=%d", Channel->Ppid());
if (Channel->Tpid())
ADDENV("REMUX_TPID=%d", Channel->Tpid());
}
else if (PatPmt) {
ADDENV("REMUX_VTYPE=%d", PatPmt->Vtype());
if (PatPmt->Vpid())
ADDENV("REMUX_VPID=%d", PatPmt->Vpid());
if (PatPmt->Ppid() != PatPmt->Vpid())
ADDENV("REMUX_PPID=%d", PatPmt->Ppid());
}
ADDENV("REMUX_CHANNEL_ID=%s", *Channel->GetChannelID().ToString());
ADDENV("REMUX_CHANNEL_NAME=%s", Channel->Name());
#if APIVERSNUM >= 10701
ADDENV("REMUX_VTYPE=%d", Channel->Vtype());
#endif
if (Channel->Vpid())
ADDENV("REMUX_VPID=%d", Channel->Vpid());
if (Channel->Ppid() != Channel->Vpid())
ADDENV("REMUX_PPID=%d", Channel->Ppid());
if (Channel->Tpid())
ADDENV("REMUX_TPID=%d", Channel->Tpid());
std::string buffer;
if (Apids && *Apids) {
@@ -102,16 +94,9 @@ cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, const cServerConnection *Connect
buffer.clear();
for (const int *pid = Apids; *pid; pid++) {
int j;
if (Channel) {
for (j = 0; Channel->Apid(j) && Channel->Apid(j) != *pid; j++)
;
(buffer += Channel->Alang(j)) += (*(pid + 1) ? " " : "");
}
else if (PatPmt) {
for (j = 0; PatPmt->Apid(j) && PatPmt->Apid(j) != *pid; j++)
;
(buffer += PatPmt->Alang(j)) += (*(pid + 1) ? " " : "");
}
for (j = 0; Channel->Apid(j) && Channel->Apid(j) != *pid; j++)
;
(buffer += Channel->Alang(j)) += (*(pid + 1) ? " " : "");
}
ADDENV("REMUX_ALANG=%s", buffer.c_str());
}
@@ -125,21 +110,14 @@ cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, const cServerConnection *Connect
buffer.clear();
for (const int *pid = Dpids; *pid; pid++) {
int j;
if (Channel) {
for (j = 0; Channel->Dpid(j) && Channel->Dpid(j) != *pid; j++)
;
(buffer += Channel->Dlang(j)) += (*(pid + 1) ? " " : "");
}
else if (PatPmt) {
for (j = 0; PatPmt->Dpid(j) && PatPmt->Dpid(j) != *pid; j++)
;
(buffer += PatPmt->Dlang(j)) += (*(pid + 1) ? " " : "");
}
for (j = 0; Channel->Dpid(j) && Channel->Dpid(j) != *pid; j++)
;
(buffer += Channel->Dlang(j)) += (*(pid + 1) ? " " : "");
}
ADDENV("REMUX_DLANG=%s", buffer.c_str());
}
if (Channel && Channel->Spid(0)) {
if (Channel->Spid(0)) {
buffer.clear();
for (const int *pid = Channel->Spids(); *pid; pid++)
(buffer += (const char *) itoa(*pid)) += (*(pid + 1) ? " " : "");
@@ -150,17 +128,6 @@ cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, const cServerConnection *Connect
(buffer += Channel->Slang(j)) += (Channel->Spid(j + 1) ? " " : "");
ADDENV("REMUX_SLANG=%s", buffer.c_str());
}
else if (PatPmt && PatPmt->Spid(0)) {
buffer.clear();
for (const int *pid = PatPmt->Spids(); *pid; pid++)
(buffer += (const char *) itoa(*pid)) += (*(pid + 1) ? " " : "");
ADDENV("REMUX_SPID=%s", buffer.c_str());
buffer.clear();
for (int j = 0; PatPmt->Spid(j); j++)
(buffer += PatPmt->Slang(j)) += (PatPmt->Spid(j + 1) ? " " : "");
ADDENV("REMUX_SLANG=%s", buffer.c_str());
}
if (Connection) {
// add vars for a CGI like interface
@@ -174,7 +141,7 @@ cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, const cServerConnection *Connect
ADDENV("SERVER_PROTOCOL=%s", Connection->Protocol());
ADDENV("SERVER_SOFTWARE=%s", VERSION);
for (tStrStrMap::const_iterator it = Connection->Headers().begin(); it != Connection->Headers().end(); ++it) {
for (tStrStrMap::const_iterator it = Connection->Headers().begin(); it != Connection->Headers().end(); it++) {
if (i >= MAXENV) {
esyslog("streamdev-server: Too many headers for externremux.sh");
break;
@@ -303,7 +270,7 @@ void cTSExt::Action(void)
dsyslog("streamdev-server: buffer full while reading from externremux");
if (result == -1) {
if (errno != EINTR && errno != EAGAIN) {
if (errno != EINTR) {
LOG_ERROR_STR("read failed");
m_Active = false;
}
@@ -330,14 +297,8 @@ void cTSExt::Put(const uchar *Data, int Count)
}
cExternRemux::cExternRemux(const cServerConnection *Connection, const cChannel *Channel, const int *Apids, const int *Dpids):
m_ResultBuffer(new cRingBufferLinear(WRITERBUFSIZE)),
m_Remux(new cTSExt(m_ResultBuffer, Connection, Channel, NULL, Apids, Dpids))
{
m_ResultBuffer->SetTimeouts(500, 100);
}
cExternRemux::cExternRemux(const cServerConnection *Connection, const cPatPmtParser *PatPmt, const int *Apids, const int *Dpids):
m_ResultBuffer(new cRingBufferLinear(WRITERBUFSIZE)),
m_Remux(new cTSExt(m_ResultBuffer, Connection, NULL, PatPmt, Apids, Dpids))
m_ResultBuffer(new cRingBufferLinear(WRITERBUFSIZE, TS_SIZE * 2)),
m_Remux(new cTSExt(m_ResultBuffer, Connection, Channel, Apids, Dpids))
{
m_ResultBuffer->SetTimeouts(500, 100);
}

View File

@@ -6,7 +6,6 @@
#include <string>
class cChannel;
class cPatPmtParser;
class cServerConnection;
namespace Streamdev {
@@ -20,7 +19,6 @@ private:
public:
cExternRemux(const cServerConnection *Connection, const cChannel *Channel, const int *APids, const int *Dpids);
cExternRemux(const cServerConnection *Connection, const cPatPmtParser *PatPmt, const int *APids, const int *Dpids);
virtual ~cExternRemux();
int Put(const uchar *Data, int Count);

View File

@@ -10,13 +10,12 @@
* The cRepacker family's code was originally written by Reinhard Nissl <rnissl@gmx.de>,
* and adapted to the VDR coding style by Klaus.Schmidinger@cadsoft.de.
*
* $Id: ts2pes.c,v 1.2 2009/06/30 06:04:33 schmirl Exp $
* $Id: ts2pes.c,v 1.1.2.3 2009/06/30 06:03:16 schmirl Exp $
*/
#include "remux/ts2pes.h"
#include <stdlib.h>
#include <vdr/channels.h>
#include <vdr/shutdown.h>
namespace Streamdev {
@@ -1803,29 +1802,6 @@ void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188)
instant_repack(Buf + 4 + off, TS_SIZE - 4 - off);
}
// --- cRingBufferLinearPes --------------------------------------------------
class cRingBufferLinearPes : public cStreamdevBuffer {
protected:
virtual int DataReady(const uchar *Data, int Count);
public:
cRingBufferLinearPes(int Size, int Margin = 0, bool Statistics = false, const char *Description = NULL)
:cStreamdevBuffer(Size, Margin, Statistics, Description) {}
};
int cRingBufferLinearPes::DataReady(const uchar *Data, int Count)
{
int c = cRingBufferLinear::DataReady(Data, Count);
if (!c && Count >= 6) {
if (!Data[0] && !Data[1] && Data[2] == 0x01) {
int Length = 6 + Data[4] * 256 + Data[5];
if (Length <= Count)
return Length;
}
}
return c;
}
// --- cTS2PESRemux ----------------------------------------------------------------
#define RESULTBUFFERSIZE KILOBYTE(256)
@@ -1837,7 +1813,7 @@ cTS2PESRemux::cTS2PESRemux(int VPid, const int *APids, const int *DPids, const i
skipped = 0;
numTracks = 0;
resultSkipped = 0;
resultBuffer = new cRingBufferLinearPes(RESULTBUFFERSIZE, IPACKS, false, "Result");
resultBuffer = new cStreamdevBuffer(RESULTBUFFERSIZE, IPACKS, false, "Result");
resultBuffer->SetTimeouts(100, 100);
if (VPid)
#define TEST_cVideoRepacker

View File

@@ -4,7 +4,7 @@
* This file is based on a copy of remux.h from Klaus Schmidinger's
* VDR, version 1.6.0.
*
* $Id: ts2pes.h,v 1.4 2009/07/06 06:11:11 schmirl Exp $
* $Id: ts2pes.h,v 1.2.2.4 2009/07/06 06:13:41 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_TS2PES_H

View File

@@ -1,5 +1,3 @@
#ifdef STREAMDEV_PS
#include "remux/ts2ps.h"
#include "server/streamer.h"
#include <vdr/channels.h>
@@ -218,4 +216,3 @@ uchar *cTS2PSRemux::Get(int &Count)
return resultData;
}
#endif

View File

@@ -1,15 +1,9 @@
#ifdef STREAMDEV_PS
#ifndef VDR_STREAMDEV_TS2PSREMUX_H
#define VDR_STREAMDEV_TS2PSREMUX_H
#include "remux/tsremux.h"
#include "server/streamer.h"
#ifndef MAXTRACKS
#define MAXTRACKS 64
#endif
namespace Streamdev {
class cTS2PS;
@@ -36,5 +30,3 @@ public:
} // namespace Streamdev
#endif // VDR_STREAMDEV_TS2PSREMUX_H
#endif

View File

@@ -1,7 +1,7 @@
#include "remux/tsremux.h"
#define SC_PICTURE 0x00 // "picture header"
#define PID_MASK_HI 0x1F
#define SC_PICTURE 0x00 // "picture header"
#define VIDEO_STREAM_S 0xE0
using namespace Streamdev;

View File

@@ -1,89 +0,0 @@
#
# Makefile for a Video Disk Recorder plugin
#
# $Id: $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
# By default the main source file also carries this name.
PLUGIN = streamdev-server
### The name of the shared object file:
SOFILE = libvdr-$(PLUGIN).so
### Includes and Defines (add further entries here):
DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
### The object files (add further files here):
COMMONOBJS = ../common.o
SERVEROBJS = $(PLUGIN).o \
server.o component.o connection.o \
componentVTP.o connectionVTP.o \
componentHTTP.o connectionHTTP.o menuHTTP.o \
componentIGMP.o connectionIGMP.o \
streamer.o livestreamer.o livefilter.o recstreamer.o recplayer.o \
menu.o suspend.o setup.o
### The main target:
all: $(SOFILE) i18n
### Implicit rules:
%.o: %.c
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
MAKEDEP = $(CXX) -MM -MG
DEPFILE = .dependencies
$(DEPFILE): Makefile
@$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(SERVEROBJS:%.o=%.c) $(COMMONOBJS:%.o=%.c) > $@
-include $(DEPFILE)
### Internationalization (I18N):
PODIR = po
I18Npo = $(wildcard $(PODIR)/*.po)
I18Nmo = $(addsuffix .mo, $(foreach file, $(I18Npo), $(basename $(file))))
I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
I18Npot = $(PODIR)/$(PLUGIN).pot
%.mo: %.po
msgfmt -c -o $@ $<
$(I18Npot): $(SERVEROBJS:%.o=%.c)
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<vdrdev@schmirler.de>' -o $@ `ls $^`
%.po: $(I18Npot)
msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
@touch $@
$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
install -D -m644 $< $@
.PHONY: i18n
i18n: $(I18Nmo) $(I18Npot)
install-i18n: $(I18Nmsgs)
### Targets:
$(SOFILE): $(SERVEROBJS) $(COMMONOBJS) \
../tools/sockettools.a ../remux/remux.a ../libdvbmpeg/libdvbmpegtools.a
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $^ -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
install: install-lib install-i18n
clean:
@-rm -f $(PODIR)/*.mo $(PODIR)/*.pot
@-rm -f $(COMMONOBJS) $(SERVEROBJS) $(DEPFILE) *.so *.tgz core* *~

View File

@@ -1,82 +0,0 @@
#
# Makefile for a Video Disk Recorder plugin
#
# $Id: Makefile,v 1.2 2010/07/19 13:49:31 schmirl Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
# By default the main source file also carries this name.
#
PLUGIN = streamdev-server
### Includes and Defines (add further entries here):
DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
### The object files (add further files here):
COMMONOBJS = ../common.o
SERVEROBJS = $(PLUGIN).o \
server.o component.o connection.o \
componentVTP.o connectionVTP.o \
componentHTTP.o connectionHTTP.o menuHTTP.o \
componentIGMP.o connectionIGMP.o \
streamer.o livestreamer.o livefilter.o recstreamer.o recplayer.o \
menu.o suspend.o setup.o
### The main target:
.PHONY: all i18n clean
all: libvdr-$(PLUGIN).so i18n
### Implicit rules:
%.o: %.c
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
MAKEDEP = $(CXX) -MM -MG
DEPFILE = .dependencies
$(DEPFILE): Makefile
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(SERVEROBJS:%.o=%.c) $(COMMONOBJS:%.o=%.c) > $@
-include $(DEPFILE)
### Internationalization (I18N):
PODIR = po
LOCALEDIR = $(VDRDIR)/locale
I18Npo = $(wildcard $(PODIR)/*.po)
I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
I18Npot = $(PODIR)/$(PLUGIN).pot
%.mo: %.po
msgfmt -c -o $@ $<
$(I18Npot): $(SERVEROBJS:%.o=%.c)
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='<http://www.vdr-developer.org/mantisbt/>' -o $@ $^
%.po: $(I18Npot)
msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
@touch $@
$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
@mkdir -p $(dir $@)
cp $< $@
i18n: $(I18Nmsgs)
### Targets:
libvdr-$(PLUGIN).so: $(SERVEROBJS) $(COMMONOBJS) \
../tools/sockettools.a ../remux/remux.a ../libdvbmpeg/libdvbmpegtools.a
%.so:
$(CXX) $(CXXFLAGS) -shared $^ -o $@
@cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
clean:
@-rm -f $(COMMONOBJS) $(SERVEROBJS) $(DEPFILE) $(PODIR)/*.mo $(PODIR)/*.pot *.so *.tgz core* *~

View File

@@ -1,5 +1,5 @@
/*
* $Id: component.c,v 1.4 2009/02/13 10:39:22 schmirl Exp $
* $Id: component.c,v 1.3.2.1 2009/02/13 10:39:42 schmirl Exp $
*/
#include "server/component.h"

View File

@@ -1,5 +1,5 @@
/*
* $Id: component.h,v 1.3 2009/02/13 10:39:22 schmirl Exp $
* $Id: component.h,v 1.2.2.1 2009/02/13 10:39:42 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_SERVERS_COMPONENT_H

View File

@@ -1,12 +1,11 @@
/*
* $Id: componentIGMP.c,v 1.2 2009/07/03 21:44:19 schmirl Exp $
* $Id: componentIGMP.c,v 1.1.2.3 2009/07/03 21:42:08 schmirl Exp $
*/
#include <netinet/ip.h>
#include <netinet/igmp.h>
#include "server/componentIGMP.h"
#include "server/connectionIGMP.h"
#include "server/server.h"
#include "server/setup.h"
#ifndef IGMP_ALL_HOSTS
@@ -38,6 +37,7 @@
class cMulticastGroup: public cListObject
{
public:
cConnectionIGMP *connection;
in_addr_t group;
in_addr_t reporter;
struct timeval timeout;
@@ -48,6 +48,7 @@ public:
};
cMulticastGroup::cMulticastGroup(in_addr_t Group) :
connection(NULL),
group(Group),
reporter(0)
{
@@ -105,11 +106,7 @@ cComponentIGMP::~cComponentIGMP(void)
{
}
#if APIVERSNUM >= 20300
cMulticastGroup* cComponentIGMP::FindGroup(in_addr_t Group)
#else
cMulticastGroup* cComponentIGMP::FindGroup(in_addr_t Group) const
#endif
{
cMulticastGroup *group = m_Groups.First();
while (group && group->group != Group)
@@ -121,12 +118,7 @@ bool cComponentIGMP::Initialize(void)
{
if (cServerComponent::Initialize() && IGMPMembership(IGMP_ALL_ROUTER))
{
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
for (const cChannel *channel = Channels->First(); channel; channel = Channels->Next(channel))
#else
for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
#endif
{
if (channel->GroupSep())
continue;
@@ -152,15 +144,8 @@ void cComponentIGMP::Destruct(void)
{
if (m_MaxChannelNumber > 0)
{
Cancel(-1);
m_CondWait.Signal();
Cancel(2);
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
for (const cChannel *channel = Channels->First(); channel; channel = Channels->Next(channel))
#else
Cancel(3);
for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
#endif
{
if (channel->GroupSep())
continue;
@@ -248,7 +233,10 @@ cServerConnection* cComponentIGMP::ProcessMessage(struct igmp *Igmp, in_addr_t G
group = new cMulticastGroup(Group);
m_Groups.Add(group);
}
conn = IGMPStartMulticast(group);
if (!group->connection) {
IGMPStartMulticast(group);
conn = group->connection;
}
IGMPStartTimer(group, Sender);
if (Igmp->igmp_type == IGMP_V1_MEMBERSHIP_REPORT)
IGMPStartV1HostTimer(group);
@@ -440,49 +428,20 @@ void cComponentIGMP::IGMPSendGroupQuery(cMulticastGroup* Group)
IGMPSendQuery(Group->group, IGMP_LAST_MEMBER_QUERY_INTERVAL_TS);
}
cServerConnection* cComponentIGMP::IGMPStartMulticast(cMulticastGroup* Group)
void cComponentIGMP::IGMPStartMulticast(cMulticastGroup* Group)
{
cServerConnection *conn = NULL;
in_addr_t g = ntohl(Group->group);
if (g > MULTICAST_PRIV_MIN && g <= MULTICAST_PRIV_MAX) {
cThreadLock lock;
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
const cChannel *channel = Channels->GetByNumber(g - MULTICAST_PRIV_MIN);
#else
cChannel *channel = Channels.GetByNumber(g - MULTICAST_PRIV_MIN);
#endif
const cList<cServerConnection>& clients = cStreamdevServer::Clients(lock);
#if APIVERSNUM >= 20300
const cServerConnection *s = clients.First();
#else
cServerConnection *s = clients.First();
#endif
while (s) {
if (s->RemoteIpAddr() == Group->group)
break;
s = clients.Next(s);
}
if (!s) {
conn = NewClient();
if (!((cConnectionIGMP *)conn)->SetChannel(channel, Group->group)) {
DELETENULL(conn);
}
Group->connection = (cConnectionIGMP*) NewClient();
if (!Group->connection->Start(channel, Group->group)) {
DELETENULL(Group->connection);
}
}
return conn;
}
void cComponentIGMP::IGMPStopMulticast(cMulticastGroup* Group)
{
cThreadLock lock;
#if APIVERSNUM >= 20300
cList<cServerConnection>& clients = cStreamdevServer::Clients(lock);
#else
const cList<cServerConnection>& clients = cStreamdevServer::Clients(lock);
#endif
for (cServerConnection *s = clients.First(); s; s = clients.Next(s)) {
if (s->RemoteIpAddr() == Group->group)
s->Close();
}
if (Group->connection)
Group->connection->Stop();
}

View File

@@ -1,5 +1,5 @@
/*
* $Id: componentIGMP.h,v 1.1 2009/02/13 10:39:22 schmirl Exp $
* $Id: componentIGMP.h,v 1.1.2.2 2009/02/13 10:39:42 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_IGMPSERVER_H
@@ -9,8 +9,8 @@
#include <time.h>
#include <vdr/thread.h>
#include "server/component.h"
#include "../common.h"
class cConnectionIGMP;
class cMulticastGroup;
class cComponentIGMP: public cServerComponent, public cThread {
@@ -24,11 +24,7 @@ private:
bool m_Querier;
cCondWait m_CondWait;
#if APIVERSNUM >= 20300
cMulticastGroup* FindGroup(in_addr_t Group);
#else
cMulticastGroup* FindGroup(in_addr_t Group) const;
#endif
/* Add or remove local host to multicast group */
bool IGMPMembership(in_addr_t Group, bool Add = true);
@@ -46,7 +42,7 @@ private:
void IGMPStartRetransmitTimer(cMulticastGroup* Group);
void IGMPClearRetransmitTimer(cMulticastGroup* Group);
void IGMPSendGroupQuery(cMulticastGroup* Group);
cServerConnection* IGMPStartMulticast(cMulticastGroup* Group);
void IGMPStartMulticast(cMulticastGroup* Group);
void IGMPStopMulticast(cMulticastGroup* Group);
virtual void Action();

View File

@@ -1,5 +1,5 @@
/*
* $Id: connection.c,v 1.16 2010/08/03 10:51:53 schmirl Exp $
* $Id: connection.c,v 1.10.2.4 2010/08/03 10:56:58 schmirl Exp $
*/
#include "server/connection.h"
@@ -8,7 +8,6 @@
#include "common.h"
#include <vdr/tools.h>
#include <vdr/thread.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
@@ -20,14 +19,12 @@ cServerConnection::cServerConnection(const char *Protocol, int Type):
m_Pending(false),
m_ReadBytes(0),
m_WriteBytes(0),
m_WriteIndex(0),
m_Streamer(NULL)
m_WriteIndex(0)
{
}
cServerConnection::~cServerConnection()
{
delete(m_Streamer);
}
const cChannel* cServerConnection::ChannelFromString(const char *String, int *Apid, int *Dpid) {
@@ -44,31 +41,14 @@ const cChannel* cServerConnection::ChannelFromString(const char *String, int *Ap
if (isnumber(string)) {
int temp = strtol(String, NULL, 10);
if (temp == 0)
temp = cDevice::CurrentChannel();
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
if (temp >= 1 && temp <= Channels->MaxNumber())
channel = Channels->GetByNumber(temp);
#else
if (temp >= 1 && temp <= Channels.MaxNumber())
channel = Channels.GetByNumber(temp);
#endif
} else {
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
channel = Channels->GetByChannelID(tChannelID::FromString(string));
#else
channel = Channels.GetByChannelID(tChannelID::FromString(string));
#endif
if (channel == NULL) {
int i = 1;
#if APIVERSNUM >= 20300
while ((channel = Channels->GetByNumber(i, 1)) != NULL) {
#else
while ((channel = Channels.GetByNumber(i, 1)) != NULL) {
#endif
if (String == channel->Name())
break;
@@ -205,14 +185,86 @@ bool cServerConnection::Respond(const char *Message, bool Last, ...)
return true;
}
bool cServerConnection::Close()
cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority)
{
if (IsOpen())
isyslog("streamdev-server: closing %s connection to %s:%d", Protocol(), RemoteIp().c_str(), RemotePort());
return cTBSocket::Close();
}
cDevice *device = NULL;
cString cServerConnection::ToText(char Delimiter) const
{
return cString::sprintf("%s%c%s:%d", Protocol(), Delimiter, RemoteIp().c_str(), RemotePort());
/*Dprintf("+ Statistics:\n");
Dprintf("+ Current Channel: %d\n", cDevice::CurrentChannel());
Dprintf("+ Current Device: %d\n", cDevice::ActualDevice()->CardIndex());
Dprintf("+ Transfer Mode: %s\n", cDevice::ActualDevice()
== cDevice::PrimaryDevice() ? "false" : "true");
Dprintf("+ Replaying: %s\n", cDevice::PrimaryDevice()->Replaying() ? "true"
: "false");*/
Dprintf(" * GetDevice(const cChannel*, int)\n");
Dprintf(" * -------------------------------\n");
#if VDRVERSNUM < 10500
device = cDevice::GetDevice(Channel, Priority);
#else
device = cDevice::GetDevice(Channel, Priority, false);
#endif
Dprintf(" * Found following device: %p (%d)\n", device,
device ? device->CardIndex() + 1 : 0);
if (device == cDevice::ActualDevice())
Dprintf(" * is actual device\n");
if (!cSuspendCtl::IsActive() && StreamdevServerSetup.SuspendMode != smAlways)
Dprintf(" * NOT suspended\n");
if (!device || (device == cDevice::ActualDevice()
&& !cSuspendCtl::IsActive()
&& StreamdevServerSetup.SuspendMode != smAlways)) {
// mustn't switch actual device
// maybe a device would be free if THIS connection did turn off its streams?
Dprintf(" * trying again...\n");
const cChannel *current = Channels.GetByNumber(cDevice::CurrentChannel());
isyslog("streamdev-server: Detaching current receiver");
Detach();
#if VDRVERSNUM < 10500
device = cDevice::GetDevice(Channel, Priority);
#else
device = cDevice::GetDevice(Channel, Priority, false);
#endif
Attach();
Dprintf(" * Found following device: %p (%d)\n", device,
device ? device->CardIndex() + 1 : 0);
if (device == cDevice::ActualDevice())
Dprintf(" * is actual device\n");
if (!cSuspendCtl::IsActive()
&& StreamdevServerSetup.SuspendMode != smAlways)
Dprintf(" * NOT suspended\n");
if (current && !TRANSPONDER(Channel, current))
Dprintf(" * NOT same transponder\n");
if (device && (device == cDevice::ActualDevice()
&& !cSuspendCtl::IsActive()
&& StreamdevServerSetup.SuspendMode != smAlways
&& current != NULL
&& !TRANSPONDER(Channel, current))) {
// now we would have to switch away live tv...let's see if live tv
// can be handled by another device
cDevice *newdev = NULL;
for (int i = 0; i < cDevice::NumDevices(); ++i) {
cDevice *dev = cDevice::GetDevice(i);
if (dev->ProvidesChannel(current, 0) && dev != device) {
newdev = dev;
break;
}
}
Dprintf(" * Found device for live tv: %p (%d)\n", newdev,
newdev ? newdev->CardIndex() + 1 : 0);
if (newdev == NULL || newdev == device) {
// no suitable device to continue live TV, giving up...
device = NULL;
dsyslog("streamdev: Not providing channel %s at priority %d - live TV not suspended", Channel->Name(), Priority);
}
else
newdev->SwitchChannel(current, true);
}
else if (!device)
dsyslog("streamdev: No device provides channel %s at priority %d", Channel->Name(), Priority);
}
return device;
}

View File

@@ -1,5 +1,5 @@
/*
* $Id: connection.h,v 1.10 2010/08/03 10:46:41 schmirl Exp $
* $Id: connection.h,v 1.5.2.4 2010/07/19 13:50:14 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_SERVER_CONNECTION_H
@@ -7,15 +7,14 @@
#include "tools/socket.h"
#include "common.h"
#include "server/streamer.h"
#include <map>
#include <string>
typedef std::map<std::string,std::string> tStrStrMap;
typedef std::pair<std::string,std::string> tStrStr;
class cChannel;
class cDevice;
/* Basic capabilities of a straight text-based protocol, most functions
virtual to support more complicated protocols */
@@ -34,8 +33,6 @@ private:
uint m_WriteBytes;
uint m_WriteIndex;
cStreamdevStreamer *m_Streamer;
tStrStrMap m_Headers;
protected:
@@ -54,12 +51,6 @@ protected:
/* Add a request header */
void SetHeader(const char *Name, const char *Value, const char *Prefix = "") { m_Headers.insert(tStrStr(std::string(Prefix) + Name, Value)); }
/* Set the streamer */
void SetStreamer(cStreamdevStreamer* Streamer) { delete m_Streamer; m_Streamer = Streamer; }
/* Return the streamer */
cStreamdevStreamer *Streamer() const { return m_Streamer; }
static const cChannel *ChannelFromString(const char *String, int *Apid = NULL, int *Dpid = NULL);
public:
@@ -100,17 +91,18 @@ public:
/* Will make the socket close after sending all queued output data */
void DeferClose(void) { m_DeferClose = true; }
/* Close the socket */
virtual bool Close(void);
/* Will retrieve an unused device for transmitting data. Use the returned
cDevice in a following call to StartTransfer */
cDevice *GetDevice(const cChannel *Channel, int Priority);
virtual void Flushed(void) {}
virtual void Detach(void) = 0;
virtual void Attach(void) = 0;
/* This connections protocol name */
virtual const char* Protocol(void) const { return m_Protocol; }
/* Text description of stream */
virtual cString ToText(char Delimiter = ' ') const;
/* std::map with additional information */
const tStrStrMap& Headers(void) const { return m_Headers; }
};

View File

@@ -1,17 +1,8 @@
/*
* $Id: connectionHTTP.c,v 1.21 2010/08/03 10:46:41 schmirl Exp $
* $Id: connectionHTTP.c,v 1.13.2.5 2010/07/22 14:18:36 schmirl Exp $
*/
#include <ctype.h>
#include <time.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <vdr/thread.h>
#include <vdr/recording.h>
#include "server/connectionHTTP.h"
#include "server/menuHTTP.h"
@@ -21,12 +12,10 @@
cConnectionHTTP::cConnectionHTTP(void):
cServerConnection("HTTP"),
m_Status(hsRequest),
m_StreamType((eStreamType)StreamdevServerSetup.HTTPStreamType),
m_LiveStreamer(NULL),
m_Channel(NULL),
m_RecPlayer(NULL),
m_ReplayPos(0),
m_ReplayFakeRange(false),
m_MenuList(NULL)
m_StreamType((eStreamType)StreamdevServerSetup.HTTPStreamType),
m_ChannelList(NULL)
{
Dprintf("constructor hsRequest\n");
m_Apid[0] = m_Apid[1] = 0;
@@ -35,9 +24,7 @@ cConnectionHTTP::cConnectionHTTP(void):
cConnectionHTTP::~cConnectionHTTP()
{
SetStreamer(NULL);
delete m_RecPlayer;
delete m_MenuList;
delete m_LiveStreamer;
}
bool cConnectionHTTP::CanAuthenticate(void)
@@ -61,24 +48,9 @@ bool cConnectionHTTP::Command(char *Cmd)
*v = 0;
SetHeader("REQUEST_METHOD", Cmd);
q = strchr(p, '?');
if (q) {
if (q)
*q = 0;
SetHeader("QUERY_STRING", q + 1);
while (q++) {
char *n = strchr(q, '&');
if (n)
*n = 0;
char *e = strchr(q, '=');
if (e)
*e++ = 0;
else
e = n ? n : v;
m_Params.insert(tStrStr(q, e));
q = n;
}
}
else
SetHeader("QUERY_STRING", "");
SetHeader("QUERY_STRING", q ? ++q : "");
SetHeader("PATH_INFO", p);
m_Status = hsHeaders;
return true;
@@ -161,282 +133,112 @@ bool cConnectionHTTP::ProcessRequest(void)
}
if (!authOk) {
isyslog("streamdev-server: HTTP authorization required");
return HttpResponse(401, true, NULL, "WWW-authenticate: basic Realm=\"Streamdev-Server\"");
DeferClose();
return Respond("HTTP/1.0 401 Authorization Required")
&& Respond("WWW-authenticate: basic Realm=\"Streamdev-Server\")")
&& Respond("");
}
}
tStrStrMap::const_iterator it;
it = m_Params.find("apid");
if (it != m_Params.end())
m_Apid[0] = atoi(it->second.c_str());
it = m_Params.find("dpid");
if (it != m_Params.end())
m_Dpid[0] = atoi(it->second.c_str());
tStrStrMap::const_iterator it_method = Headers().find(REQUEST_METHOD);
tStrStrMap::const_iterator it_pathinfo = Headers().find(PATH_INFO);
if (it_method == Headers().end() || it_pathinfo == Headers().end()) {
// should never happen
esyslog("streamdev-server connectionHTTP: Missing method or pathinfo");
} else if (it_method->second.compare("GET") == 0 && ProcessURI(it_pathinfo->second)) {
if (m_MenuList)
return Respond("%s", true, m_MenuList->HttpHeader().c_str());
if (m_ChannelList)
return Respond("%s", true, m_ChannelList->HttpHeader().c_str());
else if (m_Channel != NULL) {
if (cStreamdevLiveStreamer::ProvidesChannel(m_Channel, StreamdevServerSetup.HTTPPriority)) {
cStreamdevLiveStreamer* liveStreamer = new cStreamdevLiveStreamer(this, m_Channel, StreamdevServerSetup.HTTPPriority, m_StreamType, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL);
if (liveStreamer->GetDevice()) {
SetStreamer(liveStreamer);
cDevice *device = GetDevice(m_Channel, 0);
if (device != NULL) {
device->SwitchChannel(m_Channel, false);
m_LiveStreamer = new cStreamdevLiveStreamer(0, this);
if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL)) {
m_LiveStreamer->SetDevice(device);
if (!SetDSCP())
LOG_ERROR_STR("unable to set DSCP sockopt");
if (m_StreamType == stEXT) {
return Respond("HTTP/1.0 200 OK");
} else if (m_StreamType == stES && (m_Apid[0] || m_Dpid[0] || ISRADIO(m_Channel))) {
return HttpResponse(200, false, "audio/mpeg", "icy-name: %s", m_Channel->Name());
} else if (ISRADIO(m_Channel)) {
return HttpResponse(200, false, "audio/mpeg");
} else if (ISRADIO(m_Channel) || (m_StreamType == stES && (m_Apid[0] || m_Dpid[0]))) {
return Respond("HTTP/1.0 200 OK")
&& Respond("Content-Type: audio/mpeg")
&& Respond("icy-name: %s", true, m_Channel->Name())
&& Respond("");
} else {
return HttpResponse(200, false, "video/mpeg");
return Respond("HTTP/1.0 200 OK")
&& Respond("Content-Type: video/mpeg")
&& Respond("");
}
}
SetStreamer(NULL);
delete liveStreamer;
DELETENULL(m_LiveStreamer);
}
return HttpResponse(503, true);
}
else if (m_RecPlayer != NULL) {
Dprintf("GET recording\n");
bool isPes = m_RecPlayer->getCurrentRecording()->IsPesRecording();
// no remuxing for old PES recordings
if (isPes && m_StreamType != stPES)
return HttpResponse(503, true);
int64_t from, to;
bool hasRange = ParseRange(from, to);
cStreamdevRecStreamer* recStreamer;
if (from == 0 && hasRange && m_ReplayFakeRange) {
recStreamer = new cStreamdevRecStreamer(this, m_RecPlayer, m_StreamType, (int64_t) 0L, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL);
from += m_ReplayPos;
if (to >= 0)
to += m_ReplayPos;
}
else
recStreamer = new cStreamdevRecStreamer(this, m_RecPlayer, m_StreamType, m_ReplayPos, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL);
SetStreamer(recStreamer);
if (m_StreamType == stEXT)
return Respond("HTTP/1.0 200 OK");
else if (m_StreamType == stES && (m_Apid[0] || m_Dpid[0]))
return HttpResponse(200, false, "audio/mpeg");
const char* contentType = (isPes || m_RecPlayer->getPatPmtData()->Vpid()) ? "video/mpeg" : "audio/mpeg";
// range not supported when remuxing
if (m_StreamType != stTS && !isPes)
return HttpResponse(200, false, contentType);
uint64_t total = recStreamer->GetLength();
if (hasRange) {
int64_t length = recStreamer->SetRange(from, to);
Dprintf("range response: %lld-%lld/%lld, len %lld\n", (long long)from, (long long)to, (long long)total, (long long)length);
if (length < 0L)
return HttpResponse(416, true, contentType, "Accept-Ranges: bytes\r\nContent-Range: bytes */%llu", (unsigned long long) total);
else
return HttpResponse(206, false, contentType, "Accept-Ranges: bytes\r\nContent-Range: bytes %lld-%lld/%llu\r\nContent-Length: %lld", (long long) from, (long long) to, (unsigned long long) total, (long long) length);
}
else
return HttpResponse(200, false, contentType, "Accept-Ranges: bytes");
DeferClose();
return Respond("HTTP/1.0 409 Channel not available")
&& Respond("");
}
else {
return HttpResponse(404, true);
DeferClose();
return Respond("HTTP/1.0 404 not found")
&& Respond("");
}
} else if (it_method->second.compare("HEAD") == 0 && ProcessURI(it_pathinfo->second)) {
if (m_MenuList) {
DeferClose();
return Respond("%s", true, m_MenuList->HttpHeader().c_str());
}
DeferClose();
if (m_ChannelList)
return Respond("%s", true, m_ChannelList->HttpHeader().c_str());
else if (m_Channel != NULL) {
if (cStreamdevLiveStreamer::ProvidesChannel(m_Channel, StreamdevServerSetup.HTTPPriority)) {
cDevice *device = GetDevice(m_Channel, 0);
if (device != NULL) {
if (m_StreamType == stEXT) {
cStreamdevLiveStreamer *liveStreamer = new cStreamdevLiveStreamer(this, m_Channel, IDLEPRIORITY, m_StreamType, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL);
SetStreamer(liveStreamer);
return Respond("HTTP/1.0 200 OK");
} else if (m_StreamType == stES && (m_Apid[0] || m_Dpid[0] || ISRADIO(m_Channel))) {
return HttpResponse(200, true, "audio/mpeg", "icy-name: %s", m_Channel->Name());
} else if (ISRADIO(m_Channel)) {
return HttpResponse(200, true, "audio/mpeg");
// TODO
return Respond("HTTP/1.0 200 OK")
&& Respond("");
} else if (ISRADIO(m_Channel) || (m_StreamType == stES && (m_Apid[0] || m_Dpid[0]))) {
return Respond("HTTP/1.0 200 OK")
&& Respond("Content-Type: audio/mpeg")
&& Respond("icy-name: %s", true, m_Channel->Name())
&& Respond("");
} else {
return HttpResponse(200, true, "video/mpeg");
return Respond("HTTP/1.0 200 OK")
&& Respond("Content-Type: video/mpeg")
&& Respond("");
}
}
return HttpResponse(503, true);
}
else if (m_RecPlayer != NULL) {
Dprintf("HEAD recording\n");
bool isPes = m_RecPlayer->getCurrentRecording()->IsPesRecording();
// no remuxing for old PES recordings
if (isPes && m_StreamType != stPES)
return HttpResponse(503, true);
int64_t from, to;
bool hasRange = ParseRange(from, to);
cStreamdevRecStreamer* recStreamer;
if (from == 0 && hasRange && m_ReplayFakeRange) {
recStreamer = new cStreamdevRecStreamer(this, m_RecPlayer, m_StreamType, m_ReplayPos, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL);
from += m_ReplayPos;
if (to >= 0)
to += m_ReplayPos;
}
else
recStreamer = new cStreamdevRecStreamer(this, m_RecPlayer, m_StreamType, m_ReplayPos, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL);
SetStreamer(recStreamer);
if (m_StreamType == stEXT)
return Respond("HTTP/1.0 200 OK");
else if (m_StreamType == stES && (m_Apid[0] || m_Dpid[0]))
return HttpResponse(200, true, "audio/mpeg");
const char* contentType = (isPes || m_RecPlayer->getPatPmtData()->Vpid()) ? "video/mpeg" : "audio/mpeg";
// range not supported when remuxing
if (m_StreamType != stTS && !isPes)
return HttpResponse(200, false, contentType);
uint64_t total = recStreamer->GetLength();
if (hasRange) {
int64_t length = recStreamer->SetRange(from, to);
if (length < 0L)
return HttpResponse(416, true, contentType, "Accept-Ranges: bytes\r\nContent-Range: bytes */%llu", (unsigned long long) total);
else
return HttpResponse(206, true, contentType, "Accept-Ranges: bytes\r\nContent-Range: bytes %lld-%lld/%llu\r\nContent-Length: %lld", (long long) from, (long long) to, (unsigned long long) total, (long long) length);
}
else
return HttpResponse(200, true, contentType, "Accept-Ranges: bytes");
return Respond("HTTP/1.0 409 Channel not available")
&& Respond("");
}
else {
return HttpResponse(404, true);
return Respond("HTTP/1.0 404 not found")
&& Respond("");
}
}
return HttpResponse(400, true);
}
static const char *AAA[] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static const char *MMM[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
bool cConnectionHTTP::HttpResponse(int Code, bool Last, const char* ContentType, const char* Headers, ...)
{
va_list ap;
va_start(ap, Headers);
#if APIVERSNUM >= 10728
cString headers = cString::vsprintf(Headers, ap);
#else
cString headers = cString::sprintf(Headers, ap);
#endif
va_end(ap);
bool rc;
if (Last)
DeferClose();
switch (Code)
{
case 200: rc = Respond("HTTP/1.1 200 OK"); break;
case 206: rc = Respond("HTTP/1.1 206 Partial Content"); break;
case 400: rc = Respond("HTTP/1.1 400 Bad Request"); break;
case 401: rc = Respond("HTTP/1.1 401 Authorization Required"); break;
case 404: rc = Respond("HTTP/1.1 404 Not Found"); break;
case 416: rc = Respond("HTTP/1.1 416 Requested range not satisfiable"); break;
case 503: rc = Respond("HTTP/1.1 503 Service Unavailable"); break;
default: rc = Respond("HTTP/1.1 500 Internal Server Error");
}
if (rc && ContentType)
rc = Respond("Content-Type: %s", true, ContentType);
if (rc)
rc = Respond("Connection: close")
&& Respond("Pragma: no-cache")
&& Respond("Cache-Control: no-cache")
&& Respond("Server: VDR-%s / streamdev-server-%s", true, VDRVERSION, VERSION);
time_t t = time(NULL);
struct tm *gmt = gmtime(&t);
if (rc && gmt) {
char buf[] = "Date: AAA, DD MMM YYYY HH:MM:SS GMT";
if (snprintf(buf, sizeof(buf), "Date: %s, %.2d %s %.4d %.2d:%.2d:%.2d GMT", AAA[gmt->tm_wday], gmt->tm_mday, MMM[gmt->tm_mon], gmt->tm_year + 1900, gmt->tm_hour, gmt->tm_min, gmt->tm_sec) == sizeof(buf) - 1)
rc = Respond(buf);
}
if (rc && strlen(Headers) > 0)
rc = Respond(headers);
tStrStrMap::iterator it = m_Params.begin();
while (rc && it != m_Params.end()) {
static const char DLNA_POSTFIX[] = ".dlna.org";
if (it->first.rfind(DLNA_POSTFIX) + sizeof(DLNA_POSTFIX) - 1 == it->first.length())
rc = Respond("%s: %s", true, it->first.c_str(), it->second.c_str());
++it;
}
return rc && Respond("");
}
bool cConnectionHTTP::ParseRange(int64_t &From, int64_t &To) const
{
const static std::string RANGE("HTTP_RANGE");
From = To = 0L;
tStrStrMap::const_iterator it = Headers().find(RANGE);
if (it != Headers().end()) {
size_t b = it->second.find("bytes=");
if (b != std::string::npos) {
char* e = NULL;
const char* r = it->second.c_str() + b + sizeof("bytes=") - 1;
if (strchr(r, ',') != NULL)
esyslog("streamdev-server cConnectionHTTP::GetRange: Multi-ranges not supported");
From = strtol(r, &e, 10);
if (r != e) {
if (From < 0L) {
To = -1L;
return *e == 0 || *e == ',';
}
else if (*e == '-') {
r = e + 1;
if (*r == 0 || *e == ',') {
To = -1L;
return true;
}
To = strtol(r, &e, 10);
return r != e && To >= From &&
(*e == 0 || *e == ',');
}
}
}
}
return false;
DeferClose();
return Respond("HTTP/1.0 400 Bad Request")
&& Respond("");
}
void cConnectionHTTP::Flushed(void)
{
std::string line;
if (m_Status != hsBody)
return;
if (m_MenuList) {
if (m_MenuList->HasNext()) {
if (!Respond("%s", true, m_MenuList->Next().c_str()))
if (m_ChannelList) {
if (m_ChannelList->HasNext()) {
if (!Respond("%s", true, m_ChannelList->Next().c_str()))
DeferClose();
}
else {
DELETENULL(m_MenuList);
DELETENULL(m_ChannelList);
m_Status = hsFinished;
DeferClose();
}
return;
}
else if (Streamer()) {
else if (m_Channel != NULL) {
Dprintf("streamer start\n");
Streamer()->Start(this);
m_LiveStreamer->Start(this);
m_Status = hsFinished;
}
else {
@@ -446,61 +248,57 @@ void cConnectionHTTP::Flushed(void)
}
}
cMenuList* cConnectionHTTP::MenuListFromString(const std::string& Path, const std::string& Filebase, const std::string& Fileext) const
cChannelList* cConnectionHTTP::ChannelListFromString(const std::string& Path, const std::string& Filebase, const std::string& Fileext) const
{
std::string groupTarget;
cItemIterator *iterator = NULL;
// keys for Headers() hash
const static std::string QUERY_STRING("QUERY_STRING");
const static std::string HOST("HTTP_HOST");
tStrStrMap::const_iterator it_query = Headers().find(QUERY_STRING);
const std::string& query = it_query == Headers().end() ? "" : it_query->second;
std::string groupTarget;
cChannelIterator *iterator = NULL;
const static std::string GROUP("group");
if (Filebase.compare("tree") == 0) {
tStrStrMap::const_iterator it = m_Params.find(GROUP);
iterator = new cListTree(it == m_Params.end() ? NULL : it->second.c_str());
const cChannel* c = NULL;
size_t groupIndex = query.find("group=");
if (groupIndex != std::string::npos)
c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6));
iterator = new cListTree(c);
groupTarget = Filebase + Fileext;
} else if (Filebase.compare("groups") == 0) {
iterator = new cListGroups();
groupTarget = (std::string) "group" + Fileext;
} else if (Filebase.compare("group") == 0) {
tStrStrMap::const_iterator it = m_Params.find(GROUP);
iterator = new cListGroup(it == m_Params.end() ? NULL : it->second.c_str());
const cChannel* c = NULL;
size_t groupIndex = query.find("group=");
if (groupIndex != std::string::npos)
c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6));
iterator = new cListGroup(c);
} else if (Filebase.compare("channels") == 0) {
iterator = new cListChannels();
} else if (Filebase.compare("all") == 0 ||
(Filebase.empty() && Fileext.empty())) {
iterator = new cListAll();
} else if (Filebase.compare("recordings") == 0) {
iterator = new cRecordingsIterator(m_StreamType);
}
if (iterator) {
// assemble base url: http://host/path/
std::string base;
const static std::string HOST("HTTP_HOST");
tStrStrMap::const_iterator it = Headers().find(HOST);
if (it != Headers().end())
base = "http://" + it->second + "/";
else
base = (std::string) "http://" + LocalIp() + ":" +
(const char*) itoa(StreamdevServerSetup.HTTPServerPort) + "/";
base += Path;
if (Filebase.empty() || Fileext.compare(".htm") == 0 || Fileext.compare(".html") == 0) {
std::string self = Filebase + Fileext;
std::string rss = Filebase + ".rss";
tStrStrMap::const_iterator it = Headers().find("QUERY_STRING");
if (it != Headers().end() && !it->second.empty()) {
self += '?' + it->second;
rss += '?' + it->second;
}
return new cHtmlMenuList(iterator, m_StreamType, self.c_str(), rss.c_str(), groupTarget.c_str());
if (!query.empty())
self += '?' + query;
return new cHtmlChannelList(iterator, m_StreamType, self.c_str(), groupTarget.c_str());
} else if (Fileext.compare(".m3u") == 0) {
return new cM3uMenuList(iterator, base.c_str());
} else if (Fileext.compare(".rss") == 0) {
std::string html = Filebase + ".html";
tStrStrMap::const_iterator it = Headers().find("QUERY_STRING");
if (it != Headers().end() && !it->second.empty()) {
html += '?' + it->second;
}
return new cRssMenuList(iterator, base.c_str(), html.c_str());
std::string base;
tStrStrMap::const_iterator it = Headers().find(HOST);
if (it != Headers().end())
base = "http://" + it->second + "/";
else
base = (std::string) "http://" + LocalIp() + ":" +
(const char*) itoa(StreamdevServerSetup.HTTPServerPort) + "/";
base += Path;
return new cM3uChannelList(iterator, base.c_str());
} else {
delete iterator;
}
@@ -508,93 +306,6 @@ cMenuList* cConnectionHTTP::MenuListFromString(const std::string& Path, const st
return NULL;
}
RecPlayer* cConnectionHTTP::RecPlayerFromString(const char *FileBase, const char *FileExt)
{
RecPlayer *recPlayer = NULL;
if (strcasecmp(FileExt, ".rec") != 0)
return NULL;
char *p = NULL;
unsigned long l = strtoul(FileBase, &p, 0);
if (p != FileBase && l > 0L) {
if (*p == ':') {
// get recording by dev:inode
ino_t inode = (ino_t) strtoull(p + 1, &p, 0);
if (*p == 0 && inode > 0) {
struct stat st;
#if APIVERSNUM >= 20300
LOCK_RECORDINGS_READ;
for (const cRecording *rec = Recordings->First(); rec; rec = Recordings->Next(rec)) {
#else
cThreadLock RecordingsLock(&Recordings);
for (cRecording *rec = Recordings.First(); rec; rec = Recordings.Next(rec)) {
#endif
if (stat(rec->FileName(), &st) == 0 && st.st_dev == (dev_t) l && st.st_ino == inode)
recPlayer = new RecPlayer(rec->FileName());
}
}
}
else if (*p == 0) {
// get recording by index
#if APIVERSNUM >= 20300
LOCK_RECORDINGS_READ;
const cRecording *rec = Recordings->Get((int) l - 1);
#else
cThreadLock RecordingsLock(&Recordings);
cRecording *rec = Recordings.Get((int) l - 1);
#endif
if (rec)
recPlayer = new RecPlayer(rec->FileName());
}
if (recPlayer) {
const char *pos = NULL;
tStrStrMap::const_iterator it = m_Params.begin();
while (it != m_Params.end()) {
if (it->first == "pos") {
pos = it->second.c_str();
break;
}
++it;
}
if (pos) {
// With prefix "full_" we try to fool players
// by replying with a content range starting
// at the requested position instead of 0.
// This is a heavy violation of standards.
// Use at your own risk!
if (strncasecmp(pos, "full_", 5) == 0) {
m_ReplayFakeRange = true;
pos += 5;
}
if (strncasecmp(pos, "resume", 6) == 0) {
int id = pos[6] == '.' ? atoi(pos + 7) : 0;
m_ReplayPos = recPlayer->positionFromResume(id);
}
else if (strncasecmp(pos, "mark.", 5) == 0) {
int index = atoi(pos + 5);
m_ReplayPos = recPlayer->positionFromMark(index);
}
else if (strncasecmp(pos, "time.", 5) == 0) {
int seconds = atoi(pos + 5);
m_ReplayPos = recPlayer->positionFromTime(seconds);
}
else if (strncasecmp(pos, "frame.", 6) == 0) {
int frame = atoi(pos + 6);
m_ReplayPos = recPlayer->positionFromFrameNumber(frame);
}
else {
m_ReplayPos = atol(pos);
if (m_ReplayPos > 0L && m_ReplayPos < 100L)
m_ReplayPos = recPlayer->positionFromPercent((int) m_ReplayPos);
}
}
}
}
return recPlayer;
}
bool cConnectionHTTP::ProcessURI(const std::string& PathInfo)
{
std::string filespec, fileext;
@@ -602,24 +313,11 @@ bool cConnectionHTTP::ProcessURI(const std::string& PathInfo)
if (file_pos != std::string::npos) {
size_t ext_pos = PathInfo.rfind('.');
if (ext_pos != std::string::npos) {
// file extension including leading .
fileext = PathInfo.substr(ext_pos);
const char *ext = fileext.c_str();
// ignore dummy file extensions
if (strcasecmp(ext, ".ts") == 0 ||
strcasecmp(ext, ".vdr") == 0 ||
strcasecmp(ext, ".vob") == 0) {
size_t ext_end = ext_pos;
if (ext_pos > 0)
ext_pos = PathInfo.rfind('.', ext_pos - 1);
if (ext_pos == std::string::npos)
ext_pos = ext_end;
fileext = PathInfo.substr(ext_pos, ext_end - ext_pos);
}
}
// file basename with leading / stripped off
filespec = PathInfo.substr(file_pos + 1, ext_pos - file_pos - 1);
if (ext_pos != std::string::npos)
// file extension including leading .
fileext = PathInfo.substr(ext_pos);
}
if (fileext.length() > 5) {
//probably not an extension
@@ -630,12 +328,10 @@ bool cConnectionHTTP::ProcessURI(const std::string& PathInfo)
// Streamtype with leading / stripped off
std::string type = PathInfo.substr(1, PathInfo.find_first_of("/;", 1) - 1);
const char* pType = type.c_str();
if (strcasecmp(pType, "PES") == 0) {
m_StreamType = stPES;
#ifdef STREAMDEV_PS
} else if (strcasecmp(pType, "PS") == 0) {
if (strcasecmp(pType, "PS") == 0) {
m_StreamType = stPS;
#endif
} else if (strcasecmp(pType, "PES") == 0) {
m_StreamType = stPES;
} else if (strcasecmp(pType, "TS") == 0) {
m_StreamType = stTS;
} else if (strcasecmp(pType, "ES") == 0) {
@@ -646,12 +342,9 @@ bool cConnectionHTTP::ProcessURI(const std::string& PathInfo)
Dprintf("before channelfromstring: type(%s) filespec(%s) fileext(%s)\n", type.c_str(), filespec.c_str(), fileext.c_str());
if ((m_MenuList = MenuListFromString(PathInfo.substr(1, file_pos), filespec.c_str(), fileext.c_str())) != NULL) {
if ((m_ChannelList = ChannelListFromString(PathInfo.substr(1, file_pos), filespec.c_str(), fileext.c_str())) != NULL) {
Dprintf("Channel list requested\n");
return true;
} else if ((m_RecPlayer = RecPlayerFromString(filespec.c_str(), fileext.c_str())) != NULL) {
Dprintf("Recording %s found\n", m_RecPlayer->getCurrentRecording()->Name());
return true;
} else if ((m_Channel = ChannelFromString(filespec.c_str(), &m_Apid[0], &m_Dpid[0])) != NULL) {
Dprintf("Channel found. Apid/Dpid is %d/%d\n", m_Apid[0], m_Dpid[0]);
return true;
@@ -659,8 +352,3 @@ bool cConnectionHTTP::ProcessURI(const std::string& PathInfo)
return false;
}
cString cConnectionHTTP::ToText(char Delimiter) const
{
cString str = cServerConnection::ToText(Delimiter);
return Streamer() ? cString::sprintf("%s%c%s", *str, Delimiter, *Streamer()->ToText()) : str;
}

View File

@@ -1,5 +1,5 @@
/*
* $Id: connectionHTTP.h,v 1.7 2010/07/19 13:49:31 schmirl Exp $
* $Id: connectionHTTP.h,v 1.5.2.2 2010/07/19 13:50:14 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_SERVERS_CONNECTIONHTTP_H
@@ -7,13 +7,13 @@
#include "connection.h"
#include "server/livestreamer.h"
#include "server/recstreamer.h"
#include <map>
#include <tools/select.h>
class cChannel;
class cMenuList;
class cStreamdevLiveStreamer;
class cChannelList;
class cConnectionHTTP: public cServerConnection {
private:
@@ -26,32 +26,17 @@ private:
std::string m_Authorization;
eHTTPStatus m_Status;
tStrStrMap m_Params;
eStreamType m_StreamType;
// job: transfer
cStreamdevLiveStreamer *m_LiveStreamer;
const cChannel *m_Channel;
int m_Apid[2];
int m_Dpid[2];
// job: replay
RecPlayer *m_RecPlayer;
int64_t m_ReplayPos;
bool m_ReplayFakeRange;
eStreamType m_StreamType;
// job: listing
cMenuList *m_MenuList;
cMenuList* MenuListFromString(const std::string &PathInfo, const std::string &Filebase, const std::string &Fileext) const;
RecPlayer* RecPlayerFromString(const char* FileBase, const char* FileExt);
cChannelList *m_ChannelList;
cChannelList* ChannelListFromString(const std::string &PathInfo, const std::string &Filebase, const std::string &Fileext) const;
bool ProcessURI(const std::string &PathInfo);
bool HttpResponse(int Code, bool Last, const char* ContentType = NULL, const char* Headers = "", ...);
//__attribute__ ((format (printf, 5, 6)));
/**
* Extract byte range from HTTP Range header. Returns false if no valid
* range is found. The contents of From and To are undefined in this
* case. From may be negative in which case To is undefined.
* TODO: support for multiple ranges.
*/
bool ParseRange(int64_t &From, int64_t &To) const;
protected:
bool ProcessRequest(void);
@@ -59,7 +44,8 @@ public:
cConnectionHTTP(void);
virtual ~cConnectionHTTP();
virtual cString ToText(char Delimiter = ' ') const;
virtual void Attach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Attach(); }
virtual void Detach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Detach(); }
virtual bool CanAuthenticate(void);
@@ -71,7 +57,7 @@ public:
inline bool cConnectionHTTP::Abort(void) const
{
return !IsOpen() || (Streamer() && Streamer()->Abort());
return m_LiveStreamer && m_LiveStreamer->Abort();
}
#endif // VDR_STREAMDEV_SERVERS_CONNECTIONVTP_H

View File

@@ -1,5 +1,5 @@
/*
* $Id: connectionIGMP.c,v 1.3 2010/08/03 10:46:41 schmirl Exp $
* $Id: connectionIGMP.c,v 1.1.2.3 2010/07/19 13:50:14 schmirl Exp $
*/
#include <ctype.h>
@@ -11,67 +11,54 @@
cConnectionIGMP::cConnectionIGMP(const char* Name, int ClientPort, eStreamType StreamType) :
cServerConnection(Name, SOCK_DGRAM),
m_LiveStreamer(NULL),
m_ClientPort(ClientPort),
m_StreamType(StreamType),
m_Channel(NULL)
m_StreamType(StreamType)
{
}
cConnectionIGMP::~cConnectionIGMP()
{
delete m_LiveStreamer;
}
#if APIVERSNUM >= 20300
bool cConnectionIGMP::SetChannel(const cChannel *Channel, in_addr_t Dst)
#else
bool cConnectionIGMP::SetChannel(cChannel *Channel, in_addr_t Dst)
#endif
bool cConnectionIGMP::Start(cChannel *Channel, in_addr_t Dst)
{
if (Channel) {
m_Channel = Channel;
struct in_addr ip;
ip.s_addr = Dst;
if (Connect(inet_ntoa(ip), m_ClientPort))
return true;
if (Channel != NULL) {
cDevice *device = GetDevice(Channel, 0);
if (device != NULL) {
device->SwitchChannel(Channel, false);
struct in_addr ip;
ip.s_addr = Dst;
if (Connect(inet_ntoa(ip), m_ClientPort)) {
m_LiveStreamer = new cStreamdevLiveStreamer(0, this);
if (m_LiveStreamer->SetChannel(Channel, m_StreamType)) {
m_LiveStreamer->SetDevice(device);
if (!SetDSCP())
LOG_ERROR_STR("unable to set DSCP sockopt");
Dprintf("streamer start\n");
m_LiveStreamer->Start(this);
return true;
}
else
esyslog("streamdev-server IGMP: SetDevice failed");
DELETENULL(m_LiveStreamer);
}
else
esyslog("streamdev-server IGMP: Connect failed: %m");
}
else
esyslog("streamdev-server IGMP: Connect failed: %m");
return false;
esyslog("streamdev-server IGMP: GetDevice failed");
}
else
esyslog("streamdev-server IGMP: Channel not found");
return false;
}
void cConnectionIGMP::Welcome()
void cConnectionIGMP::Stop()
{
if (cStreamdevLiveStreamer::ProvidesChannel(m_Channel, StreamdevServerSetup.IGMPPriority)) {
cStreamdevLiveStreamer * liveStreamer = new cStreamdevLiveStreamer(this, m_Channel, StreamdevServerSetup.IGMPPriority, m_StreamType);
if (liveStreamer->GetDevice()) {
SetStreamer(liveStreamer);
if (!SetDSCP())
LOG_ERROR_STR("unable to set DSCP sockopt");
Dprintf("streamer start\n");
liveStreamer->Start(this);
}
else {
SetStreamer(NULL);
delete liveStreamer;
esyslog("streamdev-server IGMP: SetChannel failed");
}
if (m_LiveStreamer) {
m_LiveStreamer->Stop();
DELETENULL(m_LiveStreamer);
}
else
esyslog("streamdev-server IGMP: SwitchDevice failed");
}
bool cConnectionIGMP::Close()
{
if (Streamer())
Streamer()->Stop();
return cServerConnection::Close();
}
cString cConnectionIGMP::ToText(char Delimiter) const
{
cString str = cServerConnection::ToText(Delimiter);
return Streamer() ? cString::sprintf("%s%c%s", *str, Delimiter, *Streamer()->ToText()) : str;
}

View File

@@ -1,5 +1,5 @@
/*
* $Id: connectionIGMP.h,v 1.1 2009/02/13 10:39:22 schmirl Exp $
* $Id: connectionIGMP.h,v 1.1.2.2 2009/02/13 10:39:42 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_SERVERS_CONNECTIONIGMP_H
@@ -17,37 +17,29 @@ class cStreamdevLiveStreamer;
class cConnectionIGMP: public cServerConnection {
private:
cStreamdevLiveStreamer *m_LiveStreamer;
int m_ClientPort;
eStreamType m_StreamType;
#if APIVERSNUM >= 20300
const cChannel *m_Channel;
#else
cChannel *m_Channel;
#endif
public:
cConnectionIGMP(const char* Name, int ClientPort, eStreamType StreamType);
virtual ~cConnectionIGMP();
#if APIVERSNUM >= 20300
bool SetChannel(const cChannel *Channel, in_addr_t Dst);
#else
bool SetChannel(cChannel *Channel, in_addr_t Dst);
#endif
virtual void Welcome(void);
virtual cString ToText(char Delimiter = ' ') const;
bool Start(cChannel *Channel, in_addr_t Dst);
void Stop();
/* Not used here */
virtual bool Command(char *Cmd) { return false; }
virtual bool Close(void);
virtual void Attach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Attach(); }
virtual void Detach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Detach(); }
virtual bool Abort(void) const;
};
inline bool cConnectionIGMP::Abort(void) const
{
return !IsOpen() || !Streamer() || Streamer()->Abort();
return !m_LiveStreamer || m_LiveStreamer->Abort();
}
#endif // VDR_STREAMDEV_SERVERS_CONNECTIONIGMP_H

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,7 @@
#include "server/recplayer.h"
class cTBSocket;
class cStreamdevLiveStreamer;
class cStreamdevFilterStreamer;
class cLSTEHandler;
class cLSTCHandler;
@@ -19,6 +20,7 @@ class cConnectionVTP: public cServerConnection {
private:
cTBSocket *m_LiveSocket;
cStreamdevLiveStreamer *m_LiveStreamer;
cTBSocket *m_FilterSocket;
cStreamdevFilterStreamer *m_FilterStreamer;
cTBSocket *m_RecSocket;
@@ -26,9 +28,7 @@ private:
char *m_LastCommand;
eStreamType m_StreamType;
unsigned int m_ClientVersion;
bool m_FiltersSupport;
bool m_LoopPrevention;
RecPlayer *m_RecPlayer;
// Priority is only known in PROV command
@@ -53,22 +53,18 @@ public:
virtual void Welcome(void);
virtual void Reject(void);
virtual cString ToText(char Delimiter = ' ') const;
virtual bool Abort(void) const;
virtual void Detach(void);
virtual void Attach(void);
virtual bool Command(char *Cmd);
bool CmdCAPS(char *Opts);
bool CmdVERS(char *Opts);
bool CmdPROV(char *Opts);
bool CmdPORT(char *Opts);
bool CmdREAD(char *Opts);
bool CmdTUNE(char *Opts);
bool CmdPLAY(char *Opts);
bool CmdPRIO(char *Opts);
bool CmdSGNL(char *Opts);
bool CmdADDP(char *Opts);
bool CmdDELP(char *Opts);
bool CmdADDF(char *Opts);

View File

@@ -1,53 +1,19 @@
/*
* $Id: livefilter.c,v 1.7 2009/02/13 13:02:40 schmirl Exp $
* $Id: livefilter.c,v 1.5.2.2 2009/02/13 13:02:34 schmirl Exp $
*/
#include <vdr/filter.h>
#include "server/livefilter.h"
#include "server/streamer.h"
#include "common.h"
#ifndef TS_SYNC_BYTE
# define TS_SYNC_BYTE 0x47
#endif
#define FILTERBUFSIZE (1000 * TS_SIZE)
// --- cStreamdevLiveFilter -------------------------------------------------
class cStreamdevLiveFilter: public cFilter {
private:
cStreamdevFilterStreamer *m_Streamer;
bool m_On;
protected:
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
virtual void SetStatus(bool On);
public:
cStreamdevLiveFilter(cStreamdevFilterStreamer *Streamer);
virtual bool IsAttached(void) const { return m_On; };
void Set(u_short Pid, u_char Tid, u_char Mask) {
cFilter::Set(Pid, Tid, Mask);
}
void Del(u_short Pid, u_char Tid, u_char Mask) {
cFilter::Del(Pid, Tid, Mask);
}
};
cStreamdevLiveFilter::cStreamdevLiveFilter(cStreamdevFilterStreamer *Streamer) {
m_On = false;
cStreamdevLiveFilter::cStreamdevLiveFilter(cStreamdevStreamer *Streamer) {
m_Streamer = Streamer;
}
void cStreamdevLiveFilter::SetStatus(bool On)
{
m_On = On;
cFilter::SetStatus(On);
}
void cStreamdevLiveFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
{
uchar buffer[TS_SIZE];
@@ -66,86 +32,8 @@ void cStreamdevLiveFilter::Process(u_short Pid, u_char Tid, const u_char *Data,
length -= chunk;
pos += chunk;
m_Streamer->Receive(buffer);
int p = m_Streamer->Put(buffer, TS_SIZE);
if (p != TS_SIZE)
m_Streamer->ReportOverflow(TS_SIZE - p);
}
}
// --- cStreamdevFilterStreamer -------------------------------------------------
cStreamdevFilterStreamer::cStreamdevFilterStreamer():
cStreamdevStreamer("streamdev-filterstreaming"),
m_Device(NULL),
m_Filter(NULL)/*,
m_Channel(NULL)*/
{
m_ReceiveBuffer = new cStreamdevBuffer(FILTERBUFSIZE, TS_SIZE);
m_ReceiveBuffer->SetTimeouts(0, 500);
}
cStreamdevFilterStreamer::~cStreamdevFilterStreamer()
{
Dprintf("Desctructing Filter streamer\n");
Detach();
m_Device = NULL;
DELETENULL(m_Filter);
Stop();
delete m_ReceiveBuffer;
}
void cStreamdevFilterStreamer::Receive(uchar *Data)
{
int p = m_ReceiveBuffer->PutTS(Data, TS_SIZE);
if (p != TS_SIZE)
m_ReceiveBuffer->ReportOverflow(TS_SIZE - p);
}
void cStreamdevFilterStreamer::Attach(void)
{
Dprintf("cStreamdevFilterStreamer::Attach()\n");
LOCK_THREAD;
if(m_Device && m_Filter)
m_Device->AttachFilter(m_Filter);
}
void cStreamdevFilterStreamer::Detach(void)
{
Dprintf("cStreamdevFilterStreamer::Detach()\n");
LOCK_THREAD;
if(m_Device && m_Filter)
m_Device->Detach(m_Filter);
}
void cStreamdevFilterStreamer::SetDevice(cDevice *Device)
{
Dprintf("cStreamdevFilterStreamer::SetDevice()\n");
LOCK_THREAD;
Detach();
m_Device = Device;
Attach();
}
bool cStreamdevFilterStreamer::IsReceiving(void) const
{
return m_Filter && m_Filter->IsAttached();
}
bool cStreamdevFilterStreamer::SetFilter(u_short Pid, u_char Tid, u_char Mask, bool On)
{
Dprintf("cStreamdevFilterStreamer::SetFilter(%u,0x%x,0x%x,%s)\n", Pid, Tid, Mask, On?"On":"Off");
if(!m_Device)
return false;
if (On) {
if (m_Filter == NULL) {
m_Filter = new cStreamdevLiveFilter(this);
Dprintf("attaching filter to device\n");
Attach();
}
m_Filter->Set(Pid, Tid, Mask);
} else if (m_Filter != NULL)
m_Filter->Del(Pid, Tid, Mask);
return true;
}

View File

@@ -5,33 +5,28 @@
#ifndef VDR_STREAMEV_LIVEFILTER_H
#define VDR_STREAMEV_LIVEFILTER_H
#include "server/streamer.h"
#include <vdr/config.h>
class cDevice;
class cStreamdevLiveFilter;
#include <vdr/filter.h>
class cStreamdevFilterStreamer: public cStreamdevStreamer {
class cStreamdevStreamer;
class cStreamdevLiveFilter: public cFilter {
private:
cDevice *m_Device;
cStreamdevLiveFilter *m_Filter;
cStreamdevBuffer *m_ReceiveBuffer;
cStreamdevStreamer *m_Streamer;
protected:
virtual uchar* GetFromReceiver(int &Count) { return m_ReceiveBuffer->Get(Count); }
virtual void DelFromReceiver(int Count) { m_ReceiveBuffer->Del(Count); }
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
public:
cStreamdevFilterStreamer();
virtual ~cStreamdevFilterStreamer();
cStreamdevLiveFilter(cStreamdevStreamer *Streamer);
void SetDevice(cDevice *Device);
bool SetFilter(u_short Pid, u_char Tid, u_char Mask, bool On);
virtual bool IsReceiving(void) const;
void Receive(uchar *Data);
virtual void Attach(void);
virtual void Detach(void);
void Set(u_short Pid, u_char Tid, u_char Mask) {
cFilter::Set(Pid, Tid, Mask);
}
void Del(u_short Pid, u_char Tid, u_char Mask) {
cFilter::Del(Pid, Tid, Mask);
}
};
#endif // VDR_STREAMEV_LIVEFILTER_H

View File

@@ -3,52 +3,50 @@
#include <libsi/section.h>
#include <libsi/descriptor.h>
#include <vdr/ringbuffer.h>
#include "server/livestreamer.h"
#include "server/livefilter.h"
#include "remux/ts2ps.h"
#include "remux/ts2pes.h"
#include "remux/ts2es.h"
#include "remux/extern.h"
#include <vdr/transfer.h>
#include "server/livestreamer.h"
#include "server/setup.h"
#include "common.h"
using namespace Streamdev;
// device occupied timeout to prevent VDR main loop to immediately switch back
// when streamdev switched the live TV channel.
// Note that there is still a gap between the GetDevice() and SetOccupied()
// calls where the VDR main loop could strike
#define STREAMDEVTUNETIMEOUT 5
// --- cStreamdevLiveReceiver -------------------------------------------------
class cStreamdevLiveReceiver: public cReceiver {
friend class cStreamdevStreamer;
private:
cStreamdevLiveStreamer *m_Streamer;
cStreamdevStreamer *m_Streamer;
protected:
#if APIVERSNUM >= 20300
virtual void Receive(const uchar *Data, int Length);
#else
virtual void Activate(bool On);
virtual void Receive(uchar *Data, int Length);
#endif
public:
cStreamdevLiveReceiver(cStreamdevLiveStreamer *Streamer, const cChannel *Channel, int Priority, const int *Pids);
#if VDRVERSNUM < 10500
cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, int Ca, int Priority, const int *Pids);
#else
cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, tChannelID ChannelID, int Priority, const int *Pids);
#endif
virtual ~cStreamdevLiveReceiver();
};
cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevLiveStreamer *Streamer, const cChannel *Channel, int Priority, const int *Pids):
cReceiver(Channel, Priority),
#if VDRVERSNUM < 10500
cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, int Ca,
int Priority, const int *Pids):
cReceiver(Ca, Priority, 0, Pids),
#else
cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, tChannelID ChannelID,
int Priority, const int *Pids):
cReceiver(ChannelID, Priority, 0, Pids),
#endif
m_Streamer(Streamer)
{
// clears all PIDs but channel remains set
SetPids(NULL);
AddPids(Pids);
}
cStreamdevLiveReceiver::~cStreamdevLiveReceiver()
@@ -57,12 +55,16 @@ cStreamdevLiveReceiver::~cStreamdevLiveReceiver()
Detach();
}
#if APIVERSNUM >= 20300
void cStreamdevLiveReceiver::Receive(const uchar *Data, int Length) {
#else
void cStreamdevLiveReceiver::Receive(uchar *Data, int Length) {
#endif
m_Streamer->Receive(Data, Length);
int p = m_Streamer->Receive(Data, Length);
if (p != Length)
m_Streamer->ReportOverflow(Length - p);
}
inline void cStreamdevLiveReceiver::Activate(bool On)
{
Dprintf("LiveReceiver->Activate(%d)\n", On);
m_Streamer->Activate(On);
}
// --- cStreamdevPatFilter ----------------------------------------------------
@@ -179,7 +181,6 @@ int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream)
for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
switch (d->getDescriptorTag()) {
case SI::AC3DescriptorTag:
case SI::EnhancedAC3DescriptorTag:
Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n",
stream.getPid(), psStreamTypes[stream.getStreamType()], "AC3");
delete d;
@@ -258,12 +259,7 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
SI::PAT::Association assoc;
for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) {
if (!assoc.isNITPid()) {
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
const cChannel *Channel = Channels->GetByServiceID(Source(), Transponder(), assoc.getServiceId());
#else
const cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId());
#endif
if (Channel && (Channel == m_Channel)) {
int prevPmtPid = pmtPid;
if (0 != (pmtPid = assoc.getPid())) {
@@ -332,9 +328,9 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
pids[npids++] = pmtPid;
#if 0
pids[npids++] = 0x10; // pid 0x10, tid 0x40: NIT
#endif
pids[npids++] = 0x11; // pid 0x11, tid 0x42: SDT
pids[npids++] = 0x14; // pid 0x14, tid 0x70: TDT
#endif
pids[npids++] = 0x12; // pid 0x12, tid 0x4E...0x6F: EIT
for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); )
if (0 != (pids[npids] = GetPid(stream)) && npids < MAXRECEIVEPIDS)
@@ -347,36 +343,29 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
// --- cStreamdevLiveStreamer -------------------------------------------------
cStreamdevLiveStreamer::cStreamdevLiveStreamer(const cServerConnection *Connection, const cChannel *Channel, int Priority, eStreamType StreamType, const int* Apid, const int *Dpid) :
cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority, const cServerConnection *Connection):
cStreamdevStreamer("streamdev-livestreaming", Connection),
m_Priority(Priority),
m_NumPids(0),
m_Channel(Channel),
m_StreamType(stTSPIDS),
m_Channel(NULL),
m_Device(NULL),
m_Receiver(NULL),
m_PatFilter(NULL),
m_SwitchLive(false)
m_Remux(NULL)
{
m_ReceiveBuffer = new cStreamdevBuffer(LIVEBUFSIZE, TS_SIZE *2, true, "streamdev-livestreamer"),
m_ReceiveBuffer->SetTimeouts(0, 100);
if (Priority == IDLEPRIORITY) {
SetChannel(StreamType, Apid, Dpid);
}
else {
m_Device = SwitchDevice(Channel, Priority);
if (m_Device)
SetChannel(StreamType, Apid, Dpid);
memcpy(m_Caids,Channel->Caids(),sizeof(m_Caids));
}
}
cStreamdevLiveStreamer::~cStreamdevLiveStreamer()
{
Dprintf("Desctructing Live streamer\n");
Stop();
DELETENULL(m_PatFilter);
if(m_PatFilter) {
Detach();
DELETENULL(m_PatFilter);
}
DELETENULL(m_Receiver);
delete m_ReceiveBuffer;
delete m_Remux;
}
bool cStreamdevLiveStreamer::HasPid(int Pid)
@@ -456,45 +445,20 @@ bool cStreamdevLiveStreamer::SetPids(int Pid, const int *Pids1, const int *Pids2
void cStreamdevLiveStreamer::SetPriority(int Priority)
{
m_Priority = Priority;
#if VDRVERSNUM >= 20104
cThreadLock ThreadLock(m_Device);
if (m_Receiver)
m_Receiver->SetPriority(Priority);
else
#endif
StartReceiver();
StartReceiver();
}
void cStreamdevLiveStreamer::GetSignal(int *DevNum, int *Strength, int *Quality) const
void cStreamdevLiveStreamer::StartReceiver(void)
{
if (m_Device) {
*DevNum = m_Device->DeviceNumber() + 1;
*Strength = m_Device->SignalStrength();
*Quality = m_Device->SignalQuality();
}
}
cString cStreamdevLiveStreamer::ToText() const
{
if (m_Device && m_Channel) {
return cString::sprintf("DVB%-2d %3d %s", m_Device->DeviceNumber() + 1, m_Channel->Number(), m_Channel->Name());
}
return cString("");
}
bool cStreamdevLiveStreamer::IsReceiving(void) const
{
cThreadLock ThreadLock(m_Device);
return m_Receiver && m_Receiver->IsAttached();
}
void cStreamdevLiveStreamer::StartReceiver(bool Force)
{
if (m_NumPids > 0 || Force) {
if (m_NumPids > 0) {
Dprintf("Creating Receiver to respect changed pids\n");
cReceiver *current = m_Receiver;
#if VDRVERSNUM < 10500
m_Receiver = new cStreamdevLiveReceiver(this, m_Channel->Ca(), m_Priority, m_Pids);
#else
m_Receiver = new cStreamdevLiveReceiver(this, m_Channel->GetChannelID(), m_Priority, m_Pids);
#endif
cThreadLock ThreadLock(m_Device);
m_Receiver = new cStreamdevLiveReceiver(this, m_Channel, m_Priority, m_Pids);
if (IsRunning())
Attach();
delete current;
@@ -503,15 +467,17 @@ void cStreamdevLiveStreamer::StartReceiver(bool Force)
DELETENULL(m_Receiver);
}
bool cStreamdevLiveStreamer::SetChannel(eStreamType StreamType, const int* Apid, const int *Dpid)
bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType StreamType, const int* Apid, const int *Dpid)
{
Dprintf("Initializing Remuxer for full channel transfer\n");
//printf("ca pid: %d\n", Channel->Ca());
m_Channel = Channel;
m_StreamType = StreamType;
const int *Apids = Apid ? Apid : m_Channel->Apids();
const int *Dpids = Dpid ? Dpid : m_Channel->Dpids();
switch (StreamType) {
switch (m_StreamType) {
case stES:
{
int pid = ISRADIO(m_Channel) ? m_Channel->Apid(0) : m_Channel->Vpid();
@@ -519,22 +485,20 @@ bool cStreamdevLiveStreamer::SetChannel(eStreamType StreamType, const int* Apid,
pid = Apid[0];
else if (Dpid && Dpid[0])
pid = Dpid[0];
SetRemux(new cTS2ESRemux(pid));
m_Remux = new cTS2ESRemux(pid);
return SetPids(pid);
}
case stPES:
SetRemux(new cTS2PESRemux(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids()));
m_Remux = new cTS2PESRemux(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
#ifdef STREAMDEV_PS
case stPS:
SetRemux(new cTS2PSRemux(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids()));
m_Remux = new cTS2PSRemux(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
#endif
case stEXT:
SetRemux(new cExternRemux(Connection(), m_Channel, Apids, Dpids));
m_Remux = new cExternRemux(Connection(), m_Channel, Apids, Dpids);
// fall through
case stTS:
// This should never happen, but ...
@@ -552,40 +516,12 @@ bool cStreamdevLiveStreamer::SetChannel(eStreamType StreamType, const int* Apid,
case stTSPIDS:
Dprintf("pid streaming mode\n");
// No PIDs requested yet. Start receiver anyway to occupy device
StartReceiver(true);
return true;
default:
return false;
}
}
#if APIVERSNUM >= 20300
void cStreamdevLiveStreamer::Receive(const uchar *Data, int Length)
#else
void cStreamdevLiveStreamer::Receive(uchar *Data, int Length)
#endif
{
int p = m_ReceiveBuffer->PutTS(Data, Length);
if (p != Length)
m_ReceiveBuffer->ReportOverflow(Length - p);
}
void cStreamdevLiveStreamer::Action(void)
{
if (StreamdevServerSetup.LiveBufferMs) {
// wait for first data block
int count = 0;
while (Running()) {
if (m_ReceiveBuffer->Get(count) != NULL) {
cCondWait::SleepMs(StreamdevServerSetup.LiveBufferMs);
break;
}
}
}
cStreamdevStreamer::Action();
}
int cStreamdevLiveStreamer::Put(const uchar *Data, int Count)
{
// insert si data
@@ -593,12 +529,34 @@ int cStreamdevLiveStreamer::Put(const uchar *Data, int Count)
int siCount;
uchar *siData = m_PatFilter->Get(siCount);
if (siData) {
siCount = cStreamdevStreamer::Put(siData, siCount);
if (m_Remux)
siCount = m_Remux->Put(siData, siCount);
else
siCount = cStreamdevStreamer::Put(siData, siCount);
if (siCount)
m_PatFilter->Del(siCount);
}
}
return cStreamdevStreamer::Put(Data, Count);
if (m_Remux)
return m_Remux->Put(Data, Count);
else
return cStreamdevStreamer::Put(Data, Count);
}
uchar *cStreamdevLiveStreamer::Get(int &Count)
{
if (m_Remux)
return m_Remux->Get(Count);
else
return cStreamdevStreamer::Get(Count);
}
void cStreamdevLiveStreamer::Del(int Count)
{
if (m_Remux)
m_Remux->Del(Count);
else
cStreamdevStreamer::Del(Count);
}
void cStreamdevLiveStreamer::Attach(void)
@@ -606,8 +564,7 @@ void cStreamdevLiveStreamer::Attach(void)
Dprintf("cStreamdevLiveStreamer::Attach()\n");
if (m_Device) {
if (m_Receiver) {
if (m_Receiver->IsAttached())
m_Device->Detach(m_Receiver);
m_Device->Detach(m_Receiver);
m_Device->AttachReceiver(m_Receiver);
}
if (m_PatFilter) {
@@ -628,101 +585,6 @@ void cStreamdevLiveStreamer::Detach(void)
}
}
bool cStreamdevLiveStreamer::UsedByLiveTV(cDevice *device)
{
return device == cTransferControl::ReceiverDevice() ||
(device->IsPrimaryDevice() && device->HasDecoder() && !device->Replaying());
}
cDevice *cStreamdevLiveStreamer::SwitchDevice(const cChannel *Channel, int Priority)
{
cDevice *device = cDevice::GetDevice(Channel, Priority, false);
if (!device) {
dsyslog("streamdev: GetDevice failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d)", Channel->Number(), Channel->Name(), Priority, cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex());
}
else if (!device->IsTunedToTransponder(Channel) && UsedByLiveTV(device)) {
// make sure VDR main loop doesn't switch back
device->SetOccupied(STREAMDEVTUNETIMEOUT);
if (device->SwitchChannel(Channel, false)) {
// switched away live TV
m_SwitchLive = true;
}
else {
dsyslog("streamdev: SwitchChannel (live) failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d, device=%d)", Channel->Number(), Channel->Name(), Priority, cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex(), device->CardIndex());
device->SetOccupied(0);
device = NULL;
}
}
else if (!device->SwitchChannel(Channel, false)) {
dsyslog("streamdev: SwitchChannel failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d, device=%d)", Channel->Number(), Channel->Name(), Priority, cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex(), device->CardIndex());
device = NULL;
}
return device;
}
bool cStreamdevLiveStreamer::ProvidesChannel(const cChannel *Channel, int Priority)
{
cDevice *device = cDevice::GetDevice(Channel, Priority, false, true);
if (!device)
dsyslog("streamdev: No device provides channel %d (%s) at priority %d", Channel->Number(), Channel->Name(), Priority);
return device;
}
void cStreamdevLiveStreamer::ChannelChange(const cChannel *Channel)
{
if (Running() && m_Device && m_Channel == Channel) {
// Check whether the Caids actually changed
// If not, no need to re-tune, probably just an Audio PID update
if (!memcmp(m_Caids, Channel->Caids(), sizeof(m_Caids))) {
dsyslog("streamdev: channel %d (%s) changed, but caids remained the same, not re-tuning", Channel->Number(), Channel->Name());
}
else {
Detach();
if (m_Device->SwitchChannel(m_Channel, false)) {
Attach();
dsyslog("streamdev: channel %d (%s) changed, re-tuned", Channel->Number(), Channel->Name());
memcpy(m_Caids, Channel->Caids(), sizeof(m_Caids));
}
else
isyslog("streamdev: failed to re-tune after channel %d (%s) changed", Channel->Number(), Channel->Name());
}
}
}
void cStreamdevLiveStreamer::MainThreadHook()
{
if (!m_SwitchLive && Running() && m_Device && !m_Device->IsTunedToTransponder(m_Channel) && !IsReceiving()) {
cDevice *dev = SwitchDevice(m_Channel, m_Priority);
if (dev) {
dsyslog("streamdev: Lost channel %d (%s) on device %d. Continuing on device %d.", m_Channel->Number(), m_Channel->Name(), m_Device->CardIndex(), dev->CardIndex());
m_Device = dev;
StartReceiver();
}
else {
isyslog("streamdev: Lost channel %d (%s) on device %d.", m_Channel->Number(), m_Channel->Name(), m_Device->CardIndex());
Stop();
}
}
if (m_SwitchLive) {
// switched away live TV. Try previous channel on other device first
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
if (!Channels->SwitchTo(cDevice::CurrentChannel())) {
// switch to streamdev channel otherwise
Channels->SwitchTo(m_Channel->Number());
#else
if (!Channels.SwitchTo(cDevice::CurrentChannel())) {
// switch to streamdev channel otherwise
Channels.SwitchTo(m_Channel->Number());
#endif
Skins.Message(mtInfo, tr("Streaming active"));
}
if (m_Device)
m_Device->SetOccupied(0);
m_SwitchLive = false;
}
}
std::string cStreamdevLiveStreamer::Report(void)
{
std::string result;
@@ -739,3 +601,107 @@ std::string cStreamdevLiveStreamer::Report(void)
result += "\n";
return result;
}
// --- cStreamdevFilterStreamer -------------------------------------------------
cStreamdevFilterStreamer::cStreamdevFilterStreamer():
cStreamdevStreamer("streamdev-filterstreaming"),
m_Device(NULL),
m_Filter(NULL)/*,
m_Channel(NULL)*/
{
}
cStreamdevFilterStreamer::~cStreamdevFilterStreamer()
{
Dprintf("Desctructing Filter streamer\n");
Detach();
m_Device = NULL;
DELETENULL(m_Filter);
Stop();
}
void cStreamdevFilterStreamer::Attach(void)
{
Dprintf("cStreamdevFilterStreamer::Attach()\n");
LOCK_THREAD;
if(m_Device && m_Filter)
m_Device->AttachFilter(m_Filter);
}
void cStreamdevFilterStreamer::Detach(void)
{
Dprintf("cStreamdevFilterStreamer::Detach()\n");
LOCK_THREAD;
if(m_Device && m_Filter)
m_Device->Detach(m_Filter);
}
#if 0
void cStreamdevFilterStreamer::SetChannel(const cChannel *Channel)
{
LOCK_THREAD;
Dprintf("cStreamdevFilterStreamer::SetChannel(%s : %s)", Channel?Channel->Name():"<null>",
Channel ? *Channel->GetChannelID().ToString() : "");
m_Channel = Channel;
}
#endif
void cStreamdevFilterStreamer::SetDevice(cDevice *Device)
{
Dprintf("cStreamdevFilterStreamer::SetDevice()\n");
LOCK_THREAD;
if(Device != m_Device) {
Detach();
m_Device = Device;
//m_Channel = NULL;
Attach();
}
}
bool cStreamdevFilterStreamer::SetFilter(u_short Pid, u_char Tid, u_char Mask, bool On)
{
Dprintf("cStreamdevFilterStreamer::SetFilter(%u,0x%x,0x%x,%s)\n", Pid, Tid, Mask, On?"On":"Off");
if(!m_Device)
return false;
if (On) {
if (m_Filter == NULL) {
m_Filter = new cStreamdevLiveFilter(this);
Dprintf("attaching filter to device\n");
Attach();
}
m_Filter->Set(Pid, Tid, Mask);
} else if (m_Filter != NULL)
m_Filter->Del(Pid, Tid, Mask);
return true;
}
#if 0
void cStreamdevFilterStreamer::ChannelSwitch(const cDevice *Device, int ChannelNumber) {
LOCK_THREAD;
if(Device == m_Device) {
if(ChannelNumber > 0) {
cChannel *ch = Channels.GetByNumber(ChannelNumber);
if(ch != NULL) {
if(m_Filter != NULL &&
m_Channel != NULL &&
(! TRANSPONDER(ch, m_Channel))) {
isyslog("***** LiveFilterStreamer: transponder changed ! %s",
*ch->GetChannelID().ToString());
uchar buffer[TS_SIZE] = {TS_SYNC_BYTE, 0xff, 0xff, 0xff, 0x7f, 0};
strcpy((char*)(buffer + 5), ch->GetChannelID().ToString());
int p = Put(buffer, TS_SIZE);
if (p != TS_SIZE)
ReportOverflow(TS_SIZE - p);
}
m_Channel = ch;
}
}
}
}
#endif

View File

@@ -2,88 +2,81 @@
#define VDR_STREAMDEV_LIVESTREAMER_H
#include <vdr/config.h>
#include <vdr/status.h>
#include <vdr/receiver.h>
#include "server/streamer.h"
#include "server/streamdev-server.h"
#include "common.h"
#define LIVEBUFSIZE (20000 * TS_SIZE)
namespace Streamdev {
class cTSRemux;
}
class cStreamdevPatFilter;
class cStreamdevLiveReceiver;
// --- cStreamdevLiveStreamer -------------------------------------------------
class cStreamdevLiveStreamer: public cStreamdevStreamer, public cMainThreadHookSubscriber
#if VDRVERSNUM >= 20104
, public cStatus
#endif
{
class cStreamdevLiveStreamer: public cStreamdevStreamer {
private:
int m_Priority;
int m_Pids[MAXRECEIVEPIDS + 1];
int m_NumPids;
int m_Caids[MAXCAIDS + 1];
eStreamType m_StreamType;
const cChannel *m_Channel;
cDevice *m_Device;
cStreamdevLiveReceiver *m_Receiver;
cStreamdevBuffer *m_ReceiveBuffer;
cStreamdevPatFilter *m_PatFilter;
bool m_SwitchLive;
Streamdev::cTSRemux *m_Remux;
void StartReceiver(bool Force = false);
void StartReceiver(void);
bool HasPid(int Pid);
/* Test if device is in use as the transfer mode receiver device
or a FF card, displaying live TV from internal tuner */
static bool UsedByLiveTV(cDevice *device);
/* Find a suitable device and tune it to the requested channel. */
cDevice *SwitchDevice(const cChannel *Channel, int Priority);
bool SetChannel(eStreamType StreamType, const int* Apid = NULL, const int* Dpid = NULL);
protected:
virtual uchar* GetFromReceiver(int &Count) { return m_ReceiveBuffer->Get(Count); }
virtual void DelFromReceiver(int Count) { m_ReceiveBuffer->Del(Count); }
virtual int Put(const uchar *Data, int Count);
virtual void Action(void);
virtual void ChannelChange(const cChannel *Channel);
public:
cStreamdevLiveStreamer(const cServerConnection *Connection, const cChannel *Channel, int Priority, eStreamType StreamType, const int* Apid = NULL, const int* Dpid = NULL);
cStreamdevLiveStreamer(int Priority, const cServerConnection *Connection);
virtual ~cStreamdevLiveStreamer();
void SetDevice(cDevice *Device) { m_Device = Device; }
bool SetPid(int Pid, bool On);
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);
void SetPriority(int Priority);
void GetSignal(int *DevNum, int *Strength, int *Quality) const;
virtual cString ToText() const;
#if APIVERSNUM >= 20300
void Receive(const uchar *Data, int Length);
#else
void Receive(uchar *Data, int Length);
#endif
virtual bool IsReceiving(void) const;
virtual int Put(const uchar *Data, int Count);
virtual uchar *Get(int &Count);
virtual void Del(int Count);
virtual void Attach(void);
virtual void Detach(void);
cDevice *GetDevice() const { return m_Device; }
/* Test if a call to GetDevice would return a usable device. */
static bool ProvidesChannel(const cChannel *Channel, int Priority);
/* Do things which must be done in VDR's main loop */
void MainThreadHook();
// Statistical purposes:
virtual std::string Report(void);
};
// --- cStreamdevFilterStreamer -------------------------------------------------
//#include <vdr/status.h>
class cStreamdevLiveFilter;
class cStreamdevFilterStreamer: public cStreamdevStreamer /*, public cStatus*/ {
private:
cDevice *m_Device;
cStreamdevLiveFilter *m_Filter;
//const cChannel *m_Channel;
public:
cStreamdevFilterStreamer();
virtual ~cStreamdevFilterStreamer();
void SetDevice(cDevice *Device);
//void SetChannel(const cChannel *Channel);
bool SetFilter(u_short Pid, u_char Tid, u_char Mask, bool On);
virtual void Attach(void);
virtual void Detach(void);
// cStatus message handlers
//virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
};
#endif // VDR_STREAMDEV_LIVESTREAMER_H

View File

@@ -1,76 +0,0 @@
/*
* $Id: menu.c,v 1.10 2010/07/19 13:49:31 schmirl Exp $
*/
#include <vdr/menuitems.h>
#include <vdr/thread.h>
#include <vdr/player.h>
#include "server/menu.h"
#include "server/setup.h"
#include "server/server.h"
#include "server/suspend.h"
cStreamdevServerMenu::cStreamdevServerMenu(): cOsdMenu(tr("Streamdev Connections"), 4, 20) {
cThreadLock lock;
#if APIVERSNUM >= 20300
cList<cServerConnection>& clients = cStreamdevServer::Clients(lock);
#else
const cList<cServerConnection>& clients = cStreamdevServer::Clients(lock);
#endif
for (cServerConnection *s = clients.First(); s; s = clients.Next(s))
Add(new cOsdItem(s->ToText('\t')));
SetHelpKeys();
Display();
}
cStreamdevServerMenu::~cStreamdevServerMenu() {
}
void cStreamdevServerMenu::SetHelpKeys() {
SetHelp(Count() ? tr("Disconnect") : NULL, NULL, NULL, tr("Suspend"));
}
eOSState cStreamdevServerMenu::Disconnect() {
cOsdItem *item = Get(Current());
if (item) {
cThreadLock lock;
#if APIVERSNUM >= 20300
cList<cServerConnection>& clients = cStreamdevServer::Clients(lock);
#else
const cList<cServerConnection>& clients = cStreamdevServer::Clients(lock);
#endif
const char *text = item->Text();
for (cServerConnection *s = clients.First(); s; s = clients.Next(s)) {
if (!strcmp(text, s->ToText('\t'))) {
s->Close();
Del(Current());
SetHelpKeys();
Display();
break;
}
}
}
return osContinue;
}
eOSState cStreamdevServerMenu::Suspend() {
if (!cSuspendCtl::IsActive()) {
cControl::Launch(new cSuspendCtl);
return osBack;
}
return osContinue;
}
eOSState cStreamdevServerMenu::ProcessKey(eKeys Key) {
eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) {
switch (Key) {
case kRed: return Disconnect();
case kBlue: return Suspend();
case kOk: return osBack;
default: break;
}
}
return state;
}

View File

@@ -1,24 +0,0 @@
/*
* $Id: menu.h,v 1.4 2010/07/19 13:49:31 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_MENU_H
#define VDR_STREAMDEV_MENU_H
#include <vdr/osdbase.h>
#include "connection.h"
class cStreamdevServerMenu: public cOsdMenu {
private:
void SetHelpKeys();
eOSState Disconnect();
eOSState Suspend();
protected:
virtual eOSState ProcessKey(eKeys Key);
public:
cStreamdevServerMenu();
virtual ~cStreamdevServerMenu();
};
#endif // VDR_STREAMDEV_MENU_H

View File

@@ -1,244 +1,58 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <vdr/channels.h>
#include "server/menuHTTP.h"
//**************************** cRecordingIterator **************
#if APIVERSNUM >= 20300
cRecordingsIterator::cRecordingsIterator(eStreamType StreamType)
#else
cRecordingsIterator::cRecordingsIterator(eStreamType StreamType): RecordingsLock(&Recordings)
#endif
{
streamType = StreamType;
#if APIVERSNUM >= 20300
LOCK_RECORDINGS_READ;
first = NextSuitable(Recordings->First());
#else
first = NextSuitable(Recordings.First());
#endif
current = NULL;
}
const cRecording* cRecordingsIterator::NextSuitable(const cRecording *Recording)
{
while (Recording)
{
bool isPes = Recording->IsPesRecording();
if (!isPes || (isPes && streamType == stPES))
break;
#if APIVERSNUM >= 20300
LOCK_RECORDINGS_READ;
Recording = Recordings->Next(Recording);
#else
Recording = Recordings.Next(Recording);
#endif
}
return Recording;
}
bool cRecordingsIterator::Next()
{
#if APIVERSNUM >= 20300
LOCK_RECORDINGS_READ;
#endif
if (first)
{
current = first;
first = NULL;
}
else
#if APIVERSNUM >= 20300
current = NextSuitable(Recordings->Next(current));
#else
current = NextSuitable(Recordings.Next(current));
#endif
return current;
}
const cString cRecordingsIterator::ItemRessource() const
{
struct stat st;
if (stat(current->FileName(), &st) == 0)
return cString::sprintf("%lu:%llu.rec", (unsigned long) st.st_dev, (unsigned long long) st.st_ino);
return "";
}
//**************************** cChannelIterator **************
cChannelIterator::cChannelIterator(const cChannel *First)
{
first = First;
current = NULL;
}
cChannelIterator::cChannelIterator(const cChannel *First): channel(First)
{}
bool cChannelIterator::Next()
const cChannel* cChannelIterator::Next()
{
if (first)
{
current = first;
first = NULL;
}
else
current = NextChannel(current);
const cChannel *current = channel;
channel = NextChannel(channel);
return current;
}
const cString cChannelIterator::ItemId() const
{
if (current)
{
if (current->GroupSep())
{
int index = 0;
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
for (int curr = Channels->GetNextGroup(-1); curr >= 0; curr = Channels->GetNextGroup(curr))
{
if (Channels->Get(curr) == current)
#else
for (int curr = Channels.GetNextGroup(-1); curr >= 0; curr = Channels.GetNextGroup(curr))
{
if (Channels.Get(curr) == current)
#endif
return itoa(index);
index++;
}
}
else
{
return itoa(current->Number());
}
}
return cString("-1");
}
const cChannel* cChannelIterator::GetGroup(const char* GroupId)
{
int group = -1;
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
#endif
if (GroupId)
{
int Index = atoi(GroupId);
#if APIVERSNUM >= 20300
group = Channels->GetNextGroup(-1);
while (Index-- && group >= 0)
group = Channels->GetNextGroup(group);
}
return group >= 0 ? Channels->Get(group) : NULL;
#else
group = Channels.GetNextGroup(-1);
while (Index-- && group >= 0)
group = Channels.GetNextGroup(group);
}
return group >= 0 ? Channels.Get(group) : NULL;
#endif
}
const cChannel* cChannelIterator::FirstChannel()
{
const cChannel *Channel;
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
Channel = Channels->First();
#else
Channel = Channels.First();
#endif
return Channel;
}
const cChannel* cChannelIterator::NextNormal()
{
const cChannel *Channel;
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
Channel = Channels->Get(Channels->GetNextNormal(-1));
#else
Channel = Channels.Get(Channels.GetNextNormal(-1));
#endif
return Channel;
}
const cChannel* cChannelIterator::NextGroup()
{
const cChannel *Channel;
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
Channel = Channels->Get(Channels->GetNextGroup(-1));
#else
Channel = Channels.Get(Channels.GetNextGroup(-1));
#endif
return Channel;
}
//**************************** cListAll **************
cListAll::cListAll(): cChannelIterator(FirstChannel())
cListAll::cListAll(): cChannelIterator(Channels.First())
{}
const cChannel* cListAll::NextChannel(const cChannel *Channel)
{
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
if (Channel)
Channel = SkipFakeGroups(Channels->Next(Channel));
#else
if (Channel)
Channel = SkipFakeGroups(Channels.Next(Channel));
#endif
return Channel;
}
//**************************** cListChannels **************
cListChannels::cListChannels(): cChannelIterator(NextNormal())
cListChannels::cListChannels(): cChannelIterator(Channels.Get(Channels.GetNextNormal(-1)))
{}
const cChannel* cListChannels::NextChannel(const cChannel *Channel)
{
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
if (Channel)
Channel = Channels->Get(Channels->GetNextNormal(Channel->Index()));
#else
if (Channel)
Channel = Channels.Get(Channels.GetNextNormal(Channel->Index()));
#endif
return Channel;
}
// ********************* cListGroups ****************
cListGroups::cListGroups(): cChannelIterator(NextGroup())
cListGroups::cListGroups(): cChannelIterator(Channels.Get(Channels.GetNextGroup(-1)))
{}
const cChannel* cListGroups::NextChannel(const cChannel *Channel)
{
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
if (Channel)
Channel = Channels->Get(Channels->GetNextGroup(Channel->Index()));
#else
if (Channel)
Channel = Channels.Get(Channels.GetNextGroup(Channel->Index()));
#endif
return Channel;
}
//
// ********************* cListGroup ****************
cListGroup::cListGroup(const char *GroupId): cChannelIterator(GetNextChannelInGroup(GetGroup(GroupId)))
cListGroup::cListGroup(const cChannel *Group): cChannelIterator(GetNextChannelInGroup(Group))
{}
const cChannel* cListGroup::GetNextChannelInGroup(const cChannel *Channel)
{
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
if (Channel)
Channel = SkipFakeGroups(Channels->Next(Channel));
#else
if (Channel)
Channel = SkipFakeGroups(Channels.Next(Channel));
#endif
return Channel && !Channel->GroupSep() ? Channel : NULL;
}
@@ -248,65 +62,67 @@ const cChannel* cListGroup::NextChannel(const cChannel *Channel)
}
//
// ********************* cListTree ****************
cListTree::cListTree(const char *SelectedGroupId): cChannelIterator(NextGroup())
cListTree::cListTree(const cChannel *SelectedGroup): cChannelIterator(Channels.Get(Channels.GetNextGroup(-1)))
{
selectedGroup = GetGroup(SelectedGroupId);
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
currentGroup = Channels->Get(Channels->GetNextGroup(-1));
#else
selectedGroup = SelectedGroup;
currentGroup = Channels.Get(Channels.GetNextGroup(-1));
#endif
}
const cChannel* cListTree::NextChannel(const cChannel *Channel)
{
if (currentGroup == selectedGroup)
{
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
if (Channel)
Channel = SkipFakeGroups(Channels->Next(Channel));
#else
if (Channel)
Channel = SkipFakeGroups(Channels.Next(Channel));
#endif
if (Channel && Channel->GroupSep())
currentGroup = Channel;
}
else
{
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
if (Channel)
Channel = Channels->Get(Channels->GetNextGroup(Channel->Index()));
#else
if (Channel)
Channel = Channels.Get(Channels.GetNextGroup(Channel->Index()));
#endif
currentGroup = Channel;
}
return Channel;
}
// ******************** cMenuList ******************
cMenuList::cMenuList(cItemIterator *Iterator) : iterator(Iterator)
// ******************** cChannelList ******************
cChannelList::cChannelList(cChannelIterator *Iterator) : iterator(Iterator)
{}
cMenuList::~cMenuList()
cChannelList::~cChannelList()
{
delete iterator;
}
// ******************** cHtmlMenuList ******************
const char* cHtmlMenuList::menu =
int cChannelList::GetGroupIndex(const cChannel *Group)
{
int index = 0;
for (int curr = Channels.GetNextGroup(-1); curr >= 0; curr = Channels.GetNextGroup(curr))
{
if (Channels.Get(curr) == Group)
return index;
index++;
}
return -1;
}
const cChannel* cChannelList::GetGroup(int Index)
{
int group = Channels.GetNextGroup(-1);
while (Index-- && group >= 0)
group = Channels.GetNextGroup(group);
return group >= 0 ? Channels.Get(group) : NULL;
}
// ******************** cHtmlChannelList ******************
const char* cHtmlChannelList::menu =
"[<a href=\"/\">Home</a> (<a href=\"all.html\" tvid=\"RED\">no script</a>)] "
"[<a href=\"tree.html\" tvid=\"GREEN\">Tree View</a>] "
"[<a href=\"groups.html\" tvid=\"YELLOW\">Groups</a> (<a href=\"groups.m3u\">Playlist</a> | <a href=\"groups.rss\">RSS</a>)] "
"[<a href=\"channels.html\" tvid=\"BLUE\">Channels</a> (<a href=\"channels.m3u\">Playlist</a> | <a href=\"channels.rss\">RSS</a>)] "
"[<a href=\"recordings.html\">Recordings</a> (<a href=\"recordings.m3u\">Playlist</a> | <a href=\"recordings.rss\">RSS</a>)] ";
"[<a href=\"groups.html\" tvid=\"YELLOW\">Groups</a> (<a href=\"groups.m3u\">Playlist</a>)] "
"[<a href=\"channels.html\" tvid=\"BLUE\">Channels</a> (<a href=\"channels.m3u\">Playlist</a>)] ";
const char* cHtmlMenuList::css =
const char* cHtmlChannelList::css =
"<style type=\"text/css\">\n"
"<!--\n"
"a:link, a:visited, a:hover, a:active, a:focus { color:#333399; }\n"
@@ -322,7 +138,7 @@ const char* cHtmlMenuList::css =
"-->\n"
"</style>";
const char* cHtmlMenuList::js =
const char* cHtmlChannelList::js =
"<script language=\"JavaScript\">\n"
"<!--\n"
@@ -383,15 +199,13 @@ const char* cHtmlMenuList::js =
"</script>";
std::string cHtmlMenuList::StreamTypeMenu()
std::string cHtmlChannelList::StreamTypeMenu()
{
std::string typeMenu;
typeMenu += (streamType == stTS ? (std::string) "[TS] " :
(std::string) "[<a href=\"/TS/" + self + "\">TS</a>] ");
#ifdef STREAMDEV_PS
typeMenu += (streamType == stPS ? (std::string) "[PS] " :
(std::string) "[<a href=\"/PS/" + self + "\">PS</a>] ");
#endif
typeMenu += (streamType == stPES ? (std::string) "[PES] " :
(std::string) "[<a href=\"/PES/" + self + "\">PES</a>] ");
typeMenu += (streamType == stES ? (std::string) "[ES] " :
@@ -401,29 +215,27 @@ std::string cHtmlMenuList::StreamTypeMenu()
return typeMenu;
}
cHtmlMenuList::cHtmlMenuList(cItemIterator *Iterator, eStreamType StreamType, const char *Self, const char *Rss, const char *GroupTarget): cMenuList(Iterator)
cHtmlChannelList::cHtmlChannelList(cChannelIterator *Iterator, eStreamType StreamType, const char *Self, const char *GroupTarget): cChannelList(Iterator)
{
streamType = StreamType;
self = strdup(Self);
rss = strdup(Rss);
groupTarget = (GroupTarget && *GroupTarget) ? strdup(GroupTarget) : NULL;
htmlState = hsRoot;
onItem = true;
current = NULL;
}
cHtmlMenuList::~cHtmlMenuList()
cHtmlChannelList::~cHtmlChannelList()
{
free((void *) self);
free((void *) rss);
free((void *) groupTarget);
}
bool cHtmlMenuList::HasNext()
bool cHtmlChannelList::HasNext()
{
return htmlState != hsPageBottom;
}
std::string cHtmlMenuList::Next()
std::string cHtmlChannelList::Next()
{
switch (htmlState)
{
@@ -440,39 +252,39 @@ std::string cHtmlMenuList::Next()
htmlState = hsPageTop;
break;
case hsPageTop:
onItem = NextItem();
htmlState = onItem ? (IsGroup() ? hsGroupTop : hsPlainTop) : hsPageBottom;
current = NextChannel();
htmlState = current ? (current->GroupSep() ? hsGroupTop : hsPlainTop) : hsPageBottom;
break;
case hsPlainTop:
htmlState = hsPlainItem;
break;
case hsPlainItem:
onItem = NextItem();
htmlState = onItem && !IsGroup() ? hsPlainItem : hsPlainBottom;
current = NextChannel();
htmlState = current && !current->GroupSep() ? hsPlainItem : hsPlainBottom;
break;
case hsPlainBottom:
htmlState = onItem ? hsGroupTop : hsPageBottom;
htmlState = current ? hsGroupTop : hsPageBottom;
break;
case hsGroupTop:
onItem = NextItem();
htmlState = onItem && !IsGroup() ? hsItemsTop : hsGroupBottom;
current = NextChannel();
htmlState = current && !current->GroupSep() ? hsItemsTop : hsGroupBottom;
break;
case hsItemsTop:
htmlState = hsItem;
break;
case hsItem:
onItem = NextItem();
htmlState = onItem && !IsGroup() ? hsItem : hsItemsBottom;
current = NextChannel();
htmlState = current && !current->GroupSep() ? hsItem : hsItemsBottom;
break;
case hsItemsBottom:
htmlState = hsGroupBottom;
break;
case hsGroupBottom:
htmlState = onItem ? hsGroupTop : hsPageBottom;
htmlState = current ? hsGroupTop : hsPageBottom;
break;
case hsPageBottom:
default:
esyslog("streamdev-server cHtmlMenuList: invalid call to Next()");
esyslog("streamdev-server cHtmlChannelList: invalid call to Next()");
break;
}
switch (htmlState)
@@ -497,100 +309,101 @@ std::string cHtmlMenuList::Next()
}
}
std::string cHtmlMenuList::HtmlHead()
{
return (std::string) "<link rel=\"alternate\" type=\"application/rss+xml\" title=\"RSS\" href=\"" + rss + "\"/>";
}
std::string cHtmlMenuList::PageTop()
{
return (std::string) "<div class=\"menu\"><div>" + menu + "</div><div>" + StreamTypeMenu() + "</div></div>";
}
std::string cHtmlMenuList::PageBottom()
std::string cHtmlChannelList::HtmlHead()
{
return (std::string) "";
}
std::string cHtmlMenuList::GroupTitle()
std::string cHtmlChannelList::PageTop()
{
return (std::string) "<div class=\"menu\"><div>" + menu + "</div><div>" + StreamTypeMenu() + "</div></div>";
}
std::string cHtmlChannelList::PageBottom()
{
return (std::string) "";
}
std::string cHtmlChannelList::GroupTitle()
{
if (groupTarget)
{
return (std::string) "<a href=\"" + groupTarget + "?group=" + (const char*) ItemId() + "\">" +
ItemTitle() + "</a>";
return (std::string) "<a href=\"" + groupTarget + "?group=" +
(const char*) itoa(cChannelList::GetGroupIndex(current)) +
"\">" + current->Name() + "</a>";
}
else
{
return (std::string) ItemTitle();
return (std::string) current->Name();
}
}
std::string cHtmlMenuList::ItemText()
std::string cHtmlChannelList::ItemText()
{
std::string line;
std::string suffix;
switch (streamType) {
case stTS: suffix = (std::string) ".ts"; break;
#ifdef STREAMDEV_PS
case stPS: suffix = (std::string) ".vob"; break;
#endif
// for Network Media Tank
case stPES: suffix = (std::string) ".vdr"; break;
default: suffix = "";
}
line += (std::string) "<li value=\"" + (const char*) ItemId() + "\">";
line += (std::string) "<a href=\"" + (const char*) ItemRessource() + suffix + "\"";
line += (std::string) "<li value=\"" + (const char*) itoa(current->Number()) + "\">";
line += (std::string) "<a href=\"" + (std::string) current->GetChannelID().ToString() + suffix + "\"";
// for Network Media Tank
line += (std::string) " vod ";
if (strlen(ItemId()) < 4)
line += (std::string) " tvid=\"" + (const char*) ItemId() + "\"";
if (current->Number() < 1000)
line += (std::string) " tvid=\"" + (const char*) itoa(current->Number()) + "\"";
line += (std::string) ">" + ItemTitle() + "</a>";
line += (std::string) ">" + current->Name() + "</a>";
// TS always streams all PIDs
if (streamType != stTS)
int count = 0;
for (int i = 0; current->Apid(i) != 0; ++i, ++count)
;
for (int i = 0; current->Dpid(i) != 0; ++i, ++count)
;
if (count > 1)
{
int index = 1;
const char* lang;
std::string pids;
for (int i = 0; (lang = Alang(i)) != NULL; ++i, ++index) {
pids += (std::string) " <a href=\"" + (const char*) ItemRessource() +
"+" + (const char*)itoa(index) + suffix + "\" class=\"apid\" vod>" + (const char*) lang + "</a>";
}
for (int i = 0; (lang = Dlang(i)) != NULL; ++i, ++index) {
pids += (std::string) " <a href=\"" + (const char*) ItemRessource() +
"+" + (const char*)itoa(index) + suffix + "\" class=\"dpid\" vod>" + (const char*) lang + "</a>";
}
// always show audio PIDs for stES to select audio only
if (index > 2 || streamType == stES)
line += pids;
for (int i = 0; current->Apid(i) != 0; ++i, ++index) {
line += (std::string) " <a href=\"" + (std::string) current->GetChannelID().ToString() +
"+" + (const char*)itoa(index) + suffix + "\" class=\"apid\" vod>" + current->Alang(i) + "</a>";
}
for (int i = 0; current->Dpid(i) != 0; ++i, ++index) {
line += (std::string) " <a href=\"" + (std::string) current->GetChannelID().ToString() +
"+" + (const char*)itoa(index) + suffix + "\" class=\"dpid\" vod>" + current->Dlang(i) + "</a>";
}
}
line += "</li>";
return line;
}
// ******************** cM3uMenuList ******************
cM3uMenuList::cM3uMenuList(cItemIterator *Iterator, const char* Base)
: cMenuList(Iterator),
m_IConv(cCharSetConv::SystemCharacterTable(), "UTF-8")
// ******************** cM3uChannelList ******************
cM3uChannelList::cM3uChannelList(cChannelIterator *Iterator, const char* Base)
: cChannelList(Iterator)
#if defined(APIVERSNUM) && APIVERSNUM >= 10503
, m_IConv(cCharSetConv::SystemCharacterTable(), "UTF-8")
#endif
{
base = strdup(Base);
m3uState = msFirst;
}
cM3uMenuList::~cM3uMenuList()
cM3uChannelList::~cM3uChannelList()
{
free(base);
}
bool cM3uMenuList::HasNext()
bool cM3uChannelList::HasNext()
{
return m3uState != msLast;
}
std::string cM3uMenuList::Next()
std::string cM3uChannelList::Next()
{
if (m3uState == msFirst)
{
@@ -598,83 +411,30 @@ std::string cM3uMenuList::Next()
return "#EXTM3U";
}
if (!NextItem())
const cChannel *channel = NextChannel();
if (!channel)
{
m3uState = msLast;
return "";
}
std::string name = (std::string) m_IConv.Convert(ItemTitle());
#if defined(APIVERSNUM) && APIVERSNUM >= 10503
std::string name = (std::string) m_IConv.Convert(channel->Name());
#else
std::string name = channel->Name();
#endif
if (IsGroup())
if (channel->GroupSep())
{
return (std::string) "#EXTINF:-1," + name + "\r\n" +
base + "group.m3u?group=" + (const char*) ItemId();
base + "group.m3u?group=" +
(const char*) itoa(cChannelList::GetGroupIndex(channel));
}
else
{
return (std::string) "#EXTINF:-1," +
(const char*) ItemId() + " " + name + "\r\n" +
base + (const char*) ItemRessource();
(const char*) itoa(channel->Number()) + " " + name + "\r\n" +
base + (std::string) channel->GetChannelID().ToString();
}
}
// ******************** cRssMenuList ******************
cRssMenuList::cRssMenuList(cItemIterator *Iterator, const char *Base, const char *Html)
: cMenuList(Iterator),
m_IConv(cCharSetConv::SystemCharacterTable(), "UTF-8")
{
base = strdup(Base);
html = strdup(Html);
rssState = msFirst;
}
cRssMenuList::~cRssMenuList()
{
free(base);
free(html);
}
bool cRssMenuList::HasNext()
{
return rssState != msLast;
}
std::string cRssMenuList::Next()
{
std::string type_ext;
if (rssState == msFirst)
{
rssState = msContinue;
return (std::string) "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<rss version=\"2.0\">\n\t<channel>\n"
"\t\t<title>VDR</title>\n"
"\t\t<link>" + base + html + "</link>\n"
"\t\t<description>VDR channel list</description>\n"
;
}
if (!NextItem())
{
rssState = msLast;
return "\t</channel>\n</rss>\n";
}
std::string name = (std::string) m_IConv.Convert(ItemTitle());
if (IsGroup())
{
return (std::string) "\t\t<item>\n\t\t\t<title>" +
name + "</title>\n\t\t\t<link>" +
base + "group.rss?group=" + (const char*) ItemId() + "</link>\n\t\t</item>\n";
}
else
{
return (std::string) "\t\t<item>\n\t\t\t<title>" +
(const char*) ItemId() + " " + name + "</title>\n\t\t\t<link>" +
base + (const char*) ItemRessource() + "</link>\n\t\t\t<enclosure url=\"" +
base + (const char*) ItemRessource() + "\" type=\"video/mpeg\" />\n\t\t</item>\n";
}
}

View File

@@ -3,66 +3,19 @@
#include <string>
#include "../common.h"
#include <vdr/recording.h>
class cChannel;
// ******************** cItemIterator ******************
class cItemIterator
{
public:
virtual bool Next() = 0;
virtual bool IsGroup() const = 0;
virtual const cString ItemId() const = 0;
virtual const char* ItemTitle() const = 0;
virtual const cString ItemRessource() const = 0;
virtual const char* Alang(int i) const = 0;
virtual const char* Dlang(int i) const = 0;
virtual ~cItemIterator() {};
};
class cRecordingsIterator: public cItemIterator
// ******************** cChannelIterator ******************
class cChannelIterator
{
private:
eStreamType streamType;
const cRecording *first;
const cRecording *current;
cThreadLock RecordingsLock;
const cChannel *channel;
protected:
virtual const cRecording* NextSuitable(const cRecording *Recording);
public:
virtual bool Next();
virtual bool IsGroup() const { return false; }
virtual const cString ItemId() const { return current ? itoa(current->Index() + 1) : "0"; }
virtual const char* ItemTitle() const { return current ? current->Title() : ""; }
virtual const cString ItemRessource() const;
virtual const char* Alang(int i) const { return NULL; }
virtual const char* Dlang(int i) const { return NULL; }
cRecordingsIterator(eStreamType StreamType);
virtual ~cRecordingsIterator() {};
};
class cChannelIterator: public cItemIterator
{
private:
const cChannel *first;
const cChannel *current;
protected:
virtual const cChannel* FirstChannel();
virtual const cChannel* NextNormal();
virtual const cChannel* NextGroup();
virtual const cChannel* NextChannel(const cChannel *Channel) = 0;
static inline const cChannel* SkipFakeGroups(const cChannel *Channel);
// Helper which returns the group by its index
static const cChannel* GetGroup(const char* GroupId);
public:
virtual bool Next();
virtual bool IsGroup() const { return current && current->GroupSep(); }
virtual const cString ItemId() const;
virtual const char* ItemTitle() const { return current ? current->Name() : ""; }
virtual const cString ItemRessource() const { return (current ? current->GetChannelID() : tChannelID::InvalidID).ToString(); }
virtual const char* Alang(int i) const { return current && current->Apid(i) ? current->Alang(i) : NULL; }
virtual const char* Dlang(int i) const { return current && current->Dpid(i) ? current->Dlang(i) : NULL; }
const cChannel* Next();
cChannelIterator(const cChannel *First);
virtual ~cChannelIterator() {};
};
@@ -101,7 +54,7 @@ class cListGroup: public cChannelIterator
protected:
virtual const cChannel* NextChannel(const cChannel *Channel);
public:
cListGroup(const char *GroupId);
cListGroup(const cChannel *Group);
virtual ~cListGroup() {};
};
@@ -113,32 +66,31 @@ class cListTree: public cChannelIterator
protected:
virtual const cChannel* NextChannel(const cChannel *Channel);
public:
cListTree(const char *SelectedGroupId);
cListTree(const cChannel *SelectedGroup);
virtual ~cListTree() {};
};
// ******************** cMenuList ******************
class cMenuList
// ******************** cChannelList ******************
class cChannelList
{
private:
cItemIterator *iterator;
cChannelIterator *iterator;
protected:
bool NextItem() { return iterator->Next(); }
bool IsGroup() { return iterator->IsGroup(); }
const cString ItemId() { return iterator->ItemId(); }
const char* ItemTitle() { return iterator->ItemTitle(); }
const cString ItemRessource() { return iterator->ItemRessource(); }
const char* Alang(int i) { return iterator->Alang(i); }
const char* Dlang(int i) { return iterator->Dlang(i); }
const cChannel* NextChannel() { return iterator->Next(); }
public:
// Helper which returns the group index
static int GetGroupIndex(const cChannel* Group);
// Helper which returns the group by its index
static const cChannel* GetGroup(int Index);
virtual std::string HttpHeader() { return "HTTP/1.0 200 OK\r\n"; };
virtual bool HasNext() = 0;
virtual std::string Next() = 0;
cMenuList(cItemIterator *Iterator);
virtual ~cMenuList();
cChannelList(cChannelIterator *Iterator);
virtual ~cChannelList();
};
class cHtmlMenuList: public cMenuList
class cHtmlChannelList: public cChannelList
{
private:
static const char* menu;
@@ -152,10 +104,9 @@ class cHtmlMenuList: public cMenuList
hsItemsTop, hsItem, hsItemsBottom
};
eHtmlState htmlState;
bool onItem;
const cChannel *current;
eStreamType streamType;
const char* self;
const char* rss;
const char* groupTarget;
std::string StreamTypeMenu();
@@ -166,60 +117,51 @@ class cHtmlMenuList: public cMenuList
std::string PageBottom();
public:
virtual std::string HttpHeader() {
return cMenuList::HttpHeader()
return cChannelList::HttpHeader()
+ "Content-type: text/html; charset="
#if defined(APIVERSNUM) && APIVERSNUM >= 10503
+ (cCharSetConv::SystemCharacterTable() ? cCharSetConv::SystemCharacterTable() : "UTF-8")
#else
+ I18nCharSets()[Setup.OSDLanguage]
#endif
+ "\r\n";
}
virtual bool HasNext();
virtual std::string Next();
cHtmlMenuList(cItemIterator *Iterator, eStreamType StreamType, const char *Self, const char *Rss, const char *GroupTarget);
virtual ~cHtmlMenuList();
cHtmlChannelList(cChannelIterator *Iterator, eStreamType StreamType, const char *Self, const char *GroupTarget);
virtual ~cHtmlChannelList();
};
class cM3uMenuList: public cMenuList
class cM3uChannelList: public cChannelList
{
private:
char *base;
enum eM3uState { msFirst, msContinue, msLast };
eM3uState m3uState;
#if defined(APIVERSNUM) && APIVERSNUM >= 10503
cCharSetConv m_IConv;
#endif
public:
virtual std::string HttpHeader() { return cMenuList::HttpHeader() + "Content-type: audio/x-mpegurl; charset=UTF-8\r\n"; };
virtual std::string HttpHeader() {
return cChannelList::HttpHeader()
+ "Content-type: audio/x-mpegurl; charset="
#if defined(APIVERSNUM) && APIVERSNUM >= 10503
+ "UTF-8"
#else
+ I18nCharSets()[Setup.OSDLanguage]
#endif
+ "\r\n";
}
virtual bool HasNext();
virtual std::string Next();
cM3uMenuList(cItemIterator *Iterator, const char* Base);
virtual ~cM3uMenuList();
};
class cRssMenuList: public cMenuList
{
private:
char *base;
char *html;
enum eRssState { msFirst, msContinue, msLast };
eRssState rssState;
cCharSetConv m_IConv;
public:
virtual std::string HttpHeader() { return cMenuList::HttpHeader() + "Content-type: application/rss+xml\r\n"; };
virtual bool HasNext();
virtual std::string Next();
cRssMenuList(cItemIterator *Iterator, const char *Base, const char *Html);
virtual ~cRssMenuList();
cM3uChannelList(cChannelIterator *Iterator, const char* Base);
virtual ~cM3uChannelList();
};
inline const cChannel* cChannelIterator::SkipFakeGroups(const cChannel* Group)
{
#if APIVERSNUM >= 20300
LOCK_CHANNELS_READ;
#endif
while (Group && Group->GroupSep() && !*Group->Name())
#if APIVERSNUM >= 20300
Group = Channels->Next(Group);
#else
Group = Channels.Next(Group);
#endif
return Group;
}

View File

@@ -1,95 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Frank Schmirler <vdrdev@schmirler.de>, 2008
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2014-05-05 22:46+0200\n"
"PO-Revision-Date: 2008-03-30 02:11+0200\n"
"Last-Translator: Frank Schmirler <vdrdev@schmirler.de>\n"
"Language-Team: German <vdr@linuxtv.org>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-15\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Streaming active"
msgstr "Streamen im Gange"
msgid "Streamdev Connections"
msgstr "Streamdev Verbindungen"
msgid "Disconnect"
msgstr "Trennen"
msgid "Suspend"
msgstr "Pausieren"
msgid "Common Settings"
msgstr "Allgemeines"
msgid "Hide Mainmenu Entry"
msgstr "Hauptmenüeintrag verstecken"
msgid "Start with Live TV suspended"
msgstr "Live-TV beim Start pausieren"
msgid "Maximum Number of Clients"
msgstr "Maximalanzahl an Clients"
msgid "Live TV buffer delay (ms)"
msgstr "Live-TV Pufferdauer (ms)"
msgid "VDR-to-VDR Server"
msgstr "VDR-zu-VDR Server"
msgid "Start VDR-to-VDR Server"
msgstr "VDR-zu-VDR Server starten"
msgid "VDR-to-VDR Server Port"
msgstr "Port des VDR-zu-VDR Servers"
msgid "Bind to IP"
msgstr "Binde an IP"
msgid "Legacy Client Priority"
msgstr "Priorität für alte Clients"
msgid "Client may suspend"
msgstr "Client darf pausieren"
msgid "Loop Prevention"
msgstr "Schleifen verhindern"
msgid "HTTP Server"
msgstr "HTTP Server"
msgid "Start HTTP Server"
msgstr "HTTP Server starten"
msgid "HTTP Server Port"
msgstr "Port des HTTP Servers"
msgid "Priority"
msgstr "Priorität"
msgid "HTTP Streamtype"
msgstr "HTTP Streamtyp"
msgid "Multicast Streaming Server"
msgstr "Multicast Streaming Server"
msgid "Start IGMP Server"
msgstr "IGMP Server starten"
msgid "Multicast Client Port"
msgstr "Port des Multicast Clients"
msgid "Multicast Streamtype"
msgstr "Multicast Streamtyp"
msgid "VDR Streaming Server"
msgstr "VDR Streaming Server"

View File

@@ -1,95 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Javier Bradineras <jbradi@hotmail.com>, 2011
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2014-05-05 22:46+0200\n"
"PO-Revision-Date: 2010-06-19 03:58+0100\n"
"Last-Translator: Javier Bradineras <jbradi@hotmail.com>\n"
"Language-Team: Spanish <vdr@linuxtv.org>\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-15\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Streaming active"
msgstr "Trasmisión activa"
msgid "Streamdev Connections"
msgstr ""
msgid "Disconnect"
msgstr ""
msgid "Suspend"
msgstr "Suspender"
msgid "Common Settings"
msgstr "Configuración común"
msgid "Hide Mainmenu Entry"
msgstr ""
msgid "Start with Live TV suspended"
msgstr ""
msgid "Maximum Number of Clients"
msgstr "Numero máximo de clientes"
msgid "Live TV buffer delay (ms)"
msgstr ""
msgid "VDR-to-VDR Server"
msgstr "Servidor VDR-a-VDR"
msgid "Start VDR-to-VDR Server"
msgstr "Iniciar Servidor VDR-a-VDR"
msgid "VDR-to-VDR Server Port"
msgstr "Puerto del Servidor VDR-a-VDR"
msgid "Bind to IP"
msgstr "IP asociada"
msgid "Legacy Client Priority"
msgstr ""
msgid "Client may suspend"
msgstr "Permitir suspender al cliente"
msgid "Loop Prevention"
msgstr ""
msgid "HTTP Server"
msgstr "Servidor HTTP"
msgid "Start HTTP Server"
msgstr "Iniciar Servidor HTTP"
msgid "HTTP Server Port"
msgstr "Puerto del Servidor HTTP"
msgid "Priority"
msgstr ""
msgid "HTTP Streamtype"
msgstr "Tipo de flujo HTTP"
msgid "Multicast Streaming Server"
msgstr "Servidor de transmisión Multicast"
msgid "Start IGMP Server"
msgstr "Iniciar Servidor IGMP"
msgid "Multicast Client Port"
msgstr "Puerto del Cliente Multicast"
msgid "Multicast Streamtype"
msgstr "Tipo de flujo Multicast"
msgid "VDR Streaming Server"
msgstr "Servidor de transmisiones del VDR"

View File

@@ -1,95 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Rolf Ahrenberg, 2008-
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2014-05-05 22:46+0200\n"
"PO-Revision-Date: 2008-03-30 02:11+0200\n"
"Last-Translator: Rolf Ahrenberg\n"
"Language-Team: Finnish <vdr@linuxtv.org>\n"
"Language: fi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Streaming active"
msgstr "Suoratoistopalvelin aktiivinen"
msgid "Streamdev Connections"
msgstr "Suoratoistoyhteydet"
msgid "Disconnect"
msgstr "Katkaise"
msgid "Suspend"
msgstr "Pysäytä"
msgid "Common Settings"
msgstr "Yleiset asetukset"
msgid "Hide Mainmenu Entry"
msgstr "Piilota valinta päävalikosta"
msgid "Start with Live TV suspended"
msgstr "Käynnistä Live-katselu pysäytettynä"
msgid "Maximum Number of Clients"
msgstr "Suurin sallittu asiakkaiden määrä"
msgid "Live TV buffer delay (ms)"
msgstr ""
msgid "VDR-to-VDR Server"
msgstr "VDR-palvelin"
msgid "Start VDR-to-VDR Server"
msgstr "Käynnistä VDR-palvelin"
msgid "VDR-to-VDR Server Port"
msgstr "VDR-palvelimen portti"
msgid "Bind to IP"
msgstr "Sido osoitteeseen"
msgid "Legacy Client Priority"
msgstr "Legacy-asiakkaan prioriteetti"
msgid "Client may suspend"
msgstr "Asiakas saa pysäyttää palvelimen"
msgid "Loop Prevention"
msgstr "Estä asiakaslaitesilmukat"
msgid "HTTP Server"
msgstr "HTTP-palvelin"
msgid "Start HTTP Server"
msgstr "Käynnistä HTTP-palvelin"
msgid "HTTP Server Port"
msgstr "HTTP-palvelimen portti"
msgid "Priority"
msgstr "Prioriteetti"
msgid "HTTP Streamtype"
msgstr "HTTP-lähetysmuoto"
msgid "Multicast Streaming Server"
msgstr "Multicast-suoratoistopalvelin"
msgid "Start IGMP Server"
msgstr "Käynnistä IGMP-palvelin"
msgid "Multicast Client Port"
msgstr "Multicast-portti"
msgid "Multicast Streamtype"
msgstr "Multicast-lähetysmuoto"
msgid "VDR Streaming Server"
msgstr "VDR-suoratoistopalvelin"

View File

@@ -1,95 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Frank Schmirler <vdrdev@schmirler.de>, 2008
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2014-05-05 22:46+0200\n"
"PO-Revision-Date: 2008-03-30 02:11+0200\n"
"Last-Translator: micky979 <micky979@free.fr>\n"
"Language-Team: French <vdr@linuxtv.org>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-15\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Streaming active"
msgstr "Streaming actif"
msgid "Streamdev Connections"
msgstr ""
msgid "Disconnect"
msgstr ""
msgid "Suspend"
msgstr "Suspendre"
msgid "Common Settings"
msgstr "Paramètres communs"
msgid "Hide Mainmenu Entry"
msgstr ""
msgid "Start with Live TV suspended"
msgstr ""
msgid "Maximum Number of Clients"
msgstr "Nombre maximun de clients"
msgid "Live TV buffer delay (ms)"
msgstr ""
msgid "VDR-to-VDR Server"
msgstr "VDR-to-VDR Serveur"
msgid "Start VDR-to-VDR Server"
msgstr "Démarrer le serveur VDR-to-VDR"
msgid "VDR-to-VDR Server Port"
msgstr "Port du serveur VDR-to-VDR"
msgid "Bind to IP"
msgstr "Attacher aux IP"
msgid "Legacy Client Priority"
msgstr ""
msgid "Client may suspend"
msgstr "Le client peut suspendre"
msgid "Loop Prevention"
msgstr ""
msgid "HTTP Server"
msgstr "Serveur HTTP"
msgid "Start HTTP Server"
msgstr "Démarrer le serveur HTTP"
msgid "HTTP Server Port"
msgstr "Port du serveur HTTP"
msgid "Priority"
msgstr ""
msgid "HTTP Streamtype"
msgstr "Type de Streaming HTTP"
msgid "Multicast Streaming Server"
msgstr ""
msgid "Start IGMP Server"
msgstr ""
msgid "Multicast Client Port"
msgstr ""
msgid "Multicast Streamtype"
msgstr ""
msgid "VDR Streaming Server"
msgstr "Serveur de streaming VDR"

View File

@@ -1,97 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Alberto Carraro <bertocar@tin.it>, 2001
# Antonio Ospite <ospite@studenti.unina.it>, 2003
# Sean Carlos <seanc@libero.it>, 2005
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2014-05-05 22:46+0200\n"
"PO-Revision-Date: 2012-06-12 19:57+0100\n"
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
"Language-Team: Italian <vdr@linuxtv.org>\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Streaming active"
msgstr "Trasmissione attiva"
msgid "Streamdev Connections"
msgstr "Connessioni Streamdev"
msgid "Disconnect"
msgstr "Disconnetti"
msgid "Suspend"
msgstr "Sospendi"
msgid "Common Settings"
msgstr "Impostazioni comuni"
msgid "Hide Mainmenu Entry"
msgstr "Nascondi voce menu principale"
msgid "Start with Live TV suspended"
msgstr ""
msgid "Maximum Number of Clients"
msgstr "Numero massimo di Client"
msgid "Live TV buffer delay (ms)"
msgstr ""
msgid "VDR-to-VDR Server"
msgstr "Server VDR-a-VDR"
msgid "Start VDR-to-VDR Server"
msgstr "Avvia Server VDR-a-VDR"
msgid "VDR-to-VDR Server Port"
msgstr "Porta Server VDR-a-VDR"
msgid "Bind to IP"
msgstr "IP associati"
msgid "Legacy Client Priority"
msgstr "Priorità nativa client"
msgid "Client may suspend"
msgstr "Permetti sospensione al Client"
msgid "Loop Prevention"
msgstr "Evita ciclo"
msgid "HTTP Server"
msgstr "Server HTTP"
msgid "Start HTTP Server"
msgstr "Avvia Server HTTP"
msgid "HTTP Server Port"
msgstr "Porta Server HTTP"
msgid "Priority"
msgstr "Priorità"
msgid "HTTP Streamtype"
msgstr "Tipo flusso HTTP"
msgid "Multicast Streaming Server"
msgstr "Server trasmissione Multicast"
msgid "Start IGMP Server"
msgstr "Avvia Server IGMP"
msgid "Multicast Client Port"
msgstr "Porta Client Multicast"
msgid "Multicast Streamtype"
msgstr "Tipo flusso Multicast"
msgid "VDR Streaming Server"
msgstr "Server trasmissione VDR"

View File

@@ -1,95 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Frank Schmirler <vdrdev@schmirler.de>, 2008
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2014-05-05 22:46+0200\n"
"PO-Revision-Date: 2009-11-26 21:57+0200\n"
"Last-Translator: Valdemaras Pipiras <varas@ambernet.lt>\n"
"Language-Team: Lithuanian <vdr@linuxtv.org>\n"
"Language: lt\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Streaming active"
msgstr "Transliavimas vyksta"
msgid "Streamdev Connections"
msgstr ""
msgid "Disconnect"
msgstr ""
msgid "Suspend"
msgstr "Pristabdyti"
msgid "Common Settings"
msgstr "Bendri nustatymai"
msgid "Hide Mainmenu Entry"
msgstr ""
msgid "Start with Live TV suspended"
msgstr ""
msgid "Maximum Number of Clients"
msgstr "Maksimalus klientų skaičius"
msgid "Live TV buffer delay (ms)"
msgstr ""
msgid "VDR-to-VDR Server"
msgstr "VDR-su-VDR Serveris"
msgid "Start VDR-to-VDR Server"
msgstr "Paleisti VDR-su-VDR serverį"
msgid "VDR-to-VDR Server Port"
msgstr "VDR-su-VDR Serverio portas"
msgid "Bind to IP"
msgstr "Pririšti IP"
msgid "Legacy Client Priority"
msgstr ""
msgid "Client may suspend"
msgstr "Klientas gali pristabdyti"
msgid "Loop Prevention"
msgstr ""
msgid "HTTP Server"
msgstr "HTTP Serveris"
msgid "Start HTTP Server"
msgstr "Paleisti HTTP serverį"
msgid "HTTP Server Port"
msgstr "HTTP serverio portas"
msgid "Priority"
msgstr ""
msgid "HTTP Streamtype"
msgstr "HTTP transliavimo tipas"
msgid "Multicast Streaming Server"
msgstr "Multicast transliavimo serveris"
msgid "Start IGMP Server"
msgstr "Paleisti IGMP serverį"
msgid "Multicast Client Port"
msgstr "Multicast kliento portas"
msgid "Multicast Streamtype"
msgstr "Multicast transliavimo tipas"
msgid "VDR Streaming Server"
msgstr "VDR transliavimo serveris"

View File

@@ -1,96 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See
# This file is distributed under the same license as the VDR streamdev package.
# Tomasz Maciej Nowak, 2014
#
msgid ""
msgstr ""
"Project-Id-Version: vdr-streamdev-server 0.6.1-git\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2014-11-20 14:11+0100\n"
"PO-Revision-Date: 2014-11-24 18:02+0100\n"
"Last-Translator: Tomasz Maciej Nowak <tomek_n@o2.pl>\n"
"Language-Team: Polish <vdr@linuxtv.org>\n"
"Language: pl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-2\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.6.10\n"
msgid "Streaming active"
msgstr "Strumieniowanie aktywne"
msgid "Streamdev Connections"
msgstr "Po³±czenia Streamdev"
msgid "Disconnect"
msgstr "Roz³±cz"
msgid "Suspend"
msgstr "Wstrzymaj"
msgid "Common Settings"
msgstr "Ustawienia ogólne"
msgid "Hide Mainmenu Entry"
msgstr "Ukryj pozycjê w g³ównym menu"
msgid "Start with Live TV suspended"
msgstr "Uruchom ze wstrzyman± telewizj±"
msgid "Maximum Number of Clients"
msgstr "Maksymalna liczba klientów"
msgid "Live TV buffer delay (ms)"
msgstr "Bufor opó¼nieñ telewizji (ms)"
msgid "VDR-to-VDR Server"
msgstr "Serwer VDR do VDR"
msgid "Start VDR-to-VDR Server"
msgstr "Uruchom serwer VDR do VDR"
msgid "VDR-to-VDR Server Port"
msgstr "Port serwera VDR do VDR"
msgid "Bind to IP"
msgstr "Przypisz do adresu"
msgid "Legacy Client Priority"
msgstr "Priorytet dla starego klienta"
msgid "Client may suspend"
msgstr "Klient mo¿e wstrzymaæ"
msgid "Loop Prevention"
msgstr "Zapobieganie pêtli"
msgid "HTTP Server"
msgstr "Serwer HTTP"
msgid "Start HTTP Server"
msgstr "Uruchom serwer HTTP"
msgid "HTTP Server Port"
msgstr "Port serwera HTTP"
msgid "Priority"
msgstr "Priorytet"
msgid "HTTP Streamtype"
msgstr "Typ strumienia HTTP"
msgid "Multicast Streaming Server"
msgstr "Serwer strumienia Multicast"
msgid "Start IGMP Server"
msgstr "Uruchom serwer Multicast"
msgid "Multicast Client Port"
msgstr "Port klienta Multicast"
msgid "Multicast Streamtype"
msgstr "Typ strumienia Multicast"
msgid "VDR Streaming Server"
msgstr "Serwer strumieniuj±cy VDR"

View File

@@ -1,95 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2008 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Frank Schmirler <vdrdev@schmirler.de>, 2008
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2014-05-05 22:46+0200\n"
"PO-Revision-Date: 2008-06-26 15:36+0100\n"
"Last-Translator: Oleg Roitburd <oleg@roitburd.de>\n"
"Language-Team: Russian <vdr@linuxtv.org>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-5\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Streaming active"
msgstr "ÁâàØÜØÝÓ ÐÚâØÒÕÝ"
msgid "Streamdev Connections"
msgstr ""
msgid "Disconnect"
msgstr ""
msgid "Suspend"
msgstr "¾áâÐÝÞÒÚÐ"
msgid "Common Settings"
msgstr "½ÐáâàÞÙÚØ"
msgid "Hide Mainmenu Entry"
msgstr ""
msgid "Start with Live TV suspended"
msgstr ""
msgid "Maximum Number of Clients"
msgstr "¼ÐÚá. ÚÞÛØçÕáâÒÞ ÚÛØÕÝâÞÒ"
msgid "Live TV buffer delay (ms)"
msgstr ""
msgid "VDR-to-VDR Server"
msgstr "VDR-to-VDR áÕàÒÕà"
msgid "Start VDR-to-VDR Server"
msgstr "ÁâÐàâ VDR-to-VDR áÕàÒÕà"
msgid "VDR-to-VDR Server Port"
msgstr "VDR-to-VDR ßÞàâ áÕàÒÕàÐ"
msgid "Bind to IP"
msgstr "¿àØáÞÕÔØÝØâìáï Ú IP"
msgid "Legacy Client Priority"
msgstr ""
msgid "Client may suspend"
msgstr "ºÛØÕÝâ ÜÞÖÕâ ÞáâÐÝÐÒÛØÒÐâì"
msgid "Loop Prevention"
msgstr ""
msgid "HTTP Server"
msgstr "HTTP áÕàÒÕà"
msgid "Start HTTP Server"
msgstr "ÁâÐàâ HTTP áÕàÒÕàÐ"
msgid "HTTP Server Port"
msgstr "HTTP áÕàÒÕà ¿Þàâ"
msgid "Priority"
msgstr ""
msgid "HTTP Streamtype"
msgstr "ÂØß HTTP ßÞâÞÚÐ"
msgid "Multicast Streaming Server"
msgstr ""
msgid "Start IGMP Server"
msgstr ""
msgid "Multicast Client Port"
msgstr ""
msgid "Multicast Streamtype"
msgstr ""
msgid "VDR Streaming Server"
msgstr "VDR Streaming áÕàÒÕà"

View File

@@ -1,97 +0,0 @@
# VDR streamdev plugin language source file.
# Copyright (C) 2009 streamdev development team. See http://streamdev.vdr-developer.org
# This file is distributed under the same license as the VDR streamdev package.
# Milan Hrala <hrala.milan@gmail.com>, 2009
#
msgid ""
msgstr ""
"Project-Id-Version: streamdev_SK\n"
"Report-Msgid-Bugs-To: <vdrdev@schmirler.de>\n"
"POT-Creation-Date: 2014-05-05 22:46+0200\n"
"PO-Revision-Date: 2013-11-22 23:39+0100\n"
"Last-Translator: Milan Hrala <hrala.milan@gmail.com>\n"
"Language-Team: Slovak <hrala.milan@gmail.com>\n"
"Language: sk\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-2\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-Language: Slovak\n"
"X-Poedit-Country: SLOVAKIA\n"
msgid "Streaming active"
msgstr "Streamovanie aktívne"
msgid "Streamdev Connections"
msgstr "Streamdev spojenia"
msgid "Disconnect"
msgstr "Odpoji»"
msgid "Suspend"
msgstr "Pozastavi»"
msgid "Common Settings"
msgstr "V¹eobecné nastavenia"
msgid "Hide Mainmenu Entry"
msgstr "Schova» v hlavnom menu"
msgid "Start with Live TV suspended"
msgstr "Pozastavi» Live TV pri ¹tarte"
msgid "Maximum Number of Clients"
msgstr "Maximály poèet klientov"
msgid "Live TV buffer delay (ms)"
msgstr ""
msgid "VDR-to-VDR Server"
msgstr "Prenos z VDR do VDR"
msgid "Start VDR-to-VDR Server"
msgstr "Spusti» prenos z VDR do VDR"
msgid "VDR-to-VDR Server Port"
msgstr "Port servera prenosu z VDR do VDR"
msgid "Bind to IP"
msgstr "Viaza» na IP"
msgid "Legacy Client Priority"
msgstr "Dodatoèná priorita klienta"
msgid "Client may suspend"
msgstr "Klient mô¾e server pozastavi»"
msgid "Loop Prevention"
msgstr "Prevencia sluèky"
msgid "HTTP Server"
msgstr "HTTP server "
msgid "Start HTTP Server"
msgstr "Spusti» HTTP Server"
msgid "HTTP Server Port"
msgstr "Port HTTP servera"
msgid "Priority"
msgstr "Priorita"
msgid "HTTP Streamtype"
msgstr "Typ HTTP streamu"
msgid "Multicast Streaming Server"
msgstr "Streamovanie Multicastového servera"
msgid "Start IGMP Server"
msgstr "Spusti» IGMP Server"
msgid "Multicast Client Port"
msgstr "Port Multicast klienta"
msgid "Multicast Streamtype"
msgstr "Typ Multicast streamu"
msgid "VDR Streaming Server"
msgstr "VDR server streamovania"

View File

@@ -21,33 +21,27 @@
#include "recplayer.h"
// for TSPLAY patch detection
#include "vdr/device.h"
#undef _XOPEN_SOURCE
#define _XOPEN_SOURCE 600
#include <fcntl.h>
RecPlayer::RecPlayer(const char* FileName)
RecPlayer::RecPlayer(cRecording* rec)
{
file = NULL;
fileOpen = 0;
lastPosition = 0;
recording = new cRecording(FileName);
recording = rec;
for(int i = 1; i < 1000; i++) segments[i] = NULL;
// FIXME find out max file path / name lengths
indexFile = new cIndexFile(recording->FileName(), false, recording->IsPesRecording());
#if VDRVERSNUM >= 10703
indexFile = new cIndexFile(recording->FileName(), false, rec->IsPesRecording());
#else
indexFile = new cIndexFile(recording->FileName(), false);
#endif
if (!indexFile) esyslog("ERROR: Streamdev: Failed to create indexfile!");
scan();
parser = new cPatPmtParser();
unsigned char buffer[2 * TS_SIZE];
unsigned long l = getBlock(buffer, 0UL, sizeof(buffer));
if (!l || !parser->ParsePatPmt(buffer, (int) l))
esyslog("ERROR: Streamdev: Failed to parse PAT/PMT");
}
void RecPlayer::scan()
@@ -64,18 +58,24 @@ void RecPlayer::scan()
for(i = 1; i < 1000; i++)
{
#if APIVERSNUM < 10703
snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), i);
//log->log("RecPlayer", Log::DEBUG, "FILENAME: %s", fileName);
file = fopen(fileName, "r");
#else
snprintf(fileName, 2047, "%s/%05i.ts", recording->FileName(), i);
file = fopen(fileName, "r");
if (!file) {
snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), i);
file = fopen(fileName, "r");
}
#endif
if (!file) break;
segments[i] = new Segment();
segments[i]->start = totalLength;
fseek(file, 0, SEEK_END);
totalLength += ftello(file);
totalLength += ftell(file);
totalFrames = indexFile->Last();
//log->log("RecPlayer", Log::DEBUG, "File %i found, totalLength now %llu, numFrames = %lu", i, totalLength, totalFrames);
segments[i]->end = totalLength;
@@ -91,9 +91,6 @@ RecPlayer::~RecPlayer()
int i = 1;
while(segments[i++]) delete segments[i];
if (file) fclose(file);
delete indexFile;
delete recording;
delete parser;
}
int RecPlayer::openFile(int index)
@@ -102,6 +99,7 @@ int RecPlayer::openFile(int index)
char fileName[2048];
#if APIVERSNUM >= 10703
snprintf(fileName, 2047, "%s/%05i.ts", recording->FileName(), index);
isyslog("openFile called for index %i string:%s", index, fileName);
@@ -111,6 +109,7 @@ int RecPlayer::openFile(int index)
fileOpen = index;
return 1;
}
#endif
snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), index);
isyslog("openFile called for index %i string:%s", index, fileName);
@@ -176,7 +175,7 @@ unsigned long RecPlayer::getBlock(unsigned char* buffer, uint64_t position, unsi
uint32_t yetToGet = amount;
uint32_t got = 0;
uint32_t getFromThisSegment = 0;
uint64_t filePosition;
uint32_t filePosition;
while(got < amount)
{
@@ -198,7 +197,7 @@ unsigned long RecPlayer::getBlock(unsigned char* buffer, uint64_t position, unsi
if (fread(&buffer[got], getFromThisSegment, 1, file) != 1) return 0; // umm, big problem.
// Tell linux not to bother keeping the data in the FS cache
posix_fadvise(fileno(file), filePosition, getFromThisSegment, POSIX_FADV_DONTNEED);
posix_fadvise(file->_fileno, filePosition, getFromThisSegment, POSIX_FADV_DONTNEED);
got += getFromThisSegment;
currentPosition += getFromThisSegment;
@@ -219,47 +218,17 @@ cRecording* RecPlayer::getCurrentRecording()
return recording;
}
#if VDRVERSNUM < 10732
#define ALIGNED_POS(x) (positionFromFrameNumber(indexFile->GetNextIFrame(x, 1)))
#else
#define ALIGNED_POS(x) (positionFromFrameNumber(indexFile->GetClosestIFrame(x)))
#endif
uint64_t RecPlayer::positionFromResume(int ResumeID)
{
int resumeBackup = Setup.ResumeID;
Setup.ResumeID = ResumeID;
cResumeFile resume(recording->FileName(), recording->IsPesRecording());
Setup.ResumeID = resumeBackup;
return ALIGNED_POS(resume.Read());
}
uint64_t RecPlayer::positionFromMark(int MarkIndex)
{
cMarks marks;
if (marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording()) && marks.Count()) {
cMark *mark = marks.cConfig<cMark>::Get(MarkIndex);
if (mark)
return ALIGNED_POS(mark->Position());
}
return 0;
}
uint64_t RecPlayer::positionFromTime(int Seconds)
{
return ALIGNED_POS(SecondsToFrames(Seconds, recording->FramesPerSecond()));
}
uint64_t RecPlayer::positionFromPercent(int Percent)
{
return ALIGNED_POS(getLengthFrames() * Percent / 100L);
}
uint64_t RecPlayer::positionFromFrameNumber(uint32_t frameNumber)
{
if (!indexFile) return 0;
#if VDRVERSNUM >= 10703
uint16_t retFileNumber;
off_t retFileOffset;
#else
uchar retFileNumber;
int retFileOffset;
#endif
if (!indexFile->Get((int)frameNumber, &retFileNumber, &retFileOffset))
{
@@ -290,7 +259,7 @@ uint32_t RecPlayer::frameNumberFromPosition(uint64_t position)
if ((position >= segments[segmentNumber]->start) && (position < segments[segmentNumber]->end)) break;
// position is in this block
}
uint64_t askposition = position - segments[segmentNumber]->start;
uint32_t askposition = position - segments[segmentNumber]->start;
return indexFile->Get((int)segmentNumber, askposition);
}

View File

@@ -23,7 +23,6 @@
#include <stdio.h>
#include <vdr/recording.h>
#include <vdr/remux.h>
#include "server/streamer.h"
@@ -37,7 +36,7 @@ class Segment
class RecPlayer
{
public:
RecPlayer(const char* FileName);
RecPlayer(cRecording* rec);
~RecPlayer();
uint64_t getLengthBytes();
uint32_t getLengthFrames();
@@ -45,12 +44,7 @@ class RecPlayer
int openFile(int index);
uint64_t getLastPosition();
cRecording* getCurrentRecording();
const cPatPmtParser* getPatPmtData() { return parser; }
void scan();
uint64_t positionFromResume(int ResumeID);
uint64_t positionFromMark(int MarkIndex);
uint64_t positionFromTime(int Seconds);
uint64_t positionFromPercent(int Percent);
uint64_t positionFromFrameNumber(uint32_t frameNumber);
uint32_t frameNumberFromPosition(uint64_t position);
bool getNextIFrame(uint32_t frameNumber, uint32_t direction, uint64_t* rfilePosition, uint32_t* rframeNumber, uint32_t* rframeLength);
@@ -58,7 +52,6 @@ class RecPlayer
private:
cRecording* recording;
cIndexFile* indexFile;
cPatPmtParser* parser;
FILE* file;
int fileOpen;
Segment* segments[1000];

View File

@@ -1,98 +0,0 @@
#include "remux/ts2ps.h"
#include "remux/ts2pes.h"
#include "remux/ts2es.h"
#include "remux/extern.h"
#include <vdr/ringbuffer.h>
#include "server/recstreamer.h"
#include "server/connection.h"
#include "common.h"
using namespace Streamdev;
// --- cStreamdevRecStreamer -------------------------------------------------
cStreamdevRecStreamer::cStreamdevRecStreamer(const cServerConnection *Connection, RecPlayer *RecPlayer, eStreamType StreamType, int64_t StartOffset, const int *Apid, const int *Dpid):
cStreamdevStreamer("streamdev-recstreaming", Connection),
m_RecPlayer(RecPlayer),
m_StartOffset(StartOffset),
m_From(0L)
{
Dprintf("New rec streamer\n");
m_To = (int64_t) m_RecPlayer->getLengthBytes() - StartOffset - 1;
const cPatPmtParser *parser = RecPlayer->getPatPmtData();
const int *Apids = Apid ? Apid : parser->Apids();
const int *Dpids = Dpid ? Dpid : parser->Dpids();
switch (StreamType) {
case stES:
{
int pid = parser->Vpid();
if (Apid && Apid[0])
pid = Apid[0];
else if (Dpid && Dpid[0])
pid = Dpid[0];
SetRemux(new cTS2ESRemux(pid));
}
break;
case stPES:
if (!m_RecPlayer->getCurrentRecording()->IsPesRecording())
SetRemux(new cTS2PESRemux(parser->Vpid(), Apids, Dpids, parser->Spids()));
break;
#ifdef STREAMDEV_PS
case stPS:
SetRemux(new cTS2PSRemux(parser->Vpid(), Apids, Dpids, parser->Spids()));
break;
#endif
case stEXT:
SetRemux(new cExternRemux(Connection, parser, Apids, Dpids));
break;
default:
break;
}
}
cStreamdevRecStreamer::~cStreamdevRecStreamer()
{
Dprintf("Desctructing rec streamer\n");
Stop();
}
int64_t cStreamdevRecStreamer::SetRange(int64_t &From, int64_t &To)
{
int64_t l = (int64_t) GetLength();
if (From < 0L) {
From += l;
if (From < 0L)
From = 0L;
To = l - 1;
}
else {
if (To < 0L)
To += l;
else if (To >= l)
To = l - 1;
if (From > To) {
// invalid range - return whole content
From = 0L;
To = l - 1;
}
}
m_From = From;
m_To = To;
return m_To - m_From + 1;
}
uchar* cStreamdevRecStreamer::GetFromReceiver(int &Count)
{
if (m_From <= m_To) {
Count = (int) m_RecPlayer->getBlock(m_Buffer, m_StartOffset + m_From, sizeof(m_Buffer));
return m_Buffer;
}
return NULL;
}
cString cStreamdevRecStreamer::ToText() const
{
return "REPLAY";
}

View File

@@ -1,34 +0,0 @@
#ifndef VDR_STREAMDEV_RECSTREAMER_H
#define VDR_STREAMDEV_RECSTREAMER_H
#include "common.h"
#include "server/streamer.h"
#include "server/recplayer.h"
#define RECBUFSIZE (174 * TS_SIZE)
// --- cStreamdevRecStreamer -------------------------------------------------
class cStreamdevRecStreamer: public cStreamdevStreamer {
private:
//Streamdev::cTSRemux *m_Remux;
RecPlayer *m_RecPlayer;
int64_t m_StartOffset;
int64_t m_From;
int64_t m_To;
uchar m_Buffer[RECBUFSIZE];
protected:
virtual uchar* GetFromReceiver(int &Count);
virtual void DelFromReceiver(int Count) { m_From += Count; };
public:
virtual bool IsReceiving(void) const { return m_From <= m_To; };
uint64_t GetLength() { return m_RecPlayer->getLengthBytes() - m_StartOffset; }
int64_t SetRange(int64_t &From, int64_t &To);
virtual cString ToText() const;
cStreamdevRecStreamer(const cServerConnection *Connection, RecPlayer *RecPlayer, eStreamType StreamType, int64_t StartOffset = 0L, const int *Apids = NULL, const int *Dpids = NULL);
virtual ~cStreamdevRecStreamer();
};
#endif // VDR_STREAMDEV_RECSTREAMER_H

View File

@@ -1,5 +1,5 @@
/*
* $Id: server.c,v 1.10 2009/02/13 10:39:22 schmirl Exp $
* $Id: server.c,v 1.5.2.5 2009/02/13 10:39:42 schmirl Exp $
*/
#include "server/server.h"
@@ -76,7 +76,11 @@ void cStreamdevServer::Action(void)
if (m_Servers.Count() == 0) {
esyslog("ERROR: no streamdev server activated, exiting");
#if VDRVERSNUM > 10403
Cancel(-1);
#else
return;
#endif
}
cTBSelect select;
@@ -121,9 +125,7 @@ void cStreamdevServer::Action(void)
cServerConnection *client = c->Accept();
if (!client)
continue;
Lock();
m_Clients.Add(client);
Unlock();
if (m_Clients.Count() > StreamdevServerSetup.MaxClients) {
esyslog("streamdev: too many clients, rejecting %s:%d",
@@ -152,23 +154,20 @@ void cStreamdevServer::Action(void)
cServerConnection *next = m_Clients.Next(s);
if (!result) {
if (s->IsOpen())
s->Close();
Lock();
isyslog("streamdev: closing streamdev connection to %s:%d",
s->RemoteIp().c_str(), s->RemotePort());
s->Close();
m_Clients.Del(s);
Unlock();
}
s = next;
}
}
Lock();
while (m_Clients.Count() > 0) {
cServerConnection *s = m_Clients.First();
s->Close();
m_Clients.Del(s);
}
Unlock();
while (m_Servers.Count() > 0) {
cServerComponent *c = m_Servers.First();
@@ -176,13 +175,3 @@ void cStreamdevServer::Action(void)
m_Servers.Del(c);
}
}
#if APIVERSNUM >= 20300
cList<cServerConnection>& cStreamdevServer::Clients(cThreadLock& Lock)
#else
const cList<cServerConnection>& cStreamdevServer::Clients(cThreadLock& Lock)
#endif
{
Lock.Lock(m_Instance);
return m_Clients;
}

View File

@@ -1,5 +1,5 @@
/*
* $Id: server.h,v 1.6 2008/10/22 11:59:32 schmirl Exp $
* $Id: server.h,v 1.3.2.3 2008/10/22 11:59:37 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_SERVER_H
@@ -36,12 +36,6 @@ public:
static void Initialize(void);
static void Destruct(void);
static bool Active(void);
#if APIVERSNUM >= 20300
static cList<cServerConnection>& Clients(cThreadLock& Lock);
#else
static const cList<cServerConnection>& Clients(cThreadLock& Lock);
#endif
};
inline bool cStreamdevServer::Active(void)

View File

@@ -1,31 +1,26 @@
/*
* $Id: setup.c,v 1.10 2010/07/19 13:49:31 schmirl Exp $
* $Id: setup.c,v 1.3.2.4 2010/07/19 13:50:14 schmirl Exp $
*/
#include <vdr/menuitems.h>
#include "server/setup.h"
#include "server/server.h"
#include "i18n.h"
cStreamdevServerSetup StreamdevServerSetup;
cStreamdevServerSetup::cStreamdevServerSetup(void) {
HideMenuEntry = false;
MaxClients = 5;
StartSuspended = ssAuto;
LiveBufferMs = 0;
StartVTPServer = true;
VTPServerPort = 2004;
VTPPriority = 0;
LoopPrevention = false;
StartHTTPServer = true;
HTTPServerPort = 3000;
HTTPPriority = 0;
HTTPStreamType = stTS;
HTTPStreamType = stPES;
StartIGMPServer = false;
IGMPClientPort = 1234;
IGMPPriority = 0;
IGMPStreamType = stTS;
SuspendMode = smAlways;
AllowSuspend = false;
strcpy(VTPBindIP, "0.0.0.0");
strcpy(HTTPBindIP, "0.0.0.0");
@@ -33,25 +28,19 @@ cStreamdevServerSetup::cStreamdevServerSetup(void) {
}
bool cStreamdevServerSetup::SetupParse(const char *Name, const char *Value) {
if (strcmp(Name, "HideMenuEntry") == 0) HideMenuEntry = atoi(Value);
else if (strcmp(Name, "MaxClients") == 0) MaxClients = atoi(Value);
else if (strcmp(Name, "StartSuspended") == 0) StartSuspended = atoi(Value);
else if (strcmp(Name, "LiveBufferMs") == 0) LiveBufferMs = atoi(Value);
if (strcmp(Name, "MaxClients") == 0) MaxClients = atoi(Value);
else if (strcmp(Name, "StartServer") == 0) StartVTPServer = atoi(Value);
else if (strcmp(Name, "ServerPort") == 0) VTPServerPort = atoi(Value);
else if (strcmp(Name, "VTPPriority") == 0) VTPPriority = atoi(Value);
else if (strcmp(Name, "VTPBindIP") == 0) strcpy(VTPBindIP, Value);
else if (strcmp(Name, "LoopPrevention") == 0) LoopPrevention = atoi(Value);
else if (strcmp(Name, "StartHTTPServer") == 0) StartHTTPServer = atoi(Value);
else if (strcmp(Name, "HTTPServerPort") == 0) HTTPServerPort = atoi(Value);
else if (strcmp(Name, "HTTPPriority") == 0) HTTPPriority = atoi(Value);
else if (strcmp(Name, "HTTPStreamType") == 0) HTTPStreamType = atoi(Value);
else if (strcmp(Name, "HTTPBindIP") == 0) strcpy(HTTPBindIP, Value);
else if (strcmp(Name, "StartIGMPServer") == 0) StartIGMPServer = atoi(Value);
else if (strcmp(Name, "IGMPClientPort") == 0) IGMPClientPort = atoi(Value);
else if (strcmp(Name, "IGMPPriority") == 0) IGMPPriority = atoi(Value);
else if (strcmp(Name, "IGMPStreamType") == 0) IGMPStreamType = atoi(Value);
else if (strcmp(Name, "IGMPBindIP") == 0) strcpy(IGMPBindIP, Value);
else if (strcmp(Name, "SuspendMode") == 0) SuspendMode = atoi(Value);
else if (strcmp(Name, "AllowSuspend") == 0) AllowSuspend = atoi(Value);
else return false;
return true;
@@ -65,6 +54,12 @@ const char* cStreamdevServerMenuSetupPage::StreamTypes[st_Count - 1] = {
"EXT"
};
const char* cStreamdevServerMenuSetupPage::SuspendModes[sm_Count] = {
"Offer suspend mode",
"Always suspended",
"Never suspended"
};
cStreamdevServerMenuSetupPage::cStreamdevServerMenuSetupPage(void) {
m_NewSetup = StreamdevServerSetup;
@@ -75,44 +70,34 @@ cStreamdevServerMenuSetupPage::~cStreamdevServerMenuSetupPage() {
}
void cStreamdevServerMenuSetupPage::Set(void) {
static const char *StartSuspendedItems[ss_Count] =
{
trVDR("no"),
trVDR("yes"),
trVDR("auto")
};
static const char* modes[sm_Count];
for (int i = 0; i < sm_Count; i++)
modes[i] = tr(SuspendModes[i]);
int current = Current();
Clear();
AddCategory (tr("Common Settings"));
Add(new cMenuEditBoolItem(tr("Hide Mainmenu Entry"), &m_NewSetup.HideMenuEntry));
Add(new cMenuEditStraItem(tr("Start with Live TV suspended"), &m_NewSetup.StartSuspended, ss_Count, StartSuspendedItems));
Add(new cMenuEditIntItem (tr("Maximum Number of Clients"), &m_NewSetup.MaxClients, 0, 100));
Add(new cMenuEditIntItem (tr("Live TV buffer delay (ms)"), &m_NewSetup.LiveBufferMs, 0, 1500));
Add(new cMenuEditStraItem(tr("Suspend behaviour"), &m_NewSetup.SuspendMode, sm_Count, modes));
if (m_NewSetup.SuspendMode == smOffer)
Add(new cMenuEditBoolItem(tr("Client may suspend"), &m_NewSetup.AllowSuspend));
AddCategory (tr("VDR-to-VDR Server"));
Add(new cMenuEditBoolItem(tr("Start VDR-to-VDR Server"), &m_NewSetup.StartVTPServer));
Add(new cMenuEditIntItem (tr("VDR-to-VDR Server Port"), &m_NewSetup.VTPServerPort, 0, 65535));
Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.VTPBindIP));
Add(new cMenuEditIntItem (tr("Legacy Client Priority"), &m_NewSetup.VTPPriority, MINPRIORITY, MAXPRIORITY));
Add(new cMenuEditBoolItem(tr("Client may suspend"), &m_NewSetup.AllowSuspend));
if (cPluginManager::CallFirstService(LOOP_PREVENTION_SERVICE))
Add(new cMenuEditBoolItem(tr("Loop Prevention"), &m_NewSetup.LoopPrevention));
AddCategory (tr("HTTP Server"));
Add(new cMenuEditBoolItem(tr("Start HTTP Server"), &m_NewSetup.StartHTTPServer));
Add(new cMenuEditIntItem (tr("HTTP Server Port"), &m_NewSetup.HTTPServerPort, 0, 65535));
Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.HTTPBindIP));
Add(new cMenuEditIntItem (tr("Priority"), &m_NewSetup.HTTPPriority, MINPRIORITY, MAXPRIORITY));
Add(new cMenuEditStraItem(tr("HTTP Streamtype"), &m_NewSetup.HTTPStreamType, st_Count - 1, StreamTypes));
Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.HTTPBindIP));
AddCategory (tr("Multicast Streaming Server"));
Add(new cMenuEditBoolItem(tr("Start IGMP Server"), &m_NewSetup.StartIGMPServer));
Add(new cMenuEditIntItem (tr("Multicast Client Port"), &m_NewSetup.IGMPClientPort, 0, 65535));
Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.IGMPBindIP));
Add(new cMenuEditIntItem (tr("Priority"), &m_NewSetup.IGMPPriority, MINPRIORITY, MAXPRIORITY));
Add(new cMenuEditStraItem(tr("Multicast Streamtype"), &m_NewSetup.IGMPStreamType, st_Count - 1, StreamTypes));
Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.IGMPBindIP));
SetCurrent(Get(current));
Display();
}
@@ -142,25 +127,19 @@ void cStreamdevServerMenuSetupPage::Store(void) {
cStreamdevServer::Destruct();
}
SetupStore("HideMenuEntry", m_NewSetup.HideMenuEntry);
SetupStore("MaxClients", m_NewSetup.MaxClients);
SetupStore("StartSuspended", m_NewSetup.StartSuspended);
SetupStore("LiveBufferMs", m_NewSetup.LiveBufferMs);
SetupStore("StartServer", m_NewSetup.StartVTPServer);
SetupStore("ServerPort", m_NewSetup.VTPServerPort);
SetupStore("VTPBindIP", m_NewSetup.VTPBindIP);
SetupStore("VTPPriority", m_NewSetup.VTPPriority);
SetupStore("LoopPrevention", m_NewSetup.LoopPrevention);
SetupStore("StartHTTPServer", m_NewSetup.StartHTTPServer);
SetupStore("HTTPServerPort", m_NewSetup.HTTPServerPort);
SetupStore("HTTPBindIP", m_NewSetup.HTTPBindIP);
SetupStore("HTTPPriority", m_NewSetup.HTTPPriority);
SetupStore("HTTPStreamType", m_NewSetup.HTTPStreamType);
SetupStore("HTTPBindIP", m_NewSetup.HTTPBindIP);
SetupStore("StartIGMPServer", m_NewSetup.StartIGMPServer);
SetupStore("IGMPClientPort", m_NewSetup.IGMPClientPort);
SetupStore("IGMPBindIP", m_NewSetup.IGMPBindIP);
SetupStore("IGMPPriority", m_NewSetup.IGMPPriority);
SetupStore("IGMPStreamType", m_NewSetup.IGMPStreamType);
SetupStore("IGMPBindIP", m_NewSetup.IGMPBindIP);
SetupStore("SuspendMode", m_NewSetup.SuspendMode);
SetupStore("AllowSuspend", m_NewSetup.AllowSuspend);
StreamdevServerSetup = m_NewSetup;
@@ -168,3 +147,11 @@ void cStreamdevServerMenuSetupPage::Store(void) {
if (restart)
cStreamdevServer::Initialize();
}
eOSState cStreamdevServerMenuSetupPage::ProcessKey(eKeys Key) {
int oldMode = m_NewSetup.SuspendMode;
eOSState state = cMenuSetupPage::ProcessKey(Key);
if (oldMode != m_NewSetup.SuspendMode)
Set();
return state;
}

View File

@@ -1,5 +1,5 @@
/*
* $Id: setup.h,v 1.4 2010/07/19 13:49:31 schmirl Exp $
* $Id: setup.h,v 1.1.1.1.2.3 2010/07/19 13:50:14 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_SETUPSERVER_H
@@ -7,38 +7,25 @@
#include "common.h"
enum eStartSuspended {
ssNo,
ssYes,
ssAuto,
ss_Count
};
struct cStreamdevServerSetup {
cStreamdevServerSetup(void);
bool SetupParse(const char *Name, const char *Value);
int HideMenuEntry;
int MaxClients;
int StartSuspended;
int LiveBufferMs;
int StartVTPServer;
int VTPServerPort;
char VTPBindIP[20];
int VTPPriority;
int AllowSuspend;
int LoopPrevention;
int StartHTTPServer;
int HTTPServerPort;
int HTTPPriority;
int HTTPStreamType;
char HTTPBindIP[20];
int StartIGMPServer;
int IGMPClientPort;
int IGMPPriority;
int IGMPStreamType;
char IGMPBindIP[20];
int SuspendMode;
int AllowSuspend;
};
extern cStreamdevServerSetup StreamdevServerSetup;
@@ -46,12 +33,14 @@ extern cStreamdevServerSetup StreamdevServerSetup;
class cStreamdevServerMenuSetupPage: public cMenuSetupPage {
private:
static const char* StreamTypes[];
static const char* SuspendModes[];
cStreamdevServerSetup m_NewSetup;
void AddCategory(const char *Title);
void Set();
protected:
virtual void Store(void);
virtual eOSState ProcessKey(eKeys Key);
public:
cStreamdevServerMenuSetupPage(void);

View File

@@ -1,275 +0,0 @@
/*
* streamdev.c: A plugin for the Video Disk Recorder
*
* See the README file for copyright information and how to reach the author.
*
* $Id: streamdev-server.c,v 1.2 2010/07/19 13:49:32 schmirl Exp $
*/
#include <getopt.h>
#include <vdr/tools.h>
#include "streamdev-server.h"
#include "server/menu.h"
#include "server/setup.h"
#include "server/server.h"
#include "server/suspend.h"
#if !defined(APIVERSNUM) || APIVERSNUM < 10725
#error "VDR-1.7.25 or greater required to compile server! Use 'make client' to compile client only."
#endif
cList<cMainThreadHookSubscriber> cMainThreadHookSubscriber::m_Subscribers;
cMutex cMainThreadHookSubscriber::m_Mutex;
#if APIVERSNUM >= 20300
cList<cMainThreadHookSubscriber>& cMainThreadHookSubscriber::Subscribers(cMutexLock& Lock)
#else
const cList<cMainThreadHookSubscriber>& cMainThreadHookSubscriber::Subscribers(cMutexLock& Lock)
#endif
{
Lock.Lock(&m_Mutex);
return m_Subscribers;
}
cMainThreadHookSubscriber::cMainThreadHookSubscriber()
{
m_Mutex.Lock();
m_Subscribers.Add(this);
m_Mutex.Unlock();
}
cMainThreadHookSubscriber::~cMainThreadHookSubscriber()
{
m_Mutex.Lock();
m_Subscribers.Del(this, false);
m_Mutex.Unlock();
}
const char *cPluginStreamdevServer::DESCRIPTION = trNOOP("VDR Streaming Server");
cPluginStreamdevServer::cPluginStreamdevServer(void)
{
m_Suspend = false;
}
cPluginStreamdevServer::~cPluginStreamdevServer()
{
free(opt_auth);
free(opt_remux);
}
const char *cPluginStreamdevServer::Description(void)
{
return tr(DESCRIPTION);
}
const char *cPluginStreamdevServer::CommandLineHelp(void)
{
// return a string that describes all known command line options.
return
" -a <LOGIN:PASSWORD>, --auth=<LOGIN:PASSWORD> Credentials for HTTP authentication.\n"
" -r <CMD>, --remux=<CMD> Define an external command for remuxing.\n"
;
}
bool cPluginStreamdevServer::ProcessArgs(int argc, char *argv[])
{
// implement command line argument processing here if applicable.
static const struct option long_options[] = {
{ "auth", required_argument, NULL, 'a' },
{ "remux", required_argument, NULL, 'r' },
{ NULL, 0, NULL, 0 }
};
int c;
while((c = getopt_long(argc, argv, "a:r:", long_options, NULL)) != -1) {
switch (c) {
case 'a':
{
if (opt_auth)
free(opt_auth);
int l = strlen(optarg);
cBase64Encoder Base64((uchar*) optarg, l, l * 4 / 3 + 3);
const char *s = Base64.NextLine();
if (s)
opt_auth = strdup(s);
}
break;
case 'r':
if (opt_remux)
free(opt_remux);
opt_remux = strdup(optarg);
break;
default:
return false;
}
}
return true;
}
bool cPluginStreamdevServer::Start(void)
{
I18nRegister(PLUGIN_NAME_I18N);
if (!StreamdevHosts.Load(STREAMDEVHOSTSPATH, true, true)) {
esyslog("streamdev-server: error while loading %s", STREAMDEVHOSTSPATH);
fprintf(stderr, "streamdev-server: error while loading %s\n", STREAMDEVHOSTSPATH);
if (access(STREAMDEVHOSTSPATH, F_OK) != 0) {
fprintf(stderr, " Please install streamdevhosts.conf into the path "
"printed above. Without it\n"
" no client will be able to access your streaming-"
"server. An example can be\n"
" found together with this plugin's sources.\n");
}
return false;
}
if (!opt_remux)
opt_remux = strdup(DEFAULT_EXTERNREMUX);
cStreamdevServer::Initialize();
m_Suspend = StreamdevServerSetup.StartSuspended == ssAuto ?
!cDevice::PrimaryDevice()->HasDecoder() :
StreamdevServerSetup.StartSuspended;
return true;
}
void cPluginStreamdevServer::Stop(void)
{
cStreamdevServer::Destruct();
}
cString cPluginStreamdevServer::Active(void)
{
if (cStreamdevServer::Active())
{
static const char *Message = NULL;
if (!Message) Message = tr("Streaming active");
return Message;
}
return NULL;
}
const char *cPluginStreamdevServer::MainMenuEntry(void)
{
return !StreamdevServerSetup.HideMenuEntry ? tr("Streamdev Connections") : NULL;
}
cOsdObject *cPluginStreamdevServer::MainMenuAction(void)
{
return new cStreamdevServerMenu();
}
void cPluginStreamdevServer::MainThreadHook(void)
{
if (m_Suspend) {
cControl::Launch(new cSuspendCtl);
m_Suspend = false;
}
cMutexLock lock;
#if APIVERSNUM >= 20300
cList<cMainThreadHookSubscriber>& subs = cMainThreadHookSubscriber::Subscribers(lock);
#else
const cList<cMainThreadHookSubscriber>& subs = cMainThreadHookSubscriber::Subscribers(lock);
#endif
for (cMainThreadHookSubscriber *s = subs.First(); s; s = subs.Next(s))
s->MainThreadHook();
}
cMenuSetupPage *cPluginStreamdevServer::SetupMenu(void)
{
return new cStreamdevServerMenuSetupPage;
}
bool cPluginStreamdevServer::SetupParse(const char *Name, const char *Value)
{
return StreamdevServerSetup.SetupParse(Name, Value);
}
const char **cPluginStreamdevServer::SVDRPHelpPages(void)
{
static const char *HelpPages[]=
{
"LSTC\n"
" List connected clients\n",
"DISC client_id\n"
" Disconnect a client\n",
NULL
};
return HelpPages;
}
cString cPluginStreamdevServer::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
{
cString reply = NULL;
if (!strcasecmp(Command, "LSTC"))
{
reply = "";
cThreadLock lock;
#if APIVERSNUM >= 20300
cList<cServerConnection>& clients = cStreamdevServer::Clients(lock);
#else
const cList<cServerConnection>& clients = cStreamdevServer::Clients(lock);
#endif
cServerConnection *s = clients.First();
if (!s)
{
reply = "no client connected";
ReplyCode = 550;
} else
{
for (; s; s = clients.Next(s))
{
reply = cString::sprintf("%s%p: %s\n", (const char*) reply, s, (const char *) s->ToText());
}
ReplyCode = 250;
}
} else if (!strcasecmp(Command, "DISC"))
{
void *client = NULL;
if (sscanf(Option, "%p", &client) != 1 || !client)
{
reply = "invalid client handle";
ReplyCode = 501;
} else
{
cThreadLock lock;
#if APIVERSNUM >= 20300
cList<cServerConnection>& clients = cStreamdevServer::Clients(lock);
#else
const cList<cServerConnection>& clients = cStreamdevServer::Clients(lock);
#endif
cServerConnection *s = clients.First();
for (; s && s != client; s = clients.Next(s));
if (!s)
{
reply = "client not found";
ReplyCode = 501;
} else
{
s->Close();
reply = "client disconnected";
ReplyCode = 250;
}
}
}
return reply;
}
bool cPluginStreamdevServer::Service(const char *Id, void *Data)
{
if (strcmp(Id, "StreamdevServer::ClientCount-v1.0") == 0) {
if (Data) {
int *count = (int *) Data;
cThreadLock lock;
*count = cStreamdevServer::Clients(lock).Count();
}
return true;
}
return false;
}
VDRPLUGINCREATOR(cPluginStreamdevServer); // Don't touch this!

View File

@@ -1,5 +1,5 @@
/*
* $Id: streamer.c,v 1.21 2010/07/30 10:01:11 schmirl Exp $
* $Id: streamer.c,v 1.16.2.4 2010/07/19 13:50:14 schmirl Exp $
*/
#include <vdr/ringbuffer.h>
@@ -8,6 +8,8 @@
#include <unistd.h>
#include "server/streamer.h"
#include "server/suspend.h"
#include "server/setup.h"
#include "tools/socket.h"
#include "tools/select.h"
#include "common.h"
@@ -43,30 +45,20 @@ void cStreamdevWriter::Action(void)
int max = 0;
uchar *block = NULL;
int count, offset = 0;
int timeout = 0;
SetPriority(-3);
sel.Clear();
sel.Add(*m_Socket, true);
while (Running()) {
if (block == NULL) {
block = m_Streamer->Get(count);
offset = 0;
// still no data - are we done?
if (block == NULL && !m_Streamer->IsReceiving() && timeout++ > 20) {
esyslog("streamdev-server: streamer done - writer exiting");
break;
}
}
if (block != NULL) {
if (sel.Select(600) == -1) {
if (errno == ETIMEDOUT && timeout++ < 20)
continue; // still Running()?
if (sel.Select(15000) == -1) {
esyslog("ERROR: streamdev-server: couldn't send data: %m");
break;
}
timeout = 0;
if (sel.CanWrite(*m_Socket)) {
int written;
@@ -103,82 +95,69 @@ void cStreamdevWriter::Action(void)
}
}
}
m_Socket->Close();
Dprintf("Max. Transmit Blocksize was: %d\n", max);
}
// --- cRemuxDummy ------------------------------------------------------------
class cRemuxDummy: public Streamdev::cTSRemux {
private:
cStreamdevBuffer m_Buffer;
public:
cRemuxDummy();
virtual int Put(const uchar *Data, int Count) { return m_Buffer.Put(Data, Count); }
virtual uchar *Get(int& Count) { return m_Buffer.Get(Count); }
virtual void Del(int Count) { return m_Buffer.Del(Count); }
};
cRemuxDummy::cRemuxDummy(): m_Buffer(WRITERBUFSIZE, TS_SIZE * 2)
{
m_Buffer.SetTimeouts(100, 100);
}
// --- cStreamdevStreamer -----------------------------------------------------
cStreamdevStreamer::cStreamdevStreamer(const char *Name, const cServerConnection *Connection):
cThread(Name),
m_Connection(Connection),
m_Remux(new cRemuxDummy()),
m_Writer(NULL)
m_Writer(NULL),
m_RingBuffer(new cStreamdevBuffer(STREAMERBUFSIZE, TS_SIZE * 2,
true, "streamdev-streamer")),
m_SendBuffer(new cStreamdevBuffer(WRITERBUFSIZE, TS_SIZE * 2))
{
m_RingBuffer->SetTimeouts(0, 100);
m_SendBuffer->SetTimeouts(100, 100);
}
cStreamdevStreamer::~cStreamdevStreamer()
{
Dprintf("Desctructing streamer\n");
delete m_Remux;
delete m_RingBuffer;
delete m_SendBuffer;
}
void cStreamdevStreamer::Start(cTBSocket *Socket)
{
Dprintf("start writer\n");
Dprintf("start streamer\n");
m_Writer = new cStreamdevWriter(Socket, this);
m_Writer->Start();
if (!Active()) {
Dprintf("start streamer\n");
Attach();
}
void cStreamdevStreamer::Activate(bool On)
{
if (On && !Active()) {
Dprintf("activate streamer\n");
m_Writer->Start();
cThread::Start();
}
Attach();
}
void cStreamdevStreamer::Stop(void)
{
Detach();
if (Running()) {
Dprintf("stop streamer\n");
Dprintf("stopping streamer\n");
Cancel(3);
}
Dprintf("stop writer\n");
DELETENULL(m_Writer);
if (m_Writer) {
Detach();
DELETENULL(m_Writer);
}
}
void cStreamdevStreamer::Action(void)
{
SetPriority(-3);
while (Running()) {
int got;
uchar *block = GetFromReceiver(got);
uchar *block = m_RingBuffer->Get(got);
if (block) {
int count = Put(block, got);
if (count)
DelFromReceiver(count);
m_RingBuffer->Del(count);
}
}
}
int cStreamdevStreamer::Put(const uchar *Data, int Count) {
return m_Remux->Put(Data, Count);
}

View File

@@ -1,5 +1,5 @@
/*
* $Id: streamer.h,v 1.12 2010/07/19 13:49:32 schmirl Exp $
* $Id: streamer.h,v 1.8.2.4 2010/07/19 13:50:14 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_STREAMER_H
@@ -9,8 +9,6 @@
#include <vdr/ringbuffer.h>
#include <vdr/tools.h>
#include "remux/tsremux.h"
class cTBSocket;
class cStreamdevStreamer;
class cServerConnection;
@@ -19,7 +17,8 @@ class cServerConnection;
#define TS_SIZE 188
#endif
#define WRITERBUFSIZE (20000 * TS_SIZE)
#define STREAMERBUFSIZE (20000 * TS_SIZE)
#define WRITERBUFSIZE (5000 * TS_SIZE)
// --- cStreamdevBuffer -------------------------------------------------------
@@ -67,18 +66,14 @@ public:
class cStreamdevStreamer: public cThread {
private:
const cServerConnection *m_Connection;
Streamdev::cTSRemux *m_Remux;
cStreamdevWriter *m_Writer;
cStreamdevBuffer *m_SendBuffer;
cStreamdevWriter *m_Writer;
cStreamdevBuffer *m_RingBuffer;
cStreamdevBuffer *m_SendBuffer;
protected:
virtual uchar* GetFromReceiver(int &Count) = 0;
virtual void DelFromReceiver(int Count) = 0;
virtual int Put(const uchar *Data, int Count);
virtual void Action(void);
bool IsRunning(void) const { return m_Writer; }
void SetRemux(Streamdev::cTSRemux *Remux) { delete m_Remux; m_Remux = Remux; }
public:
cStreamdevStreamer(const char *Name, const cServerConnection *Connection = NULL);
@@ -88,16 +83,18 @@ public:
virtual void Start(cTBSocket *Socket);
virtual void Stop(void);
virtual bool IsReceiving(void) const = 0;
bool Abort(void);
uchar *Get(int &Count) { return m_Remux->Get(Count); }
void Del(int Count) { m_Remux->Del(Count); }
void Activate(bool On);
int Receive(uchar *Data, int Length) { return m_RingBuffer->PutTS(Data, Length); }
void ReportOverflow(int Bytes) { m_RingBuffer->ReportOverflow(Bytes); }
virtual int Put(const uchar *Data, int Count) { return m_SendBuffer->PutTS(Data, Count); }
virtual uchar *Get(int &Count) { return m_SendBuffer->Get(Count); }
virtual void Del(int Count) { m_SendBuffer->Del(Count); }
virtual void Detach(void) {}
virtual void Attach(void) {}
virtual cString ToText() const { return ""; };
};
inline bool cStreamdevStreamer::Abort(void)

View File

@@ -1,5 +1,5 @@
/*
* $Id: suspend.c,v 1.3 2008/10/22 11:59:32 schmirl Exp $
* $Id: suspend.c,v 1.2.2.1 2008/10/22 11:59:37 schmirl Exp $
*/
#include "server/suspend.h"
@@ -39,7 +39,7 @@ void cSuspendLive::Action(void) {
bool cSuspendCtl::m_Active = false;
cSuspendCtl::cSuspendCtl(void):
cControl(m_Suspend = new cSuspendLive, true) {
cControl(m_Suspend = new cSuspendLive) {
m_Active = true;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
* $Id: suspend.h,v 1.2 2008/10/22 11:59:32 schmirl Exp $
* $Id: suspend.h,v 1.1.1.1.2.1 2008/10/22 11:59:37 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_SUSPEND_H

View File

@@ -3,20 +3,21 @@
*
* See the README file for copyright information and how to reach the author.
*
* $Id: streamdev-client.c,v 1.3 2010/08/18 10:26:56 schmirl Exp $
* $Id: streamdev-client.c,v 1.5.2.2 2010/08/18 10:26:18 schmirl Exp $
*/
#include "streamdev-client.h"
#include "client/device.h"
#include "client/setup.h"
#include "i18n.h"
#if !defined(APIVERSNUM) || APIVERSNUM < 10516
#error "VDR-1.5.16 API version or greater is required!"
#if VDRVERSNUM < 10400
#error "VDR-1.4.0 or greater is required"
#endif
const char *cPluginStreamdevClient::DESCRIPTION = trNOOP("VTP Streaming Client");
const char *cPluginStreamdevClient::DESCRIPTION = "VTP Streaming Client";
cPluginStreamdevClient::cPluginStreamdevClient(void): m_Devices() {
cPluginStreamdevClient::cPluginStreamdevClient(void) {
}
cPluginStreamdevClient::~cPluginStreamdevClient() {
@@ -26,14 +27,13 @@ const char *cPluginStreamdevClient::Description(void) {
return tr(DESCRIPTION);
}
bool cPluginStreamdevClient::Initialize(void) {
for (int i = 0; i < STREAMDEV_MAXDEVICES; i++) {
if (m_Devices[i])
m_Devices[i]->ReInit(i >= StreamdevClientSetup.StartClient);
else if (i < StreamdevClientSetup.StartClient)
m_Devices[i] = new cStreamdevDevice();
}
return true;
bool cPluginStreamdevClient::Start(void) {
i18n_name = Name();
RegisterI18n(Phrases);
cStreamdevDevice::Init();
return true;
}
const char *cPluginStreamdevClient::MainMenuEntry(void) {
@@ -41,7 +41,7 @@ const char *cPluginStreamdevClient::MainMenuEntry(void) {
}
cOsdObject *cPluginStreamdevClient::MainMenuAction(void) {
if (StreamdevClientSetup.StartClient && m_Devices[0]->SuspendServer())
if (ClientSocket.SuspendServer())
Skins.Message(mtInfo, tr("Server is suspended"));
else
Skins.Message(mtError, tr("Couldn't suspend Server!"));
@@ -49,24 +49,15 @@ cOsdObject *cPluginStreamdevClient::MainMenuAction(void) {
}
cMenuSetupPage *cPluginStreamdevClient::SetupMenu(void) {
return new cStreamdevClientMenuSetupPage(this);
return new cStreamdevClientMenuSetupPage;
}
bool cPluginStreamdevClient::SetupParse(const char *Name, const char *Value) {
return StreamdevClientSetup.SetupParse(Name, Value);
}
bool cPluginStreamdevClient::Service(const char *Id, void *Data) {
if (!strcmp(Id, LOOP_PREVENTION_SERVICE)) {
cStreamdevDevice::DenyChannel((const cChannel*) Data);
return true;
}
return false;
}
void cPluginStreamdevClient::MainThreadHook(void) {
for (int i = 0; i < StreamdevClientSetup.StartClient; i++)
m_Devices[i]->UpdatePriority();
cStreamdevDevice::UpdatePriority();
}
VDRPLUGINCREATOR(cPluginStreamdevClient); // Don't touch this!

View File

@@ -1,5 +1,5 @@
/*
* $Id: streamdev-client.h,v 1.3 2010/08/18 10:26:56 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
@@ -9,25 +9,20 @@
#include <vdr/plugin.h>
#define STREAMDEV_MAXDEVICES 8
class cStreamdevDevice;
class cPluginStreamdevClient : public cPlugin {
private:
static const char *DESCRIPTION;
cStreamdevDevice *m_Devices[STREAMDEV_MAXDEVICES];
static const char *DESCRIPTION;
public:
cPluginStreamdevClient(void);
virtual ~cPluginStreamdevClient();
virtual const char *Version(void) { return VERSION; }
virtual const char *Description(void);
virtual bool Initialize(void);
virtual bool Start(void);
virtual const char *MainMenuEntry(void);
virtual cOsdObject *MainMenuAction(void);
virtual cMenuSetupPage *SetupMenu(void);
virtual bool SetupParse(const char *Name, const char *Value);
virtual bool Service(const char *Id, void *Data = NULL);
virtual void MainThreadHook(void);
};

Some files were not shown because too many files have changed in this diff Show More