Feature #119 » ttxtsubs-pts-sync-v3.diff
| Makefile | ||
|---|---|---|
|
### The object files (add further files here):
|
||
|
OBJS = $(PLUGIN).o ttxtsubsdisplayer.o ttxtsubsdisplay.o teletext.o \
|
||
|
ttxtsubspagemenu.o ttxtsubschannelsettings.o ttxtsubslivereceiver.o
|
||
|
ttxtsubspagemenu.o ttxtsubschannelsettings.o ttxtsubslivereceiver.o ttxtaudio.o
|
||
|
### Implicit rules:
|
||
|
.PHONY: all all-redirect
|
||
| ttxtaudio.c | ||
|---|---|---|
|
/*
|
||
|
* cTtxtAudio.cpp
|
||
|
*
|
||
|
* Created on: Oct 31, 2012
|
||
|
* Author: Dimitar Petrovski
|
||
|
*/
|
||
|
#include "ttxtaudio.h"
|
||
|
int64_t cTtxtAudio::pts = 0;
|
||
|
cTtxtAudio::cTtxtAudio()
|
||
|
:cExternalAudio("TtxtAudio")
|
||
|
{
|
||
|
}
|
||
|
cTtxtAudio::~cTtxtAudio()
|
||
|
{
|
||
|
}
|
||
|
void cTtxtAudio::Play(const uchar* p, int Length, uchar Id)
|
||
|
{
|
||
|
int64_t tmp_pts = 0;
|
||
|
bool audio_pts_wrap = false;
|
||
|
if (PesHasPts(p))
|
||
|
tmp_pts = PesGetPts(p);
|
||
|
if (tmp_pts != 0) {
|
||
|
if ((pts > 0x1ffff0000LL) && (tmp_pts < 0x000100000LL)) {
|
||
|
audio_pts_wrap=true;
|
||
|
}
|
||
|
if (audio_pts_wrap) { tmp_pts+=0x200000000LL; }
|
||
|
}
|
||
|
if (tmp_pts != pts) { pts=tmp_pts; }
|
||
|
}
|
||
|
void cTtxtAudio::PlayTs(const uchar* Data, int Length)
|
||
|
{
|
||
|
// isyslog("ttxtsubs: cTtxtAudio::PlayTs");
|
||
|
tsToPesTtxtAudio.PutTs(Data, Length);
|
||
|
int l;
|
||
|
if (const uchar *p = tsToPesTtxtAudio.GetPes(l)) {
|
||
|
Play(p,l,0);
|
||
|
tsToPesTtxtAudio.Reset();
|
||
|
}
|
||
|
}
|
||
| ttxtaudio.h | ||
|---|---|---|
|
/*
|
||
|
* cTtxtAudio.h
|
||
|
*
|
||
|
* Created on: Oct 31, 2012
|
||
|
* Author: Dimitar Petrovski
|
||
|
*/
|
||
|
#ifndef CTTXTAUDIO_H_
|
||
|
#define CTTXTAUDIO_H_
|
||
|
#include <vdr/audio.h>
|
||
|
#include <vdr/remux.h>
|
||
|
class cTtxtAudio : public cExternalAudio
|
||
|
{
|
||
|
public:
|
||
|
cTtxtAudio();
|
||
|
virtual ~cTtxtAudio();
|
||
|
virtual void Play(const uchar *Data, int Length, uchar Id);
|
||
|
virtual void PlayTs(const uchar *Data, int Length);
|
||
|
virtual void Mute(bool On){};
|
||
|
virtual void Clear(void){};
|
||
|
static int64_t pts;
|
||
|
private:
|
||
|
cTsToPes tsToPesTtxtAudio;
|
||
|
};
|
||
|
#endif /* CTTXTAUDIO_H_ */
|
||
| ttxtsubs.c | ||
|---|---|---|
|
#include "ttxtsubspagemenu.h"
|
||
|
#include "ttxtsubschannelsettings.h"
|
||
|
#include "ttxtsubslivereceiver.h"
|
||
|
#include "ttxtaudio.h"
|
||
|
#if defined(APIVERSNUM) && APIVERSNUM < 10706
|
||
|
#error "This version of ttxtsubs only works with vdr version >= 1.7.6!"
|
||
| ... | ... | |
|
private:
|
||
|
cTtxtSubsPlayer *mDispl;
|
||
|
cMutex mDisplLock;;
|
||
|
cTtxtAudio *mAudio;
|
||
|
char mOldLanguage[4]; // language chosen from previous version
|
||
|
int mOldHearingImpaired; // HI setting chosen from previous version
|
||
| ... | ... | |
|
bool cPluginTtxtsubs::SetupParse(const char *Name, const char *Value)
|
||
|
{
|
||
|
if(!strcasecmp(Name, "Display")) { globals.mDoDisplay = atoi(Value); globals.mRealDoDisplay=globals.mDoDisplay; }
|
||
|
else if(!strcasecmp(Name, "ReplayDelay")) globals.mReplayDelay = atoi(Value);
|
||
|
else if(!strcasecmp(Name, "ReplayTsDelay")) globals.mReplayTsDelay = atoi(Value);
|
||
|
else if(!strcasecmp(Name, "MainMenuEntry")) globals.mMainMenuEntry = atoi(Value);
|
||
|
else if(!strcasecmp(Name, "FontSize")) globals.mFontSize = atoi(Value);
|
||
|
else if(!strcasecmp(Name, "OutlineWidth")) globals.mOutlineWidth = atoi(Value);
|
||
| ... | ... | |
|
if(!mDispl) {
|
||
|
isyslog("ttxtsubs: teletext subtitles replayer started with initial page %03x", backup_page);
|
||
|
mDispl = new cTtxtSubsPlayer(backup_page);
|
||
|
if (!mAudio)
|
||
|
mAudio = new cTtxtAudio();
|
||
|
ShowTtxt();
|
||
|
} else
|
||
|
esyslog("ttxtsubs: Error: StartTtxtPlay called when already started!");
|
||
| ... | ... | |
|
}
|
||
|
Add(new cMenuEditBoolItem(tr("Display Subtitles"), &mConf.mDoDisplay));
|
||
|
Add(new cMenuEditIntItem(tr("Replay Delay (PES)"), &mConf.mReplayDelay, 0, 5000));
|
||
|
Add(new cMenuEditIntItem(tr("Replay Delay (TS)"), &mConf.mReplayTsDelay, 0, 5000));
|
||
|
if(mConf.mMainMenuEntry < 0 || mConf.mMainMenuEntry >= numMainMenuAlts)
|
||
|
mConf.mMainMenuEntry = 0; // menu item segfaults if out of range
|
||
|
Add(new cMenuEditStraItem(tr("Main Menu Alternative"), &mConf.mMainMenuEntry,
|
||
| ... | ... | |
|
}
|
||
|
SetupStore("Display", mConf.mDoDisplay);
|
||
|
SetupStore("ReplayDelay", mConf.mReplayDelay);
|
||
|
SetupStore("ReplayTsDelay", mConf.mReplayTsDelay);
|
||
|
SetupStore("MainMenuEntry", mConf.mMainMenuEntry);
|
||
|
SetupStore("FontSize", mConf.mFontSize);
|
||
|
SetupStore("OutlineWidth", mConf.mOutlineWidth);
|
||
| ttxtsubsdisplay.c | ||
|---|---|---|
|
#include <vdr/font.h>
|
||
|
#include <vdr/config.h>
|
||
|
#include <vdr/tools.h>
|
||
|
#include <vdr/device.h>
|
||
|
#include "ttxtsubsglobals.h"
|
||
|
#include "ttxtsubsdisplay.h"
|
||
| ... | ... | |
|
ShowOSD();
|
||
|
}
|
||
|
//Taken from VDR dvbsubtitle.c
|
||
|
#define LimitTo32Bit(n) ((n) & 0x00000000FFFFFFFFL)
|
||
|
#define MAXDELTA 40000 // max. reasonable PTS/STC delta in ms
|
||
|
void cTtxtSubsDisplay::TtxtData(const uint8_t *Data, uint64_t sched_time)
|
||
|
void cTtxtSubsDisplay::TtxtData(const uint8_t *Data, int64_t sched_pts)
|
||
|
{
|
||
|
int mp;
|
||
|
int mag; // X in ETSI EN 300 706
|
||
| ... | ... | |
|
if (_pageState != collecting)
|
||
|
{
|
||
|
int diff = sched_time - cTimeMs::Now();
|
||
|
//printf("Got sched_time %llx, diff %d\n", sched_time, diff);
|
||
|
if (diff > 10) cCondWait::SleepMs(diff);
|
||
|
int64_t pts = cDevice::PrimaryDevice()->GetSTC();
|
||
|
//Taken from VDR dvbsubtitle.c
|
||
|
int64_t diff = (LimitTo32Bit(sched_pts) - LimitTo32Bit(pts));// some devices only deliver 32 bits
|
||
|
if (diff > (int64_t(1) << 31))
|
||
|
diff -= (int64_t(1) << 32);
|
||
|
else if (diff < -((int64_t(1) << 31) - 1))
|
||
|
diff += (int64_t(1) << 32);
|
||
|
diff /= 90;
|
||
|
if (diff > MAXDELTA)
|
||
|
{
|
||
|
//isyslog( "ttxtsubs: too long delay (%lld ms), discarding\n", diff );
|
||
|
return;
|
||
|
}
|
||
|
//isyslog( "ttxtsubs: delay (%ld ms) sched_pts=%lld pts=%lld\n", diff, sched_pts, pts );
|
||
|
while( diff > 10 )
|
||
|
{
|
||
|
cCondWait::SleepMs(min(diff,250LL));
|
||
|
if( !_doDisplay ) return;
|
||
|
diff -= 250;
|
||
|
}
|
||
|
}
|
||
|
_pageState = collecting;
|
||
| ttxtsubsdisplay.h | ||
|---|---|---|
|
void SetPage(int Pageno); // Pageno is 0x000 to 0x799
|
||
|
void Hide(void);
|
||
|
void Show(void);
|
||
|
void TtxtData(const uint8_t *, uint64_t sched_time = 0);
|
||
|
void TtxtData(const uint8_t *, int64_t sched_pts = 0);
|
||
|
protected:
|
||
|
void ShowOSD();
|
||
| ttxtsubsdisplayer.c | ||
|---|---|---|
|
#include "ttxtsubsdisplay.h"
|
||
|
#include "utils.h"
|
||
|
#include "ttxtsubsglobals.h"
|
||
|
#include "ttxtaudio.h"
|
||
|
#include <vdr/channels.h>
|
||
|
// ----- class cTtxtSubsDisplayer -----
|
||
|
cTtxtSubsDisplayer::cTtxtSubsDisplayer(int textpage)
|
||
|
:
|
||
|
cThread("TtxtSubsDisplayer"),
|
||
|
mDisp(new cTtxtSubsDisplay()),
|
||
|
mGetMutex(),
|
||
|
mGetCond(),
|
||
|
mRingBuf(94000, true),
|
||
|
mRingBuf(188000, true),
|
||
|
mRun(0)
|
||
|
{
|
||
|
mDisp->SetPage(textpage);
|
||
| ... | ... | |
|
f = mRingBuf.Get();
|
||
|
if(f) {
|
||
|
uint64_t sched_time;
|
||
|
memcpy(&sched_time, f->Data() + 46, sizeof(sched_time));
|
||
|
mDisp->TtxtData(f->Data(), sched_time);
|
||
|
mDisp->TtxtData(f->Data(), f->Pts());
|
||
|
mRingBuf.Drop(f);
|
||
|
} else {
|
||
|
// wait for more data
|
||
| ... | ... | |
|
void cTtxtSubsPlayer::PES_data(uchar *p, int Length, bool IsPesRecording, const struct tTeletextSubtitlePage teletextSubtitlePages[], int pageCount)
|
||
|
{
|
||
|
int i;
|
||
|
int64_t pts = 0;
|
||
|
//printf("cTtxtSubsPlayer: len: %d\n", Length); // XXX
|
||
| ... | ... | |
|
if(mHasFilteredStream && !mFoundLangPage)
|
||
|
SearchLanguagePage(p, Length);
|
||
|
if (PesHasPts(p)){
|
||
|
pts = PesGetPts(p);
|
||
|
// isyslog("ttxtsubs: found pts!");
|
||
|
}
|
||
|
//Some streams are missing the Subtitle pts so we use the audio instead
|
||
|
if (!pts && cTtxtAudio::pts)
|
||
|
pts = cTtxtAudio::pts;
|
||
|
// payload_unit_start_indicator
|
||
|
for(i = 1; (i*46) < Length ; i++) {
|
||
|
if(0xff == p[i*46]) // stuffing data
|
||
|
continue;
|
||
|
uint64_t sched_time=cTimeMs::Now() + (IsPesRecording ? globals.replayDelay() : globals.replayTsDelay());
|
||
|
cFrame *f = new cFrame(p + i*46, 46 + sizeof(sched_time));
|
||
|
memcpy(f->Data() + 46, &sched_time, sizeof(sched_time));
|
||
|
cFrame *f = new cFrame(p + i*46, 46, ftUnknown, -1, pts);
|
||
|
if (mRingBuf.Put(f))
|
||
|
{
|
||
|
mGetCond.Broadcast();
|
||
| ttxtsubsglobals.h | ||
|---|---|---|
|
mRealDoDisplay(1),
|
||
|
mMainMenuEntry(0),
|
||
|
mFontSize(20),
|
||
|
mOutlineWidth(2),
|
||
|
mReplayDelay(0),
|
||
|
mReplayTsDelay(0)
|
||
|
mOutlineWidth(2)
|
||
|
{
|
||
|
memset(mLanguages, 0, sizeof(mLanguages));
|
||
|
memset(mHearingImpaireds, 0, sizeof(mHearingImpaireds));
|
||
| ... | ... | |
|
int (*hearingImpaireds(void))[MAXLANGUAGES][2] {return &mHearingImpaireds;}
|
||
|
int langChoise(const char *lang, const int HI);
|
||
|
int replayDelay(void) {return mReplayDelay;}
|
||
|
int replayTsDelay(void) {return mReplayTsDelay;}
|
||
|
protected:
|
||
|
int mDoDisplay;
|
||
| ... | ... | |
|
int mOutlineWidth;
|
||
|
char mLanguages[MAXLANGUAGES][2][4];
|
||
|
int mHearingImpaireds[MAXLANGUAGES][2];
|
||
|
int mReplayDelay;
|
||
|
int mReplayTsDelay;
|
||
|
};
|
||
|
extern cTtxtsubsConf globals;
|
||
- « Previous
- 1
- 2
- 3
- Next »