自学Libyuv 音频转码以及播放

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 __cplusplus
extern "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 PCM
	enum 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------------------
	//JasonPlayer
	jclass 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.write
	jmethodID 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){
		//解码音频类型的Packet
		if(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的size
				int 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_bytep
				memcpy(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 := all
APP_PLATFORM := android-9
APP_OPIM :=debug
由于我这里是把ffmpeg和libyuv同时放在一起
 
Android.mk
LOCAL_PATH := $(call my-dir)

#ffmpeg lib
include $(CLEAR_VARS)
LOCAL_MODULE := avcodec
LOCAL_SRC_FILES := libavcodec-56.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avdevice
LOCAL_SRC_FILES := libavdevice-56.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avfilter
LOCAL_SRC_FILES := libavfilter-5.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avformat
LOCAL_SRC_FILES := libavformat-56.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avutil
LOCAL_SRC_FILES := libavutil-54.so
include $(PREBUILT_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE := postproc
LOCAL_SRC_FILES := libpostproc-53.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swresample
LOCAL_SRC_FILES := libswresample-1.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swscale
LOCAL_SRC_FILES := libswscale-3.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := yuv
LOCAL_SRC_FILES := libyuv.so
include $(PREBUILT_SHARED_LIBRARY)

#myapp
include $(CLEAR_VARS)
LOCAL_MODULE := myffmpeg
LOCAL_SRC_FILES := dn_video_player.c dn_audio_player.c
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include/ffmpeg
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include/libyuv
LOCAL_LDLIBS := -llog -landroid
LOCAL_SHARED_LIBRARIES := avcodec avdevice avfilter avformat avutil postproc swresample swscale yuv
include $(BUILD_SHARED_LIBRARY)
2.openssl es
自学还没学到..




  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值