FFmpeg在Android使用3
2016-07-05 14:32
246 查看
android 移植ffmpeg后so库的使用
只需要将我们编译好的ffmpeg的so包(在/obj/local/armeabi/libffmpeg.so)copy到所在ndk下的\platforms\android-8\arch-arm\usr\lib文件夹下就可以了。再看下我们的代码吧:
[html] view plain copy print?
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层的代码
[html] view plain copy print?
/*
* 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的东西吧:
[html] view plain copy print?
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了。
源码也附上吧.
相关文章推荐
- 安卓蓝牙BLE设备开发
- android设计模式之装饰模式(一)
- 图解Android View的scrollTo(),scrollBy(),getScrollX(), getScrollY()
- picasso-强大的Android图片下载缓存库
- Android导航栏资源总结,单纯防丢!
- Chason Android Studio 注释模版的使用详解
- Android 4.2.2 系统签名
- android环境搭建有感
- android apilevel和android系统版本对应关系
- Android 手机号验证,用户名验证的正则表达式
- android 的textview显示过长文本时用一个按钮控制展开与收缩
- android framelayout 拖动时,界面压缩变形问题
- 各大热补丁方案分析和比较
- Android——浅谈归纳Handler各种用法
- [置顶] Android开发工具资料Android Manifest 权限描述大全 随时随地查询权限描述。
- android 基础知识回顾--- “沙箱”机制sharedUserId跟签名
- Android之好友列表中的头像置灰设置
- 在ubuntu下的android studio 建立phonegap项目
- Android--从零单排系列(8)--service的使用和利用service进行数据的传递
- 那些Android中的性能优化