mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 13:50:40 +01:00

Added for the structs VideoCodecVP8, VideoCodecVP9, VideoCodecH264, and SpatialLayer. New operators are used to replace memcmp in VCMEncoderDataBase. Using memcmp to compare structs is generally unreliable, since the struct may contain random padding bytes due to alignment requirements (affects at least VideoCodecH264). And in the case of VideoCodecVP8, we need to exclude the tl_factory pointers from the comparison. Bug: webrtc:8830 Change-Id: I40432ea7834e288f8c89ce0a28a630ae1800dff8 Reviewed-on: https://webrtc-review.googlesource.com/62761 Commit-Queue: Niels Moller <nisse@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> Cr-Commit-Position: refs/heads/master@{#22500}
194 lines
5.9 KiB
C++
194 lines
5.9 KiB
C++
/*
|
|
* Copyright (c) 2018 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/encoder_database.h"
|
|
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/logging.h"
|
|
|
|
namespace webrtc {
|
|
|
|
namespace {
|
|
const size_t kDefaultPayloadSize = 1440;
|
|
}
|
|
|
|
VCMEncoderDataBase::VCMEncoderDataBase(
|
|
VCMEncodedFrameCallback* encoded_frame_callback)
|
|
: number_of_cores_(0),
|
|
max_payload_size_(kDefaultPayloadSize),
|
|
pending_encoder_reset_(true),
|
|
send_codec_(),
|
|
external_encoder_(nullptr),
|
|
internal_source_(false),
|
|
encoded_frame_callback_(encoded_frame_callback) {}
|
|
|
|
VCMEncoderDataBase::~VCMEncoderDataBase() {
|
|
DeleteEncoder();
|
|
}
|
|
|
|
// Assuming only one registered encoder - since only one used, no need for more.
|
|
bool VCMEncoderDataBase::SetSendCodec(const VideoCodec* send_codec,
|
|
int number_of_cores,
|
|
size_t max_payload_size) {
|
|
RTC_DCHECK(send_codec);
|
|
if (max_payload_size == 0) {
|
|
max_payload_size = kDefaultPayloadSize;
|
|
}
|
|
RTC_DCHECK_GE(number_of_cores, 1);
|
|
// Make sure the start bit rate is sane...
|
|
RTC_DCHECK_LE(send_codec->startBitrate, 1000000);
|
|
RTC_DCHECK(send_codec->codecType != kVideoCodecUnknown);
|
|
bool reset_required = pending_encoder_reset_;
|
|
if (number_of_cores_ != number_of_cores) {
|
|
number_of_cores_ = number_of_cores;
|
|
reset_required = true;
|
|
}
|
|
if (max_payload_size_ != max_payload_size) {
|
|
max_payload_size_ = max_payload_size;
|
|
reset_required = true;
|
|
}
|
|
|
|
VideoCodec new_send_codec;
|
|
memcpy(&new_send_codec, send_codec, sizeof(new_send_codec));
|
|
|
|
if (new_send_codec.maxBitrate == 0) {
|
|
// max is one bit per pixel
|
|
new_send_codec.maxBitrate = (static_cast<int>(send_codec->height) *
|
|
static_cast<int>(send_codec->width) *
|
|
static_cast<int>(send_codec->maxFramerate)) /
|
|
1000;
|
|
if (send_codec->startBitrate > new_send_codec.maxBitrate) {
|
|
// But if the user tries to set a higher start bit rate we will
|
|
// increase the max accordingly.
|
|
new_send_codec.maxBitrate = send_codec->startBitrate;
|
|
}
|
|
}
|
|
|
|
if (new_send_codec.startBitrate > new_send_codec.maxBitrate)
|
|
new_send_codec.startBitrate = new_send_codec.maxBitrate;
|
|
|
|
if (!reset_required) {
|
|
reset_required = RequiresEncoderReset(new_send_codec);
|
|
}
|
|
|
|
memcpy(&send_codec_, &new_send_codec, sizeof(send_codec_));
|
|
|
|
if (!reset_required) {
|
|
return true;
|
|
}
|
|
|
|
// If encoder exists, will destroy it and create new one.
|
|
DeleteEncoder();
|
|
ptr_encoder_.reset(new VCMGenericEncoder(
|
|
external_encoder_, encoded_frame_callback_, internal_source_));
|
|
encoded_frame_callback_->SetInternalSource(internal_source_);
|
|
if (ptr_encoder_->InitEncode(&send_codec_, number_of_cores_,
|
|
max_payload_size_) < 0) {
|
|
RTC_LOG(LS_ERROR) << "Failed to initialize video encoder.";
|
|
DeleteEncoder();
|
|
return false;
|
|
}
|
|
|
|
pending_encoder_reset_ = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void VCMEncoderDataBase::DeregisterExternalEncoder() {
|
|
DeleteEncoder();
|
|
memset(&send_codec_, 0, sizeof(VideoCodec));
|
|
external_encoder_ = nullptr;
|
|
internal_source_ = false;
|
|
}
|
|
|
|
void VCMEncoderDataBase::RegisterExternalEncoder(VideoEncoder* external_encoder,
|
|
bool internal_source) {
|
|
// Since only one encoder can be used at a given time, only one external
|
|
// encoder can be registered/used.
|
|
RTC_CHECK(external_encoder_ == nullptr);
|
|
external_encoder_ = external_encoder;
|
|
internal_source_ = internal_source;
|
|
pending_encoder_reset_ = true;
|
|
}
|
|
|
|
bool VCMEncoderDataBase::RequiresEncoderReset(
|
|
const VideoCodec& new_send_codec) {
|
|
if (!ptr_encoder_)
|
|
return true;
|
|
|
|
// Does not check startBitrate, maxFramerate or plType
|
|
if (new_send_codec.codecType != send_codec_.codecType ||
|
|
new_send_codec.width != send_codec_.width ||
|
|
new_send_codec.height != send_codec_.height ||
|
|
new_send_codec.maxBitrate != send_codec_.maxBitrate ||
|
|
new_send_codec.minBitrate != send_codec_.minBitrate ||
|
|
new_send_codec.qpMax != send_codec_.qpMax ||
|
|
new_send_codec.numberOfSimulcastStreams !=
|
|
send_codec_.numberOfSimulcastStreams ||
|
|
new_send_codec.mode != send_codec_.mode) {
|
|
return true;
|
|
}
|
|
|
|
switch (new_send_codec.codecType) {
|
|
case kVideoCodecVP8:
|
|
if (new_send_codec.VP8() != *send_codec_.VP8()) {
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
case kVideoCodecVP9:
|
|
if (new_send_codec.VP9() != *send_codec_.VP9()) {
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
case kVideoCodecH264:
|
|
if (new_send_codec.H264() != *send_codec_.H264()) {
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
case kVideoCodecGeneric:
|
|
break;
|
|
// Known codecs without payload-specifics
|
|
case kVideoCodecI420:
|
|
case kVideoCodecRED:
|
|
case kVideoCodecULPFEC:
|
|
case kVideoCodecFlexfec:
|
|
case kVideoCodecMultiplex:
|
|
break;
|
|
// Unknown codec type, reset just to be sure.
|
|
case kVideoCodecUnknown:
|
|
return true;
|
|
}
|
|
|
|
for (unsigned char i = 0; i < new_send_codec.numberOfSimulcastStreams; ++i) {
|
|
if (new_send_codec.simulcastStream[i] != send_codec_.simulcastStream[i])
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
VCMGenericEncoder* VCMEncoderDataBase::GetEncoder() {
|
|
return ptr_encoder_.get();
|
|
}
|
|
|
|
void VCMEncoderDataBase::DeleteEncoder() {
|
|
if (!ptr_encoder_)
|
|
return;
|
|
ptr_encoder_->Release();
|
|
ptr_encoder_.reset();
|
|
}
|
|
|
|
bool VCMEncoderDataBase::MatchesCurrentResolution(int width, int height) const {
|
|
return send_codec_.width == width && send_codec_.height == height;
|
|
}
|
|
|
|
} // namespace webrtc
|