summaryrefslogtreecommitdiff
path: root/ttxtsubsreceiver.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 /ttxtsubsreceiver.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 'ttxtsubsreceiver.c')
-rw-r--r--ttxtsubsreceiver.c253
1 files changed, 253 insertions, 0 deletions
diff --git a/ttxtsubsreceiver.c b/ttxtsubsreceiver.c
new file mode 100644
index 0000000..a497fd6
--- /dev/null
+++ b/ttxtsubsreceiver.c
@@ -0,0 +1,253 @@
+
+#include <stdlib.h>
+#include <vdr/receiver.h>
+#include <vdr/ringbuffer.h>
+
+#include "siinfo.h"
+#include "ttxtsubsfilter.h"
+#include "ttxtsubsreceiver.h"
+#include "teletext.h"
+
+#define MAXINDEXPAGELINES 24
+
+// ----- cTtxtSubsReceiver -----
+
+cTtxtSubsReceiver::cTtxtSubsReceiver(int Ca, struct ttxtpidinfo *PI)
+ :
+ cReceiver(Ca, -1, 1, PI->pid),
+ mGetMutex(),
+ mGetCond(),
+ mRingBuf(46 * 500, true),
+ mPI(*PI),
+ mIndexPageLines(0),
+ mIndexPageCol(0),
+ mIndexPageNo(0)
+{
+ int count = 0;
+ uint16_t *pages = (uint16_t *) malloc(sizeof(uint16_t) * mPI.pagecount);
+
+ // find a free page to put the index page on
+ mIndexPageNo = 0x100;
+ int again;
+ do {
+ again = 0;
+ for(int i = 0; i < count; i++) {
+ if(pages[i] == mIndexPageNo) {
+ mIndexPageNo++;
+ if((mIndexPageNo & 0x000f) == 0x000a)
+ mIndexPageNo += 6;
+ again = 1;
+ }
+ }
+ } while(again);
+
+ // get pages to record
+ for(int i = 0; i < mPI.pagecount; i++) {
+ // only subtitle pages
+ if(mPI.i[i].type != TTXT_SUBTITLE_PAGE &&
+ mPI.i[i].type != TTXT_SUBTITLE_HEARING_IMPAIRED_PAGE)
+ continue;
+
+ pages[count] = (mPI.i[i].mag << 8) + mPI.i[i].page;
+
+ AddIndexInfo(mPI.i[i].lang, mPI.i[i].type, pages[count]);
+
+ count++;
+ }
+
+ mFilter.SetPages(count, pages);
+ EndIndexInfo();
+
+ free(pages);
+}
+
+
+cTtxtSubsReceiver::~cTtxtSubsReceiver()
+{
+ // get any waiting threads going
+ mGetCond.Broadcast();
+}
+
+
+// returns pointer buf if there is new data
+uint8_t *cTtxtSubsReceiver::Get(uint8_t *buf)
+{
+ const cFrame *f;
+
+ f = mRingBuf.Get();
+ if(f) {
+ memcpy(buf, f->Data(), 46);
+ mRingBuf.Drop(f);
+ // fprintf(stderr, "cTtxtSubsReceiver::Get: returned data!\n");
+ return buf;
+ } else {
+ return NULL;
+ }
+}
+
+
+void cTtxtSubsReceiver::IndexPage(char ***lines, int *linecount)
+{
+ static char *lineptrs[MAXINDEXPAGELINES];
+
+ for(int i = 0; i < mIndexPageLines; i++)
+ lineptrs[i] = (char *) mIndexPage[i];
+
+ *linecount = mIndexPageLines;
+ *lines = lineptrs;
+}
+
+
+// wait for more data
+void cTtxtSubsReceiver::Wait(void)
+{
+ mGetMutex.Lock();
+ mGetCond.Wait(mGetMutex);
+ mGetMutex.Unlock();
+}
+
+
+void cTtxtSubsReceiver::Activate(bool 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 cTtxtSubsReceiver::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++) {
+ char buf[46];
+
+ if(0xff == Data[4 + i*46]) // stuffing data
+ continue;
+
+ if(mFilter.Filter((char *) Data + 4 + i*46, buf)) {
+ // fprintf(stderr, "Forward Packet:\n");
+ // print_line((char *) Data + 4 + i*46);
+ // print_line(buf);
+
+ cFrame *f = new cFrame((uchar *) buf, 46);
+ mRingBuf.Put(f);
+ mGetCond.Broadcast();
+ }
+ }
+}
+
+static void init_line(uint8_t *buf, uint8_t Y, uint8_t mag)
+{
+ struct ttxt_data_field *d = (struct ttxt_data_field *) buf;
+ uint8_t magbuf[2];
+
+ d->data_unit_id = 0x02; // EBU Teletxt non-subtitle data
+ d->data_unit_length = 0x2c;
+ d->par_loff = 0xc0; // reserved bits + unknown line
+ d->framing_code = 0xe4;
+ ham8_4byte((Y << 3) | (mag & 0x7), magbuf);
+ d->mag_addr_ham[0] = invtab[magbuf[0]];
+ d->mag_addr_ham[1] = invtab[magbuf[1]];
+}
+
+static void copy_inv_par(uint8_t *dest, uint8_t *src, int count)
+{
+ for(int i = 0; i < count; i++)
+ if(parity(src[i]))
+ dest[i] = invtab[src[i] | 0x80];
+ else
+ dest[i] = invtab[src[i]];
+}
+
+void cTtxtSubsReceiver::AddIndexInfo(char *lang, int type, uint16_t page)
+{
+ //fprintf(stderr, "AddIndexInfo: %c%c%c/%d/%03x\n", lang[0], lang[1], lang[2], type, page); // XXX
+
+ if(mIndexPageLines == MAXINDEXPAGELINES) {
+ fprintf(stderr, "cTtxtSubsReceiver::AddIndexInfo: Index page full!\n");
+ return;
+ }
+
+ if(mIndexPageLines == 0) { // make Y0 and info text
+ struct ttxt_data_field *d = (struct ttxt_data_field *) mIndexPage[0];
+ uint8_t buf[40];
+ size_t txtlen;
+
+ init_line(mIndexPage[mIndexPageLines], mIndexPageLines, mIndexPageNo >> 8);
+
+ d->data[0] = invtab[ham8_4nibble(mIndexPageNo & 0x000f)];
+ d->data[1] = invtab[ham8_4nibble((mIndexPageNo >> 4) & 0x000f)];
+ uint8_t ham_inv_zero = invtab[ham8_4nibble(0)];
+ d->data[2] = ham_inv_zero;
+ d->data[3] = ham_inv_zero;
+ d->data[4] = ham_inv_zero;
+ d->data[5] = ham_inv_zero;
+ d->data[6] = ham_inv_zero;
+ d->data[7] = ham_inv_zero;
+
+ txtlen = snprintf((char *) buf, 32, "%03x", mIndexPageNo);
+ copy_inv_par(d->data + 8, buf, txtlen);
+ for(int i = txtlen; i < 32; i++)
+ d->data[i+8] = invtab[' ']; // space already has correct parity
+
+ //print_line((char *) mIndexPage[mIndexPageLines]); // XXX
+
+ mIndexPageLines++;
+
+ init_line(mIndexPage[mIndexPageLines], mIndexPageLines, mIndexPageNo >> 8);
+ d = (struct ttxt_data_field *) mIndexPage[mIndexPageLines];
+ char *header = "Subtitles Index Page";
+ txtlen = strlen(header);
+ copy_inv_par(d->data, (uint8_t *) header, txtlen);
+ for(int i = txtlen; i < 40; i++)
+ d->data[i] = invtab[' ']; // space already has correct parity
+
+ //print_line((char *) mIndexPage[mIndexPageLines]); // XXX
+
+ mIndexPageLines++;
+ }
+
+ struct ttxt_data_field *d = (struct ttxt_data_field *) mIndexPage[mIndexPageLines];
+ uint8_t buf[10];
+
+ if(mIndexPageCol == 0) {
+ init_line(mIndexPage[mIndexPageLines], mIndexPageLines, mIndexPageNo >> 8);
+ for(int i = 0; i < 40; i++)
+ d->data[i+8] = invtab[' ']; // space already has correct parity
+ }
+
+ if(page < 0x100)
+ page += 0x800;
+
+ snprintf((char *) buf, 10, "%c%c%c%c%03x ", lang[0], lang[1], lang[2],
+ type == TTXT_SUBTITLE_PAGE ? ' ' :
+ type == TTXT_SUBTITLE_HEARING_IMPAIRED_PAGE ? 'h' : 'x',
+ page);
+
+ copy_inv_par(d->data+ mIndexPageCol*8, buf, 8);
+
+ //print_line((char *) mIndexPage[mIndexPageLines]); // XXX
+
+ mIndexPageCol++;
+
+ if(mIndexPageCol == 5) {
+ mIndexPageCol = 0;
+ mIndexPageLines++;
+ }
+}
+
+void cTtxtSubsReceiver::EndIndexInfo(void)
+{
+ if(mIndexPageCol != 0) {
+ mIndexPageCol = 0;
+ mIndexPageLines++;
+ }
+}