00001
00008 #include "RingBuffer.h"
00009 #include "programinfo.h"
00010 #include "mpegtables.h"
00011 #include "mpegstreamdata.h"
00012 #include "dtvrecorder.h"
00013 #include "tv_rec.h"
00014
00015 extern "C" {
00016
00017 extern const uint8_t *ff_find_start_code(const uint8_t * restrict p, const uint8_t *end, uint32_t * restrict state);
00018 }
00019
00020 #define LOC QString("DTVRec(%1): ").arg(tvrec->GetCaptureCardNum())
00021 #define LOC_ERR QString("DTVRec(%1) Error: ").arg(tvrec->GetCaptureCardNum())
00022
00023 const uint DTVRecorder::kMaxKeyFrameDistance = 80;
00024
00033 DTVRecorder::DTVRecorder(TVRec *rec) :
00034 RecorderBase(rec),
00035
00036 _stream_fd(-1),
00037 _recording_type("all"),
00038
00039 _start_code(0xffffffff), _first_keyframe(-1),
00040 _last_gop_seen(0), _last_seq_seen(0),
00041 _last_keyframe_seen(0),
00042
00043 _pes_synced(false),
00044 _seen_sps(false),
00045
00046 _request_recording(false),
00047 _wait_for_keyframe_option(true),
00048 _has_written_other_keyframe(false),
00049
00050 _recording(false),
00051 _error(false),
00052
00053 _buffer(0), _buffer_size(0),
00054
00055 _buffer_packets(false),
00056
00057 _frames_seen_count(0), _frames_written_count(0)
00058 {
00059 SetPositionMapType(MARK_GOP_BYFRAME);
00060 }
00061
00062 DTVRecorder::~DTVRecorder()
00063 {
00064 }
00065
00066 void DTVRecorder::SetOption(const QString &name, const QString &value)
00067 {
00068 if (name == "recordingtype")
00069 _recording_type = QDeepCopy<QString>(value);
00070 else
00071 RecorderBase::SetOption(name, value);
00072 }
00073
00077 void DTVRecorder::SetOption(const QString &name, int value)
00078 {
00079 if (name == "wait_for_seqstart")
00080 _wait_for_keyframe_option = (value == 1);
00081 else if (name == "pkt_buf_size")
00082 {
00083 if (_request_recording)
00084 {
00085 VERBOSE(VB_IMPORTANT, LOC_ERR +
00086 "Attempt made to resize packet buffer while recording.");
00087 return;
00088 }
00089 int newsize = max(value - (value % TSPacket::SIZE), TSPacket::SIZE*50);
00090 unsigned char* newbuf = new unsigned char[newsize];
00091 if (newbuf) {
00092 memcpy(newbuf, _buffer, min(_buffer_size, newsize));
00093 memset(newbuf+_buffer_size, 0xFF, max(newsize-_buffer_size, 0));
00094 _buffer = newbuf;
00095 _buffer_size = newsize;
00096 }
00097 else
00098 VERBOSE(VB_IMPORTANT, LOC_ERR +
00099 "Could not allocate new packet buffer.");
00100 }
00101 }
00102
00107 void DTVRecorder::FinishRecording(void)
00108 {
00109 if (ringBuffer)
00110 {
00111 if (_payload_buffer.size())
00112 {
00113 ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size());
00114 _payload_buffer.clear();
00115 }
00116 ringBuffer->WriterFlush();
00117 }
00118
00119 if (curRecording)
00120 {
00121 if (ringBuffer)
00122 curRecording->SetFilesize(ringBuffer->GetRealFileSize());
00123 SavePositionMap(true);
00124 }
00125 positionMapLock.lock();
00126 positionMap.clear();
00127 positionMapDelta.clear();
00128 positionMapLock.unlock();
00129 }
00130
00131
00132 long long DTVRecorder::GetKeyframePosition(long long desired)
00133 {
00134 QMutexLocker locker(&positionMapLock);
00135 long long ret = -1;
00136
00137 if (positionMap.find(desired) != positionMap.end())
00138 ret = positionMap[desired];
00139
00140 return ret;
00141 }
00142
00143 void DTVRecorder::ResetForNewFile(void)
00144 {
00145 VERBOSE(VB_RECORD, LOC + "ResetForNewFile(void)");
00146 QMutexLocker locker(&positionMapLock);
00147
00148
00149 _first_keyframe =-1;
00150 _has_written_other_keyframe = false;
00151 _last_keyframe_seen = 0;
00152 _last_gop_seen = 0;
00153 _last_seq_seen = 0;
00154
00155 _error = false;
00156
00157
00158 _frames_seen_count = 0;
00159 _frames_written_count = 0;
00160 _pes_synced = false;
00161 _seen_sps = false;
00162 _h264_kf_seq.Reset();
00163 positionMap.clear();
00164 positionMapDelta.clear();
00165 _payload_buffer.clear();
00166 }
00167
00168
00169 void DTVRecorder::Reset(void)
00170 {
00171 VERBOSE(VB_RECORD, LOC + "Reset(void)");
00172 ResetForNewFile();
00173
00174 _start_code = 0xffffffff;
00175
00176 if (curRecording)
00177 curRecording->ClearPositionMap(MARK_GOP_BYFRAME);
00178 }
00179
00180 void DTVRecorder::BufferedWrite(const TSPacket &tspacket)
00181 {
00182
00183 if (_wait_for_keyframe_option && _first_keyframe<0)
00184 return;
00185
00186
00187 if (_buffer_packets)
00188 {
00189 int idx = _payload_buffer.size();
00190 _payload_buffer.resize(idx + TSPacket::SIZE);
00191 memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::SIZE);
00192 return;
00193 }
00194
00195
00196
00197 if (!_payload_buffer.empty())
00198 {
00199 if (ringBuffer)
00200 ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size());
00201 _payload_buffer.clear();
00202 }
00203
00204 if (ringBuffer)
00205 ringBuffer->Write(tspacket.data(), TSPacket::SIZE);
00206 }
00207
00234 bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket)
00235 {
00236 bool haveBufferedData = !_payload_buffer.empty();
00237 if (!tspacket->HasPayload())
00238 return !haveBufferedData;
00239
00240 if (!ringBuffer)
00241 return !haveBufferedData;
00242
00243
00244
00245
00246 const bool payloadStart = tspacket->PayloadStart();
00247 _start_code = (payloadStart) ? 0xffffffff : _start_code;
00248
00249
00250 const uint maxKFD = kMaxKeyFrameDistance;
00251 bool hasFrame = false;
00252 bool hasKeyFrame = false;
00253
00254
00255
00256
00257
00258
00259
00260 const uint8_t *bufptr = tspacket->data() + tspacket->AFCOffset();
00261 const uint8_t *bufend = tspacket->data() + TSPacket::SIZE;
00262
00263 while (bufptr < bufend)
00264 {
00265 bufptr = ff_find_start_code(bufptr, bufend, &_start_code);
00266 if ((_start_code & 0xffffff00) == 0x00000100)
00267 {
00268
00269
00270 const int stream_id = _start_code & 0x000000ff;
00271 if (PESStreamID::PictureStartCode == stream_id)
00272 hasFrame = true;
00273 else if (PESStreamID::GOPStartCode == stream_id)
00274 {
00275 _last_gop_seen = _frames_seen_count;
00276 hasKeyFrame |= true;
00277 }
00278 else if (PESStreamID::SequenceStartCode == stream_id)
00279 {
00280 _last_seq_seen = _frames_seen_count;
00281 hasKeyFrame |= (_last_gop_seen + maxKFD)<_frames_seen_count;
00282 }
00283 }
00284 }
00285
00286 if (hasFrame && !hasKeyFrame)
00287 {
00288
00289
00290
00291
00292 hasKeyFrame = !(_frames_seen_count & 0xf);
00293 hasKeyFrame &= (_last_gop_seen + maxKFD) < _frames_seen_count;
00294 hasKeyFrame &= (_last_seq_seen + maxKFD) < _frames_seen_count;
00295 }
00296
00297 if (hasKeyFrame)
00298 {
00299 _last_keyframe_seen = _frames_seen_count;
00300 HandleKeyframe();
00301 }
00302
00303 if (hasFrame)
00304 {
00305 _frames_seen_count++;
00306 if (!_wait_for_keyframe_option || _first_keyframe>=0)
00307 _frames_written_count++;
00308 }
00309
00310 return hasKeyFrame || (_payload_buffer.size() >= (188*50));
00311 }
00312
00313 bool DTVRecorder::FindAudioKeyframes(const TSPacket*)
00314 {
00315 bool hasKeyFrame = false;
00316 if (!ringBuffer || (GetStreamData()->VideoPIDSingleProgram() <= 0x1fff))
00317 return hasKeyFrame;
00318
00319 static const uint64_t msec_per_day = 24 * 60 * 60 * 1000ULL;
00320 const double frame_interval = (1000.0 / video_frame_rate);
00321 uint64_t elapsed = (uint64_t) max(_audio_timer.elapsed(), 0);
00322 uint64_t expected_frame =
00323 (uint64_t) ((double)elapsed / frame_interval);
00324
00325 while (_frames_seen_count > expected_frame + 10000)
00326 expected_frame += (uint64_t) ((double)msec_per_day / frame_interval);
00327
00328 if (!_frames_seen_count || (_frames_seen_count < expected_frame))
00329 {
00330 if (!_frames_seen_count)
00331 _audio_timer.start();
00332
00333 _frames_seen_count++;
00334
00335 if (1 == (_frames_seen_count & 0x7))
00336 {
00337 _last_keyframe_seen = _frames_seen_count;
00338 HandleKeyframe();
00339 hasKeyFrame = true;
00340 }
00341
00342 if (!_wait_for_keyframe_option || _first_keyframe>=0)
00343 _frames_written_count++;
00344 }
00345
00346 return hasKeyFrame;
00347 }
00348
00351 bool DTVRecorder::FindOtherKeyframes(const TSPacket *tspacket)
00352 {
00353 if (!ringBuffer || (GetStreamData()->VideoPIDSingleProgram() <= 0x1fff))
00354 return true;
00355
00356 if (_has_written_other_keyframe)
00357 return true;
00358
00359 VERBOSE(VB_RECORD, LOC + "DSMCC - FindOtherKeyframes() - "
00360 "generating initial key-frame");
00361
00362 _frames_seen_count++;
00363 _frames_written_count++;
00364 _last_keyframe_seen = _frames_seen_count;
00365
00366 HandleKeyframe();
00367
00368 _has_written_other_keyframe = true;
00369
00370 return true;
00371 }
00372
00373
00374 void DTVRecorder::SetNextRecording(const ProgramInfo *progInf, RingBuffer *rb)
00375 {
00376 VERBOSE(VB_RECORD, LOC + "SetNextRecord("<<progInf<<", "<<rb<<")");
00377
00378 SavePositionMap(true);
00379 if (ringBuffer)
00380 {
00381 ringBuffer->WriterFlush();
00382 if (curRecording)
00383 curRecording->SetFilesize(ringBuffer->GetRealFileSize());
00384 }
00385
00386
00387 nextRingBufferLock.lock();
00388
00389 nextRecording = NULL;
00390 if (progInf)
00391 nextRecording = new ProgramInfo(*progInf);
00392
00393 nextRingBuffer = rb;
00394 nextRingBufferLock.unlock();
00395 }
00396
00401 void DTVRecorder::HandleKeyframe(void)
00402 {
00403 if (!ringBuffer)
00404 return;
00405
00406 unsigned long long frameNum = _frames_written_count;
00407
00408 _first_keyframe = (_first_keyframe < 0) ? frameNum : _first_keyframe;
00409
00410
00411 positionMapLock.lock();
00412 if (!positionMap.contains(frameNum))
00413 {
00414 long long startpos = ringBuffer->GetWritePosition();
00415
00416 startpos += _payload_buffer.size();
00417 positionMapDelta[frameNum] = startpos;
00418 positionMap[frameNum] = startpos;
00419 }
00420 positionMapLock.unlock();
00421
00422
00423 CheckForRingBufferSwitch();
00424 }
00425
00431 bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)
00432 {
00433 if (!ringBuffer)
00434 return false;
00435
00436 bool haveBufferedData = !_payload_buffer.empty();
00437 if (!tspacket->HasPayload())
00438 return !haveBufferedData;
00439
00440 const bool payloadStart = tspacket->PayloadStart();
00441 if (payloadStart)
00442 {
00443
00444 _pes_synced = false;
00445 _start_code = 0xffffffff;
00446 }
00447
00448 bool hasFrame = false;
00449 bool hasKeyFrame = false;
00450
00451
00452 uint i = tspacket->AFCOffset();
00453 for (; i < TSPacket::SIZE; i++)
00454 {
00455
00456 if (payloadStart && !_pes_synced)
00457 {
00458
00459 if (i + 2 >= TSPacket::SIZE)
00460 {
00461 VERBOSE(VB_IMPORTANT, LOC_ERR +
00462 "PES packet start code may overflow to next TS packet, aborting keyframe search");
00463 break;
00464 }
00465
00466
00467 if (tspacket->data()[i++] != 0x00 ||
00468 tspacket->data()[i++] != 0x00 ||
00469 tspacket->data()[i++] != 0x01)
00470 {
00471 VERBOSE(VB_IMPORTANT, LOC_ERR +
00472 "PES start code not found in TS packet with PUSI set");
00473 break;
00474 }
00475
00476
00477 if (i + 5 >= TSPacket::SIZE)
00478 {
00479 VERBOSE(VB_IMPORTANT, LOC_ERR +
00480 "PES packet headers overflow to next TS packet, aborting keyframe search");
00481 break;
00482 }
00483
00484
00485
00486
00487
00488
00489
00490 const unsigned char pes_header_length = tspacket->data()[i + 5];
00491
00492
00493 if ((i + 6 + pes_header_length) >= TSPacket::SIZE)
00494 {
00495 VERBOSE(VB_IMPORTANT, LOC_ERR +
00496 "PES packet headers overflow to next TS packet, aborting keyframe search");
00497 break;
00498 }
00499
00500
00501
00502 i += 5 + pes_header_length;
00503 _pes_synced = true;
00504
00505
00506 continue;
00507 }
00508
00509
00510 if (!_pes_synced)
00511 break;
00512
00513
00514 uint32_t bytes_used = _h264_kf_seq.AddBytes(tspacket->data() + i,
00515 TSPacket::SIZE - i,
00516 ringBuffer->GetWritePosition());
00517 i += (bytes_used - 1);
00518
00519
00520 if (_h264_kf_seq.HasStateChanged())
00521 {
00522 if (_h264_kf_seq.LastSyncedType() == H264::NALUnitType::SPS)
00523 _seen_sps = true;
00524
00525 if (_h264_kf_seq.IsOnKeyframe())
00526 {
00527 hasKeyFrame = true;
00528 hasFrame = true;
00529 }
00530
00531 if (_h264_kf_seq.IsOnFrame())
00532 hasFrame = true;
00533 }
00534 }
00535
00536 if (hasKeyFrame)
00537 {
00538 _last_keyframe_seen = _frames_seen_count;
00539 HandleH264Keyframe();
00540 }
00541
00542 if (hasFrame)
00543 {
00544 _frames_seen_count++;
00545 if (!_wait_for_keyframe_option || _first_keyframe >= 0)
00546 _frames_written_count++;
00547 }
00548
00549 return hasKeyFrame || (_payload_buffer.size() >= (188*50));
00550 }
00551
00556 void DTVRecorder::HandleH264Keyframe(void)
00557 {
00558 unsigned long long frameNum = _frames_written_count;
00559
00560 _first_keyframe = (_first_keyframe < 0) ? frameNum : _first_keyframe;
00561
00562
00563 positionMapLock.lock();
00564 if (!positionMap.contains(frameNum))
00565 {
00566 positionMapDelta[frameNum] = _h264_kf_seq.KeyframeAUStreamOffset();
00567 positionMap[frameNum] = _h264_kf_seq.KeyframeAUStreamOffset();
00568 }
00569 positionMapLock.unlock();
00570
00571
00572 CheckForRingBufferSwitch();
00573 }
00574
00575