blob: c0a4d3668bc6e7a95ff118d7d669f2bac5117d0e [file] [log] [blame]
nisse6f5a6c32016-09-22 01:25:59 -07001/*
2 * Copyright (c) 2016 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 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "media/base/adaptedvideotracksource.h"
nisse6f5a6c32016-09-22 01:25:59 -070012
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "api/video/i420_buffer.h"
Yves Gerey3e707812018-11-28 16:47:49 +010014#include "api/video/video_frame_buffer.h"
15#include "api/video/video_rotation.h"
16#include "rtc_base/checks.h"
17#include "rtc_base/scoped_ref_ptr.h"
18#include "rtc_base/timeutils.h"
nisseaf916892017-01-10 07:44:26 -080019
nisse6f5a6c32016-09-22 01:25:59 -070020namespace rtc {
21
22AdaptedVideoTrackSource::AdaptedVideoTrackSource() {
23 thread_checker_.DetachFromThread();
24}
25
kthelgasonc8474172016-12-08 08:04:51 -080026AdaptedVideoTrackSource::AdaptedVideoTrackSource(int required_alignment)
27 : video_adapter_(required_alignment) {
28 thread_checker_.DetachFromThread();
29}
Paulina Hensmana680a6a2018-04-05 11:42:24 +020030AdaptedVideoTrackSource::~AdaptedVideoTrackSource() = default;
kthelgasonc8474172016-12-08 08:04:51 -080031
nisse6f5a6c32016-09-22 01:25:59 -070032bool AdaptedVideoTrackSource::GetStats(Stats* stats) {
33 rtc::CritScope lock(&stats_crit_);
34
35 if (!stats_) {
36 return false;
37 }
38
39 *stats = *stats_;
40 return true;
41}
42
nisseacd935b2016-11-11 03:55:13 -080043void AdaptedVideoTrackSource::OnFrame(const webrtc::VideoFrame& frame) {
nisse6f5a6c32016-09-22 01:25:59 -070044 rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer(
45 frame.video_frame_buffer());
46 /* Note that this is a "best effort" approach to
47 wants.rotation_applied; apply_rotation_ can change from false to
48 true between the check of apply_rotation() and the call to
49 broadcaster_.OnFrame(), in which case we generate a frame with
50 pending rotation despite some sink with wants.rotation_applied ==
51 true was just added. The VideoBroadcaster enforces
52 synchronization for us in this case, by not passing the frame on
53 to sinks which don't want it. */
magjed3f075492017-06-01 10:02:26 -070054 if (apply_rotation() && frame.rotation() != webrtc::kVideoRotation_0 &&
55 buffer->type() == webrtc::VideoFrameBuffer::Type::kI420) {
nisse6f5a6c32016-09-22 01:25:59 -070056 /* Apply pending rotation. */
Artem Titov1ebfb6a2019-01-03 23:49:37 +010057 webrtc::VideoFrame rotated_frame =
58 webrtc::VideoFrame::Builder()
59 .set_video_frame_buffer(webrtc::I420Buffer::Rotate(
60 *buffer->GetI420(), frame.rotation()))
61 .set_rotation(webrtc::kVideoRotation_0)
62 .set_timestamp_us(frame.timestamp_us())
63 .set_id(frame.id())
64 .build();
65 broadcaster_.OnFrame(rotated_frame);
nisse6f5a6c32016-09-22 01:25:59 -070066 } else {
67 broadcaster_.OnFrame(frame);
68 }
69}
70
71void AdaptedVideoTrackSource::AddOrUpdateSink(
nisseacd935b2016-11-11 03:55:13 -080072 rtc::VideoSinkInterface<webrtc::VideoFrame>* sink,
nisse6f5a6c32016-09-22 01:25:59 -070073 const rtc::VideoSinkWants& wants) {
74 RTC_DCHECK(thread_checker_.CalledOnValidThread());
75
76 broadcaster_.AddOrUpdateSink(sink, wants);
77 OnSinkWantsChanged(broadcaster_.wants());
78}
79
80void AdaptedVideoTrackSource::RemoveSink(
nisseacd935b2016-11-11 03:55:13 -080081 rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
nisse6f5a6c32016-09-22 01:25:59 -070082 RTC_DCHECK(thread_checker_.CalledOnValidThread());
83
84 broadcaster_.RemoveSink(sink);
85 OnSinkWantsChanged(broadcaster_.wants());
86}
87
88bool AdaptedVideoTrackSource::apply_rotation() {
89 return broadcaster_.wants().rotation_applied;
90}
91
92void AdaptedVideoTrackSource::OnSinkWantsChanged(
93 const rtc::VideoSinkWants& wants) {
94 RTC_DCHECK(thread_checker_.CalledOnValidThread());
sprangc5d62e22017-04-02 23:53:04 -070095 video_adapter_.OnResolutionFramerateRequest(
96 wants.target_pixel_count, wants.max_pixel_count, wants.max_framerate_fps);
nisse6f5a6c32016-09-22 01:25:59 -070097}
98
99bool AdaptedVideoTrackSource::AdaptFrame(int width,
100 int height,
101 int64_t time_us,
102 int* out_width,
103 int* out_height,
104 int* crop_width,
105 int* crop_height,
106 int* crop_x,
107 int* crop_y) {
108 {
109 rtc::CritScope lock(&stats_crit_);
Oskar Sundbom78807582017-11-16 11:09:55 +0100110 stats_ = Stats{width, height};
nisse6f5a6c32016-09-22 01:25:59 -0700111 }
112
113 if (!broadcaster_.frame_wanted()) {
114 return false;
115 }
116
117 if (!video_adapter_.AdaptFrameResolution(
Yves Gerey665174f2018-06-19 15:03:05 +0200118 width, height, time_us * rtc::kNumNanosecsPerMicrosec, crop_width,
119 crop_height, out_width, out_height)) {
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200120 broadcaster_.OnDiscardedFrame();
nisse6f5a6c32016-09-22 01:25:59 -0700121 // VideoAdapter dropped the frame.
122 return false;
123 }
124
125 *crop_x = (width - *crop_width) / 2;
126 *crop_y = (height - *crop_height) / 2;
127 return true;
128}
129
130} // namespace rtc