关于python编解码的一些坑(一)

学过python的都知道,python的encode,decode里面有一些坑,掉进去后比较难爬出来。正好这段时间想总结一下这些坑,我会写2-3篇文章来介绍我对这些坑的理解。既然是个人理解,那很可能有些考虑不对的地方。因此如果大家自认为有更准确的理解,也希望能相互交流,共同学习,一起进步!另,文章中引用的文献,我都做了说明,也都注明了出处,以方便大家查阅。

文章比较长,基本是我一手敲下来的来

一,str 和 unicode 
1) str 和 unicode 都是basestring的子类。 
str典型编码类型:gbk,utf8; 表现形式:\xc4\xe3\xba\xc3。若是你看到类似于\xc4\xe3这种类型的编码,你首先要搞清楚,这个应该是中文编码经过gbk或utf8或其他类型的编码(总归不是unicode编码),至于到底是gbk还是utf8,不知道!而看到类似于\u4f60,就需要明白,这个是中文的unicode编码或者说是unicode表示,未经具体的utf8或gbk编码 
2) str是经过编码的(采用何种编码取决于你的python编辑器,典型的如gbk, utf8。如笔者在cmd中默认为gbk编码),典型形式:\xc4\xe3。 
3) unicode 没有经过编码。这里可以认为是有一个“统一世界”,在这个世界里,所有人类世界中的字符(如英文字符,中文字符,阿拉伯字符,希腊字符等等)都有一个统一的代号。典型形式:\u4f60。 
4) str是字节串,表现形式 ” ” 或’ ’ 。是unicode经过encode编码后的字节所组成;

>>> s1="你好"
>>> s1
'\xc4\xe3\xba\xc3'
>>> len(s1)
4
>>> s2="hello"           #注意,后面“补充解释”会讲到
>>> s2   
'hello'     
>>> len(s2)
5

而unicode才是真正的字符串,表现形式为u” ”

u1=u"你好"
>>> u1
u'\u4f60\u597d'
>>> len(u1)
2
>>> u2=u'hello'          #注意,后面“补充解释”会讲到
>>> u2
u'hello'           
>>> len(u2)
5


根据上面的四点,这里要补充解释几个方面 
 str和unicode的典型表形式,为何他们长成这个样子。 
先说unicode。“unicode目前普遍采用的是UCS-2标准,它用两个字节来表示(这里说“表示”,而不是“编码”,因为我觉得这样更加准确)一个字符,故UCS-2最多只能表示65536个字符。汉字简体繁体加起来超过了7万个,但是UCS-2最多只能表示65535个字符,故肯定有部分汉字是UCS-2编码无法表示的,UCS-2的处理办法是是排除一些几乎不用的汉字。另外,为了表示所有的汉字,unicode有UCS-4编码规范,即用四个字节来表示字符串”(——百度百科)。 
就拿\u4f60来说,它是中文“你”的UCS-2表示。\u 表示是unicode,4f60是用十六进制表示的两个字节。 
因此,今后我们碰到类似“\u—-”这种东东,我们要形成的条件反射是:首先它未经过编码,它只是“某个字符”在统一世界一个统一代码表示,它完全等同于“某个字符”。它是真正的“字符串”。

再说具体的编码形式,如“utf8” 和 “gbk”。 
无论是utf8和gbk,他们所做的工作都是把unicode字符进行编码,只是编码的规则不同。从表象来看,他们都是表现为字节串的形式。 
如中文“你”(unicode为“\u4f60”)的utf编码为: “\xe4\xbd\xa0”;而gbk的编码为:“\xc4\xe3”。他们长得差不多,因此如果你看到了这种“\x–\x–\x–\x–\x–\x–”,我们要形成的条件反射是:首先它是某种编码,它是“字节串”,我们无法肯定它到底是哪种编码(python提供了判断这种字节串可能是哪种编码方式的API:chardet(),注意判断的结果只是可能是某种编码,并告知我们这种可能性有多大)。

 UTF-8和unicode的关系 
utf-8只是unicode的一种具体的实现方式。utf8是针对unicode变长编码设计的一种前缀码,根据前缀可判断是几个字节表示一个字符,如下图: 


如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。 
比如”严”的unicode是4E25(100111000100101),4E25处在第三行的范围内(0000 0800-0000 FFFF),因此”严”的UTF-8编码需要三个字节,即格式是”1110xxxx 10xxxxxx 10xxxxxx”。然后,从”严”的最后一个二进制位开始,依次从后向前填入格式中的x,高位补0,得到”严”的UTF-8编码是”11100100 10111000 10100101”。 
可以发现:对于0x00-0x7F之间的字符,十进制范围是0–127,UTF-8编码与ASCII编码完全相同。可以得到进一步的结论,由于ASCII是计算机发展史上最早的编码规范,它之后所发展的一些编码规范,典型如utf-8,gb2312等都完全兼容ASCII码。

 解释第四点4)中的举例。中文、英文在unicode和gbk的表现形式 
先拿例子说话:(在cmd中,编码格式为gbk) 
英文:

>>> u"hello"
u'hello'
>>> "hello"
'hello'
>>> u"hello".encode('gbk')
'hello'

中文

>>> u"你好"
u'\u4f60\u597d'
>>> "你好"
'\xc4\xe3\xba\xc3'
>>> u"你好".encode('gbk')
'\xc4\xe3\xba\xc3'

不知道你看了这几个例子有什么想法。怎样理解例子中发生的一切 
我说说我自己的理解。先解释一下>>> “hello”,发生了什么,这种实质上是调用的是repr(),它告诉我们该字符在python中的存放方式。(区别 >>>print “hello”, print调用的是str( ), 它实质上在输出的时候有个“编码的动作”,自己查资料吧) 
我们发现是英文时,我们无论是否指定编码方式,它在python内部就是以英文字符存在的,而是中文时,无论它是否有指定某种编码,它的方式都是某种“代码”的形式(\u4f60 或 \xc4\xe3)。 
这里,我从两个方面来试着解释上面的例子中所发生的东西。 
第一个方面: 对unicode码的操作

>>> u"hello"   
>>>u'hello' 
>>> u"你好"  
>>>u'\u4f60\u597d'

这一行的两个句子实质上都没有经过编码。只是做了一下字符形式上的变换 
表面上看,中文跟英文的unicode不一样,但实质上是一样的,还记的我们前面讲的吗“unicode码就是字符的另外一种表现形式,它没有经过其他任何编码”。拿 u”h” 来说,它的unicode码是u”\u0068”,在cmd中进行验证

>>> u"\u0068" 
>>>u'h'

那为什么>>> u”h”不显示成u“\u0068”呢?我的理解是“内部存储”和“外部显示”是不一样的。内部存储都是unicode符,而在显示给外部时,有两种选择,unicode符和字符本身。到底选择哪种方式,有一个我自己总结的原则:哪种方式更友好就显示哪种。对处在0-127范围的英文字符来讲,显示字符本身u“h”肯定比干巴巴的u“\u0068 “更友好;在0-127之外的中文字符,只有一种选择,就是显示unicode符。实质上,你完全可以把unicode和字符本身等价看待。我们可以进一步进行验证:英文的unicode是以单个字符显示的,中文字符是以unicode显示的,如下: 


第二个方面:对字符串的操作

>>> "hello"  
>>>'hello'           
>>> u"hello".encode('gbk')  
>>>'hello'
>>> "你好"  
>>>'\xc4\xe3\xba\xc3'  
>>> u"你好".encode('gbk')   
>>>'\xc4\xe3\xba\xc3'

我们是要对字符串编码为字节码,指定的编码方式是gbk。 
第一行当你敲下字符串的时候,实质上,你已经将该字符串按照gbk进行了encode(这句话实质上不严谨,后面解释,暂且这么说),从而变成了字节码;它与第一行后部分的显示地编码做的是同样的工作。根据gb2312码的编码规则(gbk是gb2312基础上的扩展),无论中文字符还是英文字符,每个字符都被编成两个字节。按照这个说法,u“hello”应该是被编成了十个字节,即>>> u”hello”.encode(‘gbk’)的结果应该是“\x–\x–\x–\x–\x–\x–\x–\x–\x–\x–”这种形式,而非显示”hello”。实质上,这涉及到了全角和半角的区别(请自行百度全角半角)。 
先抛出几个结论:全角半角只对英文字符有意义;即便指定的是gbk编码,gbk也不会对“半角”的英文字符进行编码,“半角”的英文编码全部是由ascii编码完成的,因此一个”半角”英文字符只会被编成一个字节;gbk编码只对全角英文字符编码,每个全角字符被编码为两个字节。如下: 


因此回过头再来理解第一行发生的事,实质上是对英文半角字符串进行的ascii的编码,而非gbk的编码。跟第一个方面的解释一样,python内部存储和外部显示是不一样的,在0-127范围之内显示都是字符本身,在0-127之外显示的是编码后的字节串。只是因为是英文,在0-127范围之内,按照原字符进行显示(见之前解释)。 
同理第二行也是进行了编码,因为“你好”这两个中文字符都不在0-127范围之内,故只能按照编码之后的字节码’\xc4\xe3\xba\xc3’进行显示。

特别总结一下0-127范围内的字符: 
在0-127范围内的字符,即ascii 集合内的字符。若没有经过编码(即为字符本身或unicode字符),则在python内部是以unicode存储,以字符本身进行显示。若该字符经过编码,无论什么类型的编码都与ascii的编码方式完全一样,都会按照原字符进行显示。进一步,无论它有没有经过编码,无论它经过何种类型的编码。0—127范围内的字节码和字符码的都可以认为是同一个东西,

那我们在日常的编码过程中,在与外界文件交互等的过程中,应该要注意哪些方面呢。有以下几点需要注意: 
首先一定一定要规范编码,统一编码规范,引用“http://www.mamicode.com/info-detail-308445.html”中的说法,我们可以把python解析器当成一个水池子,有个入口,有个出口。入口处,全部转成unicode, 池里全部使用unicode处理;出口处,再转成目标编码(当然,有例外,处理逻辑中要用到具体编码的情况)

 在池子内部(即在python编辑器中) 
我们要主动设置defaultencoding(默认为ascii),一般设为’utf8’,如下: 
import sys 
reload(sys) 
sys.setdefaultencoding(‘utf-8’)

对于英文字符串(准确地说是在0—127范围内的字符),若没有经过编码(即字符串前有无u,类似于u”–”),其unicode码值与ascii码值是一样的。若编码了(类似于“–” 或u“–“.encode(“utf8”)),无论指定的是什么编码,它都是按照ascii编码的,那么编码值最终反映的也是ascii码值。因此,英文字符串来讲,无所谓是否指定为unicode编码,也无所谓指定的是什么编码,最终反应的都是ascii码(码值一样)。

对于中文字符串(准确地说是在0—127之外的字符),就必须要明确我们到底要处理的是字符串,还是编码之后的字节串。若是字符串,我们必须要指定它是unicode的字符串,即前面要加上u,如u”你好”;若是我们想要编码之后的字节串,就必须要明确指定有效的字节串,如u”你好”.encoding(“utf8”)。

按照我们前面讲的原则,在python内部,我们最好是把所有涉及字符串的地方,都在前面加上u,特别是串内出现了中文的情况。除非你确定串内只有英文字符,绝不会出现0—127范围外的字符。

 在池子外部(即在python编辑器中) 
在“输入”到池子时,全部转成unicode,一般来说是用“decode()”方法;从池子往外“输出”时,转成目标编码,一般用“encode()”方法。也就是说在池子内部,尽量都保证是unicode字符码,在池子外部都转为字节码。

输入: 
a) 文本文件时。实质上读入的是字节流,因此在进入“池子”之前,需要把这些字节流统一解码为unicode码。 
如:

# 使用codecs直接开unicode通道
file = codecs.open("test", "r", "utf-8")  #字节码进python前先按”utf8”解码成unicode
for i in file:
             print type(i)    # i的类型是unicode的

b) 网页时。来自于http://python.jobbole.com/81244/ 的例子 
拿http客户端库中的requests库来讲,其中的Request对象在访问服务器后会返回一个Response对象,这个对象将返回的Http响应字节码保存到content属性中。但是如果你访问另一个属性text时,会返回一个unicode对象,乱码问题就会常常发成在这里。所以要么你直接使用content(字节码),要么记得把encoding设置正确,比如我获取了一段gbk编码的网页,就需要以下方法才能得到正确的unicode。

import requests
url = "http://xxx.xxx.xxx"
response = requests.get(url)
response.encoding = 'gbk'
print response.text

输出: 
a) 输出到shell。在将字符串在shell中打印时,实质上是直接将字节流输出到shell中的。因此需要将池子中的unicode码按照shell中编码格式编码为shell字节串。如果编成其他码,则可能会导致乱码。 
b) Write到文件时。

# -*- coding: gb2312 -*- 
s = "你好" 
u = s.decode('gbk') 
f = open('text.txt','w') 
f.write(u)  # 出错! 
f.write(u.encode('gbk')) # 这样才行 

出错的原因很简单,你想输出的是“字符”,而不是“字节”。前面说过,“字符”是抽象的,你是没有办法把一个抽象的东西写到文件里去的。当然,如果字符串内是码值是0-127范围内的字符,是可以成功的(见前面的解释),但是不推荐。最地道的写法是字符串(无论字符串码值是否在0—127范围内)在写进文件之前,统统编码为字节串。

二, string_escape 和 unicode_escape 
1)string_escape 和 unicode_escape是python特有的两种编码。官方文档的说明: 
string_escape :Produce[s] a string that is suitable as string literal in Python source code 
unicode_escape:Produce[s] a string that is suitable as Unicode literal in Python source code 
中文翻译,在python源码中生成一个适合作为unicode字面上的字符串。 
对于英语渣渣来讲:string认识,literal也认识,连一起的string literal就不认识了(unicode literal也是一样)。 
关键是这里的string literal 和 unicode literal该怎么理解?

从例子上来帮助说明: 
https://gist.github.com/zfox49/2d9f144315da3dc19e67cb5e66dcc3be 
string_escape:

>>> "你好".encode('string_escape')
'\\xc4\\xe3\\xba\\xc3'
>>> '\xe6\x88\x91'.encode('string_escape')
'\\xe6\\x88\\x91'
>>> "hello".encode('string_escape')
'hello'


Unicode_escape:

>>> u"你好".encode('unicode-escape')
'\\u4f60\\u597d'
>>> u"\u4f60\u597d".encode('unicode-escape')
'\\u4f60\\u597d'
>>> u'hello'.encode('unicode-escape')
'hello'


我们知道,

>>> u“你好”.encode(‘gbk’)                   
>>>'\xc4\xe3\xba\xc3' 
>>> '\xc4\xe3\xba\xc3'.encode('string_escape')  
>>>'\\xc4\\xe3\\xba\\xc3'

>>>u'\u4f60\u597d'
>>> u'\u4f60\u597d'.encode('unicode_escape') 
>>>'\\u4f60\\u597d'


也就是说string_escape 是把在字符串编码后的每个字节前面加上转义字符 ’\’ ,这个转义字符就是string_escape 的 “escape(转义)” 的意思。同理unicode_escape也是可以类似理解。总结来说,就是把在python内“存储”的字节码或字符码(unicode) 显式地显示出来,在显示时,原来字节串中有一个 ‘\’,再将其转义之后,就在原来基础上多加了一个 ‘\’。

这样做的意义在哪?为什么要这样做?下面谈谈我的理解。 
再次强调一遍:在ASCII字符集(0–127)范围内的字符,可以认为字符和字节就是同一个东西,它们“融合了”!无论经过怎样的encode,decode,最后的结果都是ASCII字符本身,所以也可以认为它没有了encode decode的概念。ASCII字符集内的字符在整个python世界中都是畅通无阻的!!!容易出问题的就是0—127范围之外的字符! 
回到这里,我们发现,encode之后,是生成了一个全新的字符串(也是字节串)。对python而言,我不去想它代表的是什么,它就是一个字符串而已(’\xc4\xe3\xba\xc3’ 或 ‘\u4f60\u597d’),这个串内的所有字符的码值都在0–127范围内。通过这样的处理,我们惊奇地发现存这样处理给我们带来了极大的便利:首先原始字符串(无论字符是不是在0-127范围内)的信息也没有丢失,只是换了一种表示方式;同时原始字符串被统一转化为0—127范围内的字符。还记得我们前面强调过的吗,在ASCII字符集内的字符,对python世界而言是同一个东西。因此在python与输入输出进行交互的时候,就避免了频繁的decode,encode。不过这样处理的后果是人可能看不懂,想想print出来的是’\xc4\xe3\xba\xc3’,或者输出到文件中的是’\u4f60\u597d’这种鬼东西,虽然信息没有丢失,但是我们人看不懂。因此为了人能够看懂,我们可能要对这些字符串还原成它本来的意思,于是就需要对我们就可能就需要各种encode,decode了。 
解释到这里,你应该明白了,string_escape和unicode_escape的作用就是把原始字符串(无论中文还是英文)统一成ASCII字符集的字符串,这样方便在整个python世界中(机器世界)进行处理、传输。为了方便我们人类世界看懂,才会最终使用各种encode,decode来将这些ASCII字符集的字符串还原成我们它本来的样子。

三, 那看到一个编码后的串,我们如何从字面上看它是什么编码? 
以下斜字体引用自http://www.cnblogs.com/Xjng/p/5093905.html 
1)没有办法准确地判断一个字符串的编码方式,例如gbk的“\aa”代表甲,utf-8的“\aa”代表乙,如果给定“\aa”怎么判断是哪种编码?它既可以是gbk也可以是utf-8 
2)我们能做的是粗略地判断一个字符串的编码方式,因为上面的例如的情况是很少的,更多的情况是gbk中的’\aa’代表甲,utf-8中是乱码,例如�,这样我们就能判断’\aa’是gbk编码,因为如果用utf-8编码去解码的结果是没有意义的 
3)而我们经常遇到的编码其实主要的就只有三种:utf-8,gbk,unicode 
• unicode一般是 \u 带头的,然后后面跟四位数字或字符串,例如 \u6d4b\u8bd5 ,一个 \u 对应一个汉字 
• utf-8一般是 \x 带头的,后面跟两位字母或数字,例如 \xe6\xb5\x8b\xe8\xaf\x95\xe5\x95\x8a ,三个 \x 代表一个汉字 
• gbk一般是 \x 带头的,后面跟两位字母或数字,例如 \xb2\xe2\xca\xd4\xb0\xa1 ,两个个 \x 代表一个汉字

4)使用chardet模块来判断

import chardet
raw = u'我是一只小小鸟'
print chardet.detect(raw.encode('utf-8'))
print chardet.detect(raw.encode('gbk'))

*输出: 
{‘confidence’: 0.99, ‘encoding’: ‘utf-8’} 
{‘confidence’: 0.99, ‘encoding’: ‘GB2312’} 
chardet模块可以计算这个字符串是某个编码的概率,基本对于99%的应用场景,这个模块都够用了。*

四,典型例子汇总: 
1, 关于encode decode 的常见错误(一般都是编码和解码不一致导致的) 
1) 最常见的一种错误,我们对已经编码过后的字节串再次使用encode,这种实质上有一个“隐式”的解码动作,即隐式地将字节串解码为unicode字符串(解码类型是sys.getdefaultencoding(),一般为ascii ),然后才再encode。整个过程如下: 


补充一点,本例是在cmd中,该cmd的“显式”编码类型是gbk,所谓的“显式”、“隐式”的名字是我自己取的,具体解释见另一篇博客 http://blog.youkuaiyun.com/nyyjs/article/details/56670080。

在python2.x下,最好的解决办法是保证显式隐式的编码类型一致。

1) 笔者在某个项目中有这么一段数据: 
“{\x22provinceName\x22:\x22\xE5\x8C\x97\xE4\xBA\xAC\xE5\xB8\x82\x22}” 
我们如何解析它,首先,明面上传递”\x–” 这样的字符串,说明是经过“string_escape”编码过的。“\x22”是英文字符的双引号,其他 “\x–” 不知道是什么编码。我们假设是最常用的utf8编码,那试着解析一下,解析的过程如下: 
 


Bingo! 成功

2) 网上摘取的一段字符串(https://www.v2ex.com/t/174215),如下: 
“u’\xe6\x97\xa0\xe5\x90\x8d’” 
首先字符串前的u表示它是unicode字符串,但串内又不是 “\u—-”, 而是”\x–”,试着解析一下 
 


成功

3) 摘取的另一段字符串(http://blog.youkuaiyun.com/devil_2009/article/details/38796533) 
str1 = ‘\u4f60\u597d’ 



作者:nyyjs 
来源:优快云 
原文:https://blog.youkuaiyun.com/nyyjs/article/details/56667626 
版权声明:本文为博主原创文章,转载请附上博文链接!

<think>好的,用户想了解如何使用Python处理RTSP视频流,我需要整理相关的方法和库。首先,我得回忆下常见的Python库,比如OpenCV,它应该是比较常用的,用户可能知道些,但需要详细说明。然后GStreamer也是个选项,可能更灵活但复杂。另外还有FFmpeg和VLC的Python绑定,这些可能适合不同场景。 接下来,我需要查看用户提供的引用资料。引用1提到OpenCV读取RTSP流的问题,引用2和3分别提到了GStreamer-Python和可能的问题,引用4中的代码示例用了OpenCV但存在异常。这说明用户可能遇到了稳定性问题,需要解决方案。 我应该先介绍OpenCV的方法,因为最简单,但也要指出其潜在问题,比如断流处理。然后转到GStreamer,说明如何配置管道,可能更可靠。接着是FFmpeg和PyAV,适合更底层的处理。VLC绑定可能适合需要播放的情况。然后给出示例代码,帮助用户快速上手。 还要注意用户可能遇到的常见问题,比如网络延迟、认证、断流重连,这些需要提供解决建议。比如使用队列、异步处理,或者调整OpenCV的参数。同时,根据引用4中的代码,用户可能在使用异步时出现问题,需要提醒他们正确释放资源和错误处理。 最后生成相关问题,覆盖库的选择、延迟优化、断流处理、多线程和认证处理,这样用户可以有进步探索的方向。要确保回答结构清晰,分点说明每个方法,并给出代码示例,同时注意事项部分帮助用户避免常见。</think>### Python处理RTSP视频流的库与方法 #### 、核心工具库 1. **OpenCV**(最常用) - 基础实现仅需3行代码,但需注意断流重连机制 - 示例代码: ```python import cv2 cap = cv2.VideoCapture("rtsp://username:password@ip:port/path") while cap.isOpened(): ret, frame = cap.read() if not ret: break cv2.imshow('RTSP', frame) if cv2.waitKey(1) == 27: break cap.release() ``` - 优化建议:添加`cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)`减少延迟[^4] 2. **GStreamer-Python**(工业级方案) - 支持复杂媒体处理管道搭建 - 基础管道配置示例: ```python import gi gi.require_version('Gst', '1.0') from gi.repository import Gst, GLib pipeline = Gst.parse_launch('rtspsrc location=rtsp://your_stream ! decodebin ! videoconvert ! appsink emit-signals=True') ``` 3. **FFmpeg-Python**(底层控制) - 适合需要精确控制编解码的场景 - 示例使用subprocess调用: ```python import subprocess ffmpeg_cmd = [ 'ffmpeg', '-i', 'rtsp://your_stream', '-f', 'image2pipe', '-pix_fmt', 'rgb24', '-vcodec', 'rawvideo', '-' ] pipe = subprocess.Popen(ffmpeg_cmd, stdout=subprocess.PIPE, bufsize=10**8) ``` #### 二、高级处理方案 1. **异步处理框架** - 使用asyncio解决I/O阻塞问题(参考引用4的队列机制) - 优化建议:设置最大重试次数和超时检测 2. **多线程架构** - 分离视频采集、处理、显示线程 - 推荐使用`queue.Queue`实现线程间通信 3. **硬件加速方案** - NVIDIA Jetson平台可使用`gstreamer-nv`插件 - Intel平台推荐使用VAAPI加速: ```python pipeline = 'rtspsrc ! rtph264depay ! vaapih264dec ! videoconvert ! appsink' ``` #### 三、常见问题解决方案 1. **断流重连** ```python def reset_capture(): global cap cap.release() cap = cv2.VideoCapture(url) return cap.isOpened() ``` 2. **认证处理** - URL标准格式:`rtsp://username:password@ip:port/path` 3. **低延迟优化** ```python cap.set(cv2.CAP_PROP_FPS, 25) cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*'H264')) ``` #### 四、性能对比表 | 方案 | 延迟 | CPU占用 | 稳定性 | 开发难度 | |--------------|-------|---------|--------|----------| | OpenCV | 中 | 低 | 般 | ★★☆☆☆ | | GStreamer | 低 | 中 | 高 | ★★★★☆ | | FFmpeg | 高 | 高 | 高 | ★★★★★ | | VLC-Python | 中高 | 中 | 高 | ★★★☆☆ |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值