Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Index: libs/libmythtv/r5000recorder.cpp
- ===================================================================
- --- libs/libmythtv/r5000recorder.cpp (revision 0)
- +++ libs/libmythtv/r5000recorder.cpp (revision 4)
- @@ -0,0 +1,285 @@
- +/**
- + * R5000Recorder
- + * Copyright (c) 2005 by Jim Westfall and Dave Abrahams
- + * Distributed as part of MythTV under GPL v2 and later.
- + */
- +
- +// MythTV includes
- +#include "r5000recorder.h"
- +#include "r5000channel.h"
- +#include "mythcontext.h"
- +#include "mpegtables.h"
- +#include "mpegstreamdata.h"
- +#include "tv_rec.h"
- +
- +#define LOC QString("R5000RecBase(%1): ").arg(channel->GetDevice())
- +#define LOC_ERR QString("R5000RecBase(%1), Error: ").arg(channel->GetDevice())
- +
- +R5000Recorder::R5000Recorder(TVRec *rec, R5000Channel *chan) :
- + DTVRecorder(rec),
- + channel(chan), isopen(false)
- +{
- + //_wait_for_keyframe_option = false;
- +}
- +
- +R5000Recorder::~R5000Recorder()
- +{
- + Close();
- +}
- +
- +bool R5000Recorder::Open(void)
- +{
- + if (!isopen)
- + isopen = channel->GetR5000Device()->OpenPort();
- +
- + return isopen;
- +}
- +
- +void R5000Recorder::Close(void)
- +{
- + if (isopen)
- + {
- + channel->GetR5000Device()->ClosePort();
- + isopen = false;
- + }
- +}
- +
- +void R5000Recorder::StartStreaming(void)
- +{
- + channel->GetR5000Device()->AddListener(this);
- +}
- +
- +void R5000Recorder::StopStreaming(void)
- +{
- + channel->GetR5000Device()->RemoveListener(this);
- +}
- +
- +void R5000Recorder::StartRecording(void)
- +{
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "StartRecording");
- +
- + if (!Open())
- + {
- + _error = true;
- + return;
- + }
- +
- + request_recording = true;
- + recording = true;
- +
- + StartStreaming();
- +
- + while (request_recording)
- + {
- + if (!PauseAndWait())
- + usleep(50 * 1000);
- + }
- +
- + StopStreaming();
- + FinishRecording();
- +
- + recording = false;
- +}
- +
- +void R5000Recorder::run(void)
- +{
- + LOG(VB_RECORD, LOG_INFO, LOC + "run");
- +
- + if (!Open())
- + {
- + _error = "Failed to open R5000 device";
- + LOG(VB_GENERAL, LOG_ERR, LOC + _error);
- + return;
- + }
- +
- + {
- + QMutexLocker locker(&pauseLock);
- + request_recording = true;
- + recording = true;
- + recordingWait.wakeAll();
- + }
- +
- + StartStreaming();
- +
- + while (IsRecordingRequested() && !IsErrored())
- + {
- + if (PauseAndWait())
- + continue;
- +
- + if (!IsRecordingRequested())
- + break;
- +
- + { // sleep 1 seconds unless StopRecording() or Unpause() is called,
- + // just to avoid running this too often.
- + QMutexLocker locker(&pauseLock);
- + if (!request_recording || request_pause)
- + continue;
- + unpauseWait.wait(&pauseLock, 1000);
- + }
- + }
- +
- + StopStreaming();
- + FinishRecording();
- +
- + QMutexLocker locker(&pauseLock);
- + recording = false;
- + recordingWait.wakeAll();
- +}
- +
- +void R5000Recorder::AddData(const unsigned char *data, uint len)
- +{
- + uint bufsz = buffer.size();
- + if ((SYNC_BYTE == data[0]) && (TSPacket::kSize == len) &&
- + (TSPacket::kSize > bufsz))
- + {
- + if (bufsz)
- + buffer.clear();
- +
- + ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(data)));
- + return;
- + }
- +
- + buffer.insert(buffer.end(), data, data + len);
- + bufsz += len;
- +
- + int sync_at = -1;
- + for (uint i = 0; (i < bufsz) && (sync_at < 0); i++)
- + {
- + if (buffer[i] == SYNC_BYTE)
- + sync_at = i;
- + }
- +
- + if (sync_at < 0)
- + return;
- +
- + if (bufsz < 30 * TSPacket::kSize)
- + return; // build up a little buffer
- +
- + while (sync_at + TSPacket::kSize < bufsz)
- + {
- + ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(
- + &buffer[0] + sync_at)));
- +
- + sync_at += TSPacket::kSize;
- + }
- +
- + buffer.erase(buffer.begin(), buffer.begin() + sync_at);
- +
- + return;
- +}
- +
- +bool R5000Recorder::ProcessTSPacket(const TSPacket &tspacket)
- +{
- + if (tspacket.TransportError())
- + return true;
- +
- + if (tspacket.Scrambled())
- + return true;
- +
- + if (! GetStreamData())
- + return true;
- + if (tspacket.HasAdaptationField())
- + GetStreamData()->HandleAdaptationFieldControl(&tspacket);
- +
- + if (tspacket.HasPayload())
- + {
- + const unsigned int lpid = tspacket.PID();
- + // Pass or reject packets based on PID, and parse info from them
- + if (lpid == GetStreamData()->VideoPIDSingleProgram())
- + {
- + ProgramMapTable *pmt = GetStreamData()->PMTSingleProgram();
- + uint video_stream_type = pmt->StreamType(pmt->FindPID(lpid));
- +
- + if (video_stream_type == StreamID::H264Video)
- + _buffer_packets = !FindH264Keyframes(&tspacket);
- + else if (StreamID::IsVideo(video_stream_type))
- + _buffer_packets = !FindMPEG2Keyframes(&tspacket);
- +
- + if ((video_stream_type != StreamID::H264Video) || _seen_sps)
- + BufferedWrite(tspacket);
- + }
- + else if (GetStreamData()->IsAudioPID(lpid))
- + {
- + _buffer_packets = !FindAudioKeyframes(&tspacket);
- + BufferedWrite(tspacket);
- + }
- + else if (GetStreamData()->IsListeningPID(lpid))
- + GetStreamData()->HandleTSTables(&tspacket);
- + else if (GetStreamData()->IsWritingPID(lpid))
- + BufferedWrite(tspacket);
- + }
- +
- + return true;
- +}
- +
- +void R5000Recorder::SetOptionsFromProfile(RecordingProfile *profile,
- + const QString &videodev,
- + const QString &audiodev,
- + const QString &vbidev)
- +{
- + (void)videodev;
- + (void)audiodev;
- + (void)vbidev;
- + (void)profile;
- +}
- +
- +// documented in recorderbase.cpp
- +bool R5000Recorder::PauseAndWait(int timeout)
- +{
- + if (request_pause)
- + {
- + LOG(VB_RECORD, LOG_INFO, LOC +
- + QString("PauseAndWait(%1) -- pause").arg(timeout));
- + if (!IsPaused(true))
- + {
- + StopStreaming();
- + paused = true;
- + pauseWait.wakeAll();
- + if (tvrec)
- + tvrec->RecorderPaused();
- + }
- + QMutex unpause_lock;
- + unpause_lock.lock();
- + unpauseWait.wait(&unpause_lock, timeout);
- + }
- + if (!request_pause && IsPaused(true))
- + {
- + LOG(VB_RECORD, LOG_INFO, LOC +
- + QString("PauseAndWait(%1) -- unpause").arg(timeout));
- + StartStreaming();
- + paused = false;
- + }
- + return paused;
- +}
- +
- +void R5000Recorder::SetStreamData(void)
- +{
- + _stream_data->AddMPEGSPListener(this);
- +
- + if (_stream_data->DesiredProgram() >= 0)
- + _stream_data->SetDesiredProgram(_stream_data->DesiredProgram());
- +}
- +
- +void R5000Recorder::HandleSingleProgramPAT(ProgramAssociationTable *pat)
- +{
- + if (!pat)
- + {
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "HandleSingleProgramPAT(NULL)");
- + return;
- + }
- + int next = (pat->tsheader()->ContinuityCounter()+1)&0xf;
- + pat->tsheader()->SetContinuityCounter(next);
- + BufferedWrite(*(reinterpret_cast<const TSPacket*>(pat->tsheader())));
- +}
- +
- +void R5000Recorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
- +{
- + if (!pmt)
- + {
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "HandleSingleProgramPMT(NULL)");
- + return;
- + }
- + int next = (pmt->tsheader()->ContinuityCounter()+1)&0xf;
- + pmt->tsheader()->SetContinuityCounter(next);
- + BufferedWrite(*(reinterpret_cast<const TSPacket*>(pmt->tsheader())));
- +}
- Index: libs/libmythtv/tv_rec.h
- ===================================================================
- --- libs/libmythtv/tv_rec.h (revision 1)
- +++ libs/libmythtv/tv_rec.h (revision 4)
- @@ -46,6 +46,7 @@
- class V4LChannel;
- class HDHRChannel;
- class CetonChannel;
- +class R5000Channel;
- class MPEGStreamData;
- class ProgramMapTable;
- @@ -264,6 +265,7 @@
- bool enter_power_save_mode);
- void CloseChannel(void);
- DTVChannel *GetDTVChannel(void);
- + R5000Channel *GetR5000Channel(void);
- V4LChannel *GetV4LChannel(void);
- bool SetupSignalMonitor(
- Index: libs/libmythtv/r5000signalmonitor.cpp
- ===================================================================
- --- libs/libmythtv/r5000signalmonitor.cpp (revision 0)
- +++ libs/libmythtv/r5000signalmonitor.cpp (revision 4)
- @@ -0,0 +1,294 @@
- +// -*- Mode: c++ -*-
- +// Copyright (c) 2006, Daniel Thor Kristjansson
- +
- +#include <pthread.h>
- +#include <fcntl.h>
- +#include <unistd.h>
- +#include <sys/select.h>
- +
- +#include "mythcontext.h"
- +#include "mythdbcon.h"
- +#include "atscstreamdata.h"
- +#include "mpegtables.h"
- +#include "atsctables.h"
- +#include "r5000channel.h"
- +#include "r5000signalmonitor.h"
- +
- +#define LOC QString("R5kSM(%1): ").arg(channel->GetDevice())
- +#define LOC_WARN QString("R5kSM(%1), Warning: ").arg(channel->GetDevice())
- +#define LOC_ERR QString("R5kSM(%1), Error: ").arg(channel->GetDevice())
- +
- +const uint R5000SignalMonitor::kPowerTimeout = 3000; /* ms */
- +const uint R5000SignalMonitor::kBufferTimeout = 5000; /* ms */
- +
- +QMap<void*,uint> R5000SignalMonitor::pat_keys;
- +QMutex R5000SignalMonitor::pat_keys_lock;
- +
- +/** \fn R5000SignalMonitor::R5000SignalMonitor(int,R5000Channel*,uint,const char*)
- + * \brief Initializes signal lock and signal values.
- + *
- + * Start() must be called to actually begin continuous
- + * signal monitoring. The timeout is set to 3 seconds,
- + * and the signal threshold is initialized to 0%.
- + *
- + * \param db_cardnum Recorder number to monitor,
- + * if this is less than 0, SIGNAL events will not be
- + * sent to the frontend even if SetNotifyFrontend(true)
- + * is called.
- + * \param _channel R5000Channel for card
- + * \param _flags Flags to start with
- + * \param _name Name for Qt signal debugging
- + */
- +R5000SignalMonitor::R5000SignalMonitor(
- + int db_cardnum,
- + R5000Channel *_channel,
- + uint64_t _flags, const char *_name) :
- + DTVSignalMonitor(db_cardnum, _channel, _flags),
- + dtvMonitorRunning(false),
- + stb_needs_retune(true),
- + stb_needs_to_wait_for_pat(false),
- + stb_needs_to_wait_for_power(false)
- +{
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "ctor");
- +
- + signalStrength.SetThreshold(65);
- +
- + AddFlags(kSigMon_WaitForSig);
- +
- + stb_needs_retune =
- + (R5000Device::kAVCPowerOff == _channel->GetPowerState());
- +}
- +
- +/** \fn R5000SignalMonitor::~R5000SignalMonitor()
- + * \brief Stops signal monitoring and table monitoring threads.
- + */
- +R5000SignalMonitor::~R5000SignalMonitor()
- +{
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "dtor");
- + Stop();
- +}
- +
- +/** \fn R5000SignalMonitor::Stop(void)
- + * \brief Stop signal monitoring and table monitoring threads.
- + */
- +void R5000SignalMonitor::Stop(void)
- +{
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "Stop() -- begin");
- + SignalMonitor::Stop();
- + if (dtvMonitorRunning)
- + {
- + dtvMonitorRunning = false;
- + pthread_join(table_monitor_thread, NULL);
- + }
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "Stop() -- end");
- +}
- +
- +void R5000SignalMonitor::HandlePAT(const ProgramAssociationTable *pat)
- +{
- + AddFlags(kDTVSigMon_PATSeen);
- +
- + R5000Channel *fwchan = dynamic_cast<R5000Channel*>(channel);
- + if (!fwchan)
- + return;
- +
- + bool crc_bogus = !fwchan->GetR5000Device()->IsSTBBufferCleared();
- + if (crc_bogus && stb_needs_to_wait_for_pat &&
- + (stb_wait_for_pat_timer.elapsed() < (int)kBufferTimeout))
- + {
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "HandlePAT() ignoring PAT");
- + uint tsid = pat->TransportStreamID();
- + GetStreamData()->SetVersionPAT(tsid, -1,0);
- + return;
- + }
- +
- + if (crc_bogus && stb_needs_to_wait_for_pat)
- + {
- + LOG(VB_GENERAL, LOG_DEBUG, LOC_WARN + "Wait for valid PAT timed out");
- + stb_needs_to_wait_for_pat = false;
- + }
- +
- + DTVSignalMonitor::HandlePAT(pat);
- +}
- +
- +void R5000SignalMonitor::HandlePMT(uint pnum, const ProgramMapTable *pmt)
- +{
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "HandlePMT()");
- +
- + AddFlags(kDTVSigMon_PMTSeen);
- +
- + if (!HasFlags(kDTVSigMon_PATMatch))
- + {
- + GetStreamData()->SetVersionPMT(pnum, -1,0);
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "HandlePMT() ignoring PMT");
- + return;
- + }
- +
- + DTVSignalMonitor::HandlePMT(pnum, pmt);
- +}
- +
- +void *R5000SignalMonitor::TableMonitorThread(void *param)
- +{
- + R5000SignalMonitor *mon = (R5000SignalMonitor*) param;
- + mon->RunTableMonitor();
- + return NULL;
- +}
- +
- +void R5000SignalMonitor::RunTableMonitor(void)
- +{
- + stb_needs_to_wait_for_pat = true;
- + stb_wait_for_pat_timer.start();
- + dtvMonitorRunning = true;
- +
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "RunTableMonitor(): -- begin");
- +
- + R5000Channel *lchan = dynamic_cast<R5000Channel*>(channel);
- + if (!lchan)
- + {
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "RunTableMonitor(): -- err end");
- + dtvMonitorRunning = false;
- + return;
- + }
- +
- + R5000Device *dev = lchan->GetR5000Device();
- +
- + dev->OpenPort();
- + dev->AddListener(this);
- +
- + while (dtvMonitorRunning && GetStreamData())
- + usleep(100000);
- +
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "RunTableMonitor(): -- shutdown ");
- +
- + dev->RemoveListener(this);
- + dev->ClosePort();
- +
- + dtvMonitorRunning = false;
- +
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "RunTableMonitor(): -- end");
- +}
- +
- +void R5000SignalMonitor::AddData(const unsigned char *data, uint len)
- +{
- + if (!dtvMonitorRunning)
- + return;
- +
- + if (GetStreamData())
- + GetStreamData()->ProcessData((unsigned char *)data, len);
- +}
- +
- +/** \fn R5000SignalMonitor::UpdateValues(void)
- + * \brief Fills in frontend stats and emits status Qt signals.
- + *
- + * This function uses five ioctl's FE_READ_SNR, FE_READ_SIGNAL_STRENGTH
- + * FE_READ_BER, FE_READ_UNCORRECTED_BLOCKS, and FE_READ_STATUS to obtain
- + * statistics from the frontend.
- + *
- + * This is automatically called by MonitorLoop(), after Start()
- + * has been used to start the signal monitoring thread.
- + */
- +void R5000SignalMonitor::UpdateValues(void)
- +{
- + if (!running || exit)
- + return;
- +
- + //if (!IsChannelTuned())
- + // return;
- +
- + if (dtvMonitorRunning)
- + {
- + EmitStatus();
- + if (IsAllGood())
- + SendMessageAllGood();
- + // TODO dtv signals...
- +
- + update_done = true;
- + return;
- + }
- +
- + if (stb_needs_to_wait_for_power &&
- + (stb_wait_for_power_timer.elapsed() < (int)kPowerTimeout))
- + {
- + return;
- + }
- + stb_needs_to_wait_for_power = false;
- +
- + R5000Channel *fwchan = dynamic_cast<R5000Channel*>(channel);
- + if (!fwchan)
- + return;
- +
- + if (HasFlags(kFWSigMon_WaitForPower) && !HasFlags(kFWSigMon_PowerMatch))
- + {
- + bool retried = false;
- + while (true)
- + {
- + R5000Device::PowerState power = fwchan->GetPowerState();
- + if (R5000Device::kAVCPowerOn == power)
- + {
- + AddFlags(kFWSigMon_PowerSeen | kFWSigMon_PowerMatch);
- + }
- + else if (R5000Device::kAVCPowerOff == power)
- + {
- + AddFlags(kFWSigMon_PowerSeen);
- + fwchan->SetPowerState(true);
- + stb_wait_for_power_timer.start();
- + stb_needs_to_wait_for_power = true;
- + }
- + else
- + {
- + bool qfailed = (R5000Device::kAVCPowerQueryFailed == power);
- + if (qfailed && !retried)
- + {
- + retried = true;
- + continue;
- + }
- +
- + LOG(VB_RECORD, LOG_INFO, "Can't determine if STB is power on, "
- + "assuming it is...");
- + AddFlags(kFWSigMon_PowerSeen | kFWSigMon_PowerMatch);
- + }
- + break;
- + }
- + }
- +
- + bool isLocked = !HasFlags(kFWSigMon_WaitForPower) ||
- + HasFlags(kFWSigMon_WaitForPower | kFWSigMon_PowerMatch);
- +
- + if (isLocked && stb_needs_retune)
- + {
- + fwchan->Retune();
- + isLocked = stb_needs_retune = false;
- + }
- +
- + // Set SignalMonitorValues from info from card.
- + {
- + QMutexLocker locker(&statusLock);
- + signalStrength.SetValue(isLocked ? 100 : 0);
- + signalLock.SetValue(isLocked ? 1 : 0);
- + }
- +
- + EmitStatus();
- + if (IsAllGood())
- + SendMessageAllGood();
- +
- + // Start table monitoring if we are waiting on any table
- + // and we have a lock.
- + if (isLocked && GetStreamData() &&
- + HasAnyFlag(kDTVSigMon_WaitForPAT | kDTVSigMon_WaitForPMT |
- + kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT |
- + kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT))
- + {
- + pthread_create(&table_monitor_thread, NULL,
- + TableMonitorThread, this);
- +
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "UpdateValues() -- "
- + "Waiting for table monitor to start");
- +
- + while (!dtvMonitorRunning)
- + usleep(50);
- +
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "UpdateValues() -- "
- + "Table monitor started");
- + }
- +
- + update_done = true;
- +}
- Index: libs/libmythtv/tv_rec.cpp
- ===================================================================
- --- libs/libmythtv/tv_rec.cpp (revision 1)
- +++ libs/libmythtv/tv_rec.cpp (revision 4)
- @@ -29,6 +29,7 @@
- #include "remoteutil.h"
- #include "ringbuffer.h"
- #include "mythlogging.h"
- +#include "r5000channel.h"
- #include "v4lchannel.h"
- #include "dialogbox.h"
- #include "jobqueue.h"
- @@ -1155,6 +1156,15 @@
- return dynamic_cast<DTVChannel*>(channel);
- }
- +R5000Channel *TVRec::GetR5000Channel(void)
- +{
- +#ifdef USING_R5000
- + return dynamic_cast<R5000Channel*>(channel);
- +#else
- + return NULL;
- +#endif // USING_R5000
- +}
- +
- V4LChannel *TVRec::GetV4LChannel(void)
- {
- #ifdef USING_V4L2
- Index: libs/libmythtv/libmythtv.pro
- ===================================================================
- --- libs/libmythtv/libmythtv.pro (revision 1)
- +++ libs/libmythtv/libmythtv.pro (revision 4)
- @@ -664,6 +664,25 @@
- DEFINES += USING_ASI
- }
- + #Support for R5000 usb device
- + using_r5000 {
- + HEADERS += r5000channel.h r5000recorder.h
- + HEADERS += r5000signalmonitor.h r5000device.h
- + HEADERS += r5000/r5000.h r5000/libusb_augment.h
- + HEADERS += r5000/r5000_internal.h r5000/r5000init.h
- +
- + SOURCES += r5000channel.cpp r5000recorder.cpp
- + SOURCES += r5000signalmonitor.cpp r5000device.cpp
- + SOURCES += r5000/r5000.c r5000/libusb_augment.c
- + SOURCES += r5000/r5k_vip.c r5000/r5k_pes.c
- + SOURCES += r5000/r5k_sat.c r5000/r5k_misc.c
- + SOURCES += r5000/r5k_vip_buttons.c r5000/r5k_directv_buttons.c
- + SOURCES += r5000/r5k_dish6000_buttons.c
- +
- + LIBS += -lusb
- + DEFINES += USING_R5000
- + }
- +
- DEFINES += USING_BACKEND
- }
- Index: libs/libmythtv/transporteditor.cpp
- ===================================================================
- --- libs/libmythtv/transporteditor.cpp (revision 1)
- +++ libs/libmythtv/transporteditor.cpp (revision 4)
- @@ -739,7 +739,8 @@
- left->addChild(new Modulation(id, nType));
- }
- else if ((CardUtil::FIREWIRE == nType) ||
- - (CardUtil::FREEBOX == nType))
- + (CardUtil::FREEBOX == nType) ||
- + (CardUtil::R5000 == nType))
- {
- left->addChild(new DTVStandard(id, true, true));
- }
- Index: libs/libmythtv/r5000device.cpp
- ===================================================================
- --- libs/libmythtv/r5000device.cpp (revision 0)
- +++ libs/libmythtv/r5000device.cpp (revision 4)
- @@ -0,0 +1,464 @@
- +/**
- + * R5000Device
- + * Copyright (c) 2008 by Alan Nisota
- + * Copyright (c) 2005 by Jim Westfall
- + * Distributed as part of MythTV under GPL v2 and later.
- + */
- +
- +// C++ headers
- +#include <algorithm>
- +
- +// Qt headers
- +#include <QMap>
- +
- +// for usleep
- +#include <unistd.h>
- +
- +// MythTV headers
- +#include "r5000device.h"
- +#include "mythcontext.h"
- +#include "mythlogging.h"
- +#include "pespacket.h"
- +#include "mthread.h"
- +#include "mythtimer.h"
- +
- +#define LOC QString("R5kDev: ")
- +#define LOC_WARN QString("R5kDev, Warning: ")
- +#define LOC_ERR QString("R5kDev, Error: ")
- +
- +static int r5k_init = 0;
- +QMap<uint64_t,QString> R5000Device::s_id_to_model;
- +QMutex R5000Device::s_static_lock;
- +
- +unsigned int r5000_device_tspacket_handler(unsigned char *tspacket, int len, void *callback_data)
- +{
- + R5000Device *fw = (R5000Device*) callback_data;
- + if (! fw)
- + return 0;
- + if (len > 0)
- + fw->BroadcastToListeners(tspacket, len);
- + return 1;
- +}
- +
- +void r5000_msg(char * msg)
- +{
- + LOG(VB_GENERAL, LOG_INFO, LOC +
- + QString("R5kLib: ") + msg);
- +}
- +
- +class R5kPriv
- +{
- + public:
- + R5kPriv() :
- + reset_timer_on(false),
- + run_port_handler(false), is_port_handler_running(false),
- + channel(-1),
- + is_streaming(false)
- + {
- + }
- +
- + bool reset_timer_on;
- + MythTimer reset_timer;
- +
- + bool run_port_handler;
- + bool is_port_handler_running;
- + QMutex start_stop_port_handler_lock;
- +
- + int channel;
- +
- + bool is_streaming;
- +
- + QDateTime stop_streaming_timer;
- + pthread_t port_handler_thread;
- +
- + static QMutex s_lock;
- +};
- +QMutex R5kPriv::s_lock;
- +
- +//callback functions
- +void *r5000_device_port_handler_thunk(void *param);
- +
- +R5000Device::R5000Device(int type, QString serial) :
- + m_type(type),
- + m_serial(serial),
- + m_last_channel(""), m_last_crc(0),
- + m_buffer_cleared(true), m_open_port_cnt(0),
- + m_lock(), m_priv(new R5kPriv())
- +{
- + QMutexLocker locker(&s_static_lock);
- + usbdev = NULL;
- + if (! r5k_init)
- + r5k_init = r5000_init(r5000_msg);
- +}
- +
- +R5000Device::~R5000Device()
- +{
- + if (usbdev)
- + {
- + LOG(VB_GENERAL, LOG_DEBUG, LOC_ERR + "ctor called with open port");
- + while (usbdev)
- + ClosePort();
- + }
- +
- + if (m_priv)
- + {
- + delete m_priv;
- + m_priv = NULL;
- + }
- +}
- +
- +void R5000Device::AddListener(TSDataListener *listener)
- +{
- + QMutexLocker locker(&m_lock);
- + if (listener)
- + {
- + vector<TSDataListener*>::iterator it =
- + find(m_listeners.begin(), m_listeners.end(), listener);
- +
- + if (it == m_listeners.end())
- + m_listeners.push_back(listener);
- + }
- +
- + LOG(VB_RECORD, LOG_INFO, LOC +
- + QString("AddListener() %1").arg(m_listeners.size()));
- + if (!m_listeners.empty())
- + {
- + StartStreaming();
- + }
- +}
- +
- +void R5000Device::RemoveListener(TSDataListener *listener)
- +{
- + QMutexLocker locker(&m_lock);
- + vector<TSDataListener*>::iterator it = m_listeners.end();
- +
- + do
- + {
- + it = find(m_listeners.begin(), m_listeners.end(), listener);
- + if (it != m_listeners.end())
- + m_listeners.erase(it);
- + }
- + while (it != m_listeners.end());
- +
- + LOG(VB_RECORD, LOG_INFO, LOC +
- + QString("RemoveListener() %1").arg(m_listeners.size()));
- + if (m_listeners.empty())
- + {
- + StopStreaming();
- + }
- +}
- +
- +bool R5000Device::StartStreaming(void)
- +{
- + if (m_priv->is_streaming)
- + return m_priv->is_streaming;
- +
- + if (! usbdev)
- + {
- + LOG(VB_GENERAL, LOG_DEBUG, LOC_ERR + "Device not open");
- + return false;
- + }
- + if (r5000_start_stream(usbdev))
- + {
- + m_priv->is_streaming = true;
- + }
- + else
- + {
- + LOG(VB_GENERAL, LOG_DEBUG, LOC_ERR + "Starting A/V streaming ");
- + }
- +
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "Starting A/V streaming -- done");
- +
- + return m_priv->is_streaming;
- +}
- +
- +bool R5000Device::StopStreaming(void)
- +{
- + if (m_priv->is_streaming)
- + {
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "Stopping A/V streaming -- really");
- +
- + m_priv->is_streaming = false;
- +
- + r5000_stop_stream(usbdev);
- + }
- +
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "Stopped A/V streaming");
- +
- + return true;
- +}
- +
- +bool R5000Device::SetPowerState(bool on)
- +{
- + QMutexLocker locker(&m_lock);
- + QString cmdStr = (on) ? "on" : "off";
- + LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Powering %1").arg(cmdStr));
- + r5000_power_on_off(usbdev, on);
- + return true;
- +}
- +
- +R5000Device::PowerState R5000Device::GetPowerState(void)
- +{
- + QMutexLocker locker(&m_lock);
- + int on_off;
- +
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "Requesting STB Power State");
- + on_off = r5000_get_power_state(usbdev);
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + (on_off ? "On" : "Off"));
- + return on_off ? kAVCPowerOn : kAVCPowerOff;
- +}
- +
- +bool R5000Device::SetChannel(const QString &panel_model,
- + const QString &channel, uint mpeg_prog)
- +{
- + LOG(VB_CHANNEL, LOG_DEBUG, QString("SetChannel(model %1, chan %2 mpeg_prog %3)")
- + .arg(panel_model).arg(channel).arg(mpeg_prog));
- +
- + QMutexLocker locker(&m_lock);
- + LOG(VB_CHANNEL, LOG_DEBUG, "SetChannel() -- locked");
- + if (! r5000_change_channel(usbdev, channel.toAscii().constData(), mpeg_prog))
- + LOG(VB_GENERAL, LOG_DEBUG, LOC + "Failed to set channel");
- + return true;
- +}
- +
- +void R5000Device::BroadcastToListeners(
- + const unsigned char *data, uint dataSize)
- +{
- + QMutexLocker locker(&m_lock);
- + if ((dataSize >= TSPacket::kSize) && (data[0] == SYNC_BYTE) &&
- + ((data[1] & 0x1f) == 0) && (data[2] == 0))
- + {
- + ProcessPATPacket(*((const TSPacket*)data));
- + }
- +
- + vector<TSDataListener*>::iterator it = m_listeners.begin();
- + for (; it != m_listeners.end(); ++it)
- + (*it)->AddData(data, dataSize);
- +}
- +
- +void R5000Device::SetLastChannel(const QString &channel)
- +{
- + m_buffer_cleared = (channel == m_last_channel);
- + m_last_channel = channel;
- +
- + LOG(VB_GENERAL, LOG_DEBUG, QString("SetLastChannel(%1): cleared: %2")
- + .arg(channel).arg(m_buffer_cleared ? "yes" : "no"));
- +}
- +
- +void R5000Device::ProcessPATPacket(const TSPacket &tspacket)
- +{
- + if (!tspacket.TransportError() && !tspacket.Scrambled() &&
- + tspacket.HasPayload() && tspacket.PayloadStart() && !tspacket.PID())
- + {
- + PESPacket pes = PESPacket::View(tspacket);
- + uint crc = pes.CalcCRC();
- + m_buffer_cleared |= (crc != m_last_crc);
- + m_last_crc = crc;
- +#if 0
- + LOG(VB_RECORD, LOG_DEBUG, LOC +
- + QString("ProcessPATPacket: CRC 0x%1 cleared: %2")
- + .arg(crc,0,16).arg(m_buffer_cleared ? "yes" : "no"));
- +#endif
- + }
- + else
- + {
- + LOG(VB_GENERAL, LOG_DEBUG, LOC_ERR + "Can't handle large PAT's");
- + }
- +}
- +
- +QString R5000Device::GetModelName(uint vendor_id, uint model_id)
- +{
- + QMutexLocker locker(&s_static_lock);
- +/*
- + if (s_id_to_model.empty())
- + fw_init(s_id_to_model);
- +
- + QString ret = s_id_to_model[(((uint64_t) vendor_id) << 32) | model_id];
- +
- + if (ret.isEmpty())
- + return "GENERIC";
- +*/
- + return "R5000";
- +}
- +
- +bool R5000Device::IsSTBSupported(const QString &panel_model)
- +{
- + return true;
- +}
- +
- +bool R5000Device::OpenPort(void)
- +{
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "Starting Port Handler Thread");
- + QMutexLocker mlocker(&m_lock);
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "Starting Port Handler Thread -- locked");
- + if (usbdev)
- + {
- + m_open_port_cnt++;
- + return true;
- + }
- +
- + if (m_serial.length())
- + {
- + LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Opening R5000 device type %1 with serial#: "+ m_serial).arg(m_type));
- + usbdev = r5000_open((r5ktype_t)m_type, r5000_device_tspacket_handler, this, m_serial.toAscii().constData());
- + }
- + else
- + {
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "Opening R5000 device with unknown serial#");
- + usbdev = r5000_open((r5ktype_t)m_type, r5000_device_tspacket_handler, this, NULL);
- + }
- + if (! usbdev)
- + {
- + LOG(VB_GENERAL, LOG_DEBUG, LOC + "Failed to open R5000 device");
- + return false;
- + }
- +
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "Starting port handler thread");
- + m_priv->run_port_handler = true;
- + pthread_create(&m_priv->port_handler_thread, NULL,
- + r5000_device_port_handler_thunk, this);
- +
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "Waiting for port handler thread to start");
- + while (!m_priv->is_port_handler_running)
- + {
- + m_lock.unlock();
- + usleep(5000);
- + m_lock.lock();
- + }
- +
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "Port handler thread started");
- +
- + m_open_port_cnt++;
- +
- + return true;
- +}
- +
- +bool R5000Device::ClosePort(void)
- +{
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "Stopping Port Handler Thread");
- + QMutexLocker locker(&m_priv->start_stop_port_handler_lock);
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "Stopping Port Handler Thread -- locked");
- +
- + QMutexLocker mlocker(&m_lock);
- +
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "ClosePort()");
- +
- + if (m_open_port_cnt < 1)
- + return false;
- +
- + m_open_port_cnt--;
- +
- + if (m_open_port_cnt != 0)
- + return true;
- +
- + if (!usbdev)
- + return false;
- +
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "Waiting for port handler thread to stop");
- + m_priv->run_port_handler = false;
- + while (m_priv->is_port_handler_running)
- + {
- + m_lock.unlock();
- + usleep(5000);
- + m_lock.lock();
- + }
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "Joining port handler thread");
- + pthread_join(m_priv->port_handler_thread, NULL);
- +
- + r5000_close(usbdev);
- + usbdev = NULL;
- +
- + return true;
- +}
- +
- +void *r5000_device_port_handler_thunk(void *param)
- +{
- + R5000Device *mon = (R5000Device*) param;
- + mon->RunPortHandler();
- + return NULL;
- +}
- +
- +void R5000Device::RunPortHandler(void)
- +{
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "RunPortHandler -- start");
- + m_lock.lock();
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "RunPortHandler -- got first lock");
- + m_priv->is_port_handler_running = true;
- + m_lock.unlock();
- +
- + while (m_priv->run_port_handler)
- + {
- + if (m_priv->is_streaming)
- + {
- + // This will timeout after 10ms regardless of data availability
- + r5000_loop_iterate(usbdev, 10);
- + }
- + else
- + {
- + usleep(10000);
- + }
- + }
- +
- + m_lock.lock();
- + m_priv->is_port_handler_running = false;
- + m_lock.unlock();
- + LOG(VB_RECORD, LOG_DEBUG, LOC + "RunPortHandler -- end");
- +}
- +
- +QStringList R5000Device::GetSTBList(void)
- +{
- + QStringList STBList;
- + int i;
- + r5kenum_t r5k_stbs;
- + if (! r5k_init)
- + {
- + r5k_init = r5000_init(r5000_msg);
- + if (! r5k_init)
- + return STBList;
- + }
- + if (! r5000_find_stbs(&r5k_stbs))
- + LOG(VB_GENERAL, LOG_DEBUG, LOC + "Locating R5000 devices failed."
- + " This may be a permission problem");
- +
- + for (i = 0; i < r5k_stbs.count; i++)
- + STBList.append((char *)r5k_stbs.serial[i]);
- + return STBList;
- +}
- +
- +int R5000Device::GetDeviceType(const QString &r5ktype)
- +{
- + QString type = r5ktype.toUpper();
- + if (type == "DIRECTV")
- + {
- + return R5K_STB_DIRECTV;
- + }
- + else if ("VIP211/VIP622/DISH411" == type ||
- + "VIP211/VIP422" == type ||
- + "VIP211" == type ||
- + "VIP411" == type)
- + {
- + return R5K_STB_VIP211;
- + }
- + else if ("STARCHOICE/DSR" == type)
- + {
- + return R5K_STB_DSR;
- + }
- + else if ("HDD-200" == type)
- + {
- + return R5K_STB_HDD;
- + }
- + else if ("VIP622" == type ||
- + "VIP722" == type ||
- + "BEV9242" == type)
- + {
- + return R5K_STB_VIP622;
- + }
- + else if ("DISH6000" == type)
- + {
- + return R5K_STB_DISH6000;
- + }
- + else
- + {
- + return R5K_STB_VIP211;
- + }
- +}
- Index: libs/libmythtv/cardutil.h
- ===================================================================
- --- libs/libmythtv/cardutil.h (revision 1)
- +++ libs/libmythtv/cardutil.h (revision 4)
- @@ -66,6 +66,7 @@
- DEMO = 15,
- ASI = 16,
- CETON = 17,
- + R5000 = 18,
- };
- static enum CARD_TYPES toCardType(const QString &name)
- @@ -106,6 +107,8 @@
- return ASI;
- if ("CETON" == name)
- return CETON;
- + if ("R5000" == name)
- + return R5000;
- return ERROR_UNKNOWN;
- }
- @@ -115,7 +118,8 @@
- (rawtype != "DVB") && (rawtype != "FIREWIRE") &&
- (rawtype != "HDHOMERUN") && (rawtype != "FREEBOX") &&
- (rawtype != "IMPORT") && (rawtype != "DEMO") &&
- - (rawtype != "ASI") && (rawtype != "CETON");
- + (rawtype != "ASI") && (rawtype != "CETON") &&
- + (rawtype != "R5000") ;
- }
- static bool IsV4L(const QString &rawtype)
- @@ -135,7 +139,8 @@
- return
- (rawtype == "FIREWIRE") || (rawtype == "HDPVR") ||
- (rawtype == "IMPORT") || (rawtype == "DEMO") ||
- - (rawtype == "GO7007") || (rawtype == "MJPEG");
- + (rawtype == "GO7007") || (rawtype == "MJPEG") ||
- + (rawtype == "R5000");
- }
- static QString GetScanableCardTypes(void);
- @@ -182,7 +187,7 @@
- (rawtype == "FIREWIRE") || (rawtype == "HDHOMERUN") ||
- (rawtype == "FREEBOX") || (rawtype == "ASI") ||
- (rawtype == "IMPORT") || (rawtype == "DEMO") ||
- - (rawtype == "CETON");
- + (rawtype == "CETON") || (rawtype == "R5000");
- }
- // Card creation and deletion
- Index: libs/libmythtv/r5000channel.cpp
- ===================================================================
- --- libs/libmythtv/r5000channel.cpp (revision 0)
- +++ libs/libmythtv/r5000channel.cpp (revision 4)
- @@ -0,0 +1,215 @@
- +/**
- + * R5000Channel
- + * Copyright (c) 2005 by Jim Westfall, Dave Abrahams
- + * Copyright (c) 2006 by Daniel Kristjansson
- + * Distributed as part of MythTV under GPL v2 and later.
- + */
- +
- +#include "mythcontext.h"
- +#include "tv_rec.h"
- +#include "r5000channel.h"
- +
- +#define LOC QString("R5kChan(%1): ").arg(GetDevice())
- +#define LOC_WARN QString("R5kChan(%1), Warning: ").arg(GetDevice())
- +#define LOC_ERR QString("R5kChan(%1), Error: ").arg(GetDevice())
- +
- +R5000Channel::R5000Channel(TVRec *parent, const QString &_videodevice,const QString &_r5ktype, bool pocc) :
- + DTVChannel(parent),
- + videodevice(_videodevice),
- + power_on_channel_change(pocc),
- + device(NULL),
- + current_channel(""),
- + current_mpeg_prog(0),
- + isopen(false),
- + tuning_delay(0)
- +{
- + int type = R5000Device::GetDeviceType(_r5ktype);
- + device = new R5000Device(type, videodevice);
- +
- + InitializeInputs();
- +}
- +
- +bool R5000Channel::SetChannelByString(const QString &channum)
- +{
- + QString loc = LOC + QString("SetChannelByString(%1)").arg(channum);
- + bool ok = false;
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC);
- +
- + InputMap::const_iterator it = m_inputs.find(m_currentInputID);
- + if (it == m_inputs.end())
- + return false;
- +
- + QString tvformat, modulation, freqtable, freqid, dtv_si_std;
- + int finetune;
- + uint64_t frequency;
- + int mpeg_prog_num;
- + uint atsc_major, atsc_minor, mplexid, tsid, netid;
- + if (!ChannelUtil::GetChannelData(
- + (*it)->sourceid, channum,
- + tvformat, modulation, freqtable, freqid,
- + finetune, frequency,
- + dtv_si_std, mpeg_prog_num, atsc_major, atsc_minor, tsid, netid,
- + mplexid, m_commfree))
- + {
- + LOG(VB_GENERAL, LOG_DEBUG, LOC + " " + QString(
- + "Requested channel '%1' is on input '%2' "
- + "which is in a busy input group")
- + .arg(channum).arg(m_currentInputID));
- +
- + return false;
- + }
- + uint mplexid_restriction;
- + if (!IsInputAvailable(m_currentInputID, mplexid_restriction))
- + {
- + LOG(VB_GENERAL, LOG_DEBUG, LOC + " " + QString(
- + "Requested channel '%1' is on input '%2' "
- + "which is in a busy input group")
- + .arg(channum).arg(m_currentInputID));
- +
- + return false;
- + }
- +
- + if (!(*it)->externalChanger.isEmpty())
- + {
- + ok = ChangeExternalChannel((*it)->externalChanger, freqid);
- + // -1 resets any state without executing a channel change
- + device->SetChannel(fw_opts.model, 0, mpeg_prog_num);
- + SetSIStandard("mpeg");
- + SetDTVInfo(0,0,0,0,1);
- + }
- + else
- + {
- + ok = isopen && SetChannelByNumber(freqid, mpeg_prog_num);
- + }
- +
- + if (ok)
- + {
- + if (tuning_delay) {
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + " " + QString(
- + "Adding additional delay: %1ms").arg(tuning_delay));
- + usleep(tuning_delay * 1000);
- + }
- + // Set the current channum to the new channel's channum
- + QString tmp = channum;
- + tmp.detach();
- + m_curchannelname = tmp;
- + tmp.detach();
- + (*it)->startChanNum = tmp;
- + }
- +
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + " " + ((ok) ? "success" : "failure"));
- +
- + return ok;
- +}
- +
- +bool R5000Channel::Open(void)
- +{
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "Open()");
- +
- + if (m_inputs.find(m_currentInputID) == m_inputs.end())
- + return false;
- +
- + if (!device)
- + return false;
- +
- + if (isopen)
- + return true;
- +
- + if (!device->OpenPort())
- + return false;
- +
- + isopen = true;
- +
- + return true;
- +}
- +
- +void R5000Channel::Close(void)
- +{
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "Close()");
- + if (isopen)
- + {
- + device->ClosePort();
- + isopen = false;
- + }
- +}
- +
- +QString R5000Channel::GetDevice(void) const
- +{
- + return videodevice;
- +}
- +
- +bool R5000Channel::SetPowerState(bool on)
- +{
- + if (!isopen)
- + {
- + LOG(VB_GENERAL, LOG_DEBUG, LOC_ERR +
- + "SetPowerState() called on closed R5000Channel.");
- +
- + return false;
- + }
- + if (power_on_channel_change)
- + return R5000Device::kAVCPowerOn;
- +
- + return device->SetPowerState(on);
- +}
- +
- +R5000Device::PowerState R5000Channel::GetPowerState(void) const
- +{
- + if (!isopen)
- + {
- + LOG(VB_GENERAL, LOG_DEBUG, LOC_ERR +
- + "GetPowerState() called on closed R5000Channel.");
- +
- + return R5000Device::kAVCPowerQueryFailed;
- + }
- +
- + if (power_on_channel_change)
- + return R5000Device::kAVCPowerOn;
- +
- + return device->GetPowerState();
- +}
- +
- +bool R5000Channel::Retune(void)
- +{
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + "Retune()");
- +
- + if (! power_on_channel_change && R5000Device::kAVCPowerOff == GetPowerState())
- + {
- + LOG(VB_GENERAL, LOG_DEBUG, LOC_ERR +
- + "STB is turned off, must be on to retune.");
- +
- + return false;
- + }
- +
- + if (current_channel.length())
- + return SetChannelByNumber(current_channel, current_mpeg_prog);
- +
- + return false;
- +}
- +
- +bool R5000Channel::SetChannelByNumber(const QString &channel, int mpeg_prog)
- +{
- + LOG(VB_CHANNEL, LOG_DEBUG, QString("SetChannelByNumber(%1)").arg(channel));
- + current_channel = channel;
- + current_mpeg_prog = mpeg_prog;
- +
- + if (! power_on_channel_change && R5000Device::kAVCPowerOff == GetPowerState())
- + {
- + LOG(VB_GENERAL, LOG_DEBUG, LOC_WARN +
- + "STB is turned off, must be on to set channel.");
- +
- + SetSIStandard("mpeg");
- + SetDTVInfo(0,0,0,0,1);
- +
- + return true; // signal monitor will call retune later...
- + }
- +
- + QString tmpchan = (power_on_channel_change ? "P" : "") + channel;
- + if (! device->SetChannel(fw_opts.model, tmpchan, mpeg_prog))
- + return false;
- +
- + SetSIStandard("mpeg");
- + SetDTVInfo(0,0,0,0,1);
- +
- + return true;
- +}
- Index: libs/libmythtv/channelbase.cpp
- ===================================================================
- --- libs/libmythtv/channelbase.cpp (revision 1)
- +++ libs/libmythtv/channelbase.cpp (revision 4)
- @@ -26,6 +26,7 @@
- #include "firewirechannel.h"
- #include "mythcorecontext.h"
- #include "cetonchannel.h"
- +#include "r5000channel.h"
- #include "dummychannel.h"
- #include "tvremoteutil.h"
- #include "channelutil.h"
- @@ -1197,6 +1198,15 @@
- channel = new CetonChannel(tvrec, genOpt.videodev);
- #endif
- }
- + else if (genOpt.cardtype == "R5000")
- + {
- +#ifdef USING_R5000
- + channel = new R5000Channel(tvrec, genOpt.videodev, fwOpt.model, dvbOpt.dvb_on_demand);
- + dynamic_cast<R5000Channel*>(channel)->SetSlowTuning(
- + dvbOpt.dvb_tuning_delay);
- +#endif
- + }
- +
- else if (CardUtil::IsV4L(genOpt.cardtype))
- {
- #ifdef USING_V4L2
- Index: libs/libmythtv/r5000recorder.h
- ===================================================================
- --- libs/libmythtv/r5000recorder.h (revision 0)
- +++ libs/libmythtv/r5000recorder.h (revision 4)
- @@ -0,0 +1,69 @@
- +/**
- + * R5000Recorder
- + * Copyright (c) 2005 by Jim Westfall
- + * Distributed as part of MythTV under GPL v2 and later.
- + */
- +
- +#ifndef _R5000RECORDER_H_
- +#define _R5000RECORDER_H_
- +
- +// MythTV headers
- +#include "dtvrecorder.h"
- +#include "tspacket.h"
- +#include "streamlisteners.h"
- +
- +class TVRec;
- +class R5000Channel;
- +
- +/** \class R5000Recorder
- + * \brief This is a specialization of DTVRecorder used to
- + * handle DVB and ATSC streams from a firewire input.
- + *
- + * \sa DTVRecorder
- + */
- +class R5000Recorder : public DTVRecorder,
- +// public MPEGSingleProgramStreamListener,
- + public TSDataListener
- +{
- + friend class MPEGStreamData;
- + friend class TSPacketProcessor;
- +
- + public:
- + R5000Recorder(TVRec *rec, R5000Channel *chan);
- + virtual ~R5000Recorder();
- +
- + // Commands
- + bool Open(void);
- + void Close(void);
- +
- + void StartStreaming(void);
- + void StopStreaming(void);
- +
- + void StartRecording(void);
- + void run(void);
- + bool PauseAndWait(int timeout = 100);
- +
- + void AddData(const unsigned char *data, uint dataSize);
- + bool ProcessTSPacket(const TSPacket &tspacket);
- +
- + // Sets
- + void SetOptionsFromProfile(RecordingProfile *profile,
- + const QString &videodev,
- + const QString &audiodev,
- + const QString &vbidev);
- + void SetStreamData(void);
- +
- + // MPEG Single Program
- + void HandleSingleProgramPAT(ProgramAssociationTable*);
- + void HandleSingleProgramPMT(ProgramMapTable*);
- +
- + protected:
- + R5000Recorder(TVRec *rec);
- +
- + private:
- + R5000Channel *channel;
- + bool isopen;
- + vector<unsigned char> buffer;
- +};
- +
- +#endif // _R5000RECORDER_H_
- Index: libs/libmythtv/r5000channel.h
- ===================================================================
- --- libs/libmythtv/r5000channel.h (revision 0)
- +++ libs/libmythtv/r5000channel.h (revision 4)
- @@ -0,0 +1,56 @@
- +/**
- + * R5000Channel
- + * Copyright (c) 2008 by Alan Nisota
- + * Copyright (c) 2005 by Jim Westfall and Dave Abrahams
- + * Distributed as part of MythTV under GPL v2 and later.
- + */
- +
- +#ifndef _R5000CHANNEL_H_
- +#define _R5000CHANNEL_H_
- +
- +#include "tv_rec.h"
- +#include "dtvchannel.h"
- +#include "r5000device.h"
- +
- +class R5000Channel : public DTVChannel
- +{
- + public:
- + R5000Channel(TVRec *parent, const QString &videodevice,
- + const QString &_r5ktype, bool pocc);
- + ~R5000Channel() { Close(); }
- +
- + // Commands
- + virtual bool Open(void);
- + virtual void Close(void);
- +
- + virtual bool TuneMultiplex(uint /*mplexid*/, QString /*inputname*/)
- + { return false; }
- + virtual bool Tune(const DTVMultiplex &/*tuning*/, QString /*inputname*/)
- + { return false; }
- + virtual bool Retune(void);
- +
- + // Sets
- + virtual bool SetChannelByString(const QString &chan);
- + virtual bool SetChannelByNumber(const QString &channel, int mpeg_prog);
- + virtual bool SetPowerState(bool on);
- + void SetSlowTuning(uint how_slow_in_ms)
- + { tuning_delay = how_slow_in_ms; }
- +
- + // Gets
- + virtual bool IsOpen(void) const { return isopen; }
- + virtual R5000Device::PowerState GetPowerState(void) const;
- + virtual QString GetDevice(void) const;
- + virtual R5000Device *GetR5000Device(void) { return device; }
- +
- + protected:
- + QString videodevice;
- + FireWireDBOptions fw_opts;
- + bool power_on_channel_change;
- + R5000Device *device;
- + QString current_channel;
- + uint current_mpeg_prog;
- + bool isopen;
- + uint tuning_delay;///< Extra delay to add
- +};
- +
- +#endif // _R5000CHANNEL_H_
- Index: libs/libmythtv/r5000signalmonitor.h
- ===================================================================
- --- libs/libmythtv/r5000signalmonitor.h (revision 0)
- +++ libs/libmythtv/r5000signalmonitor.h (revision 4)
- @@ -0,0 +1,61 @@
- +// -*- Mode: c++ -*-
- +
- +#ifndef _R5000SIGNALMONITOR_H_
- +#define _R5000SIGNALMONITOR_H_
- +
- +#include <qmap.h>
- +#include <qmutex.h>
- +#include <qdatetime.h>
- +
- +#include "dtvsignalmonitor.h"
- +#include "r5000device.h"
- +//#include "util.h"
- +
- +class R5000Channel;
- +
- +class R5000SignalMonitor : public DTVSignalMonitor, public TSDataListener
- +{
- + public:
- + R5000SignalMonitor(int db_cardnum, R5000Channel *_channel,
- + uint64_t _flags = kFWSigMon_WaitForPower,
- + const char *_name = "R5000SignalMonitor");
- +
- + virtual void HandlePAT(const ProgramAssociationTable*);
- + virtual void HandlePMT(uint, const ProgramMapTable*);
- +
- + void Stop(void);
- +
- + protected:
- + R5000SignalMonitor(void);
- + R5000SignalMonitor(const R5000SignalMonitor&);
- + virtual ~R5000SignalMonitor();
- +
- + virtual void UpdateValues(void);
- +
- + static void *TableMonitorThread(void *param);
- + void RunTableMonitor(void);
- +
- + bool SupportsTSMonitoring(void);
- +
- + void AddData(const unsigned char *data, uint dataSize);
- +
- + public:
- + static const uint kPowerTimeout;
- + static const uint kBufferTimeout;
- +
- + protected:
- + bool dtvMonitorRunning;
- + pthread_t table_monitor_thread;
- + bool stb_needs_retune;
- + bool stb_needs_to_wait_for_pat;
- + bool stb_needs_to_wait_for_power;
- + MythTimer stb_wait_for_pat_timer;
- + MythTimer stb_wait_for_power_timer;
- +
- + vector<unsigned char> buffer;
- +
- + static QMap<void*,uint> pat_keys;
- + static QMutex pat_keys_lock;
- +};
- +
- +#endif // _R5000SIGNALMONITOR_H_
- Index: libs/libmythtv/signalmonitor.cpp
- ===================================================================
- --- libs/libmythtv/signalmonitor.cpp (revision 1)
- +++ libs/libmythtv/signalmonitor.cpp (revision 4)
- @@ -54,6 +54,11 @@
- # include "cetonchannel.h"
- #endif
- +#ifdef USING_R5000
- +# include "r5000signalmonitor.h"
- +# include "r5000channel.h"
- +#endif
- +
- #undef DBG_SM
- #define DBG_SM(FUNC, MSG) LOG(VB_CHANNEL, LOG_DEBUG, \
- QString("SM(%1)::%2: %3").arg(channel->GetDevice()).arg(FUNC).arg(MSG))
- @@ -154,6 +159,15 @@
- }
- #endif
- +#ifdef USING_R5000
- + if (cardtype.toUpper() == "R5000")
- + {
- + R5000Channel *fc = dynamic_cast<R5000Channel*>(channel);
- + if (fc)
- + signalMonitor = new R5000SignalMonitor(db_cardnum, fc);
- + }
- +#endif
- +
- if (!signalMonitor && channel)
- {
- signalMonitor = new ScriptSignalMonitor(db_cardnum, channel);
- Index: libs/libmythtv/videosource.cpp
- ===================================================================
- --- libs/libmythtv/videosource.cpp (revision 1)
- +++ libs/libmythtv/videosource.cpp (revision 4)
- @@ -35,6 +35,7 @@
- #include "frequencies.h"
- #include "diseqcsettings.h"
- #include "firewiredevice.h"
- +#include "r5000device.h"
- #include "compat.h"
- #include "mythdb.h"
- #include "mythdirs.h"
- @@ -1530,6 +1531,101 @@
- _oldValue = v;
- };
- +class R5000TuningDelay : public SpinBoxSetting, public CaptureCardDBStorage
- +{
- + public:
- + R5000TuningDelay(const CaptureCard &parent) :
- + SpinBoxSetting(this, 0, 2000, 25),
- + CaptureCardDBStorage(this, parent, "dvb_tuning_delay")
- + {
- + setLabel(QObject::tr("R5000 Tuning Delay (msec)"));
- + setHelpText(
- + QObject::tr("Some STBS (for example the ViP boxes) require "
- + "additional time after setting the channel before starting recording. "
- + "This is especially necessary if different channels use different codecs."));
- + };
- +};
- +
- +class R5000SendPowerBeforeChannel : public CheckBoxSetting, public CaptureCardDBStorage
- +{
- + public:
- + R5000SendPowerBeforeChannel(const CaptureCard &parent) :
- + CheckBoxSetting(this),
- + CaptureCardDBStorage(this, parent, "dvb_on_demand")
- + {
- + setValue(false);
- + setLabel(QObject::tr("Turn on before Channel Change"));
- + setHelpText(QObject::tr(
- + "On some STBs klike the ViP211, the power on/off "
- + "detection isn't reliable if you let the box go into "
- + "standby. This forces a 'power-on' command before "
- + "changing channels. This will very likely do the "
- + "wrong thing for non ViP boxes."));
- +
- + };
- +};
- +
- +class R5000Serial : public ComboBoxSetting, public CaptureCardDBStorage
- +{
- + public:
- + R5000Serial(const CaptureCard &parent) :
- + ComboBoxSetting(this),
- + CaptureCardDBStorage(this, parent, "videodevice")
- + {
- + setLabel(QObject::tr("Serial #"));
- +#ifdef USING_R5000
- + QStringList serials = R5000Device::GetSTBList();
- + for (int i = 0; i < serials.size(); i++)
- + {
- + addSelection(serials[i]);
- + }
- +#endif // USING_R5000
- + }
- +};
- +
- +class R5000Model : public ComboBoxSetting, public CaptureCardDBStorage
- +{
- + public:
- + R5000Model(const CaptureCard &parent) :
- + ComboBoxSetting(this),
- + CaptureCardDBStorage(this, parent, "firewire_model")
- + {
- + setLabel(QObject::tr("R5000 STB type"));
- + addSelection("VIP211");
- + addSelection("VIP411");
- + addSelection("VIP622");
- + addSelection("VIP722");
- + addSelection("BEV9242");
- + addSelection("DISH6000");
- + addSelection("DIRECTV");
- + addSelection("STARCHOICE/DSR");
- + addSelection("HDD-200");
- + QString help = QObject::tr(
- + "Choose the type of R5000 enabled STB you are using.");
- + setHelpText(help);
- + }
- +};
- +
- +class R5000ConfigurationGroup : public VerticalConfigurationGroup
- +{
- + public:
- + R5000ConfigurationGroup(CaptureCard& a_parent):
- + VerticalConfigurationGroup(false, true, false, false),
- + parent(a_parent)
- + {
- + setUseLabel(false);
- + addChild(new R5000SendPowerBeforeChannel(parent));
- + addChild(new R5000TuningDelay(parent));
- + addChild(new R5000Serial(parent));
- + addChild(new R5000Model(parent));
- + addChild(new EmptyAudioDevice(parent));
- + addChild(new EmptyVBIDevice(parent));
- + };
- +
- + private:
- + CaptureCard &parent;
- +};
- +
- class IPTVHost : public LineEditSetting, public CaptureCardDBStorage
- {
- public:
- @@ -2296,6 +2392,10 @@
- addTarget("CETON", new CetonConfigurationGroup(parent));
- #endif // USING_CETON
- +#ifdef USING_R5000
- + addTarget("R5000", new R5000ConfigurationGroup(parent));
- +#endif // USING_R5000
- +
- // for testing without any actual tuner hardware:
- addTarget("IMPORT", new ImportConfigurationGroup(parent));
- addTarget("DEMO", new DemoConfigurationGroup(parent));
- @@ -2509,6 +2609,10 @@
- QObject::tr("Ceton Cablecard tuner "), "CETON");
- #endif // USING_CETON
- +#ifdef USING_R5000
- + setting->addSelection(QObject::tr("R5000 Capable STB"), "R5000");
- +#endif // USING_R5000
- +
- setting->addSelection(QObject::tr("Import test recorder"), "IMPORT");
- setting->addSelection(QObject::tr("Demo test recorder"), "DEMO");
- }
- Index: libs/libmythtv/r5000device.h
- ===================================================================
- --- libs/libmythtv/r5000device.h (revision 0)
- +++ libs/libmythtv/r5000device.h (revision 4)
- @@ -0,0 +1,110 @@
- +/**
- + * R5000Device
- + * Copyright (c) 2005 by Jim Westfall
- + * Distributed as part of MythTV under GPL v2 and later.
- + */
- +
- +#ifndef _R5000_DEVICE_H_
- +#define _R5000_DEVICE_H_
- +
- +// C++ headers
- +#include <vector>
- +using namespace std;
- +
- +// Qt headers
- +#include <qstring.h>
- +#include <qmutex.h>
- +
- +// MythTV headers
- +#include "streamlisteners.h"
- +
- +extern "C" {
- +#include "r5000/r5000.h"
- +}
- +
- +class TSPacket;
- +class R5kPriv;
- +class R5000Device
- +{
- + public:
- +
- + // Public enums
- + typedef enum
- + {
- + kAVCPowerOn,
- + kAVCPowerOff,
- + kAVCPowerUnknown,
- + kAVCPowerQueryFailed,
- + } PowerState;
- +
- +
- + // AVC param 0
- + typedef enum
- + {
- + kAVCPowerStateOn = 0x70,
- + kAVCPowerStateOff = 0x60,
- + kAVCPowerStateQuery = 0x7f,
- + } IEEE1394UnitPowerParam0;
- +
- + R5000Device(int type, QString serial);
- + ~R5000Device();
- +
- + bool OpenPort(void);
- + bool ClosePort(void);
- + void RunPortHandler(void);
- +
- + // Commands
- + virtual bool ResetBus(void) { return false; }
- +
- + virtual void AddListener(TSDataListener*);
- + virtual void RemoveListener(TSDataListener*);
- +
- + // Sets
- + virtual bool SetPowerState(bool on);
- + virtual bool SetChannel(const QString &panel_model,
- + const QString &channel, uint mpeg_prog);
- +
- + // Gets
- + bool IsSTBBufferCleared(void) const { return m_buffer_cleared; }
- +
- + // non-const Gets
- + virtual PowerState GetPowerState(void);
- +
- + // Statics
- + static bool IsSTBSupported(const QString &model);
- + static QString GetModelName(uint vendorid, uint modelid);
- + static QStringList GetSTBList(void);
- + static int GetDeviceType(const QString &r5ktype);
- + void BroadcastToListeners(
- + const unsigned char *data, uint dataSize);
- +
- + protected:
- +
- + bool GetSubunitInfo(uint8_t table[32]);
- +
- + void SetLastChannel(const QString &channel);
- + void ProcessPATPacket(const TSPacket&);
- + bool StartStreaming(void);
- + bool StopStreaming(void);
- +
- + int m_type;
- + QString m_serial;
- + uint m_subunitid;
- + uint m_speed;
- + QString m_last_channel;
- + uint m_last_crc;
- + bool m_buffer_cleared;
- +
- + uint m_open_port_cnt;
- + vector<TSDataListener*> m_listeners;
- + mutable QMutex m_lock;
- +
- + /// Vendor ID + Model ID to R5000Device STB model string
- + static QMap<uint64_t,QString> s_id_to_model;
- + static QMutex s_static_lock;
- +private:
- + r5kdev_t *usbdev;
- + R5kPriv *m_priv;
- +};
- +
- +#endif // _FIREWIRE_DEVICE_H_
- Index: libs/libmythtv/recorderbase.cpp
- ===================================================================
- --- libs/libmythtv/recorderbase.cpp (revision 1)
- +++ libs/libmythtv/recorderbase.cpp (revision 4)
- @@ -9,12 +9,14 @@
- #include "firewirechannel.h"
- #include "importrecorder.h"
- #include "cetonrecorder.h"
- +#include "r5000recorder.h"
- #include "dummychannel.h"
- #include "hdhrrecorder.h"
- #include "iptvrecorder.h"
- #include "mpegrecorder.h"
- #include "recorderbase.h"
- #include "cetonchannel.h"
- +#include "r5000channel.h"
- #include "asirecorder.h"
- #include "dvbrecorder.h"
- #include "hdhrchannel.h"
- @@ -578,6 +580,13 @@
- recorder = new ImportRecorder(tvrec);
- #endif
- }
- + else if (genOpt.cardtype == "R5000")
- + {
- +#ifdef USING_R5000
- + recorder = new R5000Recorder(
- + tvrec, dynamic_cast<R5000Channel*>(channel));
- +#endif // USING_R5000
- + }
- else if (CardUtil::IsV4L(genOpt.cardtype))
- {
- #ifdef USING_V4L2
- Index: configure
- ===================================================================
- --- configure (revision 1)
- +++ configure (revision 4)
- @@ -119,6 +119,7 @@
- --disable-ivtv disable ivtv support (PVR-x50) req. v4l2 support
- --disable-hdpvr disable HD-PVR support
- --disable-dvb disable DVB support
- + --disable-r5000 disable support for R5000 USB STBs
- --dvb-path=HDRLOC location of directory containing
- 'linux/dvb/frontend.h', not the
- directory with frontend.h [$dvb_path_default]
- @@ -1514,6 +1515,7 @@
- hdpvr
- iptv
- ivtv
- + r5000
- asi
- joystick_menu
- libcec
- @@ -2033,6 +2035,7 @@
- audio_oss_deps_any="soundcard_h sys_soundcard_h"
- dvb_deps="backend"
- firewire_deps="backend"
- +r5000_deps="backend"
- iptv_deps="backend"
- ivtv_deps="backend v4l2"
- hdpvr_deps="backend v4l2"
- @@ -2239,6 +2242,7 @@
- enable hdpvr
- enable iptv
- enable ivtv
- +enable r5000
- enable asi
- enable lamemp3
- enable libass
- @@ -5016,6 +5020,7 @@
- echo "HDHomeRun support ${hdhomerun-no}"
- echo "Ceton support ${ceton-no}"
- echo "IPTV support ${iptv-no}"
- + echo "R5000 support ${r5000-no}"
- echo "ASI support ${asi-no}"
- fi
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement