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