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

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

Should work with back-to-back recordings without frame loss

  • mythtv/libs/libmythtv/recorders/dtvrecorder.cpp

    diff --git a/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp b/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp
    index 60549f8..b1b63e2 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)  
    277270void DTVRecorder::BufferedWrite(const TSPacket &tspacket)
    278271{
    279272    // delay until first GOP to avoid decoder crash on res change
    280     if (_wait_for_keyframe_option && _first_keyframe<0)
     273    if (!_buffer_packets && _wait_for_keyframe_option && _first_keyframe < 0)
    281274        return;
    282275
    283276    if (curRecording && timeOfFirstDataIsSet.testAndSetRelaxed(0,1))
    static const uint frameRateMap[16] = {  
    403396 */
    404397bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket)
    405398{
    406     bool haveBufferedData = !_payload_buffer.empty();
    407399    if (!tspacket->HasPayload()) // no payload to scan
    408         return !haveBufferedData;
     400        return _first_keyframe >= 0;
    409401
    410402    if (!ringBuffer)
    411         return !haveBufferedData;
     403        return _first_keyframe >= 0;
    412404
    413405    // if packet contains start of PES packet, start
    414406    // looking for first byte of MPEG start code (3 bytes 0 0 1)
    bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket)  
    540532
    541533    if (hasKeyFrame)
    542534    {
     535#if 0
     536        LOG(VB_RECORD, LOG_ERR, LOC + QString
     537            ("Keyframe @ %1 + %2 = %3")
     538            .arg(ringBuffer->GetWritePosition())
     539            .arg(_payload_buffer.size())
     540            .arg(ringBuffer->GetWritePosition() + _payload_buffer.size()));
     541#endif
    543542        _last_keyframe_seen = _frames_seen_count;
    544         HandleKeyframe(_frames_written_count, TSPacket::kSize);
     543        HandleKeyframe(0);
    545544    }
    546545
    547546    if (hasFrame)
    548547    {
     548#if 0
     549        LOG(VB_RECORD, LOG_ERR, LOC + QString
     550            ("Frame @ %1 + %2 = %3")
     551            .arg(ringBuffer->GetWritePosition())
     552            .arg(_payload_buffer.size())
     553            .arg(ringBuffer->GetWritePosition() + _payload_buffer.size()));
     554#endif
     555        _buffer_packets = false;  // We know know if it is a keyframe, or not
    549556        _frames_seen_count++;
    550         if (!_wait_for_keyframe_option || _first_keyframe>=0)
     557        if (!_wait_for_keyframe_option || _first_keyframe >= 0)
    551558            UpdateFramesWritten();
     559        else
     560        {
     561            /* Found a frame that is not a keyframe, and we want to
     562             * start on a keyframe */
     563            _payload_buffer.clear();
     564        }
    552565    }
    553566
    554567    if ((aspectRatio > 0) && (aspectRatio != m_videoAspect))
    bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket)  
    572585        FrameRateChange(frameRate, _frames_written_count);
    573586    }
    574587
    575     return hasKeyFrame || (_payload_buffer.size() >= (188*50));
     588    return _first_keyframe >= 0;
    576589}
    577590
    578591void DTVRecorder::HandleTimestamps(int stream_id, int64_t pts, int64_t dts)
    bool DTVRecorder::FindAudioKeyframes(const TSPacket*)  
    680693        if (1 == (_frames_seen_count & 0x7))
    681694        {
    682695            _last_keyframe_seen = _frames_seen_count;
    683             HandleKeyframe(_frames_written_count);
     696            HandleKeyframe(_payload_buffer.size());
    684697            hasKeyFrame = true;
    685698        }
    686699
    bool DTVRecorder::FindOtherKeyframes(const TSPacket *tspacket)  
    708721    UpdateFramesWritten();
    709722    _last_keyframe_seen = _frames_seen_count;
    710723
    711     HandleKeyframe(_frames_written_count);
     724    HandleKeyframe(_payload_buffer.size());
    712725
    713726    _has_written_other_keyframe = true;
    714727
    bool DTVRecorder::FindOtherKeyframes(const TSPacket *tspacket)  
    719732 *  \brief This save the current frame to the position maps
    720733 *         and handles ringbuffer switching.
    721734 */
    722 void DTVRecorder::HandleKeyframe(uint64_t frameNum, int64_t extra)
     735void DTVRecorder::HandleKeyframe(int64_t extra)
    723736{
    724737    if (!ringBuffer)
    725738        return;
    726739
    727 #if 0
    728     unsigned long long frameNum = _frames_written_count;
    729 #endif
     740    // Perform ringbuffer switch if needed.
     741    CheckForRingBufferSwitch();
    730742
     743    uint64_t frameNum = _frames_written_count;
    731744    _first_keyframe = (_first_keyframe < 0) ? frameNum : _first_keyframe;
    732745
    733746    // Add key frame to position map
    734747    positionMapLock.lock();
    735748    if (!positionMap.contains(frameNum))
    736749    {
    737         long long startpos = ringBuffer->GetWritePosition();
    738         // FIXME: handle keyframes with start code spanning over two ts packets
    739         startpos += _payload_buffer.size() - extra;
     750        int64_t startpos = ringBuffer->GetWritePosition() + extra;
    740751
    741752        // Don't put negative offsets into the database, they get munged into
    742753        // MAX_INT64 - offset, which is an exceedingly large number, and
    void DTVRecorder::HandleKeyframe(uint64_t frameNum, int64_t extra)  
    750761        }
    751762    }
    752763    positionMapLock.unlock();
    753 
    754     // Perform ringbuffer switch if needed.
    755     CheckForRingBufferSwitch();
    756764}
    757765
    758766/** \fn DTVRecorder::FindH264Keyframes(const TSPacket*)
    void DTVRecorder::HandleKeyframe(uint64_t frameNum, int64_t extra)  
    762770 */
    763771bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)
    764772{
     773    if (!tspacket->HasPayload()) // no payload to scan
     774        return _first_keyframe >= 0;
     775
    765776    if (!ringBuffer)
    766777    {
    767778        LOG(VB_GENERAL, LOG_ERR, LOC + "FindH264Keyframes: No ringbuffer");
    768         return false;
     779        return _first_keyframe >= 0;
    769780    }
    770781
    771     bool haveBufferedData = !_payload_buffer.empty();
    772     if (!tspacket->HasPayload()) // no payload to scan
    773         return !haveBufferedData;
    774 
    775782    const bool payloadStart = tspacket->PayloadStart();
    776783    if (payloadStart)
    777784    {
    bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)  
    790797
    791798    // scan for PES packets and H.264 NAL units
    792799    uint i = tspacket->AFCOffset();
    793     for (; i < TSPacket::kSize; i++)
     800    for (; i < TSPacket::kSize; ++i)
    794801    {
    795802        // special handling required when a new PES packet begins
    796803        if (payloadStart && !_pes_synced)
    bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)  
    858865
    859866        // scan for a NAL unit start code
    860867
    861         uint32_t bytes_used = m_h264_parser.addBytes(
    862             tspacket->data() + i, TSPacket::kSize - i,
    863             ringBuffer->GetWritePosition() + _payload_buffer.size()
    864             );
     868        uint32_t bytes_used = m_h264_parser.addBytes
     869                              (tspacket->data() + i, TSPacket::kSize - i,
     870                               ringBuffer->GetWritePosition());
    865871        i += (bytes_used - 1);
    866872
    867873        if (m_h264_parser.stateChanged())
    bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)  
    879885                frameRate = m_h264_parser.frameRate();
    880886            }
    881887        }
    882     } // for (; i < TSPacket::kSize; i++)
     888    } // for (; i < TSPacket::kSize; ++i)
    883889
    884890    if (hasKeyFrame)
    885891    {
     892#if 0
     893        LOG(VB_RECORD, LOG_ERR, LOC + QString
     894            ("Keyframe @ %1 + %2 = %3 AU %4")
     895            .arg(ringBuffer->GetWritePosition())
     896            .arg(_payload_buffer.size())
     897            .arg(ringBuffer->GetWritePosition() + _payload_buffer.size())
     898            .arg(m_h264_parser.keyframeAUstreamOffset()));
     899#endif
    886900        _last_keyframe_seen = _frames_seen_count;
    887901        HandleH264Keyframe();
    888902    }
    889903
    890904    if (hasFrame)
    891905    {
     906#if 0
     907        LOG(VB_RECORD, LOG_ERR, LOC + QString
     908            ("Frame @ %1 + %2 = %3 AU %4")
     909            .arg(ringBuffer->GetWritePosition())
     910            .arg(_payload_buffer.size())
     911            .arg(ringBuffer->GetWritePosition() + _payload_buffer.size())
     912            .arg(m_h264_parser.keyframeAUstreamOffset()));
     913#endif
     914        _buffer_packets = false;  // We now know if this is a keyframe
    892915        _frames_seen_count++;
    893916        if (!_wait_for_keyframe_option || _first_keyframe >= 0)
    894917            UpdateFramesWritten();
     918        else
     919        {
     920            /* Found a frame that is not a keyframe, and we want to
     921             * start on a keyframe */
     922            _payload_buffer.clear();
     923        }
    895924    }
    896925
    897926    if ((aspectRatio > 0) && (aspectRatio != m_videoAspect))
    bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)  
    909938
    910939    if (frameRate != 0 && frameRate != m_frameRate)
    911940    {
    912 
    913941        LOG(VB_RECORD, LOG_INFO, LOC +
    914942            QString("FindH264Keyframes: timescale: %1, tick: %2, framerate: %3")
    915943                      .arg( m_h264_parser.GetTimeScale() )
    bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)  
    919947        FrameRateChange(frameRate, _frames_written_count);
    920948    }
    921949
    922     return hasKeyFrame || (_payload_buffer.size() >= (188*50));
     950    return _seen_sps;
    923951}
    924952
    925953/** \fn DTVRecorder::HandleH264Keyframe(void)
    bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)  
    928956 */
    929957void DTVRecorder::HandleH264Keyframe(void)
    930958{
    931     unsigned long long frameNum = _frames_written_count;
     959    // Perform ringbuffer switch if needed.
     960    CheckForRingBufferSwitch();
    932961
    933     _first_keyframe = (_first_keyframe < 0) ? frameNum : _first_keyframe;
     962    uint64_t startpos;
     963    uint64_t frameNum = _frames_written_count;
     964
     965    if (_first_keyframe < 0)
     966    {
     967        _first_keyframe = frameNum;
     968        startpos = 0;
     969    }
     970    else
     971        startpos = m_h264_parser.keyframeAUstreamOffset();
    934972
    935973    // Add key frame to position map
    936974    positionMapLock.lock();
    937975    if (!positionMap.contains(frameNum))
    938976    {
    939         positionMapDelta[frameNum] = m_h264_parser.keyframeAUstreamOffset();
    940         positionMap[frameNum]      = m_h264_parser.keyframeAUstreamOffset();
     977        positionMapDelta[frameNum] = startpos;
     978        positionMap[frameNum]      = startpos;
    941979        durationMap[frameNum]      = _total_duration / 1000;
    942980        durationMapDelta[frameNum] = _total_duration / 1000;
    943981    }
    944982    positionMapLock.unlock();
    945 
    946     // Perform ringbuffer switch if needed.
    947     CheckForRingBufferSwitch();
    948983}
    949984
    950985void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len)
    void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len)  
    10651100        if (hasKeyFrame)
    10661101        {
    10671102            _last_keyframe_seen = _frames_seen_count;
    1068             HandleKeyframe(_frames_written_count, bufptr - bufstart);
     1103            HandleKeyframe(_payload_buffer.size() - (bufptr - bufstart));
    10691104        }
    10701105
    10711106        if ((aspectRatio > 0) && (aspectRatio != m_videoAspect))
    void DTVRecorder::HandlePAT(const ProgramAssociationTable *_pat)  
    11491184
    11501185    if (!pmtpid)
    11511186    {
    1152         LOG(VB_RECORD, LOG_ERR, LOC + "SetPAT(): "
    1153             "Ignoring PAT not containing our desired program...");
     1187        LOG(VB_RECORD, LOG_ERR, LOC +
     1188            QString("SetPAT(): Ignoring PAT not containing our desired "
     1189                    "program (%1)...").arg(progNum));
    11541190        return;
    11551191    }
    11561192
    void DTVRecorder::HandlePAT(const ProgramAssociationTable *_pat)  
    11621198    delete oldpat;
    11631199
    11641200    // Listen for the other PMTs for faster channel switching
    1165     for (uint i = 0; _input_pat && (i < _input_pat->ProgramCount()); i++)
     1201    for (uint i = 0; _input_pat && (i < _input_pat->ProgramCount()); ++i)
    11661202    {
    11671203        uint pmt_pid = _input_pat->ProgramPID(i);
    11681204        if (!_stream_data->IsListeningPID(pmt_pid))
    void DTVRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt)  
    11831219        QString sistandard = GetSIStandard();
    11841220
    11851221        bool has_no_av = true;
    1186         for (uint i = 0; i < _input_pmt->StreamCount() && has_no_av; i++)
     1222        for (uint i = 0; i < _input_pmt->StreamCount() && has_no_av; ++i)
    11871223        {
    11881224            has_no_av &= !_input_pmt->IsVideo(i, sistandard);
    11891225            has_no_av &= !_input_pmt->IsAudio(i, sistandard);
    void DTVRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat)  
    12101246    pat->tsheader()->SetContinuityCounter(next_cc);
    12111247    pat->GetAsTSPackets(_scratch, next_cc);
    12121248
    1213     for (uint i = 0; i < _scratch.size(); i++)
     1249    for (uint i = 0; i < _scratch.size(); ++i)
    12141250        DTVRecorder::BufferedWrite(_scratch[i]);
    12151251}
    12161252
    void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)  
    12231259    }
    12241260
    12251261    // collect stream types for H.264 (MPEG-4 AVC) keyframe detection
    1226     for (uint i = 0; i < pmt->StreamCount(); i++)
     1262    for (uint i = 0; i < pmt->StreamCount(); ++i)
    12271263        _stream_id[pmt->StreamPID(i)] = pmt->StreamType(i);
    12281264
    12291265    if (!ringBuffer)
    void DTVRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)  
    12331269    pmt->tsheader()->SetContinuityCounter(next_cc);
    12341270    pmt->GetAsTSPackets(_scratch, next_cc);
    12351271
    1236     for (uint i = 0; i < _scratch.size(); i++)
     1272    for (uint i = 0; i < _scratch.size(); ++i)
    12371273        DTVRecorder::BufferedWrite(_scratch[i]);
    12381274}
    12391275
    bool DTVRecorder::ProcessTSPacket(const TSPacket &tspacket)  
    12601296    // Only create fake keyframe[s] if there are no audio/video streams
    12611297    if (_input_pmt && _has_no_av)
    12621298    {
    1263         _buffer_packets = !FindOtherKeyframes(&tspacket);
     1299        FindOtherKeyframes(&tspacket);
     1300        _buffer_packets = false;
    12641301    }
    12651302    else
    12661303    {
    bool DTVRecorder::ProcessVideoTSPacket(const TSPacket &tspacket)  
    12841321
    12851322    uint streamType = _stream_id[tspacket.PID()];
    12861323
    1287     // Check for keyframes and count frames
    1288     if (streamType == StreamID::H264Video)
     1324    if (tspacket.HasPayload() && tspacket.PayloadStart())
    12891325    {
    1290         _buffer_packets = !FindH264Keyframes(&tspacket);
    1291         if (_wait_for_keyframe_option && !_seen_sps)
    1292             return true;
     1326        // buffer packets until we know if this is a keyframe
     1327        _buffer_packets = true;
     1328#if 0
     1329        LOG(VB_RECORD, LOG_ERR, LOC + QString
     1330            ("ProcessVideoTSPacket PayloadStart @ %1 + %2 = %3")
     1331            .arg(ringBuffer->GetWritePosition())
     1332            .arg(_payload_buffer.size())
     1333            .arg(ringBuffer->GetWritePosition() + _payload_buffer.size()));
     1334#endif
    12931335    }
     1336
     1337    // Check for keyframes and count frames
     1338    if (streamType == StreamID::H264Video)
     1339        FindH264Keyframes(&tspacket);
     1340    else if (streamType != 0)
     1341        FindMPEG2Keyframes(&tspacket);
    12941342    else
    1295     {
    1296         _buffer_packets = !FindMPEG2Keyframes(&tspacket);
    1297     }
     1343        LOG(VB_RECORD, LOG_ERR, LOC +
     1344            "ProcessVideoTSPacket: unknown stream type!");
    12981345
    12991346    return ProcessAVTSPacket(tspacket);
    13001347}
    bool DTVRecorder::ProcessAudioTSPacket(const TSPacket &tspacket)  
    13041351    if (!ringBuffer)
    13051352        return true;
    13061353
    1307     _buffer_packets = !FindAudioKeyframes(&tspacket);
     1354    if (tspacket.HasPayload() && tspacket.PayloadStart())
     1355    {
     1356        // buffer packets until we know if this is a keyframe
     1357        _buffer_packets = true;
     1358#if 0
     1359        LOG(VB_RECORD, LOG_ERR, LOC + QString
     1360            ("ProcessAudioTSPacket PayloadStart @ %1 + %2 = %3")
     1361            .arg(ringBuffer->GetWritePosition())
     1362            .arg(_payload_buffer.size())
     1363            .arg(ringBuffer->GetWritePosition() + _payload_buffer.size()));
     1364#endif
     1365    }
     1366
     1367    FindAudioKeyframes(&tspacket);
    13081368    return ProcessAVTSPacket(tspacket);
    13091369}
    13101370
    13111371/// Common code for processing either audio or video packets
    13121372bool DTVRecorder::ProcessAVTSPacket(const TSPacket &tspacket)
    13131373{
     1374    // Sync recording start to first keyframe
     1375    if (!_buffer_packets && _wait_for_keyframe_option && _first_keyframe < 0)
     1376        return true;
     1377
    13141378    const uint pid = tspacket.PID();
    13151379
    13161380    if (pid != 0x1fff)
    bool DTVRecorder::ProcessAVTSPacket(const TSPacket &tspacket)  
    13281392                .arg(erate,5,'f',2));
    13291393    }
    13301394
    1331     // Sync recording start to first keyframe
    1332     if (_wait_for_keyframe_option && _first_keyframe < 0)
    1333         return true;
    1334 
    13351395    // Sync streams to the first Payload Unit Start Indicator
    13361396    // _after_ first keyframe iff _wait_for_keyframe_option is true
    13371397    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..b12d0ce 100644
    a b 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