프로그래밍 (299) 썸네일형 리스트형 UITextView 자동 높이 특정 사이즈까지는 높이가 커지다가 해당 사이즈 부터는 스크롤로 전환 초기에는 사이즈가 증가해야 하기에 텍스트뷰의 isScrollEnabled = false 로 설정 높이 제약을 특정 사이즈 이하(lessThanOrEqual)로 설정 let textView: UITextView = .init() func setup() { . . textView.isScrollEnabled = false . . addSubview(textView) } func setupLayout() { textView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ textView.heightAnchor.constraint(lessThanOrE.. 오디오유닛 레벨 계산 마이크에서 전달된 오디오 데이터의 렌더 이벤트 static let onGetPlayoutData: AURenderCallback = {( inRefCon: UnsafeMutableRawPointer, ioActionFlags: UnsafeMutablePointer, inTimeStamp: UnsafePointer, inBusNumber: UInt32, inNumFrames: UInt32, ioData: Optional) -> OSStatus in let myObject = unsafeBitCast(inRefCon, to: MyObject.self) // 매번 계산할지 특정 간격으로 계산을 수행할지는 ui의 표시 형태에 따라 진행한다 // 미리 설정한 오디오 세션의 ioBufferDuration 에 따라 .. Image, PixelBuffer CMSampleBuffer -> CVPixelBuffer let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)! CVPixelBuffer -> CIImage let ciimage = CIImage(cvPixelBuffer: pixelBuffer) CIImage -> CGImage context 생성은 비용이 높으므로, 미리 생성해 두고 사용 let context = CIContext(options: nil) let cgImage = context.createCGImage(ciimage, from: ciimage.extent)! CIImage, CGImage -> UIImage let uiImage = UIImage(CIImage: ciImage) l.. 아이폰 로컬 화면 공유 : Broadcast Extension 화면 전체를 녹화하기 위해서는 ReplayKit 과 Broadcast Extention 이 필요. 별도 프로세스로 동작하므로, 앱과 extention 간의 커뮤니케이션 필요.( app group, xpc or socket 등) broadcast extension 은 메모리 사용량에 50M 제약이 있으므로, 캡처되는 샘플 프레임의 사이즈와 프레임 레이트등을 고려해서 구성해야 한다. 비디오 사이즈에 따라 인코딩이나 전송단 버퍼링 등에서 50메가를 넘는 경우가 많아 실시간이나 부드러운 프레임 레이트의 제공에는 한계가 있다. 제한 메모리 사용량을 넘으면 익스텐션이 바로 종료되어 버리므로, 오디오까지 인코딩하는 경우 메모리 관리가 빡빡한 편. 익스텐션 앱에서 브로드캐스트 익스텐션 타겟 추가 익스텐션 타겟이 생성되.. [Metal] 이미지렌더링~ 카메라 입력과 가우시안 블러~ 이전 kernel shader 를 사용하는 샘플에 입력 텍스처를 이미지가 아닌 카메라 픽셀버퍼로 변경해보자~ 대부분 소스는 동일한데, 카메라 입력을 처리하기 위한 부분들만 차이가 있다. 샘플이므로 비율처리 없이 카메라 입력을 그대로 받아 256x256 사이즈로 줄이고, 가우시안블러, 최종 렌더링시에 마스킹 이미지를 추가해 실제 이미지와 블러된 이미지를 혼합해 픽셀을 결정하게 된다. ViewController 렌더러에 있던 metal view delegate 를 뷰컨트롤러로 이동하고, 렌더링 루틴을 2단계로 분리했다. 첫번째 카메라 이미지가 입력되었을때 첫번째 리사이징 렌더링을 수행하고, 해당 작업 이후에 블러와 화면 렌더링을 진행한다. 첫번째 렌더링은 별도의 렌더타겟인 텍스처에 렌더링하므로, 카메라에서 .. CVPixelBuffer, CMSampleBuffer,Data, Metal Texture, vImage CMSampleBuffer -> CVPixelBuffer let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) // nano timestamp가 필요한 경우 let scale:Float64 = 1_000_000_000 let time = Int64( CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)) * scale) CVPixelBuffer -> CMSampleBuffer var sampleBuffer: CMSampleBuffer? = nil let scale = CMTimeScale(1_000_000_000) let time = CMTime(value: CMTimeValue.. [Metal] 이미지 렌더링~ 가우시안 블러~ Kernel 쉐이더 이전 가우시안 블러 샘플을 Kernel(compute) 쉐이더를 사용해 구현해 본다. 원본이미지를 리사이징해 작은 텍스처를 만들고, 블러링 작업은 이전 샘플과 동일하게 kernel 쉐이더로 5회 적용했다. 속도는 fragment 쉐이더와 큰 차이는 없다. 렌더타겟은 사이즈를 줄여 렌더링하는 용도로만 사용한다. 가로, 세로 작업을 위한 MTLTexture, MTLComputePipelineState 와 MTLFunction을 선언했다. class Renderer:NSObject { var device:MTLDevice! var commandQueue: MTLCommandQueue! var sharedDataPtr: UnsafeMutablePointer? var imageVertexBuffer: MTLBuf.. [Metal] 이미지 렌더링~ 가우시안 블러 이번에는 이미지 필터링에 많이 사용되는 가우시안 블러를 적용해 보자. 블러링은 비용이 많이 드는 프로세스이기에 사용 조건에 따라 방식을 달리 적용해야 한다. 이미지 품질이 중요한 경우 원본 사이즈에 좀더 넓은 사이즈(탭)로 블러를 적용하고, 영상처리 같은 곳에선 속도를 위해 원본이미지를 축소해 블러를 적용한다. 이 샘플은 약 1/4 크기로 이미지를 축소하고, 7탭, 2 pass 작업을 총 5회 적용하였다. 공통타입 헤더 가우시안의 가중치 값은 초기에 미리 계산해 공통으로 사용할 데이터에 저장한다. #include typedef struct { float tapCount; float gaussian[7]; } SharedData; 2 pass 블러 이므로 가로용, 세로용 텍스처와 파이프라인을 구성 clas.. 이전 1 2 3 4 5 6 7 8 ··· 38 다음