ios - Creating a square video with custom background color and aspect-fitted video on top with AVFoundation -


i want take video (eg:16:9 shot iphone) , fit , center in square custom background color. code goes like:

- (void)videooutput {     if (!self.firstasset) {         uialertview *alert = [[uialertview alloc] initwithtitle:@"error" message:@"please load video asset first"                                                        delegate:nil cancelbuttontitle:@"ok" otherbuttontitles:nil];         [alert show];         return;     }      avmutablecomposition *mixcomposition = [[avmutablecomposition alloc] init];      avmutablecompositiontrack *videotrack = [mixcomposition addmutabletrackwithmediatype:avmediatypevideo                                                                         preferredtrackid:kcmpersistenttrackid_invalid];     [videotrack inserttimerange:cmtimerangemake(kcmtimezero, self.firstasset.duration)                         oftrack:[[self.firstasset trackswithmediatype:avmediatypevideo] objectatindex:0]                          attime:kcmtimezero error:nil];      avmutablevideocompositioninstruction *maininstruction = [avmutablevideocompositioninstruction videocompositioninstruction];     maininstruction.timerange = cmtimerangemake(kcmtimezero, self.firstasset.duration);      avmutablevideocompositionlayerinstruction *videolayerinstruction = [avmutablevideocompositionlayerinstruction videocompositionlayerinstructionwithassettrack:videotrack];     avassettrack *videoassettrack = [[self.firstasset trackswithmediatype:avmediatypevideo] objectatindex:0];      cgsize videosize = [[[firstasset trackswithmediatype:avmediatypevideo] objectatindex:0] naturalsize];     nslog(@"video size w:%f, h:%f",videosize.width,videosize.height);      float scaleratio = 600/videosize.width;      [videolayerinstruction settransform:cgaffinetransformmakescale(scaleratio, scaleratio) attime:kcmtimezero];     [videolayerinstruction setopacity:0.0 attime:self.firstasset.duration];      maininstruction.layerinstructions = [nsarray arraywithobjects:videolayerinstruction,nil];      avmutablevideocomposition *maincompositioninst = [avmutablevideocomposition videocomposition];      float renderwidth, renderheight;     renderwidth = 600;     renderheight = 600;     maincompositioninst.rendersize = cgsizemake(renderwidth, renderheight);     maincompositioninst.instructions = [nsarray arraywithobject:maininstruction];     maincompositioninst.frameduration = cmtimemake(1, 30);      [self applyvideoeffectstocomposition:maincompositioninst size:cgsizemake(600, 600)];      nsarray *paths = nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes);     nsstring *documentsdirectory = [paths objectatindex:0];     nsstring *mypathdocs =  [documentsdirectory stringbyappendingpathcomponent:                              [nsstring stringwithformat:@"finalvideo-%d.mov",arc4random() % 1000]];     nsurl *url = [nsurl fileurlwithpath:mypathdocs];      avassetexportsession *exporter = [[avassetexportsession alloc] initwithasset:mixcomposition                                                                       presetname:avassetexportpresethighestquality];     exporter.outputurl=url;     exporter.outputfiletype = avfiletypequicktimemovie;     exporter.shouldoptimizefornetworkuse = yes;     exporter.videocomposition = maincompositioninst;     [exporter exportasynchronouslywithcompletionhandler:^{         dispatch_async(dispatch_get_main_queue(), ^{             [self exportdidfinish:exporter];         });     }]; }    - (void)applyvideoeffectstocomposition:(avmutablevideocomposition *)composition size:(cgsize)size {     uiimage *borderimage = nil;      borderimage = [self imagewithcolor:[uicolor greencolor] rectsize:cgrectmake(0, 0, size.width, size.height)];       calayer *backgroundlayer = [calayer layer];     [backgroundlayer setcontents:(id)[borderimage cgimage]];     backgroundlayer.frame = cgrectmake(0, 0, size.width, size.height);     [backgroundlayer setmaskstobounds:yes];        avplayeritem *playeritem2 = [[avplayeritem alloc] initwithasset:secondasset];      avplayer *videoplayer2 = [avplayer playerwithplayeritem:playeritem2];     avplayerlayer *videolayer = [avplayerlayer playerlayerwithplayer:videoplayer2];     cgsize videosize = [[[secondasset trackswithmediatype:avmediatypevideo] objectatindex:0] naturalsize];      [videolayer setbackgroundcolor:[uicolor whitecolor].cgcolor];     videolayer.frame = cgrectmake(0, (600-337.5)/2, 600, 337.5);     calayer *parentlayer = [calayer layer];     parentlayer.frame = cgrectmake(0, 0, size.width, size.height);     [parentlayer addsublayer:backgroundlayer];     [parentlayer addsublayer:videolayer];      composition.animationtool = [avvideocompositioncoreanimationtool                                  videocompositioncoreanimationtoolwithpostprocessingasvideolayer:videolayer inlayer:parentlayer]; } 

the original video , exported result images below. can see in exported video, frame overlaid video correct. video in not maintain aspect ratio. if choose make videolayer frame square, aspect ratio remains normal.

original video (1920x1080) cropped video (600x600) original video overlaid.

i stuck @ level. trying build wysiwyg editor square videos , apply scale,translation , rotation transformations videolayer rendered in square video. specific question , forward appreciated.

this i'm getting through. have solution. if want change video rectangle shape square. need crop video , set avmutablevideocompositioninstruction's backgroundcolor colors want.

  1. confirm 'uiimageorientation' of video.
  2. crop video 'videocomposition.rendersize', rendersize.width equals rendersize.height. , rendersize.width larger side of original video size.
  3. avmutablevideocompositioninstruction *instruction = [avmutablevideocompositioninstruction videocompositioninstruction];

instruction.backgroundcolor = /cgcolorref/;

quote apple :

/* indicates background color of composition. solid bgra colors supported; patterns , other color refs not supported ignored. if background color not specified video compositor use default backgroundcolor of opaque black. if rendered pixel buffer not have alpha, alpha value of backgroundcolor ignored. */ @property (nonatomic, retain, nullable) attribute((nsobject)) cgcolorref backgroundcolor cf_returns_retained;

the wrong way set instruction backgroundcolor :

instruction.backgroundcolor = [uicolor bluecolor].cgcolor;

the correct 1 :

    cgcolorspaceref rgb = cgcolorspacecreatedevicergb();     const cgfloat mycolor[] = {1.0, 1.0, 1.0, 1.0}; //white     cgcolorref ref = cgcolorcreate(rgb, mycolor);     instruction.backgroundcolor = ref; 
  1. export video.

done!

by way, videolayer , videocomposition.rendersize must set naturalsize of original video. can not set videolayer.frame customized cgrect.


Comments

  1. Yes, its Correct way.To Remove black screen while merge Video with Image..

    let instruction = AVMutableVideoCompositionInstruction()
    instruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: mutableComposition.duration)

    let videotrack = mutableComposition.tracks(withMediaType: AVMediaType.video)[0] as AVAssetTrack
    let layerinstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videotrack)

    let rgb = CGColorSpaceCreateDeviceRGB()
    let myColor : [CGFloat] = [1.0, 1.0, 1.0, 1.0] //white
    let ref = CGColor(colorSpace: rgb, components: myColor)
    instruction.backgroundColor = ref


    instruction.layerInstructions = NSArray(object: layerinstruction) as [AnyObject] as! [AVVideoCompositionLayerInstruction]
    videoComposition.instructions = [instruction]

    ReplyDelete

Post a Comment

Popular posts from this blog

facebook - android ACTION_SEND to share with specific application only -

python - Creating a new virtualenv gives a permissions error -

go - Idiomatic way to handle template errors in golang -