summaryrefslogtreecommitdiff
path: root/ttxtsubsdisplayer.c
diff options
context:
space:
mode:
authorTobias Grimm <tobias@e-tobi.loc>2008-12-13 10:35:43 +0100
committerTobias Grimm <tobias@e-tobi.loc>2008-12-13 10:35:43 +0100
commit76ac85e366bfc27b3b688a4f13031c0735ea2436 (patch)
tree0f4f27bb366be92faee4e8c05fe01cccb32a9794 /ttxtsubsdisplayer.c
downloadvdr-plugin-ttxtsubs-0.0.1.tar.gz
vdr-plugin-ttxtsubs-0.0.1.tar.bz2
Initial version 0.0.1v0.0.1
Diffstat (limited to 'ttxtsubsdisplayer.c')
-rw-r--r--ttxtsubsdisplayer.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/ttxtsubsdisplayer.c b/ttxtsubsdisplayer.c
new file mode 100644
index 0000000..6983cd2
--- /dev/null
+++ b/ttxtsubsdisplayer.c
@@ -0,0 +1,256 @@
+
+#include "ttxtsubsdisplayer.h"
+#include "ttxtsubsdisplay.h"
+#include "utils.h"
+#include "ttxtsubs.h"
+#include "siinfo.h"
+
+// ----- class cTtxtSubsDisplayer -----
+
+cTtxtSubsDisplayer::cTtxtSubsDisplayer(int textpage)
+ :
+ mDisp(NULL),
+ mGetMutex(),
+ mGetCond(),
+ mRingBuf(18800, true),
+ mRun(0)
+{
+ mDisp = new cTtxtSubsDisplay();
+ mDisp->SetPage(textpage);
+ ShowDisplay();
+
+ mRun = 1;
+ this->Start(); // start thread
+}
+
+cTtxtSubsDisplayer::~cTtxtSubsDisplayer(void)
+{
+ // stop thread
+ mRun = false;
+ mGetCond.Broadcast();
+ this->Cancel(5);
+
+ if(mDisp) {
+ delete mDisp;
+ mDisp = NULL;
+ }
+}
+
+// handled messages in ring buffer - runs in a thread of its own
+void cTtxtSubsDisplayer::Action(void)
+{
+ while(mRun) {
+ const cFrame *f;
+
+ f = mRingBuf.Get();
+
+ if(f) {
+ mDisp->TtxtData(f->Data());
+ mRingBuf.Drop(f);
+ } else {
+ // wait for more data
+ mGetMutex.Lock();
+ mGetCond.TimedWait(mGetMutex, 500);
+ mDisp->TtxtData(NULL); // give display some idle time
+ mGetMutex.Unlock();
+ }
+ }
+}
+
+void cTtxtSubsDisplayer::ShowDisplay(void)
+{
+ mDisp->Show();
+}
+
+void cTtxtSubsDisplayer::HideDisplay(void)
+{
+ mDisp->Hide();
+}
+
+
+// ----- class cTtxtSubsLiveReceiver -----
+
+cTtxtSubsLiveReceiver::cTtxtSubsLiveReceiver(int Pid, int textpage)
+ :
+ cReceiver(0, -1, 1, Pid),
+ cTtxtSubsDisplayer(textpage)
+{
+}
+
+void cTtxtSubsLiveReceiver::Activate(bool On)
+{
+ //dprint("cTtxtSubsLiveReceiver::Activate: On:%d\n", On);
+}
+
+// Take TS packets and break out the teletext data
+// Buffer the data for processing in a separate thread
+// XXX We should do some filtering here to avoid unneccessary load!
+void cTtxtSubsLiveReceiver::Receive(uchar *Data, int Length)
+{
+ int i;
+
+ if(Length != 188) // should never happen
+ return;
+
+ if(Data[1] & 0x80) // transport_error_indicator
+ return;
+
+ // payload_unit_start_indicator
+ for(i = (Data[1] & 0x40) ? 1 : 0; i < 4; i++) {
+ if(0xff == Data[4 + i*46]) // stuffing data
+ continue;
+
+ cFrame *f = new cFrame(Data + 4 + i*46, 46);
+ mRingBuf.Put(f);
+ mGetCond.Broadcast();
+ }
+}
+
+// ----- class cTtxtSubsPlayer -----
+
+cTtxtSubsPlayer::cTtxtSubsPlayer(char *lang, int HI, int backup_textpage)
+ :
+ cTtxtSubsDisplayer(backup_textpage),
+ mHearingImpaired(HI),
+ mHasFilteredStream(0),
+ mFoundLangPage(0),
+ mLangInfoState(0)
+{
+ memcpy(mLanguage, lang, 3);
+ mLanguage[3] = '\0';
+}
+
+// Take PES packets and break out the teletext data
+// Buffer the data for processing in a separate thread
+// XXX We should do some filtering here to avoid unneccessary load!
+void cTtxtSubsPlayer::PES_data(uchar *p, int Length)
+{
+ int i;
+
+ //printf("cTtxtSubsPlayer: len: %d\n", Length); // XXX
+
+ if(Length < 46 || p[0] != 0 || p[1] != 0 || p[2] != 1 || p[3] != 0xbd || p[8] != 0x24 ||
+ p[45] < 0x10 || p[45] >= 0x20) {
+ fprintf(stderr, "cTtxtSubsPlayer::PES_data: bad indata!\n");
+ }
+
+ // Recorded teletext typically has payload type 0x10.
+ // We use the payload type 0x1f to indicate that we have our own
+ // filtered stream, if we find that we only use that.
+
+ if(p[45] == 0x1f && !mHasFilteredStream)
+ mHasFilteredStream = 1;
+
+ if(mHasFilteredStream && p[45] != 0x1f)
+ return; // other teletext data, ignore
+
+ if(mHasFilteredStream && !mFoundLangPage)
+ SearchLanguagePage(p, Length);
+
+ // payload_unit_start_indicator
+ for(i = 1; (i*46) < Length ; i++) {
+ if(0xff == p[i*46]) // stuffing data
+ continue;
+
+ cFrame *f = new cFrame(p + i*46, 46);
+ mRingBuf.Put(f);
+ mGetCond.Broadcast();
+ }
+}
+
+static void copy_inv_strip_par(uint8_t *dest, uint8_t *src, size_t len)
+{
+ size_t i;
+ for(i = 0; i < len; i++)
+ dest[i] = invtab[src[i]] & 0x7f;
+}
+
+void cTtxtSubsPlayer::SearchLanguagePage(uint8_t *p, int len)
+{
+ char *infoline = "Subtitles Index Page";
+ int foundlines = 0;
+ unsigned int foundNonHIPage = 0;
+ int foundNonHI = 0; // 1 = found non hearing impaired
+
+ if(len < (3*46))
+ return;
+
+ struct ttxt_data_field *d;
+ for(d = ((struct ttxt_data_field *) p) + 1; ((uint8_t *) d) < (p + len + 45); d++) {
+ int mp = UNHAM_INV(d->mag_addr_ham[0], d->mag_addr_ham[1]);
+ //int mag = mp & 0x7;
+ int packet = (mp >> 3) & 0x1f;
+ uint8_t buf[40];
+
+ if(d->data_unit_id != 0x02)
+ break; // a subtitle line
+
+ switch(foundlines) {
+ case 0:
+ if(packet != 0) // need a Y0 first
+ return;
+ foundlines++;
+ break;
+ case 1:
+ if(packet != 1) // need a Y1
+ return;
+ copy_inv_strip_par(buf, d->data, sizeof(buf));
+ if(memcmp((char *) buf, infoline, strlen(infoline)))
+ return;
+ foundlines++;
+ break;
+ case 2:
+ mLangInfoState++;
+ if(mLangInfoState == 3)
+ fprintf(stderr, "ttxtsubs: Language \"%c%c%c\" not found in recording, available languages:\n",
+ mLanguage[0], mLanguage[1], mLanguage[2]);
+
+ if(packet < 2) // need a Y2 or more
+ return;
+ copy_inv_strip_par(buf, d->data, sizeof(buf));
+ for(size_t i = 0; i < 40; i += 8) {
+ if(mLangInfoState == 3 && buf[i] >= 'a' && buf[i] <= 'z')
+ fprintf(stderr, " %c%c%c: %c%c%c %s\n", buf[i+4], buf[i+5], buf[i+6], buf[i], buf[i+1], buf[i+2],
+ buf[i+3] == ' ' ? "" : buf[i+3] == 'h' ? "(Hearing Impaired)" : "(Unknown type)");
+ if(buf[i] == mLanguage[0] &&
+ buf[i+1] == mLanguage[1] &&
+ buf[i+2] == mLanguage[2] &&
+ ((buf[i+3] == ' ') || (buf[i+3] == 'h')) &&
+ buf[i+4] >= '1' && buf[i+4] <= '8' &&
+ buf[i+5] >= '0' && buf[i+5] <= '9' &&
+ buf[i+6] >= '0' && buf[i+6] <= '9' &&
+ buf[i+7] == ' ') {
+ unsigned int page =
+ ((buf[i+4] - '0') << 8) +
+ ((buf[i+5] - '0') << 4) +
+ (buf[i+6] - '0');
+ if(page >= 0x100 && page <= 0x900) {
+ if(page >= 0x800)
+ page -= 0x800;
+
+ if(((!mHearingImpaired) && (buf[3+i] == ' ')) ||
+ (mHearingImpaired && (buf[3+i] == 'h'))) {
+ mDisp->SetPage(page);
+ mFoundLangPage = 1;
+ fprintf(stderr, "FOUND subtitle page: %03x\n", page); // XXX
+ return;
+ }
+ if(mHearingImpaired && (buf[3+i] == ' ')) {
+ foundNonHIPage = page;
+ foundNonHI = 1;
+ fprintf(stderr, "FOUND non hi subtitle page, remembering: %03x\n", page); // XXX
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if(foundNonHI) {
+ mDisp->SetPage(foundNonHIPage);
+ mFoundLangPage = 1;
+ fprintf(stderr, "Didn't find HI page, but found right language: %03x\n", foundNonHIPage); // XXX
+ return;
+ }
+}