cpp
复制代码
#define ADTS_HEADER_LEN 7
const int sampleFrequencyTable[] = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350};
int getADTSHeader(char *const adtsHeader, const int dataLength, const int profile, const int samplerate, const int channels)
{
int sampleFrequenceIndex = 3; // 默认使用 48000HZ
int adtslen = dataLength + 7;
int frequencise_size = sizeof(sampleFrequencyTable) / sizeof(sampleFrequencyTable[0]);
int i = 0;
for (int i = 0; i < frequencise_size; i++)
{
if (sampleFrequencyTable[i] == samplerate)
{
sampleFrequenceIndex = i;
break;
}
}
if (i >= frequencise_size)
{
av_log(NULL, AV_LOG_ERROR, "不支持次采样率:%d\n", samplerate);
return -1;
}
// syncword :同步头总是OxFFF, all bits must be 1,代表着一个ADTS帧的开始
adtsHeader[0] = 0xff; // syncword:0xff 高8bits
adtsHeader[1] = 0xf0; // syncword:0xfff 低4bits
adtsHeader[1] |= (0 << 3); // MPEG Version:0 for MPEG-4,1 for MPEG-2 1bit
adtsHeader[1] |= (0 << 1); // Layer:0 2bit
adtsHeader[1] |= 1; // protection absent:1 1bit -- 要不要CRC校验 -- 不要
adtsHeader[2] = (profile << 6); // porfile:profile 2bits
adtsHeader[2] |= (sampleFrequenceIndex & 0x0f) << 2; // sampling frequency index:sampling_frequency_index 4bits
adtsHeader[2] |= (0 << 1); // private bit:0 1bit
adtsHeader[2] |= (channels & 0x04) >> 2; // channel configuration:channels 高1bit
adtsHeader[3] = (channels & 0x03) << 6; // channel configuration:channels 低2bits
adtsHeader[3] |= (0 << 5); // original:0 1bit
adtsHeader[3] |= (0 << 4); // home:0 1bit
adtsHeader[3] |= (0 << 3); // copyright id bit: 0 1bit
adtsHeader[3] |= (0 << 2); // copyright id start: 0 1bit
adtsHeader[3] |= ((adtslen & 0x1800) >> 11); // frame length: value 高2bits
adtsHeader[4] = (uint8_t)((adtslen & 0x7f8) >> 3); // frame length:vale 中间8bits
adtsHeader[5] = (uint8_t)((adtslen & 0x7) << 5); // frame length:value 低3bits
adtsHeader[5] |= 0x1f; // buffer fullness: 0x7ff 高5bits
adtsHeader[6] = 0xfc; // buffer fullness: 0x7ff 低6bits
return 0;
}
cpp
复制代码
int DemuxingVideoAndAudio(const char *inFileName, const char *h264FileName, const char *aacFileName)
{
/*********************************************************************************/
FILE *aac_fd = fopen(aacFileName, "wb");
FILE *h264_fd = fopen(h264FileName, "wb");
if (!aac_fd || !h264_fd)
{
av_log(NULL, AV_LOG_ERROR, "open %s or %s file failed or \n", h264FileName, aacFileName);
goto _end;
}
/*********************************************************************************/
AVFormatContext *inFmtCtx = NULL;
// 当 inFmtCtx 为空时 avformat_open_input 会给 inFmtCtx 分配空间
int ret = avformat_open_input(&inFmtCtx, inFileName, NULL, NULL);
if (ret != 0)
{
av_log(NULL, AV_LOG_ERROR, "open input file:%s failed:%s\n", inFileName, av_err2str(ret));
return -1;
}
int videoIndex = av_find_best_stream(inFmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
int audioIndex = av_find_best_stream(inFmtCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
if (videoIndex < 0 || audioIndex < 0) // 输入的媒体文件必须要有视频和音频流
{
av_log(NULL, AV_LOG_ERROR, "find best stream failed,index is %s\n", av_err2str(videoIndex));
av_log(NULL, AV_LOG_ERROR, "find best stream failed,index is %s\n", av_err2str(audioIndex));
goto _end;
}
AVPacket *packet = NULL;
packet = av_packet_alloc();
av_init_packet(packet);
const AVBitStreamFilter *bsfilter = av_bsf_get_by_name("h264_mp4toannexb");
if (bsfilter == NULL)
{
av_log(NULL, AV_LOG_ERROR, "get h264_mp4toannexb bsf failed\n");
goto _end;
}
// 用于存储比特流过滤器的上下文信息
AVBSFContext *bsfCtx = NULL;
// 比特流过滤器分配内存并初始化上下文结构体。
ret = av_bsf_alloc(bsfilter, &bsfCtx);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "bsfCtx alloc failed\n");
goto _end;
}
// 输入流的参数复制到比特流过滤器的输入参数中,以便过滤器能够正确处理输入数据。
ret = avcodec_parameters_copy(bsfCtx->par_in, inFmtCtx->streams[videoIndex]->codecpar);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "avcodec parameters copy failed\n");
goto _end;
}
// 初始化比特流过滤器,准备对输入数据进行处理。
ret = av_bsf_init(bsfCtx);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "bsfCtx init failed\n");
goto _end;
}
// 不释放packet->buf 如果外部不去释放,会导致内存泄流
while (av_read_frame(inFmtCtx, packet) == 0)
{
if (packet->stream_index == videoIndex)
{
// av_bsf_send_packet 发一次
// av_bsf_receive_packet 读到返回eagain才继续send
if (av_bsf_send_packet(bsfCtx, packet) == 0) // 这行代码将数据包packet发送给比特流过滤器bsfCtx进行处理。如果返回值为0,表示成功发送数据包到过滤器。
{ // 内部把我们传入的buf转移到自己的bsfCtx 内部
int outPacketCount = 0;
while (av_bsf_receive_packet(bsfCtx, packet) == 0)
{
outPacketCount++; // 因为读到返回eagain才继续send 看下读了
size_t writeSize = fwrite(packet->data, 1, packet->size, h264_fd); // 接收到的数据包写入到文件中
if (writeSize != packet->size)
{
av_log(NULL, AV_LOG_ERROR, "wirte file failed!\n");
av_packet_unref(packet); // 释放packet资源
ret = -1;
break;
}
av_log(NULL, AV_LOG_DEBUG, "outPacketCount%d, writeSize:%ld, packet->size:%u -- line:%d\n", outPacketCount, writeSize, packet->size, __LINE__);
}
}
av_packet_unref(packet); // 释放packet资源
}
else if (packet->stream_index == audioIndex) // 处理音频
{
char adtsHeader[ADTS_HEADER_LEN] = {0};
// 如果数据包属于音频流,则会为音频数据包创建一个 ADTS 头部(ADTS 头部是一种用于封装音频数据的格式,可以通过网络传输或存储在文件中)。
getADTSHeader(adtsHeader, packet->size,
inFmtCtx->streams[audioIndex]->codecpar->profile, // 音频编解码器的配置文件。
inFmtCtx->streams[audioIndex]->codecpar->sample_rate, // 音频的采样率
inFmtCtx->streams[audioIndex]->codecpar->channels); // 音频的通道数。
// 写文件头
size_t writeSize = fwrite(adtsHeader, 1, ADTS_HEADER_LEN, aac_fd);
if (writeSize != sizeof(adtsHeader))
{
av_log(NULL, AV_LOG_ERROR, "wirte file failed!\n");
av_packet_unref(packet); // 释放packet资源
ret = -1;
break;
}
// 写 adts data
writeSize = fwrite(packet->data, 1, packet->size, aac_fd);
if (writeSize != packet->size)
{
av_log(NULL, AV_LOG_WARNING, "wirte file failed writeSize:%ld packet.size:%d\n", writeSize, packet->size);
av_packet_unref(packet); // 释放packet资源
ret = -1;
break;
}
av_packet_unref(packet);
}
else
{
av_packet_unref(packet);
}
}
av_log(NULL, AV_LOG_INFO, "decapsulation finish\n");
_end: // 释放资源
if (inFmtCtx != NULL)
avformat_close_input(&inFmtCtx);
if (h264_fd != NULL)
fclose(h264_fd);
if (aac_fd != NULL)
fclose(aac_fd);
if (bsfCtx)
av_bsf_free(&bsfCtx);
if (packet)
av_packet_free(&packet);
return ret;
}