天天看點

undefined reference to || C代碼中實作Surface顯示android之 JNI端擷取并操作Surface

共三處修改!!!!!!!

1.

surface.c對應的Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

# our source files

#

LOCAL_SRC_FILES:= \

    surface.cpp

LOCAL_SHARED_LIBRARIES := \

    libskia \

    libsurfaceflinger\

    libgui\

        libutils \

    liblog

LOCAL_C_INCLUDES += \

    $(JNI_H_INCLUDE) \

    external/skia/src/core \

    external/skia/include/core \

    frameworks/base/include \

    frameworks/base/native/include

# Optional tag would mean it doesn't get installed by default

LOCAL_MODULE_TAGS := optional

LOCAL_PRELINK_MODULE := false

LOCAL_ARM_MODE := arm

LOCAL_MODULE:= libjnivideo

include $(BUILD_SHARED_LIBRARY)

+++++

2.

int AndroidSurface_updateSurface(bool autoscale) {

    if(surface == NULL) {

        return ANDROID_SURFACE_RESULT_JNI_EXCEPTION;

    }

    if (!surface->isValid()) { //Surface::isValid()

        return ANDROID_SURFACE_RESULT_NOT_VALID;

    }

+++++

3.

static

Surface* getNativeSurface(JNIEnv* env, jobject jsurface) {

    jclass clazz = env->FindClass("android/view/Surface");

    jfieldID field_surface = env->GetFieldID(clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I");//"mSurface"

    if(field_surface == NULL) {

        return NULL;

    }

    return (Surface *) env->GetIntField(jsurface, field_surface);

}

因為 android2.2以上的版本,android.view.Surface裡面沒有“mSurface"了,而是用了一個常量 ANDROID_VIEW_SURFACE_JNI_ID, 區分下版本就行了。

++++++++整體參考架構++++

you must copy libjnivideo.so and libjniaudio.so into lib/armeabi of your project for eclipse, which pack them into apk. If you run this project on not froyo OS you will have errors because some libraries don't be there or have other name and dalvik can't find them

I tried several times and passed finally. Here is my configuration changed for elair: from the eclair source, copy your native directory to frameworks/base/, modify the file of native/video/jni/Android.mk to add libui to LOCAL_SHARED_LIBRARIES list and replace libsurfaceflinger_client with libsurfaceflinger, modify surface.cpp to replace #include with #include , add libjniaudio.so and libjnivideo.so to the end of myandroid/build/core/prelink-linux-arm.map, then I get the libjniaudio.so and libjnivideo.so in out/target/product/generic/obj/lib for eclair. I try them in my emulator, the result is exactly beyond my imagination. It will be better if your project can fit any android version. Anyway, Thank you for your porting. If possible, I will send the three .so for eclair to you for testing by other people.

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

重要參考文獻:

android之 JNI端擷取并操作Surface

  前一段時間研究android, 在jni端操作surface遇到麻煩,主要是C++基礎太差,Surface.cpp讀了n遍,也仿照網上查到的資料,試圖從Java端傳遞Surface,然後jni端進行操作。卻總是遇到各種各樣的異常,前前後後卡住了7天,最後終于解決了,放出這個方法,總會對某些朋友有幫助。

  其實不是原創的,隻是,網上有1000篇文章,有999篇都講的同一種方法,但在我這裡卻偏偏成功不了。終于那天偶然看到一篇e文的文章,是有人分析了 havlenapetr 的libjnivideo.so, 然後放出了ta使用的方法,原來想當簡單:

static android::sp<android::Surface> native_surface;

static android::Surface* getNativeSurface(JNIEnv* env, jobject jsurface, jint version)

{

    jclass clazz = env->FindClass("android/view/Surface");

    jfieldID field_surface;

    if(version <=8)

    {

        field_surface = env->GetFieldID(clazz, "mSurface", "I");

    }

    else

        field_surface = env->GetFieldID(clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I");

    if (field_surface == NULL)

    {

        return NULL;

    }

    return (android::Surface *) env->GetIntField(jsurface, field_surface);

}

int setSurface(JNIEnv *env, jobject jsurface, jint version)

{

    native_surface = getNativeSurface(env, jsurface, version);

    if(android::Surface::isValid(native_surface))

    {

        __android_log_print(ANDROID_LOG_INFO, "libjni", "native_surface is valid");

        return 1;

    }

    else

        __android_log_print(ANDROID_LOG_ERROR, "libjni", "native_surface is invalid");

    return 0;

}

  jsurface就是從Java端傳遞過來的,然後這裡的 native_surface,就是我們想要的native surface了。為什麼要 傳遞個version? 因為 android2.2以上的版本,android.view.Surface裡面沒有“mSurface"了,而是用了一個常量 ANDROID_VIEW_SURFACE_JNI_ID, 區分下版本就行了。

  然後又發現jni端操作surface也是相當簡單,至少顯示圖像之類的很容易:

static android::Surface::SurfaceInfo info;

static android::Region dirtyRegion;

做下初始化:

  dirtyRegion.set(android::Rect(0x3FFF, 0x3FFF));

然後

  native_surface->lock(&info, &dirtyRegion, true);

  memcpy(info.bits, buf, bufSize);

  native_surface->unlockAndPost();

就顯示出來了。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Android 調試/測試]問題求助,通過ndk在本地C代碼中實作Surface顯示

http://www.eoeandroid.com/thread-49423-1-1.html

我的目的是實作一個基于ffmpeg的播放器,主要參照和模仿的是havlenape的代碼。大部分功能都實作了,但在圖像輸出時遇到了問題,無法輸出。

  在java層建立了一個SUrfaceView,主要代碼如下:

    public class FFMpegMovieViewAndroid extends SurfaceView {

    。。。

        public FFMpegMovieViewAndroid(Context context) {

            super(context);

            getHolder().addCallback(mSHCallback);

        }

    。。。

    SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback() {

        public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {

            startVideo();

        }

        public void surfaceCreated(SurfaceHolder holder) {

            mSurfaceHolder = holder;

            openVideo();

        }

        public void surfaceDestroyed(SurfaceHolder holder) {

        }

    };

    。。。

    jni代碼:

    static Surface* getNativeSurface(JNIEnv* env, jobject jsurface) {

        jclass clazz = env->FindClass("android/view/Surface");

        jfieldID field_surface = env->GetFieldID(clazz, "mSurface", "I");

        if(field_surface == NULL) {

            return NULL;

        }

        return (Surface *) env->GetIntField(jsurface, field_surface);

    }

    通過這個得到Surface指針,而且java代碼調用時把surface對象傳遞過來了。

    顯示主要是通過SkBitmap來實作的,初始化後,通過函數得到指針:

    int AndroidSurface_getPixels(int width, int height, void** pixels) {

    __android_log_print(ANDROID_LOG_INFO, TAG, "getting surface's pixels %ix%i", width, height);

    if(sSurface == NULL) {

        return ANDROID_SURFACE_RESULT_JNI_EXCEPTION;

    }

    if(initBitmap(&sBitmapClient, PIXEL_FORMAT_RGB_565, width, height, true) < 0) {

        return ANDROID_SURFACE_RESULT_COULDNT_INIT_BITMAP_CLIENT;

    }

    *pixels = sBitmapClient.getPixels();

    __android_log_print(ANDROID_LOG_INFO, TAG, "getted");

    return ANDROID_SURFACE_RESULT_SUCCESS;

}

    顯示輸出首先是通過下面的代碼将frame和指針相聯系。

            mFrame = avcodec_alloc_frame();

        if (mFrame == NULL) {

                return INVALID_OPERATION;

        }

        avpicture_fill((AVPicture *) mFrame, (uint8_t *) pixels, PIX_FMT_RGB565, stream->codec->width, stream->codec->height);

    在每一副圖像輸出是,直接将圖像輸出到指針mFrame->data,然後調用AndroidSurface_updateSurface()輸出,代碼如下:

static void doUpdateSurface() {

    SkCanvas canvas(sBitmapSurface);

    SkRect surface_sBitmapClient;

    SkRect surface_sBitmapSurface;

    SkMatrix matrix;

    surface_sBitmapSurface.set(0, 0, sBitmapSurface.width(), sBitmapSurface.height());

    surface_sBitmapClient.set(0, 0, sBitmapClient.width(), sBitmapClient.height());

    matrix.setRectToRect(surface_sBitmapClient, surface_sBitmapSurface, SkMatrix::kFill_ScaleToFit);

    canvas.drawBitmapMatrix(sBitmapClient, matrix);

}

static int prepareSurfaceBitmap(Surface::SurfaceInfo* info) {

    if(initBitmap(&sBitmapSurface, info->format, info->w, info->h, false) < 0) {

        return -1;

    }

    sBitmapSurface.setPixels(info->bits);

    return 0;

}

int AndroidSurface_updateSurface() {

    static Surface::SurfaceInfo surfaceInfo;

    if(sSurface == NULL) {

        return ANDROID_SURFACE_RESULT_JNI_EXCEPTION;

    }

    if (!sSurface->isValid()) {

        return ANDROID_SURFACE_RESULT_NOT_VALID;

    }

    if (sSurface->lock(&surfaceInfo) < 0) {

        return ANDROID_SURFACE_RESULT_COULDNT_LOCK;

    }

    if(prepareSurfaceBitmap(&surfaceInfo) < 0) {

        return ANDROID_SURFACE_RESULT_COULDNT_INIT_BITMAP_SURFACE;

    }

    doUpdateSurface();

    if (sSurface->unlockAndPost() < 0) {

        return ANDROID_SURFACE_RESULT_COULDNT_UNLOCK_AND_POST;

    }

    return ANDROID_SURFACE_RESULT_SUCCESS;

}

我現在的狀态是,沒有報錯,但視訊圖像沒有顯示。

我希望得到幫助是:相關細節應用的闡述,或者類似的demo,或者能實作本地視訊輸出的其他方法。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

undefined reference to `__android_log_print'

  • 部落格分類:
  • android

Android JNI C C++ C#

原因:沒有加入支援的共享庫

出錯時:

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := testlog

LOCAL_SRC_FILES := testlog.c

include $(BUILD_SHARED_LIBRARY)

.c的頭檔案

#include <string.h>

#include <jni.h>

#include <android/log.h>

調試好的:

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := testlog

LOCAL_SRC_FILES := testlog.c

LOCAL_LDLIBS    := -llog

include $(BUILD_SHARED_LIBRARY)

.c的頭檔案

#include <string.h>

#include <jni.h>

#include <android/log.h>