ijkplayer 音频播放线程

匿名 (未验证) 提交于 2019-12-03 00:22:01

音频播放有一部分在ijkplayer读线程中提到过,就是在读线程read_thread()中调用的stream_component_open()函数中会调用audio_open(),然后会调用aout->open_audio()函数,这个函数指针的赋值在ijkplayer初始化流程中的ff_ffpipeline_android.c/ func_open_audio_output()函数赋值,func_open_audio_output函数会先选择使用audiotrack还是opensles,这里以audiotrack为例,最终会调用SDL_CreateThreadEx(…, aout_thread, aout, …)创建音频输出线程

音频输出线程aout_thread函数里面又调用ijksdl_aout_android_audiotrack.c/aout_thread_n()函数,下面来看一下该函数的重点代码

static int aout_thread_n(JNIEnv *env, SDL_Aout *aout) {         ...         audio_cblk(userdata, buffer, copy_size);         ...         if (opaque->need_flush) {             opaque->need_flush = 0;             SDL_Android_AudioTrack_flush(env, atrack);         } else {             int written = SDL_Android_AudioTrack_write(env, atrack, buffer, copy_size);             if (written != copy_size) {                 ALOGW("AudioTrack: not all data copied %d/%d", (int)written, (int)copy_size);             }         // TODO: 1 if callback return -1 or 0     }     ... }

可以看出音频播放线程这里主要干了两件事
1. 调用回调函数audio_cblk
2. 调用SDL_Android_AudioTrack_write()

1. 调用回调函数audio_cblk
首先看一下第一步,调用audio_cblk,该回调函数指针的赋值是在ff_ffplayer.c/audio_open(),里面有句话

wanted_spec.callback = sdl_audio_callback

调用audio_cblk其实就是调用来sdl_audio_callback,具体赋值有点点曲折,可以自己跟一下,来看看sdl_audio_callback函数做了些什么

/* prepare a new audio buffer */ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) {     ...     while (len > 0) {         if (is->audio_buf_index >= is->audio_buf_size) {            audio_size = audio_decode_frame(ffp);            ...         }         ...         if (!is->muted && is->audio_buf && is->audio_volume == SDL_MIX_MAXVOLUME)             memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);         else {             memset(stream, 0, len1);             if (!is->muted && is->audio_buf)                 SDL_MixAudio(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1, is->audio_volume);         }         len -= len1;         stream += len1;         is->audio_buf_index += len1;     }     ... }

sdl_audio_callback函数调用了ff_ffplayer.c/audio_decode_frame(),先来看看audio_decode_frame代码

/**  * Decode one audio frame and return its uncompressed size.  *  * The processed audio frame is decoded, converted if required, and  * stored in is->audio_buf, with size in bytes given by the return  * value.  */ static int audio_decode_frame(FFPlayer *ffp) {     ... reload:     do {         ...         if (!(af = frame_queue_peek_readable(&is->sampq)))             return -1;         frame_queue_next(&is->sampq);     } while (af->serial != is->audioq.serial);      ...     if (is->swr_ctx) {             ...     } else {         is->audio_buf = af->frame->data[0];         resampled_data_size = data_size;     }     ... }

上面函数中的ff_ffplayer.c/frame_queue_peek_readable()和ff_ffplayer.c/frame_queue_next()函数类似与ijkplayer 音频解码线程中将的frame_queue_peek_writable()和frame_queue_push(),ff_ffplayer.c/frame_queue_peek_readable()检查sampq是否为空,如果为空则阻塞,接着ff_ffplayer.c/frame_queue_next()用来唤醒sampq的写操作,因为当sampq不可写时也会阻塞,最后is->audio_buf = af->frame->data[0]给audio_buf赋值

sdl_audio_callback函数调用完ff_ffplayer.c/audio_decode_frame()后,将赋好值的audio_buf给了stream,这个stream时调用audio_cblk(userdata, buffer, copy_size)传进来的这个buffer,说白了sdl_audio_callback函数也就是将sampq中的一帧给了这个buffer

2. 调用SDL_Android_AudioTrack_write()
现在看音频播放函数中的第二步调用SDL_Android_AudioTrack_write(env, atrack, buffer, copy_size),这个buffer就是刚刚从回调函数sdl_audio_callback取出来的也就是从sampq中取出来的,怎么用这个buffer,看下面代码

int SDL_Android_AudioTrack_write(JNIEnv *env, SDL_Android_AudioTrack *atrack, uint8_t *data, int size_in_byte) {     ...     (*env)->SetByteArrayRegion(env, atrack->byte_buffer, 0, (int)size_in_byte, (jbyte*) data);     if (J4A_ExceptionCheck__catchAll(env))         return -1;      int retval = J4AC_AudioTrack__write(env, atrack->thiz, atrack->byte_buffer, 0, (int)size_in_byte);     ... }

这里将buffer也就是函数里的data放入byte_buffer中,后面调用 J4AC_AudioTrack__write函数最后调用java代码输出。

这里音频播放线程流程就结束了,其实就是干了两件事,取sampq中解码好的音频帧,然后传给java代码输出

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!