CarPlay Wireless 使用fdk |
您所在的位置:网站首页 › aac解码协议 › CarPlay Wireless 使用fdk |
CarPlay在Wireless的模式下,音频数据传输不再采用Wired模式下的LPCM格式,而是压缩编码格式。多媒体音频(Main High Audio)采用Raw AAC-LC编码格式,其他类型音频(Main Audio & Alt Audio)可选Raw AAC-ELD或OPUS编码格式。而且由于CarPlay运行时会同时出现输出多路音频流的情况,所以需要支持多解码器实例同时工作。 CarPlay over USB uses LPCM for audio. CarPlay over wireless uses raw AAC-LC for high latency audio (Main High Audio) and either OPUS or raw AAC-ELD for low latency audio (Main Audio except “media” and Alt Audio). Accessories supporting CarPlay over wireless must support multiple decode instances and concurrent decode/encode instances. 因此,考虑采用软件解码的方式来支持CarPlay Wireless的音频解码功能。常见的AAC软解码库有faad2和fdk_aac。 faad2库仅能支持包含AAC-LC的少数profile解码,而fdk_aac库是ffmpeg项目中推荐采用的高精度AAC编解码库,可以支持的profile更多,所以打算使用fdk_aac库来实现AAC-LC和AAC-ELD解码。 FAAD2的主页 GitHub上fdk-aac的项目主页 fdk-aac的介绍界面 fdk_aac源码包下载 fdk-aac解码库的API使用,可以参考其自带的文档./fdk-aac-2.0.0/documentation/aacDecoder.pdf 大致的调用流程就是: aacDecoder_Open(); aacDecoder_ConfigRaw(); loop{ aacDecoder_Fill(); aacDecoder_DecodeFrame(); } aacDecoder_Close();这里记录一些自己解码过程中遇到的2个主要问题: 1. 获取音频配置信息AudioSpecificConfigAudioSpecificConfig 定义于文档 ISO/IEC 14496-3中。如下: 从aacDecoder.pdf中文档可以看到相关说明,在调用解码API aacDecoder_DecodeFrame()之前需要进行配置: 这里说没有外带ASC或者SMC数据的话,可以不必使用aacDecoder_ConfigRaw()进行设置,aacDecoder_DecodeFrame()执行中会自己配置。但其实如果是Raw Data的话,是必须要设置的,否则解码不成功。这个看函数说明可以知道,如下: 看说明的话,我目前处理的AAC Raw Data需要提供的ASC格式的信息。但在CarPlay Wireless中手机端似乎无法直接获取到AAC Raw Data对应的信息数据块。网上找了一些ASC的格式相关的说明,如下: audioObjectType,samplingFrequencyIndex,channelConfiguration这3个字段的完整的配置可以参考这里: Audio_Specific_Config 后续的部分字段可以参考这里: Understanding_AAC 有个可以参考的GASpecificConfig信息设置: Microsoft aac-decoder 我没有在网上找到ASC完整的定义,所以自己构建ASC数据的话,可能还是有一些问题。(AAC-LC的ASC相对比较简单,GASpecificConfig中3个bits填充0即可,测试可以正常解码) 另外,有个曲线救国的办法来解决ASC的问题,先使用包含fdk_aac编解码库的ffmpeg工具转码一个指定AAC格式的文件,然后来用ffmpeg工具把音频信息中的extradata给dump出来。从ffmpeg源码中调用fdk_aac的地方可以得知,AVCodecContext结构中的extradata就是aacDecoder_ConfigRaw()需要的数据,如下: static av_cold int fdk_aac_decode_init(AVCodecContext* avctx) { FDKAACDecContext* s = avctx->priv_data; AAC_DECODER_ERROR err; s->handle = aacDecoder_Open(avctx->extradata_size ? TT_MP4_RAW : TT_MP4_ADTS, 1); if(!s->handle) { av_log(avctx, AV_LOG_ERROR, "Error opening decoder\n"); return AVERROR_UNKNOWN; } if(avctx->extradata_size) { if((err = aacDecoder_ConfigRaw(s->handle, &avctx->extradata, &avctx->extradata_size)) != AAC_DEC_OK) { av_log(avctx, AV_LOG_ERROR, "Unable to set extradata\n"); return AVERROR_INVALIDDATA; } } ... }我在进行解码功能验证前,在CarPlay Wireless代码接收RTP数据的位置分别dump出了 AAC-LC/44KHZ/STEREO 和 AAC-ELD/16KHZ/MONO 的数据到文件。比如想获取 AAC-ELD/16KHZ/MONO 这个格式的ASC可以这样: lzy@~/GitHub/ffmpeg$ ./ffmpeg -i 1.mp3 -acodec libfdk_aac -ar 16000 -ac 1 -profile:a aac_eld aac_eld_16k_ch1.m4a lzy@~/GitHub/ffmpeg$ ./ffprobe -show_data -show_streams aac_eld_16k_ch1.m4a ##省略了部分输出 [STREAM] index=0 codec_name=aac codec_long_name=AAC (Advanced Audio Coding) profile=ELD codec_type=audio codec_time_base=1/16000 codec_tag_string=mp4a nb_frames=9014 extradata= 00000000: f8f0 2000 .. . [/STREAM]可以看到extradata数据为: 0xF8 0xF0 0x20 0x00。至此,AudioSpecificConfig的问题算是解决了。 2. 解码函数调用不成功问题正确设置ASC之后,按照文档说明,循环读取dump出来的AAC文件内容进行解码,但是aacDecoder_DecodeFrame()会直接返回AAC_DEC_UNKNOWN错误。因为aacDecoder_ConfigRaw()设置完ASC之后,使用aacDecoder_GetStreamInfo()获取信息可以看到参数解析的都是正确的。最后还是看文档发现问题所在: 完整代码和测试用的ACC Raw Data放在这里了: https://github.com/lzy831/demo/tree/master/fdk_aac_decode_raw 2019-3-22 补充: 随着CarPlay Wireless的开发,遇到了一个新问题。 ACC-ELD数据每次解码出来的framesize是512或者480,这个从下面framesize的注释可以看出来: /** * \brief This structure gives information about the currently decoded audio * data. All fields are read-only. */ typedef struct { ... INT frameSize; /*!< The frame size of the decoded PCM audio signal. \n Typically this is: \n 1024 or 960 for AAC-LC \n 2048 or 1920 for HE-AAC (v2) \n 512 or 480 for AAC-LD and AAC-ELD \n 768, 1024, 2048 or 4096 for USAC */ ... INT aacSamplesPerFrame; /*!< Samples per frame for the AAC core (from ASC) divided by a (ELD) downscale factor if present. \n Typically this is (with a downscale factor of 1): \n 1024 or 960 for AAC-LC \n 512 or 480 for AAC-LD and AAC-ELD */ ... } CStreamInfo;而CarPlay Wireless中手机端发过来的ACC-ELD数据默认是固定按照480来处理的。(RTP包的timestamp值,解码数据存放的缓存都是根据这个值来设置的),所以我需要设置解码器来输出匹配的数据量。 上面代码中aacSamplesPerFrame的注释中可以看出,framesize是从ASC中获取的。但是我实在是找不到ASC对应的文档了。只能从代码里看: static TRANSPORTDEC_ERROR EldSpecificConfig_Parse(CSAudioSpecificConfig *asc, HANDLE_FDK_BITSTREAM hBs, CSTpCallBacks *cb) { ... FDKmemclear(esc, sizeof(CSEldSpecificConfig)); esc->m_frameLengthFlag = FDKreadBits(hBs, 1); if (esc->m_frameLengthFlag) { asc->m_samplesPerFrame = 480; } else { asc->m_samplesPerFrame = 512; } ... }可以看出来AAC-ELD对应的配置是EldSpecificConfig(AAC-LC对应的是GaSpecificConfig),而samplesPerFrame的值是由EldSpecificConfig中的samplesPerFrame这个bit决定的。然后我查了一下代码,这个bit就是紧跟着channelConfiguration这个域后面的一个bit。 进行正确的设置后,问题解决。 另外发现的一个小问题是在aacDecoder_ConfigRaw配置成功ASC后,CStreamInfo.frameSize的值并不会立即更新为正确的framesize,需要在第一次aacDecoder_DecodeFrame解码之后才会更新。所以提前分配输出缓存的话,可以在aacDecoder_ConfigRaw之后参考CStreamInfo.aacSamplesPerFrame的值来进行分配。 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |