学习安卓audio疑问解答:物理按键调节声音设置界面的Seekbar为什么会跟着一起同步变化?

小白学习图像处理6——Canny边缘检测算法原理 目录结构一、高斯滤波二、梯度计算1、原理2、代码如下三、非极大值抑制三、双阈值检测四、matlab 的 edge函数五、总结 Canny边缘检测算法主要步骤:高斯滤波、梯度计算、非极大值抑制和双阈值检测。 一、高斯滤波   使用高斯滤波的目的是平滑图像,滤除图像中的部分噪声(因为微分算子对噪声很敏感)。高斯滤波具体办法是生成一个高斯模板,使用卷积进行时域滤波: img = im2double(im... 阅读详情

背景:

物理音量按键也可以调节声音,设置界面的Seekbar也可以调节声音,请问二者是如何进行同步的呢?
在这里插入图片描述
物理音量调节后设置的画面的也seekbar会同步动起来,本文来剖析一下为啥可以进行音量进度条的同步。

音量调节后AudioService发送相关的变化广播

VolumeStreamState类的setIndex中会进行对应的音量变化的广播

public boolean setIndex(int index, int device, String caller,
                boolean hasModifyAudioSettings) {
       
            if (changed) {
          
                if ((index != oldIndex) && isCurrentDevice) {
                    // for single volume devices, only send the volume change broadcast
                    // on the alias stream
                    if (!mIsSingleVolume || (mStreamVolumeAlias[mStreamType] == mStreamType)) {
                        //给广播的Intent设置当前音量index和老音量oldIndex
                        mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
                        mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE,
                                oldIndex);
                        mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
                                mStreamVolumeAlias[mStreamType]);
//广播发送
                        sendBroadcastToAll(mVolumeChanged, mVolumeChangedOptions);
                    }
                }
            }
            return changed;
        }

Setting端的同步更新部分剖析

广播方式通知数据更新:
音量调节后会广播发送由AudioService发送
frameworks/base/core/java/android/preference/SeekBarVolumizer.java

 @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) {
            //获取广播intent中的相关的streamType和streamValue
                int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
                int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
                if (mDeviceHasProductStrategies && !isDelay()) {
                //调用updateVolumeSlider进行相关的ui上更新
                    updateVolumeSlider(streamType, streamValue);
                }
            } 

对应的堆栈:

postUpdateSlider:582, SeekBarVolumizer$H (android.preference)
updateVolumeSlider:684, SeekBarVolumizer$Receiver (android.preference)
onReceive:633, SeekBarVolumizer$Receiver (android.preference)
lambda$getRunnable$0:1814, LoadedApk$ReceiverDispatcher$Args (android.app)
run:0, LoadedApk$ReceiverDispatcher$Args$$ExternalSyntheticLambda0 (android.app)
handleCallback:959, Handler (android.os)
dispatchMessage:100, Handler (android.os)
loopOnce:232, Looper (android.os)
loop:317, Looper (android.os)
main:8705, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
run:580, RuntimeInit$MethodAndArgsCaller (com.android.internal.os)
main:886, ZygoteInit (com.android.internal.os)

音量变化广播是否属于唯一通知方式呢?

为了验证这个问题可以考虑把AudioService端的广播发送部分代码屏蔽了,然后看看设置中的音量进度条是否还会同步,按预想广播通知音量数据变化,现在广播都不发送的肯定是不会了,那真的是这样么?

非广播数据导致的的回调更新UI剖析:

经过调试发现还是会调用到

public void postUpdateSlider(int volume, int lastAudibleVolume, boolean mute) {
            obtainMessage(UPDATE_SLIDER, volume, lastAudibleVolume, Boolean.valueOf(mute))
                    .sendToTarget();
        }

这里经过追踪发现是updateSlider触发的调用

    private void updateSlider() {
        if (mSeekBar != null && mAudioManager != null) {
            final int volume = mAudioManager.getStreamVolume(mStreamType);
            final int lastAudibleVolume = mAudioManager.getLastAudibleStreamVolume(mStreamType);
            final boolean mute = mAudioManager.isStreamMute(mStreamType);
            mUiHandler.postUpdateSlider(volume, lastAudibleVolume, mute);
        }
    }

在经过最终发现是由VolumeHandler的MSG_GROUP_VOLUME_CHANGED消息进行调用的

    private class VolumeHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            SomeArgs args = (SomeArgs) msg.obj;
            switch (msg.what) {
                case MSG_GROUP_VOLUME_CHANGED:
             //这里会调用上面的updateSlider触发进度条变化
                    updateSlider();
                    break;
            }
        }
    }

那这里的VolumeHandler的MSG_GROUP_VOLUME_CHANGED是如何发送的呢?

相关的发送代码追踪后如下:

frameworks/base/core/java/android/preference/SeekBarVolumizer.java

  private void registerVolumeGroupCb() {
        if (mVolumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
            mAudioManager.registerVolumeGroupCallback(Runnable::run, mVolumeGroupCallback);
            updateSlider();
        }
    }


    private final AudioManager.VolumeGroupCallback mVolumeGroupCallback =
            new AudioManager.VolumeGroupCallback() {
        @Override
        public void onAudioVolumeGroupChanged(int group, int flags) {
            if (mHandler == null) {
                return;
            }
            SomeArgs args = SomeArgs.obtain();
            args.arg1 = group;
            args.arg2 = flags;
            
//可以看到这里会进行发送MSG_GROUP_VOLUME_CHANGED消息从而触发UI的更新
            mVolumeHandler.sendMessage(mHandler.obtainMessage(MSG_GROUP_VOLUME_CHANGED, args));
        }
    };

那么问题又来了,这里的mVolumeGroupCallback又是哪里触发的onAudioVolumeGroupChanged回调呢?这里就可能设计比较多了

VolumeGroupCallback部分剖析

frameworks/base/media/java/android/media/AudioManager.java

   /**
    * @hide
    * Register an audio volume group change listener.
    * @param callback the {@link VolumeGroupCallback} to register
    */
    @SystemApi
    public void registerVolumeGroupCallback(
            @NonNull Executor executor,
            @NonNull VolumeGroupCallback callback) {
    
        sAudioAudioVolumeGroupChangedHandler.init();
        // TODO: make use of executor
        sAudioAudioVolumeGroupChangedHandler.registerListener(callback);
    }

cb被添加到了mListeners这个集合中

 /**
    * @param cb the {@link AudioManager.VolumeGroupCallback} to register
    */
    public void registerListener(@NonNull AudioManager.VolumeGroupCallback cb) {
        Preconditions.checkNotNull(cb, "volume group callback shall not be null");
        synchronized (this) {
            mListeners.add(cb);
        }
        if (mHandler != null) {
            Message m = mHandler.obtainMessage(
                    AUDIOVOLUMEGROUP_EVENT_NEW_LISTENER, 0, 0, cb);
            mHandler.sendMessage(m);
        }
    }

等到后续native层面会就行回调

    @SuppressWarnings("unused")
    private static void postEventFromNative(Object moduleRef,
                                            int what, int arg1, int arg2, Object obj) {
        AudioVolumeGroupChangeHandler eventHandler =
                (AudioVolumeGroupChangeHandler) ((WeakReference) moduleRef).get();
        if (eventHandler == null) {
            return;
        }

        if (eventHandler != null) {
            Handler handler = eventHandler.handler();
            if (handler != null) {
                Message m = handler.obtainMessage(what, arg1, arg2, obj);
                // Do not remove previous messages, as we would lose notification of group changes
                handler.sendMessage(m);
            }
        }
    }

在init方法中会对这个消息进行处理
frameworks/base/media/java/android/media/audiopolicy/AudioVolumeGroupChangeHandler.java

    public void init() {
  
            mHandler = new Handler(mHandlerThread.getLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    ArrayList<AudioManager.VolumeGroupCallback> listeners;
                    synchronized (this) {
                        if (msg.what == AUDIOVOLUMEGROUP_EVENT_NEW_LISTENER) {
                            listeners =
                                    new ArrayList<AudioManager.VolumeGroupCallback>();
                                    //可以看到这里被添加到了mListeners集合中
                            if (mListeners.contains(msg.obj)) {
                                listeners.add(
                                        (AudioManager.VolumeGroupCallback) msg.obj);
                            }
                        } else {
                            listeners = (ArrayList<AudioManager.VolumeGroupCallback>)
                                    mListeners.clone();
                        }
                    }
               

                    switch (msg.what) {
                        case AUDIOVOLUMEGROUP_EVENT_VOLUME_CHANGED:
                            for (int i = 0; i < listeners.size(); i++) {
                            //这里会回调到最开始的SeekBarVolumizer的注册的cb
                                listeners.get(i).onAudioVolumeGroupChanged((int) msg.arg1,
                                                                           (int) msg.arg2);
        }
    }

native层面触发的postEventFromNative剖析

这块经过追踪发现调用流程如下:
frameworks/base/core/jni/android_media_AudioVolumeGroupCallback.cpp

void JNIAudioVolumeGroupCallback::onAudioVolumeGroupChanged(volume_group_t group, int flags)
{
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (env == NULL) {
        return;
    }
    ALOGV("%s volume group id %d", __FUNCTION__, group);
    env->CallStaticVoidMethod(mClass,
                              gAudioVolumeGroupChangeHandlerMethods.postEventFromNative,
                              mObject,
                              AUDIOVOLUMEGROUP_EVENT_VOLUME_CHANGED, group, flags, NULL);
    if (env->ExceptionCheck()) {
        ALOGW("An exception occurred while notifying an event.");
        env->ExceptionClear();
    }
}

那么接下来就是要分析native端如何调用到这里JNIAudioVolumeGroupCallback::onAudioVolumeGroupChanged方法的。这块比较复杂了就不过多展开,主要都是一些类的包装继承调用,核心就是AudioPolicy端跨进程到app的AudioSystem。

JNIAudioVolumeGroupCallback::onAudioVolumeGroupChanged这个调用实际上是远端AudioPolicyService调用到Client的,调用的堆栈如下:

09-22 21:47:43.486   373   475 D onAudioVolumeGroupChanged:   #00 pc 00000000001f3332  /system/bin/audioserver (android::AudioPolicyService::NotificationClient::onAudioVolumeGroupChanged(android::volume_group_t, int)+98) (BuildId: 7dd9e2e68a333b6dfcd47150897396da)
09-22 21:47:43.486   373   475 D onAudioVolumeGroupChanged:   #01 pc 00000000001efedc  /system/bin/audioserver (android::AudioPolicyService::doOnAudioVolumeGroupChanged(android::volume_group_t, int)+188) (BuildId: 7dd9e2e68a333b6dfcd47150897396da)
09-22 21:47:43.486   373   475 D onAudioVolumeGroupChanged:   #02 pc 00000000001edd30  /system/bin/audioserver (android::AudioPolicyService::AudioCommandThread::threadLoop()+3088) (BuildId: 7dd9e2e68a333b6dfcd47150897396da)
09-22 21:47:43.486   373   475 D onAudioVolumeGroupChanged:   #03 pc 0000000000011894  /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+324) (BuildId: 2ccdabdfae4ce3f8fa2cc828ba6cf1b1)

明显看出这里其实是在AudioCommandThread出发的,那么是哪里往AudioCommandThread线程中抛入了相关消息呢?

changeAudioVolumeGroupCommand是靠setStreamVolumeIndex这个跨进程接口调用过来的

9-22 21:47:43.484   373   645 D changeAudioVolumeGroupCommand:   #00 pc 00000000001f716b  /system/bin/audioserver (android::AudioPolicyService::AudioCommandThread::changeAudioVolumeGroupCommand(android::volume_group_t, int)+491) (BuildId: 7dd9e2e68a333b6dfcd47150897396da)
09-22 21:47:43.484   373   645 D changeAudioVolumeGroupCommand:   #01 pc 000000000006c676  /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::setVolumeIndexForAttributes(audio_attributes_t const&, int, audio_devices_t)+5974) (BuildId: bb7c4213a8c34f2f80dd11f810a5811b)
09-22 21:47:43.484   373   645 D changeAudioVolumeGroupCommand:   #02 pc 000000000006aa49  /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t, int, audio_devices_t)+345) (BuildId: bb7c4213a8c34f2f80dd11f810a5811b)
09-22 21:47:43.484   373   645 D changeAudioVolumeGroupCommand:   #03 pc 0000000000205c8e  /system/bin/audioserver (android::AudioPolicyService::setStreamVolumeIndex(android::media::audio::common::AudioStreamType, android::media::audio::common::AudioDeviceDescription const&, int)+270) (BuildId: 7dd9e2e68a333b6dfcd47150897396da)
09-22 21:47:43.484   373   645 D changeAudioVolumeGroupCommand:   #04 pc 000000000003e5ae  /system/lib64/audiopolicy-aidl-cpp.so (android::media::BnAudioPolicyService::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+20318) (BuildId: 7f9f962dc3c3a9699e71deeb561a20d9)
09-22 21:47:43.484   373   645 D changeAudioVolumeGroupCommand:   #05 pc 00000000001e25e1  /system/bin/audioserver (android::AudioPolicyService::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+1601) (BuildId: 7dd9e2e68a333b6dfcd47150897396da)
09-22 21:47:43.484   373   645 D changeAudioVolumeGroupCommand:   #06 pc 0000000000060fe1  /system/lib64/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+241) (BuildId: 3fb041052325e616d19775d7a2a0cda4)
09-22 21:47:43.484   373   645 D changeAudioVolumeGroupCommand:   #07 pc 000000000004e0f3  /system/lib64/libbinder.so (android::IPCThreadState::executeCommand(int)+1251) (BuildId: 3fb041052325e616d19775d7a2a0cda4)
09-22 21:47:43.484   373   645 D changeAudioVolumeGroupCommand:   #08 pc 000000000004db4c  /system/lib64/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+156) (BuildId: 3fb041052325e616d19775d7a2a0cda4)
09-22 21:47:43.484   373   645 D changeAudioVolumeGroupCommand:   #09 pc 000000000004e62f  /system/lib64/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+111) (BuildId: 3fb041052325e616d19775d7a2a0cda4)
09-22 21:47:43.484   373   645 D changeAudioVolumeGroupCommand:   #10 pc 0000000000056ad7  /system/lib64/libbinder.so (android::PoolThread::threadLoop()+23) (BuildId: 3fb041052325e616d19775d7a2a0cda4)
09-22 21:47:43.484   373   645 D changeAudioVolumeGroupCommand:   #11 pc 0000000000011894  /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+324) (BuildId: 2ccdabdfae4ce3f8fa2cc828ba6cf1b1)

总结图如下:

在这里插入图片描述

【网络】叶脊(Spine-Leaf)网络拓扑下全三层网络设计与实践(二) - 网络规划 2. 全三层架构设计思路 采用全三层网络架构设计的出发点是: 使用尽量少的交换机高级功能,可以尽可能减少由于功能bug故障造成的问题; 使用尽量少的网络协议,以兼容不通厂商的网络设备 实现简单,易于维护,绝对可靠的路由协议; 通过控制路由来调度流量,尽量减少设备或协议的故障域; 牺牲高级功能带来的便捷,得到更高的可用性和性能; 由上述原则,本文的设计选择只使用静态路由和BGP... 阅读详情

相关推荐

Tessy学习系列(三):单元测试——官方例程isValueInRange

注意:工程名称以及路劲不能包含空格和中文

不吃鱼的猫的博客 2348

视频隐私脱敏工程化:CSRT/KCF追踪算法在本地推理中的实现与边界

在短视频内容合规审查中,动态遮挡(Dynamic Masking)是高频且高耗时的环节。传统手动关键帧打码不仅效率低下,且在目标快速移动或遮挡时极易出现遮罩漂移。本文从计算机视觉工程角度,解析基于CSRT与KCF算法的目标追踪方案在视频隐私处理中的技术路径、性能权衡及落地实践。

Mysssone的博客 228

SQLSTATE58030

在优化一条SQL的时候遇到了执行错误 gtlions =# select t1.telnumber,t2.ua,t2.url,t1.apply_name,t2.apply_name from tb1 t1 gtlions -# left outer join tb2 t2 on t1.sid = t2.ipsid gtlions-# where t1.sum_date=20141128 a

Gtlions Tracker 3660

从一段视频到可漫游的 4D 有声场景:思路拆解与最小复现手记

只需一段手机视频,你就能生成可"走进去"的 4D 有声场景:转头时狗叫声方向随之变化,走近时声音更清晰。本文拆解 Video-to-4DAVScene 的核心思路,手把手带你用几十行 Python 搭出最小管线,把视频中的运动物体变成带空间位置的声源,并附上三个真实踩坑的排障经验,代码可直接跑。🎧

helloagent的博客 235

【抖音】a_bogus参数逆向分析

点击——展开xxx条回复﹀就会出现。可以看到这个栈是有请求相关的数据的。所以就是在bdms.js里面生成的。

qq_44990881的博客 3000

AI大模型驱动Web UI自动化测试:Playwright与RobotFramework智能整合实践

Web自动化测试是软件质量保障的关键环节,其核心原理是通过脚本模拟用户操作,对Web应用界面进行功能验证。传统方法依赖固定的元素定位和脚本逻辑,在应对频繁的UI变更时面临维护成本高、脚本脆弱的挑战。随着AI大模型技术的发展,其强大的自然语言理解和代码生成能力为自动化测试带来了新的技术价值。通过将大模型的意图理解与代码生成能力,与Playwright强大的浏览器自动化执行引擎以及RobotFramework灵活的关键字驱动框架相结合,可以构建出能够理解自然语言指令、动态生成稳定操作脚本的智能测试系统。这种融合

weixin_28718769的博客 412

本地化部署会议视频软件如何替换旧平台?账号迁移、历史数据与用户培训怎么安排?

账号先映射:身份与权限验证通过,再开放使用。资料分级处理:能查、能读、权限正确,比“全部搬完”更重要。切换可恢复:入口、增量数据和业务通知都要纳入回退方案。培训按岗位落地:让用户完成真实任务,而不是只听功能介绍。这套方法适合政企、集团及医疗等具有长期资料留存、多终端接入和业务集成需求的组织。小规模替换可以简化批次与流程,但不应省略权限验证、备份恢复和关键会议演练。

hz56789的博客 286

uni-app开发-第6篇:uni-app 样式与主题

在 uni-app 开发中,样式与主题的管理是关键部分。样式分为全局样式和局部样式,全局样式在 App.vue 中定义,适用于整个应用,而局部样式在单个 .vue 文件中定义,仅对当前页面生效。局部样式优先级高于全局样式,内联样式优先级最高。样式属性如 font-family 和 color 可被子元素继承。要覆盖全局样式,可在局部样式中重新定义相同规则。主题切换通过 CSS 变量和类名实现,动态切换主题可通过修改元素的类名来完成。例如,定义浅色和深色主题,并通过按钮点击切换主题样式。这些方法帮助开发者灵活

无 369

打字就能剪视频的AI工具

AI 会替代剪辑师吗?这个问题和“AI 会替代程序员吗”一样,问错了方向。会用 AI 工具的人,正在替代不会用的人。一个剪辑师用传统方式花三天做的宣传片,另一个人用 UniCut 一天做完,质量差不多,市场会选谁,答案很明显。工具的进化从来不是把专业的人淘汰掉,而是把专业的门槛拆掉。浏览器已经打开了,剩下的就是你愿不愿意试一下。体验地址:https://unicut.h5ds.com/开源仓库:https://github.com/mtsee/unicut。

d676015863的博客 157

【Unity3D插件】XCharts插件完全教程《全网最全》-专栏文章目录

最近在做图表类需求功能的时候,发现了一款强大的Unity3D插件,也就是XCharts图表插件,功能强大,支持多种图表。官方介绍:一款基于UGUI的功能强大、简单易用的数据可视化图表插件。支持折线图、饼状图、饼图、雷达图、散点图、热力图、环形图、K线图、极坐标、平行坐标等十多种内置图表,以及3D饼图、3D金字塔、漏斗图、仪表盘、水位图、象形柱图、甘特图、矩形树图等拓展图表。内置丰富示例和模板,参数可视化配置,效果实时预览,纯代码绘制。支持折线图、柱状图、饼图、雷达图、散点图、热力图等常见图表。

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 3197

WinCC实现定时存储数据至SQLServer

环境 Win10 WinCC V7.5 SQL Server 2016 运行结果 流程 WinCC变量 全局VB脚本 (我设置的是每2秒存一次,因此周期性触发器设置1秒)

skr? 3988

音频自动匹配歌词:本地音乐库元数据维护实践

实施顺序建议为:建立主库、统一命名、批量匹配、人工校验、权限分享、定期备份。工具选择上,SMB/WebDAV、Navidrome、Jellyfin 以及轻量文件管理服务各有适用场景,应结合访问方式、权限需求和维护成本评估。把文件组织好、把批量操作控制住、把备份习惯建立起来,歌词补全才能真正提升本地音乐库的可用性,而不是带来新的整理负担。音乐文件不常修改,但歌词、封面、播放列表和目录结构属于人工整理成果,丢失后恢复成本较高。更合理的顺序是:集中存放、统一命名、批量匹配、人工校验、权限管理、定期备份。

zxcvb153的博客 117

GRCNN抓取网络学习3【自制Jacquard数据集模型调优】

请先完成,这样有利于下面操作的理解!然后第二步是,有了自己的数据集输入到GRCNN中是三种文件,那么可以GRCNN抓取网络学习2【自制Jacquard数据集训练】!既然学会训练,那么开展下一步计划模型调优。GRCNN源码:https://github.com/skumra/robotic-grasping。

vor234的博客 2502

视频美颜sdk的API设计会影响开发效率吗?

视频美颜SDK不仅需要具备优秀的图像处理能力,API接口设计同样会影响软件开发效率。本文从接口调用、参数配置、版本兼容、开发文档以及业务扩展等多个角度,分析API设计对视频美颜SDK集成和后期维护的实际影响,为直播APP、视频社交平台等项目的SDK选型与技术开发提供参考。

wanyuekeji的博客 217

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

视频号数据怎么采?接入方式、字段范围与场景适配

视频号数据采集的技术难点不在“调哪个接口”,而在。官方API服务的是“经营与交易”闭环,返回的是直播记录、订单、售后等结构化实体,但播放完成率、互动明细、评论区内容这些内容分析赖以生存的字段,并不在官方接口的返回Schema里。这意味着任何技术方案的选择,本质上是。

城章科技 301

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

本地化部署会议视频软件如何开展试点?试用范围、评估指标与推广步骤

试用范围覆盖真实差异,评估指标具有明确口径,推广过程具备放行和回退机制。对于政企、金融、医疗及信创项目,尤其要避免三个误区:把本地部署等同于合规,把演示并发等同于生产容量,把功能清单等同于可运维能力。如果正在准备试点,建议先整理一张“网络—终端—业务—故障”矩阵,再决定试用人数。

hz56789的博客 320

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

AI 礼盒开箱视频怎么做?让商品亮相更有仪式感

AI商品视频通过精细设计开箱动作与场景节奏,将礼盒从静态包装转化为沉浸式送礼体验。从暖光布景、情感化构图到手部停顿、商品细节特写,每一帧都传递“精致”与“珍视”。以珠宝礼盒为例,俯拍视角下,红色对开门展开如舞台揭幕,银色项链在深蓝夜空衬底中缓缓呈现,掌心承托、缓慢转动,强化视觉记忆。结尾平铺构图,礼盒与商品共存,情绪由期待落至静谧珍藏。全程无文字,靠画面叙事,实现仪式感与品牌调性的深度融合。

yunhhhhh的博客 119

RN鸿蒙空间音频实战

示例仓库:https://atomgit.com/m0_37170006/react-native-ohos-spatial-audio 社区导引:框架源码与版本发布见 https://atomgit.com/CPF-RN/ohos_react_native/tree/0.84-main CPF-RN 鸿蒙社区:https://atomgit.com/CPF-rn。

buhuisuanfa的博客 2万+

通过 AIGC 生成视频何时才能告别“抽卡”!

如果视频的主体内容已经符合要求,只存在错误字幕或局部画面瑕疵时,重新生成不仅增加成本,还可能改变原本满意的部分。针对这类问题,WAND-EraseVibe+ 提供了视频擦除与画面重建能力。根据腾讯云披露的技术方案,该工具采用基于隐空间 Transformer 的生成式修复架构,先将视频画面编码为隐空间特征,在特征层推断并重建需要修复的区域,再解码为视频画面。白模前置、垂直场景调优和局部修复分别作用于不同环节,目的都是减少为了获得可用内容而付出的重复生成成本。

Enweitech Software Works 151

网页视频资源识别与本地化管理:从 HTTP 流媒体技术到完整的视频工作流

现代网页视频技术已经从简单的文件传输发展到分段传输、自适应码率和浏览器端媒体处理。这使视频播放体验不断改善,也让资源识别和本地管理变得更加复杂。对于技术人员而言,理解 HTTP、HLS、MPEG-DASH 和 MSE 的基本工作机制,有助于更准确地分析网页视频的传输过程。对于视频创作者和研究人员而言,建立从内容发现、资源识别到本地整理的完整工作流,可能比单纯寻找一个下载工具更有长期价值。

m0_68263549的博客 428

联犀 Go SIMD 实战:视频转码从 16.5ms 到 5.46ms

联犀Go视频转码实战:在352×288测试流中单帧单核CPU耗时从16.5ms到5.46ms,区分SIMD、代码及编码策略的综合收益。保留测试条件、压测结果与适用边界。

QQ603785348的博客 334

15. 调用ComfyUI生成视频!

在“导演大师”中,我们不仅支持导出分镜导演包并一键导入运行,还为用户提供了极高的自定义自由度。许多创作者希望结合自己精心调试的 MiniMax H3 工作流来生成视频,这当然是完全支持的。通常有两种操作方式:一种是手动复制,将分镜的资产与提示词手动粘贴至本地工作流中;另一种则是更为高效的自动化方案——直接在“导演大师”中调用 ComfyUI 工作流,实现一键生成。本文将重点介绍后者的配置与使用全流程,帮助你打通从分镜脚本到视频直出的自动化链路。

2601_95544990的博客 250

AI智能美妆如何适应不同面部特征?视频美颜SDK技术解析

AI智能美妆正在推动视频美颜技术向个性化方向发展。面对不同用户的脸型、眼型、唇形及肤色差异,视频美颜SDK如何通过人脸检测、关键点识别、动态追踪和实时渲染实现精准适配?本文从核心技术原理、不同面部特征的妆容适配方式,以及实际应用场景等方面展开解析,帮助开发者了解AI智能美妆的技术实现与发展趋势。

q1031691172的博客 357

Gemini Omni 1.2 Flash发布:视频10秒变15秒、720p降价30%

发布日期:2026-11-06Gemini Omni 1.2 Flash是Google于2026年11月发布的视频生成模型,支持原生15秒视频、多轮对话编辑和更强的参考素材遵循。Google公告发布于北京时间11月6日凌晨,官网标注日期为11月5日。相比Omni 1.1,新版把最长片段从10秒延长至15秒,720p视频单价降至每秒0.07美元,降幅30%。这次更新还涉及生成之后的修改:换背景、调光线、替换产品,可以围绕同一条视频继续提出要求。

aidoudoulong的博客 414

面向强噪声工业场景的 KL‑2510 音频 DSP 模组设计与多场景落地分析

KL-2510是一款22×16mm邮票孔SMT封装音频模组,集成ADC/DAC、AI-ENC降噪(45–90dB)与AEC回声消除(100dB),支持USB免驱及模拟/PDM麦克风输入,具备4档硬件拾音增益,适配医疗、矿山、安防等复杂噪声场景。通过五类真实案例验证其在病房对讲、井下报警、门铃对讲等应用中的稳定性与易用性。重点提示:需接入AEC_IN参考信号、输出加分压电路、外设勿接3V3电源,避免烧毁。适用于空间紧凑、无算法团队的嵌入式项目,显著降低音频开发门槛。

R190_6589的博客 395

实时互动、直播、点播:音视频SDK选型的技术逻辑

在远程办公、在线教育、文娱电商、政务民生等数字化业务中,音视频能力已经成为多数互联网应用的基础设施。行业内目前形成了实时互动、直播、点播三种主流业务形态,三者在技术架构、传输逻辑与技术指标上差异明显。对研发团队和技术决策者来说,先分清业务属于哪种形态,再据此匹配音视频SDK与传输方案,可以直接影响研发周期、开发成本和终端体验。本文拆解三类业务形态的技术特征、核心指标与选型逻辑,并补充相关的传输原理,供选型时参考。## 一、实时互动:低延迟双向交互的技术体系实时互动的本质,是在双方或多方之间建立低延迟、高稳定

YWamy的博客 147
上一篇: 音量调节相关的一些问题解答之Active StreamType原理
下一篇: 安卓车机车载面试福利7:一线厂商车载系统开发相关面试真题(持续更新)
千里马学框架
博客等级 码龄6年 1万+粉丝 650原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值