๐ฆธโโ๏ธ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์ ํตํด ์ธ์ ๋ ์ง ์ ํฌ์๊ฒ ์ฐ๋ฝํ์ญ์์ค!
Reference
์ด ๋ฌธ์ ์ ๊ดํ์ฌ(๐ฆธโโ๏ธAVFoundation ํํ ๋ฆฌ์ผ: iOS์์ ๋น๋์ค์ ํจ๊ณผ๋ฅผ ์ ์ฉํ๋ ๋ฐฉ๋ฒ), ์ฐ๋ฆฌ๋ ์ด๊ณณ์์ ๋ ๋ง์ ์๋ฃ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ๋ณด์๋ค https://dev.to/forasoft/avfoundation-tutorial-how-to-apply-an-effect-to-a-video-in-ios-3peํ ์คํธ๋ฅผ ์์ ๋กญ๊ฒ ๊ณต์ ํ๊ฑฐ๋ ๋ณต์ฌํ ์ ์์ต๋๋ค.ํ์ง๋ง ์ด ๋ฌธ์์ URL์ ์ฐธ์กฐ URL๋ก ๋จ๊ฒจ ๋์ญ์์ค.
์ฐ์ํ ๊ฐ๋ฐ์ ์ฝํ ์ธ ๋ฐ๊ฒฌ์ ์ ๋ (Collection and Share based on the CC Protocol.)
์ข์ ์นํ์ด์ง ์ฆ๊ฒจ์ฐพ๊ธฐ
๊ฐ๋ฐ์ ์ฐ์ ์ฌ์ดํธ ์์ง
๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ํ์ ์ฌ์ดํธ 100์ ์ถ์ฒ ์ฐ๋ฆฌ๋ ๋น์ ์ ์ํด 100๊ฐ์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ์ต ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค