如何获得音频比特率
=========

#### 问题现象

如何获得多个音频轨道里每一个音频轨的比特率。

#### 背景知识

*   [AVMetadataExtractor](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-avmetadataextractor)可以实现从原始媒体资源中获取元数据[AVMetadata](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-i#avmetadata11)。其中[AVMetadata](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-i#avmetadata11).tracks为媒体资源的轨道信息。
*   [AVPlayer](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-avplayer)用于实现端到端播放原始媒体资源。[AVPlayer](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-avplayer).[getTrackDescription](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-avplayer#gettrackdescription9)用于获得音视频媒体资源的轨道信息。
*   媒体资源的轨道信息使用[MediaDescription](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-i#mediadescription8)表示，通过key-value方式获取媒体信息。[MediaDescriptionKey](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-e#mediadescriptionkey8).MD\_KEY\_TRACK\_TYPE表示轨道类型，[MediaDescriptionKey](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-e#mediadescriptionkey8).MD\_KEY\_BITRATE表示比特率。

#### 解决方案

方案一：使用[AVMetadataExtractor](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-avmetadataextractor)调用[fetchMetadata](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-avmetadataextractor#fetchmetadata11)接口获得元数据[AVMetadata](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-i#avmetadata11)。通过[AVMetadata](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-i#avmetadata11).tracks属性获得媒体资源的轨道信息，遍历轨道信息，从音频轨信息中获得对应比特率。

try {
  let avMetadataExtractor: media.AVMetadataExtractor = await media.createAVMetadataExtractor();
  let context: Context = this.getUIContext().getHostContext() as common.UIAbilityContext;
  avMetadataExtractor.fdSrc = await context.resourceManager.getRawFd('video.mp4');
  let metadata: media.AVMetadata = await avMetadataExtractor.fetchMetadata();
  if (metadata.tracks) {
    for (const track of metadata.tracks) {
      if (track\[media.MediaDescriptionKey.MD\_KEY\_TRACK\_TYPE\] === media.MediaType.MEDIA\_TYPE\_AUD) {
        let trackIdx: number = track\[media.MediaDescriptionKey.MD\_KEY\_TRACK\_INDEX\] as number;
        let bitrate: number = track\[media.MediaDescriptionKey.MD\_KEY\_BITRATE\] as number;
        console.info(\`Audio Track ${trackIdx} bitrate is ${bitrate}\`);
      }
    }
  }
  await avMetadataExtractor.release();
} catch (error) {
  console.error(\`failed to get audio bitrate by AVMetadataExtractor: ${JSON.stringify(error)}\`);
}

方案二：使用[AVPlayer](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-avplayer)在prepared/playing/paused状态下调用[getTrackDescription](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-media-avplayer#gettrackdescription9)接口获得音视频的轨道信息，遍历轨道信息，从音频轨信息中获得对应比特率。

try {
  let avPlayer: media.AVPlayer = await media.createAVPlayer();
  avPlayer.on('stateChange', async (state: media.AVPlayerState) => {
    switch (state) {
      case 'initialized':
        await avPlayer.prepare();
        break;
      case 'prepared':
        let tracks: Array<media.MediaDescription> = await avPlayer.getTrackDescription();
        for (const track of tracks) {
          if (track\[media.MediaDescriptionKey.MD\_KEY\_TRACK\_TYPE\] === media.MediaType.MEDIA\_TYPE\_AUD) {
            let trackIdx: number = track\[media.MediaDescriptionKey.MD\_KEY\_TRACK\_INDEX\] as number;
            let bitrate: number = track\[media.MediaDescriptionKey.MD\_KEY\_BITRATE\] as number;
            console.info(\`Audio Track ${trackIdx} bitrate is ${bitrate}\`);
          }
        }
        await avPlayer.release();
        break;
      case 'error':
        await avPlayer.release();
        break;
    }
  });
  let context: Context = this.getUIContext().getHostContext() as common.UIAbilityContext;
  avPlayer.fdSrc = await context.resourceManager.getRawFd('video.mp4');
} catch (error) {
  console.error(\`failed to get audio bitrate by AVMetadataExtractor: ${JSON.stringify(error)}\`);
}

完成参考代码如下：

import { media } from '@kit.MediaKit';
import { common } from '@kit.AbilityKit';

@Entry
@Component
struct Index {
  build() {
    Column({ space: 20 }) {
      Button('AVMetadataExtractor')
        .padding(5)
        .fontSize(30)
        .onClick(async () => {
          try {
            let avMetadataExtractor: media.AVMetadataExtractor = await media.createAVMetadataExtractor();
            let context: Context = this.getUIContext().getHostContext() as common.UIAbilityContext;
            avMetadataExtractor.fdSrc = await context.resourceManager.getRawFd('video.mp4');
            let metadata: media.AVMetadata = await avMetadataExtractor.fetchMetadata();
            if (metadata.tracks) {
              for (const track of metadata.tracks) {
                if (track\[media.MediaDescriptionKey.MD\_KEY\_TRACK\_TYPE\] === media.MediaType.MEDIA\_TYPE\_AUD) {
                  let trackIdx: number = track\[media.MediaDescriptionKey.MD\_KEY\_TRACK\_INDEX\] as number;
                  let bitrate: number = track\[media.MediaDescriptionKey.MD\_KEY\_BITRATE\] as number;
                  console.info(\`Audio Track ${trackIdx} bitrate is ${bitrate}\`);
                }
              }
            }
            await avMetadataExtractor.release();
          } catch (error) {
            console.error(\`failed to get audio bitrate by AVMetadataExtractor: ${JSON.stringify(error)}\`);
          }
        });

      Button('AVPlayer')
        .padding(5)
        .fontSize(30)
        .onClick(async () => {
          try {
            let avPlayer: media.AVPlayer = await media.createAVPlayer();
            avPlayer.on('stateChange', async (state: media.AVPlayerState) => {
              switch (state) {
                case 'initialized':
                  await avPlayer.prepare();
                  break;
                case 'prepared':
                  let tracks: Array<media.MediaDescription> = await avPlayer.getTrackDescription();
                  for (const track of tracks) {
                    if (track\[media.MediaDescriptionKey.MD\_KEY\_TRACK\_TYPE\] === media.MediaType.MEDIA\_TYPE\_AUD) {
                      let trackIdx: number = track\[media.MediaDescriptionKey.MD\_KEY\_TRACK\_INDEX\] as number;
                      let bitrate: number = track\[media.MediaDescriptionKey.MD\_KEY\_BITRATE\] as number;
                      console.info(\`Audio Track ${trackIdx} bitrate is ${bitrate}\`);
                    }
                  }
                  await avPlayer.release();
                  break;
                case 'error':
                  await avPlayer.release();
                  break;
              }
            });
            let context: Context = this.getUIContext().getHostContext() as common.UIAbilityContext;
            avPlayer.fdSrc = await context.resourceManager.getRawFd('video.mp4');
          } catch (error) {
            console.error(\`failed to get audio bitrate by AVMetadataExtractor: ${JSON.stringify(error)}\`);
          }
        });
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center);
  }
}