基于GPUImage 添加濾鏡推流時推流畫面閃爍問題

隨筆

寫這個之前網絡上找了好多辦法都沒有成功解決

使用本地錄制功能錄制視頻沒問題

使用轉碼推流發(fā)送后顯示丟失幀目測是有一部分幀圖片未進行美顏濾鏡效果處理就進行了發(fā)送剂癌,所以出現閃爍的狀況

猜測問題出現的原因:

1. 本地錄制使用的獲取錄制后的元數據和直播獲取途徑不一樣

@property (nonatomic, strong) GPUImageOutput<GPUImageInput> *filter;
@property (nonatomic, strong) GPUImageOutput<GPUImageInput> *output;
@property (nonatomic, strong) GPUImageAlphaBlendFilter *blendFilter;
@property (nonatomic, strong) GPUImageUIElement *uiElementInput;

-------------添加全局-------------------
@property (nonatomic, strong) GPUImagePixelBufferOutput *gpuOutput;
---------------------------------------
    /// 視頻采集獲取關系鏈如下所示:
    /*
         要理解它的實現原理堡妒,需要搞懂GPUImageUIElement和GPUImageAlphaBlendFilter媳谁。
         GPUImageUIElement的作用是把一個視圖的layer通過CALayer的renderInContext:方法把layer轉化為image添寺,
         然后作為OpenGL的紋理傳給GPUImageAlphaBlendFilter婆誓。
         而GPUImageAlphaBlendFilter則是一個兩輸入的blend filter,
         第一個輸入是攝像頭數據吭露,
         第二個輸入是剛剛提到的GPUImageUIElement的數據捞蛋,
         GPUImageAlphaBlendFilter將這兩個輸入做alpha blend孝冒,可以簡單的理解為將第二個輸入疊加到第一個的上面,
         */
        
        /*
         雙重濾鏡疊加效果(并聯)
         fileter濾鏡->blendFilter濾鏡->gpuImageView展示
         uiElementInput->blendFilter濾鏡->gpuImageView展示//
         uiElementInput: 只有初始化的水印圖片拟杉,注釋 [self.filter addTarget:self.blendFilter] 庄涡,屏幕上只有水印錄像沒有實時影像
         filter: 實時影像
         */
        [self.filter addTarget:self.blendFilter];
        [self.uiElementInput addTarget:self.blendFilter];
        [self.blendFilter addTarget:self.gpuImageView];
    -------------------------------------------------
  |    [self.blendFilter addTarget:self.gpuOutput]; |
    -------------------------------------------------
        if(self.saveLocalVideo) [self.blendFilter addTarget:self.movieWriter];
        [self.filter addTarget:self.output];
    -------------------------------------------------
  |    [self.filter addTarget:self.gpuOutput];      |
    -------------------------------------------------
        [self.uiElementInput update];

以上圈出來的是需要加去的方法解決閃爍的水印丟失的方法

/// 原來對美顏數據的獲取方法
   [self.output setFrameProcessingCompletionBlock:^(GPUImageOutput *output, CMTime time) {
        __strong __typeof(weakSelf)strongSelf = weakSelf;
        @autoreleasepool {
            GPUImageFramebuffer *imageFramebuffer = output.framebufferForOutput;
            GPUImageFramebuffer *imageFramebuffer = output.framebufferForOutput;
            CVPixelBufferRef pixelBuffer = [imageFramebuffer pixelBuffer];
            if (pixelBuffer && _self.delegate && [_self.delegate respondsToSelector:@selector(captureOutput:pixelBuffer:isBeauty:)]) {
                [strongSelf.delegate captureOutput:strongSelf pixelBuffer:pixelBufferRef isBeauty:strongSelf.beautyFace frameTime: time];
            }
        }
    }];

原始的數據獲取就出現了推流后的閃爍問題

加入自定義方法后,獲取處理后數據的方法如下搬设;

    __weak typeof(self) weakSelf = self;
    _gpuOutput.pixelBufferCallback = ^(CVPixelBufferRef  _Nullable pixelBufferRef, CMTime frameTime) {
        __strong __typeof(weakSelf)strongSelf = weakSelf;
        if (pixelBufferRef && strongSelf.delegate && [strongSelf.delegate respondsToSelector:@selector(captureOutput:pixelBuffer:isBeauty:frameTime:)]) {
                [strongSelf.delegate captureOutput:strongSelf pixelBuffer:pixelBufferRef isBeauty:strongSelf.beautyFace frameTime:frameTime];
            }
    };

2. 錄制方法獲取可自行下載源碼研究啼染,此處貼一部分做記錄

/// GPUImageMovieWriter 錄制方法
@interface GPUImageMovieWriter : NSObject <GPUImageInput>
#pragma mark GPUImageInput protocol

- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
{
       ......
       /// 方法內部實現
}

3. 我們自定義一個GPUImagePixelBufferOutput管理我們的美顏數據,模仿錄制GPUImageMovieWriter方法進行處理輸出

@interface GPUImagePixelBufferOutput : GPUImageRawDataOutput <GPUImageInput>繼承自GPUImageRawDataOutput <GPUImageInput>

對數據更加容易處理

源碼文件:

GPUImagePixelBufferOutput.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

#if __has_include(<GPUImage/GPUImageFramework.h>)
#import <GPUImage/GPUImageRawDataOutput.h>
#else
#import "GPUImageRawDataOutput.h"

#endif

typedef void (^GPUImageBufferOutputBlock) (CVPixelBufferRef _Nullable pixelBufferRef, CMTime  frameTime);

NS_ASSUME_NONNULL_BEGIN

@interface GPUImagePixelBufferOutput : GPUImageRawDataOutput <GPUImageInput>

@property(nonatomic, copy)GPUImageBufferOutputBlock pixelBufferCallback;

- (instancetype)initwithImageSize:(CGSize)newImageSize;
@end

NS_ASSUME_NONNULL_END

GPUImagePixelBufferOutput.m

此處有自己項目的自定義需求所以保留了相機采集時的時間戳數據

使用

#pragma mark - GPUImageInput protocol

- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;方法進行數據自定義處理焕梅,效果是繼承自GPUImageRawDataOutput 是數據鏈路處理過程的數據輸出管理迹鹅,可以獲得整個視頻流處理后的數據,在這個里面進行復寫操作實現自己的業(yè)務邏輯


#import "GPUImagePixelBufferOutput.h"

@implementation GPUImagePixelBufferOutput


- (instancetype)initwithImageSize:(CGSize)newImageSize{
 
  if (self == [super initWithImageSize:newImageSize resultsInBGRAFormat:YES]) {
    
  }
  return self;
}

#pragma mark - GPUImageInput protocol
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
{
   [super newFrameReadyAtTime:frameTime atIndex:textureIndex];

//    Float64 time =  CMTimeGetSeconds(frameTime);
//    NSLog(@"采集時間贞言?斜棚??该窗? %f",time);//采集時間弟蚀??酗失?义钉? 1917.957380
    
    [self lockFramebufferForReading];
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                 [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
                                 [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
                                 nil];
//    NSDictionary *options = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{}};

    CVPixelBufferRef pixelBuffer = NULL;
    CVPixelBufferCreateWithBytes(kCFAllocatorDefault,
                                 imageSize.width,
                                 imageSize.height,
                                 kCVPixelFormatType_32BGRA,
                                 self.rawBytesForImage,
                                 self.bytesPerRowInOutput,
                                 NULL,
                                 NULL,
                                 (__bridge CFDictionaryRef)options,
                                 &pixelBuffer);


    if(self.pixelBufferCallback){
        self.pixelBufferCallback(pixelBuffer,frameTime);
    }
    CVPixelBufferRelease(pixelBuffer);
    [self unlockFramebufferAfterReading];
}

- (void)willOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer {}

- (void)processAudioBuffer:(CMSampleBufferRef)audioBuffer {}

- (BOOL)hasAudioTrack {return YES;}

@end

4.有效結局了GPUImage美顏后推流美顏效果丟失產生的閃爍問題

后記

具體原因等后續(xù)會加入進來,因為時間倉促规肴,先隨筆記錄一哈解決辦法捶闸,還有好的方法可以留言告知一哈夜畴,目前我的解決思路時模仿GPUImageMovieWriter 錄制方法內部實現方法進行處理美化后的數據。

我可能有具體解釋的可能過于牽強删壮,但是方法目前測試是行得通贪绘,后續(xù)會進行錯誤修正,希望可以不吝賜教央碟。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末税灌,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子亿虽,更是在濱河造成了極大的恐慌菱涤,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件洛勉,死亡現場離奇詭異粘秆,居然都是意外死亡,警方通過查閱死者的電腦和手機坯认,發(fā)現死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門翻擒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人牛哺,你說我怎么就攤上這事陋气。” “怎么了引润?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵巩趁,是天一觀的道長。 經常有香客問我淳附,道長议慰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任奴曙,我火速辦了婚禮别凹,結果婚禮上,老公的妹妹穿的比我還像新娘洽糟。我一直安慰自己炉菲,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布坤溃。 她就那樣靜靜地躺著拍霜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪薪介。 梳的紋絲不亂的頭發(fā)上祠饺,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音汁政,去河邊找鬼道偷。 笑死缀旁,一個胖子當著我的面吹牛,可吹牛的內容都是我干的试疙。 我是一名探鬼主播诵棵,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼抠蚣,長吁一口氣:“原來是場噩夢啊……” “哼祝旷!你這毒婦竟也來了?” 一聲冷哼從身側響起嘶窄,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤怀跛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后柄冲,有當地人在樹林里發(fā)現了一具尸體吻谋,經...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年现横,在試婚紗的時候發(fā)現自己被綠了漓拾。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡戒祠,死狀恐怖骇两,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情姜盈,我是刑警寧澤低千,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站馏颂,受9級特大地震影響示血,放射性物質發(fā)生泄漏。R本人自食惡果不足惜救拉,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一难审、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧亿絮,春花似錦告喊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至斗锭,卻和暖如春地淀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背岖是。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工帮毁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留实苞,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓烈疚,卻偏偏與公主長得像黔牵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子爷肝,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內容