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
AddOrUpdateSink(rtc::VideoSinkInterface<webrtc::VideoFrame> * sink,const rtc::VideoSinkWants & wants)64 void AdaptedVideoTrackSource::AddOrUpdateSink(
65 rtc::VideoSinkInterface<webrtc::VideoFrame>* sink,
66 const rtc::VideoSinkWants& wants) {
67 broadcaster_.AddOrUpdateSink(sink, wants);
68 OnSinkWantsChanged(broadcaster_.wants());
69 }
70
RemoveSink(rtc::VideoSinkInterface<webrtc::VideoFrame> * sink)71 void AdaptedVideoTrackSource::RemoveSink(
72 rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
73 broadcaster_.RemoveSink(sink);
74 OnSinkWantsChanged(broadcaster_.wants());
75 }
76
apply_rotation()77 bool AdaptedVideoTrackSource::apply_rotation() {
78 return broadcaster_.wants().rotation_applied;
79 }
80
OnSinkWantsChanged(const rtc::VideoSinkWants & wants)81 void AdaptedVideoTrackSource::OnSinkWantsChanged(
82 const rtc::VideoSinkWants& wants) {
83 video_adapter_.OnSinkWants(wants);
84 }
85
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)86 bool AdaptedVideoTrackSource::AdaptFrame(int width,
87 int height,
88 int64_t time_us,
89 int* out_width,
90 int* out_height,
91 int* crop_width,
92 int* crop_height,
93 int* crop_x,
94 int* crop_y) {
95 {
96 webrtc::MutexLock lock(&stats_mutex_);
97 stats_ = Stats{width, height};
98 }
99
100 if (!broadcaster_.frame_wanted()) {
101 return false;
102 }
103
104 if (!video_adapter_.AdaptFrameResolution(
105 width, height, time_us * rtc::kNumNanosecsPerMicrosec, crop_width,
106 crop_height, out_width, out_height)) {
107 broadcaster_.OnDiscardedFrame();
108 // VideoAdapter dropped the frame.
109 return false;
110 }
111
112 *crop_x = (width - *crop_width) / 2;
113 *crop_y = (height - *crop_height) / 2;
114 return true;
115 }
116
117 } // namespace rtc
118