diff --git a/erizo/src/erizo/media/Depacketizer.cpp b/erizo/src/erizo/media/Depacketizer.cpp index a70c009527..2e10fa4300 100644 --- a/erizo/src/erizo/media/Depacketizer.cpp +++ b/erizo/src/erizo/media/Depacketizer.cpp @@ -2,31 +2,34 @@ #include namespace erizo { -void Depacketizer::reset_buffer() { +DEFINE_LOGGER(Depacketizer, "media.Depacketizer"); + +void Depacketizer::resetBuffer() { buffer_ptr_ = buffer_; } void Depacketizer::reset() { - reset_impl(); - reset_buffer(); + resetImpl(); + resetBuffer(); } -void Depacketizer::buffer_check(const int len) { - if (len + (buffer_ptr_ - buffer_) >= buffer_size_) { +bool Depacketizer::bufferCheck(const int len) { + if (len + (buffer_ptr_ - buffer_) >= kUnpackageBufferSize) { reset(); - throw Depacketizer_memory_error("Not enough buffer. Dropping frame. " - "Please adjust your Depacketizer::buffer_size"); + ELOG_ERROR("Not enough buffer. Dropping frame. Please adjust your kUnpackageBufferSize in Depacketizer.h"); + return false; } + return true; } -void Vp8_depacketizer::fetch_packet(unsigned char* pkt, const int len) { +void Vp8Depacketizer::fetchPacket(unsigned char* pkt, const int len) { head_ = reinterpret_cast(pkt); last_payload_ = std::unique_ptr( parser_.parseVP8(reinterpret_cast(pkt + head_->getHeaderLength()), len - head_->getHeaderLength())); } -bool Vp8_depacketizer::process_packet() { +bool Vp8Depacketizer::processPacket() { if (!last_payload_) { return false; } @@ -36,57 +39,63 @@ bool Vp8_depacketizer::process_packet() { bool deliver = false; switch (search_state_) { - case Search_state::lookingForStart: + case SearchState::lookingForStart: if (startOfFrame && endOfFrame) { // This packet is a standalone frame. Send it on. Look for start. - reset_buffer(); - buffer_check(last_payload_->dataLength); - std::memcpy(buffer(), last_payload_->data, last_payload_->dataLength); - set_buffer_ptr(buffer_ptr() + last_payload_->dataLength); - deliver = true; + resetBuffer(); + if (bufferCheck(last_payload_->dataLength)) { + std::memcpy(buffer(), last_payload_->data, last_payload_->dataLength); + setBufferPtr(getBufferPtr() + last_payload_->dataLength); + deliver = true; + } } else if (!startOfFrame && !endOfFrame) { // This is neither the start nor the end of a frame. Reset our buffers. Look for start. - reset_buffer(); + resetBuffer(); } else if (startOfFrame && !endOfFrame) { // Found start frame. Copy to buffers. Look for our end. - buffer_check(last_payload_->dataLength); - std::memcpy(buffer_ptr(), last_payload_->data, last_payload_->dataLength); - set_buffer_ptr(buffer_ptr() + last_payload_->dataLength); - search_state_ = Search_state::lookingForEnd; + if (bufferCheck(last_payload_->dataLength)) { + std::memcpy(getBufferPtr(), last_payload_->data, last_payload_->dataLength); + setBufferPtr(getBufferPtr() + last_payload_->dataLength); + search_state_ = SearchState::lookingForEnd; + } } else { // (!startOfFrame && endOfFrame) // We got the end of a frame. Reset our buffers. - reset_buffer(); + resetBuffer(); } break; - case Search_state::lookingForEnd: + case SearchState::lookingForEnd: if (startOfFrame && endOfFrame) { // Unexpected. We were looking for the end of a frame, and got a whole new frame. // Reset our buffers, send this frame on, and go to the looking for start state. - reset_buffer(); - buffer_check(last_payload_->dataLength); - std::memcpy(buffer_ptr(), last_payload_->data, last_payload_->dataLength); - set_buffer_ptr(buffer_ptr() + last_payload_->dataLength); - deliver = true; - reset_impl(); + resetBuffer(); + if (bufferCheck(last_payload_->dataLength)) { + std::memcpy(getBufferPtr(), last_payload_->data, last_payload_->dataLength); + setBufferPtr(getBufferPtr() + last_payload_->dataLength); + deliver = true; + resetImpl(); + } } else if (!startOfFrame && !endOfFrame) { // This is neither the start nor the end. Add it to our unpackage buffer. - buffer_check(last_payload_->dataLength); - std::memcpy(buffer_ptr(), last_payload_->data, last_payload_->dataLength); - set_buffer_ptr(buffer_ptr() + last_payload_->dataLength); + if (bufferCheck(last_payload_->dataLength)) { + std::memcpy(getBufferPtr(), last_payload_->data, last_payload_->dataLength); + setBufferPtr(getBufferPtr() + last_payload_->dataLength); + } } else if (startOfFrame && !endOfFrame) { // Unexpected. We got the start of a frame. Clear out our buffer, toss this payload in, // and continue looking for the end. - reset_buffer(); - buffer_check(last_payload_->dataLength); - std::memcpy(buffer_ptr(), last_payload_->data, last_payload_->dataLength); - set_buffer_ptr(buffer_ptr() + last_payload_->dataLength); + resetBuffer(); + if (bufferCheck(last_payload_->dataLength)) { + std::memcpy(getBufferPtr(), last_payload_->data, last_payload_->dataLength); + setBufferPtr(getBufferPtr() + last_payload_->dataLength); + } } else { // (!startOfFrame && endOfFrame) // Got the end of a frame. Let's deliver and start looking for the start of a frame. - search_state_ = Search_state::lookingForStart; - buffer_check(last_payload_->dataLength); - std::memcpy(buffer_ptr(), last_payload_->data, last_payload_->dataLength); - set_buffer_ptr(buffer_ptr() + last_payload_->dataLength); - deliver = true; + search_state_ = SearchState::lookingForStart; + if (bufferCheck(last_payload_->dataLength)) { + std::memcpy(getBufferPtr(), last_payload_->data, last_payload_->dataLength); + setBufferPtr(getBufferPtr() + last_payload_->dataLength); + deliver = true; + } } break; } @@ -94,89 +103,93 @@ bool Vp8_depacketizer::process_packet() { return deliver; } -bool Vp8_depacketizer::is_keyframe() const { +bool Vp8Depacketizer::isKeyframe() const { if (!last_payload_) { return false; } return last_payload_->frameType == VP8FrameTypes::kVP8IFrame; } -void Vp8_depacketizer::reset_impl() { +void Vp8Depacketizer::resetImpl() { last_payload_ = nullptr; - search_state_ = Search_state::lookingForStart; + search_state_ = SearchState::lookingForStart; } -void H264_depacketizer::fetch_packet(unsigned char* pkt, int len) { +void H264Depacketizer::fetchPacket(unsigned char* pkt, int len) { const RtpHeader* head = reinterpret_cast(pkt); last_payload_ = std::unique_ptr( parser_.parseH264(reinterpret_cast(pkt + head->getHeaderLength()), len - head->getHeaderLength())); } -bool H264_depacketizer::is_keyframe() const { +bool H264Depacketizer::isKeyframe() const { if (!last_payload_) { return false; } return last_payload_->frameType == H264FrameTypes::kH264IFrame; } -void H264_depacketizer::reset_impl() { +void H264Depacketizer::resetImpl() { last_payload_ = nullptr; - search_state_ = Search_state::lookingForStart; + search_state_ = SearchState::lookingForStart; } -bool H264_depacketizer::process_packet() { +bool H264Depacketizer::processPacket() { switch (last_payload_->nal_type) { - case single: { - if (search_state_ == Search_state::lookingForEnd) { - reset(); - } - if (last_payload_->dataLength == 0) { - return false; - } - const auto total_size = last_payload_->dataLength + sizeof(RTPPayloadH264::start_sequence); - buffer_check(total_size); - std::memcpy(buffer_ptr(), RTPPayloadH264::start_sequence, sizeof(RTPPayloadH264::start_sequence)); - set_buffer_ptr(buffer_ptr() + sizeof(RTPPayloadH264::start_sequence)); - std::memcpy(buffer_ptr(), last_payload_->data, last_payload_->dataLength); - set_buffer_ptr(buffer_ptr() + last_payload_->dataLength); - return true; - } - case fragmented: { - if (last_payload_->dataLength == 0) { - return false; - } - const auto total_size = last_payload_->dataLength - + sizeof(RTPPayloadH264::start_sequence) - + last_payload_->fragment_nal_header_len; - buffer_check(total_size); - if (last_payload_->start_bit) { - if (search_state_ == Search_state::lookingForEnd) { + case single: { + if (search_state_ == SearchState::lookingForEnd) { reset(); } - search_state_ = Search_state::lookingForEnd; - std::memcpy(buffer_ptr(), RTPPayloadH264::start_sequence, sizeof(RTPPayloadH264::start_sequence)); - set_buffer_ptr(buffer_ptr() + sizeof(RTPPayloadH264::start_sequence)); - std::memcpy(buffer_ptr(), &last_payload_->fragment_nal_header, last_payload_->fragment_nal_header_len); - set_buffer_ptr(buffer_ptr() + last_payload_->fragment_nal_header_len); + if (last_payload_->dataLength == 0) { + return false; + } + const auto total_size = last_payload_->dataLength + sizeof(RTPPayloadH264::start_sequence); + if (bufferCheck(total_size)) { + std::memcpy(getBufferPtr(), RTPPayloadH264::start_sequence, sizeof(RTPPayloadH264::start_sequence)); + setBufferPtr(getBufferPtr() + sizeof(RTPPayloadH264::start_sequence)); + std::memcpy(getBufferPtr(), last_payload_->data, last_payload_->dataLength); + setBufferPtr(getBufferPtr() + last_payload_->dataLength); + return true; + } + break; } - std::memcpy(buffer_ptr(), last_payload_->data, last_payload_->dataLength); - set_buffer_ptr(buffer_ptr() + last_payload_->dataLength); - if (last_payload_->end_bit) { - search_state_ = Search_state::lookingForStart; - return true; + case fragmented: { + if (last_payload_->dataLength == 0) { + return false; + } + const auto total_size = last_payload_->dataLength + + sizeof(RTPPayloadH264::start_sequence) + + last_payload_->fragment_nal_header_len; + if (bufferCheck(total_size)) { + if (last_payload_->start_bit) { + if (search_state_ == SearchState::lookingForEnd) { + reset(); + } + search_state_ = SearchState::lookingForEnd; + std::memcpy(getBufferPtr(), RTPPayloadH264::start_sequence, sizeof(RTPPayloadH264::start_sequence)); + setBufferPtr(getBufferPtr() + sizeof(RTPPayloadH264::start_sequence)); + std::memcpy(getBufferPtr(), &last_payload_->fragment_nal_header, last_payload_->fragment_nal_header_len); + setBufferPtr(getBufferPtr() + last_payload_->fragment_nal_header_len); + } + std::memcpy(getBufferPtr(), last_payload_->data, last_payload_->dataLength); + setBufferPtr(getBufferPtr() + last_payload_->dataLength); + if (last_payload_->end_bit) { + search_state_ = SearchState::lookingForStart; + return true; + } + } + break; } - break; - } - case aggregated: { - if (last_payload_->unpacked_data_len == 0) { - return false; + case aggregated: { + if (last_payload_->unpacked_data_len == 0) { + return false; + } + if (bufferCheck(last_payload_->unpacked_data_len)) { + std::memcpy(getBufferPtr(), &last_payload_->unpacked_data[0], last_payload_->unpacked_data_len); + setBufferPtr(getBufferPtr() + last_payload_->unpacked_data_len); + return true; + } } - buffer_check(last_payload_->unpacked_data_len); - std::memcpy(buffer_ptr(), &last_payload_->unpacked_data[0], last_payload_->unpacked_data_len); - set_buffer_ptr(buffer_ptr() + last_payload_->unpacked_data_len); - return true; - } } return false; } diff --git a/erizo/src/erizo/media/Depacketizer.h b/erizo/src/erizo/media/Depacketizer.h index 3e3f78590d..022b4e8990 100644 --- a/erizo/src/erizo/media/Depacketizer.h +++ b/erizo/src/erizo/media/Depacketizer.h @@ -4,24 +4,19 @@ #include "rtp/RtpHeaders.h" #include "rtp/RtpVP8Parser.h" #include "rtp/RtpH264Parser.h" +#include "./logger.h" #include #include #include namespace erizo { -class Depacketizer_memory_error: public std::runtime_error { - public: - template - explicit Depacketizer_memory_error(Args&&... args) : - std::runtime_error(std::forward(args)...) { - } -}; /** * Decomposes rtp packets into frames */ class Depacketizer { - static constexpr int buffer_size_ = 1000000; + DECLARE_LOGGER(); + static constexpr int kUnpackageBufferSize = 1000000; public: virtual ~Depacketizer() = default; @@ -34,7 +29,7 @@ class Depacketizer { return buffer_; } - int frame_size() const { + int frameSize() const { return buffer_ptr_ - buffer_; } @@ -42,13 +37,13 @@ class Depacketizer { * Stores and parses a new packet. It doesn't add it the frame just yet. * Pkt must remain valid until process is called or a new packet get fetched. */ - virtual void fetch_packet(unsigned char* pkt, int len) = 0; + virtual void fetchPacket(unsigned char* pkt, int len) = 0; /** * Pushes the last fetched packet into the buffer * @returns True if a frame is ready to be grabbed */ - virtual bool process_packet() = 0; + virtual bool processPacket() = 0; /** * Resets the internal state of the depacketizer @@ -58,68 +53,66 @@ class Depacketizer { /** * @returns True if there's a frame in the buffer and it is a keyframe. The frame may be incomplete. */ - virtual bool is_keyframe() const = 0; + virtual bool isKeyframe() const = 0; protected: - void reset_buffer(); + enum class SearchState { + lookingForStart, lookingForEnd + }; + + void resetBuffer(); - void buffer_check(int len); + bool bufferCheck(int len); unsigned char* buffer() { return buffer_; } - unsigned char* buffer_ptr() { + unsigned char* getBufferPtr() { return buffer_ptr_; } - void set_buffer_ptr(unsigned char* ptr) { + void setBufferPtr(unsigned char* ptr) { buffer_ptr_ = ptr; } + SearchState search_state_ = SearchState::lookingForStart; + private: - virtual void reset_impl() = 0; + virtual void resetImpl() = 0; - unsigned char buffer_[buffer_size_]; + unsigned char buffer_[kUnpackageBufferSize]; unsigned char* buffer_ptr_ = buffer_; }; -class Vp8_depacketizer: public Depacketizer { +class Vp8Depacketizer: public Depacketizer { // Our search state for VP8 frames. - enum class Search_state { - lookingForStart, lookingForEnd - }; public: - void fetch_packet(unsigned char* pkt, int len) override; + void fetchPacket(unsigned char* pkt, int len) override; - bool process_packet() override; + bool processPacket() override; - bool is_keyframe() const override; + bool isKeyframe() const override; private: - void reset_impl() override; + void resetImpl() override; RtpVP8Parser parser_; const RtpHeader* head_; std::unique_ptr last_payload_; - Search_state search_state_ = Search_state::lookingForStart; }; -class H264_depacketizer: public Depacketizer { - enum class Search_state { - lookingForStart, lookingForEnd - }; +class H264Depacketizer: public Depacketizer { public: - void fetch_packet(unsigned char* pkt, int len) override; + void fetchPacket(unsigned char* pkt, int len) override; - bool process_packet() override; + bool processPacket() override; - bool is_keyframe() const override; + bool isKeyframe() const override; private: - void reset_impl() override; + void resetImpl() override; RtpH264Parser parser_; std::unique_ptr last_payload_; - Search_state search_state_ = Search_state::lookingForStart; }; } // namespace erizo diff --git a/erizo/src/erizo/media/ExternalOutput.cpp b/erizo/src/erizo/media/ExternalOutput.cpp index 7b6a65b684..abcbc6656f 100644 --- a/erizo/src/erizo/media/ExternalOutput.cpp +++ b/erizo/src/erizo/media/ExternalOutput.cpp @@ -18,9 +18,9 @@ namespace erizo { DEFINE_LOGGER(ExternalOutput, "media.ExternalOutput"); ExternalOutput::ExternalOutput(const std::string& output_url, const std::vector rtp_mappings) : audio_queue_{5.0, 10.0}, video_queue_{5.0, 10.0}, inited_{false}, video_stream_{nullptr}, - audio_stream_{nullptr}, unpackaged_size_{0}, video_source_ssrc_{0}, - unpackaged_buffer_part_{unpackaged_buffer_}, first_video_timestamp_{-1}, first_audio_timestamp_{-1}, - first_data_received_{}, video_offset_ms_{-1}, audio_offset_ms_{-1}, video_search_state_{kLookingForStart}, + audio_stream_{nullptr}, video_source_ssrc_{0}, + first_video_timestamp_{-1}, first_audio_timestamp_{-1}, + first_data_received_{}, video_offset_ms_{-1}, audio_offset_ms_{-1}, need_to_send_fir_{true}, rtp_mappings_{rtp_mappings}, video_codec_{AV_CODEC_ID_NONE}, audio_codec_{AV_CODEC_ID_NONE} { ELOG_DEBUG("Creating output to %s", output_url.c_str()); @@ -122,17 +122,6 @@ int32_t ExternalOutput::OnReceivedPayloadData(const uint8_t* payload_data, size_ return 0; } -bool ExternalOutput::bufferCheck(RTPPayloadVP8* payload) { - if (payload->dataLength + unpackaged_size_ >= kUnpackageBufferSize) { - ELOG_ERROR("Not enough buffer. Dropping frame. Please adjust your kUnpackageBufferSize in ExternalOutput.h"); - unpackaged_size_ = 0; - unpackaged_buffer_part_ = unpackaged_buffer_; - video_search_state_ = kLookingForStart; - return false; - } - return true; -} - void ExternalOutput::writeAudioData(char* buf, int len) { RtpHeader* head = reinterpret_cast(buf); uint16_t current_audio_sequence_number = head->getSeqNumber(); @@ -191,11 +180,10 @@ void ExternalOutput::writeVideoData(char* buf, int len) { // Something screwy. We should always see sequence numbers incrementing monotonically. ELOG_DEBUG("Unexpected video sequence number; current %d, previous %d", current_video_sequence_number, last_video_sequence_number_); - // Set our search state to look for the start of a frame, and discard what we currently have (if anything). - // it's now worthless. - video_search_state_ = kLookingForStart; - unpackaged_size_ = 0; - unpackaged_buffer_part_ = unpackaged_buffer_; + // Restart the depacketizer so it looks for the start of a frame + if (depacketizer_!= nullptr) { + depacketizer_->reset(); + } } last_video_sequence_number_ = current_video_sequence_number; @@ -206,8 +194,8 @@ void ExternalOutput::writeVideoData(char* buf, int len) { auto map_iterator = video_maps_.find(head->getPayloadType()); if (map_iterator != video_maps_.end()) { updateVideoCodec(map_iterator->second); - if (map_iterator->second.encoding_name == "VP8") { - writeVP8(buf, len); + if (map_iterator->second.encoding_name == "VP8" || map_iterator->second.encoding_name == "H264") { + maybeWriteVideoPacket(buf, len); } } } @@ -230,94 +218,18 @@ void ExternalOutput::updateVideoCodec(RtpMap map) { } video_map_ = map; if (map.encoding_name == "VP8") { + depacketizer_.reset(new Vp8Depacketizer()); video_codec_ = AV_CODEC_ID_VP8; + } else if (map.encoding_name == "H264") { + depacketizer_.reset(new H264Depacketizer()); + video_codec_ = AV_CODEC_ID_H264; } } -void ExternalOutput::writeVP8(char* buf, int len) { +void ExternalOutput::maybeWriteVideoPacket(char* buf, int len) { RtpHeader* head = reinterpret_cast(buf); - RtpVP8Parser parser; - erizo::RTPPayloadVP8* payload = parser.parseVP8(reinterpret_cast(buf + head->getHeaderLength()), - len - head->getHeaderLength()); - - bool end_of_frame = (head->getMarker() > 0); - bool start_of_frame = payload->beginningOfPartition; - - bool deliver = false; - switch (video_search_state_) { - case kLookingForStart: - if (start_of_frame && end_of_frame) { - // This packet is a standalone frame. Send it on. Look for start. - unpackaged_size_ = 0; - unpackaged_buffer_part_ = unpackaged_buffer_; - if (bufferCheck(payload)) { - memcpy(unpackaged_buffer_part_, payload->data, payload->dataLength); - unpackaged_size_ += payload->dataLength; - unpackaged_buffer_part_ += payload->dataLength; - deliver = true; - } - } else if (!start_of_frame && !end_of_frame) { - // This is neither the start nor the end of a frame. Reset our buffers. Look for start. - unpackaged_size_ = 0; - unpackaged_buffer_part_ = unpackaged_buffer_; - } else if (start_of_frame && !end_of_frame) { - // Found start frame. Copy to buffers. Look for our end. - if (bufferCheck(payload)) { - memcpy(unpackaged_buffer_part_, payload->data, payload->dataLength); - unpackaged_size_ += payload->dataLength; - unpackaged_buffer_part_ += payload->dataLength; - video_search_state_ = kLookingForEnd; - } - } else { // (!start_of_frame && end_of_frame) - // We got the end of a frame. Reset our buffers. - unpackaged_size_ = 0; - unpackaged_buffer_part_ = unpackaged_buffer_; - } - break; - case kLookingForEnd: - if (start_of_frame && end_of_frame) { - // Unexpected. We were looking for the end of a frame, and got a whole new frame. - // Reset our buffers, send this frame on, and go to the looking for start state. - video_search_state_ = kLookingForStart; - unpackaged_size_ = 0; - unpackaged_buffer_part_ = unpackaged_buffer_; - if (bufferCheck(payload)) { - memcpy(unpackaged_buffer_part_, payload->data, payload->dataLength); - unpackaged_size_ += payload->dataLength; - unpackaged_buffer_part_ += payload->dataLength; - deliver = true; - } - } else if (!start_of_frame && !end_of_frame) { - // This is neither the start nor the end. Add it to our unpackage buffer. - if (bufferCheck(payload)) { - memcpy(unpackaged_buffer_part_, payload->data, payload->dataLength); - unpackaged_size_ += payload->dataLength; - unpackaged_buffer_part_ += payload->dataLength; - } - } else if (start_of_frame && !end_of_frame) { - // Unexpected. We got the start of a frame. Clear out our buffer, toss this payload in, - // and continue looking for the end. - unpackaged_size_ = 0; - unpackaged_buffer_part_ = unpackaged_buffer_; - if (bufferCheck(payload)) { - memcpy(unpackaged_buffer_part_, payload->data, payload->dataLength); - unpackaged_size_ += payload->dataLength; - unpackaged_buffer_part_ += payload->dataLength; - } - } else { // (!start_of_frame && end_of_frame) - // Got the end of a frame. Let's deliver and start looking for the start of a frame. - video_search_state_ = kLookingForStart; - if (bufferCheck(payload)) { - memcpy(unpackaged_buffer_part_, payload->data, payload->dataLength); - unpackaged_size_ += payload->dataLength; - unpackaged_buffer_part_ += payload->dataLength; - deliver = true; - } - } - break; - } - - delete payload; + depacketizer_->fetchPacket((unsigned char*)buf, len); + bool deliver = depacketizer_->processPacket(); initContext(); if (video_stream_ == nullptr) { @@ -326,8 +238,6 @@ void ExternalOutput::writeVP8(char* buf, int len) { } if (deliver) { - unpackaged_buffer_part_ -= unpackaged_size_; - long long current_timestamp = head->getTimestamp(); // NOLINT if (current_timestamp - first_video_timestamp_ < 0) { // we wrapped. add 2^32 to correct this. @@ -346,13 +256,12 @@ void ExternalOutput::writeVP8(char* buf, int len) { AVPacket av_packet; av_init_packet(&av_packet); - av_packet.data = unpackaged_buffer_part_; - av_packet.size = unpackaged_size_; + av_packet.data = depacketizer_->frame(); + av_packet.size = depacketizer_->frameSize(); av_packet.pts = timestamp_to_write; av_packet.stream_index = 0; av_interleaved_write_frame(context_, &av_packet); // takes ownership of the packet - unpackaged_size_ = 0; - unpackaged_buffer_part_ = unpackaged_buffer_; + depacketizer_->reset(); } } diff --git a/erizo/src/erizo/media/ExternalOutput.h b/erizo/src/erizo/media/ExternalOutput.h index 05eed655f5..6c5a503c70 100644 --- a/erizo/src/erizo/media/ExternalOutput.h +++ b/erizo/src/erizo/media/ExternalOutput.h @@ -14,6 +14,7 @@ extern "C" { #include "rtp/RtpPacketQueue.h" #include "webrtc/modules/rtp_rtcp/source/ulpfec_receiver_impl.h" #include "media/MediaProcessor.h" +#include "media/Depacketizer.h" #include "lib/Clock.h" #include "SdpInfo.h" @@ -21,8 +22,6 @@ extern "C" { namespace erizo { -constexpr int kUnpackageBufferSize = 200000; - class MediaStream; // Our search state for VP8 frames. @@ -58,10 +57,8 @@ class ExternalOutput : public MediaSink, public RawDataReceiver, public Feedback AVStream *video_stream_, *audio_stream_; AVFormatContext *context_; - int unpackaged_size_; uint32_t video_source_ssrc_; - unsigned char* unpackaged_buffer_part_; - unsigned char unpackaged_buffer_[kUnpackageBufferSize]; + std::unique_ptr depacketizer_; // Timestamping strategy: we use the RTP timestamps so we don't have to restamp and we're not // subject to error due to the RTP packet queue depth and playout. @@ -117,8 +114,7 @@ class ExternalOutput : public MediaSink, public RawDataReceiver, public Feedback void writeVideoData(char* buf, int len); void updateVideoCodec(RtpMap map); void updateAudioCodec(RtpMap map); - void writeVP8(char* buf, int len); - bool bufferCheck(RTPPayloadVP8* payload); + void maybeWriteVideoPacket(char* buf, int len); }; } // namespace erizo #endif // ERIZO_SRC_ERIZO_MEDIA_EXTERNALOUTPUT_H_ diff --git a/erizo/src/erizo/rtp/LayerDetectorHandler.cpp b/erizo/src/erizo/rtp/LayerDetectorHandler.cpp index d24a25eb32..d5745cce2e 100644 --- a/erizo/src/erizo/rtp/LayerDetectorHandler.cpp +++ b/erizo/src/erizo/rtp/LayerDetectorHandler.cpp @@ -187,6 +187,9 @@ void LayerDetectorHandler::parseLayerInfoFromH264(std::shared_ptr pa RTPPayloadH264* payload = h264_parser_.parseH264( start_buffer, packet->length - rtp_header->getHeaderLength()); + int position = getSsrcPosition(rtp_header->getSSRC()); + packet->compatible_spatial_layers = {position}; + if (payload->frameType == kH264IFrame) { packet->is_keyframe = true; } else { diff --git a/erizo/src/test/media/DepacketizerTest.cpp b/erizo/src/test/media/DepacketizerTest.cpp index 7a5d82dd6e..7c28b10583 100644 --- a/erizo/src/test/media/DepacketizerTest.cpp +++ b/erizo/src/test/media/DepacketizerTest.cpp @@ -19,7 +19,7 @@ class DepacketizerVp8Test : public erizo::HandlerTest { protected: void setHandler() { - depacketizer = std::make_shared(); + depacketizer = std::make_shared(); } int Vp8PacketDataSize() { @@ -37,7 +37,7 @@ class DepacketizerH264Test : public erizo::HandlerTest { protected: void setHandler() { - depacketizer = std::make_shared(); + depacketizer = std::make_shared(); } int H264SingleNalDataSize() { @@ -56,31 +56,31 @@ class DepacketizerH264Test : public erizo::HandlerTest { }; TEST_F(DepacketizerVp8Test, isReallyEmpty) { - EXPECT_EQ(0, depacketizer->is_keyframe()); - EXPECT_EQ(0, depacketizer->frame_size()); + EXPECT_EQ(0, depacketizer->isKeyframe()); + EXPECT_EQ(0, depacketizer->frameSize()); } TEST_F(DepacketizerVp8Test, shouldDepacketSimplePacketFrame) { const auto pkt = erizo::PacketTools::createVP8Packet(seq, false, true); - depacketizer->fetch_packet(reinterpret_cast(pkt->data), pkt->length); - EXPECT_EQ(1, depacketizer->process_packet()); - EXPECT_EQ(0, depacketizer->is_keyframe()); - EXPECT_EQ(Vp8PacketDataSize(), depacketizer->frame_size()); + depacketizer->fetchPacket(reinterpret_cast(pkt->data), pkt->length); + EXPECT_EQ(1, depacketizer->processPacket()); + EXPECT_EQ(0, depacketizer->isKeyframe()); + EXPECT_EQ(Vp8PacketDataSize(), depacketizer->frameSize()); } TEST_F(DepacketizerVp8Test, shouldDepacketSimplePacketKeyframe) { const auto pkt = erizo::PacketTools::createVP8Packet(seq, true, true); - depacketizer->fetch_packet(reinterpret_cast(pkt->data), pkt->length); - EXPECT_EQ(1, depacketizer->process_packet()); - EXPECT_EQ(1, depacketizer->is_keyframe()); - EXPECT_EQ(Vp8PacketDataSize(), depacketizer->frame_size()); + depacketizer->fetchPacket(reinterpret_cast(pkt->data), pkt->length); + EXPECT_EQ(1, depacketizer->processPacket()); + EXPECT_EQ(1, depacketizer->isKeyframe()); + EXPECT_EQ(Vp8PacketDataSize(), depacketizer->frameSize()); } TEST_F(DepacketizerVp8Test, shouldDepacketMultiPacketFrame) { auto pkt = erizo::PacketTools::createVP8Packet(seq, false, false); - depacketizer->fetch_packet(reinterpret_cast(pkt->data), pkt->length); - EXPECT_EQ(0, depacketizer->process_packet()); - EXPECT_EQ(0, depacketizer->is_keyframe()); + depacketizer->fetchPacket(reinterpret_cast(pkt->data), pkt->length); + EXPECT_EQ(0, depacketizer->processPacket()); + EXPECT_EQ(0, depacketizer->isKeyframe()); pkt = erizo::PacketTools::createVP8Packet(seq + 1, false, false); // unset the bit indicating the start of partition @@ -88,9 +88,9 @@ TEST_F(DepacketizerVp8Test, shouldDepacketMultiPacketFrame) { erizo::RtpHeader* head = reinterpret_cast(pkt_ptr); pkt_ptr += head->getHeaderLength(); *pkt_ptr = erizo::change_bit(*pkt_ptr, 4, false); - depacketizer->fetch_packet(reinterpret_cast(pkt->data), pkt->length); - EXPECT_EQ(0, depacketizer->process_packet()); - EXPECT_EQ(0, depacketizer->is_keyframe()); + depacketizer->fetchPacket(reinterpret_cast(pkt->data), pkt->length); + EXPECT_EQ(0, depacketizer->processPacket()); + EXPECT_EQ(0, depacketizer->isKeyframe()); pkt = erizo::PacketTools::createVP8Packet(seq + 2, false, true); // unset the bit indicating the start of partition @@ -98,75 +98,75 @@ TEST_F(DepacketizerVp8Test, shouldDepacketMultiPacketFrame) { head = reinterpret_cast(pkt_ptr); pkt_ptr += head->getHeaderLength(); *pkt_ptr = erizo::change_bit(*pkt_ptr, 4, false); - depacketizer->fetch_packet(reinterpret_cast(pkt->data), pkt->length); - EXPECT_EQ(1, depacketizer->process_packet()); - EXPECT_EQ(0, depacketizer->is_keyframe()); - EXPECT_EQ(Vp8PacketDataSize() * 3, depacketizer->frame_size()); + depacketizer->fetchPacket(reinterpret_cast(pkt->data), pkt->length); + EXPECT_EQ(1, depacketizer->processPacket()); + EXPECT_EQ(0, depacketizer->isKeyframe()); + EXPECT_EQ(Vp8PacketDataSize() * 3, depacketizer->frameSize()); } TEST_F(DepacketizerVp8Test, shouldReset) { const auto pkt = erizo::PacketTools::createVP8Packet(seq, true, true); - depacketizer->fetch_packet(reinterpret_cast(pkt->data), pkt->length); - EXPECT_EQ(1, depacketizer->process_packet()); + depacketizer->fetchPacket(reinterpret_cast(pkt->data), pkt->length); + EXPECT_EQ(1, depacketizer->processPacket()); depacketizer->reset(); - EXPECT_EQ(0, depacketizer->is_keyframe()); - EXPECT_EQ(0, depacketizer->frame_size()); + EXPECT_EQ(0, depacketizer->isKeyframe()); + EXPECT_EQ(0, depacketizer->frameSize()); } TEST_F(DepacketizerH264Test, isReallyEmpty) { - EXPECT_EQ(0, depacketizer->is_keyframe()); - EXPECT_EQ(0, depacketizer->frame_size()); + EXPECT_EQ(0, depacketizer->isKeyframe()); + EXPECT_EQ(0, depacketizer->frameSize()); } TEST_F(DepacketizerH264Test, shouldDepacketSingleNalFrame) { const auto pkt = erizo::PacketTools::createH264SingleNalPacket(seq, timestamp, false); - depacketizer->fetch_packet(reinterpret_cast(pkt->data), pkt->length); - EXPECT_EQ(1, depacketizer->process_packet()); - EXPECT_EQ(0, depacketizer->is_keyframe()); - EXPECT_EQ(H264SingleNalDataSize(), depacketizer->frame_size()); + depacketizer->fetchPacket(reinterpret_cast(pkt->data), pkt->length); + EXPECT_EQ(1, depacketizer->processPacket()); + EXPECT_EQ(0, depacketizer->isKeyframe()); + EXPECT_EQ(H264SingleNalDataSize(), depacketizer->frameSize()); } TEST_F(DepacketizerH264Test, shouldDepacketSingleNalKeyframe) { const auto pkt = erizo::PacketTools::createH264SingleNalPacket(seq, timestamp, true); - depacketizer->fetch_packet(reinterpret_cast(pkt->data), pkt->length); - EXPECT_EQ(1, depacketizer->process_packet()); - EXPECT_EQ(1, depacketizer->is_keyframe()); - EXPECT_EQ(H264SingleNalDataSize(), depacketizer->frame_size()); + depacketizer->fetchPacket(reinterpret_cast(pkt->data), pkt->length); + EXPECT_EQ(1, depacketizer->processPacket()); + EXPECT_EQ(1, depacketizer->isKeyframe()); + EXPECT_EQ(H264SingleNalDataSize(), depacketizer->frameSize()); } TEST_F(DepacketizerH264Test, shouldDepacketAggregatedFrame) { const unsigned char nal_1_len = 100; const unsigned char nal_2_len = 187; const auto pkt = erizo::PacketTools::createH264AggregatedPacket(seq, timestamp, nal_1_len, nal_2_len); - depacketizer->fetch_packet(reinterpret_cast(pkt->data), pkt->length); - EXPECT_EQ(1, depacketizer->process_packet()); - EXPECT_EQ(0, depacketizer->is_keyframe()); + depacketizer->fetchPacket(reinterpret_cast(pkt->data), pkt->length); + EXPECT_EQ(1, depacketizer->processPacket()); + EXPECT_EQ(0, depacketizer->isKeyframe()); EXPECT_EQ(nal_1_len + nal_2_len + sizeof(erizo::RTPPayloadH264::start_sequence) * 2, - static_cast(depacketizer->frame_size())); + static_cast(depacketizer->frameSize())); } TEST_F(DepacketizerH264Test, shouldDepacketFragmentedFrame) { auto pkt = erizo::PacketTools::createH264FragmentedPacket(seq, timestamp, true, false, false); - depacketizer->fetch_packet(reinterpret_cast(pkt->data), pkt->length); - EXPECT_EQ(0, depacketizer->process_packet()); - EXPECT_EQ(0, depacketizer->is_keyframe()); + depacketizer->fetchPacket(reinterpret_cast(pkt->data), pkt->length); + EXPECT_EQ(0, depacketizer->processPacket()); + EXPECT_EQ(0, depacketizer->isKeyframe()); pkt = erizo::PacketTools::createH264FragmentedPacket(seq, timestamp, false, true, false); - depacketizer->fetch_packet(reinterpret_cast(pkt->data), pkt->length); - EXPECT_EQ(1, depacketizer->process_packet()); - EXPECT_EQ(0, depacketizer->is_keyframe()); + depacketizer->fetchPacket(reinterpret_cast(pkt->data), pkt->length); + EXPECT_EQ(1, depacketizer->processPacket()); + EXPECT_EQ(0, depacketizer->isKeyframe()); EXPECT_EQ(H264FragmentedFrameDataSize() * 2 + // 2 packets sizeof(erizo::RTPPayloadH264::start_sequence) + // 1 start sequence 1, // 1 nal header - static_cast(depacketizer->frame_size())); + static_cast(depacketizer->frameSize())); } TEST_F(DepacketizerH264Test, shouldReset) { const auto pkt = erizo::PacketTools::createH264SingleNalPacket(seq, timestamp, true); - depacketizer->fetch_packet(reinterpret_cast(pkt->data), pkt->length); - EXPECT_EQ(1, depacketizer->process_packet()); + depacketizer->fetchPacket(reinterpret_cast(pkt->data), pkt->length); + EXPECT_EQ(1, depacketizer->processPacket()); depacketizer->reset(); - EXPECT_EQ(0, depacketizer->is_keyframe()); - EXPECT_EQ(0, depacketizer->frame_size()); + EXPECT_EQ(0, depacketizer->isKeyframe()); + EXPECT_EQ(0, depacketizer->frameSize()); }