00001
00021 #include "atscstreamdata.h"
00022 #include "mpegstreamdata.h"
00023 #include "dvbstreamdata.h"
00024 #include "dtvrecorder.h"
00025 #include "programinfo.h"
00026 #include "mythlogging.h"
00027 #include "mpegtables.h"
00028 #include "ringbuffer.h"
00029 #include "tv_rec.h"
00030
00031 extern "C" {
00032 #include "libavcodec/mpegvideo.h"
00033 }
00034
00035 #define LOC ((tvrec) ? \
00036 QString("DTVRec(%1): ").arg(tvrec->GetCaptureCardNum()) : \
00037 QString("DTVRec(0x%1): ").arg(intptr_t(this),0,16))
00038
00039 const uint DTVRecorder::kMaxKeyFrameDistance = 80;
00040
00049 DTVRecorder::DTVRecorder(TVRec *rec) :
00050 RecorderBase(rec),
00051
00052 _stream_fd(-1),
00053 _recording_type("all"),
00054
00055 _start_code(0xffffffff), _first_keyframe(-1),
00056 _last_gop_seen(0), _last_seq_seen(0),
00057 _last_keyframe_seen(0),
00058 _audio_bytes_remaining(0), _video_bytes_remaining(0),
00059 _other_bytes_remaining(0),
00060
00061 _progressive_sequence(0),
00062 _repeat_pict(0),
00063
00064 _pes_synced(false),
00065 _seen_sps(false),
00066
00067 _wait_for_keyframe_option(true),
00068 _has_written_other_keyframe(false),
00069
00070 _error(),
00071 _stream_data(NULL),
00072
00073
00074 _buffer_packets(false),
00075
00076 _pid_lock(QMutex::Recursive),
00077 _input_pat(NULL),
00078 _input_pmt(NULL),
00079 _has_no_av(false),
00080
00081 _use_pts(false),
00082 _packet_count(0),
00083 _continuity_error_count(0),
00084 _frames_seen_count(0), _frames_written_count(0)
00085 {
00086 SetPositionMapType(MARK_GOP_BYFRAME);
00087 _payload_buffer.reserve(TSPacket::kSize * (50 + 1));
00088 ResetForNewFile();
00089 }
00090
00091 DTVRecorder::~DTVRecorder()
00092 {
00093 StopRecording();
00094
00095 SetStreamData(NULL);
00096
00097 if (_input_pat)
00098 {
00099 delete _input_pat;
00100 _input_pat = NULL;
00101 }
00102
00103 if (_input_pmt)
00104 {
00105 delete _input_pmt;
00106 _input_pmt = NULL;
00107 }
00108 }
00109
00110 void DTVRecorder::SetOption(const QString &name, const QString &value)
00111 {
00112 if (name == "recordingtype")
00113 {
00114 _recording_type = value;
00115 _recording_type.detach();
00116 }
00117 else
00118 RecorderBase::SetOption(name, value);
00119 }
00120
00124 void DTVRecorder::SetOption(const QString &name, int value)
00125 {
00126 if (name == "wait_for_seqstart")
00127 _wait_for_keyframe_option = (value == 1);
00128 else
00129 RecorderBase::SetOption(name, value);
00130 }
00131
00132 void DTVRecorder::SetOptionsFromProfile(RecordingProfile *profile,
00133 const QString &videodev,
00134 const QString&, const QString&)
00135 {
00136 SetOption("videodevice", videodev);
00137 DTVRecorder::SetOption("tvformat", gCoreContext->GetSetting("TVFormat"));
00138 SetStrOption(profile, "recordingtype");
00139 }
00140
00145 void DTVRecorder::FinishRecording(void)
00146 {
00147 if (ringBuffer)
00148 {
00149 if (!_payload_buffer.empty())
00150 {
00151 ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size());
00152 _payload_buffer.clear();
00153 }
00154 ringBuffer->WriterFlush();
00155 }
00156
00157 if (curRecording)
00158 {
00159 if (ringBuffer)
00160 curRecording->SaveFilesize(ringBuffer->GetRealFileSize());
00161 SavePositionMap(true);
00162 }
00163 }
00164
00165 void DTVRecorder::ResetForNewFile(void)
00166 {
00167 LOG(VB_RECORD, LOG_INFO, LOC + "ResetForNewFile(void)");
00168 QMutexLocker locker(&positionMapLock);
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178 _start_code = 0xffffffff;
00179
00180 _has_written_other_keyframe = false;
00181 _last_keyframe_seen = 0;
00182 _last_gop_seen = 0;
00183 _last_seq_seen = 0;
00184 _audio_bytes_remaining = 0;
00185 _video_bytes_remaining = 0;
00186 _other_bytes_remaining = 0;
00187
00188 _error = QString();
00189
00190 memset(_stream_id, 0, sizeof(_stream_id));
00191 memset(_pid_status, 0, sizeof(_pid_status));
00192 memset(_continuity_counter, 0xff, sizeof(_continuity_counter));
00193
00194 _progressive_sequence = 0;
00195 _repeat_pict = 0;
00196
00197 _pes_synced = false;
00198
00199 positionMap.clear();
00200 positionMapDelta.clear();
00201 _payload_buffer.clear();
00202
00203 locker.unlock();
00204 ClearStatistics();
00205 }
00206
00207 void DTVRecorder::ClearStatistics(void)
00208 {
00209 RecorderBase::ClearStatistics();
00210
00211 memset(_ts_count, 0, sizeof(_ts_count));
00212 for (int i = 0; i < 256; i++)
00213 _ts_last[i] = -1LL;
00214 for (int i = 0; i < 256; i++)
00215 _ts_first[i] = -1LL;
00216
00217 _packet_count.fetchAndStoreRelaxed(0);
00218 _continuity_error_count.fetchAndStoreRelaxed(0);
00219 _frames_seen_count = 0;
00220 _frames_written_count = 0;
00221 }
00222
00223
00224 void DTVRecorder::Reset(void)
00225 {
00226 LOG(VB_RECORD, LOG_INFO, LOC + "Reset(void)");
00227 ResetForNewFile();
00228
00229 _start_code = 0xffffffff;
00230
00231 if (curRecording)
00232 curRecording->ClearPositionMap(MARK_GOP_BYFRAME);
00233 }
00234
00235 void DTVRecorder::SetStreamData(MPEGStreamData *data)
00236 {
00237 if (data == _stream_data)
00238 return;
00239
00240 MPEGStreamData *old_data = _stream_data;
00241 _stream_data = data;
00242 if (old_data)
00243 delete old_data;
00244
00245 if (_stream_data)
00246 SetStreamData();
00247 }
00248
00249 void DTVRecorder::SetStreamData(void)
00250 {
00251 _stream_data->AddMPEGSPListener(this);
00252 _stream_data->AddMPEGListener(this);
00253
00254 DVBStreamData *dvb = dynamic_cast<DVBStreamData*>(_stream_data);
00255 if (dvb)
00256 dvb->AddDVBMainListener(this);
00257
00258 ATSCStreamData *atsc = dynamic_cast<ATSCStreamData*>(_stream_data);
00259
00260 if (atsc && atsc->DesiredMinorChannel())
00261 atsc->SetDesiredChannel(atsc->DesiredMajorChannel(),
00262 atsc->DesiredMinorChannel());
00263 else if (_stream_data->DesiredProgram() >= 0)
00264 _stream_data->SetDesiredProgram(_stream_data->DesiredProgram());
00265 }
00266
00267 void DTVRecorder::BufferedWrite(const TSPacket &tspacket)
00268 {
00269
00270 if (_wait_for_keyframe_option && _first_keyframe<0)
00271 return;
00272
00273 if (curRecording && timeOfFirstDataIsSet.testAndSetRelaxed(0,1))
00274 {
00275 QMutexLocker locker(&statisticsLock);
00276 timeOfFirstData = mythCurrentDateTime();
00277 timeOfLatestData = mythCurrentDateTime();
00278 timeOfLatestDataTimer.start();
00279 }
00280
00281 int val = timeOfLatestDataCount.fetchAndAddRelaxed(1);
00282 int thresh = timeOfLatestDataPacketInterval.fetchAndAddRelaxed(0);
00283 if (val > thresh)
00284 {
00285 QMutexLocker locker(&statisticsLock);
00286 uint elapsed = timeOfLatestDataTimer.restart();
00287 int interval = thresh;
00288 if (elapsed > kTimeOfLatestDataIntervalTarget + 250)
00289 interval = timeOfLatestDataPacketInterval
00290 .fetchAndStoreRelaxed(thresh * 4 / 5);
00291 else if (elapsed + 250 < kTimeOfLatestDataIntervalTarget)
00292 interval = timeOfLatestDataPacketInterval
00293 .fetchAndStoreRelaxed(thresh * 9 / 8);
00294
00295 timeOfLatestDataCount.fetchAndStoreRelaxed(1);
00296 timeOfLatestData = mythCurrentDateTime();
00297
00298 LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Updating timeOfLatestData ") +
00299 QString("elapsed(%1) interval(%2)")
00300 .arg(elapsed).arg(interval));
00301 }
00302
00303
00304 if (_buffer_packets)
00305 {
00306 int idx = _payload_buffer.size();
00307 _payload_buffer.resize(idx + TSPacket::kSize);
00308 memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::kSize);
00309 return;
00310 }
00311
00312
00313
00314 if (!_payload_buffer.empty())
00315 {
00316 if (ringBuffer)
00317 ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size());
00318 _payload_buffer.clear();
00319 }
00320
00321 if (ringBuffer)
00322 ringBuffer->Write(tspacket.data(), TSPacket::kSize);
00323 }
00324
00325 enum { kExtractPTS, kExtractDTS };
00326 static int64_t extract_timestamp(
00327 const uint8_t *bufptr, int bytes_left, int pts_or_dts)
00328 {
00329 if (bytes_left < 4)
00330 return -1LL;
00331
00332 bool has_pts = bufptr[3] & 0x80;
00333 int offset = 5;
00334 if (((kExtractPTS == pts_or_dts) && !has_pts) || (offset + 5 > bytes_left))
00335 return -1LL;
00336
00337 bool has_dts = bufptr[3] & 0x40;
00338 if (kExtractDTS == pts_or_dts)
00339 {
00340 if (!has_dts)
00341 return -1LL;
00342 offset += has_pts ? 5 : 0;
00343 if (offset + 5 > bytes_left)
00344 return -1LL;
00345 }
00346
00347 return ((uint64_t(bufptr[offset+0] & 0x0e) << 29) |
00348 (uint64_t(bufptr[offset+1] ) << 22) |
00349 (uint64_t(bufptr[offset+2] & 0xfe) << 14) |
00350 (uint64_t(bufptr[offset+3] ) << 7) |
00351 (uint64_t(bufptr[offset+4] & 0xfe) >> 1));
00352 }
00353
00354 static QDateTime ts_to_qdatetime(
00355 uint64_t pts, uint64_t pts_first, QDateTime &pts_first_dt)
00356 {
00357 if (pts < pts_first)
00358 pts += 0x1FFFFFFFFLL;
00359 QDateTime dt = pts_first_dt;
00360 return dt.addMSecs((pts - pts_first)/90);
00361 }
00362
00363 static const uint frameRateMap[16] = {
00364 0, 23796, 24000, 25000, 29970, 30000, 50000, 59940, 60000,
00365 0, 0, 0, 0, 0, 0, 0
00366 };
00367
00394 bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket)
00395 {
00396 bool haveBufferedData = !_payload_buffer.empty();
00397 if (!tspacket->HasPayload())
00398 return !haveBufferedData;
00399
00400 if (!ringBuffer)
00401 return !haveBufferedData;
00402
00403
00404
00405
00406 const bool payloadStart = tspacket->PayloadStart();
00407 _start_code = (payloadStart) ? 0xffffffff : _start_code;
00408
00409
00410 const uint maxKFD = kMaxKeyFrameDistance;
00411 bool hasFrame = false;
00412 bool hasKeyFrame = false;
00413
00414 uint aspectRatio = 0;
00415 uint height = 0;
00416 uint width = 0;
00417 uint frameRate = 0;
00418
00419
00420
00421
00422
00423
00424
00425
00426 const uint8_t *bufptr = tspacket->data() + tspacket->AFCOffset();
00427 const uint8_t *bufend = tspacket->data() + TSPacket::kSize;
00428 int ext_type, bytes_left;
00429 int picture_structure, top_field_first, repeat_first_field, progressive_frame;
00430 _repeat_pict = 0;
00431
00432 while (bufptr < bufend)
00433 {
00434 bufptr = avpriv_mpv_find_start_code(bufptr, bufend, &_start_code);
00435 bytes_left = bufend - bufptr;
00436 if ((_start_code & 0xffffff00) == 0x00000100)
00437 {
00438
00439
00440 const int stream_id = _start_code & 0x000000ff;
00441 if (PESStreamID::PictureStartCode == stream_id)
00442 hasFrame = true;
00443 else if (PESStreamID::GOPStartCode == stream_id)
00444 {
00445 _last_gop_seen = _frames_seen_count;
00446 hasKeyFrame |= true;
00447 }
00448 else if (PESStreamID::SequenceStartCode == stream_id)
00449 {
00450 _last_seq_seen = _frames_seen_count;
00451 hasKeyFrame |= (_last_gop_seen + maxKFD)<_frames_seen_count;
00452
00453
00454 aspectRatio = (bufptr[3] >> 4);
00455
00456
00457 height = ((bufptr[1] & 0xf) << 8) | bufptr[2];
00458 width = (bufptr[0] <<4) | (bufptr[1]>>4);
00459
00460 frameRate = frameRateMap[(bufptr[3] & 0x0000000f)];
00461 }
00462 else if (PESStreamID::MPEG2ExtensionStartCode == stream_id)
00463 {
00464 if (bytes_left >= 1)
00465 {
00466 ext_type = (bufptr[0] >> 4);
00467 switch(ext_type)
00468 {
00469 case 0x1:
00470 if (bytes_left >= 6)
00471 {
00472 _progressive_sequence = bufptr[1] & (1 << 3);
00473 }
00474 break;
00475 case 0x8:
00476 if (bytes_left >= 5)
00477 {
00478 picture_structure = bufptr[2]&3;
00479 top_field_first = bufptr[3] & (1 << 7);
00480 repeat_first_field = bufptr[3] & (1 << 1);
00481 progressive_frame = bufptr[4] & (1 << 7);
00482
00483
00484 _repeat_pict = 1;
00485 if (repeat_first_field)
00486 {
00487 if (_progressive_sequence)
00488 {
00489 if (top_field_first)
00490 _repeat_pict = 5;
00491 else
00492 _repeat_pict = 3;
00493 }
00494 else if (progressive_frame)
00495 {
00496 _repeat_pict = 2;
00497 }
00498 }
00499 }
00500 break;
00501 }
00502 }
00503 }
00504 if ((stream_id >= PESStreamID::MPEGVideoStreamBegin) &&
00505 (stream_id <= PESStreamID::MPEGVideoStreamEnd))
00506 {
00507 int64_t pts = extract_timestamp(
00508 bufptr, bytes_left, kExtractPTS);
00509 int64_t dts = extract_timestamp(
00510 bufptr, bytes_left, kExtractPTS);
00511 HandleTimestamps(stream_id, pts, dts);
00512 }
00513 }
00514 }
00515
00516 if (hasFrame && !hasKeyFrame)
00517 {
00518
00519
00520
00521
00522 hasKeyFrame = !(_frames_seen_count & 0xf);
00523 hasKeyFrame &= (_last_gop_seen + maxKFD) < _frames_seen_count;
00524 hasKeyFrame &= (_last_seq_seen + maxKFD) < _frames_seen_count;
00525 }
00526
00527 if (hasKeyFrame)
00528 {
00529 _last_keyframe_seen = _frames_seen_count;
00530 HandleKeyframe(_frames_written_count, TSPacket::kSize);
00531 }
00532
00533 if (hasFrame)
00534 {
00535 _frames_seen_count++;
00536 if (!_wait_for_keyframe_option || _first_keyframe>=0)
00537 _frames_written_count++;
00538 }
00539
00540 if ((aspectRatio > 0) && (aspectRatio != m_videoAspect))
00541 {
00542 m_videoAspect = aspectRatio;
00543 AspectChange((AspectRatio)aspectRatio, _frames_written_count);
00544 }
00545
00546 if (height && width && (height != m_videoHeight || m_videoWidth != width))
00547 {
00548 m_videoHeight = height;
00549 m_videoWidth = width;
00550 ResolutionChange(width, height, _frames_written_count);
00551 }
00552
00553 if (frameRate && frameRate != m_frameRate)
00554 {
00555 m_frameRate = frameRate;
00556 LOG(VB_RECORD, LOG_INFO, LOC +
00557 QString("FindMPEG2Keyframes: frame rate = %1") .arg(frameRate));
00558 FrameRateChange(frameRate, _frames_written_count);
00559 }
00560
00561 return hasKeyFrame || (_payload_buffer.size() >= (188*50));
00562 }
00563
00564 void DTVRecorder::HandleTimestamps(int stream_id, int64_t pts, int64_t dts)
00565 {
00566 if (pts < 0)
00567 {
00568 _ts_last[stream_id] = -1;
00569 return;
00570 }
00571
00572 if ((dts < 0) && !_use_pts)
00573 {
00574 _ts_last[stream_id] = -1;
00575 _use_pts = true;
00576 LOG(VB_RECORD, LOG_DEBUG,
00577 "Switching from dts tracking to pts tracking." +
00578 QString("TS count is %1").arg(_ts_count[stream_id]));
00579 }
00580
00581 int64_t ts = dts;
00582 int64_t gap_threshold = 90000;
00583 if (_use_pts)
00584 {
00585 ts = dts;
00586 gap_threshold = 2*90000;
00587 }
00588
00589 if (_ts_last[stream_id] >= 0)
00590 {
00591 int64_t diff = ts - _ts_last[stream_id];
00592 if ((diff < 0) && (diff < (10 * -90000)))
00593 diff += 0x1ffffffffLL;
00594 if (diff < 0)
00595 diff = -diff;
00596 if (diff > gap_threshold)
00597 {
00598 QMutexLocker locker(&statisticsLock);
00599 recordingGaps.push_back(
00600 RecordingGap(
00601 ts_to_qdatetime(
00602 _ts_last[stream_id], _ts_first[stream_id],
00603 _ts_first_dt[stream_id]),
00604 ts_to_qdatetime(
00605 ts, _ts_first[stream_id], _ts_first_dt[stream_id])));
00606 LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Inserted gap %1 dur %2")
00607 .arg(recordingGaps.back().toString()).arg(diff/90000.0));
00608 }
00609 }
00610
00611 _ts_last[stream_id] = ts;
00612
00613 if (_ts_count[stream_id] < 30)
00614 {
00615 if (!_ts_count[stream_id])
00616 {
00617 _ts_first[stream_id] = ts;
00618 _ts_first_dt[stream_id] = mythCurrentDateTime();
00619 }
00620 else if (ts < _ts_first[stream_id])
00621 {
00622 _ts_first[stream_id] = ts;
00623 _ts_first_dt[stream_id] = mythCurrentDateTime();
00624 }
00625 }
00626
00627 _ts_count[stream_id]++;
00628 }
00629
00630 bool DTVRecorder::FindAudioKeyframes(const TSPacket*)
00631 {
00632 bool hasKeyFrame = false;
00633 if (!ringBuffer || (GetStreamData()->VideoPIDSingleProgram() <= 0x1fff))
00634 return hasKeyFrame;
00635
00636 static const uint64_t msec_per_day = 24 * 60 * 60 * 1000ULL;
00637 const double frame_interval = (1000.0 / video_frame_rate);
00638 uint64_t elapsed = (uint64_t) max(_audio_timer.elapsed(), 0);
00639 uint64_t expected_frame =
00640 (uint64_t) ((double)elapsed / frame_interval);
00641
00642 while (_frames_seen_count > expected_frame + 10000)
00643 expected_frame += (uint64_t) ((double)msec_per_day / frame_interval);
00644
00645 if (!_frames_seen_count || (_frames_seen_count < expected_frame))
00646 {
00647 if (!_frames_seen_count)
00648 _audio_timer.start();
00649
00650 _frames_seen_count++;
00651
00652 if (1 == (_frames_seen_count & 0x7))
00653 {
00654 _last_keyframe_seen = _frames_seen_count;
00655 HandleKeyframe(_frames_written_count);
00656 hasKeyFrame = true;
00657 }
00658
00659 if (!_wait_for_keyframe_option || _first_keyframe>=0)
00660 _frames_written_count++;
00661 }
00662
00663 return hasKeyFrame;
00664 }
00665
00668 bool DTVRecorder::FindOtherKeyframes(const TSPacket *tspacket)
00669 {
00670 if (!ringBuffer || (GetStreamData()->VideoPIDSingleProgram() <= 0x1fff))
00671 return true;
00672
00673 if (_has_written_other_keyframe)
00674 return true;
00675
00676 LOG(VB_RECORD, LOG_INFO, LOC + "DSMCC - FindOtherKeyframes() - "
00677 "generating initial key-frame");
00678
00679 _frames_seen_count++;
00680 _frames_written_count++;
00681 _last_keyframe_seen = _frames_seen_count;
00682
00683 HandleKeyframe(_frames_written_count);
00684
00685 _has_written_other_keyframe = true;
00686
00687 return true;
00688 }
00689
00690
00691 void DTVRecorder::SetNextRecording(const ProgramInfo *progInf, RingBuffer *rb)
00692 {
00693 LOG(VB_RECORD, LOG_INFO, LOC + QString("SetNextRecord(0x%1, 0x%2)")
00694 .arg((uint64_t)progInf,0,16).arg((uint64_t)rb,0,16));
00695
00696 SavePositionMap(true);
00697 if (ringBuffer)
00698 {
00699 ringBuffer->WriterFlush();
00700 if (curRecording)
00701 curRecording->SaveFilesize(ringBuffer->GetRealFileSize());
00702 }
00703
00704
00705 nextRingBufferLock.lock();
00706
00707 nextRecording = NULL;
00708 if (progInf)
00709 nextRecording = new ProgramInfo(*progInf);
00710
00711 nextRingBuffer = rb;
00712 nextRingBufferLock.unlock();
00713 }
00714
00719 void DTVRecorder::HandleKeyframe(uint64_t frameNum, int64_t extra)
00720 {
00721 if (!ringBuffer)
00722 return;
00723
00724 #if 0
00725 unsigned long long frameNum = _frames_written_count;
00726 #endif
00727
00728 _first_keyframe = (_first_keyframe < 0) ? frameNum : _first_keyframe;
00729
00730
00731 positionMapLock.lock();
00732 if (!positionMap.contains(frameNum))
00733 {
00734 long long startpos = ringBuffer->GetWritePosition();
00735
00736 startpos += _payload_buffer.size() - extra;
00737
00738
00739
00740
00741 if (startpos >= 0)
00742 {
00743 positionMapDelta[frameNum] = startpos;
00744 positionMap[frameNum] = startpos;
00745 }
00746 }
00747 positionMapLock.unlock();
00748
00749
00750 CheckForRingBufferSwitch();
00751 }
00752
00758 bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)
00759 {
00760 if (!ringBuffer)
00761 {
00762 LOG(VB_GENERAL, LOG_ERR, LOC + "FindH264Keyframes: No ringbuffer");
00763 return false;
00764 }
00765
00766 bool haveBufferedData = !_payload_buffer.empty();
00767 if (!tspacket->HasPayload())
00768 return !haveBufferedData;
00769
00770 const bool payloadStart = tspacket->PayloadStart();
00771 if (payloadStart)
00772 {
00773
00774 _pes_synced = false;
00775 _start_code = 0xffffffff;
00776 }
00777
00778 uint aspectRatio = 0;
00779 uint height = 0;
00780 uint width = 0;
00781 uint frameRate = 0;
00782
00783 bool hasFrame = false;
00784 bool hasKeyFrame = false;
00785
00786
00787 uint i = tspacket->AFCOffset();
00788 for (; i < TSPacket::kSize; i++)
00789 {
00790
00791 if (payloadStart && !_pes_synced)
00792 {
00793
00794 if (i + 2 >= TSPacket::kSize)
00795 {
00796 LOG(VB_GENERAL, LOG_ERR, LOC +
00797 "PES packet start code may overflow to next TS packet, "
00798 "aborting keyframe search");
00799 break;
00800 }
00801
00802
00803 if (tspacket->data()[i++] != 0x00 ||
00804 tspacket->data()[i++] != 0x00 ||
00805 tspacket->data()[i++] != 0x01)
00806 {
00807 LOG(VB_GENERAL, LOG_ERR, LOC +
00808 "PES start code not found in TS packet with PUSI set");
00809 break;
00810 }
00811
00812
00813 if (i + 5 >= TSPacket::kSize)
00814 {
00815 LOG(VB_GENERAL, LOG_ERR, LOC +
00816 "PES packet headers overflow to next TS packet, "
00817 "aborting keyframe search");
00818 break;
00819 }
00820
00821
00822
00823
00824
00825
00826
00827 const unsigned char pes_header_length = tspacket->data()[i + 5];
00828
00829
00830 if ((i + 6 + pes_header_length) >= TSPacket::kSize)
00831 {
00832 LOG(VB_GENERAL, LOG_ERR, LOC +
00833 "PES packet headers overflow to next TS packet, "
00834 "aborting keyframe search");
00835 break;
00836 }
00837
00838
00839
00840
00841 i += 5 + pes_header_length;
00842 _pes_synced = true;
00843
00844 #if 0
00845 LOG(VB_RECORD, LOG_DEBUG, LOC + "PES synced");
00846 #endif
00847 continue;
00848 }
00849
00850
00851 if (!_pes_synced)
00852 break;
00853
00854
00855
00856 uint32_t bytes_used = m_h264_parser.addBytes(
00857 tspacket->data() + i, TSPacket::kSize - i,
00858 ringBuffer->GetWritePosition() + _payload_buffer.size()
00859 );
00860 i += (bytes_used - 1);
00861
00862 if (m_h264_parser.stateChanged())
00863 {
00864 if (m_h264_parser.onFrameStart() &&
00865 m_h264_parser.FieldType() != H264Parser::FIELD_BOTTOM)
00866 {
00867 hasKeyFrame = m_h264_parser.onKeyFrameStart();
00868 hasFrame = true;
00869 _seen_sps |= hasKeyFrame;
00870
00871 width = m_h264_parser.pictureWidth();
00872 height = m_h264_parser.pictureHeight();
00873 aspectRatio = m_h264_parser.aspectRatio();
00874 frameRate = m_h264_parser.frameRate();
00875 }
00876 }
00877 }
00878
00879 if (hasKeyFrame)
00880 {
00881 _last_keyframe_seen = _frames_seen_count;
00882 HandleH264Keyframe();
00883 }
00884
00885 if (hasFrame)
00886 {
00887 _frames_seen_count++;
00888 if (!_wait_for_keyframe_option || _first_keyframe >= 0)
00889 _frames_written_count++;
00890 }
00891
00892 if ((aspectRatio > 0) && (aspectRatio != m_videoAspect))
00893 {
00894 m_videoAspect = aspectRatio;
00895 AspectChange((AspectRatio)aspectRatio, _frames_written_count);
00896 }
00897
00898 if (height && width && (height != m_videoHeight || m_videoWidth != width))
00899 {
00900 m_videoHeight = height;
00901 m_videoWidth = width;
00902 ResolutionChange(width, height, _frames_written_count);
00903 }
00904
00905 if (frameRate != 0 && frameRate != m_frameRate)
00906 {
00907
00908 LOG(VB_RECORD, LOG_INFO, LOC +
00909 QString("FindH264Keyframes: timescale: %1, tick: %2, framerate: %3")
00910 .arg( m_h264_parser.GetTimeScale() )
00911 .arg( m_h264_parser.GetUnitsInTick() )
00912 .arg( frameRate ) );
00913 m_frameRate = frameRate;
00914 FrameRateChange(frameRate, _frames_written_count);
00915 }
00916
00917 return hasKeyFrame || (_payload_buffer.size() >= (188*50));
00918 }
00919
00924 void DTVRecorder::HandleH264Keyframe(void)
00925 {
00926 unsigned long long frameNum = _frames_written_count;
00927
00928 _first_keyframe = (_first_keyframe < 0) ? frameNum : _first_keyframe;
00929
00930
00931 positionMapLock.lock();
00932 if (!positionMap.contains(frameNum))
00933 {
00934 positionMapDelta[frameNum] = m_h264_parser.keyframeAUstreamOffset();
00935 positionMap[frameNum] = m_h264_parser.keyframeAUstreamOffset();
00936 }
00937 positionMapLock.unlock();
00938
00939
00940 CheckForRingBufferSwitch();
00941 }
00942
00943 void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len)
00944 {
00945 const uint maxKFD = kMaxKeyFrameDistance;
00946
00947 const uint8_t *bufstart = buffer;
00948 const uint8_t *bufptr = buffer;
00949 const uint8_t *bufend = buffer + len;
00950
00951 uint aspectRatio = 0;
00952 uint height = 0;
00953 uint width = 0;
00954 uint frameRate = 0;
00955
00956 uint skip = std::max(_audio_bytes_remaining, _other_bytes_remaining);
00957 while (bufptr + skip < bufend)
00958 {
00959 bool hasFrame = false;
00960 bool hasKeyFrame = false;
00961
00962 const uint8_t *tmp = bufptr;
00963 bufptr =
00964 avpriv_mpv_find_start_code(bufptr + skip, bufend, &_start_code);
00965 _audio_bytes_remaining = 0;
00966 _other_bytes_remaining = 0;
00967 _video_bytes_remaining -= std::min(
00968 (uint)(bufptr - tmp), _video_bytes_remaining);
00969
00970 if ((_start_code & 0xffffff00) != 0x00000100)
00971 continue;
00972
00973
00974
00975 int pes_packet_length = -1;
00976 if ((bufend - bufptr) >= 2)
00977 pes_packet_length = ((bufptr[0]<<8) | bufptr[1]) + 2 + 6;
00978
00979 const int stream_id = _start_code & 0x000000ff;
00980 if (_video_bytes_remaining)
00981 {
00982 if (PESStreamID::PictureStartCode == stream_id)
00983 {
00984 pes_packet_length = -1;
00985 uint frmtypei = 1;
00986 if (bufend-bufptr >= 4)
00987 {
00988 frmtypei = (bufptr[1]>>3) & 0x7;
00989 if ((1 <= frmtypei) && (frmtypei <= 5))
00990 hasFrame = true;
00991 }
00992 else
00993 {
00994 hasFrame = true;
00995 }
00996 }
00997 else if (PESStreamID::GOPStartCode == stream_id)
00998 {
00999 pes_packet_length = -1;
01000 _last_gop_seen = _frames_seen_count;
01001 hasKeyFrame |= true;
01002 }
01003 else if (PESStreamID::SequenceStartCode == stream_id)
01004 {
01005 pes_packet_length = -1;
01006 _last_seq_seen = _frames_seen_count;
01007 hasKeyFrame |= (_last_gop_seen + maxKFD)<_frames_seen_count;
01008
01009
01010 aspectRatio = (bufptr[3] >> 4);
01011
01012
01013 height = ((bufptr[1] & 0xf) << 8) | bufptr[2];
01014 width = (bufptr[0] <<4) | (bufptr[1]>>4);
01015
01016 frameRate = frameRateMap[(bufptr[3] & 0x0000000f)];
01017 }
01018 }
01019 else if (!_video_bytes_remaining && !_audio_bytes_remaining)
01020 {
01021 if ((stream_id >= PESStreamID::MPEGVideoStreamBegin) &&
01022 (stream_id <= PESStreamID::MPEGVideoStreamEnd))
01023 {
01024 _video_bytes_remaining = std::max(0, (int)pes_packet_length);
01025 }
01026 else if ((stream_id >= PESStreamID::MPEGAudioStreamBegin) &&
01027 (stream_id <= PESStreamID::MPEGAudioStreamEnd))
01028 {
01029 _audio_bytes_remaining = std::max(0, (int)pes_packet_length);
01030 }
01031 }
01032
01033 if (PESStreamID::PaddingStream == stream_id)
01034 {
01035 _other_bytes_remaining = std::max(0, (int)pes_packet_length);
01036 }
01037
01038 _start_code = 0xffffffff;
01039
01040 if (hasFrame && !hasKeyFrame)
01041 {
01042
01043
01044
01045
01046 hasKeyFrame = !(_frames_seen_count & 0xf);
01047 hasKeyFrame &= (_last_gop_seen + maxKFD) < _frames_seen_count;
01048 hasKeyFrame &= (_last_seq_seen + maxKFD) < _frames_seen_count;
01049 }
01050
01051 if (hasFrame)
01052 {
01053 _frames_seen_count++;
01054 if (!_wait_for_keyframe_option || _first_keyframe >= 0)
01055 _frames_written_count++;
01056 }
01057
01058 if (hasKeyFrame)
01059 {
01060 _last_keyframe_seen = _frames_seen_count;
01061 HandleKeyframe(_frames_written_count, bufptr - bufstart);
01062 }
01063
01064 if ((aspectRatio > 0) && (aspectRatio != m_videoAspect))
01065 {
01066 m_videoAspect = aspectRatio;
01067 AspectChange((AspectRatio)aspectRatio, _frames_written_count);
01068 }
01069
01070 if (height && width &&
01071 (height != m_videoHeight || m_videoWidth != width))
01072 {
01073 m_videoHeight = height;
01074 m_videoWidth = width;
01075 ResolutionChange(width, height, _frames_written_count);
01076 }
01077
01078 if (frameRate && frameRate != m_frameRate)
01079 {
01080 m_frameRate = frameRate;
01081 LOG(VB_RECORD, LOG_INFO, LOC +
01082 QString("FindPSKeyFrames: frame rate = %1").arg(frameRate));
01083 FrameRateChange(frameRate, _frames_written_count);
01084 }
01085
01086 if (hasKeyFrame || hasFrame)
01087 {
01088
01089
01090 if (!_payload_buffer.empty())
01091 {
01092 if (ringBuffer)
01093 {
01094 ringBuffer->Write(
01095 &_payload_buffer[0], _payload_buffer.size());
01096 }
01097 _payload_buffer.clear();
01098 }
01099
01100 if (ringBuffer)
01101 ringBuffer->Write(bufstart, (bufptr - bufstart));
01102
01103 bufstart = bufptr;
01104 }
01105
01106 skip = std::max(_audio_bytes_remaining, _other_bytes_remaining);
01107 }
01108
01109 int bytes_skipped = bufend - bufptr;
01110 if (bytes_skipped > 0)
01111 {
01112 _audio_bytes_remaining -= std::min(
01113 (uint)bytes_skipped, _audio_bytes_remaining);
01114 _video_bytes_remaining -= std::min(
01115 (uint)bytes_skipped, _video_bytes_remaining);
01116 _other_bytes_remaining -= std::min(
01117 (uint)bytes_skipped, _other_bytes_remaining);
01118 }
01119
01120 uint64_t idx = _payload_buffer.size();
01121 uint64_t rem = (bufend - bufstart);
01122 _payload_buffer.resize(idx + rem);
01123 memcpy(&_payload_buffer[idx], bufstart, rem);
01124 #if 0
01125 LOG(VB_GENERAL, LOG_DEBUG, LOC +
01126 QString("idx: %1, rem: %2").arg(idx).arg(rem));
01127 #endif
01128 }
01129
01130 void DTVRecorder::HandlePAT(const ProgramAssociationTable *_pat)
01131 {
01132 if (!_pat)
01133 {
01134 LOG(VB_RECORD, LOG_ERR, LOC + "SetPAT(NULL)");
01135 return;
01136 }
01137
01138 QMutexLocker change_lock(&_pid_lock);
01139
01140 int progNum = _stream_data->DesiredProgram();
01141 uint pmtpid = _pat->FindPID(progNum);
01142
01143 if (!pmtpid)
01144 {
01145 LOG(VB_RECORD, LOG_ERR, LOC + "SetPAT(): "
01146 "Ignoring PAT not containing our desired program...");
01147 return;
01148 }
01149
01150 LOG(VB_RECORD, LOG_INFO, LOC + QString("SetPAT(%1 on 0x%2)")
01151 .arg(progNum).arg(pmtpid,0,16));
01152
01153 ProgramAssociationTable *oldpat = _input_pat;
01154 _input_pat = new ProgramAssociationTable(*_pat);
01155 delete oldpat;
01156
01157
01158 for (uint i = 0; _input_pat && (i < _input_pat->ProgramCount()); i++)
01159 {
01160 uint pmt_pid = _input_pat->ProgramPID(i);
01161 if (!_stream_data->IsListeningPID(pmt_pid))
01162 _stream_data->AddListeningPID(pmt_pid, kPIDPriorityLow);
01163 }
01164 }
01165
01166 void DTVRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt)
01167 {
01168 QMutexLocker change_lock(&_pid_lock);
01169
01170 if ((int)progNum == _stream_data->DesiredProgram())
01171 {
01172 LOG(VB_RECORD, LOG_INFO, LOC + QString("SetPMT(%1)").arg(progNum));
01173 ProgramMapTable *oldpmt = _input_pmt;
01174 _input_pmt = new ProgramMapTable(*_pmt);
01175
01176 QString sistandard = GetSIStandard();
01177
01178 bool has_no_av = true;
01179 for (uint i = 0; i < _input_pmt->StreamCount() && has_no_av; i++)
01180 {
01181 has_no_av &= !_input_pmt->IsVideo(i, sistandard);
01182 has_no_av &= !_input_pmt->IsAudio(i, sistandard);
01183 }
01184 _has_no_av = has_no_av;
01185
01186 SetCAMPMT(_input_pmt);
01187 delete oldpmt;
01188 }
01189 }
01190
01191 void DTVRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat)
01192 {
01193 if (!pat)
01194 {
01195 LOG(VB_RECORD, LOG_ERR, LOC + "HandleSingleProgramPAT(NULL)");
01196 return;
01197 }
01198
01199 if (!ringBuffer)
01200 return;
01201
01202 uint next_cc = (pat->tsheader()->ContinuityCounter()+1)&0xf;
01203 pat->tsheader()->SetContinuityCounter(next_cc);
01204 pat->GetAsTSPackets(_scratch, next_cc);
01205
01206 for (uint i = 0; i < _scratch.size(); i++)
01207 DTVRecorder::BufferedWrite(_scratch[i]);
01208 }
01209
01210 void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
01211 {
01212 if (!pmt)
01213 {
01214 LOG(VB_RECORD, LOG_ERR, LOC + "HandleSingleProgramPMT(NULL)");
01215 return;
01216 }
01217
01218
01219 for (uint i = 0; i < pmt->StreamCount(); i++)
01220 _stream_id[pmt->StreamPID(i)] = pmt->StreamType(i);
01221
01222 if (!ringBuffer)
01223 return;
01224
01225 uint next_cc = (pmt->tsheader()->ContinuityCounter()+1)&0xf;
01226 pmt->tsheader()->SetContinuityCounter(next_cc);
01227 pmt->GetAsTSPackets(_scratch, next_cc);
01228
01229 for (uint i = 0; i < _scratch.size(); i++)
01230 DTVRecorder::BufferedWrite(_scratch[i]);
01231 }
01232
01233 bool DTVRecorder::ProcessTSPacket(const TSPacket &tspacket)
01234 {
01235 const uint pid = tspacket.PID();
01236
01237 if (pid != 0x1fff)
01238 _packet_count.fetchAndAddAcquire(1);
01239
01240
01241 uint old_cnt = _continuity_counter[pid];
01242 if ((pid != 0x1fff) && !CheckCC(pid, tspacket.ContinuityCounter()))
01243 {
01244 int v = _continuity_error_count.fetchAndAddRelaxed(1) + 1;
01245 double erate = v * 100.0 / _packet_count.fetchAndAddRelaxed(0);
01246 LOG(VB_RECORD, LOG_WARNING, LOC +
01247 QString("PID 0x%1 discontinuity detected ((%2+1)%16!=%3) %4\%")
01248 .arg(pid,0,16).arg(old_cnt,2)
01249 .arg(tspacket.ContinuityCounter(),2)
01250 .arg(erate));
01251 }
01252
01253
01254 if (_input_pmt && _has_no_av)
01255 {
01256 _buffer_packets = !FindOtherKeyframes(&tspacket);
01257 }
01258 else
01259 {
01260
01261
01262 if (_wait_for_keyframe_option && _first_keyframe < 0)
01263 return true;
01264
01265 _buffer_packets = true;
01266 }
01267
01268 BufferedWrite(tspacket);
01269
01270 return true;
01271 }
01272
01273 bool DTVRecorder::ProcessVideoTSPacket(const TSPacket &tspacket)
01274 {
01275 if (!ringBuffer)
01276 return true;
01277
01278 uint streamType = _stream_id[tspacket.PID()];
01279
01280
01281 if (streamType == StreamID::H264Video)
01282 {
01283 _buffer_packets = !FindH264Keyframes(&tspacket);
01284 if (_wait_for_keyframe_option && !_seen_sps)
01285 return true;
01286 }
01287 else
01288 {
01289 _buffer_packets = !FindMPEG2Keyframes(&tspacket);
01290 }
01291
01292 return ProcessAVTSPacket(tspacket);
01293 }
01294
01295 bool DTVRecorder::ProcessAudioTSPacket(const TSPacket &tspacket)
01296 {
01297 if (!ringBuffer)
01298 return true;
01299
01300 _buffer_packets = !FindAudioKeyframes(&tspacket);
01301 return ProcessAVTSPacket(tspacket);
01302 }
01303
01305 bool DTVRecorder::ProcessAVTSPacket(const TSPacket &tspacket)
01306 {
01307 const uint pid = tspacket.PID();
01308
01309 if (pid != 0x1fff)
01310 _packet_count.fetchAndAddAcquire(1);
01311
01312
01313 uint old_cnt = _continuity_counter[pid];
01314 if ((pid != 0x1fff) && !CheckCC(pid, tspacket.ContinuityCounter()))
01315 {
01316 int v = _continuity_error_count.fetchAndAddRelaxed(1) + 1;
01317 double erate = v * 100.0 / _packet_count.fetchAndAddRelaxed(0);
01318 LOG(VB_RECORD, LOG_WARNING, LOC +
01319 QString("A/V PID 0x%1 discontinuity detected ((%2+1)%16!=%3) %4\%")
01320 .arg(pid,0,16).arg(old_cnt).arg(tspacket.ContinuityCounter())
01321 .arg(erate,5,'f',2));
01322 }
01323
01324
01325 if (_wait_for_keyframe_option && _first_keyframe < 0)
01326 return true;
01327
01328
01329
01330 if (!(_pid_status[pid] & kPayloadStartSeen) && tspacket.HasPayload())
01331 {
01332 if (!tspacket.PayloadStart())
01333 return true;
01334
01335 LOG(VB_RECORD, LOG_INFO, LOC +
01336 QString("PID 0x%1 Found Payload Start").arg(pid,0,16));
01337
01338 _pid_status[pid] |= kPayloadStartSeen;
01339 }
01340
01341 BufferedWrite(tspacket);
01342
01343 return true;
01344 }
01345
01346 RecordingQuality *DTVRecorder::GetRecordingQuality(void) const
01347 {
01348 RecordingQuality *recq = RecorderBase::GetRecordingQuality();
01349 recq->AddTSStatistics(
01350 _continuity_error_count.fetchAndAddRelaxed(0),
01351 _packet_count.fetchAndAddRelaxed(0));
01352 return recq;
01353 }
01354
01355