自学Libyuv 音频转码以及播放
来源:互联网 发布:强矩阵式管理 编辑:程序博客网 时间:2024/06/05 05:36
libyuv
下载libyuv
新建jni目录吧libyuv下所有东西考入
修改Android.mk文件
末尾 STATIC 改为 SHARED
生成的文件名 libyuv_static 改为 libyuv
添加到压缩包 libyuv.zip
上传到linux服务器
unzip libyuv.zip
切换到libyuv目录
然后 ndk-build
把生成的so库 pull下来
在android项目中 记得导入libyuv include 下的头文件(/home/jason/libyuv/jni/include) 和 linux服务器上pull 下来的so库(/home/jason/libyuv/libs/armeabi)
====================================================================上面都是准备工作
1.新建JasonPlayer类
public native void sound(String input,String output);2.javah 生成头文件 com_boom_audioplayer_JasonPlayer.h
/* DO NOT EDIT THIS FILE - it is machine generated */#include "jni.h"/* Header for class com_boom_audioplayer_JasonPlayer */#ifndef _Included_com_boom_audioplayer_JasonPlayer#define _Included_com_boom_audioplayer_JasonPlayer#ifdef __cplusplusextern "C" {#endif/* * Class: com_boom_audioplayer_JasonPlayer * Method: sound * Signature: (Ljava/lang/String;Ljava/lang/String;)V */JNIEXPORT void JNICALL Java_com_boom_audioplayer_JasonPlayer_sound (JNIEnv *, jobject, jstring, jstring);#ifdef __cplusplus}#endif#endif
3.实现具体 dn_audio_player.c
#include "com_boom_audioplayer_JasonPlayer.h"#include <stdlib.h>#include <unistd.h>#include <android/log.h>#define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"jason",FORMAT,##__VA_ARGS__);#define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"jason",FORMAT,##__VA_ARGS__);#define MAX_AUDIO_FRME_SIZE 48000 * 4//封装格式#include "libavformat/avformat.h"//解码#include "libavcodec/avcodec.h"//缩放#include "libswscale/swscale.h"//重采样#include "libswresample/swresample.h"JNIEXPORT void JNICALL Java_com_boom_audioplayer_JasonPlayer_sound (JNIEnv *env, jobject jthiz, jstring input_jstr, jstring output_jstr){const char* input_cstr = (*env)->GetStringUTFChars(env,input_jstr,NULL);const char* output_cstr = (*env)->GetStringUTFChars(env,output_jstr,NULL);LOGI("%s","sound");//注册组件av_register_all();AVFormatContext *pFormatCtx = avformat_alloc_context();//打开音频文件if(avformat_open_input(&pFormatCtx,input_cstr,NULL,NULL) != 0){LOGI("%s","无法打开音频文件");return;}//获取输入文件信息if(avformat_find_stream_info(pFormatCtx,NULL) < 0){LOGI("%s","无法获取输入文件信息");return;}//获取音频流索引位置int i = 0, audio_stream_idx = -1;for(; i < pFormatCtx->nb_streams;i++){if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){audio_stream_idx = i;break;}}//获取解码器AVCodecContext *codecCtx = pFormatCtx->streams[audio_stream_idx]->codec;AVCodec *codec = avcodec_find_decoder(codecCtx->codec_id);if(codec == NULL){LOGI("%s","无法获取解码器");return;}//打开解码器if(avcodec_open2(codecCtx,codec,NULL) < 0){LOGI("%s","无法打开解码器");return;}//压缩数据AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));//解压缩数据AVFrame *frame = av_frame_alloc();//frame->16bit 44100 PCM 统一音频采样格式与采样率SwrContext *swrCtx = swr_alloc();//重采样设置参数-------------start//输入的采样格式enum AVSampleFormat in_sample_fmt = codecCtx->sample_fmt;//输出采样格式16bit PCMenum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;//输入采样率int in_sample_rate = codecCtx->sample_rate;//输出采样率int out_sample_rate = in_sample_rate;//获取输入的声道布局//根据声道个数获取默认的声道布局(2个声道,默认立体声stereo)//av_get_default_channel_layout(codecCtx->channels);uint64_t in_ch_layout = codecCtx->channel_layout;//输出的声道布局(立体声)uint64_t out_ch_layout = AV_CH_LAYOUT_STEREO;swr_alloc_set_opts(swrCtx, out_ch_layout,out_sample_fmt,out_sample_rate, in_ch_layout,in_sample_fmt,in_sample_rate, 0, NULL);swr_init(swrCtx);//输出的声道个数int out_channel_nb = av_get_channel_layout_nb_channels(out_ch_layout);//重采样设置参数-------------end//JNI begin------------------//JasonPlayerjclass player_class = (*env)->GetObjectClass(env,jthiz);//AudioTrack对象jmethodID create_audio_track_mid = (*env)->GetMethodID(env,player_class,"createAudioTrack","(II)Landroid/media/AudioTrack;");jobject audio_track = (*env)->CallObjectMethod(env,jthiz,create_audio_track_mid,out_sample_rate,out_channel_nb);//调用AudioTrack.play方法jclass audio_track_class = (*env)->GetObjectClass(env,audio_track);jmethodID audio_track_play_mid = (*env)->GetMethodID(env,audio_track_class,"play","()V");(*env)->CallVoidMethod(env,audio_track,audio_track_play_mid);//AudioTrack.writejmethodID audio_track_write_mid = (*env)->GetMethodID(env,audio_track_class,"write","([BII)I");//JNI end------------------FILE *fp_pcm = fopen(output_cstr,"wb");//16bit 44100 PCM 数据uint8_t *out_buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRME_SIZE);int got_frame = 0,index = 0, ret;//不断读取压缩数据while(av_read_frame(pFormatCtx,packet) >= 0){//解码音频类型的Packetif(packet->stream_index == audio_stream_idx){//解码ret = avcodec_decode_audio4(codecCtx,frame,&got_frame,packet);if(ret < 0){LOGI("%s","解码完成");}//解码一帧成功if(got_frame > 0){LOGI("解码:%d",index++);swr_convert(swrCtx, &out_buffer, MAX_AUDIO_FRME_SIZE,(const uint8_t **)frame->data,frame->nb_samples);//获取sample的sizeint out_buffer_size = av_samples_get_buffer_size(NULL, out_channel_nb,frame->nb_samples, out_sample_fmt, 1);fwrite(out_buffer,1,out_buffer_size,fp_pcm);//out_buffer缓冲区数据,转成byte数组jbyteArray audio_sample_array = (*env)->NewByteArray(env,out_buffer_size);jbyte* sample_bytep = (*env)->GetByteArrayElements(env,audio_sample_array,NULL);//out_buffer的数据复制到sampe_bytepmemcpy(sample_bytep,out_buffer,out_buffer_size);//同步(*env)->ReleaseByteArrayElements(env,audio_sample_array,sample_bytep,0);//AudioTrack.write PCM数据(*env)->CallIntMethod(env,audio_track,audio_track_write_mid,audio_sample_array,0,out_buffer_size);//释放局部引用(*env)->DeleteLocalRef(env,audio_sample_array);usleep(1000 * 16);}}av_free_packet(packet);}av_frame_free(&frame);av_free(out_buffer);swr_free(&swrCtx);avcodec_close(codecCtx);avformat_close_input(&pFormatCtx);(*env)->ReleaseStringUTFChars(env,input_jstr,input_cstr);(*env)->ReleaseStringUTFChars(env,output_jstr,output_cstr);}
javap -s 类名 获取类中方法的签名 (要cd到 项目的classes目录)
添加权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />Application.mk
APP_ABI := allAPP_PLATFORM := android-9APP_OPIM :=debug由于我这里是把ffmpeg和libyuv同时放在一起
Android.mk
LOCAL_PATH := $(call my-dir)#ffmpeg libinclude $(CLEAR_VARS)LOCAL_MODULE := avcodecLOCAL_SRC_FILES := libavcodec-56.soinclude $(PREBUILT_SHARED_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := avdeviceLOCAL_SRC_FILES := libavdevice-56.soinclude $(PREBUILT_SHARED_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := avfilterLOCAL_SRC_FILES := libavfilter-5.soinclude $(PREBUILT_SHARED_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := avformatLOCAL_SRC_FILES := libavformat-56.soinclude $(PREBUILT_SHARED_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := avutilLOCAL_SRC_FILES := libavutil-54.soinclude $(PREBUILT_SHARED_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := postprocLOCAL_SRC_FILES := libpostproc-53.soinclude $(PREBUILT_SHARED_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := swresampleLOCAL_SRC_FILES := libswresample-1.soinclude $(PREBUILT_SHARED_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := swscaleLOCAL_SRC_FILES := libswscale-3.soinclude $(PREBUILT_SHARED_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := yuvLOCAL_SRC_FILES := libyuv.soinclude $(PREBUILT_SHARED_LIBRARY)#myappinclude $(CLEAR_VARS)LOCAL_MODULE := myffmpegLOCAL_SRC_FILES := dn_video_player.c dn_audio_player.cLOCAL_C_INCLUDES += $(LOCAL_PATH)/include/ffmpegLOCAL_C_INCLUDES += $(LOCAL_PATH)/include/libyuvLOCAL_LDLIBS := -llog -landroidLOCAL_SHARED_LIBRARIES := avcodec avdevice avfilter avformat avutil postproc swresample swscale yuvinclude $(BUILD_SHARED_LIBRARY)
2.openssl es
自学还没学到..
阅读全文