objective c - AvAssetReader and Writer to overlay video -
i trying overlay recorded video avassetreader , avassetwriter images. following tutorial, able copy video (and audio) new file. objective overlay of initial video frames images code:
while ([assetwritervideoinput isreadyformoremediadata] && !completedorfailed) { // next video sample buffer, , append output file. cmsamplebufferref samplebuffer = [assetreadervideooutput copynextsamplebuffer]; cvpixelbufferref pixelbuffer = cmsamplebuffergetimagebuffer(samplebuffer); cvpixelbufferlockbaseaddress(pixelbuffer, 0); eaglcontext *eaglcontext = [[eaglcontext alloc] initwithapi:keaglrenderingapiopengles2]; cicontext *cicontext = [cicontext contextwitheaglcontext:eaglcontext options:@{kcicontextworkingcolorspace : [nsnull null]}]; uifont *font = [uifont fontwithname:@"helvetica" size:40]; nsdictionary *attributes = @{nsfontattributename:font, nsforegroundcolorattributename:[uicolor lighttextcolor]}; uiimage *img = [self imagefromtext:@"test" :attributes]; ciimage *filteredimage = [[ciimage alloc] initwithcgimage:img.cgimage]; [cicontext render:filteredimage tocvpixelbuffer:pixelbuffer bounds:[filteredimage extent] colorspace:cgcolorspacecreatedevicergb()]; cvpixelbufferunlockbaseaddress(pixelbuffer, 0); if (samplebuffer != null) { bool success = [assetwritervideoinput appendsamplebuffer:samplebuffer]; cfrelease(samplebuffer); samplebuffer = null; completedorfailed = !success; } else { completedorfailed = yes; } }
and create image text:
-(uiimage *)imagefromtext:(nsstring *)text :(nsdictionary *)attributes{ cgsize size = [text sizewithattributes:attributes]; uigraphicsbeginimagecontextwithoptions(size, no, 0.0); [text drawatpoint:cgpointmake(0.0, 0.0) withattributes:attributes]; uiimage *image = uigraphicsgetimagefromcurrentimagecontext(); uigraphicsendimagecontext(); return image; }
the video , audio copied, haven't text on video.
question 1: why code not working?
moreover, want able check timecode of current read frame. example insert text current timecode in video.
i try code following tutorial:
avasset *localasset = [avasset assetwithurl:murl]; nserror *localerror; avassetreader *assetreader = [[avassetreader alloc] initwithasset:localasset error:&localerror]; bool success = (assetreader != nil); // create asset reader output first timecode track of asset if (success) { avassettrack *timecodetrack = nil; // grab first timecode track, if asset has them nsarray *timecodetracks = [localasset trackswithmediatype:avmediatypetimecode]; if ([timecodetracks count] > 0) timecodetrack = [timecodetracks objectatindex:0]; if (timecodetrack) { avassetreadertrackoutput *timecodeoutput = [avassetreadertrackoutput assetreadertrackoutputwithtrack:timecodetrack outputsettings:nil]; [assetreader addoutput:timecodeoutput]; } else { nslog(@"%@ has no timecode tracks", localasset); } }
but log:
[...] has no timecode tracks
question 2: why video hasn't avmediatypetimecode? ad how can current frame timecode?
thanks help
i found solutions:
to overlay video frames, need fix decompression settings:
nsstring* key = (nsstring*)kcvpixelbufferpixelformattypekey; nsnumber* value = [nsnumber numberwithunsignedint:kcvpixelformattype_32bgra]; nsdictionary* decompressionvideosettings = [nsdictionary dictionarywithobject:value forkey:key]; // if there video track read, set decompression settings yuv , create asset reader output. assetreadervideooutput = [avassetreadertrackoutput assetreadertrackoutputwithtrack:assetvideotrack outputsettings:decompressionvideosettings];
to frame timestamp, have read video informations , use counter increment current timestamp:
durationseconds = cmtimegetseconds(asset.duration); timeperframe = 1.0 / (float64)assetvideotrack.nominalframerate; totalframes = durationseconds * assetvideotrack.nominalframerate;
then in loop
while ([assetwritervideoinput isreadyformoremediadata] && !completedorfailed)
you can found timestamp:
cmsamplebufferref samplebuffer = [assetreadervideooutput copynextsamplebuffer]; if (samplebuffer != null){ cvpixelbufferref pixelbuffer = cmsamplebuffergetimagebuffer(samplebuffer); if (pixelbuffer) { float64 secondsin = ((float)counter/totalframes)*durationseconds; cmtime imagetimeestimate = cmtimemakewithseconds(secondsin, 600); mergetime = cmtimegetseconds(imagetimeestimate); counter++; } }
i hope help!
Comments
Post a Comment