Android --- IjkPlayer 阅读native层源码之解码成功后的音频数据如何发送回Android播放(九)

整章目录:Android------- IjkPlayer 源码学习目录

本篇会有很多源代码,请注意阅读每行代码上面的注释。

本篇介绍的主要内容为上图红框圈起部分:  

在前面介绍了如何将一个AvPacket解码为一帧数据,并存入缓存队列中。对于视频帧而言,会有video_refresh_thread线程从缓存队列中取数据,然后渲染到界面上。而缓存队列中的音频数据是由谁取出的????又是如何使用的呢???本篇将聊聊音频数据是如何播放的。

如果你还不知道如何解码,请看:Android --- IjkPlayer 阅读native层源码之如何将AvPacket数据解码出一帧数据(六)

如果你还不知道stream_component_open:请看:Android ---- Ijkplayer阅读native层源码之IjkMediaPlayer_prepareAsync(五)


在stream_component_open中,启动音频解码线程audio_thread的同时,也调用了audio_open函数,去创建音频播放器并开启aout_thread线程(用于处理缓存队列中的帧数据)。下面我们将从audio_open函数开始介绍:

audio_open:

/**
 *
 * @param opaque FFPlayer
 * @param wanted_channel_layout----期望音频存储顺序 eg,AV_CH_LAYOUT_STEREO
 * @param wanted_nb_channels----期望声道数,
 * @param wanted_sample_rate----期望采样率,
 * @param audio_hw_params----记录最终播放的音频参数对象
 * @return
 */
static int audio_open(FFPlayer *opaque, int64_t wanted_channel_layout, int wanted_nb_channels, int wanted_sample_rate, struct AudioParams *audio_hw_params)
{
    
    // 省略。。。。。。
    
    // 期望的音频参数
    wanted_spec.channels = wanted_nb_channels;
    wanted_spec.freq = wanted_sample_rate;
    wanted_spec.format = AUDIO_S16SYS;//2byte
    wanted_spec.silence = 0;
    wanted_spec.samples = FFMAX(SDL_AUDIO_MIN_BUFFER_SIZE, 2 << av_log2(wanted_spec.freq / SDL_AoutGetAudioPerSecondCallBacks(ffp->aout)));
    // 注意这个回调函:将需要播放的音频发送给播放器
    wanted_spec.callback = sdl_audio_callback;
    wanted_spec.userdata = opaque;


    // 创建Java层的AudioTrack,
    // 开启处理队列中音频的线程
    // 最终播方的音频参数存放在spec中
    while (SDL_AoutOpenAudio(ffp->aout, &wanted_spec, &spec) < 0) {
         //如果创建失败,进入改变期望,然后继续创建
    }
 

    // 记录播放的音频参数
    audio_hw_params->fmt = AV_SAMPLE_FMT_S16;
    audio_hw_params->freq = spec.freq;
    audio_hw_params->channel_layout = wanted_channel_layout;
    audio_hw_params->channels =  spec.channels;
    audio_hw_params->frame_size = av_samples_get_buffer_size(NULL, audio_hw_params->channels, 1, audio_hw_params->fmt, 1);
    audio_hw_params->bytes_per_sec = av_samples_get_buffer_size(NULL, audio_hw_params->channels, audio_hw_params->freq, audio_hw_params->fmt, 1);

}

上面代码不难理解,准备一些用于创建音频播放器的参数,存储在wanted_spec结构体中。其中的channel_layout、channels、sample_rate三个参数来自于AVCodecContext中。然后将wanted_spec传入SDL_AoutOpenAudio函数,用于创建音频播放器。默认使用的音频格式为AUDIO_S16SYS(AV_SAMPLE_FMT_S16)

SDL_AoutOpenAudio:

这里需要多说两句,对于Android而言:

  1.  IjkPlayer 默认使用的播放器是Android的AudioTrack.java,所以open_audio指向的是ijksdl_aout_android_audiotrack.c中aout_open_audio函数;
  2.  但是IjkPlayer还提供了另一种播放器:OpenSLES;如果用户想使用该播放器,需要在Java层设置下面的选项:

    然后系统会构建不同的播放环境,下图:ffpipeline_android.c中的函数
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值