Ticket #1088: 1088-v1.patch

File 1088-v1.patch, 10.6 KB (added by danielk, 16 years ago)

fix for mpegrecorder

  • libs/libmythtv/dtvrecorder.h

     
    5151    void FinishRecording(void);
    5252    void ResetForNewFile(void);
    5353
    54     void HandleKeyframe();
     54    void HandleKeyframe(uint64_t extra = 0);
    5555
    5656    void BufferedWrite(const TSPacket &tspacket);
    5757
     
    6666    void HandleH264Keyframe(void);
    6767
    6868    // MPEG2 PS support (Hauppauge PVR-x50/PVR-500)
    69     void HandlePSKeyframe(void);
    70     bool FindPSKeyFrames(unsigned char *buffer, int len);
     69    void FindPSKeyFrames(const uint8_t *buffer, uint len);
    7170
    7271    // For handling other (non audio/video) packets
    7372    bool FindOtherKeyframes(const TSPacket *tspacket);
     
    9796
    9897    bool _has_written_other_keyframe;
    9998
    100     /// Used for PVR-150/250/500 which have a fixed keyframe distance of 12 or 15
    101     int _keyframedist;
    102 
    10399    // state tracking variables
    104100    /// True iff recording is actually being performed
    105101    bool _recording;
  • libs/libmythtv/dtvrecorder.cpp

     
    4646    _request_recording(false),
    4747    _wait_for_keyframe_option(true),
    4848    _has_written_other_keyframe(false),
    49     _keyframedist(15),
    5049    // state
    5150    _recording(false),
    5251    _error(false),
     
    396395    nextRingBufferLock.unlock();
    397396}
    398397
    399 /** \fn DTVRecorder::HandleKeyframe(void)
     398/** \fn DTVRecorder::HandleKeyframe(uint64_t)
    400399 *  \brief This save the current frame to the position maps
    401400 *         and handles ringbuffer switching.
    402401 */
    403 void DTVRecorder::HandleKeyframe(void)
     402void DTVRecorder::HandleKeyframe(uint64_t extra)
    404403{
    405404    if (!ringBuffer)
    406405        return;
     
    415414    {
    416415        long long startpos = ringBuffer->GetWritePosition();
    417416        // FIXME: handle keyframes with start code spanning over two ts packets
    418         startpos += _payload_buffer.size();
     417        startpos += _payload_buffer.size() + extra;
    419418        positionMapDelta[frameNum] = startpos;
    420419        positionMap[frameNum]      = startpos;
    421420    }
     
    577576    CheckForRingBufferSwitch();
    578577}
    579578
    580 /** \fn DTVRecorder::HandlePSKeyframe(void)
    581  *  \brief This save the current frame to the position maps
    582  *         and handles ringbuffer switching.
    583  */
    584 void DTVRecorder::HandlePSKeyframe(void)
     579void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len)
    585580{
    586     if (!ringBuffer)
    587         return;
     581    const uint maxKFD = kMaxKeyFrameDistance;
    588582
    589     unsigned long long frameNum = _last_gop_seen;
     583    const uint8_t *bufstart = buffer;
     584    const uint8_t *bufptr   = buffer;
     585    const uint8_t *bufend   = buffer + len;
    590586
    591     _first_keyframe = (_first_keyframe < 0) ? frameNum : _first_keyframe;
    592 
    593     // Add key frame to position map
    594     positionMapLock.lock();
    595     if (!positionMap.contains(frameNum))
     587    while (bufptr < bufend)
    596588    {
    597         long long startpos = ringBuffer->GetWritePosition();
    598         // FIXME: handle keyframes with start code spanning over two ts packets
    599         startpos += _payload_buffer.size();
    600         positionMapDelta[frameNum] = startpos;
    601         positionMap[frameNum]      = startpos;
    602     }
    603     positionMapLock.unlock();
     589        bool hasFrame     = false;
     590        bool hasKeyFrame  = false;
    604591
    605     // Perform ringbuffer switch if needed.
    606     CheckForRingBufferSwitch();
    607 }
     592        bufptr = ff_find_start_code(bufptr, bufend, &_start_code);
     593        if ((_start_code & 0xffffff00) != 0x00000100)
     594            continue;
    608595
     596        const int stream_id = _start_code & 0x000000ff;
     597        if (PESStreamID::PictureStartCode == stream_id)
     598        {
     599            hasFrame = true;
     600        }
     601        else if (PESStreamID::GOPStartCode == stream_id)
     602        {
     603            _last_gop_seen  = _frames_seen_count;
     604            hasKeyFrame    |= true;
     605        }
     606        else if (PESStreamID::SequenceStartCode == stream_id)
     607        {
     608            _last_seq_seen  = _frames_seen_count;
     609            hasKeyFrame    |= (_last_gop_seen + maxKFD)<_frames_seen_count;
     610        }
     611        else if (PESStreamID::PackHeader == stream_id)
     612        {
     613            _start_code = 0xffffffff;
     614        }
    609615
    610 bool DTVRecorder::FindPSKeyFrames(unsigned char *buffer, int len)
    611 {
    612     unsigned char *bufptr = buffer, *bufstart = buffer;
    613     uint v = 0;
    614     int leftlen = len;
    615     bool hasKeyFrame = false;
     616        if (hasFrame && !hasKeyFrame)
     617        {
     618            // If we have seen kMaxKeyFrameDistance frames since the
     619            // last GOP or SEQ stream_id, then pretend this picture
     620            // is a keyframe. We may get artifacts but at least
     621            // we will be able to skip frames.
     622            hasKeyFrame = !(_frames_seen_count & 0xf);
     623            hasKeyFrame &= (_last_gop_seen + maxKFD) < _frames_seen_count;
     624            hasKeyFrame &= (_last_seq_seen + maxKFD) < _frames_seen_count;
     625        }
    616626
    617     while (bufptr < buffer + len)
    618     {
    619         v = *bufptr++;
    620         if (_start_code == 0x000001)
     627        if (hasKeyFrame)
    621628        {
    622             _start_code = ((_start_code << 8) | v) & 0xFFFFFF;
    623             const int stream_id = _start_code & 0x000000ff;
     629            _last_keyframe_seen = _frames_seen_count;
     630            HandleKeyframe(bufstart - bufptr);
     631        }
    624632
    625             if (stream_id == PESStreamID::PackHeader)
    626             {
    627                 _last_keyframe_seen = ringBuffer->GetWritePosition() +
    628                                       _payload_buffer.size();
     633        if (hasFrame)
     634        {
     635            _frames_seen_count++;
     636            if (!_wait_for_keyframe_option || _first_keyframe>=0)
     637                _frames_written_count++;
     638        }
    629639
    630                 int curpos = bufptr - bufstart - 4;
    631                 if (curpos < 0)
     640        if (hasKeyFrame || hasFrame)
     641        {
     642            // We are free to write the packet, but if we have
     643            // buffered packet[s] we have to write them first...
     644            if (!_payload_buffer.empty())
     645            {
     646                if (ringBuffer)
    632647                {
    633                     // header was split
    634                     if (_payload_buffer.size() + curpos > 0)
    635                         ringBuffer->Write(&_payload_buffer[0],
    636                                           _payload_buffer.size() + curpos);
    637 
    638                     _payload_buffer.resize(4);
    639                     memcpy(&_payload_buffer[0], &_start_code, 4);
    640 
    641                     leftlen = leftlen - curpos + 4;
    642                     bufstart = bufptr;
     648                    ringBuffer->Write(
     649                        &_payload_buffer[0], _payload_buffer.size());
    643650                }
    644                 else
    645                 {
    646                     // header was entirely in this packet
    647                     int idx = _payload_buffer.size();
    648                     _payload_buffer.resize(idx + curpos);
    649                     memcpy(&_payload_buffer[idx], bufstart, curpos);
     651                _payload_buffer.clear();
     652            }
    650653
    651                     bufstart += curpos;
    652                     leftlen -= curpos;
     654            if (ringBuffer)
     655                ringBuffer->Write(bufstart, (bufptr - bufstart));
    653656
    654                     if (_payload_buffer.size() > 0)
    655                         ringBuffer->Write(&_payload_buffer[0],
    656                                           _payload_buffer.size());
    657                     _payload_buffer.clear();
    658                 }
    659                 _frames_seen_count++;
    660             }
    661             else if (stream_id == PESStreamID::SequenceStartCode)
    662             {
    663                 _last_seq_seen = _last_keyframe_seen;
    664             }
    665             else if (stream_id == PESStreamID::GOPStartCode &&
    666                      _last_seq_seen == _last_keyframe_seen)
    667             {
    668                 _frames_written_count = _last_gop_seen * _keyframedist;
    669                 _last_gop_seen++;
    670                 HandlePSKeyframe();
    671             }
     657            bufstart = bufptr;
    672658        }
    673         else
    674             _start_code = ((_start_code << 8) | v) & 0xFFFFFF;
    675659    }
    676660
    677     int idx = _payload_buffer.size();
    678     _payload_buffer.resize(idx + leftlen);
    679     memcpy(&_payload_buffer[idx], bufstart, leftlen);
    680 
    681     return hasKeyFrame;
     661    uint64_t idx = _payload_buffer.size();
     662    uint64_t rem = (bufend - bufstart);
     663    _payload_buffer.resize(idx + rem);
     664    memcpy(&_payload_buffer[idx], bufstart, rem);
    682665}
    683666
    684667/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmythtv/mpegrecorder.cpp

     
    9898    // TS packet handling
    9999    _stream_data(NULL)                                   
    100100{
    101     SetPositionMapType(MARK_GOP_START);
    102101}
    103102
    104103MpegRecorder::~MpegRecorder()
     
    606605        return false;
    607606    }
    608607
    609     _keyframedist = (ivtvcodec.framerate) ? 12 : _keyframedist;
    610 
    611608    return true;
    612609}
    613610
     
    706703        }
    707704    }
    708705
    709     if (driver != "hdpvr")
    710     {
    711         // Get GOP size in frames
    712         struct v4l2_ext_control ext_ctrl;
    713         struct v4l2_ext_controls ctrls;
    714 
    715         bzero(&ext_ctrl, sizeof(struct v4l2_ext_control));
    716         bzero(&ctrls, sizeof(struct v4l2_ext_controls));
    717 
    718         ext_ctrl.id    = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
    719         ext_ctrl.value = 0;
    720 
    721         ctrls.ctrl_class  = V4L2_CTRL_CLASS_MPEG;
    722         ctrls.count       = 1;
    723         ctrls.controls    = &ext_ctrl;
    724 
    725         if (ioctl(chanfd, VIDIOC_G_EXT_CTRLS, &ctrls) < 0)
    726         {
    727             VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to get "
    728                     "V4L2_CID_MPEG_VIDEO_GOP_SIZE, defaulting to 12" + ENO);
    729             ext_ctrl.value = 12;
    730         }
    731 
    732         _keyframedist = ext_ctrl.value;
    733     }
    734 
    735706    return true;
    736707}
    737708
     
    875846
    876847    if (driver == "hdpvr")
    877848    {
    878         SetPositionMapType(MARK_GOP_BYFRAME);
    879 
    880849        int progNum = 1;
    881850        MPEGStreamData *sd = new MPEGStreamData(progNum, true);
    882851        sd->SetRecordingType(_recording_type);
     
    891860        HandleSingleProgramPMT(_stream_data->PMTSingleProgram());
    892861        _wait_for_keyframe_option = true;
    893862    }
    894     else
    895     {
    896         SetPositionMapType(MARK_GOP_START);
    897     }
    898863
    899864    encoding = true;
    900865    recording = true;
     
    11471112
    11481113    if (curRecording)
    11491114    {
    1150         curRecording->ClearPositionMap(
    1151             (driver == "hdpvr") ? MARK_GOP_BYFRAME : MARK_GOP_START);
     1115        curRecording->ClearPositionMap(MARK_GOP_BYFRAME);
    11521116    }
    11531117    if (_stream_data)
    11541118        _stream_data->Reset(_stream_data->DesiredProgram());