1 | --- /media/FreeAgent GoFlex Drive/src/mythtv/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp 2013-03-26 10:41:46.000000000 +1300 |
---|
2 | +++ mythtv/mythtv/libs/libmythtv/dtvrecorder.cpp 2013-03-30 18:27:08.377633504 +1300 |
---|
3 | @@ -62,11 +62,11 @@ |
---|
4 | _repeat_pict(0), |
---|
5 | // H.264 support |
---|
6 | _pes_synced(false), |
---|
7 | _seen_sps(false), |
---|
8 | // settings |
---|
9 | - _wait_for_keyframe_option(true), |
---|
10 | + _wait_for_keyframe_option(true), // is wait_for_SPS for H264 |
---|
11 | _has_written_other_keyframe(false), |
---|
12 | // state |
---|
13 | _error(), |
---|
14 | _stream_data(NULL), |
---|
15 | // TS packet buffer |
---|
16 | @@ -274,13 +274,12 @@ |
---|
17 | |
---|
18 | void DTVRecorder::BufferedWrite(const TSPacket &tspacket, bool insert) |
---|
19 | { |
---|
20 | if (!insert) // PAT/PMT may need inserted in front of any buffered data |
---|
21 | { |
---|
22 | - // delay until first GOP to avoid decoder crash on res change |
---|
23 | - if (!_buffer_packets && _wait_for_keyframe_option && |
---|
24 | - _first_keyframe < 0) |
---|
25 | + // delay until first SPS/GOP to avoid decoder crash on res change |
---|
26 | + if (!_buffer_packets && _wait_for_keyframe_option && !_seen_sps) |
---|
27 | return; |
---|
28 | |
---|
29 | if (curRecording && timeOfFirstDataIsSet.testAndSetRelaxed(0,1)) |
---|
30 | { |
---|
31 | QMutexLocker locker(&statisticsLock); |
---|
32 | @@ -542,18 +541,19 @@ |
---|
33 | hasKeyFrame &= (_last_gop_seen + maxKFD) < _frames_seen_count; |
---|
34 | hasKeyFrame &= (_last_seq_seen + maxKFD) < _frames_seen_count; |
---|
35 | } |
---|
36 | |
---|
37 | // _buffer_packets will only be true if a payload start has been seen |
---|
38 | - if (hasKeyFrame && _buffer_packets) |
---|
39 | + if (hasKeyFrame && (_buffer_packets || _first_keyframe >= 0)) |
---|
40 | { |
---|
41 | LOG(VB_RECORD, LOG_DEBUG, LOC + QString |
---|
42 | ("Keyframe @ %1 + %2 = %3") |
---|
43 | .arg(ringBuffer->GetWritePosition()) |
---|
44 | .arg(_payload_buffer.size()) |
---|
45 | .arg(ringBuffer->GetWritePosition() + _payload_buffer.size())); |
---|
46 | |
---|
47 | + _seen_sps = true; // used by H264 to signal start rec to file |
---|
48 | _last_keyframe_seen = _frames_seen_count; |
---|
49 | HandleKeyframe(0); |
---|
50 | } |
---|
51 | |
---|
52 | if (hasFrame) |
---|
53 | @@ -896,34 +896,42 @@ |
---|
54 | // scan for a NAL unit start code |
---|
55 | |
---|
56 | uint32_t bytes_used = m_h264_parser.addBytes |
---|
57 | (tspacket->data() + i, TSPacket::kSize - i, |
---|
58 | ringBuffer->GetWritePosition()); |
---|
59 | - i += (bytes_used - 1); |
---|
60 | + |
---|
61 | + if (!_seen_sps && m_h264_parser.seen_SPS()) |
---|
62 | + _seen_sps = true; |
---|
63 | |
---|
64 | - if (m_h264_parser.stateChanged()) |
---|
65 | + if (m_h264_parser.stateChanged() && _seen_sps) |
---|
66 | { |
---|
67 | if (m_h264_parser.onFrameStart() && |
---|
68 | m_h264_parser.FieldType() != H264Parser::FIELD_BOTTOM) |
---|
69 | { |
---|
70 | hasKeyFrame = m_h264_parser.onKeyFrameStart(); |
---|
71 | hasFrame = true; |
---|
72 | - _seen_sps |= hasKeyFrame; |
---|
73 | - |
---|
74 | + |
---|
75 | width = m_h264_parser.pictureWidth(); |
---|
76 | height = m_h264_parser.pictureHeight(); |
---|
77 | aspectRatio = m_h264_parser.aspectRatio(); |
---|
78 | m_h264_parser.getFrameRate(frameRate); |
---|
79 | } |
---|
80 | } |
---|
81 | + |
---|
82 | + i += (bytes_used - 1); |
---|
83 | } // for (; i < TSPacket::kSize; ++i) |
---|
84 | |
---|
85 | // _buffer_packets will only be true if a payload start has been seen |
---|
86 | - if (hasKeyFrame && _buffer_packets) |
---|
87 | + if (_seen_sps) |
---|
88 | + _buffer_packets = false; |
---|
89 | + else |
---|
90 | + _payload_buffer.clear(); |
---|
91 | + |
---|
92 | + if (hasKeyFrame) |
---|
93 | { |
---|
94 | LOG(VB_RECORD, LOG_DEBUG, LOC + QString |
---|
95 | - ("Keyframe @ %1 + %2 = %3 AU %4") |
---|
96 | + ("H264Keyframe @ %1 + %2 = %3 AU %4") |
---|
97 | .arg(ringBuffer->GetWritePosition()) |
---|
98 | .arg(_payload_buffer.size()) |
---|
99 | .arg(ringBuffer->GetWritePosition() + _payload_buffer.size()) |
---|
100 | .arg(m_h264_parser.keyframeAUstreamOffset())); |
---|
101 | |
---|
102 | @@ -932,26 +940,19 @@ |
---|
103 | } |
---|
104 | |
---|
105 | if (hasFrame) |
---|
106 | { |
---|
107 | LOG(VB_RECORD, LOG_DEBUG, LOC + QString |
---|
108 | - ("Frame @ %1 + %2 = %3 AU %4") |
---|
109 | + ("H264Frame @ %1 + %2 = %3 AU %4") |
---|
110 | .arg(ringBuffer->GetWritePosition()) |
---|
111 | .arg(_payload_buffer.size()) |
---|
112 | .arg(ringBuffer->GetWritePosition() + _payload_buffer.size()) |
---|
113 | - .arg(m_h264_parser.keyframeAUstreamOffset())); |
---|
114 | + .arg(m_h264_parser.frameAUstreamOffset())); |
---|
115 | |
---|
116 | - _buffer_packets = false; // We now know if this is a keyframe |
---|
117 | _frames_seen_count++; |
---|
118 | if (!_wait_for_keyframe_option || _first_keyframe >= 0) |
---|
119 | UpdateFramesWritten(); |
---|
120 | - else |
---|
121 | - { |
---|
122 | - /* Found a frame that is not a keyframe, and we want to |
---|
123 | - * start on a keyframe */ |
---|
124 | - _payload_buffer.clear(); |
---|
125 | - } |
---|
126 | } |
---|
127 | |
---|
128 | if ((aspectRatio > 0) && (aspectRatio != m_videoAspect)) |
---|
129 | { |
---|
130 | m_videoAspect = aspectRatio; |
---|
131 | @@ -969,16 +970,16 @@ |
---|
132 | { |
---|
133 | LOG(VB_RECORD, LOG_INFO, LOC + |
---|
134 | QString("FindH264Keyframes: timescale: %1, tick: %2, framerate: %3") |
---|
135 | .arg( m_h264_parser.GetTimeScale() ) |
---|
136 | .arg( m_h264_parser.GetUnitsInTick() ) |
---|
137 | - .arg( frameRate.toDouble() * 1000 ) ); |
---|
138 | + .arg( frameRate.toDouble() ) ); |
---|
139 | m_frameRate = frameRate; |
---|
140 | FrameRateChange(frameRate.toDouble() * 1000, _frames_written_count); |
---|
141 | } |
---|
142 | |
---|
143 | - return _seen_sps; |
---|
144 | + return hasKeyFrame; |
---|
145 | } |
---|
146 | |
---|
147 | /** \fn DTVRecorder::HandleH264Keyframe(void) |
---|
148 | * \brief This save the current frame to the position maps |
---|
149 | * and handles ringbuffer switching. |
---|
150 | @@ -989,28 +990,40 @@ |
---|
151 | CheckForRingBufferSwitch(); |
---|
152 | |
---|
153 | uint64_t startpos; |
---|
154 | uint64_t frameNum = _frames_written_count; |
---|
155 | |
---|
156 | - if (_first_keyframe < 0) |
---|
157 | - { |
---|
158 | - _first_keyframe = frameNum; |
---|
159 | - startpos = 0; |
---|
160 | - } |
---|
161 | - else |
---|
162 | - startpos = m_h264_parser.keyframeAUstreamOffset(); |
---|
163 | + startpos = m_h264_parser.keyframeAUstreamOffset(); |
---|
164 | |
---|
165 | - // Add key frame to position map |
---|
166 | + // Add keyframe to position map |
---|
167 | positionMapLock.lock(); |
---|
168 | if (!positionMap.contains(frameNum)) |
---|
169 | { |
---|
170 | +// LOG(VB_RECORD, LOG_DEBUG, LOC + QString |
---|
171 | +// ("H264KeyFrame @ %1 tot_dur %2 AU %3") |
---|
172 | +// .arg(frameNum) |
---|
173 | +// .arg(_total_duration) |
---|
174 | +// .arg(startpos) ); |
---|
175 | + |
---|
176 | positionMapDelta[frameNum] = startpos; |
---|
177 | positionMap[frameNum] = startpos; |
---|
178 | durationMap[frameNum] = _total_duration + 0.5; |
---|
179 | durationMapDelta[frameNum] = _total_duration + 0.5; |
---|
180 | } |
---|
181 | + if ((_first_keyframe < 0) && !positionMap.contains(0)) |
---|
182 | + { |
---|
183 | + positionMapDelta[0] = 0; |
---|
184 | + positionMap[0] = 0; |
---|
185 | + durationMap[0] = 0.5; |
---|
186 | + durationMapDelta[0] = 0.5; |
---|
187 | + } |
---|
188 | positionMapLock.unlock(); |
---|
189 | + |
---|
190 | + if (_first_keyframe < 0) |
---|
191 | + { |
---|
192 | + _first_keyframe = frameNum; |
---|
193 | + } |
---|
194 | } |
---|
195 | |
---|
196 | void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len) |
---|
197 | { |
---|
198 | const uint maxKFD = kMaxKeyFrameDistance; |
---|
199 | @@ -1381,15 +1394,15 @@ |
---|
200 | |
---|
201 | FindAudioKeyframes(&tspacket); |
---|
202 | return ProcessAVTSPacket(tspacket); |
---|
203 | } |
---|
204 | |
---|
205 | -/// Common code for processing either audio or video packets |
---|
206 | +/// Common code for processing either audio or video packets (mpeg2 or h264) |
---|
207 | bool DTVRecorder::ProcessAVTSPacket(const TSPacket &tspacket) |
---|
208 | { |
---|
209 | - // Sync recording start to first keyframe |
---|
210 | - if (_wait_for_keyframe_option && _first_keyframe < 0) |
---|
211 | + // Sync recording start to first SPS/ keyframe |
---|
212 | + if (_wait_for_keyframe_option && !_seen_sps && _first_keyframe < 0) |
---|
213 | { |
---|
214 | if (_buffer_packets) |
---|
215 | BufferedWrite(tspacket); |
---|
216 | return true; |
---|
217 | } |
---|