Thursday, May 28, 2015

Using libyuv prebuilt shared library in Android

In my previous post I explained how to build libyuv shared library  now I would like to explain how to write a JNI wrapper and access the libyuv functions available.

Please go  through the above post before proceeding, as I'll be frequently referring to it.

From the post above, If you have successfully built the libyuv shared library then you should see the .so's generated at the location :-
LRD/libs/armeabi/libyuv_shared.so
LRD/libs/armeabi-v7a/libyuv_shared.so
LRD/libs/mips/libyuv_shared.so
LRD/libs/x86/libyuv_shared.so

We'll be needing the .so's, for the JNI wrapper will be accessing the functions present in it.



Create the following directory structures in your workspace:-


LibYUVDemo/prebuilt/
LibYUVDemo/include/
LibYUVDemo/jni/



Under the LibYUVDemo/prebuilt/ directoy paste the libyuv_shared.so files in the respective order :-

LibYUVDemo/prebuilt/armeabi/libyuv_shared.so
LibYUVDemo/prebuilt/armeabi-v7a/libyuv_shared.so
LibYUVDemo/prebuilt/mips/libyuv_shared.so
LibYUVDemo/prebuilt/x86/libyuv_shared.so

Copy the contents of include folder from libyuv source and paste it under
LibYUVDemo/include/ 

Now the actual JNI wrapper, create LibYUVDemo.cpp under
LibYUVDemo/jni/ and write a jni function as follows :-

#include <jni.h>
#include <string.h>
#include <stdlib.h>
#include "libyuv.h"
#include <android/log.h>

#define LOG_TAG "YUVDemo"
#define LOGI(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define printf(...) LOGI(__VA_ARGS__)

using namespace libyuv;

extern "C" {
JNIEXPORT void Java_com_demo_libyuvdemo_MainActivity_callLibYUV(JNIEnv* env, jobject thiz) {

libyuv::RotationMode mode = libyuv::kRotate180;

/*libyuv::ConvertToI420(const unsigned char *, unsigned int, unsigned char *, int, unsigned char *, int, unsigned char *, int, int, int, int, int, int, int, enum libyuv::RotationMode, unsigned int);
 */
    printf("rotation mode selected = %d",mode);
}

Create an Android.mk file under LibYUVDemo/jni/
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := yuv_shared
LOCAL_SRC_FILES := ../prebuilt/$(TARGET_ARCH_ABI)/libyuv_shared.so
ifneq (,$(wildcard $(LOCAL_PATH)/$(LOCAL_SRC_FILES)))
include $(PREBUILT_SHARED_LIBRARY)
endif


include $(CLEAR_VARS)

LOCAL_MODULE    := YUVDemo
LOCAL_SRC_FILES := LibYUVDemo.cpp
#LOCAL_SRC_FILES := LibYUVDemo.c


#
# Header Includes
#
LOCAL_C_INCLUDES := \
            $(LOCAL_PATH)/../include
#
# Compile Flags and Link Libraries
#
LOCAL_CFLAGS := -DANDROID_NDK

LOCAL_LDLIBS := -llog
LOCAL_SHARED_LIBRARIES := yuv_shared

include $(BUILD_SHARED_LIBRARY)
Finally create an Application.mk file under LibYUVDemo/jni/

APP_ABI := all
APP_PLATFORM := android-9
APP_STL := stlport_shared

Now navigate to LibYUVDemo/jni/ from command prompt and trigger ndk-build, the JNI should get compiled and you must have the new .so geneated at LibYUVDemo/libs/ for the all the architectures.


A complete working app is available at github.

Thursday, May 21, 2015

Building libyuv shared library for Android

         Recently for my project I wanted to rotate NV21 raw data obtained from device camera when the device is held in portrait mode. Sadly android does not provide any API that alters the raw data it provides through the onPreviewFrame callback, so was looking for a way to rotate the NV21 by 90 degrees and libyuv came to the rescue.

Prerequisites:-
  1. NDK setup must be done, and you must be able to compile sample ndk-apps provided in the android-ndk.
  2. Download the libyuv codebase, do an SVN checkout from here.
The directory that gets created once you do SVN checkout is the libyuv root directory, am going to refer it as LRD (LIBYUV_ROOT_DIR).
LRD contains an Android.mk file which we are going to use to build our shared library (of-course some modifications would be needed).

Once the above prerequisites have been met, then proceed with the following steps to build the shared library:-
  • Create a jni folder in LRD.
  • Copy the Android.mk file to it.
  • Create an Application.mk file and add the following lines to it. 
APP_PLATFORM := android-9
APP_ABI := all
  •  Modify the Android.mk file as below to point to the source code correctly
# This is the Android makefile for libyuv for both platform and NDK.
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_CPP_EXTENSION := .cc

LOCAL_SRC_FILES := \
    $(LOCAL_PATH)/../source/compare.cc           \
    $(LOCAL_PATH)/../source/compare_common.cc    \
    $(LOCAL_PATH)/../source/compare_neon64.cc    \
    $(LOCAL_PATH)/../source/compare_posix.cc     \
    $(LOCAL_PATH)/../source/convert.cc           \
    $(LOCAL_PATH)/../source/convert_argb.cc      \
    $(LOCAL_PATH)/../source/convert_from.cc      \
    $(LOCAL_PATH)/../source/convert_from_argb.cc \
    $(LOCAL_PATH)/../source/convert_to_argb.cc   \
    $(LOCAL_PATH)/../source/convert_to_i420.cc   \
    $(LOCAL_PATH)/../source/cpu_id.cc            \
    $(LOCAL_PATH)/../source/planar_functions.cc  \
    $(LOCAL_PATH)/../source/rotate.cc            \
    $(LOCAL_PATH)/../source/rotate_argb.cc       \
    $(LOCAL_PATH)/../source/rotate_mips.cc       \
    $(LOCAL_PATH)/../source/rotate_neon64.cc     \
    $(LOCAL_PATH)/../source/row_any.cc           \
    $(LOCAL_PATH)/../source/row_common.cc        \
    $(LOCAL_PATH)/../source/row_mips.cc          \
    $(LOCAL_PATH)/../source/row_neon64.cc        \
    $(LOCAL_PATH)/../source/row_posix.cc            \
    $(LOCAL_PATH)/../source/scale.cc             \
    $(LOCAL_PATH)/../source/scale_any.cc         \
    $(LOCAL_PATH)/../source/scale_argb.cc        \
    $(LOCAL_PATH)/../source/scale_common.cc      \
    $(LOCAL_PATH)/../source/scale_mips.cc        \
    $(LOCAL_PATH)/../source/scale_neon64.cc      \
    $(LOCAL_PATH)/../source/scale_posix.cc       \
    $(LOCAL_PATH)/../source/video_common.cc

# TODO(fbarchard): Enable mjpeg encoder.
#   source/mjpeg_decoder.cc
#   source/convert_jpeg.cc
#   source/mjpeg_validate.cc

ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
    LOCAL_CFLAGS += -DLIBYUV_NEON
    LOCAL_SRC_FILES += \
        $(LOCAL_PATH)/../source/compare_neon.cc.neon    \
        $(LOCAL_PATH)/../source/rotate_neon.cc.neon     \
        $(LOCAL_PATH)/../source/row_neon.cc.neon        \
        $(LOCAL_PATH)/../source/scale_neon.cc.neon
endif

LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../include

LOCAL_MODULE := libyuv_static
LOCAL_MODULE_TAGS := optional

include $(BUILD_STATIC_LIBRARY)
  • Open command prompt (on Windows) or Terminal in Linux or MAC, navigate to LRD/jni and type ndk-build
  • This should trigger the build process and if all goes well the libyuv_static.a (a static library) will get created inside LRD/obj/local/armeabi/
  • But we cannot use a static library with android  so we need to generate a shared library (.so),  for that simply modify the following tags as below (Android.mk file)
LOCAL_MODULE := libyuv_shared
include $(BUILD_SHARED_LIBRARY)
  • Again trigger ndk-build to generate the .so at LRD/libs/
Now the shared library obtained above has all the functions exposed like ConvertToI420,I420Rotate etc......


To check the functions available use the following command on Linux or MSYS(for windows)
 nm -C -D libyuv_shared.so

In my next post I'll try to show how to write a JNI wrapper to use the libyuv shared library.


Thursday, May 7, 2015

Building WebRTC libraries for Android

   After banging my head almost 2 weeks trying to build WebRTC libraries on Windows and MAC machine, as of today I have successfully compiled WebRTC binaries for Android using this awesome tutorial from here http://www.khirman.com/building-webrtc-libraries-android/

   Anyone reading this post, I would like to suggest don't waste time trying to build on Windows or MAC, it doesn't help, only surges your frustration.

   Linux is the only way out to compile WebRTC, I used Ubuntu 14.04.2 LTS setup in VirtualBox on a MAC.
  
   The following is the list of commands (taken from above site) that I used to compile the libraries.


# assuming we are starting from "virgin" Ubuntu installation
sudo apt-get install git
sudo apt-get install g++
sudo apt-get install subversion
sudo apt-get install git-svn
sudo apt-get install openjdk-7-jdk
sudo apt-get install ant
sudo apt-get install lib32stdc++6 lib32z1
#
# get google build tools
#
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH=`pwd`/depot_tools:"$PATH"
#
# we'll need Java
#
export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64/
#
# now we are setting our target for compilation
#
export GYP_DEFINES="OS=android"
#
# New home for WebCRT
#
mkdir WebCRT
cd WebCRT
#
# Time to pull sources ( including all dependencies derived from chromium project)
# will take quite a time
#
fetch webrtc_android
#
# Now time to build
#
cd src
#
# setup Android cross compiler build environment
#
. build/android/envsetup.sh
export GYP_DEFINES="build_with_chromium=0  $GYP_DEFINES"
export GYP_DEFINES="build_with_libjingle=1 $GYP_DEFINES"
export GYP_DEFINES="libjingle_java=1 $GYP_DEFINES"
# send WEBRTC_LOGGING to Android's logcat
export GYP_DEFINES="enable_tracing=1 $GYP_DEFINES"
#
# Generate .ninja files
#
gclient runhooks
#
# and now is an actual build....
#

#
# Build AppRTCDemo application – demonstrates interoperability of native Android
# client and Chrome JavaScript client.
# source code / project root : src/talk/examples/android/
# resulting APK : src/out/Debug/AppRTCDemo-debug.apk
#
ninja -C out/Debug AppRTCDemo
#
# Build WebRTCDemo application – exchange video+audio between two
# android clients.
# source code / project root : src/webrtc/examples/android/media_demo/
# resulting APK : src/out/Debug/WebRTCDemo-debug.apk
#
ninja -C out/Debug WebRTCDemo

One small addition, post the gclient  runhooks command in list above use this command to generate all the libraries and apks

ninja -C out/Debug

I am re-posting all the commands here just for my future reference, but might help someone else trying to build the libs.

Wednesday, December 3, 2014

Cycling || Recreation

  Since childhood I have liked cycling, but then it was just for the sake of playing. Lately I have developed inclination towards cycling and decided to take it more seriously. It all started when in my previous company we had this cycling company named cymour come with their bicycles and allow us to cycle for a while, I really liked the bicycles they had got and riding them was pleasure. Post the ride I felt that I should own one of a kind, and had decided to buy one.
    I started inquiring about different bicycle brands and evaluated the different models available, had restricted my budget to 7-8k. I made a list of bicycles that I liked as well in my budget. Unfortunately the models I had listed down turned out to be fancy ones (with dual shocks and dual disc brakes that can give up anytime) that are mostly used by kids, a friend of mine (a cycling enthusiast) explained to me that models I selected were not durable and highly unreliable for long run, and that I should go for bicycles with rigid frames (no shocks) and frame material must be made up of alloy not steel. Bicycles made of alloy frames are much lighter than others.
    Started my research all over again and now the budget had to be almost doubled, since the models that I was now looking for were expensive ones. First choice in my new list (I guess everyone's is) was Btwin Rockrider 5.0 which costs around 9k plus 1k for some important accessories (that are not a part of bicycle), despite the bicycle being great it did not appeal to me much. The bicycle had large frame but the handle was very low so I had to bend a lot and plus it did not have rapid gear shifters from shimano (which is must have).
   My next choice was Hercules Act 110, this ones from BSA an Indian manufacturer and I must say the looks really impressed me, the frame is made of alloy and has rapid gear shifters from shimano. I liked this one so much that unconsciously I had decided to buy it and did not like a single bike that I saw after this one. But the price was a major hindrance for me, the site quotes the price to be 16.5k which was way out of my league, after roaming around a few days I struck a great deal, the guy agreed to 13.2k without a single penny less. Although a bit expensive than what I had planned for a think I have made a prudent decision in the long run. I am really enjoying the ride to and fro home and office (just once a week for now :) ).

Happy Cycling!!!

Sunday, May 19, 2013

Managing Audio Focus - Android

Was just googling around how to manage the media player in an android application when a call or sms arrives, and stumbled upon this very interesting and important concept of managing audio focus...........

I have taken this directly from the documentation available at developer.android.com, as the explanation is very lucid out here.........thus saving me from the trouble of retyping it...:)

With multiple apps potentially playing audio it's important to think about how they should interact. To avoid every music app playing at the same time, Android uses audio focus to moderate audio playback—only apps that hold the audio focus should play audio.
Before your app starts playing audio it should request—and receive—the audio focus. Likewise, it should know how to listen for a loss of audio focus and respond appropriately when that happens.

Request the Audio Focus


Before your app starts playing any audio, it should hold the audio focus for the stream it will be using. This is done with a call to requestAudioFocus() which returns AUDIOFOCUS_REQUEST_GRANTED if your request is successful.
You must specify which stream you're using and whether you expect to require transient or permanent audio focus. Request transient focus when you expect to play audio for only a short time (for example when playing navigation instructions). Request permanent audio focus when you plan to play audio for the foreseeable future (for example, when playing music).
The following snippet requests permanent audio focus on the music audio stream. You should request the audio focus immediately before you begin playback, such as when the user presses play or the background music for the next game level begins.
AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...
// Request audio focus for playback
int result = am.requestAudioFocus(afChangeListener,
                                 // Use the music stream.
                                 AudioManager.STREAM_MUSIC,
                                 // Request permanent focus.
                                 AudioManager.AUDIOFOCUS_GAIN);
   if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
    // Start playback.
}
 

Once you've finished playback be sure to call abandonAudioFocus(). This notifies the system that you no longer require focus and unregisters the associated AudioManager.OnAudioFocusChangeListener. In the case of abandoning transient focus, this allows any interupted app to continue playback.

// Abandon audio focus when playback complete am.abandonAudioFocus(afChangeListener);

When requesting transient audio focus you have an additional option: whether or not you want to enable "ducking." Normally, when a well-behaved audio app loses audio focus it immediately silences its playback. By requesting a transient audio focus that allows ducking you tell other audio apps that it’s acceptable for them to keep playing, provided they lower their volume until the focus returns to them.
// Request audio focus for playback
int result = am.requestAudioFocus(afChangeListener,
                     // Use the music stream.
                      AudioManager.STREAM_MUSIC,
                     // Request permanent focus.
                     AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
   if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    // Start playback.
}
Ducking is particularly suitable for apps that use the audio stream intermittently, such as for audible driving directions.
Whenever another app requests audio focus as described above, its choice between permanent and transient (with or without support for ducking) audio focus is received by the listener you registered when requesting focus.

Handle the Loss of Audio Focus


If your app can request audio focus, it follows that it will in turn lose that focus when another app requests it. How your app responds to a loss of audio focus depends on the manner of that loss.
The onAudioFocusChange() callback method of they audio focus change listener you registered when requesting audio focus receives a parameter that describes the focus change event. Specifically, the possible focus loss events mirror the focus request types from the previous section—permanent loss, transient loss, and transient with ducking permitted.
Generally speaking, a transient (temporary) loss of audio focus should result in your app silencing it’s audio stream, but otherwise maintaining the same state. You should continue to monitor changes in audio focus and be prepared to resume playback where it was paused once you’ve regained the focus.
If the audio focus loss is permanent, it’s assumed that another application is now being used to listen to audio and your app should effectively end itself. In practical terms, that means stopping playback, removing media button listeners—allowing the new audio player to exclusively handle those events—and abandoning your audio focus. At that point, you would expect a user action (pressing play in your app) to be required before you resume playing audio.
In the following code snippet, we pause the playback or our media player object if the audio loss is transient and resume it when we have regained the focus. If the loss is permanent, it unregisters our media button event receiver and stops monitoring audio focus changes.

OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
    public void onAudioFocusChange(int focusChange) {
        if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT
            // Pause playback
        } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
            // Resume playback 
        } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
            am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
            am.abandonAudioFocus(afChangeListener);
            // Stop playback
        }
    }
};
In the case of a transient loss of audio focus where ducking is permitted, rather than pausing playback, you can "duck" instead.

Duck!


Ducking is the process of lowering your audio stream output volume to make transient audio from another app easier to hear without totally disrupting the audio from your own application.
In the following code snippet lowers the volume on our media player object when we temporarily lose focus, then returns it to its previous level when we regain focus.
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
    public void onAudioFocusChange(int focusChange) {
        if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
            // Lower the volume
        } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
            // Raise it back to normal
        }
    }
};
A loss of audio focus is the most important broadcast to react to, but not the only one. The system broadcasts a number of intents to alert you to changes in user’s audio experience. The next lesson demonstrates how to monitor them to improve the user’s overall experience.


For more detailed explanation around Managing Audio Playback you can visit http://developer.android.com/training/managing-audio/audio-focus.html  

Android Studio

Getting Started with Android Studio ........ straight from developer.android.com

EARLY ACCESS PREVIEW

Android Studio is a new Android development environment based on IntelliJ IDEA. Similar to Eclipse with the ADT Plugin, Android Studio provides integrated Android developer tools for development and debugging. On top of the capabilities you expect from IntelliJ, Android Studio offers:
  • Gradle-based build support.
  • Android-specific refactoring and quick fixes.
  • Lint tools to catch performance, usability, version compatibility and other problems.
  • ProGuard and app-signing capabilities.
  • Template-based wizards to create common Android designs and components.
  • A rich layout editor that allows you to drag-and-drop UI components, preview layouts on multiple screen configurations, and much more.
Caution: Android Studio is currently available as anearly access preview. Several features are either incomplete or not yet implemented and you may encounter bugs. If you are not comfortable using an unfinished product, you may want to instead download (or continue to use) the ADT Bundle(Eclipse with the ADT Plugin).

For more information about Android Studio or to download the same visit http://developer.android.com/sdk/installing/studio.html 

Thursday, April 25, 2013

Install apk and uninstall an app via Intents

        Currently am working on a project that requires to build an Android application that will download another apps within itself and install the same. I call the main app as parent app and the apps that will be downloaded as child apps (just for simplicity...... :)). Also it is required that the child apps should not be visible to the user and should be used only via the parent app. Finally when the parent app is uninstalled; it is required that the child apps also be uninstalled.

        Initially I thought that the requirements mentioned above were not possible, but after a little bit of reading I came up with a solution.

              1) The first requirement of downloading and installing an app within another app can be achieved by simply downloading an apk (using http) and installing the apk when download finishes. Android does not authorize to install anything without users consent (unless device is rooted), only thing we can do is prompt the user to install the apk. The app will be installed successfully if user clicks 'Install'.

Intent intent = new Intent(Intent.ACTION_VIEW);
Uri apkUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/Download/" + "app.apk")); 
intent.setDataAndType(apkUri, "application/vnd.android.package-archive"); startActivity(intent);

              2) For the child apps not be visible to user, I simply had to remove intent-filter of the launcher activity from the manifest file. When no launcher activity is present in an application, it does not have a launcher icon.



But in absence of a launcher activity how to launch an application?
Hence, to launch the actiivty we need to provide it a custom action and use it to launch the activity from the parent app.


To launch the above activity the intent call will be as below.

Intent intent = new Intent(); intent.setAction("com.temporary.nolauncher.action.NO_LAUNCHER"); startActivity(intent);

                 3) Finally for uninstalling the child apps when parent app is uninstalled, I had to register a receiver that would catch the event when any app is uninstalled. After the event is caught, I checked which app was uninstalled using the URI. If the parent app is uninstalled then the child app would prompt the user to uninstall itself. Again uninstall can't be achieved without user's consent (unless device is rooted).

The receiver has to be registered in manifest as follows. The action PACKAGE_REMOVED serves the purpose of catching the event when any anpp is uninstalled.


After the event of uinstalling any app is caught in the receiver, we can detect which app was uninstalled (using the intent). The intent returns the package name via the uri. 'intent' reference is avaible from the onReceive method in the receiver.

private String getPackageName(Intent intent) { 
      Uri uri = intent.getData(); 
      String pkg = uri != null ? uri.getSchemeSpecificPart() : null; 
      return pkg; 
}

Finally once the it is detected that the app uninstalled was the parent app then we can fire an intent that will prompt the user to uninstall the child app.

String packToUninstall = "com.temporary.nolauncher"; 
Uri packageURI = Uri.parse("package:" + packToUninstall); 
Intent uninstallIntent = new Intent(Intent.ACTION_DELETE,packageURI); uninstallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ctx.startActivity(uninstallIntent);

 'ctx' reference is avaible from the onReceive method in the receiver.