FFmpeg在Android使用3

来源:互联网 发布:node.js工资待遇 编辑:程序博客网 时间:2024/06/13 09:13
     时隔一个暑假,在暑假期间就是做北京老程公司的一个关于k歌的手机软件,这就要就我们能过软解码和硬解码。
     我是一直在利用FFmpeg这个库在做这个东西,感觉FFmpeg这个库很牛啊,不过就是太缺少相关的文档,很纠结的时啊。
     目前没课就重新收起这个东西,土壤感觉这个东西太不靠谱或者说指望几个没有流媒体的学生娃来干这事就是有点小难了,不过我还是要有点信心的。
      其他的不说了,言归正传,我以前上传的FFmpeg的东西,大家还记得不,不记得话往前看我的博客。
       这里面有一个问题啊,就是我下好这个HelloJNI程序后像再运行就不行了为什么呢?
       即使我再正一边Cygwin的NDk/ndk-build也还是不行,怎么办 啊。
     请看想这个帖子:
         

                         android 移植ffmpeg后so库的使用

  只需要将我们编译好的ffmpeg的so包(在/obj/local/armeabi/libffmpeg.so)copy到所在ndk下的\platforms\android-8\arch-arm\usr\lib文件夹下就可以了。
  再看下我们的代码吧:
public class HelloJni extends Activity{    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        /* Create a TextView and set its content.         * the text is retrieved by calling a native         * function.         */        TextView  tv = new TextView(this);        String str = String.valueOf(stringFromJNI());        str = str +"\n"+getVoice();        tv.setText(str);        setContentView(tv);    }    public native int getVoice();       public native String  stringFromJNI();    public native String  unimplementedStringFromJNI();        static {          System.loadLibrary("ffmpeg");           System.loadLibrary("hello-jni");       } }
这个是Android上层的使用。下面附上c层的代码
/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */#include <string.h>#include <jni.h>#include <android/log.h>#include <ffmpeg/libavcodec/avcodec.h>#include <ffmpeg/libavformat/avformat.h>#include <ffmpeg/libswscale/swscale.h>#include <string.h>#define LOG_TAG    "***************************lixingyun*****************" // 这个是自定义的LOG的标识#undef LOG // 取消默认的LOG#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) // 定义LOG类型#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) // 定义LOG类型#define LOGW(...)  __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) // 定义LOG类型#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) // 定义LOG类型#define LOGF(...)  __android_log_print(ANDROID_LOG_FATAL,LOG_TAG,__VA_ARGS__) // 定义LOG类型/* This is a trivial JNI example where we use a native method * to return a new VM String. See the corresponding Java source * file located at: * *   apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java */JNIEXPORT jstring Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv* env,jobject thiz) {char str[25];sprintf(str, "%d", avcodec_version());return (*env)->NewStringUTF(env, str);// return (*env)->NewStringUTF(env, "Hello from JNI !");0}JNIEXPORT jint Java_com_example_hellojni_HelloJni_getVoice(JNIEnv* env,jobject thiz) {int flag = 0;AVPacket aacpkt;aacpkt.data = NULL;aacpkt.size = 0;const char *filename = "file:/sdcard/test.mp3";av_init_packet(&aacpkt);av_register_all(); //注册所有可解码类型AVFormatContext *pInFmtCtx = NULL; //文件格式AVCodecContext *pInCodecCtx = NULL; //编码格式pInFmtCtx = avformat_alloc_context();if (av_open_input_file(&pInFmtCtx, filename, NULL, 0, NULL) != 0) //获取文件格式LOGE("av_open_input_file error\n");if (av_find_stream_info(pInFmtCtx) < 0) //获取文件内音视频流的信息LOGE("av_find_stream_info error\n");unsigned int j;// Find the first audio streamint audioStream = -1;// Dump information about file onto standard errordump_format(pInFmtCtx, 0, filename, 0);//从FormatdContext的中找到对应流对应的编码类型,若是CODEC_TYPE_AUDIO则表示是音频for (j = 0; j < pInFmtCtx->nb_streams; j++) //找到音频对应的streamif (pInFmtCtx->streams[j]->codec->codec_type == CODEC_TYPE_AUDIO) {audioStream = j;break;}if (audioStream == -1) {printf("input file has no audio stream\n");return 0; // Didn't find a audio stream}LOGE("audio stream num: %d\n", audioStream);pInCodecCtx = pInFmtCtx->streams[audioStream]->codec; //音频的编码上下文AVCodec *pInCodec = NULL;/* FILE *file3 = fopen("codec_private_data_size.txt","w"); for(int i = 0; i <200000; i++) { pInCodec = avcodec_find_decoder((CodecID)i); if (pInCodec!=NULL) { fprintf(file3,"%s %d\n",pInCodec->name,pInCodec->priv_data_size ); } } fclose(file3); system("pause"); */pInCodec = avcodec_find_decoder(pInCodecCtx->codec_id); //根据编码ID找到用于解码的结构体if (pInCodec == NULL) {printf("error no Codec found\n");return -1; // Codec not found}//使用test的代替pInCodecCtx也可以完成解码,可以看出只要获取以下几个重要信息就可以实现解码和重采样AVCodecContext *test = avcodec_alloc_context();test->bit_rate = pInCodecCtx->bit_rate; //重采样用test->sample_rate = pInCodecCtx->sample_rate; //重采样用test->channels = pInCodecCtx->channels; //重采样用test->extradata = pInCodecCtx->extradata; //若有则必有test->extradata_size = pInCodecCtx->extradata_size; //若有则必要test->codec_type = CODEC_TYPE_AUDIO; //不必要test->block_align = pInCodecCtx->block_align; //必要if (avcodec_open(test, pInCodec) < 0) //将两者结合以便在下面的解码函数中调用pInCodec中的对应解码函数{printf("error avcodec_open failed.\n");return -1; // Could not open codec}if (avcodec_open(pInCodecCtx, pInCodec) < 0) {printf("error avcodec_open failed.\n");return -1; // Could not open codec}static AVPacket packet;LOGI(" bit_rate = %d \r\n", pInCodecCtx->bit_rate);LOGI(" sample_rate = %d \r\n", pInCodecCtx->sample_rate);LOGI(" channels = %d \r\n", pInCodecCtx->channels);LOGI(" code_name = %s \r\n", pInCodecCtx->codec->name);//LOGI("extra data size: %d :data%x %x %x %x\n",pInCodecCtx->extradata_size,pInCodecCtx->extradata[0]// ,pInCodecCtx->extradata[1],pInCodecCtx->extradata[2],pInCodecCtx->extradata[3]);LOGI(" block_align = %d\n", pInCodecCtx->block_align);/********************************************************/unsigned char *outbuf = NULL;outbuf = (unsigned char *) malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE * 2);int outsize;outsize = AVCODEC_MAX_AUDIO_FRAME_SIZE * 2;int len = 0;int size = 0;FILE *out_fp;out_fp = fopen("out.dat", "wb+");while (av_read_frame(pInFmtCtx, &aacpkt) >= 0) {LOGI("***************************");if (aacpkt.stream_index == audioStream) {int declen = 0;size = aacpkt.size;while (aacpkt.size > 0) {outsize = AVCODEC_MAX_AUDIO_FRAME_SIZE * 2;memset(outbuf, 0, outsize);len = avcodec_decode_audio3(pInCodecCtx, (int16_t *) outbuf,&outsize, &aacpkt);if (len < 0) {printf("avcodec_decode_audio3 failed!\n");break;}if (outsize > 0) {fwrite(outbuf, 1, outsize, out_fp);printf("write %d bytes\n", outsize);}declen += len;if (declen == size) {av_free_packet(&aacpkt);printf("packet decoded succeed!\n");break;} else if (declen < size) {aacpkt.size -= len;aacpkt.data += len;} else {printf("decode error!\n");break;}}}}fclose(out_fp);// Close the codecavcodec_close(pInCodecCtx);// Close the video fileav_close_input_file(pInFmtCtx);return flag;}


  微笑其中的LOGE那几个就是Android下的哦。
  再附上Android.mk的东西吧:
 
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)PATH_TO_FFMPEG_SOURCE:=$(LOCAL_PATH)/ffmpeg  LOCAL_C_INCLUDES += $(PATH_TO_FFMPEG_SOURCE)  LOCAL_LDLIBS := -lffmpeg -llog  LOCAL_MODULE    := hello-jniLOCAL_SRC_FILES := hello-jni.cinclude $(BUILD_SHARED_LIBRARY)


哈哈,这样就Ok了。
源码也附上吧.



原创粉丝点击