diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp index 3eb42c7..41baca6 100644 --- a/mythtv/libs/libmythtv/avformatdecoder.cpp +++ b/mythtv/libs/libmythtv/avformatdecoder.cpp @@ -3108,7 +3108,7 @@ int AvFormatDecoder::H264PreProcessPkt(AVStream *stream, AVPacket *pkt) { buf += m_h264_parser->addBytes(buf, buf_end - buf, 0); - if (m_h264_parser->stateChanged()) + if (m_h264_parser->stateChanged() && m_h264_parser->seen_SPS()) { if (m_h264_parser->FieldType() != H264Parser::FIELD_BOTTOM) { diff --git a/mythtv/libs/libmythtv/mpeg/H264Parser.cpp b/mythtv/libs/libmythtv/mpeg/H264Parser.cpp index 3e45c60..e761138 100644 --- a/mythtv/libs/libmythtv/mpeg/H264Parser.cpp +++ b/mythtv/libs/libmythtv/mpeg/H264Parser.cpp @@ -98,7 +98,7 @@ H264Parser::H264Parser(void) rbsp_buffer_size = 0; Reset(); - I_is_keyframe = true; + I_is_keyframe = false; au_contains_keyframe_message = false; } @@ -116,14 +116,14 @@ void H264Parser::Reset(void) prev_pic_parameter_set_id = pic_parameter_set_id = -1; prev_field_pic_flag = field_pic_flag = -1; prev_bottom_field_flag = bottom_field_flag = -1; - prev_nal_ref_idc = nal_ref_idc = 0; + prev_nal_ref_idc = nal_ref_idc = 111; // != [0|1|2|3] prev_pic_order_cnt_type = pic_order_cnt_type = prev_pic_order_cnt_lsb = pic_order_cnt_lsb = 0; prev_delta_pic_order_cnt_bottom = delta_pic_order_cnt_bottom = 0; prev_delta_pic_order_cnt[0] = delta_pic_order_cnt[0] = 0; prev_delta_pic_order_cnt[1] = delta_pic_order_cnt[1] = 0; prev_nal_unit_type = nal_unit_type = UNKNOWN; - prev_idr_pic_id = idr_pic_id = 0; + prev_idr_pic_id = idr_pic_id = 111; // != [0|1|2|3] log2_max_frame_num = log2_max_pic_order_cnt_lsb = 0; seq_parameter_set_id = 0; @@ -401,6 +401,7 @@ uint32_t H264Parser::addBytes(const uint8_t *bytes, const uint8_t *startP = bytes; const uint8_t *endP; bool found_start_code; + bool good_nal_unit; state_changed = false; on_frame = false; @@ -474,23 +475,41 @@ uint32_t H264Parser::addBytes(const uint8_t *bytes, nal_unit_type = sync_accumulator & 0x1f; nal_ref_idc = (sync_accumulator >> 5) & 0x3; - if (nal_unit_type == SPS || nal_unit_type == PPS || - nal_unit_type == SEI || NALisSlice(nal_unit_type)) - { - /* This is a NAL we need to parse. We may have the body - * of it in the part of the stream past to us this call, - * or we may get the rest in subsequent calls to addBytes. - * Either way, we set have_unfinished_NAL, so that we - * start filling the rbsp buffer */ - have_unfinished_NAL = true; - } - else if (nal_unit_type == AU_DELIMITER || - (nal_unit_type > SPS_EXT && - nal_unit_type < AUXILIARY_SLICE)) +/* nal_ref_idc shall be equal to 0 for all NAL units having nal_unit_type equal to 6, 9, 10, 11, or 12. + */ + good_nal_unit = true; + if (nal_ref_idc && (nal_unit_type == SEI || (nal_unit_type >= AU_DELIMITER && + nal_unit_type <= FILLER_DATA)) ) + good_nal_unit = false; + +/* nal_ref_idc shall not be equal to 0 for NAL units with nal_unit_type equal to 5 + */ + if (!nal_ref_idc && (nal_unit_type == SLICE_IDR)) + good_nal_unit = false; + + if (good_nal_unit) { - set_AU_pending(); + if (nal_unit_type == SPS || nal_unit_type == PPS || + nal_unit_type == SEI || NALisSlice(nal_unit_type)) + { + /* This is a NAL we need to parse. We may have the body + * of it in the part of the stream past to us this call, + * or we may get the rest in subsequent calls to addBytes. + * Either way, we set have_unfinished_NAL, so that we + * start filling the rbsp buffer */ + have_unfinished_NAL = true; + } + else if (nal_unit_type == AU_DELIMITER || + (nal_unit_type > SPS_EXT && + nal_unit_type < AUXILIARY_SLICE)) + { + set_AU_pending(); + } } - } + else + LOG(VB_GENERAL, LOG_ERR, + "H264Parser::addbytes: malformed NAL units"); + } //found start code } return startP - bytes; @@ -523,6 +542,9 @@ void H264Parser::processRBSP(bool rbsp_complete) set_AU_pending(); + if (!seen_sps) + SPS_offset = pkt_offset; + decode_SPS(&gb); } else if (nal_unit_type == PPS) @@ -576,6 +598,8 @@ void H264Parser::processRBSP(bool rbsp_complete) */ bool H264Parser::decode_Header(GetBitContext *gb) { + uint first_mb_in_slice; + is_keyframe = false; if (log2_max_frame_num == 0 || pic_order_present_flag == -1) @@ -601,8 +625,7 @@ bool H264Parser::decode_Header(GetBitContext *gb) that precedes the current slice in decoding order and has the same value of colour_plane_id. */ - //uint first_mb_in_slice = get_ue_golomb(gb); - get_ue_golomb(gb); // Replaced above line + first_mb_in_slice = get_ue_golomb_long(gb); /* slice_type specifies the coding type of the slice according to @@ -611,8 +634,10 @@ bool H264Parser::decode_Header(GetBitContext *gb) When nal_unit_type is equal to 5 (IDR picture), slice_type shall be equal to 2, 4, 7, or 9 (I or SI) */ - slice_type = get_ue_golomb(gb); + slice_type = get_ue_golomb_31(gb); + /* s->pict_type = golomb_to_pict_type[slice_type % 5]; + */ /* pic_parameter_set_id specifies the picture parameter set in use. The value of pic_parameter_set_id shall be in the range of @@ -642,6 +667,8 @@ bool H264Parser::decode_Header(GetBitContext *gb) bitstream.... If the current picture is an IDR picture, frame_num shall be equal to 0. + + When max_num_ref_frames is equal to 0, slice_type shall be equal to 2, 4, 7, or 9. */ frame_num = get_bits(gb, log2_max_frame_num); @@ -683,9 +710,10 @@ bool H264Parser::decode_Header(GetBitContext *gb) { idr_pic_id = get_ue_golomb(gb); is_keyframe = true; + I_is_keyframe = true; } else - is_keyframe |= I_is_keyframe && isKeySlice(slice_type); + is_keyframe |= isKeySlice(slice_type); /* pic_order_cnt_lsb specifies the picture order count modulo MaxPicOrderCntLsb for the top field of a coded frame or for a coded @@ -702,7 +730,7 @@ bool H264Parser::decode_Header(GetBitContext *gb) { pic_order_cnt_lsb = get_bits(gb, log2_max_pic_order_cnt_lsb); - if (pic_order_present_flag && !field_pic_flag) + if ((pic_order_present_flag == 1) && !field_pic_flag) delta_pic_order_cnt_bottom = get_se_golomb(gb); else delta_pic_order_cnt_bottom = 0; @@ -731,13 +759,17 @@ bool H264Parser::decode_Header(GetBitContext *gb) { delta_pic_order_cnt[0] = get_se_golomb(gb); - if (pic_order_present_flag && !field_pic_flag) + if ((pic_order_present_flag == 1) && !field_pic_flag) delta_pic_order_cnt[1] = get_se_golomb(gb); - else + } + else + { + if (pic_order_cnt_type == 1) + { delta_pic_order_cnt[1] = 0; - } - else - delta_pic_order_cnt[0] = 0; + delta_pic_order_cnt[0] = 0; + } + } /* redundant_pic_cnt shall be equal to 0 for slices and slice data @@ -760,10 +792,13 @@ bool H264Parser::decode_Header(GetBitContext *gb) void H264Parser::decode_SPS(GetBitContext * gb) { int profile_idc; + int lastScale; + int nextScale; + int deltaScale; seen_sps = true; - profile_idc = get_bits(gb, 8); // profile_idc + profile_idc = get_bits(gb, 8); get_bits1(gb); // constraint_set0_flag get_bits1(gb); // constraint_set1_flag get_bits1(gb); // constraint_set2_flag @@ -772,9 +807,11 @@ void H264Parser::decode_SPS(GetBitContext * gb) get_bits(gb, 8); // level_idc get_ue_golomb(gb); // sps_id - if (profile_idc >= 100) + if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || + profile_idc == 244 || profile_idc == 44 || profile_idc == 83 || + profile_idc == 86 || profile_idc == 118 || profile_idc == 128 ) { // high profile - if ((chroma_format_idc = get_ue_golomb(gb)) == 3) // chroma_format_idc + if ((chroma_format_idc = get_ue_golomb(gb)) == 3) separate_colour_plane_flag = (get_bits1(gb) == 1); get_ue_golomb(gb); // bit_depth_luma_minus8 @@ -785,12 +822,18 @@ void H264Parser::decode_SPS(GetBitContext * gb) { for (int idx = 0; idx < ((chroma_format_idc != 3) ? 8 : 12); ++idx) { - if (get_bits1(gb)) // Scaling list presnent + if (get_bits1(gb)) // Scaling list present { + lastScale = nextScale = 8; int sl_n = ((idx < 6) ? 16 : 64); - for(int sl_i = 0; sl_i < sl_n; sl_i++) + for(int sl_i = 0; sl_i < sl_n; ++sl_i) { - get_se_golomb(gb); + if (nextScale != 0) + { + deltaScale = get_se_golomb(gb); + nextScale = (lastScale + deltaScale + 256) % 256; + } + lastScale = (nextScale == 0) ? lastScale : nextScale; } } } @@ -809,6 +852,7 @@ void H264Parser::decode_SPS(GetBitContext * gb) int offset_for_non_ref_pic; int offset_for_top_to_bottom_field; uint tmp; + bool gaps_in_frame_num_allowed_flag; /* pic_order_cnt_type specifies the method to decode picture order @@ -886,8 +930,7 @@ void H264Parser::decode_SPS(GetBitContext * gb) decoding process in case of an inferred gap between values of frame_num as specified in subclause 8.2.5.2. */ - //bool gaps_in_frame_num_allowed_flag = get_bits1(gb); - get_bits1(gb); // Replaced above line + gaps_in_frame_num_allowed_flag = get_bits1(gb); /* pic_width_in_mbs_minus1 plus 1 specifies the width of each @@ -1040,20 +1083,28 @@ void H264Parser::decode_SEI(GetBitContext *gb) bool broken_link_flag = false; int changing_group_slice_idc = -1; - int type = 0, size = 0; + int type = 0, size = 0, tmp_byte = 0; /* A message requires at least 2 bytes, and then * there's the stop bit plus alignment, so there * can be no message in less than 24 bits */ while (get_bits_left(gb) >= 24) { - do { - type += show_bits(gb, 8); - } while (get_bits(gb, 8) == 255); + tmp_byte = get_bits(gb, 8); + while (tmp_byte == 255) + { + type += 255; + tmp_byte = get_bits(gb, 8); + } + type += get_bits(gb, 8); //last_payload_type_byte - do { - size += show_bits(gb, 8); - } while (get_bits(gb, 8) == 255); + tmp_byte = get_bits(gb, 8); + while (tmp_byte == 255) + { + size += 255; + tmp_byte = get_bits(gb, 8); + } + size += get_bits(gb, 8); //last_payload_size_byte switch (type) { @@ -1063,6 +1114,8 @@ void H264Parser::decode_SEI(GetBitContext *gb) broken_link_flag = get_bits1(gb); changing_group_slice_idc = get_bits(gb, 2); au_contains_keyframe_message = (recovery_frame_cnt == 0); + if ((size - 12) > 0) + skip_bits(gb, (size - 12) * 8); return; default: diff --git a/mythtv/libs/libmythtv/mpeg/H264Parser.h b/mythtv/libs/libmythtv/mpeg/H264Parser.h index 9c984e0..7b750f2 100644 --- a/mythtv/libs/libmythtv/mpeg/H264Parser.h +++ b/mythtv/libs/libmythtv/mpeg/H264Parser.h @@ -60,7 +60,7 @@ class H264Parser { // ITU-T Rec. H.264 table 7-1 enum NAL_unit_type { UNKNOWN = 0, - SLICE = 1, + SLICE = 1, // 1 - 5 are VCL NAL units SLICE_DPA = 2, SLICE_DPB = 3, SLICE_DPC = 4, @@ -73,11 +73,15 @@ class H264Parser { END_STREAM = 11, FILLER_DATA = 12, SPS_EXT = 13, - AUXILIARY_SLICE = 19 + NALU_prefix = 14, + SPS_subset = 15, + AUXILIARY_SLICE = 19, + SLICE_EXTENSION = 20 }; enum SEI_type { SEI_TYPE_PIC_TIMING = 1, + SEI_FILLER_PAYLOAD = 3, SEI_TYPE_USER_DATA_UNREGISTERED = 5, SEI_TYPE_RECOVERY_POINT = 6 }; @@ -147,7 +151,9 @@ class H264Parser { uint64_t frameAUstreamOffset(void) const {return frame_start_offset;} uint64_t keyframeAUstreamOffset(void) const {return keyframe_start_offset;} + uint64_t SPSstreamOffset(void) const {return SPS_offset;} +// == NAL_type AU_delimiter: primary_pic_type = 5 static int isKeySlice(uint slice_type) { return (slice_type == SLICE_I || @@ -164,6 +170,7 @@ class H264Parser { } void use_I_forKeyframes(bool val) { I_is_keyframe = val; } + bool using_I_forKeyframes(void) const { return I_is_keyframe; } uint32_t GetTimeScale(void) const { return timeScale; } @@ -172,6 +179,10 @@ class H264Parser { void parse_SPS(uint8_t *sps, uint32_t sps_size, bool& interlaced, int32_t& max_ref_frames); + bool seen_SPS(void) const { return seen_sps; } + + bool found_AU(void) const { return AU_pending; } + private: enum constants {EXTENDED_SAR = 255}; @@ -247,6 +258,7 @@ class H264Parser { bool fixedRate; uint64_t pkt_offset, AU_offset, frame_start_offset, keyframe_start_offset; + uint64_t SPS_offset; bool on_frame, on_key_frame; }; diff --git a/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp b/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp index e25774d..21707ce 100644 --- a/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp +++ b/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp @@ -64,7 +64,7 @@ DTVRecorder::DTVRecorder(TVRec *rec) : _pes_synced(false), _seen_sps(false), // settings - _wait_for_keyframe_option(true), + _wait_for_keyframe_option(true), // is wait_for_SPS for H264 _has_written_other_keyframe(false), // state _error(), @@ -195,7 +195,7 @@ void DTVRecorder::ResetForNewFile(void) _repeat_pict = 0; //_pes_synced - //_seen_sps + _seen_sps = false; positionMap.clear(); positionMapDelta.clear(); durationMap.clear(); @@ -276,9 +276,8 @@ void DTVRecorder::BufferedWrite(const TSPacket &tspacket, bool insert) { if (!insert) // PAT/PMT may need inserted in front of any buffered data { - // delay until first GOP to avoid decoder crash on res change - if (!_buffer_packets && _wait_for_keyframe_option && - _first_keyframe < 0) + // delay until first SPS/GOP to avoid decoder crash on res change + if (!_buffer_packets && _wait_for_keyframe_option && !_seen_sps) return; if (curRecording && timeOfFirstDataIsSet.testAndSetRelaxed(0,1)) @@ -461,6 +460,7 @@ bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) } else if (PESStreamID::SequenceStartCode == stream_id) { + _seen_sps = true; // for mpeg2vid ==SeqStartHeader _last_seq_seen = _frames_seen_count; hasKeyFrame |= (_last_gop_seen + maxKFD)<_frames_seen_count; @@ -532,6 +532,12 @@ bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) } } + // _buffer_packets will only be true if a payload start has been seen + if (_seen_sps || !_wait_for_keyframe_option) + _buffer_packets = false; + else + _payload_buffer.clear(); + if (hasFrame && !hasKeyFrame) { // If we have seen kMaxKeyFrameDistance frames since the @@ -543,8 +549,7 @@ bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) hasKeyFrame &= (_last_seq_seen + maxKFD) < _frames_seen_count; } - // _buffer_packets will only be true if a payload start has been seen - if (hasKeyFrame && (_buffer_packets || _first_keyframe >= 0)) + if (hasKeyFrame) { LOG(VB_RECORD, LOG_DEBUG, LOC + QString ("Keyframe @ %1 + %2 = %3") @@ -553,7 +558,7 @@ bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) .arg(ringBuffer->GetWritePosition() + _payload_buffer.size())); _last_keyframe_seen = _frames_seen_count; - HandleKeyframe(0); + HandleKeyframe(_payload_buffer.size()); } if (hasFrame) @@ -564,16 +569,9 @@ bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) .arg(_payload_buffer.size()) .arg(ringBuffer->GetWritePosition() + _payload_buffer.size())); - _buffer_packets = false; // We now know if it is a keyframe, or not _frames_seen_count++; - if (!_wait_for_keyframe_option || _first_keyframe >= 0) + if (_first_keyframe >= 0) UpdateFramesWritten(); - else - { - /* Found a frame that is not a keyframe, and we want to - * start on a keyframe */ - _payload_buffer.clear(); - } } if ((aspectRatio > 0) && (aspectRatio != m_videoAspect)) @@ -718,6 +716,7 @@ bool DTVRecorder::FindAudioKeyframes(const TSPacket*) _audio_timer.start(); _buffer_packets = false; + _seen_sps = true; // unblock BufferedWrite() _frames_seen_count++; if (1 == (_frames_seen_count & 0x7)) @@ -898,30 +897,38 @@ bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) uint32_t bytes_used = m_h264_parser.addBytes (tspacket->data() + i, TSPacket::kSize - i, ringBuffer->GetWritePosition()); - i += (bytes_used - 1); - if (m_h264_parser.stateChanged()) + if (!_seen_sps && m_h264_parser.seen_SPS()) + _seen_sps = true; + + if (m_h264_parser.stateChanged() && _seen_sps) { if (m_h264_parser.onFrameStart() && m_h264_parser.FieldType() != H264Parser::FIELD_BOTTOM) { hasKeyFrame = m_h264_parser.onKeyFrameStart(); hasFrame = true; - _seen_sps |= hasKeyFrame; - + width = m_h264_parser.pictureWidth(); height = m_h264_parser.pictureHeight(); aspectRatio = m_h264_parser.aspectRatio(); m_h264_parser.getFrameRate(frameRate); } } + + i += (bytes_used - 1); } // for (; i < TSPacket::kSize; ++i) // _buffer_packets will only be true if a payload start has been seen - if (hasKeyFrame && (_buffer_packets || _first_keyframe >= 0)) + if (_seen_sps || !_wait_for_keyframe_option) + _buffer_packets = false; + else + _payload_buffer.clear(); + + if (hasKeyFrame) { LOG(VB_RECORD, LOG_DEBUG, LOC + QString - ("Keyframe @ %1 + %2 = %3 AU %4") + ("H264Keyframe @ %1 + %2 = %3 AU %4") .arg(ringBuffer->GetWritePosition()) .arg(_payload_buffer.size()) .arg(ringBuffer->GetWritePosition() + _payload_buffer.size()) @@ -934,22 +941,15 @@ bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) if (hasFrame) { LOG(VB_RECORD, LOG_DEBUG, LOC + QString - ("Frame @ %1 + %2 = %3 AU %4") + ("H264Frame @ %1 + %2 = %3 AU %4") .arg(ringBuffer->GetWritePosition()) .arg(_payload_buffer.size()) .arg(ringBuffer->GetWritePosition() + _payload_buffer.size()) - .arg(m_h264_parser.keyframeAUstreamOffset())); + .arg(m_h264_parser.frameAUstreamOffset())); - _buffer_packets = false; // We now know if this is a keyframe _frames_seen_count++; - if (!_wait_for_keyframe_option || _first_keyframe >= 0) + if (_first_keyframe >= 0) UpdateFramesWritten(); - else - { - /* Found a frame that is not a keyframe, and we want to - * start on a keyframe */ - _payload_buffer.clear(); - } } if ((aspectRatio > 0) && (aspectRatio != m_videoAspect)) @@ -971,12 +971,12 @@ bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket) QString("FindH264Keyframes: timescale: %1, tick: %2, framerate: %3") .arg( m_h264_parser.GetTimeScale() ) .arg( m_h264_parser.GetUnitsInTick() ) - .arg( frameRate.toDouble() * 1000 ) ); + .arg( frameRate.toDouble() ) ); m_frameRate = frameRate; FrameRateChange(frameRate.toDouble() * 1000, _frames_written_count); } - return _seen_sps; + return hasKeyFrame; } /** \fn DTVRecorder::HandleH264Keyframe(void) @@ -991,15 +991,9 @@ void DTVRecorder::HandleH264Keyframe(void) uint64_t startpos; uint64_t frameNum = _frames_written_count; - if (_first_keyframe < 0) - { - _first_keyframe = frameNum; - startpos = 0; - } - else - startpos = m_h264_parser.keyframeAUstreamOffset(); + startpos = m_h264_parser.keyframeAUstreamOffset(); - // Add key frame to position map + // Add keyframe to position map positionMapLock.lock(); if (!positionMap.contains(frameNum)) { @@ -1008,7 +1002,19 @@ void DTVRecorder::HandleH264Keyframe(void) durationMap[frameNum] = _total_duration + 0.5; durationMapDelta[frameNum] = _total_duration + 0.5; } + if ((_first_keyframe < 0) && !positionMap.contains(0)) + { + positionMapDelta[0] = 0; + positionMap[0] = 0; + durationMap[0] = 0.5; + durationMapDelta[0] = 0.5; + } positionMapLock.unlock(); + + if (_first_keyframe < 0) + { + _first_keyframe = frameNum; + } } void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len) @@ -1074,6 +1080,7 @@ void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len) else if (PESStreamID::SequenceStartCode == stream_id) { // pes_packet_length is meaningless pes_packet_length = -1; + _seen_sps = true; // for mpeg2vid ==SeqStartHeader _last_seq_seen = _frames_seen_count; hasKeyFrame |= (_last_gop_seen + maxKFD)<_frames_seen_count; @@ -1328,6 +1335,7 @@ bool DTVRecorder::ProcessTSPacket(const TSPacket &tspacket) if (_input_pmt && _has_no_av) { FindOtherKeyframes(&tspacket); + _seen_sps = true; // unblock BufferedWrite() _buffer_packets = false; } else @@ -1383,11 +1391,11 @@ bool DTVRecorder::ProcessAudioTSPacket(const TSPacket &tspacket) return ProcessAVTSPacket(tspacket); } -/// Common code for processing either audio or video packets +/// Common code for processing either audio or video packets (mpeg2 or h264) bool DTVRecorder::ProcessAVTSPacket(const TSPacket &tspacket) { - // Sync recording start to first keyframe - if (_wait_for_keyframe_option && _first_keyframe < 0) + // Sync recording start to first SPS / keyframe + if (_wait_for_keyframe_option && !_seen_sps && _first_keyframe < 0) { if (_buffer_packets) BufferedWrite(tspacket);