summaryrefslogtreecommitdiff
path: root/ttxtsubs.c
diff options
context:
space:
mode:
Diffstat (limited to 'ttxtsubs.c')
-rw-r--r--ttxtsubs.c357
1 files changed, 357 insertions, 0 deletions
diff --git a/ttxtsubs.c b/ttxtsubs.c
new file mode 100644
index 0000000..da9c2f1
--- /dev/null
+++ b/ttxtsubs.c
@@ -0,0 +1,357 @@
+/*
+ * ttxtsubs.c: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: ttxtsubs.c,v 1.11 2003/03/07 05:52:58 ragge Exp $
+ */
+
+#include <vdr/plugin.h>
+#include <vdr/status.h>
+#include <vdr/vdrttxtsubshooks.h>
+#include <vdr/menuitems.h>
+#include <vdr/config.h>
+
+#include "ttxtsubsdisplayer.h"
+#include "ttxtsubsrecorder.h"
+#include "utils.h"
+#include "siinfo.h"
+#include "ttxtsubs.h"
+
+static const char *VERSION = "0.0.1";
+static const char *DESCRIPTION = "Teletext subtitles";
+//static const char *MAINMENUENTRY = "Ttxtsubs";
+
+// ISO 639-2 language codes in VDR order
+// XXX should be replaced by something that allows for other languages and for real language names!
+// <http://www.loc.gov/standards/iso639-2/englangn_ascii.html>
+char *gLanguages[] =
+{ "eng", //English
+ "deu", //Deutsch
+ "slv", //Slovenian
+ "ita", //Italian
+ "dut", //"nld"? Dutch
+ "por", //Portuguese
+ "fre", //"fra"? French
+ "nor", //Norwegian
+ "fin", //Finnish
+ "pol", //Polish
+ "spa", //Spanish
+ "gre", //Greek
+ "swe", //Swedish
+ "rom", //Romanian
+ "hun", //Hungarian
+ // Not in translations!
+ "dan" //Danish
+ };
+int gNumLanguages = sizeof(gLanguages) / sizeof(gLanguages[0]);
+
+class cPluginTtxtsubs : public cPlugin, public cStatus, public cVDRTtxtsubsHookListener {
+public:
+ cPluginTtxtsubs(void);
+ virtual ~cPluginTtxtsubs();
+
+ // -- cPlugin
+ 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 cOsdObject *MainMenuAction(void);
+ virtual cMenuSetupPage *SetupMenu(void);
+ virtual bool SetupParse(const char *Name, const char *Value);
+
+ // -- Setup stuff
+ virtual char *Language(void) { return mLanguage; };
+ virtual int HearingImpaired(void) { return mHearingImpaired; };
+ virtual int Record(void) { return mRecord; };
+
+ virtual void SetLanguage(char *lang) { strncpy(mLanguage, lang, 4); mLanguage[3] = '\0'; };
+ virtual void SetHearingImpaired(int hi) { mHearingImpaired = hi; };
+ virtual void SetRecord(int record) { mRecord = record; };
+
+ // -- cStatus
+ protected:
+ virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
+ virtual void Replaying(const cControl *Control, const char *Name);
+ // The given player control has started replaying Name. Name is the name of the
+ // recording, without any directory path. In case of a player that can't provide
+ // a name, Name can be a string that identifies the player type (like, e.g., "DVD").
+ // If Name is NULL, the replay has ended.
+ // virtual void OsdClear(void) { ShowTtxt(); }
+ // virtual void OsdTitle(const char *Title) { HideTtxt(); }
+ // virtual void OsdStatusMessage(const char *Message) { HideTtxt(); }
+ // virtual void OsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue) { HideTtxt(); }
+ // virtual void OsdCurrentItem(const char *Text) { HideTtxt(); }
+ // virtual void OsdTextItem(const char *Text, bool Scroll) { HideTtxt(); }
+ // virtual void OsdChannel(const char *Text) { HideTtxt(); }
+ // virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle) { HideTtxt(); }
+
+ // -- cVDRTtxtsubsHookListener
+ virtual void HideOSD(void) { HideTtxt(); }
+ virtual void ShowOSD(void) { ShowTtxt(); }
+ virtual void PlayerTeletextData(uint8_t *p, int length);
+ virtual cTtxtSubsRecorderBase *NewTtxtSubsRecorder(cDevice *dev, const cChannel *ch);
+
+ // -- internal
+ private:
+ void StartTtxtLive(const cDevice *Device, int pid, int page);
+ void StartTtxtPlay(int page);
+ void StopTtxt(void);
+ void ShowTtxt(void);
+ void HideTtxt(void);
+
+private:
+ // Add any member variables or functions you may need here.
+ cTtxtSubsDisplayer *mRec;
+
+ // Setup items
+ char mLanguage[4];
+ int mHearingImpaired;
+ int mRecord;
+
+ // ugly hack for now
+ int mPage;
+};
+
+class cMenuSetupTtxtsubs : public cMenuSetupPage {
+ public:
+ cMenuSetupTtxtsubs(cPluginTtxtsubs *ttxtsubs);
+ protected:
+ virtual void Store(void);
+ private:
+ cPluginTtxtsubs *mTtxtsubs;
+ char mLanguage[4];
+ int mLanguageNo;
+ int mHearingImpaired;
+ int mRecord;
+};
+
+
+cPluginTtxtsubs::cPluginTtxtsubs(void)
+ :
+ mRec(NULL),
+ mHearingImpaired(0),
+ mRecord(1),
+ mPage(0x199)
+{
+ // 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!
+
+ strncpy(mLanguage, "unk", 4);
+}
+
+cPluginTtxtsubs::~cPluginTtxtsubs()
+{
+ // Clean up after yourself!
+}
+
+const char *cPluginTtxtsubs::CommandLineHelp(void)
+{
+ // Return a string that describes all known command line options.
+ return NULL;
+}
+
+bool cPluginTtxtsubs::ProcessArgs(int argc, char *argv[])
+{
+ // Implement command line argument processing here if applicable.
+ return true;
+}
+
+bool cPluginTtxtsubs::Start(void)
+{
+ // Start any background activities the plugin shall perform.
+
+ if(!memcmp(mLanguage, "unk", 3)) {
+ int n = Setup.OSDLanguage;
+ if(n > gNumLanguages) {
+ strncpy(mLanguage, "eng", 4);
+ } else {
+ strncpy(mLanguage, gLanguages[n], 4);
+ mLanguage[3] = '\0';
+ }
+ }
+
+ //dprint("cPluginTtxtsubs::Start\n");
+
+ HookAttach();
+
+ return true;
+}
+
+void cPluginTtxtsubs::Housekeeping(void)
+{
+ // Perform any cleanup or other regular tasks.
+}
+
+cOsdObject *cPluginTtxtsubs::MainMenuAction(void)
+{
+ // Perform the action when selected from the main VDR menu.
+ return NULL;
+}
+
+cMenuSetupPage *cPluginTtxtsubs::SetupMenu(void)
+{
+ return new cMenuSetupTtxtsubs(this);
+}
+
+bool cPluginTtxtsubs::SetupParse(const char *Name, const char *Value)
+{
+ if(!strcasecmp(Name, "Language")) { strncpy(mLanguage, Value, 4); mLanguage[3] = '\0'; }
+ else if(!strcasecmp(Name, "HearingImpaired")) mHearingImpaired = atoi(Value);
+ else if(!strcasecmp(Name, "Record")) mRecord = atoi(Value);
+ else
+ return false;
+ return true;
+}
+
+void cPluginTtxtsubs::ChannelSwitch(const cDevice *Device, int ChannelNumber)
+{
+ if(ChannelNumber) {
+ cChannel *c = Channels.GetByNumber(ChannelNumber);
+ if(c) {
+ struct ttxtinfo info;
+ int pid, page;
+
+ if(GetTtxtInfo(Device->DeviceNumber(), c->Sid(), c->Vpid(), &info)) {
+ fprintf(stderr, "ttxtsubs: Error: GetTtxtInfo failed!\n");
+ } else {
+ if(FindSubs(&info, mLanguage, mHearingImpaired, &pid, &page)) {
+ //fprintf(stderr, "CHANNELSWITCH, pid: %d page: %x\n", pid, page);
+ mPage = page; // XXX remember this for playback (temporary hack)!
+ StartTtxtLive(Device, pid, page);
+ }
+ FreeTtxtInfoData(&info);
+ }
+ }
+ } else
+ StopTtxt();
+}
+
+void cPluginTtxtsubs::Replaying(const cControl *Control, const char *Name)
+{
+ StopTtxt();
+ StartTtxtPlay(mPage); // XXX should get page in some other way!
+}
+
+void cPluginTtxtsubs::PlayerTeletextData(uint8_t *p, int length)
+{
+ cTtxtSubsPlayer *r = dynamic_cast<cTtxtSubsPlayer *>(mRec);
+
+ if(!r) {
+ fprintf(stderr, "ttxtsubs: ERROR: not a cTtxtSubsPlayer!\n");
+ return;
+ }
+
+ r->PES_data(p, length);
+}
+
+cTtxtSubsRecorderBase *cPluginTtxtsubs::NewTtxtSubsRecorder(cDevice *dev, const cChannel *ch)
+{
+ if(mRecord)
+ return new cTtxtSubsRecorder(dev, ch, mLanguage, mHearingImpaired);
+ else
+ return NULL;
+}
+
+
+// -- internal
+
+void cPluginTtxtsubs::StartTtxtLive(const cDevice *Device, int pid, int page)
+{
+ //dprint("cPluginTtxtsubs::StartTtxtLive\n");
+
+ if(!mRec) {
+ cTtxtSubsLiveReceiver *r;
+ //dprint("teletext subtitles started on pid %d\n", pid);
+ mRec = r = new cTtxtSubsLiveReceiver(pid, page);
+ if(!cDevice::PrimaryDevice()->AttachReceiver(r))
+ fprintf(stderr, "ttxtsubs: Error: AttachReceiver failed!\n"); //
+ } else
+ fprintf(stderr, "ttxtsubs: Error: StartTtxtLive called when already started!\n");
+}
+
+void cPluginTtxtsubs::StartTtxtPlay(int backup_page)
+{
+ //dprint("cPluginTtxtsubs::StartTtxtPlay\n");
+
+ if(!mRec) {
+ dprint("ttxtsubs: teletext subtitles replayer started with initial page %03x\n", backup_page);
+ mRec = new cTtxtSubsPlayer(mLanguage, mHearingImpaired, backup_page);
+ } else
+ fprintf(stderr, "ttxtsubs: Error: StartTtxtPlay called when already started!\n");
+}
+
+void cPluginTtxtsubs::StopTtxt(void)
+{
+ //dprint("cPluginTtxtsubs::StopTtxt\n");
+
+ if(mRec) {
+ HideTtxt();
+ delete mRec;
+ mRec = NULL;
+ }
+}
+
+void cPluginTtxtsubs::ShowTtxt(void)
+{
+ if(mRec)
+ mRec->ShowDisplay();
+}
+
+void cPluginTtxtsubs::HideTtxt(void)
+{
+ if(mRec)
+ mRec->HideDisplay();
+}
+
+// ----- cMenuSetupTtxtsubs -----
+
+cMenuSetupTtxtsubs::cMenuSetupTtxtsubs(cPluginTtxtsubs *ttxtsubs)
+ :
+ mTtxtsubs(ttxtsubs),
+ mLanguageNo(-1),
+ mHearingImpaired(mTtxtsubs->HearingImpaired()),
+ mRecord(mTtxtsubs->Record())
+{
+ memcpy(mLanguage, ttxtsubs->Language(), 3);
+ mLanguage[3] = '\0';
+
+ for(int i = 0; i < gNumLanguages; i++) {
+ if(!memcmp(mLanguage, gLanguages[i], 3)) {
+ mLanguageNo = i;
+ break;
+ }
+ }
+
+ if(mLanguageNo >= 0)
+ Add(new cMenuEditStraItem(tr("Language"), &mLanguageNo, gNumLanguages, gLanguages));
+ else
+ Add(new cMenuEditStrItem(tr("Language"), mLanguage, 4, "abcdefghijklmnopqrstuvwxyz"));
+
+ Add(new cMenuEditBoolItem(tr("Hearing Impaired"), &mHearingImpaired, tr("no"), tr("yes")));
+ Add(new cMenuEditBoolItem(tr("Record Subtitles"), &mRecord, tr("no"), tr("yes")));
+}
+
+void cMenuSetupTtxtsubs::Store(void)
+{
+ if(mLanguageNo >= 0) {
+ SetupStore("Language", gLanguages[mLanguageNo]);
+ mTtxtsubs->SetLanguage(gLanguages[mLanguageNo]);
+ } else {
+ SetupStore("Language", mLanguage);
+ mTtxtsubs->SetLanguage(mLanguage);
+ }
+
+ SetupStore("HearingImpaired", mHearingImpaired);
+ mTtxtsubs->SetHearingImpaired(mHearingImpaired);
+
+ SetupStore("Record", mRecord);
+ mTtxtsubs->SetRecord(mRecord);
+}
+
+
+VDRPLUGINCREATOR(cPluginTtxtsubs); // Don't touch this!