MythTV  0.26-pre
dtvrecorder.cpp
Go to the documentation of this file.
00001 
00021 #include "atscstreamdata.h"
00022 #include "mpegstreamdata.h"
00023 #include "dvbstreamdata.h"
00024 #include "dtvrecorder.h"
00025 #include "programinfo.h"
00026 #include "mythlogging.h"
00027 #include "mpegtables.h"
00028 #include "ringbuffer.h"
00029 #include "tv_rec.h"
00030 
00031 extern "C" {
00032 #include "libavcodec/mpegvideo.h"
00033 }
00034 
00035 #define LOC ((tvrec) ? \
00036     QString("DTVRec(%1): ").arg(tvrec->GetCaptureCardNum()) : \
00037     QString("DTVRec(0x%1): ").arg(intptr_t(this),0,16))
00038 
00039 const uint DTVRecorder::kMaxKeyFrameDistance = 80;
00040 
00049 DTVRecorder::DTVRecorder(TVRec *rec) :
00050     RecorderBase(rec),
00051     // file handle for stream
00052     _stream_fd(-1),
00053     _recording_type("all"),
00054     // used for scanning pes headers for keyframes
00055     _start_code(0xffffffff),        _first_keyframe(-1),
00056     _last_gop_seen(0),              _last_seq_seen(0),
00057     _last_keyframe_seen(0),
00058     _audio_bytes_remaining(0),      _video_bytes_remaining(0),
00059     _other_bytes_remaining(0),
00060     // MPEG2 parser information
00061     _progressive_sequence(0),
00062     _repeat_pict(0),
00063     // H.264 support
00064     _pes_synced(false),
00065     _seen_sps(false),
00066     // settings
00067     _wait_for_keyframe_option(true),
00068     _has_written_other_keyframe(false),
00069     // state
00070     _error(),
00071     _stream_data(NULL),
00072     // TS packet buffer
00073     // keyframe TS buffer
00074     _buffer_packets(false),
00075     // general recorder stuff
00076     _pid_lock(QMutex::Recursive),
00077     _input_pat(NULL),
00078     _input_pmt(NULL),
00079     _has_no_av(false),
00080     // statistics
00081     _use_pts(false),
00082     _packet_count(0),
00083     _continuity_error_count(0),
00084     _frames_seen_count(0),          _frames_written_count(0)
00085 {
00086     SetPositionMapType(MARK_GOP_BYFRAME);
00087     _payload_buffer.reserve(TSPacket::kSize * (50 + 1));
00088     ResetForNewFile();
00089 }
00090 
00091 DTVRecorder::~DTVRecorder()
00092 {
00093     StopRecording();
00094 
00095     SetStreamData(NULL);
00096 
00097     if (_input_pat)
00098     {
00099         delete _input_pat;
00100         _input_pat = NULL;
00101     }
00102 
00103     if (_input_pmt)
00104     {
00105         delete _input_pmt;
00106         _input_pmt = NULL;
00107     }
00108 }
00109 
00110 void DTVRecorder::SetOption(const QString &name, const QString &value)
00111 {
00112     if (name == "recordingtype")
00113     {
00114         _recording_type = value;
00115         _recording_type.detach();
00116     }
00117     else
00118         RecorderBase::SetOption(name, value);
00119 }
00120 
00124 void DTVRecorder::SetOption(const QString &name, int value)
00125 {
00126     if (name == "wait_for_seqstart")
00127         _wait_for_keyframe_option = (value == 1);
00128     else
00129         RecorderBase::SetOption(name, value);
00130 }
00131 
00132 void DTVRecorder::SetOptionsFromProfile(RecordingProfile *profile,
00133                                         const QString &videodev,
00134                                         const QString&, const QString&)
00135 {
00136     SetOption("videodevice", videodev);
00137     DTVRecorder::SetOption("tvformat", gCoreContext->GetSetting("TVFormat"));
00138     SetStrOption(profile, "recordingtype");
00139 }
00140 
00145 void DTVRecorder::FinishRecording(void)
00146 {
00147     if (ringBuffer)
00148     {
00149         if (!_payload_buffer.empty())
00150         {
00151             ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size());
00152             _payload_buffer.clear();
00153         }
00154         ringBuffer->WriterFlush();
00155     }
00156 
00157     if (curRecording)
00158     {
00159         if (ringBuffer)
00160             curRecording->SaveFilesize(ringBuffer->GetRealFileSize());
00161         SavePositionMap(true);
00162     }
00163 }
00164 
00165 void DTVRecorder::ResetForNewFile(void)
00166 {
00167     LOG(VB_RECORD, LOG_INFO, LOC + "ResetForNewFile(void)");
00168     QMutexLocker locker(&positionMapLock);
00169 
00170     // _first_keyframe, _seen_psp and m_h264_parser should
00171     // not be reset here. This will only be called just as
00172     // we're seeing the first packet of a new keyframe for
00173     // writing to the new file and anything that makes the
00174     // recorder think we're waiting on another keyframe will
00175     // send significant amounts of good data to /dev/null.
00176     // -- Daniel Kristjansson 2011-02-26
00177 
00178     _start_code                 = 0xffffffff;
00179     //_first_keyframe
00180     _has_written_other_keyframe = false;
00181     _last_keyframe_seen         = 0;
00182     _last_gop_seen              = 0;
00183     _last_seq_seen              = 0;
00184     _audio_bytes_remaining      = 0;
00185     _video_bytes_remaining      = 0;
00186     _other_bytes_remaining      = 0;
00187     //_recording
00188     _error                      = QString();
00189 
00190     memset(_stream_id,  0, sizeof(_stream_id));
00191     memset(_pid_status, 0, sizeof(_pid_status));
00192     memset(_continuity_counter, 0xff, sizeof(_continuity_counter));
00193 
00194     _progressive_sequence       = 0;
00195     _repeat_pict                = 0;
00196 
00197     _pes_synced                 = false;
00198     //_seen_sps
00199     positionMap.clear();
00200     positionMapDelta.clear();
00201     _payload_buffer.clear();
00202 
00203     locker.unlock();
00204     ClearStatistics();
00205 }
00206 
00207 void DTVRecorder::ClearStatistics(void)
00208 {
00209     RecorderBase::ClearStatistics();
00210 
00211     memset(_ts_count, 0, sizeof(_ts_count));
00212     for (int i = 0; i < 256; i++)
00213         _ts_last[i] = -1LL;
00214     for (int i = 0; i < 256; i++)
00215         _ts_first[i] = -1LL;
00216     //_ts_first_dt -- doesn't need to be cleared only used if _ts_first>=0
00217     _packet_count.fetchAndStoreRelaxed(0);
00218     _continuity_error_count.fetchAndStoreRelaxed(0);
00219     _frames_seen_count          = 0;
00220     _frames_written_count       = 0;
00221 }
00222 
00223 // documented in recorderbase.h
00224 void DTVRecorder::Reset(void)
00225 {
00226     LOG(VB_RECORD, LOG_INFO, LOC + "Reset(void)");
00227     ResetForNewFile();
00228 
00229     _start_code = 0xffffffff;
00230 
00231     if (curRecording)
00232         curRecording->ClearPositionMap(MARK_GOP_BYFRAME);
00233 }
00234 
00235 void DTVRecorder::SetStreamData(MPEGStreamData *data)
00236 {
00237     if (data == _stream_data)
00238         return;
00239 
00240     MPEGStreamData *old_data = _stream_data;
00241     _stream_data = data;
00242     if (old_data)
00243         delete old_data;
00244 
00245     if (_stream_data)
00246         SetStreamData();
00247 }
00248 
00249 void DTVRecorder::SetStreamData(void)
00250 {
00251     _stream_data->AddMPEGSPListener(this);
00252     _stream_data->AddMPEGListener(this);
00253 
00254     DVBStreamData *dvb = dynamic_cast<DVBStreamData*>(_stream_data);
00255     if (dvb)
00256         dvb->AddDVBMainListener(this);
00257 
00258     ATSCStreamData *atsc = dynamic_cast<ATSCStreamData*>(_stream_data);
00259 
00260     if (atsc && atsc->DesiredMinorChannel())
00261         atsc->SetDesiredChannel(atsc->DesiredMajorChannel(),
00262                                 atsc->DesiredMinorChannel());
00263     else if (_stream_data->DesiredProgram() >= 0)
00264         _stream_data->SetDesiredProgram(_stream_data->DesiredProgram());
00265 }
00266 
00267 void DTVRecorder::BufferedWrite(const TSPacket &tspacket)
00268 {
00269     // delay until first GOP to avoid decoder crash on res change
00270     if (_wait_for_keyframe_option && _first_keyframe<0)
00271         return;
00272 
00273     if (curRecording && timeOfFirstDataIsSet.testAndSetRelaxed(0,1))
00274     {
00275         QMutexLocker locker(&statisticsLock);
00276         timeOfFirstData = mythCurrentDateTime();
00277         timeOfLatestData = mythCurrentDateTime();
00278         timeOfLatestDataTimer.start();
00279     }
00280 
00281     int val = timeOfLatestDataCount.fetchAndAddRelaxed(1);
00282     int thresh = timeOfLatestDataPacketInterval.fetchAndAddRelaxed(0);
00283     if (val > thresh)
00284     {
00285         QMutexLocker locker(&statisticsLock);
00286         uint elapsed = timeOfLatestDataTimer.restart();
00287         int interval = thresh;
00288         if (elapsed > kTimeOfLatestDataIntervalTarget + 250)
00289             interval = timeOfLatestDataPacketInterval
00290                 .fetchAndStoreRelaxed(thresh * 4 / 5);
00291         else if (elapsed + 250 < kTimeOfLatestDataIntervalTarget)
00292             interval = timeOfLatestDataPacketInterval
00293                 .fetchAndStoreRelaxed(thresh * 9 / 8);
00294 
00295         timeOfLatestDataCount.fetchAndStoreRelaxed(1);
00296         timeOfLatestData = mythCurrentDateTime();
00297 
00298         LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Updating timeOfLatestData ") +
00299             QString("elapsed(%1) interval(%2)")
00300             .arg(elapsed).arg(interval));
00301     }
00302 
00303     // Do we have to buffer the packet for exact keyframe detection?
00304     if (_buffer_packets)
00305     {
00306         int idx = _payload_buffer.size();
00307         _payload_buffer.resize(idx + TSPacket::kSize);
00308         memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::kSize);
00309         return;
00310     }
00311 
00312     // We are free to write the packet, but if we have buffered packet[s]
00313     // we have to write them first...
00314     if (!_payload_buffer.empty())
00315     {
00316         if (ringBuffer)
00317             ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size());
00318         _payload_buffer.clear();
00319     }
00320 
00321     if (ringBuffer)
00322         ringBuffer->Write(tspacket.data(), TSPacket::kSize);
00323 }
00324 
00325 enum { kExtractPTS, kExtractDTS };
00326 static int64_t extract_timestamp(
00327     const uint8_t *bufptr, int bytes_left, int pts_or_dts)
00328 {
00329     if (bytes_left < 4)
00330         return -1LL;
00331 
00332     bool has_pts = bufptr[3] & 0x80;
00333     int offset = 5;
00334     if (((kExtractPTS == pts_or_dts) && !has_pts) || (offset + 5 > bytes_left))
00335         return -1LL;
00336 
00337     bool has_dts = bufptr[3] & 0x40;
00338     if (kExtractDTS == pts_or_dts)
00339     {
00340         if (!has_dts)
00341             return -1LL;
00342         offset += has_pts ? 5 : 0;
00343         if (offset + 5 > bytes_left)
00344             return -1LL;
00345     }
00346 
00347     return ((uint64_t(bufptr[offset+0] & 0x0e) << 29) |
00348             (uint64_t(bufptr[offset+1]       ) << 22) |
00349             (uint64_t(bufptr[offset+2] & 0xfe) << 14) |
00350             (uint64_t(bufptr[offset+3]       ) <<  7) |
00351             (uint64_t(bufptr[offset+4] & 0xfe) >>  1));
00352 }
00353 
00354 static QDateTime ts_to_qdatetime(
00355     uint64_t pts, uint64_t pts_first, QDateTime &pts_first_dt)
00356 {
00357     if (pts < pts_first)
00358         pts += 0x1FFFFFFFFLL;
00359     QDateTime dt = pts_first_dt;
00360     return dt.addMSecs((pts - pts_first)/90);
00361 }
00362 
00363 static const uint frameRateMap[16] = {
00364     0, 23796, 24000, 25000, 29970, 30000, 50000, 59940, 60000, 
00365     0, 0, 0, 0, 0, 0, 0 
00366 };
00367 
00394 bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket)
00395 {
00396     bool haveBufferedData = !_payload_buffer.empty();
00397     if (!tspacket->HasPayload()) // no payload to scan
00398         return !haveBufferedData;
00399 
00400     if (!ringBuffer)
00401         return !haveBufferedData;
00402 
00403     // if packet contains start of PES packet, start
00404     // looking for first byte of MPEG start code (3 bytes 0 0 1)
00405     // otherwise, pick up search where we left off.
00406     const bool payloadStart = tspacket->PayloadStart();
00407     _start_code = (payloadStart) ? 0xffffffff : _start_code;
00408 
00409     // Just make these local for efficiency reasons (gcc not so smart..)
00410     const uint maxKFD = kMaxKeyFrameDistance;
00411     bool hasFrame     = false;
00412     bool hasKeyFrame  = false;
00413 
00414     uint aspectRatio = 0;
00415     uint height = 0;
00416     uint width = 0;
00417     uint frameRate = 0;
00418 
00419     // Scan for PES header codes; specifically picture_start
00420     // sequence_start (SEQ) and group_start (GOP).
00421     //   00 00 01 00: picture_start_code
00422     //   00 00 01 B8: group_start_code
00423     //   00 00 01 B3: seq_start_code
00424     //   00 00 01 B5: ext_start_code
00425     //   (there are others that we don't care about)
00426     const uint8_t *bufptr = tspacket->data() + tspacket->AFCOffset();
00427     const uint8_t *bufend = tspacket->data() + TSPacket::kSize;
00428     int ext_type, bytes_left;
00429     int picture_structure, top_field_first, repeat_first_field, progressive_frame;
00430     _repeat_pict = 0;
00431 
00432     while (bufptr < bufend)
00433     {
00434         bufptr = avpriv_mpv_find_start_code(bufptr, bufend, &_start_code);
00435         bytes_left = bufend - bufptr;
00436         if ((_start_code & 0xffffff00) == 0x00000100)
00437         {
00438             // At this point we have seen the start code 0 0 1
00439             // the next byte will be the PES packet stream id.
00440             const int stream_id = _start_code & 0x000000ff;
00441             if (PESStreamID::PictureStartCode == stream_id)
00442                 hasFrame = true;
00443             else if (PESStreamID::GOPStartCode == stream_id)
00444             {
00445                 _last_gop_seen  = _frames_seen_count;
00446                 hasKeyFrame    |= true;
00447             }
00448             else if (PESStreamID::SequenceStartCode == stream_id)
00449             {
00450                 _last_seq_seen  = _frames_seen_count;
00451                 hasKeyFrame    |= (_last_gop_seen + maxKFD)<_frames_seen_count;
00452 
00453                 // Look for aspectRatio changes and store them in the database
00454                 aspectRatio = (bufptr[3] >> 4);
00455 
00456                 // Get resolution
00457                 height = ((bufptr[1] & 0xf) << 8) | bufptr[2];
00458                 width = (bufptr[0] <<4) | (bufptr[1]>>4);
00459 
00460                 frameRate = frameRateMap[(bufptr[3] & 0x0000000f)];
00461             }
00462             else if (PESStreamID::MPEG2ExtensionStartCode == stream_id)
00463             {
00464                 if (bytes_left >= 1) 
00465                 {
00466                     ext_type = (bufptr[0] >> 4);
00467                     switch(ext_type)
00468                     {
00469                     case 0x1: /* sequence extension */
00470                         if (bytes_left >= 6)
00471                         {
00472                             _progressive_sequence = bufptr[1] & (1 << 3);
00473                         }
00474                         break;
00475                     case 0x8: /* picture coding extension */
00476                         if (bytes_left >= 5)
00477                         {
00478                             picture_structure = bufptr[2]&3;
00479                             top_field_first = bufptr[3] & (1 << 7);
00480                             repeat_first_field = bufptr[3] & (1 << 1);
00481                             progressive_frame = bufptr[4] & (1 << 7);
00482 
00483                             /* check if we must repeat the frame */
00484                             _repeat_pict = 1;
00485                             if (repeat_first_field) 
00486                             {
00487                                 if (_progressive_sequence)
00488                                 {
00489                                     if (top_field_first)
00490                                         _repeat_pict = 5;
00491                                     else
00492                                         _repeat_pict = 3;
00493                                 }
00494                                 else if (progressive_frame) 
00495                                 {
00496                                     _repeat_pict = 2;
00497                                 }
00498                             }
00499                         }
00500                         break;
00501                     }
00502                 }
00503             }
00504             if ((stream_id >= PESStreamID::MPEGVideoStreamBegin) &&
00505                 (stream_id <= PESStreamID::MPEGVideoStreamEnd))
00506             {
00507                 int64_t pts = extract_timestamp(
00508                     bufptr, bytes_left, kExtractPTS);
00509                 int64_t dts = extract_timestamp(
00510                     bufptr, bytes_left, kExtractPTS);
00511                 HandleTimestamps(stream_id, pts, dts);
00512             }
00513         }
00514     }
00515 
00516     if (hasFrame && !hasKeyFrame)
00517     {
00518         // If we have seen kMaxKeyFrameDistance frames since the
00519         // last GOP or SEQ stream_id, then pretend this picture
00520         // is a keyframe. We may get artifacts but at least
00521         // we will be able to skip frames.
00522         hasKeyFrame = !(_frames_seen_count & 0xf);
00523         hasKeyFrame &= (_last_gop_seen + maxKFD) < _frames_seen_count;
00524         hasKeyFrame &= (_last_seq_seen + maxKFD) < _frames_seen_count;
00525     }
00526 
00527     if (hasKeyFrame)
00528     {
00529         _last_keyframe_seen = _frames_seen_count;
00530         HandleKeyframe(_frames_written_count, TSPacket::kSize);
00531     }
00532 
00533     if (hasFrame)
00534     {
00535         _frames_seen_count++;
00536         if (!_wait_for_keyframe_option || _first_keyframe>=0)
00537             _frames_written_count++;
00538     }
00539 
00540     if ((aspectRatio > 0) && (aspectRatio != m_videoAspect))
00541     {
00542         m_videoAspect = aspectRatio;
00543         AspectChange((AspectRatio)aspectRatio, _frames_written_count);
00544     }
00545 
00546     if (height && width && (height != m_videoHeight || m_videoWidth != width))
00547     {
00548         m_videoHeight = height;
00549         m_videoWidth = width;
00550         ResolutionChange(width, height, _frames_written_count);
00551     }
00552 
00553     if (frameRate && frameRate != m_frameRate)
00554     {
00555         m_frameRate = frameRate;
00556         LOG(VB_RECORD, LOG_INFO, LOC +
00557             QString("FindMPEG2Keyframes: frame rate = %1") .arg(frameRate));
00558         FrameRateChange(frameRate, _frames_written_count);
00559     }
00560 
00561     return hasKeyFrame || (_payload_buffer.size() >= (188*50));
00562 }
00563 
00564 void DTVRecorder::HandleTimestamps(int stream_id, int64_t pts, int64_t dts)
00565 {
00566     if (pts < 0)
00567     {
00568         _ts_last[stream_id] = -1;
00569         return;
00570     }
00571 
00572     if ((dts < 0) && !_use_pts)
00573     {
00574         _ts_last[stream_id] = -1;
00575         _use_pts = true;
00576         LOG(VB_RECORD, LOG_DEBUG,
00577             "Switching from dts tracking to pts tracking." +
00578             QString("TS count is %1").arg(_ts_count[stream_id]));
00579     }
00580 
00581     int64_t ts = dts;
00582     int64_t gap_threshold = 90000; // 1 second
00583     if (_use_pts)
00584     {
00585         ts = dts;
00586         gap_threshold = 2*90000; // two seconds, compensate for GOP ordering
00587     }
00588 
00589     if (_ts_last[stream_id] >= 0)
00590     {
00591         int64_t diff = ts - _ts_last[stream_id];
00592         if ((diff < 0) && (diff < (10 * -90000)))
00593             diff += 0x1ffffffffLL;
00594         if (diff < 0)
00595             diff = -diff;
00596         if (diff > gap_threshold)
00597         {
00598             QMutexLocker locker(&statisticsLock);
00599             recordingGaps.push_back(
00600                 RecordingGap(
00601                     ts_to_qdatetime(
00602                         _ts_last[stream_id], _ts_first[stream_id],
00603                         _ts_first_dt[stream_id]),
00604                     ts_to_qdatetime(
00605                         ts, _ts_first[stream_id], _ts_first_dt[stream_id])));
00606             LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Inserted gap %1 dur %2")
00607                 .arg(recordingGaps.back().toString()).arg(diff/90000.0));
00608         }
00609     }
00610 
00611     _ts_last[stream_id] = ts;
00612 
00613     if (_ts_count[stream_id] < 30)
00614     {
00615         if (!_ts_count[stream_id])
00616         {
00617             _ts_first[stream_id] = ts;
00618             _ts_first_dt[stream_id] = mythCurrentDateTime();
00619         }
00620         else if (ts < _ts_first[stream_id])
00621         {
00622             _ts_first[stream_id] = ts;
00623             _ts_first_dt[stream_id] = mythCurrentDateTime();
00624         }
00625     }
00626 
00627     _ts_count[stream_id]++;
00628 }
00629 
00630 bool DTVRecorder::FindAudioKeyframes(const TSPacket*)
00631 {
00632     bool hasKeyFrame = false;
00633     if (!ringBuffer || (GetStreamData()->VideoPIDSingleProgram() <= 0x1fff))
00634         return hasKeyFrame;
00635 
00636     static const uint64_t msec_per_day = 24 * 60 * 60 * 1000ULL;
00637     const double frame_interval = (1000.0 / video_frame_rate);
00638     uint64_t elapsed = (uint64_t) max(_audio_timer.elapsed(), 0);
00639     uint64_t expected_frame =
00640         (uint64_t) ((double)elapsed / frame_interval);
00641 
00642     while (_frames_seen_count > expected_frame + 10000)
00643         expected_frame += (uint64_t) ((double)msec_per_day / frame_interval);
00644 
00645     if (!_frames_seen_count || (_frames_seen_count < expected_frame))
00646     {
00647         if (!_frames_seen_count)
00648             _audio_timer.start();
00649 
00650         _frames_seen_count++;
00651 
00652         if (1 == (_frames_seen_count & 0x7))
00653         {
00654             _last_keyframe_seen = _frames_seen_count;
00655             HandleKeyframe(_frames_written_count);
00656             hasKeyFrame = true;
00657         }
00658 
00659         if (!_wait_for_keyframe_option || _first_keyframe>=0)
00660             _frames_written_count++;
00661     }
00662 
00663     return hasKeyFrame;
00664 }
00665 
00668 bool DTVRecorder::FindOtherKeyframes(const TSPacket *tspacket)
00669 {
00670     if (!ringBuffer || (GetStreamData()->VideoPIDSingleProgram() <= 0x1fff))
00671         return true;
00672 
00673     if (_has_written_other_keyframe)
00674         return true;
00675 
00676     LOG(VB_RECORD, LOG_INFO, LOC + "DSMCC - FindOtherKeyframes() - "
00677             "generating initial key-frame");
00678 
00679     _frames_seen_count++;
00680     _frames_written_count++;
00681     _last_keyframe_seen = _frames_seen_count;
00682 
00683     HandleKeyframe(_frames_written_count);
00684 
00685     _has_written_other_keyframe = true;
00686 
00687     return true;
00688 }
00689 
00690 // documented in recorderbase.h
00691 void DTVRecorder::SetNextRecording(const ProgramInfo *progInf, RingBuffer *rb)
00692 {
00693     LOG(VB_RECORD, LOG_INFO, LOC + QString("SetNextRecord(0x%1, 0x%2)")
00694             .arg((uint64_t)progInf,0,16).arg((uint64_t)rb,0,16));
00695     // First we do some of the time consuming stuff we can do now
00696     SavePositionMap(true);
00697     if (ringBuffer)
00698     {
00699         ringBuffer->WriterFlush();
00700         if (curRecording)
00701             curRecording->SaveFilesize(ringBuffer->GetRealFileSize());
00702     }
00703 
00704     // Then we set the next info
00705     nextRingBufferLock.lock();
00706 
00707     nextRecording = NULL;
00708     if (progInf)
00709         nextRecording = new ProgramInfo(*progInf);
00710 
00711     nextRingBuffer = rb;
00712     nextRingBufferLock.unlock();
00713 }
00714 
00719 void DTVRecorder::HandleKeyframe(uint64_t frameNum, int64_t extra)
00720 {
00721     if (!ringBuffer)
00722         return;
00723 
00724 #if 0
00725     unsigned long long frameNum = _frames_written_count;
00726 #endif
00727 
00728     _first_keyframe = (_first_keyframe < 0) ? frameNum : _first_keyframe;
00729 
00730     // Add key frame to position map
00731     positionMapLock.lock();
00732     if (!positionMap.contains(frameNum))
00733     {
00734         long long startpos = ringBuffer->GetWritePosition();
00735         // FIXME: handle keyframes with start code spanning over two ts packets
00736         startpos += _payload_buffer.size() - extra;
00737 
00738         // Don't put negative offsets into the database, they get munged into
00739         // MAX_INT64 - offset, which is an exceedingly large number, and
00740         // certainly not valid.
00741         if (startpos >= 0)
00742         {
00743             positionMapDelta[frameNum] = startpos;
00744             positionMap[frameNum]      = startpos;
00745         }
00746     }
00747     positionMapLock.unlock();
00748 
00749     // Perform ringbuffer switch if needed.
00750     CheckForRingBufferSwitch();
00751 }
00752 
00758 bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)
00759 {
00760     if (!ringBuffer)
00761     {
00762         LOG(VB_GENERAL, LOG_ERR, LOC + "FindH264Keyframes: No ringbuffer");
00763         return false;
00764     }
00765 
00766     bool haveBufferedData = !_payload_buffer.empty();
00767     if (!tspacket->HasPayload()) // no payload to scan
00768         return !haveBufferedData;
00769 
00770     const bool payloadStart = tspacket->PayloadStart();
00771     if (payloadStart)
00772     {
00773         // reset PES sync state
00774         _pes_synced = false;
00775         _start_code = 0xffffffff;
00776     }
00777 
00778     uint aspectRatio = 0;
00779     uint height = 0;
00780     uint width = 0;
00781     uint frameRate = 0;
00782 
00783     bool hasFrame = false;
00784     bool hasKeyFrame = false;
00785 
00786     // scan for PES packets and H.264 NAL units
00787     uint i = tspacket->AFCOffset();
00788     for (; i < TSPacket::kSize; i++)
00789     {
00790         // special handling required when a new PES packet begins
00791         if (payloadStart && !_pes_synced)
00792         {
00793             // bounds check
00794             if (i + 2 >= TSPacket::kSize)
00795             {
00796                 LOG(VB_GENERAL, LOG_ERR, LOC +
00797                     "PES packet start code may overflow to next TS packet, "
00798                     "aborting keyframe search");
00799                 break;
00800             }
00801 
00802             // must find the PES start code
00803             if (tspacket->data()[i++] != 0x00 ||
00804                 tspacket->data()[i++] != 0x00 ||
00805                 tspacket->data()[i++] != 0x01)
00806             {
00807                 LOG(VB_GENERAL, LOG_ERR, LOC +
00808                     "PES start code not found in TS packet with PUSI set");
00809                 break;
00810             }
00811 
00812             // bounds check
00813             if (i + 5 >= TSPacket::kSize)
00814             {
00815                 LOG(VB_GENERAL, LOG_ERR, LOC +
00816                     "PES packet headers overflow to next TS packet, "
00817                     "aborting keyframe search");
00818                 break;
00819             }
00820 
00821             // now we need to compute where the PES payload begins
00822             // skip past the stream_id (+1)
00823             // the next two bytes are the PES packet length (+2)
00824             // after that, one byte of PES packet control bits (+1)
00825             // after that, one byte of PES header flags bits (+1)
00826             // and finally, one byte for the PES header length
00827             const unsigned char pes_header_length = tspacket->data()[i + 5];
00828 
00829             // bounds check
00830             if ((i + 6 + pes_header_length) >= TSPacket::kSize)
00831             {
00832                 LOG(VB_GENERAL, LOG_ERR, LOC +
00833                     "PES packet headers overflow to next TS packet, "
00834                     "aborting keyframe search");
00835                 break;
00836             }
00837 
00838             // we now know where the PES payload is
00839             // normally, we should have used 6, but use 5 because the for 
00840             // loop will bump i
00841             i += 5 + pes_header_length;
00842             _pes_synced = true;
00843 
00844 #if 0
00845             LOG(VB_RECORD, LOG_DEBUG, LOC + "PES synced");
00846 #endif
00847             continue;
00848         }
00849 
00850         // ain't going nowhere if we're not PES synced
00851         if (!_pes_synced)
00852             break;
00853 
00854         // scan for a NAL unit start code
00855 
00856         uint32_t bytes_used = m_h264_parser.addBytes(
00857             tspacket->data() + i, TSPacket::kSize - i,
00858             ringBuffer->GetWritePosition() + _payload_buffer.size()
00859             );
00860         i += (bytes_used - 1);
00861 
00862         if (m_h264_parser.stateChanged())
00863         {
00864             if (m_h264_parser.onFrameStart() &&
00865                 m_h264_parser.FieldType() != H264Parser::FIELD_BOTTOM)
00866             {
00867                 hasKeyFrame = m_h264_parser.onKeyFrameStart();
00868                 hasFrame = true;
00869                 _seen_sps |= hasKeyFrame;
00870 
00871                 width = m_h264_parser.pictureWidth();
00872                 height = m_h264_parser.pictureHeight();
00873                 aspectRatio = m_h264_parser.aspectRatio();
00874                 frameRate = m_h264_parser.frameRate();
00875             }
00876         }
00877     } // for (; i < TSPacket::kSize; i++)
00878 
00879     if (hasKeyFrame)
00880     {
00881         _last_keyframe_seen = _frames_seen_count;
00882         HandleH264Keyframe();
00883     }
00884 
00885     if (hasFrame)
00886     {
00887         _frames_seen_count++;
00888         if (!_wait_for_keyframe_option || _first_keyframe >= 0)
00889             _frames_written_count++;
00890     }
00891 
00892     if ((aspectRatio > 0) && (aspectRatio != m_videoAspect))
00893     {
00894         m_videoAspect = aspectRatio;
00895         AspectChange((AspectRatio)aspectRatio, _frames_written_count);
00896     }
00897 
00898     if (height && width && (height != m_videoHeight || m_videoWidth != width))
00899     {
00900         m_videoHeight = height;
00901         m_videoWidth = width;
00902         ResolutionChange(width, height, _frames_written_count);
00903     }
00904 
00905     if (frameRate != 0 && frameRate != m_frameRate)
00906     {
00907 
00908         LOG(VB_RECORD, LOG_INFO, LOC +
00909             QString("FindH264Keyframes: timescale: %1, tick: %2, framerate: %3")
00910                       .arg( m_h264_parser.GetTimeScale() ) 
00911                       .arg( m_h264_parser.GetUnitsInTick() )
00912                       .arg( frameRate ) );
00913         m_frameRate = frameRate;
00914         FrameRateChange(frameRate, _frames_written_count);
00915     }
00916 
00917     return hasKeyFrame || (_payload_buffer.size() >= (188*50));
00918 }
00919 
00924 void DTVRecorder::HandleH264Keyframe(void)
00925 {
00926     unsigned long long frameNum = _frames_written_count;
00927 
00928     _first_keyframe = (_first_keyframe < 0) ? frameNum : _first_keyframe;
00929 
00930     // Add key frame to position map
00931     positionMapLock.lock();
00932     if (!positionMap.contains(frameNum))
00933     {
00934         positionMapDelta[frameNum] = m_h264_parser.keyframeAUstreamOffset();
00935         positionMap[frameNum]      = m_h264_parser.keyframeAUstreamOffset();
00936     }
00937     positionMapLock.unlock();
00938 
00939     // Perform ringbuffer switch if needed.
00940     CheckForRingBufferSwitch();
00941 }
00942 
00943 void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len)
00944 {
00945     const uint maxKFD = kMaxKeyFrameDistance;
00946 
00947     const uint8_t *bufstart = buffer;
00948     const uint8_t *bufptr   = buffer;
00949     const uint8_t *bufend   = buffer + len;
00950 
00951     uint aspectRatio = 0;
00952     uint height = 0;
00953     uint width = 0;
00954     uint frameRate = 0;
00955 
00956     uint skip = std::max(_audio_bytes_remaining, _other_bytes_remaining);
00957     while (bufptr + skip < bufend)
00958     {
00959         bool hasFrame     = false;
00960         bool hasKeyFrame  = false;
00961 
00962         const uint8_t *tmp = bufptr;
00963         bufptr =
00964             avpriv_mpv_find_start_code(bufptr + skip, bufend, &_start_code);
00965         _audio_bytes_remaining = 0;
00966         _other_bytes_remaining = 0;
00967         _video_bytes_remaining -= std::min(
00968             (uint)(bufptr - tmp), _video_bytes_remaining);
00969 
00970         if ((_start_code & 0xffffff00) != 0x00000100)
00971             continue;
00972 
00973         // NOTE: Length may be zero for packets that only contain bytes from
00974         // video elementary streams in TS packets. 13818-1:2000 2.4.3.7
00975         int pes_packet_length = -1;
00976         if ((bufend - bufptr) >= 2)
00977             pes_packet_length = ((bufptr[0]<<8) | bufptr[1]) + 2 + 6;
00978 
00979         const int stream_id = _start_code & 0x000000ff;
00980         if (_video_bytes_remaining)
00981         {
00982             if (PESStreamID::PictureStartCode == stream_id)
00983             { // pes_packet_length is meaningless
00984                 pes_packet_length = -1;
00985                 uint frmtypei = 1;
00986                 if (bufend-bufptr >= 4)
00987                 {
00988                     frmtypei = (bufptr[1]>>3) & 0x7;
00989                     if ((1 <= frmtypei) && (frmtypei <= 5))
00990                         hasFrame = true;
00991                 }
00992                 else
00993                 {
00994                     hasFrame = true;
00995                 }
00996             }
00997             else if (PESStreamID::GOPStartCode == stream_id)
00998             { // pes_packet_length is meaningless
00999                 pes_packet_length = -1;
01000                 _last_gop_seen  = _frames_seen_count;
01001                 hasKeyFrame    |= true;
01002             }
01003             else if (PESStreamID::SequenceStartCode == stream_id)
01004             { // pes_packet_length is meaningless
01005                 pes_packet_length = -1;
01006                 _last_seq_seen  = _frames_seen_count;
01007                 hasKeyFrame    |= (_last_gop_seen + maxKFD)<_frames_seen_count;
01008 
01009                 // Look for aspectRatio changes and store them in the database
01010                 aspectRatio = (bufptr[3] >> 4);
01011 
01012                 // Get resolution
01013                 height = ((bufptr[1] & 0xf) << 8) | bufptr[2];
01014                 width = (bufptr[0] <<4) | (bufptr[1]>>4);
01015 
01016                 frameRate = frameRateMap[(bufptr[3] & 0x0000000f)];
01017             }
01018         }
01019         else if (!_video_bytes_remaining && !_audio_bytes_remaining)
01020         {
01021             if ((stream_id >= PESStreamID::MPEGVideoStreamBegin) &&
01022                 (stream_id <= PESStreamID::MPEGVideoStreamEnd))
01023             { // ok-dvdinfo
01024                 _video_bytes_remaining = std::max(0, (int)pes_packet_length);
01025             }
01026             else if ((stream_id >= PESStreamID::MPEGAudioStreamBegin) &&
01027                      (stream_id <= PESStreamID::MPEGAudioStreamEnd))
01028             { // ok-dvdinfo
01029                 _audio_bytes_remaining = std::max(0, (int)pes_packet_length);
01030             }
01031         }
01032 
01033         if (PESStreamID::PaddingStream == stream_id)
01034         { // ok-dvdinfo
01035             _other_bytes_remaining = std::max(0, (int)pes_packet_length);
01036         }
01037 
01038         _start_code = 0xffffffff; // reset start code
01039 
01040         if (hasFrame && !hasKeyFrame)
01041         {
01042             // If we have seen kMaxKeyFrameDistance frames since the
01043             // last GOP or SEQ stream_id, then pretend this picture
01044             // is a keyframe. We may get artifacts but at least
01045             // we will be able to skip frames.
01046             hasKeyFrame = !(_frames_seen_count & 0xf);
01047             hasKeyFrame &= (_last_gop_seen + maxKFD) < _frames_seen_count;
01048             hasKeyFrame &= (_last_seq_seen + maxKFD) < _frames_seen_count;
01049         }
01050 
01051         if (hasFrame)
01052         {
01053             _frames_seen_count++;
01054             if (!_wait_for_keyframe_option || _first_keyframe >= 0)
01055                 _frames_written_count++;
01056         }
01057 
01058         if (hasKeyFrame)
01059         {
01060             _last_keyframe_seen = _frames_seen_count;
01061             HandleKeyframe(_frames_written_count, bufptr - bufstart);
01062         }
01063 
01064         if ((aspectRatio > 0) && (aspectRatio != m_videoAspect))
01065         {
01066             m_videoAspect = aspectRatio;
01067             AspectChange((AspectRatio)aspectRatio, _frames_written_count);
01068         }
01069 
01070         if (height && width && 
01071             (height != m_videoHeight || m_videoWidth != width))
01072         {
01073             m_videoHeight = height;
01074             m_videoWidth = width;
01075             ResolutionChange(width, height, _frames_written_count);
01076         }
01077 
01078         if (frameRate && frameRate != m_frameRate)
01079         {
01080             m_frameRate = frameRate;
01081             LOG(VB_RECORD, LOG_INFO, LOC +
01082                 QString("FindPSKeyFrames: frame rate = %1").arg(frameRate));
01083             FrameRateChange(frameRate, _frames_written_count);
01084         }
01085 
01086         if (hasKeyFrame || hasFrame)
01087         {
01088             // We are free to write the packet, but if we have
01089             // buffered packet[s] we have to write them first...
01090             if (!_payload_buffer.empty())
01091             {
01092                 if (ringBuffer)
01093                 {
01094                     ringBuffer->Write(
01095                         &_payload_buffer[0], _payload_buffer.size());
01096                 }
01097                 _payload_buffer.clear();
01098             }
01099 
01100             if (ringBuffer)
01101                 ringBuffer->Write(bufstart, (bufptr - bufstart));
01102 
01103             bufstart = bufptr;
01104         }
01105 
01106         skip = std::max(_audio_bytes_remaining, _other_bytes_remaining);
01107     }
01108 
01109     int bytes_skipped = bufend - bufptr;
01110     if (bytes_skipped > 0)
01111     {
01112         _audio_bytes_remaining -= std::min(
01113             (uint)bytes_skipped, _audio_bytes_remaining);
01114         _video_bytes_remaining -= std::min(
01115             (uint)bytes_skipped, _video_bytes_remaining);
01116         _other_bytes_remaining -= std::min(
01117             (uint)bytes_skipped, _other_bytes_remaining);
01118     }
01119 
01120     uint64_t idx = _payload_buffer.size();
01121     uint64_t rem = (bufend - bufstart);
01122     _payload_buffer.resize(idx + rem);
01123     memcpy(&_payload_buffer[idx], bufstart, rem);
01124 #if 0
01125     LOG(VB_GENERAL, LOG_DEBUG, LOC +
01126         QString("idx: %1, rem: %2").arg(idx).arg(rem));
01127 #endif
01128 }
01129 
01130 void DTVRecorder::HandlePAT(const ProgramAssociationTable *_pat)
01131 {
01132     if (!_pat)
01133     {
01134         LOG(VB_RECORD, LOG_ERR, LOC + "SetPAT(NULL)");
01135         return;
01136     }
01137 
01138     QMutexLocker change_lock(&_pid_lock);
01139 
01140     int progNum = _stream_data->DesiredProgram();
01141     uint pmtpid = _pat->FindPID(progNum);
01142 
01143     if (!pmtpid)
01144     {
01145         LOG(VB_RECORD, LOG_ERR, LOC + "SetPAT(): "
01146             "Ignoring PAT not containing our desired program...");
01147         return;
01148     }
01149 
01150     LOG(VB_RECORD, LOG_INFO, LOC + QString("SetPAT(%1 on 0x%2)")
01151             .arg(progNum).arg(pmtpid,0,16));
01152 
01153     ProgramAssociationTable *oldpat = _input_pat;
01154     _input_pat = new ProgramAssociationTable(*_pat);
01155     delete oldpat;
01156 
01157     // Listen for the other PMTs for faster channel switching
01158     for (uint i = 0; _input_pat && (i < _input_pat->ProgramCount()); i++)
01159     {
01160         uint pmt_pid = _input_pat->ProgramPID(i);
01161         if (!_stream_data->IsListeningPID(pmt_pid))
01162             _stream_data->AddListeningPID(pmt_pid, kPIDPriorityLow);
01163     }
01164 }
01165 
01166 void DTVRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt)
01167 {
01168     QMutexLocker change_lock(&_pid_lock);
01169 
01170     if ((int)progNum == _stream_data->DesiredProgram())
01171     {
01172         LOG(VB_RECORD, LOG_INFO, LOC + QString("SetPMT(%1)").arg(progNum));
01173         ProgramMapTable *oldpmt = _input_pmt;
01174         _input_pmt = new ProgramMapTable(*_pmt);
01175 
01176         QString sistandard = GetSIStandard();
01177 
01178         bool has_no_av = true;
01179         for (uint i = 0; i < _input_pmt->StreamCount() && has_no_av; i++)
01180         {
01181             has_no_av &= !_input_pmt->IsVideo(i, sistandard);
01182             has_no_av &= !_input_pmt->IsAudio(i, sistandard);
01183         }
01184         _has_no_av = has_no_av;
01185 
01186         SetCAMPMT(_input_pmt);
01187         delete oldpmt;
01188     }
01189 }
01190 
01191 void DTVRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat)
01192 {
01193     if (!pat)
01194     {
01195         LOG(VB_RECORD, LOG_ERR, LOC + "HandleSingleProgramPAT(NULL)");
01196         return;
01197     }
01198 
01199     if (!ringBuffer)
01200         return;
01201 
01202     uint next_cc = (pat->tsheader()->ContinuityCounter()+1)&0xf;
01203     pat->tsheader()->SetContinuityCounter(next_cc);
01204     pat->GetAsTSPackets(_scratch, next_cc);
01205 
01206     for (uint i = 0; i < _scratch.size(); i++)
01207         DTVRecorder::BufferedWrite(_scratch[i]);
01208 }
01209 
01210 void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
01211 {
01212     if (!pmt)
01213     {
01214         LOG(VB_RECORD, LOG_ERR, LOC + "HandleSingleProgramPMT(NULL)");
01215         return;
01216     }
01217 
01218     // collect stream types for H.264 (MPEG-4 AVC) keyframe detection
01219     for (uint i = 0; i < pmt->StreamCount(); i++)
01220         _stream_id[pmt->StreamPID(i)] = pmt->StreamType(i);
01221 
01222     if (!ringBuffer)
01223         return;
01224 
01225     uint next_cc = (pmt->tsheader()->ContinuityCounter()+1)&0xf;
01226     pmt->tsheader()->SetContinuityCounter(next_cc);
01227     pmt->GetAsTSPackets(_scratch, next_cc);
01228 
01229     for (uint i = 0; i < _scratch.size(); i++)
01230         DTVRecorder::BufferedWrite(_scratch[i]);
01231 }
01232 
01233 bool DTVRecorder::ProcessTSPacket(const TSPacket &tspacket)
01234 {
01235     const uint pid = tspacket.PID();
01236 
01237     if (pid != 0x1fff)
01238         _packet_count.fetchAndAddAcquire(1);
01239 
01240     // Check continuity counter
01241     uint old_cnt = _continuity_counter[pid];
01242     if ((pid != 0x1fff) && !CheckCC(pid, tspacket.ContinuityCounter()))
01243     {
01244         int v = _continuity_error_count.fetchAndAddRelaxed(1) + 1;
01245         double erate = v * 100.0 / _packet_count.fetchAndAddRelaxed(0);
01246         LOG(VB_RECORD, LOG_WARNING, LOC +
01247             QString("PID 0x%1 discontinuity detected ((%2+1)%16!=%3) %4\%")
01248                 .arg(pid,0,16).arg(old_cnt,2)
01249                 .arg(tspacket.ContinuityCounter(),2)
01250                 .arg(erate));
01251     }
01252 
01253     // Only create fake keyframe[s] if there are no audio/video streams
01254     if (_input_pmt && _has_no_av)
01255     {
01256         _buffer_packets = !FindOtherKeyframes(&tspacket);
01257     }
01258     else
01259     {
01260         // There are audio/video streams. Only write the packet
01261         // if audio/video key-frames have been found
01262         if (_wait_for_keyframe_option && _first_keyframe < 0)
01263             return true;
01264 
01265         _buffer_packets = true;
01266     }
01267 
01268     BufferedWrite(tspacket);
01269 
01270     return true;
01271 }
01272 
01273 bool DTVRecorder::ProcessVideoTSPacket(const TSPacket &tspacket)
01274 {
01275     if (!ringBuffer)
01276         return true;
01277 
01278     uint streamType = _stream_id[tspacket.PID()];
01279 
01280     // Check for keyframes and count frames
01281     if (streamType == StreamID::H264Video)
01282     {
01283         _buffer_packets = !FindH264Keyframes(&tspacket);
01284         if (_wait_for_keyframe_option && !_seen_sps)
01285             return true;
01286     }
01287     else
01288     {
01289         _buffer_packets = !FindMPEG2Keyframes(&tspacket);
01290     }
01291 
01292     return ProcessAVTSPacket(tspacket);
01293 }
01294 
01295 bool DTVRecorder::ProcessAudioTSPacket(const TSPacket &tspacket)
01296 {
01297     if (!ringBuffer)
01298         return true;
01299 
01300     _buffer_packets = !FindAudioKeyframes(&tspacket);
01301     return ProcessAVTSPacket(tspacket);
01302 }
01303 
01305 bool DTVRecorder::ProcessAVTSPacket(const TSPacket &tspacket)
01306 {
01307     const uint pid = tspacket.PID();
01308 
01309     if (pid != 0x1fff)
01310         _packet_count.fetchAndAddAcquire(1);
01311 
01312     // Check continuity counter
01313     uint old_cnt = _continuity_counter[pid];
01314     if ((pid != 0x1fff) && !CheckCC(pid, tspacket.ContinuityCounter()))
01315     {
01316         int v = _continuity_error_count.fetchAndAddRelaxed(1) + 1;
01317         double erate = v * 100.0 / _packet_count.fetchAndAddRelaxed(0);
01318         LOG(VB_RECORD, LOG_WARNING, LOC +
01319             QString("A/V PID 0x%1 discontinuity detected ((%2+1)%16!=%3) %4\%")
01320                 .arg(pid,0,16).arg(old_cnt).arg(tspacket.ContinuityCounter())
01321                 .arg(erate,5,'f',2));
01322     }
01323 
01324     // Sync recording start to first keyframe
01325     if (_wait_for_keyframe_option && _first_keyframe < 0)
01326         return true;
01327 
01328     // Sync streams to the first Payload Unit Start Indicator
01329     // _after_ first keyframe iff _wait_for_keyframe_option is true
01330     if (!(_pid_status[pid] & kPayloadStartSeen) && tspacket.HasPayload())
01331     {
01332         if (!tspacket.PayloadStart())
01333             return true; // not payload start - drop packet
01334 
01335         LOG(VB_RECORD, LOG_INFO, LOC +
01336             QString("PID 0x%1 Found Payload Start").arg(pid,0,16));
01337 
01338         _pid_status[pid] |= kPayloadStartSeen;
01339     }
01340 
01341     BufferedWrite(tspacket);
01342 
01343     return true;
01344 }
01345 
01346 RecordingQuality *DTVRecorder::GetRecordingQuality(void) const
01347 {
01348     RecordingQuality *recq = RecorderBase::GetRecordingQuality();
01349     recq->AddTSStatistics(
01350         _continuity_error_count.fetchAndAddRelaxed(0),
01351         _packet_count.fetchAndAddRelaxed(0));
01352     return recq;
01353 }
01354 
01355 /* vim: set expandtab tabstop=4 shiftwidth=4: */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends