亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

使用Python的Flask框架實(shí)現(xiàn)視頻的流媒體傳輸

 更新時(shí)間:2015年03月31日 11:42:42   作者:Miguel Grinberg  
這篇文章主要介紹了使用Python的Flask框架實(shí)現(xiàn)視頻的流媒體傳輸,包括從攝像機(jī)獲取幀到web瀏覽器的數(shù)字流傳輸,需要的朋友可以參考下

Flask 是一個(gè) Python 實(shí)現(xiàn)的 Web 開發(fā)微框架。這篇文章是一個(gè)講述如何用它實(shí)現(xiàn)傳送視頻數(shù)據(jù)流的詳細(xì)教程。

我敢肯定,現(xiàn)在你已經(jīng)知道我在O'Reilly Media上發(fā)布了有關(guān)Flask的一本書和一些視頻資料。在這些上面,F(xiàn)lask框架介紹的覆蓋面是相當(dāng)完整的,出于某種原因,也有一小部分的功能沒有太多的提到,因此我認(rèn)為在這里寫一篇介紹它們的文章是一個(gè)好主意。

這篇文章是專門介紹流媒體的,這個(gè)有趣的功能讓Flask應(yīng)用擁有這樣一種能力,以分割成小數(shù)據(jù)塊的方式,高效地為大型請(qǐng)求提供數(shù)據(jù),這可能要花費(fèi)較長(zhǎng)的時(shí)間。為了說明這個(gè)主題,我將告訴你如何構(gòu)建一個(gè)實(shí)時(shí)視頻流媒體服務(wù)器!
什么是流媒體?

流媒體是一種技術(shù),其中,服務(wù)器以數(shù)據(jù)塊的形式響應(yīng)請(qǐng)求。我能想到一個(gè)原因來解釋為什么這個(gè)技術(shù)可能是有用的:

    非常大的響應(yīng) 。對(duì)于非常大的響應(yīng)而言,內(nèi)存中收集的響應(yīng)只返回給客戶端,這是很低效的。另一種方法是將響應(yīng)寫入磁盤,然后使用flask.send_file()返回文件,但是這增加了I/O的組合。假設(shè)數(shù)據(jù)可以分塊生成,以小塊數(shù)據(jù)的方式給請(qǐng)求提供響應(yīng)是一種更好的解決方案。
    實(shí)時(shí)數(shù)據(jù) 。對(duì)于一些應(yīng)用,需要請(qǐng)求返回的數(shù)據(jù)來自實(shí)時(shí)數(shù)據(jù)源。在這個(gè)方面一個(gè)非常好的例子就是提供一個(gè)實(shí)時(shí)視頻或音頻。很多安全攝像機(jī)使用這種技術(shù)將視頻數(shù)據(jù)流傳輸給Web瀏覽器。

使用Flask實(shí)現(xiàn)流式傳輸

Flask通過使用生成器函數(shù)對(duì)流式響應(yīng)提供本機(jī)支持。生成器是一個(gè)特別的函數(shù),它可以中斷和恢復(fù)。考慮一下下面的函數(shù):

 
def gen():  
  yield 1  
  yield 2  
  yield 3

這是一個(gè)運(yùn)行三步的函數(shù),其中每步返回一個(gè)值。描述生成器如何實(shí)現(xiàn)超出了本文的范圍,但如果你有點(diǎn)好奇,下面的shell會(huì)話將給你說明生成器是如何被使用的:

 
>>> x = gen()
>>> x
<generator object gen at 0x7f06f3059c30>
>>> x.next()
1
>>> x.next()
2
>>> x.next()
3
>>> x.next()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
StopIteration

在這個(gè)簡(jiǎn)單的例子中你能看到,一個(gè)生成器函數(shù)可以順序得返回多個(gè)結(jié)果。Flask使用生成器 函數(shù)這一特性來實(shí)現(xiàn)流式傳輸。

下面的例子說明了如何使用流式傳輸能夠產(chǎn)生大的數(shù)據(jù)表,而不必將整個(gè)表放入內(nèi)存中:

 
from flask import Response, render_template
from app.models import Stock
 
def generate_stock_table():
  yield render_template('stock_header.html')
  for stock in Stock.query.all():
    yield render_template('stock_row.html', stock=stock)
  yield render_template('stock_footer.html')
 
@app.route('/stock-table')
def stock_table():
  return Response(generate_stock_table())

在這個(gè)例子中,你能看到Flask和生成器函數(shù)是如何一起工作的。返回流式響應(yīng)的路由(route)需要返回一個(gè)由生成器函數(shù)初始化的Response對(duì)象。Flask然后采取調(diào)用生成器,并以分塊的方式吧結(jié)果發(fā)送給客戶端。

對(duì)于這個(gè)特殊的例子,如果你假設(shè)Stock.query.all()返回的數(shù)據(jù)庫(kù)查詢結(jié)果是一個(gè)迭代器,那么你能一次生成一個(gè)潛在大表的一行,因此無論查詢中的字符數(shù)量有多少,Python過程中的內(nèi)存消耗不會(huì)因?yàn)檩^大的響應(yīng)字符串而越來越大。
多部分響應(yīng)

上文提到了表的例子以小塊的形式生成一個(gè)傳統(tǒng)網(wǎng)頁(yè),各個(gè)的部分連接成最后的結(jié)果。對(duì)于如何生成較大的響應(yīng)這是一個(gè)很好的例子,但更令人激動(dòng)的事情是處理實(shí)時(shí)數(shù)據(jù)。

使用流式傳輸?shù)囊粋€(gè)有趣的應(yīng)用是使用每個(gè)塊來替換原來頁(yè)面中的地方,這能使流在瀏覽器窗口中形成動(dòng)畫。利用這種技術(shù),你可以讓流中每個(gè)數(shù)據(jù)塊成為一個(gè)圖像,這給你提供了一個(gè)運(yùn)行在瀏覽器中的很酷的視頻輸入信號(hào)!

實(shí)現(xiàn)就地更新的秘密是使用多部分響應(yīng)。多部分響應(yīng)由一個(gè)報(bào)頭(header)和很多部分(parts)組成。報(bào)頭包括多部分中的一種內(nèi)容類型,后面的部分由邊界標(biāo)記分隔,每個(gè)部分中含有自身部分中的特定內(nèi)容類型。

對(duì)于不同的需求,這里有一些多部分內(nèi)容類型。對(duì)于具有流式傳輸?shù)?,每個(gè)部分替換先前部分必須使用multipart/x-mixed-replace內(nèi)容類型。為了幫助你了解它到底是什么樣子的,這里有一個(gè)多部分視頻流傳輸?shù)捻憫?yīng)結(jié)構(gòu):

 
HTTP/1.1 200 OK
Content-Type: multipart/x-mixed-replace; boundary=frame
 
--frame
Content-Type: image/jpeg
 
<jpeg data here>
--frame
Content-Type: image/jpeg
 
<jpeg data here>
...

正如你上面看到的,這個(gè)結(jié)構(gòu)非常簡(jiǎn)單。主要的Content-Type頭被設(shè)為multipart/x-mixed-replace,同時(shí)邊界標(biāo)記也被定義。然后每個(gè)部分中包括,有兩個(gè)短橫線的前綴,及這行上的邊界字符串。每個(gè)部分有自己的Content-Type頭,并且每個(gè)部分可以可選地包括一個(gè)說明所在部分有效載荷的字節(jié)長(zhǎng)度的Content-Length頭,但至少對(duì)圖像瀏覽器而言,能夠處理沒有長(zhǎng)度的流。
建立一個(gè)實(shí)時(shí)視頻流媒體服務(wù)器

這篇文章中已經(jīng)有足夠的理論,現(xiàn)在是時(shí)候來建立一個(gè)將實(shí)時(shí)視頻流式傳輸?shù)絎eb瀏覽器的完整應(yīng)用。

這里有很多方法將視頻流式傳輸?shù)綖g覽器,并且每個(gè)方法都有其優(yōu)點(diǎn)和缺點(diǎn)。與Flask流特征協(xié)同工作的一個(gè)好方法是流式傳輸獨(dú)立的JPEG圖片序列。這就是動(dòng)態(tài)JPEG。這被用于許多IP監(jiān)控?cái)z像機(jī)。這種方法具有較短的延遲時(shí)間,但傳輸質(zhì)量并不是最好的,因?yàn)閷?duì)于動(dòng)態(tài)影像而言,JPEG壓縮不是非常有效。

下面你可以看到一個(gè)非常簡(jiǎn)單但完整的Web應(yīng)用。它可以提供一個(gè)動(dòng)態(tài)JPEG流傳輸:

 
#!/usr/bin/env python
from flask import Flask, render_template, Response
from camera import Camera
 
app = Flask(__name__)
 
@app.route('/')
def index():  
  return render_template('index.html')
 
def gen(camera):
  while True:
    frame = camera.get_frame()
    yield (b'--framern'
        b'Content-Type: image/jpegrnrn' + frame + b'rn')
 
@app.route('/video_feed')
def video_feed():
  return Response(gen(Camera()),
          mimetype='multipart/x-mixed-replace; boundary=frame')
 
if __name__ == '__main__':
  app.run(host='0.0.0.0', debug=True)

這個(gè)應(yīng)用導(dǎo)入一個(gè)Camera類來負(fù)責(zé)提供幀序列。在這個(gè)例子中,將camera控制部分放入一個(gè)單獨(dú)的模塊是一個(gè)很好的主意。這樣,Web應(yīng)用會(huì)保持干凈、簡(jiǎn)單和通用。

該應(yīng)用有兩個(gè)路由(route)。/路由為主頁(yè)服務(wù),被定義在index.html模板中。下面你能看到這個(gè)模板文件中的內(nèi)容:

 
<html>
 <head>
  <title>Video Streaming Demonstration</title>
 </head>
 <body>
  <h1>Video Streaming Demonstration</h1>
  <img src="{{ url_for('video_feed') }}">
 </body>
</html>

這是一個(gè)簡(jiǎn)單的HTML頁(yè)面,只含有一個(gè)標(biāo)題和圖像標(biāo)簽。注意這個(gè)圖像標(biāo)簽的src屬性指向這個(gè)應(yīng)用的第二個(gè)路由,這就是魔法發(fā)生的地方。

/video_feed路由返回流式響應(yīng)。因?yàn)檫@個(gè)流返回要被展示在web頁(yè)面上的圖像,在圖像標(biāo)簽的src屬性中,URL指向這個(gè)路由。因?yàn)榇蠖鄶?shù)/所有瀏覽器支持多部分響應(yīng)(如果你找到一個(gè)不支持這個(gè)的瀏覽器,請(qǐng)告訴我),瀏覽器會(huì)通過顯示JPEG圖像流自動(dòng)保持圖像元素的更新。

在/video_feed路由中使用的生成器函數(shù)叫g(shù)en(),將Camera類的一個(gè)實(shí)例作為其參數(shù)。mimetype參數(shù)設(shè)置如上所示,并具有multipart/x-mixed-replace的內(nèi)容類型和設(shè)為"frame"的邊界字符串。

gen()函數(shù)進(jìn)入一個(gè)循環(huán),其中連續(xù)的從camera返回幀作為響應(yīng)塊。如上所示,這個(gè)函數(shù)通過調(diào)用camera.get_frame()方法要求camera提供幀,然后生成幀,使用image/jpeg內(nèi)容類型將該幀格式化為響應(yīng)塊。
從攝像機(jī)獲取幀

現(xiàn)在,所有剩下的就是實(shí)現(xiàn)Camera類,這必須連接攝像機(jī)硬件并從中下載實(shí)時(shí)視頻幀。將這個(gè)應(yīng)用硬件相關(guān)部分封裝在一個(gè)類中的好處是,對(duì)于不同的人這個(gè)類可以有不同的實(shí)現(xiàn),而應(yīng)用的其他部分保持不變。你可以把這個(gè)類當(dāng)做一個(gè)設(shè)備驅(qū)動(dòng),不管實(shí)際使用中的硬件設(shè)備而提供一個(gè)統(tǒng)一的實(shí)現(xiàn)。

從應(yīng)用的其余部分分離出Camera類的另一個(gè)優(yōu)點(diǎn)是,當(dāng)實(shí)際上沒有攝像機(jī)時(shí),很容易能騙過應(yīng)用程序,讓它認(rèn)為這里有攝像機(jī),因?yàn)閏amera類能被實(shí)現(xiàn)為模擬攝像機(jī)而無需真實(shí)硬件。事實(shí)上,當(dāng)我運(yùn)行這個(gè)應(yīng)用時(shí),最簡(jiǎn)單的方式是測(cè)試流能做那些,而不需擔(dān)心硬件,直到我已經(jīng)使其他部分都正確運(yùn)行。下面,你可以看到我使用的簡(jiǎn)單模擬攝像機(jī)實(shí)現(xiàn):

 
from time import time
 
class Camera(object):
  def __init__(self):
    self.frames = [open(f + '.jpg', 'rb').read() for f in ['1', '2', '3']]
 
  def get_frame(self):
    return self.frames[int(time()) % 3]

這個(gè)實(shí)現(xiàn)從磁盤中讀取三個(gè)圖像1.jpg、2.jpg、3.jpg,然后以每秒一幀的速率重復(fù)的依次返回。get_frame()函數(shù)使用當(dāng)前時(shí)間,以秒來確定在給定的時(shí)刻返回哪三個(gè)幀。很簡(jiǎn)單吧?

要運(yùn)行這個(gè)模擬攝像機(jī),我需要?jiǎng)?chuàng)建三個(gè)幀。我使用gimp做了下面的圖像:
2015331112808262.jpg (412×152)

因?yàn)閿z像機(jī)是模擬的,你能在任何環(huán)境在運(yùn)行這個(gè)應(yīng)用!我將這個(gè)應(yīng)用的所有文件放在了GitHub。如果你熟悉git,你可以使用下面的命令克隆它:

 
$ git clone https://github.com/miguelgrinberg/flask-video-streaming.git

如果你喜歡下載它,你可以在這里得到一個(gè)zip文件。

你安裝好這個(gè)應(yīng)用后,創(chuàng)建一個(gè)虛擬環(huán)境并在里面安裝Flask。然后你就可以使用下面的命令運(yùn)行這個(gè)應(yīng)用:

 
$ python app.py

當(dāng)你在你的Web瀏覽器中輸入http://localhost:5000啟動(dòng)這個(gè)應(yīng)用時(shí),你會(huì)看到模擬視頻流一遍遍地播放圖像1、2、3。很酷吧?

有一次,應(yīng)用中的所有都在運(yùn)行,我啟動(dòng)了樹莓派及其攝像機(jī)模塊,并實(shí)現(xiàn)了一個(gè)新的Camera類來將樹莓派變成一個(gè)視頻流媒體服務(wù)器,使用picamera包來控制硬件。我不會(huì)在這里討論這個(gè)camera類的實(shí)現(xiàn),但你可以在源代碼中的camera_pi.py文件中找到。

如果你有一個(gè)樹莓派和一個(gè)攝像機(jī)模塊,你可以編輯app.py文件從這個(gè)模塊中導(dǎo)入Camera類,然后你就可以利用樹莓派實(shí)時(shí)傳輸視頻流,就像我在下面的截圖中所做的:

2015331113106653.jpg (526×465)

如果你想要讓這個(gè)流傳輸應(yīng)用適用于不同的攝像機(jī),那么你要做的就是實(shí)現(xiàn)不同的Camera類。如果你最終能寫一個(gè)并提供給我的Github上的項(xiàng)目,我將不勝感激。
流的限制

當(dāng)Flask應(yīng)用服務(wù)器提供常規(guī)請(qǐng)求時(shí),請(qǐng)求周期短。工作線程(web worker)接收請(qǐng)求,調(diào)用處理函數(shù)并最終返回響應(yīng)。一旦響應(yīng)被發(fā)送回客戶端,工作線程是空閑的,并準(zhǔn)備執(zhí)行下一個(gè)請(qǐng)求。

當(dāng)接收到一個(gè)使用流式傳輸?shù)恼?qǐng)求時(shí),工作線程在整個(gè)流式傳輸?shù)某掷m(xù)時(shí)間內(nèi)綁定在一個(gè)客戶端上。當(dāng)處理時(shí)間長(zhǎng)而無止境的流時(shí),比如來自攝像機(jī)的視頻流,工作線程將鎖定在一個(gè)客戶端直到該客戶端連接斷開。這實(shí)際上意味著,除非采取特殊手段,否則應(yīng)用程序能服務(wù)的客戶端數(shù)量和工作線程是一樣的。當(dāng)使用Flask應(yīng)用的debug模式時(shí),這意味著只有一個(gè)工作線程,因此你將無法同時(shí)連接兩個(gè)瀏覽器窗口來同時(shí)查看來自兩個(gè)不同地方的數(shù)據(jù)流。

這里有辦法克服這一重要的限制。在我看來,最好的解決方案是使用基于協(xié)程的Web服務(wù)器,如gevent,F(xiàn)lask完全支持它。通過使用協(xié)程gevent能夠在一個(gè)工作線程上處理多個(gè)客戶端,因?yàn)間event修改Python I/O函數(shù)來進(jìn)行必要的上下文切換。
結(jié)論

如果你錯(cuò)過了上面的內(nèi)容,這篇文章中所包含的代碼放在了這個(gè)GitHub庫(kù)中:https://github.com/miguelgrinberg/flask-video-streaming。在這里,你可以找到一個(gè)通用的視頻流傳輸實(shí)現(xiàn)而不需要一個(gè)攝像機(jī),并且還有一個(gè)樹莓派攝像頭模塊實(shí)現(xiàn)。

我希望這篇文章闡述了一些有關(guān)流技術(shù)的話題。我關(guān)注于視頻流傳輸,因?yàn)檫@是一個(gè)我已有一些經(jīng)驗(yàn)的領(lǐng)域,但除了流媒體視頻之外,流傳輸技術(shù)還有很多其他的用途。例如,這種技術(shù)可以用來保持客戶端與服務(wù)器之間較長(zhǎng)時(shí)間的連接,允許服務(wù)器推送新的信息。這些日子,網(wǎng)絡(luò)套接字協(xié)議是實(shí)現(xiàn)這個(gè)更有效的方式,但網(wǎng)絡(luò)套接字是相當(dāng)新的,只在現(xiàn)代瀏覽器中有效,而流傳輸技術(shù)能在你能想到的任何瀏覽器中運(yùn)用。

相關(guān)文章

  • django中related_name的用法說明

    django中related_name的用法說明

    這篇文章主要介紹了django中related_name的用法說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-05-05
  • Python中python-nmap模塊的使用介紹

    Python中python-nmap模塊的使用介紹

    這篇文章主要介紹了Python中python-nmap模塊的使用,主要是portScanner()類方法展開全文,portScanner()類用于實(shí)現(xiàn)對(duì)指定主機(jī)進(jìn)行端口掃描,更多介紹內(nèi)容,需要的朋友可以參考一下
    2022-02-02
  • Python+Flask編寫一個(gè)簡(jiǎn)單的行人檢測(cè)API

    Python+Flask編寫一個(gè)簡(jiǎn)單的行人檢測(cè)API

    Flask是一個(gè)微型的Python開發(fā)的Web框架,基于Werkzeug WSGI工具箱和Jinja2模板引擎。本文將利用Flask框子編寫一個(gè)簡(jiǎn)單的行人檢測(cè)API,感興趣的可以了解一下
    2022-03-03
  • Python基礎(chǔ)之面向?qū)ο筮M(jìn)階詳解

    Python基礎(chǔ)之面向?qū)ο筮M(jìn)階詳解

    這篇文章主要為大家詳細(xì)介紹了Python基礎(chǔ)之面向?qū)ο筮M(jìn)階,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • python中如何寫類

    python中如何寫類

    在本篇文章里小編給大家分享的是一篇關(guān)于python中寫類的方法和技巧,需要的朋友們可以學(xué)習(xí)下。
    2020-06-06
  • Python數(shù)據(jù)結(jié)構(gòu)之棧詳解

    Python數(shù)據(jù)結(jié)構(gòu)之棧詳解

    棧和隊(duì)列是在程序設(shè)計(jì)中常見的數(shù)據(jù)類型,從數(shù)據(jù)結(jié)構(gòu)的角度來講,棧和隊(duì)列也是線性表,是操作受限的線性表。本文將詳細(xì)介紹一下Python中的棧,感興趣的可以了解一下
    2022-03-03
  • pycharm 2020.2.4 pip install Flask 報(bào)錯(cuò) Error:Non-zero exit code的問題

    pycharm 2020.2.4 pip install Flask 報(bào)錯(cuò) Error:Non-zero exit co

    這篇文章主要介紹了pycharm 2020.2.4 pip install Flask 報(bào)錯(cuò) Error:Non-zero exit code,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • tensorflow實(shí)現(xiàn)簡(jiǎn)單的卷積神經(jīng)網(wǎng)絡(luò)

    tensorflow實(shí)現(xiàn)簡(jiǎn)單的卷積神經(jīng)網(wǎng)絡(luò)

    這篇文章主要為大家詳細(xì)介紹了tensorflow實(shí)現(xiàn)簡(jiǎn)單的卷積神經(jīng)網(wǎng)絡(luò),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • Python優(yōu)化列表接口進(jìn)行分頁(yè)示例實(shí)現(xiàn)

    Python優(yōu)化列表接口進(jìn)行分頁(yè)示例實(shí)現(xiàn)

    最近,在做測(cè)試開發(fā)平臺(tái)的時(shí)候,需要對(duì)測(cè)試用例的列表進(jìn)行后端分頁(yè),在實(shí)際去寫代碼和測(cè)試的過程中,發(fā)現(xiàn)這里面還是有些細(xì)節(jié)的,故想復(fù)盤一下
    2021-09-09
  • Python?一篇文章看懂Python集合與字典數(shù)據(jù)類型

    Python?一篇文章看懂Python集合與字典數(shù)據(jù)類型

    集合并不是一種數(shù)據(jù)處理類型,而是一種中間類型。集合(set)是一個(gè)無序、不重復(fù)的元素序列,經(jīng)常被用來處理兩個(gè)列表進(jìn)行交并差的處理性。本文將詳細(xì)講解集合的一些常用方法,感興趣的可以了解一下
    2022-03-03

最新評(píng)論