多媒體編程——ios視頻映像繪製工具類。

來源:互聯網
上載者:User

多媒體編程——ios視頻映像繪製工具類。

IOS上視頻級的映像繪製

ios上的映像繪製常規的是 UIView的drawRect函數,但是這個函數是非同步觸發,並且由主線程執行。雖然可以通過一定技巧達到主動繪製的效果:

1、傳遞映像給UIView緩衝著。

2、然後調用UIView的setNeedDisplay 改寫重繪標誌。

(以上兩步是講映像丟給UIView,讓它自己進行繪製,但是繪製的時機不可控,有時候我們需要它馬上繪製,甚至有時候我們需要知道它什麼時候繪製完成了,就需要下面兩步)

3、在播放線程中調用UIView的 perfromOnMainThread 最後一個參數 waitUtilDone = true, 執行某個自訂函數比如叫 mydrawImage

4、mydrawImage中 調用 【NSRunloop mainLoop】run 。。。。 (執行一次訊息泵抽送)

(這樣調用perfromOnMainThread的地方就會阻塞,知道真正的繪製完成。)



但是這種方式的類比同步方式繪製 知識等待主線程繪製完成,並且如果擴充到多幀緩衝 就比較麻煩了,並且UIView必須自己繼承然後重寫。

下面附上代碼 基於類似思想,但是是基於CALayer 完成的渲染工具類,同步和非同步切換隻需要改一下 waitUtilDone的參數即可。


實際測試 幀率可以達到25左右 (ipad mini1),如果機器好點 速度應該更快。


標頭檔


#import #import #import /*  渲染視頻,只支援RGB RGB RGB 32bit格式。 */@interface TKVideoPlayer : NSObject- (bool) create:(UIView*)target width:(uint16_t)width height:(uint16_t)height frate:(float)frate ;- (bool) destory ;- (bool) update:(uint8_t*)buf len:(uint32_t) len ;- (bool) start ;- (bool) stop ;@end

實現檔案


////  TKVideoPlayer.m//  FLVPlayer////  Created by administrator on 14-7-11.//  Copyright (c) 2014年 trustsky. All rights reserved.//#import "TKVideoPlayer.h"#import "TKTimer.h"#import "TKTimer2.h"#import "TKLock.h"#import "TKTicker.h"#include #define TKVIDEO_FRAME_CACHE_COUNT 8@interface TKVideoPlayer (){    UIView*         _view    ;    float           _frate   ;    uint16_t        _width   ;    uint16_t        _height  ;        uint8_t*        _buffer  ;    uint32_t        _length  ;        TKTimer2*       _timer   ;        bool            _state   ;        TKLock*         _lockEmptyQueue ;    TKLock*         _lockFilledQueue ;        std::queue _fmEmptyQueue ;    std::queue _fmFiledQueue ;        uint8_t*             _fmbuffr[TKVIDEO_FRAME_CACHE_COUNT];        dispatch_semaphore_t _sgEmpty ;    dispatch_semaphore_t _sgfilled ;}@end@implementation TKVideoPlayer- (bool) create:(UIView*)target width:(uint16_t)width height:(uint16_t)height frate:(float)frate;{    self->_view    = target ;    self->_width   = width  ;    self->_height  = height ;    self->_frate   = frate  ;    self->_length  = width * height * 4 ;        self->_view.layer.delegate = self ;    self->_sgfilled = dispatch_semaphore_create(TKVIDEO_FRAME_CACHE_COUNT);    self->_sgEmpty  = dispatch_semaphore_create(TKVIDEO_FRAME_CACHE_COUNT);        for(int idx=0; idx_lockFilledQueue = [[TKLock alloc] init];    [self->_lockFilledQueue open];        self->_lockEmptyQueue = [[TKLock alloc] init];    [self->_lockEmptyQueue open];    return true ;}- (bool) destory{    self->_view.layer.delegate = nil ;    self->_view = nil ;        self->_buffer = NULL ;        for(int idx=0; idx_lockFilledQueue close];    [self->_lockFilledQueue release];    self->_lockFilledQueue = nil ;        [self->_lockEmptyQueue close];    [self->_lockEmptyQueue release];    self->_lockEmptyQueue = nil ;        int lastCount = TKVIDEO_FRAME_CACHE_COUNT - _fmEmptyQueue.size() - _fmFiledQueue.size() ;    for(int idx=0; idx<_fmEmptyQueue.size()+lastCount; idx++)        dispatch_semaphore_signal(self->_sgfilled);    for(int idx=0; idx<_fmFiledQueue.size()+lastCount; idx++)        dispatch_semaphore_signal(self->_sgEmpty);        dispatch_release(self->_sgfilled);    self->_sgfilled = nil ;        dispatch_release(self->_sgEmpty);    self->_sgEmpty = nil ;        return true ;}- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context{    //計算映像置中應該的尺寸    CGRect frame = [layer bounds];        float scalew = frame.size.width/_width ;    float scaleh = frame.size.height/_height;        float scale = scalew < scaleh ? scalew : scaleh ;    float image_width  = _width * scale ;    float image_height = _height * scale ;        CGRect rect = CGRectMake((frame.size.width - image_width)/2, (frame.size.height - image_height)/2, image_width, image_height);        if(_state && _buffer)    {        CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, _buffer, _length, NULL);        CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB() ;        CGImageRef imageRef = CGImageCreate(_width, _height, 8, 32, 4 * _width, colorSpaceRef, kCGBitmapByteOrder32Little|kCGImageAlphaFirst, provider, NULL, NO, kCGRenderingIntentDefault);                CGContextTranslateCTM(context, 0.0, frame.size.height);        CGContextScaleCTM(context, 1.0, -1.0);        CGContextDrawImage(context, rect, imageRef);                CGImageRelease(imageRef);        CGColorSpaceRelease(colorSpaceRef);        CGDataProviderRelease(provider);                //NSLog(@"drawLayer Time Tick = %u.", get_tick32());    }    else    {        CGContextSetRGBFillColor(context, 0, 0, 0, 1);        CGContextFillRect(context, frame);    }}- (bool) update:(uint8_t*)buf len:(uint32_t) len{    if(_state)    {        dispatch_semaphore_wait(_sgEmpty, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_MSEC* 100));                [_lockEmptyQueue lock];        if(_fmEmptyQueue.size() == 0)        {            [_lockEmptyQueue unlock];            return true;        }        uint8_t* cachebuf = _fmEmptyQueue.front();        _fmEmptyQueue.pop();        [_lockEmptyQueue unlock];                memcpy(cachebuf, buf, len);                [_lockFilledQueue lock];        _fmFiledQueue.push(cachebuf);        [_lockFilledQueue unlock];                dispatch_semaphore_signal(self->_sgfilled);    }    return true ;}- (void) timer_call{    if(_state)    {        dispatch_semaphore_wait(self->_sgfilled, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_MSEC*100)); //等待100毫秒                [_lockFilledQueue lock];        if(_fmFiledQueue.size() == 0)        {            [_lockFilledQueue unlock];            return ;        }        uint8_t* cachebuf = _fmFiledQueue.front();        _fmFiledQueue.pop();        [_lockFilledQueue unlock];                [self performSelectorOnMainThread:@selector(timerDrawFrame:)                               withObject:[NSNumber numberWithUnsignedLongLong:(uint64_t)cachebuf]                            waitUntilDone:false];    }}- (void) timerDrawFrame:(NSNumber*)bufNumber{    self->_buffer = (uint8_t*)bufNumber.unsignedLongLongValue ;        if(_state && _buffer)    {        [self->_view.layer setNeedsDisplay];        [self->_view.layer display];                [_lockEmptyQueue lock];        _fmEmptyQueue.push(self->_buffer);        [_lockEmptyQueue unlock];                dispatch_semaphore_signal(self->_sgEmpty);    }    else    {        [self->_view.layer setNeedsDisplay];        [self->_view.layer display];    }}- (bool) clear{    [self performSelectorOnMainThread:@selector(timerDrawFrame:)                           withObject:[NSNumber numberWithUnsignedLongLong:NULL]                        waitUntilDone:true];        return true ;}- (bool) start{    if(_timer == nil)    {        _timer = [[TKTimer2 alloc] init];        _timer.delay   = 1000/_frate ;        _timer.objcall = self ;        _timer.selcall = @selector(timer_call);        [_timer start];        _state = true ;    }    return true ;}- (bool) stop{    if(_timer)    {        _state = false ;        [_timer stop];        [self clear];    }    return true ;}@end


//裡面用到了一個 TKTimer計時器


計時器的標頭檔是這樣的

@interface TKTimer2 : NSObject@property (assign, nonatomic) id        objcall ;@property (assign, nonatomic) SEL       selcall ;@property (assign, nonatomic) uint32_t  delay ;- (void) start ;- (void) stop ;@end

設定回調的id + SEL 然後設定延遲 毫秒單位,調用start之後該id+sel會被重複執行。本人還在調研那種計時效果準確,所以就不發上來誤導大家了,大家自己實現吧


還用到了一個TKLock


#import @interface TKLock : NSObject- (void)open ;- (void)close ;- (void)lock ;- (void)unlock ;- (bool)trylock:(uint32_t)tick ;@end

實現如下:

#import "TKLock.h"@interface TKLock (){    dispatch_semaphore_t    _sglock ; //是否緩衝為空白}@end@implementation TKLock- (void)open{    _sglock  = dispatch_semaphore_create(1);}- (void)close{    [self trylock:1];    dispatch_semaphore_signal(_sglock);    dispatch_release(_sglock);    _sglock = nil ;}- (void)lock{    dispatch_semaphore_wait(_sglock, DISPATCH_TIME_FOREVER);}- (void)unlock{    dispatch_semaphore_signal(_sglock);}- (bool)trylock:(uint32_t)tick{    long retcode = dispatch_semaphore_wait(_sglock, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_MSEC*tick));    return (retcode == 0) ;}@end



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.