Ticket #11328: keep-first-keyframe-v4.patch

File keep-first-keyframe-v4.patch, 36.5 KB (added by jpoet, 14 years ago)

Insert PAT/PMT at the front of each back-to-back recording

  • 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)  
    831831        QMutexLocker locker(&_listener_lock);
    832832        ProgramAssociationTable *pat_sp = PATSingleProgram();
    833833        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);
    835835    }
    836836}
    837837
    void MPEGStreamData::ProcessPMT(const ProgramMapTable *pmt)  
    866866        QMutexLocker locker(&_listener_lock);
    867867        ProgramMapTable *pmt_sp = PMTSingleProgram();
    868868        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);
    870870    }
    871871}
    872872
    void MPEGStreamData::HandleTSTables(const TSPacket* tspacket)  
    977977            QMutexLocker locker(&_listener_lock);
    978978            ProgramAssociationTable *pat_sp = PATSingleProgram();
    979979            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);
    981981        }
    982982        if (TableID::PMT == psip->TableID() &&
    983983            tspacket->PID() == _pid_pmt_single_program)
    void MPEGStreamData::HandleTSTables(const TSPacket* tspacket)  
    985985            QMutexLocker locker(&_listener_lock);
    986986            ProgramMapTable *pmt_sp = PMTSingleProgram();
    987987            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);
    989989        }
    990990        DONE_WITH_PSIP_PACKET(); // already parsed this table, toss it.
    991991    }
  • 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  
    9595  protected:
    9696    virtual ~MPEGSingleProgramStreamListener() {}
    9797  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;
    100101};
    101102
    102103class 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)  
    6565        DTVRecorder::SetOption(name, value);
    6666}
    6767
     68void 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
    6876void ASIRecorder::run(void)
    6977{
    7078    if (!Open())
    void ASIRecorder::run(void)  
    102110    if (m_channel && (m_channel->GetSIStandard() == "dvb"))
    103111        _stream_data->AddListeningPID(DVB_TDT_PID);
    104112
    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();
    111114
    112115    _stream_data->AddAVListener(this);
    113116    _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  
    6969    bool Open(void);
    7070    bool IsOpen(void) const;
    7171    void Close(void);
     72    void StartNewFile(void);
    7273
    7374  private:
    7475    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)  
    4747    LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end");
    4848}
    4949
     50void 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
    5057void CetonRecorder::run(void)
    5158{
    5259    LOG(VB_RECORD, LOG_INFO, LOC + "run -- begin");
    void CetonRecorder::run(void)  
    6673        recordingWait.wakeAll();
    6774    }
    6875
    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();
    7577
    7678    _stream_data->AddAVListener(this);
    7779    _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  
    2626
    2727    bool Open(void);
    2828    void Close(void);
     29    void StartNewFile(void);
    2930
    3031    bool IsOpen(void) const { return _stream_handler; }
    3132
  • 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) :  
    8787{
    8888    SetPositionMapType(MARK_GOP_BYFRAME);
    8989    _payload_buffer.reserve(TSPacket::kSize * (50 + 1));
     90
    9091    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));
    9196}
    9297
    9398DTVRecorder::~DTVRecorder()
    void DTVRecorder::SetOptionsFromProfile(RecordingProfile *profile,  
    147152void DTVRecorder::FinishRecording(void)
    148153{
    149154    if (ringBuffer)
    150     {
    151         if (!_payload_buffer.empty())
    152         {
    153             ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size());
    154             _payload_buffer.clear();
    155         }
    156155        ringBuffer->WriterFlush();
    157     }
    158156
    159157    if (curRecording)
    160158    {
    void DTVRecorder::ResetForNewFile(void)  
    171169    LOG(VB_RECORD, LOG_INFO, LOC + "ResetForNewFile(void)");
    172170    QMutexLocker locker(&positionMapLock);
    173171
    174     // _first_keyframe, _seen_psp and m_h264_parser should
     172    // _seen_psp and m_h264_parser should
    175173    // not be reset here. This will only be called just as
    176174    // we're seeing the first packet of a new keyframe for
    177175    // writing to the new file and anything that makes the
    void DTVRecorder::ResetForNewFile(void)  
    180178    // -- Daniel Kristjansson 2011-02-26
    181179
    182180    _start_code                 = 0xffffffff;
    183     //_first_keyframe
     181    _first_keyframe             = -1;
    184182    _has_written_other_keyframe = false;
    185183    _last_keyframe_seen         = 0;
    186184    _last_gop_seen              = 0;
    void DTVRecorder::ResetForNewFile(void)  
    191189    //_recording
    192190    _error                      = QString();
    193191
    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 
    198192    _progressive_sequence       = 0;
    199193    _repeat_pict                = 0;
    200194
    201     _pes_synced                 = false;
     195    //_pes_synced
    202196    //_seen_sps
    203197    positionMap.clear();
    204198    positionMapDelta.clear();
    205199    durationMap.clear();
    206200    durationMapDelta.clear();
    207     _payload_buffer.clear();
    208201
    209202    locker.unlock();
    210203    ClearStatistics();
    void DTVRecorder::ClearStatistics(void)  
    215208    RecorderBase::ClearStatistics();
    216209
    217210    memset(_ts_count, 0, sizeof(_ts_count));
    218     for (int i = 0; i < 256; i++)
     211    for (int i = 0; i < 256; ++i)
    219212        _ts_last[i] = -1LL;
    220     for (int i = 0; i < 256; i++)
     213    for (int i = 0; i < 256; ++i)
    221214        _ts_first[i] = -1LL;
    222215    //_ts_first_dt -- doesn't need to be cleared only used if _ts_first>=0
    223216    _packet_count.fetchAndStoreRelaxed(0);
    void DTVRecorder::InitStreamData(void)  
    274267        _stream_data->SetDesiredProgram(_stream_data->DesiredProgram());
    275268}
    276269
    277 void DTVRecorder::BufferedWrite(const TSPacket &tspacket)
     270void DTVRecorder::BufferedWrite(const TSPacket &tspacket, bool insert)
    278271{
    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
    284273    {
    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;
    290278
    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        }
    312286
    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        }
    321308
    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        }
    329326    }
    330327
    331328    if (ringBuffer)
    static const uint frameRateMap[16] = {  
    403400 */
    404401bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket)
    405402{
    406     bool haveBufferedData = !_payload_buffer.empty();
    407403    if (!tspacket->HasPayload()) // no payload to scan
    408         return !haveBufferedData;
     404        return _first_keyframe >= 0;
    409405
    410406    if (!ringBuffer)
    411         return !haveBufferedData;
     407        return _first_keyframe >= 0;
    412408
    413409    // if packet contains start of PES packet, start
    414410    // looking for first byte of MPEG start code (3 bytes 0 0 1)
    bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket)  
    540536
    541537    if (hasKeyFrame)
    542538    {
     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
    543546        _last_keyframe_seen = _frames_seen_count;
    544         HandleKeyframe(_frames_written_count, TSPacket::kSize);
     547        HandleKeyframe(0);
    545548    }
    546549
    547550    if (hasFrame)
    548551    {
     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
    549560        _frames_seen_count++;
    550         if (!_wait_for_keyframe_option || _first_keyframe>=0)
     561        if (!_wait_for_keyframe_option || _first_keyframe >= 0)
    551562            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        }
    552569    }
    553570
    554571    if ((aspectRatio > 0) && (aspectRatio != m_videoAspect))
    bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket)  
    572589        FrameRateChange(frameRate, _frames_written_count);
    573590    }
    574591
    575     return hasKeyFrame || (_payload_buffer.size() >= (188*50));
     592    return _first_keyframe >= 0;
    576593}
    577594
    578595void DTVRecorder::HandleTimestamps(int stream_id, int64_t pts, int64_t dts)
    bool DTVRecorder::FindAudioKeyframes(const TSPacket*)  
    680697        if (1 == (_frames_seen_count & 0x7))
    681698        {
    682699            _last_keyframe_seen = _frames_seen_count;
    683             HandleKeyframe(_frames_written_count);
     700            HandleKeyframe(_payload_buffer.size());
    684701            hasKeyFrame = true;
    685702        }
    686703
    bool DTVRecorder::FindOtherKeyframes(const TSPacket *tspacket)  
    708725    UpdateFramesWritten();
    709726    _last_keyframe_seen = _frames_seen_count;
    710727
    711     HandleKeyframe(_frames_written_count);
     728    HandleKeyframe(_payload_buffer.size());
    712729
    713730    _has_written_other_keyframe = true;
    714731
    bool DTVRecorder::FindOtherKeyframes(const TSPacket *tspacket)  
    719736 *  \brief This save the current frame to the position maps
    720737 *         and handles ringbuffer switching.
    721738 */
    722 void DTVRecorder::HandleKeyframe(uint64_t frameNum, int64_t extra)
     739void DTVRecorder::HandleKeyframe(int64_t extra)
    723740{
    724741    if (!ringBuffer)
    725742        return;
    726743
    727 #if 0
    728     unsigned long long frameNum = _frames_written_count;
    729 #endif
     744    // Perform ringbuffer switch if needed.
     745    CheckForRingBufferSwitch();
    730746
     747    uint64_t frameNum = _frames_written_count;
    731748    _first_keyframe = (_first_keyframe < 0) ? frameNum : _first_keyframe;
    732749
    733750    // Add key frame to position map
    734751    positionMapLock.lock();
    735752    if (!positionMap.contains(frameNum))
    736753    {
    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;
    740755
    741756        // Don't put negative offsets into the database, they get munged into
    742757        // MAX_INT64 - offset, which is an exceedingly large number, and
    void DTVRecorder::HandleKeyframe(uint64_t frameNum, int64_t extra)  
    750765        }
    751766    }
    752767    positionMapLock.unlock();
    753 
    754     // Perform ringbuffer switch if needed.
    755     CheckForRingBufferSwitch();
    756768}
    757769
    758770/** \fn DTVRecorder::FindH264Keyframes(const TSPacket*)
    void DTVRecorder::HandleKeyframe(uint64_t frameNum, int64_t extra)  
    762774 */
    763775bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)
    764776{
     777    if (!tspacket->HasPayload()) // no payload to scan
     778        return _first_keyframe >= 0;
     779
    765780    if (!ringBuffer)
    766781    {
    767782        LOG(VB_GENERAL, LOG_ERR, LOC + "FindH264Keyframes: No ringbuffer");
    768         return false;
     783        return _first_keyframe >= 0;
    769784    }
    770785
    771     bool haveBufferedData = !_payload_buffer.empty();
    772     if (!tspacket->HasPayload()) // no payload to scan
    773         return !haveBufferedData;
    774 
    775786    const bool payloadStart = tspacket->PayloadStart();
    776787    if (payloadStart)
    777788    {
    bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)  
    790801
    791802    // scan for PES packets and H.264 NAL units
    792803    uint i = tspacket->AFCOffset();
    793     for (; i < TSPacket::kSize; i++)
     804    for (; i < TSPacket::kSize; ++i)
    794805    {
    795806        // special handling required when a new PES packet begins
    796807        if (payloadStart && !_pes_synced)
    bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)  
    858869
    859870        // scan for a NAL unit start code
    860871
    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());
    865875        i += (bytes_used - 1);
    866876
    867877        if (m_h264_parser.stateChanged())
    bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)  
    879889                frameRate = m_h264_parser.frameRate();
    880890            }
    881891        }
    882     } // for (; i < TSPacket::kSize; i++)
     892    } // for (; i < TSPacket::kSize; ++i)
    883893
    884894    if (hasKeyFrame)
    885895    {
     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
    886904        _last_keyframe_seen = _frames_seen_count;
    887905        HandleH264Keyframe();
    888906    }
    889907
    890908    if (hasFrame)
    891909    {
     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
    892919        _frames_seen_count++;
    893920        if (!_wait_for_keyframe_option || _first_keyframe >= 0)
    894921            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        }
    895928    }
    896929
    897930    if ((aspectRatio > 0) && (aspectRatio != m_videoAspect))
    bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)  
    909942
    910943    if (frameRate != 0 && frameRate != m_frameRate)
    911944    {
    912 
    913945        LOG(VB_RECORD, LOG_INFO, LOC +
    914946            QString("FindH264Keyframes: timescale: %1, tick: %2, framerate: %3")
    915947                      .arg( m_h264_parser.GetTimeScale() )
    bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)  
    919951        FrameRateChange(frameRate, _frames_written_count);
    920952    }
    921953
    922     return hasKeyFrame || (_payload_buffer.size() >= (188*50));
     954    return _seen_sps;
    923955}
    924956
    925957/** \fn DTVRecorder::HandleH264Keyframe(void)
    bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)  
    928960 */
    929961void DTVRecorder::HandleH264Keyframe(void)
    930962{
    931     unsigned long long frameNum = _frames_written_count;
     963    // Perform ringbuffer switch if needed.
     964    CheckForRingBufferSwitch();
    932965
    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();
    934976
    935977    // Add key frame to position map
    936978    positionMapLock.lock();
    937979    if (!positionMap.contains(frameNum))
    938980    {
    939         positionMapDelta[frameNum] = m_h264_parser.keyframeAUstreamOffset();
    940         positionMap[frameNum]      = m_h264_parser.keyframeAUstreamOffset();
     981        positionMapDelta[frameNum] = startpos;
     982        positionMap[frameNum]      = startpos;
    941983        durationMap[frameNum]      = _total_duration / 1000;
    942984        durationMapDelta[frameNum] = _total_duration / 1000;
    943985    }
    944986    positionMapLock.unlock();
    945 
    946     // Perform ringbuffer switch if needed.
    947     CheckForRingBufferSwitch();
    948987}
    949988
    950989void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len)
    void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len)  
    10651104        if (hasKeyFrame)
    10661105        {
    10671106            _last_keyframe_seen = _frames_seen_count;
    1068             HandleKeyframe(_frames_written_count, bufptr - bufstart);
     1107            HandleKeyframe(_payload_buffer.size() - (bufptr - bufstart));
    10691108        }
    10701109
    10711110        if ((aspectRatio > 0) && (aspectRatio != m_videoAspect))
    void DTVRecorder::HandlePAT(const ProgramAssociationTable *_pat)  
    11491188
    11501189    if (!pmtpid)
    11511190    {
    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));
    11541194        return;
    11551195    }
    11561196
    void DTVRecorder::HandlePAT(const ProgramAssociationTable *_pat)  
    11621202    delete oldpat;
    11631203
    11641204    // 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)
    11661206    {
    11671207        uint pmt_pid = _input_pat->ProgramPID(i);
    11681208        if (!_stream_data->IsListeningPID(pmt_pid))
    void DTVRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt)  
    11831223        QString sistandard = GetSIStandard();
    11841224
    11851225        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)
    11871227        {
    11881228            has_no_av &= !_input_pmt->IsVideo(i, sistandard);
    11891229            has_no_av &= !_input_pmt->IsAudio(i, sistandard);
    void DTVRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt)  
    11951235    }
    11961236}
    11971237
    1198 void DTVRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat)
     1238void DTVRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat,
     1239                                         bool insert)
    11991240{
    12001241    if (!pat)
    12011242    {
    void DTVRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat)  
    12101251    pat->tsheader()->SetContinuityCounter(next_cc);
    12111252    pat->GetAsTSPackets(_scratch, next_cc);
    12121253
    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);
    12151256}
    12161257
    1217 void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
     1258void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt, bool insert)
    12181259{
    12191260    if (!pmt)
    12201261    {
    void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)  
    12231264    }
    12241265
    12251266    // 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)
    12271268        _stream_id[pmt->StreamPID(i)] = pmt->StreamType(i);
    12281269
    12291270    if (!ringBuffer)
    void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)  
    12331274    pmt->tsheader()->SetContinuityCounter(next_cc);
    12341275    pmt->GetAsTSPackets(_scratch, next_cc);
    12351276
    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);
    12381279}
    12391280
    12401281bool DTVRecorder::ProcessTSPacket(const TSPacket &tspacket)
    bool DTVRecorder::ProcessTSPacket(const TSPacket &tspacket)  
    12601301    // Only create fake keyframe[s] if there are no audio/video streams
    12611302    if (_input_pmt && _has_no_av)
    12621303    {
    1263         _buffer_packets = !FindOtherKeyframes(&tspacket);
     1304        FindOtherKeyframes(&tspacket);
     1305        _buffer_packets = false;
    12641306    }
    12651307    else
    12661308    {
    bool DTVRecorder::ProcessVideoTSPacket(const TSPacket &tspacket)  
    12841326
    12851327    uint streamType = _stream_id[tspacket.PID()];
    12861328
    1287     // Check for keyframes and count frames
    1288     if (streamType == StreamID::H264Video)
     1329    if (tspacket.HasPayload() && tspacket.PayloadStart())
    12891330    {
    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
    12931340    }
     1341
     1342    // Check for keyframes and count frames
     1343    if (streamType == StreamID::H264Video)
     1344        FindH264Keyframes(&tspacket);
     1345    else if (streamType != 0)
     1346        FindMPEG2Keyframes(&tspacket);
    12941347    else
    1295     {
    1296         _buffer_packets = !FindMPEG2Keyframes(&tspacket);
    1297     }
     1348        LOG(VB_RECORD, LOG_ERR, LOC +
     1349            "ProcessVideoTSPacket: unknown stream type!");
    12981350
    12991351    return ProcessAVTSPacket(tspacket);
    13001352}
    bool DTVRecorder::ProcessAudioTSPacket(const TSPacket &tspacket)  
    13041356    if (!ringBuffer)
    13051357        return true;
    13061358
    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);
    13081373    return ProcessAVTSPacket(tspacket);
    13091374}
    13101375
    13111376/// Common code for processing either audio or video packets
    13121377bool DTVRecorder::ProcessAVTSPacket(const TSPacket &tspacket)
    13131378{
     1379    // Sync recording start to first keyframe
     1380    if (!_buffer_packets && _wait_for_keyframe_option && _first_keyframe < 0)
     1381        return true;
     1382
    13141383    const uint pid = tspacket.PID();
    13151384
    13161385    if (pid != 0x1fff)
    bool DTVRecorder::ProcessAVTSPacket(const TSPacket &tspacket)  
    13281397                .arg(erate,5,'f',2));
    13291398    }
    13301399
    1331     // Sync recording start to first keyframe
    1332     if (_wait_for_keyframe_option && _first_keyframe < 0)
    1333         return true;
    1334 
    13351400    // Sync streams to the first Payload Unit Start Indicator
    13361401    // _after_ first keyframe iff _wait_for_keyframe_option is true
    13371402    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 :  
    6464    void HandleEncryptionStatus(uint /*pnum*/, bool /*encrypted*/) { }
    6565
    6666    // 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);
    6969
    7070    // ATSC Main
    7171    void HandleSTT(const SystemTimeTable*) { UpdateCAMTimeOffset(); }
    class DTVRecorder :  
    9393    void FinishRecording(void);
    9494    void ResetForNewFile(void);
    9595
    96     void HandleKeyframe(uint64_t frameNum, int64_t extra = 0);
     96    void HandleKeyframe(int64_t extra);
    9797    void HandleTimestamps(int stream_id, int64_t pts, int64_t dts);
    9898    void UpdateFramesWritten(void);
    9999
    100     void BufferedWrite(const TSPacket &tspacket);
     100    void BufferedWrite(const TSPacket &tspacket, bool insert = false);
    101101
    102102    // MPEG TS "audio only" support
    103103    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)  
    7272    LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end");
    7373}
    7474
     75void 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
    7582void DVBRecorder::run(void)
    7683{
    7784    if (!Open())
    void DVBRecorder::run(void)  
    9299    if (_channel && (_channel->GetSIStandard() == "dvb"))
    93100        _stream_data->AddListeningPID(DVB_TDT_PID);
    94101
    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();
    101103
    102104    _stream_data->AddAVListener(this);
    103105    _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  
    2828    bool Open(void);
    2929    bool IsOpen(void) const;
    3030    void Close(void);
     31    void StartNewFile(void);
    3132
    3233  private:
    3334    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)  
    4848    LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end");
    4949}
    5050
     51void 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
    5158void HDHRRecorder::run(void)
    5259{
    5360    LOG(VB_RECORD, LOG_INFO, LOC + "run -- begin");
    void HDHRRecorder::run(void)  
    6774        recordingWait.wakeAll();
    6875    }
    6976
    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();
    7678
    7779    _stream_data->AddAVListener(this);
    7880    _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  
    2626    bool Open(void);
    2727    bool IsOpen(void) const { return _stream_handler; }
    2828    void Close(void);
     29    void StartNewFile(void);
    2930
    3031    QString GetSIStandard(void) const;
    3132
  • 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)  
    9191    return IsPaused(true);
    9292}
    9393
     94void 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
    94101void IPTVRecorder::run(void)
    95102{
    96103    LOG(VB_RECORD, LOG_INFO, LOC + "run -- begin");
    void IPTVRecorder::run(void)  
    109116        recordingWait.wakeAll();
    110117    }
    111118
    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();
    118120
    119121    _stream_data->AddAVListener(this);
    120122    _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  
    2424    virtual bool Open(void); // RecorderBase
    2525    virtual void Close(void); // RecorderBase
    2626    bool IsOpen(void) const;
     27    void StartNewFile(void);
    2728
    2829    virtual void SetStreamData(MPEGStreamData*); // DTVRecorder
    2930    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)  
    932932        _stream_data->AddWritingListener(this);
    933933
    934934        // 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);
    938937        _wait_for_keyframe_option = true;
    939938    }
    940939
    void MpegRecorder::RestartEncoding(void)  
    12531252        _stream_data->PMTSingleProgram())
    12541253    {
    12551254        _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);
    12581257    }
    12591258
    12601259    if (driver == "hdpvr") // HD-PVR will sometimes reset to defaults