diff --git a/talk/libjingle.gyp b/talk/libjingle.gyp index abb601d04f..f336daa5a4 100755 --- a/talk/libjingle.gyp +++ b/talk/libjingle.gyp @@ -227,7 +227,6 @@ 'app/webrtc/java/android', '<(webrtc_base_dir)/java/src', '<(webrtc_modules_dir)/audio_device/android/java/src', - '<(webrtc_modules_dir)/video_capture/android/java/src', '<(webrtc_modules_dir)/video_render/android/java/src', ], }, diff --git a/webrtc/build/apk_tests.gyp b/webrtc/build/apk_tests.gyp index b56c11d554..a9481d22d2 100644 --- a/webrtc/build/apk_tests.gyp +++ b/webrtc/build/apk_tests.gyp @@ -215,36 +215,6 @@ '../../build/apk_test.gypi', ], }, - { - 'target_name': 'video_capture_tests_apk', - 'type': 'none', - 'variables': { - 'test_suite_name': 'video_capture_tests', - 'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)video_capture_tests<(SHARED_LIB_SUFFIX)', - }, - 'dependencies': [ - '<(webrtc_root)/modules/modules.gyp:video_capture_tests', - 'video_capture_java', - ], - 'includes': [ - '../../build/apk_test.gypi', - ], - }, - { - # Used only by video_capture_tests_apk above, and impossible to use in the - # standalone build, which is why it's declared here instead of under - # modules/video_capture/ (to avoid the need for a forked _noop.gyp file - # like this file has; see comment at the top of this file). - 'target_name': 'video_capture_java', - 'type': 'none', - 'variables': { - 'java_in_dir': '<(webrtc_root)/modules/video_capture/android/java', - 'additional_src_dirs': [ '<(webrtc_root)/base/java/src', ], - }, - 'includes': [ - '../../build/java.gypi', - ], - }, { 'target_name': 'audio_device_java', 'type': 'none', diff --git a/webrtc/build/apk_tests_noop.gyp b/webrtc/build/apk_tests_noop.gyp index 7c1a6aa924..9a4789f9e8 100644 --- a/webrtc/build/apk_tests_noop.gyp +++ b/webrtc/build/apk_tests_noop.gyp @@ -65,9 +65,5 @@ 'target_name': 'audio_codec_speed_tests_apk', 'type': 'none', }, - { - 'target_name': 'video_capture_tests_apk', - 'type': 'none', - }, ], } diff --git a/webrtc/examples/android/media_demo/src/org/webrtc/webrtcdemo/MediaCodecVideoDecoder.java b/webrtc/examples/android/media_demo/src/org/webrtc/webrtcdemo/MediaCodecVideoDecoder.java deleted file mode 100644 index ba811d0d23..0000000000 --- a/webrtc/examples/android/media_demo/src/org/webrtc/webrtcdemo/MediaCodecVideoDecoder.java +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -package org.webrtc.webrtcdemo; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.media.MediaCodec; -import android.media.MediaCrypto; -import android.media.MediaExtractor; -import android.media.MediaFormat; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceView; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.LinkedList; - -class MediaCodecVideoDecoder { - public static final int DECODE = 0; - private enum CodecName { ON2_VP8, GOOGLE_VPX, EXYNOX_VP8 } - - private void check(boolean value, String message) { - if (value) { - return; - } - Log.e("WEBRTC-CHECK", message); - AlertDialog alertDialog = new AlertDialog.Builder(context).create(); - alertDialog.setTitle("WebRTC Error"); - alertDialog.setMessage(message); - alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, - "OK", - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - return; - } - } - ); - alertDialog.show(); - } - - class Frame { - public ByteBuffer buffer; - public long timestampUs; - - Frame(ByteBuffer buffer, long timestampUs) { - this.buffer = buffer; - this.timestampUs = timestampUs; - } - } - - // This class enables decoding being run on a separate thread. - class DecodeHandler extends Handler { - @Override - public void handleMessage(Message msg) { - // TODO(dwkang): figure out exceptions just make this thread finish. - try { - switch (msg.what) { - case DECODE: - decodePendingBuffers(); - long delayMillis = 5; // Don't busy wait. - handler.sendMessageDelayed( - handler.obtainMessage(DECODE), delayMillis); - break; - default: - break; - } - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - private static String TAG; - private Context context; - private SurfaceView surfaceView; - - private DecodeHandler handler; - private Thread looperThread; - - MediaCodec codec; - MediaFormat format; - - // Buffers supplied by MediaCodec for pushing encoded data to and pulling - // decoded data from. - private ByteBuffer[] codecInputBuffers; - private ByteBuffer[] codecOutputBuffers; - - // Frames from the native layer. - private LinkedList frameQueue; - // Indexes to MediaCodec buffers - private LinkedList availableInputBufferIndices; - private LinkedList availableOutputBufferIndices; - private LinkedList availableOutputBufferInfos; - - // Offset between system time and media time. - private long deltaTimeUs; - - public MediaCodecVideoDecoder(Context context) { - TAG = context.getString(R.string.tag); - this.context = context; - surfaceView = new SurfaceView(context); - frameQueue = new LinkedList(); - availableInputBufferIndices = new LinkedList(); - availableOutputBufferIndices = new LinkedList(); - availableOutputBufferInfos = new LinkedList(); - } - - public void dispose() { - codec.stop(); - codec.release(); - } - - // Return view that is written to by MediaCodec. - public SurfaceView getView() { return surfaceView; } - - // Entry point from the native layer. Called when the class should be ready - // to start receiving raw frames. - private boolean start(int width, int height) { - deltaTimeUs = -1; - if (!setCodecState(width, height, CodecName.ON2_VP8)) { - return false; - } - startLooperThread(); - // The decoding must happen on |looperThread| thread. - handler.sendMessage(handler.obtainMessage(DECODE)); - return true; - } - - private boolean setCodecState(int width, int height, CodecName codecName) { - // TODO(henrike): enable more than ON2_VP8 codec. - format = new MediaFormat(); - format.setInteger(MediaFormat.KEY_WIDTH, width); - format.setInteger(MediaFormat.KEY_HEIGHT, height); - try { - switch (codecName) { - case ON2_VP8: - format.setString(MediaFormat.KEY_MIME, "video/x-vnd.on2.vp8"); - codec = MediaCodec.createDecoderByType("video/x-vnd.on2.vp8"); - break; - case GOOGLE_VPX: - // SW VP8 decoder - codec = MediaCodec.createByCodecName("OMX.google.vpx.decoder"); - break; - case EXYNOX_VP8: - // Nexus10 HW VP8 decoder - codec = MediaCodec.createByCodecName("OMX.Exynos.VP8.Decoder"); - break; - default: - return false; - } - } catch (Exception e) { - // TODO(dwkang): replace this instanceof/throw with a narrower catch - // clause once the SDK advances. - if (e instanceof IOException) { - Log.e(TAG, "Failed to create MediaCodec for VP8.", e); - return false; - } - throw new RuntimeException(e); - } - Surface surface = surfaceView.getHolder().getSurface(); - MediaCrypto crypto = null; // No crypto. - int flags = 0; // Decoder (1 for encoder) - codec.configure(format, surface, crypto, flags); - codec.start(); - codecInputBuffers = codec.getInputBuffers(); - codecOutputBuffers = codec.getOutputBuffers(); - return true; - } - - private void startLooperThread() { - looperThread = new Thread() { - @Override - public void run() { - Looper.prepare(); - // Handler that is run by this thread. - handler = new DecodeHandler(); - // Notify that the thread has created a handler. - synchronized(MediaCodecVideoDecoder.this) { - MediaCodecVideoDecoder.this.notify(); - } - Looper.loop(); - } - }; - looperThread.start(); - // Wait for thread to notify that Handler has been set up. - synchronized(this) { - try { - wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - // Entry point from the native layer. It pushes the raw buffer to this class. - private void pushBuffer(ByteBuffer buffer, long renderTimeMs) { - // TODO(dwkang): figure out why exceptions just make this thread finish. - try { - final long renderTimeUs = renderTimeMs * 1000; - synchronized(frameQueue) { - frameQueue.add(new Frame(buffer, renderTimeUs)); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - private boolean hasFrame() { - synchronized(frameQueue) { - return !frameQueue.isEmpty(); - } - } - - private Frame dequeueFrame() { - synchronized(frameQueue) { - return frameQueue.removeFirst(); - } - } - - private void flush() { - availableInputBufferIndices.clear(); - availableOutputBufferIndices.clear(); - availableOutputBufferInfos.clear(); - - codec.flush(); - } - - // Media time is relative to previous frame. - private long mediaTimeToSystemTime(long mediaTimeUs) { - if (deltaTimeUs == -1) { - long nowUs = System.currentTimeMillis() * 1000; - deltaTimeUs = nowUs - mediaTimeUs; - } - return deltaTimeUs + mediaTimeUs; - } - - private void decodePendingBuffers() { - int timeoutUs = 0; // Don't block on dequeuing input buffer. - - int index = codec.dequeueInputBuffer(timeoutUs); - if (index != MediaCodec.INFO_TRY_AGAIN_LATER) { - availableInputBufferIndices.add(index); - } - while (feedInputBuffer()) {} - - MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); - index = codec.dequeueOutputBuffer(info, timeoutUs); - if (index > 0) { - availableOutputBufferIndices.add(index); - availableOutputBufferInfos.add(info); - } - if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { - codecOutputBuffers = codec.getOutputBuffers(); - } - - while (drainOutputBuffer()) {} - } - - // Returns true if MediaCodec is ready for more data and there was data - // available from the native layer. - private boolean feedInputBuffer() { - if (availableInputBufferIndices.isEmpty()) { - return false; - } - if (!hasFrame()) { - return false; - } - Frame frame = dequeueFrame(); - ByteBuffer buffer = frame.buffer; - - int index = availableInputBufferIndices.pollFirst(); - ByteBuffer codecData = codecInputBuffers[index]; - check(codecData.capacity() >= buffer.capacity(), - "Buffer is too small to copy a frame."); - buffer.rewind(); - codecData.rewind(); - codecData.put(buffer); - - try { - int offset = 0; - int flags = 0; - codec.queueInputBuffer(index, offset, buffer.capacity(), - frame.timestampUs, flags); - } catch (MediaCodec.CryptoException e) { - check(false, "CryptoException w/ errorCode " + e.getErrorCode() + - ", '" + e.getMessage() + "'"); - } - return true; - } - - // Returns true if more output data could be drained.MediaCodec has more data - // to deliver. - private boolean drainOutputBuffer() { - if (availableOutputBufferIndices.isEmpty()) { - return false; - } - - int index = availableOutputBufferIndices.peekFirst(); - MediaCodec.BufferInfo info = availableOutputBufferInfos.peekFirst(); - if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { - // End of stream is unexpected with streamed video. - check(false, "Saw output end of stream."); - return false; - } - long realTimeUs = mediaTimeToSystemTime(info.presentationTimeUs); - long nowUs = System.currentTimeMillis() * 1000; - long lateUs = nowUs - realTimeUs; - if (lateUs < -10000) { - // Frame should not be presented yet. - return false; - } - - // TODO(dwkang): For some extreme cases, just not doing rendering is not - // enough. Need to seek to the next key frame. - boolean render = lateUs <= 30000; - if (!render) { - Log.d(TAG, "video late by " + lateUs + " us. Skipping..."); - } - // Decode and render to surface if desired. - codec.releaseOutputBuffer(index, render); - availableOutputBufferIndices.removeFirst(); - availableOutputBufferInfos.removeFirst(); - return true; - } -} diff --git a/webrtc/modules/modules_java.gyp b/webrtc/modules/modules_java.gyp index 400cd11be6..060de2a067 100644 --- a/webrtc/modules/modules_java.gyp +++ b/webrtc/modules/modules_java.gyp @@ -18,18 +18,6 @@ 'includes': [ '../../build/java.gypi' ], }, # audio_device_module_java - { - 'target_name': 'video_capture_module_java', - 'type': 'none', - 'dependencies': [ - 'video_render_module_java', - ], - 'variables': { - 'java_in_dir': 'video_capture/android/java', - 'additional_src_dirs': [ '../base/java/src', ], - }, - 'includes': [ '../../build/java.gypi' ], - }, # video_capture_module_java { 'target_name': 'video_render_module_java', 'type': 'none', diff --git a/webrtc/modules/modules_java_chromium.gyp b/webrtc/modules/modules_java_chromium.gyp index 247a81d929..32d2d8d24e 100644 --- a/webrtc/modules/modules_java_chromium.gyp +++ b/webrtc/modules/modules_java_chromium.gyp @@ -16,17 +16,6 @@ }, 'includes': [ '../../../build/java.gypi' ], }, # audio_device_module_java - { - 'target_name': 'video_capture_module_java', - 'type': 'none', - 'dependencies': [ - 'video_render_module_java', - ], - 'variables': { - 'java_in_dir': 'video_capture/android/java', - }, - 'includes': [ '../../../build/java.gypi' ], - }, # video_capture_module_java { 'target_name': 'video_render_module_java', 'type': 'none', diff --git a/webrtc/modules/video_capture/BUILD.gn b/webrtc/modules/video_capture/BUILD.gn index f29e5b6c67..b0ed6f4e6c 100644 --- a/webrtc/modules/video_capture/BUILD.gn +++ b/webrtc/modules/video_capture/BUILD.gn @@ -130,21 +130,6 @@ if (!build_with_chromium) { deps += [ "//third_party/winsdk_samples" ] } - if (is_android) { - sources = [ - "android/device_info_android.cc", - "android/device_info_android.h", - "android/video_capture_android.cc", - "android/video_capture_android.h", - ] - - if (rtc_build_json) { - deps += [ "//third_party/jsoncpp" ] - } - if (rtc_build_icu) { - deps += [ "//third_party/icu:icuuc" ] - } - } if (is_ios) { sources = [ "ios/device_info_ios.h", diff --git a/webrtc/modules/video_capture/android/device_info_android.cc b/webrtc/modules/video_capture/android/device_info_android.cc deleted file mode 100644 index 974717c4b7..0000000000 --- a/webrtc/modules/video_capture/android/device_info_android.cc +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "webrtc/modules/video_capture/android/device_info_android.h" - -#include -#include -#include - -#include "unicode/unistr.h" -#include "webrtc/base/json.h" -#include "webrtc/modules/video_capture/android/video_capture_android.h" -#include "webrtc/system_wrappers/interface/logging.h" -#include "webrtc/system_wrappers/interface/ref_count.h" -#include "webrtc/system_wrappers/interface/trace.h" - -namespace webrtc { - -namespace videocapturemodule { - -// Helper for storing lists of pairs of ints. Used e.g. for resolutions & FPS -// ranges. -typedef std::pair IntPair; -typedef std::vector IntPairs; - -static std::string IntPairsToString(const IntPairs& pairs, char separator) { - std::stringstream stream; - for (size_t i = 0; i < pairs.size(); ++i) { - if (i > 0) - stream << ", "; - stream << "(" << pairs[i].first << separator << pairs[i].second << ")"; - } - return stream.str(); -} - -struct AndroidCameraInfo { - std::string name; - bool front_facing; - int orientation; - IntPairs resolutions; // Pairs are: (width,height). - // Pairs are (min,max) in units of FPS*1000 ("milli-frame-per-second"). - IntPairs mfpsRanges; - - std::string ToString() { - std::stringstream stream; - stream << "Name: [" << name << "], MFPS ranges: [" - << IntPairsToString(mfpsRanges, ':') - << "], front_facing: " << front_facing - << ", orientation: " << orientation << ", resolutions: [" - << IntPairsToString(resolutions, 'x') << "]"; - return stream.str(); - } -}; - -// Camera info; populated during DeviceInfoAndroid::Initialize() and immutable -// thereafter. -static std::vector* g_camera_info = NULL; - -// Set |*index| to the index of |name| in g_camera_info or return false if no -// match found. -static bool FindCameraIndexByName(const std::string& name, size_t* index) { - for (size_t i = 0; i < g_camera_info->size(); ++i) { - if (g_camera_info->at(i).name == name) { - *index = i; - return true; - } - } - return false; -} - -// Returns a pointer to the named member of g_camera_info, or NULL if no match -// is found. -static AndroidCameraInfo* FindCameraInfoByName(const std::string& name) { - size_t index = 0; - if (FindCameraIndexByName(name, &index)) - return &g_camera_info->at(index); - return NULL; -} - -// static -void DeviceInfoAndroid::Initialize(JNIEnv* jni) { - // TODO(henrike): this "if" would make a lot more sense as an assert, but - // Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_GetVideoEngine() and - // Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_Terminate() conspire to - // prevent this. Once that code is made to only - // VideoEngine::SetAndroidObjects() once per process, this can turn into an - // assert. - if (g_camera_info) - return; - - g_camera_info = new std::vector(); - jclass j_info_class = - jni->FindClass("org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid"); - assert(j_info_class); - jmethodID j_initialize = jni->GetStaticMethodID( - j_info_class, "getDeviceInfo", "()Ljava/lang/String;"); - jstring j_json_info = static_cast( - jni->CallStaticObjectMethod(j_info_class, j_initialize)); - - const jchar* jchars = jni->GetStringChars(j_json_info, NULL); - icu::UnicodeString ustr(jchars, jni->GetStringLength(j_json_info)); - jni->ReleaseStringChars(j_json_info, jchars); - std::string json_info; - ustr.toUTF8String(json_info); - - Json::Value cameras; - Json::Reader reader(Json::Features::strictMode()); - bool parsed = reader.parse(json_info, cameras); - if (!parsed) { - std::stringstream stream; - stream << "Failed to parse configuration:\n" - << reader.getFormattedErrorMessages(); - assert(false); - return; - } - for (Json::ArrayIndex i = 0; i < cameras.size(); ++i) { - const Json::Value& camera = cameras[i]; - AndroidCameraInfo info; - info.name = camera["name"].asString(); - info.front_facing = camera["front_facing"].asBool(); - info.orientation = camera["orientation"].asInt(); - Json::Value sizes = camera["sizes"]; - for (Json::ArrayIndex j = 0; j < sizes.size(); ++j) { - const Json::Value& size = sizes[j]; - info.resolutions.push_back(std::make_pair( - size["width"].asInt(), size["height"].asInt())); - } - Json::Value mfpsRanges = camera["mfpsRanges"]; - for (Json::ArrayIndex j = 0; j < mfpsRanges.size(); ++j) { - const Json::Value& mfpsRange = mfpsRanges[j]; - info.mfpsRanges.push_back(std::make_pair(mfpsRange["min_mfps"].asInt(), - mfpsRange["max_mfps"].asInt())); - } - g_camera_info->push_back(info); - } -} - -void DeviceInfoAndroid::DeInitialize() { - if (g_camera_info) { - delete g_camera_info; - g_camera_info = NULL; - } -} - -VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo( - const int32_t id) { - return new videocapturemodule::DeviceInfoAndroid(id); -} - -DeviceInfoAndroid::DeviceInfoAndroid(const int32_t id) : - DeviceInfoImpl(id) { -} - -DeviceInfoAndroid::~DeviceInfoAndroid() { -} - -bool DeviceInfoAndroid::FindCameraIndex(const char* deviceUniqueIdUTF8, - size_t* index) { - return FindCameraIndexByName(deviceUniqueIdUTF8, index); -} - -int32_t DeviceInfoAndroid::Init() { - return 0; -} - -uint32_t DeviceInfoAndroid::NumberOfDevices() { - return g_camera_info->size(); -} - -int32_t DeviceInfoAndroid::GetDeviceName( - uint32_t deviceNumber, - char* deviceNameUTF8, - uint32_t deviceNameLength, - char* deviceUniqueIdUTF8, - uint32_t deviceUniqueIdUTF8Length, - char* /*productUniqueIdUTF8*/, - uint32_t /*productUniqueIdUTF8Length*/) { - if (deviceNumber >= g_camera_info->size()) - return -1; - const AndroidCameraInfo& info = g_camera_info->at(deviceNumber); - if (info.name.length() + 1 > deviceNameLength || - info.name.length() + 1 > deviceUniqueIdUTF8Length) { - return -1; - } - memcpy(deviceNameUTF8, info.name.c_str(), info.name.length() + 1); - memcpy(deviceUniqueIdUTF8, info.name.c_str(), info.name.length() + 1); - return 0; -} - -int32_t DeviceInfoAndroid::CreateCapabilityMap( - const char* deviceUniqueIdUTF8) { - _captureCapabilities.clear(); - const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8); - if (info == NULL) - return -1; - - for (size_t i = 0; i < info->resolutions.size(); ++i) { - for (size_t j = 0; j < info->mfpsRanges.size(); ++j) { - const IntPair& size = info->resolutions[i]; - const IntPair& mfpsRange = info->mfpsRanges[j]; - VideoCaptureCapability cap; - cap.width = size.first; - cap.height = size.second; - cap.maxFPS = mfpsRange.second / 1000; - cap.expectedCaptureDelay = kExpectedCaptureDelay; - cap.rawType = kVideoNV21; - _captureCapabilities.push_back(cap); - } - } - return _captureCapabilities.size(); -} - -int32_t DeviceInfoAndroid::GetOrientation(const char* deviceUniqueIdUTF8, - VideoRotation& orientation) { - const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8); - if (info == NULL || - VideoCaptureImpl::RotationFromDegrees(info->orientation, - &orientation) != 0) { - return -1; - } - return 0; -} - -void DeviceInfoAndroid::GetMFpsRange(const char* deviceUniqueIdUTF8, - int max_fps_to_match, - int* min_mfps, int* max_mfps) { - const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8); - if (info == NULL) - return; - int desired_mfps = max_fps_to_match * 1000; - int best_diff_mfps = 0; - LOG(LS_INFO) << "Search for best target mfps " << desired_mfps; - // Search for best fps range with preference shifted to constant fps modes. - for (size_t i = 0; i < info->mfpsRanges.size(); ++i) { - int diff_mfps = abs(info->mfpsRanges[i].first - desired_mfps) + - abs(info->mfpsRanges[i].second - desired_mfps) + - (info->mfpsRanges[i].second - info->mfpsRanges[i].first) / 2; - LOG(LS_INFO) << "Fps range " << info->mfpsRanges[i].first << ":" << - info->mfpsRanges[i].second << ". Distance: " << diff_mfps; - if (i == 0 || diff_mfps < best_diff_mfps) { - best_diff_mfps = diff_mfps; - *min_mfps = info->mfpsRanges[i].first; - *max_mfps = info->mfpsRanges[i].second; - } - } -} - -} // namespace videocapturemodule -} // namespace webrtc diff --git a/webrtc/modules/video_capture/android/device_info_android.h b/webrtc/modules/video_capture/android/device_info_android.h deleted file mode 100644 index 581312bcb3..0000000000 --- a/webrtc/modules/video_capture/android/device_info_android.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_ANDROID_DEVICE_INFO_ANDROID_H_ -#define WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_ANDROID_DEVICE_INFO_ANDROID_H_ - -#include - -#include "webrtc/modules/video_capture/device_info_impl.h" -#include "webrtc/modules/video_capture/video_capture_impl.h" - -namespace webrtc -{ -namespace videocapturemodule -{ - -class DeviceInfoAndroid : public DeviceInfoImpl { - public: - static void Initialize(JNIEnv* env); - static void DeInitialize(); - - DeviceInfoAndroid(int32_t id); - virtual ~DeviceInfoAndroid(); - - // Set |*index| to the index of the camera matching |deviceUniqueIdUTF8|, or - // return false if no match. - bool FindCameraIndex(const char* deviceUniqueIdUTF8, size_t* index); - - virtual int32_t Init(); - virtual uint32_t NumberOfDevices(); - virtual int32_t GetDeviceName( - uint32_t deviceNumber, - char* deviceNameUTF8, - uint32_t deviceNameLength, - char* deviceUniqueIdUTF8, - uint32_t deviceUniqueIdUTF8Length, - char* productUniqueIdUTF8 = 0, - uint32_t productUniqueIdUTF8Length = 0); - virtual int32_t CreateCapabilityMap(const char* deviceUniqueIdUTF8); - - virtual int32_t DisplayCaptureSettingsDialogBox( - const char* /*deviceUniqueIdUTF8*/, - const char* /*dialogTitleUTF8*/, - void* /*parentWindow*/, - uint32_t /*positionX*/, - uint32_t /*positionY*/) { return -1; } - virtual int32_t GetOrientation(const char* deviceUniqueIdUTF8, - VideoRotation& orientation); - - // Populate |min_mfps| and |max_mfps| with the closest supported range of the - // device to |max_fps_to_match|. - void GetMFpsRange(const char* deviceUniqueIdUTF8, - int max_fps_to_match, - int* min_mfps, - int* max_mfps); - - private: - enum { kExpectedCaptureDelay = 190}; -}; - -} // namespace videocapturemodule -} // namespace webrtc - -#endif // WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_ANDROID_DEVICE_INFO_ANDROID_H_ diff --git a/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java b/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java deleted file mode 100644 index 15c86c9bbe..0000000000 --- a/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java +++ /dev/null @@ -1,463 +0,0 @@ -/* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -package org.webrtc.videoengine; - -import java.io.IOException; -import java.util.List; -import java.util.concurrent.Exchanger; - -import android.content.Context; -import android.graphics.ImageFormat; -import android.graphics.SurfaceTexture; -import android.hardware.Camera.Parameters; -import android.hardware.Camera.PreviewCallback; -import android.hardware.Camera; -import android.opengl.GLES11Ext; -import android.opengl.GLES20; -import android.os.Handler; -import android.os.Looper; -import android.os.SystemClock; -import android.view.Surface; -import android.view.SurfaceHolder.Callback; -import android.view.SurfaceHolder; -import android.view.WindowManager; - -import org.webrtc.Logging; - -// Wrapper for android Camera, with support for direct local preview rendering. -// Threading notes: this class is called from ViE C++ code, and from Camera & -// SurfaceHolder Java callbacks. Since these calls happen on different threads, -// the entry points to this class are all synchronized. This shouldn't present -// a performance bottleneck because only onPreviewFrame() is called more than -// once (and is called serially on a single thread), so the lock should be -// uncontended. Note that each of these synchronized methods must check -// |camera| for null to account for having possibly waited for stopCapture() to -// complete. -public class VideoCaptureAndroid implements PreviewCallback, Callback { - private final static String TAG = "WEBRTC-JC"; - - private static SurfaceHolder localPreview; - private Camera camera; // Only non-null while capturing. - private CameraThread cameraThread; - private Handler cameraThreadHandler; - private Context context; - private final int id; - private final Camera.CameraInfo info; - private final long native_capturer; // |VideoCaptureAndroid*| in C++. - private SurfaceTexture cameraSurfaceTexture; - private int[] cameraGlTextures = null; - // Arbitrary queue depth. Higher number means more memory allocated & held, - // lower number means more sensitivity to processing time in the client (and - // potentially stalling the capturer if it runs out of buffers to write to). - private final int numCaptureBuffers = 3; - private double averageDurationMs; - private long lastCaptureTimeMs; - private int frameCount; - private int frameDropRatio; - - // Requests future capturers to send their frames to |localPreview| directly. - public static void setLocalPreview(SurfaceHolder localPreview) { - // It is a gross hack that this is a class-static. Doing it right would - // mean plumbing this through the C++ API and using it from - // webrtc/examples/android/media_demo's MediaEngine class. - VideoCaptureAndroid.localPreview = localPreview; - } - - public VideoCaptureAndroid(int id, long native_capturer) { - this.id = id; - this.native_capturer = native_capturer; - this.context = GetContext(); - this.info = new Camera.CameraInfo(); - Camera.getCameraInfo(id, info); - } - - // Return the global application context. - private static native Context GetContext(); - - private class CameraThread extends Thread { - private Exchanger handlerExchanger; - public CameraThread(Exchanger handlerExchanger) { - this.handlerExchanger = handlerExchanger; - } - - @Override public void run() { - Looper.prepare(); - exchange(handlerExchanger, new Handler()); - Looper.loop(); - } - } - - // Called by native code. Returns true if capturer is started. - // - // Note that this actually opens the camera, and Camera callbacks run on the - // thread that calls open(), so this is done on the CameraThread. Since ViE - // API needs a synchronous success return value we wait for the result. - private synchronized boolean startCapture( - final int width, final int height, - final int min_mfps, final int max_mfps) { - Logging.d(TAG, "startCapture: " + width + "x" + height + "@" + - min_mfps + ":" + max_mfps); - if (cameraThread != null || cameraThreadHandler != null) { - throw new RuntimeException("Camera thread already started!"); - } - Exchanger handlerExchanger = new Exchanger(); - cameraThread = new CameraThread(handlerExchanger); - cameraThread.start(); - cameraThreadHandler = exchange(handlerExchanger, null); - - final Exchanger result = new Exchanger(); - cameraThreadHandler.post(new Runnable() { - @Override public void run() { - startCaptureOnCameraThread(width, height, min_mfps, max_mfps, result); - } - }); - boolean startResult = exchange(result, false); // |false| is a dummy value. - return startResult; - } - - private void startCaptureOnCameraThread( - int width, int height, int min_mfps, int max_mfps, - Exchanger result) { - Throwable error = null; - try { - camera = Camera.open(id); - - if (localPreview != null) { - localPreview.addCallback(this); - if (localPreview.getSurface() != null && - localPreview.getSurface().isValid()) { - camera.setPreviewDisplay(localPreview); - } - } else { - // No local renderer (we only care about onPreviewFrame() buffers, not a - // directly-displayed UI element). Camera won't capture without - // setPreview{Texture,Display}, so we create a SurfaceTexture and hand - // it over to Camera, but never listen for frame-ready callbacks, - // and never call updateTexImage on it. - try { - cameraGlTextures = new int[1]; - // Generate one texture pointer and bind it as an external texture. - GLES20.glGenTextures(1, cameraGlTextures, 0); - GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, - cameraGlTextures[0]); - GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, - GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, - GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, - GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); - GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, - GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); - - cameraSurfaceTexture = new SurfaceTexture(cameraGlTextures[0]); - cameraSurfaceTexture.setOnFrameAvailableListener(null); - camera.setPreviewTexture(cameraSurfaceTexture); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - Logging.d(TAG, "Camera orientation: " + info.orientation + - " .Device orientation: " + getDeviceOrientation()); - Camera.Parameters parameters = camera.getParameters(); - Logging.d(TAG, "isVideoStabilizationSupported: " + - parameters.isVideoStabilizationSupported()); - if (parameters.isVideoStabilizationSupported()) { - parameters.setVideoStabilization(true); - } - parameters.setPictureSize(width, height); - parameters.setPreviewSize(width, height); - - // Check if requested fps range is supported by camera, - // otherwise calculate frame drop ratio. - List supportedFpsRanges = parameters.getSupportedPreviewFpsRange(); - frameDropRatio = Integer.MAX_VALUE; - for (int i = 0; i < supportedFpsRanges.size(); i++) { - int[] range = supportedFpsRanges.get(i); - if (range[Parameters.PREVIEW_FPS_MIN_INDEX] == min_mfps && - range[Parameters.PREVIEW_FPS_MAX_INDEX] == max_mfps) { - frameDropRatio = 1; - break; - } - if (range[Parameters.PREVIEW_FPS_MIN_INDEX] % min_mfps == 0 && - range[Parameters.PREVIEW_FPS_MAX_INDEX] % max_mfps == 0) { - int dropRatio = range[Parameters.PREVIEW_FPS_MAX_INDEX] / max_mfps; - frameDropRatio = Math.min(dropRatio, frameDropRatio); - } - } - if (frameDropRatio == Integer.MAX_VALUE) { - Logging.e(TAG, "Can not find camera fps range"); - error = new RuntimeException("Can not find camera fps range"); - exchange(result, false); - return; - } - if (frameDropRatio > 1) { - Logging.d(TAG, "Frame dropper is enabled. Ratio: " + frameDropRatio); - } - min_mfps *= frameDropRatio; - max_mfps *= frameDropRatio; - Logging.d(TAG, "Camera preview mfps range: " + min_mfps + " - " + max_mfps); - parameters.setPreviewFpsRange(min_mfps, max_mfps); - - int format = ImageFormat.NV21; - parameters.setPreviewFormat(format); - camera.setParameters(parameters); - int bufSize = width * height * ImageFormat.getBitsPerPixel(format) / 8; - for (int i = 0; i < numCaptureBuffers; i++) { - camera.addCallbackBuffer(new byte[bufSize]); - } - camera.setPreviewCallbackWithBuffer(this); - frameCount = 0; - averageDurationMs = 1000000.0f / (max_mfps / frameDropRatio); - camera.startPreview(); - exchange(result, true); - return; - } catch (IOException e) { - error = e; - } catch (RuntimeException e) { - error = e; - } - Logging.e(TAG, "startCapture failed", error); - if (camera != null) { - Exchanger resultDropper = new Exchanger(); - stopCaptureOnCameraThread(resultDropper); - exchange(resultDropper, false); - } - exchange(result, false); - return; - } - - // Called by native code. Returns true when camera is known to be stopped. - private synchronized boolean stopCapture() { - Logging.d(TAG, "stopCapture"); - final Exchanger result = new Exchanger(); - cameraThreadHandler.post(new Runnable() { - @Override public void run() { - stopCaptureOnCameraThread(result); - } - }); - boolean status = exchange(result, false); // |false| is a dummy value here. - try { - cameraThread.join(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - cameraThreadHandler = null; - cameraThread = null; - Logging.d(TAG, "stopCapture done"); - return status; - } - - private void stopCaptureOnCameraThread( - Exchanger result) { - if (camera == null) { - throw new RuntimeException("Camera is already stopped!"); - } - Throwable error = null; - try { - camera.stopPreview(); - camera.setPreviewCallbackWithBuffer(null); - if (localPreview != null) { - localPreview.removeCallback(this); - camera.setPreviewDisplay(null); - } else { - camera.setPreviewTexture(null); - cameraSurfaceTexture = null; - if (cameraGlTextures != null) { - GLES20.glDeleteTextures(1, cameraGlTextures, 0); - cameraGlTextures = null; - } - } - camera.release(); - camera = null; - exchange(result, true); - Looper.myLooper().quit(); - return; - } catch (IOException e) { - error = e; - } catch (RuntimeException e) { - error = e; - } - Logging.e(TAG, "Failed to stop camera", error); - exchange(result, false); - Looper.myLooper().quit(); - return; - } - - private int getDeviceOrientation() { - int orientation = 0; - if (context != null) { - WindowManager wm = (WindowManager) context.getSystemService( - Context.WINDOW_SERVICE); - switch(wm.getDefaultDisplay().getRotation()) { - case Surface.ROTATION_90: - orientation = 90; - break; - case Surface.ROTATION_180: - orientation = 180; - break; - case Surface.ROTATION_270: - orientation = 270; - break; - case Surface.ROTATION_0: - default: - orientation = 0; - break; - } - } - return orientation; - } - - private native void ProvideCameraFrame( - byte[] data, int length, int rotation, long timeStamp, long captureObject); - - // Called on cameraThread so must not "synchronized". - @Override - public void onPreviewFrame(byte[] data, Camera callbackCamera) { - if (Thread.currentThread() != cameraThread) { - throw new RuntimeException("Camera callback not on camera thread?!?"); - } - if (camera == null) { - return; - } - if (camera != callbackCamera) { - throw new RuntimeException("Unexpected camera in callback!"); - } - frameCount++; - // Check if frame needs to be dropped. - if ((frameDropRatio > 1) && (frameCount % frameDropRatio) > 0) { - camera.addCallbackBuffer(data); - return; - } - long captureTimeMs = SystemClock.elapsedRealtime(); - if (frameCount > frameDropRatio) { - double durationMs = captureTimeMs - lastCaptureTimeMs; - averageDurationMs = 0.9 * averageDurationMs + 0.1 * durationMs; - if ((frameCount % 30) == 0) { - Logging.d(TAG, "Camera TS " + captureTimeMs + - ". Duration: " + (int)durationMs + " ms. FPS: " + - (int) (1000 / averageDurationMs + 0.5)); - } - } - lastCaptureTimeMs = captureTimeMs; - - int rotation = getDeviceOrientation(); - if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { - rotation = 360 - rotation; - } - rotation = (info.orientation + rotation) % 360; - - ProvideCameraFrame(data, data.length, rotation, - captureTimeMs, native_capturer); - camera.addCallbackBuffer(data); - } - - // Sets the rotation of the preview render window. - // Does not affect the captured video image. - // Called by native code. - private synchronized void setPreviewRotation(final int rotation) { - if (camera == null || cameraThreadHandler == null) { - return; - } - final Exchanger result = new Exchanger(); - cameraThreadHandler.post(new Runnable() { - @Override public void run() { - setPreviewRotationOnCameraThread(rotation, result); - } - }); - // Use the exchanger below to block this function until - // setPreviewRotationOnCameraThread() completes, holding the synchronized - // lock for the duration. The exchanged value itself is ignored. - exchange(result, null); - } - - private void setPreviewRotationOnCameraThread( - int rotation, Exchanger result) { - Logging.v(TAG, "setPreviewRotation:" + rotation); - - int resultRotation = 0; - if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { - // This is a front facing camera. SetDisplayOrientation will flip - // the image horizontally before doing the rotation. - resultRotation = ( 360 - rotation ) % 360; // Compensate for the mirror. - } else { - // Back-facing camera. - resultRotation = rotation; - } - camera.setDisplayOrientation(resultRotation); - exchange(result, null); - } - - @Override - public synchronized void surfaceChanged( - SurfaceHolder holder, int format, int width, int height) { - Logging.d(TAG, "VideoCaptureAndroid::surfaceChanged ignored: " + - format + ": " + width + "x" + height); - } - - @Override - public synchronized void surfaceCreated(final SurfaceHolder holder) { - Logging.d(TAG, "VideoCaptureAndroid::surfaceCreated"); - if (camera == null || cameraThreadHandler == null) { - return; - } - final Exchanger result = new Exchanger(); - cameraThreadHandler.post(new Runnable() { - @Override public void run() { - setPreviewDisplayOnCameraThread(holder, result); - } - }); - IOException e = exchange(result, null); // |null| is a dummy value here. - if (e != null) { - throw new RuntimeException(e); - } - } - - @Override - public synchronized void surfaceDestroyed(SurfaceHolder holder) { - Logging.d(TAG, "VideoCaptureAndroid::surfaceDestroyed"); - if (camera == null || cameraThreadHandler == null) { - return; - } - final Exchanger result = new Exchanger(); - cameraThreadHandler.post(new Runnable() { - @Override public void run() { - setPreviewDisplayOnCameraThread(null, result); - } - }); - IOException e = exchange(result, null); // |null| is a dummy value here. - if (e != null) { - throw new RuntimeException(e); - } - } - - private void setPreviewDisplayOnCameraThread( - SurfaceHolder holder, Exchanger result) { - try { - camera.setPreviewDisplay(holder); - } catch (IOException e) { - exchange(result, e); - return; - } - exchange(result, null); - return; - } - - // Exchanges |value| with |exchanger|, converting InterruptedExceptions to - // RuntimeExceptions (since we expect never to see these). - private static T exchange(Exchanger exchanger, T value) { - try { - return exchanger.exchange(value); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } -} diff --git a/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java b/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java deleted file mode 100644 index 72d7985120..0000000000 --- a/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -package org.webrtc.videoengine; - -import java.util.List; - -import android.hardware.Camera.CameraInfo; -import android.hardware.Camera.Parameters; -import android.hardware.Camera.Size; -import android.hardware.Camera; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import org.webrtc.Logging; - -public class VideoCaptureDeviceInfoAndroid { - private final static String TAG = "WEBRTC-JC"; - - private static boolean isFrontFacing(CameraInfo info) { - return info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT; - } - - private static String deviceUniqueName(int index, CameraInfo info) { - return "Camera " + index +", Facing " + - (isFrontFacing(info) ? "front" : "back") + - ", Orientation "+ info.orientation; - } - - // Returns information about all cameras on the device as a serialized JSON - // array of dictionaries encoding information about a single device. Since - // this reflects static information about the hardware present, there is no - // need to call this function more than once in a single process. It is - // marked "private" as it is only called by native code. - private static String getDeviceInfo() { - try { - JSONArray devices = new JSONArray(); - for (int i = 0; i < Camera.getNumberOfCameras(); ++i) { - CameraInfo info = new CameraInfo(); - Camera.getCameraInfo(i, info); - String uniqueName = deviceUniqueName(i, info); - JSONObject cameraDict = new JSONObject(); - devices.put(cameraDict); - List supportedSizes; - List supportedFpsRanges; - Camera camera = null; - try { - camera = Camera.open(i); - Parameters parameters = camera.getParameters(); - supportedSizes = parameters.getSupportedPreviewSizes(); - supportedFpsRanges = parameters.getSupportedPreviewFpsRange(); - Logging.d(TAG, uniqueName); - } catch (RuntimeException e) { - Logging.e(TAG, "Failed to open " + uniqueName + ", skipping", e); - continue; - } finally { - if (camera != null) { - camera.release(); - } - } - - JSONArray sizes = new JSONArray(); - for (Size supportedSize : supportedSizes) { - JSONObject size = new JSONObject(); - size.put("width", supportedSize.width); - size.put("height", supportedSize.height); - sizes.put(size); - } - - boolean is30fpsRange = false; - boolean is15fpsRange = false; - // If there is constant 30 fps mode, but no 15 fps - add 15 fps - // mode to the list of supported ranges. Frame drop will be done - // in software. - for (int[] range : supportedFpsRanges) { - if (range[Parameters.PREVIEW_FPS_MIN_INDEX] == 30000 && - range[Parameters.PREVIEW_FPS_MAX_INDEX] == 30000) { - is30fpsRange = true; - } - if (range[Parameters.PREVIEW_FPS_MIN_INDEX] == 15000 && - range[Parameters.PREVIEW_FPS_MAX_INDEX] == 15000) { - is15fpsRange = true; - } - } - if (is30fpsRange && !is15fpsRange) { - Logging.d(TAG, "Adding 15 fps support"); - int[] newRange = new int [Parameters.PREVIEW_FPS_MAX_INDEX + 1]; - newRange[Parameters.PREVIEW_FPS_MIN_INDEX] = 15000; - newRange[Parameters.PREVIEW_FPS_MAX_INDEX] = 15000; - for (int j = 0; j < supportedFpsRanges.size(); j++ ) { - int[] range = supportedFpsRanges.get(j); - if (range[Parameters.PREVIEW_FPS_MAX_INDEX] > - newRange[Parameters.PREVIEW_FPS_MAX_INDEX]) { - supportedFpsRanges.add(j, newRange); - break; - } - } - } - - JSONArray mfpsRanges = new JSONArray(); - for (int[] range : supportedFpsRanges) { - JSONObject mfpsRange = new JSONObject(); - // Android SDK deals in integral "milliframes per second" - // (i.e. fps*1000, instead of floating-point frames-per-second) so we - // preserve that through the Java->C++->Java round-trip. - mfpsRange.put("min_mfps", range[Parameters.PREVIEW_FPS_MIN_INDEX]); - mfpsRange.put("max_mfps", range[Parameters.PREVIEW_FPS_MAX_INDEX]); - mfpsRanges.put(mfpsRange); - } - - cameraDict.put("name", uniqueName); - cameraDict.put("front_facing", isFrontFacing(info)) - .put("orientation", info.orientation) - .put("sizes", sizes) - .put("mfpsRanges", mfpsRanges); - } - String ret = devices.toString(2); - Logging.d(TAG, ret); - return ret; - } catch (JSONException e) { - throw new RuntimeException(e); - } - } -} diff --git a/webrtc/modules/video_capture/android/video_capture_android.cc b/webrtc/modules/video_capture/android/video_capture_android.cc deleted file mode 100644 index 272cec42f9..0000000000 --- a/webrtc/modules/video_capture/android/video_capture_android.cc +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "webrtc/modules/video_capture/android/video_capture_android.h" - -#include "webrtc/base/common.h" -#include "webrtc/modules/utility/interface/helpers_android.h" -#include "webrtc/modules/video_capture/android/device_info_android.h" -#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" -#include "webrtc/system_wrappers/interface/logcat_trace_context.h" -#include "webrtc/system_wrappers/interface/logging.h" -#include "webrtc/system_wrappers/interface/ref_count.h" -#include "webrtc/system_wrappers/interface/trace.h" - -static JavaVM* g_jvm = NULL; -static jclass g_java_capturer_class = NULL; // VideoCaptureAndroid.class. -static jobject g_context = NULL; // Owned android.content.Context. - -namespace webrtc { - -// Called by Java to get the global application context. -jobject JNICALL GetContext(JNIEnv* env, jclass) { - assert(g_context); - return g_context; -} - -// Called by Java when the camera has a new frame to deliver. -void JNICALL ProvideCameraFrame( - JNIEnv* env, - jobject, - jbyteArray javaCameraFrame, - jint length, - jint rotation, - jlong timeStamp, - jlong context) { - webrtc::videocapturemodule::VideoCaptureAndroid* captureModule = - reinterpret_cast( - context); - jbyte* cameraFrame = env->GetByteArrayElements(javaCameraFrame, NULL); - captureModule->OnIncomingFrame( - reinterpret_cast(cameraFrame), length, rotation, 0); - env->ReleaseByteArrayElements(javaCameraFrame, cameraFrame, JNI_ABORT); -} - -int32_t SetCaptureAndroidVM(JavaVM* javaVM, jobject context) { - if (javaVM) { - assert(!g_jvm); - g_jvm = javaVM; - AttachThreadScoped ats(g_jvm); - g_context = ats.env()->NewGlobalRef(context); - - videocapturemodule::DeviceInfoAndroid::Initialize(ats.env()); - - jclass j_capture_class = - ats.env()->FindClass("org/webrtc/videoengine/VideoCaptureAndroid"); - assert(j_capture_class); - g_java_capturer_class = - reinterpret_cast(ats.env()->NewGlobalRef(j_capture_class)); - assert(g_java_capturer_class); - - JNINativeMethod native_methods[] = { - {"GetContext", - "()Landroid/content/Context;", - reinterpret_cast(&GetContext)}, - {"ProvideCameraFrame", - "([BIIJJ)V", - reinterpret_cast(&ProvideCameraFrame)}}; - if (ats.env()->RegisterNatives(g_java_capturer_class, - native_methods, 2) != 0) - assert(false); - } else { - if (g_jvm) { - AttachThreadScoped ats(g_jvm); - ats.env()->UnregisterNatives(g_java_capturer_class); - ats.env()->DeleteGlobalRef(g_java_capturer_class); - g_java_capturer_class = NULL; - ats.env()->DeleteGlobalRef(g_context); - g_context = NULL; - videocapturemodule::DeviceInfoAndroid::DeInitialize(); - g_jvm = NULL; - } - } - - return 0; -} - -namespace videocapturemodule { - -VideoCaptureModule* VideoCaptureImpl::Create( - const int32_t id, - const char* deviceUniqueIdUTF8) { - RefCountImpl* implementation = - new RefCountImpl(id); - if (implementation->Init(id, deviceUniqueIdUTF8) != 0) { - delete implementation; - implementation = NULL; - } - return implementation; -} - -int32_t VideoCaptureAndroid::OnIncomingFrame(uint8_t* videoFrame, - size_t videoFrameLength, - int32_t degrees, - int64_t captureTime) { - if (!_captureStarted) - return 0; - VideoRotation current_rotation = - (degrees <= 45 || degrees > 315) ? kVideoRotation_0 : - (degrees > 45 && degrees <= 135) ? kVideoRotation_90 : - (degrees > 135 && degrees <= 225) ? kVideoRotation_180 : - (degrees > 225 && degrees <= 315) ? kVideoRotation_270 : - kVideoRotation_0; // Impossible. - if (_rotation != current_rotation) { - LOG(LS_INFO) << "New camera rotation: " << degrees; - _rotation = current_rotation; - int32_t status = VideoCaptureImpl::SetCaptureRotation(_rotation); - if (status != 0) - return status; - } - return IncomingFrame( - videoFrame, videoFrameLength, _captureCapability, captureTime); -} - -VideoCaptureAndroid::VideoCaptureAndroid(const int32_t id) - : VideoCaptureImpl(id), - _deviceInfo(id), - _jCapturer(NULL), - _captureStarted(false) { -} - -int32_t VideoCaptureAndroid::Init(const int32_t id, - const char* deviceUniqueIdUTF8) { - const int nameLength = strlen(deviceUniqueIdUTF8); - if (nameLength >= kVideoCaptureUniqueNameLength) - return -1; - - // Store the device name - LOG(LS_INFO) << "VideoCaptureAndroid::Init: " << deviceUniqueIdUTF8; - size_t camera_id = 0; - if (!_deviceInfo.FindCameraIndex(deviceUniqueIdUTF8, &camera_id)) - return -1; - _deviceUniqueId = new char[nameLength + 1]; - memcpy(_deviceUniqueId, deviceUniqueIdUTF8, nameLength + 1); - - AttachThreadScoped ats(g_jvm); - JNIEnv* env = ats.env(); - jmethodID ctor = env->GetMethodID(g_java_capturer_class, "", "(IJ)V"); - assert(ctor); - jlong j_this = reinterpret_cast(this); - _jCapturer = env->NewGlobalRef( - env->NewObject(g_java_capturer_class, ctor, camera_id, j_this)); - assert(_jCapturer); - _rotation = kVideoRotation_0; - return 0; -} - -VideoCaptureAndroid::~VideoCaptureAndroid() { - // Ensure Java camera is released even if our caller didn't explicitly Stop. - if (_captureStarted) - StopCapture(); - AttachThreadScoped ats(g_jvm); - ats.env()->DeleteGlobalRef(_jCapturer); -} - -int32_t VideoCaptureAndroid::StartCapture( - const VideoCaptureCapability& capability) { - CriticalSectionScoped cs(&_apiCs); - AttachThreadScoped ats(g_jvm); - JNIEnv* env = ats.env(); - - if (_deviceInfo.GetBestMatchedCapability( - _deviceUniqueId, capability, _captureCapability) < 0) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, - "%s: GetBestMatchedCapability failed: %dx%d", - __FUNCTION__, capability.width, capability.height); - return -1; - } - - _captureDelay = _captureCapability.expectedCaptureDelay; - - jmethodID j_start = - env->GetMethodID(g_java_capturer_class, "startCapture", "(IIII)Z"); - assert(j_start); - int min_mfps = 0; - int max_mfps = 0; - _deviceInfo.GetMFpsRange(_deviceUniqueId, _captureCapability.maxFPS, - &min_mfps, &max_mfps); - bool started = env->CallBooleanMethod(_jCapturer, j_start, - _captureCapability.width, - _captureCapability.height, - min_mfps, max_mfps); - if (started) { - _requestedCapability = capability; - _captureStarted = true; - } - return started ? 0 : -1; -} - -int32_t VideoCaptureAndroid::StopCapture() { - _apiCs.Enter(); - AttachThreadScoped ats(g_jvm); - JNIEnv* env = ats.env(); - - memset(&_requestedCapability, 0, sizeof(_requestedCapability)); - memset(&_captureCapability, 0, sizeof(_captureCapability)); - _captureStarted = false; - // Exit critical section to avoid blocking camera thread inside - // onIncomingFrame() call. - _apiCs.Leave(); - - jmethodID j_stop = - env->GetMethodID(g_java_capturer_class, "stopCapture", "()Z"); - return env->CallBooleanMethod(_jCapturer, j_stop) ? 0 : -1; -} - -bool VideoCaptureAndroid::CaptureStarted() { - CriticalSectionScoped cs(&_apiCs); - return _captureStarted; -} - -int32_t VideoCaptureAndroid::CaptureSettings( - VideoCaptureCapability& settings) { - CriticalSectionScoped cs(&_apiCs); - settings = _requestedCapability; - return 0; -} - -int32_t VideoCaptureAndroid::SetCaptureRotation(VideoRotation rotation) { - int32_t status = VideoCaptureImpl::SetCaptureRotation(rotation); - if (status != 0) - return status; - - AttachThreadScoped ats(g_jvm); - JNIEnv* env = ats.env(); - - jmethodID j_spr = - env->GetMethodID(g_java_capturer_class, "setPreviewRotation", "(I)V"); - assert(j_spr); - int rotation_degrees; - if (RotationInDegrees(rotation, &rotation_degrees) != 0) { - assert(false); - } - env->CallVoidMethod(_jCapturer, j_spr, rotation_degrees); - return 0; -} - -} // namespace videocapturemodule -} // namespace webrtc diff --git a/webrtc/modules/video_capture/android/video_capture_android.h b/webrtc/modules/video_capture/android/video_capture_android.h deleted file mode 100644 index 8c1e7d3c8b..0000000000 --- a/webrtc/modules/video_capture/android/video_capture_android.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_ANDROID_VIDEO_CAPTURE_ANDROID_H_ -#define WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_ANDROID_VIDEO_CAPTURE_ANDROID_H_ - -#include - -#include "webrtc/modules/video_capture/android/device_info_android.h" -#include "webrtc/modules/video_capture/video_capture_impl.h" - -namespace webrtc { -namespace videocapturemodule { - -class VideoCaptureAndroid : public VideoCaptureImpl { - public: - VideoCaptureAndroid(const int32_t id); - virtual int32_t Init(const int32_t id, const char* deviceUniqueIdUTF8); - - virtual int32_t StartCapture(const VideoCaptureCapability& capability); - virtual int32_t StopCapture(); - virtual bool CaptureStarted(); - virtual int32_t CaptureSettings(VideoCaptureCapability& settings); - virtual int32_t SetCaptureRotation(VideoRotation rotation); - - int32_t OnIncomingFrame(uint8_t* videoFrame, - size_t videoFrameLength, - int32_t degrees, - int64_t captureTime = 0); - - protected: - virtual ~VideoCaptureAndroid(); - - DeviceInfoAndroid _deviceInfo; - jobject _jCapturer; // Global ref to Java VideoCaptureAndroid object. - VideoCaptureCapability _captureCapability; - VideoRotation _rotation; - bool _captureStarted; -}; - -} // namespace videocapturemodule -} // namespace webrtc -#endif // WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_ANDROID_VIDEO_CAPTURE_ANDROID_H_ diff --git a/webrtc/modules/video_capture/ensure_initialized.cc b/webrtc/modules/video_capture/ensure_initialized.cc deleted file mode 100644 index bc606bb88e..0000000000 --- a/webrtc/modules/video_capture/ensure_initialized.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -// Platform-specific initialization bits, if any, go here. - -#ifndef ANDROID - -namespace webrtc { -namespace videocapturemodule { -void EnsureInitialized() {} -} // namespace videocapturemodule -} // namespace webrtc - -#else - -#include - -// Note: this dependency is dangerous since it reaches into Chromium's base. -// There's a risk of e.g. macro clashes. This file may only be used in tests. -#include "base/android/jni_android.h" -#include "webrtc/base/checks.h" -#include "webrtc/modules/video_capture/video_capture_internal.h" - -namespace webrtc { -namespace videocapturemodule { - -static pthread_once_t g_initialize_once = PTHREAD_ONCE_INIT; - -void EnsureInitializedOnce() { - JNIEnv* jni = ::base::android::AttachCurrentThread(); - jobject context = ::base::android::GetApplicationContext(); - JavaVM* jvm = NULL; - RTC_CHECK_EQ(0, jni->GetJavaVM(&jvm)); - RTC_CHECK_EQ(0, webrtc::SetCaptureAndroidVM(jvm, context)); -} - -void EnsureInitialized() { - RTC_CHECK_EQ(0, pthread_once(&g_initialize_once, &EnsureInitializedOnce)); -} - -} // namespace videocapturemodule -} // namespace webrtc - -#endif // !ANDROID diff --git a/webrtc/modules/video_capture/ensure_initialized.h b/webrtc/modules/video_capture/ensure_initialized.h deleted file mode 100644 index 429879537c..0000000000 --- a/webrtc/modules/video_capture/ensure_initialized.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -namespace webrtc { -namespace videocapturemodule { - -// Ensure any necessary initialization of webrtc::videocapturemodule has -// completed. -void EnsureInitialized(); - -} // namespace videocapturemodule. -} // namespace webrtc. diff --git a/webrtc/modules/video_capture/test/video_capture_unittest.cc b/webrtc/modules/video_capture/test/video_capture_unittest.cc index 87794bb343..81380f438c 100644 --- a/webrtc/modules/video_capture/test/video_capture_unittest.cc +++ b/webrtc/modules/video_capture/test/video_capture_unittest.cc @@ -18,7 +18,6 @@ #include "webrtc/base/scoped_ref_ptr.h" #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" #include "webrtc/modules/utility/interface/process_thread.h" -#include "webrtc/modules/video_capture/ensure_initialized.h" #include "webrtc/modules/video_capture/include/video_capture.h" #include "webrtc/modules/video_capture/include/video_capture_factory.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" @@ -235,7 +234,6 @@ class VideoCaptureTest : public testing::Test { VideoCaptureTest() : number_of_devices_(0) {} void SetUp() { - webrtc::videocapturemodule::EnsureInitialized(); device_info_.reset(VideoCaptureFactory::CreateDeviceInfo(0)); assert(device_info_.get()); number_of_devices_ = device_info_->NumberOfDevices(); diff --git a/webrtc/modules/video_capture/video_capture.gypi b/webrtc/modules/video_capture/video_capture.gypi index 9163c1cd25..f552df7758 100644 --- a/webrtc/modules/video_capture/video_capture.gypi +++ b/webrtc/modules/video_capture/video_capture.gypi @@ -17,7 +17,6 @@ 'type': 'static_library', 'dependencies': [ 'webrtc_utility', - '<(webrtc_root)/common.gyp:webrtc_common', '<(webrtc_root)/common_video/common_video.gyp:common_video', '<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers', ], @@ -54,11 +53,13 @@ { 'target_name': 'video_capture_module_internal_impl', 'type': 'static_library', - 'dependencies': [ - 'video_capture_module', - '<(webrtc_root)/common.gyp:webrtc_common', - ], 'conditions': [ + ['OS!="android"', { + 'dependencies': [ + 'video_capture_module', + '<(webrtc_root)/common.gyp:webrtc_common', + ], + }], ['OS=="linux"', { 'sources': [ 'linux/device_info_linux.cc', @@ -115,26 +116,6 @@ ], }, }], # win - ['OS=="android"', { - 'sources': [ - 'android/device_info_android.cc', - 'android/device_info_android.h', - 'android/video_capture_android.cc', - 'android/video_capture_android.h', - ], - 'conditions': [ - ['build_json==1', { - 'dependencies': [ - '<(DEPTH)/third_party/jsoncpp/jsoncpp.gyp:jsoncpp', - ], - }], - ['build_icu==1', { - 'dependencies': [ - '<(DEPTH)/third_party/icu/icu.gyp:icuuc', - ], - }], - ], - }], # android ['OS=="ios"', { 'sources': [ 'ios/device_info_ios.h', @@ -164,7 +145,7 @@ }, ], }], # build_with_chromium==0 - ['include_tests==1', { + ['include_tests==1 and OS!="android"', { 'targets': [ { 'target_name': 'video_capture_tests', @@ -177,8 +158,6 @@ '<(DEPTH)/testing/gtest.gyp:gtest', ], 'sources': [ - 'ensure_initialized.cc', - 'ensure_initialized.h', 'test/video_capture_unittest.cc', 'test/video_capture_main_mac.mm', ], @@ -198,18 +177,6 @@ '-lX11', ], }], - ['OS=="android"', { - 'dependencies': [ - '<(DEPTH)/testing/android/native_test.gyp:native_test_native_code', - ], - # Need to disable error due to the line in - # base/android/jni_android.h triggering it: - # const BASE_EXPORT jobject GetApplicationContext() - # error: type qualifiers ignored on function return type - 'cflags': [ - '-Wno-ignored-qualifiers', - ], - }], ['OS=="mac"', { 'dependencies': [ # Link with a special main for mac so we can use the webcam. @@ -231,36 +198,6 @@ ] # conditions }, ], # targets - 'conditions': [ - ['OS=="android"', { - 'targets': [ - { - 'target_name': 'video_capture_tests_apk_target', - 'type': 'none', - 'dependencies': [ - '<(apk_tests_path):video_capture_tests_apk', - ], - }, - ], - }], - ['test_isolation_mode != "noop"', { - 'targets': [ - { - 'target_name': 'video_capture_tests_run', - 'type': 'none', - 'dependencies': [ - 'video_capture_tests', - ], - 'includes': [ - '../../build/isolate.gypi', - ], - 'sources': [ - 'video_capture_tests.isolate', - ], - }, - ], - }], - ], }], ], } diff --git a/webrtc/modules/video_capture/video_capture_factory.cc b/webrtc/modules/video_capture/video_capture_factory.cc index 5b44a6c706..f88f916ba4 100644 --- a/webrtc/modules/video_capture/video_capture_factory.cc +++ b/webrtc/modules/video_capture/video_capture_factory.cc @@ -17,7 +17,11 @@ namespace webrtc VideoCaptureModule* VideoCaptureFactory::Create(const int32_t id, const char* deviceUniqueIdUTF8) { +#if defined(ANDROID) + return nullptr; +#else return videocapturemodule::VideoCaptureImpl::Create(id, deviceUniqueIdUTF8); +#endif } VideoCaptureModule* VideoCaptureFactory::Create(const int32_t id, @@ -27,7 +31,11 @@ VideoCaptureModule* VideoCaptureFactory::Create(const int32_t id, VideoCaptureModule::DeviceInfo* VideoCaptureFactory::CreateDeviceInfo( const int32_t id) { +#if defined(ANDROID) + return nullptr; +#else return videocapturemodule::VideoCaptureImpl::CreateDeviceInfo(id); +#endif } } // namespace webrtc