unity + python socket通信,自定义数据包

article/2025/10/23 2:18:45

unity和python相互之间通过socket通信来发送自定义数据包是一个利用unity构建场景和通过python来做数据处理的方式,能够有效的利用两种不同语言的优势。

我已经将对应的操作封装为对应的一个模块,SocketTools.cs,我们先来看一下具体的代码用法(这段代码是一个简单的将unity主相机渲染的图像经过编码处理后通过socket发送给python并接收python对图像处理后结果并显示的一个代码):

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using System.Text;
using System.Runtime.InteropServices;
using System.Linq;
using UnityEngine.UI;public class HttpClient : MonoBehaviour
{public Camera cam;//关于相机的参数public RawImage rawImage;private float timeOld = 0;private RenderTexture cameraView = null;private Texture2D screenShot = null;private Texture2D texture = null;private byte[] image_recv_bytes = new byte[0];SocketTools tools = new SocketTools();private bool renderState = false;// Start is called before the first frame updatevoid Start(){cameraView = new RenderTexture(Screen.width, Screen.height, 8);cameraView.enableRandomWrite = true;texture = new Texture2D(500, 400);Rigidbody rigidbody = GetComponent<Rigidbody>();rigidbody.angularVelocity = new Vector3(0,0.2f,0);timeOld = Time.time;tools.SocketInit();tools.SetCallBackFun(CallBackFun);tools.ConnectServer("127.0.0.1", 4444);}public void CallBackFun(SocketStatus socketStatus, System.Object obj){switch (socketStatus){case SocketStatus.eSocketConnecting:Debug.Log("正在连接服务器...");break;case SocketStatus.eSocketConnected:Debug.Log("服务器连接成功...");break;case SocketStatus.eSocketReceived:{//Debug.Log("接收到消息:" + System.Text.Encoding.Default.GetString((byte[])obj));image_recv_bytes = (byte[])obj;}break;
//             case SocketStatus.eSocketSending:
//                 Debug.Log("正在发送消息...");
//                 break;
//             case SocketStatus.eSocketSent:
//                 Debug.Log("消息已发送...");
//                 break;case SocketStatus.eSocketClosed:Debug.Log("服务器已断开...");break;default:break;}}// Update is called once per framevoid Update(){if (tools.Connected && renderState){renderState = false;if (null == screenShot){screenShot = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);}// 读取屏幕像素进行渲染cam.targetTexture = cameraView;cam.Render();RenderTexture.active = cameraView;screenShot.ReadPixels(new Rect(0, 0, cameraView.width, cameraView.height), 0, 0);screenShot.Apply();byte[] bytes = screenShot.EncodeToJPG();
//             //实例化一个文件流--->与写入文件相关联  
//             FileStream fs = new FileStream("test_unity.jpg", FileMode.Create);
//             //开始写入  
//             fs.Write(bytes, 0, bytes.Length);
//             //清空缓冲区、关闭流  
//             fs.Flush();
//             fs.Close();
//             return;cam.targetTexture = null;try{timeOld = Time.time;tools.SendToServer(tools.PackData(bytes, 1));}catch{if (!tools.Connected){tools.SocketClose();Debug.Log("the server has been disconnected. ");}}}if (image_recv_bytes != null){Debug.Log("图片大小:" + image_recv_bytes.Length + "bytes, 帧间延时:" + Time.deltaTime * 1000 + "ms, 网络时间延迟:" + ((Time.time - timeOld) * 1000).ToString() + "ms");texture.LoadImage(image_recv_bytes);image_recv_bytes = null;rawImage.texture = texture;renderState = true;}if (Input.GetKeyDown(KeyCode.Space)){if (tools.Connected){tools.SocketClose();Debug.Log("socket closed. ");}else{tools.ConnectServer("127.0.0.1", 4444);}}}}

下面是对应的代码效果:

unity+python

下面将会针对一些技术细节做详细的说明,如果您对此实现的细节不感兴趣,您也可以直接下载我已经完成的项目代码:

unity和python通过自定义socket协议实现异步通信资源-CSDN文库

接下来是详细的技术实现过程,总的来讲主要技术手段分为三个部分:

1. python和unity异步socket的实现

2. python和unity处理自定义数据包的拆分和合并的实现

3. python和unity两者socket通信的数据包认证实现

4. unity数据处理异步封装逻辑

1. python和unity异步socket的实现

a. python异步socket

由于此处python主要是作为服务端的,所以此处pytho代码主要是讲python作为socket tcp server来实现的。

首先是初始化服务器代码

# 初始化服务器def socket_init(self, host, port):# 1 创建服务端套接字对象self.tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# signal_update.emit(0.2, 1, 1, 'socket object created...')# 设置端口复用,使程序退出后端口马上释放self.tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)# 2 绑定端口self.tcp_server.bind((host, port))# signal_update.emit(0.7, 1, 1, "socket bind successfully...")print('server port bind successfully, server host: {}, server port: {}...'.format(host, port))

然后是启动服务器监听代码,首先 start 开启一个新的线程用于监听tcp服务器的状态,然后在start_thread_fun线程函数中具体实现对应的代码,具体如下:

# 开始的线程函数,外部最好调用 start() 函数,不要调用此函数# 否则会阻塞def start_thread_fun(self):print("server_thread started. ")# 3 设置监听self.tcp_server.listen(self.max_connections)print('start to listen connections from client, max client count: {}'.format(self.max_connections))# 4 循环等待客户端连接请求(也就是最多可以同时有128个用户连接到服务器进行通信)while True:tcp_client_1, tcp_client_address = self.tcp_server.accept()self.tcp_clients.append(tcp_client_1)# 创建多线程对象thd = threading.Thread(target=self.client_process,args=(tcp_client_1, tcp_client_address), daemon=True)# 设置守护主线程  即如果主线程结束了 那子线程中也都销毁了  防止主线程无法退出thd.setDaemon(True)# 启动子线程对象thd.start()print("new client connected, client address: {}, total client count: {}".format(tcp_client_address, 1))# 启动服务器def start(self):self.start_thread = threading.Thread(target=self.start_thread_fun, daemon=True)self.start_thread.start()print("starting server_thread...")

注意:此处主线程不能终止,否则所有子线程都会停止,可以在主线程添加time.sleep(100)来手动延迟主线程运行时间。

b. unity 异步socket

unity的异步socket相较而言会比较麻烦一点,因为它的异步状态每次都需要手动的通过代码去复位调整,下面将针对其过程做具体的说明。

关于整个流程我觉得用流程图会比较合适,下面是代码的一个简单的流程图:

 其中各个地方的代码内容如下所示:

public void SocketInit(){socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);}public void ConnectServer(string host, int port){try{SocketAsyncEventArgs args = new SocketAsyncEventArgs();//创建连接参数对象this.endPoint = new IPEndPoint(IPAddress.Parse(host), port);args.RemoteEndPoint = this.endPoint;args.Completed += OnConnectedCompleted;//添加连接创建成功监听socket.ConnectAsync(args); //异步创建连接}catch (Exception e){Debug.Log("服务器连接异常:" + e);}}private void OnConnectedCompleted(object sender, SocketAsyncEventArgs args){try{   ///连接创建成功监听处理if (args.SocketError == SocketError.Success){StartReceiveMessage(); //启动接收消息}}catch (Exception e){Debug.Log("开启接收数据异常" + e);}}private void StartReceiveMessage(int bufferSize = 40960){//启动接收消息SocketAsyncEventArgs receiveArgs = new SocketAsyncEventArgs();//设置接收消息的缓存大小,正式项目中可以放在配置 文件中byte[] buffer = new byte[bufferSize];//设置接收缓存receiveArgs.SetBuffer(buffer, 0, buffer.Length);receiveArgs.RemoteEndPoint = this.endPoint;receiveArgs.Completed += OnReceiveCompleted; //接收成功socket.ReceiveAsync(receiveArgs);//开始异步接收监听}public void OnReceiveCompleted(object sender, SocketAsyncEventArgs args){try{//Debug.Log("网络接收成功线程:" + Thread.CurrentThread.ManagedThreadId.ToString());if (args.SocketError == SocketError.Success && args.BytesTransferred > 0){//创建读取数据的缓存byte[] bytes = new byte[args.BytesTransferred];//将数据复制到缓存中Buffer.BlockCopy(args.Buffer, 0, bytes, 0, args.BytesTransferred);Debug.Log(bytes);//再次启动接收数据监听,接收下次的数据。StartReceiveMessage();}}catch (Exception e){Debug.Log("接收数据异常:" + e);}}public void SendToServer(byte[] data){try{//创建发送参数SocketAsyncEventArgs sendEventArgs = new SocketAsyncEventArgs();sendEventArgs.RemoteEndPoint = endPoint;//设置要发送的数据sendEventArgs.SetBuffer(data, 0, data.Length);sendEventArgs.Completed += OnSendCompleted;//异步发送数据socket.SendAsync(sendEventArgs);}catch (Exception e){Debug.Log("发送数据异常:" + e);}}public void OnSendCompleted(object sender, SocketAsyncEventArgs args){if (args.SocketError == SocketError.Success){Debug.Log("send ok");}}public void SocketClose(){socket.Close();}

其中代码包含了一些最简单的异步c#socket的代码。

2. python和unity处理自定义数据包的拆分和合并的实现

但是大家都知道,tcp是流式传输协议,特别是针对图像这类大的数据包是不能够很好的实现帧之间的拆分的,我们需要自定义协议的数据包头和数据包体来实现不定长的数据传输,接下来讲一下如何在python和c#中实现字节层面上的数据拆分和组合。

a. python

python主要采用struct.pack和struct.unpack函数来实现数据的拆分和组合。具体的代码如下图所示:

    # 判断当前的数据头对不对,如果正确返回解析结果def process_protocol(self, header):header_unpack = struct.unpack(self.header_format, header)if header_unpack[0] == self.header_bytes:return True, header_unpackelse:return False, Nonedef pack_data(self, data, data_type):if type(data) is str:data = data.encode()data_pack = struct.pack(self.header_format, self.header_bytes, data_type, len(data))# print("datalen:{}".format(len(data)))return data_pack+data# 部分相关变量定义
self.header_bytes = b'\x0a\x0b'  # 占用两个字节
self.header_format = "2ssi"

b. unity

在unity的c#中,为了便于解析对应的数据帧头的内容,采用的是将对应的byte[]类型的变量直接转换为struct的方式,对应的两者相互转换的代码如下:

public static object BytesToStruct(byte[] buf, int len, Type type){object rtn;IntPtr buffer = Marshal.AllocHGlobal(len);Marshal.Copy(buf, 0, buffer, len);rtn = Marshal.PtrToStructure(buffer, type);Marshal.FreeHGlobal(buffer);return rtn;}public static byte[] StructToBytes(object structObj){//得到结构体的大小int size = Marshal.SizeOf(structObj);//创建byte数组byte[] bytes = new byte[size];//分配结构体大小的内存空间IntPtr structPtr = Marshal.AllocHGlobal(size);//将结构体拷到分配好的内存空间Marshal.StructureToPtr(structObj, structPtr, false);//从内存空间拷到byte数组Marshal.Copy(structPtr, bytes, 0, size);//释放内存空间Marshal.FreeHGlobal(structPtr);//返回byte数组return bytes;}

其次就是一些简单的内存操作,由于c#封装的缘故,我们并不能像c++那样直接通过指针的方式访问内存数据,我们需要借助Buffer类,具体的用法如下所示:

//用于同时操作内存块中的数据
public static void BlockCopy (Array src, int srcOffset, Array dst, int dstOffset, int count);

它可以将src起始位置偏移srcOffset的数据截取count位复制到dst起始位置偏移dstOffset的位置后面count长度的内粗区域中。

如果要截取一个byte[]类型的变量指定范围的数据,需要用到如下的函数:

bytes.Skip(recvLenReal).Take(bytes.Length - recvLenReal).ToArray();

从头跳过recvLenReal的长度然后截取bytes.Length - recvLenReal长的数据并将其转换为byte[]类型的变量。

3. 数据帧封装逻辑

关于自定义数据包的实现主要分为两部分:数据头和数据主体。

数据包帧头的定义方式如下:

数据头数据类型数据主体长度
       

两个字节的数据头用于进行协议的区分辨认;一个字节的数据类型用于标识后续的数据主体的数据类型,例如:图片或者文字或者其他的内容;四个字节的数据主体长度共同组成一个int类型的变量,可以指示后续的数据总长度。

其中该数据头在unity和python的实现方法如下图所示:

public struct DataHeader
{public byte header1;public byte header2;public byte data_type;public int data_len;}

python部分的代码上面有展示,此处不再重复。

4. python和unity两者socket通信的数据包认证实现

关于数据包认证的代码,两者采用的是同一个逻辑此处仅提供对应的逻辑处理注释内容,只是在代码的实现上稍有不同。

    def process_raw_data(self, recv_data):'''关于操作:本函数应该具有递归功能,否则无法处理复杂任务关于消息接收的逻辑处理:1. 首先判断当前是否已经接收过帧头 (self.frame_info.data_type is not None)接收过:根据帧头的数据长度接收对应的数据体内容没接收过:判断当前接收的数据长度是否满足帧头的长度满足:尝试解析解析失败:正常传输数据解析成功:如果有其他的数据,继续接收处理后续的数据不满足:将本次数据输出,丢弃此次的数据 !!!'''# 如果已经接收过数据头,直接继续接收内容if self.frame_info.data_type is not None:# 首先计算剩余的数据包长度recv_len_left = self.frame_info.data_all_length - self.frame_info.data_recv_length# 然后计算本次可以接收的数据长度,选取数据长度和剩余接收长度的最小值recv_len_real = min(recv_len_left, len(recv_data))self.frame_info.data_buffer += recv_data[:recv_len_real]# 更新对应的接收的数据长度self.frame_info.data_recv_length = len(self.frame_info.data_buffer)# 判断当前是否已经接受完本帧的内容if self.frame_info.data_recv_length >= self.frame_info.data_all_length:# 根据回调函数返回对应的内容if self.callback_fun is not None:self.callback_fun(self.frame_info.data_buffer)# 从剩余的数据中尝试检索出对应的数据头# 首先更新 recv_data 的数据的内容# print(self.frame_info.data_buffer)self.frame_info.reset()recv_data = recv_data[recv_len_real:len(recv_data)]if len(recv_data) != 0:self.process_raw_data(recv_data)else:return# 从剩余的数据中尝试解析数据头else:if len(recv_data) >= self.header_length:ret = self.process_protocol(recv_data[:self.header_length])if ret[0]:# 打印出协议对应的内容# print(ret[1])self.frame_info.set(ret[1][1], ret[1][2])# 此处还得继续判断当前是否转换完了,如果没有的话需要继续转换接收到的内容recv_data = recv_data[self.header_length:len(recv_data)]if len(recv_data) != 0:self.process_raw_data(recv_data)else:print(recv_data)else:print(recv_data)
    private void ProcessRawData(ref byte[] bytes){
//         关于操作:
//             本函数应该具有递归功能,否则无法处理复杂任务
//         关于消息接收的逻辑处理:
//         1.首先判断当前是否已经接收过帧头(self.frame_info.data_type is not None)
//             接收过:
//                 根据帧头的数据长度接收对应的数据体内容
//             没接收过:
//             判断当前接收的数据长度是否满足帧头的长度
//                 满足:尝试解析
//                     解析失败:正常传输数据
//                     解析成功:如果有其他的数据,继续接收处理后续的数据
//                 不满足:将本次数据输出,丢弃此次的数据!!!if (frameInfo.sPyDataTest.data_type != 0){int recvLenLeft = frameInfo.sPyDataTest.data_len - frameInfo.data_recv_len;int recvLenReal = Math.Min(recvLenLeft, bytes.Length);frameInfo.AddBufferData(bytes.Skip(0).Take(recvLenReal).ToArray());frameInfo.data_recv_len = frameInfo.GetBufferLength();if (frameInfo.data_recv_len >= frameInfo.sPyDataTest.data_len){//Debug.Log("接收成功!");socketStatus = SocketStatus.eSocketReceived;if (callBackFun != null){callBackFun(socketStatus, frameInfo.data_buffer);}frameInfo.Reset();bytes = bytes.Skip(recvLenReal).Take(bytes.Length - recvLenReal).ToArray();if (bytes.Length != 0){ProcessRawData(ref bytes);}}else{return;}}else{if (recvBuffer != null){byte[] newBytes = new byte[recvBuffer.Length + bytes.Length];Buffer.BlockCopy(recvBuffer, 0, newBytes, 0, recvBuffer.Length);Buffer.BlockCopy(bytes, 0, newBytes, recvBuffer.Length, bytes.Length);bytes = newBytes;recvBuffer = null;}if (bytes.Length >= frameInfo.StructLength){bool ret = true;ret = frameInfo.IsHeaderMatch(bytes.Take(frameInfo.StructLength).ToArray());if (ret == true){//Debug.Log(frameInfo.sPyDataTest);frameInfo.Set(frameInfo.sPyDataTest.data_type, frameInfo.sPyDataTest.data_len);bytes = bytes.Skip(frameInfo.StructLength).Take(bytes.Length - frameInfo.StructLength).ToArray();if (bytes.Length != 0){ProcessRawData(ref bytes);}}else{Debug.Log(bytes);}}else{recvBuffer = bytes;Debug.Log(bytes);}}}

总结

此处仅仅提供对应的关键步骤的代码实现手段和原理讲解,如有错误欢迎大家指正!


http://chatgpt.dhexx.cn/article/iejfZZeN.shtml

相关文章

假设电话收费标准为: (1)国际长途1.00元/分钟,(2) 国内长途0.60元/分钟,(3)市话前3分钟0.20元,3分钟以后0.10元/分钟。现假设某话单文件中每条话单包含如下信息:通话日期(10

你好&#xff0c;帮我做个C语言题目 你好&#xff0c;我是Assistant。很高兴为您做题。 请提供题目的完整题面&#xff0c;并提供任何相关的输入、输出、约束条件等信息。 如果您有任何其他问题&#xff0c;请随时与我联系。我将竭诚为您服务。 897354667qq.com 假设电话收…

电商用户行为数据分析实战(MySQL +PowerBI)

目录 一、项目概况二、数据源三、数据清洗3.1 选择子集导入&#xff0c;匹配适合的数据类型3.2 列重命名3.3重复值处理3.4 缺失值处理3.5 异常值处理从timestamps字段中提取日期数据列查看日期列数据异常情况 四、数据分析4.1 整体购物情况&#xff0c;基于AARRR模型4.1.1 各字…

【业务数据分析】——十大常用数据分析方法

&#x1f935;‍♂️ 个人主页&#xff1a;Lingxw_w的个人主页 ✍&#x1f3fb;作者简介&#xff1a;计算机科学与技术研究生在读 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4a…

基于订单的数据分析

目录 项目背景 数据理解 指标维度 指标梳理 维度梳理 导入数据 数据预处理 数据格式整理 规范字段名 增加字段 简化地址 缺失值处理 异常值分析​ 重复值处理 数据分析 描述性统计 总体销售情况 周趋势、日趋势分析 产品价格分析 地区分析 转化率分析 总结…

大数据培训 | 电商用户行为分析之订单支付实时监控

在电商网站中&#xff0c;订单的支付作为直接与营销收入挂钩的一环&#xff0c;在业务流程中非常重要。对于订单而言&#xff0c;为了正确控制业务流程&#xff0c;也为了增加用户的支付意愿&#xff0c;网站一般会设置一个支付失效时间&#xff0c;超过一段时间不支付的订单就…

订单数据分析

订单背景 订单&#xff1a;对订单的预测不仅为了企业更好的制定物料采购计划、控制库存、提升生产效率、控制生产进度&#xff0c;还为了帮助企业更好的把控市场潜在需求&#xff0c;分析目前经营状态和未来发展趋势。 宽厚板材市场价格&#xff08;只能查询到近三个月的&…

关于订单功能的处理和分析

这两天看了一下RABC的权限管理处理&#xff0c;梳理了一下订单功能的表创建&#xff0c;界面&#xff0c;功能分析。 目录 RABC RBAC0模型 那么对于RABC模型我们怎么创建数据库表&#xff1f; 订单模块的梳理 RABC RABC说的是在用户和权限之间多一个角色&#xff0c;用户与…

订单数据分析-实战

1. 京东订单数据准备 1.1 京东订单数据介绍 2020年5月25日10%抽样数据大家电-家用电器-冰箱70K 1.2 数据清洗 缺失值处理 用户城市和省份信息有部分缺失&#xff0c;部分订单的订单中支付时间为空值数据逻辑错误格式内容一致性 import pandas as pd import numpy as np im…

话单数据完整流程

原始数据__解析_____>>>解析后的数据___入库____>>>汇总的数据 1.原始数据 上游中兴的原始数据&#xff0c;在远程桌面Winscp软件中查看。丢失了下游也没法补充采集。得等上游补充采集后下游才能解析。当原始数据存在&#xff0c;而话单数据显示红点&…

话单分析账单分析行踪分析三合一数据分析

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

Office Tool Plus(安装visio)

说明&#xff1a;需要提前卸载原先的Office&#xff08;Word、PPT、Excel等&#xff09; 一、Office Tool Plus官网 https://otp.landian.vip/zh-cn/download.html 二、下载Office Tool Plus 百度网盘链接&#xff08;Office Tool Plus安装包&#xff09; 链接&#xff1a;…

FFmpeg音频解码-音频可视化

最近在做一个音频可视化的业务&#xff0c;网上有Java层的实现方法&#xff0c;但是业务需要用C实现&#xff0c;从原理出发其实很简单&#xff0c;先对音频进行解码&#xff0c;再计算分贝。这比把大象放进冰箱还简单。本文从音频可视化的业务为依托&#xff0c;以FFmpeg为基础…

基于FFmpeg的视频播放器之七:音频解码

一.流程 音频解码的流程和视频解码几乎一样,最大的区别是解码后需要进行重采样。因为解码出的AVSampleFormat格式是AV_SAMPLE_FMT_FLTP(float, planar),该格式无法直接使用SDL进行播放,需要转换成SDL支持的AV_SAMPLE_FMT_S16(signed 16 bits)格式。关于重采样,详见下篇…

2020手机音频解码芯片_2020杰理音频芯片全解析,14款音频产品代表作拆解汇总...

珠海市杰理科技股份有限公司,成立于2010年。杰理科技主要从事射频智能终端、多媒体智能终端等系统级芯片(SoC)的研究、开发和销售。 杰理科技的芯片产品主要应用于AI智能音箱、蓝牙音箱、蓝牙耳机、智能语音玩具等物联网智能终端产品,下游应用产品市场十分广泛和巨大。 杰理科…

音频编解码原理

实例说明 音频编解码常用的实现方案有三 种。 第一种就是采用专用的音频芯片对 语音信号进行采集和处理&#xff0c;音频编解码算法集成在硬件内部&#xff0c;如 MP3 编解码芯片、语音合成 分析芯片等。使用这种方案的优点就是处理速度块&#xff0c;设计周期短&#xff1b;缺…

基于STM32音频解码MP3——vs1053

基于正点原子教程 VS1053简介&#xff1a; 1.该模块采用VS1053B 作为主芯片 2.支持&#xff1a;MP3/WMA/OGG/WAV/FLAC/MIDI/AAC 等音频格式的解码 3.支持&#xff1a;OGG/WAV 音频格式的录音&#xff0c;支持高低音调节以及 EarSpeaker 空间效果设置 模块如图所示正点原子 AL…

ijkplayer音频解码播放架构分析

ijkplayer是一款跨平台播放器&#xff0c;支持Android与iOS播放&#xff0c;音频解码默认使用FFmpeg的avcodec软解。Android端播放音频可以用OpenSL ES和AudioTrack&#xff0c;而iOS端播放音频默认使用AudioQueue。 一、iOS音频解码播放 采用pipeline形式创建音频播放组件&a…

HIFI音频解码芯片ES9023

现在的HiFi播放器、解码耳放设备越来越多&#xff0c;推陈出新的速度也越来越快。各家厂商也都对产品进行了卖点细分&#xff0c;把新款旗舰级解码芯片拎出来宣传。美国ESS公司推出的ES9038Pro芯片大家都早已耳熟能详。 美国ESS系列芯片拥有行业高标准的信噪比 DNR&#xff08;…

DP7398:国产兼容替代CS4398立体声24位/192kHz音频解码芯片

目录 DP7398简介结构框图芯片特性 应用领域 DP7398简介 DP7398是立体声 24 位/192kHz 数模转换芯片。该D/A系统包括数字去加重、半分贝步长音量控制、ATAPI 通道混频、可选择的快速和慢速数字插补滤波器和过采样多位增量 Sigma-Delta 调制器&#xff1b;该调制器采用失调整形技…

ijkplayer 音频解码线程

在ijkplayer 读线程中提到&#xff0c;函数stream_component_open()中的decoder_start()会创建音频解码线程&#xff0c;来看解码线程audio_thread()的主要代码 static int audio_thread(void *arg) {...do {...if ((got_frame decoder_decode_frame(ffp, &is->auddec…