blob: 9242e5faf9baf13bb46fbf164288a61ffe06a0e5 [file] [log] [blame]
Sami Kalliomaki16032122016-07-20 16:13:08 +02001/*
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 "webrtc/api/androidvideotracksource.h"
12
13#include <utility>
14
15namespace webrtc {
16
17AndroidVideoTrackSource::AndroidVideoTrackSource(rtc::Thread* signaling_thread,
18 JNIEnv* jni,
arsanyb75f2542016-08-31 18:50:52 -070019 jobject j_egl_context,
20 bool is_screencast)
Sami Kalliomaki16032122016-07-20 16:13:08 +020021 : signaling_thread_(signaling_thread),
22 surface_texture_helper_(webrtc_jni::SurfaceTextureHelper::create(
23 jni,
24 "Camera SurfaceTextureHelper",
arsanyb75f2542016-08-31 18:50:52 -070025 j_egl_context)),
26 is_screencast_(is_screencast) {
Sami Kalliomaki16032122016-07-20 16:13:08 +020027 LOG(LS_INFO) << "AndroidVideoTrackSource ctor";
Sami Kalliomaki16032122016-07-20 16:13:08 +020028 camera_thread_checker_.DetachFromThread();
29}
30
Sami Kalliomaki16032122016-07-20 16:13:08 +020031void AndroidVideoTrackSource::SetState(SourceState state) {
32 if (rtc::Thread::Current() != signaling_thread_) {
33 invoker_.AsyncInvoke<void>(
34 RTC_FROM_HERE, signaling_thread_,
35 rtc::Bind(&AndroidVideoTrackSource::SetState, this, state));
36 return;
37 }
38
39 if (state_ != state) {
40 state_ = state;
41 FireOnChanged();
42 }
43}
44
Sami Kalliomaki16032122016-07-20 16:13:08 +020045void AndroidVideoTrackSource::OnByteBufferFrameCaptured(const void* frame_data,
46 int length,
47 int width,
48 int height,
49 int rotation,
50 int64_t timestamp_ns) {
51 RTC_DCHECK(camera_thread_checker_.CalledOnValidThread());
52 RTC_DCHECK(rotation == 0 || rotation == 90 || rotation == 180 ||
53 rotation == 270);
54
nisse6f5a6c32016-09-22 01:25:59 -070055 int64_t camera_time_us = timestamp_ns / rtc::kNumNanosecsPerMicrosec;
56 int64_t translated_camera_time_us =
57 timestamp_aligner_.TranslateTimestamp(camera_time_us, rtc::TimeMicros());
58
Sami Kalliomaki16032122016-07-20 16:13:08 +020059 int adapted_width;
60 int adapted_height;
61 int crop_width;
62 int crop_height;
63 int crop_x;
64 int crop_y;
Sami Kalliomaki16032122016-07-20 16:13:08 +020065
nisse6f5a6c32016-09-22 01:25:59 -070066 if (!AdaptFrame(width, height, camera_time_us,
Sami Kalliomaki16032122016-07-20 16:13:08 +020067 &adapted_width, &adapted_height, &crop_width, &crop_height,
nisse6f5a6c32016-09-22 01:25:59 -070068 &crop_x, &crop_y)) {
Sami Kalliomaki16032122016-07-20 16:13:08 +020069 return;
70 }
71
Sami Kalliomaki16032122016-07-20 16:13:08 +020072 const uint8_t* y_plane = static_cast<const uint8_t*>(frame_data);
73 const uint8_t* uv_plane = y_plane + width * height;
magjed1a7ef1f2016-09-17 02:39:03 -070074 const int uv_width = (width + 1) / 2;
Sami Kalliomaki16032122016-07-20 16:13:08 +020075
76 RTC_CHECK_GE(length, width * height + 2 * uv_width * ((height + 1) / 2));
77
78 // Can only crop at even pixels.
79 crop_x &= ~1;
80 crop_y &= ~1;
magjed1a7ef1f2016-09-17 02:39:03 -070081 // Crop just by modifying pointers.
82 y_plane += width * crop_y + crop_x;
83 uv_plane += uv_width * crop_y + crop_x;
Sami Kalliomaki16032122016-07-20 16:13:08 +020084
magjed1a7ef1f2016-09-17 02:39:03 -070085 rtc::scoped_refptr<webrtc::I420Buffer> buffer =
86 buffer_pool_.CreateBuffer(adapted_width, adapted_height);
87
88 nv12toi420_scaler_.NV12ToI420Scale(
89 y_plane, width,
90 uv_plane, uv_width * 2,
91 crop_width, crop_height,
92 buffer->MutableDataY(), buffer->StrideY(),
jackychened0b0db2016-09-09 16:15:11 -070093 // Swap U and V, since we have NV21, not NV12.
magjed1a7ef1f2016-09-17 02:39:03 -070094 buffer->MutableDataV(), buffer->StrideV(),
95 buffer->MutableDataU(), buffer->StrideU(),
96 buffer->width(), buffer->height());
Sami Kalliomaki16032122016-07-20 16:13:08 +020097
Sami Kalliomaki16032122016-07-20 16:13:08 +020098 OnFrame(cricket::WebRtcVideoFrame(
nisse6f5a6c32016-09-22 01:25:59 -070099 buffer, static_cast<webrtc::VideoRotation>(rotation),
nisse09347852016-10-19 00:30:30 -0700100 translated_camera_time_us));
Sami Kalliomaki16032122016-07-20 16:13:08 +0200101}
102
103void AndroidVideoTrackSource::OnTextureFrameCaptured(
104 int width,
105 int height,
106 int rotation,
107 int64_t timestamp_ns,
108 const webrtc_jni::NativeHandleImpl& handle) {
109 RTC_DCHECK(camera_thread_checker_.CalledOnValidThread());
110 RTC_DCHECK(rotation == 0 || rotation == 90 || rotation == 180 ||
111 rotation == 270);
112
nisse6f5a6c32016-09-22 01:25:59 -0700113 int64_t camera_time_us = timestamp_ns / rtc::kNumNanosecsPerMicrosec;
114 int64_t translated_camera_time_us =
115 timestamp_aligner_.TranslateTimestamp(camera_time_us, rtc::TimeMicros());
116
Sami Kalliomaki16032122016-07-20 16:13:08 +0200117 int adapted_width;
118 int adapted_height;
119 int crop_width;
120 int crop_height;
121 int crop_x;
122 int crop_y;
Sami Kalliomaki16032122016-07-20 16:13:08 +0200123
nisse6f5a6c32016-09-22 01:25:59 -0700124 if (!AdaptFrame(width, height, camera_time_us,
Sami Kalliomaki16032122016-07-20 16:13:08 +0200125 &adapted_width, &adapted_height, &crop_width, &crop_height,
nisse6f5a6c32016-09-22 01:25:59 -0700126 &crop_x, &crop_y)) {
Sami Kalliomaki16032122016-07-20 16:13:08 +0200127 surface_texture_helper_->ReturnTextureFrame();
128 return;
129 }
130
131 webrtc_jni::Matrix matrix = handle.sampling_matrix;
132
133 matrix.Crop(crop_width / static_cast<float>(width),
134 crop_height / static_cast<float>(height),
135 crop_x / static_cast<float>(width),
136 crop_y / static_cast<float>(height));
137
nisse6f5a6c32016-09-22 01:25:59 -0700138 // Make a local copy, since value of apply_rotation() may change
139 // under our feet.
140 bool do_rotate = apply_rotation();
141
142 if (do_rotate) {
Sami Kalliomaki16032122016-07-20 16:13:08 +0200143 if (rotation == webrtc::kVideoRotation_90 ||
144 rotation == webrtc::kVideoRotation_270) {
145 std::swap(adapted_width, adapted_height);
146 }
147 matrix.Rotate(static_cast<webrtc::VideoRotation>(rotation));
148 }
149
150 OnFrame(cricket::WebRtcVideoFrame(
151 surface_texture_helper_->CreateTextureFrame(
152 adapted_width, adapted_height,
153 webrtc_jni::NativeHandleImpl(handle.oes_texture_id, matrix)),
nisse6f5a6c32016-09-22 01:25:59 -0700154 do_rotate ? webrtc::kVideoRotation_0
155 : static_cast<webrtc::VideoRotation>(rotation),
nisse09347852016-10-19 00:30:30 -0700156 translated_camera_time_us));
Sami Kalliomaki16032122016-07-20 16:13:08 +0200157}
158
159void AndroidVideoTrackSource::OnOutputFormatRequest(int width,
160 int height,
161 int fps) {
Sami Kalliomaki16032122016-07-20 16:13:08 +0200162 cricket::VideoFormat format(width, height,
163 cricket::VideoFormat::FpsToInterval(fps), 0);
nisse6f5a6c32016-09-22 01:25:59 -0700164 video_adapter()->OnOutputFormatRequest(format);
Sami Kalliomaki16032122016-07-20 16:13:08 +0200165}
166
167} // namespace webrtc