2011年1月18日 星期二

整合 Android 和 FFmpeg (使用 Eclipse + NDK) on Windows

NDK 的相關設定請看 Android 上自己寫 Native Funcion

不過需要去下載 NDK-r4,在window上使用r5可能會有指令太長的錯誤

首先,我們先去下載 FFmpeg 的 src code

這邊我們利用 rockplayer 的 ffmpeg

http://rockplayer.freecoder.org/tech_en.html
or
http://www.box.net/shared/149mf76gh1

將所有檔案解壓縮之後放入 專案資料夾/jni/ffmpeg

我們要利用 NDK 來編譯一個 ffmpeg 的 library

同時也要自己寫一個使用 ffmpeg 的 library,並利用 native call 來讓 Java 呼叫

在 資料夾 jni 下新增一個資料夾 useFFmpeg,這裡之後要放我們的 Source Code

1. 在 jni 資料夾下新增兩個檔案 Android.mk 、 Application.mk

Android.mk

MY_LOCAL_PATH := $(call my-dir)
include $(all-subdir-makefiles)

Application.mk

APP_MODULES      := ffmpeg myLibName


2. 修改 jni/ffmpeg 中的 Android.mk

在 include $(CLEAR_VARS) 的下一行加上 LOCAL_ARM_MODE=arm


並把下方的

 ARM6_SRC_FILES := \
 libavcodec/arm/dsputil_armv6.S \
 libavcodec/arm/dsputil_init_armv6.c \
 libavcodec/arm/simple_idct_armv6.S \

刪除掉或是用 "#" 來註解

3. 在 useFFmpeg 資料夾下新增 test.c 及 Android.mk

test.c

#include <jni.h>
#include <stdlib.h>
#include <stdio.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>

JNIEXPORT jstring JNICALL Java_ffmpeg_test_FFmpegTest_test(JNIEnv *env, jobject obj, jstring what) {
  const jbyte *l_what;
  char  *result;

  // Register all formats and codecs
  av_register_all();

  AVFormatContext *pFormatCtx;
  AVCodecContext *pCodecCtx;

  l_what = (*env)->GetStringUTFChars(env, what, NULL);
  if (l_what == NULL) {
    return NULL; /* OutOfMemoryError already thrown */
  }

  result = malloc(strlen(l_what) + 9);
  if (result == NULL) {
    return NULL;
  }
  sprintf(result, "FFmpeg: %s", l_what);

  return (*env)->NewStringUTF(env, result);
}

Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := myLibName
LOCAL_SRC_FILES := test.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../ffmpeg
LOCAL_SHARED_LIBRARIES := ffmpeg
include $(BUILD_SHARED_LIBRARY)

如此一來就可以 Build 出兩個 Library,FFmpeg的build 要比較久

Java 的部分就打


static {

System.loadLibrary("ffmpeg");
System.loadLibrary("Player");
}
private native String test(String what);

就可以了,比較要注意的是 loadLibarary 的順序不能相反

12 則留言:

  1. 你好, 謝謝你的分享. 有些問題想在請教你一下:
    我是mac的使用者, 用xcode編譯了test.c, 但要怎麼產生.so檔?
    另外, 這裡似乎沒調用到FFmpeg, 不知是否方便私下向你請教 ^^
    kerlichung@gmail.com

    回覆刪除
  2. 不好意思,請問做完你提供的上述步驟之後我該如何下指令把.yuv格式的檔案轉換成.mp4格式的檔案呢?

    回覆刪除
    回覆
    1. 在 rockplayer 的 ffmpeg 把 encoder 的部分簡化掉了
      所以沒有辦法作影片格式的轉換
      如果需要的話要去找完整版的 ffmpeg

      刪除
  3. 您好,
    請問我照著您的步驟做完後,要怎麼做可以看到實驗結果?這個範例是要play影像嗎?先抱歉因code不熟,麻煩您指導一下。
    再請問,rockplayer的ffmpeg有支援rtmp嗎?因為我主要想要利用ffmpeg的rtmp把stream上傳到ustream,煩請版主解惑,謝謝

    回覆刪除
    回覆
    1. 這個範例主要是講解整合的部分,範例中 test.c 中有include ffmpeg 的 header 以及 test function 有呼叫 ffmpeg 的函式,不過並沒有做任何的處理,只是要用來證明 include 和 link 有成功而已,ffmepg 相關的操作請上網另外查。(實際上 test function 只是把傳進來的字串加上 FFMPEG: 後回傳)

      RTMP的部分我就不清楚了,可能要看一下rockplayer 的ffmpeg 原始碼

      刪除
    2. 版大您好
      謝謝您的回覆,我看了一下libavformat的資料夾,的確有rtmp的東西在,感謝您的幫忙。
      謝謝

      刪除
  4. 版大再請問
    程式碼用框架把它框住要怎麼用呢??
    我也想分享一下android與ffmpeg的編譯流程
    我查了一下都沒有詳細框住程式碼的說明,其實我是找不到blogger的後台要怎麼進去,不知從何設定起,麻煩您分享一下,感謝

    回覆刪除
    回覆
    1. 在 HTML 模式下加上

      <code> 程式碼放這 </code>

      即可

      刪除
  5. 怎麼我到HTML模式加上你說的條件後
    然後看到的排版變的很怪說,排版完全亂了

    ./configure \ --disable-static \ --enable-shared \ --enable-gpl \ --enable-version3 \ --enable-nonfree \ --disable-doc \ --disable-ffmpeg \ --disable-ffplay \ --disable-ffprobe \ --disable-ffserver \ --disable-avdevice \ --disable-avfilter \ --disable-mpegaudio-hp \ --enable-small \ --cross-prefix=/home/829699/android-ndk-r7b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/arm-linux-androideabi- \ --enable-cross-compile \ --target-os=linux \ --extra-cflags='-I/home/829699/android-ndk-r7b/platforms/android-14/arch-arm/usr/include' \ --extra-ldflags='-L/home/829699/android-ndk-r7b/android-14/arch-arm/usr/lib -nostdlib' \ --arch=arm \ --disable-debug \ --disable-stripping \ sed -i 's/HAVE_LRINT 0/HAVE_LRINT 1/g' config.h sed -i 's/HAVE_LRINTF 0/HAVE_LRINTF 1/g' config.h sed -i 's/HAVE_ROUND 0/HAVE_ROUND 1/g' config.h sed -i 's/HAVE_ROUNDF 0/HAVE_ROUNDF 1/g' config.h sed -i 's/HAVE_TRUNCF 0/HAVE_TRUNCF 1/g' config.h sed -i 's/HAVE_SYMVER 1/HAVE_SYMVER 0/g' config.h

    回覆刪除
    回覆
    1. 不好意思,另外還要在範本中加入以下CSS 碼

      code, .code {
      display: block; /* fixes a strange ie margin bug */
      font-family: Courier New;
      font-size: 8pt;
      overflow:auto;
      background: #f0f0f0 url(http://klcintw.images.googlepages.com/Code_BG.gif) left top repeat-y;
      border: 1px solid #ccc;
      padding: 10px 10px 10px 21px;
      max-height:200px;
      line-height: 1.2em;
      }

      刪除
  6. 抱歉版大,偶是傻逼,這段CSS碼我不知要加在哪,可以麻煩您指點一下嗎?
    我有加在HTMP的編碼下,就是跟放入程式碼的地方同一頁,但是只顯示出加入的CSS碼。
    麻煩您了,也謝謝您的幫忙

    回覆刪除
    回覆
    1. 在 BLOG 的設計中,左邊有一個"範本",點進去之後有一個修改HTML
      找到
      /* Posts----------------------------------------------- */

      所在的地方,CSS 碼放在這行的下面,應該就可以用了

      刪除