/*** Open an input stream and read the header. The codecs are not opened.* The stream must be closed with avformat_close_input().** @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context).* May be a pointer to NULL, in which case an AVFormatContext is allocated by this* function and written into ps.* Note that a user-supplied AVFormatContext will be freed on failure.* @param url URL of the stream to open.* @param fmt If non-NULL, this parameter forces a specific input format.* Otherwise the format is autodetected.* @param options A dictionary filled with AVFormatContext and demuxer-private options.* On return this parameter will be destroyed and replaced with a dict containing* options that were not found. May be NULL.** @return 0 on success, a negative AVERROR on failure.** @note If you want to use custom IO, preallocate the format context and set its pb field.*/intavformat_open_input(AVFormatContext **ps,const char *url, ff_const59 AVInputFormat *fmt, AVDictionary **options);
/*** Read packets of a media file to get stream information. This* is useful for file formats with no headers such as MPEG. This* function also computes the real framerate in case of MPEG-2 repeat* frame mode.* The logical file position is not changed by this function;* examined packets may be buffered for later processing.** @param ic media file handle* @param options If non-NULL, an ic.nb_streams long array of pointers to* dictionaries, where i-th member contains options for* codec corresponding to i-th stream.* On return each dictionary will be filled with options that were not found.* @return >=0 if OK, AVERROR_xxx on error** @note this function isn't guaranteed to open all the codecs, so* options being non-empty at return is a perfectly normal behavior.** @todo Let the user decide somehow what information is needed so that* we do not waste time getting stuff the user does not need.*/intavformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
{"ss", HAS_ARG,{.func_arg = opt_seek},"seek to a given position in seconds","pos"},{"t", HAS_ARG,{.func_arg = opt_duration},"play \"duration\" seconds of audio/video","duration"},/* if seeking requested, we execute it *//* 5. 檢測是否指定播放起始時間 */if(start_time != AV_NOPTS_VALUE){int64_t timestamp;timestamp = start_time;/* add the stream start time */if(ic->start_time != AV_NOPTS_VALUE)timestamp += ic->start_time;// seek的指定的位置開始播放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);}}
/*** Find the "best" stream in the file.* The best stream is determined according to various heuristics as the most* likely to be what the user expects.* If the decoder parameter is non-NULL, av_find_best_stream will find the* default decoder for the stream's codec; streams for which no decoder can* be found are ignored.** @param ic media file handle* @param type stream type: video, audio, subtitles, etc.* @param wanted_stream_nb user-requested stream number,* or -1 for automatic selection* @param related_stream try to find a stream related (eg. in the same* program) to this one, or -1 if none* @param decoder_ret if non-NULL, returns the decoder for the* selected stream* @param flags flags; none are currently defined* @return the non-negative stream number in case of success,* AVERROR_STREAM_NOT_FOUND if no stream with the requested type* could be found,* AVERROR_DECODER_NOT_FOUND if streams were found but no decoder* @note If av_find_best_stream returns successfully and decoder_ret is not* NULL, then *decoder_ret is guaranteed to be set to a valid AVCodec.*/intav_find_best_stream(AVFormatContext *ic,enum AVMediaType type,int wanted_stream_nb,int related_stream,AVCodec **decoder_ret,int flags);// 6.2 利用av_find_best_stream選擇流,if(!video_disable)st_index[AVMEDIA_TYPE_VIDEO]=av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,st_index[AVMEDIA_TYPE_VIDEO],-1, NULL,0);if(!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(!video_disable &&!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);
/* open a given stream. Return 0 if OK *//*** @brief stream_component_open* @param is* @param stream_index 流索引* @return Return 0 if OK*/
static intstream_component_open(VideoState *is,int stream_index)
/* 根據(jù)codec_id查找解碼器 */codec =avcodec_find_decoder(avctx->codec_id);switch(avctx->codec_type){case AVMEDIA_TYPE_AUDIO :is->last_audio_stream = stream_index;forced_codec_name = audio_codec_name;break;case AVMEDIA_TYPE_SUBTITLE:is->last_subtitle_stream = stream_index;forced_codec_name = subtitle_codec_name;break;case AVMEDIA_TYPE_VIDEO :is->last_video_stream = stream_index;forced_codec_name = video_codec_name;break;}if(forced_codec_name)codec =avcodec_find_decoder_by_name(forced_codec_name);if(!codec){if(forced_codec_name)av_log(NULL, AV_LOG_WARNING,"No codec could be found with name '%s'\n", forced_codec_name);elseav_log(NULL, AV_LOG_WARNING,"No decoder could be found for codec %s\n",avcodec_get_name(avctx->codec_id));ret =AVERROR(EINVAL);goto fail;}
// 5 檢測隊列是否已經(jīng)有足夠數(shù)據(jù)/* if the queue are full, no need to read more *//* 緩存隊列有足夠的包,不需要繼續(xù)讀取數(shù)據(jù) */if(infinite_buffer <1&&(is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE||(stream_has_enough_packets(is->audio_st, is->audio_stream,&is->audioq)&&stream_has_enough_packets(is->video_st, is->video_stream,&is->videoq)&&stream_has_enough_packets(is->subtitle_st, is->subtitle_stream,&is->subtitleq)))){/* wait 10 ms */SDL_LockMutex(wait_mutex);// 如果沒有喚醒則超時10ms退出,比如在seek操作時這里會被喚醒SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex,10);SDL_UnlockMutex(wait_mutex);continue;}