VLC播放器调试经验总结

2023-05-16

一、前言

在使用VS学习VLC源码时,可以打断点分析变量数据,跟踪代码流程,方便我们理解源码。但是在定位音视频卡顿、延时等疑难问题时,这一招就不管用了,因为打上断点就会导致实时计算的pts值不准确,影响复现真实场景。所以音视频卡顿、延时类问题,更需要我们抓包、打印每一帧数据的Timestamp、pts及clock转换中的关键数据。这里引入一个简单的方法:增加收流、解码、渲染一条线上的时间戳,便于分析。

二、时间戳日志打印具体方法

1、将live/liveMedia/include/RTPSource.hh中的fCurPacketRTPTimestamp变量修改为pubilc类型

class RTPSource: public FramedSource {
public:
    <span style="color:#3333FF;">u_int32_t fCurPacketRTPTimestamp;</span>

  static Boolean lookupByName(UsageEnvironment& env, char const* sourceName,
			      RTPSource*& resultSource);
2、在live\liveMedia\FramedSource.cpp中包含RTPSource.hh头文件,修改FramedSource::afterGetting函数,将裸码流中的Timestamp传递出去

void FramedSource::afterGetting(FramedSource* source) {
  source->fIsCurrentlyAwaitingData = False;
      // indicates that we can be read again
      // Note that this needs to be done here, in case the "fAfterFunc"
      // called below tries to read another frame (which it usually will)
  <span style="color:#3333FF;">// m by yagerfgcs begin 用时间戳fCurPacketRTPTimestamp替换fDurationInMicroseconds,传递到live555::StreamRead函数中
  if (source->fAfterGettingFunc != NULL) {
    (*(source->fAfterGettingFunc))(source->fAfterGettingClientData,
				   source->fFrameSize, source->fNumTruncatedBytes,
				   source->fPresentationTime,
                   ((RTPSource*)source)->fCurPacketRTPTimestamp);
  }
  
  /*if (source->fAfterGettingFunc != NULL) {
      (*(source->fAfterGettingFunc))(source->fAfterGettingClientData,
      source->fFrameSize, source->fNumTruncatedBytes,
      source->fPresentationTime,
      source->fDurationInMicroseconds);
      }*/
  // end</span>

}
3、在modules\access\live555.cpp中StreamRead函数中借用p_block->i_dts存储Timestamp。传递出去

    /* Update our global npt value */
    if( tk->f_npt > 0 &&
        ( tk->f_npt < p_sys->f_npt_length || p_sys->f_npt_length <= 0 ) )
        p_sys->f_npt = tk->f_npt;

    if( p_block )
    {
        if( !tk->b_muxed && !tk->b_asf )
        {
            if( i_pts != tk->i_pts )
                p_block->i_pts = VLC_TS_0 + i_pts;

            /*FIXME: for h264 you should check that packetization-mode=1 in sdp-file */
            p_block->i_dts = ( tk->fmt.i_codec == VLC_CODEC_MPGV ) ? VLC_TS_INVALID : (VLC_TS_0 + i_pts);

            <span style="color:#3333FF;">// yagerfgcs for 借dts值赋值给timestamp;
            p_block->i_dts = duration;</span>
        }

        if( tk->b_muxed )
            stream_DemuxSend( tk->p_out_muxed, p_block );
        else if( tk->b_asf )
            stream_DemuxSend( p_sys->p_out_asf, p_block );
        else
            es_out_Send(p_demux->out, tk->p_es, p_block);
    }

4、在src\input\es_out.c中EsOutSend函数中可以分别打印音视频码流时间戳timestamp、显示时间戳pts。也可以在此处屏蔽音频或视频的输入,避免送入到解码模块。

static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
{
    es_out_sys_t   *p_sys = out->p_sys;
    input_thread_t *p_input = p_sys->p_input;

    if( libvlc_stats( p_input ) )
    {
        uint64_t i_total;

        vlc_mutex_lock( &p_input->p->counters.counters_lock );
        stats_Update( p_input->p->counters.p_demux_read,
                      p_block->i_buffer, &i_total );
        stats_Update( p_input->p->counters.p_demux_bitrate, i_total, NULL );

        /* Update number of corrupted data packats */
        if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
        {
            stats_Update( p_input->p->counters.p_demux_corrupted, 1, NULL );
        }
        /* Update number of discontinuities */
        if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
        {
            stats_Update( p_input->p->counters.p_demux_discontinuity, 1, NULL );
        }
        vlc_mutex_unlock( &p_input->p->counters.counters_lock );
    }

    vlc_mutex_lock( &p_sys->lock );

    /* Mark preroll blocks */
    if( p_sys->i_preroll_end >= 0 )
    {
        int64_t i_date = p_block->i_pts;
        if( p_block->i_pts <= VLC_TS_INVALID )
            i_date = p_block->i_dts;

        if( i_date < p_sys->i_preroll_end )
            p_block->i_flags |= BLOCK_FLAG_PREROLL;
    }

    if( !es->p_dec )
    {
        block_Release( p_block );
        vlc_mutex_unlock( &p_sys->lock );
        return VLC_SUCCESS;
    }

    /* Check for sout mode */
    if( p_input->p->p_sout )
    {
        /* FIXME review this, proper lock may be missing */
        if( p_input->p->p_sout->i_out_pace_nocontrol > 0 &&
            p_input->p->b_out_pace_control )
        {
            msg_Dbg( p_input, "switching to sync mode" );
            p_input->p->b_out_pace_control = false;
        }
        else if( p_input->p->p_sout->i_out_pace_nocontrol <= 0 &&
                 !p_input->p->b_out_pace_control )
        {
            msg_Dbg( p_input, "switching to async mode" );
            p_input->p->b_out_pace_control = true;
        }
    }
<span style="color:#FF0000;">
   <span style="color:#3333FF;"> // add by yagerfgcs for log 音视频打印不同日志,便于定位
    if (es->p_dec->fmt_out.i_cat == VIDEO_ES)
    {
        msg_Dbg(p_input, "[TS es_out::EsOutSend] video pts[%llu] timestamp[%llu]", p_block->i_pts, p_block->i_dts);
    }
    else if (es->p_dec->fmt_out.i_cat == AUDIO_ES)
    {
        msg_Dbg(p_input, "[TS es_out::EsOutSend] audio pts[%llu] timestamp[%llu]", p_block->i_pts, p_block->i_dts);
    }
    // end by add</span></span>

    /* Decode */
    if( es->p_dec_record )
    {
        block_t *p_dup = block_Duplicate( p_block );
        if( p_dup )
            input_DecoderDecode( es->p_dec_record, p_dup,
                                 p_input->p->b_out_pace_control );
    }

    input_DecoderDecode(es->p_dec, p_block,
                        p_input->p->b_out_pace_control);

<span style="color:#FF0000;">    <span style="color:#3333FF;">// yagerfgcs test for:有时在定位视频问题时,为了排查干扰,可以屏蔽音频。反之亦然。需要的同仁,可以放开这段代码。
    /*if (es->p_dec->fmt_out.i_cat == VIDEO_ES)
    {
        input_DecoderDecode(es->p_dec, p_block,
            p_input->p->b_out_pace_control);
    }
    else
    {
        block_Release(p_block);
    }*/</span></span>
    
    es_format_t fmt_dsc;
    vlc_meta_t  *p_meta_dsc;
    if( input_DecoderHasFormatChanged( es->p_dec, &fmt_dsc, &p_meta_dsc ) )
    {
        EsOutUpdateInfo( out, es, &fmt_dsc, p_meta_dsc );

        es_format_Clean( &fmt_dsc );
        if( p_meta_dsc )
            vlc_meta_Delete( p_meta_dsc );
    }

    /* Check CC status */
    bool pb_cc[4];

    input_DecoderIsCcPresent( es->p_dec, pb_cc );
    for( int i = 0; i < 4; i++ )
    {
        es_format_t fmt;

        if(  es->pb_cc_present[i] || !pb_cc[i] )
            continue;
        msg_Dbg( p_input, "Adding CC track %d for es[%d]", 1+i, es->i_id );

        es_format_Init( &fmt, SPU_ES, EsOutFourccClosedCaptions[i] );
        fmt.i_group = es->fmt.i_group;
        if( asprintf( &fmt.psz_description,
                      _("Closed captions %u"), 1 + i ) == -1 )
            fmt.psz_description = NULL;
        es->pp_cc_es[i] = EsOutAdd( out, &fmt );
        es->pp_cc_es[i]->p_master = es;
        es_format_Clean( &fmt );

        /* */
        es->pb_cc_present[i] = true;
    }

    vlc_mutex_unlock( &p_sys->lock );

    return VLC_SUCCESS;
}

5、在src\input\decoder.c中DecoderProcess函数中打印音视频时间戳

static void DecoderProcess( decoder_t *p_dec, block_t *p_block )
{
    decoder_owner_sys_t *p_owner = (decoder_owner_sys_t *)p_dec->p_owner;
    const bool b_flush_request = p_block && (p_block->i_flags & BLOCK_FLAG_CORE_FLUSH);

    if( p_dec->b_error )
    {
        if( p_block )
            block_Release( p_block );
        goto flush;
    }

    if( p_block && p_block->i_buffer <= 0 )
    {
        assert( !b_flush_request );
        block_Release( p_block );
        return;
    }

#ifdef ENABLE_SOUT
    if( p_owner->b_packetizer )
    {
        if( p_block )
            p_block->i_flags &= ~BLOCK_FLAG_CORE_PRIVATE_MASK;

        DecoderProcessSout( p_dec, p_block );
    }
    else
#endif
    {
        bool b_flush = false;

        if( p_block )
        {
            const bool b_flushing = p_owner->i_preroll_end == INT64_MAX;
            DecoderUpdatePreroll( &p_owner->i_preroll_end, p_block );

            b_flush = !b_flushing && b_flush_request;

            p_block->i_flags &= ~BLOCK_FLAG_CORE_PRIVATE_MASK;
        }

        if( p_dec->fmt_out.i_cat == AUDIO_ES )
        {
            <span style="color:#3333FF;">//add by yagerfgcs for log
            if (p_block)
            {
                msg_Dbg(p_dec, "[DS 01 decoder::DecoderProcess] audio pts[%llu]", p_block->i_pts);
            }
            //end</span>
            
            DecoderProcessAudio( p_dec, p_block, b_flush );
        }
        else if( p_dec->fmt_out.i_cat == VIDEO_ES )
        {
            <span style="color:#3333FF;">//add by yagerfgcs for log
            if (p_block)
            {
                msg_Dbg(p_dec, "[DS 01 decoder::DecoderProcess] video pts[%llu]", p_block->i_pts);
            }
            //end</span>

            DecoderProcessVideo( p_dec, p_block, b_flush );
        }
        else if( p_dec->fmt_out.i_cat == SPU_ES )
        {
            DecoderProcessSpu( p_dec, p_block, b_flush );
        }
        else
        {
            msg_Err( p_dec, "unknown ES format" );
            p_dec->b_error = true;
        }
    }

    /* */
flush:
    if( b_flush_request )
        DecoderProcessOnFlush( p_dec );
}

6、在modules\codec\avcodec\video.c中DecodeVideo函数增加日志

picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
{
    .................

    if( p_block)
    {
       <span style="color:#3333FF;"> //yagerfgcs for log
        msg_Dbg(p_dec, "[DS 02 video::DecodeVideo] video pts[%llu]", p_block->i_pts);</span>

        if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
        {
            p_sys->i_pts = VLC_TS_INVALID; /* To make sure we recover properly */

            p_sys->i_late_frames = 0;

            post_mt( p_sys );
            if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
                avcodec_flush_buffers( p_context );
            wait_mt( p_sys );

            block_Release( p_block );
            return NULL;
        }

        if( p_block->i_flags & BLOCK_FLAG_PREROLL )
        {
            /* Do not care about late frames when prerolling
             * TODO avoid decoding of non reference frame
             * (ie all B except for H264 where it depends only on nal_ref_idc) */
            p_sys->i_late_frames = 0;

            <span style="color:#3333FF;">//yagerfgcs for log
            msg_Dbg(p_dec, "[DS video::DecodeVideo] p_block->i_flags == BLOCK_FLAG_PREROLL");</span>
        }
    }
    ....................
}

7、src\input\decoder.c中DecoderProcess函数

static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block )
{
    decoder_owner_sys_t *p_owner = p_dec->p_owner;
    picture_t      *p_pic;
    int i_lost = 0;
    int i_decoded = 0;
    int i_displayed = 0;

    while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) )
    {
        <span style="color:#3333FF;">//yagerfgcs for log
        msg_Dbg(p_dec, "[DS 03 decoder::DecoderDecodeVideo] video pts[%llu]", p_pic->date);</span>

        vout_thread_t  *p_vout = p_owner->p_vout;
        if( DecoderIsExitRequested( p_dec ) )
        {
            /* It prevent freezing VLC in case of broken decoder */
            vout_ReleasePicture( p_vout, p_pic );
            if( p_block )
                block_Release( p_block );
            break;
        }
        .....................
     }
     ......................
}

8、src\input\decoder.c中DecoderProcess函数

static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture,
                              int *pi_played_sum, int *pi_lost_sum )
{
    ...........................
    const bool b_dated = p_picture->date > VLC_TS_INVALID;
    int i_rate = INPUT_RATE_DEFAULT;
    
    mtime_t dateBefore = p_picture->date;
    
    DecoderFixTs( p_dec, &p_picture->date, NULL, NULL,
                  &i_rate, DECODER_BOGUS_VIDEO_DELAY );

    <span style="color:#3333FF;">//yagerfgcs for log
    msg_Dbg(p_dec, "[DS 04 decoder::DecoderPlayVideo] video date before[%llu] after DecoderFixTs[%llu]", 
            dateBefore, p_picture->date);</span>

    vlc_mutex_unlock( &p_owner->lock );

    /* */
    if( !p_picture->b_force && p_picture->date <= VLC_TS_INVALID ) // FIXME --VLC_TS_INVALID verify video_output/*
        b_reject = true;
    ............................
} 

三、让VLC默认打印debug日志,方便保存的方法

1、通过VLC菜单->工具->消息,可以将日志级别改为“2(调试)”,这样就可以打印出所有的调试日志,点击“另存为”可保存到文件中


2、也可以通过修改代码,让vlc默认打印debug日志

在modules\gui\qt4\dialogs\messages.cpp中MessagesDialog::MessagesDialog函数,修改默认级别

MessagesDialog::MessagesDialog( intf_thread_t *_p_intf)
               : QVLCFrame( _p_intf )
{
    setWindowTitle( qtr( "Messages" ) );
    setWindowRole( "vlc-messages" );
    /* Build Ui */
    ui.setupUi( this );
    ui.bottomButtonsBox->addButton( new QPushButton( qtr("&Close"), this ),
                                         QDialogButtonBox::RejectRole );

    /* Modules tree */
    ui.modulesTree->setHeaderHidden( true );

    /* Buttons and general layout */
    ui.saveLogButton->setToolTip( qtr( "Saves all the displayed logs to a file" ) );

    <span style="color:#3333FF;">int i_verbosity = 2;// var_InheritInteger(p_intf, "verbose");</span>
    changeVerbosity( i_verbosity );
    ui.verbosityBox->setValue( qMin( i_verbosity, 2 ) );
    ................
} 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

VLC播放器调试经验总结 的相关文章

  • 如何在 CentOS 7 上安装 VLC 媒体播放器

    VLC 是一种流行的开源多媒体播放器和流媒体服务器 它是跨平台的 几乎可以播放所有多媒体文件以及 DVD 音频 CD 和不同的流媒体协议 本教程介绍如何在 CentOS 7 上安装 VLC 媒体播放器 先决条件 您需要以以下身份登录具有 s
  • 在Windows下编译VLC并实现播放视频

    在Windows下编译VLC并实现播放视频 一 编译Win版的VLC真麻烦 二 获取VLC的SDK 1 下载VLC播放器 2 库文件 3 头文件 三 调用VLC实现播放视频 1 拷贝头文件和库文件 2 修改pro文件 3 封装播放器类VLC
  • VLC使用教程(一):使用VLC录制屏幕

    1 打开VLC 选择媒体 gt 打开捕获设备 2 选择捕获设备 捕获模式选择桌面 捕获期望的帧率以及更多选项中的缓冲根据需求设置 3 点击播放按钮右侧的下拉三角 选择转换 4 点击目标文件右侧的浏览 选择文件放置路径 填写MP4文件的名字
  • Vlc.DotNet播放本地文件时的路径编码

    在播放本地媒体文件时 VLC会对文件路径进行编码 将中文字符编码为utf 8 在程序中也需要如此 否则不能正常播放 C 中可以用 System Web HttpUtility UrlEncode string System Text Enc
  • 使用vlc显示海康网络摄像机的视频

    通过博主的另外一篇博客https blog csdn net u014552102 article details 86700057 配置完海康网络摄像机后 我们就可以使用vlc显示摄像机的视频了 在下图所示的浏览器页面中 我们可以知道摄像
  • libvlc 流屏幕的一部分

    我想使用 vlc 库流式传输屏幕的一部分 我写了一个小例子 include
  • 使用VLC的虚拟界面时如何防止显示控制台

    我正在尝试从 Node js 服务器脚本以 虚拟 模式启动 VLC 但是使用child process spawn vlc I dummy 使用 Windows 时 为 VLC 的输出生成一个新的控制台窗口 有没有办法防止这种情况发生并强制
  • VLCJ 创建多个视频面板

    我正在使用 vlcj 创建多个视频面板 对于每个视频窗口我应该添加代码 factory0 new MediaPlayerFactory mediaPlayer0 factory0 newEmbeddedMediaPlayer mediaPl
  • 将 VlcManager 与最新版本的 Vlc.DotNet 结合使用

    我正在尝试将 Vlc DotNet 库用于我的 WinForms C 应用程序 我不想使用 Vlc DotNet 库的 Core Interops 中的 VlcManager 但没有最新的文档 在早期版本中 您可以创建 VlcControl
  • 即使使用调用方法也出现“跨线程操作无效”

    我在这里得到 跨线程操作无效 if vlc State VlcPlayerControlState PLAYING if vlc InvokeRequired vlc Invoke new MediaPlayerNoParameterDel
  • 如何在 C# 中通过 VLC api 流式传输视频

    我正在从事视频广播的小型家庭项目 我找到了一些例子Example http csharpmagics blogspot com 但它不起作用 因为需要旧版本的库0 8 6 所以我找到了它 但是当我尝试从 API 获取组件时 我对非托管代码有
  • 如何在命令行中使用VLC保存视频流?

    我正在尝试在 Window 7 Basic 的命令行中使用 VLC 保存在线视频 以下是我尝试过并部分起作用的一些事情 I movies gt vlc http media ch9 ms ch9 7492 a92ae0a6 7b81 411
  • VLC 流至 MP4 WEBM 和 Flash

    我正在尝试将视频从 IP 摄像机流式传输到我的 WordPress 网站 我希望我的流可以通过常见设备 Windows Mac Android 和 IOS 访问 目前我正在使用 VLC 进行流式传输 但我只能使用 flash 流 但我想做
  • 构建 VLC 时需要 NDKv8b 或更高版本

    我已经在 android 中构建了 VLC 并使用代码实现 jack export ANDROID SDK android sdk jack export ANDROID NDK android ndk r9d jack export PA
  • 从 android vlc 媒体播放器获取当前帧

    我在用着VLC Android https code videolan org videolan vlc android为了在我的 Android 应用程序中播放 H264 RTSP 直播流 以下代码成功地将流视频渲染到表面视图上 Medi
  • 使用 VLC 将文件流式传输为 RTSP

    我需要创建一个可以将 mp3 文件流式传输到另一个设备的服务器 我打算使用 VLC 我查看了 VLC 文档 并对执行此操作的前进方向感到困惑 我找到了这个链接 http www videolan org doc streaming howt
  • C# 嵌入vlc控件

    我尝试将 VLC 嵌入到我的 WPF 项目中 我已经注册了 axvlc dll 还下载了 VLC nightly build 版本 2 2 2 System Windows Markup XamlParseException 类型的第一次机
  • Python VLC 实例全屏不起作用

    我对 Python 有点陌生 正在为连接运动传感器的 Raspberry Pi 开发一个应用程序 这个想法是把这个 Raspberry 放在一个房间里 在运动检测时 视频开始全屏播放 视频播放完毕后 我想让设备休眠 10 分钟 然后再次激活
  • 在应用程序启动时禁用 Windows 服务

    因为我必须在应用程序启动时关闭 Windows 高级文本服务 有什么特殊的API吗 它适用于具有默认权限的用户吗 该问题的标题是 禁用 Windows 服务 但答案都告诉我们如何停止服务 您在 Google 上会发现的大部分内容是 您可以使
  • 使用 Servlet 启动 VLC HTTP Stream 时出现问题

    我正在为自己开发一个 VLC 项目 我的目标是创建一个 HTML 前端来启动流 我通过使用 Java Servlet 来完成此操作 概述 乌班图13 04 Java 7 21 冰茶 2 3 9 Eclipse JAVAEE IDE 雄猫7

随机推荐

  • Ubuntu下的CuteCom串口详细调试教程

    I MX6ULL嵌入式开发学习 串口调试 一 Ubuntu下的串口调试助手安装 嵌入式开发学习过程中学习到串口调试这一章 xff0c 以前在Win10操作时都有相对应的串口调试界面 xff0c 安装个串口驱动在电脑设备端口里面看到COM3时
  • STM32 串口

    文章目录 USART 通信协议RS 232与TTL电平 串口通信数据包组成USART功能框图讲解引脚寄存器状态寄存器 USART SR 数据寄存器 USART DR 控制寄存器 USART CR 波特比率寄存器 USART BRR 发送过程
  • printf二进制数据

    基于之前这篇文章的代码改进了下 xff1a http blog csdn net xzongyuan article details 28889063 之前打印的数字没有补0 我打印了内存信息 xff0c 结果是这样的 xff0c 不能对齐
  • 分析MySQL数据类型的长度

    分析MySQL数据类型的长度 MySQL有几种数据类型可以限制类型的 34 长度 34 xff0c 有CHAR Length VARCHAR Length TINYINT Length SMALLINT Length MEDIUMINT L
  • 为vscode配置clangd

    目录 安装clangd 后端安装clangd 前端修改基础配置生成compile commands json文件基本效果补全warning提醒自动修改存在问题 注意事项 clangd能提供更好的补全和提示 xff0c 自带检查一些warni
  • 论文笔记(十九)RGB-D Object Tracking: A Particle Filter Approach on GPU

    RGB D Object Tracking A Particle Filter Approach on GPU 文章概括摘要1 介绍2 贡献3 粒子滤波器4 可能性评估5 实施细节6 实验A 物体模型B 合成序列C 真实序列 7 结论8 鸣
  • Ubuntu 命令行 访问网页

    安装w3m 1 进入 root apt get install w3m 2 测试是否成功 xff1a w3m https blog csdn net x xx xxx xxxx article details 92574331
  • 代码管理中Trunk、Branches、Tags的区别和联系

    我们可以将这三者想象成一棵树的组成部分 trunk为树干branches为树枝tags为整棵树 trunk用于主线开发 branches用于定制版本 修复bugs 并行开发等使用 tags用于存放release版本 xff0c 阶段性代码
  • linux使用curl请求(带参数)

    1 2 3 curl G d 34 c 61 amp a 61 34 http www net index php
  • 惯导系列(二):滤波相关的算法

    前言 我又消失了一段时间 xff0c 这段时间研究了惯性导航有关的算法 xff0c 整理了不少博客 xff0c 字数比较多 xff0c 图片比较多 学到了很多知识 目录 前言 本节介绍 一 Mahony算法 1 1 PID控制算法 1 2
  • STM32 CAN 设置多个过滤器接收多ID方法

    1 标识符列表模式 xff0c 32位模式下 void MX CAN Init void 这里是实现了两个地址的接收 一个是用来接收广播信息 一个用来接收私有地址 如果想实现多个地址可以添加多个过滤器组 stm32103 有0 13 共14
  • linux下运行动态库问题 cannot open shared object file: No such file or directory

    如果动态库不在同一级目录下 xff0c 则需要将以上文件的目录加载到动态库搜索路径中 xff0c 设置的方式有以下几种 一 将动态库路径加入到LD LIBRARY PATH环境变量 1 在终端输入 xff1a export LD LIBRA
  • 几个串口通信协议的整理

    一 UART UART是一个大家族 xff0c 其包括了RS232 RS499 RS423 RS422和RS485等接口标准规范和总线标准规范 它们的主要区别在于其各自的电平范围不相同 嵌入式设备中常常使用到的是TTL TTL转RS232的
  • 单片机中断的过程

    1 根据响应的中断源的中断优先级 使相应的优先级状态触发器置1 xff1b 2 把当前程序计数器PC的内容压入堆栈 xff0c 保护断点 xff0c 寻找中断源 xff1b 3 执行硬件中断服务子程序调用 xff1b 4 清除相应的中断请求
  • Ruby学习札记(3)- Ruby中gem的安装与卸载

    Ruby 学习札记 3 Ruby 中 gem 的安装与卸载 在 Ruby 中有 gem 包这种概念 xff0c 类似 PHP 中的 pear xff0c 相当于一种插件 具体可以 Google 一下 xff08 1 xff09 查看已经安装
  • 【linux】ubuntu20.04 运行软件 提示找不到过时的库 libQtCore.so.4、libQtGui.so.4、libpng12.so.0

    先上结果 1 nxView运行起来 环境 硬件 xff1a Jetson Xavier NX 套件 系统 xff1a Ubuntu 20 04 软件 xff1a nxView 43 libQtCore so 4 解决 0 现象 运行软件提示
  • rtt相关问题总结

    1 总结RT Thread的启动流程 xff08 启动文件部分跳过 xff09 关中断 rt hw interrupt disable 板级初始化 xff1a 需在该函数内部进行系统堆的初始化 rt hw board init 打印 RT
  • FTP 客户端C实现

    使用 Socket 通信实现 FTP 客户端程序 FTP 概述 文件传输协议 xff08 FTP xff09 作为网络共享文件的传输协议 xff0c 在网络应用软件中具有广泛的应用 FTP的目标是提高文件的共享性和可靠高效地传送数据 在传输
  • Qt编写串口通信程序全程图文讲解

    说明 我们的编程环境是windows xp下 xff0c 在Qt Creator中进行 xff0c 如果在Linux下或直接用源码编写 xff0c 程序稍有不同 xff0c 请自己改动 在Qt中并没有特定的串口控制类 xff0c 现在大部分
  • VLC播放器调试经验总结

    一 前言 在使用VS学习VLC源码时 xff0c 可以打断点分析变量数据 xff0c 跟踪代码流程 xff0c 方便我们理解源码 但是在定位音视频卡顿 延时等疑难问题时 xff0c 这一招就不管用了 xff0c 因为打上断点就会导致实时计算