1.1.方块效应
在我们视频电话时,快速移动摄像头时,会发现画面变出现很多方块。这就是方块效应。
无论是要发送的TCP数据包,还是要编码的图像,都会出现在短时间内出现较大的数据量。TCP面对尖峰,可以选择不为所动,但如果视频编码也对尖峰不为所动,那图像质量就会大打折扣了。因为如果有几帧数据量特别大,但我们仍要把码率控制在原来的水平,那么就会损失比较多的图像信息,图像就会失真。通常的表现是画面出现很多小方块,看上去像是打了马赛克一样,也就是方块效应。
1.2.开关硬编解码
在codec_database.cc文件中
//开关硬解码
#ifdef VIDEO_HARDWARE_DECODE 1
在video_encoder.cc文件中
//开关硬编码
#define VIDEO_HARDWARE_ENCODE 1
如果硬解码配置失败会切换到软解
VideoEncoder* VideoEncoder::Create(VideoEncoder::EncoderType codec_type) {
#if defined(WEBRTC_ANDROID) && defined(VIDEO_HARDWARE_ENCODE)
VideoEncoder* encoder = NULL;
LOG(LS_INFO) << "WebRTC(Android) Use Hardware Encode.";
static webrtc_jni::MediaCodecVideoEncoderFactory* factory = NULL;
if(!factory) {
factory = new webrtc_jni::MediaCodecVideoEncoderFactory;
}
switch (codec_type) {
case kH264:
LOG(LS_INFO) << "Create H264 Hardware Encode.";
encoder = factory->CreateVideoEncoder(kVideoCodecH264);
break;
case kUnsupportedCodec:
RTC_NOTREACHED();
return nullptr;
}
if(encoder) {
return encoder;
}
LOG(LS_INFO) << "WebRTC(Android) Create Hardware Encode Failed. Convert to software encode.";
#endif
switch (codec_type) {
case kH264:
RTC_DCHECK(H264Encoder::IsSupported());
LOG(LS_INFO) << "Create H264 Software Encode.";
return H264Encoder::Create();
...
case kUnsupportedCodec:
RTC_NOTREACHED();
return nullptr;
}
LOG(LS_WARNING) << "No internal encode of this type exists.";
RTC_NOTREACHED();
return nullptr;
}
1.3.修改编解码器支持更多机型
修改java层的解码和编码2个文件
./src/webrtc/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java
./src/webrtc/sdk/android/api/org/webrtc/MediaCodecVideoDecoder.java
private static final String[] supportedH264HwCodecPrefixes = {
"OMX.qcom.", "OMX.Intel.", "OMX.Exynos."
,"OMX.Nvidia.H264." /*Nexus 7(2012), Nexus 9, Tegra 3, Tegra K1*/
,"OMX.ittiam.video." /*Xiaomi Mi 1s*/
,"OMX.SEC.avc." /*Exynos 3110, Nexus S*/
,"OMX.IMG.MSVDX." /*Huawei Honor 6, Kirin 920*/
,"OMX.k3.video." /*Huawei Honor 3C, Kirin 910*/
,"OMX.hisi." /*Huawei Premium Phones, Kirin 950*/
,"OMX.TI.DUCATI1." /*Galaxy Nexus, Ti OMAP4460*/
,"OMX.MTK.VIDEO." /*no sense*/
,"OMX.LG.decoder." /*no sense*/
,"OMX.rk.video_decoder."/*Youku TVBox. our service doesn't need this */
,"OMX.amlogic.avc" /*MiBox1, 1s, 2. our service doesn't need this */
};
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓
硬编码与java层的通信在androidmediaencoder_jni.cc文件中,java层的实现在MediaCodecVideoEncoder.java文件中。
2.1.硬编码码率控制模式
MediaCodec编码码率的控制模式有2种,1是配置时设置目标码率和码率控制模式,2是动态调整目标码率。
2.1.2.配置时码率模式设置
配置时指定目标码率和码率控制模式:
//设置vbr模式
format.setInteger(MediaFormat.KEY_BITRATE_MODE,MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR);
1.CQ表示完全不控制码率,尽最大可能保证图像质量。
2.VBR表示编码器会根据图像内容的复杂度来动态调整输出码率,图像复杂则码率高,图像简单则码率低。VBR输出码率会在一定范围内波动,对于小幅晃动,方块效应会有所改善,但对剧烈晃动仍无能为力,而连续调低码率则会导致码率急剧下降,如果无法接受这个问题,那VBR就不是好的选择。VBR在画面内容保持静止时,码率会降得很低,一旦画面内容开始动起来,码率上升会跟不上,就会导致画面质量很差;VBR上调码率后,有可能导致中间网络路径的丢包/延迟增加,进而导致问题。
3.CBR表示编码器会尽量把输出码率控制为设定值,即我们前面提到的“不为所动”。
WebRTC使用的是CBR,稳定可控是CBR的优点,一旦稳定可控,那我们就可以自己实现比较可靠的控制了。CBR会存在关键帧后的几帧内容模糊的问题,如果关键帧间隔较短,可以观察到明显的呼吸效应」。
WebRTC 使用的方案是CBR+长关键帧间隔,这样「呼吸效应」就不是那么明显,而 CBR 确实能增强画面质量。
在androidmediaencoder_jni.cc文件中
int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
uint32_t frame_rate) {
RTC_DCHECK(codec_thread_checker_.CalledOnValidThread());
//帧率不大于60
frame_rate = (frame_rate < MAX_ALLOWED_VIDEO_FPS) ?
frame_rate : MAX_ALLOWED_VIDEO_FPS;
if (last_set_bitrate_kbps_ == new_bit_rate &&
last_set_fps_ == frame_rate) {
return WEBRTC_VIDEO_CODEC_OK;
}
if (scale_) {
quality_scaler_.ReportFramerate(frame_rate);
}
JNIEnv* jni = AttachCurrentThreadIfNeeded();
ScopedLocalRefFrame local_ref_frame(jni);
if (new_bit_rate > 0) {
last_set_bitrate_kbps_ = new_bit_rate;
}
if (frame_rate > 0) {
last_set_fps_ = frame_rate;
}
//反调java层的动态设置码率函数
bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
j_set_rates_method_,
last_set_bitrate_kbps_,
last_set_fps_);
CHECK_EXCEPTION(jni);
if (!ret) {
ResetCodecOnCodecThread();
return WEBRTC_VIDEO_CODEC_ERROR;
}
return WEBRTC_VIDEO_CODEC_OK;
}
动态调整目标码率,在编码中调整目标码率,下面是java层的接口:
Bundle param =new Bundle();
param.putInt(MediaCodec.PARAMETER_KEY_VIDEO_BITRATE,bitrate);
mediaCodec.setParameters(param);
2.2.关键帧触发
MediaCodec有两种方式触发输出关键帧,是由配置时设置的 KEY_FRAME_RATE 和 KEY_I_FRAME_INTERVAL参数自动触发。自动触发实际是按照帧数触发的,例如设置帧率为 25 fps,关键帧间隔为 2s,那就会每 50 帧输出一个关键帧,一旦实际帧率低于配置帧率,那就会导致关键帧间隔时间变长。
运行过程中通过setParameters手动触发输出关键帧。对于H.264编码,WebRTC设置的关键帧间隔时间为20s,显然仅靠自动触发是不可能的,因此它会根据实际输出帧的情况,决定何时手动触发输出一个关键帧,也就是前面提到的checkKeyFrameRequired函数了。而这样做的原因,就是更可控。
手动触发输出关键帧:
Bundle param = new Bundle();
param.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME,0);
mediaCodec.setParameters(param);
2.3.方块效应优化
VBR的码率存在一个波动范围,因此使用VBR可以在一定程度上优化方块效应,但对于视频内容的剧烈变化,VBR就只能无法处理了。WebRTC 的做法是,获取每个输出帧的 QP 值,如果 QP值过大,就说明图像复杂度太高,如果QP值持续超过上界,那就重启编码器,用更低的输出分辨率来编码;如果 QP 值过低,则说明图像复杂度太低,如果 QP 值持续低于下界,也会重启编码器,用更高的输出分辨率来编码。
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我正在使用ruby1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功
查看Ruby代码,它具有以下proc_arity:staticVALUEproc_arity(VALUEself){intarity=rb_proc_arity(self);returnINT2FIX(arity);}更多的是C编码风格问题,但为什么staticVALUE在单独的一行而不是像这样的:staticVALUEproc_arity(VALUEself) 最佳答案 它来自UNIX世界,因为它有助于轻松grep函数的定义:$grep-n'^proc_arity'*.c或使用vim:/^proc_arity
我创建了一个由于“在运行时执行的单例元类定义”而无法编码的对象(这段代码的描述是否正确?)。这是通过以下代码执行的:#defineclassXthatmyusesingletonclassmetaprogrammingfeatures#throughcallofmethod:break_marshalling!classXdefbreak_marshalling!meta_class=class我该怎么做才能使对象编码正确?是否可以从对象instance_of_x的classX中“移除”单例组件?我真的需要一个建议,因为我们的一些对象需要通过Marshal.dump序列化机制进行缓存。
我在使用Ruby1.9.2p290更改文本文件的编码时遇到问题。我收到错误消息invalidbytesequenceinUTF-8(ArgumentError)。问题(我认为)在于字符集似乎是未知的。如果我执行以下操作,则从命令行:$filetest.txt我得到:Non-ISOextended-ASCIIEnglishtext,withCRLFlineterminators或者,或者,如果我这样做:$file-itest.txt我得到:test.txt:text/plain;charset=unknown但是,如果我这样做,在Ruby中:data=File.open("test.tx
我正在向我的Controller发送一个base64图像并按原样保存它。现在我需要显示该图像。这是我要显示的内容,但未显示图像:"/>为了编码,我使用了这个java脚本函数encodeURIComponent();我的编码图像格式:data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/........ 最佳答案 你不需要解码base64应该可以 关于ruby-on-rails-在rails中显示base64编码的图像,我们在StackOve
我试图通过点击一个链接获得一个带有ISO-8859-1编码的页面,所以代码类似于这样:page_result=page.link_with(:text=>'link_text').click到目前为止,我得到的结果编码错误,所以我看到的字符如下:'T�tulo:'insteadof'Título:'我尝试了几种方法,包括:使用代理在第一个请求中声明编码:@page_search=@agent.get(:url=>'http://www.server.com',:headers=>{'Accept-Charset'=>'ISO-8859-1'})说明页面本身的编码page_result.