ffmpeg分析系列之七(打开输入的流)

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/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/24790158/viewspace-1040901/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值