新闻资讯

新闻资讯 行业动态

音频 data >> 音频包 Packet

编辑:008     时间:2020-02-26

拿 Audio Queue Services ,处理上一步获取的音频二进制数据 data,解析为音频数据包 packet

1. 建立音频的处理通道, 注册解析回调方法

public init() throws { let context = unsafeBitCast(self, to: UnsafeMutableRawPointer.self)
        // 创建一个活跃的音频文件流解析器,创建解析器 ID
        guard AudioFileStreamOpen(context, ParserPropertyChangeCallback, ParserPacketCallback, kAudioFileMP3Type, &streamID) == noErr else {
            throw ParserError.streamCouldNotOpen
        }
    } 

2. 传递数据进来,开始解析

public func parse(data: Data) throws { let streamID = self.streamID! let count = data.count
        _ = try data.withUnsafeBytes({ (rawBufferPointer) in let bufferPointer = rawBufferPointer.bindMemory(to: UInt8.self) if let address = bufferPointer.baseAddress{
                // 把音频数据,传给解析器
                //  streamID,  指定解析器 let result = AudioFileStreamParseBytes(streamID, UInt32(count), address, [])
                guard result == noErr else {
                    throw ParserError.failedToParseBytes(result)
                }
            }
        })
    }

3. 音频信息解析先

func ParserPropertyChangeCallback(_ context: UnsafeMutableRawPointer, _ streamID: AudioFileStreamID, _ propertyID: AudioFileStreamPropertyID, _ flags: UnsafeMutablePointer<AudioFileStreamPropertyFlags>) { let parser = Unmanaged<Parser>.fromOpaque(context).takeUnretainedValue()
    // 关心什么信息,取什么
    switch propertyID { case kAudioFileStreamProperty_DataFormat:
        // 拿数据格式
        var format = AudioStreamBasicDescription()
        GetPropertyValue(&format, streamID, propertyID)
        parser.dataFormat = AVAudioFormat(streamDescription: &format) case kAudioFileStreamProperty_AudioDataPacketCount:
         // 音频流文件,分离出来的音频数据中,的包 packet 个数
        GetPropertyValue(&parser.packetCount, streamID, propertyID)

    default:
         () 
    }
}

// 套路就是,先拿内存大小 propSize, 再拿关心的属性的值 value
func GetPropertyValue<T>(_ value: inout T, _ streamID: AudioFileStreamID, _ propertyID: AudioFileStreamPropertyID) {
    var propSize: UInt32 = 0
    guard AudioFileStreamGetPropertyInfo(streamID, propertyID, &propSize, nil) == noErr else { return }
    guard AudioFileStreamGetProperty(streamID, propertyID, &propSize, &value) == noErr else { return }
} 

4. 解析回调,处理数据

func ParserPacketCallback(_ context: UnsafeMutableRawPointer, _ byteCount: UInt32, _ packetCount: UInt32, _ data: UnsafeRawPointer, _ packetDescriptions: UnsafeMutablePointer<AudioStreamPacketDescription>) {

    // 拿回了 self ( parser ) let parser = Unmanaged<Parser>.fromOpaque(context).takeUnretainedValue() let packetDescriptionsOrNil: UnsafeMutablePointer<AudioStreamPacketDescription>? = packetDescriptions
    // ASPD 存在,就是压缩的音频包
    // 未压缩的 pcm, 使用 ASBD let isCompressed = packetDescriptionsOrNil != nil
    guard let dataFormat = parser.dataFormat else { return }
    
    // 拿到了数据,遍历,
    // 存储进去 parser.packets, 也就是 self.packets if isCompressed { for i in 0 ..< Int(packetCount) {
            // 压缩音频数据,每一个包对应一个 ASPD, 逐个计算 let packetDescription = packetDescriptions[i] let packetStart = Int(packetDescription.mStartOffset) let packetSize = Int(packetDescription.mDataByteSize) let packetData = Data(bytes: data.advanced(by: packetStart), count: packetSize)
            parser.packets.append((packetData, packetDescription))
        }
    } else {
         // 原始音频数据 pcm,文件统一配置,计算比较简单 let format = dataFormat.streamDescription.pointee let bytesPerPacket = Int(format.mBytesPerPacket) for i in 0 ..< Int(packetCount) { let packetStart = i * bytesPerPacket let packetSize = bytesPerPacket let packetData = Data(bytes: data.advanced(by: packetStart), count: packetSize)
            parser.packets.append((packetData, nil))
        }
    }
}




原文链接:https://juejin.im/post/5e52a5c55188254940670156
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

回复列表

相关推荐