스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
AVFoundation 및 Metal을 통해 HDR 비디오를 EDR로 표시
AVFoundation 및 Metal을 활용하여 효율적인 EDR 파이프라인을 빌드하는 방법을 배울 수 있습니다. AVPlayer를 사용하여 HDR 비디오를 EDR로 표시하고, 앱 보기에 재생을 추가하고 이를 Metal로 렌더링하며, Core Image나 맞춤형 Metal 셰이더를 사용하여 키잉이나 색상 관리와 같은 비디오 효과를 추가하는 방법에 대해 시연하는 과정을 살펴보시기 바랍니다. 게임 또는 전문 앱 중 무엇을 개발하든지 관계없이, 어떤 프레임워크를 사용할지 결정하는 데 도움을 드리고, Transport, ColorSpace 및 PixelBuffer 형식을 선택하기 위한 모범 사례를 공유합니다.
리소스
관련 비디오
WWDC23
Tech Talks
WWDC22
WWDC21
WWDC20
-
다운로드
♪ ♪
안녕하세요! WWDC 2022에 오신 것을 환영합니다 제 이름은 Ken Greenebaum입니다 저는 Apple의 색상 및 디스플레이 기술 팀에서 일합니다 올해 EDR 발표를 세 번 하게 되어 매우 기뻐요 'iOS의 EDR 알아보기'를 보셨으면 좋겠어요 iOS용 EDR API 지원 관련 내용입니다 'Core Image, Metal, SwiftUI로 EDR 콘텐츠 표시하기'도 있고요 작년에 제 EDR 강연을 보신 분도 계실 텐데요 그때는 EDR을 사용하여 HDR 비디오를 재생하기 위한 AV 플레이어 사용법을 보여드렸었죠
이번 강연에서는 더 자세히 알려드릴게요 Core Media 인터페이스를 사용하는 방법을 보여드릴게요 EDR 재생뿐만 아니라 여러분만의 EDR 레이어 또는 보기에서 HDR 비디오를 디코딩하고 재생하는 방법을 보여드릴게요
그리고 단순히 콘텐츠를 재생하는 것을 넘어 Core Video 디스플레이 링크를 통해 디코딩된 비디오 프레임에 실시간으로 액세스하는 방법을 보여드리겠습니다 그리고 그 프레임을 CoreImage 필터, Metal 쉐이더로 보내 색상 관리, 시각 효과를 추가하거나 다른 신호 처리를 적용하는 방법도 보여드릴게요 끝으로 결과 프레임을 Metal로 보내 렌더링하는 방법도요 그럼 EDR 호환 비디오 미디어 프레임워크부터 살펴봅시다 여러분의 응용 프로그램에 무엇이 필요한지 알 수 있을 거에요
그리고 높은 수준의 AVKit 및 AVFoundation 프레임워크에 대해 간략하게 설명하겠습니다 응용 프로그램에서 직접 재생이 필요한 경우 HDR 비디오 재생으로 필요한 모든 작업을 할 수 있죠
마지막으로 모범 사례를 소개드리겠습니다 디코딩된 비디오 프레임을 Core Video, Metal의 EDR 재생, 편집 또는 이미지 처리 엔진에서 사용하는 모범 사례를요
먼저 Apple의 비디오 프레임워크에 대해 간단히 알아볼게요 사용하기 가장 쉬운 최고 수준의 인터페이스부터 시작하여 낮은 수준의 프레임워크로 내려갑니다 코드가 복잡해지는 대신 더 많은 기회가 생깁니다 자동으로 제공되는 최적화를 활용하려면 가능한 최고 수준의 프레임워크를 사용하는 것이 가장 좋습니다 이것을 염두에 두고, 본격적으로 이야기를 시작해 봅시다 여러 가지 시나리오를 알아봅시다 간단한 EDR 재생부터 디코딩된 비디오 프레임을 보다 정교하게 연결하거나 실시간 처리를 위한 CoreImage 또는 Metal 사용하기 등을요 가장 높은 수준에는 AVKit이 있습니다 AVKit을 사용하여 사용자 인터페이스를 만들 수 있습니다 미디어 재생 뿐만 아니라 전송 제어, 챕터 탐색 화면 속 화면 지원 자막 및 폐쇄 자막 표시 등을 할 수 있죠 AVKit은 HDR 콘텐츠를 EDR로 재생할 수 있습니다 AV Player ViewController로 보여드리겠습니다 그러나 응용 프로그램에서 비디오 프레임을 추가로 처리해야 하면 미디어 프레임워크를 사용해야 합니다 이를 통해 파이프라인을 더 잘 제어할 수 있습니다 다음으로, AVFoundation이 있습니다 AVFoundation은 모든 기능을 갖춘 프레임워크입니다 Apple 플랫폼에서 시간 기반 시청각 미디어를 작업할 수 있죠 AVFoundation을 쓰면 QuickTime 동영상 및 MPEG 4 파일을 쉽게 재생하고, 만들고 편집할 수 있습니다 HLS 스트림을 재생하고 앱에 강력한 미디어 기능을 구축할 수 있습니다 이번 강연에서는 AV 플레이어와 관련된 AVPlayerLayer 인터페이스 사용법에 대해 살펴보겠습니다 Core Video는 디지털 비디오를 위한 파이프라인 모델을 제공하는 프레임워크입니다 프로세스를 개별 단계로 분할함으로써 비디오 작업 방식을 단순화합니다 또한 Core Video로 개별 프레임에 쉽게 액세스하고 조작할 수 있어요 데이터 유형 사이의 변환이나 디스플레이 동기화에 신경 쓸 필요 없죠 여기서는 DisplayLink 사용 및 Core Image가 있는 CV 픽셀 버퍼 Metal에서 CV Metal 를 보여드리겠습니다 다음은 비디오 ToolBox입니다 이것은 저수준 프레임워크입니다 하드웨어 인코더, 디코더에 직접 액세스할 수 있게 해줍니다 비디오 Toolbox로 비디오를 압축 및 압축 해제할 수 있습니다 Core Video 픽셀 버퍼에 저장된 래스터 이미지 포맷들을 바꿀 수 있습니다 VT Decompression Session은 강력한 저수준 인터페이스입니다 이 강연의 범위를 벗어나죠 그러나 고급 개발자라면 더 자세히 알아보고 싶으실 거에요 마지막으로 Core Media가 있습니다 이 프레임워크는 AVFoundation 및 기타 고급 미디어 프레임워크에서 사용하는 미디어 파이프라인을 정의합니다 Core Media의 저수준 데이터 유형 및 인터페이스를 사용하여 미디어 샘플을 효율적으로 처리하고 미디어 데이터의 대기열을 관리할 수 있습니다 그리고 이 강연의 나머지 부분에서는 이런 프레임워크들을 앱에서 언제 어떻게 사용할지 보여드릴게요 먼저 AVKit, AVFoundation을 사용하여 EDR로 렌더링된 HDR 비디오를 쉽게 재생하는 방법을 보여드릴게요 그런 다음 AVPlayer의 보다 정교한 응용 프로그램들을 사용하여 자신의 레이어에 렌더링하고 CA Display Link를 통해 개별로 디코딩된 프레임에 액세스하고 결과 CV 픽셀 버퍼를 Core Image로 보내어 처리하는 법을 보겠습니다 마지막으로 Metal에서의 처리 및 렌더링을 위해 디코딩된 프레임을 CV Metal 텍스처 캐시를 통해 Metal 텍스처로 액세스하는 것을 보여드리겠습니다 Apple 플랫폼의 비디오 미디어 레이어를 간략히 살펴보았으므로 AVKit, AVFoundation 프레임워크를 자세히 보겠습니다 먼저 HDR 비디오 콘텐츠를 AVFoundation의 AVPlayer 인터페이스로 재생하는 방법을 봅시다 AVPlayer는 컨트롤러 객체이며 미디어 에셋의 재생, 타이밍을 관리하는 데 사용됩니다 AVPlayer 인터페이스는 HDR 비디오 고성능 재생에 사용됩니다 가능한 경우 자동으로 결과를 EDR로 렌더링합니다 AVPlayer로, 스트리밍 미디어는 물론 HLS로 제공되는 QuickTime 영화와 같은 로컬 또는 원격 파일 기반 미디어를 재생할 수 있습니다 AVPlayer는 미디어 에셋을 한 번에 하나씩 재생합니다 플레이어 인스턴스를 재사용해서 추가 미디어 에셋을 연속 재생할 수 있습니다 혹은 여러 개의 인스턴스를 만들어서 하나 이상의 에셋을 동시에 재생할 수도 있습니다 그러나 AVPlayer는 미디어 에셋을 한 번에 하나씩 재생합니다 AVFoundation 프레임워크는 AVPlayer의 하위 클래스도 제공합니다 AV Queue Player라고 하는데요 HDR 미디어 에셋을 순차적으로 대기열에 넣고 재생되도록 관리합니다 여러분의 응용 프로그램은 EDR로 렌더링된 HDR 비디오 미디어를 단순히 재생만 한다면, AVPlayer View Controller를 사용하는 AVPlayer가 가장 좋은 방법일 수 있습니다 AVPlayerLayer와 함께 AVPlayer를 사용하면 iOS 또는 macOS에서 여러분만의 보기로 재생할 수 있어요
이것은 가장 간단하게 AVPlayer를 사용하는 방법입니다 두 가지 예를 보겠습니다 먼저 AVFoundation의 AVPlayer 인터페이스의 사용 방법을 봅시다 AVKit의 AVPlayer View Controller와 함께요 미디어의 URL에서 AVPlayer를 인스턴스화하는 것으로 시작합니다
다음으로 AVPlayer View Controller를 생성합니다 그런 다음 뷰어 컨트롤러의 플레이어 속성을 미디어의 URL에서 방금 만든 플레이어로 설정하고
비디오 재생을 시작하기 위해 뷰 컨트롤러를 모달로 제시합니다 AVKit은 모든 세부 정보를 관리하여 EDR을 지원하는 디스플레이에서 HDR 비디오를 자동으로 EDR로 재생합니다 앞서 말씀드린 것 처럼, 어떤 응용 프로그램에서는 그 안의 보기에서 HDR 비디오 미디어를 재생해야 하는 경우도 있습니다 그 경우에는 AVPlayer 레이어와 함께 AVPlayer를 사용하면 됩니다 앱 안의 보기에서 HDR 비디오 미디어를 EDR로 재생하려면 다시 미디어의 URL로 AVPlayer를 만드는 것으로 시작합니다 그러나 이번엔 AVPlayer 레이어를 방금 만든 플레이어로 인스턴스화합니다 그리고 보기에서 가져온 플레이어 레이어의 경계를 설정해야 합니다 이제 플레이어 레이어에 보기에서 가져온 경계가 있으므로 플레이어 레이어를 보기에 하위 레이어로 추가할 수 있습니다 마지막으로 HDR 비디오 미디어를 재생하기 위해 AVPlayer의 플레이 메소드를 호출합니다 이렇게 하면 HDR 비디오 미디어를 EDR로 재생할 수 있습니다 여러분의 레이어에서 AVPlayer, AVPlayer 레이어를 사용해서요 이렇게 AVPlayer를 사용한 HDR 비디오 재생 워크플로에서 가장 간단한 두 가지 방법을 살펴보았습니다 그러나 많은 응용 프로그램에는 단순한 미디어 재생 그 이상이 필요하죠
예를 들어 이미지 처리가 필요한 응용 프로그램도 있습니다 비디오에 컬러 그레이딩 또는 크로마키를 적용하는 경우죠 AVPlayer에서 디코딩된 비디오 프레임을 가져오는 방법을 봅시다 CoreImage 필터 또는 Metal 쉐이더를 실시간으로 적용하고 결과를 EDR로 렌더링합니다 HDR 비디오 미디어에서 EDR 프레임을 디코딩하는 AVPlayer와 AVPlayer 아이템 사용법을 보여드리겠습니다 Core Video 디스플레이 링크에서 디코딩된 프레임에 액세스하고 결과 픽셀 버퍼를 Core Image 또는 Metal로 보내 처리합니다 그런 다음 CA Metal Layer에서 결과를 EDR 지원 디스플레이를 이용해서 EDR로 렌더링 합니다 이를 기반으로 먼저 HDR 미디어가 EDR로 올바르게 렌더링되도록 하는 데 필요한 주요 속성 몇 개를 CA Metal Layer에서 설정하겠습니다 먼저 HDR 비디오 콘텐츠를 렌더링할 CA Metal Layer를 가져와야 합니다 이 레이어에서 wantsExtendedDynamicRangeContent 플래그를 true로 설정하여 EDR을 최적화합니다
Extended Dynamic Range 콘텐츠를 지원하는 픽셀 포맷을 사용하세요 뒤에 나오는 AVPlayer 예제에서는 CA Metal Layer가 하프 플로트 픽셀 포맷을 사용하도록 설정합니다 그러나 PQ 또는 HLG 전송 기능과 함께 사용되는 10비트 포맷도 사용 가능합니다 결과를 SDR로 제한하지 않으려면 레이어를 EDR 호환 가능한 확장된 색 공간으로 설정해야 합니다
이 예에서 우리는 하프 플로트 Metal 텍스처를 Extended Linear Display P3 색 공간으로 설정하겠습니다 EDR, 색 공간 및 픽셀 버퍼 포맷을 아주 간단히 살펴봤습니다 작년의 제 세션, 'EDR을 사용한 HDR 렌더링'을 확인해 보시면 좋을 거에요 자세한 내용은 올해의 'iOS의 EDR'을 참조하세요
이제 CA Metal Layer의 기본 속성을 설정했으므로 Core Image 또는 Metal 쉐이더를 사용하는 실시간 이미지 처리를 추가해 봅시다 디코딩된 비디오 프레임에 실시간으로 액세스하기 위해 AVPlayer와 함께 디스플레이 링크를 사용하겠습니다
이 작업은 AVPlayer에서 AVPlayer 항목을 만드는 것으로 시작합니다 그리고 AVPlayerItemVideoOutput을 인스턴스화합니다 EDR을 위한 적절한 픽셀 버퍼 포맷과 색 공간으로 구성합니다 그런 다음 디스플레이 링크를 만들고 구성합니다 마지막으로 디스플레이 링크를 실행하여 Core Image 또는 Metal 처리를 위한 픽셀 버퍼를 가져옵니다 CA Display 링크를 iOS에서처럼 보여드리겠습니다 macOS용으로 개발할 때는 그와 같은 CV 디스플레이 링크 인터페이스를 사용하세요 이번에는 미디어 URL에서 AVPlayer 항목을 생성하도록 선택합니다 방금 생성한 AVPlayer 항목으로 AVPlayer를 인스턴스화합니다 이제 디코딩된 프레임의 픽셀 버퍼 포맷과 색 공간을 지정하기 위해 딕셔너리 한 쌍을 만듭니다 첫 번째 딕셔너리인 videoColorProperties에서는 색 공간과 전달 함수를 지정합니다 이 예에서는 대부분의 Apple 디스플레이와 관련 있는 Display P3 색 공간과 AVFoundation이 EDR에 필요한 확장된 범위 값을 유지하게 만드는 선형 전달 함수를 요청합니다
두 번째 딕셔너리는 outputVideoSettings인데요 픽셀 버퍼 포맷의 특성을 지정합니다 또한 방금 만든 videoColorProperties에 대한 참조를 제공합니다 이 예에서는 와이드 컬러와 하프 플로트 픽셀 버퍼 포맷을 요청하죠 AVPlayer 항목 비디오 출력은 매우 유용한데요 출력 설정 딕셔너리에서 지정한 픽셀 버퍼 포맷으로 비디오를 디코딩할 뿐만 아니라 픽셀 전송 세션을 통해 필요한 모든 색상 변환을 자동으로 실행합니다 기억을 되살려보면, 비디오에는 잠재적으로 다른 색 공간을 사용하는 여러 개의 클립이 포함될 수 있었죠 AVFoundation은 이를 자동으로 관리합니다 곧 보여드리겠습니다 이렇게 하면 또한 결과적으로 디코딩된 비디오 프레임을 Metal과 같은 저수준 프레임워크로 전송할 수 있습니다 디스플레이의 색 공간에 자동 색 공간 변환을 제공하지 않는 곳으로요 이제 AVPlayer 항목 비디오 출력을 outputVideoSettings 딕셔너리로 만듭니다 세 번째 단계는, 디스플레이 링크를 설정하는 것입니다 디코딩된 프레임에 실시간으로 액세스하는 데 사용됩니다 CA Display Link는 각 디스플레이 업데이트에서 실행되는 콜백을 받습니다 잠시 뒤에 보겠지만 이 예에서는 로컬 함수를 호출할 건데요 처리하기 위해 CoreImage에 보낼 CV 픽셀 버퍼를 가져오기 위해서죠 다음으로 비디오 플레이어 항목 관찰자를 만듭니다 지정된 플레이어 항목 속성에 대한 변경 사항을 처리할 수 있습니다
이 예제에서는 플레이어 아이템의 상태가 변경될 때마다 이 코드를 실행할 것입니다
플레이어 항목의 상태가 재생 준비로 변경되면 AVPlayer 항목 비디오 출력을 방금 반환된 새 AVPlayerItem에 추가합니다 CA Display Link를 common 모드로 설정된 main 런 루프로 등록하고 HDR 비디오를 실시간으로 디코딩하기 시작합니다 동영상 플레이어에서 play를 호출해서요
마지막으로 CA Display Link 콜백 구현 사례를 살펴보겠습니다 displayLinkCopyPixelBuffers로 이전에 참조했던 로컬 함수죠 HDR 비디오가 재생되기 시작하면 CA Display Link 콜백 함수는 디스플레이를 새로 고칠 때마다 호출됩니다 예시로 일반적 디스플레이의 경우 초당 60번 호출될 수 있습니다 새 CV 픽셀 버퍼가 있을 때 표시된 프레임을 업데이트할 수 있는 기회입니다 디스플레이를 콜백할 때마다 현재 시스템 시간에 표시되는 디코딩된 비디오 프레임을 가진 CV 픽셀 버퍼를 복사합니다 그러나 copyPixelBuffer 호출은 실패할 수 있습니다 또한 디스플레이를 새로 고칠 때마다 항상 새 CV 픽셀 버퍼를 사용할 수 있는 것도 아니죠 특히 화면 재생 빈도가 재생 중인 비디오의 재생 빈도를 초과하면요 새로운 CV 픽셀 버퍼가 없으면 호출은 실패하고 렌더링은 건너뜁니다 이전 프레임은 디스플레이가 새로 고침될 때까지 화면에 남아 있겠죠 그러나 복사가 성공하면 CV 픽셀 버퍼에 새로운 비디오 프레임이 생깁니다 이 새 프레임을 처리하고 렌더링 하는 방법은 여러 가지 있습니다 한 가지는 CV 픽셀 버퍼를 Core Image로 보내어 처리하는 겁니다 Core Image는 하나 이상의 CI 필터를 함께 묶어서 비디오 프레임을 GPU 가속 이미지로 처리할 수 있습니다
모든 CI 필터가 EDR과 호환되지는 않는 것을 잊지 마세요 HDR 콘텐츠에 문제가 생길 수 있습니다 SDR 클램핑 같은 문제나 더 나쁜 일들이 일어날 수 있죠 Core Image는 많은 EDR 호환 필터를 제공합니다 CICategoryHighDynamicRange라는 필터 이름을 사용하면 EDR 호환 CoreImage 필터를 셀 수 있습니다 이 예에서는, 간단한 세피아 톤 효과를 추가합니다 이제 예제로 돌아가 Core Image를 통합하겠습니다 새로운 CV 픽셀 버퍼를 생성하는 각 디스플레이 링크 콜백으로 CI 이미지를 만듭니다
원하는 효과를 구현하기 위해 CI 필터를 인스턴스화합니다 세피아 톤 필터는 매개변수가 없어서 단순하기 때문에 썼는데요 시스템에 CI 필터가 많이 내장되어 있습니다 여러분이 직접 간단히 쓸 수도 있죠 CI 필터의 입력 이미지를 방금 생성한 CI 이미지로 설정합니다
처리된 비디오 결과는 필터의 출력 이미지에서 사용할 수 있습니다 원하는 효과를 얻는 데 필요한 만큼 CI 필터를 연결합니다 그런 다음 CI 렌더링 목표를 사용하여 결과 이미지를 응용 프로그램의 보기 코드로 렌더링합니다
이 작업에 대해 자세히 알아보려면 WWDC 2020 강연 '영상에 CI 효과 적용하기'를 참고하세요 또 다른 새 기능은 Metal과 사용자 정의 Metal 쉐이더를 사용하여 새로운 CV 픽셀 버퍼를 처리하고 렌더링하는 것입니다 CV 픽셀 버퍼를 Metal 텍스처로 변환하는 과정을 간략히 설명하겠습니다 그러나 최상의 성능을 유지하면서 이 변환을 구현하는 것은 다른 강연을 위해 남겨두는 것이 좋겠네요, 어려운 주제니까요 대신 Metal 텍스처를 CoreVideo Metal 텍스처 캐시에서 이끌어 내는 것을 추천합니다 그 과정은 이 강연의 마지막 예시로 살펴볼게요 일반적으로, CV 픽셀 버퍼에서 IO Surface를 가져와서 Metal 텍스처 설명자를 만들고 Metal 기기에서 Metal 텍스처를 만듭니다 설명자가 있는 새 텍스처를 사용해서요
하지만 텍스처가 재사용되거나 지나치게 그려질 위험이 있으니 조심스럽게 잠금해야 합니다 또, Metal 텍스처가 PixelBuffer의 모든 포맷을 지원하는 것은 아니죠 따라서 이 예제에서는 half float를 사용합니다 이렇게 복잡하기 때문에 CoreVideo에서 Metal 텍스처에 직접 액세스하는 것이 좋습니다, 바로 보여드릴게요 Core Video와 Metal을 더 자세히 살펴보겠습니다 언급했듯이 CV Metal 텍스처 캐시는 CV 픽셀 버퍼를 Metal과 함께 사용하는 간단하고 효율적인 방법입니다 CV Metal 텍스처 캐시는 Metal 텍스처를 추가 변환 없이 캐시에서 직접 얻을 수 있어서 편리합니다 CV Metal 텍스처 캐시는 자동으로 CV 픽셀 버퍼와 Metal 텍스처를 연결합니다 따라서 코드를 단순화하고 빠르게 실행할 수 있습니다 CV 픽셀 버퍼 풀과 함께 CV Metal 텍스처 캐시는 'IOSurface 매핑에 대한 Metal 텍스처'를 유지함으로써, 성능 또한 좋습니다
마지막으로, CV 메탈 텍스처 캐시를 사용하면 IO Surface를 수동으로 추적할 필요가 없습니다 이제 이번 강연의 마지막 예를 보겠습니다 Core Video에서 CV Metal 텍스처 캐시를 사용하여 Metal 텍스처를 직접 추출하는 방법을 설명할게요 시스템 기본 Metal 기기를 가져오는 것으로 시작합니다 이를 사용하여 Metal 텍스처 캐시를 생성합니다 그런 다음 Core Video Metal 텍스처 캐시를 Metal 텍스처 캐시와 연결하여 인스턴스화합니다 디코딩된 비디오 프레임에 Metal 텍스처로 액세스할 때 쓸 수 있죠 편리하게 Metal 엔진에서 직접 사용할 수 있어요 이 예에서는 'Metal 시스템 기본 기기'를 만들고 사용합니다 다음은 CV Metal 텍스처 캐시를 만들어 봅시다 CVMetalTextureCacheCreate로 방금 만든 Metal 기기를 지정합니다 그러면 Core Video Metal 텍스처를 만드는 데 필요한 CV 픽셀 버퍼의 높이와 너비를 알 수 있습니다 그리고 VMetalTextureCacheCreate TextureFromImage를 호출합니다 CV Metal 텍스처 개체를 인스턴스화하고 CV 픽셀 버퍼와 연결하기 위해서요 마지막으로 CVMetalTexture GetTexture를 호출하여 원하는 Metal 텍스처를 얻습니다 Swift 응용 프로그램은 CV Metal 텍스처에 대한 강력한 참조를 사용해야 합니다 하지만 Objective-C를 사용할 때는 CV MetalTextureRef를 릴리즈하기 전에 Metal이 완료되었는지 확인해야 합니다 Metal 명령 버퍼 완료 핸들러를 사용하면 됩니다
여기까지입니다 여러 작업 플로우를 살펴봤지요 재생, 편집, 이미지 처리하기 위해 HDR 비디오 미디어를 EDR로 렌더링했었죠
HDR 미디어를 재생하기 위해 AV Player에서 AVKit의 AV Player View Controller로 이동하는 방법을 배웠습니다 또한 보기에 HDR 미디어를 표시 하기 위해 AV Player Layer와 함께 AV Player를 사용하는 방법도 배웠어요 끝으로 재생 중에 실시간 효과를 추가하는 방법을 살펴보았습니다 AVFoundation의 AVPlayer를 CoreVideo에 연결하고 렌더링을 위해 Metal로 연결했죠 CoreImage 필터와 뿐만 아니라 Metal 쉐이더를 사용하여 실시간 효과를 적용하기도 했죠
더 깊이 알고 싶다면, WWDC 세션 몇 개를 추천드릴게요 비디오 워크플로 생성 및 HDR 미디어를 EDR과 통합하는 것에 관한 세션들이에요 특히 'AVFoundation으로 HDR 비디오 편집, 재생하기' 세션을 추천합니다 이 세션에서는 AV 비디오를 구성하는 방법을 HDR 미디어에 효과를 적용하기 위해 'CI 필터를 핸들러로 적용하는 방법'과 함께 알아봅니다 이 세션에서는 사용자 정의 합성기 를 사용하는 방법도 배우게 됩니다 각 비디오 프레임이 처리되도록 준비되었을 때 CV 픽셀 버퍼와 함께 사용할 수 있는 거에요 처음에 말씀드린 것처럼 올해도 EDR에 대한 두 개의 다른 세션을 제공하고 있어요 'iOS에서의 EDR'에서는 iOS에서도 EDR API가 지원된다고 발표드렸죠 'CoreImage, Metal 및 SwiftUI를 사용한 EDR로 HDR 콘텐츠 디스플레이하기'에서는 EDR을 다른 미디어 프레임워크와 통합하는 방법을 더 자세히 봅니다 macOS와 이제 iOS 모두에서 여러분의 HDR 비디오를 EDR 지원 응용 프로그램에 통합할 수 있기를 바랍니다 시청해주셔서 감사합니다
-
-
6:58 - Playing media using AVPlayerViewController
// Playing media using AVPlayerViewController let player = AVPlayer(URL: videoURL) // Creating a player view controller var playerViewController = AVPlayerViewController() playerViewController.player = player self.presentViewController(playerViewController, animated: true) { playerViewController.player!.play() }
-
7:38 - Playing media using AVPlayer and AVPlayerLayer
// Playing media using AVPlayer and AVPlayerLayer let player = AVPlayer(URL: videoURL) var playerLayer = AVPlayerLayer(player: player) playerLayer.frame = self.view.bounds self.view.layer.addSublayer(playerLayer) player.play()
-
9:28 - CAMetalLayer Properties
// Opt into using EDR let layer: CAMetalLayer layer.wantsExtendedDynamicRangeContent = true // Use half-float pixel format layer.pixelFormat = MTLPixelFormatRGBA16Float // Use extended linear display P3 color space layer.colorspace = kCGColorSpaceExtendedLinearDisplayP3
-
11:33 - Create an AVPlayerItemVideoOutput
let videoColorProperties = [ AVVideoColorPrimariesKey: AVVideoColorPrimaries_P3_D65, AVVideoTransferFunctionKey: AVVideoTransferFunction_Linear, AVVideoYCbCrMatrixKey: AVVideoYCbCrMatrix_ITU_R_2020 ] let outputVideoSettings = [ AVVideoAllowWideColorKey: true, AVVideoColorPropertiesKey: videoColorProperties, kCVPixelBufferPixelFormatTypeKey as String: NSNumber(value: kCVPixelFormatType_64RGBAHalf) ] as [String : Any] // Create a player item video output let videoPlayerItemOutput = AVPlayerItemVideoOutput(outputSettings: outputVideoSettings)
-
13:02 - Create a display link
// Create a display link lazy var displayLink: CADisplayLink = CADisplayLink(target: self, selector: #selector(displayLinkCopyPixelBuffers(link:))) var statusObserver: NSKeyValueObservation? statusObserver = videoPlayerItem.observe(\.status, options: [.new, .old], changeHandler: { playerItem, change in if playerItem.status == .readyToPlay { playerItem.add(videoPlayerItemOutput) displayLink.add(to: .main, forMode: .common) videoPlayer?.play() } }) }
-
14:16 - Run DisplayLink to get pixel buffers
@objc func displayLinkCopyPixelBuffers(link: CADisplayLink) { let currentTime = videoPlayerItemOutput.itemTime(forHostTime: CACurrentMediaTime()) if videoPlayerItemOutput.hasNewPixelBuffer(forItemTime: currentTime) { if let buffer = videoPlayerItemOutput.copyPixelBuffer(forItemTime: currentTime, itemTimeForDisplay: nil) { let image = CIImage(cvPixelBuffer: buffer!) let filter = CIFilter.sepiaTone() filter.inputImage = image output = filter.outputImage ?? CIImage.empty() // use context to render to you CIRenderDestination } } }
-
15:53 - Integrate Core Image
@objc func displayLinkCopyPixelBuffers(link: CADisplayLink) { let currentTime = videoPlayerItemOutput.itemTime(forHostTime: CACurrentMediaTime()) if videoPlayerItemOutput.hasNewPixelBuffer(forItemTime: currentTime) { if let buffer = videoPlayerItemOutput.copyPixelBuffer(forItemTime: currentTime, itemTimeForDisplay: nil) { let image = CIImage(cvPixelBuffer: buffer) let filter = CIFilter.sepiaTone() filter.inputImage = image output = filter.outputImage ?? CIImage.empty() // use context to render to your CIRenderDestination } } }
-
19:13 - Using CVMetalTextureCache
// Create a CVMetalTextureCacheRef let mtlDevice = MTLCreateSystemDefaultDevice() var mtlTextureCache: CVMetalTextureCache? = nil CVMetalTextureCacheCreate(allocator: kCFAllocatorDefault, cacheAttributes: nil, metalDevice: mtlDevice, textureAttributes: nil, cacheOut: &mtlTextureCache) // Create a CVMetalTextureRef using metalTextureCache and our pixelBuffer let width = CVPixelBufferGetWidth(pixelBuffer) let height = CVPixelBufferGetHeight(pixelBuffer) var cvTexture : CVMetalTexture? = nil CVMetalTextureCacheCreateTextureFromImage(allocator: kCFAllocatorDefault, textureCache: mtlTextureCache, sourceImage: pixelBuffer, textureAttributes: nil, pixelFormat: MTLPixelFormatRGBA16Float, width: width, height: height, planeIndex: 0, textureOut: &cvTexture) let texture = CVMetalTextureGetTexture(cvTexture) // In Obj-C, release CVMetalTextureRef in Metal command buffer completion handlers
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.