当前位置:网站首页>Detailed explanation of the player startup process of ijkplayer code walk through
Detailed explanation of the player startup process of ijkplayer code walk through
2022-06-13 06:27:00 【That's right】
Part 1 ijkPlayer Code walk Demoplayer in , stay Android The code level is how to start the player ,
We've already said that , A brief review , establish app When applied ,
protected void onCreate(Bundle savedInstanceState) {
mVideoView.setVideoPath(); ///> 1. Set the video source content
mVideoView.start(); ///> 2. Start the player
}
mVideoView.setVideoPath(){
mMediaPlayer = createPlayer(); ///> 1.1 Create player
mMediaPlayer.prepareAsync(); ///> 1.2 Set the player to the ready state
}
In short , Building users app when , Create in three steps ijkplayer, They are as follows :
- Create player --> 2. Set the player to the ready state --> 3. Start the player
ijkPlayer How does the kernel library build the player , This time, we will focus on reading this code .
///> The first 1 Step Create player , Source path ijkmedia/ijkplayer/ff_ffplay.c
IjkMediaPlayer *ijkmp_create(int (*msg_loop)(void*))
{
IjkMediaPlayer *mp = (IjkMediaPlayer *) mallocz(sizeof(IjkMediaPlayer));
if (!mp)
goto fail;
mp->ffplayer = ffp_create();
if (!mp->ffplayer)
goto fail;
mp->msg_loop = msg_loop;
ijkmp_inc_ref(mp);
pthread_mutex_init(&mp->mutex, NULL);
return mp;
fail:
ijkmp_destroy_p(&mp);
return NULL;
}
FFPlayer *ffp_create()
{
av_log(NULL, AV_LOG_INFO, "av_version_info: %s\n", av_version_info());
av_log(NULL, AV_LOG_INFO, "ijk_version_info: %s\n", ijk_version_info());
FFPlayer* ffp = (FFPlayer*) av_mallocz(sizeof(FFPlayer));
if (!ffp)
return NULL;
msg_queue_init(&ffp->msg_queue);
ffp->af_mutex = SDL_CreateMutex();
ffp->vf_mutex = SDL_CreateMutex();
ffp_reset_internal(ffp);
ffp->av_class = &ffp_context_class;
ffp->meta = ijkmeta_create();
av_opt_set_defaults(ffp);
return ffp;
}
IjkMediaMeta *ijkmeta_create()
{
IjkMediaMeta *meta = (IjkMediaMeta *)calloc(1, sizeof(IjkMediaMeta));
if (!meta)
return NULL;
meta->mutex = SDL_CreateMutex();
if (!meta->mutex)
goto fail;
return meta;
fail:
ijkmeta_destroy(meta);
return NULL;
}
///> The above procedure is summarized as creating the memory object of the player 、 Then create the corresponding lock .
///> The first 2 Step Get the player ready , Source path ijkmedia/ijkplayer/ff_ffplay.c
int ijkmp_prepare_async(IjkMediaPlayer *mp)
{
assert(mp);
MPTRACE("ijkmp_prepare_async()\n");
pthread_mutex_lock(&mp->mutex);
int retval = ijkmp_prepare_async_l(mp);
pthread_mutex_unlock(&mp->mutex);
MPTRACE("ijkmp_prepare_async()=%d\n", retval);
return retval;
}
static int ijkmp_prepare_async_l(IjkMediaPlayer *mp)
{
assert(mp);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_IDLE);
// MPST_RET_IF_EQ(mp->mp_state, MP_STATE_INITIALIZED);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ASYNC_PREPARING);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PREPARED);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STARTED);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PAUSED);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_COMPLETED);
// MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STOPPED);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ERROR);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_END);
assert(mp->data_source);
ijkmp_change_state_l(mp, MP_STATE_ASYNC_PREPARING);
msg_queue_start(&mp->ffplayer->msg_queue);
// released in msg_loop
ijkmp_inc_ref(mp); ///> 2.0 Create a player control queue , Such as player volume 、 Screen brightness, etc
mp->msg_thread = SDL_CreateThreadEx(&mp->_msg_thread, ijkmp_msg_loop, mp, "ff_msg_loop");
// msg_thread is detached inside msg_loop
// TODO: 9 release weak_thiz if pthread_create() failed;
///> 2.1 hold data source Send to ffplayer in .
int retval = ffp_prepare_async_l(mp->ffplayer, mp->data_source);
if (retval < 0) {
ijkmp_change_state_l(mp, MP_STATE_ERROR);
return retval;
}
return 0;
}
int ffp_prepare_async_l(FFPlayer *ffp, const char *file_name)
{
assert(ffp);
assert(!ffp->is);
assert(file_name);
if (av_stristart(file_name, "rtmp", NULL) ||
av_stristart(file_name, "rtsp", NULL)) {
///> Check whether the protocol type is rtmp,rtsp agreement
// There is total different meaning for 'timeout' option in rtmp
av_log(ffp, AV_LOG_WARNING, "remove 'timeout' option for rtmp.\n");
av_dict_set(&ffp->format_opts, "timeout", NULL, 0); ///> Configuration parameters
}
/* there is a length limit in avformat */
if (strlen(file_name) + 1 > 1024) {
///> Check url Whether the address is too long
av_log(ffp, AV_LOG_ERROR, "%s too long url\n", __func__);
if (avio_find_protocol_name("ijklongurl:")) {
av_dict_set(&ffp->format_opts, "ijklongurl-url", file_name, 0); ///> Set up expand longURL Protocol handling
file_name = "ijklongurl:";
}
}
av_log(NULL, AV_LOG_INFO, "===== versions =====\n");
ffp_show_version_str(ffp, "ijkplayer", ijk_version_info());
ffp_show_version_str(ffp, "FFmpeg", av_version_info());
ffp_show_version_int(ffp, "libavutil", avutil_version());
ffp_show_version_int(ffp, "libavcodec", avcodec_version());
ffp_show_version_int(ffp, "libavformat", avformat_version());
ffp_show_version_int(ffp, "libswscale", swscale_version());
ffp_show_version_int(ffp, "libswresample", swresample_version());
av_log(NULL, AV_LOG_INFO, "===== options =====\n");
ffp_show_dict(ffp, "player-opts", ffp->player_opts);
ffp_show_dict(ffp, "format-opts", ffp->format_opts);
ffp_show_dict(ffp, "codec-opts ", ffp->codec_opts);
ffp_show_dict(ffp, "sws-opts ", ffp->sws_dict);
ffp_show_dict(ffp, "swr-opts ", ffp->swr_opts);
av_log(NULL, AV_LOG_INFO, "===================\n");
av_opt_set_dict(ffp, &ffp->player_opts); ///> Set up ffplayer Default parameters
if (!ffp->aout) {
///> Start audio related configuration , If there is no audio, it will not be configured
ffp->aout = ffpipeline_open_audio_output(ffp->pipeline, ffp);
if (!ffp->aout)
return -1;
}
#if CONFIG_AVFILTER
if (ffp->vfilter0) {
GROW_ARRAY(ffp->vfilters_list, ffp->nb_vfilters);
ffp->vfilters_list[ffp->nb_vfilters - 1] = ffp->vfilter0;
}
#endif
///> 2.2 Turn on the video player input stream
VideoState *is = stream_open(ffp, file_name, NULL);
if (!is) {
av_log(NULL, AV_LOG_WARNING, "ffp_prepare_async_l: stream_open failed OOM");
return EIJK_OUT_OF_MEMORY;
}
ffp->is = is;
ffp->input_filename = av_strdup(file_name);
return 0;
}
///> Player setup process
static VideoState *stream_open(FFPlayer *ffp, const char *filename, AVInputFormat *iformat)
{
assert(!ffp->is);
VideoState *is;
is = av_mallocz(sizeof(VideoState));
if (!is)
return NULL;
is->filename = av_strdup(filename);
if (!is->filename)
goto fail;
is->iformat = iformat;
is->ytop = 0;
is->xleft = 0;
#if defined(__ANDROID__)
if (ffp->soundtouch_enable) {
is->handle = ijk_soundtouch_create();
}
#endif
/* start video display */ ///> 2.3 Create a video stream queue
if (frame_queue_init(&is->pictq, &is->videoq, ffp->pictq_size, 1) < 0)
goto fail; ///> Create a control flow queue
if (frame_queue_init(&is->subpq, &is->subtitleq, SUBPICTURE_QUEUE_SIZE, 0) < 0)
goto fail; ///> Create audio stream queue
if (frame_queue_init(&is->sampq, &is->audioq, SAMPLE_QUEUE_SIZE, 1) < 0)
goto fail;
if (packet_queue_init(&is->videoq) < 0 ||
packet_queue_init(&is->audioq) < 0 ||
packet_queue_init(&is->subtitleq) < 0)
goto fail;
///> 2.4 establish SDL-Cond Of continue_read_thread() Threads
if (!(is->continue_read_thread = SDL_CreateCond())) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
goto fail;
}
///> establish SDL-Cond Of video_accurate_seek_cond() Threads
if (!(is->video_accurate_seek_cond = SDL_CreateCond())) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
ffp->enable_accurate_seek = 0;
}
///> establish SDL-Cond Of audio_accurate_seek_cond() Threads
if (!(is->audio_accurate_seek_cond = SDL_CreateCond())) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
ffp->enable_accurate_seek = 0;
}
init_clock(&is->vidclk, &is->videoq.serial);
init_clock(&is->audclk, &is->audioq.serial);
init_clock(&is->extclk, &is->extclk.serial);
is->audio_clock_serial = -1;
if (ffp->startup_volume < 0)
av_log(NULL, AV_LOG_WARNING, "-volume=%d < 0, setting to 0\n", ffp->startup_volume);
if (ffp->startup_volume > 100)
av_log(NULL, AV_LOG_WARNING, "-volume=%d > 100, setting to 100\n", ffp->startup_volume);
ffp->startup_volume = av_clip(ffp->startup_volume, 0, 100);
ffp->startup_volume = av_clip(SDL_MIX_MAXVOLUME * ffp->startup_volume / 100, 0, SDL_MIX_MAXVOLUME);
is->audio_volume = ffp->startup_volume;
is->muted = 0;
is->av_sync_type = ffp->av_sync_type;
is->play_mutex = SDL_CreateMutex();
is->accurate_seek_mutex = SDL_CreateMutex();
ffp->is = is;
is->pause_req = !ffp->start_on_prepared;
///> 2.5 establish video_refresh_thread() Video refresh thread
is->video_refresh_tid = SDL_CreateThreadEx(&is->_video_refresh_tid, video_refresh_thread, ffp, "ff_vout");
if (!is->video_refresh_tid) {
av_freep(&ffp->is);
return NULL;
}
is->initialized_decoder = 0; ///> 2.6 establish read_thread() Input data reading thread
is->read_tid = SDL_CreateThreadEx(&is->_read_tid, read_thread, ffp, "ff_read");
if (!is->read_tid) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateThread(): %s\n", SDL_GetError());
goto fail;
}
if (ffp->async_init_decoder && !ffp->video_disable && ffp->video_mime_type && strlen(ffp->video_mime_type) > 0
&& ffp->mediacodec_default_name && strlen(ffp->mediacodec_default_name) > 0) {
if (ffp->mediacodec_all_videos || ffp->mediacodec_avc || ffp->mediacodec_hevc || ffp->mediacodec_mpeg2) {
///> 2.7 Initialize encoder
decoder_init(&is->viddec, NULL, &is->videoq, is->continue_read_thread);
///> 2.8 Initialize encoder video pipeline
ffp->node_vdec = ffpipeline_init_video_decoder(ffp->pipeline, ffp);
}
}
is->initialized_decoder = 1;
return is;
fail:
is->initialized_decoder = 1;
is->abort_request = true;
if (is->video_refresh_tid)
SDL_WaitThread(is->video_refresh_tid, NULL);
stream_close(ffp);
return NULL;
}
///> hold The player is configured to ' Preparatory state ' Is the core step of creating a player , I use them separately 2.0 ~ 2.8 Label it . The process is FFMPEG Basic framework logic for video decoding configuration .
///> The first 3 Step ijkmedia/ijkplayer/ff_ffplay.c Start to change the player status to play status , adopt SDL Notify of the event to FFPlayer Just okay 了 .
int ijkmp_start(IjkMediaPlayer *mp)
{
assert(mp);
MPTRACE("ijkmp_start()\n");
pthread_mutex_lock(&mp->mutex);
int retval = ijkmp_start_l(mp);
pthread_mutex_unlock(&mp->mutex);
MPTRACE("ijkmp_start()=%d\n", retval);
return retval;
}
static int ijkmp_start_l(IjkMediaPlayer *mp)
{
assert(mp);
MP_RET_IF_FAILED(ikjmp_chkst_start_l(mp->mp_state));
ffp_remove_msg(mp->ffplayer, FFP_REQ_START);
ffp_remove_msg(mp->ffplayer, FFP_REQ_PAUSE);
ffp_notify_msg1(mp->ffplayer, FFP_REQ_START); ///> notice ffplayer Play audio and video
return 0;
}
static int ikjmp_chkst_start_l(int mp_state)
{
MPST_RET_IF_EQ(mp_state, MP_STATE_IDLE);
MPST_RET_IF_EQ(mp_state, MP_STATE_INITIALIZED);
MPST_RET_IF_EQ(mp_state, MP_STATE_ASYNC_PREPARING);
// MPST_RET_IF_EQ(mp_state, MP_STATE_PREPARED);
// MPST_RET_IF_EQ(mp_state, MP_STATE_STARTED);
// MPST_RET_IF_EQ(mp_state, MP_STATE_PAUSED);
// MPST_RET_IF_EQ(mp_state, MP_STATE_COMPLETED);
MPST_RET_IF_EQ(mp_state, MP_STATE_STOPPED);
MPST_RET_IF_EQ(mp_state, MP_STATE_ERROR);
MPST_RET_IF_EQ(mp_state, MP_STATE_END);
return 0;
}
Through the above process analysis , We basically know that the player is a startup process , For not knowing FFMPEG The player students , still
I don't think the workflow of the player is very clear .
thus , I need to explain ijkplayer encapsulation ffplay The whole logic , First we need to know ijkplayer It's encapsulation ffplay,
ffplay Is running on the so Library based , That is to say, the advertiser instance is in linux User space programs , No Android In the virtual machine
Running programs , The execution efficiency of the player .
secondly ijkplayer encapsulation android The main work of the system is JNI stay ffmpeg Add some functions in ,ffplay The subject does not
Essential change .
Next blog post we are looking at ffplay How workflow works , We only focus on day reading 2.5、 2.6 and 2.8 Part of the code , You can
Clear ffplay The workflow of the . among 2.0 Part of the code is mainly ffplay Control interface threads , The way to achieve this is through SDL EVENT
Mechanism to complete , In this section, we will not expand the walk through code .
边栏推荐
- Echart rectangular tree diagram: simple implementation of rectangular tree diagram
- JetPack - - -WorkManger
- 《MATLAB 神经网络43个案例分析》:第10章 离散Hopfield神经网络的分类——高校科研能力评价
- BlockingQueue源码
- 【2022高考季】作为一个过来人想说的话
- App performance test: (II) CPU
- Kotlin basic definition class, initialization and inheritance
- 自定义View
- Differences among concurrent, parallel, serial, synchronous and asynchronous
- synchronized浅析
猜你喜欢

RFID process management solution for electroplating fixture
![[2022 college entrance examination season] what I want to say as a passer-by](/img/d7/3813b944dc2df182455d475a3669fb.jpg)
[2022 college entrance examination season] what I want to say as a passer-by

Dart class inherits and implements mixed operators

电镀挂具RFID工序管理解决方案

Wechat applet: click the event to obtain the current device information (basic)

Echart折线图:当多条折线图的name一样时也显示不同的颜色

Echart柱状图:echart实现堆叠柱状图

《MATLAB 神经网络43个案例分析》:第10章 离散Hopfield神经网络的分类——高校科研能力评价

JS convert text to language for playback

SSM框架整合--->简单后台管理
随机推荐
Echart柱状图:echart实现堆叠柱状图
Analysis of synchronized
本地文件秒搜工具 Everything
Kotlin basic definition class, initialization and inheritance
The jadx decompiler can decompile jars and apks
Echart line chart: different colors are displayed when the names of multiple line charts are the same
无刷直流电机矢量控制(四):基于滑模观测器的无传感器控制
Echart histogram: echart implements stacked histogram
Wechat applet: click the event to obtain the current device information (basic)
A brief analysis of the overall process of view drawing
[FAQs for novices on the road] about technology management
Simple use of event bus
Notifyitemchanged flash back
Kotlin collaboration - start and cancel, scope
Uni app upload file
Dragon Boat Festival wellbeing, use blessing words to generate word cloud
El form form verification
Waterfall flow layout of uni app Homepage
Echart histogram: X-axis displays value, Y-axis displays category
ADB shell content command debug database