# 时域å¯åˆ†å±‚视频编ç ## 基础概念 ### 时域å¯åˆ†å±‚视频编ç ä»‹ç» **å¯åˆ†å±‚视频编ç **,åˆå«å¯åˆ†çº§è§†é¢‘ç¼–ç ã€å¯ä¼¸ç¼©è§†é¢‘ç¼–ç ,是视频编ç çš„æ‰©å±•æ ‡å‡†ï¼Œç›®å‰å¸¸ç”¨çš„包å«SVC(H.264ç¼–ç æ ‡å‡†é‡‡ç”¨çš„å¯ä¼¸ç¼©æ‰©å±•)和SHVC(H.265ç¼–ç æ ‡å‡†é‡‡ç”¨çš„坿‰©å±•æ ‡å‡†ï¼‰ã€‚ 其特点是能一次编ç 出时域分层ã€ç©ºåŸŸåˆ†å±‚ã€è´¨é‡åŸŸåˆ†å±‚çš„ç æµç»“æž„ï¼Œæ»¡è¶³å› ç½‘ç»œã€ç»ˆç«¯èƒ½åŠ›å’Œç”¨æˆ·éœ€æ±‚ä¸åŒå¸¦æ¥çš„的差异化需求。 **时域å¯åˆ†å±‚视频编ç **, 是指能编ç å‡ºæ—¶åŸŸåˆ†å±‚ç æµçš„视频编ç ,下图是通过å‚考关系构建的4å±‚æ—¶åŸŸåˆ†å±‚ç æµç»“构。  从高到低é€å±‚ä¸¢å¼ƒéƒ¨åˆ†å±‚çº§çš„ç æµï¼ˆä¸¢å¼ƒé¡ºåºL3->L2->L1),能实现ä¸åŒç¨‹åº¦çš„å¸§çŽ‡ä¼¸ç¼©ï¼Œä»¥æ»¡è¶³ä¼ è¾“å’Œè§£ç 能力的å˜åŒ–需求。 如下图所示,是上述4å±‚æ—¶åŸŸåˆ†å±‚ç æµç»“构丢弃L3åŽç»„æˆçš„æ–°çš„ç æµç»“æž„ï¼Œèƒ½åœ¨è§£ç æ£å¸¸çš„æƒ…况下实现帧率å‡åŠçš„æ•ˆæžœã€‚其他层的丢弃åŒç†ã€‚  ### æ—¶åŸŸåˆ†å±‚ç æµç»“æž„ä»‹ç» åŸºç¡€ç æµæ˜¯ç”±ä¸€ä¸ªæˆ–多个独立图åƒç»„(Group Of Pictures,简称GOP)组åˆè€Œæˆçš„。GOP是在编ç ä¸ä¸€ç»„从I帧开始到I帧结æŸçš„连ç»çš„å¯ç‹¬ç«‹è§£ç 的图åƒç»„。 æ—¶åŸŸåˆ†å±‚ç æµå¯ä»¥åœ¨GOP内继ç»ç»†åˆ†ä¸ºç‹¬ç«‹çš„一个或多个时域图åƒç»„(Temporal Group Of Pictures, 简称TGOP),æ¯ä¸€ä¸ªTGOP由一个基本层和åŽç»çš„一个或多个增强层组åˆè€Œæˆï¼Œå¦‚上述4å±‚æ—¶åŸŸåˆ†å±‚ç æµç»“æž„ä¸çš„帧0到帧7是一个TGOP。 - **基本层(Base Layer, 简称BL):** 是GOPä¸çš„æœ€åº•层(L0)。在时域分层ä¸ï¼Œè¯¥å±‚用最低帧率进行编ç 。 - **增强层(Enhance Layer简称EL):** 是BL之上的层级,由低到高å¯ä»¥åˆ†ä¸ºå¤šå±‚(L1,L2,L3)。在时域分层ä¸ï¼Œæœ€ä½Žå±‚çš„EL便®BL获得的编ç ä¿¡æ¯ï¼Œè¿›ä¸€æ¥ç¼–ç 帧率更高的层级,更高层的ELä¼šä¾æ®BL或低层EL,æ¥ç¼–ç æ¯”低层更高帧率的视频。 ### å¦‚ä½•å®žçŽ°æ—¶åŸŸåˆ†å±‚ç æµç»“æž„ æ—¶åŸŸåˆ†å±‚ç æµç»“构的实现是ä¾é å‚考关系é€å¸§æŒ‡å®šå®žçŽ°çš„ï¼Œå‚考帧按在解ç 图åƒç¼“å˜åŒºï¼ˆDecoded Picture Buffer,简称DPBï¼‰é©»ç•™çš„æ—¶é•¿åˆ†ä¸ºçŸæœŸå‚考帧和长期å‚考帧。 - **çŸæœŸå‚考帧(Short-Term Reference,简称STR):** 是ä¸èƒ½é•¿æœŸé©»ç•™åœ¨DPBä¸çš„å‚è€ƒå¸§ï¼Œæ›´æ–°æ–¹å¼æ˜¯å…ˆè¿›å…ˆå‡ºï¼Œå¦‚æžœDPBæ»¡ï¼Œæ—§çš„çŸæœŸå‚考帧会被移出DPB。 - **长期å‚考帧(Long-Term Reference,简称LTR):** 是能长期驻留在DPBä¸çš„å‚è€ƒå¸§ï¼Œé€šè¿‡æ ‡è®°æ›¿æ¢çš„æ–¹å¼æ›´æ–°ï¼Œä¸ä¸»åŠ¨æ ‡è®°æ›¿æ¢å°±ä¸ä¼šæ›´æ–°ã€‚ 虽然STR个数大于1时,也能实现一定的跨帧å‚考结构,但å—é™äºŽå˜åœ¨æ—¶æ•ˆè¿‡çŸï¼Œæ—¶åŸŸåˆ†å±‚结构支æŒçš„跨度有é™ã€‚LTR则ä¸å˜åœ¨ä¸Šè¿°é—®é¢˜ï¼Œä¹Ÿèƒ½è¦†ç›–çŸæœŸå‚考帧跨帧场景。优选使用LTRå®žçŽ°æ—¶åŸŸåˆ†å±‚ç æµç»“构。 ## 适用场景 基于上述æè¿°çš„æ—¶åŸŸåˆ†å±‚ç¼–ç 特点,推è以下场景使用: - 场景1ï¼šæ’æ”¾ä¾§æ— ç¼“å˜æˆ–低缓å˜çš„实时编ç ä¼ è¾“åœºæ™¯ï¼Œä¾‹å¦‚è§†é¢‘ä¼šè®®ã€è§†é¢‘ç›´æ’ã€ååŒåŠžå…¬ç‰ã€‚ - 场景2ï¼šæœ‰è§†é¢‘é¢„è§ˆæ’æ”¾æˆ–å€é€Ÿæ’放需求的视频编ç 录制场景。 若开å‘åœºæ™¯ä¸æ¶‰åŠåЍæ€è°ƒæ•´æ—¶åŸŸå‚考结构,且分层结构简å•,则推è使用[全局时域å¯åˆ†å±‚特性](#全局时域å¯åˆ†å±‚特性feature_temporal_scalability),å¦åˆ™ä½¿èƒ½[长期å‚考帧特性](#长期å‚考帧特性feature_long-term_reference)。 ## 约æŸå’Œé™åˆ¶ - ä¸å¯ä»¥æ··ç”¨å…¨å±€æ—¶åŸŸå¯åˆ†å±‚特性和长期å‚考帧特性。 由于底层实现归一,全局时域å¯åˆ†å±‚特性和长期å‚考帧特性ä¸èƒ½åŒæ—¶å¼€å¯ã€‚ - å åŠ å¼ºåˆ¶IDRé…置时,请使用éšå¸§é€šè·¯é…置。 å‚考帧仅在GOP内有效,刷新I帧åŽï¼ŒDPBéšä¹‹æ¸…空,å‚è€ƒå¸§ä¹Ÿä¼šè¢«æ¸…ç©ºï¼Œå› æ¤å‚考关系的指定å—I帧刷新ä½ç½®å½±å“很大。 使能时域分层能力åŽï¼Œè‹¥éœ€è¦é€šè¿‡`OH_MD_KEY_REQUEST_I_FRAME`临时请求I帧,应使用生效时机确定的éšå¸§é€šè·¯é…置方å¼å‡†ç¡®å‘ŠçŸ¥æ¡†æž¶I帧刷新ä½ç½®ä»¥é¿å…å‚考关系错乱,å‚考éšå¸§é€šè·¯é…置相关指导,é¿å…使用生效时机ä¸ç¡®å®šçš„`OH_VideoEncoder_SetParameter`æ–¹å¼ã€‚ - 支æŒ`OH_AVBuffer`å›žè°ƒé€šè·¯ï¼Œä¸æ”¯æŒ`OH_AVMemory`回调通路。 新特性ä¾èµ–éšå¸§ç‰¹æ€§ï¼Œåº”é¿å…使用`OH_AVMemory`回调`OH_AVCodecAsyncCallback`,应使用`OH_AVBuffer`回调`OH_AVCodecCallback`。 - æ”¯æŒæ—¶åŸŸPåˆ†å±‚ï¼Œä¸æ”¯æŒæ—¶åŸŸB分层。 时域å¯åˆ†å±‚ç¼–ç æŒ‰åˆ†å±‚帧类型分为基于P帧的时域分层和基于B帧的时域编ç ï¼Œå½“å‰æ”¯æŒåˆ†å±‚Pç¼–ç ï¼Œä¸æ”¯æŒåˆ†å±‚Bç¼–ç 。 - å‡åŒ€åˆ†å±‚模å¼å½“å‰åªæ”¯æŒTGOP为2或4。 ## 全局时域å¯åˆ†å±‚特性(Feature_Temporal_Scalability) ### 接å£ä»‹ç» 全局时域å¯å±‚特性,适用于编ç 稳定和简å•的时域分层结构,åˆå§‹é…ç½®ï¼Œå…¨å±€ç”Ÿæ•ˆï¼Œä¸æ”¯æŒåЍæ€ä¿®æ”¹ã€‚å¼€å‘é…ç½®å‚æ•°å¦‚下: | é…ç½®å‚æ•° | è¯ä¹‰ | | -------- | ---------------------------- | | OH_MD_KEY_VIDEO_ENCODER_ENABLE_TEMPORAL_SCALABILITY | 全局时域分层编ç ä½¿èƒ½å‚æ•° | | OH_MD_KEY_VIDEO_ENCODER_TEMPORAL_GOP_SIZE | 全局时域分层编ç TGOP大å°å‚æ•° | | OH_MD_KEY_VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE | 全局时域分层编ç TGOPå‚è€ƒæ¨¡å¼ | - **全局时域分层编ç ä½¿èƒ½å‚æ•°ï¼š** 在é…置阶段é…ç½®ï¼Œä»…ç‰¹æ€§æ”¯æŒæ‰ä¼šçœŸæ£ä½¿èƒ½æˆåŠŸã€‚ - **全局时域分层编ç TGOP大å°å‚数:** å¯é€‰é…ç½®ï¼Œå½±å“æ—¶åŸŸå…³é”®å¸§ä¹‹é—´çš„间隔,用户需è¦åŸºäºŽè‡ªèº«ä¸šåŠ¡åœºæ™¯ä¸‹æŠ½å¸§éœ€æ±‚è‡ªå®šä¹‰å…³é”®å¸§å¯†åº¦ï¼Œå¯åœ¨[2, GopSize)范围内é…置,若ä¸é…置则使用默认值。 - **全局时域分层编ç TGOPå‚考模å¼å‚数:** å¯é€‰é…置,影å“éžå…³é”®å¸§å‚考模å¼ã€‚包括相邻å‚考`ADJACENT_REFERENCE`ã€è·¨å¸§å‚考`JUMP_REFERENCE` å’Œå‡åŒ€åˆ†å±‚`UNIFORMLY_SCALED_REFERENCE`。相邻å‚考相对跨帧å‚考拥有更好的压缩性能,跨帧å‚考相对相邻å‚考拥有更好的丢帧自由度,å‡åŒ€åˆ†å±‚模å¼ä¸¢å¸§åŽçš„ç æµåˆ†å¸ƒæ›´å‡åŒ€ï¼Œå¦‚ä¸é…置则使用默认值。 > **说明**:å‡åŒ€åˆ†å±‚模å¼å½“å‰åªæ”¯æŒTGOP为2或4。 使用举例1:TGOP=4,相邻å‚考模å¼ã€‚  使用举例2:TGOP=4,跨帧å‚考模å¼ã€‚  使用举例3:TGOP=4,å‡åŒ€åˆ†å±‚模å¼ã€‚  ### 开呿Œ‡å¯¼ åŸºç¡€ç¼–ç æµç¨‹è¯·å‚考[视频编ç 开呿Œ‡å¯¼](video-encoding.md),下é¢ä»…针与基础视频编ç 过程ä¸å˜åœ¨çš„区别åšå…·ä½“说明。 1. 在åˆå§‹é˜¶æ®µåˆ›å»ºç¼–ç å®žä¾‹æ—¶ï¼Œæ ¡éªŒå½“å‰è§†é¢‘ç¼–ç å™¨æ˜¯å¦æ”¯æŒå…¨å±€æ—¶åŸŸå¯åˆ†å±‚特性。 ```c++ // 1.1 获å–对应视频编ç å™¨èƒ½åŠ›å¥æŸ„,æ¤å¤„以H.264为例 OH_AVCapability *cap = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true); // 1.2 é€šè¿‡ç‰¹æ€§èƒ½åŠ›æŸ¥è¯¢æŽ¥å£æ ¡éªŒæ˜¯å¦æ”¯æŒå…¨å±€æ—¶åŸŸå¯åˆ†å±‚特性 bool isSupported = OH_AVCapability_IsFeatureSupported(cap, VIDEO_ENCODER_TEMPORAL_SCALABILITY); ``` 若支æŒï¼Œåˆ™å¯ä»¥ä½¿èƒ½å…¨å±€æ—¶åŸŸå¯åˆ†å±‚特性。 2. 在é…置阶段,é…置全局时域分层编ç ç‰¹æ€§å‚æ•°ã€‚ ```c++ constexpr int32_t TGOP_SIZE = 3; // 2.1 创建é…置用临时AVFormat OH_AVFormat *format = OH_AVFormat_Create(); // 2.2 å¡«å……ä½¿èƒ½å‚æ•°é”®å€¼å¯¹ OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_ENABLE_TEMPORAL_SCALABILITY, 1); // 2.3 (å¯é€‰)å¡«å……TGOP大å°å’ŒTGOP内å‚考模å¼é”®å€¼å¯¹ OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_TEMPORAL_GOP_SIZE, TGOP_SIZE); OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE, ADJACENT_REFERENCE); // 2.4 傿•°é…ç½® int32_t ret = OH_VideoEncoder_Configure(videoEnc, format); if (ret != AV_ERR_OK) { // å¼‚å¸¸å¤„ç† } // 2.5 é…置完æˆåŽé”€æ¯ä¸´æ—¶AVFormat OH_AVFormat_Destroy(format); ``` 3. (å¯é€‰ï¼‰åœ¨è¿è¡Œé˜¶æ®µè¾“出轮转ä¸ï¼ŒèŽ·å–ç æµå¯¹åº”时域层级信æ¯ã€‚ å¼€å‘者å¯åŸºäºŽå·²é…置的TGOP傿•°ï¼ŒæŒ‰ç¼–ç 出帧数目周期性获å–。 通过é…置周期获å–示例代ç 如下: ```c++ uint32_t outPoc = 0; // é€šè¿‡è¾“å‡ºå›žè°ƒä¸æœ‰æ•ˆå¸§æ•°ï¼ŒèŽ·å–TGOP内相对ä½ç½®ï¼Œå¯¹ç…§é…置确认层级 static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) { // 注:若涉åŠå¤æ‚å¤„ç†æµç¨‹ï¼Œå»ºè®®ç›¸å…³ struct OH_AVCodecBufferAttr attr; (void)buffer->GetBufferAttr(attr); // 刷新I帧åŽPOCå½’é›¶ if (attr.flags & AVCODEC_BUFFER_FLAG_KEY_FRAME) { outPoc = 0; } // æ²¡æœ‰å¸§ç æµåªæœ‰XPS的输出需è¦è·³è¿‡ if (attr.flags != AVCODEC_BUFFER_FLAG_CODEC_DATA) { int32_t tGopInner = outPoc % TGOP_SIZE; if (tGopInner == 0) { // 时域关键帧,åŽç»ä¼ 输ã€è§£ç æµç¨‹ä¸å¯ä¸¢å¼ƒ } else { // 时域éžå…³é”®å¸§ï¼ŒåŽç»ä¼ 输ã€è§£ç æµç¨‹å¯ä»¥ä¸¢å¼ƒ } outPoc++; } } ``` 4. (å¯é€‰ï¼‰åœ¨è¿è¡Œé˜¶æ®µè¾“出轮转ä¸ï¼Œä½¿ç”¨æ¥éª¤3获å–的时域层级信æ¯ï¼Œè‡ªé€‚åº”ä¼ è¾“æˆ–è‡ªé€‚åº”è§£ç 。 基于获å–的时域å¯åˆ†å±‚ç æµå’Œå¯¹åº”的层级信æ¯ï¼Œå¼€å‘者å¯é€‰æ‹©éœ€è¦çš„å±‚çº§è¿›è¡Œä¼ è¾“ï¼Œæˆ–æºå¸¦è‡³å¯¹ç«¯è‡ªé€‚应选帧解ç 。 ## 长期å‚考帧特性(Feature_Long-Term_Reference) ### 接å£ä»‹ç» 长期å‚考帧特性æä¾›å¸§çº§çµæ´»çš„å‚考关系é…ç½®ã€‚é€‚ç”¨äºŽçµæ´»å’Œå¤æ‚的时域分层结构。 | é…ç½®å‚æ•° | è¯ä¹‰ | | -------- | ---------------------------- | | OH_MD_KEY_VIDEO_ENCODER_LTR_FRAME_COUNT | 长期å‚è€ƒå¸§ä¸ªæ•°å‚æ•° | | OH_MD_KEY_VIDEO_ENCODER_PER_FRAME_MARK_LTR | 当å‰å¸§æ ‡è®°ä¸ºLTR帧 | | OH_MD_KEY_VIDEO_ENCODER_PER_FRAME_USE_LTR | 当å‰å¸§å‚考的LTR帧的POCå· | - **长期å‚è€ƒå¸§ä¸ªæ•°å‚æ•°ï¼š** 在é…置阶段é…置,应å°äºŽç‰äºŽæŸ¥è¯¢åˆ°çš„æœ€å¤§æ”¯æŒæ•°ç›®ï¼ŒæŸ¥è¯¢æ–¹å¼è¯¦è§å¼€å‘指导。 - **当å‰å¸§æ ‡è®°ä¸ºLTR帧:** BLå±‚æ ‡è®°ä¸ºLTR,被跳跃å‚考的ELå±‚ä¹Ÿæ ‡è®°ä¸ºLTR。 - **当å‰å¸§å‚考的LTR帧的POCå·ï¼š** 如当å‰å¸§éœ€è¦è·³è·ƒå‚考å‰é¢å·²è¢«æ ‡è®°ä¸ºLTR帧的POCå·ã€‚ 使用举例,实现[时域å¯åˆ†å±‚视频编ç 介ç»](#时域å¯åˆ†å±‚视频编ç 介ç»)ä¸çš„4层时域分层结构的é…置如下: 1. 在é…置阶段,将`OH_MD_KEY_VIDEO_ENCODER_LTR_FRAME_COUNT` é…置为5。 2. 在è¿è¡Œé˜¶æ®µè¾“入轮转ä¸ï¼ŒæŒ‰å¦‚下表所示éšå¸§é…ç½®LTRç›¸å…³å‚æ•°ï¼Œä¸‹è¡¨ä¸`\`表示ä¸åšé…置。 | é…ç½®\POC | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | | -------- |---|---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|----| | MARK_LTR | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | | USE_LTR | \ | \ | 0 | \ | 0 | \ | 4 | \ | 0 | \ | 8 | \ | 8 | \ | 12 | 0 | 8 | ### 开呿Œ‡å¯¼ åŸºç¡€ç¼–ç æµç¨‹è¯·å‚考[视频编ç 开呿Œ‡å¯¼](video-encoding.md),下é¢ä»…针与基础视频编ç 过程ä¸å˜åœ¨çš„区别åšå…·ä½“说明。 1. 在åˆå§‹é˜¶æ®µåˆ›å»ºç¼–ç å®žä¾‹æ—¶ï¼Œæ ¡éªŒå½“å‰è§†é¢‘ç¼–ç å™¨æ˜¯å¦æ”¯æŒLTR特性。 ```c++ constexpr int32_t NEEDED_LTR_COUNT = 5; bool isSupported = false; int32_t supportedLTRCount = 0; // 1.1 获å–对应编ç å™¨èƒ½åŠ›å¥æŸ„,æ¤å¤„以H.264为例 OH_AVCapability *cap = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true); // 1.2 é€šè¿‡ç‰¹æ€§èƒ½åŠ›æŸ¥è¯¢æŽ¥å£æ ¡éªŒæ˜¯å¦æ”¯æŒLTR特性 isSupported = OH_AVCapability_IsFeatureSupported(cap, VIDEO_ENCODER_LONG_TERM_REFERENCE); // 1.3 确定支æŒçš„LTRæ•°ç›® if (isSupported) { OH_AVFormat *properties = OH_AVCapability_GetFeatureProperties(cap, VIDEO_ENCODER_LONG_TERM_REFERENCE); OH_AVFormat_GetIntValue(properties, OH_FEATURE_PROPERTY_KEY_VIDEO_ENCODER_MAX_LTR_FRAME_COUNT, &supportedLTRCount); OH_AVFormat_Destroy(properties); // 1.4 判æ–LTRæ˜¯å¦æ»¡è¶³ç»“构需求 isSupported = supportedLTRCount >= NEEDED_LTR_COUNT; } ``` 若支æŒï¼Œä¸”支æŒçš„LTRæ•°ç›®æ»¡è¶³è‡ªèº«ç æµç»“构需求,则å¯ä»¥ä½¿èƒ½LTR特性。 2. 在é…ç½®ä¹‹å‰æ³¨å†Œå›žè°ƒæ—¶ï¼Œæ³¨å†Œéšå¸§é€šè·¯å›žè°ƒã€‚ Buffer输入模å¼ç¤ºä¾‹ï¼š ```c++ // 2.1 ç¼–ç 输入回调OH_AVCodecOnNeedInputBuffer实现 static void OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) { // 输入帧buffer对应的index,é€å…¥InIndexQueue队列 // 输入帧的数æ®bufferé€å…¥InBufferQueue队列 // æ•°æ®å¤„ç†ï¼Œè¯·å‚考: // - 写入编ç ç æµ // - 通知编ç å™¨ç æµç»“æŸ // - éšå¸§å‚数写入 OH_AVFormat *format = OH_AVBuffer_GetParameter(buffer); OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_PER_FRAME_MARK_LTR, 1); OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_PER_FRAME_USE_LTR, 4); OH_AVBuffer_SetParameter(buffer, format); OH_AVFormat_Destroy(format); // 通知编ç 器bufferè¾“å…¥å®Œæˆ OH_VideoEncoder_PushInputBuffer(codec, index); } // 2.2 ç¼–ç 输出回调OH_AVCodecOnNewOutputBuffer实现 static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) { // 完æˆå¸§buffer对应的index,é€å…¥outIndexQueue队列 // 完æˆå¸§çš„æ•°æ®bufferé€å…¥outBufferQueue队列 // æ•°æ®å¤„ç†ï¼Œè¯·å‚考: // - 释放编ç 帧 // - 记录POCå’ŒLTR生效情况 } // 2.3 注册数æ®å›žè°ƒ OH_AVCodecCallback cb; cb.onNeedInputBuffer = OnNeedInputBuffer; cb.onNewOutputBuffer = OnNewOutputBuffer; OH_VideoEncoder_RegisterCallback(codec, cb, nullptr); ``` Surface输入模å¼ç¤ºä¾‹ï¼š ```c++ // 2.1 ç¼–ç è¾“å…¥å‚æ•°å›žè°ƒOH_VideoEncoder_OnNeedInputParameter实现 static void OnNeedInputParameter(OH_AVCodec *codec, uint32_t index, OH_AVFormat *parameter, void *userData) { // 输入帧buffer对应的index,é€å…¥InIndexQueue队列 // 输入帧的数æ®avformaté€å…¥InFormatQueue队列 // æ•°æ®å¤„ç†ï¼Œè¯·å‚考: // - 写入编ç ç æµ // - 通知编ç å™¨ç æµç»“æŸ // - éšå¸§å‚数写入 OH_AVFormat_SetIntValue(parameter, OH_MD_KEY_VIDEO_ENCODER_PER_FRAME_MARK_LTR, 1); OH_AVFormat_SetIntValue(parameter, OH_MD_KEY_VIDEO_ENCODER_PER_FRAME_USE_LTR, 4); // 通知编ç 器éšå¸§å‚æ•°é…ç½®è¾“å…¥å®Œæˆ OH_VideoEncoder_PushInputParameter(codec, index); } // 2.2 ç¼–ç 输出回调OH_AVCodecOnNewOutputBuffer实现 static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) { // 完æˆå¸§buffer对应的index,é€å…¥outIndexQueue队列 // 完æˆå¸§çš„æ•°æ®bufferé€å…¥outBufferQueue队列 // æ•°æ®å¤„ç†ï¼Œè¯·å‚考: // - 释放编ç 帧 // - 记录POCå’ŒLTR生效情况 } // 2.3 注册数æ®å›žè°ƒ OH_AVCodecCallback cb; cb.onNewOutputBuffer = OnNewOutputBuffer; OH_VideoEncoder_RegisterCallback(codec, cb, nullptr); // 2.4 注册éšå¸§å‚数回调 OH_VideoEncoder_OnNeedInputParameter inParaCb = OnNeedInputParameter; OH_VideoEncoder_RegisterParameterCallback(codec, inParaCb, nullptr); ``` 3. 在é…置阶段,é…ç½®åŒæ—¶å˜åœ¨LTR最大数目。 ```c++ constexpr int32_t TGOP_SIZE = 3; // 3.1 创建é…置用临时AVFormat OH_AVFormat *format = OH_AVFormat_Create(); // 3.2 填充使能LTR个数键值对 OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_LTR_FRAME_COUNT, NEEDED_LTR_COUNT); // 3.3 傿•°é…ç½® int32_t ret = OH_VideoEncoder_Configure(videoEnc, format); if (ret != AV_ERR_OK) { // å¼‚å¸¸å¤„ç† } // 3.4 é…置完æˆåŽé”€æ¯ä¸´æ—¶AVFormat OH_AVFormat_Destroy(format); ``` 4. (å¯é€‰ï¼‰åœ¨è¿è¡Œé˜¶æ®µè¾“出轮转ä¸ï¼ŒèŽ·å–ç æµå¯¹åº”时域层级信æ¯ã€‚ åŒå…¨å±€æ—¶åŸŸåˆ†å±‚特性。 å› åœ¨è¾“å…¥è½®è½¬æœ‰é…ç½®LTR傿•°ï¼Œä¹Ÿå¯åœ¨è¾“入轮转ä¸ä¸è®°å½•ï¼Œè¾“å‡ºè½®è½¬ä¸æ‰¾åˆ°å¯¹åº”çš„è¾“å…¥å‚æ•°ã€‚ 5. (å¯é€‰ï¼‰åœ¨è¿è¡Œé˜¶æ®µè¾“出轮转ä¸ï¼Œä½¿ç”¨æ¥éª¤4获å–的时域层级信æ¯ï¼Œè‡ªé€‚åº”ä¼ è¾“æˆ–è‡ªé€‚åº”è§£ç 。 åŒå…¨å±€æ—¶åŸŸåˆ†å±‚特性。