diff options
author | Petri Hintukainen <phintuka@users.sourceforge.net> | 2012-12-31 09:37:03 +0200 |
---|---|---|
committer | Petri Hintukainen <phintuka@users.sourceforge.net> | 2012-12-31 09:37:03 +0200 |
commit | 9152e575ae53aa1c79ec7d41a96add4301af2e21 (patch) | |
tree | bf317b5d780f69dcd2d02160870085eaf54b5b61 | |
download | vdr-plugin-bluray-9152e575ae53aa1c79ec7d41a96add4301af2e21.tar.gz vdr-plugin-bluray-9152e575ae53aa1c79ec7d41a96add4301af2e21.tar.bz2 |
Initial import
-rw-r--r-- | COPYING | 340 | ||||
-rw-r--r-- | HISTORY | 8 | ||||
-rw-r--r-- | Makefile | 117 | ||||
-rw-r--r-- | README | 33 | ||||
-rw-r--r-- | bdplayer.c | 689 | ||||
-rw-r--r-- | bdplayer.h | 61 | ||||
-rw-r--r-- | bluray.c | 118 | ||||
-rw-r--r-- | discmgr.c | 141 | ||||
-rw-r--r-- | discmgr.h | 45 |
9 files changed, 1552 insertions, 0 deletions
@@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + 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 Lesser 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General +Public License instead of this License. @@ -0,0 +1,8 @@ +VDR Plugin 'bluray' Revision History +------------------------------------ + +2012-12-19: Version 0.0.1 + +- Initial revision. + Simple playback of BluRay disc main title. + No menu / track selection / subtitling support yet. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..aed22df --- /dev/null +++ b/Makefile @@ -0,0 +1,117 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id$ + +# The official name of this plugin. +# This name will be used in the '-P...' option of VDR to load the plugin. +# By default the main source file also carries this name. +# IMPORTANT: the presence of this macro is important for the Make.config +# file. So it must be defined, even if it is not used here! +# +PLUGIN = bluray + +### 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 C++ compiler and options: + +CXX ?= g++ +CXXFLAGS ?= -g -O3 -Wall -Werror=overloaded-virtual -Wno-parentheses + +LIBS += $(shell pkg-config --libs libbluray) +INCLUDES += $(shell pkg-config --cflags libbluray) + +### The directory environment: + +VDRDIR ?= ../../.. +LIBDIR ?= ../../lib +TMPDIR ?= /tmp + +### Make sure that necessary options are included: + +-include $(VDRDIR)/Make.global + +### Allow user defined options to overwrite defaults: + +-include $(VDRDIR)/Make.config + +### The version number of VDR's plugin API (taken from VDR's "config.h"): + +APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h) + +### The name of the distribution archive: + +ARCHIVE = $(PLUGIN)-$(VERSION) +PACKAGE = vdr-$(ARCHIVE) + +### Includes and Defines (add further entries here): + +INCLUDES += -I$(VDRDIR)/include + +DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' + +### The object files (add further files here): + +OBJS = $(PLUGIN).o bdplayer.o discmgr.o + +### The main target: + +all: libvdr-$(PLUGIN).so i18n + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +### Dependencies: + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Internationalization (I18N): + +PODIR = po +LOCALEDIR = $(VDRDIR)/locale +I18Npo = $(wildcard $(PODIR)/*.po) +I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file)))))) +I18Npot = $(PODIR)/$(PLUGIN).pot + +%.mo: %.po + msgfmt -c -o $@ $< + +$(I18Npot): $(wildcard *.c) + xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ $^ + +%.po: $(I18Npot) + msgmerge -U --no-wrap --no-location --backup=none -q $@ $< + @touch $@ + +$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo + @mkdir -p $(dir $@) + cp $< $@ + +.PHONY: i18n +i18n: $(I18Nmsgs) $(I18Npot) + +### Targets: + +libvdr-$(PLUGIN).so: $(OBJS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@ + @cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION) + +dist: $(I18Npo) 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* *~ $(PODIR)/*.mo $(PODIR)/*.pot @@ -0,0 +1,33 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Petri Hintukainen <phintuka@users.sourceforge.net> + +Project's homepage: http://projects.vdr-developer.org/projects/plg-bluray + +Latest version available at: http://projects.vdr-developer.org/projects/plg-bluray + +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. +See the file COPYING for more information. + + +Description: + + Simple BluRay disc player. + +Required libraries: + + libbluray (http://www.videolan.org/developers/libbluray.html) + +Options: + + -D, --device BluRay device (default /dev/sr0) + -p, --path Mount path for BluRay device (default /media/cdrom) + -m, --mount Program/script used to mount BluRay disc (default /bin/mount) + -u, --unmount Program/script used to unmount BluRay disc (default /bin/umount) + -e, --eject Program/script used to eject / close BluRay drive (default /usr/bin/eject) + + All options except BluRay disc mount path are optional. + Helper scripts are used only if the disc is not automatically mounted. diff --git a/bdplayer.c b/bdplayer.c new file mode 100644 index 0000000..96a31a7 --- /dev/null +++ b/bdplayer.c @@ -0,0 +1,689 @@ +/* + * bdplayer.c: A player for BluRay discs + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include "bdplayer.h" + +#include <vdr/remote.h> +#include <vdr/tools.h> +#include <vdr/status.h> + +#include <libbluray/bluray.h> +#include <libbluray/meta_data.h> + +#define MIN_TITLE_LENGTH (180) // seconds +#define M2TS_SIZE (188 + 4) // size of m2ts packet +#define ALIGNED_UNIT_SIZE (32 * M2TS_SIZE) // size of aligned unit (32 packets) + +// --- cBDPlayer -------------------------------------------------------- + +class cBDPlayer : public cPlayer, cThread { +private: + BLURAY *bd; + BLURAY_TITLE_INFO *title_info; + + enum ePlayModes { pmPlay, pmPause }; + ePlayModes playMode; + + uchar buffer[ALIGNED_UNIT_SIZE]; + int pos, packs; + + bool DoRead(void); + bool DoPlay(void); + + virtual void Activate(bool On); + + void UpdateTracks(unsigned int current_clip); + void HandleEvents(BD_EVENT *ev); + void Empty(); + +protected: + void Action(void); + +public: + cBDPlayer(BLURAY *bd); + ~cBDPlayer(); + + void Goto(int Seconds); + void SkipSeconds(int seconds); + void Play(); + void Pause(); + + virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); + virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed); +}; + +cBDPlayer::cBDPlayer(BLURAY *Bd) +{ + bd = Bd; + title_info = NULL; + playMode = pmPlay; + pos = packs = 0; +} + +cBDPlayer::~cBDPlayer() +{ + if (title_info) { + bd_free_title_info(title_info); + title_info = NULL; + } + + if (bd) { + bd_close(bd); + bd = NULL; + } +} + +void cBDPlayer::UpdateTracks(unsigned int current_clip) +{ + if (title_info && current_clip < title_info->clip_count) { + BLURAY_CLIP_INFO *clip = &title_info->clips[current_clip]; + int i; + + DeviceClrAvailableTracks(); + + for (i = 0; i < clip->audio_stream_count; i++) { + DeviceSetAvailableTrack(ttDolby, i, + clip->audio_streams[i].pid, + (const char *)clip->audio_streams[i].lang); + } + for (i = 0; i < clip->pg_stream_count; i++) { + DeviceSetAvailableTrack(ttSubtitle, i, + clip->pg_streams[i].pid, + (const char *)clip->pg_streams[i].lang); + } + } +} + +void cBDPlayer::HandleEvents(BD_EVENT *ev) +{ + while (ev->event != BD_EVENT_NONE) { + + switch (ev->event) { + + //case BD_EVENT_ANGLE: + //case BD_EVENT_TITLE: + + case BD_EVENT_PLAYLIST: + if (title_info) { + bd_free_title_info(title_info); + title_info = NULL; + } + title_info = bd_get_playlist_info(bd, ev->param, 0); + break; + + case BD_EVENT_PLAYITEM: + UpdateTracks(ev->param); + break; + + //case BD_EVENT_CHAPTER: + + case BD_EVENT_END_OF_TITLE: + isyslog("END_OF_TITLE"); + Cancel(-1); + break; + + default: + break; + } + + /* get next event */ + if (!bd_get_event(bd, ev)) + break; + } +} + +bool cBDPlayer::DoRead() +{ + BD_EVENT ev = {0, 0}; + + LOCK_THREAD; + + pos = 0; + packs = bd_read_ext(bd, buffer, ALIGNED_UNIT_SIZE, &ev); + + if (packs == 0) { + // EOF + isyslog("End of title"); + Cancel(-1); + } else if (packs < 0) { + // ERROR + esyslog("bd_read() error"); + return false; + } + packs /= 192; + + HandleEvents(&ev); + return true; +} + +bool cBDPlayer::DoPlay() +{ + cPoller Poller; + + if (DevicePoll(Poller, 10)) { + + LOCK_THREAD; + + for (;pos < packs; pos++) { + + uint16_t pid = (((buffer)[1+4+pos*192] << 8) | (buffer)[2+4+pos*192]) & 0x1fff; + if (pid >= 1200 && pid < 1300) { + // skip PG streams + continue; + } + if (pid >= 1400 && pid < 1500) { + // skip IG streams + continue; + } + + int w = PlayTs(buffer + pos*192 + 4, 188, false); + + if (w == 188) { + continue; + } else if (w > 0) { + esyslog("PlayTs() error: partial ts packet accepted"); + continue; + } else if (w == 0) { + //esyslog("PlayTs() error: data not accepted"); + break; + } else { + esyslog("PlayTs() error"); + return false; + } + } + } + + return true; +} + +void cBDPlayer::Activate(bool On) +{ + if (On && bd) { + Start(); + } else { + Cancel(6); + } +} + +void cBDPlayer::Action() +{ + DoRead(); + + while (Running()) { + + if (pos >= packs) { + if (!DoRead()) { + break; + } + } + + if (!DoPlay()) { + break; + } + } + + isyslog("End BluRay playback"); +} + +void cBDPlayer::SkipSeconds(int seconds) +{ + uint64_t tick = bd_tell_time(bd); + if (tick < 0) { + isyslog("bd_tell_time() failed"); + return; + } + + seconds += tick / 90000; + if (seconds < 0) { + seconds = 0; + } + + Goto(seconds); +} + +void cBDPlayer::Goto(int seconds) +{ + LOCK_THREAD; + + Empty(); + uint64_t tick = seconds; + tick *= 90000; + + isyslog("Seek to %d", seconds); + bd_seek_time(bd, tick); +} + +void cBDPlayer::Empty(void) +{ + LOCK_THREAD; + + pos = packs = 0; + + DeviceClear(); +} + +void cBDPlayer::Pause(void) +{ + // from vdr-1.7.34 + if (playMode == pmPause) { + Play(); + } else { + LOCK_THREAD; + + DeviceFreeze(); + playMode = pmPause; + } +} + +void cBDPlayer::Play(void) +{ + // from vdr-1.7.34 + if (playMode != pmPlay) { + LOCK_THREAD; + + DevicePlay(); + playMode = pmPlay; + } +} + +bool cBDPlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame) +{ + LOCK_THREAD; + + if (title_info) { + Total = title_info->duration / 90000 * 25; + Current = bd_tell_time(bd) / 90000 * 25; + return true; + } + + Current = Total = -1; + return false; +} + +bool cBDPlayer::GetReplayMode(bool &Play, bool &Forward, int &Speed) +{ + Play = (playMode == pmPlay); + Forward = true; + Speed = -1; + return true; +} + +// --- cBDControl ------------------------------------------------------- + +#define MODETIMEOUT 3 // seconds + +int cBDControl::active = 0; + +cBDControl::cBDControl(cBDPlayer *Player) +:cControl(Player) +{ + player = Player; + active++; + + displayReplay = NULL; + visible = modeOnly = shown = false; + lastCurrent = lastTotal = -1; + lastPlay = lastForward = false; + lastSpeed = -2; // an invalid value + timeoutShow = 0; + timeSearchActive = false; + + disc_name = tr("BluRay"); + + cStatus::MsgReplaying(this, "BluRay", NULL, true); +} + +cBDControl::~cBDControl() +{ + active--; + + delete player; + + cStatus::MsgReplaying(this, NULL, NULL, false); +} + +cControl *cBDControl::Create(const char *Path) +{ + const struct meta_dl *meta_data = NULL; + BLURAY *bd; + + /* open disc */ + bd = bd_open(Path, NULL); + if (!bd) { + isyslog("opening BluRay disc %s failed", Path); + return NULL; + } + + /* load title list */ + unsigned num_title_idx = bd_get_titles(bd, TITLES_RELEVANT, MIN_TITLE_LENGTH); + if (num_title_idx < 1) { + esyslog("BluRay: no titles found"); + return NULL; + } + isyslog("BluRay: %d titles", num_title_idx); + + /* guess the main title */ + + unsigned title_idx = 0; + uint64_t duration = 0; + int playlist = 99999; + + for (unsigned i = 0; i < num_title_idx; i++) { + BLURAY_TITLE_INFO *info = bd_get_title_info(bd, i, 0); + if (info) { + if (info->duration > duration) { + title_idx = i; + duration = info->duration; + playlist = info->playlist; + } + bd_free_title_info(info); + } + } + isyslog("BluRay main title: #%d (%05d.mpls)\n", title_idx, playlist); + + /* init event queue */ + bd_get_event(bd, NULL); + + /* select playlist */ + if (bd_select_title(bd, title_idx) <= 0) { + esyslog("bd_select_title(%d) failed", title_idx); + return NULL; + } + + cBDControl *control = new cBDControl(new cBDPlayer(bd)); + + /* get disc name */ + meta_data = bd_get_meta(bd); + if (meta_data && meta_data->di_name && strlen(meta_data->di_name) > 1) { + control->disc_name = meta_data->di_name; + } + + return control; +} + +void cBDControl::Pause(void) +{ + if (player) + player->Pause(); +} + +void cBDControl::Play(void) +{ + if (player) + player->Play(); +} + +void cBDControl::SkipSeconds(int seconds) +{ + if (player) + player->SkipSeconds(seconds); +} + +void cBDControl::Goto(int seconds) +{ + if (player) + player->Goto(seconds); +} + +cString cBDControl::GetHeader(void) +{ + return disc_name; +} + +void cBDControl::ShowTimed(int Seconds) +{ + // from vdr-1.7.34 + if (modeOnly) + Hide(); + if (!visible) { + shown = ShowProgress(true); + timeoutShow = (shown && Seconds > 0) ? time(NULL) + Seconds : 0; + } + else if (timeoutShow && Seconds > 0) + timeoutShow = time(NULL) + Seconds; +} + +void cBDControl::Show(void) +{ + // from vdr-1.7.34 + ShowTimed(); +} + +void cBDControl::Hide(void) +{ + // from vdr-1.7.34 + if (visible) { + delete displayReplay; + displayReplay = NULL; + SetNeedsFastResponse(false); + visible = false; + modeOnly = false; + lastPlay = lastForward = false; + lastSpeed = -2; // an invalid value + timeSearchActive = false; + timeoutShow = 0; + } +} + +void cBDControl::ShowMode(void) +{ + // from vdr-1.7.34 + if (visible || Setup.ShowReplayMode && !cOsd::IsOpen()) { + bool Play, Forward; + int Speed; + if (GetReplayMode(Play, Forward, Speed) && (!visible || Play != lastPlay || Forward != lastForward || Speed != lastSpeed)) { + bool NormalPlay = (Play && Speed == -1); + + if (!visible) { + if (NormalPlay) + return; // no need to do indicate ">" unless there was a different mode displayed before + visible = modeOnly = true; + displayReplay = Skins.Current()->DisplayReplay(modeOnly); + } + + if (modeOnly && !timeoutShow && NormalPlay) + timeoutShow = time(NULL) + MODETIMEOUT; + displayReplay->SetMode(Play, Forward, Speed); + lastPlay = Play; + lastForward = Forward; + lastSpeed = Speed; + } + } +} + +bool cBDControl::ShowProgress(bool Initial) +{ + // from vdr-1.7.34 + int Current, Total; + + if (GetIndex(Current, Total) && Total > 0) { + if (!visible) { + displayReplay = Skins.Current()->DisplayReplay(modeOnly); + SetNeedsFastResponse(true); + visible = true; + } + if (Initial) { + lastCurrent = lastTotal = -1; + } + if (Current != lastCurrent || Total != lastTotal) { + if (Total != lastTotal) { + int Index = Total; + displayReplay->SetTotal(IndexToHMSF(Index, false, FramesPerSecond())); + if (!Initial) + displayReplay->Flush(); + } + displayReplay->SetProgress(Current, Total); + if (!Initial) + displayReplay->Flush(); + displayReplay->SetCurrent(IndexToHMSF(Current, false, FramesPerSecond())); + displayReplay->Flush(); + lastCurrent = Current; + } + lastTotal = Total; + ShowMode(); + return true; + } + return false; +} + +void cBDControl::TimeSearchDisplay(void) +{ + // from vdr-1.7.34 + char buf[64]; + // TRANSLATORS: note the trailing blank! + strcpy(buf, tr("Jump: ")); + int len = strlen(buf); + char h10 = '0' + (timeSearchTime >> 24); + char h1 = '0' + ((timeSearchTime & 0x00FF0000) >> 16); + char m10 = '0' + ((timeSearchTime & 0x0000FF00) >> 8); + char m1 = '0' + (timeSearchTime & 0x000000FF); + char ch10 = timeSearchPos > 3 ? h10 : '-'; + char ch1 = timeSearchPos > 2 ? h1 : '-'; + char cm10 = timeSearchPos > 1 ? m10 : '-'; + char cm1 = timeSearchPos > 0 ? m1 : '-'; + sprintf(buf + len, "%c%c:%c%c", ch10, ch1, cm10, cm1); + displayReplay->SetJump(buf); +} + +void cBDControl::TimeSearchProcess(eKeys Key) +{ + // from vdr-1.7.34 +#define STAY_SECONDS_OFF_END 10 + int Seconds = (timeSearchTime >> 24) * 36000 + ((timeSearchTime & 0x00FF0000) >> 16) * 3600 + ((timeSearchTime & 0x0000FF00) >> 8) * 600 + (timeSearchTime & 0x000000FF) * 60; + int Current = int(round(lastCurrent / FramesPerSecond())); + int Total = int(round(lastTotal / FramesPerSecond())); + switch (Key) { + case k0 ... k9: + if (timeSearchPos < 4) { + timeSearchTime <<= 8; + timeSearchTime |= Key - k0; + timeSearchPos++; + TimeSearchDisplay(); + } + break; + case kFastRew: + case kLeft: + case kFastFwd: + case kRight: { + int dir = ((Key == kRight || Key == kFastFwd) ? 1 : -1); + if (dir > 0) + Seconds = min(Total - Current - STAY_SECONDS_OFF_END, Seconds); + SkipSeconds(Seconds * dir); + timeSearchActive = false; + } + break; +#if 0 + case kPlayPause: +#endif + case kPlay: + case kUp: + case kPause: + case kDown: + case kOk: + Seconds = min(Total - STAY_SECONDS_OFF_END, Seconds); + Goto(Seconds); + timeSearchActive = false; + break; + default: + if (!(Key & k_Flags)) // ignore repeat/release keys + timeSearchActive = false; + break; + } + + if (!timeSearchActive) { + if (timeSearchHide) + Hide(); + else + displayReplay->SetJump(NULL); + ShowMode(); + } +} + +void cBDControl::TimeSearch(void) +{ + // from vdr-1.7.34 + timeSearchTime = timeSearchPos = 0; + timeSearchHide = false; + if (modeOnly) + Hide(); + if (!visible) { + Show(); + if (visible) + timeSearchHide = true; + else + return; + } + timeoutShow = 0; + TimeSearchDisplay(); + timeSearchActive = true; +} + + +eOSState cBDControl::ProcessKey(eKeys Key) +{ + // from vdr-1.7.34 + if (!Active()) + return osEnd; + if (visible) { + if (timeoutShow && time(NULL) > timeoutShow) { + Hide(); + ShowMode(); + timeoutShow = 0; + } + else if (modeOnly) + ShowMode(); + else + shown = ShowProgress(!shown) || shown; + } + if (timeSearchActive && Key != kNone) { + TimeSearchProcess(Key); + return osContinue; + } + bool DoShowMode = true; + + switch ((int)Key) { + case kUp: + case kPlay: Play(); + break; + case kDown: + case kPause: Pause(); + break; + case kRed: TimeSearch(); break; + case kGreen: + case kPrev: SkipSeconds(-60); + break; + case kYellow: + case kNext: SkipSeconds(60); + break; + case kBlue: + case kStop: Hide(); + return osEnd; + case kBack: + break; + default: { + DoShowMode = false; + switch (int(Key)) { + default: { + switch (Key) { + case kOk: if (visible && !modeOnly) { + Hide(); + DoShowMode = true; + } + else + Show(); + break; + default: return osUnknown; + } + } + } + } + } + if (DoShowMode) + ShowMode(); + + return osContinue; +} diff --git a/bdplayer.h b/bdplayer.h new file mode 100644 index 0000000..7b74a35 --- /dev/null +++ b/bdplayer.h @@ -0,0 +1,61 @@ +/* + * bdplayer.h: A player for BluRay discs + * + * See the README file for copyright information and how to reach the author. + * + */ + +#ifndef _BDPLAYER_H +#define _BDPLAYER_H + +#include <vdr/player.h> +#include <vdr/tools.h> + +class cBDPlayer; + +class cBDControl : public cControl { +private: + static int active; + cBDPlayer *player; + cString disc_name; + + cBDControl(); + cBDControl(cBDPlayer *Player); + + void Play(); + void Pause(); + void SkipSeconds(int seconds); + void Goto(int seconds); + + cSkinDisplayReplay *displayReplay; + bool visible, modeOnly, shown; + int lastCurrent, lastTotal; + bool lastPlay, lastForward; + int lastSpeed; + time_t timeoutShow; + bool timeSearchActive, timeSearchHide; + int timeSearchTime, timeSearchPos; + + void TimeSearchDisplay(void); + void TimeSearchProcess(eKeys Key); + void TimeSearch(void); + void ShowTimed(int Seconds = 0); + void ShowMode(void); + bool ShowProgress(bool Initial); + +public: + static cControl *Create(const char *Path); + static bool Active(void) { return active > 0; } + + virtual ~cBDControl(); + + bool Visible(void) { return visible; } + + virtual void Show(void); + virtual void Hide(void); + + virtual cString GetHeader(void); + virtual eOSState ProcessKey(eKeys Key); +}; + +#endif //_BDPLAYER_H diff --git a/bluray.c b/bluray.c new file mode 100644 index 0000000..f068127 --- /dev/null +++ b/bluray.c @@ -0,0 +1,118 @@ +/* + * bluray.c: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include <getopt.h> +#include <vdr/plugin.h> + +#include "discmgr.h" +#include "bdplayer.h" + +static const char *VERSION = "0.0.1"; +static const char *DESCRIPTION = "BluRay Player"; +static const char *MAINMENUENTRY = "Play BluRay Disc"; + + +class cPluginBluray : public cPlugin { +private: + // Add any member variables or functions you may need here. + cDiscMgr mgr; + +public: + cPluginBluray(void); + virtual ~cPluginBluray(); + 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 const char *MainMenuEntry(void) { return MAINMENUENTRY; } + virtual cOsdObject *MainMenuAction(void); + }; + +cPluginBluray::cPluginBluray(void) +{ + // Initialize any member variables here. + // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL + // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! +} + +cPluginBluray::~cPluginBluray() +{ + // Clean up after yourself! +} + +const char *cPluginBluray::CommandLineHelp(void) +{ + // Return a string that describes all known command line options. + return + " -D DEV, --device=DEV device used for BluRay playback (default "DEFAULT_DEVICE")\n" + " -p DIR, --path=DIR mount point for BluRay discs (default "DEFAULT_PATH")\n" + " -m CMD, --mount=CMD program used to mount BluRay disc (default "DEFAULT_MOUNTER")\n" + " -u CMD, --umount=CMD program used to unmount BluRay disc (default "DEFAULT_UNMOUNTER")\n" + " -e CMD, --eject=CMD program used to eject BluRay disc (default "DEFAULT_EJECT")\n"; +} + +bool cPluginBluray::ProcessArgs(int argc, char *argv[]) +{ + // Implement command line argument processing here if applicable. + // Implement command line argument processing here if applicable. + static const struct option long_options[] = { + { "device", optional_argument, NULL, 'D' }, + { "path", optional_argument, NULL, 'p' }, + { "mount", optional_argument, NULL, 'm' }, + { "umount", optional_argument, NULL, 'u' }, + { "eject", optional_argument, NULL, 'e' }, + { NULL, no_argument, NULL, 0 } + }; + + int c; + while ((c = getopt_long(argc, argv, "d:", long_options, NULL)) != -1) { + switch (c) { + case 'D': + mgr.SetDevice(optarg); + break; + case 'p': + mgr.SetPath(optarg); + break; + case 'm': + mgr.SetMountCmd(optarg); + break; + case 'u': + mgr.SetUnMountCmd(optarg); + break; + case 'e': + mgr.SetEjectCmd(optarg); + break; + default: + return false; + } + } + + return true; +} + +cOsdObject *cPluginBluray::MainMenuAction(void) +{ + // Perform the action when selected from the main VDR menu. + if (cBDControl::Active()) { + return NULL; + } + + if (!mgr.CheckDisc()) { + return NULL; + } + + cControl::Shutdown(); + + cControl *control = cBDControl::Create(mgr.GetPath()); + if (control) { + cControl::Launch(control); + } + + return NULL; +} + +VDRPLUGINCREATOR(cPluginBluray); // Don't touch this! diff --git a/discmgr.c b/discmgr.c new file mode 100644 index 0000000..11b3266 --- /dev/null +++ b/discmgr.c @@ -0,0 +1,141 @@ +/* + * discmgr.c: BluRay disc / drive manager + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include <unistd.h> + +#include <vdr/thread.h> +#include <vdr/tools.h> +#include <vdr/skins.h> + +#include "discmgr.h" + + +static bool DeviceOk(const char *DevName) +{ + struct stat ds; + + if (stat(DevName, &ds) == 0) { + if (S_ISBLK(ds.st_mode)) { + if (access(DevName, R_OK) == 0) + return true; + else + esyslog("ERROR: can't access device %s", DevName); + } + else + esyslog("ERROR: %s is not a device", DevName); + } + else + LOG_ERROR_STR(DevName); + + return false; +} + +static bool PathOk(const char *DirName) +{ + struct stat ds; + + if (stat(DirName, &ds) == 0) { + if (S_ISDIR(ds.st_mode)) { + if (access(DirName, R_OK | X_OK) == 0) + return true; + else + esyslog("ERROR: can't access mount point %s", DirName); + } + else + esyslog("ERROR: mount point %s is not a directory", DirName); + } + else + LOG_ERROR_STR(DirName); + + return false; +} + +cDiscMgr::cDiscMgr() +{ + Device = DEFAULT_DEVICE; + Path = DEFAULT_PATH; + MountCmd = DEFAULT_MOUNTER; + UnMountCmd = DEFAULT_UNMOUNTER; + EjectCmd = DEFAULT_EJECT; +} + +bool cDiscMgr::IsMounted() +{ + return PathOk(cString::sprintf("%s/BDMV", *Path)); +} + +void cDiscMgr::Mount(bool Retry) +{ + cString cmd = cString::sprintf("%s \"%s\" \"%s\"", *MountCmd, *Device, *Path); + isyslog("executing '%s'", *cmd); + SystemExec(cmd); + + if (Retry && !IsMounted()) { + /* retry */ + + cCondWait::SleepMs(3000); + + isyslog("executing '%s'", *cmd); + SystemExec(cmd); + } +} + +void cDiscMgr::UnMount() +{ + cString cmd = cString::sprintf("%s \"%s\"", *UnMountCmd, *Device); + isyslog("executing '%s'", *cmd); + SystemExec(cmd); +} + +void cDiscMgr::CloseTray() +{ + cString cmd = cString::sprintf("%s -t \"%s\"", *EjectCmd, *Device); + isyslog("executing '%s'", *cmd); + SystemExec(cmd); + + cCondWait::SleepMs(3000); +} + +void cDiscMgr::Eject() +{ + cString cmd = cString::sprintf("%s \"%s\"", *EjectCmd, *Device); + isyslog("executing '%s'", *cmd); + SystemExec(cmd); +} + +bool cDiscMgr::CheckDisc() +{ + if (!PathOk(Path)) { + Skins.Message(mtError, tr("Mount point does not exist!")); + return false; + } + + if (!IsMounted()) { + + if (!DeviceOk(Device)) { + Skins.Message(mtError, tr("Can't access device!")); + return false; + } + + Mount(false); + + if (!IsMounted()) { + Skins.Message(mtWarning, tr("Failed to mount BluRay disc, retry...")); + + CloseTray(); + Mount(); + + if (!PathOk(cString::sprintf("%s/BDMV/", *Path))) { + Skins.Message(mtError, tr("Failed to mount BluRay disc!")); + + return false; + } + } + } + + return true; +} diff --git a/discmgr.h b/discmgr.h new file mode 100644 index 0000000..ba85a84 --- /dev/null +++ b/discmgr.h @@ -0,0 +1,45 @@ +/* + * discmgr.h: BluRay disc / drive manager + * + * See the README file for copyright information and how to reach the author. + * + */ + +#ifndef _DISCMGR_H +#define _DISCMGR_H + +#include <vdr/tools.h> + +#define DEFAULT_DEVICE "/dev/sr0" +#define DEFAULT_PATH "/media/cdrom" +#define DEFAULT_MOUNTER "/bin/mount" +#define DEFAULT_UNMOUNTER "/bin/umount" +#define DEFAULT_EJECT "/usr/bin/eject" + +class cDiscMgr { + +private: + + cString Device, Path, MountCmd, UnMountCmd, EjectCmd; + + bool IsMounted(void); + void Mount(bool Retry = true); + void UnMount(void); + void CloseTray(void); + + public: + cDiscMgr(); + + const char *GetPath(void) { return Path; } + + void SetDevice(const char *D) { Device = D; } + void SetPath(const char *P) { Path = P; } + void SetMountCmd(const char *M) { MountCmd = M; } + void SetUnMountCmd(const char *U) { UnMountCmd = U; } + void SetEjectCmd(const char *E) { EjectCmd = E; } + + bool CheckDisc(void); + void Eject(void); +}; + +#endif //_DISCMGR_H |