00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #include <sys/ioctl.h>
00047 #include <pthread.h>
00048 #include <fcntl.h>
00049 #include <unistd.h>
00050
00051
00052 #include <iostream>
00053 #include <algorithm>
00054 using namespace std;
00055
00056
00057 #include "RingBuffer.h"
00058 #include "programinfo.h"
00059 #include "mpegtables.h"
00060 #include "iso639.h"
00061 #include "dvbstreamdata.h"
00062 #include "atscstreamdata.h"
00063 #include "atsctables.h"
00064 #include "cardutil.h"
00065 #include "tv_rec.h"
00066
00067
00068 #include "dvbtypes.h"
00069 #include "dvbchannel.h"
00070 #include "dvbrecorder.h"
00071 #include "dvbstreamhandler.h"
00072
00073
00074 extern "C" {
00075 #include "../libavcodec/avcodec.h"
00076 #include "../libavformat/avformat.h"
00077 #include "../libavformat/mpegts.h"
00078 }
00079
00080 const int DVBRecorder::TSPACKETS_BETWEEN_PSIP_SYNC = 20000;
00081 const int DVBRecorder::POLL_INTERVAL = 50;
00082 const int DVBRecorder::POLL_WARNING_TIMEOUT = 500;
00083 const unsigned char DVBRecorder::kPayloadStartSeen;
00084
00085 #define TS_TICKS_PER_SEC 90000
00086 #define DUMMY_VIDEO_PID VIDEO_PID(0x20)
00087
00088 #define LOC QString("DVBRec(%1:%2): ") \
00089 .arg(tvrec->GetCaptureCardNum()).arg(_card_number_option)
00090 #define LOC_WARN QString("DVBRec(%1:%2) Warning: ") \
00091 .arg(tvrec->GetCaptureCardNum()).arg(_card_number_option)
00092 #define LOC_ERR QString("DVBRec(%1:%2) Error: ") \
00093 .arg(tvrec->GetCaptureCardNum()).arg(_card_number_option)
00094
00095 DVBRecorder::DVBRecorder(TVRec *rec, DVBChannel* advbchannel)
00096 : DTVRecorder(rec),
00097
00098 _card_number_option(0),
00099
00100 dvbchannel(advbchannel),
00101 _stream_handler(NULL),
00102 _stream_data(NULL),
00103 _pid_lock(true),
00104 _input_pat(NULL),
00105 _input_pmt(NULL),
00106 _has_no_av(false),
00107
00108 _continuity_error_count(0), _stream_overflow_count(0)
00109 {
00110 _buffer_size = (1024*1024 / TSPacket::SIZE) * TSPacket::SIZE;
00111
00112 _buffer = new unsigned char[_buffer_size];
00113 bzero(_buffer, _buffer_size);
00114 }
00115
00116 DVBRecorder::~DVBRecorder()
00117 {
00118 TeardownAll();
00119 }
00120
00121 void DVBRecorder::TeardownAll(void)
00122 {
00123
00124 StopRecording();
00125
00126 if (IsOpen())
00127 Close();
00128
00129 if (_buffer)
00130 {
00131 delete[] _buffer;
00132 _buffer = NULL;
00133 }
00134
00135 if (_input_pat)
00136 {
00137 delete _input_pat;
00138 _input_pat = NULL;
00139 }
00140
00141 if (_input_pmt)
00142 {
00143 delete _input_pmt;
00144 _input_pmt = NULL;
00145 }
00146 }
00147
00148 void DVBRecorder::SetOption(const QString &name, int value)
00149 {
00150 if (name == "cardnum")
00151 {
00152 _card_number_option = value;
00153 videodevice = QString::number(value);
00154 }
00155 else
00156 DTVRecorder::SetOption(name, value);
00157 }
00158
00159 void DVBRecorder::SetOptionsFromProfile(RecordingProfile *profile,
00160 const QString &videodev,
00161 const QString&, const QString&)
00162 {
00163 SetOption("cardnum", videodev.toInt());
00164 DTVRecorder::SetOption("tvformat", gContext->GetSetting("TVFormat"));
00165 SetStrOption(profile, "recordingtype");
00166 }
00167
00168 void DVBRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat)
00169 {
00170 if (!pat)
00171 {
00172 VERBOSE(VB_RECORD, LOC + "HandleSingleProgramPAT(NULL)");
00173 return;
00174 }
00175
00176 if (!ringBuffer)
00177 return;
00178
00179 uint posA[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() };
00180
00181 if (pat)
00182 {
00183 uint next_cc = (pat->tsheader()->ContinuityCounter()+1)&0xf;
00184 pat->tsheader()->SetContinuityCounter(next_cc);
00185 DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(pat->tsheader())));
00186 }
00187
00188 uint posB[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() };
00189
00190 if (posB[0] + posB[1] * TSPacket::SIZE >
00191 posA[0] + posA[1] * TSPacket::SIZE)
00192 {
00193 VERBOSE(VB_RECORD, LOC + "Wrote PAT @"
00194 << posA[0] << " + " << (posA[1] * TSPacket::SIZE));
00195 }
00196 else
00197 {
00198 VERBOSE(VB_RECORD, LOC + "Saw PAT but did not write to disk yet");
00199 }
00200 }
00201
00202 void DVBRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
00203 {
00204 if (!pmt)
00205 {
00206 VERBOSE(VB_RECORD, LOC + "HandleSingleProgramPMT(NULL)");
00207 return;
00208 }
00209
00210
00211 for (uint i = 0; i < pmt->StreamCount(); i++)
00212 _stream_id[pmt->StreamPID(i)] = pmt->StreamType(i);
00213
00214 if (!ringBuffer)
00215 return;
00216
00217 unsigned char buf[8 * 1024];
00218 uint next_cc = (pmt->tsheader()->ContinuityCounter()+1)&0xf;
00219 pmt->tsheader()->SetContinuityCounter(next_cc);
00220 uint size = pmt->WriteAsTSPackets(buf, next_cc);
00221
00222 uint posA[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() };
00223
00224 for (uint i = 0; i < size ; i += TSPacket::SIZE)
00225 DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(&buf[i])));
00226
00227 uint posB[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() };
00228
00229 if (posB[0] + posB[1] * TSPacket::SIZE >
00230 posA[0] + posA[1] * TSPacket::SIZE)
00231 {
00232 VERBOSE(VB_RECORD, LOC + "Wrote PMT @"
00233 << posA[0] << " + " << (posA[1] * TSPacket::SIZE));
00234 }
00235 else
00236 {
00237 VERBOSE(VB_RECORD, LOC + "Saw PMT but did not write to disk yet");
00238 }
00239 }
00240
00241
00242 void DVBRecorder::HandlePAT(const ProgramAssociationTable *_pat)
00243 {
00244 if (!_pat)
00245 {
00246 VERBOSE(VB_RECORD, LOC + "SetPAT(NULL)");
00247 return;
00248 }
00249
00250 QMutexLocker change_lock(&_pid_lock);
00251
00252 int progNum = _stream_data->DesiredProgram();
00253 uint pmtpid = _pat->FindPID(progNum);
00254
00255 if (!pmtpid)
00256 {
00257 VERBOSE(VB_RECORD, LOC + "SetPAT(): "
00258 "Ignoring PAT not containing our desired program...");
00259 return;
00260 }
00261
00262 VERBOSE(VB_RECORD, LOC + QString("SetPAT(%1 on 0x%2)")
00263 .arg(progNum).arg(pmtpid,0,16));
00264
00265 ProgramAssociationTable *oldpat = _input_pat;
00266 _input_pat = new ProgramAssociationTable(*_pat);
00267 delete oldpat;
00268
00269
00270 for (uint i = 0; _input_pat && (i < _input_pat->ProgramCount()); i++)
00271 {
00272 uint pmt_pid = _input_pat->ProgramPID(i);
00273 if (!_stream_data->IsListeningPID(pmt_pid))
00274 _stream_data->AddListeningPID(pmt_pid, kPIDPriorityLow);
00275 }
00276 }
00277
00278 void DVBRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt)
00279 {
00280 QMutexLocker change_lock(&_pid_lock);
00281
00282 if ((int)progNum == _stream_data->DesiredProgram())
00283 {
00284 VERBOSE(VB_RECORD, LOC + "SetPMT("<<progNum<<")");
00285 ProgramMapTable *oldpmt = _input_pmt;
00286 _input_pmt = new ProgramMapTable(*_pmt);
00287
00288 QString sistandard = dvbchannel->GetSIStandard();
00289
00290 bool has_no_av = true;
00291 for (uint i = 0; i < _input_pmt->StreamCount() && has_no_av; i++)
00292 {
00293 has_no_av &= !_input_pmt->IsVideo(i, sistandard);
00294 has_no_av &= !_input_pmt->IsAudio(i, sistandard);
00295 }
00296 _has_no_av = has_no_av;
00297
00298 dvbchannel->SetPMT(_input_pmt);
00299 delete oldpmt;
00300 }
00301 }
00302
00303 void DVBRecorder::HandleSTT(const SystemTimeTable*)
00304 {
00305 dvbchannel->SetTimeOffset(GetStreamData()->TimeOffset());
00306 }
00307
00308 void DVBRecorder::HandleTDT(const TimeDateTable*)
00309 {
00310 dvbchannel->SetTimeOffset(GetStreamData()->TimeOffset());
00311 }
00312
00313 bool DVBRecorder::Open(void)
00314 {
00315 if (IsOpen())
00316 {
00317 VERBOSE(VB_GENERAL, LOC_WARN + "Card already open");
00318 return true;
00319 }
00320
00321 if (_card_number_option < 0)
00322 return false;
00323
00324 bzero(_stream_id, sizeof(_stream_id));
00325 bzero(_pid_status, sizeof(_pid_status));
00326 memset(_continuity_counter, 0xff, sizeof(_continuity_counter));
00327
00328 _stream_handler = DVBStreamHandler::Get(_card_number_option);
00329
00330 VERBOSE(VB_RECORD, LOC + QString("Card opened successfully fd(%1)")
00331 .arg(_stream_fd));
00332
00333 return true;
00334 }
00335
00336 void DVBRecorder::Close(void)
00337 {
00338 VERBOSE(VB_RECORD, LOC + "Close() fd("<<_stream_fd<<") -- begin");
00339
00340 DVBStreamHandler::Return(_stream_handler);
00341
00342 VERBOSE(VB_RECORD, LOC + "Close() fd("<<_stream_fd<<") -- end");
00343 }
00344
00345 void DVBRecorder::SetStreamData(MPEGStreamData *data)
00346 {
00347 if (data == _stream_data)
00348 return;
00349
00350 MPEGStreamData *old_data = _stream_data;
00351 _stream_data = data;
00352 if (old_data)
00353 delete old_data;
00354
00355 if (data)
00356 {
00357 data->AddMPEGSPListener(this);
00358 data->AddMPEGListener(this);
00359
00360 DVBStreamData *dvb = dynamic_cast<DVBStreamData*>(data);
00361 if (dvb)
00362 dvb->AddDVBMainListener(this);
00363
00364 ATSCStreamData *atsc = dynamic_cast<ATSCStreamData*>(data);
00365
00366 if (atsc && atsc->DesiredMinorChannel())
00367 atsc->SetDesiredChannel(atsc->DesiredMajorChannel(),
00368 atsc->DesiredMinorChannel());
00369 else if (data->DesiredProgram() >= 0)
00370 data->SetDesiredProgram(data->DesiredProgram());
00371 }
00372 }
00373
00374 void DVBRecorder::StartRecording(void)
00375 {
00376 if (!Open())
00377 {
00378 _error = true;
00379 return;
00380 }
00381
00382 _continuity_error_count = 0;
00383 _stream_overflow_count = 0;
00384
00385 _request_recording = true;
00386 _recording = true;
00387
00388
00389 if (dvbchannel && (dvbchannel->GetSIStandard() == "dvb"))
00390 _stream_data->AddListeningPID(DVB_TDT_PID);
00391
00392
00393 bool tmp = _wait_for_keyframe_option;
00394 _wait_for_keyframe_option = false;
00395 HandleSingleProgramPAT(_stream_data->PATSingleProgram());
00396 HandleSingleProgramPMT(_stream_data->PMTSingleProgram());
00397 _wait_for_keyframe_option = tmp;
00398
00399 _stream_data->AddAVListener(this);
00400 _stream_data->AddWritingListener(this);
00401 _stream_handler->AddListener(_stream_data, false, true);
00402
00403 while (_request_recording && !_error)
00404 {
00405 usleep(50000);
00406
00407 if (PauseAndWait())
00408 continue;
00409
00410 if (!_input_pmt)
00411 {
00412 VERBOSE(VB_GENERAL, LOC_WARN +
00413 "Recording will not commence until a PMT is set.");
00414 usleep(5000);
00415 continue;
00416 }
00417
00418 if (!_stream_handler->IsRunning())
00419 {
00420 _error = true;
00421
00422 VERBOSE(VB_IMPORTANT, LOC_ERR +
00423 "Stream handler died unexpectedly.");
00424 }
00425 }
00426
00427 _stream_handler->RemoveListener(_stream_data);
00428 _stream_data->RemoveWritingListener(this);
00429 _stream_data->RemoveAVListener(this);
00430
00431 Close();
00432
00433 FinishRecording();
00434
00435 _recording = false;
00436 }
00437
00438 void DVBRecorder::ResetForNewFile(void)
00439 {
00440 DTVRecorder::ResetForNewFile();
00441
00442 bzero(_stream_id, sizeof(_stream_id));
00443 bzero(_pid_status, sizeof(_pid_status));
00444 memset(_continuity_counter, 0xff, sizeof(_continuity_counter));
00445 }
00446
00447 void DVBRecorder::StopRecording(void)
00448 {
00449 _request_recording = false;
00450 while (_recording)
00451 usleep(2000);
00452 }
00453
00454 void DVBRecorder::ReaderPaused(int )
00455 {
00456 }
00457
00458 bool DVBRecorder::PauseAndWait(int timeout)
00459 {
00460 if (request_pause)
00461 {
00462 if (!paused)
00463 {
00464 assert(_stream_handler);
00465 assert(_stream_data);
00466
00467 _stream_handler->RemoveListener(_stream_data);
00468
00469 paused = true;
00470 pauseWait.wakeAll();
00471 if (tvrec)
00472 tvrec->RecorderPaused();
00473 }
00474 unpauseWait.wait(timeout);
00475 }
00476
00477 if (!request_pause && paused)
00478 {
00479 paused = false;
00480
00481 assert(_stream_handler);
00482 assert(_stream_data);
00483
00484 _stream_handler->AddListener(_stream_data, false, true);
00485 }
00486
00487 return paused;
00488 }
00489
00490 bool DVBRecorder::ProcessVideoTSPacket(const TSPacket &tspacket)
00491 {
00492 uint streamType = _stream_id[tspacket.PID()];
00493
00494
00495 if (streamType == StreamID::H264Video)
00496 {
00497 _buffer_packets = !FindH264Keyframes(&tspacket);
00498 if (!_seen_sps)
00499 return true;
00500 }
00501 else
00502 {
00503 _buffer_packets = !FindMPEG2Keyframes(&tspacket);
00504 }
00505
00506 return ProcessAVTSPacket(tspacket);
00507 }
00508
00509 bool DVBRecorder::ProcessAudioTSPacket(const TSPacket &tspacket)
00510 {
00511 _buffer_packets = !FindAudioKeyframes(&tspacket);
00512 return ProcessAVTSPacket(tspacket);
00513 }
00514
00516 bool DVBRecorder::ProcessAVTSPacket(const TSPacket &tspacket)
00517 {
00518 const uint pid = tspacket.PID();
00519
00520
00521 if ((pid != 0x1fff) && !CheckCC(pid, tspacket.ContinuityCounter()))
00522 {
00523 VERBOSE(VB_RECORD, LOC +
00524 QString("PID 0x%1 discontinuity detected").arg(pid,0,16));
00525 _continuity_error_count++;
00526 }
00527
00528
00529 if (_wait_for_keyframe_option && _first_keyframe < 0)
00530 return true;
00531
00532
00533
00534 if (!(_pid_status[pid] & kPayloadStartSeen) && tspacket.HasPayload())
00535 {
00536 if (!tspacket.PayloadStart())
00537 return true;
00538
00539 VERBOSE(VB_RECORD,
00540 QString("PID 0x%1 Found Payload Start").arg(pid,0,16));
00541
00542 _pid_status[pid] |= kPayloadStartSeen;
00543 }
00544
00545 BufferedWrite(tspacket);
00546
00547 return true;
00548 }
00549
00550 bool DVBRecorder::ProcessTSPacket(const TSPacket &tspacket)
00551 {
00552 const uint pid = tspacket.PID();
00553
00554
00555 if ((pid != 0x1fff) && !CheckCC(pid, tspacket.ContinuityCounter()))
00556 {
00557 VERBOSE(VB_RECORD, LOC +
00558 QString("PID 0x%1 discontinuity detected").arg(pid,0,16));
00559 _continuity_error_count++;
00560 }
00561
00562
00563 if (_input_pmt && _has_no_av)
00564 {
00565 _buffer_packets = !FindOtherKeyframes(&tspacket);
00566 }
00567 else
00568 {
00569
00570
00571 if (_wait_for_keyframe_option && _first_keyframe < 0)
00572 return true;
00573
00574 _buffer_packets = true;
00575 }
00576
00577 BufferedWrite(tspacket);
00578 }
00579
00580 void DVBRecorder::BufferedWrite(const TSPacket &tspacket)
00581 {
00582
00583
00584
00585
00586 if (_buffer_packets)
00587 {
00588 int idx = _payload_buffer.size();
00589 _payload_buffer.resize(idx + TSPacket::SIZE);
00590 memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::SIZE);
00591 return;
00592 }
00593
00594
00595
00596 if (!_payload_buffer.empty())
00597 {
00598 if (ringBuffer)
00599 ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size());
00600 _payload_buffer.clear();
00601 }
00602
00603 if (ringBuffer)
00604 ringBuffer->Write(tspacket.data(), TSPacket::SIZE);
00605 }