Multimedia programming-ios video image rendering tool class.

Source: Internet
Author: User

Multimedia programming-ios video image rendering tool class.

Video-Level Image Rendering on IOS

Image Rendering on ios is typically the drawRect function of UIView. However, this function is asynchronously triggered and executed by the main thread. Although some techniques can be used to achieve the effect of active plotting:

1. Pass the image to the UIView cache.

2. Call setNeedDisplay of UIView to rewrite the re-painting mark.

(The above two steps are about throwing an image to the UIView and letting it draw it on its own, but the Painting time is uncontrollable. Sometimes we need it to be drawn immediately, sometimes we even need to know when the rendering is complete, we need to take the following two steps)

3. Call the last parameter waitUtilDone = true of perfromOnMainThread of UIView In the playback thread to execute a custom function, such as mydrawImage.

4. Call [nsunloop mainLoop] run in mydrawImage .... (Execute a message pump)

(In this way, the calling of perfromOnMainThread will be blocked, knowing that the painting is complete .)



However, the knowledge of this method of simulation synchronization is waiting for the master thread to complete the painting, and it is troublesome to extend to multiple frames of cache, And the UIView must inherit and then override it by itself.

The following code is provided based on similar ideas, but is a rendering tool Class Based on CALayer. For synchronous and asynchronous switching, you only need to change the parameter of waitUtilDone.


The actual testing frame rate can reach around 25 (ipad mini1). If the machine is better, the speed should be faster.


Header file


# Import
 
  
# Import
  
   
# Import
   
    
/* Render the video. Only the RGB 32bit format is supported. */@ 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
   
  
 

Implementation File


/// 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 [empty]; empty _ sgEmpty; empty _ 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 (rows); 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 <_ fmFil EdQueue. 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 {// calculate the size of the image center 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 = regular (); CGImageRef imageRef = CGImageCreate (_ width, _ height, 8, 32, 4 * _ width, colorSpaceRef, interval | 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); 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) {partition (_ sgEmpty, dispatch_time (DISPATCH_TIME_NOW, interval * 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); // wait 100 milliseconds [_ lockFilledQueue lock]; if (_ fmFiledQueue. size () = 0) {[_ lockFilledQueue unlock]; return;} uint8_t * cachebuf = _ fmFiledQueue. front (); _ fmFiledQueue. pop (); [_ lockFilledQueue unlock]; [self metadata: @ selector (timerDrawFrame :) withObject: [NSNumber metadata :( 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 Checking mselecw.mainthread: @ 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
     
    
   
  
 


// A TKTimer timer is used in it.


The timer header file is like this.

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

Set the callback id + SEL and set the unit of delay in milliseconds. After calling start, the id + sel will be executed repeatedly. I am still investigating the accurate timing effect, so I will not mislead you. Let's do it by yourself.


We also used a TKLock


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

The implementation is as follows:

# Import "TKLock. h "@ interface TKLock () {dispatch_semaphore_t _ sglock; // whether the cache is empty} @ 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



Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.