1 /*
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
11 #include "media/base/adapted_video_track_source.h"
12
13 #include "api/scoped_refptr.h"
14 #include "api/video/i420_buffer.h"
15 #include "api/video/video_frame_buffer.h"
16 #include "api/video/video_rotation.h"
17 #include "rtc_base/checks.h"
18 #include "rtc_base/time_utils.h"
19
20 namespace rtc {
21
22 AdaptedVideoTrackSource::AdaptedVideoTrackSource() = default;
23
AdaptedVideoTrackSource(int required_alignment)24 AdaptedVideoTrackSource::AdaptedVideoTrackSource(int required_alignment)
25 : video_adapter_(required_alignment) {}
26
27 AdaptedVideoTrackSource::~AdaptedVideoTrackSource() = default;
28
GetStats(Stats * stats)29 bool AdaptedVideoTrackSource::GetStats(Stats* stats) {
30 webrtc::MutexLock lock(&stats_mutex_);
31
32 if (!stats_) {
33 return false;
34 }
35
36 *stats = *stats_;
37 return true;
38 }
39
OnFrame(const webrtc::VideoFrame & frame)40 void AdaptedVideoTrackSource::OnFrame(const webrtc::VideoFrame& frame) {
41 rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer(
42 frame.video_frame_buffer());
43 /* Note that this is a "best effort" approach to
44 wants.rotation_applied; apply_rotation_ can change from false to
45 true between the check of apply_rotation() and the call to
46 broadcaster_.OnFrame(), in which case we generate a frame with
47 pending rotation despite some sink with wants.rotation_applied ==
48 true was just added. The VideoBroadcaster enforces
49 synchronization for us in this case, by not passing the frame on
50 to sinks which don't want it. */
51 if (apply_rotation() && frame.rotation() != webrtc::kVideoRotation_0 &&
52 buffer->type() == webrtc::VideoFrameBuffer::Type::kI420) {
53 /* Apply pending rotation. */
54 webrtc::VideoFrame rotated_frame(frame);
55 rotated_frame.set_video_frame_buffer(
56 webrtc::I420Buffer::Rotate(*buffer->GetI420(), frame.rotation()));
57 rotated_frame.set_rotation(webrtc::kVideoRotation_0);
58 broadcaster_.OnFrame(rotated_frame);
59 } else {
60 broadcaster_.OnFrame(frame);
61 }
62 }
63
OnFrameDropped()64 void AdaptedVideoTrackSource::OnFrameDropped() {
65 broadcaster_.OnDiscardedFrame();
66 }
67
AddOrUpdateSink(rtc::VideoSinkInterface<webrtc::VideoFrame> * sink,const rtc::VideoSinkWants & wants)68 void AdaptedVideoTrackSource::AddOrUpdateSink(
69 rtc::VideoSinkInterface<webrtc::VideoFrame>* sink,
70 const rtc::VideoSinkWants& wants) {
71 broadcaster_.AddOrUpdateSink(sink, wants);
72 OnSinkWantsChanged(broadcaster_.wants());
73 }
74
RemoveSink(rtc::VideoSinkInterface<webrtc::VideoFrame> * sink)75 void AdaptedVideoTrackSource::RemoveSink(
76 rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
77 broadcaster_.RemoveSink(sink);
78 OnSinkWantsChanged(broadcaster_.wants());
79 }
80
apply_rotation()81 bool AdaptedVideoTrackSource::apply_rotation() {
82 return broadcaster_.wants().rotation_applied;
83 }
84
OnSinkWantsChanged(const rtc::VideoSinkWants & wants)85 void AdaptedVideoTrackSource::OnSinkWantsChanged(
86 const rtc::VideoSinkWants& wants) {
87 video_adapter_.OnSinkWants(wants);
88 }
89
AdaptFrame(int width,int height,int64_t time_us,int * out_width,int * out_height,int * crop_width,int * crop_height,int * crop_x,int * crop_y)90 bool AdaptedVideoTrackSource::AdaptFrame(int width,
91 int height,
92 int64_t time_us,
93 int* out_width,
94 int* out_height,
95 int* crop_width,
96 int* crop_height,
97 int* crop_x,
98 int* crop_y) {
99 {
100 webrtc::MutexLock lock(&stats_mutex_);
101 stats_ = Stats{width, height};
102 }
103
104 if (!broadcaster_.frame_wanted()) {
105 return false;
106 }
107
108 if (!video_adapter_.AdaptFrameResolution(
109 width, height, time_us * rtc::kNumNanosecsPerMicrosec, crop_width,
110 crop_height, out_width, out_height)) {
111 broadcaster_.OnDiscardedFrame();
112 // VideoAdapter dropped the frame.
113 return false;
114 }
115
116 *crop_x = (width - *crop_width) / 2;
117 *crop_y = (height - *crop_height) / 2;
118 return true;
119 }
120
ProcessConstraints(const webrtc::VideoTrackSourceConstraints & constraints)121 void AdaptedVideoTrackSource::ProcessConstraints(
122 const webrtc::VideoTrackSourceConstraints& constraints) {
123 broadcaster_.ProcessConstraints(constraints);
124 }
125
126 } // namespace rtc
127