diff options
-rw-r--r-- | HISTORY | 2 | ||||
-rw-r--r-- | PLUGINS.html | 10 | ||||
-rw-r--r-- | PLUGINS/src/status/COPYING | 340 | ||||
-rw-r--r-- | PLUGINS/src/status/HISTORY | 6 | ||||
-rw-r--r-- | PLUGINS/src/status/Makefile | 79 | ||||
-rw-r--r-- | PLUGINS/src/status/README | 11 | ||||
-rw-r--r-- | PLUGINS/src/status/status.c | 179 | ||||
-rw-r--r-- | device.c | 8 | ||||
-rw-r--r-- | dvbapi.c | 2564 | ||||
-rw-r--r-- | dvbapi.h | 283 | ||||
-rw-r--r-- | interface.c | 10 | ||||
-rw-r--r-- | menu.c | 14 | ||||
-rw-r--r-- | menuitems.c | 8 | ||||
-rw-r--r-- | osd.c | 6 | ||||
-rw-r--r-- | status.c | 58 | ||||
-rw-r--r-- | status.h | 10 |
16 files changed, 678 insertions, 2910 deletions
@@ -1319,7 +1319,7 @@ Video Disk Recorder Revision History accessed (suggested by Stefan Huelswitt). - Rearranged OSD class names to make 'cOsd' available for the main OSD interface. - Completely moved OSD handling out of the cDvbApi class, into the new cOsd. -- Implemented cStatusMonitor to allow plugins to set up a status monitor. +- Implemented cStatus to allow plugins to set up a status monitor. See PLUGINS.html for details. - Moved the cEITScanner out of dvbapi.h/.c, into the new eitscan.h/.c. - Added Swedish language texts (thanks to Tomas Prybil). diff --git a/PLUGINS.html b/PLUGINS.html index a0f7ebc9..a3adc937 100644 --- a/PLUGINS.html +++ b/PLUGINS.html @@ -857,12 +857,12 @@ plugin's name, and <tt>0.0.1</tt> will be your plugin's current version number. <center><i><b>A piece of the action</b></i></center><p> If a plugin wants to get informed on various events in VDR, it can derive a class from -<tt>cStatusMonitor</tt>, as in +<tt>cStatus</tt>, as in <p><table><tr><td bgcolor=#F0F0F0><pre><br> #include <vdr/status.h> -class cMyStatusMonitor : public cStatusMonitor { +class cMyStatusMonitor : public cStatus { protected: virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber); }; @@ -914,15 +914,15 @@ Note that the actual object is created in the <tt>Start()</tt> function, not in constructor! It is also important to delete the object in the destructor, in order to avoid memory leaks. <p> -A Plugin can implement any number of <tt>cStatusMonitor</tt> derived objects, and once +A Plugin can implement any number of <tt>cStatus</tt> derived objects, and once the plugin has been started it may create and delete them as necessary. -No further action apart from creating an object derived from <tt>cStatusMonitor</tt> +No further action apart from creating an object derived from <tt>cStatus</tt> is necessary. VDR will automatically hook it into a list of status monitors, with their individual virtual member functions being called in the same sequence as the objects were created. <p> See the file <tt>status.h</tt> for detailed information on which status monitor -member functions are available in <tt>cStatusMonitor</tt>. You only need to implement +member functions are available in <tt>cStatus</tt>. You only need to implement the functions you actually want to use. <!--X1.1.3--></td></tr></table> diff --git a/PLUGINS/src/status/COPYING b/PLUGINS/src/status/COPYING new file mode 100644 index 00000000..5b6e7c66 --- /dev/null +++ b/PLUGINS/src/status/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + 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 + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +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 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 +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +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 + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + 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 +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +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 +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +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 +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +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 + + 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 +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +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 + + 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 +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +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 Library General +Public License instead of this License. diff --git a/PLUGINS/src/status/HISTORY b/PLUGINS/src/status/HISTORY new file mode 100644 index 00000000..27929362 --- /dev/null +++ b/PLUGINS/src/status/HISTORY @@ -0,0 +1,6 @@ +VDR Plugin 'status' Revision History +------------------------------------ + +2002-05-18: Version 0.0.1 + +- Initial revision. diff --git a/PLUGINS/src/status/Makefile b/PLUGINS/src/status/Makefile new file mode 100644 index 00000000..b583e7b5 --- /dev/null +++ b/PLUGINS/src/status/Makefile @@ -0,0 +1,79 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id: Makefile 1.1 2002/06/16 13:26:00 kls 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 = status + +### The version number of this plugin (taken from the main source file): + +VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g') + +### The directory environment: + +DVBDIR = ../../../../DVB/ost/include +VDRDIR = ../../.. +VDRINC = $(VDRDIR)/include +LIBDIR = ../../lib +TMPDIR = /tmp + +### The version number of VDR (taken from VDR's "config.h"): + +VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g') + +### The name of the distribution archive: + +ARCHIVE = $(PLUGIN)-$(VERSION) +PACKAGE = vdr-$(ARCHIVE) + +### Includes and Defines (add further entries here): + +INCLUDES = -I$(VDRINC) -I$(DVBDIR) + +DEFINES = -DPLUGIN_NAME_I18N='"$(PLUGIN)"' + +### The object files (add further files here): + +OBJS = $(PLUGIN).o + +### The C++ compiler and options: + +CXX = g++ +CXXFLAGS = -g -O2 -Wall -Woverloaded-virtual + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +# Dependencies: + +MAKEDEP = g++ -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Targets: + +all: libvdr-$(PLUGIN).so + +libvdr-$(PLUGIN).so: $(OBJS) + $(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@ + @cp $@ $(LIBDIR)/$@.$(VDRVERSION) + +package: clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @echo Distribution package created as $(PACKAGE).tgz + +clean: + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ diff --git a/PLUGINS/src/status/README b/PLUGINS/src/status/README new file mode 100644 index 00000000..356f1f8d --- /dev/null +++ b/PLUGINS/src/status/README @@ -0,0 +1,11 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Klaus Schmidinger <kls@cadsoft.de> + +Project's homepage: www.cadsoft.de/people/kls/vdr + +Latest version available at: www.cadsoft.de/people/kls/vdr/software.htm + +See the file COPYING for license information. + +Description: This is an example that shows the use of cStatus. diff --git a/PLUGINS/src/status/status.c b/PLUGINS/src/status/status.c new file mode 100644 index 00000000..2d5f42f3 --- /dev/null +++ b/PLUGINS/src/status/status.c @@ -0,0 +1,179 @@ +/* + * status.c: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id: status.c 1.1 2002/06/16 13:26:00 kls Exp $ + */ + +#include <vdr/plugin.h> +#include <vdr/status.h> + +static const char *VERSION = "0.0.1"; +static const char *DESCRIPTION = "Status monitor test"; +static const char *MAINMENUENTRY = NULL; + +// --- + +class cStatusTest : public cStatus { +protected: + virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber); + virtual void Recording(const cDevice *Device, const char *Name); + virtual void Replaying(const cDvbPlayerControl *DvbPlayerControl, const char *Name); + virtual void SetVolume(int Volume, bool Absolute); + virtual void OsdClear(void); + virtual void OsdTitle(const char *Title); + virtual void OsdStatusMessage(const char *Message); + virtual void OsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue); + virtual void OsdCurrentItem(const char *Text); + virtual void OsdTextItem(const char *Text, bool Scroll); + virtual void OsdChannel(const char *Text); + virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle); + }; + +void cStatusTest::ChannelSwitch(const cDevice *Device, int ChannelNumber) +{ + dsyslog("status: cStatusTest::ChannelSwitch %d %d", Device->CardIndex(), ChannelNumber); +} + +void cStatusTest::Recording(const cDevice *Device, const char *Name) +{ + dsyslog("status: cStatusTest::Recording %d %s", Device->CardIndex(), Name); +} + +void cStatusTest::Replaying(const cDvbPlayerControl *DvbPlayerControl, const char *Name) +{ + dsyslog("status: cStatusTest::Replaying %s", Name); +} + +void cStatusTest::SetVolume(int Volume, bool Absolute) +{ + dsyslog("status: cStatusTest::SetVolume %d %d", Volume, Absolute); +} + +void cStatusTest::OsdClear(void) +{ + dsyslog("status: cStatusTest::OsdClear"); +} + +void cStatusTest::OsdTitle(const char *Title) +{ + dsyslog("status: cStatusTest::OsdTitle '%s'", Title); +} + +void cStatusTest::OsdStatusMessage(const char *Message) +{ + dsyslog("status: cStatusTest::OsdStatusMessage '%s'", Message); +} + +void cStatusTest::OsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue) +{ + dsyslog("status: cStatusTest::OsdHelpKeys %s - %s - %s - %s", Red, Green, Yellow, Blue); +} + +void cStatusTest::OsdCurrentItem(const char *Text) +{ + dsyslog("status: cStatusTest::OsdCurrentItem %s", Text); +} + +void cStatusTest::OsdTextItem(const char *Text, bool Scroll) +{ + dsyslog("status: cStatusTest::OsdTextItem %s %d", Text, Scroll); +} + +void cStatusTest::OsdChannel(const char *Text) +{ + dsyslog("status: cStatusTest::OsdChannel %s", Text); +} + +void cStatusTest::OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle) +{ + char buffer[25]; + struct tm tm_r; + dsyslog("status: cStatusTest::OsdProgramme"); + strftime(buffer, sizeof(buffer), "%R", localtime_r(&PresentTime, &tm_r)); + dsyslog("%5s %s", buffer, PresentTitle); + dsyslog("%5s %s", "", PresentSubtitle); + strftime(buffer, sizeof(buffer), "%R", localtime_r(&FollowingTime, &tm_r)); + dsyslog("%5s %s", buffer, FollowingTitle); + dsyslog("%5s %s", "", FollowingSubtitle); +} + +// --- + +class cPluginStatus : public cPlugin { +private: + // Add any member variables or functions you may need here. + cStatusTest *statusTest; +public: + cPluginStatus(void); + virtual ~cPluginStatus(); + virtual const char *Version(void) { return VERSION; } + virtual const char *Description(void) { return DESCRIPTION; } + virtual const char *CommandLineHelp(void); + virtual bool ProcessArgs(int argc, char *argv[]); + virtual bool Start(void); + virtual void Housekeeping(void); + virtual const char *MainMenuEntry(void) { return MAINMENUENTRY; } + virtual cOsdMenu *MainMenuAction(void); + virtual cMenuSetupPage *SetupMenu(void); + virtual bool SetupParse(const char *Name, const char *Value); + }; + +cPluginStatus::cPluginStatus(void) +{ + // Initialize any member varaiables here. + // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL + // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! + statusTest = NULL; +} + +cPluginStatus::~cPluginStatus() +{ + // Clean up after yourself! + delete statusTest; +} + +const char *cPluginStatus::CommandLineHelp(void) +{ + // Return a string that describes all known command line options. + return NULL; +} + +bool cPluginStatus::ProcessArgs(int argc, char *argv[]) +{ + // Implement command line argument processing here if applicable. + return true; +} + +bool cPluginStatus::Start(void) +{ + // Start any background activities the plugin shall perform. + statusTest = new cStatusTest; + return true; +} + +void cPluginStatus::Housekeeping(void) +{ + // Perform any cleanup or other regular tasks. +} + +cOsdMenu *cPluginStatus::MainMenuAction(void) +{ + // Perform the action when selected from the main VDR menu. + return NULL; +} + +cMenuSetupPage *cPluginStatus::SetupMenu(void) +{ + // Return a setup menu in case the plugin supports one. + return NULL; +} + +bool cPluginStatus::SetupParse(const char *Name, const char *Value) +{ + // Parse your own setup parameters and store their values. + return false; +} + +VDRPLUGINCREATOR(cPluginStatus); // Don't touch this! @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: device.c 1.1 2002/06/16 12:29:09 kls Exp $ + * $Id: device.c 1.2 2002/06/16 13:23:31 kls Exp $ */ #include "device.h" @@ -459,7 +459,7 @@ eSetChannelResult cDevice::SetChannel(int ChannelNumber, int Frequency, char Pol //XXX+StopTransfer(); //XXX+StopReplay(); - cStatusMonitor::MsgChannelSwitch(this, 0); + cStatus::MsgChannelSwitch(this, 0); // Must set this anyway to avoid getting stuck when switching through // channels with 'Up' and 'Down' keys: @@ -639,7 +639,7 @@ eSetChannelResult cDevice::SetChannel(int ChannelNumber, int Frequency, char Pol if (Result == scrOk && siProcessor) siProcessor->SetCurrentTransponder(Frequency); - cStatusMonitor::MsgChannelSwitch(this, ChannelNumber); + cStatus::MsgChannelSwitch(this, ChannelNumber); return Result; } @@ -660,7 +660,7 @@ void cDevice::SetVolume(int Volume, bool Absolute) audioMixer_t am; am.volume_left = am.volume_right = volume; CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am)); - cStatusMonitor::MsgSetVolume(volume, Absolute); + cStatus::MsgSetVolume(volume, Absolute); if (volume > 0) mute = false; } diff --git a/dvbapi.c b/dvbapi.c deleted file mode 100644 index aa4f50e3..00000000 --- a/dvbapi.c +++ /dev/null @@ -1,2564 +0,0 @@ -/* - * dvbapi.c: Interface to the DVB driver - * - * See the main source file 'vdr.c' for copyright information and - * how to reach the author. - * - * $Id: dvbapi.c 1.180 2002/05/20 10:58:33 kls Exp $ - */ - -#include "dvbapi.h" -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -extern "C" { -#define HAVE_BOOLEAN -#include <jpeglib.h> -} -#include <stdlib.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <unistd.h> -#include "config.h" -#include "recording.h" -#include "remux.h" -#include "ringbuffer.h" -#include "status.h" -#include "tools.h" -#include "videodir.h" - -#define DEV_VIDEO "/dev/video" -#define DEV_OST_OSD "/dev/ost/osd" -#define DEV_OST_FRONTEND "/dev/ost/frontend" -#define DEV_OST_SEC "/dev/ost/sec" -#define DEV_OST_DVR "/dev/ost/dvr" -#define DEV_OST_DEMUX "/dev/ost/demux" -#define DEV_OST_VIDEO "/dev/ost/video" -#define DEV_OST_AUDIO "/dev/ost/audio" - -// The size of the array used to buffer video data: -// (must be larger than MINVIDEODATA - see remux.h) -#define VIDEOBUFSIZE MEGABYTE(1) - -// The maximum size of a single frame: -#define MAXFRAMESIZE KILOBYTE(192) - -#define MAXFILESPERRECORDING 255 - -#define MINFREEDISKSPACE (512) // MB -#define DISKCHECKINTERVAL 100 // seconds - -#define INDEXFILESUFFIX "/index.vdr" -#define RECORDFILESUFFIX "/%03d.vdr" -#define RECORDFILESUFFIXLEN 20 // some additional bytes for safety... - -// The number of frames to back up when resuming an interrupted replay session: -#define RESUMEBACKUP (10 * FRAMESPERSEC) - -// The maximum time we wait before assuming that a recorded video data stream -// is broken: -#define MAXBROKENTIMEOUT 30 // seconds - -// The maximum time to wait before giving up while catching up on an index file: -#define MAXINDEXCATCHUP 2 // seconds - -// The default priority for non-primary DVB cards: -#define DEFAULTPRIORITY -2 - -#define CHECK(s) { if ((s) < 0) LOG_ERROR; } // used for 'ioctl()' calls - -#define FATALERRNO (errno != EAGAIN && errno != EINTR) - -typedef unsigned char uchar; - -const char *IndexToHMSF(int Index, bool WithFrame) -{ - static char buffer[16]; - int f = (Index % FRAMESPERSEC) + 1; - int s = (Index / FRAMESPERSEC); - int m = s / 60 % 60; - int h = s / 3600; - s %= 60; - snprintf(buffer, sizeof(buffer), WithFrame ? "%d:%02d:%02d.%02d" : "%d:%02d:%02d", h, m, s, f); - return buffer; -} - -int HMSFToIndex(const char *HMSF) -{ - int h, m, s, f = 0; - if (3 <= sscanf(HMSF, "%d:%d:%d.%d", &h, &m, &s, &f)) - return (h * 3600 + m * 60 + s) * FRAMESPERSEC + f - 1; - return 0; -} - -// --- cIndexFile ------------------------------------------------------------ - -class cIndexFile { -private: - struct tIndex { int offset; uchar type; uchar number; short reserved; }; - int f; - char *fileName; - int size, last; - tIndex *index; - cResumeFile resumeFile; - bool CatchUp(int Index = -1); -public: - cIndexFile(const char *FileName, bool Record); - ~cIndexFile(); - bool Ok(void) { return index != NULL; } - bool Write(uchar PictureType, uchar FileNumber, int FileOffset); - bool Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType = NULL, int *Length = NULL); - int GetNextIFrame(int Index, bool Forward, uchar *FileNumber = NULL, int *FileOffset = NULL, int *Length = NULL, bool StayOffEnd = false); - int Get(uchar FileNumber, int FileOffset); - int Last(void) { CatchUp(); return last; } - int GetResume(void) { return resumeFile.Read(); } - bool StoreResume(int Index) { return resumeFile.Save(Index); } - }; - -cIndexFile::cIndexFile(const char *FileName, bool Record) -:resumeFile(FileName) -{ - f = -1; - fileName = NULL; - size = 0; - last = -1; - index = NULL; - if (FileName) { - fileName = new char[strlen(FileName) + strlen(INDEXFILESUFFIX) + 1]; - if (fileName) { - strcpy(fileName, FileName); - char *pFileExt = fileName + strlen(fileName); - strcpy(pFileExt, INDEXFILESUFFIX); - int delta = 0; - if (access(fileName, R_OK) == 0) { - struct stat buf; - if (stat(fileName, &buf) == 0) { - delta = buf.st_size % sizeof(tIndex); - if (delta) { - delta = sizeof(tIndex) - delta; - esyslog("ERROR: invalid file size (%ld) in '%s'", buf.st_size, fileName); - } - last = (buf.st_size + delta) / sizeof(tIndex) - 1; - if (!Record && last >= 0) { - size = last + 1; - index = new tIndex[size]; - if (index) { - f = open(fileName, O_RDONLY); - if (f >= 0) { - if ((int)safe_read(f, index, buf.st_size) != buf.st_size) { - esyslog("ERROR: can't read from file '%s'", fileName); - delete index; - index = NULL; - close(f); - f = -1; - } - // we don't close f here, see CatchUp()! - } - else - LOG_ERROR_STR(fileName); - } - else - esyslog("ERROR: can't allocate %d bytes for index '%s'", size * sizeof(tIndex), fileName); - } - } - else - LOG_ERROR; - } - else if (!Record) - isyslog("missing index file %s", fileName); - if (Record) { - if ((f = open(fileName, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) >= 0) { - if (delta) { - esyslog("ERROR: padding index file with %d '0' bytes", delta); - while (delta--) - writechar(f, 0); - } - } - else - LOG_ERROR_STR(fileName); - } - } - else - esyslog("ERROR: can't copy file name '%s'", FileName); - } -} - -cIndexFile::~cIndexFile() -{ - if (f >= 0) - close(f); - delete fileName; - delete index; -} - -bool cIndexFile::CatchUp(int Index) -{ - if (index && f >= 0) { - for (int i = 0; i <= MAXINDEXCATCHUP && (Index < 0 || Index >= last); i++) { - struct stat buf; - if (fstat(f, &buf) == 0) { - int newLast = buf.st_size / sizeof(tIndex) - 1; - if (newLast > last) { - if (size <= newLast) { - size *= 2; - if (size <= newLast) - size = newLast + 1; - } - index = (tIndex *)realloc(index, size * sizeof(tIndex)); - if (index) { - int offset = (last + 1) * sizeof(tIndex); - int delta = (newLast - last) * sizeof(tIndex); - if (lseek(f, offset, SEEK_SET) == offset) { - if (safe_read(f, &index[last + 1], delta) != delta) { - esyslog("ERROR: can't read from index"); - delete index; - index = NULL; - close(f); - f = -1; - break; - } - last = newLast; - } - else - LOG_ERROR_STR(fileName); - } - else - esyslog("ERROR: can't realloc() index"); - } - } - else - LOG_ERROR_STR(fileName); - if (Index >= last) - sleep(1); - else - return true; - } - } - return false; -} - -bool cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset) -{ - if (f >= 0) { - tIndex i = { FileOffset, PictureType, FileNumber, 0 }; - if (safe_write(f, &i, sizeof(i)) < 0) { - LOG_ERROR_STR(fileName); - close(f); - f = -1; - return false; - } - last++; - } - return f >= 0; -} - -bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType, int *Length) -{ - if (index) { - CatchUp(Index); - if (Index >= 0 && Index <= last) { - *FileNumber = index[Index].number; - *FileOffset = index[Index].offset; - if (PictureType) - *PictureType = index[Index].type; - if (Length) { - int fn = index[Index + 1].number; - int fo = index[Index + 1].offset; - if (fn == *FileNumber) - *Length = fo - *FileOffset; - else - *Length = -1; // this means "everything up to EOF" (the buffer's Read function will act accordingly) - } - return true; - } - } - return false; -} - -int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *FileOffset, int *Length, bool StayOffEnd) -{ - if (index) { - CatchUp(); - int d = Forward ? 1 : -1; - for (;;) { - Index += d; - if (Index >= 0 && Index < last - ((Forward && StayOffEnd) ? 100 : 0)) { - if (index[Index].type == I_FRAME) { - if (FileNumber) - *FileNumber = index[Index].number; - else - FileNumber = &index[Index].number; - if (FileOffset) - *FileOffset = index[Index].offset; - else - FileOffset = &index[Index].offset; - if (Length) { - // all recordings end with a non-I_FRAME, so the following should be safe: - int fn = index[Index + 1].number; - int fo = index[Index + 1].offset; - if (fn == *FileNumber) - *Length = fo - *FileOffset; - else { - esyslog("ERROR: 'I' frame at end of file #%d", *FileNumber); - *Length = -1; - } - } - return Index; - } - } - else - break; - } - } - return -1; -} - -int cIndexFile::Get(uchar FileNumber, int FileOffset) -{ - if (index) { - CatchUp(); - //TODO implement binary search! - int i; - for (i = 0; i < last; i++) { - if (index[i].number > FileNumber || (index[i].number == FileNumber) && index[i].offset >= FileOffset) - break; - } - return i; - } - return -1; -} - -// --- cFileName ------------------------------------------------------------- - -class cFileName { -private: - int file; - int fileNumber; - char *fileName, *pFileNumber; - bool record; - bool blocking; -public: - cFileName(const char *FileName, bool Record, bool Blocking = false); - ~cFileName(); - const char *Name(void) { return fileName; } - int Number(void) { return fileNumber; } - int Open(void); - void Close(void); - int SetOffset(int Number, int Offset = 0); - int NextFile(void); - }; - -cFileName::cFileName(const char *FileName, bool Record, bool Blocking) -{ - file = -1; - fileNumber = 0; - record = Record; - blocking = Blocking; - // Prepare the file name: - fileName = new char[strlen(FileName) + RECORDFILESUFFIXLEN]; - if (!fileName) { - esyslog("ERROR: can't copy file name '%s'", fileName); - return; - } - strcpy(fileName, FileName); - pFileNumber = fileName + strlen(fileName); - SetOffset(1); -} - -cFileName::~cFileName() -{ - Close(); - delete fileName; -} - -int cFileName::Open(void) -{ - if (file < 0) { - int BlockingFlag = blocking ? 0 : O_NONBLOCK; - if (record) { - dsyslog("recording to '%s'", fileName); - file = OpenVideoFile(fileName, O_RDWR | O_CREAT | BlockingFlag); - if (file < 0) - LOG_ERROR_STR(fileName); - } - else { - if (access(fileName, R_OK) == 0) { - dsyslog("playing '%s'", fileName); - file = open(fileName, O_RDONLY | BlockingFlag); - if (file < 0) - LOG_ERROR_STR(fileName); - } - else if (errno != ENOENT) - LOG_ERROR_STR(fileName); - } - } - return file; -} - -void cFileName::Close(void) -{ - if (file >= 0) { - if ((record && CloseVideoFile(file) < 0) || (!record && close(file) < 0)) - LOG_ERROR_STR(fileName); - file = -1; - } -} - -int cFileName::SetOffset(int Number, int Offset) -{ - if (fileNumber != Number) - Close(); - if (0 < Number && Number <= MAXFILESPERRECORDING) { - fileNumber = Number; - sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber); - if (record) { - if (access(fileName, F_OK) == 0) // file exists, let's try next suffix - return SetOffset(Number + 1); - else if (errno != ENOENT) { // something serious has happened - LOG_ERROR_STR(fileName); - return -1; - } - // found a non existing file suffix - } - if (Open() >= 0) { - if (!record && Offset >= 0 && lseek(file, Offset, SEEK_SET) != Offset) { - LOG_ERROR_STR(fileName); - return -1; - } - } - return file; - } - esyslog("ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING); - return -1; -} - -int cFileName::NextFile(void) -{ - return SetOffset(fileNumber + 1); -} - -// --- cRecordBuffer --------------------------------------------------------- - -class cRecordBuffer : public cRingBufferLinear { -private: - cDvbApi *dvbApi; - cFileName fileName; - cIndexFile *index; - cRemux remux; - uchar pictureType; - int fileSize; - int videoDev; - int recordFile; - bool recording; - time_t lastDiskSpaceCheck; - bool RunningLowOnDiskSpace(void); - bool NextFile(void); -protected: - virtual void Input(void); - virtual void Output(void); -public: - cRecordBuffer(cDvbApi *DvbApi, const char *FileName, int VPid, int APid1, int APid2, int DPid1, int DPid2); - virtual ~cRecordBuffer(); - }; - -cRecordBuffer::cRecordBuffer(cDvbApi *DvbApi, const char *FileName, int VPid, int APid1, int APid2, int DPid1, int DPid2) -:cRingBufferLinear(VIDEOBUFSIZE, true) -,fileName(FileName, true) -,remux(VPid, APid1, APid2, DPid1, DPid2, true) -{ - dvbApi = DvbApi; - index = NULL; - pictureType = NO_PICTURE; - fileSize = 0; - recordFile = fileName.Open(); - recording = false; - lastDiskSpaceCheck = time(NULL); - if (!fileName.Name()) - return; - // Create the index file: - index = new cIndexFile(FileName, true); - if (!index) - esyslog("ERROR: can't allocate index"); - // let's continue without index, so we'll at least have the recording - videoDev = dvbApi->SetModeRecord(); - Start(); -} - -cRecordBuffer::~cRecordBuffer() -{ - Stop(); - dvbApi->SetModeNormal(true); - delete index; -} - -bool cRecordBuffer::RunningLowOnDiskSpace(void) -{ - if (time(NULL) > lastDiskSpaceCheck + DISKCHECKINTERVAL) { - int Free = FreeDiskSpaceMB(fileName.Name()); - lastDiskSpaceCheck = time(NULL); - if (Free < MINFREEDISKSPACE) { - dsyslog("low disk space (%d MB, limit is %d MB)", Free, MINFREEDISKSPACE); - return true; - } - } - return false; -} - -bool cRecordBuffer::NextFile(void) -{ - if (recordFile >= 0 && pictureType == I_FRAME) { // every file shall start with an I_FRAME - if (fileSize > MEGABYTE(Setup.MaxVideoFileSize) || RunningLowOnDiskSpace()) { - recordFile = fileName.NextFile(); - fileSize = 0; - } - } - return recordFile >= 0; -} - -void cRecordBuffer::Input(void) -{ - dsyslog("input thread started (pid=%d)", getpid()); - - uchar b[MINVIDEODATA]; - time_t t = time(NULL); - recording = true; - for (;;) { - if (cFile::FileReady(videoDev, 100)) { - int r = read(videoDev, b, sizeof(b)); - if (r > 0) { - uchar *p = b; - while (r > 0) { - int w = Put(p, r); - p += w; - r -= w; - if (r > 0) - usleep(1); // this keeps the CPU load low - } - t = time(NULL); - } - else if (r < 0) { - if (FATALERRNO) { - if (errno == EBUFFEROVERFLOW) // this error code is not defined in the library - esyslog("ERROR (%s,%d): DVB driver buffer overflow", __FILE__, __LINE__); - else { - LOG_ERROR; - break; - } - } - } - } - if (time(NULL) - t > MAXBROKENTIMEOUT) { - esyslog("ERROR: video data stream broken"); - cThread::EmergencyExit(true); - t = time(NULL); - } - if (!recording) - break; - } - - dsyslog("input thread ended (pid=%d)", getpid()); -} - -void cRecordBuffer::Output(void) -{ - dsyslog("output thread started (pid=%d)", getpid()); - - uchar b[MINVIDEODATA]; - int r = 0; - for (;;) { - int g = Get(b + r, sizeof(b) - r); - if (g > 0) - r += g; - if (r > 0) { - int Count = r, Result; - const uchar *p = remux.Process(b, Count, Result, &pictureType); - if (p) { - if (!Busy() && pictureType == I_FRAME) // finish the recording before the next 'I' frame - break; - if (NextFile()) { - if (index && pictureType != NO_PICTURE) - index->Write(pictureType, fileName.Number(), fileSize); - if (safe_write(recordFile, p, Result) < 0) { - LOG_ERROR_STR(fileName.Name()); - recording = false; - return; - } - fileSize += Result; - } - else - break; - } - if (Count > 0) { - r -= Count; - memmove(b, b + Count, r); - } - if (!recording) - break; - } - else - usleep(1); // this keeps the CPU load low - } - recording = false; - - dsyslog("output thread ended (pid=%d)", getpid()); -} - -// --- ReadFrame ------------------------------------------------------------- - -int ReadFrame(int f, uchar *b, int Length, int Max) -{ - if (Length == -1) - Length = Max; // this means we read up to EOF (see cIndex) - else if (Length > Max) { - esyslog("ERROR: frame larger than buffer (%d > %d)", Length, Max); - Length = Max; - } - int r = safe_read(f, b, Length); - if (r < 0) - LOG_ERROR; - return r; -} - -// --- cBackTrace ---------------------------------------------------------- - -#define AVG_FRAME_SIZE 15000 // an assumption about the average frame size -#define DVB_BUF_SIZE (256 * 1024) // an assumption about the dvb firmware buffer size -#define BACKTRACE_ENTRIES (DVB_BUF_SIZE / AVG_FRAME_SIZE + 20) // how many entries are needed to backtrace buffer contents - -class cBackTrace { -private: - int index[BACKTRACE_ENTRIES]; - int length[BACKTRACE_ENTRIES]; - int pos, num; -public: - cBackTrace(void); - void Clear(void); - void Add(int Index, int Length); - int Get(bool Forward); - }; - -cBackTrace::cBackTrace(void) -{ - Clear(); -} - -void cBackTrace::Clear(void) -{ - pos = num = 0; -} - -void cBackTrace::Add(int Index, int Length) -{ - index[pos] = Index; - length[pos] = Length; - if (++pos >= BACKTRACE_ENTRIES) - pos = 0; - if (num < BACKTRACE_ENTRIES) - num++; -} - -int cBackTrace::Get(bool Forward) -{ - int p = pos; - int n = num; - int l = DVB_BUF_SIZE + (Forward ? 0 : 256 * 1024); //XXX (256 * 1024) == DVB_BUF_SIZE ??? - int i = -1; - - while (n && l > 0) { - if (--p < 0) - p = BACKTRACE_ENTRIES - 1; - i = index[p] - 1; - l -= length[p]; - n--; - } - return i; -} - -// --- cPlayBuffer --------------------------------------------------------- - -#define MAX_VIDEO_SLOWMOTION 63 // max. arg to pass to VIDEO_SLOWMOTION // TODO is this value correct? - -class cPlayBuffer : public cRingBufferFrame { -private: - cBackTrace backTrace; -protected: - enum ePlayModes { pmPlay, pmPause, pmSlow, pmFast, pmStill }; - enum ePlayDirs { pdForward, pdBackward }; - static int Speeds[]; - cDvbApi *dvbApi; - int videoDev, audioDev; - cPipe dolbyDev; - int blockInput, blockOutput; - ePlayModes playMode; - ePlayDirs playDir; - int trickSpeed; - int readIndex, writeIndex; - bool canDoTrickMode; - bool canToggleAudioTrack; - bool skipAC3bytes; - uchar audioTrack; - void TrickSpeed(int Increment); - virtual void Empty(bool Block = false); - virtual void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00) {} - virtual void PlayExternalDolby(const uchar *b, int MaxLength); - virtual void Output(void); - void putFrame(cFrame *Frame); - void putFrame(unsigned char *Data, int Length, eFrameType Type = ftUnknown); -public: - cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev); - virtual ~cPlayBuffer(); - virtual void Pause(void); - virtual void Play(void); - virtual void Forward(void); - virtual void Backward(void); - virtual int SkipFrames(int Frames) { return -1; } - virtual void SkipSeconds(int Seconds) {} - virtual void Goto(int Position, bool Still = false) {} - virtual void GetIndex(int &Current, int &Total, bool SnapToIFrame = false) { Current = Total = -1; } - bool GetReplayMode(bool &Play, bool &Forward, int &Speed); - bool CanToggleAudioTrack(void) { return canToggleAudioTrack; }; - virtual void ToggleAudioTrack(void); - }; - -#define NORMAL_SPEED 4 // the index of the '1' entry in the following array -#define MAX_SPEEDS 3 // the offset of the maximum speed from normal speed in either direction -#define SPEED_MULT 12 // the speed multiplier -int cPlayBuffer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 }; - -cPlayBuffer::cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev) -:cRingBufferFrame(VIDEOBUFSIZE) -{ - dvbApi = DvbApi; - videoDev = VideoDev; - audioDev = AudioDev; - blockInput = blockOutput = false; - playMode = pmPlay; - playDir = pdForward; - trickSpeed = NORMAL_SPEED; - readIndex = writeIndex = -1; - canDoTrickMode = false; - canToggleAudioTrack = false; - skipAC3bytes = false; - audioTrack = 0xC0; -} - -cPlayBuffer::~cPlayBuffer() -{ -} - -void cPlayBuffer::PlayExternalDolby(const uchar *b, int MaxLength) -{ - if (cDvbApi::AudioCommand()) { - if (!dolbyDev && !dolbyDev.Open(cDvbApi::AudioCommand(), "w")) { - esyslog("ERROR: can't open pipe to audio command '%s'", cDvbApi::AudioCommand()); - return; - } - if (b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01) { - if (b[3] == 0xBD) { // dolby - int l = b[4] * 256 + b[5] + 6; - int written = b[8] + (skipAC3bytes ? 13 : 9); // skips the PES header - int n = min(l - written, MaxLength); - while (n > 0) { - int w = fwrite(&b[written], 1, n, dolbyDev); - if (w < 0) { - LOG_ERROR; - break; - } - n -= w; - written += w; - } - } - } - } -} - -void cPlayBuffer::Output(void) -{ - dsyslog("output thread started (pid=%d)", getpid()); - - while (Busy()) { - if (blockOutput) { - if (blockOutput > 1) - blockOutput = 1; - continue; - } - const cFrame *frame = Get(); - if (frame) { - if (frame->Type() == ftDolby) - PlayExternalDolby(frame->Data(), frame->Count()); - else { - StripAudioPackets((uchar *)frame->Data(), frame->Count(), (playMode == pmFast || playMode == pmSlow) ? 0x00 : audioTrack);//XXX - const uchar *p = frame->Data(); - int r = frame->Count(); - while (r > 0 && Busy() && !blockOutput) { - if (cFile::FileReadyForWriting(videoDev, 100)) { - int w = write(videoDev, p, r); - if (w > 0) { - p += w; - r -= w; - } - else if (w < 0 && FATALERRNO) { - LOG_ERROR; - Stop(); - return; - } - } - } - writeIndex = frame->Index(); - backTrace.Add(frame->Index(), frame->Count()); - } - Drop(frame); - } - } - - dsyslog("output thread ended (pid=%d)", getpid()); -} - -void cPlayBuffer::putFrame(cFrame *Frame) -{ - while (Busy() && !blockInput) { - if (Put(Frame)) - return; - } - delete Frame; // caller relies on frame being put, otherwise this would be a memory leak! -} - -void cPlayBuffer::putFrame(unsigned char *Data, int Length, eFrameType Type) -{ - putFrame(new cFrame(Data, Length, Type)); -} - -void cPlayBuffer::TrickSpeed(int Increment) -{ - int nts = trickSpeed + Increment; - if (Speeds[nts] == 1) { - trickSpeed = nts; - if (playMode == pmFast) - Play(); - else - Pause(); - } - else if (Speeds[nts]) { - trickSpeed = nts; - int Mult = (playMode == pmSlow && playDir == pdForward) ? 1 : SPEED_MULT; - int sp = (Speeds[nts] > 0) ? Mult / Speeds[nts] : -Speeds[nts] * Mult; - if (sp > MAX_VIDEO_SLOWMOTION) - sp = MAX_VIDEO_SLOWMOTION; - CHECK(ioctl(videoDev, VIDEO_SLOWMOTION, sp)); - } -} - -void cPlayBuffer::Empty(bool Block) -{ - if (!(blockInput || blockOutput)) { - blockInput = blockOutput = 2; - EnablePut(); - EnableGet(); - time_t t0 = time(NULL); - while ((blockInput > 1 || blockOutput > 1) && time(NULL) - t0 < 2) - usleep(1); - Lock(); - if ((readIndex = backTrace.Get(playDir == pdForward)) < 0) - readIndex = writeIndex; - cRingBufferFrame::Clear(); - CHECK(ioctl(videoDev, VIDEO_CLEAR_BUFFER)); - CHECK(ioctl(audioDev, AUDIO_CLEAR_BUFFER)); - } - if (!Block) { - blockInput = blockOutput = 0; - backTrace.Clear(); - Unlock(); - } -} - -void cPlayBuffer::Pause(void) -{ - if (playMode == pmPause || playMode == pmStill) - Play(); - else { - bool empty = (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)); - if (empty) - Empty(true); - CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false)); - CHECK(ioctl(videoDev, VIDEO_FREEZE)); - playMode = pmPause; - if (empty) - Empty(false); - } -} - -void cPlayBuffer::Play(void) -{ - if (playMode != pmPlay) { - bool empty = (playMode == pmStill || playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)); - if (empty) - Empty(true); - CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, true)); - CHECK(ioctl(videoDev, VIDEO_CONTINUE)); - playMode = pmPlay; - playDir = pdForward; - if (empty) - Empty(false); - } -} - -void cPlayBuffer::Forward(void) -{ - if (canDoTrickMode) { - switch (playMode) { - case pmFast: - if (Setup.MultiSpeedMode) { - TrickSpeed(playDir == pdForward ? 1 : -1); - break; - } - else if (playDir == pdForward) { - Play(); - break; - } - // run into pmPlay - case pmPlay: - Empty(true); - CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false)); - playMode = pmFast; - playDir = pdForward; - trickSpeed = NORMAL_SPEED; - TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS); - Empty(false); - break; - case pmSlow: - if (Setup.MultiSpeedMode) { - TrickSpeed(playDir == pdForward ? -1 : 1); - break; - } - else if (playDir == pdForward) { - Pause(); - break; - } - // run into pmPause - case pmStill: - case pmPause: - CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false)); - playMode = pmSlow; - playDir = pdForward; - trickSpeed = NORMAL_SPEED; - TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS); - break; - } - } -} - -void cPlayBuffer::Backward(void) -{ - if (canDoTrickMode) { - switch (playMode) { - case pmFast: - if (Setup.MultiSpeedMode) { - TrickSpeed(playDir == pdBackward ? 1 : -1); - break; - } - else if (playDir == pdBackward) { - Play(); - break; - } - // run into pmPlay - case pmPlay: - Empty(true); - CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false)); - playMode = pmFast; - playDir = pdBackward; - trickSpeed = NORMAL_SPEED; - TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS); - Empty(false); - break; - case pmSlow: - if (Setup.MultiSpeedMode) { - TrickSpeed(playDir == pdBackward ? -1 : 1); - break; - } - else if (playDir == pdBackward) { - Pause(); - break; - } - // run into pmPause - case pmStill: - case pmPause: - Empty(true); - CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false)); - playMode = pmSlow; - playDir = pdBackward; - trickSpeed = NORMAL_SPEED; - TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS); - Empty(false); - break; - } - } -} - -bool cPlayBuffer::GetReplayMode(bool &Play, bool &Forward, int &Speed) -{ - Play = (playMode == pmPlay || playMode == pmFast); - Forward = (playDir == pdForward); - if (playMode == pmFast || playMode == pmSlow) - Speed = Setup.MultiSpeedMode ? abs(trickSpeed - NORMAL_SPEED) : 0; - else - Speed = -1; - return true; -} - -void cPlayBuffer::ToggleAudioTrack(void) -{ - if (CanToggleAudioTrack()) { - audioTrack = (audioTrack == 0xC0) ? 0xC1 : 0xC0; - Empty(); - } -} - -// --- cReplayBuffer --------------------------------------------------------- - -class cReplayBuffer : public cPlayBuffer { -private: - cIndexFile *index; - cFileName fileName; - int replayFile; - bool eof; - bool NextFile(uchar FileNumber = 0, int FileOffset = -1); - void Close(void); - virtual void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00); - void DisplayFrame(uchar *b, int Length); - int Resume(void); - bool Save(void); -protected: - virtual void Input(void); -public: - cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const char *FileName); - virtual ~cReplayBuffer(); - virtual int SkipFrames(int Frames); - virtual void SkipSeconds(int Seconds); - virtual void Goto(int Position, bool Still = false); - virtual void GetIndex(int &Current, int &Total, bool SnapToIFrame = false); - }; - -cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const char *FileName) -:cPlayBuffer(DvbApi, VideoDev, AudioDev) -,fileName(FileName, false) -{ - index = NULL; - replayFile = fileName.Open(); - eof = false; - if (!fileName.Name()) - return; - // Create the index file: - index = new cIndexFile(FileName, false); - if (!index) - esyslog("ERROR: can't allocate index"); - else if (!index->Ok()) { - delete index; - index = NULL; - } - canDoTrickMode = index != NULL; - dvbApi->SetModeReplay(); - Start(); -} - -cReplayBuffer::~cReplayBuffer() -{ - Stop(); - Save(); - Close(); - dvbApi->SetModeNormal(false); - delete index; -} - -void cReplayBuffer::Input(void) -{ - dsyslog("input thread started (pid=%d)", getpid()); - - readIndex = Resume(); - if (readIndex >= 0) - isyslog("resuming replay at index %d (%s)", readIndex, IndexToHMSF(readIndex, true)); - - uchar b[MAXFRAMESIZE]; - while (Busy() && (blockInput || NextFile())) { - if (blockInput) { - if (blockInput > 1) - blockInput = 1; - continue; - } - if (playMode != pmStill) { - int r = 0; - if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) { - uchar FileNumber; - int FileOffset, Length; - int Index = index->GetNextIFrame(readIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length, true); - if (Index >= 0) { - if (!NextFile(FileNumber, FileOffset)) - break; - } - else { - // can't call Play() here, because those functions may only be - // called from the foreground thread - and we also don't need - // to empty the buffer here - CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, true)); - CHECK(ioctl(videoDev, VIDEO_CONTINUE)); - playMode = pmPlay; - playDir = pdForward; - continue; - } - readIndex = Index; - r = ReadFrame(replayFile, b, Length, sizeof(b)); - // must call StripAudioPackets() here because the buffer is not emptied - // when falling back from "fast forward" to "play" (see above) - StripAudioPackets(b, r); - } - else if (index) { - uchar FileNumber; - int FileOffset, Length; - readIndex++; - if (!(index->Get(readIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset))) - break; - r = ReadFrame(replayFile, b, Length, sizeof(b)); - } - else // allows replay even if the index file is missing - r = read(replayFile, b, sizeof(b)); - if (r > 0) - putFrame(new cFrame(b, r, ftUnknown, readIndex)); - else if (r == 0) - eof = true; - else if (r < 0 && FATALERRNO) { - LOG_ERROR; - break; - } - } - else//XXX - usleep(1); // this keeps the CPU load low - } - - dsyslog("input thread ended (pid=%d)", getpid()); -} - -void cReplayBuffer::StripAudioPackets(uchar *b, int Length, uchar Except) -{ - if (canDoTrickMode) { - for (int i = 0; i < Length - 6; i++) { - if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) { - uchar c = b[i + 3]; - int l = b[i + 4] * 256 + b[i + 5] + 6; - switch (c) { - case 0xBD: // dolby - if (Except) - PlayExternalDolby(&b[i], Length - i); - // continue with deleting the data - otherwise it disturbs DVB replay - case 0xC0 ... 0xC1: // audio - if (c == 0xC1) - canToggleAudioTrack = true; - if (!Except || c != Except) { - int n = l; - for (int j = i; j < Length && n--; j++) - b[j] = 0x00; - } - break; - case 0xE0 ... 0xEF: // video - break; - default: - //esyslog("ERROR: unexpected packet id %02X", c); - l = 0; - } - if (l) - i += l - 1; // the loop increments, too! - } - /*XXX - else - esyslog("ERROR: broken packet header"); - XXX*/ - } - } -} - -void cReplayBuffer::DisplayFrame(uchar *b, int Length) -{ - StripAudioPackets(b, Length); - CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false)); - CHECK(ioctl(audioDev, AUDIO_SET_MUTE, true)); -/* Using the VIDEO_STILLPICTURE ioctl call would be the - correct way to display a still frame, but unfortunately this - doesn't work with frames from VDR. So let's do pretty much the - same here as in DVB/driver/dvb.c's play_iframe() - I have absolutely - no idea why it works this way, but doesn't work with VIDEO_STILLPICTURE. - If anybody ever finds out what could be changed so that VIDEO_STILLPICTURE - could be used, please let me know! - kls 2002-03-23 -*/ -//#define VIDEO_STILLPICTURE_WORKS_WITH_VDR_FRAMES -#ifdef VIDEO_STILLPICTURE_WORKS_WITH_VDR_FRAMES - videoDisplayStillPicture sp = { (char *)b, Length }; - CHECK(ioctl(videoDev, VIDEO_STILLPICTURE, &sp)); -#else -#define MIN_IFRAME 400000 - for (int i = MIN_IFRAME / Length + 1; i > 0; i--) { - safe_write(videoDev, b, Length); - usleep(1); // allows the buffer to be displayed in case the progress display is active - } -#endif -} - -void cReplayBuffer::Close(void) -{ - if (replayFile >= 0) { - fileName.Close(); - replayFile = -1; - } -} - -int cReplayBuffer::Resume(void) -{ - if (index) { - int Index = index->GetResume(); - if (Index >= 0) { - uchar FileNumber; - int FileOffset; - if (index->Get(Index, &FileNumber, &FileOffset) && NextFile(FileNumber, FileOffset)) - return Index; - } - } - return -1; -} - -bool cReplayBuffer::Save(void) -{ - if (index) { - int Index = writeIndex; - if (Index >= 0) { - Index -= RESUMEBACKUP; - if (Index > 0) - Index = index->GetNextIFrame(Index, false); - else - Index = 0; - if (Index >= 0) - return index->StoreResume(Index); - } - } - return false; -} - -int cReplayBuffer::SkipFrames(int Frames) -{ - if (index && Frames) { - int Current, Total; - GetIndex(Current, Total, true); - int OldCurrent = Current; - Current = index->GetNextIFrame(Current + Frames, Frames > 0); - return Current >= 0 ? Current : OldCurrent; - } - return -1; -} - -void cReplayBuffer::SkipSeconds(int Seconds) -{ - if (index && Seconds) { - Empty(true); - int Index = writeIndex; - if (Index >= 0) { - Index = max(Index + Seconds * FRAMESPERSEC, 0); - if (Index > 0) - Index = index->GetNextIFrame(Index, false, NULL, NULL, NULL, true); - if (Index >= 0) - readIndex = writeIndex = Index - 1; // Input() will first increment it! - } - Empty(false); - Play(); - } -} - -void cReplayBuffer::Goto(int Index, bool Still) -{ - if (index) { - Empty(true); - if (++Index <= 0) - Index = 1; // not '0', to allow GetNextIFrame() below to work! - uchar FileNumber; - int FileOffset, Length; - Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length); - if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) { - uchar b[MAXFRAMESIZE]; - int r = ReadFrame(replayFile, b, Length, sizeof(b)); - if (r > 0) { - if (playMode == pmPause) - CHECK(ioctl(videoDev, VIDEO_CONTINUE)); - DisplayFrame(b, r); - } - playMode = pmStill; - } - readIndex = writeIndex = Index; - Empty(false); - } -} - -void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame) -{ - if (index) { - if (playMode == pmStill) - Current = max(readIndex, 0); - else { - Current = max(writeIndex, 0); - if (SnapToIFrame) { - int i1 = index->GetNextIFrame(Current + 1, false); - int i2 = index->GetNextIFrame(Current, true); - Current = (abs(Current - i1) <= abs(Current - i2)) ? i1 : i2; - } - } - Total = index->Last(); - } - else - Current = Total = -1; -} - -bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset) -{ - if (FileNumber > 0) - replayFile = fileName.SetOffset(FileNumber, FileOffset); - else if (replayFile >= 0 && eof) { - Close(); - replayFile = fileName.NextFile(); - } - eof = false; - return replayFile >= 0; -} - -// --- cTransferBuffer ------------------------------------------------------- - -class cTransferBuffer : public cRingBufferLinear { -private: - cDvbApi *dvbApi; - int fromDevice, toDevice; - bool gotBufferReserve; - cRemux remux; -protected: - virtual void Input(void); - virtual void Output(void); -public: - cTransferBuffer(cDvbApi *DvbApi, int ToDevice, int VPid, int APid); - virtual ~cTransferBuffer(); - void SetAudioPid(int APid); - }; - -cTransferBuffer::cTransferBuffer(cDvbApi *DvbApi, int ToDevice, int VPid, int APid) -:cRingBufferLinear(VIDEOBUFSIZE, true) -,remux(VPid, APid, 0, 0, 0) -{ - dvbApi = DvbApi; - fromDevice = dvbApi->SetModeRecord(); - toDevice = ToDevice; - gotBufferReserve = false; - Start(); -} - -cTransferBuffer::~cTransferBuffer() -{ - Stop(); - dvbApi->SetModeNormal(true); -} - -void cTransferBuffer::SetAudioPid(int APid) -{ - Clear(); - //XXX we may need to have access to the audio device, too, in order to clear it - CHECK(ioctl(toDevice, VIDEO_CLEAR_BUFFER)); - gotBufferReserve = false; - remux.SetAudioPid(APid); -} - -void cTransferBuffer::Input(void) -{ - dsyslog("input thread started (pid=%d)", getpid()); - - uchar b[MINVIDEODATA]; - int n = 0; - while (Busy()) { - if (cFile::FileReady(fromDevice, 100)) { - int r = read(fromDevice, b + n, sizeof(b) - n); - if (r > 0) { - n += r; - int Count = n, Result; - const uchar *p = remux.Process(b, Count, Result); - if (p) { - while (Result > 0 && Busy()) { - int w = Put(p, Result); - p += w; - Result -= w; - } - } - if (Count > 0) { - n -= Count; - memmove(b, b + Count, n); - } - } - else if (r < 0) { - if (FATALERRNO) { - if (errno == EBUFFEROVERFLOW) // this error code is not defined in the library - esyslog("ERROR (%s,%d): DVB driver buffer overflow", __FILE__, __LINE__); - else { - LOG_ERROR; - break; - } - } - } - } - } - - dsyslog("input thread ended (pid=%d)", getpid()); -} - -void cTransferBuffer::Output(void) -{ - dsyslog("output thread started (pid=%d)", getpid()); - - uchar b[MINVIDEODATA]; - while (Busy()) { - if (!gotBufferReserve) { - if (Available() < MAXFRAMESIZE) { - usleep(100000); // allow the buffer to collect some reserve - continue; - } - else - gotBufferReserve = true; - } - int r = Get(b, sizeof(b)); - if (r > 0) { - uchar *p = b; - while (r > 0 && Busy() && cFile::FileReadyForWriting(toDevice, 100)) { - int w = write(toDevice, p, r); - if (w > 0) { - p += w; - r -= w; - } - else if (w < 0 && FATALERRNO) { - LOG_ERROR; - Stop(); - return; - } - } - } - else - usleep(1); // this keeps the CPU load low - } - - dsyslog("output thread ended (pid=%d)", getpid()); -} - -// --- cCuttingBuffer -------------------------------------------------------- - -class cCuttingBuffer : public cThread { -private: - const char *error; - bool active; - int fromFile, toFile; - cFileName *fromFileName, *toFileName; - cIndexFile *fromIndex, *toIndex; - cMarks fromMarks, toMarks; -protected: - virtual void Action(void); -public: - cCuttingBuffer(const char *FromFileName, const char *ToFileName); - virtual ~cCuttingBuffer(); - const char *Error(void) { return error; } - }; - -cCuttingBuffer::cCuttingBuffer(const char *FromFileName, const char *ToFileName) -{ - error = NULL; - active = false; - fromFile = toFile = -1; - fromFileName = toFileName = NULL; - fromIndex = toIndex = NULL; - if (fromMarks.Load(FromFileName) && fromMarks.Count()) { - fromFileName = new cFileName(FromFileName, false, true); - toFileName = new cFileName(ToFileName, true, true); - fromIndex = new cIndexFile(FromFileName, false); - toIndex = new cIndexFile(ToFileName, true); - toMarks.Load(ToFileName); // doesn't actually load marks, just sets the file name - Start(); - } - else - esyslog("no editing marks found for %s", FromFileName); -} - -cCuttingBuffer::~cCuttingBuffer() -{ - active = false; - Cancel(3); - delete fromFileName; - delete toFileName; - delete fromIndex; - delete toIndex; -} - -void cCuttingBuffer::Action(void) -{ - dsyslog("video cutting thread started (pid=%d)", getpid()); - - cMark *Mark = fromMarks.First(); - if (Mark) { - fromFile = fromFileName->Open(); - toFile = toFileName->Open(); - active = fromFile >= 0 && toFile >= 0; - int Index = Mark->position; - Mark = fromMarks.Next(Mark); - int FileSize = 0; - int CurrentFileNumber = 0; - int LastIFrame = 0; - toMarks.Add(0); - toMarks.Save(); - uchar buffer[MAXFRAMESIZE]; - while (active) { - uchar FileNumber; - int FileOffset, Length; - uchar PictureType; - - // Make sure there is enough disk space: - - AssertFreeDiskSpace(); - - // Read one frame: - - if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &PictureType, &Length)) { - if (FileNumber != CurrentFileNumber) { - fromFile = fromFileName->SetOffset(FileNumber, FileOffset); - CurrentFileNumber = FileNumber; - } - if (fromFile >= 0) { - int len = ReadFrame(fromFile, buffer, Length, sizeof(buffer)); - if (len < 0) { - error = "ReadFrame"; - break; - } - if (len != Length) { - CurrentFileNumber = 0; // this re-syncs in case the frame was larger than the buffer - Length = len; - } - } - else { - error = "fromFile"; - break; - } - } - else - break; - - // Write one frame: - - if (PictureType == I_FRAME) { // every file shall start with an I_FRAME - if (!Mark) // edited version shall end before next I-frame - break; - if (FileSize > MEGABYTE(Setup.MaxVideoFileSize)) { - toFile = toFileName->NextFile(); - if (toFile < 0) { - error = "toFile 1"; - break; - } - FileSize = 0; - } - LastIFrame = 0; - } - if (safe_write(toFile, buffer, Length) < 0) { - error = "safe_write"; - break; - } - if (!toIndex->Write(PictureType, toFileName->Number(), FileSize)) { - error = "toIndex"; - break; - } - FileSize += Length; - if (!LastIFrame) - LastIFrame = toIndex->Last(); - - // Check editing marks: - - if (Mark && Index >= Mark->position) { - Mark = fromMarks.Next(Mark); - toMarks.Add(LastIFrame); - if (Mark) - toMarks.Add(toIndex->Last() + 1); - toMarks.Save(); - if (Mark) { - Index = Mark->position; - Mark = fromMarks.Next(Mark); - CurrentFileNumber = 0; // triggers SetOffset before reading next frame - if (Setup.SplitEditedFiles) { - toFile = toFileName->NextFile(); - if (toFile < 0) { - error = "toFile 2"; - break; - } - FileSize = 0; - } - } - // the 'else' case (i.e. 'final end mark reached') is handled above - // in 'Write one frame', so that the edited version will end right - // before the next I-frame. - } - } - } - else - esyslog("no editing marks found!"); - dsyslog("end video cutting thread"); -} - -// --- cVideoCutter ---------------------------------------------------------- - -char *cVideoCutter::editedVersionName = NULL; -cCuttingBuffer *cVideoCutter::cuttingBuffer = NULL; -bool cVideoCutter::error = false; -bool cVideoCutter::ended = false; - -bool cVideoCutter::Start(const char *FileName) -{ - if (!cuttingBuffer) { - error = false; - ended = false; - cRecording Recording(FileName); - const char *evn = Recording.PrefixFileName('%'); - if (evn && RemoveVideoFile(evn) && MakeDirs(evn, true)) { - // XXX this can be removed once RenameVideoFile() follows symlinks (see videodir.c) - // remove a possible deleted recording with the same name to avoid symlink mixups: - char *s = strdup(evn); - char *e = strrchr(s, '.'); - if (e) { - if (strcmp(e, ".rec") == 0) { - strcpy(e, ".del"); - RemoveVideoFile(s); - } - } - delete s; - // XXX - editedVersionName = strdup(evn); - Recording.WriteSummary(); - cuttingBuffer = new cCuttingBuffer(FileName, editedVersionName); - return true; - } - } - return false; -} - -void cVideoCutter::Stop(void) -{ - bool Interrupted = cuttingBuffer && cuttingBuffer->Active(); - const char *Error = cuttingBuffer ? cuttingBuffer->Error() : NULL; - delete cuttingBuffer; - cuttingBuffer = NULL; - if ((Interrupted || Error) && editedVersionName) { - if (Interrupted) - isyslog("editing process has been interrupted"); - if (Error) - esyslog("ERROR: '%s' during editing process", Error); - RemoveVideoFile(editedVersionName); //XXX what if this file is currently being replayed? - } -} - -bool cVideoCutter::Active(void) -{ - if (cuttingBuffer) { - if (cuttingBuffer->Active()) - return true; - error = cuttingBuffer->Error(); - Stop(); - if (!error) - cRecordingUserCommand::InvokeCommand(RUC_EDITEDRECORDING, editedVersionName); - delete editedVersionName; - editedVersionName = NULL; - ended = true; - } - return false; -} - -bool cVideoCutter::Error(void) -{ - bool result = error; - error = false; - return result; -} - -bool cVideoCutter::Ended(void) -{ - bool result = ended; - ended = false; - return result; -} - -// --- cDvbApi --------------------------------------------------------------- - -static const char *OstName(const char *Name, int n) -{ - static char buffer[_POSIX_PATH_MAX]; - snprintf(buffer, sizeof(buffer), "%s%d", Name, n); - return buffer; -} - -static int OstOpen(const char *Name, int n, int Mode, bool ReportError = false) -{ - const char *FileName = OstName(Name, n); - int fd = open(FileName, Mode); - if (fd < 0 && ReportError) - LOG_ERROR_STR(FileName); - return fd; -} - -int cDvbApi::NumDvbApis = 0; -int cDvbApi::useDvbApi = 0; -cDvbApi *cDvbApi::dvbApi[MAXDVBAPI] = { NULL }; -cDvbApi *cDvbApi::PrimaryDvbApi = NULL; -char *cDvbApi::audioCommand = NULL; - -cDvbApi::cDvbApi(int n) -{ - frontendType = FrontendType(-1); // don't know how else to initialize this - there is no FE_UNKNOWN - vPid = aPid1 = aPid2 = dPid1 = dPid2 = 0; - siProcessor = NULL; - recordBuffer = NULL; - replayBuffer = NULL; - transferBuffer = NULL; - transferringFromDvbApi = NULL; - ca = -1; - priority = DEFAULTPRIORITY; - cardIndex = n; - - // Devices that are only present on DVB-C or DVB-S cards: - - fd_frontend = OstOpen(DEV_OST_FRONTEND, n, O_RDWR); - fd_sec = OstOpen(DEV_OST_SEC, n, O_RDWR); - - // Devices that all DVB cards must have: - - fd_demuxv = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); - fd_demuxa1 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); - fd_demuxa2 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); - fd_demuxd1 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); - fd_demuxd2 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); - fd_demuxt = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); - - // Devices not present on "budget" cards: - - fd_osd = OstOpen(DEV_OST_OSD, n, O_RDWR); - fd_video = OstOpen(DEV_OST_VIDEO, n, O_RDWR | O_NONBLOCK); - fd_audio = OstOpen(DEV_OST_AUDIO, n, O_RDWR | O_NONBLOCK); - - // Devices that will be dynamically opened and closed when necessary: - - fd_dvr = -1; - - // Video format: - - SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3); - - // We only check the devices that must be present - the others will be checked before accessing them: - - if (fd_frontend >= 0 && fd_demuxv >= 0 && fd_demuxa1 >= 0 && fd_demuxa2 >= 0 && fd_demuxd1 >= 0 && fd_demuxd2 >= 0 && fd_demuxt >= 0) { - siProcessor = new cSIProcessor(OstName(DEV_OST_DEMUX, n)); - FrontendInfo feinfo; - CHECK(ioctl(fd_frontend, FE_GET_INFO, &feinfo)); - frontendType = feinfo.type; - } - else - esyslog("ERROR: can't open video device %d", n); - - currentChannel = 1; - mute = false; - volume = Setup.CurrentVolume; -} - -cDvbApi::~cDvbApi() -{ - delete siProcessor; - StopReplay(); - StopRecord(); - StopTransfer(); - // We're not explicitly closing any device files here, since this sometimes - // caused segfaults. Besides, the program is about to terminate anyway... -} - -void cDvbApi::SetUseDvbApi(int n) -{ - if (n < MAXDVBAPI) - useDvbApi |= (1 << n); -} - -bool cDvbApi::SetPrimaryDvbApi(int n) -{ - n--; - if (0 <= n && n < NumDvbApis && dvbApi[n]) { - isyslog("setting primary DVB to %d", n + 1); - PrimaryDvbApi = dvbApi[n]; - return true; - } - esyslog("invalid DVB interface: %d", n + 1); - return false; -} - -int cDvbApi::CanShift(int Ca, int Priority, int UsedCards) -{ - // Test whether a recording on this DVB device can be shifted to another one - // in order to perform a new recording with the given Ca and Priority on this device: - int ShiftLevel = -1; // default means this device can't be shifted - if (UsedCards & (1 << CardIndex()) != 0) - return ShiftLevel; // otherwise we would get into a loop - if (Recording()) { - if (ProvidesCa(Ca) // this device provides the requested Ca - && (Ca != this->Ca() // the requested Ca is different from the one currently used... - || Priority > this->Priority())) { // ...or the request comes from a higher priority - cDvbApi *d = NULL; - int Provides[MAXDVBAPI]; - UsedCards |= (1 << CardIndex()); - for (int i = 0; i < NumDvbApis; i++) { - if ((Provides[i] = dvbApi[i]->ProvidesCa(this->Ca())) != 0) { // this device is basicly able to do the job - if (dvbApi[i] != this) { // it is not _this_ device - int sl = dvbApi[i]->CanShift(this->Ca(), Priority, UsedCards); // this is the original Priority! - if (sl >= 0 && (ShiftLevel < 0 || sl < ShiftLevel)) { - d = dvbApi[i]; - ShiftLevel = sl; - } - } - } - } - if (ShiftLevel >= 0) - ShiftLevel++; // adds the device's own shift - } - } - else if (Priority > this->Priority()) - ShiftLevel = 0; // no shifting necessary, this device can do the job - return ShiftLevel; -} - -cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority) -{ - cDvbApi *d = NULL; - int Provides[MAXDVBAPI]; - // Check which devices provide Ca: - for (int i = 0; i < NumDvbApis; i++) { - if ((Provides[i] = dvbApi[i]->ProvidesCa(Ca)) != 0) { // this device is basicly able to do the job - if (Priority > dvbApi[i]->Priority() // Priority is high enough to use this device - && (!d // we don't have a device yet, or... - || dvbApi[i]->Priority() < d->Priority() // ...this one has an even lower Priority - || (dvbApi[i]->Priority() == d->Priority() // ...same Priority... - && Provides[i] < Provides[d->CardIndex()]))) // ...but this one provides fewer Ca values - d = dvbApi[i]; - } - } - if (!d && Ca > MAXDVBAPI) { - // We didn't find one the easy way, so now we have to try harder: - int ShiftLevel = -1; - for (int i = 0; i < NumDvbApis; i++) { - if (Provides[i]) { // this device is basicly able to do the job, but for some reason we didn't get it above - int sl = dvbApi[i]->CanShift(Ca, Priority); // asks this device to shift its job to another device - if (sl >= 0 && (ShiftLevel < 0 || sl < ShiftLevel)) { - d = dvbApi[i]; // found one that can be shifted with the fewest number of subsequent shifts - ShiftLevel = sl; - } - } - } - } - return d; -} - -void cDvbApi::SetCaCaps(void) -{ - for (int d = 0; d < NumDvbApis; d++) { - for (int i = 0; i < MAXCACAPS; i++) - dvbApi[d]->caCaps[i] = Setup.CaCaps[dvbApi[d]->CardIndex()][i]; - } -} - -int cDvbApi::ProvidesCa(int Ca) -{ - if (Ca == CardIndex() + 1) - return 1; // exactly _this_ card was requested - if (Ca && Ca <= MAXDVBAPI) - return 0; // a specific card was requested, but not _this_ one - int result = Ca ? 0 : 1; // by default every card can provide FTA - int others = Ca ? 1 : 0; - for (int i = 0; i < MAXCACAPS; i++) { - if (caCaps[i]) { - if (caCaps[i] == Ca) - result = 1; - else - others++; - } - } - return result ? result + others : 0; -} - -bool cDvbApi::Probe(const char *FileName) -{ - if (access(FileName, F_OK) == 0) { - dsyslog("probing %s", FileName); - int f = open(FileName, O_RDONLY); - if (f >= 0) { - close(f); - return true; - } - else if (errno != ENODEV && errno != EINVAL) - LOG_ERROR_STR(FileName); - } - else if (errno != ENOENT) - LOG_ERROR_STR(FileName); - return false; -} - -bool cDvbApi::Initialize(void) -{ - NumDvbApis = 0; - for (int i = 0; i < MAXDVBAPI; i++) { - if (useDvbApi == 0 || (useDvbApi & (1 << i)) != 0) { - if (Probe(OstName(DEV_OST_FRONTEND, i))) - dvbApi[NumDvbApis++] = new cDvbApi(i); - else - break; - } - } - PrimaryDvbApi = dvbApi[0]; - if (NumDvbApis > 0) - isyslog("found %d video device%s", NumDvbApis, NumDvbApis > 1 ? "s" : ""); - else - esyslog("ERROR: no video device found, giving up!"); - SetCaCaps(); - return NumDvbApis > 0; -} - -void cDvbApi::Shutdown(void) -{ - for (int i = 0; i < NumDvbApis; i++) { - delete dvbApi[i]; - dvbApi[i] = NULL; - } - PrimaryDvbApi = NULL; -} - -bool cDvbApi::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY) -{ - int videoDev = OstOpen(DEV_VIDEO, CardIndex(), O_RDWR, true); - if (videoDev >= 0) { - int result = 0; - struct video_mbuf mbuf; - result |= ioctl(videoDev, VIDIOCGMBUF, &mbuf); - if (result == 0) { - int msize = mbuf.size; - unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0); - if (mem && mem != (unsigned char *)-1) { - // set up the size and RGB - struct video_capability vc; - result |= ioctl(videoDev, VIDIOCGCAP, &vc); - struct video_mmap vm; - vm.frame = 0; - if ((SizeX > 0) && (SizeX <= vc.maxwidth) && - (SizeY > 0) && (SizeY <= vc.maxheight)) { - vm.width = SizeX; - vm.height = SizeY; - } - else { - vm.width = vc.maxwidth; - vm.height = vc.maxheight; - } - vm.format = VIDEO_PALETTE_RGB24; - result |= ioctl(videoDev, VIDIOCMCAPTURE, &vm); - result |= ioctl(videoDev, VIDIOCSYNC, &vm.frame); - // make RGB out of BGR: - int memsize = vm.width * vm.height; - unsigned char *mem1 = mem; - for (int i = 0; i < memsize; i++) { - unsigned char tmp = mem1[2]; - mem1[2] = mem1[0]; - mem1[0] = tmp; - mem1 += 3; - } - - if (Quality < 0) - Quality = 255; //XXX is this 'best'??? - - isyslog("grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height); - FILE *f = fopen(FileName, "wb"); - if (f) { - if (Jpeg) { - // write JPEG file: - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cinfo); - jpeg_stdio_dest(&cinfo, f); - cinfo.image_width = vm.width; - cinfo.image_height = vm.height; - cinfo.input_components = 3; - cinfo.in_color_space = JCS_RGB; - - jpeg_set_defaults(&cinfo); - jpeg_set_quality(&cinfo, Quality, true); - jpeg_start_compress(&cinfo, true); - - int rs = vm.width * 3; - JSAMPROW rp[vm.height]; - for (int k = 0; k < vm.height; k++) - rp[k] = &mem[rs * k]; - jpeg_write_scanlines(&cinfo, rp, vm.height); - jpeg_finish_compress(&cinfo); - jpeg_destroy_compress(&cinfo); - } - else { - // write PNM file: - if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 || - fwrite(mem, vm.width * vm.height * 3, 1, f) < 0) { - LOG_ERROR_STR(FileName); - result |= 1; - } - } - fclose(f); - } - else { - LOG_ERROR_STR(FileName); - result |= 1; - } - munmap(mem, msize); - } - else - result |= 1; - } - close(videoDev); - return result == 0; - } - return false; -} - -int cDvbApi::Priority(void) -{ - return (this == PrimaryDvbApi && !Recording()) ? Setup.PrimaryLimit - 1 : priority; -} - -int cDvbApi::SetModeRecord(void) -{ - // Sets up the DVB device for recording - - SetPids(true); - if (fd_dvr >= 0) - close(fd_dvr); - fd_dvr = OstOpen(DEV_OST_DVR, CardIndex(), O_RDONLY | O_NONBLOCK); - if (fd_dvr < 0) - LOG_ERROR; - return fd_dvr; -} - -void cDvbApi::SetModeReplay(void) -{ - // Sets up the DVB device for replay - - if (fd_video >= 0 && fd_audio >= 0) { - if (siProcessor) - siProcessor->SetStatus(false); - CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); - CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY)); - CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); - CHECK(ioctl(fd_audio, AUDIO_PLAY)); - CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY)); - CHECK(ioctl(fd_video, VIDEO_PLAY)); - } -} - -void cDvbApi::SetModeNormal(bool FromRecording) -{ - // Puts the DVB device back into "normal" viewing mode (after replay or recording) - - if (FromRecording) { - close(fd_dvr); - fd_dvr = -1; - SetPids(false); - } - else { - if (fd_video >= 0 && fd_audio >= 0) { - CHECK(ioctl(fd_video, VIDEO_STOP, true)); - CHECK(ioctl(fd_audio, AUDIO_STOP, true)); - CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); - CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); - CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX)); - CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX)); - CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); - CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false)); - if (siProcessor) - siProcessor->SetStatus(true); - } - } -} - -void cDvbApi::SetVideoFormat(videoFormat_t Format) -{ - if (fd_video >= 0) - CHECK(ioctl(fd_video, VIDEO_SET_FORMAT, Format)); -} - -bool cDvbApi::SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output) -{ - if (Pid) { - CHECK(ioctl(fd, DMX_STOP)); - if (Pid != 0x1FFF) { - dmxPesFilterParams pesFilterParams; - pesFilterParams.pid = Pid; - pesFilterParams.input = DMX_IN_FRONTEND; - pesFilterParams.output = Output; - pesFilterParams.pesType = PesType; - pesFilterParams.flags = DMX_IMMEDIATE_START; - if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { - LOG_ERROR; - return false; - } - } - } - return true; -} - -bool cDvbApi::SetPids(bool ForRecording) -{ - return SetVpid(vPid, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) && - SetApid1(aPid1, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) && - SetApid2(ForRecording ? aPid2 : 0, DMX_OUT_TS_TAP) && (!Setup.RecordDolbyDigital || - SetDpid1(ForRecording ? dPid1 : 0, DMX_OUT_TS_TAP) && - SetDpid2(ForRecording ? dPid2 : 0, DMX_OUT_TS_TAP)); -} - -eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int Frequency, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr) -{ - StopTransfer(); - StopReplay(); - - cStatusMonitor::MsgChannelSwitch(this, 0); - - // Must set this anyway to avoid getting stuck when switching through - // channels with 'Up' and 'Down' keys: - currentChannel = ChannelNumber; - vPid = Vpid; - aPid1 = Apid1; - aPid2 = Apid2; - dPid1 = Dpid1; - dPid2 = Dpid2; - - // Avoid noise while switching: - - if (fd_video >= 0 && fd_audio >= 0) { - CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true)); - CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); - CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); - CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); - } - - // Stop setting system time: - - if (siProcessor) - siProcessor->SetCurrentTransponder(0); - - // If this card can't receive this channel, we must not actually switch - // the channel here, because that would irritate the driver when we - // start replaying in Transfer Mode immediately after switching the channel: - bool NeedsTransferMode = (this == PrimaryDvbApi && !ProvidesCa(Ca)); - - if (!NeedsTransferMode) { - - // Turn off current PIDs: - - SetVpid( 0x1FFF, DMX_OUT_DECODER); - SetApid1(0x1FFF, DMX_OUT_DECODER); - SetApid2(0x1FFF, DMX_OUT_DECODER); - SetDpid1(0x1FFF, DMX_OUT_DECODER); - SetDpid2(0x1FFF, DMX_OUT_DECODER); - SetTpid( 0x1FFF, DMX_OUT_DECODER); - - FrontendParameters Frontend; - - switch (frontendType) { - case FE_QPSK: { // DVB-S - - // Frequency offsets: - - unsigned int freq = Frequency; - int tone = SEC_TONE_OFF; - - if (freq < (unsigned int)Setup.LnbSLOF) { - freq -= Setup.LnbFrequLo; - tone = SEC_TONE_OFF; - } - else { - freq -= Setup.LnbFrequHi; - tone = SEC_TONE_ON; - } - - Frontend.Frequency = freq * 1000UL; - Frontend.Inversion = INVERSION_AUTO; - Frontend.u.qpsk.SymbolRate = Srate * 1000UL; - Frontend.u.qpsk.FEC_inner = FEC_AUTO; - - int volt = (Polarization == 'v' || Polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18; - - // DiseqC: - - secCommand scmd; - scmd.type = 0; - scmd.u.diseqc.addr = 0x10; - scmd.u.diseqc.cmd = 0x38; - scmd.u.diseqc.numParams = 1; - scmd.u.diseqc.params[0] = 0xF0 | ((Diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0); - - secCmdSequence scmds; - scmds.voltage = volt; - scmds.miniCommand = SEC_MINI_NONE; - scmds.continuousTone = tone; - scmds.numCommands = Setup.DiSEqC ? 1 : 0; - scmds.commands = &scmd; - - CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds)); - } - break; - case FE_QAM: { // DVB-C - - // Frequency and symbol rate: - - Frontend.Frequency = Frequency * 1000000UL; - Frontend.Inversion = INVERSION_AUTO; - Frontend.u.qam.SymbolRate = Srate * 1000UL; - Frontend.u.qam.FEC_inner = FEC_AUTO; - Frontend.u.qam.QAM = QAM_64; - } - break; - case FE_OFDM: { // DVB-T - - // Frequency and OFDM paramaters: - - Frontend.Frequency = Frequency * 1000UL; - Frontend.Inversion = INVERSION_AUTO; - Frontend.u.ofdm.bandWidth=BANDWIDTH_8_MHZ; - Frontend.u.ofdm.HP_CodeRate=FEC_2_3; - Frontend.u.ofdm.LP_CodeRate=FEC_1_2; - Frontend.u.ofdm.Constellation=QAM_64; - Frontend.u.ofdm.TransmissionMode=TRANSMISSION_MODE_2K; - Frontend.u.ofdm.guardInterval=GUARD_INTERVAL_1_32; - Frontend.u.ofdm.HierarchyInformation=HIERARCHY_NONE; - } - break; - default: - esyslog("ERROR: attempt to set channel with unknown DVB frontend type"); - return scrFailed; - } - - // Tuning: - - CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend)); - - // Wait for channel sync: - - if (cFile::FileReady(fd_frontend, 5000)) { - FrontendEvent event; - int res = ioctl(fd_frontend, FE_GET_EVENT, &event); - if (res >= 0) { - if (event.type != FE_COMPLETION_EV) { - esyslog("ERROR: channel %d not sync'ed on DVB card %d!", ChannelNumber, CardIndex() + 1); - if (this == PrimaryDvbApi) - cThread::RaisePanic(); - return scrFailed; - } - } - else - esyslog("ERROR %d in frontend get event (channel %d, card %d)", res, ChannelNumber, CardIndex() + 1); - } - else - esyslog("ERROR: timeout while tuning"); - - // PID settings: - - if (!SetPids(false)) { - esyslog("ERROR: failed to set PIDs for channel %d", ChannelNumber); - return scrFailed; - } - SetTpid(Tpid, DMX_OUT_DECODER); - if (fd_audio >= 0) - CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); - } - - if (this == PrimaryDvbApi && siProcessor) - siProcessor->SetCurrentServiceID(Pnr); - - eSetChannelResult Result = scrOk; - - // If this DVB card can't receive this channel, let's see if we can - // use the card that actually can receive it and transfer data from there: - - if (NeedsTransferMode) { - cDvbApi *CaDvbApi = GetDvbApi(Ca, 0); - if (CaDvbApi && !CaDvbApi->Recording()) { - if ((Result = CaDvbApi->SetChannel(ChannelNumber, Frequency, Polarization, Diseqc, Srate, Vpid, Apid1, Apid2, Dpid1, Dpid2, Tpid, Ca, Pnr)) == scrOk) { - SetModeReplay(); - transferringFromDvbApi = CaDvbApi->StartTransfer(fd_video); - } - } - else - Result = scrNoTransfer; - } - - if (fd_video >= 0 && fd_audio >= 0) { - CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false)); - CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false)); - } - - // Start setting system time: - - if (Result == scrOk && siProcessor) - siProcessor->SetCurrentTransponder(Frequency); - - cStatusMonitor::MsgChannelSwitch(this, ChannelNumber); - - return Result; -} - -bool cDvbApi::Transferring(void) -{ - return transferBuffer; -} - -cDvbApi *cDvbApi::StartTransfer(int TransferToVideoDev) -{ - StopTransfer(); - transferBuffer = new cTransferBuffer(this, TransferToVideoDev, vPid, aPid1); - return this; -} - -void cDvbApi::StopTransfer(void) -{ - if (transferBuffer) { - delete transferBuffer; - transferBuffer = NULL; - } - if (transferringFromDvbApi) { - transferringFromDvbApi->StopTransfer(); - transferringFromDvbApi = NULL; - } -} - -int cDvbApi::SecondsToFrames(int Seconds) -{ - return Seconds * FRAMESPERSEC; -} - -bool cDvbApi::Recording(void) -{ - if (recordBuffer && !recordBuffer->Active()) - StopRecord(); - return recordBuffer != NULL; -} - -bool cDvbApi::Replaying(void) -{ - if (replayBuffer && !replayBuffer->Active()) - StopReplay(); - return replayBuffer != NULL; -} - -bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority) -{ - if (Recording()) { - esyslog("ERROR: StartRecord() called while recording - ignored!"); - return false; - } - - StopTransfer(); - - StopReplay(); // TODO: remove this if the driver is able to do record and replay at the same time - - // Check FileName: - - if (!FileName) { - esyslog("ERROR: StartRecord: file name is (null)"); - return false; - } - isyslog("record %s", FileName); - - // Create directories if necessary: - - if (!MakeDirs(FileName, true)) - return false; - - // Make sure the disk is up and running: - - SpinUpDisk(FileName); - - // Create recording buffer: - - recordBuffer = new cRecordBuffer(this, FileName, vPid, aPid1, aPid2, dPid1, dPid2); - - if (recordBuffer) { - ca = Ca; - priority = Priority; - return true; - } - else - esyslog("ERROR: can't allocate recording buffer"); - - return false; -} - -void cDvbApi::StopRecord(void) -{ - if (recordBuffer) { - delete recordBuffer; - recordBuffer = NULL; - ca = -1; - priority = DEFAULTPRIORITY; - } -} - -bool cDvbApi::StartReplay(const char *FileName) -{ - if (Recording()) { - esyslog("ERROR: StartReplay() called while recording - ignored!"); - return false; - } - StopTransfer(); - StopReplay(); - if (fd_video >= 0 && fd_audio >= 0) { - - // Check FileName: - - if (!FileName) { - esyslog("ERROR: StartReplay: file name is (null)"); - return false; - } - isyslog("replay %s", FileName); - - // Create replay buffer: - - replayBuffer = new cReplayBuffer(this, fd_video, fd_audio, FileName); - if (replayBuffer) - return true; - else - esyslog("ERROR: can't allocate replaying buffer"); - } - return false; -} - -void cDvbApi::StopReplay(void) -{ - if (replayBuffer) { - delete replayBuffer; - replayBuffer = NULL; - if (this == PrimaryDvbApi) { - // let's explicitly switch the channel back in case it was in Transfer Mode: - cChannel *Channel = Channels.GetByNumber(currentChannel); - if (Channel) { - Channel->Switch(this, false); - usleep(100000); // allow driver to sync in case a new replay will start immediately - } - } - } -} - -void cDvbApi::Pause(void) -{ - if (replayBuffer) - replayBuffer->Pause(); -} - -void cDvbApi::Play(void) -{ - if (replayBuffer) - replayBuffer->Play(); -} - -void cDvbApi::Forward(void) -{ - if (replayBuffer) - replayBuffer->Forward(); -} - -void cDvbApi::Backward(void) -{ - if (replayBuffer) - replayBuffer->Backward(); -} - -void cDvbApi::SkipSeconds(int Seconds) -{ - if (replayBuffer) - replayBuffer->SkipSeconds(Seconds); -} - -int cDvbApi::SkipFrames(int Frames) -{ - if (replayBuffer) - return replayBuffer->SkipFrames(Frames); - return -1; -} - -bool cDvbApi::GetIndex(int &Current, int &Total, bool SnapToIFrame) -{ - if (replayBuffer) { - replayBuffer->GetIndex(Current, Total, SnapToIFrame); - return true; - } - return false; -} - -bool cDvbApi::GetReplayMode(bool &Play, bool &Forward, int &Speed) -{ - return replayBuffer && replayBuffer->GetReplayMode(Play, Forward, Speed); -} - -void cDvbApi::Goto(int Position, bool Still) -{ - if (replayBuffer) - replayBuffer->Goto(Position, Still); -} - -bool cDvbApi::CanToggleAudioTrack(void) -{ - return replayBuffer ? replayBuffer->CanToggleAudioTrack() : (aPid1 && aPid2 && aPid1 != aPid2); -} - -bool cDvbApi::ToggleAudioTrack(void) -{ - if (replayBuffer) { - replayBuffer->ToggleAudioTrack(); - return true; - } - else { - int a = aPid2; - aPid2 = aPid1; - aPid1 = a; - if (transferringFromDvbApi) - return transferringFromDvbApi->ToggleAudioTrack(); - else { - if (transferBuffer) - transferBuffer->SetAudioPid(aPid1); - return SetPids(transferBuffer != NULL); - } - } - return false; -} - -bool cDvbApi::ToggleMute(void) -{ - int OldVolume = volume; - mute = !mute; - SetVolume(0, mute); - volume = OldVolume; - return mute; -} - -void cDvbApi::SetVolume(int Volume, bool Absolute) -{ - if (fd_audio >= 0) { - volume = min(max(Absolute ? Volume : volume + Volume, 0), MAXVOLUME); - audioMixer_t am; - am.volume_left = am.volume_right = volume; - CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am)); - cStatusMonitor::MsgSetVolume(volume, Absolute); - if (volume > 0) - mute = false; - } -} - -void cDvbApi::SetAudioCommand(const char *Command) -{ - delete audioCommand; - audioCommand = strdup(Command); -} diff --git a/dvbapi.h b/dvbapi.h deleted file mode 100644 index 036ded85..00000000 --- a/dvbapi.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * dvbapi.h: Interface to the DVB driver - * - * See the main source file 'vdr.c' for copyright information and - * how to reach the author. - * - * $Id: dvbapi.h 1.72 2002/05/20 10:58:20 kls Exp $ - */ - -#ifndef __DVBAPI_H -#define __DVBAPI_H - -#include <stdlib.h> // FIXME: this is apparently necessary for the ost/... header files - // FIXME: shouldn't every header file include ALL the other header - // FIXME: files it depends on? The sequence in which header files - // FIXME: are included here should not matter - and it should NOT - // FIXME: be necessary to include <stdlib.h> here! -#include <linux/videodev.h> -#include <ost/dmx.h> -#include <ost/sec.h> -#include <ost/frontend.h> -#include <ost/video.h> -#include <ost/audio.h> -#include <stdio.h> -#include "eit.h" -#include "thread.h" - -#define FRAMESPERSEC 25 - -// The maximum file size is limited by the range that can be covered -// with 'int'. 4GB might be possible (if the range is considered -// 'unsigned'), 2GB should be possible (even if the range is considered -// 'signed'), so let's use 2000MB for absolute safety (the actual file size -// may be slightly higher because we stop recording only before the next -// 'I' frame, to have a complete Group Of Pictures): -#define MAXVIDEOFILESIZE 2000 // MB -#define MINVIDEOFILESIZE 100 // MB - -#define MAXVOLUME 255 -#define VOLUMEDELTA 5 // used to increase/decrease the volume - -const char *IndexToHMSF(int Index, bool WithFrame = false); - // Converts the given index to a string, optionally containing the frame number. -int HMSFToIndex(const char *HMSF); - // Converts the given string (format: "hh:mm:ss.ff") to an index. - -enum eSetChannelResult { scrOk, scrNoTransfer, scrFailed }; - -class cChannel; - -class cRecordBuffer; -class cPlayBuffer; -class cReplayBuffer; -class cTransferBuffer; -class cCuttingBuffer; - -class cVideoCutter { -private: - static char *editedVersionName; - static cCuttingBuffer *cuttingBuffer; - static bool error; - static bool ended; -public: - static bool Start(const char *FileName); - static void Stop(void); - static bool Active(void); - static bool Error(void); - static bool Ended(void); - }; - -class cDvbApi { - friend class cOsd; - friend class cRecordBuffer; - friend class cReplayBuffer; - friend class cTransferBuffer; -private: - FrontendType frontendType; - int fd_osd, fd_frontend, fd_sec, fd_dvr, fd_audio, fd_video, fd_demuxa1, fd_demuxa2, fd_demuxd1, fd_demuxd2, fd_demuxv, fd_demuxt; - int vPid, aPid1, aPid2, dPid1, dPid2; - int OsdDeviceHandle(void) { return fd_osd; } - bool SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output); - bool SetVpid(int Vpid, dmxOutput_t Output) { return SetPid(fd_demuxv, DMX_PES_VIDEO, Vpid, Output); } - bool SetApid1(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa1, DMX_PES_AUDIO, Apid, Output); } - bool SetApid2(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa2, DMX_PES_OTHER, Apid, Output); } - bool SetDpid1(int Dpid, dmxOutput_t Output) { return SetPid(fd_demuxd1, DMX_PES_OTHER, Dpid, Output); } - bool SetDpid2(int Dpid, dmxOutput_t Output) { return SetPid(fd_demuxd2, DMX_PES_OTHER, Dpid, Output); } - bool SetTpid(int Tpid, dmxOutput_t Output) { return SetPid(fd_demuxt, DMX_PES_TELETEXT, Tpid, Output); } - bool SetPids(bool ForRecording); - cDvbApi(int n); -public: - ~cDvbApi(); - -#define MAXDVBAPI 4 // the maximum number of DVB cards in the system -#define MAXCACAPS 16 // the maximum number of different CA values per DVB card - - static int NumDvbApis; -private: - static cDvbApi *dvbApi[MAXDVBAPI]; - static int useDvbApi; - int cardIndex; - int caCaps[MAXCACAPS]; - int CanShift(int Ca, int Priority, int UsedCards = 0); -public: - static cDvbApi *PrimaryDvbApi; - static void SetUseDvbApi(int n); - // Sets the 'useDvbApi' flag of the given DVB device. - // If this function is not called before Initialize(), all DVB devices - // will be used. - static bool SetPrimaryDvbApi(int n); - // Sets the primary DVB device to 'n' (which must be in the range - // 1...NumDvbApis) and returns true if this was possible. - static cDvbApi *GetDvbApi(int Ca, int Priority); - // Selects a free DVB device, avoiding the PrimaryDvbApi if possible. - // If Ca is not 0, the device with the given number will be returned - // in case Ca is <= MAXDVBAPI, or the device that provides the given - // value in its caCaps. - // If all DVB devices are currently recording, the one recording the - // lowest priority timer (if any) that is lower than the given Priority - // will be returned. - // The caller must check whether the returned DVB device is actually - // recording and stop recording if necessary. - int CardIndex(void) const { return cardIndex; } - // Returns the card index of this DvbApi (0 ... MAXDVBAPI - 1). - static void SetCaCaps(void); - // Sets the CaCaps of all DVB devices according to the Setup data. - int ProvidesCa(int Ca); - // Checks whether this DVB device provides the given value in its - // caCaps. Returns 0 if the value is not provided, 1 if only this - // value is provided, and > 1 if this and other values are provided. - // If the given value is equal to the number of this DVB device, - // 1 is returned. If it is 0 (FTA), 1 plus the number of other values - // in caCaps is returned. - static bool Probe(const char *FileName); - // Probes for existing DVB devices. - static bool Initialize(void); - // Initializes the DVB API. - // Must be called before accessing any DVB functions. - static void Shutdown(void); - // Closes down all DVB devices. - // Must be called at the end of the program. - - // EIT facilities - -private: - cSIProcessor *siProcessor; -public: - // Image Grab facilities - - bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); - - // Video format facilities: - - void SetVideoFormat(videoFormat_t Format); - - // Channel facilities - -private: - int currentChannel; -public: - eSetChannelResult SetChannel(int ChannelNumber, int Frequency, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr); - static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; } - int Channel(void) { return currentChannel; } - - // Transfer facilities - -private: - cTransferBuffer *transferBuffer; - cDvbApi *transferringFromDvbApi; -public: - bool Transferring(void); - // Returns true if we are currently transferring video data. -private: - cDvbApi *StartTransfer(int TransferToVideoDev); - // Starts transferring video data from this DVB device to TransferToVideoDev. - void StopTransfer(void); - // Stops transferring video data (in case a transfer is currently active). - - // Record/Replay facilities - -private: - cRecordBuffer *recordBuffer; - cPlayBuffer *replayBuffer; - int ca; - int priority; - int Priority(void); - // Returns the priority of the current recording session (0..MAXPRIORITY), - // or -1 if no recording is currently active. The primary DVB device will - // always return at least Setup.PrimaryLimit-1. - int SetModeRecord(void); - // Initiates recording mode and returns the file handle to read from. - void SetModeReplay(void); - void SetModeNormal(bool FromRecording); -public: - int Ca(void) { return ca; } - // Returns the ca of the current recording session. - int SecondsToFrames(int Seconds); - // Returns the number of frames corresponding to the given number of seconds. - bool Recording(void); - // Returns true if we are currently recording. - bool Replaying(void); - // Returns true if we are currently replaying. - bool StartRecord(const char *FileName, int Ca, int Priority); - // Starts recording the current channel into the given file, with - // the given ca and priority. - // In order to be able to record longer movies, - // a numerical suffix will be appended to the file name. The inital - // value of that suffix will be larger than any existing file under - // the given name, thus allowing an interrupted recording to continue - // gracefully. - // Returns true if recording was started successfully. - // If there is already a recording session active, false will be - // returned. - void StopRecord(void); - // Stops the current recording session (if any). - bool StartReplay(const char *FileName); - // Starts replaying the given file. - // If there is already a replay session active, it will be stopped - // and the new file will be played back. - void StopReplay(void); - // Stops the current replay session (if any). - void Pause(void); - // Pauses the current replay session, or resumes a paused session. - void Play(void); - // Resumes normal replay mode. - void Forward(void); - // Runs the current replay session forward at a higher speed. - void Backward(void); - // Runs the current replay session backwards at a higher speed. - void SkipSeconds(int Seconds); - // Skips the given number of seconds in the current replay session. - // The sign of 'Seconds' determines the direction in which to skip. - // Use a very large negative value to go all the way back to the - // beginning of the recording. - int SkipFrames(int Frames); - // Returns the new index into the current replay session after skipping - // the given number of frames (no actual repositioning is done!). - // The sign of 'Frames' determines the direction in which to skip. - bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); - // Returns the current and total frame index, optionally snapped to the - // nearest I-frame. - bool GetReplayMode(bool &Play, bool &Forward, int &Speed); - // Returns the current replay mode (if applicable). - // 'Play' tells whether we are playing or pausing, 'Forward' tells whether - // we are going forward or backward and 'Speed' is -1 if this is normal - // play/pause mode, 0 if it is single speed fast/slow forward/back mode - // and >0 if this is multi speed mode. - void Goto(int Index, bool Still = false); - // Positions to the given index and displays that frame as a still picture - // if Still is true. - - // Audio track facilities - -public: - bool CanToggleAudioTrack(void); - // Returns true if we are currently replaying and this recording has two - // audio tracks, or if the current channel has two audio PIDs. - bool ToggleAudioTrack(void); - // Toggles the audio track if possible. - - // Dolby Digital audio facilities - -private: - static char *audioCommand; -public: - static void SetAudioCommand(const char *Command); - static const char *AudioCommand(void) { return audioCommand; } - - // Volume facilities: - -private: - bool mute; - int volume; -public: - bool IsMute(void) { return mute; } - bool ToggleMute(void); - // Turns the volume off or on and returns the new mute state. - void SetVolume(int Volume, bool Absolute = false); - // Sets the volume to the given value, either absolutely or relative to - // the current volume. - static int CurrentVolume(void) { return PrimaryDvbApi ? PrimaryDvbApi->volume : 0; } - }; - -#endif //__DVBAPI_H diff --git a/interface.c b/interface.c index ed9d0b1e..fa36b4cb 100644 --- a/interface.c +++ b/interface.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.51 2002/06/10 16:30:00 kls Exp $ + * $Id: interface.c 1.52 2002/06/16 13:23:40 kls Exp $ */ #include "interface.h" @@ -128,7 +128,7 @@ void cInterface::Clear(void) { if (open) cOsd::Clear(); - cStatusMonitor::MsgOsdClear(); + cStatus::MsgOsdClear(); } void cInterface::ClearEol(int x, int y, eDvbColor Color) @@ -289,7 +289,7 @@ void cInterface::Title(const char *s) x = 0; Write(x, 0, s, clrBlack, clrCyan); } - cStatusMonitor::MsgOsdTitle(s); + cStatus::MsgOsdTitle(s); } void cInterface::Status(const char *s, eDvbColor FgColor, eDvbColor BgColor) @@ -302,7 +302,7 @@ void cInterface::Status(const char *s, eDvbColor FgColor, eDvbColor BgColor) x = 0; Write(x, Line, s, FgColor, BgColor); } - cStatusMonitor::MsgOsdStatusMessage(s); + cStatus::MsgOsdStatusMessage(s); } void cInterface::Info(const char *s) @@ -358,7 +358,7 @@ void cInterface::Help(const char *Red, const char *Green, const char *Yellow, co HelpButton(1, Green, clrBlack, clrGreen); HelpButton(2, Yellow, clrBlack, clrYellow); HelpButton(3, Blue, clrWhite, clrBlue); - cStatusMonitor::MsgOsdHelpKeys(Red, Green, Yellow, Blue); + cStatus::MsgOsdHelpKeys(Red, Green, Yellow, Blue); } void cInterface::QueryKeys(void) @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.196 2002/06/16 12:11:02 kls Exp $ + * $Id: menu.c 1.197 2002/06/16 13:23:51 kls Exp $ */ #include "menu.h" @@ -2169,7 +2169,7 @@ void cDisplayChannel::DisplayChannel(const cChannel *Channel) Interface->Write(0, 0, buffer); const char *date = DayDateTime(); Interface->Write(-strlen(date), 0, date); - cStatusMonitor::MsgOsdChannel(buffer); + cStatus::MsgOsdChannel(buffer); } void cDisplayChannel::DisplayInfo(void) @@ -2223,7 +2223,7 @@ void cDisplayChannel::DisplayInfo(void) Interface->Flush(); lines = Lines; lastTime = time_ms(); - cStatusMonitor::MsgOsdProgramme(Present ? Present->GetTime() : 0, PresentTitle, PresentSubtitle, Following ? Following->GetTime() : 0, FollowingTitle, FollowingSubtitle); + cStatus::MsgOsdProgramme(Present ? Present->GetTime() : 0, PresentTitle, PresentSubtitle, Following ? Following->GetTime() : 0, FollowingTitle, FollowingSubtitle); } } } @@ -2445,7 +2445,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer) recorder = new cRecorder(fileName, ch->ca, timer->priority, ch->vpid, ch->apid1, ch->apid2, ch->dpid1, ch->dpid2); if (device->Attach(recorder)) { Recording.WriteSummary(); - cStatusMonitor::MsgRecording(device, fileName); + cStatus::MsgRecording(device, fileName); Interface->DisplayRecording(device->CardIndex(), true); } else @@ -2492,7 +2492,7 @@ bool cRecordControl::GetEventInfo(void) void cRecordControl::Stop(bool KeepInstant) { if (timer) { - cStatusMonitor::MsgRecording(device, NULL); + cStatus::MsgRecording(device, NULL); DELETENULL(recorder); timer->SetRecording(false); if ((IsInstant() && !KeepInstant) || (timer->IsSingleEvent() && !timer->Matches())) { @@ -2694,14 +2694,14 @@ cReplayControl::cReplayControl(void) if (!Start(fileName)) Interface->Error(tr("Channel locked (recording)!"));//XXX+ else - cStatusMonitor::MsgReplaying(this, fileName); + cStatus::MsgReplaying(this, fileName); } } cReplayControl::~cReplayControl() { Hide(); - cStatusMonitor::MsgReplaying(this, NULL); + cStatus::MsgReplaying(this, NULL); Stop(); } diff --git a/menuitems.c b/menuitems.c index a66cbc30..6a54a86d 100644 --- a/menuitems.c +++ b/menuitems.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menuitems.c 1.5 2002/05/19 12:34:33 kls Exp $ + * $Id: menuitems.c 1.6 2002/06/16 13:23:56 kls Exp $ */ #include "menuitems.h" @@ -398,7 +398,7 @@ void cMenuTextItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor) // scroll indicators use inverted color scheme! if (CanScrollUp()) Interface->Write(x + w - 1, y, "^", bgColor, fgColor); if (CanScrollDown()) Interface->Write(x + w - 1, y + h - 1, "v", bgColor, fgColor); - cStatusMonitor::MsgOsdTextItem(text); + cStatus::MsgOsdTextItem(text); } void cMenuTextItem::ScrollUp(bool Page) @@ -408,7 +408,7 @@ void cMenuTextItem::ScrollUp(bool Page) offset = max(offset - (Page ? h : 1), 0); Display(); } - cStatusMonitor::MsgOsdTextItem(NULL, true); + cStatus::MsgOsdTextItem(NULL, true); } void cMenuTextItem::ScrollDown(bool Page) @@ -418,7 +418,7 @@ void cMenuTextItem::ScrollDown(bool Page) offset = min(offset + (Page ? h : 1), lines - h); Display(); } - cStatusMonitor::MsgOsdTextItem(NULL, false); + cStatus::MsgOsdTextItem(NULL, false); } eOSState cMenuTextItem::ProcessKey(eKeys Key) @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.28 2002/06/10 16:30:00 kls Exp $ + * $Id: osd.c 1.29 2002/06/16 13:24:00 kls Exp $ */ #include "osd.h" @@ -434,7 +434,7 @@ void cOsdMenu::Display(void) if (item) { item->Display(i - first, i == current ? clrBlack : clrWhite, i == current ? clrCyan : clrBackground); if (i == current) - cStatusMonitor::MsgOsdCurrentItem(item->Text()); + cStatus::MsgOsdCurrentItem(item->Text()); } if (++n == MAXOSDITEMS) //TODO get this from Interface!!! break; @@ -462,7 +462,7 @@ void cOsdMenu::DisplayCurrent(bool Current) if (item) { item->Display(current - first, Current ? clrBlack : clrWhite, Current ? clrCyan : clrBackground); if (Current) - cStatusMonitor::MsgOsdCurrentItem(item->Text()); + cStatus::MsgOsdCurrentItem(item->Text()); } } @@ -4,93 +4,93 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: status.c 1.2 2002/06/16 12:10:44 kls Exp $ + * $Id: status.c 1.3 2002/06/16 13:24:36 kls Exp $ */ #include "status.h" -// --- cStatusMonitor -------------------------------------------------------- +// --- cStatus --------------------------------------------------------------- -cList<cStatusMonitor> cStatusMonitor::statusMonitors; +cList<cStatus> cStatus::statusMonitors; -cStatusMonitor::cStatusMonitor(void) +cStatus::cStatus(void) { statusMonitors.Add(this); } -cStatusMonitor::~cStatusMonitor() +cStatus::~cStatus() { statusMonitors.Del(this, false); } -void cStatusMonitor::MsgChannelSwitch(const cDevice *Device, int ChannelNumber) +void cStatus::MsgChannelSwitch(const cDevice *Device, int ChannelNumber) { - for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) sm->ChannelSwitch(Device, ChannelNumber); } -void cStatusMonitor::MsgRecording(const cDevice *Device, const char *Name) +void cStatus::MsgRecording(const cDevice *Device, const char *Name) { - for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) sm->Recording(Device, Name); } -void cStatusMonitor::MsgReplaying(const cDvbPlayerControl *DvbPlayerControl, const char *Name) +void cStatus::MsgReplaying(const cDvbPlayerControl *DvbPlayerControl, const char *Name) { - for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) sm->Replaying(DvbPlayerControl, Name); } -void cStatusMonitor::MsgSetVolume(int Volume, bool Absolute) +void cStatus::MsgSetVolume(int Volume, bool Absolute) { - for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) sm->SetVolume(Volume, Absolute); } -void cStatusMonitor::MsgOsdClear(void) +void cStatus::MsgOsdClear(void) { - for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) sm->OsdClear(); } -void cStatusMonitor::MsgOsdTitle(const char *Title) +void cStatus::MsgOsdTitle(const char *Title) { - for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) sm->OsdTitle(Title); } -void cStatusMonitor::MsgOsdStatusMessage(const char *Message) +void cStatus::MsgOsdStatusMessage(const char *Message) { - for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) sm->OsdStatusMessage(Message); } -void cStatusMonitor::MsgOsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue) +void cStatus::MsgOsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue) { - for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) sm->OsdHelpKeys(Red, Green, Yellow, Blue); } -void cStatusMonitor::MsgOsdCurrentItem(const char *Text) +void cStatus::MsgOsdCurrentItem(const char *Text) { - for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) sm->OsdCurrentItem(Text); } -void cStatusMonitor::MsgOsdTextItem(const char *Text, bool Scroll) +void cStatus::MsgOsdTextItem(const char *Text, bool Scroll) { - for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) sm->OsdTextItem(Text, Scroll); } -void cStatusMonitor::MsgOsdChannel(const char *Text) +void cStatus::MsgOsdChannel(const char *Text) { - for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) sm->OsdChannel(Text); } -void cStatusMonitor::MsgOsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle) +void cStatus::MsgOsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle) { - for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) sm->OsdProgramme(PresentTime, PresentTitle, PresentSubtitle, FollowingTime, FollowingTitle, FollowingSubtitle); } @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: status.h 1.2 2002/06/16 12:09:55 kls Exp $ + * $Id: status.h 1.3 2002/06/16 13:24:50 kls Exp $ */ #ifndef __STATUS_H @@ -15,9 +15,9 @@ #include "dvbplayer.h" #include "tools.h" -class cStatusMonitor : public cListObject { +class cStatus : public cListObject { private: - static cList<cStatusMonitor> statusMonitors; + static cList<cStatus> statusMonitors; protected: // These functions can be implemented by derived classes to receive status information: virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber) {} @@ -55,8 +55,8 @@ protected: virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle) {} // The OSD displays the given programme information. public: - cStatusMonitor(void); - virtual ~cStatusMonitor(); + cStatus(void); + virtual ~cStatus(); // These functions are called whenever the related status information changes: static void MsgChannelSwitch(const cDevice *Device, int ChannelNumber); static void MsgRecording(const cDevice *Device, const char *Name); |