--- /media/FreeAgent GoFlex Drive/src/mythtv/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp 2013-03-26 10:41:46.000000000 +1300 +++ mythtv/mythtv/libs/libmythtv/dtvrecorder.cpp 2013-03-30 18:27:08.377633504 +1300 @@ -62,11 +62,11 @@ _repeat_pict(0), // H.264 support _pes_synced(false), _seen_sps(false), // settings - _wait_for_keyframe_option(true), + _wait_for_keyframe_option(true), // is wait_for_SPS for H264 _has_written_other_keyframe(false), // state _error(), _stream_data(NULL), // TS packet buffer @@ -274,13 +274,12 @@ void DTVRecorder::BufferedWrite(const TSPacket &tspacket, bool insert) { if (!insert) // PAT/PMT may need inserted in front of any buffered data { - // delay until first GOP to avoid decoder crash on res change - if (!_buffer_packets && _wait_for_keyframe_option && - _first_keyframe < 0) + // delay until first SPS/GOP to avoid decoder crash on res change + if (!_buffer_packets && _wait_for_keyframe_option && !_seen_sps) return; if (curRecording && timeOfFirstDataIsSet.testAndSetRelaxed(0,1)) { QMutexLocker locker(&statisticsLock); @@ -542,18 +541,19 @@ hasKeyFrame &= (_last_gop_seen + maxKFD) < _frames_seen_count; hasKeyFrame &= (_last_seq_seen + maxKFD) < _frames_seen_count; } // _buffer_packets will only be true if a payload start has been seen - if (hasKeyFrame && _buffer_packets) + if (hasKeyFrame && (_buffer_packets || _first_keyframe >= 0)) { LOG(VB_RECORD, LOG_DEBUG, LOC + QString ("Keyframe @ %1 + %2 = %3") .arg(ringBuffer->GetWritePosition()) .arg(_payload_buffer.size()) .arg(ringBuffer->GetWritePosition() + _payload_buffer.size())); + _seen_sps = true; // used by H264 to signal start rec to file _last_keyframe_seen = _frames_seen_count; HandleKeyframe(0); } if (hasFrame) @@ -896,34 +896,42 @@ // scan for a NAL unit start code uint32_t bytes_used = m_h264_parser.addBytes (tspacket->data() + i, TSPacket::kSize - i, ringBuffer->GetWritePosition()); - i += (bytes_used - 1); + + if (!_seen_sps && m_h264_parser.seen_SPS()) + _seen_sps = true; - if (m_h264_parser.stateChanged()) + if (m_h264_parser.stateChanged() && _seen_sps) { if (m_h264_parser.onFrameStart() && m_h264_parser.FieldType() != H264Parser::FIELD_BOTTOM) { hasKeyFrame = m_h264_parser.onKeyFrameStart(); hasFrame = true; - _seen_sps |= hasKeyFrame; - + width = m_h264_parser.pictureWidth(); height = m_h264_parser.pictureHeight(); aspectRatio = m_h264_parser.aspectRatio(); m_h264_parser.getFrameRate(frameRate); } } + + i += (bytes_used - 1); } // for (; i < TSPacket::kSize; ++i) // _buffer_packets will only be true if a payload start has been seen - if (hasKeyFrame && _buffer_packets) + if (_seen_sps) + _buffer_packets = false; + else + _payload_buffer.clear(); + + if (hasKeyFrame) { LOG(VB_RECORD, LOG_DEBUG, LOC + QString - ("Keyframe @ %1 + %2 = %3 AU %4") + ("H264Keyframe @ %1 + %2 = %3 AU %4") .arg(ringBuffer->GetWritePosition()) .arg(_payload_buffer.size()) .arg(ringBuffer->GetWritePosition() + _payload_buffer.size()) .arg(m_h264_parser.keyframeAUstreamOffset())); @@ -932,26 +940,19 @@ } if (hasFrame) { LOG(VB_RECORD, LOG_DEBUG, LOC + QString - ("Frame @ %1 + %2 = %3 AU %4") + ("H264Frame @ %1 + %2 = %3 AU %4") .arg(ringBuffer->GetWritePosition()) .arg(_payload_buffer.size()) .arg(ringBuffer->GetWritePosition() + _payload_buffer.size()) - .arg(m_h264_parser.keyframeAUstreamOffset())); + .arg(m_h264_parser.frameAUstreamOffset())); - _buffer_packets = false; // We now know if this is a keyframe _frames_seen_count++; if (!_wait_for_keyframe_option || _first_keyframe >= 0) UpdateFramesWritten(); - else - { - /* Found a frame that is not a keyframe, and we want to - * start on a keyframe */ - _payload_buffer.clear(); - } } if ((aspectRatio > 0) && (aspectRatio != m_videoAspect)) { m_videoAspect = aspectRatio; @@ -969,16 +970,16 @@ { LOG(VB_RECORD, LOG_INFO, LOC + QString("FindH264Keyframes: timescale: %1, tick: %2, framerate: %3") .arg( m_h264_parser.GetTimeScale() ) .arg( m_h264_parser.GetUnitsInTick() ) - .arg( frameRate.toDouble() * 1000 ) ); + .arg( frameRate.toDouble() ) ); m_frameRate = frameRate; FrameRateChange(frameRate.toDouble() * 1000, _frames_written_count); } - return _seen_sps; + return hasKeyFrame; } /** \fn DTVRecorder::HandleH264Keyframe(void) * \brief This save the current frame to the position maps * and handles ringbuffer switching. @@ -989,28 +990,40 @@ CheckForRingBufferSwitch(); uint64_t startpos; uint64_t frameNum = _frames_written_count; - if (_first_keyframe < 0) - { - _first_keyframe = frameNum; - startpos = 0; - } - else - startpos = m_h264_parser.keyframeAUstreamOffset(); + startpos = m_h264_parser.keyframeAUstreamOffset(); - // Add key frame to position map + // Add keyframe to position map positionMapLock.lock(); if (!positionMap.contains(frameNum)) { +// LOG(VB_RECORD, LOG_DEBUG, LOC + QString +// ("H264KeyFrame @ %1 tot_dur %2 AU %3") +// .arg(frameNum) +// .arg(_total_duration) +// .arg(startpos) ); + positionMapDelta[frameNum] = startpos; positionMap[frameNum] = startpos; durationMap[frameNum] = _total_duration + 0.5; durationMapDelta[frameNum] = _total_duration + 0.5; } + if ((_first_keyframe < 0) && !positionMap.contains(0)) + { + positionMapDelta[0] = 0; + positionMap[0] = 0; + durationMap[0] = 0.5; + durationMapDelta[0] = 0.5; + } positionMapLock.unlock(); + + if (_first_keyframe < 0) + { + _first_keyframe = frameNum; + } } void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len) { const uint maxKFD = kMaxKeyFrameDistance; @@ -1381,15 +1394,15 @@ FindAudioKeyframes(&tspacket); return ProcessAVTSPacket(tspacket); } -/// Common code for processing either audio or video packets +/// Common code for processing either audio or video packets (mpeg2 or h264) bool DTVRecorder::ProcessAVTSPacket(const TSPacket &tspacket) { - // Sync recording start to first keyframe - if (_wait_for_keyframe_option && _first_keyframe < 0) + // Sync recording start to first SPS/ keyframe + if (_wait_for_keyframe_option && !_seen_sps && _first_keyframe < 0) { if (_buffer_packets) BufferedWrite(tspacket); return true; }