diff options
author | Tobias Grimm <tobias@e-tobi.loc> | 2008-12-13 10:35:43 +0100 |
---|---|---|
committer | Tobias Grimm <tobias@e-tobi.loc> | 2008-12-13 10:35:43 +0100 |
commit | 76ac85e366bfc27b3b688a4f13031c0735ea2436 (patch) | |
tree | 0f4f27bb366be92faee4e8c05fe01cccb32a9794 /ttxtsubsdisplayer.c | |
download | vdr-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.c | 256 |
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; + } +} |