理解ffmpeg

2023-07-08 06:01:01

ffmpeg是一個完整的、跨平臺的音訊和視訊錄製、轉換和串流媒體解決方案。

它的官網:https://ffmpeg.org/

這裡有一份中文的檔案:https://ffmpeg.p2hp.com/

ffmpeg提供了什麼?

在centos上,可以通過yum進行安裝:

yum install epel-release

rpm -Uvh https://download1.rpmfusion.org/free/el/rpmfusion-free-release-7.noarch.rpm

yum install ffmpeg ffmpeg-devel


按照上述命令安裝完ffmpeg-devel後,會在 /usr/lib64/ 路徑找到對應的庫

  • libavcodec.so
  • libavutil.so
  • ...

ffmpeg安裝完以後會有三個工具:

  • ffmpeg 用於在格式之間轉換多媒體檔案的命令列工具
  • ffplay 基於SDL和FFmpeg庫的簡單媒體播放器
  • ffprobe 一個簡單的多媒體流分析器

ffmpeg還提供一系列的庫,能提供開發者進行編碼開發。

  • libavutil 是一個包含用於簡化變成的函數的庫,包括亂數生成器、資料結構、數學例程、核心多媒體實用程式等等。
  • libavcodec 是一個包含音訊/視訊編解碼器的解碼器和編碼器的庫。
  • libavformat 是一個包含用於多媒體容器格式的複用器和複用器的庫
  • libavdevice 是一個包含輸入和輸出裝置的庫,用於從許多常見的多媒體輸入/輸出軟體框架中抓取和渲染,包括Video4Linux, Video4Linux2, VfW和ALSA。
  • libavfilter 是一個包含媒體過濾器的庫。
  • libswscacle 是一個執行高度優化的影象播放和色彩空間/畫素格式轉換操作的庫。
  • libswresample 是一個執行高度優化的音訊重取樣、重矩陣化和樣本格式轉換操作的庫。

原始碼

ffmpeg是開源的,原始碼可以直接

git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg

FFmpeg主要是使用C語言編寫的,由於FFmpeg需要對音訊和視訊進行底層處理,包括解碼、編碼、封裝、解封裝等操作,因此選擇C語言是非常合適的,因為它可以提供對底層作業系統和硬體的直接存取。

libavutil

FFmpeg的Libavutil庫提供了許多方法和功能,用於在多媒體處理中進行通用的實用工具和基本功能。以下是一些常見的Libavutil庫提供的方法和功能:

  1. 記憶體管理:
    • av_malloc()av_mallocz():動態分配記憶體。
    • av_free():釋放先前分配的記憶體。
    • av_memcpy_backptr():從後向前拷貝記憶體。
    • av_fast_malloc():快速分配記憶體。
  2. 字串操作:
    • av_strstart()av_stristart():檢查字串的字首。
    • av_stristr():在字串中查詢子字串,忽略大小寫。
    • av_get_token():從輸入字串中提取標記。
    • av_strcasecmp()av_strncasecmp():比較字串,忽略大小寫。
  3. 時間和時鐘:
    • av_gettime():獲取當前時間戳。
    • av_gettime_relative():獲取相對時間戳。
    • av_usleep():微秒級延遲。
  4. 數學和整數操作:
    • av_clipl_int32()av_clipf():對整數和浮點數進行範圍限制。
    • av_log2():計算以2為底的對數。
    • av_gcd():計算最大公約數。
    • av_rescale_q():按比例轉換數值。
  5. 位元組操作:
    • av_be2ne16()av_be2ne32():將大端位元組序轉換為本地位元組序。
    • av_memcpy_backptr():從後向前拷貝位元組。
  6. 位元組流處理:
    • avio_* 系列函數:用於讀寫位元組流,如開啟、關閉、讀取和寫入檔案。

這只是一小部分Libavutil庫提供的方法和功能列表。Libavutil還提供了許多其他有用的函數,用於處理時間戳、計算時間間隔、處理位元組流、顏色空間轉換等等。

更多方法見:http://ffmpeg.org/doxygen/trunk/group__lavu.html

libavcodec

FFmpeg的libavcodec庫是用於音訊和視訊編解碼的核心庫。它提供了豐富的方法和功能,用於處理不同編解碼器的音視訊資料。以下是一些常見的libavcodec庫提供的方法和功能:

  1. 編解碼器操作:
    • avcodec_find_encoder()avcodec_find_decoder():查詢編碼器和解碼器。
    • avcodec_open2()avcodec_close():開啟和關閉編碼器和解碼器。
    • avcodec_parameters_to_context():將編碼器引數轉換為編碼器上下文。
  2. 編碼器和解碼器引數設定:
    • avcodec_parameters_alloc()avcodec_parameters_free():分配和釋放編碼器引數物件。
    • avcodec_parameters_copy():複製編碼器引數。
    • avcodec_parameters_from_context():從編碼器上下文中獲取編碼器引數。
  3. 編碼和解碼:
    • avcodec_send_packet():傳送封包給編碼器或解碼器。
    • avcodec_receive_frame():接收解碼器輸出的幀。
    • avcodec_encode_video2()avcodec_encode_audio2():編碼視訊和音訊資料。
    • avcodec_decode_video2()avcodec_decode_audio4():解碼視訊和音訊資料。
  4. 視訊和音訊幀操作:
    • av_frame_alloc()av_frame_free():分配和釋放幀物件。
    • av_frame_get_best_effort_timestamp():獲取最佳時間戳。
    • av_frame_copy()av_frame_copy_props():複製幀資料和屬性。
  5. 編解碼器引數查詢:
    • av_codec_get_name():獲取編解碼器名稱。
    • av_codec_get_tag2():獲取編解碼器的四位元組標籤。
  6. 錯誤處理和資訊獲取:
    • av_strerror():獲取錯誤訊息字串。
    • avcodec_error_to_string():將錯誤程式碼轉換為字串。
    • avcodec_get_name():獲取編解碼器的名稱。
    • avcodec_get_type():獲取編解碼器的型別。

這只是一小部分libavcodec庫提供的方法和功能列表。libavcodec庫還提供了更多用於處理音視訊編解碼的功能,如設定編碼引數、處理編碼器的選項、幀格式轉換等。

更多方法見:http://ffmpeg.org/doxygen/trunk/group__libavc.html

libavformat

FFmpeg的libavformat庫提供了用於音視訊封裝和解封裝的方法和功能。它支援多種音視訊容器格式,如AVI、MP4、MKV等。以下是一些常見的libavformat庫提供的方法和功能:

  1. 格式上下文操作:
    • avformat_open_input()avformat_close_input():開啟和關閉媒體檔案。
    • avformat_find_stream_info():獲取媒體檔案的流資訊。
    • avformat_alloc_context()avformat_free_context():分配和釋放格式上下文。
  2. 流操作:
    • av_find_best_stream():查詢最佳的音視訊流。
    • av_read_frame():讀取音視訊幀。
    • av_seek_frame():在媒體檔案中進行幀級別的跳轉。
    • av_write_frame():寫入音視訊幀。
  3. 封裝格式操作:
    • avformat_write_header()avformat_write_trailer():寫入封裝格式的頭部和尾部。
    • avio_open()avio_close():開啟和關閉封裝格式的IO上下文。
  4. 流資訊獲取:
    • avformat_new_stream():建立新的音視訊流。
    • av_stream_get_end_pts():獲取流的結束時間戳。
    • av_stream_get_r_frame_rate():獲取流的影格率。
  5. 格式引數設定和獲取:
    • avformat_alloc_output_context2():分配輸出格式上下文。
    • avformat_alloc_output_context2():獲取輸入格式上下文的引數。
  6. 時間基和時間戳處理:
    • av_rescale_q():按比例轉換時間戳。
    • av_guess_frame_rate():猜測影格率。
  7. 錯誤處理和資訊獲取:
    • av_strerror():獲取錯誤訊息字串。
    • avformat_version():獲取libavformat庫的版本號。
    • av_dump_format():輸出媒體檔案的格式資訊。

這只是一小部分libavformat庫提供的方法和功能列表。libavformat庫還提供了更多用於音視訊封裝和解封裝的功能,如後設資料操作、時間碼處理、流選擇、封裝格式的選項設定等。

更多方法見:http://ffmpeg.org/doxygen/trunk/group__libavf.html

libavdevice

FFmpeg的libavdevice庫提供了與音視訊裝置互動的方法和功能。它允許您進行音訊和視訊的採集和播放,並提供了與裝置的互動介面。以下是一些常見的libavdevice庫提供的方法和功能:

  1. 裝置操作:
    • avdevice_register_all():註冊所有可用的裝置。
    • avdevice_list_devices():列出可用的音視訊裝置。
    • avdevice_get_input_list():獲取輸入裝置列表。
    • avdevice_get_output_list():獲取輸出裝置列表。
    • avdevice_open()avdevice_close():開啟和關閉裝置。
  2. 裝置引數設定:
    • avdevice_capabilities_create()avdevice_capabilities_free():建立和釋放裝置引數物件。
    • avdevice_list_input_sources()avdevice_list_output_sinks():列出輸入源和輸出介面。
    • avdevice_list_formats():列出裝置支援的音視訊格式。
  3. 裝置採集和播放:
    • avdevice_read_packet():從裝置讀取音視訊包。
    • avdevice_write_packet():向裝置寫入音視訊包。
  4. 錯誤處理和資訊獲取:
    • av_strerror():獲取錯誤訊息字串。
    • avdevice_version():獲取libavdevice庫的版本號。

更多方法見:http://ffmpeg.org/doxygen/trunk/group__lavd.html

libavfilter

FFmpeg的libavfilter庫提供了音視訊濾鏡處理的方法和功能。它允許您對音視訊資料進行各種濾鏡和效果的處理,如裁剪、縮放、旋轉、色彩調整等。以下是一些常見的libavfilter庫提供的方法和功能:

  1. 濾鏡圖處理:
    • avfilter_register_all():註冊所有可用的濾鏡。
    • avfilter_graph_alloc()avfilter_graph_free():建立和釋放濾鏡圖。
    • avfilter_graph_parse2():解析濾鏡圖的字串描述。
  2. 濾鏡操作:
    • avfilter_get_by_name():通過名稱獲取濾鏡。
    • avfilter_graph_create_filter():建立濾鏡範例。
    • avfilter_init_str():初始化濾鏡引數。
  3. 輸入輸出處理:
    • av_buffersrc_add_frame():向輸入緩衝區新增幀資料。
    • av_buffersink_get_frame():從輸出緩衝區獲取幀資料。
  4. 濾鏡引數設定和查詢:
    • avfilter_inout_alloc()avfilter_inout_free():建立和釋放輸入輸出結構。
    • avfilter_graph_config():設定濾鏡圖。
  5. 錯誤處理和資訊獲取:
    • av_strerror():獲取錯誤訊息字串。
    • avfilter_version():獲取libavfilter庫的版本號。

libswscale

FFmpeg的libswscale庫提供了影象縮放和顏色空間轉換的方法和功能。它用於對視訊幀進行大小調整、畫素格式轉換和色彩空間轉換等操作。以下是一些常見的libswscale庫提供的方法和功能:

  1. 縮放和影象處理:
    • sws_getContext()sws_freeContext():建立和釋放影象縮放上下文。
    • sws_scale():縮放和轉換影象。
    • sws_setColorspaceDetails():設定顏色空間細節。
  2. 影象引數獲取和設定:
    • sws_getCachedContext()sws_getContext():獲取和設定影象縮放上下文的快取。
  3. 顏色空間轉換:
    • sws_convertPalette8ToPacked32():將8位元調色盤轉換為32位元色彩。
    • sws_setColorspaceDetails():設定顏色空間細節。
  4. 錯誤處理和資訊獲取:
    • sws_strerror():獲取錯誤訊息字串。
    • swscale_version():獲取libswscale庫的版本號。

libswresample

FFmpeg的libswresample庫提供了音訊重取樣和格式轉換的方法和功能。它用於對音訊資料進行取樣率、通道佈局和樣本格式的轉換。以下是一些常見的libswresample庫提供的方法和功能:

  1. 上下文和重取樣操作:
    • swr_alloc()swr_free():建立和釋放音訊重取樣上下文。
    • swr_init():初始化音訊重取樣上下文。
    • swr_convert():進行音訊重取樣。
  2. 引數設定和查詢:
    • swr_config_frame():設定輸入/輸出音訊幀的引數。
    • swr_set_compensation():設定音訊重取樣補償。
  3. 輸入/輸出音訊幀處理:
    • swr_alloc_set_opts():設定輸入/輸出音訊幀的引數並建立音訊重取樣上下文。
    • swr_convert_frame():進行音訊重取樣並輸出音訊幀。
  4. 延遲處理:
    • swr_get_delay():獲取重取樣的延遲。
    • swr_inject_silence():注入靜音樣本。
  5. 錯誤處理和資訊獲取:
    • swresample_strerror():獲取錯誤訊息字串。
    • swresample_version():獲取libswresample庫的版本號。

如何讀取一個mp4?

我現在有一個mp4檔案,要讀取這個檔案應該怎麼操作呢?

我是按照簽名說的yum的方式安裝ffmpeg-devel,它的

動態庫地址為:/user/lib64/

header標頭檔案地址為:/usr/include/ffmpeg/libavcodec/

在程式中直接參照就行

#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>

以下是一段讀取網際網路mp4的程式碼。

#include <iostream>

extern "C" 
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
}

int main() {
    std::cout << "start read url mp4" << std::endl;
    
    // 做註冊處理
	av_register_all();

    avformat_network_init();

	AVFormatContext *inputContext = NULL;
    // 開啟一個url的資訊
    std::string url = "https://demo.com/BigBuckBunny.mp4";
	int ret = avformat_open_input(&inputContext, url.c_str(), NULL, NULL);
    if ( ret != 0) {
    	// 開啟檔案失敗,處理錯誤
        // 可以通過呼叫 av_strerror() 函數將錯誤碼轉換為可讀的錯誤訊息
        char errorStr[AV_ERROR_MAX_STRING_SIZE];
        av_strerror(ret, errorStr, sizeof(errorStr));
        printf("Failed to open input file: %s\n", errorStr);
        return ret;
	}

    ret = avformat_find_stream_info(inputContext, NULL);
    if (ret < 0) {
       char errorStr[AV_ERROR_MAX_STRING_SIZE];
        av_strerror(ret, errorStr, sizeof(errorStr));
        printf("Failed to avformat_find_stream_info file: %s\n", errorStr);
        return ret; 
    }

    // 輸出AVFormatContent資訊
    av_dump_format(inputContext, -1, url.c_str(), 0);

	for (int i = 0; i < inputContext->nb_streams; i++) {
    	AVStream *stream = inputContext->streams[i];
    	if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
        	// 處理音訊流
    	}
    	else if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
        	// 處理視訊流
    	}

      int64_t duration = stream->duration;
      std::cout << duration << std::endl;
	}

	avformat_close_input(&inputContext);

	std::cout << "ok" << std::endl;
	return 0;
}

輸出:

start read url mp4
Input #-1, mov,mp4,m4a,3gp,3g2,mj2, from 'https://demo.com/BigBuckBunny.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isomavc1mp42
    creation_time   : 2010-01-10T08:29:06.000000Z
  Duration: 00:09:56.47, start: 0.000000, bitrate: 2119 kb/s
    Stream #-1:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 125 kb/s (default)
    Metadata:
      creation_time   : 2010-01-10T08:29:06.000000Z
      handler_name    : (C) 2007 Google Inc. v08.13.2007.
    Stream #-1:1(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1991 kb/s, 24 fps, 24 tbr, 24k tbn, 48 tbc (default)
    Metadata:
      creation_time   : 2010-01-10T08:29:06.000000Z
      handler_name    : (C) 2007 Google Inc. v08.13.2007.
26304512
14315000
ok

這裡的關鍵的函數呼叫邏輯如下:

  • av_register_all 初始化ffmpeg庫
  • avformat_network_init 初始化ffmpeg的網路存取,如果我們的輸入檔案是url,則需要初始化
  • avformat_open_input 開啟音視訊檔,這個時候並沒有讀取到這個音視訊檔的資訊
  • AVFormatContext 這個是非常重要的結構,表示音視訊格式的上下文,一些重要欄位
    • AVInputFormat:指向輸入格式的指標,包含解封裝函數等資訊。
    • AVStream:指向音視訊流的陣列,每個流都有對應的索引。
    • nb_streams:音視訊流的數量。
    • duration:音視訊檔的總時長。
    • bit_rate:音視訊檔的位元率。
    • metadata:後設資料,包含了檔案的附加資訊,如標題、作者、描述等。
  • avformat_find_stream_info 獲取音視訊檔的流資訊
  • av_dump_format 列印AVFormatContext的資訊
  • av_strerror 將錯誤碼轉換為可讀的錯誤訊息字串