ffmpeg 源代碼簡單分析 : av_read_frame()

此前寫了好幾篇ffmpeg源代碼分析文章,列表如下:

圖解FFMPEG打開媒體的函數avformat_open_input
ffmpeg 源代碼簡單分析 : av_register_all()
ffmpeg 源代碼簡單分析 : avcodec_register_all()
ffmpeg 源代碼簡單分析 : av_read_frame()
ffmpeg 源代碼簡單分析 : avcodec_decode_video2()

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


ffmpeg中的av_read_frame()的作用是讀取碼流中的音頻若干幀或者視頻一幀。例如,解碼視頻的時候,每解碼一個視頻幀,需要先調用 av_read_frame()獲得一幀視頻的壓縮數據,然後才能對該數據進行解碼(例如H.264中一幀壓縮數據通常對應一個NAL)。

對該函數源代碼的分析是很久之前做的了,現在翻出來,用博客記錄一下。


上代碼之前,先參考了其他人對av_read_frame()的解釋,在此做一個參考:

通過av_read_packet(***),讀取一個包,需要說明的是此函數必須是包含整數幀的,不存在半幀的情況,以ts流爲例,是讀取一個完整的PES包(一個完整pes包包含若干視頻或音頻es包),讀取完畢後,通過av_parser_parse2(***)分析出視頻一幀(或音頻若干幀),返回,下次進入循環的時候,如果上次的數據沒有完全取完,則st = s->cur_st;不會是NULL,即再此進入av_parser_parse2(***)流程,而不是下面的av_read_packet(**)流程,這樣就保證了,如果讀取一次包含了N幀視頻數據(以視頻爲例),則調用av_read_frame(***)N次都不會去讀數據,而是返回第一次讀取的數據,直到全部解析完畢。

av_read_frame()的源代碼如下:

  1. //獲取一個AVPacket  
  2. /* 
  3.  * av_read_frame - 新版本的ffmpeg用的是av_read_frame,而老版本的是av_read_packet 
  4.  * 。區別是av_read_packet讀出的是包,它可能是半幀或多幀,不保證幀的完整性。av_read_frame對 
  5.  * av_read_packet進行了封裝,使讀出的數據總是完整的幀 
  6.  */  
  7. int av_read_frame(AVFormatContext *s, AVPacket *pkt)  
  8. {  
  9.     const int genpts = s->flags & AVFMT_FLAG_GENPTS;  
  10.     int          eof = 0;  
  11.   
  12.     if (!genpts)  
  13.         /** 
  14.          * This buffer is only needed when packets were already buffered but 
  15.          * not decoded, for example to get the codec parameters in MPEG 
  16.          * streams. 
  17.          * 一般情況下會調用read_frame_internal(s, pkt) 
  18.          * 直接返回 
  19.          */  
  20.         return s->packet_buffer ? read_from_packet_buffer(s, pkt) :  
  21.                                   read_frame_internal(s, pkt);  
  22.   
  23.     for (;;) {  
  24.         int ret;  
  25.         AVPacketList *pktl = s->packet_buffer;  
  26.   
  27.         if (pktl) {  
  28.             AVPacket *next_pkt = &pktl->pkt;  
  29.   
  30.             if (next_pkt->dts != AV_NOPTS_VALUE) {  
  31.                 int wrap_bits = s->streams[next_pkt->stream_index]->pts_wrap_bits;  
  32.                 while (pktl && next_pkt->pts == AV_NOPTS_VALUE) {  
  33.                     if (pktl->pkt.stream_index == next_pkt->stream_index &&  
  34.                         (av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2LL << (wrap_bits - 1)) < 0) &&  
  35.                          av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2LL << (wrap_bits - 1))) { //not b frame  
  36.                         next_pkt->pts = pktl->pkt.dts;  
  37.                     }  
  38.                     pktl = pktl->next;  
  39.                 }  
  40.                 pktl = s->packet_buffer;  
  41.             }  
  42.   
  43.             /* read packet from packet buffer, if there is data */  
  44.             if (!(next_pkt->pts == AV_NOPTS_VALUE &&  
  45.                   next_pkt->dts != AV_NOPTS_VALUE && !eof))  
  46.                 return read_from_packet_buffer(s, pkt);  
  47.         }  
  48.   
  49.         ret = read_frame_internal(s, pkt);  
  50.         if (ret < 0) {  
  51.             if (pktl && ret != AVERROR(EAGAIN)) {  
  52.                 eof = 1;  
  53.                 continue;  
  54.             } else  
  55.                 return ret;  
  56.         }  
  57.   
  58.         if (av_dup_packet(add_to_pktbuf(&s->packet_buffer, pkt,  
  59.                           &s->packet_buffer_end)) < 0)  
  60.             return AVERROR(ENOMEM);  
  61.     }  
  62. }  

一般情況下,av_read_frame()會調用read_frame_internal(),其代碼如下所示:

  1. //av_read_frame對他進行了封裝  
  2. static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)  
  3. {  
  4.     AVStream *st;  
  5.     int len, ret, i;  
  6.     //初始化  
  7.     av_init_packet(pkt);  
  8.   
  9.     for(;;) {  
  10.         /* 選擇當前的 input stream */  
  11.         st = s->cur_st;  
  12.         if (st) {  
  13.             //不需要解析。不清楚哪些數據屬於這類  
  14.             if (!st->need_parsing || !st->parser) {  
  15.                 /* no parsing needed: we just output the packet as is */  
  16.                 /* raw data support */  
  17.                 *pkt = st->cur_pkt;  
  18.                 st->cur_pkt.data= NULL;  
  19.                 st->cur_pkt.side_data_elems = 0;  
  20.                 st->cur_pkt.side_data = NULL;  
  21.                 compute_pkt_fields(s, st, NULL, pkt);  
  22.                 s->cur_st = NULL;  
  23.                 if ((s->iformat->flags & AVFMT_GENERIC_INDEX) &&  
  24.                     (pkt->flags & AV_PKT_FLAG_KEY) && pkt->dts != AV_NOPTS_VALUE) {  
  25.                     ff_reduce_index(s, st->index);  
  26.                     av_add_index_entry(st, pkt->pos, pkt->dts, 0, 0, AVINDEX_KEYFRAME);  
  27.                 }  
  28.                 break;  
  29.             } //需要解析  
  30.             else if (st->cur_len > 0 && st->discard < AVDISCARD_ALL) {  
  31.                 //解析  
  32.                 len = av_parser_parse2(st->parser, st->codec, &pkt->data, &pkt->size,  
  33.                                        st->cur_ptr, st->cur_len,  
  34.                                        st->cur_pkt.pts, st->cur_pkt.dts,  
  35.                                        st->cur_pkt.pos);  
  36.                 st->cur_pkt.pts = AV_NOPTS_VALUE;  
  37.                 st->cur_pkt.dts = AV_NOPTS_VALUE;  
  38.                 /* increment read pointer */  
  39.                 st->cur_ptr += len;  
  40.                 st->cur_len -= len;  
  41.   
  42.                 /* return packet if any */  
  43.                 if (pkt->size) {  
  44.                 got_packet:  
  45.                     pkt->duration = 0;  
  46.                     pkt->stream_index = st->index;  
  47.                     pkt->pts = st->parser->pts;  
  48.                     pkt->dts = st->parser->dts;  
  49.                     pkt->pos = st->parser->pos;  
  50.                     if(pkt->data == st->cur_pkt.data && pkt->size == st->cur_pkt.size){  
  51.                         s->cur_st = NULL;  
  52.                         pkt->destruct= st->cur_pkt.destruct;  
  53.                         st->cur_pkt.destruct= NULL;  
  54.                         st->cur_pkt.data    = NULL;  
  55.                         assert(st->cur_len == 0);  
  56.                     }else{  
  57.                         pkt->destruct = NULL;  
  58.                     }  
  59.                     compute_pkt_fields(s, st, st->parser, pkt);  
  60.   
  61.                     if((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & AV_PKT_FLAG_KEY){  
  62.                         int64_t pos= (st->parser->flags & PARSER_FLAG_COMPLETE_FRAMES) ? pkt->pos : st->parser->frame_offset;  
  63.                         ff_reduce_index(s, st->index);  
  64.                         av_add_index_entry(st, pos, pkt->dts,  
  65.                                            0, 0, AVINDEX_KEYFRAME);  
  66.                     }  
  67.   
  68.                     break;  
  69.                 }  
  70.             } else {  
  71.                 /* free packet */  
  72.                 av_free_packet(&st->cur_pkt);  
  73.                 s->cur_st = NULL;  
  74.             }  
  75.         } else {  
  76.             AVPacket cur_pkt;  
  77.             /* read next packet */  
  78.             //讀取AVPacket,老版本里只有av_read_packet,現在被封裝了  
  79.             ret = av_read_packet(s, &cur_pkt);  
  80.             if (ret < 0) {  
  81.                 if (ret == AVERROR(EAGAIN))  
  82.                     return ret;  
  83.                 /* return the last frames, if any */  
  84.                 for(i = 0; i < s->nb_streams; i++) {  
  85.                     st = s->streams[i];  
  86.                     if (st->parser && st->need_parsing) {  
  87.                         av_parser_parse2(st->parser, st->codec,  
  88.                                         &pkt->data, &pkt->size,  
  89.                                         NULL, 0,  
  90.                                         AV_NOPTS_VALUE, AV_NOPTS_VALUE,  
  91.                                         AV_NOPTS_VALUE);  
  92.                         if (pkt->size)  
  93.                             goto got_packet;  
  94.                     }  
  95.                 }  
  96.                 /* no more packets: really terminate parsing */  
  97.                 return ret;  
  98.             }  
  99.             st = s->streams[cur_pkt.stream_index];  
  100.             st->cur_pkt= cur_pkt;  
  101.   
  102.             if(st->cur_pkt.pts != AV_NOPTS_VALUE &&  
  103.                st->cur_pkt.dts != AV_NOPTS_VALUE &&  
  104.                st->cur_pkt.pts < st->cur_pkt.dts){  
  105.                 av_log(s, AV_LOG_WARNING, "Invalid timestamps stream=%d, pts=%"PRId64", dts=%"PRId64", size=%d\n",  
  106.                     st->cur_pkt.stream_index,  
  107.                     st->cur_pkt.pts,  
  108.                     st->cur_pkt.dts,  
  109.                     st->cur_pkt.size);  
  110. //                av_free_packet(&st->cur_pkt);  
  111. //                return -1;  
  112.             }  
  113.   
  114.             if(s->debug & FF_FDEBUG_TS)  
  115.                 av_log(s, AV_LOG_DEBUG, "av_read_packet stream=%d, pts=%"PRId64", dts=%"PRId64", size=%d, duration=%d, flags=%d\n",  
  116.                     st->cur_pkt.stream_index,  
  117.                     st->cur_pkt.pts,  
  118.                     st->cur_pkt.dts,  
  119.                     st->cur_pkt.size,  
  120.                     st->cur_pkt.duration,  
  121.                     st->cur_pkt.flags);  
  122.   
  123.             s->cur_st = st;  
  124.             st->cur_ptr = st->cur_pkt.data;  
  125.             st->cur_len = st->cur_pkt.size;  
  126.             if (st->need_parsing && !st->parser && !(s->flags & AVFMT_FLAG_NOPARSE)) {  
  127.                 st->parser = av_parser_init(st->codec->codec_id);  
  128.                 if (!st->parser) {  
  129.                     av_log(s, AV_LOG_VERBOSE, "parser not found for codec "  
  130.                            "%s, packets or times may be invalid.\n",  
  131.                            avcodec_get_name(st->codec->codec_id));  
  132.                     /* no parser available: just output the raw packets */  
  133.                     st->need_parsing = AVSTREAM_PARSE_NONE;  
  134.                 }else if(st->need_parsing == AVSTREAM_PARSE_HEADERS){  
  135.                     st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;  
  136.                 }else if(st->need_parsing == AVSTREAM_PARSE_FULL_ONCE){  
  137.                     st->parser->flags |= PARSER_FLAG_ONCE;  
  138.                 }  
  139.             }  
  140.         }  
  141.     }  
  142.     if(s->debug & FF_FDEBUG_TS)  
  143.         av_log(s, AV_LOG_DEBUG, "read_frame_internal stream=%d, pts=%"PRId64", dts=%"PRId64", size=%d, duration=%d, flags=%d\n",  
  144.             pkt->stream_index,  
  145.             pkt->pts,  
  146.             pkt->dts,  
  147.             pkt->size,  
  148.             pkt->duration,  
  149.             pkt->flags);  
  150.   
  151.     return 0;  
  152. }  

一般的碼流都需要解析,這是需要調用av_paser_parse2(),它的代碼如下所示:

  1. //解析。例如解析264裏的NAL等等  
  2. int av_parser_parse2(AVCodecParserContext *s,  
  3.                      AVCodecContext *avctx,  
  4.                      uint8_t **poutbuf, int *poutbuf_size,  
  5.                      const uint8_t *buf, int buf_size,  
  6.                      int64_t pts, int64_t dts,  
  7.                      int64_t pos)  
  8. {  
  9.     int index, i;  
  10.     uint8_t dummy_buf[FF_INPUT_BUFFER_PADDING_SIZE];  
  11.   
  12.     if(!(s->flags & PARSER_FLAG_FETCHED_OFFSET)) {  
  13.         s->next_frame_offset =  
  14.         s->cur_offset        = pos;  
  15.         s->flags |= PARSER_FLAG_FETCHED_OFFSET;  
  16.     }  
  17.   
  18.     if (buf_size == 0) {  
  19.         /* padding is always necessary even if EOF, so we add it here */  
  20.         memset(dummy_buf, 0, sizeof(dummy_buf));  
  21.         buf = dummy_buf;  
  22.     } else if (s->cur_offset + buf_size !=  
  23.                s->cur_frame_end[s->cur_frame_start_index]) { /* skip remainder packets */  
  24.         /* add a new packet descriptor */  
  25.             i = (s->cur_frame_start_index + 1) & (AV_PARSER_PTS_NB - 1);  
  26.             s->cur_frame_start_index = i;  
  27.             s->cur_frame_offset[i] = s->cur_offset;  
  28.             s->cur_frame_end[i] = s->cur_offset + buf_size;  
  29.             s->cur_frame_pts[i] = pts;  
  30.             s->cur_frame_dts[i] = dts;  
  31.             s->cur_frame_pos[i] = pos;  
  32.     }  
  33.   
  34.     if (s->fetch_timestamp){  
  35.         s->fetch_timestamp=0;  
  36.         s->last_pts = s->pts;  
  37.         s->last_dts = s->dts;  
  38.         s->last_pos = s->pos;  
  39.         ff_fetch_timestamp(s, 0, 0);  
  40.     }  
  41.   
  42.     /* WARNING: the returned index can be negative */  
  43.     //H264裏對應的就是parser_parse=h264_parse,  
  44.     index = s->parser->parser_parse(s, avctx, (const uint8_t **)poutbuf, poutbuf_size, buf, buf_size);  
  45. //av_log(NULL, AV_LOG_DEBUG, "parser: in:%"PRId64", %"PRId64", out:%"PRId64", %"PRId64", in:%d out:%d id:%d\n", pts, dts, s->last_pts, s->last_dts, buf_size, *poutbuf_size, avctx->codec_id);  
  46.     /* update the file pointer */  
  47.     if (*poutbuf_size) {  
  48.         /* fill the data for the current frame */  
  49.         s->frame_offset = s->next_frame_offset;  
  50.   
  51.         /* offset of the next frame */  
  52.         s->next_frame_offset = s->cur_offset + index;  
  53.         s->fetch_timestamp=1;  
  54.     }  
  55.     if (index < 0)  
  56.         index = 0;  
  57.     s->cur_offset += index;  
  58.     return index;  
  59. }  

從index = s->parser->parser_parse(s, avctx, (const uint8_t **)poutbuf, poutbuf_size, buf, buf_size);這句代碼可以看出,最終調用了相應解碼器的parser_parse()函數。

有點累了,先不做詳細分析,以後有機會再補上。


原文地址:http://blog.csdn.net/leixiaohua1020/article/details/12678577

發佈了4 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章