Merge "Remove renderscript samples."
@@ -174,7 +174,6 @@ developers/build/prebuilts/gradle/AdvancedImmersiveMode/ sam
|
|||||||
developers/build/prebuilts/gradle/ImmersiveMode/ samples/${PLATFORM_NAME}/ui/ImmersiveMode
|
developers/build/prebuilts/gradle/ImmersiveMode/ samples/${PLATFORM_NAME}/ui/ImmersiveMode
|
||||||
developers/build/prebuilts/gradle/RepeatingAlarm/ samples/${PLATFORM_NAME}/background/RepeatingAlarm
|
developers/build/prebuilts/gradle/RepeatingAlarm/ samples/${PLATFORM_NAME}/background/RepeatingAlarm
|
||||||
developers/build/prebuilts/gradle/TextLinkify/ samples/${PLATFORM_NAME}/ui/TextLinkify
|
developers/build/prebuilts/gradle/TextLinkify/ samples/${PLATFORM_NAME}/ui/TextLinkify
|
||||||
developers/build/prebuilts/gradle/BasicRenderScript samples/${PLATFORM_NAME}/renderscript/BasicRenderScript
|
|
||||||
developers/build/prebuilts/gradle/RenderScriptIntrinsic samples/${PLATFORM_NAME}/renderscript/RenderScriptIntrinsic
|
developers/build/prebuilts/gradle/RenderScriptIntrinsic samples/${PLATFORM_NAME}/renderscript/RenderScriptIntrinsic
|
||||||
developers/build/prebuilts/gradle/SlidingTabsBasic samples/${PLATFORM_NAME}/ui/SlidingTabsBasic
|
developers/build/prebuilts/gradle/SlidingTabsBasic samples/${PLATFORM_NAME}/ui/SlidingTabsBasic
|
||||||
developers/build/prebuilts/gradle/SlidingTabsColors samples/${PLATFORM_NAME}/ui/SlidingTabsColors
|
developers/build/prebuilts/gradle/SlidingTabsColors samples/${PLATFORM_NAME}/ui/SlidingTabsColors
|
||||||
@@ -199,7 +198,6 @@ developers/build/prebuilts/gradle/ElevationBasic sam
|
|||||||
developers/build/prebuilts/gradle/ElevationDrag samples/${PLATFORM_NAME}/ui/views/Elevation/ElevationDrag
|
developers/build/prebuilts/gradle/ElevationDrag samples/${PLATFORM_NAME}/ui/views/Elevation/ElevationDrag
|
||||||
developers/build/prebuilts/gradle/ClippingBasic samples/${PLATFORM_NAME}/ui/views/Clipping/ClippingBasic
|
developers/build/prebuilts/gradle/ClippingBasic samples/${PLATFORM_NAME}/ui/views/Clipping/ClippingBasic
|
||||||
developers/build/prebuilts/gradle/JobScheduler samples/${PLATFORM_NAME}/background/JobScheduler
|
developers/build/prebuilts/gradle/JobScheduler samples/${PLATFORM_NAME}/background/JobScheduler
|
||||||
developers/build/prebuilts/gradle/HdrViewfinder samples/${PLATFORM_NAME}/media/HdrViewfinder
|
|
||||||
developers/build/prebuilts/gradle/DocumentCentricApps samples/${PLATFORM_NAME}/ui/activitytasks/DocumentCentricApps
|
developers/build/prebuilts/gradle/DocumentCentricApps samples/${PLATFORM_NAME}/ui/activitytasks/DocumentCentricApps
|
||||||
developers/build/prebuilts/gradle/DocumentCentricRelinquishIdentity samples/${PLATFORM_NAME}/ui/activitytasks/DocumentCentricRelinquishIdentity
|
developers/build/prebuilts/gradle/DocumentCentricRelinquishIdentity samples/${PLATFORM_NAME}/ui/activitytasks/DocumentCentricRelinquishIdentity
|
||||||
developers/build/prebuilts/gradle/AppRestrictionEnforcer samples/${PLATFORM_NAME}/admin/AppRestrictionEnforcer
|
developers/build/prebuilts/gradle/AppRestrictionEnforcer samples/${PLATFORM_NAME}/admin/AppRestrictionEnforcer
|
||||||
@@ -304,7 +302,6 @@ development/samples/WiFiDirectServiceDiscovery samples/${PLATFORM_NAME}/legacy/W
|
|||||||
development/samples/Wiktionary samples/${PLATFORM_NAME}/legacy/Wiktionary
|
development/samples/Wiktionary samples/${PLATFORM_NAME}/legacy/Wiktionary
|
||||||
development/samples/WiktionarySimple samples/${PLATFORM_NAME}/legacy/WiktionarySimple
|
development/samples/WiktionarySimple samples/${PLATFORM_NAME}/legacy/WiktionarySimple
|
||||||
development/samples/XmlAdapters samples/${PLATFORM_NAME}/legacy/XmlAdapters
|
development/samples/XmlAdapters samples/${PLATFORM_NAME}/legacy/XmlAdapters
|
||||||
development/samples/RenderScript/HelloCompute samples/${PLATFORM_NAME}/legacy/RenderScript/HelloCompute
|
|
||||||
|
|
||||||
# NOTICE files are copied by build/core/Makefile from sdk.git
|
# NOTICE files are copied by build/core/Makefile from sdk.git
|
||||||
development/sdk/sdk_files_NOTICE.txt samples/${PLATFORM_NAME}/NOTICE.txt
|
development/sdk/sdk_files_NOTICE.txt samples/${PLATFORM_NAME}/NOTICE.txt
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
include $(call all-subdir-makefiles)
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (C) 2011 The Android Open Source Project
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
|
|
||||||
package {
|
|
||||||
// See: http://go/android-license-faq
|
|
||||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
|
||||||
}
|
|
||||||
|
|
||||||
// This variable is used to match the 'LOCAL_SDK_VERSION' field in the former Android.mk file.
|
|
||||||
local_sdk_version = "14"
|
|
||||||
// This variable is used to set the value of the '-target-api' option for the 'llvm-rs-cc' command.
|
|
||||||
// Note: it may NOT always be the same as the 'local_sdk_version', due to the existing logic in the Make build system.
|
|
||||||
// For the Android.mk to Android.bp conversion, it is recommend to run the build before and after
|
|
||||||
// the conversion, to make sure the value of the '-target-api' option to be the same.
|
|
||||||
target_api_level = local_sdk_version
|
|
||||||
|
|
||||||
android_app {
|
|
||||||
name: "RsHelloCompute",
|
|
||||||
srcs: [
|
|
||||||
"src/**/*.java",
|
|
||||||
":RsHelloCompute-rscript{RsHelloCompute.srcjar}",
|
|
||||||
],
|
|
||||||
resource_zips: [
|
|
||||||
":RsHelloCompute-rscript{RsHelloCompute.res.zip}",
|
|
||||||
],
|
|
||||||
sdk_version: local_sdk_version,
|
|
||||||
}
|
|
||||||
|
|
||||||
genrule {
|
|
||||||
name: "RsHelloCompute-rscript",
|
|
||||||
srcs: [
|
|
||||||
"src/**/*.rscript",
|
|
||||||
":rs_script_api",
|
|
||||||
":rs_clang_headers",
|
|
||||||
],
|
|
||||||
tools: [
|
|
||||||
"llvm-rs-cc",
|
|
||||||
"soong_zip",
|
|
||||||
],
|
|
||||||
out: [
|
|
||||||
"RsHelloCompute.srcjar",
|
|
||||||
"RsHelloCompute.res.zip",
|
|
||||||
],
|
|
||||||
cmd: "for f in $(locations src/**/*.rscript); do " +
|
|
||||||
" $(location llvm-rs-cc) -target-api " + target_api_level +
|
|
||||||
" -o $(genDir)/res/raw -p $(genDir)/src " +
|
|
||||||
" -I $$(dirname $$(echo $(locations :rs_script_api) | awk '{ print $$1 }')) " +
|
|
||||||
" -I $$(dirname $$(echo $(locations :rs_clang_headers) | awk '{ print $$1 }')) $${f}; " +
|
|
||||||
"done && " +
|
|
||||||
"$(location soong_zip) -srcjar -o $(location RsHelloCompute.srcjar) -C $(genDir)/src -D $(genDir)/src &&" +
|
|
||||||
"$(location soong_zip) -o $(location RsHelloCompute.res.zip) -C $(genDir)/res -D $(genDir)/res",
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Copyright (C) 2011 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="com.example.android.rs.hellocompute">
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
|
||||||
<uses-sdk android:minSdkVersion="14" />
|
|
||||||
<application android:label="RsHelloCompute">
|
|
||||||
<activity android:name="HelloCompute">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
</application>
|
|
||||||
</manifest>
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
<p>A Renderscript compute sample that filters a bitmap. No Renderscript graphics APIs are used
|
|
||||||
in this sample.</p>
|
|
||||||
|
Before Width: | Height: | Size: 75 KiB |
@@ -1,31 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Copyright (C) 2011 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/displayin"
|
|
||||||
android:layout_width="320dip"
|
|
||||||
android:layout_height="266dip" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/displayout"
|
|
||||||
android:layout_width="320dip"
|
|
||||||
android:layout_height="266dip" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.example.android.rs.hellocompute;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.renderscript.RenderScript;
|
|
||||||
import android.renderscript.Allocation;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
|
|
||||||
public class HelloCompute extends Activity {
|
|
||||||
private Bitmap mBitmapIn;
|
|
||||||
private Bitmap mBitmapOut;
|
|
||||||
|
|
||||||
private RenderScript mRS;
|
|
||||||
private Allocation mInAllocation;
|
|
||||||
private Allocation mOutAllocation;
|
|
||||||
private ScriptC_mono mScript;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.main);
|
|
||||||
|
|
||||||
mBitmapIn = loadBitmap(R.drawable.data);
|
|
||||||
mBitmapOut = Bitmap.createBitmap(mBitmapIn.getWidth(), mBitmapIn.getHeight(),
|
|
||||||
mBitmapIn.getConfig());
|
|
||||||
|
|
||||||
ImageView in = (ImageView) findViewById(R.id.displayin);
|
|
||||||
in.setImageBitmap(mBitmapIn);
|
|
||||||
|
|
||||||
ImageView out = (ImageView) findViewById(R.id.displayout);
|
|
||||||
out.setImageBitmap(mBitmapOut);
|
|
||||||
|
|
||||||
createScript();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void createScript() {
|
|
||||||
mRS = RenderScript.create(this);
|
|
||||||
|
|
||||||
mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn,
|
|
||||||
Allocation.MipmapControl.MIPMAP_NONE,
|
|
||||||
Allocation.USAGE_SCRIPT);
|
|
||||||
mOutAllocation = Allocation.createFromBitmap(mRS, mBitmapOut,
|
|
||||||
Allocation.MipmapControl.MIPMAP_NONE,
|
|
||||||
Allocation.USAGE_SCRIPT);
|
|
||||||
|
|
||||||
mScript = new ScriptC_mono(mRS);
|
|
||||||
|
|
||||||
mScript.forEach_root(mInAllocation, mOutAllocation);
|
|
||||||
mOutAllocation.copyTo(mBitmapOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Bitmap loadBitmap(int resource) {
|
|
||||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
|
||||||
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
|
||||||
return BitmapFactory.decodeResource(getResources(), resource, options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma version(1)
|
|
||||||
#pragma rs java_package_name(com.example.android.rs.hellocompute)
|
|
||||||
|
|
||||||
const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
|
|
||||||
|
|
||||||
void root(const uchar4 *v_in, uchar4 *v_out) {
|
|
||||||
float4 f4 = rsUnpackColor8888(*v_in);
|
|
||||||
|
|
||||||
float3 mono = dot(f4.rgb, gMonoMult);
|
|
||||||
*v_out = rsPackColorTo8888(mono);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (C) 2012 The Android Open Source Project
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
|
|
||||||
package {
|
|
||||||
// See: http://go/android-license-faq
|
|
||||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
|
||||||
}
|
|
||||||
|
|
||||||
android_app {
|
|
||||||
name: "LevelsRS",
|
|
||||||
srcs: [
|
|
||||||
"src/**/*.java",
|
|
||||||
":LevelsRS-rscript{LevelsRS.srcjar}",
|
|
||||||
],
|
|
||||||
resource_zips: [
|
|
||||||
":LevelsRS-rscript{LevelsRS.res.zip}",
|
|
||||||
],
|
|
||||||
sdk_version: "current",
|
|
||||||
}
|
|
||||||
|
|
||||||
genrule {
|
|
||||||
name: "LevelsRS-rscript",
|
|
||||||
srcs: [
|
|
||||||
"src/**/*.rscript",
|
|
||||||
":rs_script_api",
|
|
||||||
":rs_clang_headers",
|
|
||||||
],
|
|
||||||
tools: [
|
|
||||||
"llvm-rs-cc",
|
|
||||||
"soong_zip",
|
|
||||||
],
|
|
||||||
out: [
|
|
||||||
"LevelsRS.srcjar",
|
|
||||||
"LevelsRS.res.zip",
|
|
||||||
],
|
|
||||||
cmd: "for f in $(locations src/**/*.rscript); do " +
|
|
||||||
" $(location llvm-rs-cc) -o $(genDir)/res/raw -p $(genDir)/src " +
|
|
||||||
" -I $$(dirname $$(echo $(locations :rs_script_api) | awk '{ print $$1 }')) " +
|
|
||||||
" -I $$(dirname $$(echo $(locations :rs_clang_headers) | awk '{ print $$1 }')) $${f}; " +
|
|
||||||
"done && " +
|
|
||||||
"$(location soong_zip) -srcjar -o $(location LevelsRS.srcjar) -C $(genDir)/src -D $(genDir)/src &&" +
|
|
||||||
"$(location soong_zip) -o $(location LevelsRS.res.zip) -C $(genDir)/res -D $(genDir)/res",
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2012 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
-->
|
|
||||||
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="com.android.rs.levels">
|
|
||||||
<uses-sdk android:minSdkVersion="14" />
|
|
||||||
<application android:label="Levels RS"
|
|
||||||
android:hardwareAccelerated="true">
|
|
||||||
|
|
||||||
<activity android:name="LevelsRSActivity"
|
|
||||||
android:label="Levels RS">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
<activity android:name="LevelsDalvikActivity"
|
|
||||||
android:label="Levels Dalvik">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
</application>
|
|
||||||
</manifest>
|
|
||||||
|
Before Width: | Height: | Size: 597 KiB |
@@ -1,140 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Copyright (C) 2012 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:id="@+id/toplevel">
|
|
||||||
<SurfaceView
|
|
||||||
android:id="@+id/surface"
|
|
||||||
android:layout_width="1dip"
|
|
||||||
android:layout_height="1dip" />
|
|
||||||
<ScrollView
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent">
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent">
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/display"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
<Button
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/benchmark"
|
|
||||||
android:onClick="benchmark"/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/benchmarkText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="8pt"
|
|
||||||
android:text="@string/saturation"/>
|
|
||||||
</LinearLayout>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/inSaturationText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="8pt"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginTop="15sp"
|
|
||||||
android:text="@string/saturation"/>
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/inSaturation"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginRight="10sp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/outWhiteText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginTop="15sp"
|
|
||||||
android:textSize="8pt"
|
|
||||||
android:text="@string/out_white"/>
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/outWhite"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginRight="10sp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/inWhiteText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="8pt"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginTop="15sp"
|
|
||||||
android:text="@string/in_white"/>
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/inWhite"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginRight="10sp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/outBlackText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="8pt"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginTop="15sp"
|
|
||||||
android:text="@string/out_black"/>
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/outBlack"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginRight="10sp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/inBlackText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="8pt"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginTop="15sp"
|
|
||||||
android:text="@string/in_black"/>
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/inBlack"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginRight="10sp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/inGammaText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="8pt"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginTop="15sp"
|
|
||||||
android:text="@string/gamma"/>
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/inGamma"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginRight="10sp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Copyright (C) 2012 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:id="@+id/toplevel">
|
|
||||||
<SurfaceView
|
|
||||||
android:id="@+id/surface"
|
|
||||||
android:layout_width="1dip"
|
|
||||||
android:layout_height="1dip" />
|
|
||||||
<ScrollView
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent">
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent">
|
|
||||||
<TextureView
|
|
||||||
android:id="@+id/display"
|
|
||||||
android:layout_width="800sp"
|
|
||||||
android:layout_height="423sp" />
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
<Button
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/benchmark"
|
|
||||||
android:onClick="benchmark"/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/benchmarkText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="8pt"
|
|
||||||
android:text="@string/saturation"/>
|
|
||||||
</LinearLayout>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/inSaturationText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="8pt"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginTop="15sp"
|
|
||||||
android:text="@string/saturation"/>
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/inSaturation"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginRight="10sp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/outWhiteText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginTop="15sp"
|
|
||||||
android:textSize="8pt"
|
|
||||||
android:text="@string/out_white"/>
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/outWhite"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginRight="10sp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/inWhiteText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="8pt"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginTop="15sp"
|
|
||||||
android:text="@string/in_white"/>
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/inWhite"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginRight="10sp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/outBlackText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="8pt"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginTop="15sp"
|
|
||||||
android:text="@string/out_black"/>
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/outBlack"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginRight="10sp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/inBlackText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="8pt"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginTop="15sp"
|
|
||||||
android:text="@string/in_black"/>
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/inBlack"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginRight="10sp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/inGammaText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="8pt"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginTop="15sp"
|
|
||||||
android:text="@string/gamma"/>
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/inGamma"
|
|
||||||
android:layout_marginLeft="10sp"
|
|
||||||
android:layout_marginRight="10sp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2012 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<!-- General -->
|
|
||||||
<skip />
|
|
||||||
<!--slider label -->
|
|
||||||
<string name="in_white">In White</string>
|
|
||||||
<string name="out_white">Out White</string>
|
|
||||||
<string name="in_black">In Black</string>
|
|
||||||
<string name="out_black">Out Black</string>
|
|
||||||
<string name="gamma">Gamma</string>
|
|
||||||
<string name="saturation">Saturation</string>
|
|
||||||
<string name="benchmark">Benchmark</string>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2012 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.rs.levels;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.renderscript.Matrix3f;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.SeekBar;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
public class LevelsDalvikActivity extends Activity
|
|
||||||
implements SeekBar.OnSeekBarChangeListener {
|
|
||||||
private final String TAG = "Img";
|
|
||||||
private Bitmap mBitmapIn;
|
|
||||||
private Bitmap mBitmapOut;
|
|
||||||
private float mInBlack = 0.0f;
|
|
||||||
private SeekBar mInBlackSeekBar;
|
|
||||||
private float mOutBlack = 0.0f;
|
|
||||||
private SeekBar mOutBlackSeekBar;
|
|
||||||
private float mInWhite = 255.0f;
|
|
||||||
private SeekBar mInWhiteSeekBar;
|
|
||||||
private float mOutWhite = 255.0f;
|
|
||||||
private SeekBar mOutWhiteSeekBar;
|
|
||||||
private float mGamma = 1.0f;
|
|
||||||
private SeekBar mGammaSeekBar;
|
|
||||||
private float mSaturation = 1.0f;
|
|
||||||
private SeekBar mSaturationSeekBar;
|
|
||||||
private TextView mBenchmarkResult;
|
|
||||||
private ImageView mDisplayView;
|
|
||||||
|
|
||||||
Matrix3f satMatrix = new Matrix3f();
|
|
||||||
float mInWMinInB;
|
|
||||||
float mOutWMinOutB;
|
|
||||||
float mOverInWMinInB;
|
|
||||||
|
|
||||||
int mInPixels[];
|
|
||||||
int mOutPixels[];
|
|
||||||
|
|
||||||
private void setLevels() {
|
|
||||||
mInWMinInB = mInWhite - mInBlack;
|
|
||||||
mOutWMinOutB = mOutWhite - mOutBlack;
|
|
||||||
mOverInWMinInB = 1.f / mInWMinInB;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setSaturation() {
|
|
||||||
float rWeight = 0.299f;
|
|
||||||
float gWeight = 0.587f;
|
|
||||||
float bWeight = 0.114f;
|
|
||||||
float oneMinusS = 1.0f - mSaturation;
|
|
||||||
|
|
||||||
satMatrix.set(0, 0, oneMinusS * rWeight + mSaturation);
|
|
||||||
satMatrix.set(0, 1, oneMinusS * rWeight);
|
|
||||||
satMatrix.set(0, 2, oneMinusS * rWeight);
|
|
||||||
satMatrix.set(1, 0, oneMinusS * gWeight);
|
|
||||||
satMatrix.set(1, 1, oneMinusS * gWeight + mSaturation);
|
|
||||||
satMatrix.set(1, 2, oneMinusS * gWeight);
|
|
||||||
satMatrix.set(2, 0, oneMinusS * bWeight);
|
|
||||||
satMatrix.set(2, 1, oneMinusS * bWeight);
|
|
||||||
satMatrix.set(2, 2, oneMinusS * bWeight + mSaturation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
|
||||||
if (fromUser) {
|
|
||||||
if (seekBar == mInBlackSeekBar) {
|
|
||||||
mInBlack = (float)progress;
|
|
||||||
setLevels();
|
|
||||||
} else if (seekBar == mOutBlackSeekBar) {
|
|
||||||
mOutBlack = (float)progress;
|
|
||||||
setLevels();
|
|
||||||
} else if (seekBar == mInWhiteSeekBar) {
|
|
||||||
mInWhite = (float)progress + 127.0f;
|
|
||||||
setLevels();
|
|
||||||
} else if (seekBar == mOutWhiteSeekBar) {
|
|
||||||
mOutWhite = (float)progress + 127.0f;
|
|
||||||
setLevels();
|
|
||||||
} else if (seekBar == mGammaSeekBar) {
|
|
||||||
mGamma = (float)progress/100.0f;
|
|
||||||
mGamma = Math.max(mGamma, 0.1f);
|
|
||||||
mGamma = 1.0f / mGamma;
|
|
||||||
} else if (seekBar == mSaturationSeekBar) {
|
|
||||||
mSaturation = (float)progress / 50.0f;
|
|
||||||
setSaturation();
|
|
||||||
}
|
|
||||||
|
|
||||||
filter();
|
|
||||||
mDisplayView.invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.main);
|
|
||||||
|
|
||||||
mBitmapIn = loadBitmap(R.drawable.city);
|
|
||||||
mBitmapOut = loadBitmap(R.drawable.city);
|
|
||||||
|
|
||||||
mDisplayView = (ImageView) findViewById(R.id.display);
|
|
||||||
mDisplayView.setImageBitmap(mBitmapOut);
|
|
||||||
|
|
||||||
mInBlackSeekBar = (SeekBar)findViewById(R.id.inBlack);
|
|
||||||
mInBlackSeekBar.setOnSeekBarChangeListener(this);
|
|
||||||
mInBlackSeekBar.setMax(128);
|
|
||||||
mInBlackSeekBar.setProgress(0);
|
|
||||||
mOutBlackSeekBar = (SeekBar)findViewById(R.id.outBlack);
|
|
||||||
mOutBlackSeekBar.setOnSeekBarChangeListener(this);
|
|
||||||
mOutBlackSeekBar.setMax(128);
|
|
||||||
mOutBlackSeekBar.setProgress(0);
|
|
||||||
|
|
||||||
mInWhiteSeekBar = (SeekBar)findViewById(R.id.inWhite);
|
|
||||||
mInWhiteSeekBar.setOnSeekBarChangeListener(this);
|
|
||||||
mInWhiteSeekBar.setMax(128);
|
|
||||||
mInWhiteSeekBar.setProgress(128);
|
|
||||||
mOutWhiteSeekBar = (SeekBar)findViewById(R.id.outWhite);
|
|
||||||
mOutWhiteSeekBar.setOnSeekBarChangeListener(this);
|
|
||||||
mOutWhiteSeekBar.setMax(128);
|
|
||||||
mOutWhiteSeekBar.setProgress(128);
|
|
||||||
|
|
||||||
mGammaSeekBar = (SeekBar)findViewById(R.id.inGamma);
|
|
||||||
mGammaSeekBar.setOnSeekBarChangeListener(this);
|
|
||||||
mGammaSeekBar.setMax(150);
|
|
||||||
mGammaSeekBar.setProgress(100);
|
|
||||||
|
|
||||||
mSaturationSeekBar = (SeekBar)findViewById(R.id.inSaturation);
|
|
||||||
mSaturationSeekBar.setOnSeekBarChangeListener(this);
|
|
||||||
mSaturationSeekBar.setProgress(50);
|
|
||||||
|
|
||||||
mBenchmarkResult = (TextView) findViewById(R.id.benchmarkText);
|
|
||||||
mBenchmarkResult.setText("Result: not run");
|
|
||||||
|
|
||||||
mInPixels = new int[mBitmapIn.getHeight() * mBitmapIn.getWidth()];
|
|
||||||
mOutPixels = new int[mBitmapOut.getHeight() * mBitmapOut.getWidth()];
|
|
||||||
mBitmapIn.getPixels(mInPixels, 0, mBitmapIn.getWidth(), 0, 0,
|
|
||||||
mBitmapIn.getWidth(), mBitmapIn.getHeight());
|
|
||||||
|
|
||||||
setLevels();
|
|
||||||
setSaturation();
|
|
||||||
filter();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Bitmap loadBitmap(int resource) {
|
|
||||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
|
||||||
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
|
||||||
Bitmap b = BitmapFactory.decodeResource(getResources(), resource, options);
|
|
||||||
Bitmap b2 = Bitmap.createBitmap(b.getWidth(), b.getHeight(), b.getConfig());
|
|
||||||
Canvas c = new Canvas(b2);
|
|
||||||
c.drawBitmap(b, 0, 0, null);
|
|
||||||
b.recycle();
|
|
||||||
return b2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void filter() {
|
|
||||||
final float[] m = satMatrix.getArray();
|
|
||||||
|
|
||||||
for (int i=0; i < mInPixels.length; i++) {
|
|
||||||
float r = (float)(mInPixels[i] & 0xff);
|
|
||||||
float g = (float)((mInPixels[i] >> 8) & 0xff);
|
|
||||||
float b = (float)((mInPixels[i] >> 16) & 0xff);
|
|
||||||
|
|
||||||
float tr = r * m[0] + g * m[3] + b * m[6];
|
|
||||||
float tg = r * m[1] + g * m[4] + b * m[7];
|
|
||||||
float tb = r * m[2] + g * m[5] + b * m[8];
|
|
||||||
r = tr;
|
|
||||||
g = tg;
|
|
||||||
b = tb;
|
|
||||||
|
|
||||||
if (r < 0.f) r = 0.f;
|
|
||||||
if (r > 255.f) r = 255.f;
|
|
||||||
if (g < 0.f) g = 0.f;
|
|
||||||
if (g > 255.f) g = 255.f;
|
|
||||||
if (b < 0.f) b = 0.f;
|
|
||||||
if (b > 255.f) b = 255.f;
|
|
||||||
|
|
||||||
r = (r - mInBlack) * mOverInWMinInB;
|
|
||||||
g = (g - mInBlack) * mOverInWMinInB;
|
|
||||||
b = (b - mInBlack) * mOverInWMinInB;
|
|
||||||
|
|
||||||
if (mGamma != 1.0f) {
|
|
||||||
r = (float)java.lang.Math.pow(r, mGamma);
|
|
||||||
g = (float)java.lang.Math.pow(g, mGamma);
|
|
||||||
b = (float)java.lang.Math.pow(b, mGamma);
|
|
||||||
}
|
|
||||||
|
|
||||||
r = (r * mOutWMinOutB) + mOutBlack;
|
|
||||||
g = (g * mOutWMinOutB) + mOutBlack;
|
|
||||||
b = (b * mOutWMinOutB) + mOutBlack;
|
|
||||||
|
|
||||||
if (r < 0.f) r = 0.f;
|
|
||||||
if (r > 255.f) r = 255.f;
|
|
||||||
if (g < 0.f) g = 0.f;
|
|
||||||
if (g > 255.f) g = 255.f;
|
|
||||||
if (b < 0.f) b = 0.f;
|
|
||||||
if (b > 255.f) b = 255.f;
|
|
||||||
|
|
||||||
mOutPixels[i] = ((int)r) + (((int)g) << 8) + (((int)b) << 16)
|
|
||||||
+ (mInPixels[i] & 0xff000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
mBitmapOut.setPixels(mOutPixels, 0, mBitmapOut.getWidth(), 0, 0,
|
|
||||||
mBitmapOut.getWidth(), mBitmapOut.getHeight());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void benchmark(View v) {
|
|
||||||
filter();
|
|
||||||
long t = java.lang.System.currentTimeMillis();
|
|
||||||
filter();
|
|
||||||
t = java.lang.System.currentTimeMillis() - t;
|
|
||||||
mDisplayView.invalidate();
|
|
||||||
mBenchmarkResult.setText("Result: " + t + " ms");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2012 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.rs.levels;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.graphics.SurfaceTexture;
|
|
||||||
import android.view.Surface;
|
|
||||||
import android.renderscript.Allocation;
|
|
||||||
import android.renderscript.Matrix3f;
|
|
||||||
import android.renderscript.RenderScript;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.TextureView;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.SeekBar;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
public class LevelsRSActivity extends Activity
|
|
||||||
implements SeekBar.OnSeekBarChangeListener,
|
|
||||||
TextureView.SurfaceTextureListener
|
|
||||||
{
|
|
||||||
private final String TAG = "Img";
|
|
||||||
private Bitmap mBitmapIn;
|
|
||||||
private float mInBlack = 0.0f;
|
|
||||||
private SeekBar mInBlackSeekBar;
|
|
||||||
private float mOutBlack = 0.0f;
|
|
||||||
private SeekBar mOutBlackSeekBar;
|
|
||||||
private float mInWhite = 255.0f;
|
|
||||||
private SeekBar mInWhiteSeekBar;
|
|
||||||
private float mOutWhite = 255.0f;
|
|
||||||
private SeekBar mOutWhiteSeekBar;
|
|
||||||
private float mGamma = 1.0f;
|
|
||||||
private SeekBar mGammaSeekBar;
|
|
||||||
private float mSaturation = 1.0f;
|
|
||||||
private SeekBar mSaturationSeekBar;
|
|
||||||
private TextView mBenchmarkResult;
|
|
||||||
private TextureView mDisplayView;
|
|
||||||
|
|
||||||
Matrix3f satMatrix = new Matrix3f();
|
|
||||||
float mInWMinInB;
|
|
||||||
float mOutWMinOutB;
|
|
||||||
float mOverInWMinInB;
|
|
||||||
|
|
||||||
private RenderScript mRS;
|
|
||||||
private Allocation mInPixelsAllocation;
|
|
||||||
private Allocation mOutPixelsAllocation;
|
|
||||||
private ScriptC_levels mScript;
|
|
||||||
|
|
||||||
private void setLevels() {
|
|
||||||
mInWMinInB = mInWhite - mInBlack;
|
|
||||||
mOutWMinOutB = mOutWhite - mOutBlack;
|
|
||||||
mOverInWMinInB = 1.f / mInWMinInB;
|
|
||||||
|
|
||||||
mScript.set_inBlack(mInBlack);
|
|
||||||
mScript.set_outBlack(mOutBlack);
|
|
||||||
mScript.set_inWMinInB(mInWMinInB);
|
|
||||||
mScript.set_outWMinOutB(mOutWMinOutB);
|
|
||||||
mScript.set_overInWMinInB(mOverInWMinInB);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setSaturation() {
|
|
||||||
float rWeight = 0.299f;
|
|
||||||
float gWeight = 0.587f;
|
|
||||||
float bWeight = 0.114f;
|
|
||||||
float oneMinusS = 1.0f - mSaturation;
|
|
||||||
|
|
||||||
satMatrix.set(0, 0, oneMinusS * rWeight + mSaturation);
|
|
||||||
satMatrix.set(0, 1, oneMinusS * rWeight);
|
|
||||||
satMatrix.set(0, 2, oneMinusS * rWeight);
|
|
||||||
satMatrix.set(1, 0, oneMinusS * gWeight);
|
|
||||||
satMatrix.set(1, 1, oneMinusS * gWeight + mSaturation);
|
|
||||||
satMatrix.set(1, 2, oneMinusS * gWeight);
|
|
||||||
satMatrix.set(2, 0, oneMinusS * bWeight);
|
|
||||||
satMatrix.set(2, 1, oneMinusS * bWeight);
|
|
||||||
satMatrix.set(2, 2, oneMinusS * bWeight + mSaturation);
|
|
||||||
mScript.set_colorMat(satMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
|
||||||
if (fromUser) {
|
|
||||||
if (seekBar == mInBlackSeekBar) {
|
|
||||||
mInBlack = (float)progress;
|
|
||||||
setLevels();
|
|
||||||
} else if (seekBar == mOutBlackSeekBar) {
|
|
||||||
mOutBlack = (float)progress;
|
|
||||||
setLevels();
|
|
||||||
} else if (seekBar == mInWhiteSeekBar) {
|
|
||||||
mInWhite = (float)progress + 127.0f;
|
|
||||||
setLevels();
|
|
||||||
} else if (seekBar == mOutWhiteSeekBar) {
|
|
||||||
mOutWhite = (float)progress + 127.0f;
|
|
||||||
setLevels();
|
|
||||||
} else if (seekBar == mGammaSeekBar) {
|
|
||||||
mGamma = (float)progress/100.0f;
|
|
||||||
mGamma = Math.max(mGamma, 0.1f);
|
|
||||||
mGamma = 1.0f / mGamma;
|
|
||||||
mScript.set_gamma(mGamma);
|
|
||||||
} else if (seekBar == mSaturationSeekBar) {
|
|
||||||
mSaturation = (float)progress / 50.0f;
|
|
||||||
setSaturation();
|
|
||||||
}
|
|
||||||
|
|
||||||
filter();
|
|
||||||
mDisplayView.invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.rs);
|
|
||||||
|
|
||||||
mBitmapIn = loadBitmap(R.drawable.city);
|
|
||||||
mDisplayView = (TextureView) findViewById(R.id.display);
|
|
||||||
|
|
||||||
mInBlackSeekBar = (SeekBar)findViewById(R.id.inBlack);
|
|
||||||
mInBlackSeekBar.setOnSeekBarChangeListener(this);
|
|
||||||
mInBlackSeekBar.setMax(128);
|
|
||||||
mInBlackSeekBar.setProgress(0);
|
|
||||||
mOutBlackSeekBar = (SeekBar)findViewById(R.id.outBlack);
|
|
||||||
mOutBlackSeekBar.setOnSeekBarChangeListener(this);
|
|
||||||
mOutBlackSeekBar.setMax(128);
|
|
||||||
mOutBlackSeekBar.setProgress(0);
|
|
||||||
|
|
||||||
mInWhiteSeekBar = (SeekBar)findViewById(R.id.inWhite);
|
|
||||||
mInWhiteSeekBar.setOnSeekBarChangeListener(this);
|
|
||||||
mInWhiteSeekBar.setMax(128);
|
|
||||||
mInWhiteSeekBar.setProgress(128);
|
|
||||||
mOutWhiteSeekBar = (SeekBar)findViewById(R.id.outWhite);
|
|
||||||
mOutWhiteSeekBar.setOnSeekBarChangeListener(this);
|
|
||||||
mOutWhiteSeekBar.setMax(128);
|
|
||||||
mOutWhiteSeekBar.setProgress(128);
|
|
||||||
|
|
||||||
mGammaSeekBar = (SeekBar)findViewById(R.id.inGamma);
|
|
||||||
mGammaSeekBar.setOnSeekBarChangeListener(this);
|
|
||||||
mGammaSeekBar.setMax(150);
|
|
||||||
mGammaSeekBar.setProgress(100);
|
|
||||||
|
|
||||||
mSaturationSeekBar = (SeekBar)findViewById(R.id.inSaturation);
|
|
||||||
mSaturationSeekBar.setOnSeekBarChangeListener(this);
|
|
||||||
mSaturationSeekBar.setProgress(50);
|
|
||||||
|
|
||||||
mBenchmarkResult = (TextView) findViewById(R.id.benchmarkText);
|
|
||||||
mBenchmarkResult.setText("Result: not run");
|
|
||||||
|
|
||||||
mRS = RenderScript.create(this);
|
|
||||||
mInPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapIn,
|
|
||||||
Allocation.MipmapControl.MIPMAP_NONE,
|
|
||||||
Allocation.USAGE_SCRIPT);
|
|
||||||
mOutPixelsAllocation = Allocation.createTyped(mRS, mInPixelsAllocation.getType(),
|
|
||||||
Allocation.USAGE_SCRIPT |
|
|
||||||
Allocation.USAGE_IO_OUTPUT);
|
|
||||||
mDisplayView.setSurfaceTextureListener(this);
|
|
||||||
|
|
||||||
mScript = new ScriptC_levels(mRS);
|
|
||||||
mScript.set_gamma(mGamma);
|
|
||||||
|
|
||||||
setSaturation();
|
|
||||||
setLevels();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Bitmap loadBitmap(int resource) {
|
|
||||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
|
||||||
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
|
||||||
Bitmap b = BitmapFactory.decodeResource(getResources(), resource, options);
|
|
||||||
Bitmap b2 = Bitmap.createBitmap(b.getWidth(), b.getHeight(), b.getConfig());
|
|
||||||
Canvas c = new Canvas(b2);
|
|
||||||
c.drawBitmap(b, 0, 0, null);
|
|
||||||
b.recycle();
|
|
||||||
return b2;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void filter() {
|
|
||||||
mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
|
|
||||||
mOutPixelsAllocation.ioSend();
|
|
||||||
mRS.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void benchmark(View v) {
|
|
||||||
filter();
|
|
||||||
long t = java.lang.System.currentTimeMillis();
|
|
||||||
filter();
|
|
||||||
t = java.lang.System.currentTimeMillis() - t;
|
|
||||||
mDisplayView.invalidate();
|
|
||||||
mBenchmarkResult.setText("Result: " + t + " ms");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
|
|
||||||
if (surface != null) {
|
|
||||||
mOutPixelsAllocation.setSurface(new Surface(surface));
|
|
||||||
}
|
|
||||||
filter();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
|
|
||||||
if (surface != null) {
|
|
||||||
mOutPixelsAllocation.setSurface(new Surface(surface));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
|
|
||||||
mOutPixelsAllocation.setSurface(null);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2012 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma version(1)
|
|
||||||
#pragma rs java_package_name(com.android.rs.levels)
|
|
||||||
|
|
||||||
float inBlack;
|
|
||||||
float outBlack;
|
|
||||||
float inWMinInB;
|
|
||||||
float outWMinOutB;
|
|
||||||
float overInWMinInB;
|
|
||||||
float gamma;
|
|
||||||
rs_matrix3x3 colorMat;
|
|
||||||
|
|
||||||
void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
|
|
||||||
float3 pixel = convert_float4(in[0]).rgb;
|
|
||||||
pixel = rsMatrixMultiply(&colorMat, pixel);
|
|
||||||
pixel = clamp(pixel, 0.f, 255.f);
|
|
||||||
pixel = (pixel - inBlack) * overInWMinInB;
|
|
||||||
if (gamma != 1.0f)
|
|
||||||
pixel = pow(pixel, (float3)gamma);
|
|
||||||
pixel = pixel * outWMinOutB + outBlack;
|
|
||||||
pixel = clamp(pixel, 0.f, 255.f);
|
|
||||||
out->xyz = convert_uchar3(pixel);
|
|
||||||
out->w = 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<p>A set of samples that demonstrate how to use various features of the Renderscript APIs.</p>
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?><!--
|
|
||||||
Copyright 2014 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="com.example.android.basicrenderscript"
|
|
||||||
android:versionCode="1"
|
|
||||||
android:versionName="1.0">
|
|
||||||
|
|
||||||
<!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
|
|
||||||
|
|
||||||
<application
|
|
||||||
android:allowBackup="true"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:icon="@drawable/ic_launcher"
|
|
||||||
android:theme="@style/AppTheme">
|
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name=".MainActivity"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:theme="@style/FullscreenTheme">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
</application>
|
|
||||||
|
|
||||||
|
|
||||||
</manifest>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
|
|
||||||
page.tags="BasicRenderScript"
|
|
||||||
sample.group=RenderScript
|
|
||||||
@jd:body
|
|
||||||
|
|
||||||
<p>
|
|
||||||
|
|
||||||
This sample demonstrates using RenderScript to perform basic image manipulation. Specifically, it allows users
|
|
||||||
to dynamically adjust the saturation for an image using a slider. A custom RenderScript kernel performs the saturation
|
|
||||||
adjustment, running the computation on the device\'s GPU or other compute hardware as deemed appropriate by the system.
|
|
||||||
|
|
||||||
</p>
|
|
||||||
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 196 B |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 11 KiB |
@@ -1,22 +0,0 @@
|
|||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="#0099cc"
|
|
||||||
tools:context=".MainActivity">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/imageView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:scaleType="fitCenter"
|
|
||||||
android:src="@drawable/data" />
|
|
||||||
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/seekBar1"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:layout_marginBottom="16dp" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!-- Semantic definitions -->
|
|
||||||
|
|
||||||
<dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
|
|
||||||
<dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<style name="Widget.SampleMessage">
|
|
||||||
<item name="android:textAppearance">?android:textAppearanceLarge</item>
|
|
||||||
<item name="android:lineSpacingMultiplier">1.2</item>
|
|
||||||
<item name="android:shadowDy">-6.5</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Base application theme for API 11+. This theme completely replaces
|
|
||||||
AppBaseTheme from res/values/styles.xml on API 11+ devices.
|
|
||||||
-->
|
|
||||||
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
|
|
||||||
<!-- API 11 theme customizations can go here. -->
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="FullscreenTheme" parent="android:Theme.Holo">
|
|
||||||
<item name="android:actionBarStyle">@style/FullscreenActionBarStyle</item>
|
|
||||||
<item name="android:windowActionBarOverlay">true</item>
|
|
||||||
<item name="android:windowBackground">@null</item>
|
|
||||||
<item name="buttonBarStyle">?android:attr/buttonBarStyle</item>
|
|
||||||
<item name="buttonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="FullscreenActionBarStyle" parent="android:Widget.Holo.ActionBar">
|
|
||||||
<item name="android:background">@color/black_overlay</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!-- Activity themes -->
|
|
||||||
<style name="Theme.Base" parent="android:Theme.Holo.Light" />
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<resources>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Base application theme for API 14+. This theme completely replaces
|
|
||||||
AppBaseTheme from BOTH res/values/styles.xml and
|
|
||||||
res/values-v11/styles.xml on API 14+ devices.
|
|
||||||
-->
|
|
||||||
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
|
|
||||||
<!-- API 14 theme customizations can go here. -->
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!-- Activity themes -->
|
|
||||||
<style name="Theme.Base" parent="android:Theme.Material.Light">
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
<string name="app_name">BasicRenderScript</string>
|
|
||||||
<string name="intro_message">
|
|
||||||
<![CDATA[
|
|
||||||
|
|
||||||
|
|
||||||
This sample demonstrates using RenderScript to perform basic image manipulation. Specifically, it allows users
|
|
||||||
to dynamically adjust the saturation for an image using a slider. A custom RenderScript kernel performs the saturation
|
|
||||||
adjustment, running the computation on the device\'s GPU or other compute hardware as deemed appropriate by the system.
|
|
||||||
|
|
||||||
|
|
||||||
]]>
|
|
||||||
</string>
|
|
||||||
</resources>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<resources>
|
|
||||||
|
|
||||||
<color name="black_overlay">#66000000</color>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
|
|
||||||
<style name="FullscreenTheme" parent="android:Theme.NoTitleBar">
|
|
||||||
<item name="android:windowContentOverlay">@null</item>
|
|
||||||
<item name="android:windowBackground">@null</item>
|
|
||||||
<item name="buttonBarStyle">@style/ButtonBar</item>
|
|
||||||
<item name="buttonBarButtonStyle">@style/ButtonBarButton</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="ButtonBar">
|
|
||||||
<item name="android:paddingLeft">2dp</item>
|
|
||||||
<item name="android:paddingTop">5dp</item>
|
|
||||||
<item name="android:paddingRight">2dp</item>
|
|
||||||
<item name="android:paddingBottom">0dp</item>
|
|
||||||
<item name="android:background">@android:drawable/bottom_bar</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="ButtonBarButton" />
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
|
|
||||||
|
|
||||||
<dimen name="margin_tiny">4dp</dimen>
|
|
||||||
<dimen name="margin_small">8dp</dimen>
|
|
||||||
<dimen name="margin_medium">16dp</dimen>
|
|
||||||
<dimen name="margin_large">32dp</dimen>
|
|
||||||
<dimen name="margin_huge">64dp</dimen>
|
|
||||||
|
|
||||||
<!-- Semantic definitions -->
|
|
||||||
|
|
||||||
<dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
|
|
||||||
<dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!-- Activity themes -->
|
|
||||||
|
|
||||||
<style name="Theme.Base" parent="android:Theme.Light" />
|
|
||||||
|
|
||||||
<style name="Theme.Sample" parent="Theme.Base" />
|
|
||||||
|
|
||||||
<style name="AppTheme" parent="Theme.Sample" />
|
|
||||||
<!-- Widget styling -->
|
|
||||||
|
|
||||||
<style name="Widget" />
|
|
||||||
|
|
||||||
<style name="Widget.SampleMessage">
|
|
||||||
<item name="android:textAppearance">?android:textAppearanceMedium</item>
|
|
||||||
<item name="android:lineSpacingMultiplier">1.1</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="Widget.SampleMessageTile">
|
|
||||||
<item name="android:background">@drawable/tile</item>
|
|
||||||
<item name="android:shadowColor">#7F000000</item>
|
|
||||||
<item name="android:shadowDy">-3.5</item>
|
|
||||||
<item name="android:shadowRadius">2</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.example.android.basicrenderscript;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.SeekBar;
|
|
||||||
import android.widget.SeekBar.OnSeekBarChangeListener;
|
|
||||||
import android.support.v8.renderscript.*;
|
|
||||||
|
|
||||||
public class MainActivity extends Activity {
|
|
||||||
/* Number of bitmaps that is used for renderScript thread and UI thread synchronization.
|
|
||||||
Ideally, this can be reduced to 2, however in some devices, 2 buffers still showing tierings on UI.
|
|
||||||
Investigating a root cause.
|
|
||||||
*/
|
|
||||||
private final int NUM_BITMAPS = 3;
|
|
||||||
private int mCurrentBitmap = 0;
|
|
||||||
private Bitmap mBitmapIn;
|
|
||||||
private Bitmap[] mBitmapsOut;
|
|
||||||
private ImageView mImageView;
|
|
||||||
|
|
||||||
private RenderScript mRS;
|
|
||||||
private Allocation mInAllocation;
|
|
||||||
private Allocation[] mOutAllocations;
|
|
||||||
private ScriptC_saturation mScript;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
setContentView(R.layout.main_layout);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize UI
|
|
||||||
*/
|
|
||||||
mBitmapIn = loadBitmap(R.drawable.data);
|
|
||||||
mBitmapsOut = new Bitmap[NUM_BITMAPS];
|
|
||||||
for (int i = 0; i < NUM_BITMAPS; ++i) {
|
|
||||||
mBitmapsOut[i] = Bitmap.createBitmap(mBitmapIn.getWidth(),
|
|
||||||
mBitmapIn.getHeight(), mBitmapIn.getConfig());
|
|
||||||
}
|
|
||||||
|
|
||||||
mImageView = (ImageView) findViewById(R.id.imageView);
|
|
||||||
mImageView.setImageBitmap(mBitmapsOut[mCurrentBitmap]);
|
|
||||||
mCurrentBitmap += (mCurrentBitmap + 1) % NUM_BITMAPS;
|
|
||||||
|
|
||||||
SeekBar seekbar = (SeekBar) findViewById(R.id.seekBar1);
|
|
||||||
seekbar.setProgress(50);
|
|
||||||
seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
|
|
||||||
public void onProgressChanged(SeekBar seekBar, int progress,
|
|
||||||
boolean fromUser) {
|
|
||||||
float max = 2.0f;
|
|
||||||
float min = 0.0f;
|
|
||||||
float f = (float) ((max - min) * (progress / 100.0) + min);
|
|
||||||
updateImage(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create renderScript
|
|
||||||
*/
|
|
||||||
createScript();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Invoke renderScript kernel and update imageView
|
|
||||||
*/
|
|
||||||
updateImage(1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize RenderScript
|
|
||||||
* In the sample, it creates RenderScript kernel that performs saturation manipulation.
|
|
||||||
*/
|
|
||||||
private void createScript() {
|
|
||||||
//Initialize RS
|
|
||||||
mRS = RenderScript.create(this);
|
|
||||||
|
|
||||||
//Allocate buffers
|
|
||||||
mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn);
|
|
||||||
mOutAllocations = new Allocation[NUM_BITMAPS];
|
|
||||||
for (int i = 0; i < NUM_BITMAPS; ++i) {
|
|
||||||
mOutAllocations[i] = Allocation.createFromBitmap(mRS, mBitmapsOut[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Load script
|
|
||||||
mScript = new ScriptC_saturation(mRS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* In the AsyncTask, it invokes RenderScript intrinsics to do a filtering.
|
|
||||||
* After the filtering is done, an operation blocks at Allication.copyTo() in AsyncTask thread.
|
|
||||||
* Once all operation is finished at onPostExecute() in UI thread, it can invalidate and update ImageView UI.
|
|
||||||
*/
|
|
||||||
private class RenderScriptTask extends AsyncTask<Float, Integer, Integer> {
|
|
||||||
Boolean issued = false;
|
|
||||||
|
|
||||||
protected Integer doInBackground(Float... values) {
|
|
||||||
int index = -1;
|
|
||||||
if (isCancelled() == false) {
|
|
||||||
issued = true;
|
|
||||||
index = mCurrentBitmap;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set global variable in RS
|
|
||||||
*/
|
|
||||||
mScript.set_saturationValue(values[0]);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Invoke saturation filter kernel
|
|
||||||
*/
|
|
||||||
mScript.forEach_saturation(mInAllocation, mOutAllocations[index]);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copy to bitmap and invalidate image view
|
|
||||||
*/
|
|
||||||
mOutAllocations[index].copyTo(mBitmapsOut[index]);
|
|
||||||
mCurrentBitmap = (mCurrentBitmap + 1) % NUM_BITMAPS;
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateView(Integer result) {
|
|
||||||
if (result != -1) {
|
|
||||||
// Request UI update
|
|
||||||
mImageView.setImageBitmap(mBitmapsOut[result]);
|
|
||||||
mImageView.invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onPostExecute(Integer result) {
|
|
||||||
updateView(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onCancelled(Integer result) {
|
|
||||||
if (issued) {
|
|
||||||
updateView(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderScriptTask currentTask = null;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Invoke AsynchTask and cancel previous task.
|
|
||||||
When AsyncTasks are piled up (typically in slow device with heavy kernel),
|
|
||||||
Only the latest (and already started) task invokes RenderScript operation.
|
|
||||||
*/
|
|
||||||
private void updateImage(final float f) {
|
|
||||||
if (currentTask != null)
|
|
||||||
currentTask.cancel(false);
|
|
||||||
currentTask = new RenderScriptTask();
|
|
||||||
currentTask.execute(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Helper to load Bitmap from resource
|
|
||||||
*/
|
|
||||||
private Bitmap loadBitmap(int resource) {
|
|
||||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
|
||||||
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
|
||||||
return BitmapFactory.decodeResource(getResources(), resource, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2013 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.example.android.common.media;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.hardware.Camera;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Environment;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Camera related utilities.
|
|
||||||
*/
|
|
||||||
public class CameraHelper {
|
|
||||||
|
|
||||||
public static final int MEDIA_TYPE_IMAGE = 1;
|
|
||||||
public static final int MEDIA_TYPE_VIDEO = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterate over supported camera video sizes to see which one best fits the
|
|
||||||
* dimensions of the given view while maintaining the aspect ratio. If none can,
|
|
||||||
* be lenient with the aspect ratio.
|
|
||||||
*
|
|
||||||
* @param supportedVideoSizes Supported camera video sizes.
|
|
||||||
* @param previewSizes Supported camera preview sizes.
|
|
||||||
* @param w The width of the view.
|
|
||||||
* @param h The height of the view.
|
|
||||||
* @return Best match camera video size to fit in the view.
|
|
||||||
*/
|
|
||||||
public static Camera.Size getOptimalVideoSize(List<Camera.Size> supportedVideoSizes,
|
|
||||||
List<Camera.Size> previewSizes, int w, int h) {
|
|
||||||
// Use a very small tolerance because we want an exact match.
|
|
||||||
final double ASPECT_TOLERANCE = 0.1;
|
|
||||||
double targetRatio = (double) w / h;
|
|
||||||
|
|
||||||
// Supported video sizes list might be null, it means that we are allowed to use the preview
|
|
||||||
// sizes
|
|
||||||
List<Camera.Size> videoSizes;
|
|
||||||
if (supportedVideoSizes != null) {
|
|
||||||
videoSizes = supportedVideoSizes;
|
|
||||||
} else {
|
|
||||||
videoSizes = previewSizes;
|
|
||||||
}
|
|
||||||
Camera.Size optimalSize = null;
|
|
||||||
|
|
||||||
// Start with max value and refine as we iterate over available video sizes. This is the
|
|
||||||
// minimum difference between view and camera height.
|
|
||||||
double minDiff = Double.MAX_VALUE;
|
|
||||||
|
|
||||||
// Target view height
|
|
||||||
int targetHeight = h;
|
|
||||||
|
|
||||||
// Try to find a video size that matches aspect ratio and the target view size.
|
|
||||||
// Iterate over all available sizes and pick the largest size that can fit in the view and
|
|
||||||
// still maintain the aspect ratio.
|
|
||||||
for (Camera.Size size : videoSizes) {
|
|
||||||
double ratio = (double) size.width / size.height;
|
|
||||||
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
|
|
||||||
continue;
|
|
||||||
if (Math.abs(size.height - targetHeight) < minDiff && previewSizes.contains(size)) {
|
|
||||||
optimalSize = size;
|
|
||||||
minDiff = Math.abs(size.height - targetHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cannot find video size that matches the aspect ratio, ignore the requirement
|
|
||||||
if (optimalSize == null) {
|
|
||||||
minDiff = Double.MAX_VALUE;
|
|
||||||
for (Camera.Size size : videoSizes) {
|
|
||||||
if (Math.abs(size.height - targetHeight) < minDiff && previewSizes.contains(size)) {
|
|
||||||
optimalSize = size;
|
|
||||||
minDiff = Math.abs(size.height - targetHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return optimalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the default camera on the device. Return null if there is no camera on the device.
|
|
||||||
*/
|
|
||||||
public static Camera getDefaultCameraInstance() {
|
|
||||||
return Camera.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the default rear/back facing camera on the device. Returns null if camera is not
|
|
||||||
* available.
|
|
||||||
*/
|
|
||||||
public static Camera getDefaultBackFacingCameraInstance() {
|
|
||||||
return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the default front facing camera on the device. Returns null if camera is not
|
|
||||||
* available.
|
|
||||||
*/
|
|
||||||
public static Camera getDefaultFrontFacingCameraInstance() {
|
|
||||||
return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_FRONT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param position Physical position of the camera i.e Camera.CameraInfo.CAMERA_FACING_FRONT
|
|
||||||
* or Camera.CameraInfo.CAMERA_FACING_BACK.
|
|
||||||
* @return the default camera on the device. Returns null if camera is not available.
|
|
||||||
*/
|
|
||||||
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
|
|
||||||
private static Camera getDefaultCamera(int position) {
|
|
||||||
// Find the total number of cameras available
|
|
||||||
int mNumberOfCameras = Camera.getNumberOfCameras();
|
|
||||||
|
|
||||||
// Find the ID of the back-facing ("default") camera
|
|
||||||
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
|
|
||||||
for (int i = 0; i < mNumberOfCameras; i++) {
|
|
||||||
Camera.getCameraInfo(i, cameraInfo);
|
|
||||||
if (cameraInfo.facing == position) {
|
|
||||||
return Camera.open(i);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a media file in the {@code Environment.DIRECTORY_PICTURES} directory. The directory
|
|
||||||
* is persistent and available to other applications like gallery.
|
|
||||||
*
|
|
||||||
* @param type Media type. Can be video or image.
|
|
||||||
* @return A file object pointing to the newly created file.
|
|
||||||
*/
|
|
||||||
public static File getOutputMediaFile(int type){
|
|
||||||
// To be safe, you should check that the SDCard is mounted
|
|
||||||
// using Environment.getExternalStorageState() before doing this.
|
|
||||||
if (!Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
|
|
||||||
Environment.DIRECTORY_PICTURES), "CameraSample");
|
|
||||||
// This location works best if you want the created images to be shared
|
|
||||||
// between applications and persist after your app has been uninstalled.
|
|
||||||
|
|
||||||
// Create the storage directory if it does not exist
|
|
||||||
if (! mediaStorageDir.exists()){
|
|
||||||
if (! mediaStorageDir.mkdirs()) {
|
|
||||||
Log.d("CameraSample", "failed to create directory");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a media file name
|
|
||||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
|
||||||
File mediaFile;
|
|
||||||
if (type == MEDIA_TYPE_IMAGE){
|
|
||||||
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
|
|
||||||
"IMG_"+ timeStamp + ".jpg");
|
|
||||||
} else if(type == MEDIA_TYPE_VIDEO) {
|
|
||||||
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
|
|
||||||
"VID_"+ timeStamp + ".mp4");
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mediaFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,387 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2013 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.example.android.common.media;
|
|
||||||
|
|
||||||
import android.media.*;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.view.Surface;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.Queue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simplifies the MediaCodec interface by wrapping around the buffer processing operations.
|
|
||||||
*/
|
|
||||||
public class MediaCodecWrapper {
|
|
||||||
|
|
||||||
// Handler to use for {@code OutputSampleListener} and {code OutputFormatChangedListener}
|
|
||||||
// callbacks
|
|
||||||
private Handler mHandler;
|
|
||||||
|
|
||||||
|
|
||||||
// Callback when media output format changes.
|
|
||||||
public interface OutputFormatChangedListener {
|
|
||||||
void outputFormatChanged(MediaCodecWrapper sender, MediaFormat newFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
private OutputFormatChangedListener mOutputFormatChangedListener = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for decodes frames. Observers can register a listener for optional stream
|
|
||||||
* of decoded data
|
|
||||||
*/
|
|
||||||
public interface OutputSampleListener {
|
|
||||||
void outputSample(MediaCodecWrapper sender, MediaCodec.BufferInfo info, ByteBuffer buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The {@link MediaCodec} that is managed by this class.
|
|
||||||
*/
|
|
||||||
private MediaCodec mDecoder;
|
|
||||||
|
|
||||||
// References to the internal buffers managed by the codec. The codec
|
|
||||||
// refers to these buffers by index, never by reference so it's up to us
|
|
||||||
// to keep track of which buffer is which.
|
|
||||||
private ByteBuffer[] mInputBuffers;
|
|
||||||
private ByteBuffer[] mOutputBuffers;
|
|
||||||
|
|
||||||
// Indices of the input buffers that are currently available for writing. We'll
|
|
||||||
// consume these in the order they were dequeued from the codec.
|
|
||||||
private Queue<Integer> mAvailableInputBuffers;
|
|
||||||
|
|
||||||
// Indices of the output buffers that currently hold valid data, in the order
|
|
||||||
// they were produced by the codec.
|
|
||||||
private Queue<Integer> mAvailableOutputBuffers;
|
|
||||||
|
|
||||||
// Information about each output buffer, by index. Each entry in this array
|
|
||||||
// is valid if and only if its index is currently contained in mAvailableOutputBuffers.
|
|
||||||
private MediaCodec.BufferInfo[] mOutputBufferInfo;
|
|
||||||
|
|
||||||
// An (optional) stream that will receive decoded data.
|
|
||||||
private OutputSampleListener mOutputSampleListener;
|
|
||||||
|
|
||||||
private MediaCodecWrapper(MediaCodec codec) {
|
|
||||||
mDecoder = codec;
|
|
||||||
codec.start();
|
|
||||||
mInputBuffers = codec.getInputBuffers();
|
|
||||||
mOutputBuffers = codec.getOutputBuffers();
|
|
||||||
mOutputBufferInfo = new MediaCodec.BufferInfo[mOutputBuffers.length];
|
|
||||||
mAvailableInputBuffers = new ArrayDeque<Integer>(mOutputBuffers.length);
|
|
||||||
mAvailableOutputBuffers = new ArrayDeque<Integer>(mInputBuffers.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Releases resources and ends the encoding/decoding session.
|
|
||||||
*/
|
|
||||||
public void stopAndRelease() {
|
|
||||||
mDecoder.stop();
|
|
||||||
mDecoder.release();
|
|
||||||
mDecoder = null;
|
|
||||||
mHandler = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getter for the registered {@link OutputFormatChangedListener}
|
|
||||||
*/
|
|
||||||
public OutputFormatChangedListener getOutputFormatChangedListener() {
|
|
||||||
return mOutputFormatChangedListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param outputFormatChangedListener the listener for callback.
|
|
||||||
* @param handler message handler for posting the callback.
|
|
||||||
*/
|
|
||||||
public void setOutputFormatChangedListener(final OutputFormatChangedListener
|
|
||||||
outputFormatChangedListener, Handler handler) {
|
|
||||||
mOutputFormatChangedListener = outputFormatChangedListener;
|
|
||||||
|
|
||||||
// Making sure we don't block ourselves due to a bad implementation of the callback by
|
|
||||||
// using a handler provided by client.
|
|
||||||
Looper looper;
|
|
||||||
mHandler = handler;
|
|
||||||
if (outputFormatChangedListener != null && mHandler == null) {
|
|
||||||
if ((looper = Looper.myLooper()) != null) {
|
|
||||||
mHandler = new Handler();
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Looper doesn't exist in the calling thread");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs the {@link MediaCodecWrapper} wrapper object around the video codec.
|
|
||||||
* The codec is created using the encapsulated information in the
|
|
||||||
* {@link MediaFormat} object.
|
|
||||||
*
|
|
||||||
* @param trackFormat The format of the media object to be decoded.
|
|
||||||
* @param surface Surface to render the decoded frames.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static MediaCodecWrapper fromVideoFormat(final MediaFormat trackFormat,
|
|
||||||
Surface surface) throws IOException {
|
|
||||||
MediaCodecWrapper result = null;
|
|
||||||
MediaCodec videoCodec = null;
|
|
||||||
|
|
||||||
// BEGIN_INCLUDE(create_codec)
|
|
||||||
final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
|
|
||||||
|
|
||||||
// Check to see if this is actually a video mime type. If it is, then create
|
|
||||||
// a codec that can decode this mime type.
|
|
||||||
if (mimeType.contains("video/")) {
|
|
||||||
videoCodec = MediaCodec.createDecoderByType(mimeType);
|
|
||||||
videoCodec.configure(trackFormat, surface, null, 0);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// If codec creation was successful, then create a wrapper object around the
|
|
||||||
// newly created codec.
|
|
||||||
if (videoCodec != null) {
|
|
||||||
result = new MediaCodecWrapper(videoCodec);
|
|
||||||
}
|
|
||||||
// END_INCLUDE(create_codec)
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a media sample to the decoder.
|
|
||||||
*
|
|
||||||
* A "sample" here refers to a single atomic access unit in the media stream. The definition
|
|
||||||
* of "access unit" is dependent on the type of encoding used, but it typically refers to
|
|
||||||
* a single frame of video or a few seconds of audio. {@link android.media.MediaExtractor}
|
|
||||||
* extracts data from a stream one sample at a time.
|
|
||||||
*
|
|
||||||
* @param input A ByteBuffer containing the input data for one sample. The buffer must be set
|
|
||||||
* up for reading, with its position set to the beginning of the sample data and its limit
|
|
||||||
* set to the end of the sample data.
|
|
||||||
*
|
|
||||||
* @param presentationTimeUs The time, relative to the beginning of the media stream,
|
|
||||||
* at which this buffer should be rendered.
|
|
||||||
*
|
|
||||||
* @param flags Flags to pass to the decoder. See {@link MediaCodec#queueInputBuffer(int,
|
|
||||||
* int, int, long, int)}
|
|
||||||
*
|
|
||||||
* @throws MediaCodec.CryptoException
|
|
||||||
*/
|
|
||||||
public boolean writeSample(final ByteBuffer input,
|
|
||||||
final MediaCodec.CryptoInfo crypto,
|
|
||||||
final long presentationTimeUs,
|
|
||||||
final int flags) throws MediaCodec.CryptoException, WriteException {
|
|
||||||
boolean result = false;
|
|
||||||
int size = input.remaining();
|
|
||||||
|
|
||||||
// check if we have dequed input buffers available from the codec
|
|
||||||
if (size > 0 && !mAvailableInputBuffers.isEmpty()) {
|
|
||||||
int index = mAvailableInputBuffers.remove();
|
|
||||||
ByteBuffer buffer = mInputBuffers[index];
|
|
||||||
|
|
||||||
// we can't write our sample to a lesser capacity input buffer.
|
|
||||||
if (size > buffer.capacity()) {
|
|
||||||
throw new MediaCodecWrapper.WriteException(String.format(
|
|
||||||
"Insufficient capacity in MediaCodec buffer: "
|
|
||||||
+ "tried to write %d, buffer capacity is %d.",
|
|
||||||
input.remaining(),
|
|
||||||
buffer.capacity()));
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.clear();
|
|
||||||
buffer.put(input);
|
|
||||||
|
|
||||||
// Submit the buffer to the codec for decoding. The presentationTimeUs
|
|
||||||
// indicates the position (play time) for the current sample.
|
|
||||||
if (crypto == null) {
|
|
||||||
mDecoder.queueInputBuffer(index, 0, size, presentationTimeUs, flags);
|
|
||||||
} else {
|
|
||||||
mDecoder.queueSecureInputBuffer(index, 0, crypto, presentationTimeUs, flags);
|
|
||||||
}
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MediaCodec.CryptoInfo cryptoInfo= new MediaCodec.CryptoInfo();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a media sample to the decoder.
|
|
||||||
*
|
|
||||||
* A "sample" here refers to a single atomic access unit in the media stream. The definition
|
|
||||||
* of "access unit" is dependent on the type of encoding used, but it typically refers to
|
|
||||||
* a single frame of video or a few seconds of audio. {@link android.media.MediaExtractor}
|
|
||||||
* extracts data from a stream one sample at a time.
|
|
||||||
*
|
|
||||||
* @param extractor Instance of {@link android.media.MediaExtractor} wrapping the media.
|
|
||||||
*
|
|
||||||
* @param presentationTimeUs The time, relative to the beginning of the media stream,
|
|
||||||
* at which this buffer should be rendered.
|
|
||||||
*
|
|
||||||
* @param flags Flags to pass to the decoder. See {@link MediaCodec#queueInputBuffer(int,
|
|
||||||
* int, int, long, int)}
|
|
||||||
*
|
|
||||||
* @throws MediaCodec.CryptoException
|
|
||||||
*/
|
|
||||||
public boolean writeSample(final MediaExtractor extractor,
|
|
||||||
final boolean isSecure,
|
|
||||||
final long presentationTimeUs,
|
|
||||||
int flags) {
|
|
||||||
boolean result = false;
|
|
||||||
boolean isEos = false;
|
|
||||||
|
|
||||||
if (!mAvailableInputBuffers.isEmpty()) {
|
|
||||||
int index = mAvailableInputBuffers.remove();
|
|
||||||
ByteBuffer buffer = mInputBuffers[index];
|
|
||||||
|
|
||||||
// reads the sample from the file using extractor into the buffer
|
|
||||||
int size = extractor.readSampleData(buffer, 0);
|
|
||||||
if (size <= 0) {
|
|
||||||
flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Submit the buffer to the codec for decoding. The presentationTimeUs
|
|
||||||
// indicates the position (play time) for the current sample.
|
|
||||||
if (!isSecure) {
|
|
||||||
mDecoder.queueInputBuffer(index, 0, size, presentationTimeUs, flags);
|
|
||||||
} else {
|
|
||||||
extractor.getSampleCryptoInfo(cryptoInfo);
|
|
||||||
mDecoder.queueSecureInputBuffer(index, 0, cryptoInfo, presentationTimeUs, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a peek() operation in the queue to extract media info for the buffer ready to be
|
|
||||||
* released i.e. the head element of the queue.
|
|
||||||
*
|
|
||||||
* @param out_bufferInfo An output var to hold the buffer info.
|
|
||||||
*
|
|
||||||
* @return True, if the peek was successful.
|
|
||||||
*/
|
|
||||||
public boolean peekSample(MediaCodec.BufferInfo out_bufferInfo) {
|
|
||||||
// dequeue available buffers and synchronize our data structures with the codec.
|
|
||||||
update();
|
|
||||||
boolean result = false;
|
|
||||||
if (!mAvailableOutputBuffers.isEmpty()) {
|
|
||||||
int index = mAvailableOutputBuffers.peek();
|
|
||||||
MediaCodec.BufferInfo info = mOutputBufferInfo[index];
|
|
||||||
// metadata of the sample
|
|
||||||
out_bufferInfo.set(
|
|
||||||
info.offset,
|
|
||||||
info.size,
|
|
||||||
info.presentationTimeUs,
|
|
||||||
info.flags);
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes, releases and optionally renders the output buffer available at the head of the
|
|
||||||
* queue. All observers are notified with a callback. See {@link
|
|
||||||
* OutputSampleListener#outputSample(MediaCodecWrapper, android.media.MediaCodec.BufferInfo,
|
|
||||||
* java.nio.ByteBuffer)}
|
|
||||||
*
|
|
||||||
* @param render True, if the buffer is to be rendered on the {@link Surface} configured
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void popSample(boolean render) {
|
|
||||||
// dequeue available buffers and synchronize our data structures with the codec.
|
|
||||||
update();
|
|
||||||
if (!mAvailableOutputBuffers.isEmpty()) {
|
|
||||||
int index = mAvailableOutputBuffers.remove();
|
|
||||||
|
|
||||||
if (render && mOutputSampleListener != null) {
|
|
||||||
ByteBuffer buffer = mOutputBuffers[index];
|
|
||||||
MediaCodec.BufferInfo info = mOutputBufferInfo[index];
|
|
||||||
mOutputSampleListener.outputSample(this, info, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// releases the buffer back to the codec
|
|
||||||
mDecoder.releaseOutputBuffer(index, render);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Synchronize this object's state with the internal state of the wrapped
|
|
||||||
* MediaCodec.
|
|
||||||
*/
|
|
||||||
private void update() {
|
|
||||||
// BEGIN_INCLUDE(update_codec_state)
|
|
||||||
int index;
|
|
||||||
|
|
||||||
// Get valid input buffers from the codec to fill later in the same order they were
|
|
||||||
// made available by the codec.
|
|
||||||
while ((index = mDecoder.dequeueInputBuffer(0)) != MediaCodec.INFO_TRY_AGAIN_LATER) {
|
|
||||||
mAvailableInputBuffers.add(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Likewise with output buffers. If the output buffers have changed, start using the
|
|
||||||
// new set of output buffers. If the output format has changed, notify listeners.
|
|
||||||
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
|
|
||||||
while ((index = mDecoder.dequeueOutputBuffer(info, 0)) != MediaCodec.INFO_TRY_AGAIN_LATER) {
|
|
||||||
switch (index) {
|
|
||||||
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
|
|
||||||
mOutputBuffers = mDecoder.getOutputBuffers();
|
|
||||||
mOutputBufferInfo = new MediaCodec.BufferInfo[mOutputBuffers.length];
|
|
||||||
mAvailableOutputBuffers.clear();
|
|
||||||
break;
|
|
||||||
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
|
|
||||||
if (mOutputFormatChangedListener != null) {
|
|
||||||
mHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mOutputFormatChangedListener
|
|
||||||
.outputFormatChanged(MediaCodecWrapper.this,
|
|
||||||
mDecoder.getOutputFormat());
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Making sure the index is valid before adding to output buffers. We've already
|
|
||||||
// handled INFO_TRY_AGAIN_LATER, INFO_OUTPUT_FORMAT_CHANGED &
|
|
||||||
// INFO_OUTPUT_BUFFERS_CHANGED i.e all the other possible return codes but
|
|
||||||
// asserting index value anyways for future-proofing the code.
|
|
||||||
if(index >= 0) {
|
|
||||||
mOutputBufferInfo[index] = info;
|
|
||||||
mAvailableOutputBuffers.add(index);
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Unknown status from dequeueOutputBuffer");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
// END_INCLUDE(update_codec_state)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private class WriteException extends Throwable {
|
|
||||||
private WriteException(final String detailMessage) {
|
|
||||||
super(detailMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma version(1)
|
|
||||||
#pragma rs java_package_name(com.example.android.basicrenderscript)
|
|
||||||
#pragma rs_fp_relaxed
|
|
||||||
|
|
||||||
const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
|
|
||||||
|
|
||||||
float saturationValue = 0.f;
|
|
||||||
|
|
||||||
/*
|
|
||||||
RenderScript kernel that performs saturation manipulation.
|
|
||||||
*/
|
|
||||||
uchar4 __attribute__((kernel)) saturation(uchar4 in)
|
|
||||||
{
|
|
||||||
float4 f4 = rsUnpackColor8888(in);
|
|
||||||
float3 result = dot(f4.rgb, gMonoMult);
|
|
||||||
result = mix( result, f4.rgb, saturationValue );
|
|
||||||
|
|
||||||
return rsPackColorTo8888(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright 2014 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
<manifest
|
|
||||||
package="com.example.android.hdrviewfinder"
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:versionCode="1"
|
|
||||||
android:versionName="1.0">
|
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.camera"/>
|
|
||||||
<uses-feature
|
|
||||||
android:name="android.hardware.camera.front"
|
|
||||||
android:required="false"/>
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.CAMERA"/>
|
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
|
||||||
|
|
||||||
<application
|
|
||||||
android:allowBackup="true"
|
|
||||||
android:icon="@drawable/ic_launcher"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:theme="@style/AppTheme">
|
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name=".HdrViewfinderActivity"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:screenOrientation="landscape"
|
|
||||||
android:theme="@style/Theme.AppCompat.Light">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
</application>
|
|
||||||
|
|
||||||
|
|
||||||
</manifest>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
|
|
||||||
page.tags="HdrViewfinder"
|
|
||||||
sample.group=Media
|
|
||||||
@jd:body
|
|
||||||
|
|
||||||
<p>
|
|
||||||
|
|
||||||
This demo implements a real-time high-dynamic-range camera viewfinder, by alternating
|
|
||||||
the sensor\'s exposure time between two exposure values on even and odd frames, and then
|
|
||||||
compositing together the latest two frames whenever a new frame is captured.
|
|
||||||
|
|
||||||
</p>
|
|
||||||
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 196 B |
|
Before Width: | Height: | Size: 665 B |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 11 KiB |
@@ -1,100 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright (C) 2014 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
<LinearLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:custom="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:id="@+id/panels"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
tools:context="com.example.android.hdrviewfinder.HdrViewfinderActivity">
|
|
||||||
|
|
||||||
<com.example.android.hdrviewfinder.FixedAspectSurfaceView
|
|
||||||
android:id="@+id/preview"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:layout_weight="4"
|
|
||||||
custom:aspectRatio="1.333"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/control_bar_contents"
|
|
||||||
android:layout_width="0px"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_margin="5dp">
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/help_button"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/help_button"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/mode_label"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="16sp"
|
|
||||||
tools:text="MODE: HDR"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/auto_exposure_label"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/auto_exposure_label"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/auto_exposure"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textSize="20sp"
|
|
||||||
tools:text="33.33 ms"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/even_exposure_label"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/even_exposure_label"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/even_exposure"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textSize="20sp"
|
|
||||||
tools:text="30.30 ms"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/odd_exposure_label"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/odd_exposure_label"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/odd_exposure"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textSize="20sp"
|
|
||||||
tools:text="30.30 ms"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/info"
|
|
||||||
android:icon="@drawable/ic_action_info"
|
|
||||||
android:showAsAction="always"
|
|
||||||
android:title="@string/info"/>
|
|
||||||
|
|
||||||
</menu>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!-- Semantic definitions -->
|
|
||||||
|
|
||||||
<dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
|
|
||||||
<dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<style name="Widget.SampleMessage">
|
|
||||||
<item name="android:textAppearance">?android:textAppearanceLarge</item>
|
|
||||||
<item name="android:lineSpacingMultiplier">1.2</item>
|
|
||||||
<item name="android:shadowDy">-6.5</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!-- Activity themes -->
|
|
||||||
<style name="Theme.Base" parent="android:Theme.Holo.Light" />
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!-- Activity themes -->
|
|
||||||
<style name="Theme.Base" parent="android:Theme.Material.Light">
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright (C) 2014 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
<resources>
|
|
||||||
<declare-styleable name="FixedAspectSurfaceView">
|
|
||||||
<attr name="aspectRatio" format="float"/>
|
|
||||||
</declare-styleable>
|
|
||||||
</resources>
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
<string name="app_name">HdrViewfinder</string>
|
|
||||||
<string name="intro_message">
|
|
||||||
<![CDATA[
|
|
||||||
|
|
||||||
|
|
||||||
This demo implements a real-time high-dynamic-range camera viewfinder, by alternating
|
|
||||||
the sensor\'s exposure time between two exposure values on even and odd frames, and then
|
|
||||||
compositing together the latest two frames whenever a new frame is captured.
|
|
||||||
|
|
||||||
|
|
||||||
]]>
|
|
||||||
</string>
|
|
||||||
</resources>
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Copyright (C) 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<string name="help_button">Help</string>
|
|
||||||
|
|
||||||
<string-array name="mode_label_array">
|
|
||||||
<!-- must be in same order as ViewfinderProcessor.MODE_ ints -->
|
|
||||||
<item>Mode: Normal</item>
|
|
||||||
<item>Mode: Split</item>
|
|
||||||
<item>Mode: HDR</item>
|
|
||||||
</string-array>
|
|
||||||
|
|
||||||
<string name="auto_exposure_label">Auto exp. time:</string>
|
|
||||||
<string name="even_exposure_label">Even exp. time:</string>
|
|
||||||
<string name="odd_exposure_label">Odd exp. time:</string>
|
|
||||||
|
|
||||||
<string name="help_text">
|
|
||||||
<b>HDR Viewfinder Demo:</b>\n\n
|
|
||||||
|
|
||||||
Tap viewfinder to switch modes.\n\n
|
|
||||||
|
|
||||||
<b>Normal:</b> Standard camera preview\n
|
|
||||||
<b>Split:</b> Manual exposure control\n
|
|
||||||
<b>HDR:</b> Fused HDR viewfinder\n\n
|
|
||||||
|
|
||||||
Swipe up/down in Split/HDR modes to change manual exposure
|
|
||||||
values.\n\n
|
|
||||||
|
|
||||||
The left half of the viewfinder controls exposure time for
|
|
||||||
even-numbered frames, and the right half of the viewfinder
|
|
||||||
controls exposure time for odd-numbered frames
|
|
||||||
</string>
|
|
||||||
|
|
||||||
<string name="info">Info</string>
|
|
||||||
|
|
||||||
<string name="camera_permission_rationale">This sample app requires camera access in order to
|
|
||||||
demo the API.</string>
|
|
||||||
<string name="camera_no_good">No back-facing sufficiently capable camera available!</string>
|
|
||||||
<string name="camera_disabled">Camera is disabled by device policy</string>
|
|
||||||
<string name="camera_disconnected">Camera was disconnected before it was opened</string>
|
|
||||||
<string name="camera_error">Camera service reported an error</string>
|
|
||||||
<string name="camera_unknown">Unknown camera error: %s</string>
|
|
||||||
<string name="camera_permission_denied_explanation">You\'ve denied a permission that the app
|
|
||||||
needs for core functionality. If you selected "don\'t ask again" in the past then
|
|
||||||
you need to use Settings to re-enable the permission.</string>
|
|
||||||
|
|
||||||
<string name="ok">OK</string>
|
|
||||||
<string name="settings">Settings</string>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
|
|
||||||
|
|
||||||
<dimen name="margin_tiny">4dp</dimen>
|
|
||||||
<dimen name="margin_small">8dp</dimen>
|
|
||||||
<dimen name="margin_medium">16dp</dimen>
|
|
||||||
<dimen name="margin_large">32dp</dimen>
|
|
||||||
<dimen name="margin_huge">64dp</dimen>
|
|
||||||
|
|
||||||
<!-- Semantic definitions -->
|
|
||||||
|
|
||||||
<dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
|
|
||||||
<dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<!--
|
|
||||||
Copyright 2013 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!-- Activity themes -->
|
|
||||||
|
|
||||||
<style name="Theme.Base" parent="android:Theme.Light" />
|
|
||||||
|
|
||||||
<style name="Theme.Sample" parent="Theme.Base" />
|
|
||||||
|
|
||||||
<style name="AppTheme" parent="Theme.Sample" />
|
|
||||||
<!-- Widget styling -->
|
|
||||||
|
|
||||||
<style name="Widget" />
|
|
||||||
|
|
||||||
<style name="Widget.SampleMessage">
|
|
||||||
<item name="android:textAppearance">?android:textAppearanceMedium</item>
|
|
||||||
<item name="android:lineSpacingMultiplier">1.1</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="Widget.SampleMessageTile">
|
|
||||||
<item name="android:background">@drawable/tile</item>
|
|
||||||
<item name="android:shadowColor">#7F000000</item>
|
|
||||||
<item name="android:shadowDy">-3.5</item>
|
|
||||||
<item name="android:shadowRadius">2</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -1,284 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.example.android.hdrviewfinder;
|
|
||||||
|
|
||||||
import android.hardware.camera2.CameraAccessException;
|
|
||||||
import android.hardware.camera2.CameraCaptureSession;
|
|
||||||
import android.hardware.camera2.CameraDevice;
|
|
||||||
import android.hardware.camera2.CameraManager;
|
|
||||||
import android.hardware.camera2.CaptureRequest;
|
|
||||||
import android.os.ConditionVariable;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.HandlerThread;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.Surface;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple interface for operating the camera, with major camera operations
|
|
||||||
* all performed on a background handler thread.
|
|
||||||
*/
|
|
||||||
public class CameraOps {
|
|
||||||
|
|
||||||
private static final String TAG = "CameraOps";
|
|
||||||
|
|
||||||
public static final long CAMERA_CLOSE_TIMEOUT = 2000; // ms
|
|
||||||
|
|
||||||
private final CameraManager mCameraManager;
|
|
||||||
private CameraDevice mCameraDevice;
|
|
||||||
private CameraCaptureSession mCameraSession;
|
|
||||||
private List<Surface> mSurfaces;
|
|
||||||
|
|
||||||
private final ConditionVariable mCloseWaiter = new ConditionVariable();
|
|
||||||
|
|
||||||
private HandlerThread mCameraThread;
|
|
||||||
private Handler mCameraHandler;
|
|
||||||
|
|
||||||
private final ErrorDisplayer mErrorDisplayer;
|
|
||||||
|
|
||||||
private final CameraReadyListener mReadyListener;
|
|
||||||
private final Handler mReadyHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new camera ops thread.
|
|
||||||
*
|
|
||||||
* @param errorDisplayer listener for displaying error messages
|
|
||||||
* @param readyListener listener for notifying when camera is ready for requests
|
|
||||||
* @param readyHandler the handler for calling readyListener methods on
|
|
||||||
*/
|
|
||||||
CameraOps(CameraManager manager, ErrorDisplayer errorDisplayer,
|
|
||||||
CameraReadyListener readyListener, Handler readyHandler) {
|
|
||||||
mCameraThread = new HandlerThread("CameraOpsThread");
|
|
||||||
mCameraThread.start();
|
|
||||||
|
|
||||||
if (manager == null || errorDisplayer == null ||
|
|
||||||
readyListener == null || readyHandler == null) {
|
|
||||||
throw new IllegalArgumentException("Need valid displayer, listener, handler");
|
|
||||||
}
|
|
||||||
|
|
||||||
mCameraManager = manager;
|
|
||||||
mErrorDisplayer = errorDisplayer;
|
|
||||||
mReadyListener = readyListener;
|
|
||||||
mReadyHandler = readyHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open the first back-facing camera listed by the camera manager.
|
|
||||||
* Displays a dialog if it cannot open a camera.
|
|
||||||
*/
|
|
||||||
public void openCamera(final String cameraId) {
|
|
||||||
mCameraHandler = new Handler(mCameraThread.getLooper());
|
|
||||||
|
|
||||||
mCameraHandler.post(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
if (mCameraDevice != null) {
|
|
||||||
throw new IllegalStateException("Camera already open");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
mCameraManager.openCamera(cameraId, mCameraDeviceListener, mCameraHandler);
|
|
||||||
} catch (CameraAccessException e) {
|
|
||||||
String errorMessage = mErrorDisplayer.getErrorString(e);
|
|
||||||
mErrorDisplayer.showErrorDialog(errorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the camera and wait for the close callback to be called in the camera thread.
|
|
||||||
* Times out after @{value CAMERA_CLOSE_TIMEOUT} ms.
|
|
||||||
*/
|
|
||||||
public void closeCameraAndWait() {
|
|
||||||
mCloseWaiter.close();
|
|
||||||
mCameraHandler.post(mCloseCameraRunnable);
|
|
||||||
boolean closed = mCloseWaiter.block(CAMERA_CLOSE_TIMEOUT);
|
|
||||||
if (!closed) {
|
|
||||||
Log.e(TAG, "Timeout closing camera");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Runnable mCloseCameraRunnable = new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
if (mCameraDevice != null) {
|
|
||||||
mCameraDevice.close();
|
|
||||||
}
|
|
||||||
mCameraDevice = null;
|
|
||||||
mCameraSession = null;
|
|
||||||
mSurfaces = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the output Surfaces, and finish configuration if otherwise ready.
|
|
||||||
*/
|
|
||||||
public void setSurfaces(final List<Surface> surfaces) {
|
|
||||||
mCameraHandler.post(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
mSurfaces = surfaces;
|
|
||||||
startCameraSession();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a request builder for the current camera.
|
|
||||||
*/
|
|
||||||
public CaptureRequest.Builder createCaptureRequest(int template) throws CameraAccessException {
|
|
||||||
CameraDevice device = mCameraDevice;
|
|
||||||
if (device == null) {
|
|
||||||
throw new IllegalStateException("Can't get requests when no camera is open");
|
|
||||||
}
|
|
||||||
return device.createCaptureRequest(template);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a repeating request.
|
|
||||||
*/
|
|
||||||
public void setRepeatingRequest(final CaptureRequest request,
|
|
||||||
final CameraCaptureSession.CaptureCallback listener,
|
|
||||||
final Handler handler) {
|
|
||||||
mCameraHandler.post(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
mCameraSession.setRepeatingRequest(request, listener, handler);
|
|
||||||
} catch (CameraAccessException e) {
|
|
||||||
String errorMessage = mErrorDisplayer.getErrorString(e);
|
|
||||||
mErrorDisplayer.showErrorDialog(errorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a repeating request.
|
|
||||||
*/
|
|
||||||
public void setRepeatingBurst(final List<CaptureRequest> requests,
|
|
||||||
final CameraCaptureSession.CaptureCallback listener,
|
|
||||||
final Handler handler) {
|
|
||||||
mCameraHandler.post(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
mCameraSession.setRepeatingBurst(requests, listener, handler);
|
|
||||||
} catch (CameraAccessException e) {
|
|
||||||
String errorMessage = mErrorDisplayer.getErrorString(e);
|
|
||||||
mErrorDisplayer.showErrorDialog(errorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure the camera session.
|
|
||||||
*/
|
|
||||||
private void startCameraSession() {
|
|
||||||
// Wait until both the camera device is open and the SurfaceView is ready
|
|
||||||
if (mCameraDevice == null || mSurfaces == null) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
mCameraDevice.createCaptureSession(
|
|
||||||
mSurfaces, mCameraSessionListener, mCameraHandler);
|
|
||||||
} catch (CameraAccessException e) {
|
|
||||||
String errorMessage = mErrorDisplayer.getErrorString(e);
|
|
||||||
mErrorDisplayer.showErrorDialog(errorMessage);
|
|
||||||
mCameraDevice.close();
|
|
||||||
mCameraDevice = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main listener for camera session events
|
|
||||||
* Invoked on mCameraThread
|
|
||||||
*/
|
|
||||||
private CameraCaptureSession.StateCallback mCameraSessionListener =
|
|
||||||
new CameraCaptureSession.StateCallback() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConfigured(CameraCaptureSession session) {
|
|
||||||
mCameraSession = session;
|
|
||||||
mReadyHandler.post(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
// This can happen when the screen is turned off and turned back on.
|
|
||||||
if (null == mCameraDevice) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mReadyListener.onCameraReady();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConfigureFailed(CameraCaptureSession session) {
|
|
||||||
mErrorDisplayer.showErrorDialog("Unable to configure the capture session");
|
|
||||||
mCameraDevice.close();
|
|
||||||
mCameraDevice = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main listener for camera device events.
|
|
||||||
* Invoked on mCameraThread
|
|
||||||
*/
|
|
||||||
private CameraDevice.StateCallback mCameraDeviceListener = new CameraDevice.StateCallback() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onOpened(CameraDevice camera) {
|
|
||||||
mCameraDevice = camera;
|
|
||||||
startCameraSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClosed(CameraDevice camera) {
|
|
||||||
mCloseWaiter.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisconnected(CameraDevice camera) {
|
|
||||||
mErrorDisplayer.showErrorDialog("The camera device has been disconnected.");
|
|
||||||
camera.close();
|
|
||||||
mCameraDevice = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(CameraDevice camera, int error) {
|
|
||||||
mErrorDisplayer.showErrorDialog("The camera encountered an error:" + error);
|
|
||||||
camera.close();
|
|
||||||
mCameraDevice = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple listener for main code to know the camera is ready for requests, or failed to
|
|
||||||
* start.
|
|
||||||
*/
|
|
||||||
public interface CameraReadyListener {
|
|
||||||
public void onCameraReady();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple listener for displaying error messages
|
|
||||||
*/
|
|
||||||
public interface ErrorDisplayer {
|
|
||||||
public void showErrorDialog(String errorMessage);
|
|
||||||
|
|
||||||
public String getErrorString(CameraAccessException e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.example.android.hdrviewfinder;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.TypedArray;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.GestureDetector;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.SurfaceView;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup.LayoutParams;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A SurfaceView that maintains its aspect ratio to be a desired target value.
|
|
||||||
*
|
|
||||||
* <p>Depending on the layout, the FixedAspectSurfaceView may not be able to maintain the
|
|
||||||
* requested aspect ratio. This can happen if both the width and the height are exactly
|
|
||||||
* determined by the layout. To avoid this, ensure that either the height or the width is
|
|
||||||
* adjustable by the view; for example, by setting the layout parameters to be WRAP_CONTENT for
|
|
||||||
* the dimension that is best adjusted to maintain the aspect ratio.</p>
|
|
||||||
*/
|
|
||||||
public class FixedAspectSurfaceView extends SurfaceView {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Desired width/height ratio
|
|
||||||
*/
|
|
||||||
private float mAspectRatio;
|
|
||||||
|
|
||||||
private GestureDetector mGestureDetector;
|
|
||||||
|
|
||||||
public FixedAspectSurfaceView(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
|
|
||||||
// Get initial aspect ratio from custom attributes
|
|
||||||
TypedArray a =
|
|
||||||
context.getTheme().obtainStyledAttributes(attrs,
|
|
||||||
R.styleable.FixedAspectSurfaceView, 0, 0);
|
|
||||||
setAspectRatio(a.getFloat(
|
|
||||||
R.styleable.FixedAspectSurfaceView_aspectRatio, 1.f));
|
|
||||||
a.recycle();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the desired aspect ratio for this view.
|
|
||||||
*
|
|
||||||
* @param aspect the desired width/height ratio in the current UI orientation. Must be a
|
|
||||||
* positive value.
|
|
||||||
*/
|
|
||||||
public void setAspectRatio(float aspect) {
|
|
||||||
if (aspect <= 0) {
|
|
||||||
throw new IllegalArgumentException("Aspect ratio must be positive");
|
|
||||||
}
|
|
||||||
mAspectRatio = aspect;
|
|
||||||
requestLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a gesture listener to listen for touch events
|
|
||||||
*/
|
|
||||||
public void setGestureListener(Context context, GestureDetector.OnGestureListener listener) {
|
|
||||||
if (listener == null) {
|
|
||||||
mGestureDetector = null;
|
|
||||||
} else {
|
|
||||||
mGestureDetector = new GestureDetector(context, listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
||||||
|
|
||||||
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
|
||||||
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
|
||||||
int width = MeasureSpec.getSize(widthMeasureSpec);
|
|
||||||
int height = MeasureSpec.getSize(heightMeasureSpec);
|
|
||||||
|
|
||||||
// General goal: Adjust dimensions to maintain the requested aspect ratio as much
|
|
||||||
// as possible. Depending on the measure specs handed down, this may not be possible
|
|
||||||
|
|
||||||
// Only set one of these to true
|
|
||||||
boolean scaleWidth = false;
|
|
||||||
boolean scaleHeight = false;
|
|
||||||
|
|
||||||
// Sort out which dimension to scale, if either can be. There are 9 combinations of
|
|
||||||
// possible measure specs; a few cases below handle multiple combinations
|
|
||||||
if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
|
|
||||||
// Can't adjust sizes at all, do nothing
|
|
||||||
} else if (widthMode == MeasureSpec.EXACTLY) {
|
|
||||||
// Width is fixed, heightMode either AT_MOST or UNSPECIFIED, so adjust height
|
|
||||||
scaleHeight = true;
|
|
||||||
} else if (heightMode == MeasureSpec.EXACTLY) {
|
|
||||||
// Height is fixed, widthMode either AT_MOST or UNSPECIFIED, so adjust width
|
|
||||||
scaleWidth = true;
|
|
||||||
} else if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
|
|
||||||
// Need to fit into box <= [width, height] in size.
|
|
||||||
// Maximize the View's area while maintaining aspect ratio
|
|
||||||
// This means keeping one dimension as large as possible and shrinking the other
|
|
||||||
float boxAspectRatio = width / (float) height;
|
|
||||||
if (boxAspectRatio > mAspectRatio) {
|
|
||||||
// Box is wider than requested aspect; pillarbox
|
|
||||||
scaleWidth = true;
|
|
||||||
} else {
|
|
||||||
// Box is narrower than requested aspect; letterbox
|
|
||||||
scaleHeight = true;
|
|
||||||
}
|
|
||||||
} else if (widthMode == MeasureSpec.AT_MOST) {
|
|
||||||
// Maximize width, heightSpec is UNSPECIFIED
|
|
||||||
scaleHeight = true;
|
|
||||||
} else if (heightMode == MeasureSpec.AT_MOST) {
|
|
||||||
// Maximize height, widthSpec is UNSPECIFIED
|
|
||||||
scaleWidth = true;
|
|
||||||
} else {
|
|
||||||
// Both MeasureSpecs are UNSPECIFIED. This is probably a pathological layout,
|
|
||||||
// with width == height == 0
|
|
||||||
// but arbitrarily scale height anyway
|
|
||||||
scaleHeight = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do the scaling
|
|
||||||
if (scaleWidth) {
|
|
||||||
width = (int) (height * mAspectRatio);
|
|
||||||
} else if (scaleHeight) {
|
|
||||||
height = (int) (width / mAspectRatio);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override width/height if needed for EXACTLY and AT_MOST specs
|
|
||||||
width = View.resolveSizeAndState(width, widthMeasureSpec, 0);
|
|
||||||
height = View.resolveSizeAndState(height, heightMeasureSpec, 0);
|
|
||||||
|
|
||||||
// Finally set the calculated dimensions
|
|
||||||
setMeasuredDimension(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onTouchEvent(MotionEvent event) {
|
|
||||||
if (mGestureDetector != null) {
|
|
||||||
return mGestureDetector.onTouchEvent(event);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,667 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.example.android.hdrviewfinder;
|
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.hardware.camera2.CameraAccessException;
|
|
||||||
import android.hardware.camera2.CameraCaptureSession;
|
|
||||||
import android.hardware.camera2.CameraCharacteristics;
|
|
||||||
import android.hardware.camera2.CameraDevice;
|
|
||||||
import android.hardware.camera2.CameraManager;
|
|
||||||
import android.hardware.camera2.CaptureRequest;
|
|
||||||
import android.hardware.camera2.CaptureResult;
|
|
||||||
import android.hardware.camera2.TotalCaptureResult;
|
|
||||||
import android.hardware.camera2.params.StreamConfigurationMap;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.provider.Settings;
|
|
||||||
import android.renderscript.RenderScript;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.design.widget.Snackbar;
|
|
||||||
import android.support.v4.app.ActivityCompat;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.util.Size;
|
|
||||||
import android.view.GestureDetector;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.Surface;
|
|
||||||
import android.view.SurfaceHolder;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A small demo of advanced camera functionality with the Android camera2 API.
|
|
||||||
*
|
|
||||||
* <p>This demo implements a real-time high-dynamic-range camera viewfinder,
|
|
||||||
* by alternating the sensor's exposure time between two exposure values on even and odd
|
|
||||||
* frames, and then compositing together the latest two frames whenever a new frame is
|
|
||||||
* captured.</p>
|
|
||||||
*
|
|
||||||
* <p>The demo has three modes: Regular auto-exposure viewfinder, split-screen manual exposure,
|
|
||||||
* and the fused HDR viewfinder. The latter two use manual exposure controlled by the user,
|
|
||||||
* by swiping up/down on the right and left halves of the viewfinder. The left half controls
|
|
||||||
* the exposure time of even frames, and the right half controls the exposure time of odd frames.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <p>In split-screen mode, the even frames are shown on the left and the odd frames on the right,
|
|
||||||
* so the user can see two different exposures of the scene simultaneously. In fused HDR mode,
|
|
||||||
* the even/odd frames are merged together into a single image. By selecting different exposure
|
|
||||||
* values for the even/odd frames, the fused image has a higher dynamic range than the regular
|
|
||||||
* viewfinder.</p>
|
|
||||||
*
|
|
||||||
* <p>The HDR fusion and the split-screen viewfinder processing is done with RenderScript; as is the
|
|
||||||
* necessary YUV->RGB conversion. The camera subsystem outputs YUV images naturally, while the GPU
|
|
||||||
* and display subsystems generally only accept RGB data. Therefore, after the images are
|
|
||||||
* fused/composited, a standard YUV->RGB color transform is applied before the the data is written
|
|
||||||
* to the output Allocation. The HDR fusion algorithm is very simple, and tends to result in
|
|
||||||
* lower-contrast scenes, but has very few artifacts and can run very fast.</p>
|
|
||||||
*
|
|
||||||
* <p>Data is passed between the subsystems (camera, RenderScript, and display) using the
|
|
||||||
* Android {@link android.view.Surface} class, which allows for zero-copy transport of large
|
|
||||||
* buffers between processes and subsystems.</p>
|
|
||||||
*/
|
|
||||||
public class HdrViewfinderActivity extends AppCompatActivity implements
|
|
||||||
SurfaceHolder.Callback, CameraOps.ErrorDisplayer, CameraOps.CameraReadyListener {
|
|
||||||
|
|
||||||
private static final String TAG = "HdrViewfinderDemo";
|
|
||||||
|
|
||||||
private static final String FRAGMENT_DIALOG = "dialog";
|
|
||||||
|
|
||||||
private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* View for the camera preview.
|
|
||||||
*/
|
|
||||||
private FixedAspectSurfaceView mPreviewView;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Root view of this activity.
|
|
||||||
*/
|
|
||||||
private View rootView;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This shows the current mode of the app.
|
|
||||||
*/
|
|
||||||
private TextView mModeText;
|
|
||||||
|
|
||||||
// These show lengths of exposure for even frames, exposure for odd frames, and auto exposure.
|
|
||||||
private TextView mEvenExposureText, mOddExposureText, mAutoExposureText;
|
|
||||||
|
|
||||||
private Handler mUiHandler;
|
|
||||||
|
|
||||||
private CameraCharacteristics mCameraInfo;
|
|
||||||
|
|
||||||
private Surface mPreviewSurface;
|
|
||||||
private Surface mProcessingHdrSurface;
|
|
||||||
private Surface mProcessingNormalSurface;
|
|
||||||
CaptureRequest.Builder mHdrBuilder;
|
|
||||||
ArrayList<CaptureRequest> mHdrRequests = new ArrayList<CaptureRequest>(2);
|
|
||||||
|
|
||||||
CaptureRequest mPreviewRequest;
|
|
||||||
|
|
||||||
RenderScript mRS;
|
|
||||||
ViewfinderProcessor mProcessor;
|
|
||||||
CameraManager mCameraManager;
|
|
||||||
CameraOps mCameraOps;
|
|
||||||
|
|
||||||
private int mRenderMode = ViewfinderProcessor.MODE_NORMAL;
|
|
||||||
|
|
||||||
// Durations in nanoseconds
|
|
||||||
private static final long MICRO_SECOND = 1000;
|
|
||||||
private static final long MILLI_SECOND = MICRO_SECOND * 1000;
|
|
||||||
private static final long ONE_SECOND = MILLI_SECOND * 1000;
|
|
||||||
|
|
||||||
private long mOddExposure = ONE_SECOND / 33;
|
|
||||||
private long mEvenExposure = ONE_SECOND / 33;
|
|
||||||
|
|
||||||
private Object mOddExposureTag = new Object();
|
|
||||||
private Object mEvenExposureTag = new Object();
|
|
||||||
private Object mAutoExposureTag = new Object();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.main);
|
|
||||||
|
|
||||||
rootView = findViewById(R.id.panels);
|
|
||||||
|
|
||||||
mPreviewView = (FixedAspectSurfaceView) findViewById(R.id.preview);
|
|
||||||
mPreviewView.getHolder().addCallback(this);
|
|
||||||
mPreviewView.setGestureListener(this, mViewListener);
|
|
||||||
|
|
||||||
Button helpButton = (Button) findViewById(R.id.help_button);
|
|
||||||
helpButton.setOnClickListener(mHelpButtonListener);
|
|
||||||
|
|
||||||
mModeText = (TextView) findViewById(R.id.mode_label);
|
|
||||||
mEvenExposureText = (TextView) findViewById(R.id.even_exposure);
|
|
||||||
mOddExposureText = (TextView) findViewById(R.id.odd_exposure);
|
|
||||||
mAutoExposureText = (TextView) findViewById(R.id.auto_exposure);
|
|
||||||
|
|
||||||
mUiHandler = new Handler(Looper.getMainLooper());
|
|
||||||
|
|
||||||
mRS = RenderScript.create(this);
|
|
||||||
|
|
||||||
// When permissions are revoked the app is restarted so onCreate is sufficient to check for
|
|
||||||
// permissions core to the Activity's functionality.
|
|
||||||
if (!checkCameraPermissions()) {
|
|
||||||
requestCameraPermissions();
|
|
||||||
} else {
|
|
||||||
findAndOpenCamera();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
|
|
||||||
// Wait until camera is closed to ensure the next application can open it
|
|
||||||
if (mCameraOps != null) {
|
|
||||||
mCameraOps.closeCameraAndWait();
|
|
||||||
mCameraOps = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
getMenuInflater().inflate(R.menu.main, menu);
|
|
||||||
return super.onCreateOptionsMenu(menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
switch (item.getItemId()) {
|
|
||||||
case R.id.info: {
|
|
||||||
MessageDialogFragment.newInstance(R.string.intro_message)
|
|
||||||
.show(getFragmentManager(), FRAGMENT_DIALOG);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
private GestureDetector.OnGestureListener mViewListener
|
|
||||||
= new GestureDetector.SimpleOnGestureListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onDown(MotionEvent e) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onSingleTapUp(MotionEvent e) {
|
|
||||||
switchRenderMode(1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
|
||||||
if (mRenderMode == ViewfinderProcessor.MODE_NORMAL) return false;
|
|
||||||
|
|
||||||
float xPosition = e1.getAxisValue(MotionEvent.AXIS_X);
|
|
||||||
float width = mPreviewView.getWidth();
|
|
||||||
float height = mPreviewView.getHeight();
|
|
||||||
|
|
||||||
float xPosNorm = xPosition / width;
|
|
||||||
float yDistNorm = distanceY / height;
|
|
||||||
|
|
||||||
final float ACCELERATION_FACTOR = 8;
|
|
||||||
double scaleFactor = Math.pow(2.f, yDistNorm * ACCELERATION_FACTOR);
|
|
||||||
|
|
||||||
// Even on left, odd on right
|
|
||||||
if (xPosNorm > 0.5) {
|
|
||||||
mOddExposure *= scaleFactor;
|
|
||||||
} else {
|
|
||||||
mEvenExposure *= scaleFactor;
|
|
||||||
}
|
|
||||||
|
|
||||||
setHdrBurst();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show help dialogs.
|
|
||||||
*/
|
|
||||||
private View.OnClickListener mHelpButtonListener = new View.OnClickListener() {
|
|
||||||
public void onClick(View v) {
|
|
||||||
MessageDialogFragment.newInstance(R.string.help_text)
|
|
||||||
.show(getFragmentManager(), FRAGMENT_DIALOG);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the current state of the camera permissions.
|
|
||||||
*/
|
|
||||||
private boolean checkCameraPermissions() {
|
|
||||||
int permissionState = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
|
|
||||||
|
|
||||||
// Check if the Camera permission is already available.
|
|
||||||
if (permissionState != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
// Camera permission has not been granted.
|
|
||||||
Log.i(TAG, "CAMERA permission has NOT been granted.");
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
// Camera permissions are available.
|
|
||||||
Log.i(TAG, "CAMERA permission has already been granted.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to initialize the camera.
|
|
||||||
*/
|
|
||||||
private void initializeCamera() {
|
|
||||||
mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
|
|
||||||
if (mCameraManager != null) {
|
|
||||||
mCameraOps = new CameraOps(mCameraManager,
|
|
||||||
/*errorDisplayer*/ this,
|
|
||||||
/*readyListener*/ this,
|
|
||||||
/*readyHandler*/ mUiHandler);
|
|
||||||
|
|
||||||
mHdrRequests.add(null);
|
|
||||||
mHdrRequests.add(null);
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "Couldn't initialize the camera");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void requestCameraPermissions() {
|
|
||||||
boolean shouldProvideRationale =
|
|
||||||
ActivityCompat.shouldShowRequestPermissionRationale(this,
|
|
||||||
Manifest.permission.CAMERA);
|
|
||||||
|
|
||||||
// Provide an additional rationale to the user. This would happen if the user denied the
|
|
||||||
// request previously, but didn't check the "Don't ask again" checkbox.
|
|
||||||
if (shouldProvideRationale) {
|
|
||||||
Log.i(TAG, "Displaying camera permission rationale to provide additional context.");
|
|
||||||
Snackbar.make(rootView, R.string.camera_permission_rationale, Snackbar
|
|
||||||
.LENGTH_INDEFINITE)
|
|
||||||
.setAction(R.string.ok, new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
// Request Camera permission
|
|
||||||
ActivityCompat.requestPermissions(HdrViewfinderActivity.this,
|
|
||||||
new String[]{Manifest.permission.CAMERA},
|
|
||||||
REQUEST_PERMISSIONS_REQUEST_CODE);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.show();
|
|
||||||
} else {
|
|
||||||
Log.i(TAG, "Requesting camera permission");
|
|
||||||
// Request Camera permission. It's possible this can be auto answered if device policy
|
|
||||||
// sets the permission in a given state or the user denied the permission
|
|
||||||
// previously and checked "Never ask again".
|
|
||||||
ActivityCompat.requestPermissions(HdrViewfinderActivity.this,
|
|
||||||
new String[]{Manifest.permission.CAMERA},
|
|
||||||
REQUEST_PERMISSIONS_REQUEST_CODE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback received when a permissions request has been completed.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
|
||||||
@NonNull int[] grantResults) {
|
|
||||||
Log.i(TAG, "onRequestPermissionResult");
|
|
||||||
if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
|
|
||||||
if (grantResults.length <= 0) {
|
|
||||||
// If user interaction was interrupted, the permission request is cancelled and you
|
|
||||||
// receive empty arrays.
|
|
||||||
Log.i(TAG, "User interaction was cancelled.");
|
|
||||||
} else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
|
||||||
// Permission was granted.
|
|
||||||
findAndOpenCamera();
|
|
||||||
} else {
|
|
||||||
// Permission denied.
|
|
||||||
|
|
||||||
// In this Activity we've chosen to notify the user that they
|
|
||||||
// have rejected a core permission for the app since it makes the Activity useless.
|
|
||||||
// We're communicating this message in a Snackbar since this is a sample app, but
|
|
||||||
// core permissions would typically be best requested during a welcome-screen flow.
|
|
||||||
|
|
||||||
// Additionally, it is important to remember that a permission might have been
|
|
||||||
// rejected without asking the user for permission (device policy or "Never ask
|
|
||||||
// again" prompts). Therefore, a user interface affordance is typically implemented
|
|
||||||
// when permissions are denied. Otherwise, your app could appear unresponsive to
|
|
||||||
// touches or interactions which have required permissions.
|
|
||||||
Snackbar.make(rootView, R.string.camera_permission_denied_explanation, Snackbar
|
|
||||||
.LENGTH_INDEFINITE)
|
|
||||||
.setAction(R.string.settings, new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
// Build intent that displays the App settings screen.
|
|
||||||
Intent intent = new Intent();
|
|
||||||
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
|
||||||
Uri uri = Uri.fromParts("package", BuildConfig.APPLICATION_ID, null);
|
|
||||||
intent.setData(uri);
|
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void findAndOpenCamera() {
|
|
||||||
boolean cameraPermissions = checkCameraPermissions();
|
|
||||||
if (cameraPermissions) {
|
|
||||||
String errorMessage = "Unknown error";
|
|
||||||
boolean foundCamera = false;
|
|
||||||
initializeCamera();
|
|
||||||
if (cameraPermissions && mCameraOps != null) {
|
|
||||||
try {
|
|
||||||
// Find first back-facing camera that has necessary capability.
|
|
||||||
String[] cameraIds = mCameraManager.getCameraIdList();
|
|
||||||
for (String id : cameraIds) {
|
|
||||||
CameraCharacteristics info = mCameraManager.getCameraCharacteristics(id);
|
|
||||||
int facing = info.get(CameraCharacteristics.LENS_FACING);
|
|
||||||
|
|
||||||
int level = info.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
|
|
||||||
boolean hasFullLevel
|
|
||||||
= (level
|
|
||||||
== CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
|
|
||||||
|
|
||||||
int[] capabilities = info
|
|
||||||
.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
|
|
||||||
int syncLatency = info.get(CameraCharacteristics.SYNC_MAX_LATENCY);
|
|
||||||
boolean hasManualControl = hasCapability(capabilities,
|
|
||||||
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
|
|
||||||
boolean hasEnoughCapability = hasManualControl &&
|
|
||||||
syncLatency
|
|
||||||
== CameraCharacteristics.SYNC_MAX_LATENCY_PER_FRAME_CONTROL;
|
|
||||||
|
|
||||||
// All these are guaranteed by
|
|
||||||
// CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL, but checking
|
|
||||||
// for only the things we care about expands range of devices we can run on.
|
|
||||||
// We want:
|
|
||||||
// - Back-facing camera
|
|
||||||
// - Manual sensor control
|
|
||||||
// - Per-frame synchronization (so that exposure can be changed every frame)
|
|
||||||
if (facing == CameraCharacteristics.LENS_FACING_BACK &&
|
|
||||||
(hasFullLevel || hasEnoughCapability)) {
|
|
||||||
// Found suitable camera - get info, open, and set up outputs
|
|
||||||
mCameraInfo = info;
|
|
||||||
mCameraOps.openCamera(id);
|
|
||||||
configureSurfaces();
|
|
||||||
foundCamera = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!foundCamera) {
|
|
||||||
errorMessage = getString(R.string.camera_no_good);
|
|
||||||
}
|
|
||||||
} catch (CameraAccessException e) {
|
|
||||||
errorMessage = getErrorString(e);
|
|
||||||
}
|
|
||||||
if (!foundCamera) {
|
|
||||||
showErrorDialog(errorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasCapability(int[] capabilities, int capability) {
|
|
||||||
for (int c : capabilities) {
|
|
||||||
if (c == capability) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void switchRenderMode(int direction) {
|
|
||||||
if (mCameraOps != null) {
|
|
||||||
mRenderMode = (mRenderMode + direction) % 3;
|
|
||||||
|
|
||||||
mModeText.setText(getResources().getStringArray(R.array.mode_label_array)[mRenderMode]);
|
|
||||||
|
|
||||||
if (mProcessor != null) {
|
|
||||||
mProcessor.setRenderMode(mRenderMode);
|
|
||||||
}
|
|
||||||
if (mRenderMode == ViewfinderProcessor.MODE_NORMAL) {
|
|
||||||
mCameraOps.setRepeatingRequest(mPreviewRequest,
|
|
||||||
mCaptureCallback, mUiHandler);
|
|
||||||
} else {
|
|
||||||
setHdrBurst();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure the surfaceview and RS processing.
|
|
||||||
*/
|
|
||||||
private void configureSurfaces() {
|
|
||||||
// Find a good size for output - largest 16:9 aspect ratio that's less than 720p
|
|
||||||
final int MAX_WIDTH = 1280;
|
|
||||||
final float TARGET_ASPECT = 16.f / 9.f;
|
|
||||||
final float ASPECT_TOLERANCE = 0.1f;
|
|
||||||
|
|
||||||
StreamConfigurationMap configs =
|
|
||||||
mCameraInfo.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
|
|
||||||
|
|
||||||
Size[] outputSizes = configs.getOutputSizes(SurfaceHolder.class);
|
|
||||||
|
|
||||||
Size outputSize = outputSizes[0];
|
|
||||||
float outputAspect = (float) outputSize.getWidth() / outputSize.getHeight();
|
|
||||||
for (Size candidateSize : outputSizes) {
|
|
||||||
if (candidateSize.getWidth() > MAX_WIDTH) continue;
|
|
||||||
float candidateAspect = (float) candidateSize.getWidth() / candidateSize.getHeight();
|
|
||||||
boolean goodCandidateAspect =
|
|
||||||
Math.abs(candidateAspect - TARGET_ASPECT) < ASPECT_TOLERANCE;
|
|
||||||
boolean goodOutputAspect =
|
|
||||||
Math.abs(outputAspect - TARGET_ASPECT) < ASPECT_TOLERANCE;
|
|
||||||
if ((goodCandidateAspect && !goodOutputAspect) ||
|
|
||||||
candidateSize.getWidth() > outputSize.getWidth()) {
|
|
||||||
outputSize = candidateSize;
|
|
||||||
outputAspect = candidateAspect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Log.i(TAG, "Resolution chosen: " + outputSize);
|
|
||||||
|
|
||||||
// Configure processing
|
|
||||||
mProcessor = new ViewfinderProcessor(mRS, outputSize);
|
|
||||||
setupProcessor();
|
|
||||||
|
|
||||||
// Configure the output view - this will fire surfaceChanged
|
|
||||||
mPreviewView.setAspectRatio(outputAspect);
|
|
||||||
mPreviewView.getHolder().setFixedSize(outputSize.getWidth(), outputSize.getHeight());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Once camera is open and output surfaces are ready, configure the RS processing
|
|
||||||
* and the camera device inputs/outputs.
|
|
||||||
*/
|
|
||||||
private void setupProcessor() {
|
|
||||||
if (mProcessor == null || mPreviewSurface == null) return;
|
|
||||||
|
|
||||||
mProcessor.setOutputSurface(mPreviewSurface);
|
|
||||||
mProcessingHdrSurface = mProcessor.getInputHdrSurface();
|
|
||||||
mProcessingNormalSurface = mProcessor.getInputNormalSurface();
|
|
||||||
|
|
||||||
List<Surface> cameraOutputSurfaces = new ArrayList<Surface>();
|
|
||||||
cameraOutputSurfaces.add(mProcessingHdrSurface);
|
|
||||||
cameraOutputSurfaces.add(mProcessingNormalSurface);
|
|
||||||
|
|
||||||
mCameraOps.setSurfaces(cameraOutputSurfaces);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start running an HDR burst on a configured camera session
|
|
||||||
*/
|
|
||||||
public void setHdrBurst() {
|
|
||||||
|
|
||||||
mHdrBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, 1600);
|
|
||||||
mHdrBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION, ONE_SECOND / 30);
|
|
||||||
|
|
||||||
mHdrBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, mEvenExposure);
|
|
||||||
mHdrBuilder.setTag(mEvenExposureTag);
|
|
||||||
mHdrRequests.set(0, mHdrBuilder.build());
|
|
||||||
|
|
||||||
mHdrBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, mOddExposure);
|
|
||||||
mHdrBuilder.setTag(mOddExposureTag);
|
|
||||||
mHdrRequests.set(1, mHdrBuilder.build());
|
|
||||||
|
|
||||||
mCameraOps.setRepeatingBurst(mHdrRequests, mCaptureCallback, mUiHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener for completed captures
|
|
||||||
* Invoked on UI thread
|
|
||||||
*/
|
|
||||||
private CameraCaptureSession.CaptureCallback mCaptureCallback
|
|
||||||
= new CameraCaptureSession.CaptureCallback() {
|
|
||||||
|
|
||||||
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
|
|
||||||
TotalCaptureResult result) {
|
|
||||||
|
|
||||||
// Only update UI every so many frames
|
|
||||||
// Use an odd number here to ensure both even and odd exposures get an occasional update
|
|
||||||
long frameNumber = result.getFrameNumber();
|
|
||||||
if (frameNumber % 3 != 0) return;
|
|
||||||
|
|
||||||
long exposureTime = result.get(CaptureResult.SENSOR_EXPOSURE_TIME);
|
|
||||||
|
|
||||||
// Format exposure time nicely
|
|
||||||
String exposureText;
|
|
||||||
if (exposureTime > ONE_SECOND) {
|
|
||||||
exposureText = String.format("%.2f s", exposureTime / 1e9);
|
|
||||||
} else if (exposureTime > MILLI_SECOND) {
|
|
||||||
exposureText = String.format("%.2f ms", exposureTime / 1e6);
|
|
||||||
} else if (exposureTime > MICRO_SECOND) {
|
|
||||||
exposureText = String.format("%.2f us", exposureTime / 1e3);
|
|
||||||
} else {
|
|
||||||
exposureText = String.format("%d ns", exposureTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object tag = request.getTag();
|
|
||||||
Log.i(TAG, "Exposure: " + exposureText);
|
|
||||||
|
|
||||||
if (tag == mEvenExposureTag) {
|
|
||||||
mEvenExposureText.setText(exposureText);
|
|
||||||
|
|
||||||
mEvenExposureText.setEnabled(true);
|
|
||||||
mOddExposureText.setEnabled(true);
|
|
||||||
mAutoExposureText.setEnabled(false);
|
|
||||||
} else if (tag == mOddExposureTag) {
|
|
||||||
mOddExposureText.setText(exposureText);
|
|
||||||
|
|
||||||
mEvenExposureText.setEnabled(true);
|
|
||||||
mOddExposureText.setEnabled(true);
|
|
||||||
mAutoExposureText.setEnabled(false);
|
|
||||||
} else {
|
|
||||||
mAutoExposureText.setText(exposureText);
|
|
||||||
|
|
||||||
mEvenExposureText.setEnabled(false);
|
|
||||||
mOddExposureText.setEnabled(false);
|
|
||||||
mAutoExposureText.setEnabled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callbacks for the FixedAspectSurfaceView
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
|
||||||
mPreviewSurface = holder.getSurface();
|
|
||||||
|
|
||||||
setupProcessor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
|
||||||
mPreviewSurface = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callbacks for CameraOps
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onCameraReady() {
|
|
||||||
// Ready to send requests in, so set them up
|
|
||||||
try {
|
|
||||||
CaptureRequest.Builder previewBuilder =
|
|
||||||
mCameraOps.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
|
|
||||||
previewBuilder.addTarget(mProcessingNormalSurface);
|
|
||||||
previewBuilder.setTag(mAutoExposureTag);
|
|
||||||
mPreviewRequest = previewBuilder.build();
|
|
||||||
|
|
||||||
mHdrBuilder =
|
|
||||||
mCameraOps.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
|
|
||||||
mHdrBuilder.set(CaptureRequest.CONTROL_AE_MODE,
|
|
||||||
CaptureRequest.CONTROL_AE_MODE_OFF);
|
|
||||||
mHdrBuilder.addTarget(mProcessingHdrSurface);
|
|
||||||
|
|
||||||
switchRenderMode(0);
|
|
||||||
|
|
||||||
} catch (CameraAccessException e) {
|
|
||||||
String errorMessage = getErrorString(e);
|
|
||||||
showErrorDialog(errorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility methods
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void showErrorDialog(String errorMessage) {
|
|
||||||
MessageDialogFragment.newInstance(errorMessage).show(getFragmentManager(), FRAGMENT_DIALOG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getErrorString(CameraAccessException e) {
|
|
||||||
String errorMessage;
|
|
||||||
switch (e.getReason()) {
|
|
||||||
case CameraAccessException.CAMERA_DISABLED:
|
|
||||||
errorMessage = getString(R.string.camera_disabled);
|
|
||||||
break;
|
|
||||||
case CameraAccessException.CAMERA_DISCONNECTED:
|
|
||||||
errorMessage = getString(R.string.camera_disconnected);
|
|
||||||
break;
|
|
||||||
case CameraAccessException.CAMERA_ERROR:
|
|
||||||
errorMessage = getString(R.string.camera_error);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
errorMessage = getString(R.string.camera_unknown, e.getReason());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return errorMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.example.android.hdrviewfinder;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.app.DialogFragment;
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
public class MessageDialogFragment extends DialogFragment {
|
|
||||||
|
|
||||||
private static final String ARG_MESSAGE_INT = "message_int";
|
|
||||||
private static final String ARG_MESSAGE_STRING = "message_string";
|
|
||||||
|
|
||||||
public static MessageDialogFragment newInstance(int message) {
|
|
||||||
MessageDialogFragment fragment = new MessageDialogFragment();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putInt(ARG_MESSAGE_INT, message);
|
|
||||||
fragment.setArguments(args);
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MessageDialogFragment newInstance(String message) {
|
|
||||||
MessageDialogFragment fragment = new MessageDialogFragment();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putString(ARG_MESSAGE_STRING, message);
|
|
||||||
fragment.setArguments(args);
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
|
||||||
builder.setPositiveButton(android.R.string.ok, null);
|
|
||||||
Bundle args = getArguments();
|
|
||||||
if (args.containsKey(ARG_MESSAGE_INT)) {
|
|
||||||
builder.setMessage(args.getInt(ARG_MESSAGE_INT));
|
|
||||||
} else if (args.containsKey(ARG_MESSAGE_STRING)) {
|
|
||||||
builder.setMessage(args.getString(ARG_MESSAGE_STRING));
|
|
||||||
}
|
|
||||||
return builder.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.example.android.hdrviewfinder;
|
|
||||||
|
|
||||||
import android.graphics.ImageFormat;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.HandlerThread;
|
|
||||||
import android.renderscript.Allocation;
|
|
||||||
import android.renderscript.Element;
|
|
||||||
import android.renderscript.RenderScript;
|
|
||||||
import android.renderscript.Type;
|
|
||||||
import android.util.Size;
|
|
||||||
import android.view.Surface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renderscript-based merger for an HDR viewfinder
|
|
||||||
*/
|
|
||||||
public class ViewfinderProcessor {
|
|
||||||
|
|
||||||
private Allocation mInputHdrAllocation;
|
|
||||||
private Allocation mInputNormalAllocation;
|
|
||||||
private Allocation mPrevAllocation;
|
|
||||||
private Allocation mOutputAllocation;
|
|
||||||
|
|
||||||
private Surface mOutputSurface;
|
|
||||||
private HandlerThread mProcessingThread;
|
|
||||||
private Handler mProcessingHandler;
|
|
||||||
private ScriptC_hdr_merge mHdrMergeScript;
|
|
||||||
|
|
||||||
public ProcessingTask mHdrTask;
|
|
||||||
public ProcessingTask mNormalTask;
|
|
||||||
|
|
||||||
private Size mSize;
|
|
||||||
|
|
||||||
private int mMode;
|
|
||||||
|
|
||||||
public final static int MODE_NORMAL = 0;
|
|
||||||
public final static int MODE_SIDE_BY_SIDE = 1;
|
|
||||||
public final static int MODE_HDR = 2;
|
|
||||||
|
|
||||||
public ViewfinderProcessor(RenderScript rs, Size dimensions) {
|
|
||||||
mSize = dimensions;
|
|
||||||
|
|
||||||
Type.Builder yuvTypeBuilder = new Type.Builder(rs, Element.YUV(rs));
|
|
||||||
yuvTypeBuilder.setX(dimensions.getWidth());
|
|
||||||
yuvTypeBuilder.setY(dimensions.getHeight());
|
|
||||||
yuvTypeBuilder.setYuvFormat(ImageFormat.YUV_420_888);
|
|
||||||
mInputHdrAllocation = Allocation.createTyped(rs, yuvTypeBuilder.create(),
|
|
||||||
Allocation.USAGE_IO_INPUT | Allocation.USAGE_SCRIPT);
|
|
||||||
mInputNormalAllocation = Allocation.createTyped(rs, yuvTypeBuilder.create(),
|
|
||||||
Allocation.USAGE_IO_INPUT | Allocation.USAGE_SCRIPT);
|
|
||||||
|
|
||||||
Type.Builder rgbTypeBuilder = new Type.Builder(rs, Element.RGBA_8888(rs));
|
|
||||||
rgbTypeBuilder.setX(dimensions.getWidth());
|
|
||||||
rgbTypeBuilder.setY(dimensions.getHeight());
|
|
||||||
mPrevAllocation = Allocation.createTyped(rs, rgbTypeBuilder.create(),
|
|
||||||
Allocation.USAGE_SCRIPT);
|
|
||||||
mOutputAllocation = Allocation.createTyped(rs, rgbTypeBuilder.create(),
|
|
||||||
Allocation.USAGE_IO_OUTPUT | Allocation.USAGE_SCRIPT);
|
|
||||||
|
|
||||||
mProcessingThread = new HandlerThread("ViewfinderProcessor");
|
|
||||||
mProcessingThread.start();
|
|
||||||
mProcessingHandler = new Handler(mProcessingThread.getLooper());
|
|
||||||
|
|
||||||
mHdrMergeScript = new ScriptC_hdr_merge(rs);
|
|
||||||
|
|
||||||
mHdrMergeScript.set_gPrevFrame(mPrevAllocation);
|
|
||||||
|
|
||||||
mHdrTask = new ProcessingTask(mInputHdrAllocation, dimensions.getWidth()/2, true);
|
|
||||||
mNormalTask = new ProcessingTask(mInputNormalAllocation, 0, false);
|
|
||||||
|
|
||||||
setRenderMode(MODE_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Surface getInputHdrSurface() {
|
|
||||||
return mInputHdrAllocation.getSurface();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Surface getInputNormalSurface() {
|
|
||||||
return mInputNormalAllocation.getSurface();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOutputSurface(Surface output) {
|
|
||||||
mOutputAllocation.setSurface(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRenderMode(int mode) {
|
|
||||||
mMode = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple class to keep track of incoming frame count,
|
|
||||||
* and to process the newest one in the processing thread
|
|
||||||
*/
|
|
||||||
class ProcessingTask implements Runnable, Allocation.OnBufferAvailableListener {
|
|
||||||
private int mPendingFrames = 0;
|
|
||||||
private int mFrameCounter = 0;
|
|
||||||
private int mCutPointX;
|
|
||||||
private boolean mCheckMerge;
|
|
||||||
|
|
||||||
private Allocation mInputAllocation;
|
|
||||||
|
|
||||||
public ProcessingTask(Allocation input, int cutPointX, boolean checkMerge) {
|
|
||||||
mInputAllocation = input;
|
|
||||||
mInputAllocation.setOnBufferAvailableListener(this);
|
|
||||||
mCutPointX = cutPointX;
|
|
||||||
mCheckMerge = checkMerge;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBufferAvailable(Allocation a) {
|
|
||||||
synchronized(this) {
|
|
||||||
mPendingFrames++;
|
|
||||||
mProcessingHandler.post(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
|
|
||||||
// Find out how many frames have arrived
|
|
||||||
int pendingFrames;
|
|
||||||
synchronized(this) {
|
|
||||||
pendingFrames = mPendingFrames;
|
|
||||||
mPendingFrames = 0;
|
|
||||||
|
|
||||||
// Discard extra messages in case processing is slower than frame rate
|
|
||||||
mProcessingHandler.removeCallbacks(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get to newest input
|
|
||||||
for (int i = 0; i < pendingFrames; i++) {
|
|
||||||
mInputAllocation.ioReceive();
|
|
||||||
}
|
|
||||||
|
|
||||||
mHdrMergeScript.set_gFrameCounter(mFrameCounter++);
|
|
||||||
mHdrMergeScript.set_gCurrentFrame(mInputAllocation);
|
|
||||||
mHdrMergeScript.set_gCutPointX(mCutPointX);
|
|
||||||
if (mCheckMerge && mMode == MODE_HDR) {
|
|
||||||
mHdrMergeScript.set_gDoMerge(1);
|
|
||||||
} else {
|
|
||||||
mHdrMergeScript.set_gDoMerge(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run processing pass
|
|
||||||
mHdrMergeScript.forEach_mergeHdrFrames(mPrevAllocation, mOutputAllocation);
|
|
||||||
mOutputAllocation.ioSend();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
#pragma version(1)
|
|
||||||
#pragma rs java_package_name(com.example.android.hdrviewfinder)
|
|
||||||
#pragma rs_fp_relaxed
|
|
||||||
|
|
||||||
rs_allocation gCurrentFrame;
|
|
||||||
rs_allocation gPrevFrame;
|
|
||||||
|
|
||||||
int gCutPointX = 0;
|
|
||||||
int gDoMerge = 0;
|
|
||||||
int gFrameCounter = 0;
|
|
||||||
|
|
||||||
uchar4 __attribute__((kernel)) mergeHdrFrames(uchar4 prevPixel, uint32_t x, uint32_t y) {
|
|
||||||
|
|
||||||
// Read in pixel values from latest frame - YUV color space
|
|
||||||
|
|
||||||
uchar4 curPixel;
|
|
||||||
curPixel.r = rsGetElementAtYuv_uchar_Y(gCurrentFrame, x, y);
|
|
||||||
curPixel.g = rsGetElementAtYuv_uchar_U(gCurrentFrame, x, y);
|
|
||||||
curPixel.b = rsGetElementAtYuv_uchar_V(gCurrentFrame, x, y);
|
|
||||||
curPixel.a = 255;
|
|
||||||
|
|
||||||
uchar4 mergedPixel;
|
|
||||||
if (gDoMerge == 1) {
|
|
||||||
// Complex HDR fusion technique
|
|
||||||
mergedPixel = curPixel / 2 + prevPixel / 2;
|
|
||||||
|
|
||||||
/* Experimental color saturation boosting merge
|
|
||||||
mergedPixel.r = curPixel.r / 2 + prevPixel.r / 2;
|
|
||||||
|
|
||||||
uchar saturationCurrent = abs(curPixel.g - 128) + abs(curPixel.b - 128);
|
|
||||||
uchar saturationPrev = abs(prevPixel.g - 128) + abs(prevPixel.b - 128);
|
|
||||||
mergedPixel.g = saturationCurrent > saturationPrev ? curPixel.g : prevPixel.g;
|
|
||||||
mergedPixel.b = saturationCurrent > saturationPrev ? curPixel.b : prevPixel.b;
|
|
||||||
*/
|
|
||||||
} else if (gCutPointX > 0) {
|
|
||||||
// Composite side by side
|
|
||||||
mergedPixel = ((x < gCutPointX) ^ (gFrameCounter & 0x1)) ?
|
|
||||||
curPixel : prevPixel;
|
|
||||||
} else {
|
|
||||||
// Straight passthrough
|
|
||||||
mergedPixel = curPixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert YUV to RGB, JFIF transform with fixed-point math
|
|
||||||
// R = Y + 1.402 * (V - 128)
|
|
||||||
// G = Y - 0.34414 * (U - 128) - 0.71414 * (V - 128)
|
|
||||||
// B = Y + 1.772 * (U - 128)
|
|
||||||
|
|
||||||
int4 rgb;
|
|
||||||
rgb.r = mergedPixel.r +
|
|
||||||
mergedPixel.b * 1436 / 1024 - 179;
|
|
||||||
rgb.g = mergedPixel.r -
|
|
||||||
mergedPixel.g * 46549 / 131072 + 44 -
|
|
||||||
mergedPixel.b * 93604 / 131072 + 91;
|
|
||||||
rgb.b = mergedPixel.r +
|
|
||||||
mergedPixel.g * 1814 / 1024 - 227;
|
|
||||||
rgb.a = 255;
|
|
||||||
|
|
||||||
// Store current pixel for next frame
|
|
||||||
rsSetElementAt_uchar4(gPrevFrame, curPixel, x, y);
|
|
||||||
|
|
||||||
// Write out merged HDR result
|
|
||||||
uchar4 out = convert_uchar4(clamp(rgb, 0, 255));
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||