FFmpeg源代碼簡單分析-解碼-avformat_close_input()

參考鏈接

  • FFmpeg源代碼簡單分析:avformat_close_input()_雷霄驊的博客-CSDN博客_avformat_close_input

avformat_close_input()

  • 本文簡單分析FFmpeg的avformat_close_input()函數。
  • 該函數用于關閉一個AVFormatContext,一般情況下是和avformat_open_input()成對使用的。
  • avformat_close_input()的聲明位于libavformat\avformat.h,如下所示。
/*** Close an opened input AVFormatContext. Free it and all its contents* and set *s to NULL.*/
void avformat_close_input(AVFormatContext **s);
  • 下面看一下avformat_close_input()的源代碼,位于demux.c文件中。?
void avformat_close_input(AVFormatContext **ps)
{AVFormatContext *s;AVIOContext *pb;if (!ps || !*ps)return;s  = *ps;pb = s->pb;if ((s->iformat && strcmp(s->iformat->name, "image2") && s->iformat->flags & AVFMT_NOFILE) ||(s->flags & AVFMT_FLAG_CUSTOM_IO))pb = NULL;if (s->iformat)if (s->iformat->read_close)s->iformat->read_close(s);avformat_free_context(s);*ps = NULL;avio_close(pb);
}

函數調用關系圖

  • 函數的調用關系如下圖所示

  • ?從源代碼中可以看出,avformat_close_input()主要做了以下幾步工作:
    • (1)調用AVInputFormat的read_close()方法關閉輸入流
    • (2)調用avformat_free_context()釋放AVFormatContext
    • (3)調用avio_close()關閉并且釋放AVIOContext

AVInputFormat-> read_close()

  • AVInputFormat的read_close()是一個函數指針,指向關閉輸入流的函數。
  • 不同的AVInputFormat包含有不同的read_close()方法。
  • 例如,FLV格式對應的AVInputFormat的定義如下。
const AVInputFormat ff_flv_demuxer = {.name           = "flv",.long_name      = NULL_IF_CONFIG_SMALL("FLV (Flash Video)"),.priv_data_size = sizeof(FLVContext),.read_probe     = flv_probe,.read_header    = flv_read_header,.read_packet    = flv_read_packet,.read_seek      = flv_read_seek,.read_close     = flv_read_close,.extensions     = "flv",.priv_class     = &flv_kux_class,
};
  • 從ff_flv_demuxer的定義中可以看出,read_close()指向的函數是flv_read_close()
  • 我們可以看一下flv_read_close()的定義,如下所示。
  • 從flv_read_close()的定義可以看出,該函數釋放了FLVContext中的new_extradata數組中每個元素指向的內存。
static int flv_read_close(AVFormatContext *s)
{int i;FLVContext *flv = s->priv_data;for (i=0; i<FLV_STREAM_TYPE_NB; i++)av_freep(&flv->new_extradata[i]);av_freep(&flv->keyframe_times);av_freep(&flv->keyframe_filepositions);return 0;
}

avformat_free_context()

  • avformat_free_context()是一個FFmpeg的API函數,用于釋放一個AVFormatContext。
  • 在這里要注意搞清楚avformat_free_context()和avformat_close_input()之間的區別與聯系。
  • 有關avformat_free_context()可以參考文章:FFmpeg源代碼簡單分析-通用-常見結構體的初始化和銷毀(AVFormatContext,AVFrame等)_MY CUP OF TEA的博客-CSDN博客

avio_close()

  • avio_close()是一個FFmpeg的API函數,用于關閉和釋放AVIOContext。
  • 它的聲明位于libavformat\avio.h,如下所示
/*** Close the resource accessed by the AVIOContext s and free it.* This function can only be used if s was opened by avio_open().** The internal buffer is automatically flushed before closing the* resource.** @return 0 on success, an AVERROR < 0 on error.* @see avio_closep*/
int avio_close(AVIOContext *s);
int avio_close(AVIOContext *s)
{FFIOContext *const ctx = ffiocontext(s);URLContext *h;int ret, error;if (!s)return 0;avio_flush(s);h         = s->opaque;s->opaque = NULL;av_freep(&s->buffer);if (s->write_flag)av_log(s, AV_LOG_VERBOSE,"Statistics: %"PRId64" bytes written, %d seeks, %d writeouts\n",ctx->bytes_written, ctx->seek_count, ctx->writeout_count);elseav_log(s, AV_LOG_VERBOSE, "Statistics: %"PRId64" bytes read, %d seeks\n",ctx->bytes_read, ctx->seek_count);av_opt_free(s);error = s->error;avio_context_free(&s);ret = ffurl_close(h);if (ret < 0)return ret;return error;
}
  • 從源代碼可以看出,avio_close()按照順序做了以下幾個步驟:
    • (1)調用avio_flush()強制清除緩存中的數據
    • (2)調用av_freep()釋放掉AVIOContext種的buffer
    • (3)調用av_free()釋放掉AVIOContext結構體? av_free函數棄用,av_opt_free和avio_context_free
    • (4)調用ffurl_close()關閉并且釋放掉URLContext
  • 下面按照順序分別看看avio_flush()和ffurl_close()這兩個函數

avio_flush()

  • avio_flush()是一個FFmpeg的API函數,聲明位于libavformat\avio.h,如下所示。
void avio_flush(AVIOContext *s)
{int seekback = s->write_flag ? FFMIN(0, s->buf_ptr - s->buf_ptr_max) : 0;flush_buffer(s);if (seekback)avio_seek(s, seekback, SEEK_CUR);
}
  • 可以看出avio_flush()簡單調用了flush_buffer()函數。我們看一下flush_buffer()的定義。
static void flush_buffer(AVIOContext *s)
{s->buf_ptr_max = FFMAX(s->buf_ptr, s->buf_ptr_max);if (s->write_flag && s->buf_ptr_max > s->buffer) {writeout(s, s->buffer, s->buf_ptr_max - s->buffer);if (s->update_checksum) {s->checksum     = s->update_checksum(s->checksum, s->checksum_ptr,s->buf_ptr_max - s->checksum_ptr);s->checksum_ptr = s->buffer;}}s->buf_ptr = s->buf_ptr_max = s->buffer;if (!s->write_flag)s->buf_end = s->buffer;
}
  • 從flush_buffer()定義我們可以看出,該函數將當前緩存指針buf_ptr的位置重新設置到緩存buffer的首部,然后根據AVIOContext對應的流是否可寫分別做不同的處理。
  • 如果AVIOContext對應的流是只讀的(write_flag取值為0),就將緩存的尾部buf_end設定到緩存首部位置;
  • 如果AVIOContext對應的流如果是可寫的(write_flag取值非0),則會調用writeout()函數輸出緩存中剩余的數據。
  • 在這里我們看一下writeout()函數的定義,如下所示。
static void writeout(AVIOContext *s, const uint8_t *data, int len)
{FFIOContext *const ctx = ffiocontext(s);if (!s->error) {int ret = 0;if (s->write_data_type)ret = s->write_data_type(s->opaque, (uint8_t *)data,len,ctx->current_type,ctx->last_time);else if (s->write_packet)ret = s->write_packet(s->opaque, (uint8_t *)data, len);if (ret < 0) {s->error = ret;} else {ctx->bytes_written += len;s->bytes_written = ctx->bytes_written;if (s->pos + len > ctx->written_output_size) {ctx->written_output_size = s->pos + len;
#if FF_API_AVIOCONTEXT_WRITTEN
FF_DISABLE_DEPRECATION_WARNINGSs->written = ctx->written_output_size;
FF_ENABLE_DEPRECATION_WARNINGS
#endif}}}if (ctx->current_type == AVIO_DATA_MARKER_SYNC_POINT ||ctx->current_type == AVIO_DATA_MARKER_BOUNDARY_POINT) {ctx->current_type = AVIO_DATA_MARKER_UNKNOWN;}ctx->last_time = AV_NOPTS_VALUE;ctx->writeout_count++;s->pos += len;
}
  • 從定義可以看出,writeout()調用了AVIOContext的write_packet()方法。根據此前文章《FFmpeg源代碼簡單分析:avio_open2()》中的分析我們可以了解到,AVIOContext的write_packet()實際指向了ffurl_write()函數,而ffurl_write()經過retry_transfer_wrapper()函數最終調用了URLProtocol的url_write()函數。url_write()是一個函數指針,不同的URLProtocol的url_write()指向不同的函數。
  • 例如,file(文件)對應的URLProtocol的定義位于libavformat\file.c,如下所示。
const URLProtocol ff_file_protocol = {.name                = "file",.url_open            = file_open,.url_read            = file_read,.url_write           = file_write,.url_seek            = file_seek,.url_close           = file_close,.url_get_file_handle = file_get_handle,.url_check           = file_check,.url_delete          = file_delete,.url_move            = file_move,.priv_data_size      = sizeof(FileContext),.priv_data_class     = &file_class,.url_open_dir        = file_open_dir,.url_read_dir        = file_read_dir,.url_close_dir       = file_close_dir,.default_whitelist   = "file,crypto,data"
};
  • 可以看出ff_file_protocol中的url_write()指向的是file_write()函數。
  • 我們繼續看一下file_write()的源代碼,如下所示。
  • 從源代碼中可以看出file_write()調用了系統的write()方法向文件中寫數據(很多人可能對write()函數很陌生,可以簡單理解為它等同于fwrite())。
static int file_write(URLContext *h, const unsigned char *buf, int size)
{FileContext *c = h->priv_data;int ret;size = FFMIN(size, c->blocksize);ret = write(c->fd, buf, size);return (ret == -1) ? AVERROR(errno) : ret;
}

ffurl_close()和ffurl_closep()

  • ffurl_close()和ffurl_closep()是FFmpeg內部的兩個函數,它們的聲明位于libavformat\url.h,如下所示。
  • 其實這兩個函數是等同的
/*** Close the resource accessed by the URLContext h, and free the* memory used by it. Also set the URLContext pointer to NULL.** @return a negative value if an error condition occurred, 0* otherwise*/
int ffurl_closep(URLContext **h);
int ffurl_close(URLContext *h);
  • 可見ffurl_close()調用了ffurl_closep()。
int ffurl_close(URLContext *h)
{return ffurl_closep(&h);
}
  • ffurl_closep()的定義如下所示。
int ffurl_closep(URLContext **hh)
{URLContext *h= *hh;int ret = 0;if (!h)return 0;     /* can happen when ffurl_open fails */if (h->is_connected && h->prot->url_close)ret = h->prot->url_close(h);
#if CONFIG_NETWORKif (h->prot->flags & URL_PROTOCOL_FLAG_NETWORK)ff_network_close();
#endifif (h->prot->priv_data_size) {if (h->prot->priv_data_class)av_opt_free(h->priv_data);av_freep(&h->priv_data);}av_opt_free(h);av_freep(hh);return ret;
}
  • 從ffurl_closep()的定義可以看出,它主要做了兩步工作:
    • (1)調用URLProtocol的url_close()
    • (2)調用av_freep()釋放URLContext結構體
  • 其中URLProtocol的url_close()是一個函數指針,其指向的函數與具體的URLProtocol有關,這里我們還是看一下file(文件)對應的URLProtocol,如下所示。
const URLProtocol ff_file_protocol = {.name                = "file",.url_open            = file_open,.url_read            = file_read,.url_write           = file_write,.url_seek            = file_seek,.url_close           = file_close,.url_get_file_handle = file_get_handle,.url_check           = file_check,.url_delete          = file_delete,.url_move            = file_move,.priv_data_size      = sizeof(FileContext),.priv_data_class     = &file_class,.url_open_dir        = file_open_dir,.url_read_dir        = file_read_dir,.url_close_dir       = file_close_dir,.default_whitelist   = "file,crypto,data"
};
  • 從ff_file_protocol中可以看出,url_close()指向file_close()函數。我們再看一下file_close()的定義,如下所示。、
static int file_close(URLContext *h)
{FileContext *c = h->priv_data;int ret = close(c->fd);return (ret == -1) ? AVERROR(errno) : 0;
}
  • 可見file_close()最終調用了系統函數close()關閉了文件指針(不熟悉close()的可以簡單把它理解為fclose())。
  • 至此avio_close()函數分析完畢。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/445952.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/445952.shtml
英文地址,請注明出處:http://en.pswp.cn/news/445952.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

android 使用shell模擬觸屏_[Android]通過adb shell input上報命令模擬屏幕點擊事件【轉】...

常用的 input上報命令&#xff1a;input text 1234 實際向界面注入1234文字&#xff0c;有輸入框&#xff0c;能明顯看到效果input keyevent 4 鍵盤事件&#xff0c;4 為返回input tap 100 300 單擊觸屏事件 &#xff0c;模擬點擊x100 y 300 位置input swipe 100 300 500 300 …

用Python連接MySQL并進行CRUD

Tag: MySQL, PyMySQL, Python 準備條件 Python 2.7MySQL 5.5安裝 PyMySQL pip install PyMySQL 放碼過來 創建一數據表 CREATE TABLE users (id int(11) NOT NULL AUTO_INCREMENT,email varchar(255) COLLATE utf8_bin NOT NULL,password varchar(255) COLLATE utf8_bin N…

python網絡爬蟲的方法有幾種_Python網絡爬蟲過程中5種網頁去重方法簡要介紹

一般的&#xff0c;我們想抓取一個網站所有的URL&#xff0c;首先通過起始URL&#xff0c;之后通過網絡爬蟲提取出該網頁中所有的URL鏈接&#xff0c;之后再對提取出來的每個URL進行爬取&#xff0c;提取出各個網頁中的新一輪URL&#xff0c;以此類推。整體的感覺就是自上而下進…

FFmpeg源代碼簡單分析-編碼-avformat_alloc_output_context2()

參考鏈接 FFmpeg源代碼簡單分析&#xff1a;avformat_alloc_output_context2()_雷霄驊的博客-CSDN博客_avformat_alloc_context avformat_alloc_output_context2() 在基于FFmpeg的視音頻編碼器程序中&#xff0c;該函數通常是第一個調用的函數&#xff08;除了組件注冊函數av…

《深入理解JVM.2nd》筆記(一):走進Java

概述 Java技術體系 Java程序設計語言各種硬件平臺上的Java虛擬機Class文件格式Java API類庫來自商業機構和開源社區的第三方Java類庫 Java發展史 Java虛擬機發展史 展望Java技術的未來 模塊化 混合語言 多核并行 進一步豐富語法 64位虛擬機 實戰&#xff1a;自己編譯…

js監聽只讀文本框_js 動態控制 input 框 的只讀屬性

input 框的只讀屬性&#xff1a; readonly在頁面中直接添加為只讀時&#xff0c;可在input中直接添加 readonly"readonly"&#xff0c;但是如果想通過點擊按鈕來改變的話&#xff0c;需要通過js(或jquery)來實現。最近一次使用這個&#xff0c;終于發現了以前寫這…

FFmpeg源代碼簡單分析-編碼-avformat_write_header()

參考鏈接 FFmpeg源代碼簡單分析&#xff1a;avformat_write_header()_雷霄驊的博客-CSDN博客_avformat_write_header avformat_write_header() FFmpeg寫文件用到的3個函數&#xff1a;avformat_write_header()&#xff0c;av_write_frame()以及av_write_trailer()其中av_writ…

《深入理解JVM.2nd》筆記(二):Java內存區域與內存溢出異常

文章目錄概述運行時數據區域程序計數器Java虛擬機棧本地方法棧Java堆方法區運行時常量池直接內存HotSpot虛擬機對象探秘對象的創建第一步第二步第三步第四步最后一腳對象的內存布局對象頭Header第一部分第二部分實例數據Instance對齊填充Padding對象的訪問定位句柄直接指針對象…

vue底部選擇器_Vue組件-極簡的地址選擇器

一、前言本文用Vue完成一個極簡的地點選擇器&#xff0c;我們接下來帶大家實現這個。當然其中也有一些值得學習與注意的地方。話不多說&#xff0c;我們先上demo圖。因為每個人的需要不一樣&#xff0c;我這邊就不在實現更多的功能&#xff0c;所以留有更大的空間供大家增刪改。…

FFmpeg源代碼簡單分析-編碼-avcodec_encode_video()已被send_frame 和 receive_packet替代

參考鏈接 FFmpeg源代碼簡單分析&#xff1a;avcodec_encode_video()_雷霄驊的博客-CSDN博客_avcodec_encode_video2 avcodec_encode_video() 該函數用于編碼一幀視頻數據。函數已被棄用參考鏈接&#xff1a;FFmpeg 新舊版本編碼 API 的區別_zouzhiheng的博客-CSDN博客 send_f…

《深入理解JVM.2nd》筆記(三):垃圾收集器與垃圾回收策略

文章目錄概述對象已死嗎引用計數算法可達性分析算法再談引用finalize()&#xff1a;生存還是死亡回收方法區垃圾收集算法標記-清除算法復制算法標記-整理算法分代收集算法HotSpot的算法實現枚舉根結點安全點安全區域垃圾收集器SerialParNewParallel ScavengeSerial OldParallel…

python計算股票趨勢_通過機器學習的線性回歸算法預測股票走勢(用Python實現)...

1 波士頓房價數據分析安裝好Python的Sklearn庫后&#xff0c;在安裝包下的路徑中就能看到描述波士頓房價的csv文件&#xff0c;具體路徑是“python安裝路徑\Lib\site-packages\sklearn\datasets\data”&#xff0c;在這個目錄中還包含了Sklearn庫會用到的其他數據文件&#xff…

FFmpeg源代碼簡單分析-編碼-av_write_frame()

參考鏈接 FFmpeg源代碼簡單分析&#xff1a;av_write_frame()_雷霄驊的博客-CSDN博客_av_write_frame av_write_frame() av_write_frame()用于輸出一幀視音頻數據&#xff0c;它的聲明位于libavformat\avformat.h&#xff0c;如下所示。 /*** Write a packet to an output me…

《深入理解JVM.2nd》筆記(四):虛擬機性能監控與故障處理工具

文章目錄概述JDK的命令行工具jps&#xff1a;虛擬機進程狀況工具jstat&#xff1a;虛擬機統計信息監視工具jinfo&#xff1a;Java配置信息工具jmap&#xff1a;Java內存映像工具jhat&#xff1a;虛擬機堆轉儲快照分析工具jstack&#xff1a;Java堆棧跟蹤工具HSDIS&#xff1a;J…

postgresql 主從配置_Postgresql主從配置

一、簡介PostgreSql在9.0之后引入了主從的流復制機制&#xff0c;所謂流復制&#xff0c;就是從服務器通過tcp流從主服務器中同步相應的數據。這樣當主服務器數據丟失時從服務器中仍有備份。與基于文件日志傳送相比&#xff0c;流復制允許保持從服務器更新。 從服務器連接主服務…

FFmpeg源代碼簡單分析-編碼-av_write_trailer()

參考鏈接&#xff1a; FFmpeg源代碼簡單分析&#xff1a;av_write_trailer()_雷霄驊的博客-CSDN博客_av_malloc av_write_trailer() av_write_trailer()用于輸出文件尾&#xff0c;它的聲明位于libavformat\avformat.h&#xff0c;如下所示 /*** Write the stream trailer to…

科沃斯掃地機器人風扇模塊_掃地機器人不能開機,不能關機,風扇不轉

家庭的重要性自不必再細說&#xff0c;而小編今天要說的則是家庭環境的重要性。一般家庭最少居住三口人&#xff0c;兩個大人加一個孩子&#xff0c;每天回到家&#xff0c;看到家里整潔舒適的環境&#xff0c;心情該是多么地愜意。要是我們每天下班回到家中&#xff0c;看到滿…

MySQL關鍵字EXPLAIN的用法及其案例

文章目錄概述EXPLAIN輸出的列的解釋實例說明select_type的說明UNIONDEPENDENT UNION與DEPENDENT SUBQUERYSUBQUERYDERIVEDtype的說明system&#xff0c;consteq_refrefref_or_nullindex_mergeunique_subqueryindex_subqueryrangeindexALLextra的說明DistinctNot existsRange ch…

FFmpeg源代碼簡單分析-其他-日志輸出系統(av_log()等)

參考鏈接 FFmpeg源代碼簡單分析&#xff1a;日志輸出系統&#xff08;av_log()等&#xff09;_雷霄驊的博客-CSDN博客_ffmpeg源碼分析 日志輸出系統&#xff08;av_log()等&#xff09; 本文分析一下FFmpeg的日志&#xff08;Log&#xff09;輸出系統的源代碼。日志輸出部分的…

FFmpeg源代碼簡單分析-其他-AVClass和AVoption

參考鏈接 FFmpeg源代碼簡單分析&#xff1a;結構體成員管理系統-AVClass_雷霄驊的博客-CSDN博客FFmpeg源代碼簡單分析&#xff1a;結構體成員管理系統-AVOption_雷霄驊的博客-CSDN博客 概述 AVOption用于在FFmpeg中描述結構體中的成員變量。它最主要的作用可以概括為兩個字&a…