Migrating Eclipse android project with NDK and Gst

2019-08-13 11:36发布

问题:

I have a perfectly working android project in Eclipse, the project includes NDK support and uses Gstreamer. When I migrate the project from Eclipse to Android Studio all sorts of problems pop up, and I just cant successfully compile the project.

I did a thorough research on each and every error I've encountered but still couldn't compile and run the project on android studio.

https://drive.google.com/file/d/0B_euzgSjTAqcQngwbzR1cXY0MkU/view?usp=sharing

A link to the working Eclipse project, I hope someone could direct me on the right way.

This is the import summary:

ECLIPSE ANDROID PROJECT IMPORT SUMMARY

Ignored Files:

The following files were not copied into the new Gradle project; you should evaluate whether these are still needed in your project and if so manually move them:

  • .externalToolBuilders\
  • .externalToolBuilders\Wiz.launch
  • gst-build\
  • gst-build\gstreamer_android.c
  • gst-build\gstreamer_android.o

Replaced Jars with Dependencies:

The importer recognized the following .jar files as third party libraries and replaced them with Gradle dependencies instead. This has the advantage that more explicit version information is known, and the libraries can be updated automatically. However, it is possible that the .jar file in your project was of an older version than the dependency we picked, which could render the project not compileable. You can disable the jar replacement in the import wizard and try again:

android-support-v4.jar => com.android.support:support-v4:23.3.0

Moved Files:

Android Gradle projects use a different directory structure than ADT Eclipse projects. Here's how the projects were restructured:

  • AndroidManifest.xml => app\src\main\AndroidManifest.xml
  • assets\ => app\src\main\assets\
  • jni\ => app\src\main\jni\
  • libs\armeabi\libavcodec.so => app\src\main\jniLibs\armeabi\libavcodec.so
  • libs\armeabi\libavdevice.so => app\src\main\jniLibs\armeabi\libavdevice.so
  • libs\armeabi\libavfilter.so => app\src\main\jniLibs\armeabi\libavfilter.so
  • libs\armeabi\libavformat.so => app\src\main\jniLibs\armeabi\libavformat.so
  • libs\armeabi\libavutil.so => app\src\main\jniLibs\armeabi\libavutil.so
  • libs\armeabi\libgstreamer_android.so => app\src\main\jniLibs\armeabi\libgstreamer_android.so
  • libs\armeabi\libjniARToolKitPlus.so => app\src\main\jniLibs\armeabi\libjniARToolKitPlus.so
  • libs\armeabi\libjniavcodec.so => app\src\main\jniLibs\armeabi\libjniavcodec.so
  • libs\armeabi\libjniavdevice.so => app\src\main\jniLibs\armeabi\libjniavdevice.so
  • libs\armeabi\libjniavfilter.so => app\src\main\jniLibs\armeabi\libjniavfilter.so
  • libs\armeabi\libjniavformat.so => app\src\main\jniLibs\armeabi\libjniavformat.so
  • libs\armeabi\libjniavutil.so => app\src\main\jniLibs\armeabi\libjniavutil.so
  • libs\armeabi\libjnicvkernels.so => app\src\main\jniLibs\armeabi\libjnicvkernels.so
  • libs\armeabi\libjniopencv_calib3d.so => app\src\main\jniLibs\armeabi\libjniopencv_calib3d.so
  • libs\armeabi\libjniopencv_contrib.so => app\src\main\jniLibs\armeabi\libjniopencv_contrib.so
  • libs\armeabi\libjniopencv_core.so => app\src\main\jniLibs\armeabi\libjniopencv_core.so
  • libs\armeabi\libjniopencv_features2d.so => app\src\main\jniLibs\armeabi\libjniopencv_features2d.so
  • libs\armeabi\libjniopencv_flann.so => app\src\main\jniLibs\armeabi\libjniopencv_flann.so
  • libs\armeabi\libjniopencv_highgui.so => app\src\main\jniLibs\armeabi\libjniopencv_highgui.so
  • libs\armeabi\libjniopencv_imgproc.so => app\src\main\jniLibs\armeabi\libjniopencv_imgproc.so
  • libs\armeabi\libjniopencv_legacy.so => app\src\main\jniLibs\armeabi\libjniopencv_legacy.so
  • libs\armeabi\libjniopencv_ml.so => app\src\main\jniLibs\armeabi\libjniopencv_ml.so
  • libs\armeabi\libjniopencv_nonfree.so => app\src\main\jniLibs\armeabi\libjniopencv_nonfree.so
  • libs\armeabi\libjniopencv_objdetect.so => app\src\main\jniLibs\armeabi\libjniopencv_objdetect.so
  • libs\armeabi\libjniopencv_photo.so => app\src\main\jniLibs\armeabi\libjniopencv_photo.so
  • libs\armeabi\libjniopencv_stitching.so => app\src\main\jniLibs\armeabi\libjniopencv_stitching.so
  • libs\armeabi\libjniopencv_video.so => app\src\main\jniLibs\armeabi\libjniopencv_video.so
  • libs\armeabi\libjniopencv_videostab.so => app\src\main\jniLibs\armeabi\libjniopencv_videostab.so
  • libs\armeabi\libjnipostproc.so => app\src\main\jniLibs\armeabi\libjnipostproc.so
  • libs\armeabi\libjniswresample.so => app\src\main\jniLibs\armeabi\libjniswresample.so
  • libs\armeabi\libjniswscale.so => app\src\main\jniLibs\armeabi\libjniswscale.so
  • libs\armeabi\libopencv_calib3d.so => app\src\main\jniLibs\armeabi\libopencv_calib3d.so
  • libs\armeabi\libopencv_contrib.so => app\src\main\jniLibs\armeabi\libopencv_contrib.so
  • libs\armeabi\libopencv_core.so => app\src\main\jniLibs\armeabi\libopencv_core.so
  • libs\armeabi\libopencv_features2d.so => app\src\main\jniLibs\armeabi\libopencv_features2d.so
  • libs\armeabi\libopencv_flann.so => app\src\main\jniLibs\armeabi\libopencv_flann.so
  • libs\armeabi\libopencv_highgui.so => app\src\main\jniLibs\armeabi\libopencv_highgui.so
  • libs\armeabi\libopencv_imgproc.so => app\src\main\jniLibs\armeabi\libopencv_imgproc.so
  • libs\armeabi\libopencv_info.so => app\src\main\jniLibs\armeabi\libopencv_info.so
  • libs\armeabi\libopencv_legacy.so => app\src\main\jniLibs\armeabi\libopencv_legacy.so
  • libs\armeabi\libopencv_ml.so => app\src\main\jniLibs\armeabi\libopencv_ml.so
  • libs\armeabi\libopencv_nonfree.so => app\src\main\jniLibs\armeabi\libopencv_nonfree.so
  • libs\armeabi\libopencv_objdetect.so => app\src\main\jniLibs\armeabi\libopencv_objdetect.so
  • libs\armeabi\libopencv_photo.so => app\src\main\jniLibs\armeabi\libopencv_photo.so
  • libs\armeabi\libopencv_stitching.so => app\src\main\jniLibs\armeabi\libopencv_stitching.so
  • libs\armeabi\libopencv_ts.so => app\src\main\jniLibs\armeabi\libopencv_ts.so
  • libs\armeabi\libopencv_video.so => app\src\main\jniLibs\armeabi\libopencv_video.so
  • libs\armeabi\libopencv_videostab.so => app\src\main\jniLibs\armeabi\libopencv_videostab.so
  • libs\armeabi\libpostproc.so => app\src\main\jniLibs\armeabi\libpostproc.so
  • libs\armeabi\libswresample.so => app\src\main\jniLibs\armeabi\libswresample.so
  • libs\armeabi\libswscale.so => app\src\main\jniLibs\armeabi\libswscale.so
  • libs\armeabi\libtbb.so => app\src\main\jniLibs\armeabi\libtbb.so
  • libs\javacpp.jar => app\libs\javacpp.jar
  • libs\javacv.jar => app\libs\javacv.jar
  • res\ => app\src\main\res\
  • src\ => app\src\main\java\

Next Steps:

You can now build the project. The Gradle project needs network connectivity to download dependencies.

Bugs:

If for some reason your project does not build, and you determine that it is due to a bug or limitation of the Eclipse to Gradle importer, please file a bug at http://b.android.com with category Component-Tools.

(This import summary is for your information only, and can be deleted after import once you are satisfied with the results.)

Build.Gradle:

apply plugin: 'com.android.model.application'

model {
    android {
        compileSdkVersion = 23
        buildToolsVersion = "23.0.2"

        defaultConfig.with {
            applicationId = "com.gst_sdk_tutorials.tutorial_4"
            minSdkVersion.apiLevel = 17
            targetSdkVersion.apiLevel = 22
        }

    }

    android.ndk {
        moduleName = "tutorial-4"
        cppFlags.addAll(["-I${file("src/main/jni/Common/native_app_glue")}".toString(),
                         "-I${file("src/main/jni/Common/cpufeatures")}".toString(),
                         "-I${file("src/main/jni/Common/ndk_helper")}".toString()])
        ldLibs.addAll(["android", "EGL", "GLESv2", "dl", "log", "atomic"])
        stl     = "c++_static"
    }
    // jni is the default dir; config this if yours is in different directory
    android.sources {
        main {
            jni {
                source {
                    srcDirs 'src/main/jni'
                }
            }
        }
    }
    android.buildTypes {
        release {
            minifyEnabled = false
            proguardFiles.add(file('proguard-rules.txt'))
        }
    }
    // Turn on hard float support in armeabi-v7a
    android.abis {
        create("armeabi-v7a") {
            cppFlags.addAll(["-mhard-float", "-D_NDK_MATH_NO_SOFTFP=1", "-mfloat-abi=hard"])
            ldLibs.add("m_hard")
            ldFlags.add("-Wl,--no-warn-mismatch")
        }
    }
    android.productFlavors {
        create ("arm7") {
            ndk.abiFilters.add("armeabi-v7a")
        }
        create ("arm8") {
            ndk.abiFilters.add("arm64-v8a")
        }
        create ("x86-32") {
            ndk.abiFilters.add("x86")
        }
        // for detailed abiFilter descriptions, refer to "Supported ABIs" @
        // https://developer.android.com/ndk/guides/abis.html#sa
        // build one including all productFlavors
        create("fat")
    }
}

dependencies {
    compile 'com.android.support:support-v4:23.3.0'
    compile files('libs/javacpp.jar')
    compile files('libs/javacv.jar')
}

local.properties:

ndk.dir=C\:\\Users\\wiz\\Downloads\\android-ndk-r9d
sdk.dir=D\:\\sdk

.c file:(not complete due to character limit)

#include <string.h>
#include <jni.h>
#include <android/log.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>
#include <gst/gst.h>
#include <gst/interfaces/xoverlay.h>
#include <gst/video/video.h>
#include <pthread.h>

GST_DEBUG_CATEGORY_STATIC (debug_category);
#define GST_CAT_DEFAULT debug_category

/*
 * These macros provide a way to store the native pointer to CustomData, which might be 32 or 64 bits, into
 * a jlong, which is always 64 bits, without warnings.
 */
#if GLIB_SIZEOF_VOID_P == 8
# define GET_CUSTOM_DATA(env, thiz, fieldID) (CustomData *)(*env)->GetLongField (env, thiz, fieldID)
# define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)data)
#else
# define GET_CUSTOM_DATA(env, thiz, fieldID) (CustomData *)(jint)(*env)->GetLongField (env, thiz, fieldID)
# define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)(jint)data)
#endif

/* Do not allow seeks to be performed closer than this distance. It is visually useless, and will probably
 * confuse some demuxers. */
#define SEEK_MIN_DELAY (500 * GST_MSECOND)

/* Structure to contain all our information, so we can pass it to callbacks */
typedef struct _CustomData {
  jobject app;                  /* Application instance, used to call its methods. A global reference is kept. */
  GstElement *pipeline;         /* The running pipeline */
  GMainContext *context;        /* GLib context used to run the main loop */
  GMainLoop *main_loop;         /* GLib main loop */
  gboolean initialized;         /* To avoid informing the UI multiple times about the initialization */
  ANativeWindow *native_window; /* The Android native window where video will be rendered */
  GstState state;               /* Current pipeline state */
  GstState target_state;        /* Desired pipeline state, to be set once buffering is complete */
  gint64 duration;              /* Cached clip duration */
  gint64 desired_position;      /* Position to seek to, once the pipeline is running */
  GstClockTime last_seek_time;  /* For seeking overflow prevention (throttling) */
  gboolean is_live;             /* Live streams do not use buffering */
} CustomData;

/* playbin2 flags */
typedef enum {
  GST_PLAY_FLAG_TEXT = (1 << 2)  /* We want subtitle output */
} GstPlayFlags;

/* These global variables cache values which are not changing during execution */
static pthread_t gst_app_thread;
static pthread_key_t current_jni_env;
static JavaVM *java_vm;
static jfieldID custom_data_field_id;
static jmethodID set_message_method_id;
static jmethodID set_current_position_method_id;
static jmethodID on_gstreamer_initialized_method_id;
static jmethodID on_media_size_changed_method_id;

/*
 * Private methods
 */

/* Register this thread with the VM */
static JNIEnv *attach_current_thread (void) {
  JNIEnv *env;
  JavaVMAttachArgs args;

  GST_DEBUG ("Attaching thread %p", g_thread_self ());
  args.version = JNI_VERSION_1_4;
  args.name = NULL;
  args.group = NULL;

  if ((*java_vm)->AttachCurrentThread (java_vm, &env, &args) < 0) {
    GST_ERROR ("Failed to attach current thread");
    return NULL;
  }

  return env;
}

/* Unregister this thread from the VM */
static void detach_current_thread (void *env) {
  GST_DEBUG ("Detaching thread %p", g_thread_self ());
  (*java_vm)->DetachCurrentThread (java_vm);
}

/* Retrieve the JNI environment for this thread */
static JNIEnv *get_jni_env (void) {
  JNIEnv *env;

  if ((env = pthread_getspecific (current_jni_env)) == NULL) {
    env = attach_current_thread ();
    pthread_setspecific (current_jni_env, env);
  }

  return env;
}

android.mk before import:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := tutorial-4
LOCAL_SRC_FILES := tutorial-4.c
LOCAL_SHARED_LIBRARIES := gstreamer_android
LOCAL_LDLIBS := -llog -landroid
include $(BUILD_SHARED_LIBRARY)

ifndef GSTREAMER_SDK_ROOT
ifndef GSTREAMER_SDK_ROOT_ANDROID
$(error GSTREAMER_SDK_ROOT_ANDROID is not defined!)
endif
GSTREAMER_SDK_ROOT        := $(GSTREAMER_SDK_ROOT_ANDROID)
endif
GSTREAMER_NDK_BUILD_PATH  := $(GSTREAMER_SDK_ROOT)/share/gst-android/ndk-build/
include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk
GSTREAMER_PLUGINS         := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_PLAYBACK) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_NET) $(GSTREAMER_PLUGINS_SYS) $(GSTREAMER_PLUGINS_NET_RESTRICTED) 
GSTREAMER_EXTRA_DEPS      := gstreamer-interfaces-0.10 gstreamer-video-0.10
include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer.mk

回答1:

I suggest to move to AS but keep the NDK build "the traditional way". My main argument to defend this approach is that the experimental plugin is still a "moving target": the DSL changes all the time, and its limitations require workarounds that change with every release of the experimental plugin. The second reason is that 3rd party tools like Fabric will not work with the experimental plugin.

For the non-experimental plugin, you can use the following piece in build.gradle:

def ndkBuild = android.ndkDirectory
import org.apache.tools.ant.taskdefs.condition.Os
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
    ndkBuild += '.cmd'
}

task buildNative(type: Exec, description: 'Compile JNI source via NDK') {
    commandLine '$ndkBuild', 'NDK_PROJECT_PATH="$jniSrc/..'
}

task cleanNative(type: Exec, description: 'Clean JNI object files') {
    commandLine '$ndkBuild', 'clean', 'NDK_PROJECT_PATH="$jniSrc/..'
}

clean.dependsOn 'cleanNative'

tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn buildNative
}

tasks.all {
    task -> if (task.name.contains('compileDebugNdk') || task.name.contains('compileReleaseNdk')) task.enabled = false
}