【FFMPEG源码终极解析】 avformat_open_input (一)
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                【FFMPEG源码终极解析】 avformat_open_input   (一)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                avformat_open_input??
打開媒體函數,先上全部源碼。然后逐語句分析。
int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {//第一部分解析AVFormatContext *s = *ps;int i, ret = 0;AVDictionary *tmp = NULL;ID3v2ExtraMeta *id3v2_extra_meta = NULL;//第二部分解析 if (!s && !(s = avformat_alloc_context()))return AVERROR(ENOMEM);if (!s->av_class) {av_log(NULL, AV_LOG_ERROR, "Input context has not been properly allocated by avformat_alloc_context() and is not NULL either\n");return AVERROR(EINVAL);}//第三部分解析 //如果用戶指定了輸入格式,直接使用它 if (fmt)s->iformat = fmt;//===================================================================================if (options)av_dict_copy(&tmp, *options, 0);if (s->pb) // must be before any goto fails->flags |= AVFMT_FLAG_CUSTOM_IO;if ((ret = av_opt_set_dict(s, &tmp)) < 0)goto fail;if (!(s->url = av_strdup(filename ? filename : ""))) {ret = AVERROR(ENOMEM);goto fail;}#if FF_API_FORMAT_FILENAME FF_DISABLE_DEPRECATION_WARNINGSav_strlcpy(s->filename, filename ? filename : "", sizeof(s->filename)); FF_ENABLE_DEPRECATION_WARNINGS #endifif ((ret = init_input(s, filename, &tmp)) < 0)goto fail;s->probe_score = ret;if (!s->protocol_whitelist && s->pb && s->pb->protocol_whitelist) {s->protocol_whitelist = av_strdup(s->pb->protocol_whitelist);if (!s->protocol_whitelist) {ret = AVERROR(ENOMEM);goto fail;}}if (!s->protocol_blacklist && s->pb && s->pb->protocol_blacklist) {s->protocol_blacklist = av_strdup(s->pb->protocol_blacklist);if (!s->protocol_blacklist) {ret = AVERROR(ENOMEM);goto fail;}}if (s->format_whitelist && av_match_list(s->iformat->name, s->format_whitelist, ',') <= 0) {av_log(s, AV_LOG_ERROR, "Format not on whitelist \'%s\'\n", s->format_whitelist);ret = AVERROR(EINVAL);goto fail;}avio_skip(s->pb, s->skip_initial_bytes);/* Check filename in case an image number is expected. */if (s->iformat->flags & AVFMT_NEEDNUMBER) {if (!av_filename_number_test(filename)) {ret = AVERROR(EINVAL);goto fail;}}s->duration = s->start_time = AV_NOPTS_VALUE;/* Allocate private data. */if (s->iformat->priv_data_size > 0) {if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) {ret = AVERROR(ENOMEM);goto fail;}if (s->iformat->priv_class) {*(const AVClass **) s->priv_data = s->iformat->priv_class;av_opt_set_defaults(s->priv_data);if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0)goto fail;}}/* e.g. AVFMT_NOFILE formats will not have a AVIOContext */if (s->pb)ff_id3v2_read_dict(s->pb, &s->internal->id3v2_meta, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)if ((ret = s->iformat->read_header(s)) < 0)goto fail;if (!s->metadata) {s->metadata = s->internal->id3v2_meta;s->internal->id3v2_meta = NULL;} else if (s->internal->id3v2_meta) {av_log(s, AV_LOG_WARNING, "Discarding ID3 tags because more suitable tags were found.\n");av_dict_free(&s->internal->id3v2_meta);}if (id3v2_extra_meta) {if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac") ||!strcmp(s->iformat->name, "tta") || !strcmp(s->iformat->name, "wav")) {if ((ret = ff_id3v2_parse_apic(s, id3v2_extra_meta)) < 0)goto close;if ((ret = ff_id3v2_parse_chapters(s, id3v2_extra_meta)) < 0)goto close;if ((ret = ff_id3v2_parse_priv(s, id3v2_extra_meta)) < 0)goto close;} elseav_log(s, AV_LOG_DEBUG, "demuxer does not support additional id3 data, skipping\n");}ff_id3v2_free_extra_meta(&id3v2_extra_meta);if ((ret = avformat_queue_attached_pictures(s)) < 0)goto close;if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->internal->data_offset)s->internal->data_offset = avio_tell(s->pb);s->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;update_stream_avctx(s);for (i = 0; i < s->nb_streams; i++)s->streams[i]->internal->orig_codec_id = s->streams[i]->codecpar->codec_id;if (options) {av_dict_free(options);*options = tmp;}*ps = s;return 0;close:if (s->iformat->read_close)s->iformat->read_close(s); fail:ff_id3v2_free_extra_meta(&id3v2_extra_meta);av_dict_free(&tmp);if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO))avio_closep(&s->pb);avformat_free_context(s);*ps = NULL;return ret; }?
第一部分:以下是定義了一些必備的變量。
AVFormatContext *s = *ps;int i, ret = 0;AVDictionary *tmp = NULL;ID3v2ExtraMeta *id3v2_extra_meta = NULL;?
第二部分:創建上下文結構,其作用為開辟相關空間并且進行一些初始化賦值。返回上下文結構的指針。
if (!s && !(s = avformat_alloc_context()))return AVERROR(ENOMEM);avformat_alloc_context 函數詳細解析:
AVFormatContext *avformat_alloc_context(void) {//定義封裝上下文結構體AVFormatContext *ic;AVFormatInternal *internal;//使用sizeof計算結構體大小并且分配空間ic = av_malloc(sizeof(AVFormatContext));if (!ic) return ic;internal = av_mallocz(sizeof(*internal));if (!internal) {av_free(ic);return NULL;}avformat_get_context_defaults(ic);ic->internal = internal;ic->internal->offset = AV_NOPTS_VALUE;ic->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;ic->internal->shortest_end = AV_NOPTS_VALUE;return ic; }其中av_malloc封裝了c的malloc內存分配函數
void *av_malloc(size_t size) {void *ptr = NULL;//max_aloc_size 為 2147483647 if (size > max_alloc_size)return NULL;#if HAVE_POSIX_MEMALIGNif (size) //OS X on SDK 10.6 has a broken posix_memalign implementationif (posix_memalign(&ptr, ALIGN, size))ptr = NULL; #elif HAVE_ALIGNED_MALLOCptr = _aligned_malloc(size, ALIGN); #elif HAVE_MEMALIGN #ifndef __DJGPP__ptr = memalign(ALIGN, size); #elseptr = memalign(size, ALIGN); #endif/* Why 64?* Indeed, we should align it:* on 4 for 386* on 16 for 486* on 32 for 586, PPro - K6-III* on 64 for K7 (maybe for P3 too).* Because L1 and L2 caches are aligned on those values.* But I don't want to code such logic here!*//* Why 32?* For AVX ASM. SSE / NEON needs only 16.* Why not larger? Because I did not see a difference in benchmarks ...*//* benchmarks with P3* memalign(64) + 1 3071, 3051, 3032* memalign(64) + 2 3051, 3032, 3041* memalign(64) + 4 2911, 2896, 2915* memalign(64) + 8 2545, 2554, 2550* memalign(64) + 16 2543, 2572, 2563* memalign(64) + 32 2546, 2545, 2571* memalign(64) + 64 2570, 2533, 2558** BTW, malloc seems to do 8-byte alignment by default here.*/ #elseptr = malloc(size); #endifif(!ptr && !size) {size = 1;ptr= av_malloc(1);} #if CONFIG_MEMORY_POISONINGif (ptr)memset(ptr, FF_MEMORY_POISON, size); #endifreturn ptr; }第三部分:
如果已經事先定義好了AVInputFormat那么就把定義好的直接賦予在這里。具體結構可以參考下面
typedef struct AVInputFormat {const char *name; // 輸入格式的短名稱const char *long_name; // 格式的長名稱(相對于短名稱而言,更易于閱讀)/*** Can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_SHOW_IDS,* AVFMT_GENERIC_INDEX, AVFMT_TS_DISCONT, AVFMT_NOBINSEARCH,* AVFMT_NOGENSEARCH, AVFMT_NO_BYTE_SEEK, AVFMT_SEEK_TO_PTS.*/int flags;const char *extensions; // 如果定義了擴展,就不會進行格式探測。但因為該功能目前支持不夠,不推薦使用const struct AVCodecTag * const *codec_tag; // 見名知意const AVClass *priv_class; ///< AVClass for the private contextconst char *mime_type; // mime類型,它用于在探測時檢查匹配的mime類型。/* 此行下方的任何字段都不是公共API的一部分。 它們不能在libavformat之外使用,可以隨意更改和刪除。* 應在上方添加新的公共字段。*/struct AVInputFormat *next; // 用于鏈接下一個AVInputFormatint raw_codec_id; // 原始demuxers將它們的解碼器id保存在這里。int priv_data_size; // 私有數據大小,可以用于確定需要分配多大的內存來容納下這些數據。/*** 判斷給定文件是否有可能被解析為此格式。 提供的緩沖區保證為AVPROBE_PADDING_SIZE字節大,因此除非您需 * 要更多,否則無需檢查。*/int (*read_probe)(AVProbeData *);/*** 讀取格式頭,并初始化AVFormatContext結構體* @return 0 表示操作成功*/int (*read_header)(struct AVFormatContext *);/*** 讀取一個packet并存入pkt指針中。pts和flags會被同時設置。* @return 0 表示操作成功, < 0 發生異常* 當返回異常時,pkt可定沒有allocated或者在函數返回之前被釋放了。*/int (*read_packet)(struct AVFormatContext *, AVPacket *pkt);// 關閉流,AVFormatContext和AVStreams并不會被這個函數釋放。int (*read_close)(struct AVFormatContext *);/*** 在stream_index的流中,使用一個給定的timestamp,seek到附近幀。* @param stream_index 不能為-1* @param flags 如果沒有完全匹配,決定向前還是向后匹配。* @return >= 0 成功*/int (*read_seek)(struct AVFormatContext *,int stream_index, int64_t timestamp, int flags);// 獲取stream[stream_index]的下一個時間戳,如果發生異常返回AV_NOPTS_VALUEint64_t (*read_timestamp)(struct AVFormatContext *s, int stream_index,int64_t *pos, int64_t pos_limit);// 開始或者恢復播放,只有在播放rtsp格式的網絡格式才有意義。int (*read_play)(struct AVFormatContext *);int (*read_pause)(struct AVFormatContext *);// 暫停播放,只有在播放rtsp格式的網絡格式才有意義。/*** 快進到指定的時間戳* @param stream_index 需要快進操作的流* @param ts 需要快進到的地方* @param min_ts max_ts seek的區間,ts需要在這個范圍中。*/int (*read_seek2)(struct AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);// 返回設備列表和其屬性int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list);// 初始化設備能力子模塊int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps);// 釋放設備能力子模塊int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); } AVInputFormat;?
?
?
?
總結
以上是生活随笔為你收集整理的【FFMPEG源码终极解析】 avformat_open_input (一)的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 查看Linux进程命令(linux 进程
- 下一篇: FFmpeg options
