提取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;
}