【音视频 | Ogg】libogg库详细介绍以及使用——附带libogg库解析.opus文件的C源码
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍libogg库,并给出ligogg库使用的例子🍭
😎金句分享😎:🍭子曰:不患人之不己知,患不知人也。——《论语·学而篇》。意思是,不要担心别人不了解自己,只需要担心自己不了解别人。🍭
本文未经允许,不得转发!!!
相关文章:
1、RFC3533 :Ogg封装格式版本 0(The Ogg Encapsulation Format Version 0)
2、Ogg封装格式详解——包含Ogg封装过程、数据包(packet)、页(page)、段(segment)等
3、libogg库详解介绍以及使用——附带libogg库解析.opus文件的C源码
4、RFC7845:Opus音频编解码器的Ogg封装(Ogg Encapsulation for the Opus Audio Codec)
5、opus编解码库(opus-1.4)详细介绍以及使用——附带解码示例代码
6、opus编码的Ogg封装文件详解
目录
- 🎄一、libogg库概述
- 🎄二、libogg库编译
- ✨2.1 编译环境如下:
- ✨2.2 libogg编译
- 🎄三、libogg库简单介绍
- ✨3.1 ogg.h 头文件
- ✨3.2 libogg 库函数解析
- 🎄四、Ogg封装格式使用 libogg 库解码——C语言代码
- 🎄五、总结
![]()
🎄一、libogg库概述
Ogg是一种多媒体容器格式,是Xiph.org多媒体编解码器的原生文件和流格式。与所有Xiph.org技术一样,它是一种开放的格式,任何人都可以免费使用。
libogg库包含创建、解码和处理ogg比特流的必要功能。最新版本稳定版本更新到1.3.4,开发版本更新到1.3.5,libogg库的下载链接:https://xiph.org/downloads/

![]()
🎄二、libogg库编译
本文下载的是libogg-1.3.5.tar.gz。
✨2.1 编译环境如下:
$ uname -a
Linux ubuntu 4.4.0-128-generic #154~14.04.1-Ubuntu SMP Fri May 25 14:58:51 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.5 LTS
Release: 14.04
Codename: trusty$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-2ubuntu1~14.04.4' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.4)
✨2.2 libogg编译
tar zxvf libogg-1.3.5.tar.gz
cd libogg-1.3.5/
./configure --prefix=`pwd`/result_gcc
make && make install
![]()
🎄三、libogg库简单介绍
✨3.1 ogg.h 头文件
libogg库的所有结构体和函数都定义在 ogg.h 头文件中,并且大概分为5个部分:
- 1、结构体;
- 2、比特流打包函数;
- 3、Ogg编码相关函数;
- 4、Ogg解码相关函数;
- 5、通用函数。
头文件内容如下:
/********************************************************************* ** THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. ** USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS ** GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE ** IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. ** ** THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 ** by the Xiph.Org Foundation http://www.xiph.org/ ** *********************************************************************function: toplevel libogg include********************************************************************/
#ifndef _OGG_H
#define _OGG_H#ifdef __cplusplus
extern "C" {
#endif#include <stddef.h>
#include <ogg/os_types.h>typedef struct {void *iov_base;size_t iov_len;
} ogg_iovec_t;typedef struct {long endbyte;int endbit;unsigned char *buffer;unsigned char *ptr;long storage;
} oggpack_buffer;/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/typedef struct {unsigned char *header;long header_len;unsigned char *body;long body_len;
} ogg_page;/* ogg_stream_state contains the current encode/decode state of a logicalOgg bitstream **********************************************************/typedef struct {unsigned char *body_data; /* bytes from packet bodies */long body_storage; /* storage elements allocated */long body_fill; /* elements stored; fill mark */long body_returned; /* elements of fill returned */int *lacing_vals; /* The values that will go to the segment table */ogg_int64_t *granule_vals; /* granulepos values for headers. Not compactthis way, but it is simple coupled to thelacing fifo */long lacing_storage;long lacing_fill;long lacing_packet;long lacing_returned;unsigned char header[282]; /* working space for header encode */int header_fill;int e_o_s; /* set when we have buffered the last packet in thelogical bitstream */int b_o_s; /* set after we've written the initial pageof a logical bitstream */long serialno;long pageno;ogg_int64_t packetno; /* sequence number for decode; the framingknows where there's a hole in the data,but we need coupling so that the codec(which is in a separate abstractionlayer) also knows about the gap */ogg_int64_t granulepos;} ogg_stream_state;/* ogg_packet is used to encapsulate the data and metadata belongingto a single raw Ogg/Vorbis packet *************************************/typedef struct {unsigned char *packet;long bytes;long b_o_s;long e_o_s;ogg_int64_t granulepos;ogg_int64_t packetno; /* sequence number for decode; the framingknows where there's a hole in the data,but we need coupling so that the codec(which is in a separate abstractionlayer) also knows about the gap */
} ogg_packet;typedef struct {unsigned char *data;int storage;int fill;int returned;int unsynced;int headerbytes;int bodybytes;
} ogg_sync_state;/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/extern void oggpack_writeinit(oggpack_buffer *b);
extern int oggpack_writecheck(oggpack_buffer *b);
extern void oggpack_writetrunc(oggpack_buffer *b,long bits);
extern void oggpack_writealign(oggpack_buffer *b);
extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits);
extern void oggpack_reset(oggpack_buffer *b);
extern void oggpack_writeclear(oggpack_buffer *b);
extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits);
extern long oggpack_look(oggpack_buffer *b,int bits);
extern long oggpack_look1(oggpack_buffer *b);
extern void oggpack_adv(oggpack_buffer *b,int bits);
extern void oggpack_adv1(oggpack_buffer *b);
extern long oggpack_read(oggpack_buffer *b,int bits);
extern long oggpack_read1(oggpack_buffer *b);
extern long oggpack_bytes(oggpack_buffer *b);
extern long oggpack_bits(oggpack_buffer *b);
extern unsigned char *oggpack_get_buffer(oggpack_buffer *b);extern void oggpackB_writeinit(oggpack_buffer *b);
extern int oggpackB_writecheck(oggpack_buffer *b);
extern void oggpackB_writetrunc(oggpack_buffer *b,long bits);
extern void oggpackB_writealign(oggpack_buffer *b);
extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits);
extern void oggpackB_reset(oggpack_buffer *b);
extern void oggpackB_writeclear(oggpack_buffer *b);
extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits);
extern long oggpackB_look(oggpack_buffer *b,int bits);
extern long oggpackB_look1(oggpack_buffer *b);
extern void oggpackB_adv(oggpack_buffer *b,int bits);
extern void oggpackB_adv1(oggpack_buffer *b);
extern long oggpackB_read(oggpack_buffer *b,int bits);
extern long oggpackB_read1(oggpack_buffer *b);
extern long oggpackB_bytes(oggpack_buffer *b);
extern long oggpackB_bits(oggpack_buffer *b);
extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b);/* Ogg BITSTREAM PRIMITIVES: encoding **************************/extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op);
extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov,int count, long e_o_s, ogg_int64_t granulepos);
extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og);
extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill);
extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og);
extern int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill);/* Ogg BITSTREAM PRIMITIVES: decoding **************************/extern int ogg_sync_init(ogg_sync_state *oy);
extern int ogg_sync_clear(ogg_sync_state *oy);
extern int ogg_sync_reset(ogg_sync_state *oy);
extern int ogg_sync_destroy(ogg_sync_state *oy);
extern int ogg_sync_check(ogg_sync_state *oy);extern char *ogg_sync_buffer(ogg_sync_state *oy, long size);
extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes);
extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);/* Ogg BITSTREAM PRIMITIVES: general ***************************/extern int ogg_stream_init(ogg_stream_state *os,int serialno);
extern int ogg_stream_clear(ogg_stream_state *os);
extern int ogg_stream_reset(ogg_stream_state *os);
extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno);
extern int ogg_stream_destroy(ogg_stream_state *os);
extern int ogg_stream_check(ogg_stream_state *os);
extern int ogg_stream_eos(ogg_stream_state *os);extern void ogg_page_checksum_set(ogg_page *og);extern int ogg_page_version(const ogg_page *og);
extern int ogg_page_continued(const ogg_page *og);
extern int ogg_page_bos(const ogg_page *og);
extern int ogg_page_eos(const ogg_page *og);
extern ogg_int64_t ogg_page_granulepos(const ogg_page *og);
extern int ogg_page_serialno(const ogg_page *og);
extern long ogg_page_pageno(const ogg_page *og);
extern int ogg_page_packets(const ogg_page *og);extern void ogg_packet_clear(ogg_packet *op);#ifdef __cplusplus
}
#endif#endif /* _OGG_H */
✨3.2 libogg 库函数解析
下面简单介绍在Ogg封装格式解码过程中需要用到的库函数,需要了解更多库函数解释的可以参考:https://xiph.org/ogg/doc/libogg/reference.html
int ogg_sync_init(ogg_sync_state *oy);
功能:将 ogg_sync_state *结构体 初始化为已知状态
参数:ogg_sync_state *
long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
功能: 将同步到比特流中的下一页,并返回关于我们前进或跳过了多少字节的信息。
返回值:-n:跳过的字节;0:页没准备好,需要更多的字节,且没跳过字节;n:页的总字节数n
char *ogg_sync_buffer(ogg_sync_state *oy, long size);
功能:分配数据缓冲区
int ogg_sync_wrote(ogg_sync_state *oy, long bytes);
功能:告知添加了多少字节
int ogg_page_bos(const ogg_page *og);
功能:起始页返回1//--------------------------------------
int ogg_page_eos(const ogg_page *og);
功能:结束页返回1//--------------------------------------
ogg_int64_t ogg_page_granulepos(const ogg_page *og);
功能:获取页的 granule position//--------------------------------------
int ogg_page_serialno(const ogg_page *og);
功能:获取流的序列号//--------------------------------------
long ogg_page_pageno(const ogg_page *og);
功能:获取页的序号//--------------------------------------
int ogg_page_packets(const ogg_page *og);
功能:获取页的的包(段segment)个数
int ogg_stream_init(ogg_stream_state *os,int serialno);
功能:初始化ogg_stream_state结构,并分配适当的内存以准备编码或解码//--------------------------------------
int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
功能:将一个完整的页面添加到比特流中。//--------------------------------------
int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
功能:数据已经被提交到ogg_stream_state之后。每次连续调用该函数都会返回从这些数据段构建的下一个完整数据包。//--------------------------------------
int ogg_stream_clear(ogg_stream_state *os);
功能:这个函数清除并释放ogg_stream_state结构使用的内部内存,但不释放结构本身。在同一个结构上多次调用ogg_stream_clear是安全的。
![]()
🎄四、Ogg封装格式使用 libogg 库解码——C语言代码
在 上篇文章 第五小节 ,笔者用C语言写了一个读取Ogg文件的测试程序,现在,这里使用ligogg库再实现一个Ogg封装格式文件读取的程序。
解码程序步骤:
- 1、打开文件;
- 2、调用
ogg_sync_init初始化一个ogg_sync_state结构体; - 3、获取一页数据,并处理;
- 3.1、根据序列号初始化一个比特流
ogg_stream_init; - 3.2、把页数据给到比特流
ogg_stream_pagein; - 3.3、获取数据包
ogg_stream_packetout; - 3.4、释放比特流;
- 3.1、根据序列号初始化一个比特流
- 4、关闭文件
程序使用的 48000Hz-s16le-1ch-ChengDu.opus ,是opus编码的Ogg封装文件。
程序编译需要了解前面编译好的ligogg库和头文件,参考:
gcc liboggDec.c ../../libogg-1.3.5/result_gcc/lib/libogg.a -I ../../libogg-1.3.5/result_gcc/include/
Ogg文件解码程序如下,虽然并没有完整解析出音频,但可以加深对libogg库的理解:
// ligoggDec.c
// gcc liboggDec.c ../../libogg-1.3.5/result_gcc/lib/libogg.a -I ../../libogg-1.3.5/result_gcc/include/
/*
* ogg_sync_init:将结构体初始化为已知状态* ogg_sync_pageseek: 将同步到比特流中的下一页,并返回关于我们前进或跳过了多少字节的信息。返回值:-n:跳过的字节;0:页没准备好,需要更多的字节,且没跳过字节;n:页的总字节数n* ogg_sync_buffer:分配数据缓冲区* ogg_sync_wrote:告知添加了多少字节* ogg_page_serialno:获取序列号* ogg_page_bos:起始页* ogg_page_eos:结束页* ogg_page_pageno:获取页号* ogg_page_granulepos:获取页 granule pos* ogg_page_packets:获取该页 段 (segment)个数* ogg_stream_init:初始化ogg_stream_state结构,并分配适当的内存以准备编码或解码* ogg_stream_pagein:将一个完整的页面添加到比特流中。* ogg_stream_packetout:数据已经被提交到ogg_stream_state之后。每次连续调用该函数都会返回从这些数据段构建的下一个完整数据包。* ogg_stream_clear:这个函数清除并释放ogg_stream_state结构使用的内部内存,但不释放结构本身。在同一个结构上多次调用ogg_stream_clear是安全的。
*/#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include "ogg/ogg.h"#define CHUNK 4096ogg_sync_state g_ogsync;
ogg_page g_page;// 获取下一页数据 2023-11-03 10:31:28
static int get_next_page(FILE *f, ogg_sync_state *ogsync, ogg_page *page,ogg_int64_t *written)
{int ret;char *buffer;size_t bytes;while((ret = ogg_sync_pageseek(ogsync, page)) <= 0) {if(ret < 0) {/* unsynced, we jump over bytes to a possible capture - we don't need to read more just yet */printf("WARNING: Hole in data (%d bytes) found at approximate offset %" PRId64 " bytes. Corrupted Ogg.\n", -ret, *written);continue;}/* zero return, we didn't have enough data to find a whole page, read */buffer = ogg_sync_buffer(ogsync, CHUNK);bytes = fread(buffer, 1, CHUNK, f);if(bytes == 0) {ogg_sync_wrote(ogsync, 0);return 0;}ogg_sync_wrote(ogsync, (long)bytes);*written += bytes;}return 1;
}int main()
{FILE *file = fopen("48000Hz-s16le-1ch-ChengDu.opus", "rb");if(!file) {printf("fopen error\n");return -1;}ogg_sync_init(&g_ogsync);ogg_int64_t written;while (get_next_page(file, &g_ogsync, &g_page, &written)){int packets = ogg_page_packets(&g_page);printf("page_num:%03lu; ",ogg_page_pageno(&g_page));printf("Oggs:%c %c %c %c; ",g_page.header[0],g_page.header[1],g_page.header[2],g_page.header[3]);printf("type=%d, granule_position:%08lld, seg_num=%d; ", g_page.header[5],(long long)ogg_page_granulepos(&g_page), packets);// 准备bit流ogg_stream_state streamState;ogg_packet packet;ogg_stream_init(&streamState, ogg_page_serialno(&g_page)); // 给定一个流序列号,初始化 streamStateogg_stream_pagein(&streamState, &g_page); // 将页数据给到 比特流int i = 0;for(i=0; i<packets; i++){ogg_stream_packetout(&streamState, &packet);if(packet.bytes >= 19 && memcmp(packet.packet, "OpusHead", 8)==0){printf("OpusHead; ");}}printf("\n");ogg_stream_clear(&streamState);}return 0;
}
Ogg编码程序,这里就不给了,需要的话,可以去看看opus-tool工具的源码。
![]()
🎄五、总结
本文介绍了ligogg-1.3.5库的下载、编译,以及个别库函数的用法,最后给出一个Ogg封装格式的解码程序代码。

如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁
相关文章:
【音视频 | Ogg】libogg库详细介绍以及使用——附带libogg库解析.opus文件的C源码
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...
如何使用群晖NAS的Audio Station结合内网穿透实现远程访问本地曲库
文章目录 本教程解决的问题是:按照本教程方法操作后,达到的效果是本教程使用环境:1 群晖系统安装audiostation套件2 下载移动端app3 内网穿透,映射至公网 很多老铁想在上班路上听点喜欢的歌或者相声解解闷儿,于是打开手…...
要在CentOS中安装Docker
要在CentOS中安装Docker,请按照以下步骤进行操作: 首先,确保系统已更新到最新版本。运行以下命令: sudo yum update接下来,安装需要的软件包以允许使用HTTPS进行软件包下载。运行以下命令: sudo yum ins…...
Android Gldie复用只取之前decode过的缓存resource,Kotlin
Android Gldie复用只取之前decode过的缓存resource,Kotlin import android.graphics.Bitmap import android.os.Bundle import android.util.Log import android.widget.ImageView import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.life…...
EasyExcel实现动态表头功能
EasyExcel实现动态表头功能 开发过程中,大部分都会使用到导出报表功能,目前阶段会用得有 poi导出(暂无), easyexcel导出(官方文档,https://easyexcel.opensource.alibaba.com/docs/current/&am…...
Python | 安装、环境配置及包的安装
Python | 安装、环境配置及包的安装 一、前言二、python安装及编辑器配置2.1 python安装2.2 python调试2.3 python编辑器 | PyCharm2.3.1 PyCharm下载2.3.2 PyCharm安装2.3.3 PyCharm启动界面2.3.4 PyCharm初步设置2.3.5 PyCharm环境配置(含Python Interpreter配置)2.3.5.1 New…...
CentOS 7 安装 JDK17(注意版本号要与自己的版本一致)
查看是否有自带的 JDK java -versionrpm -qa | grep jdk卸载自带 JDK rpm -e --nodeps [name] # 如 rpm -e --nodeps java-1.8.0-openjdk-1.8.0.242.b08-1.el7.x86_64查看自带 JDK 是否卸载干净 java -versionrpm -qa | grep jdk在 oracle 官网下载自己所需 JDK 版本&#x…...
JavaScript 数组操作
JavaScript 中的数组提供了各种操作方法,包括增加、删除、修改、查找、排序、遍历、去重和转换等。以下是一些常用的数组操作方法: 增加元素 push(element1, element2, …, elementN): 将一个或多个元素添加到数组的末尾,并返回新数组的长度…...
idea使用lombok编译问题
idea编译报错问题如下: java: You arent using a compiler supported by lombok, so lombok will not work and has been disabled.Your processor is: com.sun.proxy.$Proxy26Lombok supports: OpenJDK javac, ECJ解决方案:在idea配置中File->Setti…...
GoLong的学习之路(番外)如何使用依赖注入工具:wire
我为什么要直接写番外呢?其原因很简单。项目中会使用,其实在这里大家就可以写一些项目来了。 依赖注入的工具本质思想其实都大差不差。无非控制反转和依赖注入。 文章目录 控制反转为什么需要依赖注入工具 wire的概念提供者(provider&#x…...
【pyspider】爬取ajax请求数据(post),如何处理python2字典的unicode编码字段?
情景:传统的爬虫只需要设置fetch_typejs即可,因为可以获取到整个页面。但是现在ajax应用越来越广泛,所以有的网页不能用此种爬虫类型来获取页面的数据,只能用slef.crawl()来发起http请求来抓取数据。 直接上例子: 可以…...
torch.cumprod实现累乘计算
cumprod取自“cumulative product”的缩写,即“累计乘法”。 数学公式为: y i x 1 x 2 x 3 . . . x i y_ix_1\times{x_2}\times{x_3}\times{...}\times{x_i} yix1x2x3...xi 官方链接:torch.cumprod 用法: impo…...
设计模式之迭代器模式
什么是迭代器模式 迭代器模式(Iterator pattern)是一种对象行为型设计模式,它提供了一种方法来顺序访问聚合对象中的元素,而又不暴露该对象的内部表示,同时也可以将迭代逻辑与聚合对象的实现分离,增强了代码…...
使用SSH ,让windows和linux互通
简介 SSH 是一种安全网络协议,旨在让客户端和服务器之间进行安全的数据传输。SSH 的核心思想是利用公钥加密技术和共享密钥加密技术相结合的方式,使客户端和服务器之间建立起安全的连接。 当客户端发起连接请求时,服务器会对客户端进行身份验…...
常用设计模式——策略模式
策略模式是什么 策略模式(Strategy):针对一组算法,将每一个算法封装起来,从而使得它们可以相互替换。 比如我们一个软件的会员等级,每一个等级都会有对应的一些等级权益,那么每一个等级权益就…...
牛客网 CM11.链表分割
目录 1.解题思路2.代码实现 1.解题思路 此题目思路相对简单,利用双指针,一个指针指向小于val的,一个指针指向大于等于val的,但实现起来,如果仅仅使用单链表,那么还需特别判断第一个指针是否为空从而特意做…...
[iOS开发]iOS中TabBar中间按钮凸起的实现
在日常使用app的过程中,经常能看到人家实现了底部分栏控制器的中间按钮凸起的效果,那么这是怎么实现的呢? 效果演示: 实现原理: 创建按钮 创建一个UITabBar的子类,重写它的layoutSubviews方法࿱…...
数字时代,企业的数据共享意味着什么?
随着数字化整体在社会方方面面的推进,通过数据直接或间接创造的价值越来越大,逐渐成为了构建现代社会的重要要素。而对于企业来说,数据也是在数字经济中容易接触也切实能够利用产生大量价值,所以如何最大化利用数据,让…...
壹[1],QT自定义控件创建(QtDesigner)
1,环境 Qt 5.14.2 VS2022 原因:厌烦了控件提升的繁琐设置,且看不到界面预览显示。 2,QT制作自定义控件 2.1,New/其他项目/Qt4 设计师自定义控件 2.2,设置项目名称 2.3,设置 2.4,设…...
解决Java对接LDAP AD域登录出现Unprocessed Continuation Reference(s)错误
出现该错误的原因,主要是因为Java namingx的库,默认选项是未设置跟随,389返回的是AD域条目的引用,需要进行引用跟随。 解决方法分为两种,第一类不使用全局目录服务的端口389和636,而是使用真实端口 把代码…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
rknn toolkit2搭建和推理
安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...
