Ticket #1088: 1088-v1.patch
File 1088-v1.patch, 10.6 KB (added by , 16 years ago) |
---|
-
libs/libmythtv/dtvrecorder.h
51 51 void FinishRecording(void); 52 52 void ResetForNewFile(void); 53 53 54 void HandleKeyframe( );54 void HandleKeyframe(uint64_t extra = 0); 55 55 56 56 void BufferedWrite(const TSPacket &tspacket); 57 57 … … 66 66 void HandleH264Keyframe(void); 67 67 68 68 // 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); 71 70 72 71 // For handling other (non audio/video) packets 73 72 bool FindOtherKeyframes(const TSPacket *tspacket); … … 97 96 98 97 bool _has_written_other_keyframe; 99 98 100 /// Used for PVR-150/250/500 which have a fixed keyframe distance of 12 or 15101 int _keyframedist;102 103 99 // state tracking variables 104 100 /// True iff recording is actually being performed 105 101 bool _recording; -
libs/libmythtv/dtvrecorder.cpp
46 46 _request_recording(false), 47 47 _wait_for_keyframe_option(true), 48 48 _has_written_other_keyframe(false), 49 _keyframedist(15),50 49 // state 51 50 _recording(false), 52 51 _error(false), … … 396 395 nextRingBufferLock.unlock(); 397 396 } 398 397 399 /** \fn DTVRecorder::HandleKeyframe( void)398 /** \fn DTVRecorder::HandleKeyframe(uint64_t) 400 399 * \brief This save the current frame to the position maps 401 400 * and handles ringbuffer switching. 402 401 */ 403 void DTVRecorder::HandleKeyframe( void)402 void DTVRecorder::HandleKeyframe(uint64_t extra) 404 403 { 405 404 if (!ringBuffer) 406 405 return; … … 415 414 { 416 415 long long startpos = ringBuffer->GetWritePosition(); 417 416 // FIXME: handle keyframes with start code spanning over two ts packets 418 startpos += _payload_buffer.size() ;417 startpos += _payload_buffer.size() + extra; 419 418 positionMapDelta[frameNum] = startpos; 420 419 positionMap[frameNum] = startpos; 421 420 } … … 577 576 CheckForRingBufferSwitch(); 578 577 } 579 578 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) 579 void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len) 585 580 { 586 if (!ringBuffer) 587 return; 581 const uint maxKFD = kMaxKeyFrameDistance; 588 582 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; 590 586 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) 596 588 { 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; 604 591 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; 608 595 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 } 609 615 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 } 616 626 617 while (bufptr < buffer + len) 618 { 619 v = *bufptr++; 620 if (_start_code == 0x000001) 627 if (hasKeyFrame) 621 628 { 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 } 624 632 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 } 629 639 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) 632 647 { 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()); 643 650 } 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 } 650 653 651 bufstart += curpos;652 leftlen -= curpos;654 if (ringBuffer) 655 ringBuffer->Write(bufstart, (bufptr - bufstart)); 653 656 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; 672 658 } 673 else674 _start_code = ((_start_code << 8) | v) & 0xFFFFFF;675 659 } 676 660 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); 682 665 } 683 666 684 667 /* vim: set expandtab tabstop=4 shiftwidth=4: */ -
libs/libmythtv/mpegrecorder.cpp
98 98 // TS packet handling 99 99 _stream_data(NULL) 100 100 { 101 SetPositionMapType(MARK_GOP_START);102 101 } 103 102 104 103 MpegRecorder::~MpegRecorder() … … 606 605 return false; 607 606 } 608 607 609 _keyframedist = (ivtvcodec.framerate) ? 12 : _keyframedist;610 611 608 return true; 612 609 } 613 610 … … 706 703 } 707 704 } 708 705 709 if (driver != "hdpvr")710 {711 // Get GOP size in frames712 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 735 706 return true; 736 707 } 737 708 … … 875 846 876 847 if (driver == "hdpvr") 877 848 { 878 SetPositionMapType(MARK_GOP_BYFRAME);879 880 849 int progNum = 1; 881 850 MPEGStreamData *sd = new MPEGStreamData(progNum, true); 882 851 sd->SetRecordingType(_recording_type); … … 891 860 HandleSingleProgramPMT(_stream_data->PMTSingleProgram()); 892 861 _wait_for_keyframe_option = true; 893 862 } 894 else895 {896 SetPositionMapType(MARK_GOP_START);897 }898 863 899 864 encoding = true; 900 865 recording = true; … … 1147 1112 1148 1113 if (curRecording) 1149 1114 { 1150 curRecording->ClearPositionMap( 1151 (driver == "hdpvr") ? MARK_GOP_BYFRAME : MARK_GOP_START); 1115 curRecording->ClearPositionMap(MARK_GOP_BYFRAME); 1152 1116 } 1153 1117 if (_stream_data) 1154 1118 _stream_data->Reset(_stream_data->DesiredProgram());