視訊的水印通常指附加在原始視訊上的可見或者不可見的,與原始視訊無直接關聯的辨別。通常在有線電視畫面上電視台的台标以及視訊網站上的logo就是典型的視訊水印的應用場景。通常實作視訊水印可以通過FFMpeg提供的libavfilter庫實作。libavfilter庫實際上實作的是視訊的濾鏡功能,除了水印之外,還可以實作視訊幀的灰階化、平滑、翻轉、直方圖均衡、裁剪等操作。
我們這裡實作的視訊水印等操作,完全在視訊像素域實作,即從一個yuv檔案中讀取資料到AVFrame結構,對AVFrame結構進行處理後再輸出到另一個yuv檔案。中間不涉及封裝或編碼解碼等操作。
我們通過與之前類似的方式,在指令行中擷取輸入、輸出檔案名,圖像寬高。首先定義如下的結構體用于儲存配置資訊:
在這個結構體中,filterIdx用于表示目前工程選擇哪一種filter,即希望實作哪一種功能。
在進入main函數之後,調用hello函數來解析指令行參數:
該函數實作了輸入輸出檔案的檔案名擷取并打開,并讀取filter索引。
在進行初始化之前,必須調用filter的init函數,之後才能針對Video Filter進行各種操作。其聲明如下:
為了實作視訊水印的功能,所需要的相關結構主要有:
其中AVFilterContext用于表示一個filter的執行個體上下文,AVFilterGraph表示一個video filtering的工作流。Video Filter的初始化實作如以下函數:
我們首先聲明AVFrame類型的對象和指向像素緩存的指針:
然後配置設定AVFrame對象,并配置設定其中的緩存區:
這一部分主要包括三大部分:
讀取原始的YUV資料到輸入的frame;
使用預先定義好的filter_graph處理輸入frame,生成輸出frame;
将輸出frame中的像素值寫入輸出yuv檔案;
第一部分,讀取原始yuv的實作由自定義函數Read_yuv_data_to_buf實作:
第二部分實際上分為兩部分,即将輸入frame送入filter graph,以及從filter graph中取出輸出frame。實作方法分别為:
第三部分,寫出輸出frame到輸出yuv檔案:
該部分的綜合實作如下:
整體實作完成後,需要進行善後的收尾工作有釋放輸入和輸出frame、關閉輸入輸出檔案,以及釋放filter graph:
處理前的原始圖像如下:

添加水印之後的圖像如下: