FFmpeg 解码 AAC 格式的音频

news2024/11/24 6:43:48

FFmpeg 默认是可以解码 AAC 格式的音频,但是如果需要获取 PCM16 此类数据则需要经过音频转码。首先要打开解码器,然后向解码器发送 AAC 音频帧(不带 ADTS),然后从解码器获取解码后的音频帧,数据是 float 类型的,如果需要则进行转码流程将 float 转成整型。

一、AAC 音频

AAC 是高级音频编码(Advanced Audio Coding)的缩写,出现于 1997 年,最初是基于 MPEG-2 的音频编码技术。由Fraunhofer IIS、Dolby Laboratories、AT&T、Sony 等公司共同开发,目的是取代 MP3 格式。2000 年,MPEG-4 标准出台,AAC 重新集成了其它技术(PS、SBR),为区别于传统的 MPEG-2 AAC,故含有 SBR 或 PS 特性的 AAC 又称为 MPEG-4 AAC。

AAC 是新一代的音频有损压缩技术,它通过一些附加的编码技术(比如 PS、SBR 等),衍生出了LC-AAC、HE-AAC、HE-AACv2 三种主要的编码,LC-AAC 就是比较传统的 AAC,相对而言,主要用于中高码率(>=80Kbps),HE-AAC(相当于AAC+SBR)主要用于中低码(<=80Kbps),而新近推出的 HE-AACv2 (相当于AAC+SBR+PS)主要用于低码率(<=48Kbps),事实上大部分编码器设成 <=48Kbps 自动启用 PS 技术,而 >48Kbps 就不加 PS,就相当于普通的 HE-AAC。

1.1 种类

FFmpeg 中一共定义了十种 Profile 格式的 AAC,带 MPEG2 为 MPEG2 支持,其他的为 MPEG4 支持的。

avcodec.h
 

#define FF_PROFILE_AAC_MAIN 0
#define FF_PROFILE_AAC_LOW  1
#define FF_PROFILE_AAC_SSR  2
#define FF_PROFILE_AAC_LTP  3
#define FF_PROFILE_AAC_HE   4
#define FF_PROFILE_AAC_HE_V2 28
#define FF_PROFILE_AAC_LD   22
#define FF_PROFILE_AAC_ELD  38
#define FF_PROFILE_MPEG2_AAC_LOW 128
#define FF_PROFILE_MPEG2_AAC_HE  131

MAIN 代表主规格

LOW 低复杂度规格(Low Complexity)

SSR 可变采样率规格(Scaleable Sample Rate)

LTP 长时期预测规格(Long Term Predicition)

HE 高效率规格(High Efficiency)AAC+

HE_V2 高效率 V2 规格(High Efficiency V2)Enhanced AAC+

LD 低延迟规格(Low Delay)

ELD 增强低延迟规格(Enhanced low Low Delay)

1.2 格式

查看《ISO/IEC 13818-7》可进一步了解 AAC 音频的详细格式。AAC 的音频文件格式有 ADIF 和 ADTS。

ADIF:Audio Data Interchange Format

音频数据交换格式。这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中。

音频数据交换格式序列包括 ADIF 头,字节对齐和实际数据。

adif_id 表示音频数据交换格式的 ID。它的值是 0x41444946 (最高位在前),这是字符串“ADIF”的 ASCII 表示形式。

copyright_id_present 指示copyright_id是否存在。

copyright_id 该字段由一个8位的 copyright_identifier 和一个64位的 copyright_number 组成。

original_copy 参见 ISO/IEC 11172-3 第 2.4.2.3 款对版权的定义。

home 参见 ISO/IEC 11172-3,第 2.4.2.3 小节对 original_copy 的定义。

bitstream_type 指明位流类型的标志:

“0”恒速率比特流;

“1”可变速率比特流。

bitrate 一个23位无符号整数,指示在恒定速率的比特流中比特流的比特率,或在可变速率的比特流中最大峰值比特率(每帧测量)。0表示不知道比特率。

num_program_config_element program_config_element() 的数量。

adif_buffer_fullness 在 adif_sequence() 中对第一个 raw_data_block() 进行编码后 bit reservoir 的状态。

ADTS:Audio Data Transport Stream

音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于 mp3 数据流格式。

一般情况下 ADTS 的头信息都是 7 个字节,分为 2 部分:

adts_fixed_header() —— 固定部

adts_variable_header() —— 可变部分

 

syncword 同步头,总是 0xFFF,代表着一个 ADTS 帧的开始。

ID MPEG 版本:0 代表 MPEG-4,1 代表 MPEG-2。

layer 总是 ‘00’。

profile 表示使用哪个级别的 AAC。

sampling_frequency_index 表示使用的采样率下标,通过这个下标在 Sampling Frequencies[] 数组中查找得知采样率的值。

channel_configuration表示声道数。

frame_length 一个 ADTS 帧的长度包括 ADTS 头和 AAC 原始流。

adts_buffer_fullness ADTS 帧编码过程中 bit reservoir 的状态 ,0x7FF 说明是码率可变的码流。

protection_absent 指示是否存在 error_check() 数据。

private_bit 参见 ISO/IEC 11172-3,第 2.4.2.3 条。

copyright_identification_bit 表示 72 位版权标识字段。

copyright_identification_start 表示 copyright_identification_bit

音频帧是 72 位版权标识的第一个位。如果没有版权标识被传送,这个位应该被保留 “0”。

number_of_raw_data_blocks_in_frame 被复用的 raw_data_block() 的数目。

 

二、AAC 音频解码

1.获取 AAC 解码器 Codec,调用 avcodec_find_decoder(AV_CODEC_ID_AAC) 获取;

2.调用 avcodec_alloc_context3(…) 分配 AVCodecContext 结构,它是解码器 Codec 上下文;

3.调用 avcodec_parameters_alloc() 分配 AVCodecParameters 结构,可用来给解码器设置必要参数;

4.将必要解码参数设置到 AVCodecParameters,采样率、声道数、解码后的格式(此处需要注意,实际上 AAC 解码器默认解码后的格式都是 AV_SAMPLE_FMT_FLTP)等;

5.接下来调用 avcodec_parameters_to_context(…) 将 AVCodecParameters 结构中的参数复制到 AVCodecContext,AVCodecParameters 结构完成使命调用 avcodec_parameters_free(…) 释放其内存;

6.现在可以调用 avcodec_open2(…) 打开解码器。

接下来就可以从 PacketQueue 队列(存放 AAC 编码的帧队列,不需要带 ADTS 头,因为解码器中的必要信息已经设置)源源不断获取 AAC 编码后的音频帧送入解码器进行解码。将编码帧送到解码器是调用 avcodec_send_packet(…) 实现的,然后就可以调用 avcodec_receive_frame(…) 获取解码帧。

由于有些平台并不支持 AV_SAMPLE_FMT_FLTP 格式的 PCM 直接播放,所以需要将 float PCM 转成 AV_SAMPLE_FMT_S16。

转码流程

1.调用 swr_alloc() 分配 SwrContext 转码上下文结构;

2.调用 swr_alloc_set_opts(…) 给转码上下文结构设置必要参数;

3.调用 swr_init(…) 初始化 SwrContext 转码上下文结构;

4.重复调用 swr_convert(…) 进行转码。

最后,不在使用的 SwrContext 结构、AVFrame 、AVCodecContext 全部都要调用其释放函数进行收尾工作。

FFmpeg 解码 AAC 格式音频代码

将 AAC 解码封装到 AudioDecoder 类中。
 

//
// Created by liuhongwei on 2021/12/7.
//
 
#ifndef AUDIODECODER_H
#define AUDIODECODER_H
 
extern "C" {
//编解码
#include "libavcodec/avcodec.h"
#include <libswresample/swresample.h>
}
 
#include "PacketQueue.h"
#include "cb/FrameDataCallback.h"
 
class AudioDecoder {
public:
    AudioDecoder(PacketQueue *packetQueue);
 
    ~AudioDecoder();
 
    bool open(unsigned int sampleFreq, unsigned int channels, unsigned int profile = 1);
 
    void close();
 
    void decode();
 
    static void *_decode(void *self) {
        static_cast<AudioDecoder *>(self)->decode();
        return nullptr;
    }
 
    void setFrameDataCallback(FrameDataCallback *frameDataCallback);
 
private:
    PacketQueue *pPacketQueue;
    AVCodecContext *pAudioAVCodecCtx;
    AVFrame *pFrame;
    unsigned int gSampleFreq;
 
    bool volatile isDecoding;
    pthread_t decodeThread;
    pthread_mutex_t *pFrameDataCallbackMutex;
    FrameDataCallback *pFrameDataCallback;
 
    SwrContext *pSwrContext;
    uint8_t *pPCM16OutBuf;
};
 
 
#endif //AUDIODECODER_H

 具体实现

//
// Created by liuhongwei on 2021/12/7.
//
 
#include <unistd.h>
#include "AudioDecoder.h"
 
AudioDecoder::AudioDecoder(PacketQueue *packetQueue) {
    pPacketQueue = packetQueue;
    pFrameDataCallbackMutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
    int ret = pthread_mutex_init(pFrameDataCallbackMutex, nullptr);
    if (ret != 0) {
        LOGE("audio FrameDataCallbackMutex init failed.\n");
    }
 
    pFrameDataCallback = nullptr;
    pSwrContext = nullptr;
    pPCM16OutBuf = nullptr;
}
 
AudioDecoder::~AudioDecoder() {
    pthread_mutex_destroy(pFrameDataCallbackMutex);
 
    if (nullptr != pFrameDataCallbackMutex) {
        free(pFrameDataCallbackMutex);
        pFrameDataCallbackMutex = nullptr;
    }
}
 
bool AudioDecoder::open(unsigned int sampleFreq, unsigned int channels, unsigned int profile) {
    gSampleFreq = sampleFreq;
 
    int ret;
    AVCodec *dec = avcodec_find_decoder(AV_CODEC_ID_AAC);
    LOGI("%s audio decoder name: %s", __FUNCTION__, dec->name);
    enum AVSampleFormat sample_fmt = AV_SAMPLE_FMT_FLTP;//注意:设置为其他值并不生效
    int bytesPerSample = av_get_bytes_per_sample(sample_fmt);
 
    pAudioAVCodecCtx = avcodec_alloc_context3(dec);
 
    if (pAudioAVCodecCtx == nullptr) {
        LOGE("%s AudioAVCodecCtx alloc failed", __FUNCTION__);
        return false;
    }
 
    AVCodecParameters *par = avcodec_parameters_alloc();
    if (par == nullptr) {
        LOGE("%s audio AVCodecParameters alloc failed", __FUNCTION__);
        avcodec_free_context(&pAudioAVCodecCtx);
        return false;
    }
 
    par->codec_type = AVMEDIA_TYPE_AUDIO;
    par->sample_rate = (int) sampleFreq;
    par->channel_layout = av_get_default_channel_layout((int) channels);
    par->channels = (int) channels;
    par->bit_rate = sampleFreq * channels * bytesPerSample;
    par->format = sample_fmt;
    par->profile = (int) profile;
 
    avcodec_parameters_to_context(pAudioAVCodecCtx, par);
    avcodec_parameters_free(&par);
 
    LOGI("%s sample_rate=%d channels=%d bytesPerSample=%d", __FUNCTION__, sampleFreq, channels,
         bytesPerSample);
    ret = avcodec_open2(pAudioAVCodecCtx, dec, nullptr);
    if (ret < 0) {
        LOGE("%s Can not open audio encoder", __FUNCTION__);
        avcodec_free_context(&pAudioAVCodecCtx);
        return false;
    }
    LOGI("%s avcodec_open2 audio SUCC", __FUNCTION__);
    pFrame = av_frame_alloc();
    if (pFrame == nullptr) {
        LOGE("%s audio av_frame_alloc failed", __FUNCTION__);
        avcodec_free_context(&pAudioAVCodecCtx);
        return false;
    }
 
    pSwrContext = swr_alloc();
    if (pSwrContext == nullptr) {
        LOGE("%s swr_alloc failed", __FUNCTION__);
        avcodec_free_context(&pAudioAVCodecCtx);
        av_frame_free(&pFrame);
        return false;
    }
 
    swr_alloc_set_opts(
            pSwrContext,
            pAudioAVCodecCtx->channel_layout,
            AV_SAMPLE_FMT_S16,
            pAudioAVCodecCtx->sample_rate,
            pAudioAVCodecCtx->channel_layout,
            pAudioAVCodecCtx->sample_fmt,
            pAudioAVCodecCtx->sample_rate,
            0, nullptr
    );
 
    ret = swr_init(pSwrContext);
    if (ret != 0) {
        LOGE("%s swr_init failed", __FUNCTION__);
        avcodec_free_context(&pAudioAVCodecCtx);
        av_frame_free(&pFrame);
        swr_free(&pSwrContext);
        return false;
    }
 
    pPCM16OutBuf = (uint8_t *) malloc(
            av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * 1024);
 
    if (pPCM16OutBuf == nullptr) {
        LOGE("%s PCM16OutBufs malloc failed", __FUNCTION__);
        avcodec_free_context(&pAudioAVCodecCtx);
        av_frame_free(&pFrame);
        swr_free(&pSwrContext);
        return false;
    }
 
    isDecoding = true;
    ret = pthread_create(&decodeThread, nullptr, &AudioDecoder::_decode, (void *) this);
    if (ret != 0) {
        LOGE("audio decode-thread create failed.\n");
        isDecoding = false;
        avcodec_free_context(&pAudioAVCodecCtx);
        av_frame_free(&pFrame);
        swr_free(&pSwrContext);
 
        free(pPCM16OutBuf);
        pPCM16OutBuf = nullptr;
        return false;
    }
 
    return true;
}
 
void AudioDecoder::close() {
    isDecoding = false;
    pthread_join(decodeThread, nullptr);
 
    if (pPCM16OutBuf != nullptr) {
        free(pPCM16OutBuf);
        pPCM16OutBuf = nullptr;
        LOGI("%s PCM16OutBuf free", __FUNCTION__);
    }
 
    if (pSwrContext != nullptr) {
        swr_free(&pSwrContext);
        LOGI("%s SwrContext free", __FUNCTION__);
    }
 
    if (pFrame != nullptr) {
        av_frame_free(&pFrame);
        LOGI("%s audio Frame free", __FUNCTION__);
    }
 
    if (pAudioAVCodecCtx != nullptr) {
        avcodec_free_context(&pAudioAVCodecCtx);
        LOGI("%s audio avcodec_free_context", __FUNCTION__);
    }
}
 
void AudioDecoder::setFrameDataCallback(FrameDataCallback *frameDataCallback) {
    pthread_mutex_lock(pFrameDataCallbackMutex);
    pFrameDataCallback = frameDataCallback;
    pthread_mutex_unlock(pFrameDataCallbackMutex);
}
 
void AudioDecoder::decode() {
    int ret;
    unsigned sleepDelta = 1024 * 1000000 / gSampleFreq / 4;// 一帧音频的 1/4
 
    while (isDecoding) {
        if (pPacketQueue == nullptr) {
            usleep(sleepDelta);
            continue;
        }
 
        AVPacket *pkt = av_packet_alloc();
        if (pkt == nullptr) {
            usleep(sleepDelta);
            continue;
        }
 
        PACKET_STRUCT *packetStruct;
        bool isDone = pPacketQueue->Take(packetStruct);
        if (isDone && packetStruct != nullptr && packetStruct->data != nullptr &&
            packetStruct->data_size > 0) {
            ret = av_new_packet(pkt, packetStruct->data_size);
            if (ret < 0) {
                av_packet_free(&pkt);
                free(packetStruct->data);
                free(packetStruct);
                
                continue;
            }
        } else {
            av_packet_free(&pkt);
            usleep(sleepDelta);
            continue;
        }
 
        memcpy(pkt->data, packetStruct->data, packetStruct->data_size);
 
        pkt->pts = packetStruct->timestamp;
        pkt->dts = packetStruct->timestamp;
 
 
        /* send the packet for decoding */
        ret = avcodec_send_packet(pAudioAVCodecCtx, pkt);
        //LOGD("%s send the audio packet for decoding pkt size=%d", __FUNCTION__, pkt->size);
        free(packetStruct->data);
        free(packetStruct);
 
        av_packet_unref(pkt);
        av_packet_free(&pkt);
 
        if (ret < 0) {
            LOGE("%s Error sending the audio pkt to the decoder ret=%d", __FUNCTION__, ret);
            usleep(sleepDelta);
            continue;
        } else {
            // 编码和解码都是一样的,都是send 1次,然后receive多次, 直到AVERROR(EAGAIN)或者AVERROR_EOF
            while (ret >= 0) {
                ret = avcodec_receive_frame(pAudioAVCodecCtx, pFrame);
                if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                    usleep(sleepDelta);
                    continue;
                } else if (ret < 0) {
                    LOGE("%s Error receive decoding audio frame ret=%d", __FUNCTION__, ret);
                    usleep(sleepDelta);
                    continue;
                }
 
                // 解码固定为 AV_SAMPLE_FMT_FLTP,需要转码为 AV_SAMPLE_FMT_S16
                // 数据都装在 data[0] 中,而大小则为 linesize[0](实际发现此处大小并不对,大小计算见下面)
                int planeNum = 1;
                int dataLen[planeNum];
                /*dataLen[0] = pFrame->nb_samples *
                             av_get_bytes_per_sample((enum AVSampleFormat) (pFrame->format));*/
                // 重采样转为 S16
                uint8_t *pcmOut[1] = {nullptr};
                pcmOut[0] = pPCM16OutBuf;
                // 音频重采样
                int number = swr_convert(
                        pSwrContext,
                        pcmOut,
                        pFrame->nb_samples,
                        (const uint8_t **) pFrame->data,
                        pFrame->nb_samples
                );
 
                if (number != pFrame->nb_samples) {
                    LOGE("%s swr_convert appear problem number=%d", __FUNCTION__, number);
                } else {
                    dataLen[0] = pFrame->nb_samples *
                                 av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
                    pthread_mutex_lock(pFrameDataCallbackMutex);
                    if (pFrameDataCallback != nullptr) {
                        //LOGD("%s receive the decode frame size=%d nb_samples=%d", __FUNCTION__, dataLen[0], pFrame->nb_samples);
                        pFrameDataCallback->onDataArrived(StreamType::AUDIO,
                                                          (long long) pFrame->pts,
                                                          (char **) pcmOut,
                                                          dataLen,
                                                          planeNum,
                                                          pAudioAVCodecCtx->channels,
                                                          pAudioAVCodecCtx->sample_rate,
                                                          -1,
                                                          -1);
                    }
                    pthread_mutex_unlock(pFrameDataCallbackMutex);
 
                }
 
 
                av_frame_unref(pFrame);
            }
        }
 
    }
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/685364.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【软考网络管理员】2023年软考网管初级常见知识考点(12)-应用层协议

涉及知识点 应用层协议详解&#xff0c;DNS的概念&#xff0c;FTP的概念&#xff0c;DHCP的概念&#xff0c;Telnet的概念&#xff0c;电子邮件协议 软考网络管理员常考知识点&#xff0c;软考网络管理员网络安全&#xff0c;网络管理员考点汇总。 原创于&#xff1a;CSDN博主…

我的内网渗透-代理转发(2)

目录 ssh telnet与SSH的区别 安装环境 常用参数 本地端口转发 远程端口转发 动态端口转发 Socks 使用方法 msf端口转发 常用参数 使用方法 创建监听 MSF读取文件命令&#xff08;开启msf的时候直接读取文件就自动设置好监听的各种配置&#xff09; 获取会话后 …

NCI Core Control Messages

NCI 版本参数应编码为 8 位字段&#xff0c;由两个 4 位无符号值组成&#xff0c;表示本规范的主要和次要版本级别。 最高有效 4 位应表示主要版本级别。 最低有效 4 位应表示本规范的次要版本级别。 如果 DH 支持 NFCC 报告的主要版本&#xff0c;则 DH 应继续通信&#xff0…

同比增长超300%,「手势识别」前装赛道借势多模态座舱交互

在座舱多模态交互系统中&#xff0c;手势识别功能正在成为主流的配置之一。高工智能汽车研究院监测数据显示&#xff0c;2022年中国市场&#xff08;不含进出口&#xff09;乘用车前装标配手势识别功能交付37.39万辆&#xff1b;今年1-4月交付23.90万辆&#xff0c;同比增长超过…

Linux下的free、uname、uptime、netstat、dmesg指令

文章目录 1 查看内存的使用情况&#xff1a;free2 查看系统与内核相关信息&#xff1a;uname3 查看系统运行时间和负载&#xff08;uptime&#xff09;4 查看端口监听&#xff1a;netstat5 分析内核产生的信息&#xff1a;dmesg 1 查看内存的使用情况&#xff1a;free free -m…

C++进阶—二叉搜索树

目录 0. 前言 1. 二叉搜索树概念 2. 二叉搜索树操作 3. 二叉搜索树的实现 3.1 非递归实现插入操作Insert 3.2 二叉搜索树中序遍历递归实现&#xff08;排序&#xff09; 3.3 非递归实现查找操作Find 3.4 非递归实现删除操作Erase 3.5 递归实现插入操作InsertR 3.5 递…

c++读取文件之---yaml-cpp使用

实际项目总会遇到有很多超参数的情况&#xff0c;用常规的结构体等无法有效的涵盖所有&#xff0c;为了方便用户进行配置使用&#xff0c;因此使用yaml的方式进行编辑配置&#xff0c;因此去调研使用了yaml-cpp的使用方法。 1、yaml-cpp下载和编译 下载方式很简单&#xff0c…

openfeign实现远程调用

一 openfeign简介 Feign 是声明性(注解)web 服务客户端它使编写 web 服务客户端更加容易请创建一个接口并对其进行注解.它具有可插入注解支持&#xff0c;包括Feign注解和JAXRS注解Feign 还支持可插拔编码器和解码器。Spring cloud 添加了对Spring MVC注解的支持&#xff0c;并…

chatgpt赋能python:Python编译成SO文件和反编译的介绍

Python编译成SO文件和反编译的介绍 什么是SO文件&#xff1f; SO文件&#xff0c;也称为共享对象文件&#xff0c;是一种二进制文件格式&#xff0c;用于在多个应用程序之间共享代码和数据。在Unix和类Unix系统中&#xff0c;它们通常是共享库文件的形式。因此&#xff0c;SO…

chatgpt赋能python:Python编译成可执行文件:让你的代码更加优雅高效

Python编译成可执行文件&#xff1a;让你的代码更加优雅高效 Python作为世界上最受欢迎的编程语言之一&#xff0c;拥有着丰富的库、面向对象的语法和简单易懂的语法结构。然而&#xff0c;在开发Python应用程序时&#xff0c;受限于Python的解释性&#xff0c;导致程序的效率…

Qt实现自定义控件能够以插件的方式加载到Qt设计师

目录 1、自定义部件/控件2、改进法3、插件法3.1、创建工程3.2、工程目录3.3、修改插件类的代码3.3.1、HexSpinBox类的头文件3.3.2、HexSpinBox类的源文件3.3.3、HexSpinBox类的UI文件3.3.4 需要的注意的事项 3.4、生成动态库 4、测试插件能否正常使用4.1、测试Qt设计师能否识别…

认识@Validated 和 @Valid

对于web应用来说&#xff0c;对方法参数的校验是十分重要的&#xff0c;参数校验的是否全面&#xff0c;直接决定整个方法的健壮性。 除了使用麻烦的if判断校验参数&#xff0c;还可以使用Validated 和 Valid注解来进行优雅地参数校验&#xff0c;让参数校验和写诗一样优雅。 …

手机移动 APP测试流程及测试点

1 APP测试基本流程 1.1 流程图 1.2 测试周期 测试周期可按项目的开发周期来确定测试时间&#xff0c; 一般测试时间为两三 周(即 15 个工作日)&#xff0c;根据项目情况以及版本质量可适当缩短或延长 测试时间。正式测试前先向主管确认项目排期。 1.3 测试资源 测试任务开始…

移动云智能算力调度平台,谱写算力互联互通新篇章

中国移动算力网络建设取得新进展&#xff01;移动云智能算力调度平台验证了多云服务商间异构算力的统一调度能力&#xff0c;联动国家级超算中心、智算中心&#xff0c;促进东部业务灵活使用西部算力&#xff0c;作为未来算力互联网的统一调度平台将持续开展技术攻关与应用创新…

linux系统LNMP架构部署

文章目录 一、Nginx编译安装1、关闭防火墙&#xff0c;安全机制2、安装依赖包3、创建运行用户与组4、解压包、编译安装路径5、编译安装6、优化路径7、添加 Nginx 系统服务、赋权 二、安装 MySQL 服务1、安装环境依赖包2、创建运行用户与组3、解压包、编译安装路径4.编译安装5、…

chatgpt赋能python:用Python编程计算BMI,轻松掌握健康

用Python编程计算BMI&#xff0c;轻松掌握健康 作为一个现代人&#xff0c;保持健康的体态是我们每个人都需要关注的问题。那么&#xff0c;如何快速地计算自己的BMI呢&#xff1f;Python编程可以帮助我们轻松地实现这个目标。 什么是BMI&#xff1f; BMI全称为Body Mass In…

【Linux操作系统】互斥的4个概念以及认识信号量

文章目录 进程互斥的4个概念认识信号量认识接口理解IPC 信号量主要用于同步和互斥的&#xff0c;下面先来看看什么是同步和互斥。 进程互斥的4个概念 我们把大家都能看到的资源&#xff0c;称为公共资源。并且要想实现进程间通信&#xff0c;首要条件就是要让互相通信的进程看…

一文了解kubernetes部署:API部署过程

API部署 准备工作 一、镜像制作 请参考&#xff1a;《API镜像制作》 二、为k8s配置docker私服密钥 请参考&#xff1a;《配置docker私服密钥》 部署API 修改yaml文件 vi/opt/kubernetes/api/config-server.yaml vi/opt/kubernetes/api/api.yaml 1、修改api相应image值为您的镜…

【深度学习】日常笔记7

可以通过在⽹络中加⼊⼀个或多个隐藏层来克服线性模型的限制&#xff0c;使其能处理更普遍的函数关系类型。要做到这⼀点&#xff0c;最简单的⽅法是将许多全连接层堆叠在⼀起。每⼀层都输出到上⾯的层&#xff0c;直到⽣成最后的输出。 上面红框的公式其实换个角度是没错的。实…

总结911

目标规划&#xff1a; 月目标&#xff1a;6月&#xff08;线性代数强化9讲&#xff0c;考研核心词过三遍&#xff09; 周目标&#xff1a;线性代数强化5讲&#xff0c;英语背3篇文章并回诵&#xff0c;检测 每日规划 今日已做 1.回诵之前文章 2.每日长难句&#xff0c;句句…