diff --git a/src/Extension/Frame.cpp b/src/Extension/Frame.cpp index 62965553..2b25ea19 100644 --- a/src/Extension/Frame.cpp +++ b/src/Extension/Frame.cpp @@ -192,10 +192,11 @@ bool FrameMerger::willFlush(const Frame::Ptr &frame) const{ switch (frame->getCodecId()) { case CodecH264 : { auto type = H264_TYPE(frame->data()[frame->prefixSize()]); - if ((frame->data()[frame->prefixSize()+1]&0x80) !=0 && type >=H264Frame::NAL_B_P && type<=H264Frame::NAL_IDR ) {// sei aud pps sps 不判断 + if ((frame->data()[frame->prefixSize() + 1] & 0x80) != 0 && type >= H264Frame::NAL_B_P && + type <= H264Frame::NAL_IDR) {// sei aud pps sps 不判断 //264 新一帧的开始,刷新输出 return true; - }else{ + } else { // 不刷新输出 return false; } @@ -203,10 +204,11 @@ bool FrameMerger::willFlush(const Frame::Ptr &frame) const{ } case CodecH265 : { auto type = H265_TYPE(frame->data()[frame->prefixSize()]); - if ((type>=H265Frame::NAL_TRAIL_R &&type<= H265Frame::NAL_RSV_IRAP_VCL23) && ( (frame->data()[frame->prefixSize()+2]>>7 & 0x01) != 0)) { + if ((type >= H265Frame::NAL_TRAIL_R && type <= H265Frame::NAL_RSV_IRAP_VCL23) && + ((frame->data()[frame->prefixSize() + 2] >> 7 & 0x01) != 0)) { //first_slice_segment_in_pic_flag is frame start return true; - }else{ + } else { return false; } break; @@ -244,64 +246,68 @@ void FrameMerger::doMerge(BufferLikeString &merged, const Frame::Ptr &frame) con default: /*不可达*/ assert(0); break; } } + bool FrameMerger::shouldDrop(const Frame::Ptr &frame) const{ switch (frame->getCodecId()) { - case CodecH264:{ - auto type = H264_TYPE(frame->data()[frame->prefixSize()]); - if(type == H264Frame::NAL_SEI || type == H264Frame::NAL_AUD){ - // 防止吧AUD或者SEI当成一帧 - return true; - } - break; - } - case CodecH265: { - //如果是新的一帧,前面的缓存需要输出 - auto type = H265_TYPE(frame->data()[frame->prefixSize()]); - if(type == H265Frame::NAL_AUD || type == H265Frame::NAL_SEI_PREFIX || type == H265Frame::NAL_SEI_SUFFIX){ - // 防止吧AUD或者SEI当成一帧 - return true; - } - break; - } - default: break; + case CodecH264: { + auto type = H264_TYPE(frame->data()[frame->prefixSize()]); + if (type == H264Frame::NAL_SEI || type == H264Frame::NAL_AUD) { + // 防止吧AUD或者SEI当成一帧 + return true; } + break; + } + case CodecH265: { + //如果是新的一帧,前面的缓存需要输出 + auto type = H265_TYPE(frame->data()[frame->prefixSize()]); + if (type == H265Frame::NAL_AUD || type == H265Frame::NAL_SEI_PREFIX || type == H265Frame::NAL_SEI_SUFFIX) { + // 防止吧AUD或者SEI当成一帧 + return true; + } + break; + } + default: + break; + } return false; } -bool FrameMerger::frameCacheHasVCL(List &frameCached) const{ + +bool FrameMerger::frameCacheHasVCL(List &frameCached) const { bool hasVCL = false; bool isH264OrH265 = false; - frameCached.for_each([&hasVCL,&isH264OrH265](const Frame::Ptr &frame){ + frameCached.for_each([&hasVCL, &isH264OrH265](const Frame::Ptr &frame) { switch (frame->getCodecId()) { - case CodecH264:{ - auto type = H264_TYPE(frame->data()[frame->prefixSize()]); - if(type >=H264Frame::NAL_B_P && type <= H264Frame::NAL_IDR){ - //有编码数据 - hasVCL=true; - } - isH264OrH265 = true; - break; + case CodecH264: { + auto type = H264_TYPE(frame->data()[frame->prefixSize()]); + if (type >= H264Frame::NAL_B_P && type <= H264Frame::NAL_IDR) { + //有编码数据 + hasVCL = true; } - case CodecH265: { - //如果是新的一帧,前面的缓存需要输出 - auto type = H265_TYPE(frame->data()[frame->prefixSize()]); - if(type>=H265Frame::NAL_TRAIL_R &&type<= H265Frame::NAL_RSV_IRAP_VCL23){ - //有编码数据 - hasVCL=true; - } - isH264OrH265 = true; - break; - } - default: break; + isH264OrH265 = true; + break; } + case CodecH265: { + //如果是新的一帧,前面的缓存需要输出 + auto type = H265_TYPE(frame->data()[frame->prefixSize()]); + if (type >= H265Frame::NAL_TRAIL_R && type <= H265Frame::NAL_RSV_IRAP_VCL23) { + //有编码数据 + hasVCL = true; + } + isH264OrH265 = true; + break; + } + default: + break; + } }); - if(isH264OrH265){ - return hasVCL; + if (isH264OrH265) { + return hasVCL; } return true; - } + void FrameMerger::inputFrame(const Frame::Ptr &frame, const onOutput &cb) { - if(shouldDrop(frame)){ + if (shouldDrop(frame)) { return; } if (willFlush(frame) && frameCacheHasVCL(_frameCached)) { diff --git a/src/Extension/H264Rtmp.cpp b/src/Extension/H264Rtmp.cpp index f3c7734c..b0f2e58d 100644 --- a/src/Extension/H264Rtmp.cpp +++ b/src/Extension/H264Rtmp.cpp @@ -95,22 +95,21 @@ void H264RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) { } if (pkt->buffer.size() > 9) { - auto iTotalLen = pkt->buffer.size(); - size_t iOffset = 5; + auto total_len = pkt->buffer.size(); + size_t offset = 5; uint8_t *cts_ptr = (uint8_t *) (pkt->buffer.data() + 2); int32_t cts = (((cts_ptr[0] << 16) | (cts_ptr[1] << 8) | (cts_ptr[2])) + 0xff800000) ^ 0xff800000; auto pts = pkt->time_stamp + cts; - - while(iOffset + 4 < iTotalLen){ - uint32_t iFrameLen; - memcpy(&iFrameLen, pkt->buffer.data() + iOffset, 4); - iFrameLen = ntohl(iFrameLen); - iOffset += 4; - if(iFrameLen + iOffset > iTotalLen){ + while (offset + 4 < total_len) { + uint32_t frame_len; + memcpy(&frame_len, pkt->buffer.data() + offset, 4); + frame_len = ntohl(frame_len); + offset += 4; + if (frame_len + offset > total_len) { break; } - onGetH264(pkt->buffer.data() + iOffset, iFrameLen, pkt->time_stamp , pts); - iOffset += iFrameLen; + onGetH264(pkt->buffer.data() + offset, frame_len, pkt->time_stamp, pts); + offset += frame_len; } } } @@ -151,79 +150,73 @@ void H264RtmpEncoder::makeConfigPacket(){ if (!_sps.empty() && !_pps.empty()) { //获取到sps/pps makeVideoConfigPkt(); - _gotSpsPps = true; + _got_config_frame = true; } } void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { - auto pcData = frame->data() + frame->prefixSize(); - auto iLen = frame->size() - frame->prefixSize(); - auto type = H264_TYPE(((uint8_t*)pcData)[0]); - if(type == H264Frame::NAL_SEI || type == H264Frame::NAL_AUD){ - return; - } - - if (!_gotSpsPps) { - //尝试从frame中获取sps pps - switch (type) { - case H264Frame::NAL_SPS: { - //sps - _sps = string(pcData, iLen); + auto data = frame->data() + frame->prefixSize(); + auto len = frame->size() - frame->prefixSize(); + auto type = H264_TYPE(((uint8_t*)data)[0]); + switch (type) { + case H264Frame::NAL_SEI: + case H264Frame::NAL_AUD: return; + case H264Frame::NAL_SPS: { + if (!_got_config_frame) { + _sps = string(data, len); makeConfigPacket(); - break; } - case H264Frame::NAL_PPS: { - //pps - _pps = string(pcData, iLen); - makeConfigPacket(); - break; - } - default: - break; + break; } + case H264Frame::NAL_PPS: { + if (!_got_config_frame) { + _pps = string(data, len); + makeConfigPacket(); + } + break; + } + default : break; } - if(frame->configFrame() && _lastPacket &&_lastPacketHasVCL){ + + if (frame->configFrame() && _rtmp_packet && _has_vcl) { //sps pps flush frame - RtmpCodec::inputRtmp(_lastPacket); - _lastPacket = nullptr; - _lastPacketHasVCL = false; + RtmpCodec::inputRtmp(_rtmp_packet); + _has_vcl = false; + _rtmp_packet = nullptr; } - if(_lastPacket && (_lastPacket->time_stamp != frame->dts() || ((pcData[1]&0x80) != 0 && type>=H264Frame::NAL_B_P && type<=H264Frame::NAL_IDR && _lastPacketHasVCL))) { - RtmpCodec::inputRtmp(_lastPacket); - _lastPacket = nullptr; - _lastPacketHasVCL = false; + if (_rtmp_packet && (_rtmp_packet->time_stamp != frame->dts() || ((data[1] & 0x80) != 0 && type >= H264Frame::NAL_B_P && type <= H264Frame::NAL_IDR && _has_vcl))) { + RtmpCodec::inputRtmp(_rtmp_packet); + _has_vcl = false; + _rtmp_packet = nullptr; } - if(type>=H264Frame::NAL_B_P && type<=H264Frame::NAL_IDR){ - _lastPacketHasVCL = true; + if (type >= H264Frame::NAL_B_P && type <= H264Frame::NAL_IDR) { + _has_vcl = true; } - - if(!_lastPacket) { + if (!_rtmp_packet) { //I or P or B frame int8_t flags = FLV_CODEC_H264; bool is_config = false; flags |= (((frame->configFrame() || frame->keyFrame()) ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4); - _lastPacket = RtmpPacket::create(); - _lastPacket->buffer.push_back(flags); - _lastPacket->buffer.push_back(!is_config); + _rtmp_packet = RtmpPacket::create(); + _rtmp_packet->buffer.push_back(flags); + _rtmp_packet->buffer.push_back(!is_config); int32_t cts = frame->pts() - frame->dts(); if (cts < 0) { cts = 0; } cts = htonl(cts); - _lastPacket->buffer.append((char *)&cts + 1, 3); - - _lastPacket->chunk_id = CHUNK_VIDEO; - _lastPacket->stream_index = STREAM_MEDIA; - _lastPacket->time_stamp = frame->dts(); - _lastPacket->type_id = MSG_VIDEO; - + _rtmp_packet->buffer.append((char *) &cts + 1, 3); + _rtmp_packet->chunk_id = CHUNK_VIDEO; + _rtmp_packet->stream_index = STREAM_MEDIA; + _rtmp_packet->time_stamp = frame->dts(); + _rtmp_packet->type_id = MSG_VIDEO; } - uint32_t size = htonl((uint32_t)iLen); - _lastPacket->buffer.append((char *) &size, 4); - _lastPacket->buffer.append(pcData, iLen); - _lastPacket->body_size = _lastPacket->buffer.size(); + uint32_t size = htonl((uint32_t) len); + _rtmp_packet->buffer.append((char *) &size, 4); + _rtmp_packet->buffer.append(data, len); + _rtmp_packet->body_size = _rtmp_packet->buffer.size(); } void H264RtmpEncoder::makeVideoConfigPkt() { diff --git a/src/Extension/H264Rtmp.h b/src/Extension/H264Rtmp.h index c45da3a6..ee59a2fe 100644 --- a/src/Extension/H264Rtmp.h +++ b/src/Extension/H264Rtmp.h @@ -78,10 +78,10 @@ public: private: void makeVideoConfigPkt(); private: + bool _has_vcl = false; + bool _got_config_frame = false; H264Track::Ptr _track; - bool _gotSpsPps = false; - bool _lastPacketHasVCL = false; - RtmpPacket::Ptr _lastPacket; + RtmpPacket::Ptr _rtmp_packet; }; }//namespace mediakit diff --git a/src/Extension/H265.cpp b/src/Extension/H265.cpp index 79248989..883a4839 100644 --- a/src/Extension/H265.cpp +++ b/src/Extension/H265.cpp @@ -64,7 +64,7 @@ bool H265Frame::configFrame() const { } bool H265Frame::isKeyFrame(int type, const char *ptr) { - if(ptr){ + if (ptr) { return (((*((uint8_t *) ptr + 2)) >> 7) & 0x01) == 1 && (type == NAL_IDR_N_LP || type == NAL_IDR_W_RADL); } return false; diff --git a/src/Extension/H265Rtmp.cpp b/src/Extension/H265Rtmp.cpp index e5f2a8ec..4d5c7e61 100644 --- a/src/Extension/H265Rtmp.cpp +++ b/src/Extension/H265Rtmp.cpp @@ -73,22 +73,21 @@ void H265RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) { } if (pkt->buffer.size() > 9) { - auto iTotalLen = pkt->buffer.size(); - size_t iOffset = 5; + auto total_len = pkt->buffer.size(); + size_t offset = 5; uint8_t *cts_ptr = (uint8_t *) (pkt->buffer.data() + 2); int32_t cts = (((cts_ptr[0] << 16) | (cts_ptr[1] << 8) | (cts_ptr[2])) + 0xff800000) ^ 0xff800000; auto pts = pkt->time_stamp + cts; - - while(iOffset + 4 < iTotalLen){ - uint32_t iFrameLen; - memcpy(&iFrameLen, pkt->buffer.data() + iOffset, 4); - iFrameLen = ntohl(iFrameLen); - iOffset += 4; - if(iFrameLen + iOffset > iTotalLen){ + while (offset + 4 < total_len) { + uint32_t frame_len; + memcpy(&frame_len, pkt->buffer.data() + offset, 4); + frame_len = ntohl(frame_len); + offset += 4; + if (frame_len + offset > total_len) { break; } - onGetH265(pkt->buffer.data() + iOffset, iFrameLen, pkt->time_stamp , pts); - iOffset += iFrameLen; + onGetH265(pkt->buffer.data() + offset, frame_len, pkt->time_stamp, pts); + offset += frame_len; } } } @@ -130,87 +129,85 @@ void H265RtmpEncoder::makeConfigPacket(){ if (!_sps.empty() && !_pps.empty() && !_vps.empty()) { //获取到sps/pps makeVideoConfigPkt(); - _gotSpsPps = true; + _got_config_frame = true; } } void H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) { - auto pcData = frame->data() + frame->prefixSize(); - auto iLen = frame->size() - frame->prefixSize(); - auto type = H265_TYPE(((uint8_t*)pcData)[0]); + auto data = frame->data() + frame->prefixSize(); + auto len = frame->size() - frame->prefixSize(); + auto type = H265_TYPE(((uint8_t*)data)[0]); - if (!_gotSpsPps) { - //尝试从frame中获取sps pps - switch (type) { - case H265Frame::NAL_SPS: { - //sps - _sps = string(pcData, iLen); + switch (type) { + case H265Frame::NAL_SPS: { + if (!_got_config_frame) { + _sps = string(data, len); makeConfigPacket(); - break; } - case H265Frame::NAL_PPS: { - //pps - _pps = string(pcData, iLen); - makeConfigPacket(); - break; - } - case H265Frame::NAL_VPS: { - //vps - _vps = string(pcData, iLen); - makeConfigPacket(); - break; - } - default: - break; + break; } + case H265Frame::NAL_PPS: { + if (!_got_config_frame) { + _pps = string(data, len); + makeConfigPacket(); + } + break; + } + case H265Frame::NAL_VPS: { + if (!_got_config_frame) { + _vps = string(data, len); + makeConfigPacket(); + break; + } + } + case H265Frame::NAL_AUD: + case H265Frame::NAL_SEI_PREFIX: + case H265Frame::NAL_SEI_SUFFIX: return; + default: break; } - if(type == H265Frame::NAL_SEI_PREFIX || type == H265Frame::NAL_SEI_SUFFIX || type == H265Frame::NAL_AUD){ - return;// 防止sei aud 作为一帧 - } - - if(frame->configFrame() && _lastPacket &&_lastPacketHasVCL){ + if(frame->configFrame() && _rtmp_packet && _has_vcl){ // sps pps flush frame - RtmpCodec::inputRtmp(_lastPacket); - _lastPacket = nullptr; - _lastPacketHasVCL = false; + RtmpCodec::inputRtmp(_rtmp_packet); + _rtmp_packet = nullptr; + _has_vcl = false; } - if (_lastPacket && (_lastPacket->time_stamp != frame->dts() || (_lastPacketHasVCL &&type>=H265Frame::NAL_TRAIL_R &&type<= H265Frame::NAL_RSV_IRAP_VCL23 && (pcData[2]>>7 &0x01) !=0))) { - RtmpCodec::inputRtmp(_lastPacket); - _lastPacket = nullptr; - _lastPacketHasVCL = false; + if (_rtmp_packet && (_rtmp_packet->time_stamp != frame->dts() || (_has_vcl && type >= H265Frame::NAL_TRAIL_R && type <= H265Frame::NAL_RSV_IRAP_VCL23 && (data[2] >> 7 & 0x01) != 0))) { + RtmpCodec::inputRtmp(_rtmp_packet); + _has_vcl = false; + _rtmp_packet = nullptr; } - if(type>=H265Frame::NAL_TRAIL_R &&type<= H265Frame::NAL_RSV_IRAP_VCL23){ - _lastPacketHasVCL = true; + if (type >= H265Frame::NAL_TRAIL_R && type <= H265Frame::NAL_RSV_IRAP_VCL23) { + _has_vcl = true; } - if(!_lastPacket) { + if (!_rtmp_packet) { //I or P or B frame int8_t flags = FLV_CODEC_H265; bool is_config = false; flags |= (((frame->configFrame() || frame->keyFrame()) ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4); - // to do - // 必须是IDR帧才能是关键帧,否则有可能开始帧会花屏 SPS PPS VPS 打头的是一般I帧,但不一定是IDR帧 - // RtmpCodec::inputRtmp 时需要判断 是否是IDR帧,做出相应的修改 - _lastPacket = RtmpPacket::create(); - _lastPacket->buffer.push_back(flags); - _lastPacket->buffer.push_back(!is_config); - auto cts = frame->pts() - frame->dts(); + // todo 必须是IDR帧才能是关键帧,否则有可能开始帧会花屏 SPS PPS VPS 打头的是一般I帧,但不一定是IDR帧 + // RtmpCodec::inputRtmp 时需要判断 是否是IDR帧,做出相应的修改 + _rtmp_packet = RtmpPacket::create(); + _rtmp_packet->buffer.push_back(flags); + _rtmp_packet->buffer.push_back(!is_config); + int32_t cts = frame->pts() - frame->dts(); + if (cts < 0) { + cts = 0; + } cts = htonl(cts); - _lastPacket->buffer.append((char *)&cts + 1, 3); - - _lastPacket->chunk_id = CHUNK_VIDEO; - _lastPacket->stream_index = STREAM_MEDIA; - _lastPacket->time_stamp = frame->dts(); - _lastPacket->type_id = MSG_VIDEO; - + _rtmp_packet->buffer.append((char *) &cts + 1, 3); + _rtmp_packet->chunk_id = CHUNK_VIDEO; + _rtmp_packet->stream_index = STREAM_MEDIA; + _rtmp_packet->time_stamp = frame->dts(); + _rtmp_packet->type_id = MSG_VIDEO; } - uint32_t size = htonl((uint32_t)iLen); - _lastPacket->buffer.append((char *) &size, 4); - _lastPacket->buffer.append(pcData, iLen); - _lastPacket->body_size = _lastPacket->buffer.size(); + uint32_t size = htonl((uint32_t) len); + _rtmp_packet->buffer.append((char *) &size, 4); + _rtmp_packet->buffer.append(data, len); + _rtmp_packet->body_size = _rtmp_packet->buffer.size(); } void H265RtmpEncoder::makeVideoConfigPkt() { @@ -218,7 +215,6 @@ void H265RtmpEncoder::makeVideoConfigPkt() { int8_t flags = FLV_CODEC_H265; flags |= (FLV_KEY_FRAME << 4); bool is_config = true; - auto rtmpPkt = RtmpPacket::create(); //header rtmpPkt->buffer.push_back(flags); @@ -237,10 +233,8 @@ void H265RtmpEncoder::makeVideoConfigPkt() { WarnL << "生成H265 extra_data 失败"; return; } - //HEVCDecoderConfigurationRecord rtmpPkt->buffer.append((char *)extra_data, extra_data_size); - rtmpPkt->body_size = rtmpPkt->buffer.size(); rtmpPkt->chunk_id = CHUNK_VIDEO; rtmpPkt->stream_index = STREAM_MEDIA; diff --git a/src/Extension/H265Rtmp.h b/src/Extension/H265Rtmp.h index 6ba0f8a1..c9ef7420 100644 --- a/src/Extension/H265Rtmp.h +++ b/src/Extension/H265Rtmp.h @@ -78,13 +78,13 @@ private: void makeVideoConfigPkt(); private: - bool _gotSpsPps = false; + bool _has_vcl = false; + bool _got_config_frame = false; string _vps; string _sps; string _pps; H265Track::Ptr _track; - RtmpPacket::Ptr _lastPacket; - bool _lastPacketHasVCL = false; + RtmpPacket::Ptr _rtmp_packet; }; }//namespace mediakit