【音视频 | Ogg】libogg库详细介绍以及使用——附带libogg库解析.opus文件的C源码

2023-11-03 15:45

本文主要是介绍【音视频 | 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源码

目录

  • 🎄一、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封装格式文件读取的程序。

// 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源码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/339208

相关文章

SpringBoot线程池配置使用示例详解

《SpringBoot线程池配置使用示例详解》SpringBoot集成@Async注解,支持线程池参数配置(核心数、队列容量、拒绝策略等)及生命周期管理,结合监控与任务装饰器,提升异步处理效率与系统... 目录一、核心特性二、添加依赖三、参数详解四、配置线程池五、应用实践代码说明拒绝策略(Rejected

C++ Log4cpp跨平台日志库的使用小结

《C++Log4cpp跨平台日志库的使用小结》Log4cpp是c++类库,本文详细介绍了C++日志库log4cpp的使用方法,及设置日志输出格式和优先级,具有一定的参考价值,感兴趣的可以了解一下... 目录一、介绍1. log4cpp的日志方式2.设置日志输出的格式3. 设置日志的输出优先级二、Window

Ubuntu如何分配​​未使用的空间

《Ubuntu如何分配​​未使用的空间》Ubuntu磁盘空间不足,实际未分配空间8.2G因LVM卷组名称格式差异(双破折号误写)导致无法扩展,确认正确卷组名后,使用lvextend和resize2fs... 目录1:原因2:操作3:报错5:解决问题:确认卷组名称​6:再次操作7:验证扩展是否成功8:问题已解

Qt使用QSqlDatabase连接MySQL实现增删改查功能

《Qt使用QSqlDatabase连接MySQL实现增删改查功能》这篇文章主要为大家详细介绍了Qt如何使用QSqlDatabase连接MySQL实现增删改查功能,文中的示例代码讲解详细,感兴趣的小伙伴... 目录一、创建数据表二、连接mysql数据库三、封装成一个完整的轻量级 ORM 风格类3.1 表结构

使用Docker构建Python Flask程序的详细教程

《使用Docker构建PythonFlask程序的详细教程》在当今的软件开发领域,容器化技术正变得越来越流行,而Docker无疑是其中的佼佼者,本文我们就来聊聊如何使用Docker构建一个简单的Py... 目录引言一、准备工作二、创建 Flask 应用程序三、创建 dockerfile四、构建 Docker

Python使用vllm处理多模态数据的预处理技巧

《Python使用vllm处理多模态数据的预处理技巧》本文深入探讨了在Python环境下使用vLLM处理多模态数据的预处理技巧,我们将从基础概念出发,详细讲解文本、图像、音频等多模态数据的预处理方法,... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

Python使用pip工具实现包自动更新的多种方法

《Python使用pip工具实现包自动更新的多种方法》本文深入探讨了使用Python的pip工具实现包自动更新的各种方法和技术,我们将从基础概念开始,逐步介绍手动更新方法、自动化脚本编写、结合CI/C... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

Conda与Python venv虚拟环境的区别与使用方法详解

《Conda与Pythonvenv虚拟环境的区别与使用方法详解》随着Python社区的成长,虚拟环境的概念和技术也在不断发展,:本文主要介绍Conda与Pythonvenv虚拟环境的区别与使用... 目录前言一、Conda 与 python venv 的核心区别1. Conda 的特点2. Python v

Spring Boot中WebSocket常用使用方法详解

《SpringBoot中WebSocket常用使用方法详解》本文从WebSocket的基础概念出发,详细介绍了SpringBoot集成WebSocket的步骤,并重点讲解了常用的使用方法,包括简单消... 目录一、WebSocket基础概念1.1 什么是WebSocket1.2 WebSocket与HTTP

C#中Guid类使用小结

《C#中Guid类使用小结》本文主要介绍了C#中Guid类用于生成和操作128位的唯一标识符,用于数据库主键及分布式系统,支持通过NewGuid、Parse等方法生成,感兴趣的可以了解一下... 目录前言一、什么是 Guid二、生成 Guid1. 使用 Guid.NewGuid() 方法2. 从字符串创建