ijkplayer阅读笔记06-音频流程

本节主要介绍音频从读取,到解码,再到播放的流程:

读取音视频数据(文件或流) --> 创建播放线程 --> 创建解码线程 --> 循环读取音频包 --> 推送到is->audioq ---> audio_thread从audioq获取音频包解码并推送到sampq --> aout_thread 从 sampq获取解码好的音频帧,推送到AudioTrack播放


音频解码流程:从文件或流中读取音频包,推送到is->audioq队列中

1)读取线程
read_thread{
   avformat_open_input
   avformat_find_stream_info
   for (i = 0; i < ic->nb_streams; i++) {
        AVStream *st = ic->streams[i];
        enum AVMediaType type = st->codec->codec_type;
        st_index[type] = i;
   }
   st_index[AVMEDIA_TYPE_AUDIO] = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,
                                st_index[AVMEDIA_TYPE_AUDIO],
                                st_index[AVMEDIA_TYPE_VIDEO],
                                NULL, 0);

   if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
       ret = stream_component_open(ffp, st_index[AVMEDIA_TYPE_VIDEO]);{
           Vid eoState *is = ffp->is;
           AVFormatContext *ic = is->ic;
           AVCodecContext *avctx;
           AVCodec *codec;
           avctx = ic->streams[stream_index]->codec;
           codec = avcodec_find_decoder(avctx->codec_id);
           audio_open(ffp, channel_layout, nb_channels, sample_rate, &is->audio_tgt);{
               wanted_spec.callback = sdl_audio_callback;
               wanted_spec.userdata = opaque;
               SDL_AoutOpenAudio(ffp->aout, &wanted_spec, &spec){
                  aout->open_audio(aout, desired, obtained);{
                      aout_open_audio_n{
                         // aout_thread 线程从解码好的音频帧队列sampq中,循环取数据推入AudioTrack中播放
                         SDL_CreateThreadEx(&opaque->_audio_tid, aout_thread);{
                         }
                      }
                  }
               }
           }
           is->audio_stream = stream_index;
           is->audio_st = ic->streams[stream_index];
           is->audio_tid = SDL_CreateThreadEx(&is->_audio_tid, audio_thread, ffp, "ff_audio_dec"); //创建音频解码线程,从audioq队列中获取音频包,解码并加入sampq音频帧列表中
       }
   }

   for (;;) {
       ret = av_read_frame(ic, pkt);
       packet_queue_put(&is->audioq, pkt);  //读取音频帧,推送到音频帧队列is->aidopq中
   }
}


2)音频解码线程:从is->audioq中获取音频包解码,推送到音频解码帧列表is->sampq中
audio_thread{
do {
      decoder_decode_frame(ffp, &is->auddec, frame, NULL){
         packet_queue_get_or_buffering(ffp, d->queue, &pkt)
         avcodec_decode_audio4
      }
      af = frame_queue_peek_writable(&is->sampq)
      av_frame_move_ref(af->frame, frame);
      frame_queue_push(&is->sampq);
}
}



3)音频播放线程:从音频解码帧列表中is->sampq获取解码帧,推送到AudioTrack播放
aout_thread{
   aout_thread_n{
      while (!opaque->abort_request) {
         audio_cblk(userdata, buffer, copy_size);{
            sdl_audio_callback(void *opaque, Uint8 *stream, int len){
               while (len > 0) {
                  audio_size = audio_decode_frame(ffp);{
                     af = frame_queue_peek_readable(&is->sampq)
                     is->audio_buf = af->frame->data[0];
                  }
                  memcpy(stream, (uint8_t *)is->audio_buf+is->audio_buf_index, len1);
               }
            }
         }
         SDL_Android_AudioTrack_write_byte(env, atrack, buffer, copy_size);
      }
   }
}


你可能感兴趣的:(ffmpeg,android,ijkplayer)