1# 获取支持的编解码能力
2
3因来源不同、编解码器协议不同以及设备在编解码能力部署上的不同,在不同设备上开发者可用的编解码器及其能力是有差异的。
4
5为确保编解码行为符合预期,开发者应提前通过音视频编解码能力系列接口查询系统支持的音视频编解码器及其关联的能力参数,找到符合开发场景需求的编解码器,并正确配置编解码参数。
6
7## 通用开发指导
81. 在CMake脚本中链接动态库。
9
10   ``` cmake
11   target_link_libraries(sample PUBLIC libnative_media_codecbase.so)
12   target_link_libraries(sample PUBLIC libnative_media_core.so)
13   target_link_libraries(sample PUBLIC libnative_media_venc.so)
14   target_link_libraries(sample PUBLIC libnative_media_vdec.so)
15   ```
16   > **说明:**
17   >
18   > 上述'sample'字样仅为示例,此处由开发者根据实际工程目录自定义。
19   >
20
212. 添加头文件。
22
23   ```c++
24   #include <multimedia/player_framework/native_avcapability.h>
25   #include <multimedia/player_framework/native_avcodec_base.h>
26   #include <multimedia/player_framework/native_avformat.h>
27   #include <multimedia/player_framework/native_avcodec_videoencoder.h>
28   #include <multimedia/player_framework/native_avcodec_videodecoder.h>
29   ```
30
313. 获得音视频编解码能力实例。
32
33   支持两种获取音视频编解码能力实例的方式:
34
35   方式一:通过`OH_AVCodec_GetCapability`获取框架推荐的音视频编解码器能力实例。与`OH_XXX_CreateByMime`系列接口框架推荐策略一致。
36   ```c++
37   // 获取系统推荐的音频AAC解码器能力实例
38   OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_AUDIO_AAC, false);
39   ```
40
41   方式二:通过`OH_AVCodec_GetCapabilityByCategory`获取指定软件或硬件的编解码能力实例。
42   ```c++
43   // 获取指定硬件的视频AVC编码器能力实例
44   OH_AVCapability *capability = OH_AVCodec_GetCapabilityByCategory(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true, HARDWARE);
45   ```
46   若获取能力实例成功,则可继续向下执行。开发者无需关注该实例的回收问题,框架会自行回收。
47
484. 按需调用相应查询接口,详细的API说明请参考[API文档](../../reference/apis-avcodec-kit/_a_v_capability.md)。
49
50## 场景化开发指导
51基于开发者可能遇到特定场景,举例说明能力查询接口使用方法。
52
53### 创建指定名称的编解码器
54
55如系统内存在相同MIME类型的多个编码器或多个解码器。使用`OH_XXX_CreateByMime`系列接口只能创建系统推荐的特定编解码器。若需创建其他编解码器,开发者可先获取编解码器名称,再通过`OH_XXX_CreateByName`系列接口创建指定名称的编解码器。
56
57| 接口     | 功能描述                         |
58| -------- | -------------------------------- |
59| OH_AVCapability_GetName     | 获取能力实例对应编解码器的名称 |
60
61H.264软件解码器和H.264硬件解码器共存时,创建H.264软件解码器示例:
62```c++
63// 1. 获取H.264软件解码器能力实例
64OH_AVCapability *capability = OH_AVCodec_GetCapabilityByCategory(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false, SOFTWARE);
65if (capability != nullptr) {
66   // 2. 获取H.264软件解码器名称
67   const char *codecName = OH_AVCapability_GetName(capability);
68   // 3. 创建H.264软件解码器实例
69   OH_AVCodec *videoDec = OH_VideoDecoder_CreateByName(codecName);
70}
71```
72
73### 针对软硬件类别差异化配置编解码器参数
74
75软件编解码器和硬件编解码器定义如下:
76
77* **软件编解码器:** 指在CPU上进行编解码工作的编解码器,能力可灵活迭代,相比硬件编解码器具有更好的兼容性,更好的协议和规格扩展能力。
78
79* **硬件编解码器:** 指在专有硬件上进行编解码工作的编解码器,其特点是已在硬件平台硬化,能力随硬件平台迭代。相比软件编解码器具有更好的功耗、耗时和吞吐表现,同时能降低CPU负载。
80
81基于上述软件编解码器和硬件编解码器的特点,在硬件编解码器满足要求的时候,优先使用硬件编解码器,否则使用软件编解码器。开发者可基于软件还是硬件类别差异化配置编解码参数。
82
83| 接口     | 功能描述                         |
84| -------- | -------------------------------- |
85| OH_AVCapability_IsHardware  | 确认能力实例对应的编解码器是否是硬件的 |
86
87视频编码,软硬件差异化配置帧率示例:
88
89```c++
90// 1. 确认推荐的H.264编码器的软硬件类别
91OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
92bool isHardward = OH_AVCapability_IsHardware(capability);
93// 2. 基于软硬件类别差异化配置
94OH_AVCodec *videoEnc = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);
95OH_AVFormat *format = OH_AVFormat_CreateVideoFormat(OH_AVCODEC_MIMETYPE_VIDEO_AVC, 1920, 1080);
96double frameRate = isHardward ? 60.0 : 30.0;
97if (!OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, frameRate)) {
98   // 异常处理
99}
100if (OH_VideoEncoder_Configure(videoEnc, format) != AV_ERR_OK) {
101   // 异常处理
102}
103OH_AVFormat_Destroy(format);
104```
105
106### 创建多路编解码器
107
108部分业务场景涉及创建多路编解码器,基于各类资源的限制,某一编解码器的实例数是有限的,不能无限制创建。
109
110| 接口     | 功能描述                         |
111| -------- | -------------------------------- |
112| OH_AVCapability_GetMaxSupportedInstances  | 获取能力实例对应编解码器可同时运行的最大实例数,实际能成功创建的数目还受系统其他资源的约束 |
113
114优先创建硬件解码器实例,不够时再创建软件解码器实例,示例如下:
115
116```c++
117constexpr int32_t NEEDED_VDEC_NUM = 8;
118// 1. 创建硬件解码器实例
119OH_AVCapability *capHW = OH_AVCodec_GetCapabilityByCategory(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false, HARDWARE);
120int32_t vDecNumHW = min(OH_AVCapability_GetMaxSupportedInstances(capHW), NEEDED_VDEC_NUM);
121int32_t createdVDecNum = 0;
122for (int i = 0; i < vDecNumHW; i++) {
123   OH_AVCodec *videoDec = OH_VideoDecoder_CreateByName(OH_AVCapability_GetName(capHW));
124   if (videoDec != nullptr) {
125      // 维护在videoDecVector中
126      createdVDecNum++;
127   }
128}
129if (createdVDecNum < NEEDED_VDEC_NUM) {
130   // 2. 不够时,创建软件解码器实例
131   OH_AVCapability *capSW = OH_AVCodec_GetCapabilityByCategory(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false, SOFTWARE);
132   int32_t vDecNumSW = min(OH_AVCapability_GetMaxSupportedInstances(capSW), NEEDED_VDEC_NUM - createdVDecNum);
133   for (int i = 0; i < vDecNumSW; i++) {
134      OH_AVCodec *videoDec = OH_VideoDecoder_CreateByName(OH_AVCapability_GetName(capSW));
135      if (videoDec != nullptr) {
136         // 维护在videoDecVector中
137         createdVDecNum++;
138      }
139   }
140}
141```
142
143### 控制编码质量
144
145当前提供三种码控模式供开发者选用,分别是恒定码率(CBR)码控模式、动态码率(VBR)码控模式,以及恒定质量(CQ)码控模式。对于CBR和VBR码控模式,编码质量由码率参数决定。对于CQ码控模式,编码质量由质量参数决定。
146
147| 接口     | 功能描述                         |
148| -------- | ---------------------------- |
149| OH_AVCapability_IsEncoderBitrateModeSupported  | 确认当前编解码器是否支持给定的码控模式 |
150| OH_AVCapability_GetEncoderBitrateRange     | 获取当前编解码器支持的码率范围,在CBR和VBR码控模式下使用|
151| OH_AVCapability_GetEncoderQualityRange  | 获取当前编解码器支持的质量范围,在CQ码控模式下使用  |
152
153CBR和VBR码控模式示例如下:
154
155```c++
156OH_BitrateMode bitrateMode = BITRATE_MODE_CBR;
157int32_t bitrate = 3000000;
158OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
159if (capability == nullptr) {
160   // 异常处理
161}
162// 1. 确认待配置码控模式是否支持
163bool isSupported = OH_AVCapability_IsEncoderBitrateModeSupported(capability, bitrateMode);
164if (!isSupported) {
165   // 异常处理
166}
167// 2. 获取码率范围,判断待配置码率参数是否在范围内
168OH_AVRange bitrateRange = {-1, -1};
169int32_t ret = OH_AVCapability_GetEncoderBitrateRange(capability, &bitrateRange);
170if (ret != AV_ERR_OK || bitrateRange.maxVal <= 0) {
171   // 异常处理
172}
173if (bitrate > bitrateRange.maxVal || bitrate < bitrateRange.minVal) {
174   // 3.(可选)调整待配置码率参数
175}
176// 4. 配置编码参数
177OH_AVCodec *videoEnc = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);
178OH_AVFormat *format = OH_AVFormat_CreateVideoFormat(OH_AVCODEC_MIMETYPE_VIDEO_AVC, 1920, 1080);
179if (OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, bitrateMode) &&
180   OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, static_cast<int64_t>(bitrate)) == false) {
181   // 异常处理
182}
183if (OH_VideoEncoder_Configure(videoEnc, format) != AV_ERR_OK) {
184   // 异常处理
185}
186OH_AVFormat_Destroy(format);
187```
188
189CQ码控模式示例如下:
190
191```c++
192OH_BitrateMode bitrateMode = BITRATE_MODE_CQ;
193int32_t quality = 0;
194OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
195if (capability == nullptr) {
196   // 异常处理
197}
198// 1. 确认待配置码控模式是否支持
199bool isSupported = OH_AVCapability_IsEncoderBitrateModeSupported(capability, bitrateMode);
200if (!isSupported) {
201   // 异常处理
202}
203// 2. 获取质量范围,判断待配置质量参数是否在范围内
204OH_AVRange qualityRange = {-1, -1};
205int32_t ret = OH_AVCapability_GetEncoderQualityRange(capability, &qualityRange);
206if (ret != AV_ERR_OK || qualityRange.maxVal < 0) {
207   // 异常处理
208}
209if (quality > qualityRange.maxVal || quality < qualityRange.minVal) {
210   // 3.(可选)调整待配置质量参数
211}
212// 5. 配置编码参数
213OH_AVCodec *videoEnc = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);
214OH_AVFormat *format = OH_AVFormat_CreateVideoFormat(OH_AVCODEC_MIMETYPE_VIDEO_AVC, 1920, 1080);
215if (OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, bitrateMode) &&
216   OH_AVFormat_SetIntValue(format, OH_MD_KEY_QUALITY, quality) == false) {
217   // 异常处理
218}
219if (OH_VideoEncoder_Configure(videoEnc, format) != AV_ERR_OK) {
220   // 异常处理
221}
222OH_AVFormat_Destroy(format);
223```
224
225### 查询编解码器支持复杂度范围
226
227复杂度等级决定了编解码器使用的工具的数目,仅部分编解码器支持。
228
229| 接口     | 功能描述                         |
230| -------- | ---------------------------- |
231| OH_AVCapability_GetEncoderComplexityRange | 获取当前编解码器支持的复杂度范围 |
232
233```c++
234OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_AUDIO_AAC, true);
235if (capability == nullptr) {
236   // 异常处理
237}
238// 确认支持的编码复杂度范围
239OH_AVRange complexityRange = {-1, -1};
240int32_t ret = OH_AVCapability_GetEncoderComplexityRange(capability, &complexityRange);
241```
242
243### 设置正确的音频编解码参数
244
245在音频编解码场景中,有采样率、通道数以及码率(仅音频编码)等参数需要查询后设置。
246
247| 接口     | 功能描述                         |
248| -------- | ---------------------------- |
249| OH_AVCapability_GetAudioSupportedSampleRates     | 获取当前音频编解码器支持的采样率范围 |
250| OH_AVCapability_GetAudioChannelCountRange  | 获取当前音频编解码器支持的通道数范围 |
251| OH_AVCapability_GetEncoderBitrateRange     | 获取当前编码器支持的码率范围 |
252
253音频编码场景,确认并设置正确的编码的参数,示例如下:
254
255```c++
256int32_t sampleRate = 44100;
257int32_t channelCount = 2;
258int32_t bitrate = 261000;
259OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_AUDIO_AAC, true);
260if (capability == nullptr) {
261   // 异常处理
262}
263// 1. 确认待配置采样率是否支持
264const int32_t *sampleRates = nullptr;
265uint32_t sampleRateNum = 0;
266int32_t ret = OH_AVCapability_GetAudioSupportedSampleRates(capability, &sampleRates, &sampleRateNum);
267if (ret != AV_ERR_OK || sampleRates == nullptr || sampleRateNum == 0) {
268   // 异常处理
269}
270bool isMatched = false;
271for (int i = 0; i < sampleRateNum; i++) {
272   if (sampleRates[i] == sampleRate) {
273      isMatched = true;
274   }
275}
276if (!isMatched) {
277   // 2.(可选)调整待配置采样率
278}
279// 3. 获取通道数范围,判断待配置通道数参数是否在范围内
280OH_AVRange channelRange = {-1, -1};
281ret = OH_AVCapability_GetAudioChannelCountRange(capability, &channelRange);
282if (ret != AV_ERR_OK || channelRange.maxVal <= 0) {
283   // 异常处理
284}
285if (channelCount > channelRange.maxVal || channelCount < channelRange.minVal ) {
286   // 4.(可选)调整待配置通道数
287}
288// 5. 获取码率范围,判断待配置码率参数是否在范围内
289OH_AVRange bitrateRange = {-1, -1};
290ret = OH_AVCapability_GetEncoderBitrateRange(capability, &bitrateRange);
291if (ret != AV_ERR_OK || bitrateRange.maxVal <= 0) {
292   // 异常处理
293}
294if (bitrate > bitrateRange.maxVal || bitrate < bitrateRange.minVal ) {
295   // 7.(可选)调整待配置码率值
296}
297// 8. 配置编码参数
298OH_AVCodec *audioEnc = OH_AudioEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_AUDIO_AAC);
299OH_AVFormat *format = OH_AVFormat_Create();
300if (OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, sampleRate) &&
301   OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, channelCount) &&
302   OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, static_cast<int64_t>(bitrate)) == false) {
303   // 异常处理
304}
305if (OH_AudioEncoder_Configure(audioEnc, format) != AV_ERR_OK) {
306   // 异常处理
307}
308OH_AVFormat_Destroy(format);
309```
310
311### 查询编解码档次和级别支持情况
312
313编解码标准由很多编码工具构成,能应对多种编码场景。对于特定应用场景,并非需要所有的工具,编解码标准按档次确定多种编码工具的开启与关闭情况。以H.264为例,存在基本档次、主档次和高档次,参考[OH_AVCProfile](../../reference/apis-avcodec-kit/_codec_base.md#oh_avcprofile-1)。
314
315级别是对编解码器所需的处理能力和储存空间的划分。以H.264为例,存在1到6.2的20个级别,参考[OH_AVCLevel](../../reference/apis-avcodec-kit/_codec_base.md#oh_avclevel-1)。
316
317| 接口     | 功能描述                         |
318| -------- | ---------------------------- |
319| OH_AVCapability_GetSupportedProfiles                    | 获取当前编解码器支持的档次 |
320| OH_AVCapability_GetSupportedLevelsForProfile            | 获取当前编解码器在给定档次的情况下支持的等级信息 |
321| OH_AVCapability_AreProfileAndLevelSupported             | 确认当前编解码器是否支持特定的档次和等级组合 |
322
323确认待配置档次是否支持,并查询能支持的级别,示例如下:
324
325```c++
326OH_AVCProfile profile = AVC_PROFILE_MAIN;
327OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
328if (capability == nullptr) {
329   // 异常处理
330}
331// 1. 确认待配置档次是否支持
332const int32_t *profiles = nullptr;
333uint32_t profileNum = 0;
334int32_t ret = OH_AVCapability_GetSupportedProfiles(capability, &profiles, &profileNum);
335if (ret != AV_ERR_OK || profiles == nullptr || profileNum == 0) {
336   // 异常处理
337}
338bool isMatched = false;
339for (int i = 0; i < profileNum; i++) {
340   if (profiles[i] == profile) {
341      isMatched = true;
342   }
343}
344// 2. 查询待配置档次能支持的级别范围
345const int32_t *levels = nullptr;
346uint32_t levelNum = 0;
347ret = OH_AVCapability_GetSupportedLevelsForProfile(capability, profile, &levels, &levelNum);
348if (ret != AV_ERR_OK || levels == nullptr || levelNum == 0) {
349   // 异常处理
350}
351OH_AVCLevel maxLevel = static_cast<OH_AVCLevel>(levels[levelNum -1]);
352// 3.(可选)基于支持的最大级别做业务逻辑区分
353switch (maxLevel) {
354   case AVC_LEVEL_31:
355      // level 3.1-3.2,宽、高最大可配1280x720
356      break;
357   case AVC_LEVEL_51:
358      // level 4.0以上,宽、高最大可配1920x1080
359      break;
360   default:
361      // 报错,不做编码
362}
363// 4. 配置档次参数
364OH_AVCodec *videoEnc = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);
365OH_AVFormat *format = OH_AVFormat_CreateVideoFormat(OH_AVCODEC_MIMETYPE_VIDEO_AVC, 1920, 1080);
366if (!OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, profile)) {
367   // 异常处理
368}
369if (OH_VideoEncoder_Configure(videoEnc, format) != AV_ERR_OK) {
370   // 异常处理
371}
372OH_AVFormat_Destroy(format);
373```
374
375已知需要的编码档次和级别组合,直接查询支持情况示例如下:
376
377```c++
378// 1. 获取H.264编码器能力实例
379OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
380if (capability == nullptr) {
381   // 异常处理
382}
383// 2. 查询编码档次和级别是否支持
384bool isSupported = OH_AVCapability_AreProfileAndLevelSupported(capability, AVC_PROFILE_MAIN, AVC_LEVEL_51);
385```
386
387### 设置正确的视频宽高
388
389视频编解码器对宽高存在对齐约束,如主流编解码器默认编解码像素格式为YUV420系列中的,会对UV分量下采样,在此情况下视频编解码的宽高至少要按2对齐。此外还有其他因素可能导致更加严格的对齐约束。
390
391视频编解码的宽高不仅会受帧级编解码能力限制,同时也会受协议中级别对帧级能力的限制。以H.264为例,AVC_LEVEL_51限定最大每帧宏块数目为36864。
392
393给定图像宽和高,求最大帧率的公式如下, 其中*MaxMBsPerFrameLevelLimits*是编解码器能支持的最大级别在协议中限定的最大每帧宏块数, *MaxMBsPerFrameSubmit*是编解码器上报能支持的最大每帧宏块数,实际能力取两者交集。
394
395![](figures/formula-maxmbsperframe.png)
396
397| 接口     | 功能描述                         |
398| -------- | ---------------------------- |
399| OH_AVCapability_GetVideoWidthAlignment     | 获取当前视频编解码器的宽对齐 |
400| OH_AVCapability_GetVideoHeightAlignment    | 确认当前视频编解码器的高对齐 |
401| OH_AVCapability_GetVideoWidthRange             | 获取当前视频编解码器支持的宽的范围 |
402| OH_AVCapability_GetVideoHeightRange            | 获取当前视频编解码器支持的高的范围 |
403| OH_AVCapability_GetVideoWidthRangeForHeight    | 获取当前视频编解码器在给定高情况下的宽的范围 |
404| OH_AVCapability_GetVideoHeightRangeForWidth    | 获取当前视频编解码器在给定宽情况下的高的范围 |
405| OH_AVCapability_IsVideoSizeSupported           | 确认当前视频编解码器是否支持给定的宽高组合 |
406
407已知视频高和视频宽,校验是否支持,示例如下:
408
409```c++
410int32_t width = 1920;
411int32_t height = 1080;
412OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
413// 1. 确认视频宽高是否支持
414bool isSupported = OH_AVCapability_IsVideoSizeSupported(capability, width, height);
415if (!isSupported) {
416   // 2. (可选) 按已知视频高或已知视频宽查询详细限制,并调整
417}
418```
419
420若遇到基于已知视频高和视频宽校验不支持或配置失败,可用下列示意的多种方式尝试找到正确的视频宽高范围。
421
422已知视频宽,找到正确的尺寸配置,示例如下:
423
424```c++
425int32_t width = 1920;
426OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
427// 1. 确认视频宽符合宽对齐要求
428int32_t widthAlignment = 0;
429int32_t ret = OH_AVCapability_GetVideoWidthAlignment(capability, &widthAlignment);
430if (ret != AV_ERR_OK || widthAlignment <= 0) {
431   // 异常处理
432} else if (width % widthAlignment != 0) {
433   // 2. (可选) 对齐视频宽
434   width = (width + widthAlignment - 1) / widthAlignment * widthAlignment;
435}
436// 3. 确认视频宽处在可支持宽范围内
437OH_AVRange widthRange = {-1, -1};
438ret = OH_AVCapability_GetVideoWidthRange(capability, &widthRange);
439if (ret != AV_ERR_OK || widthRange.maxVal <= 0) {
440   // 异常处理
441} else if (width < widthRange.minVal || width > widthRange.maxVal) {
442   // 4. (可选) 调整视频宽
443   width = min(max(width, widthRange.minVal), widthRange.maxVal);
444}
445// 5. 基于视频宽,获取可选视频高的范围
446OH_AVRange heightRange = {-1, -1};
447ret = OH_AVCapability_GetVideoHeightRangeForWidth(capability, width, &heightRange);
448if (ret != AV_ERR_OK || heightRange.maxVal <= 0) {
449   // 异常处理
450}
451// 6. 从可选高度范围中挑选合适的高度配置
452```
453
454已知视频高,找到正确的尺寸配置,示例如下:
455
456```c++
457int32_t height = 1080;
458OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
459// 1. 确认视频高符合高对齐要求
460int32_t heightAlignment = 0;
461int32_t ret = OH_AVCapability_GetVideoHeightAlignment(capability, &heightAlignment);
462if (ret != AV_ERR_OK || heightAlignment <= 0) {
463   // 异常处理
464} else if (height % heightAlignment != 0) {
465   // 2. (可选) 对齐视频高
466   height = (height + heightAlignment - 1) / heightAlignment * heightAlignment;
467}
468// 3. 确认视频高处在可支持高范围内
469OH_AVRange heightRange = {-1, -1};
470ret = OH_AVCapability_GetVideoHeightRange(capability, &heightRange);
471if (ret != AV_ERR_OK || heightRange.maxVal <= 0) {
472   // 异常处理
473} else if (height < heightRange.minVal || height > heightRange.maxVal) {
474   // 4. (可选) 调整视频高
475   height = min(max(height, heightRange.minVal), heightRange.maxVal);
476}
477// 5. 基于视频高,获取可选视频宽的范围
478OH_AVRange widthRange = {-1, -1};
479ret = OH_AVCapability_GetVideoWidthRangeForHeight(capability, height, &widthRange);
480if (ret != AV_ERR_OK || widthRange.maxVal <= 0) {
481   // 异常处理
482}
483// 6. 从可选宽度范围中挑选合适的宽度配置
484```
485
486### 设置正确的视频帧率
487
488视频编解码的帧率不仅会受编解码器秒级编解码能力限制,同时也会受协议中级别对秒级能力的限制。以H.264为例,AVC_LEVEL_51限定最大每秒宏块数目为983040。
489
490给定图像宽和高,求最大帧率的公式如下, 其中*MaxMBsPerSecondLevelLimits*是编解码器能支持的最大级别在协议中限定的最大每秒宏块数, *MaxMBsPerSecondSubmit*是编解码器上报能支持的最大每秒宏块数,实际能力取两者交集。
491
492![](figures/formula-maxmbspersecond.png)
493
494| 接口     | 功能描述                         |
495| -------- | ---------------------------- |
496| OH_AVCapability_GetVideoFrameRateRange             | 获取当前视频编解码器支持的帧率的范围 |
497| OH_AVCapability_GetVideoFrameRateRangeForSize      | 获取当前视频编解码器在给定图像尺寸情况下的帧率的范围 |
498| OH_AVCapability_AreVideoSizeAndFrameRateSupported  | 检查视频编解码器是否支持视频大小和帧率的特定组合 |
499
500有需求的帧率目标,确认帧率是否在可选范围内,示例如下:
501
502```c++
503int32_t frameRate = 120;
504OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
505// 1. 获取支持的帧率范围
506OH_AVRange frameRateRange = {-1, -1};
507int32_t ret = OH_AVCapability_GetVideoFrameRateRange(capability, &frameRateRange);
508if (ret != AV_ERR_OK || frameRateRange.maxVal <= 0) {
509   // 异常处理
510}
511// 2. 判断是否在可选帧率范围内
512bool isSupported = frameRate >= frameRateRange.minVal && frameRate <= frameRateRange.maxVal;
513```
514
515基于待配置的尺寸找到合适的帧率配置,示例代码如下:
516
517```c++
518constexpr int32_t width = 1920;
519constexpr int32_t height = 1080;
520int32_t frameRate = 120;
521OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
522// 1. 确认待配置尺寸是否能达到理想帧率
523bool isSupported = OH_AVCapability_AreVideoSizeAndFrameRateSupported(capability, width, height, frameRate);
524if (!isSupported) {
525   // 2. 基于待配置视频尺寸,查询支持的帧率范围,并基于查询到的帧率调整待配置帧率
526   OH_AVRange frameRateRange = {-1, -1};
527   int32_t ret = OH_AVCapability_GetVideoFrameRateRangeForSize(capability, width, height, &frameRateRange);
528   if (ret != AV_ERR_OK || frameRateRange.maxVal <= 0) {
529      // 异常处理
530   }
531   frameRate = min(max(frameRate, frameRateRange.minVal), frameRateRange.maxVal);
532}
533
534// 3. 配置尺寸和帧率参数
535OH_AVCodec *videoEnc = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);
536OH_AVFormat *format = OH_AVFormat_CreateVideoFormat(OH_AVCODEC_MIMETYPE_VIDEO_AVC, width, height);
537if (!OH_AVFormat_SetIntValue(format, OH_MD_KEY_FRAME_RATE, frameRate)) {
538   // 异常处理
539}
540if (OH_VideoEncoder_Configure(videoEnc, format) != AV_ERR_OK) {
541   // 异常处理
542}
543OH_AVFormat_Destroy(format);
544```
545
546### 设置正确的视频像素格式信息
547
548视频像素格式指示的编码输入图像或解码输出图像的像素排布方式,参考[OH_AVPixelFormat](../../reference/apis-avcodec-kit/_core.md#oh_avpixelformat-1)。
549
550| 接口     | 功能描述                         |
551| -------- | ---------------------------- |
552| OH_AVCapability_GetVideoSupportedPixelFormats             | 获取当前视频编解码器支持的像素格式 |
553
554```c++
555constexpr OH_AVPixelFormat DEFAULT_PIXELFORMAT = AV_PIXEL_FORMAT_NV12;
556OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
557if (capability == nullptr) {
558   // 异常处理
559}
560// 1. 获取当前视频编解码器支持的像素格式
561const int32_t *pixFormats = nullptr;
562uint32_t pixFormatNum = 0;
563int32_t ret = OH_AVCapability_GetVideoSupportedPixelFormats(capability, &pixFormats, &pixFormatNum);
564if (ret != AV_ERR_OK || pixFormats == nullptr || pixFormatNum == 0) {
565   // 异常处理
566}
567// 2. 校验是否支持对应像素格式
568bool isMatched = false;
569for (int i = 0; i < pixFormatNum; i++) {
570   if (pixFormats[i] == DEFAULT_PIXELFORMAT) {
571      isMatched = true;
572   }
573}
574if (!isMatched) {
575   // 3. 替换其他像素格式输入或选择其他编解码器
576}
577```
578
579### 查询编解码特性支持情况并获取特性属性信息
580
581编解码特性是指仅在特定编解码场景中使用的可选特性,参考[OH_AVCapabilityFeature](../../reference/apis-avcodec-kit/_a_v_capability.md#oh_avcapabilityfeature-1)。
582| 接口     | 功能描述                         |
583| -------- | ---------------------------- |
584| OH_AVCapability_IsFeatureSupported              | 确认当前编解码器是否支持给定的特性 |
585| OH_AVCapability_GetFeatureProperties            | 获取当前编码器支持的指定特性的属性,仅部分特性存在属性信息 |
586
587查询H.264编码器是否支持长期参考帧特性示例如下:
588
589```c++
590constexpr int32_t NEEDED_LTR_NUM = 2;
591OH_AVFormat *format = OH_AVFormat_CreateVideoFormat(OH_AVCODEC_MIMETYPE_VIDEO_AVC, 1920, 1080);
592OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
593if (capability == nullptr) {
594   // 异常处理
595}
596// 1. 查询是否支持长期参考帧特性
597bool isSupported = OH_AVCapability_IsFeatureSupported(capability,VIDEO_ENCODER_LONG_TERM_REFERENCE);
598if (isSupported) {
599   // 2. 查询支持的长期参考帧个数
600   OH_AVFormat *properties = OH_AVCapability_GetFeatureProperties(capability, VIDEO_ENCODER_LONG_TERM_REFERENCE);
601   int32_t maxLTRCount = -1;
602   bool ret = OH_AVFormat_GetIntValue(properties, OH_FEATURE_PROPERTY_KEY_VIDEO_ENCODER_MAX_LTR_FRAME_COUNT, &maxLTRCount);
603   if (ret && maxLTRCount >= NEEDED_LTR_NUM) {
604      if (!OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_LTR_FRAME_COUNT, NEEDED_LTR_NUM)) {
605         // 异常处理
606      }
607   }
608}
609// 3. 编码器创建和配置
610OH_AVCodec *videoEnc = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);
611if (OH_VideoEncoder_Configure(videoEnc, format) != AV_ERR_OK) {
612   // 异常处理
613}
614```