使用GPUImage實現視頻濾鏡

關於GPUImage

這裏直接引用官方描述:
The GPUImage framework is a BSD-licensed iOS library that lets you apply GPU-accelerated filters and other effects to images, live camera video, and movies. In comparison to Core Image (part of iOS 5.0), GPUImage allows you to write your own custom filters, supports deployment to iOS 4.0, and has a simpler interface. However, it currently lacks some of the more advanced features of Core Image, such as facial detection.
項目地址:https://github.com/BradLarson/GPUImage

濾鏡基本原理

濾鏡處理的原理就是把靜態圖片或者視頻的每一幀進行圖形變換再顯示出來。它的本質就是像素點的座標和顏色變化,這點從GPUImage項目中濾鏡的源代碼就可以瞭解到。
例如下面就是一個名爲DarkenBlend的濾鏡代碼:


NSString *const kGPUImageDarkenBlendFragmentShaderString = SHADER_STRING
(
 varying highp vec2 textureCoordinate;
 varying highp vec2 textureCoordinate2;

 uniform sampler2D inputImageTexture;
 uniform sampler2D inputImageTexture2;

 void main()
 {
    lowp vec4 base = texture2D(inputImageTexture, textureCoordinate);
    lowp vec4 overlayer = texture2D(inputImageTexture2, textureCoordinate2);

    gl_FragColor = vec4(min(overlayer.rgb * base.a, base.rgb * overlayer.a) + overlayer.rgb * (1.0 - base.a) + base.rgb * (1.0 - overlayer.a), 1.0);
 }
);

GPUImage的最新版本已經內置了125個濾鏡。也支持編寫自定義濾鏡(custom filter)。

圖像處理流程

數據源需要實現GPUImageOutput接口,而後續各個環節(包括最後處理輸出結果)的對象都要實現GPUImageInput接口。每個處理環節都是從上一個環節獲取圖像數據,進行處理後再將結果傳遞給下一個。下游的處理對象稱爲上一步的target。使用addTarget:方法爲處理鏈路添加每個環節的對象。一個常見的鏈條如下:
數據源(例如GPUImageVideoCamera或者GPUImageMovie)->各類filter->GPUImageView
如果需要將結果輸出到文件,只要把上述流程中最末的GPUImageView改爲一個GPUImageMovieWriter即可。所以濾鏡的添加和替換,以及輸出結果都十分簡單方便。

附一張GPUImage的結構圖
Snip20160222_3

接入app

將濾鏡接入app非常簡單,只要創建一個GPUImageMovie,一個具體的GPUImageFilter和一個用來顯示的GPUImageView,然後按處理鏈條的上下游關係把它們用addTarget串起來。
下面附上我的app裏面的調用代碼(預覽視頻):


    _movie = [[GPUImageMovie alloc] initWithURL:url];
    _movie.shouldRepeat = YES;
    _movie.playAtActualSpeed = YES;
    _movie.playSound = YES;
    _movie.delegate = self;
    
    GPUImageMissEtikateFilter *filter = [[GPUImageMissEtikateFilter alloc] init];//膠片效果
    [_movie addTarget:filter];
    [filter addTarget:self.gpuImageView];
    
    [_movie startProcessing];

然後就是一些重要的參數設置:
playAtActualSpeed
控制GPUImageView預覽視頻時的速度是否要保持真實的速度。如果設爲NO,則會將視頻的所有幀無間隔渲染,導致速度非常快。設爲YES,則會根據視頻本身時長計算出每幀的時間間隔,然後每渲染一幀,就sleep一個時間間隔,從而達到正常的播放速度。

shouldRepeat
控制視頻是否循環播放。

當你不想預覽,而是想將處理過的結果輸出到文件時,步驟也類似,只是不再需要創建GPUImageView,而是需要一個GPUImageMovieWriter:


    _writer = [[GPUImageMovieWriter alloc] initWithMovieURL:filtedMovieURL size:CGSizeMake(480, 640) fileType:(NSString *)kUTTypeMPEG4 outputSettings:outputSettings];
    _writer.encodingLiveVideo = NO;
    _writer.shouldPassthroughAudio = NO;
    _movie.audioEncodingTarget = _writer;
    _movie.playAtActualSpeed = NO;
    [_movie addTarget:_curFilter];
    [_curFilter addTarget:_writer];
    [_movie enableSynchronizedEncodingUsingMovieWriter:_writer];
    [_writer startRecording];
    [_movie startProcessing];

一些侷限和踩過的坑

1.預覽時不支持播放聲音
視頻結果輸出到GPUImageView預覽時不支持播放聲音,所以要自行添加聲音播放:
自行創建了一個播放器對象


- (void) setupSound
{
    if (theAudioPlayer != nil)
    {
        [theAudioPlayer pause];
        [theAudioPlayer seekToTime:kCMTimeZero];
        theAudioPlayer = nil;
    }
    theAudioPlayer = [[AVPlayer alloc] initWithURL:self.url];
}

跟GPUImageView的圖像同步播放


    if (self.playSound && hasAudioTrack)
    {
        [theAudioPlayer seekToTime:kCMTimeZero];
        [theAudioPlayer play];
    }

由於GPUImageMovie裏面沒有在這幾個重要位置提供回調,所以只能在源代碼中直接添加,這也導致了對源碼的侵入,不利於以後版本升級。

2.GPUImageView預覽視頻並循環播放時,當播放重新開始時,有大約50%的概率會有紅屏閃一下,目前還未定位到原因

3.GPUImageView預覽視頻時,app切到後臺會crash,所以要特別處理下,在willDisappear和handleApplicationWillEnterBackgroundNotify這兩個時機都要暫停濾鏡處理:


    if (_movie) {
        [_movie endProcessing];
        [_movie removeAllTargets];
        _movie = nil;
    }

對應的,在willAppear和handleApplicationWillEnterForegroundNotify這兩個時機要重啓處理:


    if (!_movie) {
        _movie = [[GPUImageMovie alloc] initWithURL:url];
    }
    
    _movie.shouldRepeat = YES;
    _movie.playAtActualSpeed = YES;
    _movie.playSound = YES;
    _movie.delegate = self;

    [_movie addTarget:_curFilter];
    [_curFilter addTarget:self.gpuImageView];
    
    [_movie startProcessing];

掃我,和雲棲在線交流

【雲棲快訊】首屆阿里巴巴在線技術峯會,將於7月19日-21日20:00-21:30在線舉辦。峯會邀請到阿里集團9位技術大V,分享電商架構、安全、數據處理、數據庫、多應用部署、互動技術、Docker持續交付與微服務等一線實戰經驗,解讀最新技術在阿里集團的應用實踐。  詳情請點擊

本文轉自雲棲社區:https://yq.aliyun.com
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章