Android本地视频播放器开发--ffmpeg解码视频文件中的音频(1)

在上一章中Android本地视频播放器开发--NDK编译FFmpeg能够获取编译出来的ffmpeg库,接下来就是调用ffmpeg来实现解码,这里我们先解码音频,然后在播放音频,同时为了适应性我会用不同的方法进行播放例如使用Android提供的AudioTrack,SDL、OpengAL,OpenSL ES,最终合入视频播放器的是OpenSL ES,这样可以减少CPU的利用率。接下来在这一章中,先简单的介绍如何解码音频,在下一章中,实现音频的播放。

首先就是编写调用ffmpeg的文件这里命名为:Decodec_Audio.c

 

#include <stdio.h>

#include <stdlib.h>



#include <android/log.h>



#include "VideoPlayerDecode.h"

#include "../ffmpeg/libavutil/avutil.h"

#include "../ffmpeg/libavcodec/avcodec.h"

#include "../ffmpeg/libavformat/avformat.h"



#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "graduation", __VA_ARGS__))



AVFormatContext *pFormatCtx = NULL;

int             audioStream, delay_time, videoFlag = 0;

AVCodecContext  *aCodecCtx;

AVCodec         *aCodec;

AVFrame         *aFrame;

AVPacket        packet;

int  frameFinished = 0;



	JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayer

(JNIEnv *env, jclass clz, jstring fileName)

{

	const char* local_title = (*env)->GetStringUTFChars(env, fileName, NULL);

	av_register_all();//注册所有支持的文件格式以及编解码器

	/*

	 *只读取文件头,并不会填充流信息

	 */

	if(avformat_open_input(&pFormatCtx, local_title, NULL, NULL) != 0)

		return -1;

	/*

	 *获取文件中的流信息,此函数会读取packet,并确定文件中所有流信息,

	 *设置pFormatCtx->streams指向文件中的流,但此函数并不会改变文件指针,

	 *读取的packet会给后面的解码进行处理。

	 */

	if(avformat_find_stream_info(pFormatCtx, NULL) < 0)

		return -1;

	/*

	 *输出文件的信息,也就是我们在使用ffmpeg时能够看到的文件详细信息,

	 *第二个参数指定输出哪条流的信息,-1代表ffmpeg自己选择。最后一个参数用于

	 *指定dump的是不是输出文件,我们的dump是输入文件,因此一定要为0

	 */

	av_dump_format(pFormatCtx, -1, local_title, 0);

	int i = 0;

	for(i=0; i< pFormatCtx->nb_streams; i++)

	{

		if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){

			audioStream = i;

			break;

		}

	}



	if(audioStream < 0)return -1;

	aCodecCtx = pFormatCtx->streams[audioStream]->codec;

	aCodec = avcodec_find_decoder(aCodecCtx->codec_id);

	if(avcodec_open2(aCodecCtx, aCodec, NULL) < 0)return -1;

	aFrame = avcodec_alloc_frame();

	if(aFrame == NULL)return -1;

	int ret;

	while(videoFlag != -1)

	{

		if(av_read_frame(pFormatCtx, &packet) < 0)break;

		if(packet.stream_index == audioStream)

		{

			ret = avcodec_decode_audio4(aCodecCtx, aFrame, &frameFinished, &packet);

			if(ret > 0 && frameFinished)

			{

				int data_size = av_samples_get_buffer_size(

						aFrame->linesize,aCodecCtx->channels,

						aFrame->nb_samples,aCodecCtx->sample_fmt, 0);

				LOGI("audioDecodec  :%d",data_size);

			}



		}

		usleep(50000);

		while(videoFlag != 0)

		{

			if(videoFlag == 1)//暂停

			{

				sleep(1);

			}else if(videoFlag == -1) //停止

			{

				break;

			}

		}

		av_free_packet(&packet);

	}

	av_free(aFrame);

	avcodec_close(aCodecCtx);

	avformat_close_input(&pFormatCtx);

	(*env)->ReleaseStringUTFChars(env, fileName, local_title);

}



JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayerPauseOrPlay

  (JNIEnv *env, jclass clz)

{

        if(videoFlag == 1)

        {

                videoFlag = 0;

        }else if(videoFlag == 0){

                videoFlag = 1;

        }

        return videoFlag;

}



JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayerStop

  (JNIEnv *env, jclass clz)

{

        videoFlag = -1;

}


接下来就是编写Android.mk:

 

 

#######################################################

##########              ffmpeg-prebuilt         #######

#######################################################

#declare the prebuilt library

include $(CLEAR_VARS)

LOCAL_MODULE := ffmpeg-prebuilt

LOCAL_SRC_FILES := ffmpeg/android/armv7-a/libffmpeg-neon.so

LOCAL_EXPORT_C_INCLUDES := ffmpeg/android/armv7-a/include

LOCAL_EXPORT_LDLIBS := ffmpeg/android/armv7-a/libffmpeg-neon.so

LOCAL_PRELINK_MODULE := true

include $(PREBUILT_SHARED_LIBRARY)



########################################################

##              ffmpeg-test-neno.so             ########

########################################################

include $(CLEAR_VARS)

TARGET_ARCH_ABI=armeabi-v7a

LOCAL_ARM_MODE=arm

LOCAL_ARM_NEON=true

LOCAL_ALLOW_UNDEFINED_SYMBOLS=false

LOCAL_MODULE := ffmpeg-test-neon

LOCAL_SRC_FILES := jniffmpeg/Decodec_Audio.c



LOCAL_C_INCLUDES := $(LOCAL_PATH)/ffmpeg/android/armv7-a/include \

                    $(LOCAL_PATH)/ffmpeg \

                    $(LOCAL_PATH)/ffmpeg/libavutil \

                    $(LOCAL_PATH)/ffmpeg/libavcodec \

                    $(LOCAL_PATH)/ffmpeg/libavformat \

                    $(LOCAL_PATH)/ffmpeg/libavcodec \

                    $(LOCAL_PATH)/ffmpeg/libswscale \

                    $(LOCAL_PATH)/jniffmpeg \

                    $(LOCAL_PATH)

LOCAL_SHARED_LIBRARY := ffmpeg-prebuilt

LOCAL_LDLIBS    := -llog -ljnigraphics -lz -lm $(LOCAL_PATH)/ffmpeg/android/armv7-a/libffmpeg-neon.so

include $(BUILD_SHARED_LIBRARY)


然后在终端运行ndk-build,运行结果如下:

 

 

root@zhangjie:/Graduation/jni# ndk-build

Install        : libffmpeg-neon.so => libs/armeabi/libffmpeg-neon.so

Compile arm    : ffmpeg-test-neon <= Decodec_Audio.c

SharedLibrary  : libffmpeg-test-neon.so

Install        : libffmpeg-test-neon.so => libs/armeabi/libffmpeg-test-neon.so


把编译出来的

libffmpeg-test-neon.so
libffmpeg-neon.so

 

 
  

 

拷贝到之前android功能下的libs/armeabi目录下面,点击视频,视频文件开始解码音频,当解码成功,则打印出解码音频包的大小:


 

06-07 04:51:30.953: I/graduation(7014): audioDecodec  :2048

06-07 04:51:31.000: I/graduation(7014): audioDecodec  :2048

06-07 04:51:31.109: I/graduation(7014): audioDecodec  :2048

06-07 04:51:31.156: I/graduation(7014): audioDecodec  :2048

06-07 04:51:31.257: I/graduation(7014): audioDecodec  :2048

06-07 04:51:31.304: I/graduation(7014): audioDecodec  :2048

06-07 04:51:31.406: I/graduation(7014): audioDecodec  :2048

06-07 04:51:31.460: I/graduation(7014): audioDecodec  :2048

06-07 04:51:31.554: I/graduation(7014): audioDecodec  :2048

06-07 04:51:31.609: I/graduation(7014): audioDecodec  :2048

06-07 04:51:31.710: I/graduation(7014): audioDecodec  :2048

06-07 04:51:31.757: I/graduation(7014): audioDecodec  :2048

06-07 04:51:31.859: I/graduation(7014): audioDecodec  :2048

06-07 04:51:31.914: I/graduation(7014): audioDecodec  :2048

06-07 04:51:32.015: I/graduation(7014): audioDecodec  :2048

06-07 04:51:32.062: I/graduation(7014): audioDecodec  :2048

06-07 04:51:32.164: I/graduation(7014): audioDecodec  :2048

06-07 04:51:32.210: I/graduation(7014): audioDecodec  :2048

06-07 04:51:32.312: I/graduation(7014): audioDecodec  :2048

06-07 04:51:32.367: I/graduation(7014): audioDecodec  :2048

06-07 04:51:32.468: I/graduation(7014): audioDecodec  :2048

06-07 04:51:32.515: I/graduation(7014): audioDecodec  :2048

06-07 04:51:32.617: I/graduation(7014): audioDecodec  :2048

06-07 04:51:32.671: I/graduation(7014): audioDecodec  :2048

06-07 04:51:32.773: I/graduation(7014): audioDecodec  :2048

在logcat里面可以看到解码音频成功,下面一章我们将解码出来的音频进行播放。

 

你可能感兴趣的:(android)