blob: 41f2cad6ffec1fa9f545556da96575a2e2b1d3b4 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
sprang3911c262016-04-15 01:24:14 -07002* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3*
4* Use of this source code is governed by a BSD-style license
5* that can be found in the LICENSE file in the root of the source
6* tree. An additional intellectual property rights grant can be found
7* in the file PATENTS. All contributing project authors may
8* be found in the AUTHORS file in the root of the source tree.
9*/
niklase@google.com470e71d2011-07-07 08:21:25 +000010
philipel9d3ab612015-12-21 04:12:39 -080011#include "webrtc/modules/video_coding/generic_encoder.h"
12
13#include <vector>
14
nisseaf916892017-01-10 07:44:26 -080015#include "webrtc/api/video/i420_buffer.h"
Guo-wei Shieh2c370782015-04-08 13:00:10 -070016#include "webrtc/base/checks.h"
pbos854e84c2015-11-16 16:39:06 -080017#include "webrtc/base/logging.h"
pbosd9eec762015-11-17 06:03:43 -080018#include "webrtc/base/trace_event.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010019#include "webrtc/modules/video_coding/encoded_frame.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010020#include "webrtc/modules/video_coding/media_optimization.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010021#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000022
23namespace webrtc {
Sergey Ulanov525df3f2016-08-02 17:46:41 -070024
Peter Boström4f5db112015-10-29 16:53:59 +010025VCMGenericEncoder::VCMGenericEncoder(
26 VideoEncoder* encoder,
Peter Boström4f5db112015-10-29 16:53:59 +010027 VCMEncodedFrameCallback* encoded_frame_callback,
sprang3911c262016-04-15 01:24:14 -070028 bool internal_source)
pbos@webrtc.org891d4832015-02-26 13:15:22 +000029 : encoder_(encoder),
Peter Boström4f5db112015-10-29 16:53:59 +010030 vcm_encoded_frame_callback_(encoded_frame_callback),
sprang3911c262016-04-15 01:24:14 -070031 internal_source_(internal_source),
Erik Språng08127a92016-11-16 16:41:30 +010032 encoder_params_({BitrateAllocation(), 0, 0, 0}),
Peter Boström69ccb332015-10-29 16:30:23 +010033 is_screenshare_(false) {}
niklase@google.com470e71d2011-07-07 08:21:25 +000034
Peter Boström4f5db112015-10-29 16:53:59 +010035VCMGenericEncoder::~VCMGenericEncoder() {}
36
37int32_t VCMGenericEncoder::Release() {
Peter Boström02bafc62016-07-01 12:45:15 +020038 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
Peter Boström4fd6cda2016-01-26 10:19:53 +010039 TRACE_EVENT0("webrtc", "VCMGenericEncoder::Release");
Peter Boström4f5db112015-10-29 16:53:59 +010040 return encoder_->Release();
niklase@google.com470e71d2011-07-07 08:21:25 +000041}
42
Peter Boström4f5db112015-10-29 16:53:59 +010043int32_t VCMGenericEncoder::InitEncode(const VideoCodec* settings,
sprang3911c262016-04-15 01:24:14 -070044 int32_t number_of_cores,
45 size_t max_payload_size) {
Peter Boström02bafc62016-07-01 12:45:15 +020046 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
pbosd9eec762015-11-17 06:03:43 -080047 TRACE_EVENT0("webrtc", "VCMGenericEncoder::InitEncode");
Peter Boström4f5db112015-10-29 16:53:59 +010048 is_screenshare_ = settings->mode == VideoCodecMode::kScreensharing;
sprang3911c262016-04-15 01:24:14 -070049 if (encoder_->InitEncode(settings, number_of_cores, max_payload_size) != 0) {
Peter Boström4f5db112015-10-29 16:53:59 +010050 LOG(LS_ERROR) << "Failed to initialize the encoder associated with "
51 "payload name: "
52 << settings->plName;
53 return -1;
54 }
55 encoder_->RegisterEncodeCompleteCallback(vcm_encoded_frame_callback_);
56 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000057}
58
sprang3911c262016-04-15 01:24:14 -070059int32_t VCMGenericEncoder::Encode(const VideoFrame& frame,
60 const CodecSpecificInfo* codec_specific,
61 const std::vector<FrameType>& frame_types) {
Peter Boström02bafc62016-07-01 12:45:15 +020062 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
pbosd9eec762015-11-17 06:03:43 -080063 TRACE_EVENT1("webrtc", "VCMGenericEncoder::Encode", "timestamp",
sprang3911c262016-04-15 01:24:14 -070064 frame.timestamp());
pbosd9eec762015-11-17 06:03:43 -080065
sprang3911c262016-04-15 01:24:14 -070066 for (FrameType frame_type : frame_types)
pbos22993e12015-10-19 02:39:06 -070067 RTC_DCHECK(frame_type == kVideoFrameKey || frame_type == kVideoFrameDelta);
guoweis@webrtc.org54d072e2015-03-17 21:54:50 +000068
sprang3911c262016-04-15 01:24:14 -070069 int32_t result = encoder_->Encode(frame, codec_specific, &frame_types);
Peter Boströmb7d9a972015-12-18 16:01:11 +010070
Erik Språng2c4c9142015-06-24 11:24:44 +020071 if (is_screenshare_ &&
72 result == WEBRTC_VIDEO_CODEC_TARGET_BITRATE_OVERSHOOT) {
73 // Target bitrate exceeded, encoder state has been reset - try again.
sprang3911c262016-04-15 01:24:14 -070074 return encoder_->Encode(frame, codec_specific, &frame_types);
Erik Språng2c4c9142015-06-24 11:24:44 +020075 }
76
77 return result;
niklase@google.com470e71d2011-07-07 08:21:25 +000078}
79
Peter Boström69ccb332015-10-29 16:30:23 +010080void VCMGenericEncoder::SetEncoderParameters(const EncoderParameters& params) {
Peter Boström02bafc62016-07-01 12:45:15 +020081 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
Peter Boström69ccb332015-10-29 16:30:23 +010082 bool channel_parameters_have_changed;
83 bool rates_have_changed;
84 {
85 rtc::CritScope lock(&params_lock_);
86 channel_parameters_have_changed =
87 params.loss_rate != encoder_params_.loss_rate ||
88 params.rtt != encoder_params_.rtt;
89 rates_have_changed =
90 params.target_bitrate != encoder_params_.target_bitrate ||
91 params.input_frame_rate != encoder_params_.input_frame_rate;
92 encoder_params_ = params;
93 }
Erik Språng08127a92016-11-16 16:41:30 +010094 if (channel_parameters_have_changed) {
95 int res = encoder_->SetChannelParameters(params.loss_rate, params.rtt);
96 if (res != 0) {
97 LOG(LS_WARNING) << "Error set encoder parameters (loss = "
98 << params.loss_rate << ", rtt = " << params.rtt
99 << "): " << res;
100 }
101 }
Peter Boström69ccb332015-10-29 16:30:23 +0100102 if (rates_have_changed) {
Erik Språng08127a92016-11-16 16:41:30 +0100103 int res = encoder_->SetRateAllocation(params.target_bitrate,
104 params.input_frame_rate);
105 if (res != 0) {
106 LOG(LS_WARNING) << "Error set encoder rate (total bitrate bps = "
107 << params.target_bitrate.get_sum_bps()
108 << ", framerate = " << params.input_frame_rate
109 << "): " << res;
110 }
Peter Boström69ccb332015-10-29 16:30:23 +0100111 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000112}
113
Peter Boström69ccb332015-10-29 16:30:23 +0100114EncoderParameters VCMGenericEncoder::GetEncoderParameters() const {
115 rtc::CritScope lock(&params_lock_);
116 return encoder_params_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000117}
118
philipel9d3ab612015-12-21 04:12:39 -0800119int32_t VCMGenericEncoder::SetPeriodicKeyFrames(bool enable) {
Peter Boström02bafc62016-07-01 12:45:15 +0200120 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
philipel9d3ab612015-12-21 04:12:39 -0800121 return encoder_->SetPeriodicKeyFrames(enable);
niklase@google.com470e71d2011-07-07 08:21:25 +0000122}
123
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000124int32_t VCMGenericEncoder::RequestFrame(
stefan@webrtc.orgcf216862012-10-25 11:29:51 +0000125 const std::vector<FrameType>& frame_types) {
Peter Boström02bafc62016-07-01 12:45:15 +0200126 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
nissedf2ceb82016-12-15 06:29:53 -0800127
128 // TODO(nisse): Used only with internal source. Delete as soon as
129 // that feature is removed. The only implementation I've been able
130 // to find ignores what's in the frame.
131 return encoder_->Encode(VideoFrame(I420Buffer::Create(1, 1),
132 kVideoRotation_0, 0),
133 NULL, &frame_types);
134 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000135}
136
philipel9d3ab612015-12-21 04:12:39 -0800137bool VCMGenericEncoder::InternalSource() const {
138 return internal_source_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000139}
140
Peter Boströmeb66e802015-06-05 11:08:03 +0200141bool VCMGenericEncoder::SupportsNativeHandle() const {
Peter Boström02bafc62016-07-01 12:45:15 +0200142 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
Peter Boströmeb66e802015-06-05 11:08:03 +0200143 return encoder_->SupportsNativeHandle();
144}
145
andresp@webrtc.org1df9dc32014-01-09 08:01:57 +0000146VCMEncodedFrameCallback::VCMEncodedFrameCallback(
perkj376b1922016-05-02 11:35:24 -0700147 EncodedImageCallback* post_encode_callback,
148 media_optimization::MediaOptimization* media_opt)
149 : internal_source_(false),
150 post_encode_callback_(post_encode_callback),
151 media_opt_(media_opt) {}
niklase@google.com470e71d2011-07-07 08:21:25 +0000152
sprang3911c262016-04-15 01:24:14 -0700153VCMEncodedFrameCallback::~VCMEncodedFrameCallback() {}
niklase@google.com470e71d2011-07-07 08:21:25 +0000154
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700155EncodedImageCallback::Result VCMEncodedFrameCallback::OnEncodedImage(
Peter Boströmb7d9a972015-12-18 16:01:11 +0100156 const EncodedImage& encoded_image,
sprang3911c262016-04-15 01:24:14 -0700157 const CodecSpecificInfo* codec_specific,
158 const RTPFragmentationHeader* fragmentation_header) {
pbosd9eec762015-11-17 06:03:43 -0800159 TRACE_EVENT_INSTANT1("webrtc", "VCMEncodedFrameCallback::Encoded",
Peter Boströmb7d9a972015-12-18 16:01:11 +0100160 "timestamp", encoded_image._timeStamp);
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700161 Result result = post_encode_callback_->OnEncodedImage(
162 encoded_image, codec_specific, fragmentation_header);
163 if (result.error != Result::OK)
164 return result;
niklase@google.com470e71d2011-07-07 08:21:25 +0000165
sprang3911c262016-04-15 01:24:14 -0700166 if (media_opt_) {
167 media_opt_->UpdateWithEncodedData(encoded_image);
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700168 if (internal_source_) {
169 // Signal to encoder to drop next frame.
170 result.drop_next_frame = media_opt_->DropFrame();
171 }
changbin.shao@webrtc.orgf31f56d2015-02-09 09:14:03 +0000172 }
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700173 return result;
niklase@google.com470e71d2011-07-07 08:21:25 +0000174}
175
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000176} // namespace webrtc