시간? 20 년대의 독서
Original/si-Shi-pin-de-bian-Jie-ma-bian-ma-pian/
테마 iOS 개발 MacOS
이전에는 일반적으로 사용하는 FFmpeg 멀티미디어 라이브러리가 CPU 를 사용하여 비디오 코덱을 수행하고 CPU 리소스를 사용하며 비효율적이며 소프트 코덱으로 알려졌습니다. 20 14 년, 애플은 VideoToolbox.framwork 프레임워크를 개방하여 GPU 또는 전용 프로세서를 사용하여 인코딩하고 디코딩하며, 일반적으로 하드 코덱이라고 합니다. 이전에는 이 프레임워크를 MAC OS 시스템에서만 사용할 수 있었고 iOS8 에서는 전용 프레임워크였습니다. 마지막으로,
WWDC 에서 직접 비디오 인코딩 및 디코딩 20 14 에 액세스하여 애플은 비디오 도구상자를 사용하여 하드 코딩 및 디코딩을 시작했습니다.
하드 코덱을 사용하면 몇 가지 장점이 있습니다. * 성능 향상 * 효율성 향상 * 전력 사용 확대.
코덱의 경우 AVFoundation 프레임워크는 1 기능만 제공합니다. 직접 압축 해제 후 표시;
2. 문서로 직접 압축합니다.
비디오 도구 상자의 경우 1 을 통해 데이터를 가져와서 네트워크를 통해 스트리밍할 수 있습니다. 이미지의 데이터 구조로 압축을 풉니다.
비디오 이미지로 압축 된 컨테이너 데이터 구조.
첫째, videoToolbox 의 기본 데이터
비디오 도구상자에서 비디오 코덱 전후에 적용해야 하는 데이터 구조에 대해 설명합니다.
CVPixelBuffer: 인코딩 전/후 이미지 데이터 구조. 이 컨텐츠에는 일련의 CVPixelBufferPool 컨텐츠가 포함되어 있습니다.
CMTime, CMClock 및 CMTimebase: 타임스탬프 종속관계. 시간은 64 비트 /32 비트로 나타납니다.
PixelBufferAttributes: 사전 설정. 여기에는 폭/높이, 픽셀 형식 유형,? 호환성 (예: OpenGL ES, 핵심 애니메이션)
CMBlockBuffer: 인코딩 후 생성된 이미지의 데이터 구조입니다.
CMVideoFormatDescription: 이미지 저장 모드, 코덱 및 기타 형식 설명.
(CMSampleBuffer: 인코딩 및 디코딩 전후의 비디오 이미지를 저장하는 컨테이너 데이터 구조입니다.
CMClock
CMTimebase: CMClock, 시간 매핑 및 속도 제어를 포함한 CMClock 에 대한 제어 뷰.
두 번째로 우리가 알 수 있는 것은, 우리가 얻은 데이터 (cmsamplebufferref) sample buffer data 입니다.
그림1..1
위 그림에서 인코딩 전후의 비디오 이미지는 CMSampleBuffer 에 캡슐화되고 인코딩하기 전에 CVPixelBuffer 에 저장됩니다. 인코딩 후 CMBlockBuffer 에 저장됩니다. 또한 둘 다 CMTime 과 CMVideoFormatDesc 를 포함하고 있습니다.
둘째, 비디오 데이터 스트림이 인코딩되어 서버에 업로드됩니다.
1. VTCompressionSession 을 사용하여 CVPixelBuffer 데이터 스트림을 하드 코딩합니다.
(1) VTCompressionSession 초기화
Vt _ export OS status vtcompressionsession create (cm _ nullable cfallocatorref? Allocator, int32_t width, int32_t height, CMVideoCodecType codecType, cm _ nullable cfdictionaryref encodes Cm _ nullable cfdictionaryref sourceimagebufferattributes, CM_NULLABLE CFAllocatorRef? CompressedDataAllocator, cm _ nullable vtcompressionoutputcallback output callback, void * CM_NULLABLE? OutputCallbackRefCon, cm _ returns _ retained _ parameter cm _ nullable vtcompressionref * cm _ nonnull compref
VTCompressionSession 초기화 매개변수 설명:
디스패처: NULL 을 기본 할당으로 설정하는 디스패처.
폭: 폭
높이: 높음
CodecType: 인코딩 유형 (예: kCMVideoCodecType _ H264) 입니다.
EncoderSpecification: 코딩 사양입니다. NULL 설정은 videoToolbox 가 직접 선택합니다.
SourceImageBufferAttributes: 소스 픽셀 버퍼 속성. NULL 을 설정하면 videToolbox 가 만들어지지 않고 직접 만들어집니다.
데이터 분배기를 압축하다. 비어 있음, 기본 할당으로 설정합니다.
OutputCallback: VTCompression 세션 EncodeFrame 압축을 한 번 호출하면 비동기적으로 호출됩니다. 참고: NULL 을 설정할 때 vt compression session encode frame houtbutthandler 메서드를 호출하여 프레임을 압축하고 iOS9.0 이상을 지원해야 합니다.
OutputCallbackRefCon: 콜백 사용자 정의 참조 값.
CompressionSessionOut: 세션 변수를 압축합니다.
(2) VTCompressionSession 구성
VTSessionSetProperty () 호출을 사용하여 압축을 구성합니다. * kvtcompressionpropertykey allowframereordering: 프레임 순서 변경을 허용합니다. 기본값은 true * KvtCompressionPropertyKey 평균 비트율입니다. 원하는 평균 인코딩 속도 설정 * KvtCompressionPropertyKey H264 엔트로피 인코딩 모드: H264 엔트로피 인코딩 모드. 컨텍스트 기반 이진 산술 코딩 CABAC 와 가변 길이 인코딩 VLC 의 두 가지 모드가 있습니다. 슬라이스 레이어 (그림 및 시퀀스) 이상은 고정 길이 또는 가변 길이 이진 인코딩을 사용하고 슬라이스 레이어 아래에는 VLC 또는 CABAC 를 사용합니다. 자세한 내용은 * kvt compression property key real time: 비디오 인코딩 압축은 실시간입니까? CFBoolean 또는 NULL 을 설정할 수 있습니다. 기본값은 null * KVTCompression PropertyKey 프로파일 수준입니다. 인코딩 스트림의 구성과 기준을 지정합니다. 예를 들어 KVTProfilelevel H264 주 자동화 레벨입니다.
VTCompressionSession 을 구성한 후 VTCompression Sessions Prepareto 를 호출하여 준비할 프레임을 인코딩하도록 선택할 수 있습니다.
(3) 입력 데이터의 하드 코딩을 시작하십시오.
VtCompression 세션 EncodeFrame 메서드를 사용하여 인코딩합니다. 인코딩이 완료되면 outputCallback 콜백 함수를 호출합니다.
VT_EXPORT OSStatus? Vtcompressionsessionencodeframe (? Cm _ nonnull vt compression session ref? 세션, cm _ nonnull cvimagebufferref image buffer, CMTime? PresentationTimeStamp, CMTime? 기간,//아마도 kcmtimenivalidcm _ nullable cfdictionaryref frame properties, void* CM_NULLABLE? SourceFrameRefCon, vtencodeinfoflags * cm _ nullable info flags out) _ OS x _ 사용 가능 _ 시작 (_ _ MAC _/klook
PresentationTimeStamp: 가져온 이 샘플 버퍼 데이터의 표시 타임스탬프입니다. 이 세션에 전달된 각 타임스탬프는 이전 프레젠테이션 타임스탬프보다 큽니다.
기간: 가져온 샘플 버퍼 데이터의 이 프레임이 표시되는 시간입니다. 시간 정보가 없으면 kCMTimeInvalid 를 설정할 수 있습니다.
FrameProperties: 이 프레임의 속성을 포함합니다. 프레임을 변경하면 이후의 인코딩된 프레임에 영향을 줍니다.
SourceFrameRefCon: 콜백 함수는 설정한 이 프레임의 참조 값을 참조합니다.
InfoFlagsOut: 인코딩 작업을 허용하는 VTEncodeInfoFlags 를 가리킵니다. 비동기 작업을 사용하는 경우 kVTEncodeInfo _ Asynchronous 동기화 작업을 설정하고 kVTEncodeInfo _ FrameDropped 를 설정하여 이 정보를 허용하지 않도록 NULL 을 설정합니다.
(4) VTCompressionOutputCallback 콜백 함수를 실행합니다.
Typedef void (* vtcompressionoutputcallback) (void * cm _ nullable outputcallbackrefcon, void * cm _ nullable VTEncodeInfoFlags infoFlags, cm _ nullable cmsamplebufferref sample buffer);
OutputCallbackRefCon: 콜백 함수에 대한 참조 값
Sourceframefcon: vt compression sessions encodeframe 함수에 설정된 프레임의 참조 값입니다.
상태: 압축 성공은 noErr 이고 실패에는 오류 코드가 있습니다.
InfoFlags: 인코딩 작업에 대한 정보 식별자를 포함합니다.
샘플 버퍼: 압축에 성공하거나 프레임이 손실되지 않은 경우 이 압축 데이터 SampleBuffer 를 포함합니다. 그렇지 않으면 NULL 입니다.
(5) 성공적으로 압축된 sampleBuffer 데이터를 기본 스트림 NSData 로 처리하고 서버에 업로드합니다.
MPEG-4 는 오디오 및 비디오 정보를 위한 압축 인코딩 표준 세트입니다.
그림 1. 1 에서 $$CMSampleBuffer = CMTime (선택 사항)+cmblock buffer+cmideoformat desc 를 볼 수 있습니다
5. 1 먼저 압축된 데이터가 정확한지 판단합니다.
//없는 경우 (! 샘플 버퍼) 반환; 만약 (상태! = noErr) 반환; //sampleBuffer 에서 가변 사전이 포함된 불변 배열 또는 nullcfarrayrearray =? 를 반환합니다 Cmsamplebuffergetsampleattachmentsaray (samplebuffer, true); 만약 (! 배열) 반환 -응? Cfdictionaryrefdic = cfarraygetvalueatindex (array, 0); 만약 (! Dic) 반환 //issue3: kcmsampletachmentkey _ notsync: 이 키가 없으면 동기화를 나타내고, 비동기를 나타냅니다. 아니오: 부울 키프레임 동기화 =! CFDictionaryContainsKey(dic, kcmsampletachmentkey _ notsync); //동기화를 나타냅니다.
질문 3 의 경우 문자 그대로는 위의 해석을 의미하지만, 대부분 온라인 쿼리가 비디오 키프레임인지, 쿼리 문서에서 이 키 키 값 Kcmsamplebufferattachmentkey _ forcekeyframe 이 존재하는지 확인하기 때문에 이 값을 알고 있으면 자세한 내용을 알려 주세요.
5.2 cmvideoformattesc 데이터 얻기 세 번째 부분에서 cmvideoformattesc 에는 이미지의 윤곽, 계층, 폭 높이, 블록 제거 필터 등이 포함되어 있음을 알 수 있습니다. 여기에는 첫 번째 NALU 의 SPS (시퀀스 매개변수 세트) 와 두 번째 NALU 의 PPS (화면 매개변수 세트) 가 포함됩니다.
//if (키프레임 & amp& amp! 인코더->; Sps) {// samplebuffer 에서 cmvedeoformattesc cmformatdescriptoref format = cmsamplebuffergetformatdescription 가져오기 (샘플 be //H264 매개 변수 세트에서 SPS 및 ppsconstuint8 _ t * sparametersetsize _ t sparametersetsize, sparameterSetCount 가져오기? Osstatus status code = cmvideoformattescriptiongeth 264 parametersetandix (format, 0, & ampspara meterset & amp;; SparameterSetSize & amp;; SparameterSetCount, 0); If (status code = = noerr) {size _ t pparametersetsize, Pparametersetcountconst uint8 _ t * pparametersetos status status code = cmvideoformatedescriptiongeth 264 parametersetandix PparameterSetSize 입니다. PparameterSetCount, 0); If (status code = = noerr) {encoder-> Sps = [nsdatadatawithbytes: sparametersetlength: sparametersetsize]; 인코더->; Pps = [nsdatadatawithbytes: pparametersetlength: pparametersetsize]; }}}}
5.3 CMBlockBuffer 를 가져와 데이터로 변환
Cmblockbufferref block buffer = cmsamplebuffergetdatabuffer (샘플 버퍼); Size_t? LengthAtOffset, totalLengthchar * dataPointer// 수신된 데이터는 OS 상태 표시 block buffer status = cmblockbuffergetdatapointer (blockbuffergetdatapointer) 길이 간격띄우기. 총 길이. Data pointer); If(blockBufferStatus! = kcmblockbuffernoerr) {size _ t buffer offset = 0; Staticconstantavccheaderlength = 4; While(buffer offset & lt;; 총 길이? AVCCHeaderLength) {// NAL 단위 길이 읽기 uint32 _ t nalunitlength = 0; /* *
*? Void *memcpy(void *dest, const void *src, size _ TN);
*? 소스 src 가 가리키는 메모리 주소의 시작 위치에서 대상 dest 가 가리키는 메모리 주소의 시작 위치로 n 바이트를 복사합니다.
*/memcpy (& NALUnitLength, dataPointer+bufferOffset, avccheaderlength); //바이트 높은 비트에서 낮은 비트까지 nalunitlength = cfswapint32bigthost (nalunitlength); Rtavvideoframe * frame = [rtavvideoframenew]; Frame.sps = encoder-> Spsframe.pps = encoder-> Ppsframe.data = [nsdata datawithbytes: (data pointer+buffer offset+avccheaderlength) length: nalunitles Buffer offset+= nalunitlength+avccheaderlength; }}
얻은 H264 데이터는 푸시 스트림을 준비하기 위해 다음 RTMP 프로토콜에 적용됩니다.