智慧教室无纸化方案应用领域和技术实践探究

news2024/11/24 9:09:45

智慧教室无纸化应用场景

智慧教室无纸化方案在多个领域得到了广泛应用,主要体现在教育领域,但随着技术的发展和应用的深入,其应用范围也在逐渐扩大。以下是一些主要的应用领域:

一、教育领域

  1. 课堂教学
    • 中小学数学课堂:利用电子显示屏和触摸屏技术,解决传统黑板无法高效展示图文并茂内容的问题,提高教学效率。学生可以通过平板电脑进行作答和抢答,增加课堂互动性和参与度。
    • 其他学科教学:智慧教室的无纸化方案不仅限于数学,还广泛应用于物理、化学、生物、地理等多门学科。通过虚拟仿真和增强现实技术,学生可以进行虚拟实验和场景模拟,提高学习的趣味性和实效性。
  2. 教学资源管理
    • 提供个性化学习路径和资源,根据学生的学习需求和能力差异进行精准推送,实现自主学习和提升学习效果。
    • 借助云计算和大数据技术,将教学过程数字化和网络化,方便教师和学生进行课前准备、课堂互动和课后作业。
  3. 教学评价与反馈
    • 通过多样化系统,如分组教学系统和自动跟踪系统,实时监控和记录学生的课堂表现和作业完成情况,为教师提供全面和客观的教学评价依据。
    • 教师可以根据即时反馈调整教学策略,确保教学质量的持续提升。

二、企业培训领域

随着企业对员工培训重视程度的提高,智慧教室无纸化方案也逐渐被应用于企业培训中。通过模拟实际工作场景和业务流程,员工可以在虚拟环境中进行实践操作和团队协作,提高培训效果和工作效率。

三、科研机构

科研机构在进行实验研究和数据分析时,往往需要处理大量的数据和文档。智慧教室无纸化方案可以提供高效的数据管理和文档编辑工具,帮助科研人员更加便捷地进行数据整理和分析工作。同时,通过虚拟仿真技术,科研人员还可以进行复杂实验的模拟和预测,降低实验成本和风险。

四、公共服务领域

在图书馆、博物馆等公共服务场所,智慧教室无纸化方案可以应用于展览展示和公众教育活动中。通过数字化展示和互动体验设备,观众可以更加直观地了解展品信息和历史文化知识,提高公共服务的水平和质量。

智慧教室无纸化方案

大牛直播SDK的跨平台Widows、Linux(x86_64|aarch64架构)、Android、iOS的RTMP推拉流模块,服务了业内非常多的智慧教室无纸化业务诉求。

下面就开发者关注的问题,做个答疑:

1. 轻量级RTSP服务还是RTMP?

我们在做智慧教室无纸化同屏的时候,问的最多的是,能不能不要自建服务,直接主讲人或教师端,直接启动轻量级RTSP服务,其他终端拉流,如果是小并发,比如5人内的小范围的同屏,Windows平台走轻量级RTSP无可厚非,如果是30-60甚至100人的会议室,建议走RTMP。

2. 推送分辨率和码率选择

我们接触到好多设备,性能一般,但是屏幕是高分屏,甚至可以采集到4K的,考虑到实时编码和并发环境下,AP的承载能力,一般建议选择适合自己的分辨率码率即可,不要只追求高分辨率高码率,导致组网困难,单个或双通道AP压力大,一般建议控制在1920*1080分辨率内,码率控制在1-5M。

3. 软编码还是硬编码

Windows平台,一般优先考虑软编,因为大多Windows性能瓶颈不太大,超过1080P可以考虑硬编,Android平台建议直接硬编码。

4. 高分屏采集编码效率低怎么办

高分屏,不管是Windows还是Android,采集后的数据,建议先压缩,再编码,Windows平台我们可以设置压缩比例(scale rate),Android平台亦可,比如采集原始屏幕,或者缩放后的屏幕,具体见下图:

  /* BackgroudService.java
   * Author: daniusdk.com
   * WeChat: xinsheng120
   */ 
  private void createScreenEnvironment() {

        sreenWindowWidth = mWindowManager.getDefaultDisplay().getWidth();
        screenWindowHeight = mWindowManager.getDefaultDisplay().getHeight();

        Log.i(TAG, "screenWindowWidth: " + sreenWindowWidth + ",screenWindowHeight: "
                + screenWindowHeight);

        if (sreenWindowWidth > 800)
        {
            if (screen_resolution_type_ == SCREEN_RESOLUTION_STANDARD)
            {
                scale_rate = SCALE_RATE_HALF;
                sreenWindowWidth = align(sreenWindowWidth / 2, 16);
                screenWindowHeight = align(screenWindowHeight / 2, 16);
            }
            else if(screen_resolution_type_ == SCREEN_RESOLUTION_LOW)
            {
                scale_rate = SCALE_RATE_TWO_FIFTHS;
                sreenWindowWidth = align(sreenWindowWidth * 2 / 5, 16);
                screenWindowHeight = align(screenWindowHeight * 2 / 5, 16);
            }
        }

        Log.i(TAG, "After adjust mWindowWidth: " + sreenWindowWidth + ", mWindowHeight: " + screenWindowHeight);

        int pf = mWindowManager.getDefaultDisplay().getPixelFormat();
        Log.i(TAG, "display format:" + pf);

        DisplayMetrics displayMetrics = new DisplayMetrics();
        mWindowManager.getDefaultDisplay().getMetrics(displayMetrics);
        mScreenDensity = displayMetrics.densityDpi;

        mImageReader = ImageReader.newInstance(sreenWindowWidth,
                screenWindowHeight, 0x1, 6);

        mMediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
    }

5. Android横竖屏自动适配

Android平台,如果是pad采集,基本就是横屏采集,如果手机端,需要确保横竖屏模式下都可以正常采集。需要确保横竖屏切换的时候,能自动切换宽高,或者,一开始固定好横竖屏模式也可以。

4. 为什么要考虑补帧

Android的时候,一定的采集模式下,屏幕如果没有变化,不会一直有实时屏幕数据回调下来,这时候,为了保持帧率或数据采集的完整性,建议补帧。

5. 异常网络处理、事件回调机制

网络状态,不管是推送端,还是播放端,都是需要有实时的状态回调,确保客户端可以实时感知网络状态。

backgroudService.SetEventListener(new EventListener() {
                  @Override
                  public void onPublisherEventCallback(long handle, int id, long param1, long param2, String param3, String param4, Object param5) {
                      String publisher_event = "";

                      switch (id) {
                          case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_STARTED:
                              publisher_event = "开始..";
                              break;
                          case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_CONNECTING:
                              publisher_event = "连接中..";
                              break;
                          case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_CONNECTION_FAILED:
                              publisher_event = "连接失败..";
                              break;
                          case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_CONNECTED:
                              publisher_event = "连接成功..";
                              break;
                          case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_DISCONNECTED:
                              publisher_event = "连接断开..";
                              break;
                          case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_STOP:
                              publisher_event = "关闭..";
                              break;
                          case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_RECORDER_START_NEW_FILE:
                              publisher_event = "开始一个新的录像文件 : " + param3;
                              break;
                          case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_ONE_RECORDER_FILE_FINISHED:
                              publisher_event = "已生成一个录像文件 : " + param3;
                              break;

                          case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_SEND_DELAY:
                              publisher_event = "发送时延: " + param1 + " 帧数:" + param2;
                              break;

                          case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_CAPTURE_IMAGE:
                              publisher_event = "快照: " + param1 + " 路径:" + param3;

                              if (param1 == 0) {
                                  publisher_event = publisher_event + "截取快照成功..";
                              } else {
                                  publisher_event = publisher_event + "截取快照失败..";
                              }
                              break;
                          case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_RTSP_URL:
                              publisher_event = "RTSP服务URL: " + param3;
                              break;
                          case NTSmartEventID.EVENT_DANIULIVE_ERC_PUSH_RTSP_SERVER_RESPONSE_STATUS_CODE:
                              publisher_event = "RTSP status code received, codeID: " + param1 + ", RTSP URL: " + param3;
                              break;
                          case NTSmartEventID.EVENT_DANIULIVE_ERC_PUSH_RTSP_SERVER_NOT_SUPPORT:
                              publisher_event = "服务器不支持RTSP推送, 推送的RTSP URL: " + param3;
                              break;
                      }

                      String str = "当前状态:" + publisher_event;

                      Log.i(TAG, str);

                      if (handler_ != null) {
                          Message message = new Message();
                          message.what = PUBLISHER_EVENT_MSG;
                          message.obj = publisher_event;
                          handler_.sendMessage(message);
                      }
                  }
            });

6. 采集到的数据可以按需录像吗

可以,而且很有必要,智慧教室无纸化场景同屏的时候,如果需要把授课、开会等内容实时保存下来,这时候,可以随时启动录像。

    public boolean startRecorder()
    {
        Log.i(TAG, "onClick startRecorder..");

        if(!stream_publisher_.is_publishing())
        {
            startCaptureScreen();
        }

        if (layer_post_thread_ != null)
            layer_post_thread_.update_layers();

        if (stream_publisher_.is_recording()) {
            stopRecorder();
            return false;
        }

        InitAndSetConfig();

        ConfigRecorderParam();

        boolean start_ret = stream_publisher_.StartRecorder();
        if (!start_ret) {
            stream_publisher_.try_release();
            Log.e(TAG, "Failed to start recorder.");
            return false;
        }

        startAudioRecorder();
        startLayerPostThread();

        return true;
    }

    //停止录像
    public void stopRecorder() {
        stream_publisher_.StopRecorder();
        stream_publisher_.try_release();

        if (!stream_publisher_.is_publishing())
            stopAudioRecorder();
    }

7. 文字、图片水印

需要而且建议支持,比如实时时间、学校或公司logo等,需要叠加到屏幕数据的文字或者图片信息。

        //水印效果选择++++++++++
        watermarkSelctor = (Spinner) findViewById(R.id.watermarkSelctor);
        watermarkSelctor.setEnabled(false);
        final String[] watermarks = new String[]{"图片水印", "全部水印", "文字水印", "不加水印"};

        ArrayAdapter<String> adapterWatermark = new ArrayAdapter<String>(this,
                android.R.layout.simple_spinner_item, watermarks);

        adapterWatermark.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        watermarkSelctor.setAdapter(adapterWatermark);

        watermarkSelctor.setSelection(3,true);
        watemarkType = 3;   //默认不加水印

        watermarkSelctor.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {

            @Override
            public void onItemSelected(AdapterView<?> parent, View view,
                                       int position, long id) {

                watemarkType = position;

                Log.i(TAG, "[水印类型]Currently choosing: " + watermarks[position] + ", watemarkType: " + watemarkType);

                if(backgroudService !=null) {
                    backgroudService.updateWatermarker(watemarkType);
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });

8. 可以同时启动轻量级RTSP服务吗?

智慧教室场景下,如果需要对学生的屏幕进行轮循,或查看某个学生的屏幕,可以在学生端,启动轻量级的RTSP服务,然后,教师或管理终端,直接进行拉流就好。

    public boolean startRtspService(int port)
    {
        Log.i(TAG, "startRtspService++");

        rtsp_handle_ = lib_publisher_.OpenRtspServer(0);

        if (rtsp_handle_ == 0) {
            Log.e(TAG, "创建rtsp server实例失败! 请检查SDK有效性");
        } else {
            if (lib_publisher_.SetRtspServerPort(rtsp_handle_, port) != 0) {
                lib_publisher_.CloseRtspServer(rtsp_handle_);
                rtsp_handle_ = 0;
                Log.e(TAG, "创建rtsp server端口失败! 请检查端口是否重复或者端口不在范围内!");
            }

            if (lib_publisher_.StartRtspServer(rtsp_handle_, 0) == 0) {
                Log.i(TAG, "启动rtsp server 成功!");
            } else {
                lib_publisher_.CloseRtspServer(rtsp_handle_);
                rtsp_handle_ = 0;
                Log.e(TAG, "启动rtsp server失败! 请检查设置的端口是否被占用!");
            }

            isRTSPServiceRunning = true;
        }

        return true;
    }

    //停止RTSP服务
    public void stopRtspService() {
        Log.i(TAG, "stopRtspService++");
        if(!isRTSPServiceRunning)
        {
            return;
        }
        if (lib_publisher_ != null && rtsp_handle_ != 0) {
            lib_publisher_.StopRtspServer(rtsp_handle_);
            lib_publisher_.CloseRtspServer(rtsp_handle_);
            rtsp_handle_ = 0;
        }

        isRTSPServiceRunning = false;
    }

    public boolean startRtspPublisher(){
        Log.i(TAG, "startRtspPublisher++");

        if(!stream_publisher_.is_publishing())
        {
            startCaptureScreen();
        }

        InitAndSetConfig();

        String rtsp_stream_name = "stream1";
        stream_publisher_.SetRtspStreamName(rtsp_stream_name);
        stream_publisher_.ClearRtspStreamServer();

        stream_publisher_.AddRtspStreamServer(rtsp_handle_);

        if (!stream_publisher_.StartRtspStream()) {
            stream_publisher_.try_release();
            Log.e(TAG, "调用发布rtsp流接口失败!");
            return false;
        }

        startAudioRecorder();
        startLayerPostThread();

        return true;
    }

    //停止发布RTSP流
    public void stopRtspPublisher() {
        Log.i(TAG, "stopRtspPublisher++");
        stream_publisher_.StopRtspStream();
        stream_publisher_.try_release();

        if (!stream_publisher_.is_publishing())
            stopAudioRecorder();
    }

    public int getRtspSessionNumbers(){
        int session_numbers = 0;
        if (lib_publisher_ != null && rtsp_handle_ != 0) {
            session_numbers = lib_publisher_.GetRtspServerClientSessionNumbers(rtsp_handle_);
            Log.i(TAG, "GetRtspSessionNumbers: " + session_numbers);
        }

        return session_numbers;
    }

9. 同屏延迟,能不能做到毫秒级

内网环境下,如果网络(比如无线AP)和设备性能没有瓶颈的前提下,使用大牛直播SDK的同屏和播放模块,可以轻松做到毫秒级延迟。下图以Android平台采集屏幕数据为例,分别推送RTMP服务和启动轻量级RTSP服务,windows端分别进行rtmp和rtsp拉流播放,整体时延。

10. 能不能采集到扬声器的audio?

Windows不在话下,Android平台需要高版本支持,高版本是可以采集到扬声器数据的,我们也实现了相关的demo,可以同时采集麦克风和扬声器的audio,单独推送或者同时混音输出。

11. 同屏过程中,重点画面可以快照吗?

当然可以,我们同屏采集端,支持采集编码png或jpg格式输出。

总结

智慧教室无纸化方案在教育、企业培训、科研机构和公共服务等多个领域都得到了广泛应用,并发挥了重要作用。随着技术的不断进步和应用场景的不断拓展,其应用前景将更加广阔。其实一个好的智慧教室无纸化同屏系统,需要考虑组网、分辨率、码率、时延、音视频同步和连续性等各个指标,本文抛砖引玉,感兴趣的开发者,可以跟我单独沟通讨论。

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

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

相关文章

BFS迷宫最小路径问题

给定一个迷宫&#xff0c;0表示空地可以走&#xff0c;1表示墙壁不能穿越&#xff1b;在迷宫中可以向&#xff08;上下左右&#xff09;四个方向行进&#xff1b; 找到从左上角到右下角的最短路径&#xff0c;并计算最短路径的长度。 迷宫示例如下&#xff1a; 算法步骤&…

org.aspectj.apache.bcel.classfile.ClassFormatException 深度解析

org.aspectj.apache.bcel.classfile.ClassFormatException 深度解析 ### 概述 在前端开发和Java后端交互的复杂环境中&#xff0c;org.aspectj.apache.bcel.classfile.ClassFormatException 作为一个难以预测的异常&#xff0c;时常给开发者带来困扰。这个异常主要与 AspectJ—…

Trigger源码分析 -- ant-design-vue系列

Trigger源码分析 – ant-design-vue系列 1 概述 源码地址&#xff1a; https://github.com/vueComponent/ant-design-vue/blob/main/components/vc-trigger/Trigger.tsx 在源码的实现中&#xff0c;Trigger组件主要有两个作用&#xff1a; 使用Portal组件&#xff0c;把Pop…

迟滞比较器/施密特触发器

功能 从下面原理图像看来&#xff0c;只有在达到上下阈值才会出现输出电平的转换&#xff0c;这样防止信号的杂波跳变。而且每次的阈值是随着输出而变化的&#xff0c;当输出高时&#xff0c;阈值如下图中&#xff0c;V_PV_N V_R*( RF/(R1RF) )VH*( R1/(R1RF) );当输出低时&a…

QT核心机制

目录 学习内容&#xff1a; 1. 对话框 1.1 消息对话框&#xff08;QMessageBox&#xff09; 1.2 消息对话框实例 1.3 颜色对话框&#xff08;QColorDialog&#xff09;、字体对话框&#xff08;QFontDialog&#xff09;、文件对话框&#xff08;QFileDialog&#xff09; …

Python面试常见问题及详细解答:从基础到高级概念全覆盖

创作不易&#xff0c;您的打赏、关注、点赞、收藏和转发是我坚持下去的动力&#xff01; 以下是Python面试中常见的一些问题及其详细答案的整理&#xff1a; 1. Python的可变与不可变对象 问题: 什么是可变对象和不可变对象&#xff1f;举例说明。答案: 可变对象: 可以在原地…

实现卷积层的前向传播(Pythom版)

在TensorFlow框架中&#xff0c;实现卷积层&#xff08;2维&#xff09;的代码是 tf.keras.layers.Conv2D()。它主要接收如下几个参数&#xff0c; filters&#xff1a;卷积核的个数&#xff0c;也就是卷积层输出的通道数&#xff08;沿axis-1的维度&#xff09; kernel_size&a…

AI秒画损失函数曲线图(Loss Function Curve)

在深度学习模型训练中&#xff0c;Loss曲线图是衡量模型性能的一个重要指标。通过绘制Loss曲线&#xff0c;能够清楚地观察到模型在训练过程中的收敛情况&#xff0c;从而帮助我们判断模型是否出现过拟合或欠拟合。本文将介绍如何通过简单几步&#xff0c;快速绘制出训练的Loss…

iphone16-iphone16pro原壁纸分享

iphone16-iphone16pro原壁纸分享 苹果公司在2024年9月10日的秋季新品发布会上正式推出了iPhone 16系列智能手机。以下是iPhone 16系列的主要特点和更新&#xff1a; 全新A18芯片&#xff1a;iPhone 16系列搭载了苹果最新的A18芯片&#xff0c;这款芯片专为苹果智能&#xff08;…

【WebGIS实例】(16)GeoServer 自定义样式 - 渲染矢量数据

1. 前言 本篇博客将会分享一系列的 GeoServer 样式&#xff0c;通过这些样式预先在服务端完成数据渲染&#xff0c;让前端应用更便捷的加载数据服务。 2. 面矢量 示例数据&#xff1a; {type: FeatureCollection,features: [{type: Feature,properties: {分类字段: 字段一…

PPT复制图表时颜色发生变化怎么办?

有时可能想复制其他PPT的图表到另一个PPT里&#xff0c;复制过来发现颜色发生了变化&#xff0c;这与我们PPT中的主题色颜色不同有关&#xff0c;所以就导致了图表的变色。 以上两张图片就是发生了变色的情况&#xff0c;一个是原来的颜色&#xff0c;一个是变化后的颜色。 解…

【鸿蒙】HarmonyOS NEXT星河入门到实战4-ArkTS界面布局深入

目录 一、布局元素组成 1.1 内边距-padding 1.2 外边距 margin 1.3 实战案例-QQ音乐-登录 1.4 边框 border 二、设置组件圆角 2.1 基本圆角设置 2.2 特殊形状的圆角设置 三、背景属性 3.1 背景图片-backgroundImage 3.2 背景图片位置-backgroundImagePosition 3.3 背…

什么是梯度? 梯度的作用 梯度的应用场景。

梯度 是一个非常重要的概念,它直接关系到模型的训练过程。以下是对梯度的详细解释: 梯度的基本概念 梯度 是一个向量,表示函数在某一点的导数或偏导数。在多维空间中,梯度指向的是函数值上升最快的方向。对于一个函数 f(x),在某一点 x 处的梯度记作 ∇f(x),它可以理解为在…

【Linux进程详解】进程地址空间

目录 1.直接写代码看现象 2.引入最基本的理解 3.细节问题-理解它 1.直接写代码看现象 #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <unistd.h> int g_val 100;int main() {printf("fath…

常回家看看之house of kiwi

house of kiwi 前言&#xff1a;house_of_kiwi 一般是通过触发__malloc_assert来刷新IO流&#xff0c;最后可以劫持程序流或者通过和setcontext来打配合来进行栈迁移来得到flag。 我们看看触发的源码 #if IS_IN (libc) #ifndef NDEBUG # define __assert_fail(assertion, fi…

MFC之CString类及其成员函数用法详解

CString是 CStringT(属于MFC 和 ATL 之间共享的类) 的类模板的专用化&#xff0c;没有基类。在头文件atlstr.h中可以看到CString的定义&#xff1a; CString对象由可变长度的一队字符组成。CString是基于TCHAR数据类型的对象。如果在你的程序中定义了符号_UNICODE&#xff0c;则…

Leetcode 300. 最长递增子序列 记忆化搜索、贪心二分 C++实现

Leetcode 300. 最长递增子序列 问题&#xff1a;给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是…

猫头虎推荐:2024国内好用的PyPIP换源库

猫头虎推荐&#xff1a;2024国内好用的PyPIP换源库&#x1f525;&#x1f680; 在国内使用 Python 时&#xff0c;由于访问官方的 PyPI 速度较慢甚至无法连接&#xff0c;选择一个可靠的国内 PyPI 镜像源至关重要&#x1f4c8;。为了更高效地完成项目开发&#xff0c;今天猫头…

BC172 牛牛的排列数(c 语言)

1.我们先输入n m的数字&#xff0c;因为n!/(n-m)!的阶乘。即4&#xff01;4*3*2*1&#xff0c;2&#xff01;2*1&#xff0c;4&#xff01;/2&#xff01;12.或者4&#xff01;4*3*2&#xff01;。 #include<sdtio.h> int main() {int n 0;int m 0;long long a 1;whi…

Leetcode面试经典150题-55.跳跃游戏

解法都在代码里&#xff0c;不懂就留言或者私信 class Solution {public boolean canJump(int[] nums) {/**如果就一个位置&#xff0c;你本来就在这&#xff0c;肯定可以跳到*/if(nums.length 1) {return true;}/**这个题的解题思路是遍历数组&#xff0c;如果当前位置不在之…