blob: bddd4171aafef5e836535345062bfbad0512ba98 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
jlmiller@webrtc.org5f93d0a2015-01-20 21:36:13 +00003 * Copyright 2013 Google Inc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28// Hints for future visitors:
29// This entire file is an implementation detail of the org.webrtc Java package,
30// the most interesting bits of which are org.webrtc.PeerConnection{,Factory}.
31// The layout of this file is roughly:
32// - various helper C++ functions & classes that wrap Java counterparts and
33// expose a C++ interface that can be passed to the C++ PeerConnection APIs
34// - implementations of methods declared "static" in the Java package (named
35// things like Java_org_webrtc_OMG_Can_This_Name_Be_Any_Longer, prescribed by
36// the JNI spec).
37//
38// Lifecycle notes: objects are owned where they will be called; in other words
39// FooObservers are owned by C++-land, and user-callable objects (e.g.
40// PeerConnection and VideoTrack) are owned by Java-land.
41// When this file allocates C++ RefCountInterfaces it AddRef()s an artificial
42// ref simulating the jlong held in Java-land, and then Release()s the ref in
43// the respective free call. Sometimes this AddRef is implicit in the
44// construction of a scoped_refptr<> which is then .release()d.
45// Any persistent (non-local) references from C++ to Java must be global or weak
46// (in which case they must be checked before use)!
47//
48// Exception notes: pretty much all JNI calls can throw Java exceptions, so each
49// call through a JNIEnv* pointer needs to be followed by an ExceptionCheck()
50// call. In this file this is done in CHECK_EXCEPTION, making for much easier
51// debugging in case of failure (the alternative is to wait for control to
52// return to the Java frame that called code in this file, at which point it's
53// impossible to tell which JNI call broke).
54
55#include <jni.h>
56#undef JNIEXPORT
57#define JNIEXPORT __attribute__((visibility("default")))
58
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000059#include <limits>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000061#include "talk/app/webrtc/java/jni/classreferenceholder.h"
62#include "talk/app/webrtc/java/jni/jni_helpers.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000063#include "talk/app/webrtc/mediaconstraintsinterface.h"
64#include "talk/app/webrtc/peerconnectioninterface.h"
65#include "talk/app/webrtc/videosourceinterface.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000066#include "talk/media/base/videocapturer.h"
67#include "talk/media/base/videorenderer.h"
68#include "talk/media/devices/videorendererfactory.h"
69#include "talk/media/webrtc/webrtcvideocapturer.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000070#include "talk/media/webrtc/webrtcvideodecoderfactory.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000071#include "talk/media/webrtc/webrtcvideoencoderfactory.h"
fischman@webrtc.org3d496fb2013-07-30 17:14:35 +000072#include "third_party/icu/source/common/unicode/unistr.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000073#include "third_party/libyuv/include/libyuv/convert.h"
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +000074#include "third_party/libyuv/include/libyuv/convert_from.h"
75#include "third_party/libyuv/include/libyuv/video_common.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000076#include "webrtc/base/bind.h"
andresp@webrtc.org4d19e052014-09-09 11:45:44 +000077#include "webrtc/base/checks.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000078#include "webrtc/base/logging.h"
79#include "webrtc/base/messagequeue.h"
80#include "webrtc/base/ssladapter.h"
glaznev@webrtc.org44ae4c82015-02-09 23:25:58 +000081#include "webrtc/base/stringutils.h"
glaznev@webrtc.org99678452014-09-15 17:52:42 +000082#include "webrtc/common_video/interface/texture_video_frame.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000083#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
glaznev@webrtc.org44ae4c82015-02-09 23:25:58 +000084#include "webrtc/system_wrappers/interface/field_trial_default.h"
henrike@webrtc.org9de257d2013-07-17 14:42:53 +000085#include "webrtc/system_wrappers/interface/trace.h"
86#include "webrtc/video_engine/include/vie_base.h"
87#include "webrtc/voice_engine/include/voe_base.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088
glaznev@webrtc.org99678452014-09-15 17:52:42 +000089#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
90#include <android/log.h>
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000091#include "talk/app/webrtc/androidvideocapturer.h"
perkj@webrtc.org96e4db92015-02-13 12:46:51 +000092#include "talk/app/webrtc/java/jni/androidvideocapturer_jni.h"
andresp@webrtc.org85ef7702014-09-17 11:44:51 +000093#include "webrtc/modules/video_render/video_render_internal.h"
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000094#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
glaznev@webrtc.org99678452014-09-15 17:52:42 +000095#include "webrtc/system_wrappers/interface/tick_util.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000096using webrtc::CodecSpecificInfo;
97using webrtc::DecodedImageCallback;
98using webrtc::EncodedImage;
99using webrtc::I420VideoFrame;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +0000100using webrtc::LogcatTraceContext;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000101using webrtc::RTPFragmentationHeader;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000102using webrtc::TextureVideoFrame;
103using webrtc::TickTime;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000104using webrtc::VideoCodec;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +0000105#endif
106
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000107using rtc::Bind;
108using rtc::Thread;
109using rtc::ThreadManager;
110using rtc::scoped_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111using webrtc::AudioSourceInterface;
112using webrtc::AudioTrackInterface;
113using webrtc::AudioTrackVector;
114using webrtc::CreateSessionDescriptionObserver;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000115using webrtc::DataBuffer;
116using webrtc::DataChannelInit;
117using webrtc::DataChannelInterface;
118using webrtc::DataChannelObserver;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000119using webrtc::IceCandidateInterface;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000120using webrtc::NativeHandle;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121using webrtc::MediaConstraintsInterface;
122using webrtc::MediaSourceInterface;
123using webrtc::MediaStreamInterface;
124using webrtc::MediaStreamTrackInterface;
125using webrtc::PeerConnectionFactoryInterface;
126using webrtc::PeerConnectionInterface;
127using webrtc::PeerConnectionObserver;
128using webrtc::SessionDescriptionInterface;
129using webrtc::SetSessionDescriptionObserver;
130using webrtc::StatsObserver;
131using webrtc::StatsReport;
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +0000132using webrtc::StatsReports;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000133using webrtc::VideoRendererInterface;
134using webrtc::VideoSourceInterface;
135using webrtc::VideoTrackInterface;
136using webrtc::VideoTrackVector;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000137using webrtc::kVideoCodecVP8;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000138
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000139namespace webrtc_jni {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140
glaznev@webrtc.org44ae4c82015-02-09 23:25:58 +0000141// Field trials initialization string
142static char *field_trials_init_string = NULL;
143
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000144#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
145// Set in PeerConnectionFactory_initializeAndroidGlobals().
146static bool factory_static_initialized = false;
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +0000147static bool vp8_hw_acceleration_enabled = true;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000148#endif
149
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000150extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000151 jint ret = InitGlobalJniVariables(jvm);
152 if (ret < 0)
153 return -1;
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000154
155 CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()";
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000156 LoadGlobalClassReferenceHolder();
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000157
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000158 return ret;
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000159}
160
161extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000162 FreeGlobalClassReferenceHolder();
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000163 CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()";
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000164}
165
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000166// Return the (singleton) Java Enum object corresponding to |index|;
167// |state_class_fragment| is something like "MediaSource$State".
168jobject JavaEnumFromIndex(
169 JNIEnv* jni, const std::string& state_class_fragment, int index) {
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000170 const std::string state_class = "org/webrtc/" + state_class_fragment;
171 return JavaEnumFromIndex(jni, FindClass(jni, state_class.c_str()),
172 state_class, index);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000173}
174
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000175static DataChannelInit JavaDataChannelInitToNative(
176 JNIEnv* jni, jobject j_init) {
177 DataChannelInit init;
178
179 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
180 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
181 jfieldID max_retransmit_time_id =
182 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
183 jfieldID max_retransmits_id =
184 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
185 jfieldID protocol_id =
186 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
187 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
188 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
189
190 init.ordered = GetBooleanField(jni, j_init, ordered_id);
191 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
192 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
193 init.protocol = JavaToStdString(
194 jni, GetStringField(jni, j_init, protocol_id));
195 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
196 init.id = GetIntField(jni, j_init, id_id);
197
198 return init;
199}
200
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000201class ConstraintsWrapper;
202
203// Adapter between the C++ PeerConnectionObserver interface and the Java
204// PeerConnection.Observer interface. Wraps an instance of the Java interface
205// and dispatches C++ callbacks to Java.
206class PCOJava : public PeerConnectionObserver {
207 public:
208 PCOJava(JNIEnv* jni, jobject j_observer)
209 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000210 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
211 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
212 j_media_stream_ctor_(GetMethodID(
213 jni, *j_media_stream_class_, "<init>", "(J)V")),
214 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000215 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000216 jni, *j_audio_track_class_, "<init>", "(J)V")),
217 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
218 j_video_track_ctor_(GetMethodID(
219 jni, *j_video_track_class_, "<init>", "(J)V")),
220 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
221 j_data_channel_ctor_(GetMethodID(
222 jni, *j_data_channel_class_, "<init>", "(J)V")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000223 }
224
225 virtual ~PCOJava() {}
226
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000227 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000228 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000229 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000230 CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000231 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
232 jmethodID ctor = GetMethodID(jni(), candidate_class,
233 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000234 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
235 jstring j_sdp = JavaStringFromStdString(jni(), sdp);
236 jobject j_candidate = jni()->NewObject(
237 candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000238 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000239 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000240 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000241 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000242 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000243 }
244
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000245 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000246 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000247 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000248 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000249 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000250 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000251 jobject new_state_enum =
252 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
253 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000254 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000255 }
256
257 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000258 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000259 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000260 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000261 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000262 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000263 jobject new_state_enum = JavaEnumFromIndex(
264 jni(), "PeerConnection$IceConnectionState", new_state);
265 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000266 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000267 }
268
269 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000270 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000271 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000272 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000273 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000274 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000275 jobject new_state_enum = JavaEnumFromIndex(
276 jni(), "PeerConnection$IceGatheringState", new_state);
277 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000278 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000279 }
280
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000281 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000282 ScopedLocalRefFrame local_ref_frame(jni());
283 jobject j_stream = jni()->NewObject(
284 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000285 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000286
287 AudioTrackVector audio_tracks = stream->GetAudioTracks();
288 for (size_t i = 0; i < audio_tracks.size(); ++i) {
289 AudioTrackInterface* track = audio_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000290 jstring id = JavaStringFromStdString(jni(), track->id());
291 jobject j_track = jni()->NewObject(
292 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000293 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000294 jfieldID audio_tracks_id = GetFieldID(jni(),
295 *j_media_stream_class_,
296 "audioTracks",
297 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000298 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000299 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000300 GetObjectClass(jni(), audio_tracks),
301 "add",
302 "(Ljava/lang/Object;)Z");
303 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000304 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
305 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000306 }
307
308 VideoTrackVector video_tracks = stream->GetVideoTracks();
309 for (size_t i = 0; i < video_tracks.size(); ++i) {
310 VideoTrackInterface* track = video_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000311 jstring id = JavaStringFromStdString(jni(), track->id());
312 jobject j_track = jni()->NewObject(
313 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000314 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000315 jfieldID video_tracks_id = GetFieldID(jni(),
316 *j_media_stream_class_,
317 "videoTracks",
318 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000319 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000320 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000321 GetObjectClass(jni(), video_tracks),
322 "add",
323 "(Ljava/lang/Object;)Z");
324 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000325 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
326 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000327 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000328 streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000329 CHECK_EXCEPTION(jni()) << "error during NewWeakGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000330
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000331 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
332 "(Lorg/webrtc/MediaStream;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000333 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000334 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000335 }
336
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000337 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000338 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000339 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000340 CHECK(it != streams_.end()) << "unexpected stream: " << std::hex << stream;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000341
342 WeakRef s(jni(), it->second);
343 streams_.erase(it);
344 if (!s.obj())
345 return;
346
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000347 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
348 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000349 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000350 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000351 }
352
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000353 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000354 ScopedLocalRefFrame local_ref_frame(jni());
355 jobject j_channel = jni()->NewObject(
356 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000357 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000358
359 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
360 "(Lorg/webrtc/DataChannel;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000361 jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000362
363 // Channel is now owned by Java object, and will be freed from
364 // DataChannel.dispose(). Important that this be done _after_ the
365 // CallVoidMethod above as Java code might call back into native code and be
366 // surprised to see a refcount of 2.
367 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000368 CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000369
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000370 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000371 }
372
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000373 virtual void OnRenegotiationNeeded() OVERRIDE {
374 ScopedLocalRefFrame local_ref_frame(jni());
375 jmethodID m =
376 GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
377 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000378 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000379 }
380
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000381 void SetConstraints(ConstraintsWrapper* constraints) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000382 CHECK(!constraints_.get()) << "constraints already set!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000383 constraints_.reset(constraints);
384 }
385
386 const ConstraintsWrapper* constraints() { return constraints_.get(); }
387
388 private:
389 JNIEnv* jni() {
390 return AttachCurrentThreadIfNeeded();
391 }
392
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000393 const ScopedGlobalRef<jobject> j_observer_global_;
394 const ScopedGlobalRef<jclass> j_observer_class_;
395 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000396 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000397 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000398 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000399 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000400 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000401 const ScopedGlobalRef<jclass> j_data_channel_class_;
402 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000403 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
404 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000405 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000406};
407
408// Wrapper for a Java MediaConstraints object. Copies all needed data so when
409// the constructor returns the Java object is no longer needed.
410class ConstraintsWrapper : public MediaConstraintsInterface {
411 public:
412 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
413 PopulateConstraintsFromJavaPairList(
414 jni, j_constraints, "mandatory", &mandatory_);
415 PopulateConstraintsFromJavaPairList(
416 jni, j_constraints, "optional", &optional_);
417 }
418
419 virtual ~ConstraintsWrapper() {}
420
421 // MediaConstraintsInterface.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000422 virtual const Constraints& GetMandatory() const OVERRIDE {
423 return mandatory_;
424 }
425
426 virtual const Constraints& GetOptional() const OVERRIDE {
427 return optional_;
428 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000429
430 private:
431 // Helper for translating a List<Pair<String, String>> to a Constraints.
432 static void PopulateConstraintsFromJavaPairList(
433 JNIEnv* jni, jobject j_constraints,
434 const char* field_name, Constraints* field) {
435 jfieldID j_id = GetFieldID(jni,
436 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
437 jobject j_list = GetObjectField(jni, j_constraints, j_id);
438 jmethodID j_iterator_id = GetMethodID(jni,
439 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
440 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000441 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000442 jmethodID j_has_next = GetMethodID(jni,
443 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
444 jmethodID j_next = GetMethodID(jni,
445 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
446 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000447 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000448 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000449 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450 jmethodID get_key = GetMethodID(jni,
451 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
452 jstring j_key = reinterpret_cast<jstring>(
453 jni->CallObjectMethod(entry, get_key));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000454 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000455 jmethodID get_value = GetMethodID(jni,
456 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
457 jstring j_value = reinterpret_cast<jstring>(
458 jni->CallObjectMethod(entry, get_value));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000459 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000460 field->push_back(Constraint(JavaToStdString(jni, j_key),
461 JavaToStdString(jni, j_value)));
462 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000463 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464 }
465
466 Constraints mandatory_;
467 Constraints optional_;
468};
469
470static jobject JavaSdpFromNativeSdp(
471 JNIEnv* jni, const SessionDescriptionInterface* desc) {
472 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000473 CHECK(desc->ToString(&sdp)) << "got so far: " << sdp;
fischman@webrtc.org41776152014-01-09 00:31:17 +0000474 jstring j_description = JavaStringFromStdString(jni, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000475
476 jclass j_type_class = FindClass(
477 jni, "org/webrtc/SessionDescription$Type");
478 jmethodID j_type_from_canonical = GetStaticMethodID(
479 jni, j_type_class, "fromCanonicalForm",
480 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000481 jstring j_type_string = JavaStringFromStdString(jni, desc->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000482 jobject j_type = jni->CallStaticObjectMethod(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000483 j_type_class, j_type_from_canonical, j_type_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000484 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000485
486 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
487 jmethodID j_sdp_ctor = GetMethodID(
488 jni, j_sdp_class, "<init>",
489 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
490 jobject j_sdp = jni->NewObject(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000491 j_sdp_class, j_sdp_ctor, j_type, j_description);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000492 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000493 return j_sdp;
494}
495
496template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
497class SdpObserverWrapper : public T {
498 public:
499 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
500 ConstraintsWrapper* constraints)
501 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000502 j_observer_global_(jni, j_observer),
503 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000504 }
505
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000506 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000507
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000508 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509 virtual void OnSuccess() {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000510 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000511 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
512 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000513 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000514 }
515
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000516 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000517 virtual void OnSuccess(SessionDescriptionInterface* desc) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000518 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000519 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000520 jni(), *j_observer_class_, "onCreateSuccess",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521 "(Lorg/webrtc/SessionDescription;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000522 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
523 jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000524 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000525 }
526
527 protected:
528 // Common implementation for failure of Set & Create types, distinguished by
529 // |op| being "Set" or "Create".
530 void OnFailure(const std::string& op, const std::string& error) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000531 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
532 "(Ljava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000533 jstring j_error_string = JavaStringFromStdString(jni(), error);
534 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000535 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000536 }
537
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000538 JNIEnv* jni() {
539 return AttachCurrentThreadIfNeeded();
540 }
541
fischman@webrtc.org41776152014-01-09 00:31:17 +0000542 private:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000543 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000544 const ScopedGlobalRef<jobject> j_observer_global_;
545 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000546};
547
548class CreateSdpObserverWrapper
549 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
550 public:
551 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
552 ConstraintsWrapper* constraints)
553 : SdpObserverWrapper(jni, j_observer, constraints) {}
554
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000555 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000556 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000557 SdpObserverWrapper::OnFailure(std::string("Create"), error);
558 }
559};
560
561class SetSdpObserverWrapper
562 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
563 public:
564 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
565 ConstraintsWrapper* constraints)
566 : SdpObserverWrapper(jni, j_observer, constraints) {}
567
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000568 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000569 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000570 SdpObserverWrapper::OnFailure(std::string("Set"), error);
571 }
572};
573
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000574// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
575// and dispatching the callback from C++ back to Java.
576class DataChannelObserverWrapper : public DataChannelObserver {
577 public:
578 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
579 : j_observer_global_(jni, j_observer),
580 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +0000581 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000582 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
583 "onStateChange", "()V")),
584 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
585 "(Lorg/webrtc/DataChannel$Buffer;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000586 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
587 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
588 }
589
590 virtual ~DataChannelObserverWrapper() {}
591
592 virtual void OnStateChange() OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000593 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000594 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000595 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000596 }
597
598 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000599 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000600 jobject byte_buffer =
601 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
602 buffer.data.length());
603 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
604 byte_buffer, buffer.binary);
605 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000606 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000607 }
608
609 private:
610 JNIEnv* jni() {
611 return AttachCurrentThreadIfNeeded();
612 }
613
614 const ScopedGlobalRef<jobject> j_observer_global_;
615 const ScopedGlobalRef<jclass> j_observer_class_;
616 const ScopedGlobalRef<jclass> j_buffer_class_;
617 const jmethodID j_on_state_change_mid_;
618 const jmethodID j_on_message_mid_;
619 const jmethodID j_buffer_ctor_;
620};
621
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000622// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
623// dispatching the callback from C++ back to Java.
624class StatsObserverWrapper : public StatsObserver {
625 public:
626 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000627 : j_observer_global_(jni, j_observer),
628 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
629 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000630 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000631 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632 "(Ljava/lang/String;Ljava/lang/String;D"
633 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000634 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000635 jni, "org/webrtc/StatsReport$Value")),
636 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000637 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000638 "(Ljava/lang/String;Ljava/lang/String;)V")) {
639 }
640
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000641 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000642
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +0000643 virtual void OnComplete(const StatsReports& reports) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000644 ScopedLocalRefFrame local_ref_frame(jni());
645 jobjectArray j_reports = ReportsToJava(jni(), reports);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000646 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
647 "([Lorg/webrtc/StatsReport;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000648 jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000649 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000650 }
651
652 private:
653 jobjectArray ReportsToJava(
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +0000654 JNIEnv* jni, const StatsReports& reports) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000655 jobjectArray reports_array = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000656 reports.size(), *j_stats_report_class_, NULL);
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +0000657 int i = 0;
658 for (const auto* report : reports) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000659 ScopedLocalRefFrame local_ref_frame(jni);
tommi@webrtc.org8e327c42015-01-19 20:41:26 +0000660 jstring j_id = JavaStringFromStdString(jni, report->id().ToString());
661 jstring j_type = JavaStringFromStdString(jni, report->TypeToString());
662 jobjectArray j_values = ValuesToJava(jni, report->values());
fischman@webrtc.org41776152014-01-09 00:31:17 +0000663 jobject j_report = jni->NewObject(*j_stats_report_class_,
664 j_stats_report_ctor_,
665 j_id,
666 j_type,
tommi@webrtc.org8e327c42015-01-19 20:41:26 +0000667 report->timestamp(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000668 j_values);
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +0000669 jni->SetObjectArrayElement(reports_array, i++, j_report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670 }
671 return reports_array;
672 }
673
674 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
675 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000676 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000677 for (int i = 0; i < values.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000678 ScopedLocalRefFrame local_ref_frame(jni);
tommi@webrtc.org8e327c42015-01-19 20:41:26 +0000679 const auto& value = values[i];
tommi@webrtc.orgc57310b2014-12-12 17:41:28 +0000680 // Should we use the '.name' enum value here instead of converting the
681 // name to a string?
tommi@webrtc.org8e327c42015-01-19 20:41:26 +0000682 jstring j_name = JavaStringFromStdString(jni, value->display_name());
683 jstring j_value = JavaStringFromStdString(jni, value->value);
fischman@webrtc.org41776152014-01-09 00:31:17 +0000684 jobject j_element_value =
685 jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
686 jni->SetObjectArrayElement(j_values, i, j_element_value);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000687 }
688 return j_values;
689 }
690
691 JNIEnv* jni() {
692 return AttachCurrentThreadIfNeeded();
693 }
694
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000695 const ScopedGlobalRef<jobject> j_observer_global_;
696 const ScopedGlobalRef<jclass> j_observer_class_;
697 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000698 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000699 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000700 const jmethodID j_value_ctor_;
701};
702
703// Adapter presenting a cricket::VideoRenderer as a
704// webrtc::VideoRendererInterface.
705class VideoRendererWrapper : public VideoRendererInterface {
706 public:
707 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
708 if (renderer)
709 return new VideoRendererWrapper(renderer);
710 return NULL;
711 }
712
713 virtual ~VideoRendererWrapper() {}
714
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000715 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000716 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000717 const bool kNotReserved = false; // What does this param mean??
718 renderer_->SetSize(width, height, kNotReserved);
719 }
720
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000721 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000722 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000723 renderer_->RenderFrame(frame);
724 }
725
726 private:
727 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
728 : renderer_(renderer) {}
729
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000730 scoped_ptr<cricket::VideoRenderer> renderer_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000731};
732
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000733// Wrapper for texture object in TextureVideoFrame.
734class NativeHandleImpl : public NativeHandle {
735 public:
736 NativeHandleImpl() :
737 ref_count_(0), texture_object_(NULL), texture_id_(-1) {}
738 virtual ~NativeHandleImpl() {}
739 virtual int32_t AddRef() {
740 return ++ref_count_;
741 }
742 virtual int32_t Release() {
743 return --ref_count_;
744 }
745 virtual void* GetHandle() {
746 return texture_object_;
747 }
748 int GetTextureId() {
749 return texture_id_;
750 }
751 void SetTextureObject(void *texture_object, int texture_id) {
752 texture_object_ = reinterpret_cast<jobject>(texture_object);
753 texture_id_ = texture_id;
754 }
755 int32_t ref_count() {
756 return ref_count_;
757 }
758
759 private:
760 int32_t ref_count_;
761 jobject texture_object_;
762 int32_t texture_id_;
763};
764
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000765// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
766// instance.
767class JavaVideoRendererWrapper : public VideoRendererInterface {
768 public:
769 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000770 : j_callbacks_(jni, j_callbacks),
771 j_set_size_id_(GetMethodID(
772 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
773 j_render_frame_id_(GetMethodID(
774 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
775 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
776 j_frame_class_(jni,
777 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000778 j_i420_frame_ctor_id_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000779 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000780 j_texture_frame_ctor_id_(GetMethodID(
781 jni, *j_frame_class_, "<init>",
782 "(IILjava/lang/Object;I)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000783 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000784 CHECK_EXCEPTION(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000785 }
786
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000787 virtual ~JavaVideoRendererWrapper() {}
788
789 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000790 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000792 CHECK_EXCEPTION(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000793 }
794
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000795 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000796 ScopedLocalRefFrame local_ref_frame(jni());
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000797 if (frame->GetNativeHandle() != NULL) {
798 jobject j_frame = CricketToJavaTextureFrame(frame);
799 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
800 CHECK_EXCEPTION(jni());
801 } else {
802 jobject j_frame = CricketToJavaI420Frame(frame);
803 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
804 CHECK_EXCEPTION(jni());
805 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000806 }
807
808 private:
809 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000810 jobject CricketToJavaI420Frame(const cricket::VideoFrame* frame) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000811 jintArray strides = jni()->NewIntArray(3);
812 jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000813 strides_array[0] = frame->GetYPitch();
814 strides_array[1] = frame->GetUPitch();
815 strides_array[2] = frame->GetVPitch();
fischman@webrtc.org41776152014-01-09 00:31:17 +0000816 jni()->ReleaseIntArrayElements(strides, strides_array, 0);
817 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
818 jobject y_buffer = jni()->NewDirectByteBuffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000819 const_cast<uint8*>(frame->GetYPlane()),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000820 frame->GetYPitch() * frame->GetHeight());
821 jobject u_buffer = jni()->NewDirectByteBuffer(
822 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
823 jobject v_buffer = jni()->NewDirectByteBuffer(
824 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
825 jni()->SetObjectArrayElement(planes, 0, y_buffer);
826 jni()->SetObjectArrayElement(planes, 1, u_buffer);
827 jni()->SetObjectArrayElement(planes, 2, v_buffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000828 return jni()->NewObject(
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000829 *j_frame_class_, j_i420_frame_ctor_id_,
fischman@webrtc.org41776152014-01-09 00:31:17 +0000830 frame->GetWidth(), frame->GetHeight(), strides, planes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000831 }
832
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000833 // Return a VideoRenderer.I420Frame referring texture object in |frame|.
834 jobject CricketToJavaTextureFrame(const cricket::VideoFrame* frame) {
835 NativeHandleImpl* handle =
836 reinterpret_cast<NativeHandleImpl*>(frame->GetNativeHandle());
837 jobject texture_object = reinterpret_cast<jobject>(handle->GetHandle());
838 int texture_id = handle->GetTextureId();
839 return jni()->NewObject(
840 *j_frame_class_, j_texture_frame_ctor_id_,
841 frame->GetWidth(), frame->GetHeight(), texture_object, texture_id);
842 }
843
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000844 JNIEnv* jni() {
845 return AttachCurrentThreadIfNeeded();
846 }
847
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000848 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 jmethodID j_set_size_id_;
850 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000851 ScopedGlobalRef<jclass> j_frame_class_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000852 jmethodID j_i420_frame_ctor_id_;
853 jmethodID j_texture_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000854 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000855};
856
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000857#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000858// TODO(fischman): consider pulling MediaCodecVideoEncoder out of this file and
859// into its own .h/.cc pair, if/when the JNI helper stuff above is extracted
860// from this file.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000861
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000862// #define TRACK_BUFFER_TIMING
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000863#define TAG "MediaCodecVideo"
864#ifdef TRACK_BUFFER_TIMING
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +0000865#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
866#else
867#define ALOGV(...)
868#endif
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000869#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
870#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +0000871
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +0000872// Color formats supported by encoder - should mirror supportedColorList
873// from MediaCodecVideoEncoder.java
874enum COLOR_FORMATTYPE {
875 COLOR_FormatYUV420Planar = 0x13,
876 COLOR_FormatYUV420SemiPlanar = 0x15,
877 COLOR_QCOM_FormatYUV420SemiPlanar = 0x7FA30C00,
878 // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
879 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
880 // This format is presumably similar to COLOR_FormatYUV420SemiPlanar,
881 // but requires some (16, 32?) byte alignment.
882 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04
883};
884
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000885// Arbitrary interval to poll the codec for new outputs.
886enum { kMediaCodecPollMs = 10 };
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000887// Media codec maximum output buffer ready timeout.
888enum { kMediaCodecTimeoutMs = 500 };
889// Interval to print codec statistics (bitrate, fps, encoding/decoding time).
890enum { kMediaCodecStatisticsIntervalMs = 3000 };
891
892static int64_t GetCurrentTimeMs() {
893 return TickTime::Now().Ticks() / 1000000LL;
894}
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000895
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +0000896// Allow Invoke() calls from from current thread.
897static void AllowBlockingCalls() {
898 Thread* current_thread = Thread::Current();
899 if (current_thread != NULL)
900 current_thread->SetAllowBlockingCalls(true);
901}
902
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000903// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
904// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
905// HW-backed video encode. This C++ class is implemented as a very thin shim,
906// delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
907// MediaCodecVideoEncoder is created, operated, and destroyed on a single
908// thread, currently the libjingle Worker thread.
909class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000910 public rtc::MessageHandler {
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000911 public:
912 virtual ~MediaCodecVideoEncoder();
913 explicit MediaCodecVideoEncoder(JNIEnv* jni);
914
915 // webrtc::VideoEncoder implementation. Everything trampolines to
916 // |codec_thread_| for execution.
917 virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
918 int32_t /* number_of_cores */,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000919 size_t /* max_payload_size */) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000920 virtual int32_t Encode(
921 const webrtc::I420VideoFrame& input_image,
922 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
923 const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
924 virtual int32_t RegisterEncodeCompleteCallback(
925 webrtc::EncodedImageCallback* callback) OVERRIDE;
926 virtual int32_t Release() OVERRIDE;
927 virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000928 int64_t /* rtt */) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000929 virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
930
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000931 // rtc::MessageHandler implementation.
932 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000933
934 private:
935 // CHECK-fail if not running on |codec_thread_|.
936 void CheckOnCodecThread();
937
938 // Release() and InitEncode() in an attempt to restore the codec to an
939 // operable state. Necessary after all manner of OMX-layer errors.
940 void ResetCodec();
941
942 // Implementation of webrtc::VideoEncoder methods above, all running on the
943 // codec thread exclusively.
944 //
945 // If width==0 then this is assumed to be a re-initialization and the
946 // previously-current values are reused instead of the passed parameters
947 // (makes it easier to reason about thread-safety).
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +0000948 int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps);
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000949 int32_t EncodeOnCodecThread(
950 const webrtc::I420VideoFrame& input_image,
951 const std::vector<webrtc::VideoFrameType>* frame_types);
952 int32_t RegisterEncodeCompleteCallbackOnCodecThread(
953 webrtc::EncodedImageCallback* callback);
954 int32_t ReleaseOnCodecThread();
955 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
956
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000957 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
958 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
959 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
960 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
961 jlong GetOutputBufferInfoPresentationTimestampUs(
962 JNIEnv* jni,
963 jobject j_output_buffer_info);
964
965 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
966 // true on success.
967 bool DeliverPendingOutputs(JNIEnv* jni);
968
969 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
970 // |codec_thread_| synchronously.
971 webrtc::EncodedImageCallback* callback_;
972
973 // State that is constant for the lifetime of this object once the ctor
974 // returns.
975 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
976 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
977 ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
978 jmethodID j_init_encode_method_;
979 jmethodID j_dequeue_input_buffer_method_;
980 jmethodID j_encode_method_;
981 jmethodID j_release_method_;
982 jmethodID j_set_rates_method_;
983 jmethodID j_dequeue_output_buffer_method_;
984 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +0000985 jfieldID j_color_format_field_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000986 jfieldID j_info_index_field_;
987 jfieldID j_info_buffer_field_;
988 jfieldID j_info_is_key_frame_field_;
989 jfieldID j_info_presentation_timestamp_us_field_;
990
991 // State that is valid only between InitEncode() and the next Release().
992 // Touched only on codec_thread_ so no explicit synchronization necessary.
993 int width_; // Frame width in pixels.
994 int height_; // Frame height in pixels.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000995 bool inited_;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +0000996 uint16_t picture_id_;
perkj@webrtc.org96e4db92015-02-13 12:46:51 +0000997 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format.
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000998 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +0000999 int last_set_fps_; // Last-requested frame rate.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001000 int64_t current_timestamp_us_; // Current frame timestamps in us.
1001 int frames_received_; // Number of frames received by encoder.
1002 int frames_dropped_; // Number of frames dropped by encoder.
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001003 int frames_resolution_update_; // Number of frames with new codec resolution.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001004 int frames_in_queue_; // Number of frames in encoder queue.
1005 int64_t start_time_ms_; // Start time for statistics.
1006 int current_frames_; // Number of frames in the current statistics interval.
1007 int current_bytes_; // Encoded bytes in the current statistics interval.
1008 int current_encoding_time_ms_; // Overall encoding time in the current second
1009 int64_t last_input_timestamp_ms_; // Timestamp of last received yuv frame.
1010 int64_t last_output_timestamp_ms_; // Timestamp of last encoded frame.
1011 std::vector<int32_t> timestamps_; // Video frames timestamp queue.
1012 std::vector<int64_t> render_times_ms_; // Video frames render time queue.
1013 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
1014 // encoder input.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001015 // Frame size in bytes fed to MediaCodec.
1016 int yuv_size_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001017 // True only when between a callback_->Encoded() call return a positive value
1018 // and the next Encode() call being ignored.
1019 bool drop_next_input_frame_;
1020 // Global references; must be deleted in Release().
1021 std::vector<jobject> input_buffers_;
1022};
1023
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001024MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001025 // Call Release() to ensure no more callbacks to us after we are deleted.
1026 Release();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001027}
1028
1029MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001030 : callback_(NULL),
1031 inited_(false),
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001032 picture_id_(0),
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001033 codec_thread_(new Thread()),
1034 j_media_codec_video_encoder_class_(
1035 jni,
1036 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
1037 j_media_codec_video_encoder_(
1038 jni,
1039 jni->NewObject(*j_media_codec_video_encoder_class_,
1040 GetMethodID(jni,
1041 *j_media_codec_video_encoder_class_,
1042 "<init>",
1043 "()V"))) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001044 ScopedLocalRefFrame local_ref_frame(jni);
1045 // It would be nice to avoid spinning up a new thread per MediaCodec, and
1046 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
1047 // 2732 means that deadlocks abound. This class synchronously trampolines
1048 // to |codec_thread_|, so if anything else can be coming to _us_ from
1049 // |codec_thread_|, or from any thread holding the |_sendCritSect| described
1050 // in the bug, we have a problem. For now work around that with a dedicated
1051 // thread.
1052 codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001053 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001054
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001055 jclass j_output_buffer_info_class =
1056 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1057 j_init_encode_method_ = GetMethodID(jni,
1058 *j_media_codec_video_encoder_class_,
1059 "initEncode",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001060 "(IIII)[Ljava/nio/ByteBuffer;");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001061 j_dequeue_input_buffer_method_ = GetMethodID(
1062 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1063 j_encode_method_ = GetMethodID(
1064 jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1065 j_release_method_ =
1066 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1067 j_set_rates_method_ = GetMethodID(
1068 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1069 j_dequeue_output_buffer_method_ =
1070 GetMethodID(jni,
1071 *j_media_codec_video_encoder_class_,
1072 "dequeueOutputBuffer",
1073 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1074 j_release_output_buffer_method_ = GetMethodID(
1075 jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1076
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001077 j_color_format_field_ =
1078 GetFieldID(jni, *j_media_codec_video_encoder_class_, "colorFormat", "I");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001079 j_info_index_field_ =
1080 GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1081 j_info_buffer_field_ = GetFieldID(
1082 jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1083 j_info_is_key_frame_field_ =
1084 GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1085 j_info_presentation_timestamp_us_field_ = GetFieldID(
1086 jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001087 CHECK_EXCEPTION(jni) << "MediaCodecVideoEncoder ctor failed";
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00001088 AllowBlockingCalls();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001089}
1090
1091int32_t MediaCodecVideoEncoder::InitEncode(
1092 const webrtc::VideoCodec* codec_settings,
1093 int32_t /* number_of_cores */,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001094 size_t /* max_payload_size */) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001095 // Factory should guard against other codecs being used with us.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001096 CHECK(codec_settings->codecType == kVideoCodecVP8) << "Unsupported codec";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001097
1098 return codec_thread_->Invoke<int32_t>(
1099 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1100 this,
1101 codec_settings->width,
1102 codec_settings->height,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001103 codec_settings->startBitrate,
1104 codec_settings->maxFramerate));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001105}
1106
1107int32_t MediaCodecVideoEncoder::Encode(
1108 const webrtc::I420VideoFrame& frame,
1109 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1110 const std::vector<webrtc::VideoFrameType>* frame_types) {
1111 return codec_thread_->Invoke<int32_t>(Bind(
1112 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1113}
1114
1115int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1116 webrtc::EncodedImageCallback* callback) {
1117 return codec_thread_->Invoke<int32_t>(
1118 Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1119 this,
1120 callback));
1121}
1122
1123int32_t MediaCodecVideoEncoder::Release() {
1124 return codec_thread_->Invoke<int32_t>(
1125 Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1126}
1127
1128int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001129 int64_t /* rtt */) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001130 return WEBRTC_VIDEO_CODEC_OK;
1131}
1132
1133int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1134 uint32_t frame_rate) {
1135 return codec_thread_->Invoke<int32_t>(
1136 Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1137 this,
1138 new_bit_rate,
1139 frame_rate));
1140}
1141
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001142void MediaCodecVideoEncoder::OnMessage(rtc::Message* msg) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001143 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1144 ScopedLocalRefFrame local_ref_frame(jni);
1145
1146 // We only ever send one message to |this| directly (not through a Bind()'d
1147 // functor), so expect no ID/data.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001148 CHECK(!msg->message_id) << "Unexpected message!";
1149 CHECK(!msg->pdata) << "Unexpected message!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001150 CheckOnCodecThread();
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001151 if (!inited_) {
1152 return;
1153 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001154
1155 // It would be nice to recover from a failure here if one happened, but it's
1156 // unclear how to signal such a failure to the app, so instead we stay silent
1157 // about it and let the next app-called API method reveal the borkedness.
1158 DeliverPendingOutputs(jni);
1159 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1160}
1161
1162void MediaCodecVideoEncoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001163 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
1164 << "Running on wrong thread!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001165}
1166
1167void MediaCodecVideoEncoder::ResetCodec() {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001168 ALOGE("ResetCodec");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001169 if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1170 codec_thread_->Invoke<int32_t>(Bind(
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001171 &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this,
1172 width_, height_, 0, 0)) != WEBRTC_VIDEO_CODEC_OK) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001173 // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1174 // degrade to a SW encoder at this point? There isn't one AFAICT :(
1175 // https://code.google.com/p/webrtc/issues/detail?id=2920
1176 }
1177}
1178
1179int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001180 int width, int height, int kbps, int fps) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001181 CheckOnCodecThread();
1182 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1183 ScopedLocalRefFrame local_ref_frame(jni);
1184
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001185 ALOGD("InitEncodeOnCodecThread %d x %d. Bitrate: %d kbps. Fps: %d",
1186 width, height, kbps, fps);
1187 if (kbps == 0) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001188 kbps = last_set_bitrate_kbps_;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001189 }
1190 if (fps == 0) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001191 fps = last_set_fps_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001192 }
1193
1194 width_ = width;
1195 height_ = height;
1196 last_set_bitrate_kbps_ = kbps;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001197 last_set_fps_ = fps;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001198 yuv_size_ = width_ * height_ * 3 / 2;
1199 frames_received_ = 0;
1200 frames_dropped_ = 0;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001201 frames_resolution_update_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001202 frames_in_queue_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001203 current_timestamp_us_ = 0;
1204 start_time_ms_ = GetCurrentTimeMs();
1205 current_frames_ = 0;
1206 current_bytes_ = 0;
1207 current_encoding_time_ms_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001208 last_input_timestamp_ms_ = -1;
1209 last_output_timestamp_ms_ = -1;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001210 timestamps_.clear();
1211 render_times_ms_.clear();
1212 frame_rtc_times_ms_.clear();
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001213 drop_next_input_frame_ = false;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001214 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001215 // We enforce no extra stride/padding in the format creation step.
1216 jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1217 jni->CallObjectMethod(*j_media_codec_video_encoder_,
1218 j_init_encode_method_,
1219 width_,
1220 height_,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001221 kbps,
1222 fps));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001223 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001224 if (IsNull(jni, input_buffers))
1225 return WEBRTC_VIDEO_CODEC_ERROR;
1226
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001227 inited_ = true;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001228 switch (GetIntField(jni, *j_media_codec_video_encoder_,
1229 j_color_format_field_)) {
1230 case COLOR_FormatYUV420Planar:
1231 encoder_fourcc_ = libyuv::FOURCC_YU12;
1232 break;
1233 case COLOR_FormatYUV420SemiPlanar:
1234 case COLOR_QCOM_FormatYUV420SemiPlanar:
1235 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
1236 encoder_fourcc_ = libyuv::FOURCC_NV12;
1237 break;
1238 default:
1239 LOG(LS_ERROR) << "Wrong color format.";
1240 return WEBRTC_VIDEO_CODEC_ERROR;
1241 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001242 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001243 CHECK(input_buffers_.empty())
1244 << "Unexpected double InitEncode without Release";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001245 input_buffers_.resize(num_input_buffers);
1246 for (size_t i = 0; i < num_input_buffers; ++i) {
1247 input_buffers_[i] =
1248 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001249 int64 yuv_buffer_capacity =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001250 jni->GetDirectBufferCapacity(input_buffers_[i]);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001251 CHECK_EXCEPTION(jni);
1252 CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001253 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001254 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001255
1256 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1257 return WEBRTC_VIDEO_CODEC_OK;
1258}
1259
1260int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1261 const webrtc::I420VideoFrame& frame,
1262 const std::vector<webrtc::VideoFrameType>* frame_types) {
1263 CheckOnCodecThread();
1264 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1265 ScopedLocalRefFrame local_ref_frame(jni);
1266
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001267 if (!inited_) {
1268 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
1269 }
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001270 frames_received_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001271 if (!DeliverPendingOutputs(jni)) {
1272 ResetCodec();
1273 // Continue as if everything's fine.
1274 }
1275
1276 if (drop_next_input_frame_) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001277 ALOGV("Encoder drop frame - failed callback.");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001278 drop_next_input_frame_ = false;
1279 return WEBRTC_VIDEO_CODEC_OK;
1280 }
1281
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001282 CHECK(frame_types->size() == 1) << "Unexpected stream count";
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001283 if (frame.width() != width_ || frame.height() != height_) {
1284 frames_resolution_update_++;
1285 ALOGD("Unexpected frame resolution change from %d x %d to %d x %d",
1286 width_, height_, frame.width(), frame.height());
1287 if (frames_resolution_update_ > 3) {
1288 // Reset codec if we received more than 3 frames with new resolution.
1289 width_ = frame.width();
1290 height_ = frame.height();
1291 frames_resolution_update_ = 0;
1292 ResetCodec();
1293 }
1294 return WEBRTC_VIDEO_CODEC_OK;
1295 }
1296 frames_resolution_update_ = 0;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001297
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001298 bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1299
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001300 // Check if we accumulated too many frames in encoder input buffers
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001301 // or the encoder latency exceeds 70 ms and drop frame if so.
1302 if (frames_in_queue_ > 0 && last_input_timestamp_ms_ >= 0) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001303 int encoder_latency_ms = last_input_timestamp_ms_ -
1304 last_output_timestamp_ms_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001305 if (frames_in_queue_ > 2 || encoder_latency_ms > 70) {
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001306 ALOGD("Drop frame - encoder is behind by %d ms. Q size: %d",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001307 encoder_latency_ms, frames_in_queue_);
1308 frames_dropped_++;
1309 return WEBRTC_VIDEO_CODEC_OK;
1310 }
1311 }
1312
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001313 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1314 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001315 CHECK_EXCEPTION(jni);
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001316 if (j_input_buffer_index == -1) {
1317 // Video codec falls behind - no input buffer available.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001318 ALOGV("Encoder drop frame - no input buffers available");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001319 frames_dropped_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001320 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001321 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001322 if (j_input_buffer_index == -2) {
1323 ResetCodec();
1324 return WEBRTC_VIDEO_CODEC_ERROR;
1325 }
1326
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001327 ALOGV("Encode frame # %d. Buffer # %d. TS: %lld.",
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001328 frames_received_, j_input_buffer_index, current_timestamp_us_ / 1000);
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001329
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001330 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001331 uint8* yuv_buffer =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001332 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001333 CHECK_EXCEPTION(jni);
1334 CHECK(yuv_buffer) << "Indirect buffer??";
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001335 CHECK(!libyuv::ConvertFromI420(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001336 frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane),
1337 frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane),
1338 frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane),
1339 yuv_buffer, width_,
1340 width_, height_,
1341 encoder_fourcc_))
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001342 << "ConvertFromI420 failed";
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001343 last_input_timestamp_ms_ = current_timestamp_us_ / 1000;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001344 frames_in_queue_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001345
1346 // Save input image timestamps for later output
1347 timestamps_.push_back(frame.timestamp());
1348 render_times_ms_.push_back(frame.render_time_ms());
1349 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
1350
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001351 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1352 j_encode_method_,
1353 key_frame,
1354 j_input_buffer_index,
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001355 yuv_size_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001356 current_timestamp_us_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001357 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001358 current_timestamp_us_ += 1000000 / last_set_fps_;
1359
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001360 if (!encode_status || !DeliverPendingOutputs(jni)) {
1361 ResetCodec();
1362 return WEBRTC_VIDEO_CODEC_ERROR;
1363 }
1364
1365 return WEBRTC_VIDEO_CODEC_OK;
1366}
1367
1368int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1369 webrtc::EncodedImageCallback* callback) {
1370 CheckOnCodecThread();
1371 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1372 ScopedLocalRefFrame local_ref_frame(jni);
1373 callback_ = callback;
1374 return WEBRTC_VIDEO_CODEC_OK;
1375}
1376
1377int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001378 if (!inited_) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001379 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001380 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001381 CheckOnCodecThread();
1382 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001383 ALOGD("EncoderRelease: Frames received: %d. Frames dropped: %d.",
perkj@webrtc.org96e4db92015-02-13 12:46:51 +00001384 frames_received_, frames_dropped_);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001385 ScopedLocalRefFrame local_ref_frame(jni);
1386 for (size_t i = 0; i < input_buffers_.size(); ++i)
1387 jni->DeleteGlobalRef(input_buffers_[i]);
1388 input_buffers_.clear();
1389 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001390 CHECK_EXCEPTION(jni);
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001391 rtc::MessageQueueManager::Clear(this);
1392 inited_ = false;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001393 return WEBRTC_VIDEO_CODEC_OK;
1394}
1395
1396int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1397 uint32_t frame_rate) {
1398 CheckOnCodecThread();
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001399 if (last_set_bitrate_kbps_ == new_bit_rate &&
1400 last_set_fps_ == frame_rate) {
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001401 return WEBRTC_VIDEO_CODEC_OK;
1402 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001403 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1404 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001405 if (new_bit_rate > 0) {
1406 last_set_bitrate_kbps_ = new_bit_rate;
1407 }
1408 if (frame_rate > 0) {
1409 last_set_fps_ = frame_rate;
1410 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001411 bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1412 j_set_rates_method_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001413 last_set_bitrate_kbps_,
1414 last_set_fps_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001415 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001416 if (!ret) {
1417 ResetCodec();
1418 return WEBRTC_VIDEO_CODEC_ERROR;
1419 }
1420 return WEBRTC_VIDEO_CODEC_OK;
1421}
1422
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001423int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1424 JNIEnv* jni,
1425 jobject j_output_buffer_info) {
1426 return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1427}
1428
1429jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1430 JNIEnv* jni,
1431 jobject j_output_buffer_info) {
1432 return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1433}
1434
1435bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1436 JNIEnv* jni,
1437 jobject j_output_buffer_info) {
1438 return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1439}
1440
1441jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1442 JNIEnv* jni,
1443 jobject j_output_buffer_info) {
1444 return GetLongField(
1445 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1446}
1447
1448bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1449 while (true) {
1450 jobject j_output_buffer_info = jni->CallObjectMethod(
1451 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001452 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001453 if (IsNull(jni, j_output_buffer_info)) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001454 break;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001455 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001456
1457 int output_buffer_index =
1458 GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1459 if (output_buffer_index == -1) {
1460 ResetCodec();
1461 return false;
1462 }
1463
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001464 // Get frame timestamps from a queue.
1465 last_output_timestamp_ms_ =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001466 GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1467 1000;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001468 int32_t timestamp = timestamps_.front();
1469 timestamps_.erase(timestamps_.begin());
1470 int64_t render_time_ms = render_times_ms_.front();
1471 render_times_ms_.erase(render_times_ms_.begin());
1472 int64_t frame_encoding_time_ms = GetCurrentTimeMs() -
1473 frame_rtc_times_ms_.front();
1474 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001475 frames_in_queue_--;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001476
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001477 // Extract payload and key frame flag.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001478 int32_t callback_status = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001479 jobject j_output_buffer =
1480 GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1481 bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1482 size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1483 uint8* payload = reinterpret_cast<uint8_t*>(
1484 jni->GetDirectBufferAddress(j_output_buffer));
1485 CHECK_EXCEPTION(jni);
1486
1487 ALOGV("Encoder got output buffer # %d. Size: %d. TS: %lld. Latency: %lld."
1488 " EncTime: %lld",
1489 output_buffer_index, payload_size, last_output_timestamp_ms_,
1490 last_input_timestamp_ms_ - last_output_timestamp_ms_,
1491 frame_encoding_time_ms);
1492
1493 // Calculate and print encoding statistics - every 3 seconds.
1494 current_frames_++;
1495 current_bytes_ += payload_size;
1496 current_encoding_time_ms_ += frame_encoding_time_ms;
1497 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
1498 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
1499 current_frames_ > 0) {
1500 ALOGD("Encoder bitrate: %d, target: %d kbps, fps: %d,"
1501 " encTime: %d for last %d ms",
1502 current_bytes_ * 8 / statistic_time_ms,
1503 last_set_bitrate_kbps_,
1504 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
1505 current_encoding_time_ms_ / current_frames_, statistic_time_ms);
1506 start_time_ms_ = GetCurrentTimeMs();
1507 current_frames_ = 0;
perkj@webrtc.org96e4db92015-02-13 12:46:51 +00001508 current_bytes_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001509 current_encoding_time_ms_ = 0;
1510 }
1511
1512 // Callback - return encoded frame.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001513 if (callback_) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001514 scoped_ptr<webrtc::EncodedImage> image(
1515 new webrtc::EncodedImage(payload, payload_size, payload_size));
1516 image->_encodedWidth = width_;
1517 image->_encodedHeight = height_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001518 image->_timeStamp = timestamp;
1519 image->capture_time_ms_ = render_time_ms;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001520 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1521 image->_completeFrame = true;
1522
1523 webrtc::CodecSpecificInfo info;
1524 memset(&info, 0, sizeof(info));
1525 info.codecType = kVideoCodecVP8;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001526 info.codecSpecific.VP8.pictureId = picture_id_;
1527 info.codecSpecific.VP8.nonReference = false;
1528 info.codecSpecific.VP8.simulcastIdx = 0;
1529 info.codecSpecific.VP8.temporalIdx = webrtc::kNoTemporalIdx;
1530 info.codecSpecific.VP8.layerSync = false;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001531 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1532 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001533 picture_id_ = (picture_id_ + 1) & 0x7FFF;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001534
1535 // Generate a header describing a single fragment.
1536 webrtc::RTPFragmentationHeader header;
1537 memset(&header, 0, sizeof(header));
1538 header.VerifyAndAllocateFragmentationHeader(1);
1539 header.fragmentationOffset[0] = 0;
1540 header.fragmentationLength[0] = image->_length;
1541 header.fragmentationPlType[0] = 0;
1542 header.fragmentationTimeDiff[0] = 0;
1543
1544 callback_status = callback_->Encoded(*image, &info, &header);
1545 }
1546
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001547 // Return output buffer back to the encoder.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001548 bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1549 j_release_output_buffer_method_,
1550 output_buffer_index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001551 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001552 if (!success) {
1553 ResetCodec();
1554 return false;
1555 }
1556
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001557 if (callback_status > 0) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001558 drop_next_input_frame_ = true;
1559 // Theoretically could handle callback_status<0 here, but unclear what that
1560 // would mean for us.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001561 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001562 }
1563
1564 return true;
1565}
1566
1567// Simplest-possible implementation of an encoder factory, churns out
1568// MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1569class MediaCodecVideoEncoderFactory
1570 : public cricket::WebRtcVideoEncoderFactory {
1571 public:
1572 MediaCodecVideoEncoderFactory();
1573 virtual ~MediaCodecVideoEncoderFactory();
1574
1575 // WebRtcVideoEncoderFactory implementation.
1576 virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1577 OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001578 virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1579 virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1580
1581 private:
1582 // Empty if platform support is lacking, const after ctor returns.
1583 std::vector<VideoCodec> supported_codecs_;
1584};
1585
1586MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1587 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1588 ScopedLocalRefFrame local_ref_frame(jni);
1589 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1590 bool is_platform_supported = jni->CallStaticBooleanMethod(
1591 j_encoder_class,
1592 GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001593 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001594 if (!is_platform_supported)
1595 return;
1596
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001597 // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1598 // encoder? Sure would be. Too bad it doesn't. So we hard-code some
1599 // reasonable defaults.
1600 supported_codecs_.push_back(
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001601 VideoCodec(kVideoCodecVP8, "VP8", 1280, 1280, 30));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001602}
1603
1604MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1605
1606webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1607 webrtc::VideoCodecType type) {
1608 if (type != kVideoCodecVP8 || supported_codecs_.empty())
1609 return NULL;
1610 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1611}
1612
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001613const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1614MediaCodecVideoEncoderFactory::codecs() const {
1615 return supported_codecs_;
1616}
1617
1618void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1619 webrtc::VideoEncoder* encoder) {
1620 delete encoder;
1621}
1622
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001623class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001624 public rtc::MessageHandler {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001625 public:
1626 explicit MediaCodecVideoDecoder(JNIEnv* jni);
1627 virtual ~MediaCodecVideoDecoder();
1628
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001629 static int SetAndroidObjects(JNIEnv* jni, jobject render_egl_context);
1630
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001631 virtual int32_t InitDecode(const VideoCodec* codecSettings,
1632 int32_t numberOfCores) OVERRIDE;
1633
1634 virtual int32_t
1635 Decode(const EncodedImage& inputImage, bool missingFrames,
1636 const RTPFragmentationHeader* fragmentation,
1637 const CodecSpecificInfo* codecSpecificInfo = NULL,
1638 int64_t renderTimeMs = -1) OVERRIDE;
1639
1640 virtual int32_t RegisterDecodeCompleteCallback(
1641 DecodedImageCallback* callback) OVERRIDE;
1642
1643 virtual int32_t Release() OVERRIDE;
1644
1645 virtual int32_t Reset() OVERRIDE;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001646 // rtc::MessageHandler implementation.
1647 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001648
1649 private:
1650 // CHECK-fail if not running on |codec_thread_|.
1651 void CheckOnCodecThread();
1652
1653 int32_t InitDecodeOnCodecThread();
1654 int32_t ReleaseOnCodecThread();
1655 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001656 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1657 // true on success.
1658 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
1659
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001660
1661 bool key_frame_required_;
1662 bool inited_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001663 bool use_surface_;
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00001664 int error_count_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001665 VideoCodec codec_;
1666 I420VideoFrame decoded_image_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001667 NativeHandleImpl native_handle_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001668 DecodedImageCallback* callback_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001669 int frames_received_; // Number of frames received by decoder.
1670 int frames_decoded_; // Number of frames decoded by decoder
1671 int64_t start_time_ms_; // Start time for statistics.
1672 int current_frames_; // Number of frames in the current statistics interval.
1673 int current_bytes_; // Encoded bytes in the current statistics interval.
1674 int current_decoding_time_ms_; // Overall decoding time in the current second
1675 uint32_t max_pending_frames_; // Maximum number of pending input frames
1676 std::vector<int32_t> timestamps_;
1677 std::vector<int64_t> ntp_times_ms_;
1678 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
1679 // decoder input.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001680
1681 // State that is constant for the lifetime of this object once the ctor
1682 // returns.
1683 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1684 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
1685 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
1686 jmethodID j_init_decode_method_;
1687 jmethodID j_release_method_;
1688 jmethodID j_dequeue_input_buffer_method_;
1689 jmethodID j_queue_input_buffer_method_;
1690 jmethodID j_dequeue_output_buffer_method_;
1691 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001692 // MediaCodecVideoDecoder fields.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001693 jfieldID j_input_buffers_field_;
1694 jfieldID j_output_buffers_field_;
1695 jfieldID j_color_format_field_;
1696 jfieldID j_width_field_;
1697 jfieldID j_height_field_;
1698 jfieldID j_stride_field_;
1699 jfieldID j_slice_height_field_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001700 jfieldID j_surface_texture_field_;
1701 jfieldID j_textureID_field_;
1702 // MediaCodecVideoDecoder.DecoderOutputBufferInfo fields.
1703 jfieldID j_info_index_field_;
1704 jfieldID j_info_offset_field_;
1705 jfieldID j_info_size_field_;
1706 jfieldID j_info_presentation_timestamp_us_field_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001707
1708 // Global references; must be deleted in Release().
1709 std::vector<jobject> input_buffers_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001710 jobject surface_texture_;
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00001711 jobject previous_surface_texture_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001712
1713 // Render EGL context.
1714 static jobject render_egl_context_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001715};
1716
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001717jobject MediaCodecVideoDecoder::render_egl_context_ = NULL;
1718
1719int MediaCodecVideoDecoder::SetAndroidObjects(JNIEnv* jni,
1720 jobject render_egl_context) {
1721 if (render_egl_context_) {
1722 jni->DeleteGlobalRef(render_egl_context_);
1723 }
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00001724 if (IsNull(jni, render_egl_context)) {
1725 render_egl_context_ = NULL;
1726 } else {
1727 render_egl_context_ = jni->NewGlobalRef(render_egl_context);
glaznev@webrtc.org359d7202014-09-29 23:07:08 +00001728 CHECK_EXCEPTION(jni) << "error calling NewGlobalRef for EGL Context.";
1729 jclass j_egl_context_class = FindClass(jni, "android/opengl/EGLContext");
1730 if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) {
1731 ALOGE("Wrong EGL Context.");
1732 jni->DeleteGlobalRef(render_egl_context_);
1733 render_egl_context_ = NULL;
1734 }
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00001735 }
glaznev@webrtc.org359d7202014-09-29 23:07:08 +00001736 if (render_egl_context_ == NULL) {
1737 ALOGD("NULL VideoDecoder EGL context - HW surface decoding is disabled.");
1738 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001739 return 0;
1740}
1741
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001742MediaCodecVideoDecoder::MediaCodecVideoDecoder(JNIEnv* jni)
1743 : key_frame_required_(true),
1744 inited_(false),
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00001745 error_count_(0),
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00001746 surface_texture_(NULL),
1747 previous_surface_texture_(NULL),
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001748 codec_thread_(new Thread()),
1749 j_media_codec_video_decoder_class_(
1750 jni,
1751 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
1752 j_media_codec_video_decoder_(
1753 jni,
1754 jni->NewObject(*j_media_codec_video_decoder_class_,
1755 GetMethodID(jni,
1756 *j_media_codec_video_decoder_class_,
1757 "<init>",
1758 "()V"))) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001759 ScopedLocalRefFrame local_ref_frame(jni);
1760 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001761 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001762
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001763 j_init_decode_method_ = GetMethodID(
1764 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00001765 "(IIZZLandroid/opengl/EGLContext;)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001766 j_release_method_ =
1767 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
1768 j_dequeue_input_buffer_method_ = GetMethodID(
1769 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
1770 j_queue_input_buffer_method_ = GetMethodID(
1771 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
1772 j_dequeue_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001773 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
1774 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo;");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001775 j_release_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001776 jni, *j_media_codec_video_decoder_class_, "releaseOutputBuffer", "(IZ)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001777
1778 j_input_buffers_field_ = GetFieldID(
1779 jni, *j_media_codec_video_decoder_class_,
1780 "inputBuffers", "[Ljava/nio/ByteBuffer;");
1781 j_output_buffers_field_ = GetFieldID(
1782 jni, *j_media_codec_video_decoder_class_,
1783 "outputBuffers", "[Ljava/nio/ByteBuffer;");
1784 j_color_format_field_ = GetFieldID(
1785 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
1786 j_width_field_ = GetFieldID(
1787 jni, *j_media_codec_video_decoder_class_, "width", "I");
1788 j_height_field_ = GetFieldID(
1789 jni, *j_media_codec_video_decoder_class_, "height", "I");
1790 j_stride_field_ = GetFieldID(
1791 jni, *j_media_codec_video_decoder_class_, "stride", "I");
1792 j_slice_height_field_ = GetFieldID(
1793 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001794 j_textureID_field_ = GetFieldID(
1795 jni, *j_media_codec_video_decoder_class_, "textureID", "I");
1796 j_surface_texture_field_ = GetFieldID(
1797 jni, *j_media_codec_video_decoder_class_, "surfaceTexture",
1798 "Landroid/graphics/SurfaceTexture;");
1799
1800 jclass j_decoder_output_buffer_info_class = FindClass(jni,
1801 "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
1802 j_info_index_field_ = GetFieldID(
1803 jni, j_decoder_output_buffer_info_class, "index", "I");
1804 j_info_offset_field_ = GetFieldID(
1805 jni, j_decoder_output_buffer_info_class, "offset", "I");
1806 j_info_size_field_ = GetFieldID(
1807 jni, j_decoder_output_buffer_info_class, "size", "I");
1808 j_info_presentation_timestamp_us_field_ = GetFieldID(
1809 jni, j_decoder_output_buffer_info_class, "presentationTimestampUs", "J");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001810
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001811 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00001812 use_surface_ = true;
1813 if (render_egl_context_ == NULL)
1814 use_surface_ = false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001815 memset(&codec_, 0, sizeof(codec_));
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00001816 AllowBlockingCalls();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001817}
1818
1819MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001820 // Call Release() to ensure no more callbacks to us after we are deleted.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001821 Release();
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00001822 // Delete global references.
1823 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1824 if (previous_surface_texture_ != NULL)
1825 jni->DeleteGlobalRef(previous_surface_texture_);
1826 if (surface_texture_ != NULL)
1827 jni->DeleteGlobalRef(surface_texture_);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001828}
1829
1830int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
1831 int32_t numberOfCores) {
1832 if (inst == NULL) {
1833 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
1834 }
1835 int ret_val = Release();
1836 if (ret_val < 0) {
1837 return ret_val;
1838 }
1839 // Save VideoCodec instance for later.
1840 if (&codec_ != inst) {
1841 codec_ = *inst;
1842 }
1843 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1;
1844
1845 // Always start with a complete key frame.
1846 key_frame_required_ = true;
1847 frames_received_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001848 frames_decoded_ = 0;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001849
1850 // Call Java init.
1851 return codec_thread_->Invoke<int32_t>(
1852 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
1853}
1854
1855int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
1856 CheckOnCodecThread();
1857 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1858 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00001859 ALOGD("InitDecodeOnCodecThread: %d x %d. Fps: %d. Errors: %d",
1860 codec_.width, codec_.height, codec_.maxFramerate, error_count_);
1861 bool use_sw_codec = false;
1862 if (error_count_ > 1) {
1863 // If more than one critical errors happen for HW codec, switch to SW codec.
1864 use_sw_codec = true;
1865 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001866
1867 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
1868 j_init_decode_method_,
1869 codec_.width,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001870 codec_.height,
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00001871 use_sw_codec,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001872 use_surface_,
1873 render_egl_context_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001874 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001875 if (!success) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001876 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001877 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001878 inited_ = true;
1879
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001880 max_pending_frames_ = 0;
1881 if (use_surface_) {
1882 max_pending_frames_ = 1;
1883 }
1884 start_time_ms_ = GetCurrentTimeMs();
1885 current_frames_ = 0;
1886 current_bytes_ = 0;
1887 current_decoding_time_ms_ = 0;
1888 timestamps_.clear();
1889 ntp_times_ms_.clear();
1890 frame_rtc_times_ms_.clear();
1891
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001892 jobjectArray input_buffers = (jobjectArray)GetObjectField(
1893 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
1894 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001895 input_buffers_.resize(num_input_buffers);
1896 for (size_t i = 0; i < num_input_buffers; ++i) {
1897 input_buffers_[i] =
1898 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001899 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001900 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001901
1902 if (use_surface_) {
1903 jobject surface_texture = GetObjectField(
1904 jni, *j_media_codec_video_decoder_, j_surface_texture_field_);
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00001905 if (previous_surface_texture_ != NULL) {
1906 jni->DeleteGlobalRef(previous_surface_texture_);
1907 }
1908 previous_surface_texture_ = surface_texture_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001909 surface_texture_ = jni->NewGlobalRef(surface_texture);
1910 }
1911 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1912
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001913 return WEBRTC_VIDEO_CODEC_OK;
1914}
1915
1916int32_t MediaCodecVideoDecoder::Release() {
1917 return codec_thread_->Invoke<int32_t>(
1918 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
1919}
1920
1921int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001922 if (!inited_) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001923 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001924 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001925 CheckOnCodecThread();
1926 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1927 ALOGD("DecoderRelease: Frames received: %d.", frames_received_);
1928 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001929 for (size_t i = 0; i < input_buffers_.size(); i++) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001930 jni->DeleteGlobalRef(input_buffers_[i]);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001931 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001932 input_buffers_.clear();
1933 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001934 CHECK_EXCEPTION(jni);
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001935 rtc::MessageQueueManager::Clear(this);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001936 inited_ = false;
1937 return WEBRTC_VIDEO_CODEC_OK;
1938}
1939
1940
1941void MediaCodecVideoDecoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001942 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
1943 << "Running on wrong thread!";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001944}
1945
1946int32_t MediaCodecVideoDecoder::Decode(
1947 const EncodedImage& inputImage,
1948 bool missingFrames,
1949 const RTPFragmentationHeader* fragmentation,
1950 const CodecSpecificInfo* codecSpecificInfo,
1951 int64_t renderTimeMs) {
1952 if (!inited_) {
1953 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
1954 }
1955 if (callback_ == NULL) {
1956 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
1957 }
1958 if (inputImage._buffer == NULL && inputImage._length > 0) {
1959 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
1960 }
1961 // Check if encoded frame dimension has changed.
1962 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
1963 (inputImage._encodedWidth != codec_.width ||
1964 inputImage._encodedHeight != codec_.height)) {
1965 codec_.width = inputImage._encodedWidth;
1966 codec_.height = inputImage._encodedHeight;
1967 InitDecode(&codec_, 1);
1968 }
1969
1970 // Always start with a complete key frame.
1971 if (key_frame_required_) {
1972 if (inputImage._frameType != webrtc::kKeyFrame) {
1973 return WEBRTC_VIDEO_CODEC_ERROR;
1974 }
1975 if (!inputImage._completeFrame) {
1976 return WEBRTC_VIDEO_CODEC_ERROR;
1977 }
1978 key_frame_required_ = false;
1979 }
1980 if (inputImage._length == 0) {
1981 return WEBRTC_VIDEO_CODEC_ERROR;
1982 }
1983
1984 return codec_thread_->Invoke<int32_t>(Bind(
1985 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
1986}
1987
1988int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
1989 const EncodedImage& inputImage) {
1990 static uint8_t yVal_ = 0x7f;
1991
1992 CheckOnCodecThread();
1993 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1994 ScopedLocalRefFrame local_ref_frame(jni);
1995
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001996 // Try to drain the decoder and wait until output is not too
1997 // much behind the input.
1998 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
1999 ALOGV("Wait for output...");
2000 if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs * 1000)) {
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002001 error_count_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002002 Reset();
2003 return WEBRTC_VIDEO_CODEC_ERROR;
2004 }
2005 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2006 ALOGE("Output buffer dequeue timeout");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002007 error_count_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002008 Reset();
2009 return WEBRTC_VIDEO_CODEC_ERROR;
2010 }
2011 }
2012
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002013 // Get input buffer.
2014 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
2015 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002016 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002017 if (j_input_buffer_index < 0) {
2018 ALOGE("dequeueInputBuffer error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002019 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002020 Reset();
2021 return WEBRTC_VIDEO_CODEC_ERROR;
2022 }
2023
2024 // Copy encoded data to Java ByteBuffer.
2025 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
2026 uint8* buffer =
2027 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002028 CHECK(buffer) << "Indirect buffer??";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002029 int64 buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002030 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002031 if (buffer_capacity < inputImage._length) {
2032 ALOGE("Input frame size %d is bigger than buffer size %d.",
2033 inputImage._length, buffer_capacity);
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002034 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002035 Reset();
2036 return WEBRTC_VIDEO_CODEC_ERROR;
2037 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002038 ALOGV("Decoder frame in # %d. Buffer # %d. Size: %d",
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002039 frames_received_, j_input_buffer_index, inputImage._length);
2040 memcpy(buffer, inputImage._buffer, inputImage._length);
2041
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002042 // Save input image timestamps for later output.
2043 frames_received_++;
2044 current_bytes_ += inputImage._length;
2045 timestamps_.push_back(inputImage._timeStamp);
2046 ntp_times_ms_.push_back(inputImage.ntp_time_ms_);
2047 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
2048
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002049 // Feed input to decoder.
2050 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
2051 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2052 j_queue_input_buffer_method_,
2053 j_input_buffer_index,
2054 inputImage._length,
2055 timestamp_us);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002056 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002057 if (!success) {
2058 ALOGE("queueInputBuffer error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002059 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002060 Reset();
2061 return WEBRTC_VIDEO_CODEC_ERROR;
2062 }
2063
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002064 // Try to drain the decoder
2065 if (!DeliverPendingOutputs(jni, 0)) {
2066 ALOGE("DeliverPendingOutputs error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002067 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002068 Reset();
2069 return WEBRTC_VIDEO_CODEC_ERROR;
2070 }
2071
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002072 return WEBRTC_VIDEO_CODEC_OK;
2073}
2074
2075bool MediaCodecVideoDecoder::DeliverPendingOutputs(
2076 JNIEnv* jni, int dequeue_timeout_us) {
2077 if (frames_received_ <= frames_decoded_) {
2078 // No need to query for output buffers - decoder is drained.
2079 return true;
2080 }
2081 // Get decoder output.
2082 jobject j_decoder_output_buffer_info = jni->CallObjectMethod(
2083 *j_media_codec_video_decoder_,
2084 j_dequeue_output_buffer_method_,
2085 dequeue_timeout_us);
2086
2087 CHECK_EXCEPTION(jni);
2088 if (IsNull(jni, j_decoder_output_buffer_info)) {
2089 return true;
2090 }
2091
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002092 // Extract output buffer info from Java DecoderOutputBufferInfo.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002093 int output_buffer_index =
2094 GetIntField(jni, j_decoder_output_buffer_info, j_info_index_field_);
2095 if (output_buffer_index < 0) {
2096 ALOGE("dequeueOutputBuffer error : %d", output_buffer_index);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002097 return false;
2098 }
2099 int output_buffer_offset =
2100 GetIntField(jni, j_decoder_output_buffer_info, j_info_offset_field_);
2101 int output_buffer_size =
2102 GetIntField(jni, j_decoder_output_buffer_info, j_info_size_field_);
2103 CHECK_EXCEPTION(jni);
2104
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002105 // Get decoded video frame properties.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002106 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
2107 j_color_format_field_);
2108 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
2109 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
2110 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
2111 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
2112 j_slice_height_field_);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002113 int texture_id = GetIntField(jni, *j_media_codec_video_decoder_,
2114 j_textureID_field_);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002115
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002116 // Extract data from Java ByteBuffer and create output yuv420 frame -
2117 // for non surface decoding only.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002118 if (!use_surface_) {
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002119 if (output_buffer_size < width * height * 3 / 2) {
2120 ALOGE("Insufficient output buffer size: %d", output_buffer_size);
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002121 return false;
2122 }
2123 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
2124 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
2125 jobject output_buffer =
2126 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
2127 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
2128 output_buffer));
2129 CHECK_EXCEPTION(jni);
2130 payload += output_buffer_offset;
2131
2132 // Create yuv420 frame.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002133 if (color_format == COLOR_FormatYUV420Planar) {
2134 decoded_image_.CreateFrame(
2135 stride * slice_height, payload,
2136 (stride * slice_height) / 4, payload + (stride * slice_height),
perkj@webrtc.org96e4db92015-02-13 12:46:51 +00002137 (stride * slice_height) / 4,
2138 payload + (5 * stride * slice_height / 4),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002139 width, height,
2140 stride, stride / 2, stride / 2);
2141 } else {
2142 // All other supported formats are nv12.
2143 decoded_image_.CreateEmptyFrame(width, height, width,
2144 width / 2, width / 2);
2145 libyuv::NV12ToI420(
2146 payload, stride,
2147 payload + stride * slice_height, stride,
2148 decoded_image_.buffer(webrtc::kYPlane),
2149 decoded_image_.stride(webrtc::kYPlane),
2150 decoded_image_.buffer(webrtc::kUPlane),
2151 decoded_image_.stride(webrtc::kUPlane),
2152 decoded_image_.buffer(webrtc::kVPlane),
2153 decoded_image_.stride(webrtc::kVPlane),
2154 width, height);
2155 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002156 }
2157
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002158 // Get frame timestamps from a queue.
2159 int32_t timestamp = timestamps_.front();
2160 timestamps_.erase(timestamps_.begin());
2161 int64_t ntp_time_ms = ntp_times_ms_.front();
2162 ntp_times_ms_.erase(ntp_times_ms_.begin());
2163 int64_t frame_decoding_time_ms = GetCurrentTimeMs() -
2164 frame_rtc_times_ms_.front();
2165 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
2166
2167 ALOGV("Decoder frame out # %d. %d x %d. %d x %d. Color: 0x%x. Size: %d."
2168 " DecTime: %lld", frames_decoded_, width, height, stride, slice_height,
2169 color_format, output_buffer_size, frame_decoding_time_ms);
2170
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002171 // Return output buffer back to codec.
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002172 bool success = jni->CallBooleanMethod(
2173 *j_media_codec_video_decoder_,
2174 j_release_output_buffer_method_,
2175 output_buffer_index,
2176 use_surface_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002177 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002178 if (!success) {
2179 ALOGE("releaseOutputBuffer error");
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002180 return false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002181 }
2182
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002183 // Calculate and print decoding statistics - every 3 seconds.
2184 frames_decoded_++;
2185 current_frames_++;
2186 current_decoding_time_ms_ += frame_decoding_time_ms;
2187 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
2188 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
2189 current_frames_ > 0) {
2190 ALOGD("Decoder bitrate: %d kbps, fps: %d, decTime: %d for last %d ms",
2191 current_bytes_ * 8 / statistic_time_ms,
2192 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
2193 current_decoding_time_ms_ / current_frames_, statistic_time_ms);
2194 start_time_ms_ = GetCurrentTimeMs();
2195 current_frames_ = 0;
perkj@webrtc.org96e4db92015-02-13 12:46:51 +00002196 current_bytes_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002197 current_decoding_time_ms_ = 0;
2198 }
2199
2200 // Callback - output decoded frame.
2201 int32_t callback_status = WEBRTC_VIDEO_CODEC_OK;
2202 if (use_surface_) {
2203 native_handle_.SetTextureObject(surface_texture_, texture_id);
2204 TextureVideoFrame texture_image(
2205 &native_handle_, width, height, timestamp, 0);
2206 texture_image.set_ntp_time_ms(ntp_time_ms);
2207 callback_status = callback_->Decoded(texture_image);
2208 } else {
2209 decoded_image_.set_timestamp(timestamp);
2210 decoded_image_.set_ntp_time_ms(ntp_time_ms);
2211 callback_status = callback_->Decoded(decoded_image_);
2212 }
2213 if (callback_status > 0) {
2214 ALOGE("callback error");
2215 }
2216
2217 return true;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002218}
2219
2220int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
2221 DecodedImageCallback* callback) {
2222 callback_ = callback;
2223 return WEBRTC_VIDEO_CODEC_OK;
2224}
2225
2226int32_t MediaCodecVideoDecoder::Reset() {
2227 ALOGD("DecoderReset");
2228 if (!inited_) {
2229 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2230 }
2231 return InitDecode(&codec_, 1);
2232}
2233
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002234void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002235 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2236 ScopedLocalRefFrame local_ref_frame(jni);
2237 if (!inited_) {
2238 return;
2239 }
2240 // We only ever send one message to |this| directly (not through a Bind()'d
2241 // functor), so expect no ID/data.
2242 CHECK(!msg->message_id) << "Unexpected message!";
2243 CHECK(!msg->pdata) << "Unexpected message!";
2244 CheckOnCodecThread();
2245
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002246 if (!DeliverPendingOutputs(jni, 0)) {
2247 error_count_++;
2248 Reset();
2249 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002250 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002251}
2252
2253class MediaCodecVideoDecoderFactory
2254 : public cricket::WebRtcVideoDecoderFactory {
2255 public:
2256 MediaCodecVideoDecoderFactory();
2257 virtual ~MediaCodecVideoDecoderFactory();
2258 // WebRtcVideoDecoderFactory implementation.
2259 virtual webrtc::VideoDecoder* CreateVideoDecoder(
2260 webrtc::VideoCodecType type) OVERRIDE;
2261
2262 virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) OVERRIDE;
2263
2264 private:
2265 bool is_platform_supported_;
2266};
2267
2268MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
2269 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2270 ScopedLocalRefFrame local_ref_frame(jni);
2271 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
2272 is_platform_supported_ = jni->CallStaticBooleanMethod(
2273 j_decoder_class,
2274 GetStaticMethodID(jni, j_decoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002275 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002276}
2277
2278MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {}
2279
2280webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
2281 webrtc::VideoCodecType type) {
2282 if (type != kVideoCodecVP8 || !is_platform_supported_) {
2283 return NULL;
2284 }
2285 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded());
2286}
2287
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002288void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
2289 webrtc::VideoDecoder* decoder) {
2290 delete decoder;
2291}
2292
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002293#endif // #if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002294
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002295static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002296 jfieldID native_dc_id = GetFieldID(jni,
2297 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
2298 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002299 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002300}
2301
2302JOW(jlong, DataChannel_registerObserverNative)(
2303 JNIEnv* jni, jobject j_dc, jobject j_observer) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002304 scoped_ptr<DataChannelObserverWrapper> observer(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002305 new DataChannelObserverWrapper(jni, j_observer));
2306 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +00002307 return jlongFromPointer(observer.release());
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002308}
2309
2310JOW(void, DataChannel_unregisterObserverNative)(
2311 JNIEnv* jni, jobject j_dc, jlong native_observer) {
2312 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
2313 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
2314}
2315
2316JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
2317 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
2318}
2319
2320JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
2321 return JavaEnumFromIndex(
2322 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
2323}
2324
2325JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
2326 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002327 CHECK_LE(buffered_amount, std::numeric_limits<int64>::max())
2328 << "buffered_amount overflowed jlong!";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002329 return static_cast<jlong>(buffered_amount);
2330}
2331
2332JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
2333 ExtractNativeDC(jni, j_dc)->Close();
2334}
2335
2336JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
2337 jbyteArray data, jboolean binary) {
2338 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
2339 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002340 rtc::Buffer(bytes, jni->GetArrayLength(data)),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002341 binary));
2342 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2343 return ret;
2344}
2345
2346JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002347 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002348}
2349
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002350JOW(void, Logging_nativeEnableTracing)(
2351 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
2352 jint nativeSeverity) {
2353 std::string path = JavaToStdString(jni, j_path);
2354 if (nativeLevels != webrtc::kTraceNone) {
andrew@webrtc.org90805182013-09-05 16:40:43 +00002355 webrtc::Trace::set_level_filter(nativeLevels);
glaznev@webrtc.orge6581242014-09-19 16:53:46 +00002356#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002357 if (path != "logcat:") {
2358#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002359 CHECK_EQ(0, webrtc::Trace::SetTraceFile(path.c_str(), false))
2360 << "SetTraceFile failed";
glaznev@webrtc.orge6581242014-09-19 16:53:46 +00002361#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002362 } else {
2363 // Intentionally leak this to avoid needing to reason about its lifecycle.
2364 // It keeps no state and functions only as a dispatch point.
2365 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
2366 }
2367#endif
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002368 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002369 rtc::LogMessage::LogToDebug(nativeSeverity);
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002370}
2371
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002372JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002373 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002374}
2375
2376JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
2377 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
2378 delete p;
2379}
2380
2381JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002382 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002383}
2384
2385JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
2386 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
2387}
2388
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002389JOW(void, VideoRenderer_freeGuiVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002390 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
2391}
2392
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002393JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
2394 delete reinterpret_cast<JavaVideoRendererWrapper*>(j_p);
2395}
2396
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002397JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002398 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002399}
2400
2401JOW(jboolean, MediaStream_nativeAddAudioTrack)(
2402 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002403 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002404 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002405}
2406
2407JOW(jboolean, MediaStream_nativeAddVideoTrack)(
2408 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002409 return reinterpret_cast<MediaStreamInterface*>(pointer)
2410 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002411}
2412
2413JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
2414 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002415 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002416 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002417}
2418
2419JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
2420 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002421 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002422 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002423}
2424
2425JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
2426 return JavaStringFromStdString(
2427 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
2428}
2429
2430JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002431 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002432}
2433
2434JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
2435 JNIEnv * jni, jclass, jobject j_observer) {
2436 return (jlong)new PCOJava(jni, j_observer);
2437}
2438
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002439#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002440JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002441 JNIEnv* jni, jclass, jobject context,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002442 jboolean initialize_audio, jboolean initialize_video,
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002443 jboolean vp8_hw_acceleration, jobject render_egl_context) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002444 bool failure = false;
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002445 vp8_hw_acceleration_enabled = vp8_hw_acceleration;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002446 if (!factory_static_initialized) {
andresp@webrtc.org85ef7702014-09-17 11:44:51 +00002447 if (initialize_video) {
perkj@webrtc.org96e4db92015-02-13 12:46:51 +00002448 failure |= webrtc::SetRenderAndroidVM(GetJVM());
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00002449 failure |= AndroidVideoCapturerJni::SetAndroidObjects(jni, context);
andresp@webrtc.org85ef7702014-09-17 11:44:51 +00002450 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002451 if (initialize_audio)
perkj@webrtc.org96e4db92015-02-13 12:46:51 +00002452 failure |= webrtc::VoiceEngine::SetAndroidObjects(GetJVM(), jni, context);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002453 factory_static_initialized = true;
2454 }
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00002455 if (initialize_video) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002456 failure |= MediaCodecVideoDecoder::SetAndroidObjects(jni,
2457 render_egl_context);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00002458 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002459 return !failure;
2460}
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002461#endif // defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002462
glaznev@webrtc.org44ae4c82015-02-09 23:25:58 +00002463JOW(void, PeerConnectionFactory_initializeFieldTrials)(
2464 JNIEnv* jni, jclass, jstring j_trials_init_string) {
2465 field_trials_init_string = NULL;
2466 if (j_trials_init_string != NULL) {
2467 const char* init_string =
2468 jni->GetStringUTFChars(j_trials_init_string, NULL);
2469 int init_string_length = jni->GetStringUTFLength(j_trials_init_string);
2470 field_trials_init_string = new char[init_string_length + 1];
2471 rtc::strcpyn(field_trials_init_string, init_string_length + 1, init_string);
2472 jni->ReleaseStringUTFChars(j_trials_init_string, init_string);
perkj@webrtc.org96e4db92015-02-13 12:46:51 +00002473 LOG(LS_INFO) << "initializeFieldTrials: " << field_trials_init_string;
glaznev@webrtc.org44ae4c82015-02-09 23:25:58 +00002474 }
2475 webrtc::field_trial::InitFieldTrialsFromString(field_trials_init_string);
2476}
2477
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002478// Helper struct for working around the fact that CreatePeerConnectionFactory()
2479// comes in two flavors: either entirely automagical (constructing its own
2480// threads and deleting them on teardown, but no external codec factory support)
2481// or entirely manual (requires caller to delete threads after factory
2482// teardown). This struct takes ownership of its ctor's arguments to present a
2483// single thing for Java to hold and eventually free.
2484class OwnedFactoryAndThreads {
2485 public:
2486 OwnedFactoryAndThreads(Thread* worker_thread,
2487 Thread* signaling_thread,
2488 PeerConnectionFactoryInterface* factory)
2489 : worker_thread_(worker_thread),
2490 signaling_thread_(signaling_thread),
2491 factory_(factory) {}
2492
2493 ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
2494
2495 PeerConnectionFactoryInterface* factory() { return factory_; }
2496
2497 private:
2498 const scoped_ptr<Thread> worker_thread_;
2499 const scoped_ptr<Thread> signaling_thread_;
2500 PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor.
2501};
2502
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002503JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
2504 JNIEnv* jni, jclass) {
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002505 // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
2506 // ThreadManager only WrapCurrentThread()s the thread where it is first
2507 // created. Since the semantics around when auto-wrapping happens in
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002508 // webrtc/base/ are convoluted, we simply wrap here to avoid having to think
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002509 // about ramifications of auto-wrapping there.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002510 rtc::ThreadManager::Instance()->WrapCurrentThread();
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002511 webrtc::Trace::CreateTrace();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002512 Thread* worker_thread = new Thread();
2513 worker_thread->SetName("worker_thread", NULL);
2514 Thread* signaling_thread = new Thread();
2515 signaling_thread->SetName("signaling_thread", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002516 CHECK(worker_thread->Start() && signaling_thread->Start())
2517 << "Failed to start threads";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002518 scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002519 scoped_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002520#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002521 if (vp8_hw_acceleration_enabled) {
2522 encoder_factory.reset(new MediaCodecVideoEncoderFactory());
2523 decoder_factory.reset(new MediaCodecVideoDecoderFactory());
2524 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002525#endif
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002526 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002527 webrtc::CreatePeerConnectionFactory(worker_thread,
2528 signaling_thread,
2529 NULL,
2530 encoder_factory.release(),
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002531 decoder_factory.release()));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002532 OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
2533 worker_thread, signaling_thread, factory.release());
2534 return jlongFromPointer(owned_factory);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002535}
2536
2537JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002538 delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
glaznev@webrtc.org44ae4c82015-02-09 23:25:58 +00002539 if (field_trials_init_string) {
2540 webrtc::field_trial::InitFieldTrialsFromString(NULL);
2541 delete field_trials_init_string;
2542 field_trials_init_string = NULL;
2543 }
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002544 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002545}
2546
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002547static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
2548 return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
2549}
2550
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002551JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
2552 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002553 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002554 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002555 rtc::scoped_refptr<MediaStreamInterface> stream(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002556 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
2557 return (jlong)stream.release();
2558}
2559
2560JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
2561 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
2562 jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002563 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002564 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002565 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002566 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002567 rtc::scoped_refptr<VideoSourceInterface> source(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002568 factory->CreateVideoSource(
2569 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
2570 constraints.get()));
2571 return (jlong)source.release();
2572}
2573
2574JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
2575 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2576 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002577 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002578 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002579 rtc::scoped_refptr<VideoTrackInterface> track(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002580 factory->CreateVideoTrack(
2581 JavaToStdString(jni, id),
2582 reinterpret_cast<VideoSourceInterface*>(native_source)));
2583 return (jlong)track.release();
2584}
2585
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002586JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
2587 JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
2588 scoped_ptr<ConstraintsWrapper> constraints(
2589 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002590 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002591 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002592 rtc::scoped_refptr<AudioSourceInterface> source(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002593 factory->CreateAudioSource(constraints.get()));
2594 return (jlong)source.release();
2595}
2596
2597JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
2598 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2599 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002600 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002601 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002602 rtc::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002603 JavaToStdString(jni, id),
2604 reinterpret_cast<AudioSourceInterface*>(native_source)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002605 return (jlong)track.release();
2606}
2607
phoglund@webrtc.org006521d2015-02-12 09:23:59 +00002608JOW(void, PeerConnectionFactory_nativeSetOptions)(
2609 JNIEnv* jni, jclass, jlong native_factory, jobject options) {
2610 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
2611 factoryFromJava(native_factory));
2612 jclass options_class = jni->GetObjectClass(options);
2613 jfieldID network_ignore_mask_field =
2614 jni->GetFieldID(options_class, "networkIgnoreMask", "I");
2615 int network_ignore_mask =
2616 jni->GetIntField(options, network_ignore_mask_field);
2617 PeerConnectionFactoryInterface::Options options_to_set;
2618
2619 // This doesn't necessarily match the c++ version of this struct; feel free
2620 // to add more parameters as necessary.
2621 options_to_set.network_ignore_mask = network_ignore_mask;
2622 factory->SetOptions(options_to_set);
2623}
2624
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002625static void JavaIceServersToJsepIceServers(
2626 JNIEnv* jni, jobject j_ice_servers,
2627 PeerConnectionInterface::IceServers* ice_servers) {
2628 jclass list_class = GetObjectClass(jni, j_ice_servers);
2629 jmethodID iterator_id = GetMethodID(
2630 jni, list_class, "iterator", "()Ljava/util/Iterator;");
2631 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002632 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002633 jmethodID iterator_has_next = GetMethodID(
2634 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
2635 jmethodID iterator_next = GetMethodID(
2636 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
2637 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002638 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002639 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002640 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002641 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
2642 jfieldID j_ice_server_uri_id =
2643 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
2644 jfieldID j_ice_server_username_id =
2645 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
2646 jfieldID j_ice_server_password_id =
2647 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
2648 jstring uri = reinterpret_cast<jstring>(
2649 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
2650 jstring username = reinterpret_cast<jstring>(
2651 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
2652 jstring password = reinterpret_cast<jstring>(
2653 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
2654 PeerConnectionInterface::IceServer server;
2655 server.uri = JavaToStdString(jni, uri);
2656 server.username = JavaToStdString(jni, username);
2657 server.password = JavaToStdString(jni, password);
2658 ice_servers->push_back(server);
2659 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002660 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002661}
2662
2663JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
2664 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
2665 jobject j_constraints, jlong observer_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002666 rtc::scoped_refptr<PeerConnectionFactoryInterface> f(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002667 reinterpret_cast<PeerConnectionFactoryInterface*>(
2668 factoryFromJava(factory)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002669 PeerConnectionInterface::IceServers servers;
2670 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
2671 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
2672 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002673 rtc::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
mallinath@webrtc.orga0d30672014-04-26 00:00:15 +00002674 servers, observer->constraints(), NULL, NULL, observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002675 return (jlong)pc.release();
2676}
2677
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002678static rtc::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002679 JNIEnv* jni, jobject j_pc) {
2680 jfieldID native_pc_id = GetFieldID(jni,
2681 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
2682 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002683 return rtc::scoped_refptr<PeerConnectionInterface>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002684 reinterpret_cast<PeerConnectionInterface*>(j_p));
2685}
2686
2687JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
2688 const SessionDescriptionInterface* sdp =
2689 ExtractNativePC(jni, j_pc)->local_description();
2690 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2691}
2692
2693JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
2694 const SessionDescriptionInterface* sdp =
2695 ExtractNativePC(jni, j_pc)->remote_description();
2696 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2697}
2698
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002699JOW(jobject, PeerConnection_createDataChannel)(
2700 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
2701 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002702 rtc::scoped_refptr<DataChannelInterface> channel(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002703 ExtractNativePC(jni, j_pc)->CreateDataChannel(
2704 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00002705 // Mustn't pass channel.get() directly through NewObject to avoid reading its
2706 // vararg parameter as 64-bit and reading memory that doesn't belong to the
2707 // 32-bit parameter.
2708 jlong nativeChannelPtr = jlongFromPointer(channel.get());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002709 CHECK(nativeChannelPtr) << "Failed to create DataChannel";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002710 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
2711 jmethodID j_data_channel_ctor = GetMethodID(
2712 jni, j_data_channel_class, "<init>", "(J)V");
2713 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00002714 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002715 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002716 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002717 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002718 CHECK(bumped_count == 2) << "Unexpected refcount";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002719 return j_channel;
2720}
2721
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002722JOW(void, PeerConnection_createOffer)(
2723 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2724 ConstraintsWrapper* constraints =
2725 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002726 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
2727 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002728 jni, j_observer, constraints));
2729 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
2730}
2731
2732JOW(void, PeerConnection_createAnswer)(
2733 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2734 ConstraintsWrapper* constraints =
2735 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002736 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
2737 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002738 jni, j_observer, constraints));
2739 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
2740}
2741
2742// Helper to create a SessionDescriptionInterface from a SessionDescription.
2743static SessionDescriptionInterface* JavaSdpToNativeSdp(
2744 JNIEnv* jni, jobject j_sdp) {
2745 jfieldID j_type_id = GetFieldID(
2746 jni, GetObjectClass(jni, j_sdp), "type",
2747 "Lorg/webrtc/SessionDescription$Type;");
2748 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
2749 jmethodID j_canonical_form_id = GetMethodID(
2750 jni, GetObjectClass(jni, j_type), "canonicalForm",
2751 "()Ljava/lang/String;");
2752 jstring j_type_string = (jstring)jni->CallObjectMethod(
2753 j_type, j_canonical_form_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002754 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002755 std::string std_type = JavaToStdString(jni, j_type_string);
2756
2757 jfieldID j_description_id = GetFieldID(
2758 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
2759 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
2760 std::string std_description = JavaToStdString(jni, j_description);
2761
2762 return webrtc::CreateSessionDescription(
2763 std_type, std_description, NULL);
2764}
2765
2766JOW(void, PeerConnection_setLocalDescription)(
2767 JNIEnv* jni, jobject j_pc,
2768 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002769 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
2770 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002771 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2772 ExtractNativePC(jni, j_pc)->SetLocalDescription(
2773 observer, JavaSdpToNativeSdp(jni, j_sdp));
2774}
2775
2776JOW(void, PeerConnection_setRemoteDescription)(
2777 JNIEnv* jni, jobject j_pc,
2778 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002779 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
2780 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002781 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2782 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
2783 observer, JavaSdpToNativeSdp(jni, j_sdp));
2784}
2785
2786JOW(jboolean, PeerConnection_updateIce)(
2787 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
2788 PeerConnectionInterface::IceServers ice_servers;
2789 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002790 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002791 new ConstraintsWrapper(jni, j_constraints));
2792 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
2793}
2794
2795JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
2796 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
2797 jint j_sdp_mline_index, jstring j_candidate_sdp) {
2798 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
2799 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002800 scoped_ptr<IceCandidateInterface> candidate(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002801 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
2802 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
2803}
2804
2805JOW(jboolean, PeerConnection_nativeAddLocalStream)(
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +00002806 JNIEnv* jni, jobject j_pc, jlong native_stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002807 return ExtractNativePC(jni, j_pc)->AddStream(
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +00002808 reinterpret_cast<MediaStreamInterface*>(native_stream));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002809}
2810
2811JOW(void, PeerConnection_nativeRemoveLocalStream)(
2812 JNIEnv* jni, jobject j_pc, jlong native_stream) {
2813 ExtractNativePC(jni, j_pc)->RemoveStream(
2814 reinterpret_cast<MediaStreamInterface*>(native_stream));
2815}
2816
2817JOW(bool, PeerConnection_nativeGetStats)(
2818 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002819 rtc::scoped_refptr<StatsObserverWrapper> observer(
2820 new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002821 return ExtractNativePC(jni, j_pc)->GetStats(
jiayl@webrtc.orgdb41b4d2014-03-03 21:30:06 +00002822 observer,
2823 reinterpret_cast<MediaStreamTrackInterface*>(native_track),
2824 PeerConnectionInterface::kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002825}
2826
2827JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
2828 PeerConnectionInterface::SignalingState state =
2829 ExtractNativePC(jni, j_pc)->signaling_state();
2830 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
2831}
2832
2833JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
2834 PeerConnectionInterface::IceConnectionState state =
2835 ExtractNativePC(jni, j_pc)->ice_connection_state();
2836 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
2837}
2838
braveyao@webrtc.orgfedb9ea2015-01-21 07:57:06 +00002839JOW(jobject, PeerConnection_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002840 PeerConnectionInterface::IceGatheringState state =
2841 ExtractNativePC(jni, j_pc)->ice_gathering_state();
braveyao@webrtc.orgfedb9ea2015-01-21 07:57:06 +00002842 return JavaEnumFromIndex(jni, "PeerConnection$IceGatheringState", state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002843}
2844
2845JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
2846 ExtractNativePC(jni, j_pc)->Close();
2847 return;
2848}
2849
2850JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002851 rtc::scoped_refptr<MediaSourceInterface> p(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002852 reinterpret_cast<MediaSourceInterface*>(j_p));
2853 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
2854}
2855
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00002856JOW(jobject, VideoCapturer_nativeCreateVideoCapturer)(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002857 JNIEnv* jni, jclass, jstring j_device_name) {
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00002858// Since we can't create platform specific java implementations in Java, we
2859// defer the creation to C land.
2860#if defined(ANDROID)
2861 jclass j_video_capturer_class(
2862 FindClass(jni, "org/webrtc/VideoCapturerAndroid"));
2863 const jmethodID j_videocapturer_ctor(GetMethodID(
2864 jni, j_video_capturer_class, "<init>", "()V"));
2865 jobject j_video_capturer = jni->NewObject(j_video_capturer_class,
2866 j_videocapturer_ctor);
2867 CHECK_EXCEPTION(jni) << "error during NewObject";
2868
2869 const jmethodID m(GetMethodID(
2870 jni, j_video_capturer_class, "Init", "(Ljava/lang/String;)Z"));
2871 if (!jni->CallBooleanMethod(j_video_capturer, m, j_device_name)) {
2872 return nullptr;
2873 }
2874 CHECK_EXCEPTION(jni) << "error during CallVoidMethod";
2875
2876 rtc::scoped_ptr<webrtc::AndroidVideoCapturerDelegate> delegate(
2877 new AndroidVideoCapturerJni(jni, j_video_capturer));
2878 rtc::scoped_ptr<webrtc::AndroidVideoCapturer> capturer(
2879 new webrtc::AndroidVideoCapturer(delegate.Pass()));
2880
2881#else
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002882 std::string device_name = JavaToStdString(jni, j_device_name);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002883 scoped_ptr<cricket::DeviceManagerInterface> device_manager(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002884 cricket::DeviceManagerFactory::Create());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002885 CHECK(device_manager->Init()) << "DeviceManager::Init() failed";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002886 cricket::Device device;
2887 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002888 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002889 return 0;
2890 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002891 scoped_ptr<cricket::VideoCapturer> capturer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002892 device_manager->CreateVideoCapturer(device));
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00002893
2894 jclass j_video_capturer_class(
2895 FindClass(jni, "org/webrtc/VideoCapturer"));
2896 const jmethodID j_videocapturer_ctor(GetMethodID(
2897 jni, j_video_capturer_class, "<init>", "()V"));
2898 jobject j_video_capturer =
2899 jni->NewObject(j_video_capturer_class,
2900 j_videocapturer_ctor);
2901 CHECK_EXCEPTION(jni) << "error during creation of VideoCapturer";
2902
2903#endif
2904 const jmethodID j_videocapturer_set_native_capturer(GetMethodID(
2905 jni, j_video_capturer_class, "setNativeCapturer", "(J)V"));
2906 jni->CallVoidMethod(j_video_capturer,
2907 j_videocapturer_set_native_capturer,
2908 (jlong)capturer.release());
2909 CHECK_EXCEPTION(jni) << "error during setNativeCapturer";
2910 return j_video_capturer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002911}
2912
2913JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
2914 JNIEnv* jni, jclass, int x, int y) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002915 scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
2916 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002917 return (jlong)renderer.release();
2918}
2919
2920JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
2921 JNIEnv* jni, jclass, jobject j_callbacks) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002922 scoped_ptr<JavaVideoRendererWrapper> renderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002923 new JavaVideoRendererWrapper(jni, j_callbacks));
2924 return (jlong)renderer.release();
2925}
2926
glaznev@webrtc.orgf6932292015-02-05 17:29:59 +00002927JOW(void, VideoRenderer_nativeCopyPlane)(
2928 JNIEnv *jni, jclass, jobject j_src_buffer, jint width, jint height,
2929 jint src_stride, jobject j_dst_buffer, jint dst_stride) {
2930 size_t src_size = jni->GetDirectBufferCapacity(j_src_buffer);
2931 size_t dst_size = jni->GetDirectBufferCapacity(j_dst_buffer);
2932 CHECK(src_stride >= width) << "Wrong source stride " << src_stride;
2933 CHECK(dst_stride >= width) << "Wrong destination stride " << dst_stride;
2934 CHECK(src_size >= src_stride * height)
2935 << "Insufficient source buffer capacity " << src_size;
2936 CHECK(dst_size >= dst_stride * height)
2937 << "Isufficient destination buffer capacity " << dst_size;
2938 uint8_t *src =
2939 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_src_buffer));
2940 uint8_t *dst =
2941 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_dst_buffer));
2942 if (src_stride == dst_stride) {
2943 memcpy(dst, src, src_stride * height);
2944 } else {
2945 for (int i = 0; i < height; i++) {
2946 memcpy(dst, src, width);
2947 src += src_stride;
2948 dst += dst_stride;
2949 }
2950 }
2951}
2952
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002953JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
2954 cricket::VideoCapturer* capturer =
2955 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002956 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002957 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
2958 capturer->Stop();
2959 return jlongFromPointer(format.release());
2960}
2961
2962JOW(void, VideoSource_restart)(
2963 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002964 CHECK(j_p_source);
2965 CHECK(j_p_format);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002966 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002967 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
2968 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
2969 StartCapturing(cricket::VideoFormat(*format));
2970}
2971
fischman@webrtc.orga7266ca2013-10-03 19:04:18 +00002972JOW(void, VideoSource_freeNativeVideoFormat)(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002973 JNIEnv* jni, jclass, jlong j_p) {
2974 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
2975}
2976
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002977JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002978 return JavaStringFromStdString(
2979 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002980}
2981
2982JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002983 return JavaStringFromStdString(
2984 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002985}
2986
2987JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002988 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002989}
2990
2991JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002992 return JavaEnumFromIndex(
2993 jni,
2994 "MediaStreamTrack$State",
2995 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002996}
2997
2998JOW(jboolean, MediaStreamTrack_nativeSetState)(
2999 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003000 MediaStreamTrackInterface::TrackState new_state =
3001 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003002 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3003 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003004}
3005
3006JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
3007 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003008 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3009 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003010}
3011
3012JOW(void, VideoTrack_nativeAddRenderer)(
3013 JNIEnv* jni, jclass,
3014 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003015 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003016 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3017}
3018
3019JOW(void, VideoTrack_nativeRemoveRenderer)(
3020 JNIEnv* jni, jclass,
3021 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003022 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003023 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3024}
perkj@webrtc.org96e4db92015-02-13 12:46:51 +00003025
3026} // namespace webrtc_jni