读取数据的ff_read_packet 浅显分析

来源:互联网 发布:手机淘宝怎么关注 编辑:程序博客网 时间:2024/06/06 10:59
 本篇文章主要介绍了"【ffmpeg】试图从raw buffer中读取数据的ff_read_packet 浅显分析",主要涉及到【ffmpeg】试图从raw buffer中读取数据的ff_read_packet 浅显分析方面的内容,对于【ffmpeg】试图从raw buffer中读取数据的ff_read_packet 浅显分析感兴趣的同学可以参考一下。

故事的主角是ff_read_packet,显然,如今ff_read_packet已经不是对外的接口了,是ffmpeg内部使用的一个接口。

想要理解ff_read_packet,必须从之前的接口av_read_packet的设计意图着手:

‘#if FF_API_READ_PACKET
int av_read_packet(AVFormatContext *s, AVPacket *pkt)
{
return ff_read_packet(s, pkt);
}
‘#endif

obsolete是废弃的,老式的,意思。

这个函数是用来从媒体文件中读取一个transport 包的,这里头参数AVFormatContext被认为是一个“媒体文件句柄”,所需要读取的包就是pkt,将会被这个函数填充。

因此应该传入的是包的地址。

返回值为0,表示成功,其他的AVERROR_XXXX都是错误.

‘#if FF_API_READ_PACKET
/**
* @deprecated use AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE to read raw
* unprocessed packets
*
* Read a transport packet from a media file.
*
* This function is obsolete and should never be used.
* Use av_read_frame() instead.
*
* @param s media file handle
* @param pkt is filled
* @return 0 if OK, AVERROR_xxx on error
*/
attribute_deprecated
int av_read_packet(AVFormatContext *s, AVPacket *pkt);
‘#endif

当然,这个接口已经被废弃了,对外的接口是av_read_frame,这俩肯定有不同的。

============

其实这个函数启动起来之后就是想方设法的读取一个包填充pkt,虽然人家有个for(;;)的无线循环,但是人家的目的只在“一个包”。

用for(;;)的目的在于,遇到一些情况(比如的得到的pkt有问题,需要重新读一个才能返回给上层),可以continue,重新来过,如果一直读不到一个合适的包,

那么这个函数会一直无限循环下去(当然,函数的调用者应该会有个判断吧,不会让这个函数一直for下去吧。),单从这个函数看,他是阻塞的。

函数包括两部分:

(1)当raw buffer 中有数据,那么从队头出队一个节点,将其中的pkt填充。

如果得到了这么一个pkt,是不是要立即退出for(;;)呢?

可以看到,只有当

if(st->request_probe <= 0){//-1是probe完成,0是不要probe

的时候,才回立即退出for(;;),这个request_probe和probe的过程,我不是很理解。

所以到底是不是从raw buffer中成功出队就一定会退出for,我不确定。

关于raw buffer的讨论,参见http://blog.csdn.net/commshare/article/details/16908917

(2)但是,如果从raw buffer没有成功出队,这说明raw buffer是空的,只有调用一个具体的读包函数,继续为能获取pkt而努力。

    //0表示成功,小于0表示错误,pkt就在这里获取到。    ret= s->iformat->read_packet(s, pkt);       

读取一个pkt,这个pkt填充调用者所需要的pkt,但不一定就是返回给调用者的pkt,因为:

====

之后,需要经过一系列的检查,如果失败就continue,重新用read_packet来读取一个。

这个检查的过程,下面的代码都有,但我也不太清楚。

=======

如果可以成功的通过具体的read_packet得到一个正确的pkt,那么

1) 当

    if(!pktl && st->request_probe <= 0)    {               return ret;    }

就退出for,该pkt就是所需pkt,但是不入队列raw buffer中。

注意,这里显示(pktl为NULL) 并且(不进行probe)的时候,才直接退出for(意味着函数会退出)并且不加入到raw buffer中。

pktl为NULL,表示此时没能从raw buffer中取到结点(才执行的具体的read_packet的这个流程)。

2) 不返回,而是加入raw buffer中,并继续for循环(意味着此次具体格式的read_packet是成功的,但是不把这次得到的pkt结果返回(不退出for,不退出函数))。

那么调用入队列函数,add_to_pktbuf 加入到raw buffer中。

关于这个入队列函数参见http://blog.csdn.net/commshare/article/details/16910051

那么这个pkt就是要填充的pkt,

===========================

int ff_read_packet(AVFormatContext *s, AVPacket *pkt)

{
int ret, i;
AVStream *st;

//endless loop ,这里头其实就是一个不断的从出队列一个pkt(raw buffer只要有数据)返回给上层和不断的读取数据加入到raw buffer(这个新读取的数据,会被返回给上层)
for(;;){

    AVPacketList *pktl = s->raw_packet_buffer; //node    if (pktl) {       av_log(s,AV_LOG_WARNING,"raw_packet_buffer %s","NOT NULL ");          //得到        *pkt = pktl->pkt; //get a pkt from raw pkt buffer        st = s->streams[pkt->stream_index];//judge stream type by pkt stream_indexs        if(st->request_probe <= 0){//-1是probe完成,0是不要probe     s->raw_packet_buffer = pktl->next;            //归还队列一些空间            s->raw_packet_buffer_remaining_size += pkt->size;            av_free(pktl);            return 0;            }   printf("### st->request_probe > 0  \n");    }//end if(pktl)    //////////////raw_packet_buffer 里头没有,自己去读/////   //先赋个初值    pkt->data = NULL;    pkt->size = 0;//初始化一下    av_init_packet(pkt);            //0表示成功,小于0表示错误,pkt就在这里获取到。    ret= s->iformat->read_packet(s, pkt);           //表示错误了。    if (ret < 0) { //貌似返回的是0    if (!pktl || ret == AVERROR(EAGAIN))            return ret;        for (i = 0; i < s->nb_streams; i++) {            st = s->streams[i];            if (st->probe_packets) {                probe_codec(s, st, NULL);            }            av_assert0(st->request_probe <= 0);        }        //读取失败了,重新来过        continue;    }    //读取成功    //判断是不是要丢掉    if ((s->flags & AVFMT_FLAG_DISCARD_CORRUPT) &&        (pkt->flags & AV_PKT_FLAG_CORRUPT)) {        av_log(s, AV_LOG_WARNING,               "Dropped corrupted packet (stream = %d)\n",               pkt->stream_index);        av_free_packet(pkt);        continue;    }    if(!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA))        av_packet_merge_side_data(pkt);    if(pkt->stream_index >= (unsigned)s->nb_streams){ //也没走吧        av_log(s, AV_LOG_ERROR, "Invalid stream index %d\n", pkt->stream_index);        continue;    }    printf("###wrap_timestamp \n");    //得到读取到的这个包所在的stream,以为pkt获取时间戳    st= s->streams[pkt->stream_index];    pkt->dts = wrap_timestamp(st, pkt->dts);    pkt->pts = wrap_timestamp(st, pkt->pts);    force_codec_ids(s, st);    /* TODO: audio: time filter 音频要做时间过滤;    video: frame reordering (pts != dts) 视频帧的重排序(当视频帧的dts和pts不等的时候)*/    if (s->use_wallclock_as_timestamps) //这里好像没走    pkt->dts = pkt->pts = av_rescale_q(av_gettime(), AV_TIME_BASE_Q, st->time_base);    if(!pktl && st->request_probe <= 0)    {        return ret;    }     //这是给raw buffer存入数据啊,看来raw buffer也是有大小限制的,就是raw_packet_buffer_remaining_size 这么大。      add_to_pktbuf(&s->raw_packet_buffer, pkt, &s->raw_packet_buffer_end);    s->raw_packet_buffer_remaining_size -= pkt->size;    probe_codec(s, st, pkt);}

}

int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
{
int ret, i;
AVStream *st;

//endless loop ,这里头其实就是一个不断的从出队列一个pkt(raw buffer只要有数据)返回给上层和不断的读取数据加入到raw buffer(这个新读取的数据,会被返回给上层)
for(;;){

    AVPacketList *pktl = s->raw_packet_buffer; //node    if (pktl) {       av_log(s,AV_LOG_WARNING,"raw_packet_buffer %s","NOT NULL ");    //得到        *pkt = pktl->pkt; //get a pkt from raw pkt buffer        st = s->streams[pkt->stream_index];//judge stream type by pkt stream_indexs        if(st->request_probe <= 0){//-1是probe完成,0是不要probe

s->raw_packet_buffer = pktl->next;
//归还队列一些空间
s->raw_packet_buffer_remaining_size += pkt->size;
av_free(pktl);
return 0; //成功
}
printf(“### st->request_probe > 0 \n”);
}//end if(pktl)

    //////////////raw_packet_buffer 里头没有,自己去读/////   //先赋个初值    pkt->data = NULL;    pkt->size = 0;

//初始化一下
av_init_packet(pkt);
//0表示成功,小于0表示错误,pkt就在这里获取到。
ret= s->iformat->read_packet(s, pkt);

    //表示错误了。    if (ret < 0) { //貌似返回的是0

if (!pktl || ret == AVERROR(EAGAIN)) //这是返回错误值
return ret;
for (i = 0; i < s->nb_streams; i++) {
st = s->streams[i];
if (st->probe_packets) {
probe_codec(s, st, NULL);
}
av_assert0(st->request_probe <= 0);
}
//读取失败了,重新来过
continue;
}

    //读取成功,此时ret为0    //判断是不是要丢掉    if ((s->flags & AVFMT_FLAG_DISCARD_CORRUPT) &&        (pkt->flags & AV_PKT_FLAG_CORRUPT)) {        av_log(s, AV_LOG_WARNING,               "Dropped corrupted packet (stream = %d)\n",               pkt->stream_index);        av_free_packet(pkt);        continue;    }    if(!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA))        av_packet_merge_side_data(pkt);    if(pkt->stream_index >= (unsigned)s->nb_streams){ //也没走吧        av_log(s, AV_LOG_ERROR, "Invalid stream index %d\n", pkt->stream_index);        continue;    }    printf("###wrap_timestamp \n");    //得到读取到的这个包所在的stream,以为pkt获取时间戳    st= s->streams[pkt->stream_index];    pkt->dts = wrap_timestamp(st, pkt->dts);    pkt->pts = wrap_timestamp(st, pkt->pts);    force_codec_ids(s, st);    /* TODO: audio: time filter 音频要做时间过滤;    video: frame reordering (pts != dts) 视频帧的重排序(当视频帧的dts和pts不等的时候)*/    if (s->use_wallclock_as_timestamps) //这里好像没走

pkt->dts = pkt->pts = av_rescale_q(av_gettime(), AV_TIME_BASE_Q, st->time_base);

 //这个时候返回的,应该是0,代表成功获取并填充了一个pkt    if(!pktl && st->request_probe <= 0)    {        return ret;  //这个时候返回的,应该是0    }   //这是给raw buffer入队,但是并不通知调用者,我们获取到了一个pkt,继续执行for     //这是给raw buffer存入数据啊,看来raw buffer也是有大小限制的,就是raw_packet_buffer_remaining_size 这么大。    add_to_pktbuf(&s->raw_packet_buffer, pkt, &s->raw_packet_buffer_end);    s->raw_packet_buffer_remaining_size -= pkt->size;    probe_codec(s, st, pkt);} //end for

}

原创粉丝点击