blob: c8c3222a1236e33f2244c6a2c717689348f0f658 [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
Steve Anton10542f22019-01-11 09:11:00 -080011#include "media/base/adapted_video_track_source.h"
nisse6f5a6c32016-09-22 01:25:59 -070012
Mirko Bonadeid9708072019-01-25 20:26:48 +010013#include "api/scoped_refptr.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020014#include "api/video/i420_buffer.h"
Yves Gerey3e707812018-11-28 16:47:49 +010015#include "api/video/video_frame_buffer.h"
16#include "api/video/video_rotation.h"
17#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080018#include "rtc_base/time_utils.h"
nisseaf916892017-01-10 07:44:26 -080019
nisse6f5a6c32016-09-22 01:25:59 -070020namespace rtc {
21
Magnus Jedvert167316b2019-01-31 13:23:46 +010022AdaptedVideoTrackSource::AdaptedVideoTrackSource() = default;
nisse6f5a6c32016-09-22 01:25:59 -070023
kthelgasonc8474172016-12-08 08:04:51 -080024AdaptedVideoTrackSource::AdaptedVideoTrackSource(int required_alignment)
Magnus Jedvert167316b2019-01-31 13:23:46 +010025 : video_adapter_(required_alignment) {}
26
Paulina Hensmana680a6a2018-04-05 11:42:24 +020027AdaptedVideoTrackSource::~AdaptedVideoTrackSource() = default;
kthelgasonc8474172016-12-08 08:04:51 -080028
nisse6f5a6c32016-09-22 01:25:59 -070029bool AdaptedVideoTrackSource::GetStats(Stats* stats) {
30 rtc::CritScope lock(&stats_crit_);
31
32 if (!stats_) {
33 return false;
34 }
35
36 *stats = *stats_;
37 return true;
38}
39
nisseacd935b2016-11-11 03:55:13 -080040void AdaptedVideoTrackSource::OnFrame(const webrtc::VideoFrame& frame) {
nisse6f5a6c32016-09-22 01:25:59 -070041 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. */
magjed3f075492017-06-01 10:02:26 -070051 if (apply_rotation() && frame.rotation() != webrtc::kVideoRotation_0 &&
52 buffer->type() == webrtc::VideoFrameBuffer::Type::kI420) {
nisse6f5a6c32016-09-22 01:25:59 -070053 /* Apply pending rotation. */
Ilya Nikolaevskiy4fc08552019-06-05 15:59:12 +020054 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);
Artem Titov1ebfb6a2019-01-03 23:49:37 +010058 broadcaster_.OnFrame(rotated_frame);
nisse6f5a6c32016-09-22 01:25:59 -070059 } else {
60 broadcaster_.OnFrame(frame);
61 }
62}
63
64void AdaptedVideoTrackSource::AddOrUpdateSink(
nisseacd935b2016-11-11 03:55:13 -080065 rtc::VideoSinkInterface<webrtc::VideoFrame>* sink,
nisse6f5a6c32016-09-22 01:25:59 -070066 const rtc::VideoSinkWants& wants) {
nisse6f5a6c32016-09-22 01:25:59 -070067 broadcaster_.AddOrUpdateSink(sink, wants);
68 OnSinkWantsChanged(broadcaster_.wants());
69}
70
71void AdaptedVideoTrackSource::RemoveSink(
nisseacd935b2016-11-11 03:55:13 -080072 rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
nisse6f5a6c32016-09-22 01:25:59 -070073 broadcaster_.RemoveSink(sink);
74 OnSinkWantsChanged(broadcaster_.wants());
75}
76
77bool AdaptedVideoTrackSource::apply_rotation() {
78 return broadcaster_.wants().rotation_applied;
79}
80
81void AdaptedVideoTrackSource::OnSinkWantsChanged(
82 const rtc::VideoSinkWants& wants) {
sprangc5d62e22017-04-02 23:53:04 -070083 video_adapter_.OnResolutionFramerateRequest(
84 wants.target_pixel_count, wants.max_pixel_count, wants.max_framerate_fps);
nisse6f5a6c32016-09-22 01:25:59 -070085}
86
87bool AdaptedVideoTrackSource::AdaptFrame(int width,
88 int height,
89 int64_t time_us,
90 int* out_width,
91 int* out_height,
92 int* crop_width,
93 int* crop_height,
94 int* crop_x,
95 int* crop_y) {
96 {
97 rtc::CritScope lock(&stats_crit_);
Oskar Sundbom78807582017-11-16 11:09:55 +010098 stats_ = Stats{width, height};
nisse6f5a6c32016-09-22 01:25:59 -070099 }
100
101 if (!broadcaster_.frame_wanted()) {
102 return false;
103 }
104
105 if (!video_adapter_.AdaptFrameResolution(
Yves Gerey665174f2018-06-19 15:03:05 +0200106 width, height, time_us * rtc::kNumNanosecsPerMicrosec, crop_width,
107 crop_height, out_width, out_height)) {
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200108 broadcaster_.OnDiscardedFrame();
nisse6f5a6c32016-09-22 01:25:59 -0700109 // VideoAdapter dropped the frame.
110 return false;
111 }
112
113 *crop_x = (width - *crop_width) / 2;
114 *crop_y = (height - *crop_height) / 2;
115 return true;
116}
117
118} // namespace rtc