FFmpeg在Android使用3

        android 移植ffmpeg后so库的使用

  只需要将我们编译好的ffmpeg的so包(在/obj/local/armeabi/libffmpeg.so)copy到所在ndk下的platformsandroid-8arch-armusrlib文件夹下就可以了。
  再看下我们的代码吧:
  1. public class HelloJni extends Activity  
  2. {  
  3.     /** Called when the activity is first created. */  
  4.     @Override  
  5.     public void onCreate(Bundle savedInstanceState)  
  6.     {  
  7.         super.onCreate(savedInstanceState);  
  8.   
  9.         /* Create a TextView and set its content.  
  10.          * the text is retrieved by calling a native  
  11.          * function.  
  12.          */  
  13.         TextView  tv = new TextView(this);  
  14.         String str = String.valueOf(stringFromJNI());  
  15.         str = str +" "+getVoice();  
  16.         tv.setText(str);  
  17.         setContentView(tv);  
  18.     }  
  19.   
  20.     public native int getVoice();     
  21.     public native String  stringFromJNI();  
  22.     public native String  unimplementedStringFromJNI();  
  23.   
  24.       
  25.     static {    
  26.         System.loadLibrary("ffmpeg");    
  27.          System.loadLibrary("hello-jni");    
  28.      }   
  29. }  
这个是Android上层的使用。下面附上c层的代码
  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 <string.h>  
  18. #include <jni.h>  
  19. #include <android/log.h>  
  20. #include <ffmpeg/libavcodec/avcodec.h>  
  21. #include <ffmpeg/libavformat/avformat.h>  
  22. #include <ffmpeg/libswscale/swscale.h>  
  23. #include <string.h>  
  24.   
  25. #define LOG_TAG    "***************************lixingyun*****************" // 这个是自定义的LOG的标识  
  26. #undef LOG // 取消默认的LOG  
  27. #define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) // 定义LOG类型  
  28. #define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) // 定义LOG类型  
  29. #define LOGW(...)  __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) // 定义LOG类型  
  30. #define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) // 定义LOG类型  
  31. #define LOGF(...)  __android_log_print(ANDROID_LOG_FATAL,LOG_TAG,__VA_ARGS__) // 定义LOG类型  
  32. /* This is a trivial JNI example where we use a native method  
  33.  * to return a new VM String. See the corresponding Java source  
  34.  * file located at:  
  35.  *  
  36.  *   apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java  
  37.  */  
  38. JNIEXPORT jstring Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv* env,  
  39.         jobject thiz) {  
  40.     char str[25];  
  41.     sprintf(str, "%d", avcodec_version());  
  42.   
  43.     return (*env)->NewStringUTF(env, str);  
  44.     // return (*env)->NewStringUTF(env, "Hello from JNI !");0  
  45. }  
  46.   
  47. JNIEXPORT jint Java_com_example_hellojni_HelloJni_getVoice(JNIEnv* env,  
  48.         jobject thiz) {  
  49.     int flag = 0;  
  50.     AVPacket aacpkt;  
  51.     aacpkt.data = NULL;  
  52.     aacpkt.size = 0;  
  53.   
  54.     const char *filename = "file:/sdcard/test.mp3";  
  55.     av_init_packet(&aacpkt);  
  56.     av_register_all(); //注册所有可解码类型  
  57.   
  58.     AVFormatContext *pInFmtCtx = NULL; //文件格式  
  59.     AVCodecContext *pInCodecCtx = NULL; //编码格式  
  60.   
  61.     pInFmtCtx = avformat_alloc_context();  
  62.   
  63.     if (av_open_input_file(&pInFmtCtx, filename, NULL, 0, NULL) != 0) //获取文件格式  
  64.         LOGE("av_open_input_file error ");  
  65.     if (av_find_stream_info(pInFmtCtx) 0) //获取文件内音视频流的信息  
  66.         LOGE("av_find_stream_info error ");  
  67.     unsigned int j;  
  68.     // Find the first audio stream  
  69.   
  70.     int audioStream = -1;  
  71.     // Dump information about file onto standard error  
  72.     dump_format(pInFmtCtx, 0, filename, 0);  
  73.   
  74.     //从FormatdContext的中找到对应流对应的编码类型,若是CODEC_TYPE_AUDIO则表示是音频  
  75.     for (j = 0; j pInFmtCtx->nb_streams; j++) //找到音频对应的stream  
  76.         if (pInFmtCtx->streams[j]->codec->codec_type == CODEC_TYPE_AUDIO) {  
  77.             audioStream = j;  
  78.             break;  
  79.         }  
  80.     if (audioStream == -1) {  
  81.         printf("input file has no audio stream ");  
  82.         return 0; // Didn't find a audio stream  
  83.   
  84.     }  
  85.     LOGE("audio stream num: %d ", audioStream);  
  86.   
  87.     pInCodecCtx = pInFmtCtx->streams[audioStream]->codec; //音频的编码上下文  
  88.     AVCodec *pInCodec = NULL;  
  89.     /* FILE *file3 = fopen("codec_private_data_size.txt","w");  
  90.      for(int i = 0; i <200000; i++)  
  91.      {  
  92.      pInCodec = avcodec_find_decoder((CodecID)i);  
  93.      if (pInCodec!=NULL)  
  94.      {  
  95.      fprintf(file3,"%s %d ",pInCodec->name,pInCodec->priv_data_size );  
  96.      }  
  97.      }  
  98.      fclose(file3);  
  99.      system("pause");  
  100.      */  
  101.     pInCodec = avcodec_find_decoder(pInCodecCtx->codec_id); //根据编码ID找到用于解码的结构体  
  102.     if (pInCodec == NULL) {  
  103.         printf("error no Codec found ");  
  104.         return -1; // Codec not found  
  105.     }  
  106.   
  107.     //使用test的代替pInCodecCtx也可以完成解码,可以看出只要获取以下几个重要信息就可以实现解码和重采样  
  108.     AVCodecContext *test = avcodec_alloc_context();  
  109.     test->bit_rate = pInCodecCtx->bit_rate; //重采样用  
  110.     test->sample_rate = pInCodecCtx->sample_rate; //重采样用  
  111.     test->channels = pInCodecCtx->channels; //重采样用  
  112.     test->extradata = pInCodecCtx->extradata; //若有则必有  
  113.     test->extradata_size = pInCodecCtx->extradata_size; //若有则必要  
  114.     test->codec_type = CODEC_TYPE_AUDIO; //不必要  
  115.     test->block_align = pInCodecCtx->block_align; //必要  
  116.   
  117.     if (avcodec_open(test, pInCodec) 0) //将两者结合以便在下面的解码函数中调用pInCodec中的对应解码函数  
  118.             {  
  119.         printf("error avcodec_open failed. ");  
  120.         return -1; // Could not open codec  
  121.   
  122.     }  
  123.   
  124.     if (avcodec_open(pInCodecCtx, pInCodec) 0) {  
  125.         printf("error avcodec_open failed. ");  
  126.         return -1; // Could not open codec  
  127.   
  128.     }  
  129.   
  130.     static AVPacket packet;  
  131.   
  132.     LOGI(" bit_rate = %d  ", pInCodecCtx->bit_rate);  
  133.     LOGI(" sample_rate = %d  ", pInCodecCtx->sample_rate);  
  134.     LOGI(" channels = %d  ", pInCodecCtx->channels);  
  135.     LOGI(" code_name = %s  ", pInCodecCtx->codec->name);  
  136.     //LOGI("extra data size: %d :data%x %x %x %x ",pInCodecCtx->extradata_size,pInCodecCtx->extradata[0]  
  137.     // ,pInCodecCtx->extradata[1],pInCodecCtx->extradata[2],pInCodecCtx->extradata[3]);  
  138.     LOGI(" block_align = %d ", pInCodecCtx->block_align);  
  139.     /********************************************************/  
  140.     unsigned char *outbuf = NULL;  
  141.     outbuf = (unsigned char *) malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE * 2);  
  142.     int outsize;  
  143.     outsize = AVCODEC_MAX_AUDIO_FRAME_SIZE * 2;  
  144.     int len = 0;  
  145.     int size = 0;  
  146.   
  147.     FILE *out_fp;  
  148.   
  149.     out_fp = fopen("out.dat", "wb+");  
  150.     while (av_read_frame(pInFmtCtx, &aacpkt) >= 0) {  
  151.         LOGI("***************************");  
  152.   
  153.         if (aacpkt.stream_index == audioStream) {  
  154.             int declen = 0;  
  155.             size = aacpkt.size;  
  156.             while (aacpkt.size > 0) {  
  157.                 outsize = AVCODEC_MAX_AUDIO_FRAME_SIZE * 2;  
  158.                 memset(outbuf, 0, outsize);  
  159.                 len = avcodec_decode_audio3(pInCodecCtx, (int16_t *) outbuf,  
  160.                         &outsize, &aacpkt);  
  161.                 if (len 0) {  
  162.                     printf("avcodec_decode_audio3 failed! ");  
  163.                     break;  
  164.                 }  
  165.                 if (outsize > 0) {  
  166.                     fwrite(outbuf, 1, outsize, out_fp);  
  167.                     printf("write %d bytes ", outsize);  
  168.                 }  
  169.                 declen += len;  
  170.                 if (declen == size) {  
  171.                     av_free_packet(&aacpkt);  
  172.                     printf("packet decoded succeed! ");  
  173.                     break;  
  174.                 } else if (declen size) {  
  175.                     aacpkt.size -= len;  
  176.                     aacpkt.data += len;  
  177.                 } else {  
  178.                     printf("decode error! ");  
  179.                     break;  
  180.                 }  
  181.   
  182.             }  
  183.   
  184.         }  
  185.   
  186.     }  
  187.   
  188.     fclose(out_fp);  
  189.     // Close the codec  
  190.     avcodec_close(pInCodecCtx);  
  191.   
  192.     // Close the video file  
  193.     av_close_input_file(pInFmtCtx);  
  194.   
  195.     return flag;  
  196.   
  197. }  


  微笑其中的LOGE那几个就是Android下的哦。
  再附上Android.mk的东西吧:
 
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4. PATH_TO_FFMPEG_SOURCE:=$(LOCAL_PATH)/ffmpeg    
  5. LOCAL_C_INCLUDES += $(PATH_TO_FFMPEG_SOURCE)    
  6. LOCAL_LDLIBS := -lffmpeg -llog    
  7. LOCAL_MODULE    := hello-jni  
  8. LOCAL_SRC_FILES := hello-jni.c  
  9.   
  10. include $(BUILD_SHARED_LIBRARY)  
 
哈哈,这样就Ok了。
源码也附上吧.
 
原文地址:https://www.cnblogs.com/android-blogs/p/5643533.html