提取mp4中的音频Pkt,以adts的方式写为aac文件

 提取mp4文件中的音频pkt,加上adts头写入到文件中(位运算的方式)

/*****************************************************************//**
 * \file   writeAAC01.cpp
 * \brief  提取出mp4文件中的音频包,加上adts_header, 写入到aac格式音频文件
 * 
 * \author 13648
 * \date   April 2024
 *********************************************************************/
#define _CRT_SECURE_NO_WARNINGS
#include "myLog.h"
#include <iostream>

extern "C"
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
}

#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avcodec.lib")

// 根据采样率查找对应的采样率下标
const int sampling_frequencies[] = {
	96000,  // 0x0
	88200,  // 0x1
	64000,  // 0x2
	48000,  // 0x3
	44100,  // 0x4
	32000,  // 0x5
	24000,  // 0x6
	22050,  // 0x7
	16000,  // 0x8
	12000,  // 0x9
	11025,  // 0xa
	8000   // 0xb
	// 0xc d e f是保留的
};

int get_adts_header_buffer(char* const adts_header_buff, const int pkt_size, const int profile,
	const int sample_rate, const int channels)
{
	int sampling_frequency_index = 3;    // 默认使用48khz
	int adtsLen = pkt_size + 7;			 // 数据长度加7字节头长度

	int frequencies_size = sizeof(sampling_frequencies) / sizeof(sampling_frequencies[0]);
	for (int i = 0; i < frequencies_size; i++)
	{
		sampling_frequency_index = i;
		if (sampling_frequencies[i] == sample_rate)
		{
			break;
		}
	}
	if (sampling_frequency_index >= frequencies_size)
	{
		LOG_WARNING("unsupport samplerate:%d\n", sample_rate);
		return -1;
	}

	// syncword:0xfff	adts frame start(同步字)
	adts_header_buff[0] = 0xff;
	adts_header_buff[1] = 0xf0;													// 12 bits

	// 0001
	// 0: MPEG-4 00(给00即可)  1: 表示无校验码		
	adts_header_buff[1] |= (0 << 3);    //MPEG Version:0 for MPEG-4,1 for MPEG-2  1 bit
	adts_header_buff[1] |= (0 << 1);    //Layer:0                                 2 bits
	adts_header_buff[1] |= 1;           //protection absent:1(表示没有校验码)     1 bit

	// 01 0100 0 0
	// AAC级别:profile   2 bits  
	adts_header_buff[2] = (profile) << 6;
	// sampling frequency index:采样率索引  4bits   44100: index =  4
	adts_header_buff[2] |= (sampling_frequency_index & 0x0f) << 2;
	//private bit:0                   1bit
	adts_header_buff[2] |= (0 << 1);
	//channel configuration:channels  占3bit 此处剩高位1bit
	adts_header_buff[2] |= (channels & 0x04) >> 2;	// 0000 0010 & 0000 0100 (0 >> 2)

	// 10 0 0     0 0 00
	adts_header_buff[3] = (channels & 0x03) << 6;  //channel configuration:channels 低2bits
	adts_header_buff[3] |= (0 << 5);               //original:0                1bit
	adts_header_buff[3] |= (0 << 4);               //home:0                    1bit

	// 变长adts_header
	adts_header_buff[3] |= (0 << 3);               //copyright id bit:0        1bit
	adts_header_buff[3] |= (0 << 2);               //copyright id start:0      1bit
	adts_header_buff[3] |= ((adtsLen & 0x1800) >> 11);           //frame length:一共13bits   高2bits

	// 0000 0000
	adts_header_buff[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);     //frame length:value    中间8bits

	// 000 11111
	adts_header_buff[5] = (uint8_t)((adtsLen & 0x7) << 5);       //frame length:value    低3bits
	adts_header_buff[5] |= 0x1f;                                 //码率可变:0x7ff 高5bits

	// 1111 1100
	adts_header_buff[6] = 0xfc;     		 // buffer fullness:0x7ff 低6bits
	// 后还有 2bit 低位字节
	// 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧(数据块)
	return 0;
}

int main_writeAAC01()
{
	const std::string in_filename = "./MediaFile/HTA_13s.mp4";
	AVFormatContext* ifmt_ctx = nullptr;
	size_t nRet = avformat_open_input(&ifmt_ctx, in_filename.c_str(), NULL, NULL);
	if (nRet != 0)
	{
		LOG_WARNING("avformat_open_input error\n");
		return -1;
	}

	nRet = avformat_find_stream_info(ifmt_ctx, NULL);
	if (nRet < 0)
	{
		LOG_WARNING("avformat_find_stream_info error\n");
		avformat_close_input(&ifmt_ctx);
		return -2;
	}

	int audio_idx = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
	if (audio_idx < 0)
	{
		LOG_WARNING("av_find_best_stream audio error\n");
		avformat_close_input(&ifmt_ctx);
		return -3;
	}

	// 不是AAC编码
	if (ifmt_ctx->streams[audio_idx]->codecpar->codec_id != AV_CODEC_ID_AAC)
	{
		LOG_WARNING("this file audio not is aac\n");
		avformat_close_input(&ifmt_ctx);
		return -4;
	}

	AVStream* audio_stream = ifmt_ctx->streams[audio_idx];
	// 打印AAC级别
	LOG_INFO("audio profile: %d, FF_PROFILE_AAC_LOW:%d\n", audio_stream->codecpar->profile, FF_PROFILE_AAC_LOW);

	// 读取音频包写入到本地文件
	const std::string out_filename = "./MediaFile/out.aac";
	FILE* out_fp = fopen(out_filename.c_str(), "wb");
	if (NULL == out_fp)
	{
		avformat_close_input(&ifmt_ctx);
		LOG_WARNING("open out_filename faild\n");
		return -5;
	}

	AVPacket* pkt = av_packet_alloc();
	while (av_read_frame(ifmt_ctx, pkt) >= 0)
	{
		if (pkt->stream_index == audio_idx)
		{
			char adts_header_buff[7] = { 0 };	// adts头信息
			nRet = get_adts_header_buffer(adts_header_buff, pkt->size, audio_stream->codecpar->profile, 
				audio_stream->codecpar->sample_rate, audio_stream->codecpar->ch_layout.nb_channels);
			if (nRet >= 0)
			{
				nRet = fwrite(adts_header_buff, 1, sizeof(adts_header_buff), out_fp);
			}
			nRet = fwrite(pkt->data, 1, pkt->size, out_fp);
			if (nRet != pkt->size)
			{
				LOG_WARNING("write size != pkt->size\n");
			}
		}
		av_packet_unref(pkt);
	}

	av_packet_free(&pkt);
	fclose(out_fp);
	if (ifmt_ctx)
	{
		avformat_close_input(&ifmt_ctx);
	}
	return 0;
}

 提取mp4文件中的音频pkt,加上adts头写入到文件中(位域的方式) 

/*****************************************************************//**
 * \file   writeAAC02.cpp
 * \brief  提取出mp4文件中的音频包,加上adts_header, 写入到aac格式音频文件(使用位域的方式)
 *			
 * \author 13648
 * \date   April 2024
 *********************************************************************/
#define _CRT_SECURE_NO_WARNINGS
#include "myLog.h"
#include <iostream>

extern "C"
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
}

#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avcodec.lib")

// 根据采样率查找对应的采样率下标
const int sampling_frequencies[] = {
	96000,  // 0x0
	88200,  // 0x1
	64000,  // 0x2
	48000,  // 0x3
	44100,  // 0x4
	32000,  // 0x5
	24000,  // 0x6
	22050,  // 0x7
	16000,  // 0x8
	12000,  // 0x9
	11025,  // 0xa
	8000   // 0xb
	// 0xc d e f是保留的
};

// adts_header
struct st_adts_header
{
	// adts_fixed_header
	unsigned int syncword : 12;
	unsigned int id : 1;
	unsigned int layer : 2;
	unsigned int protection_absent : 1;
	unsigned int profile : 2;
	unsigned int sampling_frequency_index : 4;
	unsigned int private_bit : 1;
	unsigned int channel_configuration : 3;
	unsigned int original_copy : 1;
	unsigned int home : 1;

	// adts_var_header
	unsigned int copyright_identification_bit : 1;
	unsigned int copyright_identification_start : 1;
	unsigned int aac_frame_length : 13;
	unsigned int adts_buffer_fullness : 11;
	unsigned int number_of_raw_data_blocks_in_frame : 2;
};

unsigned long long copyAdtsHeaderToCharArray(st_adts_header* header)
{
	// 将fixed_header的各个字段按照ADTS的同步词格式排列
	// 同步词占用前12位,其余字段按照ADTS头部格式排列
	// (0000多的4bit) 1111 1111 1111 0 00 0 00 0000 0 000 0 0
	unsigned int fixed_part = (header->syncword << 16) |	// 1111 1111 1111
		(header->id << 15) |
		(header->layer << 13) |
		(header->protection_absent << 12) |
		(header->profile << 10) |
		(header->sampling_frequency_index << 6) |
		(header->private_bit << 5) |
		(header->channel_configuration << 2) |
		(header->original_copy << 1) |
		(header->home << 0);

	std::cout << std::hex << fixed_part << std::endl;

	// 将var_header的各个字段按照ADTS的格式排列
	// (0000多的bit) 0 0 0000000000000 00000000000 00
	unsigned int var_part = (header->copyright_identification_bit << 27) |
		(header->copyright_identification_start << 26) |
		(header->aac_frame_length << 13) |
		(header->adts_buffer_fullness << 2) |
		(header->number_of_raw_data_blocks_in_frame << 0);

	std::cout << std::hex << var_part << std::endl;

	unsigned long long ret = (fixed_part & 0XFFFFFFFFFFFFFFFF);	// 低32bit
	// 将fixed_part和var_part合并成一个64位整数
	unsigned long long adts_header_combined = (ret << 28) | var_part;
	std::cout << std::hex << adts_header_combined << std::endl;
	return adts_header_combined;
}

static int get_adts_header_buffer(char* const adts_header_buff, const int pkt_size, const int profile,
	const int sample_rate, const int channels)
{
	int sampling_frequency_index = 3;    // 默认使用48khz
	int adtsLen = pkt_size + 7;			 // 数据长度加7字节头长度

	int frequencies_size = sizeof(sampling_frequencies) / sizeof(sampling_frequencies[0]);
	for (int i = 0; i < frequencies_size; i++)
	{
		sampling_frequency_index = i;
		if (sampling_frequencies[i] == sample_rate)
		{
			break;
		}
	}
	if (sampling_frequency_index >= frequencies_size)
	{
		LOG_WARNING("unsupport samplerate:%d\n", sample_rate);
		return -1;
	}

	// 使用位域的方式填入adts_header数据
	st_adts_header adts_header;
	// 赋值ADTS的固定头部分
	adts_header.syncword = 0xFFF;
	adts_header.id = 0;
	adts_header.layer = 0;
	adts_header.protection_absent = 1;

	adts_header.profile = profile;
	adts_header.sampling_frequency_index = sampling_frequency_index;
	adts_header.private_bit = 0x00;
	adts_header.channel_configuration = channels;
	adts_header.original_copy = 0x00;
	adts_header.home = 0x00;
	// 赋值ADTS的可变头部分
	adts_header.copyright_identification_bit = 0x00;
	adts_header.copyright_identification_start = 0x00;
	adts_header.aac_frame_length = adtsLen;
	adts_header.adts_buffer_fullness = 0x7FF;
	adts_header.number_of_raw_data_blocks_in_frame = 0x00;

	// 获取一个64bit的值,然后逐个拷贝到adts_header_buff中
	unsigned long long value = copyAdtsHeaderToCharArray(&adts_header);
	// 00000000 00000000 00000000 00000000 00000000 00000000 00000000 (56 bit)
	for (int i = 0; i < 7; i++)
	{
		adts_header_buff[i] = value >> ((7 - i - 1) * 8);
	}

	return 0;
}

int main()
{
	const std::string in_filename = "./MediaFile/HTA_13s.mp4";
	AVFormatContext* ifmt_ctx = nullptr;
	size_t nRet = avformat_open_input(&ifmt_ctx, in_filename.c_str(), NULL, NULL);
	if (nRet != 0)
	{
		LOG_WARNING("avformat_open_input error\n");
		return -1;
	}

	nRet = avformat_find_stream_info(ifmt_ctx, NULL);
	if (nRet < 0)
	{
		LOG_WARNING("avformat_find_stream_info error\n");
		avformat_close_input(&ifmt_ctx);
		return -2;
	}

	int audio_idx = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
	if (audio_idx < 0)
	{
		LOG_WARNING("av_find_best_stream audio error\n");
		avformat_close_input(&ifmt_ctx);
		return -3;
	}

	// 不是AAC编码
	if (ifmt_ctx->streams[audio_idx]->codecpar->codec_id != AV_CODEC_ID_AAC)
	{
		LOG_WARNING("this file audio not is aac\n");
		avformat_close_input(&ifmt_ctx);
		return -4;
	}

	AVStream* audio_stream = ifmt_ctx->streams[audio_idx];
	// 打印AAC级别
	LOG_INFO("audio profile: %d, FF_PROFILE_AAC_LOW:%d\n", audio_stream->codecpar->profile, FF_PROFILE_AAC_LOW);

	// 读取音频包写入到本地文件
	const std::string out_filename = "./MediaFile/out_02.aac";
	FILE* out_fp = fopen(out_filename.c_str(), "wb");
	if (NULL == out_fp)
	{
		avformat_close_input(&ifmt_ctx);
		LOG_WARNING("open out_filename faild\n");
		return -5;
	}

	AVPacket* pkt = av_packet_alloc();
	while (av_read_frame(ifmt_ctx, pkt) >= 0)
	{
		if (pkt->stream_index == audio_idx)
		{
			char adts_header_buff[7] = { 0 };	// adts头信息
			nRet = get_adts_header_buffer(adts_header_buff, pkt->size, audio_stream->codecpar->profile,
				audio_stream->codecpar->sample_rate, audio_stream->codecpar->ch_layout.nb_channels);
			if (nRet >= 0)
			{
				nRet = fwrite(adts_header_buff, 1, sizeof(adts_header_buff), out_fp);
			}
			nRet = fwrite(pkt->data, 1, pkt->size, out_fp);
			if (nRet != pkt->size)
			{
				LOG_WARNING("write size != pkt->size\n");
			}
		}
		av_packet_unref(pkt);
	}

	av_packet_free(&pkt);
	fclose(out_fp);
	if (ifmt_ctx)
	{
		avformat_close_input(&ifmt_ctx);
	}
	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
实验题目小型局域网络设计pkt文件,是指设计一个包含了小型规模的局域网的网络拓扑结构,并生成相应的pkt文件来模拟网络通信过程。 首先,对于小型局域网的设计,需要考虑到网络的设备数量和布局、网络拓扑结构、IP地址规划、网络安全等因素。 在设备数量和布局方面,需要确定网络包含的设备类型,例如交换机、路由器、服务器和终端设备等。并根据设备数量和互连方式,设置合适的布局方案,如星型结构、环型结构或混合结构。 在网络拓扑结构方面,可以考虑使用层次结构或扁平结构。层次结构适用于规模较大的局域网,可以将网络划分为多个子网,每个子网内有自己的交换机和路由器。扁平结构适用于规模较小的局域网,所有设备处于同一个子网。 在IP地址规划方面,需要为局域网的设备分配适当的IP地址,确保每个设备都能够正常通信。可以选择使用私有IP地址段,如10.0.0.0/8、172.16.0.0/12和192.168.0.0/16,并根据设备的数量和位置进行合理划分。 在网络安全方面,需要考虑网络的安全策略和设备的安全配置。可以使用防火墙、入侵检测系统和访问控制列表等安全设备或技术,保护局域网的安全性。 针对题目pkt文件设计,可以使用网络模拟软件,如GNS3、Packet Tracer等,来创建网络拓扑,并生成相应的pkt文件pkt文件是一种仿真文件,可以模拟网络通信过程,如设备之间的数据传输、数据包的转发和路由等。 在设计pkt文件时,可以定义源IP地址、目的IP地址、数据包类型、数据包大小等参数,以模拟真实的网络通信过程。可以通过发送和接收数据包来测试网络的性能和可靠性,检测是否存在延迟、丢包和冲突等问题,并根据实验结果进行网络的优化和调整。 综上所述,小型局域网络设计pkt文件需要考虑到设备数量与布局、网络拓扑结构、IP地址规划和网络安全等方面。通过合理设计pkt文件,并使用适当的网络模拟软件,可以模拟网络通信过程,检测网络性能,并对网络进行优化和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

石小浪♪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值