FFMPEG库实现mp4/flv文件(H264+AAC)的封装与分离

ffmepeg 4.4(亲测可用)
一、使用FFMPEG库封装264视频和acc音频数据到 mp4/flv 文件中
封装流程
1.使用avformat_open_input分别打开视频和音频文件,初始化其AVFormatContext,使用avformat_find_stream_info获取编码器基本信息
2.使用avformat_alloc_output_context2初始化输出的AVFormatContext结构
3.使用函数avformat_new_stream给输出的AVFormatContext结构创建音频和视频流,使用avcodec_parameters_copy方法将音视频的编码参数拷贝到新创建的对应的流的codecpar结构中
4.使用avio_open打开输出文件,初始化输出AVFormatContext结构中的IO上下文结构
5.使用avformat_write_header写入流的头信息到输出文件中
6.根据时间戳同步原则交错写入音视频数据,并对时间戳信息进行设置和校准
7.写入流预告信息到输出文件中(moov)
8.释放空间,关闭文件
【mp4_muxer.cpp】
#include <stdio.h>
 
#define __STDC_CONSTANT_MACROS
 
#ifdef _WIN32
 //Windows
extern "C"
{
#include "libavformat/avformat.h"
};
#else
 //Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavformat/avformat.h>
#ifdef __cplusplus
};
#endif
#endif
 
 
 
int main(int argc, char* argv[]) {
    const AVOutputFormat* ofmt = NULL;
    //Input AVFormatContext and Output AVFormatContext
    AVFormatContext* ifmt_ctx_v = NULL, * ifmt_ctx_a = NULL, * ofmt_ctx = NULL;
    AVPacket pkt;
    int ret;
    unsigned int i;
    int videoindex_v = -1, videoindex_out = -1;
    int audioindex_a = -1, audioindex_out = -1;
    int frame_index = 0;
    int64_t cur_pts_v = 0, cur_pts_a = 0;
    int writing_v = 1, writing_a = 1;
 
    const char* in_filename_v = "test.h264";
    const char* in_filename_a = "audio_chn0.aac";
 
    const char* out_filename = "test.mp4";//Output file URL
 
 
    if ((ret = avformat_open_input(&ifmt_ctx_v, in_filename_v, 0, 0)) < 0) {
        printf("Could not open input file.");
        goto end;
    }
    if ((ret = avformat_find_stream_info(ifmt_ctx_v, 0)) < 0) {
        printf("Failed to retrieve input stream information");
        goto end;
    }
 
    if ((ret = avformat_open_input(&ifmt_ctx_a, in_filename_a, 0, 0)) < 0) {
        printf("Could not open input file.");
        goto end;
    }
    if ((ret = avformat_find_stream_info(ifmt_ctx_a, 0)) < 0) {
        printf("Failed to retrieve input stream information");
        goto end;
    }
    //Output
    avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
    if (!ofmt_ctx) {
        printf("Could not create output context\n");
        ret = AVERROR_UNKNOWN;
        goto end;
    }
    ofmt = ofmt_ctx->oformat;
 
    for (i = 0; i < ifmt_ctx_v->nb_streams; i++) {
        //Create output AVStream according to input AVStream
        if (ifmt_ctx_v->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
 
            AVStream* out_stream = avformat_new_stream(ofmt_ctx, nullptr);
            videoindex_v = i;
            if (!out_stream) {
                printf("Failed allocating output stream\n");
                ret = AVERROR_UNKNOWN;
                goto end;
            }
            videoindex_out = out_stream->index;
            //Copy the settings of AVCodecContext
            if (avcodec_parameters_copy(out_stream->codecpar, ifmt_ctx_v->streams[i]->codecpar) < 0) {
                printf("Failed to copy context from input to output stream codec context\n");
                goto end;
            }
 
 
            break;
        }
    }
 
    for (i = 0; i < ifmt_ctx_a->nb_streams; i++) {
        //Create output AVStream according to input AVStream
        if (ifmt_ctx_a->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
 
            AVStream* out_stream = avformat_new_stream(ofmt_ctx, nullptr);
            audioindex_a = i;
            if (!out_stream) {
                printf("Failed allocating output stream\n");
                ret = AVERROR_UNKNOWN;
                goto end;
            }
            audioindex_out = out_stream->index;
 
            //Copy the settings of AVCodecContext
            if (avcodec_parameters_copy(out_stream->codecpar, ifmt_ctx_a->streams[i]->codecpar) < 0) {
                printf("Failed to copy context from input to output stream codec context\n");
                goto end;
            }
            out_stream->codecpar->codec_tag = 0;
            if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
                ofmt_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
            break;
        }
    }
 
    /* open the output file, if needed */
    if (!(ofmt->flags & AVFMT_NOFILE)) {
        if (avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE)) {
            fprintf(stderr, "Could not open '%s': %d\n", out_filename,
                ret);
            goto end;
        }
    }
 
    //Write file header
    if (avformat_write_header(ofmt_ctx, NULL) < 0) {
        fprintf(stderr, "Error occurred when opening output file: %d\n",
            ret);
        goto end;
    }
 
    //写入数据
    while (writing_v || writing_a)
    {
        AVFormatContext* ifmt_ctx;
        int stream_index = 0;
        AVStream* in_stream, * out_stream;
        int av_type = 0;

        if (writing_v &&
            (!writing_a || av_compare_ts(cur_pts_v, ifmt_ctx_v->streams[videoindex_v]->time_base,
                cur_pts_a, ifmt_ctx_a->streams[audioindex_a]->time_base) <= 0))
        {
            av_type = 0;
            ifmt_ctx = ifmt_ctx_v;
            stream_index = videoindex_out;
 
            if (av_read_frame(ifmt_ctx, &pkt) >= 0)
            {
                do {
                    in_stream = ifmt_ctx->streams[pkt.stream_index];
                    out_stream = ofmt_ctx->streams[stream_index];
 
                    if (pkt.stream_index == videoindex_v)
                    {
                        //FIX:No PTS (Example: Raw H.264)
                        //Simple Write PTS
                        if (pkt.pts == AV_NOPTS_VALUE)
                        {
                            //Write PTS
                            AVRational time_base1 = in_stream->time_base;
                            //Duration between 2 frames (us)
                            int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
                            
                            //Parameters
                            pkt.pts = (double)(frame_index * calc_duration) / (double)(av_q2d(time_base1) * AV_TIME_BASE);
                            pkt.dts = pkt.pts;
                            pkt.duration = (double)calc_duration / (double)(av_q2d(time_base1) * AV_TIME_BASE);
                            frame_index++;
                            printf("frame_index:  %d\n", frame_index);
                        }
 
                        cur_pts_v = pkt.pts;
                        break;
                    }
                } while
                    (av_read_frame(ifmt_ctx, &pkt) >= 0);
            }
            else
            {
                writing_v = 0;
                continue;
            }
        }
        else
        {
            av_type = 1;
            ifmt_ctx = ifmt_ctx_a;
            stream_index = audioindex_out;

            if (av_read_frame(ifmt_ctx, &pkt) >= 0)
            {
                do {
                    in_stream = ifmt_ctx->streams[pkt.stream_index];
                    out_stream = ofmt_ctx->streams[stream_index];
 
                    if (pkt.stream_index == audioindex_a)
                    {
                        //FIX:No PTS
                        //Simple Write PTS
                        if (pkt.pts == AV_NOPTS_VALUE)
                        {
                            //Write PTS
                            AVRational time_base1 = in_stream->time_base;
                            //Duration between 2 frames (us)
                            int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
                            //Parameters
                            pkt.pts = (double)(frame_index * calc_duration) /
                                (double)(av_q2d(time_base1) * AV_TIME_BASE);
                            pkt.dts = pkt.pts;
                            pkt.duration = (double)calc_duration / (double)(av_q2d(time_base1) * AV_TIME_BASE);
                            frame_index++;
                        }
                        cur_pts_a = pkt.pts;
                        break;
                    }
                } while (av_read_frame(ifmt_ctx, &pkt) >= 0);
            }
            else
            {
                writing_a = 0;
                continue;
            }
        }
 
        //Convert PTS/DTS
        pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base,
            (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
        pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base,
            (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
        pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
        pkt.pos = -1;
        pkt.stream_index = stream_index;
 
        printf("Write 1 Packet. type:%d, size:%d\tpts:%ld\n", av_type, pkt.size, pkt.pts);
        //Write
        if (av_interleaved_write_frame(ofmt_ctx, &pkt) < 0) {
            printf("Error muxing packet\n");
            break;
        }
        av_packet_unref(&pkt);
    }
 
    printf("Write file trailer.\n");
    //Write file trailer
    av_write_trailer(ofmt_ctx);
 
end:
    avformat_close_input(&ifmt_ctx_v);
    avformat_close_input(&ifmt_ctx_a);
    /* close output */
    if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
        avio_close(ofmt_ctx->pb);
    avformat_free_context(ofmt_ctx);
    if (ret < 0 && ret != AVERROR_EOF) {
        printf("Error occurred.\n");
        return -1;
    }
    return 0;
}
【Makefile】
CROSS_COMPILE = aarch64-himix200-linux-

CC = $(CROSS_COMPILE)g++
AR = $(CROSS_COMPILE)ar
STRIP = $(CROSS_COMPILE)strip

CFLAGS = -Wall -O2 -I../../source/mp4Lib/include
LIBS += -L../../source/mp4Lib/lib -lpthread
LIBS += -lavformat -lavcodec -lavdevice -lavutil -lavfilter -lswscale -lswresample -lz


SRCS = $(wildcard *.cpp)
OBJS = $(SRCS:%.cpp=%.o)
DEPS = $(SRCS:%.cpp=%.d)
TARGET = mp4muxer

all:$(TARGET)

-include $(DEPS)

%.o:%.cpp
        $(CC) $(CFLAGS) -c -o $@ $<

%.d:%.c
        @set -e; rm -f $@; \
        $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
        sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
        rm -f $@.$$$$


$(TARGET):$(OBJS)
        $(CC) -o $@ $^ $(LIBS)
        $(STRIP) $@ 

.PHONY:clean

clean:
        rm -fr $(TARGET) $(OBJS) $(DEPS)
二、使用FFMPEG分离mp4/flv文件中的264视频和aac音频
分离流程
1.使用avformat_open_input 函数打开文件并初始化结构AVFormatContext
2.查找是否存在音频和视频信息
3.构建一个h264_mp4toannexb比特流的过滤器,用来给视频avpaket包添加头信息
4.打开2个输出文件(音频, 视频)
5.循环读取视频文件,并将音视频分别写入文件
注意:音频需要手动添加头信息,没有提供aac的adts自动添加的过滤器
【mp4_demuxer.cpp】
#include <stdio.h>
extern "C"
{
#include <libavformat/avformat.h>
}
 
/* 打印编码器支持该采样率并查找指定采样率下标 */
static int find_sample_rate_index(const AVCodec* codec, int sample_rate)
{
        const int* p = codec->supported_samplerates;
        int sample_rate_index = -1; //支持的分辨率下标
        int count = 0;
        while (*p != 0) {// 0作为退出条件,比如libfdk-aacenc.c的aac_sample_rates
                printf("%s 支持采样率: %dhz  对应下标:%d\n", codec->name, *p, count);
 
                if (*p == sample_rate)
                        sample_rate_index = count;
                p++;
                count++;
        }
        return sample_rate_index;
}
 
 
/// <summary>
/// 给aac音频数据添加adts头
/// </summary>
/// <param name="header">adts数组</param>
/// <param name="sample_rate">采样率</param>
/// <param name="channals">通道数</param>
/// <param name="prfile">音频编码器配置文件(FF_PROFILE_AAC_LOW  定义在 avcodec.h)</param>
/// <param name="len">音频包长度</param>
void addHeader(char header[], int sample_rate, int channals, int prfile, int len)
{
        uint8_t sampleIndex = 0;    
        switch (sample_rate) {
        case 96000: sampleIndex = 0; break;
        case 88200: sampleIndex = 1; break;
        case 64000: sampleIndex = 2; break;
        case 48000: sampleIndex = 3; break;
        case 44100: sampleIndex = 4; break;
        case 32000: sampleIndex = 5; break;
        case 24000: sampleIndex = 6; break;
        case 22050: sampleIndex = 7; break;
        case 16000: sampleIndex = 8; break;
        case 12000: sampleIndex = 9; break;
        case 11025: sampleIndex = 10; break;
        case 8000: sampleIndex = 11; break;
        case 7350: sampleIndex = 12; break;
        default: sampleIndex = 4; break;
        }
 
        uint8_t audioType = 2;  //AAC LC
 
        uint8_t channelConfig = 2;      //双通道
 
        len += 7;
        //0,1是固定的
        header[0] = (uint8_t)0xff;         //syncword:0xfff                          高8bits
        header[1] = (uint8_t)0xf0;         //syncword:0xfff                          低4bits
        header[1] |= (0 << 3);    //MPEG Version:0 for MPEG-4,1 for MPEG-2  1bit
        header[1] |= (0 << 1);    //Layer:0                                 2bits 
        header[1] |= 1;           //protection absent:1                     1bit
        //根据aac类型,采样率,通道数来配置
        header[2] = (audioType - 1) << 6;            //profile:audio_object_type - 1                      2bits
        header[2] |= (sampleIndex & 0x0f) << 2; //sampling frequency index:sampling_frequency_index  4bits 
        header[2] |= (0 << 1);                             //private bit:0                                      1bit
        header[2] |= (channelConfig & 0x04) >> 2;           //channel configuration:channel_config               高1bit
        //根据通道数+数据长度来配置
        header[3] = (channelConfig & 0x03) << 6;     //channel configuration:channel_config      低2bits
        header[3] |= (0 << 5);                      //original:0                               1bit
        header[3] |= (0 << 4);                      //home:0                                   1bit
        header[3] |= (0 << 3);                      //copyright id bit:0                       1bit  
        header[3] |= (0 << 2);                      //copyright id start:0                     1bit
        header[3] |= ((len & 0x1800) >> 11);           //frame length:value   高2bits
        //根据数据长度来配置
        header[4] = (uint8_t)((len & 0x7f8) >> 3);     //frame length:value    中间8bits
        header[5] = (uint8_t)((len & 0x7) << 5);       //frame length:value    低3bits
        header[5] |= (uint8_t)0x1f;                    //buffer fullness:0x7ff 高5bits
        header[6] = (uint8_t)0xfc;
}
 
 
int main() {
        AVFormatContext* ifmt_ctx = NULL;
        AVPacket pkt;
        int ret;
    unsigned int i;
        int videoindex = -1, audioindex = -1;
        const char* in_filename = "test.mp4";
        const char* out_filename_v = "test1.h264";
        const char* out_filename_a = "test1.aac";
 
        if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
                printf("Could not open input file.");
                return -1;
        }
 
        if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
                printf("Failed to retrieve input stream information");
                return -1;
        }
 
        videoindex = -1;
        for (i = 0; i < ifmt_ctx->nb_streams; i++) { //nb_streams:视音频流的个数
                if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
                        videoindex = i;
                else if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
                        audioindex = i;
        }
 
        printf("\nInput Video===========================\n");
        av_dump_format(ifmt_ctx, 0, in_filename, 0);  // 打印信息
        printf("\n======================================\n");
 
        FILE* fp_audio = fopen(out_filename_a, "wb+");
        FILE* fp_video = fopen(out_filename_v, "wb+");
 
 
        AVBSFContext* bsf_ctx = NULL;
        const AVBitStreamFilter* pfilter = av_bsf_get_by_name("h264_mp4toannexb");
        if (pfilter == NULL) {
                printf("Get bsf failed!\n");
        }
 
        if ((ret = av_bsf_alloc(pfilter, &bsf_ctx)) != 0) {
                printf("Alloc bsf failed!\n");
 
        }
 
        ret = avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[videoindex]->codecpar);
        if (ret < 0) {
                printf("Set Codec failed!\n");
 
        }
        ret = av_bsf_init(bsf_ctx);
        if (ret < 0) {
                printf("Init bsf failed!\n");
 
        }
 
        //这里遍历音频编码器打印支持的采样率,并找到当前音频采样率所在的下表,用于后面添加adts头
    //本程序并没有使用,只是测试,如果为了程序健壮性可以采用此方式
        const AVCodec* codec = nullptr;
        codec  = avcodec_find_encoder(ifmt_ctx->streams[audioindex]->codecpar->codec_id);
        int sample_rate_index = find_sample_rate_index(codec, ifmt_ctx->streams[audioindex]->codecpar->sample_rate);
        printf("分辨率数组下表:%d\n", sample_rate_index);
 
        while (av_read_frame(ifmt_ctx, &pkt) >= 0) {
                if (pkt.stream_index == videoindex) {
 
                        av_bsf_send_packet(bsf_ctx, &pkt);
 
                        while (true)
                        {
                                ret = av_bsf_receive_packet(bsf_ctx, &pkt);
                                if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                                        break;
                                else if (ret < 0) {
                                        printf("Receive Pkt failed!\n");
                                        break;
                                }
 
                                printf("Write Video Packet. size:%d\tpts:%ld\n", pkt.size, pkt.pts);
 
                                fwrite(pkt.data, 1, pkt.size, fp_video);
                        }

                }
                else if (pkt.stream_index == audioindex) {
                        printf("Write Audio Packet. size:%d\tpts:%ld\n", pkt.size, pkt.pts);
                        char adts[7] = { 0 };
                        addHeader(adts, ifmt_ctx->streams[audioindex]->codecpar->sample_rate, 
                                ifmt_ctx->streams[audioindex]->codecpar->channels, 
                                ifmt_ctx->streams[audioindex]->codecpar->profile,
                                pkt.size);
                        fwrite(adts, 1, 7, fp_audio);
                        fwrite(pkt.data, 1, pkt.size, fp_audio);
                }
                av_packet_unref(&pkt);
        }
 
        av_bsf_free(&bsf_ctx);
 
 
        fclose(fp_video);
        fclose(fp_audio);
 
        avformat_close_input(&ifmt_ctx);
        return 0;
 
 
        if (ifmt_ctx)
                avformat_close_input(&ifmt_ctx);
        if (fp_audio)
                fclose(fp_audio);
        if (fp_video)
                fclose(fp_video);
        if (bsf_ctx)
                av_bsf_free(&bsf_ctx);
        return -1;
}
【Makefile】
CROSS_COMPILE = aarch64-himix200-linux-

CC = $(CROSS_COMPILE)g++
AR = $(CROSS_COMPILE)ar
STRIP = $(CROSS_COMPILE)strip

CFLAGS = -Wall -O2 -I../../source/mp4Lib/include
LIBS += -L../../source/mp4Lib/lib -lpthread
LIBS += -lavformat -lavcodec -lavdevice -lavutil -lavfilter -lswscale -lswresample -lz

SRCS = $(wildcard *.cpp)
OBJS = $(SRCS:%.cpp=%.o)
DEPS = $(SRCS:%.cpp=%.d)
TARGET = mp4demuxer

all:$(TARGET)

-include $(DEPS)

%.o:%.cpp
        $(CC) $(CFLAGS) -c -o $@ $<

%.d:%.c
        @set -e; rm -f $@; \
        $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
        sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
        rm -f $@.$$$$


$(TARGET):$(OBJS)
        $(CC) -o $@ $^ $(LIBS)
        $(STRIP) $@ 

.PHONY:clean

clean:
        rm -fr $(TARGET) $(OBJS) $(DEPS)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Cloud Config、Apollo、Nacos和Archaius对比

一、适应场景 Spring Cloud Config、Apollo、Nacos、Archaius这四个配置中心在功能和使用场景上有所差异。 1.Spring Cloud Config Spring Cloud Config是Spring Cloud官方提供的分布式系统的外部配置中心。它提供了服务器和客户端支持&#xff0c;可以集中管理不同环境、不同集…

【性能测试】Linux下Docker安装与docker-compose管理容器(超细整理)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、Linux下Docker…

conda修改虚拟环境名称

conda 修改虚拟环境名称 conda 不能直接更改名称&#xff0c;但是可以通过克隆环境解决 新建环境&#xff08;克隆旧环境&#xff09; conda create --name 新环境名 --clone 旧环境名 删除原环境 conda remove --name 旧环境名 --all 查看现有环境 conda env list conda i…

commons-io

概述 commons-io是apache开源基金组织提供的一组有关IO操作的类库&#xff0c;可以提高IO功能开发的效率。 commons-io工具包提供了很多有关io操作的类。有两个主要的类FileUtils, IOUtils。 FileUtils主要有如下方法: 使用commons-io简化io流读写 在项目中创建一个文件夹&…

银河麒麟操作系统安装_V4/V10系统详细使用教程

银河麒麟桌面操作系统V10是一款简单易用、稳定高效、安全创新的新一代图形化桌面操作系统产品。现已适配国产主流软硬件产品&#xff0c;同源支持飞腾、鲲鹏、海思麒麟、龙芯、申威、海光、兆芯等国产CPU和Intel、AMD平台&#xff0c;通过功耗管理、内核锁及页拷贝、网络、VFS、…

筹码穿透率指标选股公式,衡量筹码抛压

在前面的文章中&#xff0c;介绍了博弈K线&#xff0c;它是根据筹码分布的原理结合普通K线的方法绘制出来的。当博弈K线的实体部分比较长的时候&#xff0c;说明当天穿越筹码密集区&#xff0c;有大量的筹码解套。通过引入换手率&#xff0c;可以衡量套牢盘的抛压程度。如果穿越…

Open3D 使用自定义多边形numpy数组边界裁剪点云( 附python 代码)多边形内部点

首先创建了一个包含多个多边形边界点的numpy 坐标数组。 然后,我们定义了一个多边形选择体积的顶点坐标数组 vertices,用于创建 SelectionPolygonVolume 对象 selection_volume。我们设置了 orthogonal_axis 为 "Z",表示选择体积的法向轴为 Z 轴;并设置了 bound…

科普测量开关电源输出波形的三种方法及电源波形自动化测试步骤

开关电源波形测试就是对开关电源的输出波形进行检测和分析&#xff0c;观察开关电源参数变化&#xff0c;以此来判断开关电源的性能是否符合要求。好的开关电源对于设备以及整个电路的正常运行是非常重要的&#xff0c;因此开关电源输出波形测试是开关电源测试的重要环节&#…

flink1.18.0 自适应调度器 资源弹性缩放 flink帮你决定并行度

jobmanager.scheduler Elastic Scaling | Apache Flink 配置文件修改并重启flink后,webui上会显示调整并行度的按钮,他可以自己调整,你也可以通过webUI手动调整: 点击 之后: 调整完成后:

win10 如何显示文件后缀名和隐藏文件

显示文件扩展名&#xff1a; 显示文件扩展名可以帮助你更容易地识别文件类型。默认情况下&#xff0c;Windows 10会隐藏文件的扩展名。 打开“文件资源管理器”&#xff08;File Explorer&#xff09;文件夹。或者你可以通过点击任务栏下方的文件夹图标或使用快捷键Win E来打…

【C++心愿便利店】No.12---C++之探索string底层实现

文章目录 前言一、写实拷贝&#xff08;了解&#xff09;二、string类常用接口实现2.1 成员变量2.2 默认构造函数2.3 拷贝构造函数2.4 operator2.5 operator[]2.6 c_str2.7 size()2.8 capacity() 三、迭代器的实现3.1 begin()和end()3.2 范围for 四、string类增删查改4.1 reser…

开发知识点-Mybatis

MybatisPlus [项目实战]Spring Boot 2.x 实现《百思不得姐》2-APP数据抓包3-基础环境搭建4-抓取原始数据5-json序列化与反序列化6-URL爬虫实现7-MyBatis保存原始数据8-数据建模19-配置优化与项目上线电商秒杀系统实战&&集成环境mybatis&springboot在 application.p…

关于有源电力滤波器在地铁站低压配电系统中的应用分析

安科瑞 崔丽洁 摘要&#xff1a;作为国家提出的绿色电网、节能降耗已成为现代化企业努力的目标&#xff0c;也是企业急需解决的问题。作为地铁车站这类市政公共交通建筑的着重系统——配电系统。实现绿色电网实质上是解决电网中存在的各种电能问题&#xff0c;主要是涉及到谐波…

【科研绘图】MacOS上的LaTeX公式插入工具——LaTeXiT

在Mac上经常用OmniGraffle绘图&#xff0c;但是有个致命缺点是没办法插入LaTeX公式&#xff0c;很头疼。之前有尝试用Pages文稿插入公式&#xff0c;但是调字体和颜色很麻烦。并且&#xff0c;PPT中的公式插入感觉也不太好看。 偶然机会了解到了LaTeXiT这个工具&#xff0c;可…

NVM安装node后提示没有对应npm包(即:无法将“npm”项识别为 cmdlet、函数、脚本文件)

背景 windows11 node版本降低到v12.22.12后&#xff0c;执行&#xff1a;nvm -v npm -v npm : 无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写&#xff0c;如果 包括路径&#xff0c;请确保路径正确&#xff0c;然后再试一次。 所在位置 …

XOR Construction

思路&#xff1a; 通过题目可以得出结论 b1^b2a1 b2^b3a2 ....... bn-1^bnan-1 所以就可以得出 (b1^b2)^(b2^b3)a1^a2 b1^b3a1^a2 有因为当确定一个数的时候就可以通过异或得到其他所有的数&#xff0c;且题目所求的是一个n-1的全排列 那么求出a的前缀异或和arr之后…

Zeitgeist ZTG Token以及其预测市场加入Moonbeam生态

波卡上的首选多链开发平台Moonbeam宣布与Zeitgeist达成XCM集成&#xff0c;将ZTG Token引入Moonbeam。此集成将使波卡内的Moonbeam和Zeitgeist网络之间的流动性得以流动&#xff0c;并通过Moonbeam的互连合约实现远程链集成。 Zeitgeist是一个基于波卡的Substrate区块链框架构…

使用微信小程序控制蓝牙小车(微信小程序端)

目录 使用接口界面效果界面设计界面逻辑设计 使用接口 微信小程序官方开发文档 接口说明wx.openBluetoothAdapter初始化蓝牙模块wx.closeBluetoothAdapter关闭蓝牙模块(调用该方法将断开所有已建立的连接并释放系统资源)wx.startBluetoothDevicesDiscovery开始搜寻附近的蓝牙…

【ATTCK】MITRE ATTCK 设计与哲学

MITRE ATT&CK™:设计与哲学 来源&#xff1a;MITRE ATT&CK™: Design and Philosophy 摘要 MITRE ATT&CK知识库描述了网络对手的行为&#xff0c;并为攻击和防御提供了一个通用的分类。它已成为跨许多网络安全领域的一个有用工具&#xff0c;用于传递威胁情报&…

纵行科技LPWAN2.0芯片产品ZT1826获“2023年度硬核芯”大奖

2023年10月30日&#xff0c;由深圳市芯师爷科技有限公司主办、慕尼黑华南电子展协办、深圳市半导体行业协会支持的“第五届硬核芯生态大会暨2023汽车芯片技术创新与应用论坛”在深圳国际会展中心1号馆圆满落幕。当晚&#xff0c;“2023年度硬核芯评选”获奖榜单同步揭晓并进行颁…