使用JNI调用FFmpeg解码音频并输出到AudioTrack求助

207 篇文章 4 订阅
80 篇文章 1 订阅

http://bbs.csdn.net/topics/390899416

#include <string.h>
#include <jni.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <android/log.h>
//#include "codes_orion_swplayer_MediaObj.h"
#define FILENAME_MAXLEN 1024
#define null NULL
 
char  fileName[FILENAME_MAXLEN];
 
AVFormatContext *pFormatCtx=NULL;
AVCodecContext *pCodecCtx=NULL;
AVCodec *pCodec=NULL;
AVPacket avpkt;
AVFrame *avfrm;
int  audioStream;
size_t  data_size;
 
JNIEXPORT  void  JNICALL Java_codes_orion_swplayer_MediaObj_openFile
   (JNIEnv * env, jobject obj, jstring jfileName) {
     //Convert filename
     strncpy (fileName,(*env)->GetStringUTFChars(env,jfileName,0),FILENAME_MAXLEN);
     //open file to AVFormatContext
     if (avformat_open_input(&pFormatCtx, fileName, NULL, NULL)!=0) {
         __android_log_print(ANDROID_LOG_DEBUG, null,  "fail to open file" );
     }
     if (avformat_find_stream_info(pFormatCtx,NULL)<0) {
         __android_log_print(ANDROID_LOG_DEBUG, null,  "fail to open track" );
     }
     //Find Stream
     int  i;
     audioStream=-1;
     for  (i=0;i<pFormatCtx->nb_streams; i++) {
         if  (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
             audioStream=i;
             break ;
         }
         //TODO:Check Video track
     }
     if  (audioStream == -1) {
         __android_log_print(ANDROID_LOG_DEBUG, null,  "fail to open track" );
     }
     //find decoder
     pCodecCtx=pFormatCtx->streams[audioStream]->codec;
     pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
     if (pCodec==NULL) {
         __android_log_print(ANDROID_LOG_DEBUG, null,  "fail to find decoder" );
     }
     if (pCodec->capabilities & CODEC_CAP_TRUNCATED)
         pCodecCtx->flags|=CODEC_FLAG_TRUNCATED;
 
     if (avcodec_open2(pCodecCtx, pCodec,NULL)<0) {
         __android_log_print(ANDROID_LOG_DEBUG, null,  "fail to open decoder" );
     }
     __android_log_print(ANDROID_LOG_DEBUG, null,  "File opened:\n decoder: %s" ,pCodec->name);
}
 
char  *arr=NULL;
jbyteArray jarr;
 
JNIEXPORT jbyteArray JNICALL Java_codes_orion_swplayer_MediaObj_stream
   (JNIEnv* env, jobject obj, jint minbufsize) {
     data_size=0;
     if  (!arr) {
         arr= malloc ( sizeof ( char )*minbufsize*2);
     }
     while  (data_size<minbufsize) {
         //__android_log_print(ANDROID_LOG_DEBUG, null, "reading");
         for (;;) {
                 if (av_read_frame(pFormatCtx,&avpkt)<0) {
                     __android_log_print(ANDROID_LOG_DEBUG, null,  "cannot read packet" );
                     data_size=0;
                     free (arr);
                     arr=NULL;
                     return  ;
                 }
                 if (avpkt.stream_index!=audioStream) {
                     av_free_packet(&avpkt);
                     continue ;
                 }
                 break ;
             }
             int  got_frame=0,len;
             len = avcodec_decode_audio4(pCodecCtx,avfrm,&got_frame,&avpkt);
             if  (len < 0) {
                 __android_log_print(ANDROID_LOG_DEBUG, null,  "packet len<0" );
                 break ;
             }
         if  (got_frame) {
             int  dsize = av_samples_get_buffer_size(NULL,pCodecCtx->channels,
                                                        avfrm->nb_samples,
                                                        pCodecCtx->sample_fmt, 1);
             memcpy (arr+data_size,avfrm->data[0],dsize);
             data_size+=dsize;
             av_free_packet(&avpkt);
         else  break ;
     }
     __android_log_print(ANDROID_LOG_DEBUG, null,  "minbuf: %d, data_size: %d" ,minbufsize,data_size);
     jarr= (*env)->NewByteArray(env,data_size);
     (*env)->SetByteArrayRegion(env,jarr, 0,data_size,(jbyte*)arr);
     return  jarr;
}
 
JNIEXPORT jint JNICALL Java_codes_orion_swplayer_MediaObj_data_1size
   (JNIEnv *env, jobject obj) {
     return  (jint)data_size;
}
 
 
JNIEXPORT jint JNICALL Java_codes_orion_swplayer_MediaObj_getSampleRate
   (JNIEnv *env, jobject obj) {
     if  (pCodecCtx)
         return  (jint)(pCodecCtx->sample_rate);
}
 
JNIEXPORT jint JNICALL Java_codes_orion_swplayer_MediaObj_getChannel
   (JNIEnv *env, jobject obj) {
     if  (pCodecCtx)
             return  (jint)(pCodecCtx->channels);
}
 
JNIEXPORT  void  JNICALL Java_codes_orion_swplayer_MediaObj_JNIinit
   (JNIEnv *env, jobject obj) {
     //init
     av_register_all();
     avcodec_register_all();
     avfrm=av_frame_alloc();
     av_init_packet(&avpkt);
}
 
JNIEXPORT  void  JNICALL Java_codes_orion_swplayer_MediaObj_JNIexit
   (JNIEnv *env, jobject obj) {
         av_frame_free(&avfrm);
         avcodec_close(pCodecCtx);
         avformat_close_input(&pFormatCtx);
         avformat_free_context(pFormatCtx);
         free (arr);
         arr=NULL;
}

MediaObj.java
Java code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package  codes.orion.swplayer;
 
import  java.io.IOException;
 
import  android.media.AudioTrack;
import  android.media.AudioFormat;
import  android.os.Handler;
import  android.util.Log;
 
 
public  class  MediaObj {
     private  AudioTrack audioTrack;
     private  Handler handler =  new  Handler();
     private  Runnable updateThread =  new  Runnable(){
         public  void  run() {
                 byte [] bytes=stream(minbufsize);
                 int  dsize=data_size();
                 if (audioTrack.write(bytes,  0 , dsize)<dsize) {
                     Log.w( null , "Data not written completely" );
                 }
             handler.postDelayed(updateThread, 50 );
         }
     };
     
     private  int  samplerate,channeltype,minbufsize;
     
     public  void  setDataSource(String sourceFile)  throws  IOException {
         openFile(sourceFile);
         samplerate=getSampleRate();
         if  (getChannel()== 1 )
             channeltype=AudioFormat.CHANNEL_OUT_MONO;
         else
             channeltype=AudioFormat.CHANNEL_OUT_STEREO;
         minbufsize=AudioTrack.getMinBufferSize (samplerate, channeltype, AudioFormat.ENCODING_PCM_16BIT);
         audioTrack =  new  AudioTrack(android.media.AudioManager.STREAM_MUSIC,samplerate,channeltype,
                 AudioFormat.ENCODING_PCM_16BIT,
                 minbufsize* 2 ,
                 AudioTrack.MODE_STREAM);
     }
     
     public  void  prepare() {
     }
     
     public  void  play() {
         handler.post(updateThread);
         audioTrack.play();
     }
     
     public  MediaObj() {
         JNIinit();
     }
     
     @Override
     protected  void  finalize()  throws  Throwable {
         JNIexit();
         handler.removeCallbacks(updateThread);
         super .finalize();
     }
     
     public  native  byte [] stream( int  minbufsize);
     public  native  int  data_size();
     public  native  void  openFile(String sourceFile)  throws  IOException;
     public  native  int  getSampleRate();
     public  native  int  getChannel();
     public  native  void  JNIinit();
     public  native  void  JNIexit();
     static  {
         System.loadLibrary( "mediaobj-jni" );
     }
     
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值