【音视频 | opus】opus编码的Ogg封装文件详解

这篇具有很好参考价值的文章主要介绍了【音视频 | opus】opus编码的Ogg封装文件详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍 opus 编码的 Ogg 封装文件🍭
😎金句分享😎:🍭🍭

本文未经允许,不得转发!!!

opus和Ogg相关系列文章:
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封装文件详解


opushead wopustags,音视频基础,音视频,opus,Ogg,Ogg封装格式解析,Ogg解码C语言

🎄一、概述

前面的文章 Ogg封装格式详解 介绍了Ogg格式的封装,介绍了封装过程、Ogg的页结构、Ogg的段,但没涉及到每个段的内容,因为这跟编码有关系。本文就介绍 opus 编码在 Ogg 封装文件中是怎样存储的,同样地,从一个 opus 编码的Ogg文件去查看十六进制,最终了解 opus 编码 Ogg 封装文件的整个结构,这样就可以轻易将这类文件解码为PCM了。

opus 编码的Ogg文件结构如下图:

  • 逻辑Ogg比特流中的第一个数据包必须包含ID头部数据(ID Header),该头部数据将流唯一标识为Opus音频。
  • 逻辑Ogg比特流中的第二个数据包必须包含注释头部数据(Comment Header),其中包含用户提供的元数据。
  • 之后的所有页面(page)都是音频数据页面。
    opushead wopustags,音视频基础,音视频,opus,Ogg,Ogg封装格式解析,Ogg解码C语言
    下文分析的Ogg封装文件为 48000Hz-s16le-1ch-ChengDu.opus,下载链接:https://download.csdn.net/download/wkd_007/88492683

opushead wopustags,音视频基础,音视频,opus,Ogg,Ogg封装格式解析,Ogg解码C语言

🎄二、ID头部数据(ID Header)

✨2.1、ID 头部数据的介绍

opus编码的逻辑Ogg比特流中,第一页必须包含ID头部数据,其结构如下图,包括8个字段,各个字段代表的含义如下:

opushead wopustags,音视频基础,音视频,opus,Ogg,Ogg封装格式解析,Ogg解码C语言

  • 1、Magic Signature(8字节):

    这是一个8位字节(64位)字段,允许编解码器识别,并且是人类可读的。它按顺序包含以下的字母:

    0x4F 'O'
    0x70 'p'
    0x75 'u'
    0x73 's'
    0x48 'H'
    0x65 'e'
    0x61 'a'
    0x64 'd'
    

    从“Op”开始有助于将其与音频数据包区分开来,因为这是一个无效的TOC序列。

  • 2、Version (1字节, unsigned):
    对于此版本的封装规范,版本号必须始终为“1”。实现应该将版本号的前四位与已识别规范的版本号匹配的流视为与该规范向后兼容。也就是说,版本号可以分为“主要”和“次要”版本子字段,次要子字段的变化(在较低的四位中)表示兼容的变化。例如,本规范的实现应该接受版本号为“15”或更低的任何流,并且应该假设版本号为”16“或更高的任何流不兼容。选择初始版本“1”是为了防止实现依赖此八位字节作为“OpusHead”字符串的null终止符。

  • 3、Output Channel Count ‘C’ (1字节, unsigned)
    这是输出通道的数量。这可能与编码信道的数量不同,编码信道的数目可以在逐包的基础上改变。此值不得为零。最大允许值取决于通道映射族,可能大到255。详见[RFC7845]文档的第5.1.1节。

  • 4、Pre-skip (2字节, unsigned, little endian):

    这是开始播放时要从解码器输出中丢弃的采样数(48 kHz),也是要从页面的颗粒位置中减去以计算其PCM采样位置的数量。当裁剪现有Ogg Opus流的开头时,建议预跳过至少3840个样本(80ms),以确保解码器完全收敛。

  • 5、Input Sample Rate (4字节, unsigned, little endian):

    这是原始输入(编码前)的采样率,单位为Hz。该字段不是用于播放编码数据的采样率。

    Opus可以在4、6、8、12和20kHz的内部音频带宽之间切换。流中的每个数据包可以具有不同的音频带宽。不管音频带宽如何,参考解码器都支持以8、12、16、24或48kHz的采样率对任何流进行解码。传递到编码器的音频的原始采样率不被有损压缩所保留。

    Ogg Opus播放器应根据以下程序选择播放采样率:

    1.如果硬件支持48 kHz播放,则以48 kHz进行解码。

    2.否则,如果硬件的最高可用采样率是支持的速率,则以该采样率进行解码。

    3.否则,如果硬件的最高可用采样率小于48kHz,则以高于最高可用硬件速率的下一个更高的Opus支持速率进行解码并重新采样。

    4.否则,以48 kHz解码并重新采样。

    然而,“输入采样率”字段允许复用器将原始输入流的采样率作为元数据传递。当用户需要输出采样率来匹配输入采样率时,这是有用的。例如,当不播放输出时,将PCM格式样本写入磁盘的实现可能会选择将音频重新采样回原始输入采样率,以减少用户的意外,因为用户可能会合理地期望以相同的采样率返回文件。

    零值表示“未指定”。复用器应该写入实际输入采样率或零,但使用该字段执行某些操作的实现应该注意,如果给定疯狂的值(例如,如果请求,不要实际将输出上采样到10MHz),则行为要理智。实现应支持 8kHz 和 192kHz(包括8kHz)之间的输入采样率。此范围之外的速率可以通过回落到默认速率 48kHz 来忽略。

  • 6、Output Gain (2字节, signed, little endian):

    这是解码时要应用的增益。它是对解码器输出进行缩放以获得所需播放量的因子的20*log10,存储在具有8个小数比特的16比特、带符号的2的补码定点值中(即Q7.8[Q-NOTATION])。

    为了应用增益,实现可以使用以下内容:

    sample *= pow(10, output_gain/(20.0*256))
    

    其中“output_gain”是来自标头的原始16位值。

    玩家和媒体框架应该默认应用它。如果播放器选择应用任何音量调整或增益修改,如R128_TRACK_AIN(见第5.2节),则除了此输出增益外,还必须应用该调整,以实现标准化音量的播放。

    复用器应该将该字段设置为零,而不是在编码之前应用任何增益,只要这是可能的,并且不会与用户的愿望相冲突。非零输出增益表示在编码之后调整了增益,或者用户希望在保持恢复原始信号幅度的能力的同时调整增益以进行回放。

    尽管输出增益具有巨大的范围(+/-128 dB,足以将听不见的声音放大到身体疼痛的阈值),但大多数应用程序只能合理地使用零附近这个范围的一小部分。大范围的部分作用是确保增益始终可以在OpusHead和R128增益标签之间无损传输(见下文)而不会饱和。

  • 7、Channel Mapping Family (1字节, unsigned):

    这个八位字节表示输出通道的顺序和语义。

    该八位位组的每个当前指定值都指示一个映射族,该映射族定义了一组允许的通道计数,以及每个允许的通道数的有序通道名称集。详见[RFC7845]文档的第5.1.1节。

  • 8、Channel Mapping Table:

    此表定义了从编码流到输出通道的映射。其内容见[RFC7845]文档的第5.1.1节。ID标头中的所有字段都是必需的,但“通道映射表”除外,当通道映射族为0时,必须省略该字段,否则为必需字段。如果流包含的ID标头没有足够的数据用于这些字段,即使它包含有效的“魔术签名”,实现也应该将其视为无效。该规范的未来版本,甚至是向后兼容的版本,可能会在ID头中包含额外的字段。如果ID标头具有兼容的主版本,但具有较大的次版本,则实现不得将其视为无效,因为它包含此处未指定的其他数据,前提是它仍然在第一页上完成。

✨2.2、.opus 文件 ID头部数据 分析

现在按照上面的字段,分析opus编码的Ogg文件,用Notepad打开 48000Hz-s16le-1ch-ChengDu.opus 并查看十六进制模式:

opushead wopustags,音视频基础,音视频,opus,Ogg,Ogg封装格式解析,Ogg解码C语言

  • 前面蓝色背景的部分(包括0x13)是Ogg页头部数据,不清楚的看 上篇文章 的 4.2 节;
  • 紫色框开始是opus编码的ID头部数据,内容是8个字符:OpusHead
  • 接下去的蓝色框是版本号,目前的版本,该值为 1
  • 紧接着的蓝色框是声道数量,这里值为 1 ,表示单声道;
  • 后面的橙色框表示 “开始播放时要从解码器输出中丢弃的采样数”,值为0x0138
  • 接着的绿色框表示 “原始输入(编码前)的采样率”,值为0xbb80,对应十进制 48000
  • 后面的蓝色框表示 “解码时要应用的增益”;
  • 后面的黑色框表示 “表示输出通道的顺序和语义”,值为 0 ,代表使用映射族0,允许的通道数:1或2,且省略通道映射表(Channel Mapping Table);

opushead wopustags,音视频基础,音视频,opus,Ogg,Ogg封装格式解析,Ogg解码C语言

🎄三、注释头部数据(Comment Header)

✨3.1、注释头部数据的介绍

opus编码的逻辑Ogg比特流中,第二页必须包含注释头部数据。它可能跨越多个页面(page),从逻辑流的第二页开始。无论它跨越多少页,注释头数据包都必须结束在一个完整的页面,其结构如下图,包括6个字段,各个字段代表的含义如下:
opushead wopustags,音视频基础,音视频,opus,Ogg,Ogg封装格式解析,Ogg解码C语言

  • 1、Magic Signature(8个字节):

    这是一个8位字节(64位)字段,允许编解码器识别,并且是人类可读的。它按顺序包含以下神奇数字:

    0x4F 'O'
    0x70 'p'
    0x75 'u'
    0x73 's'
    0x54 'T'
    0x61 'a'
    0x67 'g'
    0x73 's'
    

    从“Op”开始有助于将其与音频数据包区分开来,因为这是一个无效的TOC序列。

  • 2、Vendor String Length (4个字节, unsigned, little endian):

    此字段给出下个字段Vendor String的长度,单位为八位字节。它不得指示供应商字符串比数据包的其余部分长。

  • 3、Vendor String (variable length, UTF-8 vector):

    这是一个用于供应商信息的简单可读标签,编码为UTF-8字符串[RFC3629]。不需要终止空八位字节。

    此标签旨在识别编解码器编码器和封装实现,以跟踪技术行为的差异。面向用户的应用程序可以使用“ENCODER”用户注释标记来标识自己。

  • 4、User Comment List Length (4个字节, unsigned, little endian):

    此字段指示用户提供的注释个数。它可能表示用户提供的注释为零,在这种情况下,数据包中没有其他字段。它不能表明有太多的注释,以至于注释字符串长度需要比数据包其余部分更多的数据。

  • 5、User Comment #i String Length (4个字节, unsigned, little endian):

    此字段给出下个字段User Comment #i String的长度,单位为八位字节。“用户评论列表长度”字段指示的每个用户评论都有一个。它不能指示字符串比数据包的其余部分长。

  • 6、User Comment #i String (variable length, UTF-8 vector):

    此字段包含编码为UTF-8字符串的单个用户注释[RFC3629]。“用户评论列表长度”字段指示的每个用户评论都有一个。

✨3.2、.opus 文件 注释头部数据 分析

下图是用Notepad打开 48000Hz-s16le-1ch-ChengDu.opus 并查看十六进制模式的截图,这里分析的是第二页数据:
opushead wopustags,音视频基础,音视频,opus,Ogg,Ogg封装格式解析,Ogg解码C语言

  • 前面蓝色背景的部分是Ogg页头部数据,不清楚的看 上篇文章 的 4.2 节第二页数据;
  • 紫色框开始是opus编码的注释头部数据,内容是8个字符:OpusTags
  • 接下去的红色色框的4个字节是供应商字符串长度, 此字段给出下个字段Vendor String的长度,这里是0x0b
  • 紧接着的红色框的11个字节就是供应商字符串,内容是libopus 1.1
  • 后面的绿色框表示 “注释个数”,值为0x01,表示只有一个注释 ;
  • 接着的蓝色框表示 “第一个注释字符串的长度”,值为0x25,对应十进制 37,表示后面有37个字符的注释;
  • 后面的橙色框表示 “注释字符串”,内容是ENCODER=opusenc form opus-tools 0.1.8,共37个字符;

opushead wopustags,音视频基础,音视频,opus,Ogg,Ogg封装格式解析,Ogg解码C语言

🎄四、opus 编码数据包

在一个opus编码的Ogg格式文件中,除了一个ID头部数据包和一个 注释头部数据包(有时可以跨多页),剩下的都是 opus编码音频数据包,音频数据包也是存储在Ogg格式文件的各个段(Segment)中,下面从一个实际的Ogg文件分析音频数据包。

下图是用Notepad打开 48000Hz-s16le-1ch-ChengDu.opus 并查看十六进制模式的截图,这里分析的是第三页数据:

opushead wopustags,音视频基础,音视频,opus,Ogg,Ogg封装格式解析,Ogg解码C语言

  • 图中黑色框表示该Ogg页数据中有 0x33(十进制51)个段(Segment),但并不表示有51个opus音频数据包,因为段的长度为0xff时,表示该段存不下一个音频数据包,下个段仍然是这个包的数据。
  • 蓝色背景的51个字节就是各个段的长度,可以看到第一个段长度是0xff,表示第一个音频包存储了2个段,第一个音频包的实际长度应该是0xff+0x06;后面49个段长度中,都没有0xff,说明每个都存储了一个音频数据包。所以这一页应该是50个音频数据包。每个数据包读取后,都可以直接送到 opus-1.4 的库去解码成PCM音频数据。

opushead wopustags,音视频基础,音视频,opus,Ogg,Ogg封装格式解析,Ogg解码C语言

🎄五、opus编码的Ogg封装文件解码C语言源码

清楚了前面的知识,就可以对opus编码的Ogg文件进行解码了,你可以使用 libogg库加上 opus-1.4 的库进行解码,那样会更简洁一点,下面给出的源码只使用了opus-1.4去解码音频包,有很大的参考价值:

opusDec.h

/**
 * @file opusDec.h
 * @author wkd_007
 * @date 2023-10-27 15:47:38
 */
#ifndef	__OPUS_DEC_H__
#define __OPUS_DEC_H__

#include "opus/opus.h"

#define MAX_OPUS_DEC_FRAME  48000   // opus解码最大采样点个数,如果个数时间小于120ms,可能停止解码,这里设置1000ms的个数
#define OPUS_DEC_CHANNELS   2
class COpusDec
{
public:
    COpusDec();
    ~COpusDec();

    int CreateOpusDecoder(int sampleRate, int channels);
    int OpusDecode(unsigned char* in_data, int in_len, short *out_buf);

private:
    OpusDecoder *decoder;   // opus 解码器指针
    int sample_rate;        // 采样率
    int channel_num;        // 通道数
};
#endif// __OPUS_DEC_H__


opusDec.cpp

/**
 * @file 	opusDec.cpp
 * @author 	wkd_007
 * @brief 	opus 解码
 * @date 	2023-10-27 15:38:43
 */

#include <stdio.h>
#include "opusDec.h"

COpusDec::COpusDec()
{
	decoder = NULL;
	sample_rate = 0;
	channel_num = 0;
}

COpusDec::~COpusDec()
{
	sample_rate = 0;
	channel_num = 0;
	if(decoder)
	{
		opus_decoder_destroy(decoder);
		decoder = NULL;
	}
}

int COpusDec::CreateOpusDecoder(int sampleRate, int channels)
{
	int err = 0;
    decoder = opus_decoder_create(sampleRate, channels, &err);
	if(err != OPUS_OK || decoder == NULL)
    {
        printf("[%s %d]err=%d decoderIsNULL=%d\n",__FILE__,__LINE__,err, decoder == NULL);
        return -1;
	}
    opus_decoder_ctl(decoder, OPUS_SET_LSB_DEPTH(16));
    sample_rate = sampleRate;
    channel_num = channels;
	return err;
}

int COpusDec::OpusDecode(unsigned char* in_data, int in_len, short *out_buf)
{
	if(decoder == NULL)
		return -1;
    int frame_size = opus_decode(decoder, in_data, in_len, out_buf, MAX_OPUS_DEC_FRAME, 0);
    if (frame_size < 0)
    {
       printf("[%s %d] frame_size=%d in_len=%d\n",__FILE__,__LINE__, frame_size,in_len);
       return frame_size;
    }
    return frame_size;
}


readOggFile.c

// g++ readOggFile.c opusDec.cpp ../../opus-1.4/result_gcc/lib/libopus.a -I ../../opus-1.4/result_gcc/include/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "opusDec.h"

COpusDec g_OpusDec;

// 8字节数组转成 unsigned long long
unsigned long long ToULL(unsigned char num[8], int len)
{
	unsigned long long ret = 0;
	if(len==8)
	{	
		int i=0;
		for(i=0; i<len; i++)
		{
			ret |= ((unsigned long long)num[i] << (i*8));
		}
	}
	return ret;
}

// 4字节数组转成 unsigned int
unsigned int ToUInt(unsigned char num[4], int len)
{
	unsigned int ret = 0;
	if(len==4)
	{
		int i=0;
		for(i=0; i<len; i++)
		{
			ret |= ((unsigned int)num[i] << (i*8));
		}
	}
	return ret;
}

int readOggPage(char *oggFile)
{
	typedef struct PAGE_HEADER{  
		char           Oggs[4];        
		unsigned char  ver;
		unsigned char  header_type_flag;
		unsigned char  granule_position[8];
		unsigned char  stream_serial_num[4];
		unsigned char  page_sequence_number[4];
		unsigned char  CRC_checksum[4];
		unsigned char  seg_num;
		unsigned char  segment_table[];
	}PAGE_HEADER;
	
	FILE *fp=fopen(oggFile,"rb");
	FILE *fpout=fopen("opus_out.pcm","wb+");;
	
	while(fp!=NULL && !feof(fp))
	{
		// 1、读取 page_header
		PAGE_HEADER page_header;
		if(1 != fread(&page_header,sizeof(page_header),1,fp))
			break;
		printf("page_num:%03u; ",ToUInt(page_header.page_sequence_number, 4));
		printf("Oggs:%c %c %c %c; ",page_header.Oggs[0],page_header.Oggs[1],page_header.Oggs[2],page_header.Oggs[3]);
		printf("type=%d, granule_position:%08llu; ", page_header.header_type_flag,ToULL(page_header.granule_position, 8));
		//printf("seg_num:%d \n",page_header.seg_num);
		
		// 2、读取 Segment_table
		unsigned char *pSegment_table = (unsigned char *)malloc(page_header.seg_num);
		fread(pSegment_table,sizeof(unsigned char),page_header.seg_num,fp);
		
		// 3、计算段数据总大小
		unsigned int TotalSegSize = 0;
		int i=0;
		for(i=0; i<page_header.seg_num; i++)
		{
			TotalSegSize += pSegment_table[i];
		}
		printf("TotalSegSize:%d \n",TotalSegSize);
		
		// 4、读取段数据
		unsigned char *pSegment_data = (unsigned char *)malloc(TotalSegSize);
		fread(pSegment_data,sizeof(unsigned char),TotalSegSize,fp);
		
		if(page_header.header_type_flag == 4)
			printf("Last 4 Byte: %x %x %x %x\n",pSegment_data[TotalSegSize-4],pSegment_data[TotalSegSize-3], pSegment_data[TotalSegSize-2],pSegment_data[TotalSegSize-1]);
		
		// 5、解码opus
		unsigned sample_pos = ToULL(page_header.granule_position, 8);
		if(sample_pos)
		{
			short out_buf[48000*2] = {0};
			int decodedLen = 0; // 已经解码的长度
			int preSegLen =0;	// 前面分段的长度
			
			for(i=0; i<page_header.seg_num; i++)
			{
				if(pSegment_table[i] == 255)// 这个包延续到后面,把该段长度累加起来
				{
					preSegLen += pSegment_table[i];
					continue;
				}
				
				int decFrames = g_OpusDec.OpusDecode((unsigned char*)pSegment_data+decodedLen, (int)preSegLen+pSegment_table[i], out_buf);
				if(decFrames < 0)
				{
					printf("decodedLen=%d TotalSegSize=%d pSegment_table[i]=%d %d %d\n",decodedLen, 
						TotalSegSize,pSegment_table[i-1],pSegment_table[i],pSegment_table[i+1]);
				}
				else
				{
					fwrite(out_buf,decFrames * sizeof(unsigned short),1,fpout);
				}

				decodedLen += (preSegLen+pSegment_table[i]);
				preSegLen = 0;
			}
		}
		
		free(pSegment_data);
		free(pSegment_table);
	}
	fclose(fp);
	fclose(fpout);
	return 0;
}

int main()
{
	g_OpusDec.CreateOpusDecoder(48000, 1);
	readOggPage((char *)"48000Hz-s16le-1ch-ChengDu.opus");
	return 0;
}

opushead wopustags,音视频基础,音视频,opus,Ogg,Ogg封装格式解析,Ogg解码C语言

🎄六、总结

本文介绍了opus编码的Ogg文件的 ID数据头部、注释数据头部、opus编码数据包的结构和解析,并用一个.opus文件的十六进行带着读者理解各个数据包,最后给出了笔者的C语言代码,将opus编码Ogg格式解析为PCM。看完一定大有所获,别忘记点赞、收藏、支持一下。

opushead wopustags,音视频基础,音视频,opus,Ogg,Ogg封装格式解析,Ogg解码C语言
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁文章来源地址https://www.toymoban.com/news/detail-780263.html

到了这里,关于【音视频 | opus】opus编码的Ogg封装文件详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • OpenHarmony音视频—opus

    Opus是一种用于在互联网上进行交互式语音和音频传输的编解码器。它可以从低比特率窄带语音扩展到非常高的高品质立体声音乐。 直接在OpenHarmony-SIG仓中搜索opus并下载。 以OpenHarmony 3.1 Beta的rk3568版本为例 将下载的opus库代码存在以下路径:./third_party/opus 修改添加依赖的编译

    2024年04月26日
    浏览(46)
  • 走进音视频的世界——Opus编解码协议

    Opus是一种开源免费的音频编解码器,支持音乐和语音,具有低延时、带内FEC、DTX、PLC等特点,默认22.5ms延时,非常适用网络实时传输。官网:https://www.opus-codec.org。Opus协议收录于RFC6716,使用SILK和CELT两种编码。 目录 一、Opus特点 二、码率、音质、延时 1、音质与码率比较 2、

    2023年04月08日
    浏览(85)
  • 【FFmpeg】ffmpeg 命令行参数 ⑤ ( 使用 ffmpeg 命令提取 音视频 数据 | 保留封装格式 | 保留编码格式 | 重新编码 )

    使用 ffmpeg 命令 从 视频数据 中 提取 音频数据 / 视频数据 保留封装格式 , 封装格式 指的就是 封装 视频数据 的 容器 ; 一个 mp4 格式的视频 , 其 封装容器 就是 mp4 容器 , 其中 封装了 h.264 格式的视频数据 和 aac 格式的 音频数据 ; 执行 命令 , 从 input.mp4 输入文件中 , 提取 音频

    2024年03月23日
    浏览(59)
  • FFmpeg入门详解之19:音视频封装原理简介

    什么是数据封装和解封装? 数据封装(baiData Encapsulation) ,笼统地讲,就是把业务数据映射到du某个封装协议zhi的净dao荷中,然后填充对应协议的包头,形成封装协议的数据包,并完成速率适配。 解封装 ,就是封装的逆过程,拆解协议包,处理包头中的信息,取出净荷中的业

    2023年04月09日
    浏览(50)
  • 【音视频处理】音频编码AAC详解,低码率提高音质?

    大家好,欢迎来到停止重构的频道。 本期我们介绍 音频编码格式AAC 。 AAC是音频最常用的编码格式之一 ,几乎所有的播放器都支持这个编码格式。 其他音频编码格式都是类似的,只是某些细节存在差别,如压缩算法、某些音频参数存在限制等。 我们按这样的顺序讨论 :

    2024年02月09日
    浏览(90)
  • 音视频开发 RTMP协议发送H.264编码及AAC编码的音视频(C++实现)

    RTMP(Real Time Messaging Protocol)是专门用来传输音视频数据的流媒体协议,最初由Macromedia 公司创建,后来归Adobe公司所有,是一种私有协议,主要用来联系Flash Player和RtmpServer,如 FMS , Red5 , crtmpserver 等。RTMP协议可用于实现直播、点播应用,通过 FMLE(Flash Media Live Encoder) 推送音

    2023年04月08日
    浏览(79)
  • 音视频开发:音频编码原理+采集+编码实战

    消除冗余信息,压缩量最大,也叫有损压缩 剔除人耳听觉范围外的音频信号20Hz以下和20000Hz以上; 去除被掩蔽的音频信号,信号的遮蔽可以分为频域遮蔽和时域遮蔽; 频域遮蔽效应 屏蔽70分贝以下,20HZ以下,20000HZ以上 屏蔽分贝小,频率小的声音 两个频率相近发出的声音,

    2024年02月05日
    浏览(61)
  • Android音视频编码(2)

    Android本身提供了音视频编解码工具,很多时候是不需要第三方工具的,比如 ffmpeg , OpenCV 等,在android中引入第三库比较复杂,在Android音视频编码中介绍了如何引入第三方库libpng来进行进行图片处理,同时引入这些第三方库,是程序结构变得复杂。 本文介绍的音视频编解码利

    2024年01月17日
    浏览(51)
  • 音视频——视频流H264编码格式

    我们了解了什么是宏快,宏快作为压缩视频的最小的一部分,需要被组织,然后在网络之间做相互传输。 H264更深层次 —》宏块 太浅了 ​ 如果单纯的用 宏快 来发送数据是 杂乱无章 的,就好像在没有 集装箱 出现之前,货物总是随意被堆放到船上。 上货(编码),下货是非

    2024年02月15日
    浏览(60)
  • 音视频——封装格式原理

    视频解码基础 一、封裝格式 ​ 我们播放的视频文件一般都是用一种 封装格式 封装起来的,封装格式的作用是什么呢?一般视频文件里不光有视频,还有音频,封装格式的作用就是把视频和音频打包起来。 所以我们先要 解封装格式 ,看有哪些视频流和哪些音频流,此时的

    2024年02月15日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包