当前位置:操作系统 > 安卓/Android >>

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

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

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


[cpp]
#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_v

补充:移动开发 , Android ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,