zoukankan      html  css  js  c++  java
  • Android多媒体开发(3)————使用Android NKD编译havlenapetr-FFMpeg-7c27aa2

    1、

            使用NDK去编译官方的FFmpeg原版的话,还得自己实现JNI层与Java层,工程量比较大。所以移植FFmpeg到Android平台时,可以移植一些已经实现JNI与JAVA层的开源项目,毕竟软件行业从来都是站在巨人肩膀上发展的。


    2、移植/FFMpeg  


    havlenapetr的开源项目是比较出名的一个FFmpeg工程,很多Android多媒体项目都是在此基础上面修改的。


    下载地址:https://github.com/havlenapetr/FFMpeg

    可以直接ZIP包:https://github.com/havlenapetr/FFMpeg/zipball/debug

    或者通过Git方式下载,新建一个目录,然后在Linux的终端下执行,当然了,你要事情安装git的相关工具

    1. git clone https://github.com/havlenapetr/FFMpeg.git  

    3、利用NDK编译生成so库


    下载后直接在havlenapetr-FFMpeg-7c27aa2的顶级目录下执行

    1. $ndk/ndk-build  

    是可以编译通过的,不会提示任何error。

    关于如何利用NDK编译,可以参考我之前的博文:http://blog.csdn.net/conowen/article/details/7518870


    4、导入java工程,实现播放

           然后把在eclipse里面,把havlenapetr-FFMpeg-7c27aa2这个项目import进来,就可以播放视频了。


    4.1、需要注意的是:这个版本的havlenapetr FFmpeg工程只能在Android 2.2上面运行,因为havlenapetr采用的是音视频直接在JNI层输入。可以注意到havlenapetr-FFMpeg-7c27aa2目录下有prebuilt这样一个目录,此目录下有Android 2.2版本的libjniaudio.so和libjnivideo.so两个库文件。


    4.2、Android版本不同导致不能播放:

    havlenapetr的FFmpeg项目音视频输出如下

    音频:采用Android底层的audiotrack输出。

    视频:在FFmpeg解码之后,得到YUV信号,然后转换成RGB信号,最终通过Android底层的surface输出。


    提示:可以移植SDL开源库实现音视频输出,因为SDL的视频输出机制是通过OPenGL呈现画面,这样就可以兼容所有的Android平台。


           但是问题就来了,Android每个版本的framework都是不大一样的,所以要在底层使用Android的audiotrack和surface来输入音视频信号,就要在相应版本的Android源代码中,重新编译生成libjniaudio.so和libjnivideo.so两个库文件了。


    5、编译havlenapetr FFmpeg工程Android 2.3版本的libjniaudio.so和libjnivideo.so

              首先要明白一点,Android的官方源代码编译之后,是不会生成libjniaudio.so和libjnivideo.so的。所以要自己添加audiotrack.cpp、surface.cpp和Android.mk文件到Android源代码里面编译生成。(每次编译libjniaudio.so和libjnivideo.so都要重新编译这个Android源代码,时间比较长。)

    5.1下载audio与video文件夹

    可以在https://github.com/havlenapetr/android_frameworks_base下载audiotrack.cpp、surface.cpp和Android.mk,注意要选择正确的branch(分支)

    froyo---->Android 2.2

    gingerbread---->Android 2.3

    ICS---->Android 4.0


    关于havlenapetr-FFMpeg在Android 4.0(ICS)的补充说明



    5.2、编译Android系统源代码

         下载之后,然后找到里面的native文件夹,把里面的audio和video文件夹拖进Android源代码的frameworks/base/native目录下。

    绿色的是新加入的文件


    需要注意的一点是:

    gingerbread下载之后,里面是没有audio和video文件夹的,但是可以用froyo版本的audio和video文件夹。(也就是下载gingerbread感觉也没啥用Orz~~~)

    但是我们可以使用froyo的audio和video文件夹,编译Android源代码是可以成功通过的,ndk-build也可以通过,但是在Android的java工程里面使用就会有以下错误信息。

    1. java.lang.NoSuchFieldError: no field with name='mSurface' signature='I' in class Landroid/view/Surface;  

    加载库时,找不到mSruface类
    修改方法是:
    将surface.cpp中mSurface改为 mNativeSurface ,然后重新编译即可。当然了,你也可以用ICS的surface.cpp文件,这个版本是没有问题的。


    另外编译havlenapetr FFmpeg工程Android 4.0版本的libjniaudio.so和libjnivideo.so与上面步骤差不多。


    /************************************************************************/

    附上我所使用的audio与video(来源havlenapetr的项目)

    video/jni/surface.cpp(注意目录结构)


    1. /* 
    2.  * Copyright (C) 2009 The Android Open Source Project 
    3.  * 
    4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
    5.  * you may not use this file except in compliance with the License. 
    6.  * You may obtain a copy of the License at 
    7.  * 
    8.  *      http://www.apache.org/licenses/LICENSE-2.0 
    9.  * 
    10.  * Unless required by applicable law or agreed to in writing, software 
    11.  * distributed under the License is distributed on an "AS IS" BASIS, 
    12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
    13.  * See the License for the specific language governing permissions and 
    14.  * limitations under the License. 
    15.  */  
    16. #include <android/surface.h>  
    17. #include <surfaceflinger/Surface.h>  
    18. #include <utils/Log.h>  
    19. #include <SkBitmap.h>  
    20. #include <SkCanvas.h>  
    21.   
    22. #define TAG "SurfaceWrapper"  
    23.   
    24. using namespace android;  
    25.   
    26. static Surface*     sSurface;  
    27. static SkBitmap     sBitmapClient;  
    28. static SkBitmap     sBitmapSurface;  
    29.   
    30. static Surface* getNativeSurface(JNIEnv* env, jobject jsurface) {  
    31.     jclass clazz = env->FindClass("android/view/Surface");  
    32.     jfieldID field_surface = env->GetFieldID(clazz, "mNativeSurface", "I");  
    33.     if(field_surface == NULL) {  
    34.         return NULL;  
    35.     }  
    36.     return (Surface *) env->GetIntField(jsurface, field_surface);  
    37. }  
    38.   
    39. static int initBitmap(SkBitmap *bitmap, int format, int width, int height, bool allocPixels) {  
    40.     switch (format) {  
    41.         case PIXEL_FORMAT_RGBA_8888:  
    42.             bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);  
    43.             break;  
    44.               
    45.         case PIXEL_FORMAT_RGBA_4444:  
    46.             bitmap->setConfig(SkBitmap::kARGB_4444_Config, width, height);  
    47.             break;  
    48.               
    49.         case PIXEL_FORMAT_RGB_565:  
    50.             bitmap->setConfig(SkBitmap::kRGB_565_Config, width, height);  
    51.             break;  
    52.               
    53.         case PIXEL_FORMAT_A_8:  
    54.             bitmap->setConfig(SkBitmap::kA8_Config, width, height);  
    55.             break;  
    56.               
    57.         default:  
    58.             bitmap->setConfig(SkBitmap::kNo_Config, width, height);  
    59.             break;  
    60.     }  
    61.       
    62.     if(allocPixels) {  
    63.         bitmap->setIsOpaque(true);  
    64.         //-- alloc array of pixels  
    65.         if(!bitmap->allocPixels()) {  
    66.             return -1;  
    67.         }  
    68.     }  
    69.     return 0;  
    70. }  
    71.   
    72. int AndroidSurface_register(JNIEnv* env, jobject jsurface) {  
    73.     __android_log_print(ANDROID_LOG_INFO, TAG, "registering video surface");  
    74.       
    75.     sSurface = getNativeSurface(env, jsurface);  
    76.     if(sSurface == NULL) {  
    77.          return ANDROID_SURFACE_RESULT_JNI_EXCEPTION;  
    78.     }  
    79.       
    80.     __android_log_print(ANDROID_LOG_INFO, TAG, "registered");  
    81.       
    82.     return ANDROID_SURFACE_RESULT_SUCCESS;  
    83. }  
    84.   
    85. int AndroidSurface_getPixels(int width, int height, void** pixels) {  
    86.     __android_log_print(ANDROID_LOG_INFO, TAG, "getting surface's pixels %ix%i", width, height);  
    87.     if(sSurface == NULL) {  
    88.         return ANDROID_SURFACE_RESULT_JNI_EXCEPTION;  
    89.     }  
    90.     if(initBitmap(&sBitmapClient, PIXEL_FORMAT_RGB_565, width, height, true) < 0) {  
    91.         return ANDROID_SURFACE_RESULT_COULDNT_INIT_BITMAP_CLIENT;  
    92.     }  
    93.     *pixels = sBitmapClient.getPixels();  
    94.     __android_log_print(ANDROID_LOG_INFO, TAG, "getted");  
    95.     return ANDROID_SURFACE_RESULT_SUCCESS;  
    96. }  
    97.   
    98. static void doUpdateSurface() {  
    99.     SkCanvas    canvas(sBitmapSurface);  
    100.     SkRect      surface_sBitmapClient;  
    101.     SkRect      surface_sBitmapSurface;  
    102.     SkMatrix    matrix;  
    103.       
    104.     surface_sBitmapSurface.set(0, 0, sBitmapSurface.width(), sBitmapSurface.height());  
    105.     surface_sBitmapClient.set(0, 0, sBitmapClient.width(), sBitmapClient.height());  
    106.     matrix.setRectToRect(surface_sBitmapClient, surface_sBitmapSurface, SkMatrix::kFill_ScaleToFit);  
    107.       
    108.     canvas.drawBitmapMatrix(sBitmapClient, matrix);  
    109. }  
    110.   
    111. static int prepareSurfaceBitmap(Surface::SurfaceInfo* info) {  
    112.     if(initBitmap(&sBitmapSurface, info->format, info->w, info->h, false) < 0) {  
    113.         return -1;  
    114.     }  
    115.     sBitmapSurface.setPixels(info->bits);  
    116.     return 0;  
    117. }  
    118.   
    119. int AndroidSurface_updateSurface() {  
    120.     static Surface::SurfaceInfo surfaceInfo;  
    121.     if(sSurface == NULL) {  
    122.         return ANDROID_SURFACE_RESULT_JNI_EXCEPTION;  
    123.     }  
    124.     if (!Surface::isValid (sSurface)){  
    125.         return ANDROID_SURFACE_RESULT_NOT_VALID;  
    126.     }  
    127.     if (sSurface->lock(&surfaceInfo) < 0) {  
    128.         return ANDROID_SURFACE_RESULT_COULDNT_LOCK;  
    129.     }  
    130.       
    131.     if(prepareSurfaceBitmap(&surfaceInfo) < 0) {  
    132.         return ANDROID_SURFACE_RESULT_COULDNT_INIT_BITMAP_SURFACE;  
    133.     }  
    134.       
    135.     doUpdateSurface();  
    136.       
    137.     if (sSurface->unlockAndPost() < 0) {  
    138.         return ANDROID_SURFACE_RESULT_COULDNT_UNLOCK_AND_POST;  
    139.     }  
    140.     return ANDROID_SURFACE_RESULT_SUCCESS;  
    141. }  
    142.   
    143. int AndroidSurface_unregister() {  
    144.     __android_log_print(ANDROID_LOG_INFO, TAG, "unregistering video surface");  
    145.     __android_log_print(ANDROID_LOG_INFO, TAG, "unregistered");  
    146.     return ANDROID_SURFACE_RESULT_SUCCESS;  
    147. }  



    video/jni/Android.mk(注意目录结构)

    1. LOCAL_PATH:= $(call my-dir)  
    2. include $(CLEAR_VARS)  
    3.   
    4. # our source files  
    5. #  
    6. LOCAL_SRC_FILES:=   
    7.     surface.cpp  
    8.   
    9. LOCAL_SHARED_LIBRARIES :=   
    10.     libskia   
    11.         libsurfaceflinger_client   
    12.         libutils   
    13.     liblog  
    14.   
    15. LOCAL_C_INCLUDES +=   
    16.     $(JNI_H_INCLUDE)   
    17.     external/skia/src/core   
    18.     external/skia/include/core   
    19.     frameworks/base/include   
    20.     frameworks/base/native/include  
    21.   
    22. # Optional tag would mean it doesn't get installed by default  
    23. LOCAL_MODULE_TAGS := optional  
    24.   
    25. LOCAL_PRELINK_MODULE := false  
    26.   
    27. LOCAL_MODULE:= libjnivideo  
    28.   
    29. include $(BUILD_SHARED_LIBRARY)  


    /audio/jni/audiotrack.cpp(注意目录结构)

    1. /* 
    2.  * Copyright (C) 2009 The Android Open Source Project 
    3.  * 
    4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
    5.  * you may not use this file except in compliance with the License. 
    6.  * You may obtain a copy of the License at 
    7.  * 
    8.  *      http://www.apache.org/licenses/LICENSE-2.0 
    9.  * 
    10.  * Unless required by applicable law or agreed to in writing, software 
    11.  * distributed under the License is distributed on an "AS IS" BASIS, 
    12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
    13.  * See the License for the specific language governing permissions and 
    14.  * limitations under the License. 
    15.  */  
    16.   
    17. #include <android/audiotrack.h>  
    18. #include <utils/Log.h>  
    19. #include <media/AudioTrack.h>  
    20. #include <media/AudioSystem.h>  
    21. #include <utils/Errors.h>  
    22.   
    23. #include <binder/MemoryHeapBase.h>  
    24. #include <binder/MemoryBase.h>  
    25.   
    26. #define TAG "AudioTrackWrapper"  
    27.   
    28. using namespace android;  
    29.   
    30. //struct audiotrack_fields_t {  
    31. static AudioTrack*                        track;  
    32. //sp<MemoryHeapBase>                    memHeap;  
    33. //sp<MemoryBase>                        memBase;  
    34. //};  
    35. //static struct audiotrack_fields_t audio;  
    36.   
    37. static AudioTrack* getNativeAudioTrack(JNIEnv* env, jobject jaudioTrack) {  
    38.     jclass clazz = env->FindClass("android/media/AudioTrack");  
    39.     jfieldID field_track = env->GetFieldID(clazz, "mNativeTrackInJavaObj", "I");  
    40.     if(field_track == NULL) {  
    41.         return NULL;  
    42.     }  
    43.     return (AudioTrack *) env->GetIntField(jaudioTrack, field_track);  
    44. }  
    45.   
    46. /* 
    47. static bool allocSharedMem(int sizeInBytes) { 
    48.     memHeap = new MemoryHeapBase(sizeInBytes); 
    49.     if (memHeap->getHeapID() < 0) { 
    50.         return false; 
    51.     } 
    52.     memBase = new MemoryBase(memHeap, 0, sizeInBytes); 
    53.     return true; 
    54. */  
    55.   
    56. int AndroidAudioTrack_register() {  
    57.     __android_log_print(ANDROID_LOG_INFO, TAG, "registering audio track");  
    58.     track = new AudioTrack();  
    59.     if(track == NULL) {  
    60.          return ANDROID_AUDIOTRACK_RESULT_JNI_EXCEPTION;  
    61.     }  
    62.     __android_log_print(ANDROID_LOG_INFO, TAG, "registered");  
    63.     return ANDROID_AUDIOTRACK_RESULT_SUCCESS;  
    64. }  
    65.   
    66. int AndroidAudioTrack_start() {  
    67.     //__android_log_print(ANDROID_LOG_INFO, TAG, "starting audio track");  
    68.     if(track == NULL) {  
    69.         return ANDROID_AUDIOTRACK_RESULT_ALLOCATION_FAILED;  
    70.     }  
    71.     track->start();  
    72.     return ANDROID_AUDIOTRACK_RESULT_SUCCESS;  
    73. }  
    74.   
    75. int AndroidAudioTrack_set(int streamType,  
    76.                           uint32_t sampleRate,  
    77.                           int format,  
    78.                           int channels) {  
    79.     if(track == NULL) {  
    80.         return ANDROID_AUDIOTRACK_RESULT_ALLOCATION_FAILED;  
    81.     }  
    82.       
    83.     __android_log_print(ANDROID_LOG_INFO, TAG, "setting audio track");  
    84.       
    85.     status_t ret = track->set(streamType,   
    86.                               sampleRate,   
    87.                               format,   
    88.                               channels,   
    89.                               0,   
    90.                               0,  
    91.                               0,   
    92.                               0,  
    93.                               false);  
    94.       
    95.     if (ret != NO_ERROR) {  
    96.         return ANDROID_AUDIOTRACK_RESULT_ERRNO;  
    97.     }  
    98.     return ANDROID_AUDIOTRACK_RESULT_SUCCESS;  
    99. }  
    100.   
    101. int AndroidAudioTrack_flush() {  
    102.     if(track == NULL) {  
    103.         return ANDROID_AUDIOTRACK_RESULT_ALLOCATION_FAILED;  
    104.     }  
    105.     track->flush();  
    106.     return ANDROID_AUDIOTRACK_RESULT_SUCCESS;  
    107. }  
    108.   
    109. int AndroidAudioTrack_stop() {  
    110.     if(track == NULL) {  
    111.         return ANDROID_AUDIOTRACK_RESULT_ALLOCATION_FAILED;  
    112.     }  
    113.     track->stop();  
    114.     return ANDROID_AUDIOTRACK_RESULT_SUCCESS;  
    115. }  
    116.   
    117. int AndroidAudioTrack_reload() {  
    118.     if(track == NULL) {  
    119.         return ANDROID_AUDIOTRACK_RESULT_ALLOCATION_FAILED;  
    120.     }  
    121.     if(track->reload() != NO_ERROR) {  
    122.         return ANDROID_AUDIOTRACK_RESULT_ERRNO;  
    123.     }  
    124.     return ANDROID_AUDIOTRACK_RESULT_SUCCESS;  
    125. }  
    126.   
    127. int AndroidAudioTrack_unregister() {  
    128.     __android_log_print(ANDROID_LOG_INFO, TAG, "unregistering audio track");  
    129.     if(!track->stopped()) {  
    130.         track->stop();  
    131.     }  
    132.     //memBase.clear();  
    133.     //memHeap.clear();  
    134.     free(track);  
    135.     //track = NULL;  
    136.     __android_log_print(ANDROID_LOG_INFO, TAG, "unregistered");  
    137.     return ANDROID_AUDIOTRACK_RESULT_SUCCESS;  
    138. }  
    139.   
    140. int AndroidAudioTrack_write(void *buffer, int buffer_size) {  
    141.     // give the data to the native AudioTrack object (the data starts at the offset)  
    142.     ssize_t written = 0;  
    143.     // regular write() or copy the data to the AudioTrack's shared memory?  
    144.     if (track->sharedBuffer() == 0) {  
    145.         written = track->write(buffer, buffer_size);  
    146.     } else {  
    147.         // writing to shared memory, check for capacity  
    148.         if ((size_t)buffer_size > track->sharedBuffer()->size()) {  
    149.             __android_log_print(ANDROID_LOG_INFO, TAG, "buffer size was too small");  
    150.             buffer_size = track->sharedBuffer()->size();  
    151.         }  
    152.         memcpy(track->sharedBuffer()->pointer(), buffer, buffer_size);  
    153.         written = buffer_size;  
    154.     }  
    155.     return written;  
    156. }  


    /audio/jni/Android.mk(注意目录结构)

      1. LOCAL_PATH:= $(call my-dir)  
      2. include $(CLEAR_VARS)  
      3.   
      4. # our source files  
      5. #  
      6. LOCAL_SRC_FILES:=   
      7.     audiotrack.cpp  
      8.   
      9. LOCAL_SHARED_LIBRARIES :=   
      10.     libbinder   
      11.         libmedia   
      12.         libutils   
      13.     liblog  
      14.   
      15. LOCAL_C_INCLUDES +=   
      16.     $(JNI_H_INCLUDE)   
      17.     frameworks/base/include   
      18.     frameworks/base/native/include  
      19.   
      20. # Optional tag would mean it doesn't get installed by default  
      21. LOCAL_MODULE_TAGS := optional  
      22.   
      23. LOCAL_PRELINK_MODULE := false  
      24.   
      25. LOCAL_MODULE:= libjniaudio  
      26.   
      27. include $(BUILD_SHARED_LIBRARY) 
  • 相关阅读:
    Django中查询相关操作
    django Field选项中null和blank的区别
    翻转链表和k个一组翻转以及两两反转
    一道腾讯面试题:如何快速判断某 URL 是否在 20 亿的网址 URL 集合中?
    struct-config.xml配置文件的解析
    taglib标签在web.xml文件中报错的解决办法
    解决html中的乱码问题
    css的学习笔记
    选择器要这么用!!!!66666
    什么是个CDN???CDN是干什么的??
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/6154896.html
Copyright © 2011-2022 走看看