blob: 3084b5b2d943b8bdf0f52fcc4c09381d9679e6f0 [file] [log] [blame]
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/video_coding/rtp_frame_reference_finder.h"
#include <utility>
#include "absl/types/variant.h"
#include "modules/video_coding/frame_object.h"
#include "modules/video_coding/rtp_frame_id_only_ref_finder.h"
#include "modules/video_coding/rtp_generic_ref_finder.h"
#include "modules/video_coding/rtp_seq_num_only_ref_finder.h"
#include "modules/video_coding/rtp_vp8_ref_finder.h"
#include "modules/video_coding/rtp_vp9_ref_finder.h"
namespace webrtc {
namespace video_coding {
namespace internal {
class RtpFrameReferenceFinderImpl {
public:
RtpFrameReferenceFinderImpl() = default;
RtpFrameReferenceFinder::ReturnVector ManageFrame(
std::unique_ptr<RtpFrameObject> frame);
RtpFrameReferenceFinder::ReturnVector PaddingReceived(uint16_t seq_num);
void ClearTo(uint16_t seq_num);
private:
using RefFinder = absl::variant<absl::monostate,
RtpGenericFrameRefFinder,
RtpFrameIdOnlyRefFinder,
RtpSeqNumOnlyRefFinder,
RtpVp8RefFinder,
RtpVp9RefFinder>;
template <typename T>
T& GetRefFinderAs();
RefFinder ref_finder_;
};
RtpFrameReferenceFinder::ReturnVector RtpFrameReferenceFinderImpl::ManageFrame(
std::unique_ptr<RtpFrameObject> frame) {
const RTPVideoHeader& video_header = frame->GetRtpVideoHeader();
if (video_header.generic.has_value()) {
return GetRefFinderAs<RtpGenericFrameRefFinder>().ManageFrame(
std::move(frame), *video_header.generic);
}
switch (frame->codec_type()) {
case kVideoCodecVP8: {
const RTPVideoHeaderVP8& vp8_header =
absl::get<RTPVideoHeaderVP8>(video_header.video_type_header);
if (vp8_header.temporalIdx == kNoTemporalIdx ||
vp8_header.tl0PicIdx == kNoTl0PicIdx) {
if (vp8_header.pictureId == kNoPictureId) {
return GetRefFinderAs<RtpSeqNumOnlyRefFinder>().ManageFrame(
std::move(frame));
}
return GetRefFinderAs<RtpFrameIdOnlyRefFinder>().ManageFrame(
std::move(frame), vp8_header.pictureId);
}
return GetRefFinderAs<RtpVp8RefFinder>().ManageFrame(std::move(frame));
}
case kVideoCodecVP9: {
const RTPVideoHeaderVP9& vp9_header =
absl::get<RTPVideoHeaderVP9>(video_header.video_type_header);
if (vp9_header.temporal_idx == kNoTemporalIdx) {
if (vp9_header.picture_id == kNoPictureId) {
return GetRefFinderAs<RtpSeqNumOnlyRefFinder>().ManageFrame(
std::move(frame));
}
return GetRefFinderAs<RtpFrameIdOnlyRefFinder>().ManageFrame(
std::move(frame), vp9_header.picture_id);
}
return GetRefFinderAs<RtpVp9RefFinder>().ManageFrame(std::move(frame));
}
case kVideoCodecGeneric: {
if (auto* generic_header = absl::get_if<RTPVideoHeaderLegacyGeneric>(
&video_header.video_type_header)) {
return GetRefFinderAs<RtpFrameIdOnlyRefFinder>().ManageFrame(
std::move(frame), generic_header->picture_id);
}
return GetRefFinderAs<RtpSeqNumOnlyRefFinder>().ManageFrame(
std::move(frame));
}
default: {
return GetRefFinderAs<RtpSeqNumOnlyRefFinder>().ManageFrame(
std::move(frame));
}
}
}
RtpFrameReferenceFinder::ReturnVector
RtpFrameReferenceFinderImpl::PaddingReceived(uint16_t seq_num) {
if (auto* ref_finder = absl::get_if<RtpSeqNumOnlyRefFinder>(&ref_finder_)) {
return ref_finder->PaddingReceived(seq_num);
}
return {};
}
void RtpFrameReferenceFinderImpl::ClearTo(uint16_t seq_num) {
struct ClearToVisitor {
void operator()(absl::monostate& ref_finder) {}
void operator()(RtpGenericFrameRefFinder& ref_finder) {}
void operator()(RtpFrameIdOnlyRefFinder& ref_finder) {}
void operator()(RtpSeqNumOnlyRefFinder& ref_finder) {
ref_finder.ClearTo(seq_num);
}
void operator()(RtpVp8RefFinder& ref_finder) {
ref_finder.ClearTo(seq_num);
}
void operator()(RtpVp9RefFinder& ref_finder) {
ref_finder.ClearTo(seq_num);
}
uint16_t seq_num;
};
absl::visit(ClearToVisitor{seq_num}, ref_finder_);
}
template <typename T>
T& RtpFrameReferenceFinderImpl::GetRefFinderAs() {
if (auto* ref_finder = absl::get_if<T>(&ref_finder_)) {
return *ref_finder;
}
return ref_finder_.emplace<T>();
}
} // namespace internal
RtpFrameReferenceFinder::RtpFrameReferenceFinder(
OnCompleteFrameCallback* frame_callback)
: RtpFrameReferenceFinder(frame_callback, 0) {}
RtpFrameReferenceFinder::RtpFrameReferenceFinder(
OnCompleteFrameCallback* frame_callback,
int64_t picture_id_offset)
: picture_id_offset_(picture_id_offset),
frame_callback_(frame_callback),
impl_(std::make_unique<internal::RtpFrameReferenceFinderImpl>()) {}
RtpFrameReferenceFinder::~RtpFrameReferenceFinder() = default;
void RtpFrameReferenceFinder::ManageFrame(
std::unique_ptr<RtpFrameObject> frame) {
// If we have cleared past this frame, drop it.
if (cleared_to_seq_num_ != -1 &&
AheadOf<uint16_t>(cleared_to_seq_num_, frame->first_seq_num())) {
return;
}
HandOffFrames(impl_->ManageFrame(std::move(frame)));
}
void RtpFrameReferenceFinder::PaddingReceived(uint16_t seq_num) {
HandOffFrames(impl_->PaddingReceived(seq_num));
}
void RtpFrameReferenceFinder::ClearTo(uint16_t seq_num) {
cleared_to_seq_num_ = seq_num;
impl_->ClearTo(seq_num);
}
void RtpFrameReferenceFinder::HandOffFrames(ReturnVector frames) {
for (auto& frame : frames) {
frame->id.picture_id += picture_id_offset_;
for (size_t i = 0; i < frame->num_references; ++i) {
frame->references[i] += picture_id_offset_;
}
frame_callback_->OnCompleteFrame(std::move(frame));
}
}
} // namespace video_coding
} // namespace webrtc