• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "sdk/android/src/jni/android_video_track_source.h"
12 
13 #include "sdk/android/generated_video_jni/NativeAndroidVideoTrackSource_jni.h"
14 
15 #include <utility>
16 
17 #include "rtc_base/bind.h"
18 #include "rtc_base/logging.h"
19 
20 namespace webrtc {
21 namespace jni {
22 
23 namespace {
24 // MediaCodec wants resolution to be divisible by 2.
25 const int kRequiredResolutionAlignment = 2;
26 
jintToVideoRotation(jint rotation)27 VideoRotation jintToVideoRotation(jint rotation) {
28   RTC_DCHECK(rotation == 0 || rotation == 90 || rotation == 180 ||
29              rotation == 270);
30   return static_cast<VideoRotation>(rotation);
31 }
32 
OptionalAspectRatio(jint j_width,jint j_height)33 absl::optional<std::pair<int, int>> OptionalAspectRatio(jint j_width,
34                                                         jint j_height) {
35   if (j_width > 0 && j_height > 0)
36     return std::pair<int, int>(j_width, j_height);
37   return absl::nullopt;
38 }
39 
40 }  // namespace
41 
AndroidVideoTrackSource(rtc::Thread * signaling_thread,JNIEnv * jni,bool is_screencast,bool align_timestamps)42 AndroidVideoTrackSource::AndroidVideoTrackSource(rtc::Thread* signaling_thread,
43                                                  JNIEnv* jni,
44                                                  bool is_screencast,
45                                                  bool align_timestamps)
46     : AdaptedVideoTrackSource(kRequiredResolutionAlignment),
47       signaling_thread_(signaling_thread),
48       is_screencast_(is_screencast),
49       align_timestamps_(align_timestamps) {
50   RTC_LOG(LS_INFO) << "AndroidVideoTrackSource ctor";
51 }
52 AndroidVideoTrackSource::~AndroidVideoTrackSource() = default;
53 
is_screencast() const54 bool AndroidVideoTrackSource::is_screencast() const {
55   return is_screencast_.load();
56 }
57 
needs_denoising() const58 absl::optional<bool> AndroidVideoTrackSource::needs_denoising() const {
59   return false;
60 }
61 
SetState(JNIEnv * env,jboolean j_is_live)62 void AndroidVideoTrackSource::SetState(JNIEnv* env,
63                                        jboolean j_is_live) {
64   const SourceState state = j_is_live ? kLive : kEnded;
65   if (state_.exchange(state) != state) {
66     if (rtc::Thread::Current() == signaling_thread_) {
67       FireOnChanged();
68     } else {
69       // TODO(sakal): Is this even necessary, does FireOnChanged have to be
70       // called from signaling thread?
71       signaling_thread_->PostTask(
72           RTC_FROM_HERE,
73           rtc::Bind(
74               &AndroidVideoTrackSource::FireOnChanged,
75               static_cast<webrtc::Notifier<webrtc::VideoTrackSourceInterface>*>(
76                   this)));
77     }
78   }
79 }
80 
state() const81 AndroidVideoTrackSource::SourceState AndroidVideoTrackSource::state() const {
82   return state_.load();
83 }
84 
remote() const85 bool AndroidVideoTrackSource::remote() const {
86   return false;
87 }
88 
SetIsScreencast(JNIEnv * env,jboolean j_is_screencast)89 void AndroidVideoTrackSource::SetIsScreencast(JNIEnv* env,
90                                               jboolean j_is_screencast) {
91   is_screencast_.store(j_is_screencast);
92 }
93 
AdaptFrame(JNIEnv * env,jint j_width,jint j_height,jint j_rotation,jlong j_timestamp_ns)94 ScopedJavaLocalRef<jobject> AndroidVideoTrackSource::AdaptFrame(
95     JNIEnv* env,
96     jint j_width,
97     jint j_height,
98     jint j_rotation,
99     jlong j_timestamp_ns) {
100   const VideoRotation rotation = jintToVideoRotation(j_rotation);
101 
102   const int64_t camera_time_us = j_timestamp_ns / rtc::kNumNanosecsPerMicrosec;
103   const int64_t aligned_timestamp_ns =
104       align_timestamps_ ? rtc::kNumNanosecsPerMicrosec *
105                               timestamp_aligner_.TranslateTimestamp(
106                                   camera_time_us, rtc::TimeMicros())
107                         : j_timestamp_ns;
108 
109   int adapted_width = 0;
110   int adapted_height = 0;
111   int crop_width = 0;
112   int crop_height = 0;
113   int crop_x = 0;
114   int crop_y = 0;
115   bool drop;
116 
117   // TODO(magjed): Move this logic to users of NativeAndroidVideoTrackSource
118   // instead, in order to keep this native wrapping layer as thin as possible.
119   if (rotation % 180 == 0) {
120     drop = !rtc::AdaptedVideoTrackSource::AdaptFrame(
121         j_width, j_height, camera_time_us, &adapted_width, &adapted_height,
122         &crop_width, &crop_height, &crop_x, &crop_y);
123   } else {
124     // Swap all width/height and x/y.
125     drop = !rtc::AdaptedVideoTrackSource::AdaptFrame(
126         j_height, j_width, camera_time_us, &adapted_height, &adapted_width,
127         &crop_height, &crop_width, &crop_y, &crop_x);
128   }
129 
130   return Java_NativeAndroidVideoTrackSource_createFrameAdaptationParameters(
131       env, crop_x, crop_y, crop_width, crop_height, adapted_width,
132       adapted_height, aligned_timestamp_ns, drop);
133 }
134 
OnFrameCaptured(JNIEnv * env,jint j_rotation,jlong j_timestamp_ns,const JavaRef<jobject> & j_video_frame_buffer)135 void AndroidVideoTrackSource::OnFrameCaptured(
136     JNIEnv* env,
137     jint j_rotation,
138     jlong j_timestamp_ns,
139     const JavaRef<jobject>& j_video_frame_buffer) {
140   rtc::scoped_refptr<VideoFrameBuffer> buffer =
141       AndroidVideoBuffer::Create(env, j_video_frame_buffer);
142   const VideoRotation rotation = jintToVideoRotation(j_rotation);
143 
144   // AdaptedVideoTrackSource handles applying rotation for I420 frames.
145   if (apply_rotation() && rotation != kVideoRotation_0)
146     buffer = buffer->ToI420();
147 
148   OnFrame(VideoFrame::Builder()
149               .set_video_frame_buffer(buffer)
150               .set_rotation(rotation)
151               .set_timestamp_us(j_timestamp_ns / rtc::kNumNanosecsPerMicrosec)
152               .build());
153 }
154 
AdaptOutputFormat(JNIEnv * env,jint j_landscape_width,jint j_landscape_height,const JavaRef<jobject> & j_max_landscape_pixel_count,jint j_portrait_width,jint j_portrait_height,const JavaRef<jobject> & j_max_portrait_pixel_count,const JavaRef<jobject> & j_max_fps)155 void AndroidVideoTrackSource::AdaptOutputFormat(
156     JNIEnv* env,
157     jint j_landscape_width,
158     jint j_landscape_height,
159     const JavaRef<jobject>& j_max_landscape_pixel_count,
160     jint j_portrait_width,
161     jint j_portrait_height,
162     const JavaRef<jobject>& j_max_portrait_pixel_count,
163     const JavaRef<jobject>& j_max_fps) {
164   video_adapter()->OnOutputFormatRequest(
165       OptionalAspectRatio(j_landscape_width, j_landscape_height),
166       JavaToNativeOptionalInt(env, j_max_landscape_pixel_count),
167       OptionalAspectRatio(j_portrait_width, j_portrait_height),
168       JavaToNativeOptionalInt(env, j_max_portrait_pixel_count),
169       JavaToNativeOptionalInt(env, j_max_fps));
170 }
171 
172 }  // namespace jni
173 }  // namespace webrtc
174