|
MythTV
0.26-pre
|
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 // file handle for stream 00052 _stream_fd(-1), 00053 _recording_type("all"), 00054 // used for scanning pes headers for keyframes 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 // MPEG2 parser information 00061 _progressive_sequence(0), 00062 _repeat_pict(0), 00063 // H.264 support 00064 _pes_synced(false), 00065 _seen_sps(false), 00066 // settings 00067 _wait_for_keyframe_option(true), 00068 _has_written_other_keyframe(false), 00069 // state 00070 _error(), 00071 _stream_data(NULL), 00072 // TS packet buffer 00073 // keyframe TS buffer 00074 _buffer_packets(false), 00075 // general recorder stuff 00076 _pid_lock(QMutex::Recursive), 00077 _input_pat(NULL), 00078 _input_pmt(NULL), 00079 _has_no_av(false), 00080 // statistics 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 // _first_keyframe, _seen_psp and m_h264_parser should 00171 // not be reset here. This will only be called just as 00172 // we're seeing the first packet of a new keyframe for 00173 // writing to the new file and anything that makes the 00174 // recorder think we're waiting on another keyframe will 00175 // send significant amounts of good data to /dev/null. 00176 // -- Daniel Kristjansson 2011-02-26 00177 00178 _start_code = 0xffffffff; 00179 //_first_keyframe 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 //_recording 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 //_seen_sps 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 //_ts_first_dt -- doesn't need to be cleared only used if _ts_first>=0 00217 _packet_count.fetchAndStoreRelaxed(0); 00218 _continuity_error_count.fetchAndStoreRelaxed(0); 00219 _frames_seen_count = 0; 00220 _frames_written_count = 0; 00221 } 00222 00223 // documented in recorderbase.h 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 // delay until first GOP to avoid decoder crash on res change 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 // Do we have to buffer the packet for exact keyframe detection? 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 // We are free to write the packet, but if we have buffered packet[s] 00313 // we have to write them first... 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()) // no payload to scan 00398 return !haveBufferedData; 00399 00400 if (!ringBuffer) 00401 return !haveBufferedData; 00402 00403 // if packet contains start of PES packet, start 00404 // looking for first byte of MPEG start code (3 bytes 0 0 1) 00405 // otherwise, pick up search where we left off. 00406 const bool payloadStart = tspacket->PayloadStart(); 00407 _start_code = (payloadStart) ? 0xffffffff : _start_code; 00408 00409 // Just make these local for efficiency reasons (gcc not so smart..) 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 // Scan for PES header codes; specifically picture_start 00420 // sequence_start (SEQ) and group_start (GOP). 00421 // 00 00 01 00: picture_start_code 00422 // 00 00 01 B8: group_start_code 00423 // 00 00 01 B3: seq_start_code 00424 // 00 00 01 B5: ext_start_code 00425 // (there are others that we don't care about) 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 // At this point we have seen the start code 0 0 1 00439 // the next byte will be the PES packet stream id. 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 // Look for aspectRatio changes and store them in the database 00454 aspectRatio = (bufptr[3] >> 4); 00455 00456 // Get resolution 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: /* sequence extension */ 00470 if (bytes_left >= 6) 00471 { 00472 _progressive_sequence = bufptr[1] & (1 << 3); 00473 } 00474 break; 00475 case 0x8: /* picture coding extension */ 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 /* check if we must repeat the frame */ 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 // If we have seen kMaxKeyFrameDistance frames since the 00519 // last GOP or SEQ stream_id, then pretend this picture 00520 // is a keyframe. We may get artifacts but at least 00521 // we will be able to skip frames. 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; // 1 second 00583 if (_use_pts) 00584 { 00585 ts = dts; 00586 gap_threshold = 2*90000; // two seconds, compensate for GOP ordering 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 // documented in recorderbase.h 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 // First we do some of the time consuming stuff we can do now 00696 SavePositionMap(true); 00697 if (ringBuffer) 00698 { 00699 ringBuffer->WriterFlush(); 00700 if (curRecording) 00701 curRecording->SaveFilesize(ringBuffer->GetRealFileSize()); 00702 } 00703 00704 // Then we set the next info 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 // Add key frame to position map 00731 positionMapLock.lock(); 00732 if (!positionMap.contains(frameNum)) 00733 { 00734 long long startpos = ringBuffer->GetWritePosition(); 00735 // FIXME: handle keyframes with start code spanning over two ts packets 00736 startpos += _payload_buffer.size() - extra; 00737 00738 // Don't put negative offsets into the database, they get munged into 00739 // MAX_INT64 - offset, which is an exceedingly large number, and 00740 // certainly not valid. 00741 if (startpos >= 0) 00742 { 00743 positionMapDelta[frameNum] = startpos; 00744 positionMap[frameNum] = startpos; 00745 } 00746 } 00747 positionMapLock.unlock(); 00748 00749 // Perform ringbuffer switch if needed. 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()) // no payload to scan 00768 return !haveBufferedData; 00769 00770 const bool payloadStart = tspacket->PayloadStart(); 00771 if (payloadStart) 00772 { 00773 // reset PES sync state 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 // scan for PES packets and H.264 NAL units 00787 uint i = tspacket->AFCOffset(); 00788 for (; i < TSPacket::kSize; i++) 00789 { 00790 // special handling required when a new PES packet begins 00791 if (payloadStart && !_pes_synced) 00792 { 00793 // bounds check 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 // must find the PES start code 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 // bounds check 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 // now we need to compute where the PES payload begins 00822 // skip past the stream_id (+1) 00823 // the next two bytes are the PES packet length (+2) 00824 // after that, one byte of PES packet control bits (+1) 00825 // after that, one byte of PES header flags bits (+1) 00826 // and finally, one byte for the PES header length 00827 const unsigned char pes_header_length = tspacket->data()[i + 5]; 00828 00829 // bounds check 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 // we now know where the PES payload is 00839 // normally, we should have used 6, but use 5 because the for 00840 // loop will bump i 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 // ain't going nowhere if we're not PES synced 00851 if (!_pes_synced) 00852 break; 00853 00854 // scan for a NAL unit start code 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 } // for (; i < TSPacket::kSize; i++) 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 // Add key frame to position map 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 // Perform ringbuffer switch if needed. 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 // NOTE: Length may be zero for packets that only contain bytes from 00974 // video elementary streams in TS packets. 13818-1:2000 2.4.3.7 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 { // pes_packet_length is meaningless 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 { // pes_packet_length is meaningless 00999 pes_packet_length = -1; 01000 _last_gop_seen = _frames_seen_count; 01001 hasKeyFrame |= true; 01002 } 01003 else if (PESStreamID::SequenceStartCode == stream_id) 01004 { // pes_packet_length is meaningless 01005 pes_packet_length = -1; 01006 _last_seq_seen = _frames_seen_count; 01007 hasKeyFrame |= (_last_gop_seen + maxKFD)<_frames_seen_count; 01008 01009 // Look for aspectRatio changes and store them in the database 01010 aspectRatio = (bufptr[3] >> 4); 01011 01012 // Get resolution 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 { // ok-dvdinfo 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 { // ok-dvdinfo 01029 _audio_bytes_remaining = std::max(0, (int)pes_packet_length); 01030 } 01031 } 01032 01033 if (PESStreamID::PaddingStream == stream_id) 01034 { // ok-dvdinfo 01035 _other_bytes_remaining = std::max(0, (int)pes_packet_length); 01036 } 01037 01038 _start_code = 0xffffffff; // reset start code 01039 01040 if (hasFrame && !hasKeyFrame) 01041 { 01042 // If we have seen kMaxKeyFrameDistance frames since the 01043 // last GOP or SEQ stream_id, then pretend this picture 01044 // is a keyframe. We may get artifacts but at least 01045 // we will be able to skip frames. 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 // We are free to write the packet, but if we have 01089 // buffered packet[s] we have to write them first... 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 // Listen for the other PMTs for faster channel switching 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 // collect stream types for H.264 (MPEG-4 AVC) keyframe detection 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 // Check continuity counter 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 // Only create fake keyframe[s] if there are no audio/video streams 01254 if (_input_pmt && _has_no_av) 01255 { 01256 _buffer_packets = !FindOtherKeyframes(&tspacket); 01257 } 01258 else 01259 { 01260 // There are audio/video streams. Only write the packet 01261 // if audio/video key-frames have been found 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 // Check for keyframes and count frames 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 // Check continuity counter 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 // Sync recording start to first keyframe 01325 if (_wait_for_keyframe_option && _first_keyframe < 0) 01326 return true; 01327 01328 // Sync streams to the first Payload Unit Start Indicator 01329 // _after_ first keyframe iff _wait_for_keyframe_option is true 01330 if (!(_pid_status[pid] & kPayloadStartSeen) && tspacket.HasPayload()) 01331 { 01332 if (!tspacket.PayloadStart()) 01333 return true; // not payload start - drop packet 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 /* vim: set expandtab tabstop=4 shiftwidth=4: */
1.7.6.1