Ticket #11328: keep-first-keyframe-v4-v0.25.patch
File keep-first-keyframe-v4-v0.25.patch, 36.8 KB (added by , 11 years ago) |
---|
-
mythtv/libs/libmythtv/asirecorder.cpp
diff --git a/mythtv/libs/libmythtv/asirecorder.cpp b/mythtv/libs/libmythtv/asirecorder.cpp index 830ac23..883d83b 100644
a b void ASIRecorder::SetOption(const QString &name, int value) 62 62 DTVRecorder::SetOption(name, value); 63 63 } 64 64 65 void ASIRecorder::StartNewFile(void) 66 { 67 // Make sure the first things in the file are a PAT & PMT 68 HandleSingleProgramPAT(_stream_data->PATSingleProgram(), true); 69 HandleSingleProgramPMT(_stream_data->PMTSingleProgram(), true); 70 } 71 72 65 73 void ASIRecorder::run(void) 66 74 { 67 75 if (!Open()) … … void ASIRecorder::run(void) 99 107 if (m_channel && (m_channel->GetSIStandard() == "dvb")) 100 108 _stream_data->AddListeningPID(DVB_TDT_PID); 101 109 102 // Make sure the first things in the file are a PAT & PMT 103 bool tmp = _wait_for_keyframe_option; 104 _wait_for_keyframe_option = false; 105 HandleSingleProgramPAT(_stream_data->PATSingleProgram()); 106 HandleSingleProgramPMT(_stream_data->PMTSingleProgram()); 107 _wait_for_keyframe_option = tmp; 110 StartNewFile(); 108 111 109 112 _stream_data->AddAVListener(this); 110 113 _stream_data->AddWritingListener(this); -
mythtv/libs/libmythtv/asirecorder.h
diff --git a/mythtv/libs/libmythtv/asirecorder.h b/mythtv/libs/libmythtv/asirecorder.h index f29ccc5..06c5bc4 100644
a b class ASIRecorder : public DTVRecorder 68 68 bool Open(void); 69 69 bool IsOpen(void) const; 70 70 void Close(void); 71 void StartNewFile(void); 71 72 72 73 private: 73 74 ASIChannel *m_channel; -
mythtv/libs/libmythtv/cetonrecorder.cpp
diff --git a/mythtv/libs/libmythtv/cetonrecorder.cpp b/mythtv/libs/libmythtv/cetonrecorder.cpp index f7aacf4..b923770 100644
a b void CetonRecorder::Close(void) 46 46 LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end"); 47 47 } 48 48 49 void CetonRecorder::StartNewFile(void) 50 { 51 // Make sure the first things in the file are a PAT & PMT 52 HandleSingleProgramPAT(_stream_data->PATSingleProgram(), true); 53 HandleSingleProgramPMT(_stream_data->PMTSingleProgram(), true); 54 } 55 49 56 void CetonRecorder::run(void) 50 57 { 51 58 LOG(VB_RECORD, LOG_INFO, LOC + "run -- begin"); … … void CetonRecorder::run(void) 65 72 recordingWait.wakeAll(); 66 73 } 67 74 68 // Make sure the first things in the file are a PAT & PMT 69 bool tmp = _wait_for_keyframe_option; 70 _wait_for_keyframe_option = false; 71 HandleSingleProgramPAT(_stream_data->PATSingleProgram()); 72 HandleSingleProgramPMT(_stream_data->PMTSingleProgram()); 73 _wait_for_keyframe_option = tmp; 75 StartNewFile(); 74 76 75 77 _stream_data->AddAVListener(this); 76 78 _stream_data->AddWritingListener(this); -
mythtv/libs/libmythtv/cetonrecorder.h
diff --git a/mythtv/libs/libmythtv/cetonrecorder.h b/mythtv/libs/libmythtv/cetonrecorder.h index fe2d176..8233d46 100644
a b class CetonRecorder : public DTVRecorder 26 26 27 27 bool Open(void); 28 28 void Close(void); 29 void StartNewFile(void); 29 30 30 31 bool IsOpen(void) const { return _stream_handler; } 31 32 -
mythtv/libs/libmythtv/dtvrecorder.cpp
diff --git a/mythtv/libs/libmythtv/dtvrecorder.cpp b/mythtv/libs/libmythtv/dtvrecorder.cpp index 9d7d89f..3ebd7ee 100644
a b DTVRecorder::DTVRecorder(TVRec *rec) : 85 85 { 86 86 SetPositionMapType(MARK_GOP_BYFRAME); 87 87 _payload_buffer.reserve(TSPacket::kSize * (50 + 1)); 88 88 89 ResetForNewFile(); 90 91 memset(_stream_id, 0, sizeof(_stream_id)); 92 memset(_pid_status, 0, sizeof(_pid_status)); 93 memset(_continuity_counter, 0xff, sizeof(_continuity_counter)); 89 94 } 90 95 91 96 DTVRecorder::~DTVRecorder() … … void DTVRecorder::SetOptionsFromProfile(RecordingProfile *profile, 145 150 void DTVRecorder::FinishRecording(void) 146 151 { 147 152 if (ringBuffer) 148 {149 if (!_payload_buffer.empty())150 {151 ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size());152 _payload_buffer.clear();153 }154 153 ringBuffer->WriterFlush(); 155 }156 154 157 155 if (curRecording) 158 156 { … … void DTVRecorder::ResetForNewFile(void) 167 165 LOG(VB_RECORD, LOG_INFO, LOC + "ResetForNewFile(void)"); 168 166 QMutexLocker locker(&positionMapLock); 169 167 170 // _ first_keyframe, _seen_psp and m_h264_parser should168 // _seen_psp and m_h264_parser should 171 169 // not be reset here. This will only be called just as 172 170 // we're seeing the first packet of a new keyframe for 173 171 // writing to the new file and anything that makes the … … void DTVRecorder::ResetForNewFile(void) 176 174 // -- Daniel Kristjansson 2011-02-26 177 175 178 176 _start_code = 0xffffffff; 179 //_first_keyframe177 _first_keyframe = -1; 180 178 _has_written_other_keyframe = false; 181 179 _last_keyframe_seen = 0; 182 180 _last_gop_seen = 0; … … void DTVRecorder::ResetForNewFile(void) 187 185 //_recording 188 186 _error = QString(); 189 187 190 memset(_stream_id, 0, sizeof(_stream_id));191 memset(_pid_status, 0, sizeof(_pid_status));192 memset(_continuity_counter, 0xff, sizeof(_continuity_counter));193 194 188 _progressive_sequence = 0; 195 189 _repeat_pict = 0; 196 190 197 _pes_synced = false;191 //_pes_synced 198 192 //_seen_sps 199 193 positionMap.clear(); 200 194 positionMapDelta.clear(); 201 _payload_buffer.clear();202 195 203 196 locker.unlock(); 204 197 ClearStatistics(); … … void DTVRecorder::ClearStatistics(void) 209 202 RecorderBase::ClearStatistics(); 210 203 211 204 memset(_ts_count, 0, sizeof(_ts_count)); 212 for (int i = 0; i < 256; i++)205 for (int i = 0; i < 256; ++i) 213 206 _ts_last[i] = -1LL; 214 for (int i = 0; i < 256; i++)207 for (int i = 0; i < 256; ++i) 215 208 _ts_first[i] = -1LL; 216 209 //_ts_first_dt -- doesn't need to be cleared only used if _ts_first>=0 217 210 _packet_count.fetchAndStoreRelaxed(0); … … void DTVRecorder::SetStreamData(void) 264 257 _stream_data->SetDesiredProgram(_stream_data->DesiredProgram()); 265 258 } 266 259 267 void DTVRecorder::BufferedWrite(const TSPacket &tspacket )260 void DTVRecorder::BufferedWrite(const TSPacket &tspacket, bool insert) 268 261 { 269 // delay until first GOP to avoid decoder crash on res change 270 if (_wait_for_keyframe_option && _first_keyframe<0) 271 return; 272 273 if (curRecording && timeOfFirstDataIsSet.testAndSetRelaxed(0,1)) 262 if (!insert) 274 263 { 275 QMutexLocker locker(&statisticsLock); 276 timeOfFirstData = mythCurrentDateTime(); 277 timeOfLatestData = mythCurrentDateTime(); 278 timeOfLatestDataTimer.start(); 279 } 264 // delay until first GOP to avoid decoder crash on res change 265 if (!_buffer_packets && _wait_for_keyframe_option && 266 _first_keyframe < 0) 267 return; 280 268 281 int val = timeOfLatestDataCount.fetchAndAddRelaxed(1); 282 int thresh = timeOfLatestDataPacketInterval.fetchAndAddRelaxed(0); 283 if (val > thresh) 284 { 285 QMutexLocker locker(&statisticsLock); 286 uint elapsed = timeOfLatestDataTimer.restart(); 287 int interval = thresh; 288 if (elapsed > kTimeOfLatestDataIntervalTarget + 250) 289 interval = timeOfLatestDataPacketInterval 290 .fetchAndStoreRelaxed(thresh * 4 / 5); 291 else if (elapsed + 250 < kTimeOfLatestDataIntervalTarget) 292 interval = timeOfLatestDataPacketInterval 293 .fetchAndStoreRelaxed(thresh * 9 / 8); 294 295 timeOfLatestDataCount.fetchAndStoreRelaxed(1); 296 timeOfLatestData = mythCurrentDateTime(); 297 298 LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Updating timeOfLatestData ") + 299 QString("elapsed(%1) interval(%2)") 300 .arg(elapsed).arg(interval)); 301 } 269 if (curRecording && timeOfFirstDataIsSet.testAndSetRelaxed(0,1)) 270 { 271 QMutexLocker locker(&statisticsLock); 272 timeOfFirstData = mythCurrentDateTime(); 273 timeOfLatestData = mythCurrentDateTime(); 274 timeOfLatestDataTimer.start(); 275 } 302 276 303 // Do we have to buffer the packet for exact keyframe detection? 304 if (_buffer_packets) 305 { 306 int idx = _payload_buffer.size(); 307 _payload_buffer.resize(idx + TSPacket::kSize); 308 memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::kSize); 309 return; 310 } 277 int val = timeOfLatestDataCount.fetchAndAddRelaxed(1); 278 int thresh = timeOfLatestDataPacketInterval.fetchAndAddRelaxed(0); 279 if (val > thresh) 280 { 281 QMutexLocker locker(&statisticsLock); 282 uint elapsed = timeOfLatestDataTimer.restart(); 283 int interval = thresh; 284 if (elapsed > kTimeOfLatestDataIntervalTarget + 250) 285 interval = timeOfLatestDataPacketInterval 286 .fetchAndStoreRelaxed(thresh * 4 / 5); 287 else if (elapsed + 250 < kTimeOfLatestDataIntervalTarget) 288 interval = timeOfLatestDataPacketInterval 289 .fetchAndStoreRelaxed(thresh * 9 / 8); 290 291 timeOfLatestDataCount.fetchAndStoreRelaxed(1); 292 timeOfLatestData = mythCurrentDateTime(); 293 294 LOG(VB_RECORD, LOG_DEBUG, LOC + 295 QString("Updating timeOfLatestData elapsed(%1) interval(%2)") 296 .arg(elapsed).arg(interval)); 297 } 311 298 312 // We are free to write the packet, but if we have buffered packet[s] 313 // we have to write them first... 314 if (!_payload_buffer.empty()) 315 { 316 if (ringBuffer) 317 ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 318 _payload_buffer.clear(); 299 // Do we have to buffer the packet for exact keyframe detection? 300 if (_buffer_packets) 301 { 302 int idx = _payload_buffer.size(); 303 _payload_buffer.resize(idx + TSPacket::kSize); 304 memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::kSize); 305 return; 306 } 307 308 // We are free to write the packet, but if we have buffered packet[s] 309 // we have to write them first... 310 if (!_payload_buffer.empty()) 311 { 312 if (ringBuffer) 313 ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 314 _payload_buffer.clear(); 315 } 319 316 } 320 317 321 318 if (ringBuffer) … … static QDateTime ts_to_qdatetime( 361 358 } 362 359 363 360 static const uint frameRateMap[16] = { 364 0, 23796, 24000, 25000, 29970, 30000, 50000, 59940, 60000, 365 0, 0, 0, 0, 0, 0, 0 361 0, 23796, 24000, 25000, 29970, 30000, 50000, 59940, 60000, 362 0, 0, 0, 0, 0, 0, 0 366 363 }; 367 364 368 365 /** \fn DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) … … static const uint frameRateMap[16] = { 393 390 */ 394 391 bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) 395 392 { 396 bool haveBufferedData = !_payload_buffer.empty();397 393 if (!tspacket->HasPayload()) // no payload to scan 398 return !haveBufferedData;394 return _first_keyframe >= 0; 399 395 400 396 if (!ringBuffer) 401 return !haveBufferedData;397 return _first_keyframe >= 0; 402 398 403 399 // if packet contains start of PES packet, start 404 400 // looking for first byte of MPEG start code (3 bytes 0 0 1) … … bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) 461 457 } 462 458 else if (PESStreamID::MPEG2ExtensionStartCode == stream_id) 463 459 { 464 if (bytes_left >= 1) 460 if (bytes_left >= 1) 465 461 { 466 462 ext_type = (bufptr[0] >> 4); 467 463 switch(ext_type) … … bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) 482 478 483 479 /* check if we must repeat the frame */ 484 480 _repeat_pict = 1; 485 if (repeat_first_field) 481 if (repeat_first_field) 486 482 { 487 483 if (_progressive_sequence) 488 484 { … … bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) 491 487 else 492 488 _repeat_pict = 3; 493 489 } 494 else if (progressive_frame) 490 else if (progressive_frame) 495 491 { 496 492 _repeat_pict = 2; 497 493 } … … bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) 527 523 if (hasKeyFrame) 528 524 { 529 525 _last_keyframe_seen = _frames_seen_count; 530 HandleKeyframe( _frames_written_count, TSPacket::kSize);526 HandleKeyframe(0); 531 527 } 532 528 533 529 if (hasFrame) 534 530 { 531 _buffer_packets = false; // We now know if it is a keyframe, or not 535 532 _frames_seen_count++; 536 if (!_wait_for_keyframe_option || _first_keyframe >=0)533 if (!_wait_for_keyframe_option || _first_keyframe >= 0) 537 534 _frames_written_count++; 535 else 536 { 537 /* Found a frame that is not a keyframe, and we want to 538 * start on a keyframe */ 539 _payload_buffer.clear(); 540 } 538 541 } 539 542 540 543 if ((aspectRatio > 0) && (aspectRatio != m_videoAspect)) … … bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) 558 561 FrameRateChange(frameRate, _frames_written_count); 559 562 } 560 563 561 return hasKeyFrame || (_payload_buffer.size() >= (188*50));564 return _first_keyframe >= 0; 562 565 } 563 566 564 567 void DTVRecorder::HandleTimestamps(int stream_id, int64_t pts, int64_t dts) … … bool DTVRecorder::FindAudioKeyframes(const TSPacket*) 652 655 if (1 == (_frames_seen_count & 0x7)) 653 656 { 654 657 _last_keyframe_seen = _frames_seen_count; 655 HandleKeyframe(_ frames_written_count);658 HandleKeyframe(_payload_buffer.size()); 656 659 hasKeyFrame = true; 657 660 } 658 661 … … bool DTVRecorder::FindOtherKeyframes(const TSPacket *tspacket) 680 683 _frames_written_count++; 681 684 _last_keyframe_seen = _frames_seen_count; 682 685 683 HandleKeyframe(_ frames_written_count);686 HandleKeyframe(_payload_buffer.size()); 684 687 685 688 _has_written_other_keyframe = true; 686 689 … … void DTVRecorder::SetNextRecording(const ProgramInfo *progInf, RingBuffer *rb) 716 719 * \brief This save the current frame to the position maps 717 720 * and handles ringbuffer switching. 718 721 */ 719 void DTVRecorder::HandleKeyframe( uint64_t frameNum,int64_t extra)722 void DTVRecorder::HandleKeyframe(int64_t extra) 720 723 { 721 724 if (!ringBuffer) 722 725 return; 723 726 724 #if 0 725 unsigned long long frameNum = _frames_written_count; 726 #endif 727 // Perform ringbuffer switch if needed. 728 CheckForRingBufferSwitch(); 727 729 730 uint64_t frameNum = _frames_written_count; 728 731 _first_keyframe = (_first_keyframe < 0) ? frameNum : _first_keyframe; 729 732 730 733 // Add key frame to position map 731 734 positionMapLock.lock(); 732 735 if (!positionMap.contains(frameNum)) 733 736 { 734 long long startpos = ringBuffer->GetWritePosition(); 735 // FIXME: handle keyframes with start code spanning over two ts packets 736 startpos += _payload_buffer.size() - extra; 737 int64_t startpos = ringBuffer->GetWritePosition() + extra; 737 738 738 739 // Don't put negative offsets into the database, they get munged into 739 740 // MAX_INT64 - offset, which is an exceedingly large number, and … … void DTVRecorder::HandleKeyframe(uint64_t frameNum, int64_t extra) 745 746 } 746 747 } 747 748 positionMapLock.unlock(); 748 749 // Perform ringbuffer switch if needed.750 CheckForRingBufferSwitch();751 749 } 752 750 753 751 /** \fn DTVRecorder::FindH264Keyframes(const TSPacket*) … … void DTVRecorder::HandleKeyframe(uint64_t frameNum, int64_t extra) 757 755 */ 758 756 bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) 759 757 { 758 if (!tspacket->HasPayload()) // no payload to scan 759 return _first_keyframe >= 0; 760 760 761 if (!ringBuffer) 761 762 { 762 763 LOG(VB_GENERAL, LOG_ERR, LOC + "FindH264Keyframes: No ringbuffer"); 763 return false;764 return _first_keyframe >= 0; 764 765 } 765 766 766 bool haveBufferedData = !_payload_buffer.empty();767 if (!tspacket->HasPayload()) // no payload to scan768 return !haveBufferedData;769 770 767 const bool payloadStart = tspacket->PayloadStart(); 771 768 if (payloadStart) 772 769 { … … bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) 785 782 786 783 // scan for PES packets and H.264 NAL units 787 784 uint i = tspacket->AFCOffset(); 788 for (; i < TSPacket::kSize; i++)785 for (; i < TSPacket::kSize; ++i) 789 786 { 790 787 // special handling required when a new PES packet begins 791 788 if (payloadStart && !_pes_synced) … … bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) 836 833 } 837 834 838 835 // we now know where the PES payload is 839 // normally, we should have used 6, but use 5 because the for 836 // normally, we should have used 6, but use 5 because the for 840 837 // loop will bump i 841 838 i += 5 + pes_header_length; 842 839 _pes_synced = true; … … bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) 853 850 854 851 // scan for a NAL unit start code 855 852 856 uint32_t bytes_used = m_h264_parser.addBytes( 857 tspacket->data() + i, TSPacket::kSize - i, 858 ringBuffer->GetWritePosition() + _payload_buffer.size() 859 ); 853 uint32_t bytes_used = m_h264_parser.addBytes 854 (tspacket->data() + i, TSPacket::kSize - i, 855 ringBuffer->GetWritePosition()); 860 856 i += (bytes_used - 1); 861 857 862 858 if (m_h264_parser.stateChanged()) … … bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) 874 870 frameRate = m_h264_parser.frameRate(); 875 871 } 876 872 } 877 } // for (; i < TSPacket::kSize; i++)873 } // for (; i < TSPacket::kSize; ++i) 878 874 879 875 if (hasKeyFrame) 880 876 { … … bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) 884 880 885 881 if (hasFrame) 886 882 { 883 _buffer_packets = false; // We now know if this is a keyframe 887 884 _frames_seen_count++; 888 885 if (!_wait_for_keyframe_option || _first_keyframe >= 0) 889 886 _frames_written_count++; 887 else 888 { 889 /* Found a frame that is not a keyframe, and we want to 890 * start on a keyframe */ 891 _payload_buffer.clear(); 892 } 890 893 } 891 894 892 895 if ((aspectRatio > 0) && (aspectRatio != m_videoAspect)) … … bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) 904 907 905 908 if (frameRate != 0 && frameRate != m_frameRate) 906 909 { 907 908 910 LOG(VB_RECORD, LOG_INFO, LOC + 909 911 QString("FindH264Keyframes: timescale: %1, tick: %2, framerate: %3") 910 .arg( m_h264_parser.GetTimeScale() ) 912 .arg( m_h264_parser.GetTimeScale() ) 911 913 .arg( m_h264_parser.GetUnitsInTick() ) 912 914 .arg( frameRate ) ); 913 915 m_frameRate = frameRate; 914 916 FrameRateChange(frameRate, _frames_written_count); 915 917 } 916 918 917 return hasKeyFrame || (_payload_buffer.size() >= (188*50));919 return _seen_sps; 918 920 } 919 921 920 922 /** \fn DTVRecorder::HandleH264Keyframe(void) … … bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) 923 925 */ 924 926 void DTVRecorder::HandleH264Keyframe(void) 925 927 { 926 unsigned long long frameNum = _frames_written_count; 928 // Perform ringbuffer switch if needed. 929 CheckForRingBufferSwitch(); 927 930 928 _first_keyframe = (_first_keyframe < 0) ? frameNum : _first_keyframe; 931 uint64_t startpos; 932 uint64_t frameNum = _frames_written_count; 933 934 if (_first_keyframe < 0) 935 { 936 _first_keyframe = frameNum; 937 startpos = 0; 938 } 939 else 940 startpos = m_h264_parser.keyframeAUstreamOffset(); 929 941 930 942 // Add key frame to position map 931 943 positionMapLock.lock(); 932 944 if (!positionMap.contains(frameNum)) 933 945 { 934 positionMapDelta[frameNum] = m_h264_parser.keyframeAUstreamOffset();935 positionMap[frameNum] = m_h264_parser.keyframeAUstreamOffset();946 positionMapDelta[frameNum] = startpos; 947 positionMap[frameNum] = startpos; 936 948 } 937 949 positionMapLock.unlock(); 938 939 // Perform ringbuffer switch if needed.940 CheckForRingBufferSwitch();941 950 } 942 951 943 952 void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len) … … void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len) 1057 1066 if (hasKeyFrame) 1058 1067 { 1059 1068 _last_keyframe_seen = _frames_seen_count; 1060 HandleKeyframe(_ frames_written_count, bufptr - bufstart);1069 HandleKeyframe(_payload_buffer.size() - (bufptr - bufstart)); 1061 1070 } 1062 1071 1063 1072 if ((aspectRatio > 0) && (aspectRatio != m_videoAspect)) … … void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len) 1066 1075 AspectChange((AspectRatio)aspectRatio, _frames_written_count); 1067 1076 } 1068 1077 1069 if (height && width && 1078 if (height && width && 1070 1079 (height != m_videoHeight || m_videoWidth != width)) 1071 1080 { 1072 1081 m_videoHeight = height; … … void DTVRecorder::HandlePAT(const ProgramAssociationTable *_pat) 1141 1150 1142 1151 if (!pmtpid) 1143 1152 { 1144 LOG(VB_RECORD, LOG_ERR, LOC + "SetPAT(): " 1145 "Ignoring PAT not containing our desired program..."); 1153 LOG(VB_RECORD, LOG_ERR, LOC + 1154 QString("SetPAT(): Ignoring PAT not containing our desired " 1155 "program (%1)...").arg(progNum)); 1146 1156 return; 1147 1157 } 1148 1158 … … void DTVRecorder::HandlePAT(const ProgramAssociationTable *_pat) 1154 1164 delete oldpat; 1155 1165 1156 1166 // Listen for the other PMTs for faster channel switching 1157 for (uint i = 0; _input_pat && (i < _input_pat->ProgramCount()); i++)1167 for (uint i = 0; _input_pat && (i < _input_pat->ProgramCount()); ++i) 1158 1168 { 1159 1169 uint pmt_pid = _input_pat->ProgramPID(i); 1160 1170 if (!_stream_data->IsListeningPID(pmt_pid)) … … void DTVRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt) 1175 1185 QString sistandard = GetSIStandard(); 1176 1186 1177 1187 bool has_no_av = true; 1178 for (uint i = 0; i < _input_pmt->StreamCount() && has_no_av; i++)1188 for (uint i = 0; i < _input_pmt->StreamCount() && has_no_av; ++i) 1179 1189 { 1180 1190 has_no_av &= !_input_pmt->IsVideo(i, sistandard); 1181 1191 has_no_av &= !_input_pmt->IsAudio(i, sistandard); … … void DTVRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt) 1187 1197 } 1188 1198 } 1189 1199 1190 void DTVRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat) 1200 void DTVRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat, 1201 bool insert) 1191 1202 { 1192 1203 if (!pat) 1193 1204 { … … void DTVRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat) 1202 1213 pat->tsheader()->SetContinuityCounter(next_cc); 1203 1214 pat->GetAsTSPackets(_scratch, next_cc); 1204 1215 1205 for (uint i = 0; i < _scratch.size(); i++)1206 DTVRecorder::BufferedWrite(_scratch[i] );1216 for (uint i = 0; i < _scratch.size(); ++i) 1217 DTVRecorder::BufferedWrite(_scratch[i], insert); 1207 1218 } 1208 1219 1209 void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt )1220 void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt, bool insert) 1210 1221 { 1211 1222 if (!pmt) 1212 1223 { … … void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt) 1215 1226 } 1216 1227 1217 1228 // collect stream types for H.264 (MPEG-4 AVC) keyframe detection 1218 for (uint i = 0; i < pmt->StreamCount(); i++)1229 for (uint i = 0; i < pmt->StreamCount(); ++i) 1219 1230 _stream_id[pmt->StreamPID(i)] = pmt->StreamType(i); 1220 1231 1221 1232 if (!ringBuffer) … … void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt) 1225 1236 pmt->tsheader()->SetContinuityCounter(next_cc); 1226 1237 pmt->GetAsTSPackets(_scratch, next_cc); 1227 1238 1228 for (uint i = 0; i < _scratch.size(); i++)1229 DTVRecorder::BufferedWrite(_scratch[i] );1239 for (uint i = 0; i < _scratch.size(); ++i) 1240 DTVRecorder::BufferedWrite(_scratch[i], insert); 1230 1241 } 1231 1242 1232 1243 bool DTVRecorder::ProcessTSPacket(const TSPacket &tspacket) … … bool DTVRecorder::ProcessTSPacket(const TSPacket &tspacket) 1252 1263 // Only create fake keyframe[s] if there are no audio/video streams 1253 1264 if (_input_pmt && _has_no_av) 1254 1265 { 1255 _buffer_packets = !FindOtherKeyframes(&tspacket); 1266 FindOtherKeyframes(&tspacket); 1267 _buffer_packets = false; 1256 1268 } 1257 1269 else 1258 1270 { … … bool DTVRecorder::ProcessVideoTSPacket(const TSPacket &tspacket) 1276 1288 1277 1289 uint streamType = _stream_id[tspacket.PID()]; 1278 1290 1279 // Check for keyframes and count frames 1280 if (streamType == StreamID::H264Video) 1291 if (tspacket.HasPayload() && tspacket.PayloadStart()) 1281 1292 { 1282 _buffer_packets = !FindH264Keyframes(&tspacket); 1283 if (_wait_for_keyframe_option && !_seen_sps) 1284 return true; 1293 // buffer packets until we know if this is a keyframe 1294 _buffer_packets = true; 1295 #if 0 1296 LOG(VB_RECORD, LOG_ERR, LOC + QString 1297 ("ProcessVideoTSPacket PayloadStart @ %1 + %2 = %3") 1298 .arg(ringBuffer->GetWritePosition()) 1299 .arg(_payload_buffer.size()) 1300 .arg(ringBuffer->GetWritePosition() + _payload_buffer.size())); 1301 #endif 1285 1302 } 1303 1304 // Check for keyframes and count frames 1305 if (streamType == StreamID::H264Video) 1306 FindH264Keyframes(&tspacket); 1307 else if (streamType != 0) 1308 FindMPEG2Keyframes(&tspacket); 1286 1309 else 1287 { 1288 _buffer_packets = !FindMPEG2Keyframes(&tspacket); 1289 } 1310 LOG(VB_RECORD, LOG_ERR, LOC + 1311 "ProcessVideoTSPacket: unknown stream type!"); 1290 1312 1291 1313 return ProcessAVTSPacket(tspacket); 1292 1314 } … … bool DTVRecorder::ProcessAudioTSPacket(const TSPacket &tspacket) 1296 1318 if (!ringBuffer) 1297 1319 return true; 1298 1320 1299 _buffer_packets = !FindAudioKeyframes(&tspacket); 1321 if (tspacket.HasPayload() && tspacket.PayloadStart()) 1322 { 1323 // buffer packets until we know if this is a keyframe 1324 _buffer_packets = true; 1325 #if 0 1326 LOG(VB_RECORD, LOG_ERR, LOC + QString 1327 ("ProcessAudioTSPacket PayloadStart @ %1 + %2 = %3") 1328 .arg(ringBuffer->GetWritePosition()) 1329 .arg(_payload_buffer.size()) 1330 .arg(ringBuffer->GetWritePosition() + _payload_buffer.size())); 1331 #endif 1332 } 1333 1334 FindAudioKeyframes(&tspacket); 1300 1335 return ProcessAVTSPacket(tspacket); 1301 1336 } 1302 1337 1303 1338 /// Common code for processing either audio or video packets 1304 1339 bool DTVRecorder::ProcessAVTSPacket(const TSPacket &tspacket) 1305 1340 { 1341 // Sync recording start to first keyframe 1342 if (!_buffer_packets && _wait_for_keyframe_option && _first_keyframe < 0) 1343 return true; 1344 1306 1345 const uint pid = tspacket.PID(); 1307 1346 1308 1347 if (pid != 0x1fff) … … bool DTVRecorder::ProcessAVTSPacket(const TSPacket &tspacket) 1320 1359 .arg(erate,5,'f',2)); 1321 1360 } 1322 1361 1323 // Sync recording start to first keyframe1324 if (_wait_for_keyframe_option && _first_keyframe < 0)1325 return true;1326 1327 1362 // Sync streams to the first Payload Unit Start Indicator 1328 1363 // _after_ first keyframe iff _wait_for_keyframe_option is true 1329 1364 if (!(_pid_status[pid] & kPayloadStartSeen) && tspacket.HasPayload()) -
mythtv/libs/libmythtv/dtvrecorder.h
diff --git a/mythtv/libs/libmythtv/dtvrecorder.h b/mythtv/libs/libmythtv/dtvrecorder.h index e2749bf..5ecbf1b 100644
a b class DTVRecorder : 66 66 void HandleEncryptionStatus(uint /*pnum*/, bool /*encrypted*/) { } 67 67 68 68 // MPEG Single Program Stream Listener 69 void HandleSingleProgramPAT(ProgramAssociationTable *pat );70 void HandleSingleProgramPMT(ProgramMapTable *pmt );69 void HandleSingleProgramPAT(ProgramAssociationTable *pat, bool insert); 70 void HandleSingleProgramPMT(ProgramMapTable *pmt, bool insert); 71 71 72 72 // ATSC Main 73 73 void HandleSTT(const SystemTimeTable*) { UpdateCAMTimeOffset(); } … … class DTVRecorder : 93 93 void FinishRecording(void); 94 94 void ResetForNewFile(void); 95 95 96 void HandleKeyframe( uint64_t frameNum, int64_t extra = 0);96 void HandleKeyframe(int64_t extra); 97 97 void HandleTimestamps(int stream_id, int64_t pts, int64_t dts); 98 98 99 void BufferedWrite(const TSPacket &tspacket );99 void BufferedWrite(const TSPacket &tspacket, bool insert = false); 100 100 101 101 // MPEG TS "audio only" support 102 102 bool FindAudioKeyframes(const TSPacket *tspacket); -
mythtv/libs/libmythtv/dvbrecorder.cpp
diff --git a/mythtv/libs/libmythtv/dvbrecorder.cpp b/mythtv/libs/libmythtv/dvbrecorder.cpp index c1b66d5..abd322a 100644
a b void DVBRecorder::Close(void) 72 72 LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end"); 73 73 } 74 74 75 void DVBRecorder::StartNewFile(void) 76 { 77 // Make sure the first things in the file are a PAT & PMT 78 HandleSingleProgramPAT(_stream_data->PATSingleProgram(), true); 79 HandleSingleProgramPMT(_stream_data->PMTSingleProgram(), true); 80 } 81 75 82 void DVBRecorder::run(void) 76 83 { 77 84 if (!Open()) … … void DVBRecorder::run(void) 92 99 if (_channel && (_channel->GetSIStandard() == "dvb")) 93 100 _stream_data->AddListeningPID(DVB_TDT_PID); 94 101 95 // Make sure the first things in the file are a PAT & PMT 96 bool tmp = _wait_for_keyframe_option; 97 _wait_for_keyframe_option = false; 98 HandleSingleProgramPAT(_stream_data->PATSingleProgram()); 99 HandleSingleProgramPMT(_stream_data->PMTSingleProgram()); 100 _wait_for_keyframe_option = tmp; 102 StartNewFile(); 101 103 102 104 _stream_data->AddAVListener(this); 103 105 _stream_data->AddWritingListener(this); -
mythtv/libs/libmythtv/dvbrecorder.h
diff --git a/mythtv/libs/libmythtv/dvbrecorder.h b/mythtv/libs/libmythtv/dvbrecorder.h index eb0b5f8..e82c2fe 100644
a b class DVBRecorder : public DTVRecorder 28 28 bool Open(void); 29 29 bool IsOpen(void) const; 30 30 void Close(void); 31 void StartNewFile(void); 31 32 32 33 private: 33 34 bool PauseAndWait(int timeout = 100); -
mythtv/libs/libmythtv/hdhrrecorder.cpp
diff --git a/mythtv/libs/libmythtv/hdhrrecorder.cpp b/mythtv/libs/libmythtv/hdhrrecorder.cpp index 63e128b..08422dd 100644
a b void HDHRRecorder::Close(void) 47 47 LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end"); 48 48 } 49 49 50 void HDHRRecorder::StartNewFile(void) 51 { 52 // Make sure the first things in the file are a PAT & PMT 53 HandleSingleProgramPAT(_stream_data->PATSingleProgram(), true); 54 HandleSingleProgramPMT(_stream_data->PMTSingleProgram(), true); 55 } 56 50 57 void HDHRRecorder::run(void) 51 58 { 52 59 LOG(VB_RECORD, LOG_INFO, LOC + "run -- begin"); … … void HDHRRecorder::run(void) 66 73 recordingWait.wakeAll(); 67 74 } 68 75 69 // Make sure the first things in the file are a PAT & PMT 70 bool tmp = _wait_for_keyframe_option; 71 _wait_for_keyframe_option = false; 72 HandleSingleProgramPAT(_stream_data->PATSingleProgram()); 73 HandleSingleProgramPMT(_stream_data->PMTSingleProgram()); 74 _wait_for_keyframe_option = tmp; 76 StartNewFile(); 75 77 76 78 _stream_data->AddAVListener(this); 77 79 _stream_data->AddWritingListener(this); -
mythtv/libs/libmythtv/hdhrrecorder.h
diff --git a/mythtv/libs/libmythtv/hdhrrecorder.h b/mythtv/libs/libmythtv/hdhrrecorder.h index 44b3fc1..7523e37 100644
a b class HDHRRecorder : public DTVRecorder 26 26 bool Open(void); 27 27 bool IsOpen(void) const { return _stream_handler; } 28 28 void Close(void); 29 void StartNewFile(void); 29 30 30 31 QString GetSIStandard(void) const; 31 32 -
mythtv/libs/libmythtv/iptvrecorder.cpp
diff --git a/mythtv/libs/libmythtv/iptvrecorder.cpp b/mythtv/libs/libmythtv/iptvrecorder.cpp index 58cb956..f289e6c 100644
a b void IPTVRecorder::StopRecording(void) 69 69 request_recording = false; 70 70 unpauseWait.wakeAll(); 71 71 pauseLock.unlock(); 72 72 73 73 // we can't hold the pause lock while we wait for the IPTV feeder to stop 74 74 _channel->GetFeeder()->Stop(); 75 75 } 76 76 77 void IPTVRecorder::StartNewFile(void) 78 { 79 // Make sure the first things in the file are a PAT & PMT 80 HandleSingleProgramPAT(_stream_data->PATSingleProgram(), true); 81 HandleSingleProgramPMT(_stream_data->PMTSingleProgram(), true); 82 } 83 77 84 void IPTVRecorder::run(void) 78 85 { 79 86 LOG(VB_RECORD, LOG_INFO, LOC + "run() -- begin"); … … void IPTVRecorder::run(void) 91 98 recordingWait.wakeAll(); 92 99 } 93 100 101 StartNewFile(); 102 94 103 // Go into main RTSP loop, feeding data to AddData 95 104 _channel->GetFeeder()->Run(); 96 105 -
mythtv/libs/libmythtv/iptvrecorder.h
diff --git a/mythtv/libs/libmythtv/iptvrecorder.h b/mythtv/libs/libmythtv/iptvrecorder.h index 1ed625f..a395664 100644
a b class IPTVRecorder : public DTVRecorder, public TSDataListener 29 29 bool Open(void); 30 30 void Close(void); 31 31 void StopRecording(void); 32 void StartNewFile(void); 32 33 33 34 virtual void run(void); 34 35 -
mythtv/libs/libmythtv/mpeg/mpegstreamdata.cpp
diff --git a/mythtv/libs/libmythtv/mpeg/mpegstreamdata.cpp b/mythtv/libs/libmythtv/mpeg/mpegstreamdata.cpp index 43bcbe8..d819776 100644
a b void MPEGStreamData::ProcessPAT(const ProgramAssociationTable *pat) 836 836 QMutexLocker locker(&_listener_lock); 837 837 ProgramAssociationTable *pat_sp = PATSingleProgram(); 838 838 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++) 839 _mpeg_sp_listeners[i]->HandleSingleProgramPAT(pat_sp );839 _mpeg_sp_listeners[i]->HandleSingleProgramPAT(pat_sp, false); 840 840 } 841 841 } 842 842 … … void MPEGStreamData::ProcessPMT(const ProgramMapTable *pmt) 871 871 QMutexLocker locker(&_listener_lock); 872 872 ProgramMapTable *pmt_sp = PMTSingleProgram(); 873 873 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++) 874 _mpeg_sp_listeners[i]->HandleSingleProgramPMT(pmt_sp );874 _mpeg_sp_listeners[i]->HandleSingleProgramPMT(pmt_sp, false); 875 875 } 876 876 } 877 877 … … void MPEGStreamData::HandleTSTables(const TSPacket* tspacket) 982 982 QMutexLocker locker(&_listener_lock); 983 983 ProgramAssociationTable *pat_sp = PATSingleProgram(); 984 984 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++) 985 _mpeg_sp_listeners[i]->HandleSingleProgramPAT(pat_sp );985 _mpeg_sp_listeners[i]->HandleSingleProgramPAT(pat_sp, false); 986 986 } 987 987 if (TableID::PMT == psip->TableID() && 988 988 tspacket->PID() == _pid_pmt_single_program) … … void MPEGStreamData::HandleTSTables(const TSPacket* tspacket) 990 990 QMutexLocker locker(&_listener_lock); 991 991 ProgramMapTable *pmt_sp = PMTSingleProgram(); 992 992 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++) 993 _mpeg_sp_listeners[i]->HandleSingleProgramPMT(pmt_sp );993 _mpeg_sp_listeners[i]->HandleSingleProgramPMT(pmt_sp, false); 994 994 } 995 995 DONE_WITH_PSIP_PACKET(); // already parsed this table, toss it. 996 996 } -
mythtv/libs/libmythtv/mpeg/streamlisteners.h
diff --git a/mythtv/libs/libmythtv/mpeg/streamlisteners.h b/mythtv/libs/libmythtv/mpeg/streamlisteners.h index bc9cb2d..9412d5d 100644
a b class MPEGSingleProgramStreamListener 95 95 protected: 96 96 virtual ~MPEGSingleProgramStreamListener() {} 97 97 public: 98 virtual void HandleSingleProgramPAT(ProgramAssociationTable*) = 0; 99 virtual void HandleSingleProgramPMT(ProgramMapTable*) = 0; 98 virtual void HandleSingleProgramPAT(ProgramAssociationTable*, 99 bool insert) = 0; 100 virtual void HandleSingleProgramPMT(ProgramMapTable*, bool insert) = 0; 100 101 }; 101 102 102 103 class ATSCMainStreamListener -
mythtv/libs/libmythtv/mpegrecorder.cpp
diff --git a/mythtv/libs/libmythtv/mpegrecorder.cpp b/mythtv/libs/libmythtv/mpegrecorder.cpp index ebb6e1a..66747f2 100644
a b void MpegRecorder::run(void) 929 929 _stream_data->AddWritingListener(this); 930 930 931 931 // Make sure the first things in the file are a PAT & PMT 932 _wait_for_keyframe_option = false; 933 HandleSingleProgramPAT(_stream_data->PATSingleProgram()); 934 HandleSingleProgramPMT(_stream_data->PMTSingleProgram()); 932 HandleSingleProgramPAT(_stream_data->PATSingleProgram(), true); 933 HandleSingleProgramPMT(_stream_data->PMTSingleProgram(), true); 935 934 _wait_for_keyframe_option = true; 936 935 } 937 936 … … void MpegRecorder::RestartEncoding(void) 1256 1255 _stream_data->PMTSingleProgram()) 1257 1256 { 1258 1257 _wait_for_keyframe_option = false; 1259 HandleSingleProgramPAT(_stream_data->PATSingleProgram() );1260 HandleSingleProgramPMT(_stream_data->PMTSingleProgram() );1258 HandleSingleProgramPAT(_stream_data->PATSingleProgram(), false); 1259 HandleSingleProgramPMT(_stream_data->PMTSingleProgram(), false); 1261 1260 } 1262 1261 1263 1262 if (driver == "hdpvr") // HD-PVR will sometimes reset to defaults