FFmpeg在Android使用3

     时隔一个暑假,在暑假期间就是做北京老程公司的一个关于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 stream

	int audioStream = -1;
	// Dump information about file onto standard error
	dump_format(pInFmtCtx, 0, filename, 0);

	//从FormatdContext的中找到对应流对应的编码类型,若是CODEC_TYPE_AUDIO则表示是音频
	for (j = 0; j < pInFmtCtx->nb_streams; j++) //找到音频对应的stream
		if (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 codec
	avcodec_close(pInCodecCtx);

	// Close the video file
	av_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-jni
LOCAL_SRC_FILES := hello-jni.c

include $(BUILD_SHARED_LIBRARY)


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



  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值