【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
在开始搜索框中输入“专用字符编辑程序”
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
1、新建QtGUI应用,选取QWidget为基类,取消创建界面
2、widget.h中 #ifndef WIDGET_H #define WIDGET_H #include #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = 0); ~Widget(); private: QSlider *slider[6]; QLabel *lbl[3]; private slots: void valueChanged1(int value); void valueChanged2(int value); void valueChanged3(int value); }; #endif // WIDGET_H
widget.cpp中 #include "widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) { int xpos = 20, ypos = 20; for(int i = 0 ; i < 6 ; i++) { if(i <= 2) { slider[i] = new QSlider(Qt::Vertical, this); slider[i]->setGeometry(xpos, 20, 30, 80); xpos += 30; } else if(i >= 3) { slider[i] = new QSlider(Qt::Horizontal, this); slider[i]->setGeometry(130, ypos, 80, 30); ypos += 30; } slider[i]->setRange(0, 100); slider[i]->setValue(50); } xpos = 20; for(int i = 0 ; i < 3 ; i++) { lbl[i] = new QLabel(QString("%1").arg(slider[i]->value()), this); lbl[i]->setGeometry(xpos+10, 100, 30, 40); xpos += 30; } connect(slider[0], SIGNAL(valueChanged(int)), this, SLOT(valueChanged1(int))); connect(slider[1], SIGNAL(valueChanged(int)), this, SLOT(valueChanged2(int))); connect(slider[2], SIGNAL(valueChanged(int)), this, SLOT(valueChanged3(int))); } void Widget::valueChanged1(int value) { lbl[0]->setText(QString("%1").arg(value)); slider[3]->setValue(slider[0]->value()); } void Widget::valueChanged2(int value) { lbl[1]->setText(QString("%1").arg(value)); slider[4]->setValue(slider[1]->value()); } void Widget::valueChanged3(int value) { lbl[2]->setText(QString("%1").arg(value)); slider[5]->setValue(slider[2]->value()); } Widget::~Widget() { }
效果:
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
年初因为工作需要,开始学习 WebRTC ,就被其复杂的编译环境和巨大的代码量所折服,注定是一块难啃的骨头。俗话说万事开头难,坚持一个恒心,终究能学习到 WebRTC 的设计精髓。今天和大家聊聊 WebRTC 中音频的那些事。 WebRTC 由语音引擎,视频引擎和网络传输三大模块组成,其中语音引擎是 WebRTC 中最具价值的技术之一,实现了音频数据的采集、前处理、编码、发送、接受、解码、混音、后处理、播放等一系列处理流程。
音频引擎主要包含:音频设备模块 ADM 、音频编码器工厂、音频解码器工厂、混音器 Mixer 、音频前处理 APM 。
音频工作机制
想要系统的了解音频引擎,首先需要了解核心的实现类和音频数据流向,接下来我们将简单的分析一下。
音频引擎核心类图:
音频引擎 WebrtcVoiceEngine 主要包含音频设备模块 AudioDeviceModule 、音频混音器 AudioMixer 、音频 3A 处理器 AudioProcessing 、音频管理类 AudioState 、音频编码器工厂 AudioEncodeFactory 、音频解码器工厂 AudioDecodeFactory 、语音媒体通道包含发送和接受等。
1. 音频设备模块 AudioDeviceModule 主要负责硬件设备层,包括音频数据的采集和播放,以及硬件设备的相关操作。
2. 音频混音器 AudioMixer 主要负责音频发送数据的混音(设备采集和伴音的混音)、音频播放数据的混音(多路接受音频和伴音的混音)。
3. 音频 3A 处理器 AudioProcessing 主要负责音频采集数据的前处理,包含回声消除 AEC 、自动增益控制 AGC 、噪声抑制 NS 。 APM 分为两个流,一个近端流,一个远端流。近端( Near-end )流是指从麦克风进入的数据;远端( Far-end )流是指接收到的数据。
4. 音频管理类 AudioState 包含音频设备模块 ADM 、音频前处理模块 APM 、音频混音器 Mixer 以及数据流转中心 AudioTransportImpl 。
5. 音频编码器工厂 AudioEncodeFactory 包含了 Opus 、 iSAC 、 G711 、 G722 、 iLBC 、 L16 等 codec 。
6. 音频解码器工厂 AudioDecodeFactory 包含了 Opus 、 iSAC 、 G711 、 G722 、 iLBC 、 L16 等 codec 。
音频的工作流程图:
1. 发起端通过麦克风进行声音采集
2. 发起端将采集到的声音信号输送给 APM 模块,进行回声消除 AEC ,噪音抑制 NS ,自动增益控制处理 AGC
3. 发起端将处理之后的数据输送给编码器进行语音压缩编码
4. 发起端将编码后的数据通过 RtpRtcp 传输模块发送,通过 Internet 网路传输到接收端
5. 接收端接受网络传输过来的音频数据,先输送给 NetEQ 模块进行抖动消除,丢包隐藏解码等操作
6. 接收端将处理过后的音频数据送入声卡设备进行播放
NetEQ 模块是 Webrtc 语音引擎中的核心模块
在 NetEQ 模块中,又被大致分为 MCU 模块和 DSP 模块。 MCU 主要负责做延时及抖动的计算统计,并生成对应的控制命令。而 DSP 模块负责接收并根据 MCU 的控制命令进行对应的数据包处理,并传输给下一个环节 .
音频数据流向
根据上面介绍的音频工作流程图,我们将继续细化一下音频的数据流向。将会重点介绍一下数据流转中心 AudioTransportImpl 在整个环节中扮演的重要角色。
数据流转中心 AudioTransportImpl 实现了采集数据处理接口 RecordDataIsAvailbale 和播放数据处理接口 NeedMorePlayData 。 RecordDataIsAvailbale 负责采集音频数据的处理和将其分发到所有的发送 Streams 。 NeedMorePlayData 负责混音所有接收到的 Streams ,然后输送给 APM 作为一路参考信号处理,最后将其重采样到请求输出的采样率。
RecordDataIsAvailbale 内部主要流程: 由硬件采集过来的音频数据,直接重采样到发送采样率 由音频前处理针对重采样之后的音频数据进行 3A 处理 VAD 处理 数字增益调整采集音量 音频数据回调外部进行外部前处理 混音发送端所有需要发送的音频数据,包括采集的数据和伴音的数据 计算音频数据的能量值 将其分发到所有的发送 Streams
NeedMorePlayData 内部主要流程: 混音所有接收到的 Streams 的音频数据
1.1 计算输出采样率 CalculateOutputFrequency()
1.2 从 Source 收集音频数据 GetAudioFromSources(), 选取没有 mute ,且能量最大的三路进行混音
1.3 执行混音操作 FrameCombiner::Combine() 特定条件下,进行噪声注入,用于采集侧作为参考信号 对本地伴音进行混音操作 数字增益调整播放音量 音频数据回调外部进行外部前处理 计算音频数据的能量值 将音频重采样到请求输出的采样率 将音频数据输送给 APM 作为一路参考信号处理
由上图的数据流向发现,为什么需要 FineAudioBuffer 和 AudioDeviceBuffer ?因为 WebRTC 的音频流水线只支持处理 10 ms 的数据,不同的操作系统平台提供了不同的采集和播放时长的音频数据,不同的采样率也会提供不同时长的数据。例如 iOS 上, 16K 采样率会提供 8ms 的音频数据 128 帧; 8K 采样率会提供 16ms 的音频数据 128 帧; 48K 采样率会提供 10.67ms 的音频数据 512 帧 .
AudioDeviceModule 播放和采集的数据,总会通过 AudioDeviceBuffer 拿进来或者送出去 10 ms 的音频数据。对于不支持采集和播放 10 ms 音频数据的平台,在平台的 AudioDeviceModule 和 AudioDeviceBuffer 还会插入一个 FineAudioBuffer ,用于将平台的音频数据格式转换为 10 ms 的 WebRTC 能处理的音频帧。在 AudioDeviceBuffer 中,还会 10s 定时统计一下当前硬件设备过来的音频数据对应的采样点个数和采样率,可以用于检测当前硬件的一个工作状态。
音频相关改动 音频 Profile 的实现,支持 Voip 和 Music 2 种场景,实现了采样率、编码码率、编码模式、声道数的综合性技术策略。
iOS 实现了采集和播放线程的分离,支持双声道的播放。 音频 3A 参数的兼容性下发适配方案。 耳机场景的适配,蓝牙耳机和普通耳机的适配,动态 3A 切换适配。 Noise_Injection 噪声注入算法,作为一路参考信号,在耳机场景的回声消除中的作用特别明显。 支持本地伴音文件 file 和网络伴音文件 http&https 。 Audio Nack 的实现,提高音频的抗丢包能力,目前正在进行 In-band FEC 。 音频处理在单讲和双讲方面的优化。 iOS 在 Built-In AGC 方面的研究: Built-In AGC 对于 Speech 和 Music 有效,对于 noise 和环境底噪不会产生作用。 不同机型的麦克风硬件的增益不同, iPhone 7 Plus > iPhone 8 > iPhone X; 因此会在软件 AGC 和硬件 AGC 都关闭的情况下,远端听到的声音大小表现不一样。 iOS 除了提供的可开关的 AGC 以外,还有一个 AGC 会一直工作,对信号的 level 进行微调;猜想这个一直工作的 AGC 是 iOS 自带的 analog AGC ,可能和硬件有关,且没有 API 可以开关,而可开关的 AGC 是一个 digital AGC 。 在大部分 iOS 机型上,外放模式 “ 耳机再次插入后 ” , input 的音量会变小。当前的解决方案是在耳机再次插入后,增加一个 preGain 来把输入的音量拉回正常值。
音频问题排查
和大家分享一下音频最常见的一些现象以及原因:
更多技术干货,欢迎关注 vx 公众号 “ 网易智慧企业技术 +” 。系列课程提前看,精品礼物免费得,还可直接对话 CTO 。
听网易 CTO 讲述前沿观察,看最有价值技术干货,学网易最新实践经验。网易智慧企业技术 + ,陪你从思考者成长为技术专家。
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
安装
https://github.com/Bingnan/ffmpeg3.0.1
注:安装完会在/root/bin下,但是这样有时在脚本里就没法执行ffmpeg,所以把文件都到/usr/bin下,问题解决
一次编译安装完成,/root/bin/ff* 下的文件就可以拷贝到其他机器上使用了
参数 -codecs 列出编解<和谐>码器 -formats 列出分装格式 -f 格式化
一般会自动识别,不需要这个字段 -i input -c / -codec指定,编解<和谐>码器 -c copy 不用重新编码
例子
ffmpeg -i index_1-0.wmv -c:v libx264 -c:a libfdk_aac out.mp4
ffmpeg -f concat -i /home/lsr/record/42887.txt -c copy /home/lsr/record/42887-test.flv ffmpeg -i rtmp://strtmpplay.cdn.suicam.com/sclive/46508 -f segment -codec copy -map 0 -vbsf h264_mp4toannexb -flags -global_header -segment_format mpegts -segment_list 46508.m3u8 -segment_time 10 -segment_list_entry_prefix /home/lsr/data/ -segment_list_size 5 seg-%03d.ts
推流:
ffmpeg -re -i 123.mp4 -c copy -f flv rtmp://xxx/xxx
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
设计师都喜欢浏览一些设计网站,那么什么样的网站是对我们平时的工作学习有一定的帮助的呢?今天小编给大家整理了20个设计网站,用途不同,觉得有用的小伙伴可以收藏学习。
设计的网站推荐:
1, dribbble-追波
比较潮流的设计内容查看。
2, Behance
国外的站酷。内容优质全面
3.站酷
国内设计师平台,每天必看。
4.UI中国
国内UI交流平台
5.
有很多非常棒的高清创意视频
6.
UI素材搜索引擎,提供大量的PSD源文件免费下载
7.找字网
找字网提供大量的中英文字体
8.网页设计师联盟
国内专业网页设计人才基地
9.优设网
一线设计师,总监干货分享。
10.花瓣
Huabanpro.com 你想要的花瓣回来了
11.C4D之家
12.。直线教程网
视频学习网
13.千图网
素材下载
14.包图网
15.92素材网
16.JVshi
正版素材
17.映速社区
很好的教学平台
18.doyoudo
小莫老师不容错过
19.盒子UI
20.FONTS
全球最大的字体提供者
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
下载Essential Studio for Xamarin最新版本
Essential Studio for Xamarin 是全面的Xamarin.iOS、Xamarin.Android和Xamarin.Forms组件套包,包含最快的图表和网格。
分段控制不定开关
在进一步定制分段控制时,它可以作为典型开关或具有三种状态的不确定开关:开、关和平衡。
Indeterminate switch with Syncfusion’s Xamarin.Forms Segmented Control.
功能丰富范围滑块
范围滑块控件允许用户使用优雅的界面选择最小和最大范围内的值或值范围。
Syncfusion’s Xamarin.Forms Range Slider.
带有单选按钮组的组选项
单选按钮控件为用户提供了一个优雅的界面,可以从两个或多个选项中进行选择,而不会占用太多空间。
Syncfusion’s Xamarin.Forms Radio Button.
不确定复选框
使用复选框控件,当一组子选项同时具有未选中和已选中状态时,通过用不确定状态指示,确保选中或未选中所有子选项。
Syncfusion’s Xamarin.Forms CheckBox.
自定义视图分级
您可以自定义我们的Xamarin.Forms分级控制,而不是像传统的明星一样的外观,通过建立一个反应或情绪界面来改善用户体验,就像Facebook等社交网络应用程序中的那样。
Syncfusion’s Xamarin.Forms Rating control.
总结
在这篇文章中,我们介绍了用于创建表单的Syncfusion Xamarin.Forms输入控件。可以看到DataForm控件本身在应用程序需要大量表单的地方创建基于对象的数据表单是多么容易。
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
下载Essential Studio for Xamarin最新版本
Essential Studio for Xamarin 是全面的Xamarin.iOS、Xamarin.Android和Xamarin.Forms组件套包,包含最快的图表和网格。
用于日期选择的轻量级日历
使用强大的日历控件获取精确的日期输入。用户可以从月视图导航到年视图。
Syncfusion’s Xamarin.Forms Calendar.
使用文本输入布局使条目现代化
文本输入布局控件通知用户预期要输入的类型数据,如果输入的类型数据错误,则使用验证消息通知用户。它允许您添加密码切换图标以显示或隐藏密码;辅助标签(如浮动标签)以及条目控件顶部的提示、错误和帮助文本。
Syncfusion’s Xamarin.Forms Text Input Layout.
自定义格式的数字项
使用数字输入控件将输入限制为数值。控件根据区域适应设备文化。
Syncfusion’s Xamarin.Forms Numeric Entry
用NumericUpDown旋转数字
使用NumericUpDown控件以频繁的步骤限制数字输入。它就像一个重复按钮,通过简单的按钮单击来增加或减少数值。
Syncfusion’s Xamarin.Forms NumericUpDown.
使用屏蔽项指定模式
通过提供自定义掩码或regex,将用户输入限制为某些类型的字符(如电话号码、IP地址和产品ID等输入的文本),确保使用屏蔽输入控件的输入符合特定模式。
Syncfusion’s Xamarin.Forms Masked Entry.
可滚动分段控件
使用分段控件为用户提供一个优雅的界面,从两个或多个上下文中进行选择。表单分段控制可以取代传统的单选按钮。
Syncfusion’s Xamarin.Forms Segmented Control.
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
下载Essential Studio for Xamarin最新版本
Essential Studio for Xamarin 是全面的Xamarin.iOS、Xamarin.Android和Xamarin.Forms组件套包,包含最快的图表和网格。
如何将Syncfusion输入控件添加到数据表单中
从Visual Studio模板创建项目
从NuGet添加引用
添加控件初始化代码
在以下步骤中,已添加必要的XAML代码以初始化控件。
步骤1:在相应的页面中包含SfAutoComplete命名空间。
1
2
< contentpage xmlns:autocomplete = "clr-namespace:Syncfusion.SfAutoComplete.XForms;assembly=Syncfusion.SfAutoComplete.XForms" x:class = "GettingStarted.MainPage" >
contentpage >
步骤2:通过将高度定义为40来声明内容页的SfAutoComplete,因为地址栏需要40像素的高度。
1
2
3
< contentpage xmlns:autocomplete = "clr-namespace:Syncfusion.SfAutoComplete.XForms;assembly=Syncfusion.SfAutoComplete.XForms" x:class = "GettingStarted.MainPage" >
< autocomplete:sfautocomplete heightrequest = "40" >
autocomplete:sfautocomplete > contentpage >
注意:前面的步骤适用于将所有Syncfusion的Xamarin.Forms输入控件添加到Xamarin.Forms应用程序中。
添加建议项
当然,自动完成控件可以与数据源以及直接字符串项绑定。
1
2
3
4
5
6
7
8
9
10
11
12
13
< contentpage xmlns:autocomplete = "clr-namespace:Syncfusion.SfAutoComplete.XForms;assembly=Syncfusion.SfAutoComplete.XForms" xmlns:listcollection = "clr-namespace:System.Collections.Generic;assembly=mscorlib" x:class = "GettingStarted.MainPage" >
< autocomplete:sfautocomplete heightrequest = "40" >
< autocomplete:sfautocomplete.autocompletesource >
< listcollection:list x:typearguments = "x:String" >
< x:string >Aqua x:string >
< x:string >Blue x:string >
< x:string >Indigo x:string >
< x:string >Red x:string >
< x:string >Purple x:string >
listcollection:list >
autocomplete:sfautocomplete.autocompletesource >
autocomplete:sfautocomplete >
contentpage >
带切换操作的高级按钮
Xamarin.Forms按钮是一个自定义按钮控件,具有用户界面自定义、切换状态和主题支持。您可以设置图标、背景图像和角边半径,也可以使用可视状态管理器自定义不同可视状态的外观。
Syncfusion’s Xamarin.Forms Button.
可编辑组合框
表单组合框控件是一种数据输入控件,允许用户从固定的项目列表中选择选项。组合框用于选择一个国家,可以打开下拉列表,也可以简单地键入开始键入其名称。
Syncfusion’s Xamarin.Forms ComboBox.
多功能选择器
我们甚至提供了一个通用的选择器控件,可以用来从任何类型的列表数据中进行选择。这决定了选取器作为日期选取器、时间选取器、语言选取器、颜色选取器等的性质。直观的多列选项支持层叠选择。选择器控件是唯一一个根据数据源结构自动生成其列的组件。在此表单中,选取器控件可以提供一个通用的UI来选取日期值。
Syncfusion’s Xamarin.Forms Picker.
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
下载Essential Studio for Xamarin最新版本
Essential Studio for Xamarin 是全面的Xamarin.iOS、Xamarin.Android和Xamarin.Forms组件套包,包含最快的图表和网格。
介绍
欢迎学习使用Syncfusion的一些输入控件(如用于Xamarin.Forms平台的内置DataForm控件)创建数据输入表单。
Xamarin.Forms数据表单控件用于显示和编辑任何数据对象的属性,使用各种内置编辑器来处理不同的数据类型。它简化了各种表单的开发,如登录、保留和数据输入。
除DataForm控件外, Syncfusion Essential Studio for Xamarin 还提供其他单独的输入控件,使您可以根据自己的喜好创建自己的数据输入窗体: Autocomplete、Button、Badge View、Chips、ComboBox、Picker、Calendar、Numeric Entry、NumericUpDown、Masked Entry、CheckBox、Radio Button、Range Slider、Rating和Segmented Control,使您能够根据规范创建自己的数据输入表单。
如果有预定义的模型,请使用DataForm控件
如果您的应用程序有很多表单,并且您有预定义的模型,那么我们提供一个DataForm控件,它可以基于您的数据对象创建表单,从而简化表单创建过程。DataForm可以帮助您以多种方式呈现数据,例如在预定义的布局中呈现模型项的集合。
以下步骤说明如何使用DataForm创建具有预定义模型的表单:
步骤1:导入控件命名空间 “xmlns:dataForm=”clr-namespace:Syncfusion.XForms.DataForm;assembly=Syncfusion.SfDataForm.XForms” 在XAML页中,创建DataForm控件的实例并将其作为视图添加到线性布局中。
1
2
3
< contentpage xmlns:dataform = "clr-namespace:Syncfusion.XForms.DataForm;assembly=Syncfusion.SfDataForm.XForms" x:class = "GettingStarted.MainPage" >
< dataform:sfdataform >
dataform:sfdataform > contentpage >
步骤2:数据表单是一个数据编辑控件,因此创建一个数据对象来编辑数据对象。这里,名为ItemInfo的数据对象是用一些属性创建的。
1
2
3
4
5
6
7
8
public class ItemInfo
{
public ItemInfo() { }
public int TotalAmount { get; set; }
public DateTime? Date { get; set; }
public string Name { get; set; }
public bool IsBillable { get; set; }
}
步骤3:在一个新的类文件中创建一个具有用必需数据初始化的ItemInfo属性的模型存储库类,如下面的代码示例所示。
1
2
3
4
5
6
7
8
public class ViewModel
{
public ItemInfo ItemInfo { get; set; }
public ViewModel()
{
ItemInfo= new ItemInfo();
}
}
步骤4:要在数据表单中填充标签和编辑器,请设置DataObject属性。
1
2
3
4
5
6
< contentpage xmlns:local = "clr-namespace:GettingStarted" xmlns:dataform = "clr-namespace:Syncfusion.XForms.DataForm;assembly=Syncfusion.SfDataForm.XForms" x:class = "GettingStarted.MainPage" >
< contentpage.bindingcontext >
< local:viewmodel >
local:viewmodel > contentpage.bindingcontext >
< dataform:sfdataform dataobject = "{Binding ItemInfo}" >
dataform:sfdataform > contentpage >
Syncfusion’s Xamarin.Forms DataForm.
Syncfusion的Xamarin.Forms输入控件表单无模型数据表单
到目前为止,我们讨论了Syncfusion的Xamarin.Forms数据表单控件如何帮助创建预定义的模型数据表单。现在,让我们看看Syncfusion输入控件如何通过丰富的功能显著改善最终用户的数据输入体验。
快速且功能丰富的自动完成功能
Syncfusion的Xamarin.Forms自动完成控件在用户键入建议列表时提示用户进行选择,从而使数据输入更快、更不容易出错。例如,在表单中,用户可以通过使用此控件进行搜索来选择邮政编码。
高性能搜索引擎可以在不到一秒钟的时间内加载和搜索100000个项目。自定义搜索的打字公差功能、有效数据利用的按需加载、带标记表示的多重选择、匹配文本的突出显示和音调符号敏感性是此控件的其他几个重要功能。
Syncfusion’s Xamarin.Forms Autocomplete.
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
编者注
记录Alembic(三维中间件)的编译过程。
安装编译环境
安装Clion
略
安装MinGW
作者偷懒,直接下载DEVCpp,其中内置MinGW。路径为C:\Program Files (x86)\Dev-Cpp\MinGW64
CMake检查
Alemic项目检查 ====================[ Build | abcdiff | Debug ]================================= C:
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
一、在windows上搭建基于ffmpeg解决方案的开发环境
系统 : Windows 10 x86_64系统 i5 4核cpu 8gb内存
工具: Visual Studio Community 2007
库文件和头文件:ffmpeg 开发库,这里需要Shared、Dev库,下载地址为《 Windows ffmpeg Build 》
Shared 动态库dll : 以及依赖dll的可执行文件。
Dev开发库: 包含FFMPEG头文件的include,包含静态库的lib 【这种静态库只包含头元信息,这是需要Shared库原因】
注意:Shared和Static库原则上必须保持同一版本,否则可能无法引用
假设以上文件放置目录如下:
include 头文件 | d:/ffmpeg/include lib 静态库 | share 动态库 d:/ffmpeg/lib | d:/ffmpeg/share |
---|
二、配置开发环境
1、根据自己的需要创建Visual C++的应用项目
2、环境配置
2.1 打开项目属性面板
2.2 选择【VC++目录】,配置include位置和lib
2.3 接下来选择【链接器 -> 输入 】中的【附加依赖项】进行编辑,添加静态库引用
正常情况下项目配置完成了,但是ffmpeg提供的lib文件不包含代码实现部分,因此我们需要添加dll库进来,这样运行会提示找不到dll文件。
3、添加dll动态链接库
添加dll文件的方式有2种,一般来说,我们需要把dll放到项目的根目录下,当然还有另一种方式就是链接的方式。
3.1 、添加dll到项目目录下
在visual studio 下,第一层路径为【解决方案路径】,dll需要放置到解决方案路径下的子项目中,换种说法是放置到包含vcxproj文件的目录下。这种方式一般用于项目发布。
因此,拷贝dll到项目目录下即可。
3.2、临时修改环境变量
运行环境会扫描path路径,可以将share库目录添加到path中,同样也可以临时性修改。
三、代码开发注意事项
1、由于ffmpeg 是基于gcc标准开发的,因此在msvc上,需要关闭SDL检查
2、Visual Studio系统创建的项目是C++程序,引入的header需要注意
extern "C"{
#include ....
}
3、msvc编译时强制要求预定义__STDC_CONSTANT_MACROS,因此合并第二个,#include部分可以如下使用 #ifdef __cplusplus extern "C" { #ifndef __STDC_CONSTANT_MACROS #define __STDC_CONSTANT_MACROS #include
#include #include #include #endif } #else #ifndef __STDC_CONSTANT_MACROS #define __STDC_CONSTANT_MACROS #include #include #include #include #endif #endif
3、编译时cpu arc选择x64
综上,开发环境配置完成。 【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
VARCHART XGantt 是一款功能强大的 甘特图控件 ,其模块化的设计让您可以创建满足需要的应用程序。 XGantt 可用于.NET,ActiveX和ASP.NET应用程序,可以快速、简单地集成到您的应用程序中,帮助您识别 性能瓶颈 、 避免延迟 以及 高效利用资源 ,使复杂数据变得更加容易理解。
本文主要介绍如何在分组视图中更好地 显示节点 ,有任何建议或提示请在下方评论区留言。
在甘特图中活动通常以组的形式展现,比如machine Gantt代表机器负载可视化,它区分机器组和各自的机器,这被称为双阶段分组。甘特图的分组可以用来表示扩张或者收缩,这取决于你想从哪个角度查看详细数据。
有一个传统甘特图控制所面临的问题:那就是通常节点只在一个组级别中显示。那么如何在甘特图组中显示节点?是在顶部折叠或是在底部展开?在下文中将详细介绍如何在组级别上可视化节点,以及基于节点的单个组的排列如何增强甘特图的信息价值。
VARCHART XGantt的位移技巧
VARCHART XGantt是一款非常灵活的 .Net甘特控制工具 ,仅通过少量的编程就可以针对面向时间的规划数据进行几乎所有可视化需求定制。
当特定机器的甘特图启动时如果显示崩溃,下面的示例将显示机器组,而单个机器最初并没有显示,并且所有节点都显示在顶层。
当展开机器组后,可以看到第二层单独的机器。现在我们直观的将节点从机器组移动到机器上(只需撤销移动,节点就会再次出现在第一层)。
在一行中优化节点的排列
为了将节点排列在第一层和第二层,我们同时选择了VARCHART XGantt模式 all nodes in one row 和 nodes optimized 选项。这样就可以实现: 所有节点都显示在彼此相邻的一行中,这样可以一眼看到机器的利用率。 如果节点重叠,则显示另一行,并且重叠的节点出现在新行中。
在第二层展开时更改节点排列
由于我们希望为planner提供尽可能详细的视图选项,所以我们将 all nodes in one row 更改为 nodes in separate rows ,方法是为第二个分组级别勾选相应的复选框。
在展开机器视图时,每个节点将被清晰地安排在它自己的一行中,这样规划人员就可以识别出活动的确切时间。此外活动是按开始日期排序的,因此计划人员可以很容易地立即找到下一个计划的活动
在使用VARCHART XGantt分组视图时进行节点排列
Step 1:
本例中不使用扩展数据表,在传统的数据结构中,组是根据节点的分组标准 自动创建 的。VARCHART XGantt属性页上的设置如下: 第一个分组级别的组名 第二个分组级别的组名 虚拟分组数据字段
如果第二个分组字段为空,例如空字符串,则VARCHART XGantt将各个节点排序到下一个最高级别的组中。不要简单地将第二层的分组名称替换为空字符串,因为这样肯定会删除该值,并且无法再分配该值。这就是为什么我们需要在需要时将空字符串或第二层的分组名称复制到其中的虚拟数据字段(最初虚拟数据字段将保持为空)。
Step 2:
接下来如果尚未指定,我们将在设置中为这两个分组级别中的每一个创建 GroupLevelLayout : 分组方式:分组字段对应虚拟数据字段 单独行中的节点:false 节点优化:ture 群体崩溃:ture
Step 3:
现在需要导出VARCHART XGantt配置文件,使用文本编辑器进行编辑,然后再次导入。导出的INI文件会为每个分组级别显示 CreateGroupForEmptyEntry 关键字,为了简化问题,对于所有现有分组级别,这个关键字设置必须从YES改为NO。并且不要忘记为以后添加的所有分组级别 再次设置此键 。
Step 4:
我们需要检查哪个分组级别触发了修改后的事件,参考以下代码: 如果第一级被折叠或展开,我们必须创建第二级,并通过 foreach循环移动 节点。 如果第二层被折叠或展开,我们必须在单线视图或多线视图之间切换。 private void vcGantt1_VcGroupModified(object sender, VcGroupModifiedEventArgs e) { vcGantt1.SuspendUpdate(true); if (e.Group.GroupingLevel == 0) { if (e.Group.Collapsed) { foreach (VcNode node in e.Group.NodeCollection) { node.set_DataField(DT.Maindata_GroupLvl2FieldIndex, ""); node.Update(); e.Group.NodesOptimized = true; e.Group.Update(); } } else { foreach (VcNode node in e.Group.NodeCollection) { node.set_DataField(DT.Maindata_GroupLvl2FieldIndex, node.get_DataField(DT.Maindata_GroupLvl2DummyFieldIndex)); node.Update(); } } } if (e.Group.GroupingLevel == 1) { if (e.Group.Collapsed) { e.Group.NodesArrangedInOneRow = true; e.Group.NodesOptimized = true; e.Group.Update(); } else { e.Group.NodesArrangedInOneRow = false; e.Group.Update(); } } vcGantt1.SuspendUpdate(false); }
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
Vue Demo 【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
Docker CE 即社区免费版,Docker EE 即企业版,强调安全,但需付费使用。
Docker-ce提供四种版本: stable,edge,test,nightly 。 从Docker 1.13版以后,新版本号成发发布年份和月份为准。例:18.09.0
Docker-ce版本分为静态链接与动态链接两种: 静态链接版本不依赖操作系统库,所有包较大。 (windows 和mac目前只提供静态链接版) 动态链接版可以执行程序小一些,与操作系统库相关,只能在某种操作系统的具体发行版下安装。 centos ,debian,fedora,raspbian,ubuntu五类发版。
Docker支持以下的CentOS版本: CentOS 7 (64-bit) CentOS 6.5 (64-bit) 或更高的版本
Docker 运行在 CentOS 7 上,要求系统为64位、系统内核版本为 3.10 以上。
Docker 运行在 CentOS-6.5 或更高的版本的 CentOS 上,要求系统为64位、系统内核版本为 2.6.32-431 或者更高版本。
内核编译时需要激活namespace,CGgroup,netfilter,veth等特性,还对iptablest等工具版有依赖要求。
验证当前环境是否满足Docker 运行要求
下载脚本并执行 https://raw.githubusercontent.com/moby/mobymaster/contrib/check-config.sh
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
概要:
Crystal Reports(水晶报表)是一款商务智能( BI )软件,主要用于设计及产生报表。水晶报表是业内最专业、功能最强的 报表系统 ,它除了强大的报表功能外。最大的优势是实现了与绝大多数流行开发工具的集成和接口。在VS.Net平台做过报表开发的程序员,一定都对水晶报表强大、高效、集成等特性留下了深刻印象。 除了开发新程序外,在工作中我们常需要接触到很多较早的软件系统报表功能升级的需求,如果能结合水晶报表这一强大的工具,往往能事半功倍。
配置准备的东西:
JDBC 相关jar包 --- mysql-connector-java-5.1.22-bin.jar(MySQL)
或者 ojdbc5.jar(oracle)
开始配置:
1.找到你java的jdk路径一直到bin
如:D:\JAVA\Java\jdk1.6.0_45\bin,记录下来。
2.找到你的水晶报表路径中有一个叫external的文件夹,如果你找不到就打开你水晶报表的路径。然后跳到Business Objects文件夹这里
然后跟着这个路径找下去:Business Objects\Common\4.0\java\lib\external。
在这个文件夹里面放入你下载的.jar包。
3.配置文件CRConfig.xml
它的位置在Business Objects\Common\4.0\java中
(1)修改
放入你jdk的位置(1中记录的位置)
(2)在中添加
C:\Program Files\Business Objects\Common\4.0\java/lib/external/mysql-connector-java-5.1.22-bin.jar;(你下载的.jar包的位置)
4.打开测试
连接 URL : jdbc:mysql://LOCAL_HOST:3306/DB_NAME
例如: --- ( jdbc:mysql://localhost:3306/db_name )
资料库类别名称: com.mysql.jdbc.Driver--mysql
oracle.jdbc.driver.OracleDriver--oracle
使用者和密码就是数据库的用户和密码
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
编译完GDAL和JAVA接口后,如果需要使用C#调用,就需要编译C#的接口。方法如下:
注意:使用的SWIG版本不能使用太高版本,否则,会报一堆的类型未找到的错误,我是无从下手。使用swig2.0.7(据说2.0.6到2.0.9)表现都是一样的问题,后面详细解释修改代码的方法。
配置好nmake.opt里的swig后。启动vs2015的64位命令行工具,并切到gdal源码的swig/csharp目录下。执行如下命令:
nmake /f makefile.vc interface
等待执行完后,先不要编译,进入到swig/csharp目录下,修改如下生成的源码文件:
swig\csharp\gdal\GdalPINVOKE.cs
swig\csharp\ogr\OgrPINVOKE.cs
swig\csharp\osr\OsrPINVOKE.cs
这三个文件,分别按下图注释掉多余的代码:
然后分别打开如下三个文件
csharp\gdal\Band.cs
csharp\gdal\Dataset.cs
csharp\gdal\Driver.cs
修改第17行,将红色位置部分按如下修改,解决接口成员名错误问题。
Band.cs文件:
public Band(IntPtr cPtr, bool cMemoryOwn, object parent) : base(GdalPINVOKE. Band_SWIGUpcast (cPtr), cMemoryOwn, parent)
Dataset.cs文件:
public Dataset(IntPtr cPtr, bool cMemoryOwn, object parent) : base(GdalPINVOKE. Dataset_SWIGUpcast (cPtr), cMemoryOwn, parent)
Driver.cs文件:
public Driver(IntPtr cPtr, bool cMemoryOwn, object parent) : base(GdalPINVOKE. Driver_SWIGUpcast (cPtr), cMemoryOwn, parent) {
完成以上修改后,就可以切回到命令行窗口,切换到swig/csharp目录下执行如下命令:
nmake /f makefile.vc
等待一会儿,就会辨已完成,然后执行
nmake /f makefile.vc install
会把编译出来的8个dll复制到安装目录下的csharp目录下。
把gdal203.dll复制到这个目录下备用。
使用的时候,c#工程下引入这8个文件,然后把gdal203.dll这个文件系统路径或则工程路径对应的目录下,就可以使用了。
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
高斯分布也称为正态分布(normal distribution)。
常用的成熟的生成高斯分布随机数序列的方法由Marsaglia和Bray在1964年提出,C++版本如下: #include #include double gaussrand() { static double V1, V2, S; static int phase = 0; double X; if ( phase == 0 ) { do { double U1 = (double)rand() / RAND_MAX; double U2 = (double)rand() / RAND_MAX; V1 = 2 * U1 - 1; V2 = 2 * U2 - 1; S = V1 * V1 + V2 * V2; } while(S >= 1 || S == 0); X = V1 * sqrt(-2 * log(S) / S); } else X = V2 * sqrt(-2 * log(S) / S); phase = 1 - phase; return X; }
这样生成的高斯分布随机数序列的期望为0.0,方差为1.0。若指定期望为E,方差为V,则只需增加: X = X * V + E;
期望E=μ
方差V=σ^2
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
很多命令可以参考:
https://www.cnblogs.com/frost-yen/p/5848781.html
1.分离视频音频流
ffmpeg -i input_file -vcodec copy -an output_file_video //分离视频流
ffmpeg -i input_file -acodec copy -vn output_file_audio //分离音频流
2.视音频解复用
视频
ffmpeg –i test.mp4 –vcodec copy –an –f m4v test.264
ffmpeg –i test.avi –vcodec copy –an –f m4v test.264
ffmpeg -i input.mp4 -vcodec copy -an out.h264
音频
ffmpeg -i input.mp4 -an -vcodec copy -f mp3 out.mp3
3.视频转码
ffmpeg –i test.mp4 –vcodec h264 –s 352*278 –an –f m4v test.264 //转码为码流原始文件
ffmpeg –i test.mp4 –vcodec h264 –bf 0 –g 25 –s 352*278 –an –f m4v test.264 //转码为码流原始文件
ffmpeg –i test.avi -vcodec mpeg4 –vtag xvid –qsame test_xvid.avi //转码为封装文件
//-bf B帧数目控制,-g 关键帧间隔控制,-s 分辨率控制
4.视频封装
ffmpeg –i video_file –i audio_file –vcodec copy –acodec copy output_file
5.视频剪切
ffmpeg –i test.avi –r 1 –f image2 image-%3d.jpeg //提取图片
ffmpeg -ss 0:1:30 -t 0:0:20 -i input.avi -vcodec copy -acodec copy output.avi //剪切视频
//-r 提取图像的频率,-ss 开始时间,-t 持续时间
6.视频录制
ffmpeg –i rtsp://192.168.3.205:5555/test –vcodec copy out.avi
7.YUV序列播放
提取yuv
ffplay -f rawvideo -video_size 960x400 out.yuv
提取pcm
ffmpeg -i oceans.mp4 -vn -ar 44100 -ac 2 -f s16le out.pcm
播放
fflpay -ar 44100 -ac 2 -f s16le out.pcm
ffplay -f rawvideo -video_size 1920x1080 input.yuv
8.YUV序列转AVI
ffmpeg –s w*h –pix_fmt yuv420p –i input.yuv –vcodec mpeg4 output.avi
常用参数说明:
主要参数:
-i 设定输入流
-f 设定输出格式
-ss 开始时间 视频参数:
-b 设定视频流量,默认为200Kbit/s
-r 设定帧速率,默认为25
-s 设定画面的宽与高
-aspect 设定画面的比例
-vn 不处理视频
-vcodec 设定视频编解码类型,未设定时则使用与输入流相同的编解码类型
音频参数:
-ar 设定采样率
-ac 设定声音的Channel数
-acodec 设定声音编解码类型,未设定时则使用与输入流相同的编解码类型,
-an 不处理音频
9、视频裁剪
画面裁剪
corp=out_w:out_h:x:y
ffmpeg -i oceans.mov -vf crop=in_w-100:in_h-100 -c:v libx264 -c:a aac crop_out.mp4
长度裁剪
ffmpeg -i onceans.mp4 -ss 00:00:00 -t 10 out.ts
ffmpeg -i onceans.mp4 -ss 00:00:00 -t 00:00:10 out.ts
视频合成
视频转图片
ffmpeg -i movie.mp4 -r 1 -f image2 images/icon_%3d.jpeg
图片转视频
ffmpeg -i images/icon_%3d.jpeg movie_images.mp4
----------------------------------------------------
0.压缩转码mp4文件
ffmpeg -i input.avi -s 640x480 output.avi
ffmpeg -i input.avi -strict -2 -s vga output.avi
1、将文件当做直播送至live
ffmpeg -re -i localFile.mp4 -c copy -f flv rtmp://server/live/streamName
2、将直播媒体保存至本地文件
ffmpeg -i rtmp://server/live/streamName -c copy dump.flv
3、将其中一个直播流,视频改用h264压缩,音频不变,送至另外一个直播服务流
ffmpeg -i rtmp://server/live/originalStream -c:a copy -c:v libx264 -vpre slow -f flv rtmp://server/live/h264Stream
4、将其中一个直播流,视频改用h264压缩,音频改用faac压缩,送至另外一个直播服务流
ffmpeg -i rtmp://server/live/originalStream -c:a libfaac -ar 44100 -ab 48k -c:v libx264 -vpre slow -vpre baseline -f flv rtmp://server/live/h264Stream
5、将其中一个直播流,视频不变,音频改用faac压缩,送至另外一个直播服务流
ffmpeg -i rtmp://server/live/originalStream -acodec libfaac -ar 44100 -ab 48k -vcodec copy -f flv rtmp://server/live/h264_AAC_Stream
6、将一个高清流,复制为几个不同视频清晰度的流重新发布,其中音频不变
ffmpeg -re -i rtmp://server/live/high_FMLE_stream -acodec copy -vcodec x264lib -s 640×360 -b 500k -vpre medium -vpre baseline rtmp://server/live/baseline_500k -acodec copy -vcodec x264lib -s 480×272 -b 300k -vpre medium -vpre baseline rtmp://server/live/baseline_300k -acodec copy -vcodec x264lib -s 320×200 -b 150k -vpre medium -vpre baseline rtmp://server/live/baseline_150k -acodec libfaac -vn -ab 48k rtmp://server/live/audio_only_AAC_48k
7、功能一样,只是采用-x264opts选项
ffmpeg -re -i rtmp://server/live/high_FMLE_stream -c:a copy -c:v x264lib -s 640×360 -x264opts bitrate=500:profile=baseline:preset=slow rtmp://server/live/baseline_500k -c:a copy -c:v x264lib -s 480×272 -x264opts bitrate=300:profile=baseline:preset=slow rtmp://server/live/baseline_300k -c:a copy -c:v x264lib -s 320×200 -x264opts bitrate=150:profile=baseline:preset=slow rtmp://server/live/baseline_150k -c:a libfaac -vn -b:a 48k rtmp://server/live/audio_only_AAC_48k
8、将当前摄像头及音频通过DSSHOW采集,视频h264、音频faac压缩后发布
ffmpeg -r 25 -f dshow -s 640×480 -i video=”video source name”:audio=”audio source name” -vcodec libx264 -b 600k -vpre slow -acodec libfaac -ab 128k -f flv rtmp://server/application/stream_name
9、将一个JPG图片经过h264压缩循环输出为mp4视频
ffmpeg.exe -i INPUT.jpg -an -vcodec libx264 -coder 1 -flags +loop -cmp +chroma -subq 10 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -flags2 +dct8x8 -trellis 2 -partitions +parti8x8+parti4x4 -crf 24 -threads 0 -r 25 -g 25 -y OUTPUT.mp4
10、将普通流视频改用h264压缩,音频不变,送至高清流服务(新版本FMS live=1)
ffmpeg -i rtmp://server/live/originalStream -c:a copy -c:v libx264 -vpre slow -f flv “rtmp://server/live/h264Stream live=1〃
1.采集usb摄像头视频命令:
ffmpeg -t 20 -f vfwcap -i 0 -r 8 -f mp4 cap1111.mp4
./ffmpeg -t 10 -f vfwcap -i 0 -r 8 -f mp4 cap.mp4
具体说明如下:我们采集10秒,采集工具为vfwcap类型设备,第0个vfwcap采集工具(如果系统有多个vfw的视频采集工具,可以通过-i num来选择),每秒8帧,输出方式为文件,格式为mp4。
2.最简单的抓屏:
ffmpeg -f gdigrab -i desktop out.mpg
3.从屏幕的(10,20)点处开始,抓取640x480的屏幕,设定帧率为5 :
ffmpeg -f gdigrab -framerate 5 -offset_x 10 -offset_y 20 -video_size 640x480 -i desktop out.mpg
4.ffmpeg从视频中生成gif图片:
ffmpeg -i capx.mp4 -t 10 -s 320x240 -pix_fmt rgb24 jidu1.gif
5.ffmpeg将图片转换为视频:
http://blog.sina.com.cn/s/blog_40d73279010113c2.html
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
2019阿里云云上Hi购季活动已经于2月25日正式开启,从已开放的活动页面来看,活动分为三个阶段: 2月25日-3月04日的活动报名阶段、3月04日-3月16日的新购满返+5折抢购阶段、3月16日-3月31日的续费抽豪礼+5折抢购阶段。
做为整个Hi购季非常重要的一个分会场——云通信会场,今日开放售卖!
下面,云栖社区小编就为各位开发者分享该会场的攻略:
丨云通信会场活动阵地: https://promotion.aliyun.com/ntms/act/product-section-2019/communication.html
丨关键词:短信套餐包、0.028元/条、新人礼包、套餐折上折
丨该会场必买爆款清单
一、国内通用套餐包
1.活动对象
满足以下条件的阿里云用户:阿里云官网已实名认证的注册会员用户。
2.活动时间
2019年2月25日-2019年3月31日
3.活动规则
1)活动期间,用户通过相关具体活动页面,按照活动规则参与活动的可享受相应的代金券满减优惠待遇。
2)满减代金券具体优惠内容如下:
活动期间,短信套餐包订单金额满1800减100,满17000减1000,满32000减2000,满90000减6000。
3)用户参加活动所购买的相关产品及所获得的相应权益,仅限本账号使用,不得转让、出售或以其他方式换取利益。
4)活动期间,阿里云新老客户均可领取。同一用户同一面额满减券仅限领取一张。
5)满减券仅限在国内通用短信套餐包购买时使用,购买内通用短信套餐包时直接减免。每个订单只能使用一张满减券。
6)除特殊情况外,用户参加本活动购买的产品,不支持退订。如因特殊原因发生退订的,退订前需交回通过本活动所享受的相关权益,例如:补足差价、退还已使用的代金券金额、交回奖品等。
7)如用户在活动中存在隐瞒、虚构、作弊、欺诈或通过其他非正常手段规避活动规则、获取不当利益的行为,例如:作弊领取、网络攻击、虚假交易等,阿里云有权收回相关权益、取消用户的活动参与资格,撤销违规交易,必要时追究违规用户的法律责任。
8)活动名称仅为方便用户理解参考使用,不具有效力,实际活动内容以具体活动规则为准。
二、云通信新人礼包
①个人版新人礼包,支付9.9元即可获得400条国内短信包。
②企业版新人礼包,支付19.9元即可获得700条国内短信+30条国际短信+30分钟语音通知 +30分钟号码隐私保护通话时长+30兆物联网+5000次号码认证。
三、物联网无线连接服务
以下4款产品享75折优惠,其他物联网产品享9折优惠
四、场景套餐折上折
(一)社区服务通信场景
居民在手机上使用短信验证码服务或号码认证服务成功注册并登录社区服务APP,同时完成下单。 社区服务云端系统获取下单信息,然后以语音通知或短信通知方式,将订单发送给提供服务的商家。 服务提供商接单后,通过号码隐私保护服务隐藏双方号码,与终端用户互相联系。
其他场景
可广泛应用于电商、物流外卖、中介服务、用车出行等场景。
套餐点此查看: https://promotion.aliyun.com/ntms/act/product-section-2019/communication.html
(二)物联网通信场景
产品描述
物联网流量卡及模组合约是云通信基于物联网行业场景进行的流量卡和模组合约套餐服务,总补贴金额3000万,预购从速。
建议使用场景
充电桩、智能售货机、GPS行业、多媒体。
活动声明
模组补贴金额有限,所以属于预订业务,发货周期在3周左右。
套餐点此查看: https://promotion.aliyun.com/ntms/act/product-section-2019/communication.html
五、狂欢已“种草”,有问题咨询怎么办?
面对如此折扣力度,丰富的促销活动,如果有问题建议一定要提前向云小二询问,避开购买高峰期,售前咨询:95187转1。云小二会为大家提供全方位的购买咨询、精准的配置推荐 、灵活的价格方案、1对1的贴心服务。
原文链接
本文为云栖社区原创内容,未经允许不得转载。
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
基本介绍
经常遇到一些开发者问:
1.我们播放的时候,会有黑边怎么处理?尤其是在类似于抖音,直播这样的场景下,如果视频有黑边,很影响画面的视觉效果。而阿里云播放器提供了缩放功能,用来去除黑边,达到视频全屏的效果。
2.直播时摄像头采集经常会遇到反向的问题,就是采集出来的视频画面中的字是反的,对于这种情况怎么处理呢?阿里云播放器提供了镜像的功能,可以水平和垂直镜像,让画面变成你想要的样子。
3.对一些横屏拍摄的视频同时我们提供了旋转功能,可以选择90、270度,旋转之后就可以实现全屏渲染了。
渲染模式设置
Android接口
播放器提供了 setVideoScalingMode 方法提供去改变画面的大小。它可以设置两种方式:
1. VIDEO_SCALING_MODE_SCALE_TO_FIT
按照视频的宽高比,放到SurfaceView(TextureView)中。不会剪裁视频画面,画面的内容是完整的。比如我的SurfaceView是1920:1080的,然后播放一个1280x720的视频,如果使用FIT模式,最终显示的话,播放器把1280x720这个视频按照原始比例放大,直到宽或者高跟SurfaceView的宽或者高一直,最终只有上下有黑边或者左右有黑边。
2. VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
按照视频的宽高比,将画面铺满SurfaceView(TextureView)中。此时会剪裁视频的画面,可能两边有部分内容不会被显示。crop方式肯定是没有黑边的。 播放器默认的缩放效果为:VIDEO_SCALING_MODE_SCALE_TO_FIT。
VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING 是以牺牲画面的完整性为代价,从而实现了没有黑边。所以,当画面的宽高比与实际的宽高比相差太大时,不太合适使用此配置。
我们来看具体的显示效果,比如播放一个竖屏的视频。
1.设置VIDEO_SCALING_MODE_SCALE_TO_FIT。即按照视频的宽高比,放到SurfaceView(TextureView)中。 if (aliyunVodPlayer != null) { aliyunVodPlayer.setVideoScalingMode(IAliyunVodPlayer.VideoScalingMode.VIDEO_SCALING_MODE_SCALE_TO_FIT); }
可以看到,有明显的黑边,但是画面会被完整的显示出来。
2.设置VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING。即:按照视频的宽高比,将画面铺满SurfaceView(TextureView)中。 if (aliyunVodPlayer != null) { aliyunVodPlayer.setVideoScalingMode(IAliyunVodPlayer.VideoScalingMode.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING); }
可以看到,黑边没有了,但是画面的部分内容已经看不到了。
iOS接口
iOS提供了一个属性来获取和设置渲染模式 @property(nonatomic, readwrite) ScalingMode scalingMode; enum { scalingModeAspectFit = 0, scalingModeAspectFitWithCropping = 1, }; typedef NSInteger ScalingMode;
和Android类似,scalingModeAspectFit对应Android的VIDEO_SCALING_MODE_SCALE_TO_FIT,scalingModeAspectFitWithCropping对应Android的VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING,具体接口说明和效果和Android一样,在这里不在赘述。
镜像设置
iOS接口
iOS提供了如下接口来实现镜像的设置,支持水平和垂直镜像。 -(void) setRenderMirrorMode:(RenderMirrorMode)mirrorMode; enum { renderMirrorModeNone = 0, renderMirrorHorizonMode, renderMirrorVerticalMode, }; typedef NSInteger RenderMirrorMode;
水平镜像
垂直镜像
Android接口 public void setRenderMirrorMode(VideoMirrorMode mirrorMode); enum VideoMirrorMode { VIDEO_MIRROR_MODE_NONE(0), VIDEO_MIRROR_MODE_HORIZONTAL(1), VIDEO_MIRROR_MODE_VERTICAL(2); }
旋转设置
iOS接口
iOS提供了如下接口来实现旋转的设置,旋转支持0、90、180、270度的旋转。 -(void) setRenderRotate:(RenderRotate)rotate; enum { renderRotate0 = 0, renderRotate90 = 90, renderRotate180 = 180, renderRotate270 = 270, }; typedef NSInteger RenderRotate;
Android接口 public void setRenderRotate(VideoRotate rotate); public static class VideoRotate { public static VideoRotate ROTATE_0 = new VideoRotate(0); public static VideoRotate ROTATE_90 = new VideoRotate(90); public static VideoRotate ROTATE_180 = new VideoRotate(180); public static VideoRotate ROTATE_270 = new VideoRotate(270); }
原文链接
本文为云栖社区原创内容,未经允许不得转载。
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
blob 其实是 h5 表征的 Blob 对象数据,具体请看 文档 。我们可以使用 Blob 对象隐藏真实的资源路径,在一定程度上可以起到数据的加密性,更多的是为了干扰爬虫。
比如日常使用的一些音频,视频,图片,我们都可以使用其 Blob 二进制数据流来表征数据,而非使用 uri,就像经常用到的 image src 的 dataUrl。
要使用 blob 来表征数据资源,需做到以下两点:
1、服务端返回的为资源的二进制数据
2、前端接收到二进制数据后,使用 URL.createObjectURL(blobData) 方法将服务端返回的二进制数据转换为 blob 的 url 资源挂载到相应的资源对象。
实例
对 video.mp4 资源加密,不使用静态 url 进行加载,使用 blob url 进行加密。
服务端 index.php 前端 index.html
Blob Url
这样真是的视频资源静态地址就可以被隐藏掉了
我们只是实例讲解下如何生成 blob 资源地址,生产中是很少会将一个资源以二进制流的方式返回给前端进行 Blob “加密”的,因为服务端需要将相应的资源打开读取,会消耗对应的内存,比如一个视频如果50M,那我们服务端返回其二进制数据时,就要消耗 50M 的服务器内存将文件载入,然后返回给前端,这代价略大,而且网络传输相应速度也不允许,如果返回个 500M 的二进制数据,估计就会有很大的卡顿了。
生产场景往往是对切片格式的视频 m3u8 地址进行 blob 格式处理,其实并不是为了加密,因为浏览器还是会解析 blob 并去 get 请求对应的 m3u8 地址,使用 blob uri 的好处在于可以在一定层度上干扰爬虫。 「深度学习福利」大神带你进阶工程师,立即查看>>>
「推荐」萌新如何绘制一个完整的动漫人物? 画动漫最基础你要了解人体结构知识,(注:打草稿用块面比较好理解~)
起草稿,轻松就好。投入点感情,不要有太多束缚和压力,来点走心即可!补齐大概的东西,然后就阔以勾线啦~人体实在渣到矬的阔爱们,推荐你们去祥细了解人体结构知识来补救一下吧!
有好的草稿画线也能轻松点,如果草稿起的不好,我宁愿Ctrl+Delete都不想去勾线!!草稿到线稿,这个过程推荐大家把草稿图层降低不透明在新图层上来进一步描线和添加细节。
勾完线就阔以上色啦~线稿正片叠底然后在新建几个图层分层铺色(注:分层一定要备注好,怎么分层就看个人喜好啦,我喜欢由内覆外:皮肤一层,衣服一层,头发一层,同色系一层。分完层之后,再将图层保护不透明勾上。这样一来图层上色方便快捷,不会导致涂得很乱)
不备注好真令人头大
分层上色实在痛苦,在此给阔爱们推荐一个快捷的小技巧,选定你之前线稿图层,图层选项上有这么一个选项!就是用来指定选取来源!勾选它!你再从线稿图层下新建一个分层上底色图层,然后再点油漆桶(勾选油漆桶的同时你要注意这几个问题:1、确定是在新的图层上填充
2、确定所在填充区域线稿是封闭的 3、填充也不是万能的填不到的地方需要自己补补)
还有如果你画的线稿毛毛躁躁断断续续的,请放弃这个办法!苦逼的 一笔一笔填.......
.
铺完底色以后就可以轻松上色了,上色的时候要切忌不要就一个图层画的太过深入!分图层的原因不是要你一层层画好!整体刻画才能把握好色调。阔以先大概的将明暗关系冷暖色调铺一下!如果不知道色彩关系的阔爱们,去查阅相关资料
举个列子: 这张图的裙底为啥用紫色?因为紫色是黄色的对比色。能让黄色突出!对比更强烈而且紫色具有丰富的神秘感!
接下来就逐步深入刻画了,画的时候脑子里一定要具备的色彩关系意识!要有明暗关系意识等等!!!
最后一步就是调整啦!合并图层用PHOTOSHOP曲线色介什么调整色调
「深度学习福利」大神带你进阶工程师,立即查看>>>
给图片加上滤镜,实现图片处理各种效果,例如:旧照片处理、曝光处理、亮度处理、饱和度处理等等滤镜效果。感兴趣的朋友可以下载学习看看
效果图
点击 实现图片处理各种效果工具源码 IOS版 观看。
「深度学习福利」大神带你进阶工程师,立即查看>>>
下载Infragistics Ultimate UI for WPF最新版本
Infragistics Ultimate UI for WPF 是一款提供高速的网格和图表,轻松创建仿Office应用程序的WPF界面框架,从广度和深度两方面使得开发者在缩短开发时间的同时能够为市场构建出现代化的,引领潮流的应用程序。
Infragistics Ultimate UI for WPF 18.2 发布,拥有很多新特性。
Excel引擎
已经有很多功能来满足图表需求,还有更好的将把业务线WPF应用程序带到下一个级别。
波形图
火花线是工作表单元格中的一个小图表,它提供了数据的可视化表示。火花线可以用来显示一系列数值的趋势,如季节性的增减和经济周期;它们也可以用来突出最大值和最小值。在工作表数据中显示趋势可能是有用的,尤其是在与其他人共享数据时。
随着18.2的发布,现在可以使用Infragistics Excel Library将一行代码添加到Excel文档中。
有了Infragistics工作表的实例后,只需调用SparklineGroups集合上的Add方法。提供用户希望创建的火花线的类型(列、线或堆栈),提供用户希望插入火花线的单元格,然后提供表示火花线将使用的数据的单元格范围。
在创建了火花线之后,Infragistics Excel Library为用户提供了一个直观的API,用户可以使用它来设置火花线的各个方面的样式,以满足可视化需求。API允许用户启用和控制高、低点、负点、第一点、最后一点和所有标记的颜色。
这些样式点与Microsoft Excel的上下文“Design”选项卡对齐,当在Excel中选择火花线时将显示该选项卡。
图表支持
在Excel库中添加图表支持来展示。通过支持70种不同的图表类型,现在可以创建仪表板报告,以清晰、易于理解的方式可视化数据。这个全新的Excel Charting API使用户能够完全控制图表的呈现方式,包括图例、标题、轴标题以及大量的样式选项,如网格线、勾号、颜色等等。你完全掌握了Excel图表的能力。用户甚至不需要安装MS Excel!
向Excel文档添加图表很容易。
使用Infragistics Excel Library,创建或获取工作表对象的实例,然后简单地调用Shapes集合上的AddChart方法。提供用户希望创建的图表类型(从70中选择),提供图表的大小和位置,然后提供数据和任何其他要应用于图表的格式设置。
因为我们正在创建本地Excel图表,所以当用户在Excel中打开文档并选择图表时,用户将获得“Design”和“Format”上下文选项卡,如果要在MS Excel中直接创建图表,用户将获得这些选项卡。
「深度学习福利」大神带你进阶工程师,立即查看>>>
1、用策略模式比较颜色
策略设计模式是一种面向对象的设计模式。这种模式尽可能地将算法的复杂性隐藏在一个直观的编程借口后面,更有利于算法的部署。
注意:在现代体系中,浮点数的欧几里得距离的计算速度比(RGB差值的绝对值)进行累加。
2、计算向量的欧几里得范数的函数
return static_cast(cv::Vec3i(color[0]-target[0],color[1]-target[1],color[2]-target[2])));
3、 cv::saturate_cast函数 。计算像素时会自动调用这个函数,保证像素值在0-255。
4、 threshold(output,output,maxDist,255,cv::THRESH_BINARY_INV)
这个函数通常用于将所有像素与某个阈值(第三个参数)进行比较,并在常规阈值化模式(THRESH_BINARY)下,将所有大于指定阈值的像素赋值为预定的最大值,。将其他像素赋值为0。这里用了THRESH_BINARY_INV。
一般来说,直接使用OPENCV函数,可以快速建立复杂程序,减少潜在错误,而且程序的运行效率通常也较高。 不过这样做会执行很多中间步骤,消耗更多内存。
5、 floodFill函数——找出与指定颜色接近的像素
floodFill函数的做法在判断一个像素时,还要检查附近像素的状态,这是为了识别某种颜色的相关区域。用户只需要指定一个起始位置和允许的误差,就可以找出颜色相近的连续区域。
cv::floodFill(image,//输入、输出图像
Point(100,50),起始点(与这个点比较,找这个点像素的近似)
Scalar(255,255,255),填充颜色
Rect* 0,填充区域的边界矩形(绘制的颜色,这里是白色)
Scalar(35,35,35),偏差的最小、最大阈值
Scalar(35,35,35),正差阈值,两个阈值通常相等
FLOODFILL_FIXED_RANGE);与起始点像素比较
颜色接近的像素会被重新绘制成第三个参数指定的新颜色。
定义比参考色更高或更低的值作为阈值。
6、 GrabCut算法分割图像
从 静态图像中提取前景物体 ,使用GrabCut算法。
Mat result;
Mat bgModel,fgModel;
grabCut(image,//输入图像
result,分割结果
rectangle,包含前景的矩形
bgModel,fgModel,模型
5,迭代次数
GC_INIT_WITH_RECT); 使用矩形
这里,使用GC_INIT_WITH_RECT参数表示使用带边框的矩形模型。输入/输出的分割图像可以是以下四个值:
GC_BGD//明确属于背景的像素
GC_FGD明确属于前景的像素
GC_PR_BGD可能属于背景的像素
GC_PR_BGD可能属于前景的像素
调用这个函数之后,取得结果方式:
compare(result,GC_PR_FGD,result,CMP_EQ);
foreground(image.size(),CV_8UC3,Scalar(255,255,255);
image.copyTo(foreground,result);
实现原理:把所有未标记的像素临时标记为前景,基于当前的分类情况,算法把像素划分为多个颜色相近的组,引入前景和背景像素之间的边缘,确定背景前景的分割。在此过程中,将试图连接具有相似标记的像素,并且避免边缘出现在强度相对均匀的区域。
把问题表示成一幅连同的矩形,然后在图形上分割,以形成最优的解决方案。分割完毕后,像素会有新的标记,然后重复这个分组过程,找到最优的分割方案。
「深度学习福利」大神带你进阶工程师,立即查看>>>
光线跟踪方法
基本光线跟踪算法
光线与对象表面的求交计算
光线-球面求交
光线-多面体求交
减少对象求交计算量
空间分割方法
模拟照相机的聚焦效果
光线跟踪反走样
分布式光线跟踪
「深度学习福利」大神带你进阶工程师,立即查看>>>
1.下载
wget https://www.imagemagick.org/download/ImageMagick-7.0.8-13.tar.gz
2. 解压刚才下载的文件:
tar xvf ImageMagick-7.0.8-13.tar.gz
3.进入解压目录:
cd ImageMagick-7.0.8-13
4.检查配置:
./configure
如果发现没有安装jpeg,则必须先安装jpeg
5.安装jpeg:
yum install libjpeg* libpng* freetype* gd*
6.安装ImageMagick
make install
输入convert -resize 100x100 src.jpg des.jpg 执行成功,表明安装成功。
「深度学习福利」大神带你进阶工程师,立即查看>>>
新建控制台应用 #include
#include #include #include qint64 du(const QString &path) { QDir dir(path); // if(dir.exists()){ // if(dir.isAbsolute()){ // qDebug() << "绝对路径" << "总条目(文件、目录、符合链接)" << dir.count(); // qDebug() << "目录下所有条目" << dir.entryList(); // } // } qint64 size = 0; foreach(QFileInfo fileInfo,dir.entryInfoList(QDir::Files)) //获取dir下面文件目录的大小 { size += fileInfo.size(); } foreach(QString subDir,dir.entryList(QDir::Dirs|QDir::NoDotAndDotDot)) { size += du(path+QDir::separator()+subDir); } char unit ='B'; qint64 curSize=size; if(curSize>1024) { curSize/=1024; unit ='K'; if(curSize>1024) { curSize/=1024; unit ='M'; if(curSize>1024) { curSize/=1024; unit ='G'; } } } qDebug()<1) { path = args[1]; } else { path = QDir::currentPath(); } qDebug()<「深度学习福利」大神带你进阶工程师,立即查看>>>
1、NAL全称Network Abstract Layer, 即网络抽象层。
在H.264/AVC视频编码标准中,整个系统框架被分为了两个层面:视频编码层面(VCL)和网络抽象层面(NAL)。其中,前者负责有效表示视频数据的内容,而后者则负责格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传输。因此我们平时的每帧数据就是一个NAL单元(SPS与PPS除外)。在实际的H264数据帧中,往往帧前面带有00 00 00 01 或 00 00 01分隔符,一般来说编码器编出的首帧数据为PPS与SPS,接着为I帧……
如下图:
2、如何判断帧类型(是图像参考帧还是I、P帧等)?
NALU类型是我们判断帧类型的利器,从官方文档中得出如下图:
我们还是接着看最上面图的码流对应的数据来层层分析,以00 00 00 01分割之后的下一个字节就是NALU类型,将其转为二进制数据后,解读顺序为从左往右算,如下:
(1)第1位禁止位,值为1表示语法出错
(2)第2~3位为参考级别
(3)第4~8为是nal单元类型
例如上面00000001后有67,68以及65
其中0x67的二进制码为:
0110 0111
4-8为00111,转为十进制7,参考第二幅图:7对应序列参数集SPS
其中0x68的二进制码为:
0110 1000
4-8为01000,转为十进制8,参考第二幅图:8对应图像参数集PPS
其中0x65的二进制码为:
0110 0101
4-8为00101,转为十进制5,参考第二幅图:5对应IDR图像中的片(I帧)
所以判断是否为I帧的算法为: (NALU类型 & 0001 1111) = 5 即 NALU类型 & 31 = 5
比如0x65 & 31 = 5
http://blog.csdn.net/evsqiezi/article/details/8492593
帧格式
H264帧由NALU头和NALU主体组成。
NALU头由一个字节组成,它的语法如下:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
F: 1个比特.
forbidden_zero_bit. 在 H.264 规范中规定了这一位必须为 0.
NRI: 2个比特.
nal_ref_idc. 取00~11,似乎指示这个NALU的重要性,如00的NALU解码器可以丢弃它而不影响图像的回放,0~3,取值越大,表示当前NAL越重要,需要优先受到保护。如果当前NAL是属于参考帧的片,或是序列参数集,或是图像参数集这些重要的单位时,本句法元素必需大于0。
Type: 5个比特.
nal_unit_type. 这个NALU单元的类型,1~12由H.264使用,24~31由H.264以外的应用使用,简述如下:
0 没有定义
1-23 NAL单元 单个 NAL 单元包
1 不分区,非IDR图像的片
2 片分区A
3 片分区B
4 片分区C
5 IDR图像中的片
6 补充增强信息单元(SEI)
7 SPS
8 PPS
9 序列结束
10 序列结束
11 码流借宿
12 填充
13-23 保留
24 STAP-A 单一时间的组合包
25 STAP-B 单一时间的组合包
26 MTAP16 多个时间的组合包
27 MTAP24 多个时间的组合包
28 FU-A 分片的单元
29 FU-B 分片的单元
30-31 没有定义
AUD
一般文档没有对AUD进行描叙,其实这是一个帧开始的标志,字节顺序为:00 00 00 01 09 f0
从结构上看,有start code, 所以确实是一个NALU,类型09在H264定义里就是AUD(分割器)。大部分播放器可以在没有AUD的情况下正常播放。
紧随AUD,一般是SPS/PPS/SEI/IDR的组合或者简单就是一个SLICE,也就是一个帧的开始。像Flash这样的播放器,每次需要一个完整的帧数据,那么把2个AUD之间的数据按照格式打包给播放器就可以了。
H.264编码时,在每个NAL前添加起始码 0x000001,解码器在码流中检测到起始码,当前NAL结束。为了防止NAL内部出现0x000001的数据,h.264又提出'防止竞争 emulation prevention"机制,在编码完一个NAL时,如果检测出有连续两个0x00字节,就在后面插入一个0x03。当解码器在NAL内部检测到0x000003的数据,就把0x03抛弃,恢复原始数据。
0x000000 >>>>>> 0x00000300
0x000001 >>>>>> 0x00000301
0x000002 >>>>>> 0x00000302
0x000003 >>>>>> 0x00000303
总的来说H264的码流的打包方式有两种,一种为annex-b byte stream format 的格式,这个是绝大部分编码器的默认输出格式,就是每个帧的开头的3~4个字节是H264的start_code,0x00000001或者0x000001。
另一种是原始的NAL打包格式,就是开始的若干字节(1,2,4字节)是NAL的长度,而不是start_code,此时必须借助某个全局的数据来获得编 码器的profile,level,PPS,SPS等信息才可以解码。
SPS,PPS的解析
SPS
profile_idc和level_idc是指比特流所遵守的配置和级别。
constraint_set0_flag 等于1是指比特流遵从某节中的所有规定。constraint_set0_flag 等于0是指该比特流可以遵从也可以不遵从某节中的所有规定。当profile_idc等于100、110、122或144时,constraint_set0_flag、constraint_set1_flag和constraint_set2_flag都应等于0。
log2_max_frame_num_minus4的值应在0-12范围内(包括0和12),这个句法元素主要是为读取另一个句法元素 frame_num 服务的,frame_num 是最重要的句法元素之一,它标识所属图像的解码顺序 。这个句法元素同时也指明了 frame_num 的所能达到的最大值: MaxFrameNum = 2*exp( log2_max_frame_num_minus4 + 4 ) 。
pic_order_cnt_type 是指解码图像顺序的计数方法。pic_order_cnt_type 的取值范围是0到2(包括0和2)。
log2_max_pic_order_cnt_lsb_minus4表示用于某节规定的图像顺序数解码过程中的变量MaxPicOrderCntLsb的值,
num_ref_frames规定了可能在视频序列中任何图像帧间预测的解码过程中用到的短期参考帧和长期参考帧、互补参考场对以及不成对的参考场的最大数量。num_ref_frames 的取值范围应该在0到MaxDpbSize。
gaps_in_frame_num_value_allowed_flag 表示某节给出的frame_num 的允许值以及在某节给出的frame_num 值之间存在推测的差异的情况下进行的解码过程。
pic_width_in_mbs_minus1加1是指以宏块为单元的每个解码图像的宽度。
pic_height_in_map_units_minus1 的语义依赖于变量frame_mbs_only_flag,规定如下:-— 如果 frame_mbs_only_flag 等于0,
pic_height_in_map_units_minus1加1就表示以宏块为单位的一场的高度。-— 否则(frame_mbs_only_flag等于1),pic_height_in_map_units_minus1加1就表示
以宏块为单位的一帧的高度。变量 FrameHeightInMbs 由下列公式得出:FrameHeightInMbs = ( 2 – frame_mbs_only_flag ) * PicHeightInMapUnits。
mb_adaptive_frame_field_flag 等于0表示在一个图像的帧和场宏块之间没有交换。mb_adaptive_frame_field_flag 等于1表示在帧和帧内的场宏块之间可能会有交换。当mb_adaptive_frame_field_flag没有特别规定时,默认其值为0。
direct_8x8_inference_flag 表示在某节中规定的B_Skip、B_Direct_16x16和B_Direct_8x8亮度运动矢量的计算过程使用的方法。当frame_mbs_only_flag 等于0时
direct_8x8_inference_flag 应等于1。
frame_cropping_flag 等于1表示帧剪切偏移参数遵从视频序列参数集中的下一个值。frame_cropping_flag 等于0表示不存在帧剪切偏移参数。
vui_parameters_present_flag 等于1 表示存在如附录E 提到的vui_parameters( ) 语法结构。vui_parameters_present_flag 等于0表示不存在如附录E提到的vui_parameters( ) 语法结构。
PPS
seq_parameter_set_id是指活动的序列参数集。变量seq_parameter_set_id的值应该在0到31的范围内(包括0和31)。
entropy_coding_mode_flag 用于选取语法元素的熵编码方式,在语法表中由两个标识符代表,具体如下:如果entropy_coding_mode_flag 等于0,那么采用语法表中左边的描述符所指定的方法。
pic_order_present_flag等于1 表示与图像顺序数有关的语法元素将出现于条带头中,pic_order_present_flag 等于0表示条带头中不会出现与图像顺序数有关的语法元素。
num_slice_groups_minus1加1表示一个图像中的条带组数。当num_slice_groups_minus1 等于0时,图像中所有的条带属于同一个条带组。
num_ref_idx_l0_active_minus1表示参考图像列表0 的最大参考索引号,该索引号将用来在一幅图像中num_ref_idx_active_override_flag 等于0 的条带使用列表0 预测时,解码该图像的这些条带。当MbaffFrameFlag等于1时,num_ref_idx_l0_active_minus1 是帧宏块解码的最大索引号值,而2 *num_ref_idx_l0_active_minus1 + 1是场宏块解码的最大索引号值。num_ref_idx_l0_active_minus1 的值应该在0到31的范围内(包括0和31)。
weighted_pred_flag等于0表示加权的预测不应用于P和SP条带。weighted_pred_flag等于1表示在P和SP条带中应使用加权的预测。
weighted_bipred_idc等于0表示B条带应该采用默认的加权预测。weighted_bipred_idc等于1表示B条带应该采用具体指明的加权预测。weighted_bipred_idc 等于2表示B 条带应该采用隐含的加权预测。
weighted_bipred_idc 的值应该在0到2之间(包括0和2)。
pic_init_qp_minus26表示每个条带的SliceQPY 初始值减26。当解码非0值的slice_qp_delta 时,该初始值在条带层被修正,并且在宏块层解码非0 值的mb_qp_delta 时进一步被修正。pic_init_qp_minus26 的值应该在-(26 + QpBdOffsetY ) 到 +25之间(包括边界值)。
pic_init_qs_minus26表示在SP 或SI 条带中的所有宏块的SliceQSY 初始值减26。当解码非0 值的slice_qs_delta 时,该初始值在条带层被修正。pic_init_qs_minus26 的值应该在-26 到 +25之间(包括边界值)。
chroma_qp_index_offset表示为在QPC 值的表格中寻找Cb色度分量而应加到参数QPY 和 QSY 上的偏移。chroma_qp_index_offset的值应在-12 到 +12范围内(包括边界值)。
deblocking_filter_control_present_flag等于1 表示控制去块效应滤波器的特征的一组语法元素将出现在条带头中。deblocking_filter_control_present_flag 等于0 表示控制去块效应滤波器的特征的一组语法元素不会出现在条带头中,并且它们的推定值将会生效。
constrained_intra_pred_flag等于0 表示帧内预测允许使用残余数据,且使用帧内宏块预测模式编码的宏块的预测可以使用帧间宏块预测模式编码的相邻宏块的解码样值。constrained_intra_pred_flag 等于1 表示受限制的帧内预测,在这种情况下,使用帧内宏块预测模式编码的宏块的预测仅使用残余数据和来自I或SI宏块类型的解码样值。
redundant_pic_cnt_present_flag等于0 表示redundant_pic_cnt 语法元素不会在条带头、图像参数集中指明(直接或与相应的数据分割块A关联)的数据分割块B和数据分割块C中出现。redundant_pic_cnt_present_flag等于1表示redundant_pic_cnt 语法元素将出现在条带头、图像参数集中指明(直接或与相应的数据分割块A关联)的数据分割块B和数据分割块C中。
分包
h264包在传输的时候,如果包太大,会被分成多个片。NALU头会被如下的2个自己代替。
The FU indicator octet has the following format:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
别被名字吓到这个格式就是上面提到的RTP h264负载类型,Type为FU-A
The FU header has the following format:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+---------------+
S bit为1表示分片的NAL开始,当它为1时,E不能为1
E bit为1表示结束,当它为1,S不能为1
R bit保留位
Type就是NALU头中的Type,取1-23的那个值
H.264先进的视频编译码标准
http://blog.csdn.net/gl1987807/article/details/11945357
H.264先进视讯编译码标准
郭其昌/工研院电通所
1. 前言
在2001年12月,ITU-T VCEG与ISO MPEG共同组成联合视讯小组(Joint Video Term,JVT)来研订新的视频压缩格式,此新格式在ITU-T组织中称为H.264,在ISO组织中则纳入MPEG-4 Part-10 (ISO/IEC 14496-10)并命名为Advanced VideoCoding (AVC),通常合并称为H.264/AVC [1],其国际标准的第一版于2003年公布,而增修的第二版也于2005年3月定案。相关研究显示H.264/AVC与MPEG-2及MPEG-4相较之下,无论是压缩率或视讯质量皆有大幅的提升[2],而且H.264/AVC也首次将视讯编码层(Video Coding Layer,VCL)与网络提取层(Network Abstraction Layer,NAL)的概念涵盖进来,以往视讯标准着重的是压缩效能部分,而H.264/AVC包含一个内建的NAL网络协议适应层,藉由NAL来提供网络的状态,可以让VCL有更好的编译码弹性与纠错能力,使得H.264/AVC非常适用于多媒体串流(multimedia streaming)及行动电视(mobile TV)的相关应用。在第一版的标准规范中,H.264/AVC根据使用的编码工具种类来提供三种编码规模(Profile),如表1所示分别为Baseline Profile、Main Profile、Extension Profile,而相对应的影片尺寸与比特率等级由Level 1至Level 5.1,涵盖小画面与高分辨率画面的应用范围。Baseline Profile主要是着眼于低比特率的应用(例如:影像通讯),而且其运算复杂度低,所以也适合应用于个人随身的多媒体拨放机;Main Profile因为有支持交错式影片(interlaced content)的编码,所以适合应用于HDTV数字电视广播,而且非常容易整合在传统的MPEG-2 Transport/Program Stream上来传送H.264/AVC比特流;对于IP-TV或是MOD(Multimedia On Demand)等应用,使用包含高抗错性编码工具(error resilient tools)的Extension Profile即可以满足这些需求。然而,微软公司在2003年将其视频压缩技术向美国的电影电视工程师协会(Society of Motion Picture and Television Engineers,SMPTE)提出公开标准化的申请,并以VC-1(Video Codec 1)为此新标准的命名[3],由于VC-1在高分辨率影片上的表现出色,导致H.264/AVC在DVD Forum与Blu-ray Disc Association的高分辨率DVD影片测试中败阵下来,其主要原因是H.264/AVC使用较小尺寸的转换公式与无法调整的量化矩阵,造成不能完整保留影像的高频细节信息,因此H.264/AVC于2004年展开标准增修的讨论,来纳入称之为Fidelity Range Extensions (FRExt) [4]的新编码工具,并以先前MainProfile为基础来扩充增加4个新的等级(Table 1),期望能够在高分辨率影片的应用上扳回劣势,目前增修的H.264/AVC第二版标准已于2005年3月发表。本文后段将探讨网络提取层的相关特性,接着来说明视讯编码层的原理,最后并讨论H.264/AVC的应用现况。
2. 网络提取层 (Network Abstraction Layer,NAL)
H.264/AVC标准的特色是将网络提取层的概念涵盖进来,亦即以NAL封包为单位的方式来做为VCL编译码的运算单位,这样传输层拿到NAL封包之后不需要再进行切割,只需附加该传输协议的文件头信息(adding header only)就可以交由底层传送出去,如图1所示,可以将NAL当成是一个专作封装(packaging)的模块,用来将VCL压缩过的bitstream封装成适当大小的封包单位(NAL-unit),并在NAL-unit Header中的NAL-unit Type字段记载此封包的型式,每种型式分别对应到VCL中不同的编解碼工具。NAL另外一个重要的功能为当网络发生壅塞而导致封包错误或接收次序错乱(out-of-order)的状况时,传输层协议会在Reference Flag作设定的动作,接收端的VCL在收到这种NAL封包时,就知道要进行所谓的纠错运算(error concealment),在解压缩的同时也会尝试将错误修正回来。如图2所示,一个完整的H.264/AVC bitstream是由多个NAL-units所组成的,所以此bitstream也称之为NAL unit stream,一个NAL unit stream内可以包含多个压缩视讯序列(coded video sequence),一个单独的压缩视讯序列代表一部视讯影片,而压缩视讯序列又是由多个access units所组成,当接收端收到一个access unit后,可以完整地译码成单张的画面,而每个压缩视讯序列的第一个access unit必须为Instantaneous Decoding Refresh (IDR) access unit,IDRaccess unit的内容全是采用intra-prediction编码,所以自己本身即可完全译码,不用参考其他access unit的数据。access unit亦是由多个NAL-units所组成,标准中总共规范12种的NAL-unit型式,这些可以进一步分类成VCL NAL-unit及non-VCL NAL-unit,所谓的VCL NAL-unit纯粹是压缩影像的内容,而所谓的non-VCL NAL-unit则有两种:Parameter Sets与Supplemental Enhancement Information (SEI),SEI可以存放影片简介、版权宣告、用户自行定义的数据…等;Parameter Sets主要是描述整个压缩视讯序列的参数,例如:长宽比例、影像显现的时间点(timestamp)、相关译码所需的参数…等,这些信息非常重要,万一在传送的过程中发生错误,会导致整段影片无法译码,以往像MPEG-2/-4都把这些信息放在一般的packet header,所以很容易随着packet loss而消失,现在H.264/AVC将这些信息独立出来成为特殊的parameter set,可以采用所谓的out-of-band的方式来传送,以便将out-of-band channel用最高层级的信道编码(channel coding)保护机制,来保证传输的正确性。
3. 视讯编码层 (Video Coding Layer,VCL)
视频压缩的原理是利用影像在时间与空间上存有相似性,这些相似的数据经过压缩算法处理之后,可以将人眼无法感知的部分抽离出来,这些称为视觉冗余(visual redundancy)的部分在去除之后,就可以达到视频压缩的目的。如图1所示,H.264/AVC的视讯编码机制是以图块(block-based)为基础单元,也就是说先将整张影像分割成许多矩形的小区域,称之为巨图块(macroblock,MB),再将这些巨图块进行编码,先使用画面内预测(intra-prediction)与画面间预测(inter-prediction)技术,以去除影像之间的相似性来得到所谓的差余影像(residual),再将差余影像施以空间转换(transform)与量化(quantize)来去除视觉冗余,最后视讯编码层会输出编码过的比特流(bitstream),之后再包装成网络提取层的单元封包(NAL-unit),经由网络传送到远程或储存在储存媒体中。H.264/AVC允许视讯影片以frame或是以filed的方式来进行编码,两者可以共存,而frame可以是progress或是interlace形式,对同一段影片来说也可使用两者来混合编码,这个特性与MPEG-2相同。而在影像色彩格式的支持上,H.264/AVC第一版的标准只支持YCrCb 4:2:0取样的方式,而在增修的第二版标准中增加4:2:2与4:4:4取样格式,通常这些格式会被数字电影或HDTV影片所采用。
3.1 H.264/AVC影像格式阶层架构
H.264/AVC的阶层架构由小到大依序是sub-block、block、macroblock、slice、slicegroup、frame/field-picture、sequence。对一个采用4:2:0取样的MB而言,它是由16x16点的Luma与相对应的2个8x8点Chroma来组成,而在H.264/AVC的规范中,MB可再分割成多个16x8、8x16、8x8、8x4、4x8、4x4格式的sub-blocks。所谓的slice是许多MB的集合,而一张影像是由许多slice所组成(图3),slice为H.264/AVC格式中的最小可译码单位(self-decodable unit),也就是说一个slice单靠本身的压缩数据就能译码,而不必依靠其他slice,这样的好处是当传送到远程时,每接收完一笔slice的压缩数据就能马上译码,不用等待整张的数据接收完后才能开始,而且万一传送的过程中发生数据遗失或错误,也只是影响该笔slice,不会对其他slice有所影响,但跟MPEG-2的slice不同处在于它允许slice的范围可以超过一行MB,也就是说H.264/AVC允许整张影像只由单一个slice组成。H.264/AVC的slice架构还有一项特性称为Flexible Macroblock Ordering (FMO),也就是说组成slice的MB可以不必局限于循序扫描(rasterscan)的排列方式,例如:图3最右侧的排法就非常适用于多个前景(foreground) slice groups与一个独自的背景(background) slice group,好处是对不同的slice group可以用不同质量的压缩参数,例如:对于前景物件通常是人眼较感兴趣的区域,可以用较小的压缩率来维持较好的质量。
3.2 Slice的编码模式
H.264/AVC的slice依照编码的类型可以分成下列种类:(1)I-slice: slice的全部MB都采用intra-prediction的方式来编码;(2) P-slice: slice中的MB使用intra-prediction和inter-prediction的方式来编码,但每一个inter-prediction block最多只能使用一个移动向量;(3) B-slice:与P-slice类似,但每一个inter-prediction block可以使用二个移动向量。比较特别的是B-slice的‘B’是指Bi-predictive,与MPEG-2/-4 B-frame的Bi-directional概念有很大的不同,MPEG-2/-4 B-frame被限定只能由前一张和后一张的I(或P)-frame来做inter- prediction,但是H.264/AVC B-slice除了可由前一张和后一张影像的I(或P、B)-slice外,也能从前二张不同影像的I(或P、B)-slice来做inter- prediction,而H.264/AVC另外增加两种特殊slice类型:(1) SP-slice:即所谓的Switching P slice,为P-slice的一种特殊类型,用来串接两个不同bitrate的bitstream;(2) SI-slice: 即所谓的Switching I slice,为I-slice的一种特殊类型,除了用来串接两个不同content的bitstream外,也可用来执行随机存取(random access)来达到网络VCR的功能。这两种特殊的slice主要是考虑当进行Video-On-Demand streaming的应用时,对同一个视讯内容的影片来说,server会预先存放不同bitrate的压缩影片,而当带宽改变时,server就会送出适合当时带宽比特率的影片,传统的做法是需要等到适当的时间点来传送新的I-slice (容量较P-slice大上许多),但因为带宽变小导致需要较多的时间来传送I-slice,如此会让client端的影像有所延迟,为了让相同content但不同bitrate的bitstream可以较平顺地串接,使用SP-slice会很容易来达成(图4),不仅可以直接送出新的bitstream,也因为传送的P-slice的容量较小,所以不会有时间延迟的情形出现。当client端的使用者要切换到新的接收频道(channel)时,因为与目前传送的bitstream不但内容不同连比特率也不同,传统的做法需让client重新缓冲(buffering)一段新频道的内容(图5),此时是为了要接收新频道bitstream的I-slice,然后再开始传送新频道bitstream后续的P-slice,如此client也会发生延迟接收的现象,而且当client要进行所谓的快转、倒转、随机存取(random access)的动作时,传统的做法无法达到实时的反应,H.264/AVC利用SI-slice就可以轻易地达到目的。
3.3画面内预测技术(Intra-frame Prediction)
以往的压缩标准在进行intra-prediction时,多半只是将转换系数做差值编码,而H.264/AVC在空间领域(spatial domain)来进行像点之间的预测,而不是用转换过的系数,它提供两种intra-prediction的型式:intra_4x4及intra_16x16,所谓的intra_4x4是以Luma 4x4 sub-block为单位,找出它的参考对象(predictor)后,再将其与参考对象相减后所产生的差余影像(residual)送入转换算法,而寻找参考对象的模式共有9种预测的方向(图6),以mode 0 (vertical)为例,{a,e,i,m}、{b,f,j,n}、{c,g,k,o}、{d,h,l,p}的参考对象分别为A、B、C、D;Luma intra_16x16与Chroma的模式跟Luma intra_4x4类似,详细的运算公式可以参考[1]。
3.4画面间预测技术(Inter-frame Prediction)
至于横跨每张画面之间的预测技术,H.264/AVC提供了更丰富的编码模式,计有下述几种区块分割(partition)的方法:16x16、16x8、8x16、8x8、8x4、4x8、4x4,多样的分割方式可以让移动向量的预测更准确,如图7所示,画面中有些移动的区域并不是正方形,使用长方形或较小的4x4分割来做预测的区域,可以大幅降低差余影像的数值来增加了压缩比,但也因此P-slice中的MB最多可有16个移动向量(motion vector),而B-slice中的MB最多可拥有32个移动向量,虽然这些会增加移动向量档头(header)的容量,但整体来说对压缩比仍有正面的益处。再者,以往的压缩标准所使用的动态估测(motion estimation),只有使用前一张图像来作为预测的对象,H.264/AVC提供了多重参考图像(multiple reference frames)的概念,使得移动向量不再只限于前后相邻的影像,而是可以跨过多张影像,如图8所示,在时间点t的图块,可以使用t-1到t-2图像中的图块来作为预测的对象,当影片有周期重复性的内容时,例如:背景影像周期性的出现或被遮盖、对象有来回跳动的行为、形状忽大忽小,或是摄影机在拍摄时,因为有多处的取景点,并且摄影画面在取景点之间来回移动,这种情形在球类比赛转播时常出现,这些状况都能得到较好的动态预测结果,因而提高了压缩的效能。
3.5 转换、量化与熵编码算法 (Transform, Quantization, and EntropyCoding)
H.264/AVC的转换算法采用所谓的4x4与8x8整数转换,跟MPEG-2/-4的8x8 DCT(Discrete Cosine Transform)有很大的不同,因为是整数运算的缘故,不像小数运算的DCT有系数还原后无法匹配的问题,而且以4x4的区块大小来进行转换也可减低区块效应的程度。在量化技术方面,H.264/AVC只使用加法与乘法而没有除法运算,有利于集成电路的实现。跟以往MPEG-2/-4的熵编码技术(entropy coding)不同的是,H.264/AVC针对量化过的转换系数与非转换系数数据(文件头数据、移动向量…等),分别使用二个不同的编码法则。非转换系数数据使用单一个的编码表,好处是可以节省编码表所占用的内存空间;针对量化过的转换系数数据来说,不像MPEG-2/-4对每种影像都使用固定的编码表,H.264/AVC使用所谓的内容适应性编码技术(context-adaptive),也就是会根据编码的内容来统计某些代码(code-word)的出现机率,而产生一个最适合于目前影像的编码表,好处是能够提高压缩比,但要使用额外的带宽来传送这些编码表。H.264/AVC内容适应性编码技术有两种:Context Adaptive Variable Length Coding (CAVLC)以及ContextAdaptive Arithmetic Binary Coding (CABAC),CAVLC的基本原理跟MPEG-2/-4的VLC相同,而CABAC的复杂度比CAVLC高,但却可以提供较高的压缩比,尤其是用在压缩交错式的数字电视影片。
3.6 内嵌式去区块效应滤波器(In-Loop De-blocking Filter)
先前有提到H.264/AVC也是一种block-based的压缩方法,所以会有区块效应(blocking-effect)的现象,虽然它采用4x4转换可以稍减区块效应的程度,但是在影像较平滑的区域,仍需依靠去区块效应滤波器来做影像质量的修补。通常去区块效应滤波器分成两种:post filter及in-loop filter,所谓post filter就是在译码的流程之后再进行的,而不在解压缩标准的规范中,好处是厂商可以依应用的复杂度,有弹性地决定滤波器的实现方式,而所谓的in-loop filter就是直接规范在编译码的流程中,虽然会增加复杂度,但由于经过滤波器处理后的影像质量较好,若以此作为画面间预测的参考图像,其预测精确度会大幅的提升,因而增加了压缩比。
4. 结论
由于H.264/AVC在视讯编码算法上的改进,其压缩比及视讯质量与MPEG-2/-4相较下有大幅度的提升,而其NAL概念有助于在有限带宽的传输通道上来传送高质量的视讯内容,此外,对于高画质数字电视或高画质DVD,以H.264/AVC的编码技术都可以很轻易地满足应用需求,但就市场面来看,VC-1标准凭借着微软在PC平台的优势与低价授权的策略,今后将成为H.264/AVC最强大的挑战者。
「深度学习福利」大神带你进阶工程师,立即查看>>>
1、创建QtGUI应用,基类选择QWidget,取消创建界面,类名Anolog Clock
2、analogclock.h头文件: #ifndef ANALOGCLOCK_H #define ANALOGCLOCK_H #include #include class AnalogClock : public QWidget { Q_OBJECT public: AnalogClock(QWidget *parent = 0); ~AnalogClock(); protected: void paintEvent(QPaintEvent *event); }; #endif // ANALOGCLOCK_H
analogclock.cpp: #include "analogclock.h" #include AnalogClock::AnalogClock(QWidget *parent) : QWidget(parent) { QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(update())); timer->start(1000); setWindowTitle(tr("Analog Clock")); resize(200, 200); } void AnalogClock::paintEvent(QPaintEvent *event) { static const QPoint hourHand[3] = { QPoint(7, 8), QPoint(-7, 8), QPoint(0, -40) }; static const QPoint minuteHand[3] = { QPoint(7, 8), QPoint(-7, 8), QPoint(0, -70) }; static const QPoint secondHand[3] = { QPoint(7, 8), QPoint(-7, 8), QPoint(0, -90) }; QColor hourColor(127, 0, 127); QColor minuteColor(0, 127, 127, 191); QColor secondColor(0, 12, 127, 127); int side = qMin(width(), height()); QTime time = QTime::currentTime(); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.translate(width()/2, height()/2); painter.scale(side/200.0, side/200.0); painter.setPen(Qt::NoPen); painter.setBrush(hourColor); painter.save(); painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0))); painter.drawConvexPolygon(hourHand, 3); painter.restore(); painter.setPen(hourColor); //画刻度 for (int i = 0; i < 12; ++i) { painter.drawLine(88, 0, 96, 0); painter.rotate(30.0); } //-----画分钟------- painter.setPen(Qt::NoPen); painter.setBrush(minuteColor); painter.save(); painter.rotate(6.0 * (time.minute() + time.second() / 60.0)); painter.drawConvexPolygon(minuteHand, 3); painter.restore(); painter.setPen(minuteColor); for (int j = 0; j < 60; ++j) { if ((j % 5) != 0) painter.drawLine(92, 0, 96, 0); painter.rotate(6.0); } //-----画秒钟 painter.setPen(Qt::NoPen); painter.setBrush(secondColor); painter.save(); painter.rotate(6.0 * time.second()); painter.drawConvexPolygon(secondHand, 3); painter.restore(); painter.end(); } AnalogClock::~AnalogClock() { }
「深度学习福利」大神带你进阶工程师,立即查看>>>
1、新建QTGUI应用,基类选择QWidget,取消创建界面
2、
添加菜单
#include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) { QMenuBar *menuBar = new QMenuBar(this); QMenu *menu[3]; menu[0] = new QMenu("File"); menu[0]->addAction("Edit"); menu[0]->addAction("View"); menu[0]->addAction("Tools"); menu[1] = new QMenu("Save"); QAction *act[2]; act[0] = new QAction("New", this); act[0]->setShortcut(Qt::CTRL | Qt::Key_A); act[0]->setStatusTip("This is a New menu."); menu[1]->addAction(act[0]); act[1] = new QAction("Open", this); act[1]->setCheckable(true); menu[1]->addAction(act[1]); menu[2] = new QMenu("Print"); menu[2]->addAction("Page Setup"); menu[2]->addMenu(menu[1]); menuBar->addMenu(menu[0]); menuBar->addMenu(menu[2]); menuBar->addMenu(menu[0]); menuBar->setGeometry(0, 0, 600, 40); lbl = new QLabel("",this); lbl->setGeometry(10, 70, 200, 40); connect(menuBar, SIGNAL(triggered(QAction*)), this, SLOT(trigerMenu(QAction*))); } void Widget::trigerMenu(QAction *act) { QString str = QString("Selected Menu : %1").arg(act->text()); lbl->setText(str); }
「深度学习福利」大神带你进阶工程师,立即查看>>>
计数符号
加号、乘号、分子、分母、二分之一的符号
℅⅐⅑⅒⅓⅔⅕⅖⅗⅘⅙⅚⅛⅜⅝⅞↉∟∬∭∮∵∷≌≐≑≒≓≙≚≛≜≝≞≟≦≧⊶⊷⊸⊾⊿⋀⋁╳✕✖✚﹢﹣﹤﹥%+-/=∧∠∩∪°÷≡≥∞∫≤≠∨‰⊥π±√∑²³∴×
单位符号
长度单位,温度的单位,面积单位,摄氏、 华氏符号
℃℉㎎㎏㎜㎝㎞㎡㏄㏎㏑㏒㏕
数字符号
带圆圈的数字符号、带方框的数字符号
ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻ①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⓪❶❷❸❹❺❻❼❽❾❿㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩㊀㊁㊂㊃㊄㊅㊆㊇㊈㊉0123456789
「深度学习福利」大神带你进阶工程师,立即查看>>> 这篇文章可以作为AV1规范中与解码器型号和级别有关的部分的简介,本文的其余部分描述了一些AV1基本概念,AV1解码器模型,并提供了开发它时做出决策的原因。有关解码器模型的更多详细信息,请阅读AV1规范。
文 / Andrey Norkin
原文链接:https://norkin.org/research/av1_decoder_model/
为什么编解码器需要解码器模型
大多数现代视频编解码器都具有某种形式的解码器模型。在MPEG-2中,它被称为视频缓冲验证器(VBV);在H.264 / AVC和HEVC / H.265中,它可以称为假设参考解码器(HRD)。解码器模型提高了互操作性。解码器模型允许确认一个比特流是否可以被一个特定的解码器解码。这些模型还可以向解码器提供关于何时开始解码帧以能够及时显示它的指令。
通常来说,视频解码器声明支持某个配置文件和级别。配置文件可以指定有关比特深度和色度二次采样的视频格式,以及解码器需要支持的以解码比特流的一组编码工具。级别描述了视频比特流的定量特征,例如分辨率,帧速率和比特率。对于视频编解码器生态系统而言至关重要的一点是,表明支持某个级别的解码器是否能够解码符合该级别要求的任何比特流,并且内容提供商和编码器制造商可以检查其生成的流是否符合这些要求。
为了实现这些目标,由开放媒体联盟(AOM)开发的AV1规范定义了与配置文件和级别系统耦合的解码器模型。AV1解码器模型包括平滑/位流缓冲区,解码过程以及对解码后的帧缓冲区的操作。这篇文章可以作为AV1规范中与解码器型号和级别有关的部分的简介。本文的其余部分描述了一些AV1基本概念,AV1解码器模型,并提供了开发它时做出决策的原因。有关解码器模型的更多详细信息,请阅读AV1规范。
AV1比特流的高级结构
在更高级别上,AV1结构以开放比特流单元(OBU)打包。每个OBU都有一个标头,该标头提供标识其有效负载的信息(请参见图1)。可以在AV1视频比特流中出现的OBU类型的示例是序列头OBU,帧头OBU,元数据OBU,时间定界符OBU和图块组OBU。帧OBU由打包到一个OBU中的帧头和图块组OBU组成,以提供一种通用结构的更有效表示,其中帧头数据后紧跟着帧或图块组数据。
根据语法元素show_existing_frame的值,AV1帧头可以分为两种主要类型。
show_existing_frame等于0的帧头是需要解码的常规帧。show_existing_frame等于1的帧头指定了在该帧头中指定的显示时间显示先前解码的帧(由frame_to_show_map_idx表示)的命令。当解码顺序与显示顺序不同时,该机制有助于帧重新排序。
另一个AV1概念是时间单元(TU),它由时间定界符OBU和在此之后且在下一个时间定界符OBU之前的所有OBU组成。TU始终遵循递增的显示顺序。如果未使用可伸缩性,则TU仅包含一个显示帧,即show_existing_frame等于1或show_frame等于1的帧。如果使用了可伸缩性,则TU中来自不同可伸缩层的所有显示帧都对应于相同的呈现时间。 一个TU也可以包含show_frame标志等于0的帧。此类帧会被解码但不会立即显示。它们用于支持如上所述的帧重排序。类似地,也可以发送覆盖帧,该覆盖帧会对先前解码的帧(称为替代参考帧(ARF))与源帧之间的差异进行编码。AV1比特流的这一方面类似于VP9编解码器中的超帧。
在图2中显示出了将比特流划分为时间单元的示例。在该图中,帧编号按照显示顺序编号。比特流使用具有三个时间层的4帧的双向层级预测结构。show_frame等于0的帧显示为青色框,show_frame等于1的帧显示为深绿色框。FrameHdr 2是show_existing_frame标志等于1的帧头,该帧指向先前解码的Frame 2。
平滑缓冲
平滑缓冲器是AV1解码器的一部分,用于存储AV1比特流,直到压缩数据被解码器解码完毕为止。缓冲区由所谓的“漏桶”模型构成。漏桶的类比和编码器的操作有关,在压缩器中,压缩帧被分块转储到缓冲区中,并且数据以恒定速率连续离开缓冲区。解码器缓冲区是编码器之一的对应部分。注意,平滑缓冲器是解码器内部的。通常来说,解码系统会在更高级别上具有其他缓冲区,这些缓冲区不在AV1规范的范围内。从解码器模型的角度来看,可以将较高级别的缓冲区视为传输通道中造成总延迟的一部分。例如,从解码器的角度来看,与自适应流式传输有关的缓冲将被视为传输通道的一部分,在本文中不再讨论。而且,可能经常出现预先准备编码的比特流,而这会使延迟相当长。但是,对于模型而言,这样的长延迟通常不是问题,因为它在方程式中被抵消了。
平滑缓冲区可确保解码器具有足够的内部存储器来存储到达(或读取)的位流的数据。当解码器需要时,它还确保下一帧的压缩数据在缓冲区中。平滑缓冲器的大小限制了瞬时比特率的变化,并限制了帧数据消耗的时序。
AV1解码器模型仅支持可变比特率(VBR)操作模式,而不支持恒定比特率(CBR)模式。解码器模型的VBR模式是一种抽象模式,其中速率在最大级别比特率和零之间交替。听起来可能有限制。但是,此模型足以确保在最坏的情况下确保比特流与解码器功能匹配。
平滑缓冲区充满度随时间变化的示意图如图3所示。时钟从与帧0有关的第一个比特的到达开始。斜线的斜率与比特到达的速率相对应。Removal [i]对应于从缓冲区中删除帧i的数据并开始解码帧i的时刻。注意,可能会有一段时间没有新的比特到达,例如Removal[1]之后的时间。这与编码器没有要发送的位(即编码器缓冲区为空)的时间段匹配。
帧i的removal [i]是根据两种解码模式之一来定义的。在解码调度模式下,这些值在比特流中用信号发送。在资源可用性模式下,根据解码器操作导出Removal [i]。解码的开始,即Removal [0],由两种模式中的变量decoder_buffer_delay确定。
在时间Removal [i]时从解码缓冲区中删除的比特属于可解码帧组(DFG)i,即与帧i − 1相关的最后一个OBU的末尾与与帧i相关的最后一个OBU的末尾之间的所有OBU 。DFG中的OBU可以包括序列头OBU,帧和图块组OBU,帧头OBU和元数据OBU。
DFG i的第一位到达平滑缓冲区由FirstBitArrival [i]确定,该值如下所示:
关于后一个表达式中coder_buffer_delay和decoder_buffer_delay之间关系以及其他有用的信息可以从Ribas-Corbera et al, 2003中找到很好的解释。该模型假设一个编码器具有一个以恒定速率发送比特的平滑缓冲器,并且一个解码器带有一个以该比特率接收比特的平滑缓冲器。通常来说,encoder_buffer_delay和decoder_buffer_delay的作用是确定帧的编码和解码之间的延迟,因此限制了比特流存储在解码器缓冲区中的“窗口”(通过网络/信道进行的传输是排除在外的)。由于缓冲区大小设置为比特流在最大级别比特率下的1秒,因此建议不要将这两个变量的总和超过90 000,这相当于时钟频率的1秒。
当low_delay_mode标志等于1时,解码器在低延迟模式下运行,在该模式下,帧数据在预定的移除时间可能还不在缓冲区,在这种情况下,移除时间会延迟,直到数据到达缓冲区。
除非处于低延迟模式,否则平滑缓冲区不应下溢。平滑缓冲区也不应溢出。这些限制适用于所有一致的比特流。
解码帧缓冲区
帧缓冲器用于存储解码后的帧,以便可以将它们用于帧间预测或之后的显示。AV1定义了一个缓冲池,该缓冲池代表帧缓冲区的存储区域。AV1帧缓冲区的管理示意图如图4所示。AV1规范要求解码器支持10个物理帧缓冲区。帧缓冲器的时隙应能够以对应级别的最大分辨率存储帧。虚拟缓冲器索引(VBI)用于指向图片间预测中的帧。VBI可以在帧缓冲池中存储8个帧索引。并且允许不同的VBI条目指向同一缓冲区。空的VBI条目值为-1。当前帧缓冲区索引(cfbi)将索引存储到正在解码当前帧的帧缓冲区。注意,有一个“额外的”物理帧缓冲区,可用于保存帧以用于显示。
数组DecoderRefCount和PlayerRefCount(图4中的前两行)分别跟踪解码和显示过程是否仍需要帧缓冲区。DecoderRefCount跟踪对VBI中的帧缓冲区的引用数,并由语法元素refresh_frame_flags更新,而当帧在上次演示时已显示时,PlayerRefCount设置为0。空帧缓冲区和相应的计数器在图4中显示为白色方块。
帧缓冲器对视频帧的解码和表示施加了限制,从而限制了编码器可以使用哪些预测结构和帧的重新排序。通常来说,10个帧缓冲区允许支持相当复杂的预测结构。解码器模型在应显示该帧时会验证该帧是否可用,并且在应解码一帧时在缓冲池中有一个空闲位置。
解码过程
AV1解码器模型的解码过程将对平滑缓冲区和解码器帧缓冲区的操作联系在一起。特别地,解码器模型确定何时开始帧解码以及从平滑缓冲器中移除帧比特,这立即使平滑缓冲器的饱和度降低了相应的量。解码器模型还会计算解码何时完成,并将解码后的帧添加到帧缓冲区。它还确定何时为显示输出帧并将其从缓冲区中移除。
AV1的一个特点是广泛使用替代参考帧(ARF),即用作预测参考但从未显示过的帧。此外,AV1在主配置文件中支持参考图片的缩放和可伸缩性。这意味着该模型应适应帧解码所需的不同时间,并支持不同的帧解码和显示速率。请注意,即使H.264和HEVC允许显示不可显示的图片,但这并不是这些编解码器的典型用法,而在AV1中,这是一种典型的使用情况,需要解码器模型很好地支持。
图5中展示了使用ARF进行编码的示例。该图显示了sub-GOP大小为4的双向层级结构编码。可显示的帧显示为灰色矩形。不显示的替代参考帧(ARF),用白色矩形表示。通常,该帧是在相同时间位置的帧的滤波版本,这为帧间预测带来了优势。由于对ARF进行了低通滤波,因此可以使用ARF作为预测因子对覆盖帧(图5中的OL)进行编码。覆盖帧会添加高频和纹理信息。
为了支持替代参考帧和不同分辨率的帧,AV1解码器模型引入了以下功能:
l在解码器中使用不同数量的时间单位并显示时钟节拍的可能性。注意,图5中的显示时钟节拍(DispCT)和解码时钟节拍(DecCT)具有不同的长度,因为解码和显示速率不同。解码器和显示刻度均使用相同的时标,并且时钟已同步l帧不会立即解码,并且根据帧分辨率和其他因素,可以有不同的时间可以看到,图5中的解码和显示时间轴使用了不同的时钟节拍。显然,在显示帧之前需要完成每个帧的解码。为了确保将来有可用的帧,编码器可以使用initial_display_delay_minus_1,该参数对应已解码的帧数减去在显示第一帧之前帧缓冲区中应可用的帧数。此参数相对于解码偏移了显示过程。如果未发信号,则将initial_display_delay_minus_1的值推断为BUFFER_POOL_MAX_SIZE −1。总的显示延迟包括coder_buffer_delay,它与图3中的变量相同,是从第一个比特到达到开始解码帧0之间的时间,即Removal [0]。
解码帧i所需的时间确定为:
TimeToDecode [i] = lumaSamples [i]÷MaxDecodeRate,
其中,MaxDecodeRate以样本/秒为单位进行测量,并由每个解码器级别指定。依次为帧内预测帧计算lumaSamples,如下所示:
lumaSamples [i] = UpscaledWidth [i] * FrameHeight [i]。
UpscaledWidth是使用可选的超分辨率工具后的帧的宽度。对于帧间预测帧,在参考图片重采样的情况下,考虑到来自分辨率更高的帧的可能运动补偿,可以确定此数量,如下所示
lumaSamples [i] = max_frame_width * max_frame_height。
在可伸缩比特流中,将lumaSamples确定为当前可伸缩层的最大宽度和高度的乘积。
除了知道帧解码需要花费多长时间之外,解码器模型还需要确定何时开始解码以及从平滑缓冲区中删除压缩帧,即Removal [i]。关于如何计算Removal [i],AV1具有两种不同的模式。这两种模式是以下描述的资源可用性模式和解码调度模式。
资源可用性模式
在资源可用性模式中,如果在解码的帧缓冲区中有可用的空闲位置,则在完成前一帧解码之后立即解码一帧。否则,在一个位置释放后对帧进行解码。如果比特流低于解码器的最大级别限制,则逐帧解码这些帧,直到它们填满所有可用的帧缓冲区,此后解码速度会减慢。然后,仅在解码的帧缓冲区释放后,才进行下一帧的解码。帧0的删除时间由decoder_buffer_delay确定:
Removal[ 0 ] = decoder_buffer_delay ÷ 90 000
要使用资源可用性模式,应在比特流中设置以下参数:Timing_info_present_flag = 1,decoder_model_info_present_flag = 0,并且equal_picture_interval =1。标志equal_picture_interval等于1表示使用了恒定的帧速率,并且不发送显示时间。而是从帧速率和initial_display_delay_minus_1得出显示时间。解码定时Removal [i]由解码的帧缓冲器可用时的时刻来决定,并且也不发信号通知。一些解码器模型参数在资源可用性模式下采用默认值,例如,encoder_buffer_delay = 20 000,decoder_buffer_delay = 70 000,low_delay_mode_flag = 0。
解码调度模式
在解码调度模式下,除了帧显示时间之外,还在视频比特流中用信号发送解码时间Removal [i]。该模型灵活地定义了何时从平滑缓冲区中删除帧并对其进行解码,以及何时显示该帧。除了使用恒定的帧速率外,该模型还可以通过显式发送帧表示时间来支持变化的帧速率。除此之外,解码器时钟节拍DecCT以及decoder_buffer_delay,encoder_buffer_delay和ScheduledRemovalTiming [i]也以这种解码模式发送信号。
在这种模式下,帧i的计划删除时间如下所示。
ScheduledRemovalTiming [0] = encoder_buffer_delay÷90 000。
ScheduledRemovalTiming [i] = ScheduledRemovalTiming [PrevRap] + buffer_removal_time [i] * DecCT,
其中PrevRap是先前的随机访问点(RAP)。如果帧i对应于RAP,但不是比特流中的第一帧,则PrevRAP对应于先前的RAP。这里的随机访问点是指比特流中的一个位置,可以从中解码该比特流。它通常对应于一个关键帧,并且应包含所有开始解码位流所需的信息,包括序列头。
除非解码器在低延迟模式下运行,否则删除时间与计划的删除时间一致
Removal [i] = ScheduledRemovalTiming [i]。
为了支持可伸缩性,解码器模型针对每个工作点(OP)单独发出信号。工作点与某个可伸缩层的解码及其解码所需的较低可伸缩层有关。比特流中较高的工作点可能需要使用符合较高级别的解码器。
解码器模型的两种模式之间的差异
可以注意到,解码调度模式下的解码器操作是资源可用性模式下的解码器操作的超集。编码器应该有可能用信号通知在资源可用性模式中可能已经导出的相同Removal [i]。解码时间表模式也可以用于控制帧解码时间表。图6示出了当比特流需求低于最大等级能力时的情形。在资源可用性模式下,将帧依次解码,并且当帧缓冲区中没有剩余空闲时隙时,解码速度会变慢。在解码调度模式下,可以以恒定速度解码比特流。注意,当解码器接近其最大能力工作时(例如,比特流接近于等级限制的分辨率和帧率),两种模式下的解码器操作是相似的。
另外,可以使用解码调度模式来更好地控制平滑缓冲区的饱和度(见图7)。该图说明了平滑缓冲区充满度如何随时间变化,取决于参数coder_buffer_delay和decoder_buffer_delay的值。该图使用1920×1080的视频,每秒24帧,编码为4.0级AV1比特流。选择符合8帧分层预测结构的帧大小;该示例已构建,并不代表任何特定的视频编码。最大的平滑缓冲区容量由水平虚线显示。
图7(a)显示了encoder_buffer_delay = 20 000,decoder_buffer_delay = 70 000时随时间变化的缓冲区充满度,它们等于资源可用性模式中使用的默认值。
通过减少coder_buffer_delay,可以更早开始解码,这在图7(b)中通过使用encoder_buffer_delay和decoder_buffer_delay均等于45 000进行了演示。请注意,encoder_buffer_delay与decoder_buffer_delay的总和等于90 000,这对应于1秒,即平滑缓冲区可以保持的最大级别比特率下的比特流持续时间。
通过使用参数coder_buffer_delay = 10000,decoder_buffer_delay = 45000,也可以将缓冲区充满度保持在较低水平,如图7(c)所示。
显示时间
AV1的显示时间通过frame_presentation_time语法元素发出信号。实际的显示时间还取决于InitialPresentationDelay,其计算方式如下:
PresentationTime [0] = InitialPresentationDelay,
PresentationTime [j] = PresentationTime [PrevPresent] + frame_presentation_time [j] * DispCT,
其中,如果前一个RAP是关键帧RAP,则PrevPresent对应于与最后一个关键帧随机接入点(RAP)关联的索引;如果前一个RAP是延迟RAP,则PrevPresent对应于延迟恢复点(即对应于前向关键帧/open-GOP)。延迟的恢复点对应于open-GOP中的关键帧的显示时间。
InitialPresentationDelay依次确定如下:
InitialPresentationDelay =Removal[initial_display_delay_minus_1] + TimeToDecode [initial_display_delay_minus_1]。
换句话说,InitialPresentationDelay是帧缓冲区中存在initial_display_delay_minus_1 + 1个解码帧的时间。
当equal_picture_interval等于1时,使用恒定帧率模式,并且大于0的帧j的显示时间推导如下:
PresentationTime [j] = PresentationTime [j − 1] +(num_ticks_per_picture_minus_1 + 1)* DispCT,
其中PresentationTime [j-1]指的是显示顺序中的前一帧。如上导出PresentationTime [0]。
解码器模型信令
解码器模型参数主要在序列和帧级别上发出信号。序列标头可以包括Timing_info()结构,该结构包含显示时序信息。基本的解码器模型信息位于decoder_model_info()结构中。除此之外,还可以在序列头中用信号发送一个或多个操作点(OP),以实现可伸缩的比特流。每个OP对应于解码该OP所必需的解码器级别,并且可以可选地被分配一组解码器模型参数。
Timing_info()结构包含时间刻度和显示刻度号num_units_in_display_tick中的时间单位数,而coder_model_info()结构包含解码器刻度号num_units_in_decoding_tick中的单位数以及其他解码器模型语法元素的长度。这两个语法元素将DispCT和DecCT变量的持续时间定义为:
DispCT = num_units_in_display_tick÷time_scale,
DecCT = num_units_in_decoding_tick÷time_scale。
operating_parameters_info()结构包含用于操作点的 encoder_buffer_delay 和decoder_buffer_delay 以及低延迟模式标志。如果使用解码器模型,则可以在帧头中为选定的工作点发信号通知以解码时钟节拍为单位的buffer_removal_time。帧头中的temporal_point_info()结构包含frame_presentation_time语法元素,该元素以显示时钟节拍表示信号的显示时间。
AV1等级
在撰写本文时,AV1规范定义了2.0到6.3级,该级别大致涵盖了将视频从426×240 @ 30fps解码到7680×4320 @ 120fps所需的解码器功能。解码器模型将比特流和解码器一致性统一到了一定水平。AV1级别声明支持某种帧分辨率(一帧中的样本数),解码以及显示的采样率。与解码器模型相关的其他级别参数包括最大比特率和帧头速率。级别可以属于两个级别(主级别和高级级别)之一,其中高级级别具有比主级别更高的最大比特率,并且面向专业和特殊应用。
最大比特率直接定义了平滑缓冲区的大小,该平滑缓冲区应能够以最大级别的比特率保持最多1秒的压缩流。由于对一致的比特流不允许缓冲区上溢或下溢,因此这对峰值比特率施加了限制。除此之外,还规定了帧的最小压缩率。
声称符合某个级别的比特流,如果通过解码器模型,则不应违反约束。顺便说一句,相应的解码器应能够解码相同或更低级别的任何顺应性比特流,只要该比特流符合AV1规范(包括通过相应级别的解码器模型测试)即可。
可以在此Wikipedia链接上找到AV1级别的表,尽管通常推荐的来源是AV1规范。
进一步阅读
这篇文章介绍了AV1解码器模型。它还提供了一些有关在开发时进行的设计选择的背景。在AV1规范(https://aomediacodec.github.io/av1-spec/av1-spec.pdf)中可以找到AV1解码器模型的完整描述和更多细节。
「深度学习福利」大神带你进阶工程师,立即查看>>>
不知道什么时候开始,中国出现了南抖音、北快手的互文格局(东市买骏马,西市买鞍鞯…)。刚才提到了,之前比较喜欢刷抖音,对于我这种佛系程序猿,看网上这些整容妹子基本一个样。喜欢抖音主要是两个初衷,学做菜听音乐。朋友之前常说,人家抖音看妹子看的乐呵呵,你看人家做菜也能津津有味,一个人在那儿傻笑…民以食为天,我看到色香味俱全的菜,做的那么好吃的乐呵乐呵还不行么。
抖音捧红了很多人,也让很多本不怎么让大家熟知的歌曲、BGM,经过翻唱、混剪与视频搭配,从而传播大街小巷。什么“若不是你,突然闯进我心里…”亦或者“也许未来遥远在光年之外,我愿守候未知里为你等待…”,成了大家闲时在嘴边哼唱的调调。那么,有没有想过将这些好听的剪辑批量下载下来呢?
Python 链接抖音
python下载抖音内容的帖子网上有一些,但都比较麻烦,需要通过adb连接安卓手机后,模拟操作。我这么懒,这种事儿玩不来…那么,该如何获取抖音内容呢?网上搜了下大概有两种方式,一个是浏览器插件快抖,另外一个是我今天要说的抖音网页版。其实这两者差别不是很大,都是先将抖音内容下载至服务器后,通过开发简单网站配置域名后,让大家访问。让我们来看看 抖音网页版 :
哎哟吼,居然看到了昨天爬虫的“乔奶奶”…当然今天的重点不是视频,而是下载它 全站所有的音乐 !
爬虫实现分析 热歌榜内容
大家先开看看这个抖音热歌榜歌曲,每页20首歌曲,一个55页。但细不细心大家都能发现,很多歌曲存在重复的问题。所以,等下爬虫的时候,我们需要先准备一个music_list,用来识别这首歌曲是否已经下载过了… 网页解析
网页比较简单,一个div中包裹了一个ul>li*20,我们是不是该这样获取:
soup.find('div',{"class":"pull-left"}).find('ul').findAll('a')
如果你说是,那么一定没有好好看我前天整理的文章通过哪吒豆瓣影评,带你分析python爬虫快速入门: https://www. jianshu.com/p/ae38f7607 902 ,我在文章中专门提到了一个小技巧,通过使用attr的属性进行快速解析,那么最快速的获取方式是:
soup.findAll('a', attrs={'onclick': True})
我们只需要获取所有的a标签,切这些标签中包含onclick这个属性即可。 巧用eval
我们解析到的内容通过attr[‘onclick’],可以得到他的属性open1(‘夜’,’ http:// p9-dy.byteimg.com/obj/6 1a20007a98954b0831d ),如何能快速获取歌曲名字和url呢?这里我们需要用到一个eval的小技巧:
index = "open1('夜','http://p9-dy.byteimg.com/obj/61a20007a98954b0831d','')" index[5:] "('夜','http://p9-dy.byteimg.com/obj/61a20007a98954b0831d','')" index_tuple = eval(index[5:]) print(index_tuple, type(index_tuple)) ('夜', 'http://p9-dy.byteimg.com/obj/61a20007a98954b0831d', '') index_tuple[0] '夜' index_tuple[1] 'http://p9-dy.byteimg.com/obj/61a20007a98954b0831d'
ps:今天一个朋友说我写代码没注释,我这是现身说法的告诉你,如何能写出让别人压根看不懂的代码,就是不写注释啊,哈哈!其实,代码我都在文章中一点一点的讲解了,所以没有写,但秉承着害怕大佬们取关的心态,我还是把注释加上吧…
代码实现
总体来说实现比较简单,全部代码如下:
# -*- coding: utf-8 -*- # @Author : 王翔 # @JianShu : 清风Python # @Date : 2019/7/31 23:25 # @Software : PyCharm # @version :Python 3.7.3 # @File : DouYinMusic.py import os import requests from bs4 import BeautifulSoup import threading import time class DouYinMusic: def __init__(self): self.music_list = [] self.path = self.download_path() @staticmethod def download_path(): """ 获取代码执行目录,并在目录下创建Music文件夹 :return Music文件夹全路径 """ base_dir = os.path.dirname(os.path.abspath(__file__)) _path = os.path.join(base_dir, "Music") if not os.path.exists(_path): os.mkdir(_path) return _path def get_request(self, url): """ 封装requests.get方法 如果为网页请求,返回网页内容 否则,解析音乐地址,并返回音乐二进制文件 :param url: 请求url(分网页、音乐两类) :return: 网页内容 & 音乐二进制文件 """ r = requests.get(url, timeout=5) if url.endswith('html'): return r.text else: return r.content def analysis_html(self, html): """ 根据获取的网页内容,解析音乐名称、下载地址 调用音乐下载方法 :param html: 网页内容 """ soup = BeautifulSoup(html, 'lxml') # 根据关键字onclick查找每个下载地址 for tag_a in soup.findAll('a', attrs={'onclick': True}): # 下载格式'("name","link","")',通过eval将str转化为tuple类型 link_list = eval(tag_a['onclick'][5:]) music_name, music_link = link_list[:2] # 因为存在部分重复音乐,故设置判断下载过的音乐跳过 if music_name in self.music_list: continue self.music_list.append(music_name) t = threading.Thread(target=self.download_music, args=(music_name, music_link)) time.sleep(0.5) t.start() def download_music(self, music_name, music_link): """ 解析音乐文件,完成音乐下载 :param music_name: 音乐名称 :param music_link: 下载地址 """ _full_name = os.path.join(self.path, music_name) with open(_full_name + '.mp3', 'wb') as f: f.write(self.get_request(music_link)) print("抖音音乐:{} 下载完成".format(music_name)) def run(self): """ 主方法,用于批量生成url """ for page in range(1,55): url = "http://douyin.bm8.com.cn/t_{}.html".format(page) html = self.get_request(url) self.analysis_html(html) if __name__ == '__main__': main = DouYinMusic() main.run()
来让我们看看效果吧:
网站是通过nginx负载均衡搭建的,有一些链接已经失效了。 最终下载了不重复的592首抖音音乐 。
同样的,大家喜欢可以按照这种方法,尝试下载一下网站的抖音视频。
本文作者华为云 | 清风Python
点击关注,第一时间了解华为云新鲜技术~
「深度学习福利」大神带你进阶工程师,立即查看>>>
怎么通过画中画的方式添加水印?给视频添加水印,已经是社交媒体的必备操作之一。但是大家对于水印的添加方式可能并不了解,甚至很多人的水印都是社交媒体默认的名称水印,今天小编就教大家一个添加水印的新方法。
传统的添加水印是将一张图片添加到视频的某个位置,表明创作者的身份,今天小编要将大家的是使用“画中画”的功能在视频中进行水印添加。打开“清爽视频编辑,”点进首页的“视频编辑,”勾选需要进行水印添加的视频,点击下一步进入编辑页面。
在编辑页面,根据我们需要进行的操作,点击页面底部功能区域中的“画中画。”大家也可以通过“加水印”的功能进行水印添加,但是两者有一定的区别。
在画中画编辑页面,我们可以看到页面底部出现的视频和照片选项,意思就是我们可以选择一个视频,也可以选择一张照片添加到画面中作为水印,而“加水印”功能只能够添加图片作为水印。
选择好之后调整视频或图片在也页面中的大小、位置,然后点击绿色勾号,在画中画添加页面选择水印出现的时间,添加不同的水印等等,完成之后点击绿色勾号返回视频编辑页面进行导出。感兴趣的小伙伴快打开清爽视频编辑,给自己的视频添加一个动态水印吧。
「深度学习福利」大神带你进阶工程师,立即查看>>>
想对音频进行格式转换?人们常说“音乐”可以帮助我们放松疲惫的大脑,减轻工作与生活的压力,音乐的无形力量远远超出了人们的想象,如果人的一生没有音乐,该多么无趣啊,因此听音乐和欣赏音乐成为现代人非常普遍的生活方式。
听音乐时,想必有兴趣的朋友都会想对一些喜欢的音乐进行操作,比如转换格式或者变速恶搞、截取一些喜欢的歌曲部分等,这些操作在网易云音乐、QQ音乐软件上可操作不了哦。必须运用到相应的转换器软件。下面我安利一款简单好用的迅捷音频转换器给大家,方便进行音频格式转换。
转换步骤
第一步:
百度搜索并下载迅捷音频转换器,版本是下面这个哦
**第二步:**成功安装后,打开软件即可见到下面的功能界面。
用鼠标点击音频转换,然后添加音频文件即可。音频文件添加后,可见关于音频的一系列信息,比如时长、格式、大小、质量等。在文件右方可选择输出格式。
文件的输出格式有很多,如下图红框所示,依据个人需求进行优选。
**第三步:**修改文件保存目录,然后点击全部转换,随后就可以打开相应文件看到转换后的音频了。
以上几个简单的操作就可以完成音频格式转换了,做出来不仅快速,而且效果还OK哦,如果你还想对一些音乐进行个人创意化的操作,就尝试一下其他功能吧,比如音频剪切、合并、降噪、提取、录制、变速、音量调整等。我觉得你会和我一样,想分享这个软件给别人,哈哈。
「深度学习福利」大神带你进阶工程师,立即查看>>>
上学的时候最耗时间作业,不是听不懂的英语,也不是令人抓耳挠腮的数学,而是人人都会的语文。毕竟英语和数学说不会就是真的不会,而语文更像是一种带有主观性的开放题,不说人人都懂,但至少每个人都会一点。
尤其是每个周末和期末的学习笔记,说起来挺简单,但在做的时候既要完整的读完整本书,还要分析书中的主要人物,弄清楚大致细节,一套分析下来至少要把书反复看三四遍。小编就教大家只看一遍就能完成作业的好方法。
首先在翻阅书本之前,将我们要进行分析的内容罗列到纸上,在浏览器搜索迅捷画图,进入官网,选择思维导图,在搜索框中输入关键词读书笔记,点击搜索,在符合条件的诸多模板中,挑选自己喜欢的模板。
通过ENTER和TAB键设置大致节点,在大节点上输入需要进行探讨的问题,然后开始阅读书籍,在看书的过程中,将书本中的问题答案填写到每个问题后面的小节点上。
通过这种方式完成读书笔记,很快就可以将问题的答案寻找出来,既清晰明了,又方便修改,以著名红色读本《红岩》为例,小编读过一遍后,边写边记,很快就将读书笔记完成了。
在迅捷画图中,除了思维导图还有组织结构图、逻辑图、树状图等等,绝大部分工作学习中需要用到的图形都有模板。感兴趣的话就去迅捷画图的官网试试吧。
「深度学习福利」大神带你进阶工程师,立即查看>>>
DragonBonesPro制作补间动画、龙骨动画
开场动画
导入素材
将素材拖入到舞台并调整位置
调整层级关系
添加关键帧并创建补间动画
结果
小丑盒子
导入素材
将素材拖入到舞台并调整位置和层级关系
创建骨骼
创建补间动画
结果
跑步的人
导入.json文件
导入数据到项目
选择.json文件
创建骨骼
手臂和腿部
身体和头部
从属关系
制作动画
跑步
跳
结果
跑
跳
跳跳羊
导入.json到舞台
创建骨骼
创建网格
制作动画
结果
「深度学习福利」大神带你进阶工程师,立即查看>>>
连月来的新冠疫情,冲刷着我们的一切,随着疫情闭关以来第一个长假期的来临,准备出门的防风的人肯定是不在少数,但相信其中也不乏有不少人由于种种原因会宅在家中度过这个五一。那么问题来了,除了吃饭睡觉打豆豆,还能做点啥?为何不用Kodi来观赏大片?追一下美剧?刷一遍韩剧?
接下来让我们看一下在中国大陆,哪些朋友在用Kodi这一神器
更多详情请见:
https://mp.weixin.qq.com/s/luFaMtMyaELCFh2gnrH8aw
http://www.kodi.org.cn
「深度学习福利」大神带你进阶工程师,立即查看>>>
去年,8K风靡一时。在CES、NAB和IBC贸易展览上,很多产品和讨论都与即将到来的8K革命有关。这是一个建立在技术进步和渴望,迈入下一个大事件基础上的行业的重要组成部分。也就是在今年,CES展出了三星、LG、夏普等品牌的8K显示屏,8K已经成为这家电视供应商的最新旗舰产品。
文 / Adrian Pennington
译 / 元宝
原文 /
https://www.streamingmedia.com/Articles/Editorial/Featured-Articles/8K-and-Beyond-How-Much-is-Too-Much-136152.aspx
任何关于8K的讨论都能推动狂热者们对超高分辨率所存在可能性的热情,有的人追求极限的超清分辨率,但有的人又觉得4K对于他们来说都已经过分清晰了。真相是存在于实用主义者之间的,8K不会像3D那样最终暴死, 但是电视市场却也有自己的对于该如何运用技术的见解,单纯为了应用新技术而推出一项产品是一种本末倒置的做法。按照乔布斯的说法,应该是先出现用户需求,才开始研发技术,最后推出对应产品。
一个显而易见的事实是,8K电视目前只占用一个小众市场,而且很可能在未来10年甚至更长的时间里都是如此。与此同时,使用8K作为生产和交付格式的可能性是在增加的。在未来的某个时间点,随着各方面成本的降低,这两者必然都会实现。
三星在2019年国际消费电子展上推出了QLED 8K电视,8K再次成为2020年国际消费电子展的热门话题。
零相关
据IHS Markit的数据显示,在全球范围内,他们的4K超高清电视在2018年第四季度的出货量首次超过总出货量的一半。其中在北美,大约1/3的家庭拥有超高清电视,到了2021年,这一占比将超过1/2,而到了2023年,这一占比将达到64%。
预计到了2023年,西欧将有46%的家庭拥有超高清电视,由于他们的更换电视速度的更快,因此这一增长速度也将快于中国。然而,中国在今年将有140万户家庭会安装8K显示器,这一采用率是引领全球的。
顺便说一下,在中国拥有8K电视其实没有什么用来观看的价值。相反,人们购买8K电视更多是作为一种身份的象征,其中有一部分原因是8K电视机的尺寸更大。在世界上其实只有一个电视频道播放8K的节目,而且它位于日本。到今年夏天,日本将有6.2万人能够以8K超高清格式收看NHK对东京奥运会的报道。这样的数据是不是令人很惊讶?对于一个有5000万人口的国家来说,其中只有0.1%的人口有能力在本地安装8K电视,这其实是不可能实现的。
IHS Markit执行董事Maria Rua Aguete表示:“由于偏爱较小的屏幕尺寸,日本在这方面是明显落后的。”到2020年,只有19%的日本家庭将拥有超高清电视机,到2023年这一比例将达到32%。尽管有超高清4K和8K的广播,但到2023年,日本的大部分地区将仍然是依赖高清和标清。”
8K电视的安装基数是很小的。Rua Aguete说:“内容和产品之间是没有相关性的”。换句话说,这个行业是可以把它想要的任意多的8K屏幕发送到ether中,但是广播公司并没有上钩。
65英寸以上的大屏幕被认为能提供最佳的8K家庭观影体验,并且世界范围内,屏幕尺寸也是在逐渐增大的。然而,由于物流配送和安装上的影响,这些因素可能会影响它的销售。
IHS Markit估计,一台75英寸电视的包装、运输和配送的成本是65英寸电视的两倍,因为它需要两个人才能把它搬到家里。
虽然到2022年,一半的英国家庭应该会拥有4K屏幕的电视(采用4K电视的比例与历史上高清电视的销售比例是相当的),但分析人士对8K电视的普及率仍然是极为谨慎的,预计到2023年,全球8K电视的销量将达到300万台(其中在西欧只有62.5万台)。
IHS Markit技术研究和分析主管保罗·格雷(Paul Gray)在十月份的英国DTG小组会议上说:“我们认为8K看起来像是一个采样率过高的显示器,但它的SD是不够高的,所以最佳点位于这两者之间。”
内容生产商可能会一致认为,高动态范围(HDR)提供了比分辨率更重要的视觉冲击,但这将需要一段时间去让观众明白,更多的像素意味着更好的像素。
Vewd的核心产品高级副总裁Frode Hernes表示:“我们为6英寸手机支付的价格是要高于60英寸电视的,而且手机的使用时间会更短。”“电视实在是太便宜了,但生产起来却复杂得多,我们希望它们能像手机一样流畅,体验效果和手机一样好。但是这是不现实的。”
如果电视制造业能够通过创新走出当前的低收益规模替代周期,那么它就有一线生机。一个答案可能在于新的形式因素,比如可滚动的、模块化的或墙纸显示,这些在最近的CES展会上已经被原型化了。
屏幕实际可用面积
除此之外,电视本身的功能也在扩展,包括人工智能、语音控制和智能家居等控制功能。
为了在屏幕区域内可以容纳多个用例,显示器的尺寸可能会很大。出于这个原因,对于只是使用全屏来观看内容的观看者来说,8K分辨率的作用会很小,而对在一部分屏幕中观看4K节目,在另一部分屏幕中使用视频共享等应用程序的观看者来说,这个用处会更大。其他用例可能是指导性的(例如,用于显示道路情况的Google Maps视频)。
计算机视觉正在推动图像质量的提高,并且它是在屏幕进入市场时将低分辨率的内容输入扩大到8K的解决方案之一。电视芯片制造商HiSilicon的国际业务发展和营销总监Alan Delaney向DTG解释称:“我们可以使用人工智能实时动态检查内容输入,并对其进行改进,这样你就不必再扔垃圾了。”
由于在显示和分销渠道方面的可寻市场有限,因此目前尚无激励优质内容生产商掌握8K节目的动机。