ffmpeg分析系列之七(開啟輸入的流)

helloxchen發表於2010-11-04
ffmpeg分析系列之七(開啟輸入的流)

err = av_open_input_stream(ic_ptr, pb, filename, fmt, ap);


int av_open_input_stream(

AVFormatContext **ic_ptr, // 輸出引數: 格式上下文
ByteIOContext *pb,
// 位元組IO上下文

const char *filename, // 檔名
AVInputFormat *fmt,
// 輸入的格式

AVFormatParameters *ap) // 格式引數, 呼叫時為NULL
{
int err;
AVFormatContext *ic;
AVFormatParameters default_ap;

// 使用預設的格式引數
if(!ap){
ap=&default_ap;
memset(ap, 0, sizeof(default_ap));
}

if(!ap->prealloced_context)
ic = avformat_alloc_context(); // 分配格式上下文
else
ic = *ic_ptr;
if (!ic) {
err = AVERROR(ENOMEM);
goto fail;
}

// 初始化格式上下文 ic->iformat = fmt; // 格式
ic->pb = pb; // 位元組IO上下文
ic->duration = AV_NOPTS_VALUE;
ic->start_time = AV_NOPTS_VALUE;
av_strlcpy(ic->filename, filename, sizeof(ic->filename)); // 檔名

/* 分配私有資料 */
if (fmt->priv_data_size > 0) {
ic->priv_data = av_mallocz(fmt->priv_data_size);
if (!ic->priv_data) {
err = AVERROR(ENOMEM);
goto fail;
}
} else {
ic->priv_data = NULL;
}

// 讀首部
if (ic->iformat->read_header) {
err = ic->iformat->read_header(ic, ap);
if (err < 0)
goto fail;
}

// 獲得資料偏移
if (pb && !ic->data_offset)
ic->data_offset = url_ftell(ic->pb);

#if LIBAVFORMAT_VERSION_MAJOR < 53
ff_metadata_demux_compat(ic);
#endif

// 原始的包緩衝剩餘的大小
ic->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;

// 輸出引數: 格式上下文

*ic_ptr = ic;
return 0;

}


具體請參看
ffmpeg分析系列之三(輸入輸出格式)
格式上下文結構:

typedef struct AVFormatContext {
const AVClass *av_class; /**< Set by avformat_alloc_context. */

// 省略部分內容}

AV類結構:

typedef struct {/**
* The name of the class; usually it is the same name as the
* context structure type to which the AVClass is associated.
*/

const char* class_name;
/**
* A pointer to a function which returns the name of a context
* instance ctx associated with the class.
*/

const char* (*item_name)(void* ctx);
/**
* a pointer to the first option specified in the class if any or NULL
*
* @see av_set_default_options()
*/

const struct AVOption *option;
/**
* LIBAVUTIL_VERSION with which this structure was created.
* This is used to allow fields to be added without requiring major
* version bumps everywhere.
*/


int version;
} AVClass;

進入avformat_alloc_context函式, 分配格式上下文:

AVFormatContext *avformat_alloc_context(void)
{
AVFormatContext *ic;
ic = av_malloc(sizeof(AVFormatContext));
if (!ic) return ic;
avformat_get_context_defaults(ic);
ic->av_class = &av_format_context_class;
return ic;
}

static const AVClass av_format_context_class = { "AVFormatContext", format_to_name, options, LIBAVUTIL_VERSION_INT };

進入avformat_get_context_defaults函式, 格式獲得預設上下文:

static void avformat_get_context_defaults(AVFormatContext *s)
{
memset(s, 0, sizeof(AVFormatContext));
s->av_class = &av_format_context_class;
av_opt_set_defaults(s);
}


av_opt_set_defaults函式就不分析了.
下面繼續分析:

err = ic->iformat->read_header(ic, ap)

以輸入格式為libavformat/raw.c下的h264_demuxer為例:

AVInputFormat h264_demuxer = {
"h264",
NULL_IF_CONFIG_SMALL("raw H.264 video format"),
0,
h264_probe,
video_read_header,
ff_raw_read_partial_packet,
.flags= AVFMT_GENERIC_INDEX,
.extensions = "h26l,h264,264",
//FIXME remove after writing mpeg4_probe
.value = CODEC_ID_H264,
};

會呼叫video_read_header函式:

static int video_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
AVStream *st;

st = av_new_stream(s, 0); // 格式上下文增加一個流
if (!st)
return AVERROR(ENOMEM);

// 初始化流
st->codec->codec_type = AVMEDIA_TYPE_VIDEO; // 編碼編碼器型別
st->codec->codec_id = s->iformat->value; // 為 CODEC_ID_H264
st->need_parsing = AVSTREAM_PARSE_FULL; // 需要全分析

/* for MJPEG, specify frame rate */
/* for MPEG-4 specify it, too (most MPEG-4 streams do not have the fixed_vop_rate set ...)*/
if (ap->time_base.num) {

st->codec->time_base= ap->time_base;
} else if ( st->codec->codec_id == CODEC_ID_MJPEG ||
st->codec->codec_id == CODEC_ID_MPEG4 ||
st->codec->codec_id == CODEC_ID_DIRAC ||
st->codec->codec_id == CODEC_ID_DNXHD ||
st->codec->codec_id == CODEC_ID_H264) {
st->codec->time_base= (AVRational){1,25}; // 設定時基
}
av_set_pts_info(st, 64, 1, 1200000); // 設定PTS(顯示時間截)資訊

return 0;
}


進入av_new_stream函式:

AVStream *av_new_stream(AVFormatContext *s, int id)
{
AVStream *st;
int i;

// 格式上下文不能太多流
if (s->nb_streams >= MAX_STREAMS)
return NULL;

// 分配一個流
st = av_mallocz(sizeof(AVStream));
if (!st)
return NULL;

// 分配解碼器上下文
st->codec= avcodec_alloc_context();
if (s->iformat) {
/* no default bitrate if decoding */
st->codec->bit_rate = 0;
}
st->index = s->nb_streams; // 流索引
st->id = id; // ID, 為0
st->start_time = AV_NOPTS_VALUE; // 開始時間
st->duration = AV_NOPTS_VALUE;
/* we set the current DTS to 0 so that formats without any timestamps
but durations get some timestamps, formats with some unknown
timestamps have their first few packets buffered and the
timestamps corrected before they are returned to the user */

st->cur_dts = 0; // 當前的解碼時間截
st->first_dts = AV_NOPTS_VALUE; // 起始的解碼時間截
st->probe_packets = MAX_PROBE_PACKETS; // 探測的最大包數

/* default pts setting is MPEG-like */

av_set_pts_info(st, 33, 1, 90000); // 設定PTS顯示時間截資訊
st->last_IP_pts = AV_NOPTS_VALUE;
for(i=0; i<MAX_REORDER_DELAY+1; i++)
st->pts_buffer[i]= AV_NOPTS_VALUE;
st->reference_dts = AV_NOPTS_VALUE;

st->sample_aspect_ratio = (AVRational){0,1};

s->streams[s->nb_streams++] = st; // 記錄流, 同時流數加一
return st;
}


分配編碼解碼器上下文:

static const AVClass av_codec_context_class = { "AVCodecContext", context_to_name, options, LIBAVUTIL_VERSION_INT };


void avcodec_get_context_defaults2(AVCodecContext *s, enum AVMediaType codec_type){
int flags=0;
memset(s, 0, sizeof(AVCodecContext));

s->av_class= &av_codec_context_class;

s->codec_type = codec_type;
if(codec_type == AVMEDIA_TYPE_AUDIO)
flags= AV_OPT_FLAG_AUDIO_PARAM;
else if(codec_type == AVMEDIA_TYPE_VIDEO)
flags= AV_OPT_FLAG_VIDEO_PARAM;
else if(codec_type == AVMEDIA_TYPE_SUBTITLE)
flags= AV_OPT_FLAG_SUBTITLE_PARAM;
av_opt_set_defaults2(s, flags, flags);

s->time_base= (AVRational){0,1};
s->get_buffer= avcodec_default_get_buffer;
s->release_buffer= avcodec_default_release_buffer;
s->get_format= avcodec_default_get_format;
s->execute= avcodec_default_execute;
s->execute2= avcodec_default_execute2;
s->sample_aspect_ratio= (AVRational){0,1};
s->pix_fmt= PIX_FMT_NONE;
s->sample_fmt= SAMPLE_FMT_NONE;

s->palctrl = NULL;
s->reget_buffer= avcodec_default_reget_buffer;
s->reordered_opaque= AV_NOPTS_VALUE;
}

AVCodecContext *avcodec_alloc_context2(enum AVMediaType codec_type){
AVCodecContext *avctx= av_malloc(sizeof(AVCodecContext));

if(avctx==NULL) return NULL;

avcodec_get_context_defaults2(avctx, codec_type);

return avctx;
}

void avcodec_get_context_defaults(AVCodecContext *s){
avcodec_get_context_defaults2(s, AVMEDIA_TYPE_UNKNOWN);
}

AVCodecContext *avcodec_alloc_context(void){
return avcodec_alloc_context2(AVMEDIA_TYPE_UNKNOWN);
}

轉自http://blog.chinaunix.net/u3/104564/showart_2369664.html
[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24790158/viewspace-1040901/,如需轉載,請註明出處,否則將追究法律責任。

相關文章