๐Ÿฆธโ€โ™‚๏ธAVFoundation ํŠœํ† ๋ฆฌ์–ผ: iOS์—์„œ ๋น„๋””์˜ค์— ํšจ๊ณผ๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

3564 ๋‹จ์–ด beginnerstutorialvideoios
๋น„๋””์˜ค๊ฐ€ ์ฒ˜๋ฆฌ๋˜๋Š” ๋ฐฉ์‹์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ด ๋ณธ ์ ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ํšจ๊ณผ๋ฅผ ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ? ์ด AVFoundation ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” iOS์—์„œ์˜ ๋น„๋””์˜ค ์ฒ˜๋ฆฌ๋ฅผ ๊ฐ„๋‹จํ•œ ์šฉ์–ด๋กœ ์„ค๋ช…ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ด ์ฃผ์ œ๋Š” ์ƒ๋‹นํžˆ ๋ณต์žกํ•˜๋ฉด์„œ๋„ ํฅ๋ฏธ๋กญ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์—์„œ ํšจ๊ณผ๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๊ฐ„๋‹จํ•œ ๊ฐ€์ด๋“œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ์ด๋ฏธ์ง€



Core Image๋Š” ๊ณ ์„ฑ๋Šฅ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ๋ฐ ๋ถ„์„์„ ์œ„ํ•œ Apple์˜ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. ํด๋ž˜์Šค CIImage, CIFilter ๋ฐ CiContext๋Š” ์ด ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ฃผ์š” ๊ตฌ์„ฑ ์š”์†Œ์ž…๋‹ˆ๋‹ค.

Core Image๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‚ฌ์šฉ์ž ์ •์˜ ํšจ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์„œ๋กœ ๋‹ค๋ฅธ ํ•„ํ„ฐ(CiFilter)๋ฅผ ํ•จ๊ป˜ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ GPU(๊ทธ๋ž˜ํ”ฝ ํ”„๋กœ์„ธ์„œ)์—์„œ ์ž‘๋™ํ•˜๋Š” ํšจ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ CPU(์ค‘์•™ ํ”„๋กœ์„ธ์„œ)์—์„œ ์•ฝ๊ฐ„์˜ ๋ถ€ํ•˜๋ฅผ ์ด๋™ํ•˜์—ฌ ์•ฑ ์†๋„๋ฅผ ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

AV์žฌ๋‹จ



AVFoundation์€ iOS, macOS, watchOS ๋ฐ tvOS์—์„œ ๋ฏธ๋””์–ด ํŒŒ์ผ ์ž‘์—…์„ ์œ„ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. AVFoundation์„ ์‚ฌ์šฉํ•˜๋ฉด QuickTime ์˜ํ™” ๋ฐ MPEG-4(MP4) ํŒŒ์ผ์„ ์‰ฝ๊ฒŒ ์ƒ์„ฑ, ํŽธ์ง‘ ๋ฐ ์žฌ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ HLS ์ŠคํŠธ๋ฆผ์„ ์žฌ์ƒํ•˜๊ณ (HLShere์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ธฐ) ํ”Œ๋ ˆ์ด์–ด, ํŽธ์ง‘๊ธฐ ๋“ฑ๊ณผ ๊ฐ™์€ ๋น„๋””์˜ค ๋ฐ ์˜ค๋””์˜ค ํŒŒ์ผ๊ณผ ํ•จ๊ป˜ ์ž‘๋™ํ•˜๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํšจ๊ณผ ์ถ”๊ฐ€



๋™์˜์ƒ์— ํญ๋ฐœ ํšจ๊ณผ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋„ˆ ๋ญํ•˜๋‹ˆ?

๋จผ์ € ํšจ๊ณผ๋ฅผ ์ ์šฉํ•  ๋ฉ”์ธ ๋น„๋””์˜ค, ์•ŒํŒŒ ์ฑ„๋„์ด ์žˆ๋Š” ํšจ๊ณผ ๋น„๋””์˜ค, ์•ŒํŒŒ ์ฑ„๋„์ด ์—†๋Š” ํšจ๊ณผ ๋น„๋””์˜ค์˜ ์„ธ ๊ฐ€์ง€ ๋น„๋””์˜ค๋ฅผ ์ค€๋น„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์•ŒํŒŒ ์ฑ„๋„์€ ์ด๋ฏธ์ง€์— ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ๋Š” ์ถ”๊ฐ€ ์ฑ„๋„์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ์ด๋ฏธ์ง€์˜ ํˆฌ๋ช…๋„์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉฐ ์•ŒํŒŒ ์œ ํ˜•์— ๋”ฐ๋ผ ๋‹ค์–‘ํ•œ ํˆฌ๋ช…๋„ ์ˆ˜์ค€์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํšจ๊ณผ๊ฐ€ ์žˆ๋Š” ๋น„๋””์˜ค๊ฐ€ ๊ธฐ๋ณธ ๋น„๋””์˜ค์™€ ๊ฒน์น˜์ง€ ์•Š๋„๋ก ์•ŒํŒŒ ์ฑ„๋„์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์•ŒํŒŒ ์ฑ„๋„์ด ์žˆ๋Š” ๊ทธ๋ฆผ๊ณผ ์—†๋Š” ๊ทธ๋ฆผ์˜ ์˜ˆ์ž…๋‹ˆ๋‹ค.



์ƒ‰์ด ํ•˜์–—๊ฒŒ ๋ ์ˆ˜๋ก ํˆฌ๋ช…๋„๊ฐ€ ๋–จ์–ด์ง‘๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ฒ€์€์ƒ‰์€ ์™„์ „ํžˆ ํˆฌ๋ช…ํ•˜์ง€๋งŒ ํฐ์ƒ‰์€ ์ „ํ˜€ ํˆฌ๋ช…ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋น„๋””์˜ค ํšจ๊ณผ๋ฅผ ์ ์šฉํ•œ ํ›„์—๋Š” ํญ๋ฐœ ์ž์ฒด(์˜ค๋ฅธ์ชฝ ์ด๋ฏธ์ง€์˜ ํฐ์ƒ‰ ๋ถ€๋ถ„)๋งŒ ํ‘œ์‹œ๋˜๊ณ  ๋‚˜๋จธ์ง€๋Š” ํˆฌ๋ช…ํ•ด์ง‘๋‹ˆ๋‹ค. ํšจ๊ณผ๋ฅผ ์ ์šฉํ•œ ๋ฉ”์ธ ๋น„๋””์˜ค๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ๋‹ค์Œ ์„ธ ๊ฐœ์˜ ๋น„๋””์˜ค๋ฅผ ๋™์‹œ์— ์ฝ๊ณ  CIFilter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ์ง€๋ฅผ ๊ฒฐํ•ฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋จผ์ € CMSampleBuffer๋ฅผ ํ†ตํ•ด CVImageBuffer์— ๋Œ€ํ•œ ๋งํฌ๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค. ๋‹ค์–‘ํ•œ ์œ ํ˜•์˜ ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ์–ดํ•˜๋Š” โ€‹โ€‹๋ฐ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. CVImageBuffer๋Š” ๋‚˜์ค‘์— ํ•„์š”ํ•  CVPixelBuffer์—์„œ ํŒŒ์ƒ๋ฉ๋‹ˆ๋‹ค. CVImageBuffer์—์„œ CIImage๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ž…๋‹ˆ๋‹ค.

CVImageBufferRef imageRecordBuffer = CMSampleBufferGetImageBuffer(recordBuffer);
CIImage *ciBackground = [CIImage imageWithCVPixelBuffer:imageRecordBuffer];

CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(buffer);
CIImage *ciTop = [CIImage imageWithCVPixelBuffer:imageBuffer];*

CVImageBufferRef imageAlphaBuffer = CMSampleBufferGetImageBuffer(alphaBuffer);
CIImage *ciMask = [CIImage imageWithCVPixelBuffer:imageAlphaBuffer];


3๊ฐœ์˜ ๋น„๋””์˜ค ๊ฐ๊ฐ์— ๋Œ€ํ•ด CIImage๋ฅผ ์ˆ˜์‹ ํ•œ ํ›„ CIFilter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปดํŒŒ์ผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋Š” ๋Œ€๋žต ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

CIFilter *filterMask = [CIFilter filterWithName:@"CIBlendWithMask" keysAndValues:@"inputBackgroundImage", ciBackground, @"inputImage", ciTop, @"inputMaskImage", ciMask, nil];
CIImage *outputImage = [filterMask outputImage];


๋‹ค์‹œ ํ•œ ๋ฒˆ CIImage๋ฅผ ๋ฐ›์•˜์ง€๋งŒ ์ด๋ฒˆ์—๋Š” ์ด์ „์— ์–ป์€ ์„ธ ๊ฐœ์˜ CIImage๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ด์ œ CIIContext๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ CVPixelBufferRef์—์„œ ์ƒˆ CIImage๋ฅผ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋Š” ๋Œ€๋žต ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

CVPixelBufferRef pixelBuffer =[self.contextEffect renderToPixelBufferNew:outputImage];


์ด์ œ ์™„์„ฑ๋œ ํ”ฝ์…€ ๋ฒ„ํผ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋น„๋””์˜ค ์ƒ˜ํ”Œ ๋ฒ„ํผ์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋ฉฐ ๊ทธ ํ›„์— ํšจ๊ณผ๊ฐ€ ์žˆ๋Š” ๋น„๋””์˜ค๋ฅผ ๋ฐ›๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

[self.writerAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:CMTimeMake(self.frameUse, 30)]


ํšจ๊ณผ๊ฐ€ ์—ฌ๊ธฐ ๋น„๋””์˜ค์— ์„ฑ๊ณต์ ์œผ๋กœ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์ž‘์—…์€ GPU๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์™„๋ฃŒ๋˜์—ˆ์œผ๋ฉฐ, ์ด๋Š” ์šฐ๋ฆฌ๊ฐ€ CPU์—์„œ ๋ถ€ํ•˜๋ฅผ ๋œ์–ด ์•ฑ ์†๋„๋ฅผ ๋†’์ด๋Š” ๋ฐ ๋„์›€์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก 



iOS์—์„œ ๋น„๋””์˜ค์— ํšจ๊ณผ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ์ƒ๋‹นํžˆ ๋ณต์žกํ•œ ์ž‘์—…์ด์ง€๋งŒ iOS์—์„œ ๋ฏธ๋””์–ด ์ž‘์—…์„ ์œ„ํ•œ ๊ธฐ๋ณธ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ๋” ์•Œ๊ณ  ์‹ถ๋‹ค๋ฉด Contact us form์„ ํ†ตํ•ด ์–ธ์ œ๋“ ์ง€ ์ €ํฌ์—๊ฒŒ ์—ฐ๋ฝํ•˜์‹ญ์‹œ์˜ค!

์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ