00001
00008
00009 #include <pthread.h>
00010 #include <unistd.h>
00011 #include <sys/types.h>
00012 #include <sys/socket.h>
00013 #include <netinet/in.h>
00014 #include <arpa/inet.h>
00015 #include <netdb.h>
00016 #include <sys/time.h>
00017 #include <fcntl.h>
00018
00019
00020 #include <iostream>
00021 #include <algorithm>
00022 using namespace std;
00023
00024
00025 #include "RingBuffer.h"
00026 #include "hdhrchannel.h"
00027 #include "hdhrrecorder.h"
00028 #include "atsctables.h"
00029 #include "atscstreamdata.h"
00030 #include "dvbstreamdata.h"
00031 #include "eithelper.h"
00032 #include "tv_rec.h"
00033
00034 #define LOC QString("HDHRRec(%1): ").arg(tvrec->GetCaptureCardNum())
00035 #define LOC_ERR QString("HDHRRec(%1), Error: ") \
00036 .arg(tvrec->GetCaptureCardNum())
00037
00038 HDHRRecorder::HDHRRecorder(TVRec *rec, HDHRChannel *channel)
00039 : DTVRecorder(rec),
00040 _channel(channel), _video_socket(NULL),
00041 _stream_data(NULL),
00042 _input_pat(NULL), _input_pmt(NULL),
00043 _reset_pid_filters(false),_pid_lock(true)
00044 {
00045 }
00046
00047 HDHRRecorder::~HDHRRecorder()
00048 {
00049 TeardownAll();
00050 }
00051
00052 void HDHRRecorder::TeardownAll(void)
00053 {
00054 StopRecording();
00055 Close();
00056 if (_stream_data)
00057 {
00058 delete _stream_data;
00059 _stream_data = NULL;
00060 }
00061
00062 if (_input_pat)
00063 {
00064 delete _input_pat;
00065 _input_pat = NULL;
00066 }
00067
00068 if (_input_pmt)
00069 {
00070 delete _input_pmt;
00071 _input_pmt = NULL;
00072 }
00073 }
00074
00075 void HDHRRecorder::SetOptionsFromProfile(RecordingProfile *profile,
00076 const QString &videodev,
00077 const QString &audiodev,
00078 const QString &vbidev)
00079 {
00080 (void)audiodev;
00081 (void)vbidev;
00082 (void)profile;
00083
00084 SetOption("videodevice", videodev);
00085 SetOption("tvformat", gContext->GetSetting("TVFormat"));
00086 SetOption("vbiformat", gContext->GetSetting("VbiFormat"));
00087
00088
00089
00090 SetOption("videodevice", QString::number(tvrec->GetCaptureCardNum()));
00091
00092 }
00093
00094 bool HDHRRecorder::Open(void)
00095 {
00096 VERBOSE(VB_RECORD, LOC + "Open()");
00097 if (_video_socket)
00098 {
00099 VERBOSE(VB_RECORD, LOC + "Card already open (recorder)");
00100 return true;
00101 }
00102
00103
00104 uint buffersize = gContext->GetNumSetting(
00105 "HDRingbufferSize", 50 * TSPacket::SIZE) * 1024;
00106 buffersize /= VIDEO_DATA_PACKET_SIZE;
00107 buffersize *= VIDEO_DATA_PACKET_SIZE;
00108
00109
00110 buffersize = max(49 * TSPacket::SIZE * 128, buffersize);
00111
00112
00113 _video_socket = hdhomerun_video_create(0, buffersize, NULL);
00114 if (!_video_socket)
00115 {
00116 VERBOSE(VB_IMPORTANT, LOC + "Open() failed to open socket");
00117 return false;
00118 }
00119
00120
00121 return true;
00122 }
00123
00127 bool HDHRRecorder::StartData(void)
00128 {
00129 VERBOSE(VB_RECORD, LOC + "StartData()");
00130 uint localPort = hdhomerun_video_get_local_port(_video_socket);
00131 return _channel->DeviceSetTarget(localPort);
00132 }
00133
00134 void HDHRRecorder::Close(void)
00135 {
00136 VERBOSE(VB_RECORD, LOC + "Close()");
00137 if (_video_socket)
00138 {
00139 hdhomerun_video_destroy(_video_socket);
00140 _video_socket = NULL;
00141 }
00142 }
00143
00144 void HDHRRecorder::ProcessTSData(const uint8_t *buffer, int len)
00145 {
00146 QMutexLocker locker(&_pid_lock);
00147 const uint8_t *data = buffer;
00148 const uint8_t *end = buffer + len;
00149
00150 while (data + 188 <= end)
00151 {
00152 if (data[0] != 0x47)
00153 {
00154 return;
00155 }
00156
00157 const TSPacket *tspacket = reinterpret_cast<const TSPacket*>(data);
00158 ProcessTSPacket(*tspacket);
00159
00160 data += 188;
00161 }
00162 }
00163
00164 void HDHRRecorder::SetStreamData(MPEGStreamData *data)
00165 {
00166 if (data == _stream_data)
00167 return;
00168
00169 MPEGStreamData *old_data = _stream_data;
00170 _stream_data = data;
00171 if (old_data)
00172 delete old_data;
00173
00174 if (data)
00175 {
00176 data->AddMPEGSPListener(this);
00177 data->AddMPEGListener(this);
00178
00179 DVBStreamData *dvb = dynamic_cast<DVBStreamData*>(data);
00180 if (dvb)
00181 dvb->AddDVBMainListener(this);
00182
00183 ATSCStreamData *atsc = dynamic_cast<ATSCStreamData*>(data);
00184 if (atsc && atsc->DesiredMinorChannel())
00185 atsc->SetDesiredChannel(atsc->DesiredMajorChannel(),
00186 atsc->DesiredMinorChannel());
00187 else if (data->DesiredProgram() >= 0)
00188 data->SetDesiredProgram(data->DesiredProgram());
00189 }
00190 }
00191
00192 ATSCStreamData *HDHRRecorder::GetATSCStreamData(void)
00193 {
00194 return dynamic_cast<ATSCStreamData*>(_stream_data);
00195 }
00196
00197 void HDHRRecorder::HandlePAT(const ProgramAssociationTable *_pat)
00198 {
00199 if (!_pat)
00200 {
00201 VERBOSE(VB_RECORD, LOC + "SetPAT(NULL)");
00202 return;
00203 }
00204
00205 QMutexLocker change_lock(&_pid_lock);
00206
00207 int progNum = _stream_data->DesiredProgram();
00208 uint pmtpid = _pat->FindPID(progNum);
00209
00210 if (!pmtpid)
00211 {
00212 VERBOSE(VB_RECORD, LOC + "SetPAT(): "
00213 "Ignoring PAT not containing our desired program...");
00214 return;
00215 }
00216
00217 VERBOSE(VB_RECORD, LOC + QString("SetPAT(%1 on 0x%2)")
00218 .arg(progNum).arg(pmtpid,0,16));
00219
00220 ProgramAssociationTable *oldpat = _input_pat;
00221 _input_pat = new ProgramAssociationTable(*_pat);
00222 delete oldpat;
00223
00224 _reset_pid_filters = true;
00225 }
00226
00227 void HDHRRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt)
00228 {
00229 QMutexLocker change_lock(&_pid_lock);
00230
00231 if ((int)progNum == _stream_data->DesiredProgram())
00232 {
00233 VERBOSE(VB_RECORD, LOC + "SetPMT("<<progNum<<")");
00234 ProgramMapTable *oldpmt = _input_pmt;
00235 _input_pmt = new ProgramMapTable(*_pmt);
00236 delete oldpmt;
00237
00238 _reset_pid_filters = true;
00239 }
00240 }
00241
00242 void HDHRRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat)
00243 {
00244 if (!pat)
00245 return;
00246
00247 int next = (pat->tsheader()->ContinuityCounter()+1)&0xf;
00248 pat->tsheader()->SetContinuityCounter(next);
00249 BufferedWrite(*(reinterpret_cast<TSPacket*>(pat->tsheader())));
00250 }
00251
00252 void HDHRRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
00253 {
00254 if (!pmt)
00255 return;
00256
00257 unsigned char buf[8 * 1024];
00258 uint next_cc = (pmt->tsheader()->ContinuityCounter()+1)&0xf;
00259 pmt->tsheader()->SetContinuityCounter(next_cc);
00260 uint size = pmt->WriteAsTSPackets(buf, next_cc);
00261
00262 for (uint i = 0; i < size ; i += TSPacket::SIZE)
00263 DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(&buf[i])));
00264 }
00265
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283 bool HDHRRecorder::ProcessTSPacket(const TSPacket& tspacket)
00284 {
00285 bool ok = !tspacket.TransportError();
00286 if (ok && !tspacket.ScramplingControl())
00287 {
00288 if (tspacket.HasAdaptationField())
00289 GetStreamData()->HandleAdaptationFieldControl(&tspacket);
00290 if (tspacket.HasPayload())
00291 {
00292 const unsigned int lpid = tspacket.PID();
00293
00294 if ((GetStreamData()->VideoPIDSingleProgram() > 0x1fff) &&
00295 _wait_for_keyframe_option)
00296 {
00297 _wait_for_keyframe_option = false;
00298 }
00299
00300
00301 if (lpid == GetStreamData()->VideoPIDSingleProgram())
00302 {
00303
00304 ProgramMapTable *pmt = _stream_data->PMTSingleProgram();
00305 uint video_stream_type = pmt->StreamType(pmt->FindPID(lpid));
00306
00307 if (video_stream_type == StreamID::H264Video)
00308 _buffer_packets = !FindH264Keyframes(&tspacket);
00309 else if (StreamID::IsVideo(video_stream_type))
00310 _buffer_packets = !FindMPEG2Keyframes(&tspacket);
00311
00312 if ((video_stream_type != StreamID::H264Video) || _seen_sps)
00313 BufferedWrite(tspacket);
00314 }
00315 else if (GetStreamData()->IsAudioPID(lpid))
00316 {
00317
00318 _buffer_packets = !FindAudioKeyframes(&tspacket);
00319 BufferedWrite(tspacket);
00320 }
00321 else if (GetStreamData()->IsListeningPID(lpid))
00322 {
00323
00324 GetStreamData()->HandleTSTables(&tspacket);
00325 }
00326 else if (GetStreamData()->IsWritingPID(lpid))
00327 BufferedWrite(tspacket);
00328 }
00329 }
00330 return ok;
00331 }
00332
00333 void HDHRRecorder::StartRecording(void)
00334 {
00335 VERBOSE(VB_RECORD, LOC + "StartRecording -- begin");
00336
00337
00338 if (!Open())
00339 {
00340 _error = true;
00341 VERBOSE(VB_RECORD, LOC + "StartRecording -- end 1");
00342 return;
00343 }
00344
00345 _request_recording = true;
00346 _recording = true;
00347
00348 if (!StartData())
00349 {
00350 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting recording "
00351 "(set target failed). Aborting.");
00352 Close();
00353 _error = true;
00354 VERBOSE(VB_RECORD, LOC + "StartRecording -- end 2");
00355 return;
00356 }
00357
00358 hdhomerun_video_flush(_video_socket);
00359 while (_request_recording && !_error)
00360 {
00361 if (PauseAndWait())
00362 continue;
00363
00364 if (_stream_data)
00365 {
00366 QMutexLocker read_lock(&_pid_lock);
00367 _reset_pid_filters |= _stream_data->HasEITPIDChanges(_eit_pids);
00368 }
00369
00370 if (_reset_pid_filters)
00371 {
00372 _reset_pid_filters = false;
00373 VERBOSE(VB_RECORD, LOC + "Resetting Demux Filters");
00374 AdjustFilters();
00375 }
00376
00377 size_t read_size = 64 * 1024;
00378 read_size /= VIDEO_DATA_PACKET_SIZE;
00379 read_size *= VIDEO_DATA_PACKET_SIZE;
00380
00381 size_t data_length;
00382 unsigned char *data_buffer =
00383 hdhomerun_video_recv(_video_socket, read_size, &data_length);
00384 if (!data_buffer)
00385 {
00386 usleep(5000);
00387 continue;
00388 }
00389
00390 ProcessTSData(data_buffer, data_length);
00391 }
00392
00393 VERBOSE(VB_RECORD, LOC + "StartRecording -- ending...");
00394
00395 _channel->DeviceClearTarget();
00396 Close();
00397
00398 FinishRecording();
00399 _recording = false;
00400
00401 VERBOSE(VB_RECORD, LOC + "StartRecording -- end");
00402 }
00403
00404 bool HDHRRecorder::AdjustFilters(void)
00405 {
00406 QMutexLocker change_lock(&_pid_lock);
00407
00408 if (!_channel)
00409 {
00410 VERBOSE(VB_IMPORTANT, LOC_ERR + "AdjustFilters() no channel");
00411 return false;
00412 }
00413
00414 if (!_input_pat || !_input_pmt)
00415 {
00416 VERBOSE(VB_IMPORTANT, LOC + "AdjustFilters() no pmt or no pat");
00417 return false;
00418 }
00419
00420 uint_vec_t add_pid;
00421
00422 add_pid.push_back(MPEG_PAT_PID);
00423 _stream_data->AddListeningPID(MPEG_PAT_PID);
00424
00425 for (uint i = 0; i < _input_pat->ProgramCount(); i++)
00426 {
00427 add_pid.push_back(_input_pat->ProgramPID(i));
00428 _stream_data->AddListeningPID(_input_pat->ProgramPID(i));
00429 }
00430
00431
00432 bool need_pcr_pid = true;
00433 for (uint i = 0; i < _input_pmt->StreamCount(); i++)
00434 {
00435 add_pid.push_back(_input_pmt->StreamPID(i));
00436 need_pcr_pid &= (_input_pmt->StreamPID(i) != _input_pmt->PCRPID());
00437 _stream_data->AddWritingPID(_input_pmt->StreamPID(i));
00438 }
00439
00440 if (need_pcr_pid && (_input_pmt->PCRPID()))
00441 {
00442 add_pid.push_back(_input_pmt->PCRPID());
00443 _stream_data->AddWritingPID(_input_pmt->PCRPID());
00444 }
00445
00446
00447 AdjustEITPIDs();
00448 for (uint i = 0; i < _eit_pids.size(); i++)
00449 {
00450 add_pid.push_back(_eit_pids[i]);
00451 _stream_data->AddListeningPID(_eit_pids[i]);
00452 }
00453
00454
00455 vector<uint>::const_iterator it;
00456 vector<uint> pids = _channel->GetPIDs();
00457 for (it = pids.begin(); it != pids.end(); ++it)
00458 {
00459 if (find(add_pid.begin(), add_pid.end(), *it) == add_pid.end())
00460 {
00461 _stream_data->RemoveListeningPID(*it);
00462 _stream_data->RemoveWritingPID(*it);
00463 _channel->DelPID(*it, false);
00464 }
00465 }
00466
00467 for (it = add_pid.begin(); it != add_pid.end(); ++it)
00468 _channel->AddPID(*it, false);
00469
00470 _channel->UpdateFilters();
00471
00472 return add_pid.size();
00473 }
00474
00478 bool HDHRRecorder::AdjustEITPIDs(void)
00479 {
00480 bool changes = false;
00481 uint_vec_t add, del;
00482
00483 QMutexLocker change_lock(&_pid_lock);
00484
00485 if (GetStreamData()->HasEITPIDChanges(_eit_pids))
00486 changes = GetStreamData()->GetEITPIDChanges(_eit_pids, add, del);
00487
00488 if (!changes)
00489 return false;
00490
00491 for (uint i = 0; i < del.size(); i++)
00492 {
00493 uint_vec_t::iterator it;
00494 it = find(_eit_pids.begin(), _eit_pids.end(), del[i]);
00495 if (it != _eit_pids.end())
00496 _eit_pids.erase(it);
00497 }
00498
00499 for (uint i = 0; i < add.size(); i++)
00500 _eit_pids.push_back(add[i]);
00501
00502 return true;
00503 }
00504