ffmpeg面向对象-rtsp拉流相关对象

news2024/11/25 16:34:26

目录

    • 1.AVFormatContext类。
      • 1.1 概述
      • 1.2 构造函数
      • 1.3 oopc的继承实现
    • 2. AVInputFormat 类。
      • 2.1 多态的实现
    • 3.所用设计模式
        • 3.1模板模式
          • 3.2 工厂模式?
        • 3.3 rtsp拉流建链
    • 4.this指针
    • 5.小结
    • 6.rtsp拉流流程

1.AVFormatContext类。

1.1 概述

用户看到的是AVFormatContext指针,它是基类,实质实例化的是其派生类(子类)FFFormatContext。
AVFormatContext指针是对用户可见的,被用户拿来使用的流对象基类指针,而它——FFFormatContext——才是ffmpeg隐藏于内部的流对象——流对象基类指针指向的实质对象。

其他的函数调用就是以这个类为中心,实质是实例化这个类(初始化,构造函数)、调用这个类的方法,最后销毁这个类对象。
比如拉流的必经流程:
avformat_open_input
av_read_frame
avformat_close_input

很明显的对应构造,调用方法和析构函数。

1.2 构造函数

rtsp拉流第一步都是avformat_open_input,其入参可以看下怎么用:

AVFormatContext *fmt_ctx = NULL;
result = avformat_open_input(&fmt_ctx, input_filename, NULL, NULL);

其中fmt_ctx 如何分配内存的?如下

int avformat_open_input(AVFormatContext **ps, const char *filename,
                        const AVInputFormat *fmt, AVDictionary **options)
{
    AVFormatContext *s = *ps;
    FFFormatContext *si;
    AVDictionary *tmp = NULL;
    ID3v2ExtraMeta *id3v2_extra_meta = NULL;
    int ret = 0;

    if (!s && !(s = avformat_alloc_context()))
……
}

avformat_alloc_context来给fmt_ctx 分配内存的,看它实质分配的内存有多大:

AVFormatContext *avformat_alloc_context(void)
{
    FFFormatContext *const si = av_mallocz(sizeof(*si));
    AVFormatContext *s;

    if (!si)
        return NULL;

    s = &si->pub;
    s->av_class = &av_format_context_class;
    s->io_open  = io_open_default;
    s->io_close = ff_format_io_close_default;
    s->io_close2= io_close2_default;

    av_opt_set_defaults(s);

    si->pkt = av_packet_alloc();
    si->parse_pkt = av_packet_alloc();
    if (!si->pkt || !si->parse_pkt) {
        avformat_free_context(s);
        return NULL;
    }

    si->shortest_end = AV_NOPTS_VALUE;

    return s;
}

1.3 oopc的继承实现

可以看到它实际分配的内存是FFFormatContext这么大的,但是返回的地址是AVFormatContext *类型的,缩小了。这就是典型的oopc的接口继承

FFFormatContext类如下实现:

typedef struct FFFormatContext {
    /**
     * The public context.
     */
    AVFormatContext pub;

    /**
     * Number of streams relevant for interleaving.
     * Muxing only.
     */
    int nb_interleaved_streams;
    ……
}

oopc的继承实现是结构体套结构体。如上结构体,FFFormatContext继承自AVFormatContext。

同时可以看到它的特点,一般父类都是作为子类第一个成员,这样方便强转更改访问权限。
FFFormatContext第1个成员就是父类AVFormatContext的成员,把它命名为pub——注释中说是public公共上下文——公共的——这就是面向对象中常用的抽象出的基类的基本方法。

所谓接口继承,就是创建子类返父类的地址,这是多态实现的基础。

oopc中,这种继承是个老套路,也是经典套路,linux中,还有rtthread RTOS的内核实现中常用这种套路,这个应该是oopc的经典。

对应的对象图简略示意图如下:
1

2. AVInputFormat 类。

就像linux一切统一于文件,这里一切拉流格式统一于AVInputFormat类,这个数据结构对所有拉流输入格式进行了抽象——同时它提现了面向对象的多态——不同子类的方法不同,在oopc中就是采用函数指针实现。

AVFormatContext的成员iformat是AVInputFormat类的,其主要包含了avformat_open_input输入的url,它是如何拿到AVInputFormat信息的呢?
AVInputFormat是对它支持的所有格式的抽象,它的具体代码体现在demuxer_list数组——其定义在libavformat/demuxer_list.c中,该文件是编译FFMPEG configure的时候生成的,举例生成的数组如下:

static const AVInputFormat * const demuxer_list[] = {
    &ff_aa_demuxer,
    &ff_aac_demuxer,
    &ff_ac3_demuxer,
    &ff_acm_demuxer,
    &ff_act_demuxer,
    &ff_adf_demuxer,
    &ff_adp_demuxer,
    &ff_ads_demuxer,
    &ff_adx_demuxer,
    &ff_aea_demuxer,
    &ff_afc_demuxer,
    &ff_aiff_demuxer,
    &ff_aix_demuxer,
    &ff_amr_demuxer,
    &ff_amrnb_demuxer,
    &ff_amrwb_demuxer,
    &ff_anm_demuxer,
    &ff_apc_demuxer,
    &ff_ape_demuxer,
    &ff_apng_demuxer,
    &ff_aptx_demuxer,
    &ff_aptx_hd_demuxer,
    &ff_aqtitle_demuxer,
    &ff_asf_demuxer,
    &ff_asf_o_demuxer,
    &ff_ass_demuxer,
    &ff_ast_demuxer,
    &ff_au_demuxer,
    &ff_avi_demuxer,
    &ff_avr_demuxer,
    &ff_avs_demuxer,
    &ff_bethsoftvid_demuxer,
    &ff_bfi_demuxer,
    &ff_bintext_demuxer,
    &ff_bink_demuxer,
    &ff_bit_demuxer,
    &ff_bmv_demuxer,
    &ff_bfstm_demuxer,
    &ff_brstm_demuxer,
    &ff_boa_demuxer,
    &ff_c93_demuxer,
    &ff_caf_demuxer,
    &ff_cavsvideo_demuxer,
    &ff_cdg_demuxer,
    &ff_cdxl_demuxer,
    &ff_cine_demuxer,
    &ff_codec2_demuxer,
    &ff_codec2raw_demuxer,
    &ff_concat_demuxer,
    &ff_data_demuxer,
    &ff_daud_demuxer,
    &ff_dcstr_demuxer,
    &ff_dfa_demuxer,
    &ff_dirac_demuxer,
    &ff_dnxhd_demuxer,
    &ff_dsf_demuxer,
    &ff_dsicin_demuxer,
    &ff_dss_demuxer,
    &ff_dts_demuxer,
    &ff_dtshd_demuxer,
    &ff_dv_demuxer,
    &ff_dvbsub_demuxer,
    &ff_dvbtxt_demuxer,
    &ff_dxa_demuxer,
    &ff_ea_demuxer,
    &ff_ea_cdata_demuxer,
    &ff_eac3_demuxer,
    &ff_epaf_demuxer,
    &ff_ffmetadata_demuxer,
    &ff_filmstrip_demuxer,
    &ff_fits_demuxer,
    &ff_flac_demuxer,
    &ff_flic_demuxer,
    &ff_flv_demuxer,
    &ff_live_flv_demuxer,
    &ff_fourxm_demuxer,
    &ff_frm_demuxer,
    &ff_fsb_demuxer,
    &ff_g722_demuxer,
    &ff_g723_1_demuxer,
    &ff_g726_demuxer,
    &ff_g726le_demuxer,
    &ff_g729_demuxer,
    &ff_gdv_demuxer,
    &ff_genh_demuxer,
    &ff_gif_demuxer,
    &ff_gsm_demuxer,
    &ff_gxf_demuxer,
    &ff_h261_demuxer,
    &ff_h263_demuxer,
    &ff_h264_demuxer,
    &ff_hevc_demuxer,
    &ff_hls_demuxer,
    &ff_hnm_demuxer,
    &ff_ico_demuxer,
    &ff_idcin_demuxer,
    &ff_idf_demuxer,
    &ff_iff_demuxer,
    &ff_ilbc_demuxer,
    &ff_image2_demuxer,
    &ff_image2pipe_demuxer,
    &ff_image2_alias_pix_demuxer,
    &ff_image2_brender_pix_demuxer,
    &ff_ingenient_demuxer,
    &ff_ipmovie_demuxer,
    &ff_ircam_demuxer,
    &ff_iss_demuxer,
    &ff_iv8_demuxer,
    &ff_ivf_demuxer,
    &ff_ivr_demuxer,
    &ff_jacosub_demuxer,
    &ff_jv_demuxer,
    &ff_lmlm4_demuxer,
    &ff_loas_demuxer,
    &ff_lrc_demuxer,
    &ff_lvf_demuxer,
    &ff_lxf_demuxer,
    &ff_m4v_demuxer,
    &ff_matroska_demuxer,
    &ff_mgsts_demuxer,
    &ff_microdvd_demuxer,
    &ff_mjpeg_demuxer,
    &ff_mjpeg_2000_demuxer,
    &ff_mlp_demuxer,
    &ff_mlv_demuxer,
    &ff_mm_demuxer,
    &ff_mmf_demuxer,
    &ff_mov_demuxer,
    &ff_mp3_demuxer,
    &ff_mpc_demuxer,
    &ff_mpc8_demuxer,
    &ff_mpegps_demuxer,
    &ff_mpegts_demuxer,
    &ff_mpegtsraw_demuxer,
    &ff_mpegvideo_demuxer,
    &ff_mpjpeg_demuxer,
    &ff_mpl2_demuxer,
    &ff_mpsub_demuxer,
    &ff_msf_demuxer,
    &ff_msnwc_tcp_demuxer,
    &ff_mtaf_demuxer,
    &ff_mtv_demuxer,
    &ff_musx_demuxer,
    &ff_mv_demuxer,
    &ff_mvi_demuxer,
    &ff_mxf_demuxer,
    &ff_mxg_demuxer,
    &ff_nc_demuxer,
    &ff_nistsphere_demuxer,
    &ff_nsp_demuxer,
    &ff_nsv_demuxer,
    &ff_nut_demuxer,
    &ff_nuv_demuxer,
    &ff_ogg_demuxer,
    &ff_oma_demuxer,
    &ff_paf_demuxer,
    &ff_pcm_alaw_demuxer,
    &ff_pcm_mulaw_demuxer,
    &ff_pcm_f64be_demuxer,
    &ff_pcm_f64le_demuxer,
    &ff_pcm_f32be_demuxer,
    &ff_pcm_f32le_demuxer,
    &ff_pcm_s32be_demuxer,
    &ff_pcm_s32le_demuxer,
    &ff_pcm_s24be_demuxer,
    &ff_pcm_s24le_demuxer,
    &ff_pcm_s16be_demuxer,
    &ff_pcm_s16le_demuxer,
    &ff_pcm_s8_demuxer,
    &ff_pcm_u32be_demuxer,
    &ff_pcm_u32le_demuxer,
    &ff_pcm_u24be_demuxer,
    &ff_pcm_u24le_demuxer,
    &ff_pcm_u16be_demuxer,
    &ff_pcm_u16le_demuxer,
    &ff_pcm_u8_demuxer,
    &ff_pjs_demuxer,
    &ff_pmp_demuxer,
    &ff_pva_demuxer,
    &ff_pvf_demuxer,
    &ff_qcp_demuxer,
    &ff_r3d_demuxer,
    &ff_rawvideo_demuxer,
    &ff_realtext_demuxer,
    &ff_redspark_demuxer,
    &ff_rl2_demuxer,
    &ff_rm_demuxer,
    &ff_roq_demuxer,
    &ff_rpl_demuxer,
    &ff_rsd_demuxer,
    &ff_rso_demuxer,
    &ff_rtp_demuxer,
    &ff_rtsp_demuxer,
    &ff_s337m_demuxer,
    &ff_sami_demuxer,
    &ff_sap_demuxer,
    &ff_sbc_demuxer,
    &ff_sbg_demuxer,
    &ff_scc_demuxer,
    &ff_sdp_demuxer,
    &ff_sdr2_demuxer,
    &ff_sds_demuxer,
    &ff_sdx_demuxer,
    &ff_segafilm_demuxer,
    &ff_shorten_demuxer,
    &ff_siff_demuxer,
    &ff_sln_demuxer,
    &ff_smacker_demuxer,
    &ff_smjpeg_demuxer,
    &ff_smush_demuxer,
    &ff_sol_demuxer,
    &ff_sox_demuxer,
    &ff_spdif_demuxer,
    &ff_srt_demuxer,
    &ff_str_demuxer,
    &ff_stl_demuxer,
    &ff_subviewer1_demuxer,
    &ff_subviewer_demuxer,
    &ff_sup_demuxer,
    &ff_svag_demuxer,
    &ff_swf_demuxer,
    &ff_tak_demuxer,
    &ff_tedcaptions_demuxer,
    &ff_thp_demuxer,
    &ff_threedostr_demuxer,
    &ff_tiertexseq_demuxer,
    &ff_tmv_demuxer,
    &ff_truehd_demuxer,
    &ff_tta_demuxer,
    &ff_txd_demuxer,
    &ff_tty_demuxer,
    &ff_ty_demuxer,
    &ff_v210_demuxer,
    &ff_v210x_demuxer,
    &ff_vag_demuxer,
    &ff_vc1_demuxer,
    &ff_vc1t_demuxer,
    &ff_vivo_demuxer,
    &ff_vmd_demuxer,
    &ff_vobsub_demuxer,
    &ff_voc_demuxer,
    &ff_vpk_demuxer,
    &ff_vplayer_demuxer,
    &ff_vqf_demuxer,
    &ff_w64_demuxer,
    &ff_wav_demuxer,
    &ff_wc3_demuxer,
    &ff_webm_dash_manifest_demuxer,
    &ff_webvtt_demuxer,
    &ff_wsaud_demuxer,
    &ff_wsd_demuxer,
    &ff_wsvqa_demuxer,
    &ff_wtv_demuxer,
    &ff_wve_demuxer,
    &ff_wv_demuxer,
    &ff_xa_demuxer,
    &ff_xbin_demuxer,
    &ff_xmv_demuxer,
    &ff_xvag_demuxer,
    &ff_xwma_demuxer,
    &ff_yop_demuxer,
    &ff_yuv4mpegpipe_demuxer,
    &ff_image_bmp_pipe_demuxer,
    &ff_image_dds_pipe_demuxer,
    &ff_image_dpx_pipe_demuxer,
    &ff_image_exr_pipe_demuxer,
    &ff_image_j2k_pipe_demuxer,
    &ff_image_jpeg_pipe_demuxer,
    &ff_image_jpegls_pipe_demuxer,
    &ff_image_pam_pipe_demuxer,
    &ff_image_pbm_pipe_demuxer,
    &ff_image_pcx_pipe_demuxer,
    &ff_image_pgmyuv_pipe_demuxer,
    &ff_image_pgm_pipe_demuxer,
    &ff_image_pictor_pipe_demuxer,
    &ff_image_png_pipe_demuxer,
    &ff_image_ppm_pipe_demuxer,
    &ff_image_psd_pipe_demuxer,
    &ff_image_qdraw_pipe_demuxer,
    &ff_image_sgi_pipe_demuxer,
    &ff_image_svg_pipe_demuxer,
    &ff_image_sunrast_pipe_demuxer,
    &ff_image_tiff_pipe_demuxer,
    &ff_image_webp_pipe_demuxer,
    &ff_image_xpm_pipe_demuxer,
    &ff_image_xwd_pipe_demuxer,
    NULL };

在avformat_open_input中,调用 init_input 获取到的,
如下调用链
init_input => av_probe_input_format2 => av_probe_input_format3 => av_demuxer_iterate。

const AVInputFormat *av_demuxer_iterate(void **opaque)
{
    static const uintptr_t size = sizeof(demuxer_list)/sizeof(demuxer_list[0]) - 1;
    uintptr_t i = (uintptr_t)*opaque;
    const AVInputFormat *f = NULL;
    uintptr_t tmp;

    if (i < size) 
    {
        f = demuxer_list[i];
    } 
    else if (tmp = atomic_load_explicit(&indev_list_intptr, memory_order_relaxed)) 
    {
        const AVInputFormat *const *indev_list = (const AVInputFormat *const *)tmp;
        f = indev_list[i - size];
    }

    if (f)
        *opaque = (void*)(i + 1);
    return f;
}

2.1 多态的实现

在这里就是循环遍历libavformat/demuxer_list.c中的demuxer_list数组,和输入的url进行匹配,不同的输入匹配不同的AVInputFormat类的对象(全局变量)。ffmpeg在各个格式的c文件中定义了AVInputFormat类的对象(全局变量),最后被加入到demuxer_list数组中。这样实现多态。

这样AVFormatContext的成员iformat就指向了匹配到的全局变量。

这里比如rtsp拉流,它会匹配到ff_rtsp_demuxer这个全局变量(通过调用probe),定义在libavformat/rtspdec.c中,如下定义:

const AVInputFormat ff_rtsp_demuxer = {
    .name           = "rtsp",
    .long_name      = NULL_IF_CONFIG_SMALL("RTSP input"),
    .priv_data_size = sizeof(RTSPState),
    .read_probe     = rtsp_probe,
    .read_header    = rtsp_read_header,
    .read_packet    = rtsp_read_packet,
    .read_close     = rtsp_read_close,
    .read_seek      = rtsp_read_seek,
    .flags          = AVFMT_NOFILE,
    .read_play      = rtsp_read_play,
    .read_pause     = rtsp_read_pause,
    .priv_class     = &rtsp_demuxer_class,
};

抽象的这些方法包括:
探测或者称之为辨识是不是本格式的方法probe,
读头信息,读取包数据,等等。把各种格式都抽象统一于此,这样同样的子类但是方法不同,实现了多态。

3.所用设计模式

3.1模板模式

上面这些赋值的很关键,这就是根据对avformat_open_input输入的url进行解析,接着统一的操作如下:
在这里插入图片描述
这种统一操作,不管啥格式的,都走这个流程,就像linux的一切皆文件一样,这种设计模式是为模版模式。

avformat_open_input中的流程,可以说是对所有输入格式抽象出来的共性流程,这种提取出的共性流程,基本万古不变,变得只是函数指针指向或者参数配置,那么这种流程就像一个“模板”一样,这就是模板模式。

这种模式是常见的模式,因为行业固定,行业对应的业务流程基本能抽出共性的流程,那么随着代码的迭代,共性代码会自然出现,而不是因为“设计模式”才出现模板模式,而是因为这样的代码出现了,对它总结,起个名字叫“模板模式”。设计模式来源于现成代码的概念抽象和总结。

3.2 工厂模式?

其根据url来匹配对应的AVInputFormat,有点类似策略模式(但是策略模式的特点是运行中可以更改算法,但这里不是,初始化完毕就不能动了),又有点像工厂模式。

不管了,反正记住一点,设计模式是对现有代码的抽象,先有代码,再有提出对应设计模式的概念

3.3 rtsp拉流建链

而rtsp拉流则调用的是rtsp_read_header,如下

static int rtsp_read_header(AVFormatContext *s)
{
    RTSPState *rt = s->priv_data;
    int ret;

    if (rt->initial_timeout > 0)
        rt->rtsp_flags |= RTSP_FLAG_LISTEN;

    if (rt->rtsp_flags & RTSP_FLAG_LISTEN) {
        ret = rtsp_listen(s);
        if (ret)
            return ret;
    } else {
        ret = ff_rtsp_connect(s);
        if (ret)
            return ret;

        rt->real_setup_cache = !s->nb_streams ? NULL :
            av_calloc(s->nb_streams, 2 * sizeof(*rt->real_setup_cache));
        if (!rt->real_setup_cache && s->nb_streams) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }
        rt->real_setup = rt->real_setup_cache + s->nb_streams;

        if (rt->initial_pause) {
            /* do not start immediately */
        } else {
            ret = rtsp_read_play(s);
            if (ret < 0)
                goto fail;
        }
    }

    return 0;

fail:
    rtsp_read_close(s);
    return ret;
}

这里就包含了rtsp协议链接到完成,所以比较关键。

4.this指针

看下oopc是如何模拟this指针的。
再次突出强调下,rtsp拉流对象是FFFormatContext——对用户看到的是其基类AVFormatContext指针——this指针

FFFormatContext这个就是流对象。this指针实质指向的就是这个流对象的地址。

看下前面的调用
avformat_open_input
av_read_frame
avformat_close_input
它们几个的第一个形参都是流对象的基类指针。

还有其内部调用方法形式:

在这里插入图片描述
s->iformat->read_header(s),
它模拟的就是面向对象的如下形式:
对象指针->对象方法(形参1,形参2,…)

因为面向对象的this指针是默认参数(c++是this,python是self),代码中不需要显式调用,但是oopc中this指针只能如上形式进行显式调用。

而且,还能发现AVInputFormat对所有格式抽象的方法第一个形参都是AVFormatContext指针,这就是this指针,这里this指针指的就是FFFormatContext的基类对象指针。

再看下av_read_frame这个调用,它第一个形参也是这个this指针,内部怎么调用的呢?截取如下

int av_read_frame(AVFormatContext *s, AVPacket *pkt)
{
    FFFormatContext *const si = ffformatcontext(s);
	……
	        ret = read_frame_internal(s, pkt);
	        ……

}

static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
{
    FFFormatContext *const si = ffformatcontext(s);

``    while (!got_packet && !si->parse_queue.head) {
        AVStream *st;
        FFStream *sti;

        /* read next packet */
        ret = ff_read_packet(s, pkt);
        ……
        
}
int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
{
    FFFormatContext *const si = ffformatcontext(s);
`    for (;;) {
		……
`        err = s->iformat->read_packet(s, pkt);
`	……

}

调用链一路到了ff_read_packet,最终到了如下调用:
s->iformat->read_packet(s, pkt);
和之前的形式一样,模拟了面向对象的方法调用形式,但是this指针需要显式调用。

另外AVFormatContext 基类指针怎么取到子类FFFormatContext 指针的呢?ffformatcontext(s)调用,如下

static av_always_inline FFFormatContext *ffformatcontext(AVFormatContext *s)
{
    return (FFFormatContext*)s;
}

很显然,就是强转改变访问权限,不像c++需要维护虚表,运行时选择。因为c没有这个机制,只能这样子,当然linux内核没有做的这么方便,用的是内核第一宏container_of()根据成员地址推算结构体指针,这样父类可以不放到子类结构体的第一个成员。

5.小结

发散下思维,想下面向对象语言是拉流业务怎么搞?
伪代码:

new 拉流对象;
while(1)
{
拉流对象指针->读数据方法(packet);
}
delete 拉流对象;

oopc模拟的话,类使用结构体表示的,继承一般采用结构体套结构体的形式,多态采用函数指针形式。

调用方法形式:
对象.方法(对象指针即this指针,形参1,形参2,…)

ffmpeg拉流呢,就是模拟的这样,比如创建FFFormatContext类对象,然后返回其父类指针,然后调用AVFormatContext的拉流方法readPacket。
其他的方法都是以这个流对象为中心,实质是对流对象进行操作——构造、析构、方法调用。这个方法包含了各种格式,编码、解码、转换,这个流对象就是中心操作对象——流对象内部存放了百宝箱——有数据有方法——这就是面向对象的类对象。这样化繁为简,统一操作。

如果你学过一门面向对象语言,只要掌握基础的类定义,继承,封装,接口类等基础语法,还有了解下智能指针,再看这个ffmpeg代码或者rtthreadrtos内核源码,那么就会感觉无缝衔接,如果了解过oopc的套路,更加无缝衔接。

如果再学下设计模式,那就能看到设计模式。
设计模式是现有代码再由人总结出来的概念。

6.rtsp拉流流程

很多博客有,不再赘述。
如下
https://blog.csdn.net/baidu_41388533/article/details/112728029

https://www.cnblogs.com/caiyingyong/p/16947075.html

https://blog.csdn.net/u013692429/article/details/101698740

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

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

相关文章

精益管理|Toyota Kata 是什么意思?

丰田套路是一种培养持续改进习惯的系统方法&#xff0c;也是精益管理&#xff08;CLMP&#xff09;中的一套方法。“Toyota Kata”一词来自精益专家 Mike Rother 的管理书籍《Toyota Kata&#xff1a;Managing People for Improvement, Adaptiveness, and Superior Results》。…

2024/9/11 小型PLC典型应用2:伺服canlink配置、指令、应用

下面这个指令需要设置伺服的急停方式&#xff08;例如&#xff1a;惯性停机、急停等等&#xff09; 通讯故障步骤排查 1&#xff1a;接线问题 2&#xff1a;配置问题&#xff08;波特率.....&#xff09;

安卓13允许app启动服务 android13允许应用启动服务 无法启动服务 Background start not allowed: service

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.编译6.彩蛋1.前言 android13应用启动服务,有些应用会被禁止启动服务,开启的服务会失败,这是高版本的android的特性,我们需要更改下frameworks的代码。 2.问题分析 查看下logcat信息 B…

百元榜哪个牌子的蓝牙耳机最好用?四大闭眼入高性价比耳机推荐!

蓝牙耳机的普及率在近年来越来越高&#xff0c;行业发展十分迅猛&#xff01;在很多好的品牌涌现的同时&#xff0c;也有很多的品牌质量不过关&#xff0c;货不对版&#xff0c;使得很多的人以为&#xff0c;百元的就没有好用蓝牙耳机&#xff0c;不少小伙伴在选择蓝牙耳机的时…

N-152基于java贪吃蛇游戏5

开发工具eclipse,jdk1.8 文档截图&#xff1a; N-152基于java贪吃蛇游戏5

抽象工厂模式abstract factory

此篇为学习笔记&#xff0c;原文链接 https://refactoringguru.cn/design-patterns/abstract-factory 它能创建一系列相关的对象&#xff0c; 而无需指定其具体类。抽象工厂提供了一个接口&#xff0c; 可用于创建每个系列产品的对象。 优点 你可以确保同一工厂生成的产品相…

2024/9/10黑马头条跟学笔记(六)

D6 1.今日学习内容 1.1需求分析 点击下架之后&#xff0c;app端显示以下架 耦合&#xff0c;没技术点&#xff0c;不用&#xff0c;咱用kafka&#xff0c;流量削峰&#xff0c;异步调用&#xff0c;解耦 为什么要学&#xff1f; 面时提问 2.kafka概述 rabbitMQ&#xff0c;…

C#基础:字段的初始化,特性,类的继承和多态基础demo

目录 一、字段 1.认识字段和属性 2.初始化字段 二、特性 1.特性的基础 2.特性的自定义和使用 三、继承 1.多继承 2.重写父类和增加子类方法 四、多态 一、字段 1.认识字段和属性 public class Test { public int field //我是字段public int property { get; set; …

建议AI大模型小白必看的学习教程!!

逼自己两周刷完 AI大模型(白嫖) LLM大模型自用资料&#xff0c;以及学习路线整理 整理了我入门大模型的学习路线和自用资料&#xff0c;在全民LLM时期&#xff0c;多输入一些就多一重安全感。建议先对LLM全貌有了解&#xff0c;然后自顶向下去学习。前置知识是nlp基础如transf…

Vue3.5正式上线,有哪些新特性和用法?

9月1日&#xff0c; Vue 3.5 正式发布了&#xff01; 此次要版本不包含重大更改&#xff0c;并且包括内部改进和有用的新功能。我们将在这篇博文中介绍一些亮点 - 有关更改和新功能的完整列表&#xff0c;请参阅 GitHub 上的完整更新日志。 1. Props 解构 在vue3.5 之前&#…

C语言14--作用域与存储期

作用域基本概念 C语言中&#xff0c;标识符都有一定的可见范围&#xff0c;这些可见范围保证了标识符只能在一个有限的区域内使用&#xff0c;这个可见范围&#xff0c;被称为作用域&#xff08;scope&#xff09;。 软件开发中&#xff0c;尽量缩小标识符的作用域是一项基本原…

细致刨析JDBC ③ 高级篇

目录 一、JDBC优化及工具类封装 1.现有问题 2.JDBC工具类封装V1.0 3.ThreadLocal 4.JDBC工具类封装V2.0 二、DAO封装及BaseDAO工具类 1.BaseDAO概念 2.BaseDao层代码实现 ① BaseDao层——通用的修改方法 ② 通用的查询方法 ③ 单行查询方法优化 三、事务 1、事务回顾 2.JDBC中…

批量操作Excel的四个方法(求和、移动、对比、合并)

Excel文件肯定少不了保存大量数据&#xff0c;那么在使用excel的时候会不会要大批量数据进行操作&#xff1f;今天分享4个快速使用excel操作的小技巧。希望能够帮大家提高excel制作效率。 技巧一&#xff1a;快速求和 当你想要分别得到行列的总和&#xff0c;我们可以选中表格…

WeChatFerry学习使用

准备 下载软件安装微信 安装python环境 conda create --prefixD:\PythonEnvs\wechatrobotstu python3.10 conda activate D:\PythonEnvs\wechatrobotstu使用 新建python项目 安装依赖包 pip install --upgrade wcferry -i https://pypi.doubanio.com/simple解压dll到一个…

安卓开发板_联发科MTK开发板使用ADB开发

1. ADB 使用 1.1. 前言 ADB&#xff0c;全称 Android Debug Bridge&#xff0c;是 Android 的命令行调试工具&#xff0c;可以完成多种功能&#xff0c;如跟踪系统日志&#xff0c;上传下载文件&#xff0c;安装应用等。 1.2. 准备连接 使用 adb时&#xff0c;你需要&#x…

转到大模型方向来得及吗?

最近不少同学问想搞大模型来得及吗&#xff1f;咨询的同学分成两类&#xff0c;一类是在公司的同学&#xff0c;一类是在校的同学。 第一&#xff0c;对于在校的同学。 一句话&#xff0c;能转到这个方向尽快转。今年校招包括招聘实习生&#xff0c;很多方向比如搜索推荐广告…

敏捷与企业架构:战略联盟

介绍 企业架构的三大支柱是对齐、洞察力和质量。 对齐&#xff1a;企业架构&#xff08;Enterprise Architecture&#xff09;使战略与运营、业务需求与IT供应保持一致&#xff0c;并确保这些变化符合企业战略和目标。 洞察力&#xff1a;企业架构提供对组织、信息系统和技术…

基于JavaWeb开发的Java+jquery+SpringMVC校园网站平台设计和实现

基于JavaWeb开发的JavajquerySpringMVC校园网站平台设计和实现 &#x1f345; 作者主页 网顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接各种…

shutil模块详解

shutil模块提供了一系列高级文件操作功能&#xff0c;包括复制、移动、删除和搜索文件或目录。shutil 模块对压缩包的处理是调用 ZipFile 和 TarFile这两个模块来进行的。 下面详细介绍并给出示例代码&#xff1a; 1. shutil.copy(src, dst) 复制文件&#xff0c;但不保留权限…

【程序员必读】如何用AI修复代码Bug,让你节省宝贵的调试时间!

在编程的旅程中&#xff0c;bug就像是我们前行路上的小石子&#xff0c;时不时地绊倒我们。无论你是刚入门的编程新手&#xff0c;还是经验丰富的开发者&#xff0c;调试代码时总会遇到各种各样的挑战。&#x1f629; 有时候&#xff0c;错误的信息可能模糊不清&#xff0c;令…