Ticket #11328: keep-first-keyframe-v4.patch
| File keep-first-keyframe-v4.patch, 36.5 KB (added by , 14 years ago) |
|---|
-
mythtv/libs/libmythtv/mpeg/mpegstreamdata.cpp
diff --git a/mythtv/libs/libmythtv/mpeg/mpegstreamdata.cpp b/mythtv/libs/libmythtv/mpeg/mpegstreamdata.cpp index db9f694..32506e4 100644
a b void MPEGStreamData::ProcessPAT(const ProgramAssociationTable *pat) 831 831 QMutexLocker locker(&_listener_lock); 832 832 ProgramAssociationTable *pat_sp = PATSingleProgram(); 833 833 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++) 834 _mpeg_sp_listeners[i]->HandleSingleProgramPAT(pat_sp );834 _mpeg_sp_listeners[i]->HandleSingleProgramPAT(pat_sp, false); 835 835 } 836 836 } 837 837 … … void MPEGStreamData::ProcessPMT(const ProgramMapTable *pmt) 866 866 QMutexLocker locker(&_listener_lock); 867 867 ProgramMapTable *pmt_sp = PMTSingleProgram(); 868 868 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++) 869 _mpeg_sp_listeners[i]->HandleSingleProgramPMT(pmt_sp );869 _mpeg_sp_listeners[i]->HandleSingleProgramPMT(pmt_sp, false); 870 870 } 871 871 } 872 872 … … void MPEGStreamData::HandleTSTables(const TSPacket* tspacket) 977 977 QMutexLocker locker(&_listener_lock); 978 978 ProgramAssociationTable *pat_sp = PATSingleProgram(); 979 979 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++) 980 _mpeg_sp_listeners[i]->HandleSingleProgramPAT(pat_sp );980 _mpeg_sp_listeners[i]->HandleSingleProgramPAT(pat_sp, false); 981 981 } 982 982 if (TableID::PMT == psip->TableID() && 983 983 tspacket->PID() == _pid_pmt_single_program) … … void MPEGStreamData::HandleTSTables(const TSPacket* tspacket) 985 985 QMutexLocker locker(&_listener_lock); 986 986 ProgramMapTable *pmt_sp = PMTSingleProgram(); 987 987 for (uint i = 0; i < _mpeg_sp_listeners.size(); i++) 988 _mpeg_sp_listeners[i]->HandleSingleProgramPMT(pmt_sp );988 _mpeg_sp_listeners[i]->HandleSingleProgramPMT(pmt_sp, false); 989 989 } 990 990 DONE_WITH_PSIP_PACKET(); // already parsed this table, toss it. 991 991 } -
mythtv/libs/libmythtv/mpeg/streamlisteners.h
diff --git a/mythtv/libs/libmythtv/mpeg/streamlisteners.h b/mythtv/libs/libmythtv/mpeg/streamlisteners.h index b217860..0e4127f 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/recorders/asirecorder.cpp
diff --git a/mythtv/libs/libmythtv/recorders/asirecorder.cpp b/mythtv/libs/libmythtv/recorders/asirecorder.cpp index 148d1d5..640ebc3 100644
a b void ASIRecorder::SetOption(const QString &name, int value) 65 65 DTVRecorder::SetOption(name, value); 66 66 } 67 67 68 void ASIRecorder::StartNewFile(void) 69 { 70 // Make sure the first things in the file are a PAT & PMT 71 HandleSingleProgramPAT(_stream_data->PATSingleProgram(), true); 72 HandleSingleProgramPMT(_stream_data->PMTSingleProgram(), true); 73 } 74 75 68 76 void ASIRecorder::run(void) 69 77 { 70 78 if (!Open()) … … void ASIRecorder::run(void) 102 110 if (m_channel && (m_channel->GetSIStandard() == "dvb")) 103 111 _stream_data->AddListeningPID(DVB_TDT_PID); 104 112 105 // Make sure the first things in the file are a PAT & PMT 106 bool tmp = _wait_for_keyframe_option; 107 _wait_for_keyframe_option = false; 108 HandleSingleProgramPAT(_stream_data->PATSingleProgram()); 109 HandleSingleProgramPMT(_stream_data->PMTSingleProgram()); 110 _wait_for_keyframe_option = tmp; 113 StartNewFile(); 111 114 112 115 _stream_data->AddAVListener(this); 113 116 _stream_data->AddWritingListener(this); -
mythtv/libs/libmythtv/recorders/asirecorder.h
diff --git a/mythtv/libs/libmythtv/recorders/asirecorder.h b/mythtv/libs/libmythtv/recorders/asirecorder.h index a973f9d..22d52b9 100644
a b class ASIRecorder : public DTVRecorder 69 69 bool Open(void); 70 70 bool IsOpen(void) const; 71 71 void Close(void); 72 void StartNewFile(void); 72 73 73 74 private: 74 75 ASIChannel *m_channel; -
mythtv/libs/libmythtv/recorders/cetonrecorder.cpp
diff --git a/mythtv/libs/libmythtv/recorders/cetonrecorder.cpp b/mythtv/libs/libmythtv/recorders/cetonrecorder.cpp index 8910c66..51c9a57 100644
a b void CetonRecorder::Close(void) 47 47 LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end"); 48 48 } 49 49 50 void CetonRecorder::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 CetonRecorder::run(void) 51 58 { 52 59 LOG(VB_RECORD, LOG_INFO, LOC + "run -- begin"); … … void CetonRecorder::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/recorders/cetonrecorder.h
diff --git a/mythtv/libs/libmythtv/recorders/cetonrecorder.h b/mythtv/libs/libmythtv/recorders/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/recorders/dtvrecorder.cpp
diff --git a/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp b/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp index 60549f8..d619d9c 100644
a b DTVRecorder::DTVRecorder(TVRec *rec) : 87 87 { 88 88 SetPositionMapType(MARK_GOP_BYFRAME); 89 89 _payload_buffer.reserve(TSPacket::kSize * (50 + 1)); 90 90 91 ResetForNewFile(); 92 93 memset(_stream_id, 0, sizeof(_stream_id)); 94 memset(_pid_status, 0, sizeof(_pid_status)); 95 memset(_continuity_counter, 0xff, sizeof(_continuity_counter)); 91 96 } 92 97 93 98 DTVRecorder::~DTVRecorder() … … void DTVRecorder::SetOptionsFromProfile(RecordingProfile *profile, 147 152 void DTVRecorder::FinishRecording(void) 148 153 { 149 154 if (ringBuffer) 150 {151 if (!_payload_buffer.empty())152 {153 ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size());154 _payload_buffer.clear();155 }156 155 ringBuffer->WriterFlush(); 157 }158 156 159 157 if (curRecording) 160 158 { … … void DTVRecorder::ResetForNewFile(void) 171 169 LOG(VB_RECORD, LOG_INFO, LOC + "ResetForNewFile(void)"); 172 170 QMutexLocker locker(&positionMapLock); 173 171 174 // _ first_keyframe, _seen_psp and m_h264_parser should172 // _seen_psp and m_h264_parser should 175 173 // not be reset here. This will only be called just as 176 174 // we're seeing the first packet of a new keyframe for 177 175 // writing to the new file and anything that makes the … … void DTVRecorder::ResetForNewFile(void) 180 178 // -- Daniel Kristjansson 2011-02-26 181 179 182 180 _start_code = 0xffffffff; 183 //_first_keyframe181 _first_keyframe = -1; 184 182 _has_written_other_keyframe = false; 185 183 _last_keyframe_seen = 0; 186 184 _last_gop_seen = 0; … … void DTVRecorder::ResetForNewFile(void) 191 189 //_recording 192 190 _error = QString(); 193 191 194 memset(_stream_id, 0, sizeof(_stream_id));195 memset(_pid_status, 0, sizeof(_pid_status));196 memset(_continuity_counter, 0xff, sizeof(_continuity_counter));197 198 192 _progressive_sequence = 0; 199 193 _repeat_pict = 0; 200 194 201 _pes_synced = false;195 //_pes_synced 202 196 //_seen_sps 203 197 positionMap.clear(); 204 198 positionMapDelta.clear(); 205 199 durationMap.clear(); 206 200 durationMapDelta.clear(); 207 _payload_buffer.clear();208 201 209 202 locker.unlock(); 210 203 ClearStatistics(); … … void DTVRecorder::ClearStatistics(void) 215 208 RecorderBase::ClearStatistics(); 216 209 217 210 memset(_ts_count, 0, sizeof(_ts_count)); 218 for (int i = 0; i < 256; i++)211 for (int i = 0; i < 256; ++i) 219 212 _ts_last[i] = -1LL; 220 for (int i = 0; i < 256; i++)213 for (int i = 0; i < 256; ++i) 221 214 _ts_first[i] = -1LL; 222 215 //_ts_first_dt -- doesn't need to be cleared only used if _ts_first>=0 223 216 _packet_count.fetchAndStoreRelaxed(0); … … void DTVRecorder::InitStreamData(void) 274 267 _stream_data->SetDesiredProgram(_stream_data->DesiredProgram()); 275 268 } 276 269 277 void DTVRecorder::BufferedWrite(const TSPacket &tspacket )270 void DTVRecorder::BufferedWrite(const TSPacket &tspacket, bool insert) 278 271 { 279 // delay until first GOP to avoid decoder crash on res change 280 if (_wait_for_keyframe_option && _first_keyframe<0) 281 return; 282 283 if (curRecording && timeOfFirstDataIsSet.testAndSetRelaxed(0,1)) 272 if (!insert) // PAT/PMT may need inserted in front of any buffered data 284 273 { 285 QMutexLocker locker(&statisticsLock); 286 timeOfFirstData = MythDate::current(); 287 timeOfLatestData = MythDate::current(); 288 timeOfLatestDataTimer.start(); 289 } 274 // delay until first GOP to avoid decoder crash on res change 275 if (!_buffer_packets && _wait_for_keyframe_option && 276 _first_keyframe < 0) 277 return; 290 278 291 int val = timeOfLatestDataCount.fetchAndAddRelaxed(1); 292 int thresh = timeOfLatestDataPacketInterval.fetchAndAddRelaxed(0); 293 if (val > thresh) 294 { 295 QMutexLocker locker(&statisticsLock); 296 uint elapsed = timeOfLatestDataTimer.restart(); 297 int interval = thresh; 298 if (elapsed > kTimeOfLatestDataIntervalTarget + 250) 299 interval = timeOfLatestDataPacketInterval 300 .fetchAndStoreRelaxed(thresh * 4 / 5); 301 else if (elapsed + 250 < kTimeOfLatestDataIntervalTarget) 302 interval = timeOfLatestDataPacketInterval 303 .fetchAndStoreRelaxed(thresh * 9 / 8); 304 305 timeOfLatestDataCount.fetchAndStoreRelaxed(1); 306 timeOfLatestData = MythDate::current(); 307 308 LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Updating timeOfLatestData ") + 309 QString("elapsed(%1) interval(%2)") 310 .arg(elapsed).arg(interval)); 311 } 279 if (curRecording && timeOfFirstDataIsSet.testAndSetRelaxed(0,1)) 280 { 281 QMutexLocker locker(&statisticsLock); 282 timeOfFirstData = MythDate::current(); 283 timeOfLatestData = MythDate::current(); 284 timeOfLatestDataTimer.start(); 285 } 312 286 313 // Do we have to buffer the packet for exact keyframe detection? 314 if (_buffer_packets) 315 { 316 int idx = _payload_buffer.size(); 317 _payload_buffer.resize(idx + TSPacket::kSize); 318 memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::kSize); 319 return; 320 } 287 int val = timeOfLatestDataCount.fetchAndAddRelaxed(1); 288 int thresh = timeOfLatestDataPacketInterval.fetchAndAddRelaxed(0); 289 if (val > thresh) 290 { 291 QMutexLocker locker(&statisticsLock); 292 uint elapsed = timeOfLatestDataTimer.restart(); 293 int interval = thresh; 294 if (elapsed > kTimeOfLatestDataIntervalTarget + 250) 295 interval = timeOfLatestDataPacketInterval 296 .fetchAndStoreRelaxed(thresh * 4 / 5); 297 else if (elapsed + 250 < kTimeOfLatestDataIntervalTarget) 298 interval = timeOfLatestDataPacketInterval 299 .fetchAndStoreRelaxed(thresh * 9 / 8); 300 301 timeOfLatestDataCount.fetchAndStoreRelaxed(1); 302 timeOfLatestData = MythDate::current(); 303 304 LOG(VB_RECORD, LOG_DEBUG, LOC + 305 QString("Updating timeOfLatestData elapsed(%1) interval(%2)") 306 .arg(elapsed).arg(interval)); 307 } 321 308 322 // We are free to write the packet, but if we have buffered packet[s] 323 // we have to write them first... 324 if (!_payload_buffer.empty()) 325 { 326 if (ringBuffer) 327 ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 328 _payload_buffer.clear(); 309 // Do we have to buffer the packet for exact keyframe detection? 310 if (_buffer_packets) 311 { 312 int idx = _payload_buffer.size(); 313 _payload_buffer.resize(idx + TSPacket::kSize); 314 memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::kSize); 315 return; 316 } 317 318 // We are free to write the packet, but if we have buffered packet[s] 319 // we have to write them first... 320 if (!_payload_buffer.empty()) 321 { 322 if (ringBuffer) 323 ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 324 _payload_buffer.clear(); 325 } 329 326 } 330 327 331 328 if (ringBuffer) … … static const uint frameRateMap[16] = { 403 400 */ 404 401 bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) 405 402 { 406 bool haveBufferedData = !_payload_buffer.empty();407 403 if (!tspacket->HasPayload()) // no payload to scan 408 return !haveBufferedData;404 return _first_keyframe >= 0; 409 405 410 406 if (!ringBuffer) 411 return !haveBufferedData;407 return _first_keyframe >= 0; 412 408 413 409 // if packet contains start of PES packet, start 414 410 // looking for first byte of MPEG start code (3 bytes 0 0 1) … … bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) 540 536 541 537 if (hasKeyFrame) 542 538 { 539 #if 0 540 LOG(VB_RECORD, LOG_ERR, LOC + QString 541 ("Keyframe @ %1 + %2 = %3") 542 .arg(ringBuffer->GetWritePosition()) 543 .arg(_payload_buffer.size()) 544 .arg(ringBuffer->GetWritePosition() + _payload_buffer.size())); 545 #endif 543 546 _last_keyframe_seen = _frames_seen_count; 544 HandleKeyframe( _frames_written_count, TSPacket::kSize);547 HandleKeyframe(0); 545 548 } 546 549 547 550 if (hasFrame) 548 551 { 552 #if 0 553 LOG(VB_RECORD, LOG_ERR, LOC + QString 554 ("Frame @ %1 + %2 = %3") 555 .arg(ringBuffer->GetWritePosition()) 556 .arg(_payload_buffer.size()) 557 .arg(ringBuffer->GetWritePosition() + _payload_buffer.size())); 558 #endif 559 _buffer_packets = false; // We now know if it is a keyframe, or not 549 560 _frames_seen_count++; 550 if (!_wait_for_keyframe_option || _first_keyframe >=0)561 if (!_wait_for_keyframe_option || _first_keyframe >= 0) 551 562 UpdateFramesWritten(); 563 else 564 { 565 /* Found a frame that is not a keyframe, and we want to 566 * start on a keyframe */ 567 _payload_buffer.clear(); 568 } 552 569 } 553 570 554 571 if ((aspectRatio > 0) && (aspectRatio != m_videoAspect)) … … bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) 572 589 FrameRateChange(frameRate, _frames_written_count); 573 590 } 574 591 575 return hasKeyFrame || (_payload_buffer.size() >= (188*50));592 return _first_keyframe >= 0; 576 593 } 577 594 578 595 void DTVRecorder::HandleTimestamps(int stream_id, int64_t pts, int64_t dts) … … bool DTVRecorder::FindAudioKeyframes(const TSPacket*) 680 697 if (1 == (_frames_seen_count & 0x7)) 681 698 { 682 699 _last_keyframe_seen = _frames_seen_count; 683 HandleKeyframe(_ frames_written_count);700 HandleKeyframe(_payload_buffer.size()); 684 701 hasKeyFrame = true; 685 702 } 686 703 … … bool DTVRecorder::FindOtherKeyframes(const TSPacket *tspacket) 708 725 UpdateFramesWritten(); 709 726 _last_keyframe_seen = _frames_seen_count; 710 727 711 HandleKeyframe(_ frames_written_count);728 HandleKeyframe(_payload_buffer.size()); 712 729 713 730 _has_written_other_keyframe = true; 714 731 … … bool DTVRecorder::FindOtherKeyframes(const TSPacket *tspacket) 719 736 * \brief This save the current frame to the position maps 720 737 * and handles ringbuffer switching. 721 738 */ 722 void DTVRecorder::HandleKeyframe( uint64_t frameNum,int64_t extra)739 void DTVRecorder::HandleKeyframe(int64_t extra) 723 740 { 724 741 if (!ringBuffer) 725 742 return; 726 743 727 #if 0 728 unsigned long long frameNum = _frames_written_count; 729 #endif 744 // Perform ringbuffer switch if needed. 745 CheckForRingBufferSwitch(); 730 746 747 uint64_t frameNum = _frames_written_count; 731 748 _first_keyframe = (_first_keyframe < 0) ? frameNum : _first_keyframe; 732 749 733 750 // Add key frame to position map 734 751 positionMapLock.lock(); 735 752 if (!positionMap.contains(frameNum)) 736 753 { 737 long long startpos = ringBuffer->GetWritePosition(); 738 // FIXME: handle keyframes with start code spanning over two ts packets 739 startpos += _payload_buffer.size() - extra; 754 int64_t startpos = ringBuffer->GetWritePosition() + extra; 740 755 741 756 // Don't put negative offsets into the database, they get munged into 742 757 // MAX_INT64 - offset, which is an exceedingly large number, and … … void DTVRecorder::HandleKeyframe(uint64_t frameNum, int64_t extra) 750 765 } 751 766 } 752 767 positionMapLock.unlock(); 753 754 // Perform ringbuffer switch if needed.755 CheckForRingBufferSwitch();756 768 } 757 769 758 770 /** \fn DTVRecorder::FindH264Keyframes(const TSPacket*) … … void DTVRecorder::HandleKeyframe(uint64_t frameNum, int64_t extra) 762 774 */ 763 775 bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) 764 776 { 777 if (!tspacket->HasPayload()) // no payload to scan 778 return _first_keyframe >= 0; 779 765 780 if (!ringBuffer) 766 781 { 767 782 LOG(VB_GENERAL, LOG_ERR, LOC + "FindH264Keyframes: No ringbuffer"); 768 return false;783 return _first_keyframe >= 0; 769 784 } 770 785 771 bool haveBufferedData = !_payload_buffer.empty();772 if (!tspacket->HasPayload()) // no payload to scan773 return !haveBufferedData;774 775 786 const bool payloadStart = tspacket->PayloadStart(); 776 787 if (payloadStart) 777 788 { … … bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) 790 801 791 802 // scan for PES packets and H.264 NAL units 792 803 uint i = tspacket->AFCOffset(); 793 for (; i < TSPacket::kSize; i++)804 for (; i < TSPacket::kSize; ++i) 794 805 { 795 806 // special handling required when a new PES packet begins 796 807 if (payloadStart && !_pes_synced) … … bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) 858 869 859 870 // scan for a NAL unit start code 860 871 861 uint32_t bytes_used = m_h264_parser.addBytes( 862 tspacket->data() + i, TSPacket::kSize - i, 863 ringBuffer->GetWritePosition() + _payload_buffer.size() 864 ); 872 uint32_t bytes_used = m_h264_parser.addBytes 873 (tspacket->data() + i, TSPacket::kSize - i, 874 ringBuffer->GetWritePosition()); 865 875 i += (bytes_used - 1); 866 876 867 877 if (m_h264_parser.stateChanged()) … … bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) 879 889 frameRate = m_h264_parser.frameRate(); 880 890 } 881 891 } 882 } // for (; i < TSPacket::kSize; i++)892 } // for (; i < TSPacket::kSize; ++i) 883 893 884 894 if (hasKeyFrame) 885 895 { 896 #if 0 897 LOG(VB_RECORD, LOG_ERR, LOC + QString 898 ("Keyframe @ %1 + %2 = %3 AU %4") 899 .arg(ringBuffer->GetWritePosition()) 900 .arg(_payload_buffer.size()) 901 .arg(ringBuffer->GetWritePosition() + _payload_buffer.size()) 902 .arg(m_h264_parser.keyframeAUstreamOffset())); 903 #endif 886 904 _last_keyframe_seen = _frames_seen_count; 887 905 HandleH264Keyframe(); 888 906 } 889 907 890 908 if (hasFrame) 891 909 { 910 #if 0 911 LOG(VB_RECORD, LOG_ERR, LOC + QString 912 ("Frame @ %1 + %2 = %3 AU %4") 913 .arg(ringBuffer->GetWritePosition()) 914 .arg(_payload_buffer.size()) 915 .arg(ringBuffer->GetWritePosition() + _payload_buffer.size()) 916 .arg(m_h264_parser.keyframeAUstreamOffset())); 917 #endif 918 _buffer_packets = false; // We now know if this is a keyframe 892 919 _frames_seen_count++; 893 920 if (!_wait_for_keyframe_option || _first_keyframe >= 0) 894 921 UpdateFramesWritten(); 922 else 923 { 924 /* Found a frame that is not a keyframe, and we want to 925 * start on a keyframe */ 926 _payload_buffer.clear(); 927 } 895 928 } 896 929 897 930 if ((aspectRatio > 0) && (aspectRatio != m_videoAspect)) … … bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) 909 942 910 943 if (frameRate != 0 && frameRate != m_frameRate) 911 944 { 912 913 945 LOG(VB_RECORD, LOG_INFO, LOC + 914 946 QString("FindH264Keyframes: timescale: %1, tick: %2, framerate: %3") 915 947 .arg( m_h264_parser.GetTimeScale() ) … … bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) 919 951 FrameRateChange(frameRate, _frames_written_count); 920 952 } 921 953 922 return hasKeyFrame || (_payload_buffer.size() >= (188*50));954 return _seen_sps; 923 955 } 924 956 925 957 /** \fn DTVRecorder::HandleH264Keyframe(void) … … bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) 928 960 */ 929 961 void DTVRecorder::HandleH264Keyframe(void) 930 962 { 931 unsigned long long frameNum = _frames_written_count; 963 // Perform ringbuffer switch if needed. 964 CheckForRingBufferSwitch(); 932 965 933 _first_keyframe = (_first_keyframe < 0) ? frameNum : _first_keyframe; 966 uint64_t startpos; 967 uint64_t frameNum = _frames_written_count; 968 969 if (_first_keyframe < 0) 970 { 971 _first_keyframe = frameNum; 972 startpos = 0; 973 } 974 else 975 startpos = m_h264_parser.keyframeAUstreamOffset(); 934 976 935 977 // Add key frame to position map 936 978 positionMapLock.lock(); 937 979 if (!positionMap.contains(frameNum)) 938 980 { 939 positionMapDelta[frameNum] = m_h264_parser.keyframeAUstreamOffset();940 positionMap[frameNum] = m_h264_parser.keyframeAUstreamOffset();981 positionMapDelta[frameNum] = startpos; 982 positionMap[frameNum] = startpos; 941 983 durationMap[frameNum] = _total_duration / 1000; 942 984 durationMapDelta[frameNum] = _total_duration / 1000; 943 985 } 944 986 positionMapLock.unlock(); 945 946 // Perform ringbuffer switch if needed.947 CheckForRingBufferSwitch();948 987 } 949 988 950 989 void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len) … … void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len) 1065 1104 if (hasKeyFrame) 1066 1105 { 1067 1106 _last_keyframe_seen = _frames_seen_count; 1068 HandleKeyframe(_ frames_written_count, bufptr - bufstart);1107 HandleKeyframe(_payload_buffer.size() - (bufptr - bufstart)); 1069 1108 } 1070 1109 1071 1110 if ((aspectRatio > 0) && (aspectRatio != m_videoAspect)) … … void DTVRecorder::HandlePAT(const ProgramAssociationTable *_pat) 1149 1188 1150 1189 if (!pmtpid) 1151 1190 { 1152 LOG(VB_RECORD, LOG_ERR, LOC + "SetPAT(): " 1153 "Ignoring PAT not containing our desired program..."); 1191 LOG(VB_RECORD, LOG_ERR, LOC + 1192 QString("SetPAT(): Ignoring PAT not containing our desired " 1193 "program (%1)...").arg(progNum)); 1154 1194 return; 1155 1195 } 1156 1196 … … void DTVRecorder::HandlePAT(const ProgramAssociationTable *_pat) 1162 1202 delete oldpat; 1163 1203 1164 1204 // Listen for the other PMTs for faster channel switching 1165 for (uint i = 0; _input_pat && (i < _input_pat->ProgramCount()); i++)1205 for (uint i = 0; _input_pat && (i < _input_pat->ProgramCount()); ++i) 1166 1206 { 1167 1207 uint pmt_pid = _input_pat->ProgramPID(i); 1168 1208 if (!_stream_data->IsListeningPID(pmt_pid)) … … void DTVRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt) 1183 1223 QString sistandard = GetSIStandard(); 1184 1224 1185 1225 bool has_no_av = true; 1186 for (uint i = 0; i < _input_pmt->StreamCount() && has_no_av; i++)1226 for (uint i = 0; i < _input_pmt->StreamCount() && has_no_av; ++i) 1187 1227 { 1188 1228 has_no_av &= !_input_pmt->IsVideo(i, sistandard); 1189 1229 has_no_av &= !_input_pmt->IsAudio(i, sistandard); … … void DTVRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt) 1195 1235 } 1196 1236 } 1197 1237 1198 void DTVRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat) 1238 void DTVRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat, 1239 bool insert) 1199 1240 { 1200 1241 if (!pat) 1201 1242 { … … void DTVRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat) 1210 1251 pat->tsheader()->SetContinuityCounter(next_cc); 1211 1252 pat->GetAsTSPackets(_scratch, next_cc); 1212 1253 1213 for (uint i = 0; i < _scratch.size(); i++)1214 DTVRecorder::BufferedWrite(_scratch[i] );1254 for (uint i = 0; i < _scratch.size(); ++i) 1255 DTVRecorder::BufferedWrite(_scratch[i], insert); 1215 1256 } 1216 1257 1217 void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt )1258 void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt, bool insert) 1218 1259 { 1219 1260 if (!pmt) 1220 1261 { … … void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt) 1223 1264 } 1224 1265 1225 1266 // collect stream types for H.264 (MPEG-4 AVC) keyframe detection 1226 for (uint i = 0; i < pmt->StreamCount(); i++)1267 for (uint i = 0; i < pmt->StreamCount(); ++i) 1227 1268 _stream_id[pmt->StreamPID(i)] = pmt->StreamType(i); 1228 1269 1229 1270 if (!ringBuffer) … … void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt) 1233 1274 pmt->tsheader()->SetContinuityCounter(next_cc); 1234 1275 pmt->GetAsTSPackets(_scratch, next_cc); 1235 1276 1236 for (uint i = 0; i < _scratch.size(); i++)1237 DTVRecorder::BufferedWrite(_scratch[i] );1277 for (uint i = 0; i < _scratch.size(); ++i) 1278 DTVRecorder::BufferedWrite(_scratch[i], insert); 1238 1279 } 1239 1280 1240 1281 bool DTVRecorder::ProcessTSPacket(const TSPacket &tspacket) … … bool DTVRecorder::ProcessTSPacket(const TSPacket &tspacket) 1260 1301 // Only create fake keyframe[s] if there are no audio/video streams 1261 1302 if (_input_pmt && _has_no_av) 1262 1303 { 1263 _buffer_packets = !FindOtherKeyframes(&tspacket); 1304 FindOtherKeyframes(&tspacket); 1305 _buffer_packets = false; 1264 1306 } 1265 1307 else 1266 1308 { … … bool DTVRecorder::ProcessVideoTSPacket(const TSPacket &tspacket) 1284 1326 1285 1327 uint streamType = _stream_id[tspacket.PID()]; 1286 1328 1287 // Check for keyframes and count frames 1288 if (streamType == StreamID::H264Video) 1329 if (tspacket.HasPayload() && tspacket.PayloadStart()) 1289 1330 { 1290 _buffer_packets = !FindH264Keyframes(&tspacket); 1291 if (_wait_for_keyframe_option && !_seen_sps) 1292 return true; 1331 // buffer packets until we know if this is a keyframe 1332 _buffer_packets = true; 1333 #if 0 1334 LOG(VB_RECORD, LOG_ERR, LOC + QString 1335 ("ProcessVideoTSPacket PayloadStart @ %1 + %2 = %3") 1336 .arg(ringBuffer->GetWritePosition()) 1337 .arg(_payload_buffer.size()) 1338 .arg(ringBuffer->GetWritePosition() + _payload_buffer.size())); 1339 #endif 1293 1340 } 1341 1342 // Check for keyframes and count frames 1343 if (streamType == StreamID::H264Video) 1344 FindH264Keyframes(&tspacket); 1345 else if (streamType != 0) 1346 FindMPEG2Keyframes(&tspacket); 1294 1347 else 1295 { 1296 _buffer_packets = !FindMPEG2Keyframes(&tspacket); 1297 } 1348 LOG(VB_RECORD, LOG_ERR, LOC + 1349 "ProcessVideoTSPacket: unknown stream type!"); 1298 1350 1299 1351 return ProcessAVTSPacket(tspacket); 1300 1352 } … … bool DTVRecorder::ProcessAudioTSPacket(const TSPacket &tspacket) 1304 1356 if (!ringBuffer) 1305 1357 return true; 1306 1358 1307 _buffer_packets = !FindAudioKeyframes(&tspacket); 1359 if (tspacket.HasPayload() && tspacket.PayloadStart()) 1360 { 1361 // buffer packets until we know if this is a keyframe 1362 _buffer_packets = true; 1363 #if 0 1364 LOG(VB_RECORD, LOG_ERR, LOC + QString 1365 ("ProcessAudioTSPacket PayloadStart @ %1 + %2 = %3") 1366 .arg(ringBuffer->GetWritePosition()) 1367 .arg(_payload_buffer.size()) 1368 .arg(ringBuffer->GetWritePosition() + _payload_buffer.size())); 1369 #endif 1370 } 1371 1372 FindAudioKeyframes(&tspacket); 1308 1373 return ProcessAVTSPacket(tspacket); 1309 1374 } 1310 1375 1311 1376 /// Common code for processing either audio or video packets 1312 1377 bool DTVRecorder::ProcessAVTSPacket(const TSPacket &tspacket) 1313 1378 { 1379 // Sync recording start to first keyframe 1380 if (!_buffer_packets && _wait_for_keyframe_option && _first_keyframe < 0) 1381 return true; 1382 1314 1383 const uint pid = tspacket.PID(); 1315 1384 1316 1385 if (pid != 0x1fff) … … bool DTVRecorder::ProcessAVTSPacket(const TSPacket &tspacket) 1328 1397 .arg(erate,5,'f',2)); 1329 1398 } 1330 1399 1331 // Sync recording start to first keyframe1332 if (_wait_for_keyframe_option && _first_keyframe < 0)1333 return true;1334 1335 1400 // Sync streams to the first Payload Unit Start Indicator 1336 1401 // _after_ first keyframe iff _wait_for_keyframe_option is true 1337 1402 if (!(_pid_status[pid] & kPayloadStartSeen) && tspacket.HasPayload()) -
mythtv/libs/libmythtv/recorders/dtvrecorder.h
diff --git a/mythtv/libs/libmythtv/recorders/dtvrecorder.h b/mythtv/libs/libmythtv/recorders/dtvrecorder.h index 6617366..70d287c 100644
a b class DTVRecorder : 64 64 void HandleEncryptionStatus(uint /*pnum*/, bool /*encrypted*/) { } 65 65 66 66 // MPEG Single Program Stream Listener 67 void HandleSingleProgramPAT(ProgramAssociationTable *pat );68 void HandleSingleProgramPMT(ProgramMapTable *pmt );67 void HandleSingleProgramPAT(ProgramAssociationTable *pat, bool insert); 68 void HandleSingleProgramPMT(ProgramMapTable *pmt, bool insert); 69 69 70 70 // ATSC Main 71 71 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 void UpdateFramesWritten(void); 99 99 100 void BufferedWrite(const TSPacket &tspacket );100 void BufferedWrite(const TSPacket &tspacket, bool insert = false); 101 101 102 102 // MPEG TS "audio only" support 103 103 bool FindAudioKeyframes(const TSPacket *tspacket); -
mythtv/libs/libmythtv/recorders/dvbrecorder.cpp
diff --git a/mythtv/libs/libmythtv/recorders/dvbrecorder.cpp b/mythtv/libs/libmythtv/recorders/dvbrecorder.cpp index 9aba52f..e0ea31f 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/recorders/dvbrecorder.h
diff --git a/mythtv/libs/libmythtv/recorders/dvbrecorder.h b/mythtv/libs/libmythtv/recorders/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/recorders/hdhrrecorder.cpp
diff --git a/mythtv/libs/libmythtv/recorders/hdhrrecorder.cpp b/mythtv/libs/libmythtv/recorders/hdhrrecorder.cpp index 363d373..b98495e 100644
a b void HDHRRecorder::Close(void) 48 48 LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end"); 49 49 } 50 50 51 void HDHRRecorder::StartNewFile(void) 52 { 53 // Make sure the first things in the file are a PAT & PMT 54 HandleSingleProgramPAT(_stream_data->PATSingleProgram(), true); 55 HandleSingleProgramPMT(_stream_data->PMTSingleProgram(), true); 56 } 57 51 58 void HDHRRecorder::run(void) 52 59 { 53 60 LOG(VB_RECORD, LOG_INFO, LOC + "run -- begin"); … … void HDHRRecorder::run(void) 67 74 recordingWait.wakeAll(); 68 75 } 69 76 70 // Make sure the first things in the file are a PAT & PMT 71 bool tmp = _wait_for_keyframe_option; 72 _wait_for_keyframe_option = false; 73 HandleSingleProgramPAT(_stream_data->PATSingleProgram()); 74 HandleSingleProgramPMT(_stream_data->PMTSingleProgram()); 75 _wait_for_keyframe_option = tmp; 77 StartNewFile(); 76 78 77 79 _stream_data->AddAVListener(this); 78 80 _stream_data->AddWritingListener(this); -
mythtv/libs/libmythtv/recorders/hdhrrecorder.h
diff --git a/mythtv/libs/libmythtv/recorders/hdhrrecorder.h b/mythtv/libs/libmythtv/recorders/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/recorders/iptvrecorder.cpp
diff --git a/mythtv/libs/libmythtv/recorders/iptvrecorder.cpp b/mythtv/libs/libmythtv/recorders/iptvrecorder.cpp index 39a35b1..3d081bc 100644
a b bool IPTVRecorder::PauseAndWait(int timeout) 91 91 return IsPaused(true); 92 92 } 93 93 94 void IPTVRecorder::StartNewFile(void) 95 { 96 // Make sure the first things in the file are a PAT & PMT 97 HandleSingleProgramPAT(_stream_data->PATSingleProgram(), true); 98 HandleSingleProgramPMT(_stream_data->PMTSingleProgram(), true); 99 } 100 94 101 void IPTVRecorder::run(void) 95 102 { 96 103 LOG(VB_RECORD, LOG_INFO, LOC + "run -- begin"); … … void IPTVRecorder::run(void) 109 116 recordingWait.wakeAll(); 110 117 } 111 118 112 // Make sure the first things in the file are a PAT & PMT 113 bool tmp = _wait_for_keyframe_option; 114 _wait_for_keyframe_option = false; 115 HandleSingleProgramPAT(_stream_data->PATSingleProgram()); 116 HandleSingleProgramPMT(_stream_data->PMTSingleProgram()); 117 _wait_for_keyframe_option = tmp; 119 StartNewFile(); 118 120 119 121 _stream_data->AddAVListener(this); 120 122 _stream_data->AddWritingListener(this); -
mythtv/libs/libmythtv/recorders/iptvrecorder.h
diff --git a/mythtv/libs/libmythtv/recorders/iptvrecorder.h b/mythtv/libs/libmythtv/recorders/iptvrecorder.h index d68c1e6..cbcd041 100644
a b class IPTVRecorder : public DTVRecorder 24 24 virtual bool Open(void); // RecorderBase 25 25 virtual void Close(void); // RecorderBase 26 26 bool IsOpen(void) const; 27 void StartNewFile(void); 27 28 28 29 virtual void SetStreamData(MPEGStreamData*); // DTVRecorder 29 30 virtual bool PauseAndWait(int timeout = 100); // RecorderBase -
mythtv/libs/libmythtv/recorders/mpegrecorder.cpp
diff --git a/mythtv/libs/libmythtv/recorders/mpegrecorder.cpp b/mythtv/libs/libmythtv/recorders/mpegrecorder.cpp index 1a5aee0..ffb6642 100644
a b void MpegRecorder::run(void) 932 932 _stream_data->AddWritingListener(this); 933 933 934 934 // Make sure the first things in the file are a PAT & PMT 935 _wait_for_keyframe_option = false; 936 HandleSingleProgramPAT(_stream_data->PATSingleProgram()); 937 HandleSingleProgramPMT(_stream_data->PMTSingleProgram()); 935 HandleSingleProgramPAT(_stream_data->PATSingleProgram(), true); 936 HandleSingleProgramPMT(_stream_data->PMTSingleProgram(), true); 938 937 _wait_for_keyframe_option = true; 939 938 } 940 939 … … void MpegRecorder::RestartEncoding(void) 1253 1252 _stream_data->PMTSingleProgram()) 1254 1253 { 1255 1254 _wait_for_keyframe_option = false; 1256 HandleSingleProgramPAT(_stream_data->PATSingleProgram() );1257 HandleSingleProgramPMT(_stream_data->PMTSingleProgram() );1255 HandleSingleProgramPAT(_stream_data->PATSingleProgram(), false); 1256 HandleSingleProgramPMT(_stream_data->PMTSingleProgram(), false); 1258 1257 } 1259 1258 1260 1259 if (driver == "hdpvr") // HD-PVR will sometimes reset to defaults
