资讯详情

ijkplayer 代码走读之 播放器启动过程详解2

这部分是 <<ijkplayer 代码走读之 详细说明播放器启动过程>> 的延续。

我们在看看 ijkplayer 工作流是工作流, 我们只关注走读 2.5、 2.6 和 2.8 有些代码,可以 清晰 ffplay 的工作流. 其中 2.0 有些代码主要是 ffplay 通过控制接口线程SDL EVENT 机制完成后,我们将不展开这部分代码。

///> 2.6 创建 read_thread() 输入数据读取线程, 源码路径ijkmedia/ijkplayer/ff_ffplay.c  /* this thread gets the stream from the disk or the network */ static int read_thread(void *arg) { 
            FFPlayer *ffp = arg;      ///> arg = ffp 播放器实例     VideoState *is = ffp->is;     AVFormatContext *ic = NULL;     int err, i, ret __unused;     int st_index[AVMEDIA_TYPE_NB];     AVPacket pkt1, *pkt = &pkt1;     int64_t stream_start_time;     int completed = 0;     int pkt_in_play_range = 0;     AVDictionaryEntry *t;     SDL_mutex *wait_mutex = SDL_CreateMutex();     int scan_all_pmts_set = 0;     int64_t pkt_ts;     int last_error = 0;     int64_t prev_io_tick_counter = 0;     int64_t io_tick_counter = 0;     int init_ijkmeta = 0;      if (!wait_mutex) { 
                av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());         ret = AVERROR(ENOMEM); goto fail; } memset(st_index, -1, sizeof(st_index)); is->last_video_stream = is->video_stream = -1; is->last_audio_stream = is->audio_stream = -1; is->last_subtitle_stream = is->subtitle_stream = -1; is->eof = 0; ic = avformat_alloc_context(); ///> 创建 avformat context  if (!ic) { 
         av_log(NULL, AV_LOG_FATAL, "Could not allocate context.\n"); ret = AVERROR(ENOMEM); goto fail; } ic->interrupt_callback.callback = decode_interrupt_cb; ///> 设置decode中断回调函数 ic->interrupt_callback.opaque = is; if (!av_dict_get(ffp->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) { 
         av_dict_set(&ffp->format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE); ///> 此部分内容下面会专写一篇博文详解 scan_all_pmts_set = 1; } if (av_stristart(is->filename, "rtmp", NULL) || av_stristart(is->filename, "rtsp", NULL)) { 
         ///> 配置数据源为 rtmp rtsp 类型参数 // 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); } if (ffp->skip_calc_frame_rate) { 
         ///> 配置播放器帧速率 av_dict_set_int(&ic->metadata, "skip-calc-frame-rate", ffp->skip_calc_frame_rate, 0); av_dict_set_int(&ffp->format_opts, "skip-calc-frame-rate", ffp->skip_calc_frame_rate, 0); } if (ffp->iformat_name) is->iformat = av_find_input_format(ffp->iformat_name); err = avformat_open_input(&ic, is->filename, is->iformat, &ffp->format_opts); ///> 配置数据源的视频格式 if (err < 0) { 
         print_error(is->filename, err); ret = -1; goto fail; } ffp_notify_msg1(ffp, FFP_MSG_OPEN_INPUT); ///> 开启 播放器控制输入 if (scan_all_pmts_set) av_dict_set(&ffp->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE); if ((t = av_dict_get(ffp->format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) { 
         av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key); #ifdef FFP_MERGE ret = AVERROR_OPTION_NOT_FOUND; goto fail; #endif } is->ic = ic; if (ffp->genpts) ic->flags |= AVFMT_FLAG_GENPTS; ///> Generate missing pts even if it requires parsing future frames. av_format_inject_global_side_data(ic); // //AVDictionary **opts; //int orig_nb_streams; //opts = setup_find_stream_info_opts(ic, ffp->codec_opts); //orig_nb_streams = ic->nb_streams; if (ffp->find_stream_info) { 
         ///> 根据 codec_opts 内容匹配支持视频流格式,如 flv,mpeg AVDictionary **opts = setup_find_stream_info_opts(ic, ffp->codec_opts); int orig_nb_streams = ic->nb_streams; do { 
         if (av_stristart(is->filename, "data:", NULL) && orig_nb_streams > 0) { 
         for (i = 0; i < orig_nb_streams; i++) { 
         if (!ic->streams[i] || !ic->streams[i]->codecpar || ic->streams[i]->codecpar->profile == FF_PROFILE_UNKNOWN) { 
         break; } } if (i == orig_nb_streams) { 
         break; } } err = avformat_find_stream_info(ic, opts); ///> 匹配过程,重点函数 } while(0); ffp_notify_msg1(ffp, FFP_MSG_FIND_STREAM_INFO);///> 通知播放器视频流格式 for (i = 0; i < orig_nb_streams; i++) av_dict_free(&opts[i]); av_freep(&opts); if (err < 0) { 
         av_log(NULL, AV_LOG_WARNING, "%s: could not find codec parameters\n", is->filename); ret = -1; goto fail; } } if (ic->pb) ic->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use avio_feof() to test for the end if (ffp->seek_by_bytes < 0) ffp->seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT) && strcmp("ogg", ic->iformat->name); is->max_frame_duration = (ic->iformat->flags & AVFMT_TS_DISCONT) ? 10.0 : 3600.0; is->max_frame_duration = 10.0; av_log(ffp, AV_LOG_INFO, "max_frame_duration: %.3f\n", is->max_frame_duration); #ifdef FFP_MERGE if (!window_title && (t = av_dict_get(ic->metadata, "title", NULL, 0))) window_title = av_asprintf("%s - %s", t->value, input_filename); #endif /* if seeking requested, we execute it */ if (ffp->start_time != AV_NOPTS_VALUE) { 
         int64_t timestamp; timestamp = ffp->start_time; /* add the stream start time */ if (ic->start_time != AV_NOPTS_VALUE) timestamp += ic->start_time; ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0); if (ret < 0) { 
         av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n", is->filename, (double)timestamp / AV_TIME_BASE); } } is->realtime = is_realtime(ic); av_dump_format(ic, 0, is->filename, 0); ///> int video_stream_count = 0; int h264_stream_count = 0; int first_h264_stream = -1; for (i = 0; i < ic->nb_streams; i++) { 
         AVStream *st = ic->streams[i]; enum AVMediaType type = st->codecpar->codec_type; st->discard = AVDISCARD_ALL; if (type >= 0 && ffp->wanted_stream_spec[type] && st_index[type] == -1) if (avformat_match_stream_specifier(ic, st, ffp->wanted_stream_spec[type]) > 0) st_index[type] = i; // choose first h264 if (type == AVMEDIA_TYPE_VIDEO) { 
         enum AVCodecID codec_id = st->codecpar->codec_id; video_stream_count++; if (codec_id == AV_CODEC_ID_H264) { 
         h264_stream_count++; if (first_h264_stream < 0) first_h264_stream = i; } } } if (video_stream_count > 1 && st_index[AVMEDIA_TYPE_VIDEO] < 0) { 
         st_index[AVMEDIA_TYPE_VIDEO] = first_h264_stream; av_log(NULL, AV_LOG_WARNING, "multiple video stream found, prefer first h264 stream: %d\n", first_h264_stream); } if (!ffp->video_disable) ///> 配置当前播放器最优的视频解码器 st_index[AVMEDIA_TYPE_VIDEO] = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, st_index[AVMEDIA_TYPE_VIDEO], -1, NULL, 0); if (!ffp->audio_disable) ///> 配置当前播放器最优的音频解码器 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 (!ffp->video_disable && !ffp->subtitle_disable) ///> 配置当前播放器控制 st_index[AVMEDIA_TYPE_SUBTITLE] = av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE, st_index[AVMEDIA_TYPE_SUBTITLE], (st_index[AVMEDIA_TYPE_AUDIO] >= 0 ? st_index[AVMEDIA_TYPE_AUDIO] : st_index[AVMEDIA_TYPE_VIDEO]), NULL, 0); is->show_mode = ffp->show_mode; #ifdef FFP_MERGE // bbc: dunno if we need this if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) { 
         AVStream *st = ic->streams[st_index[AVMEDIA_TYPE_VIDEO]]; AVCodecParameters *codecpar = st->codecpar; AVRational sar = av_guess_sample_aspect_ratio(ic, st, NULL); if (codecpar->width) set_default_window_size(codecpar->width, codecpar->height, sar); } #endif /* open the streams */ if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) { 
         ///> 如果音频有就打开这个流 stream_component_open(ffp, st_index[AVMEDIA_TYPE_AUDIO]); } else { 
         ffp->av_sync_type = AV_SYNC_VIDEO_MASTER; is->av_sync_type = ffp->av_sync_type; } ret = -1; if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) { 
         ///> 如果视频有就打开这个流 ret = stream_component_open(ffp, st_index[AVMEDIA_TYPE_VIDEO]); } if (is->show_mode == SHOW_MODE_NONE) is->show_mode = ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT; if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) { 
         ///> 如果有副标题就打开这个流 stream_component_open(ffp, st_index[AVMEDIA_TYPE_SUBTITLE]); } ffp_notify_msg1(ffp, FFP_MSG_COMPONENT_OPEN); if (!ffp->ijkmeta_delay_init) { 
         ijkmeta_set_avformat_context_l(ffp->meta, ic); ///> 配置 音视频播放参数和副标题语言类型 } ffp->stat.bit_rate = ic->bit_rate; ///> 设置视频播放码率 if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) ijkmeta_set_int64_l(ffp->meta, IJKM_KEY_VIDEO_STREAM, st_index[AVMEDIA_TYPE_VIDEO]); if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) ijkmeta_set_int64_l(ffp->meta, IJKM_KEY_AUDIO_STREAM, st_index[AVMEDIA_TYPE_AUDIO]); if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) ijkmeta_set_int64_l(ffp->meta, IJKM_KEY_TIMEDTEXT_STREAM, st_index[AVMEDIA_TYPE_SUBTITLE]); if (is->video_stream < 0 && is->audio_stream < 0) { 
         av_log(NULL, AV_LOG_FATAL, "Failed to open file '%s' or configure filtergraph\n", is->filename); ret = -1; goto fail; } if (is->audio_stream >= 0) { 
         ///> 配置音视频的队列 is->audioq.is_buffer_indicator = 1; is->buffer_indicator_queue = &is->audioq; } else if (is->video_stream >= 0) { 
         is->videoq.is_buffer_indicator = 1; is->buffer_indicator_queue = &is->videoq; } else { 
         assert("invalid streams"); } if (ffp->infinite_buffer < 0 && is->realtime) ffp->infinite_buffer = 1; if (!ffp->render_wait_start && !ffp->start_on_prepared) ///>  toggle_pause(ffp, 1); if (is->video_st && is->video_st->codecpar) { 
         AVCodecParameters *codecpar = is->video_st->codecpar; ffp_notify_msg3(ffp, FFP_MSG_VIDEO_SIZE_CHANGED, codecpar->width, codecpar->height); ffp_notify_msg3(ffp, FFP_MSG_SAR_CHANGED, codecpar->sample_aspect_ratio.num, codecpar->sample_aspect_ratio.den); } ffp->prepared = true; ffp_notify_msg1(ffp, FFP_MSG_PREPARED); ///> 通知播放器已经准备好 if (!ffp->render_wait_start && !ffp->start_on_prepared) { 
         while (is->pause_req && !is->abort_request) { 
         SDL_Delay(20); } } if (ffp->auto_resume) { 
         ffp_notify_msg1(ffp, FFP_REQ_START); ffp->auto_resume = 0; } /* offset should be seeked*/ if (ffp->seek_at_start > 0) { 
         ffp_seek_to_l(ffp, (long)(ffp->seek_at_start)); } ///> read_thread 线程的 LOOP 主体 for (;;) { 
         if (is->abort_request) break; #ifdef FFP_MERGE if (is->paused != is->last_paused) { 
         is->last_paused = is->paused; if (is->paused) is->read_pause_return = av_read_pause(ic); else av_read_play(ic); } #endif #if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL if (is->paused && (!strcmp(ic->iformat->name, "rtsp") || (ic->pb && !strncmp(ffp->input_filename, "mmsh:", 5)))) { 
         /* wait 10 ms to avoid trying to get another packet */ /* XXX: horrible */ SDL_Delay(10
        标签: 连接器q18j4a

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台