您好,登錄后才能下訂單哦!
小編給大家分享一下使用Flask實現視頻的流媒體傳輸的方法,希望大家閱讀完這篇文章后大所收獲,下面讓我們一起去探討吧!
Flask 是一個 Python 實現的 Web 開發微框架。如何用它實現傳送視頻數據流呢?Flask應用擁有這樣一種能力,以分割成小數據塊的方式,高效地為大型請求提供數據。
什么是流媒體?
流媒體是一種技術,其中,服務器以數據塊的形式響應請求。我能想到一個原因來解釋為什么這個技術可能是有用的:
非常大的響應 。對于非常大的響應而言,內存中收集的響應只返回給客戶端,這是很低效的。另一種方法是將響應寫入磁盤,然后使用flask.send_file()返回文件,但是這增加了I/O的組合。假設數據可以分塊生成,以小塊數據的方式給請求提供響應是一種更好的解決方案。
實時數據 。對于一些應用,需要請求返回的數據來自實時數據源。
使用Flask實現流式傳輸
Flask通過使用生成器函數對流式響應提供本機支持。生成器是一個特別的函數,它可以中斷和恢復。考慮一下下面的函數:
def gen(): yield 1 yield 2 yield 3
這是一個運行三步的函數,其中每步返回一個值。描述生成器如何實現超出了本文的范圍,但如果你有點好奇,下面的shell會話將給你說明生成器是如何被使用的:
>>> 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
在這個簡單的例子中你能看到,一個生成器函數可以順序得返回多個結果。Flask使用生成器 函數這一特性來實現流式傳輸。
下面的例子說明了如何使用流式傳輸能夠產生大的數據表,而不必將整個表放入內存中:
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())
在這個例子中,你能看到Flask和生成器函數是如何一起工作的。返回流式響應的路由(route)需要返回一個由生成器函數初始化的Response對象。Flask然后采取調用生成器,并以分塊的方式吧結果發送給客戶端。
對于這個特殊的例子,如果你假設Stock.query.all()返回的數據庫查詢結果是一個迭代器,那么你能一次生成一個潛在大表的一行,因此無論查詢中的字符數量有多少,Python過程中的內存消耗不會因為較大的響應字符串而越來越大。
多部分響應
上文提到了表的例子以小塊的形式生成一個傳統網頁,各個的部分連接成最后的結果。對于如何生成較大的響應這是一個很好的例子,但更令人激動的事情是處理實時數據。
使用流式傳輸的一個有趣的應用是使用每個塊來替換原來頁面中的地方,這能使流在瀏覽器窗口中形成動畫。利用這種技術,你可以讓流中每個數據塊成為一個圖像,這給你提供了一個運行在瀏覽器中的很酷的視頻輸入信號!
實現就地更新的秘密是使用多部分響應。多部分響應由一個報頭(header)和很多部分(parts)組成。報頭包括多部分中的一種內容類型,后面的部分由邊界標記分隔,每個部分中含有自身部分中的特定內容類型。
對于不同的需求,這里有一些多部分內容類型。對于具有流式傳輸的,每個部分替換先前部分必須使用multipart/x-mixed-replace內容類型。為了幫助你了解它到底是什么樣子的,這里有一個多部分視頻流傳輸的響應結構:
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=""> ... </jpeg></jpeg>
正如你上面看到的,這個結構非常簡單。主要的Content-Type頭被設為multipart/x-mixed-replace,同時邊界標記也被定義。然后每個部分中包括,有兩個短橫線的前綴,及這行上的邊界字符串。每個部分有自己的Content-Type頭,并且每個部分可以可選地包括一個說明所在部分有效載荷的字節長度的Content-Length頭,但至少對圖像瀏覽器而言,能夠處理沒有長度的流。
建立一個實時視頻流媒體服務器
這篇文章中已經有足夠的理論,現在是時候來建立一個將實時視頻流式傳輸到Web瀏覽器的完整應用。
這里有很多方法將視頻流式傳輸到瀏覽器,并且每個方法都有其優點和缺點。與Flask流特征協同工作的一個好方法是流式傳輸獨立的JPEG圖片序列。這就是動態JPEG。這被用于許多IP監控攝像機。這種方法具有較短的延遲時間,但傳輸質量并不是最好的,因為對于動態影像而言,JPEG壓縮不是非常有效。
下面你可以看到一個非常簡單但完整的Web應用。它可以提供一個動態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)
這個應用導入一個Camera類來負責提供幀序列。在這個例子中,將camera控制部分放入一個單獨的模塊是一個很好的主意。這樣,Web應用會保持干凈、簡單和通用。
該應用有兩個路由(route)。/路由為主頁服務,被定義在index.html模板中。下面你能看到這個模板文件中的內容:
<title>Video Streaming Demonstration</title> <h2>Video Streaming Demonstration</h2> <img src="{{ url_for('video_feed') }}">
這是一個簡單的HTML頁面,只含有一個標題和圖像標簽。注意這個圖像標簽的src屬性指向這個應用的第二個路由,這就是魔法發生的地方。
/video_feed路由返回流式響應。因為這個流返回要被展示在web頁面上的圖像,在圖像標簽的src屬性中,URL指向這個路由。因為大多數/所有瀏覽器支持多部分響應(如果你找到一個不支持這個的瀏覽器,請告訴我),瀏覽器會通過顯示JPEG圖像流自動保持圖像元素的更新。
在/video_feed路由中使用的生成器函數叫gen(),將Camera類的一個實例作為其參數。mimetype參數設置如上所示,并具有multipart/x-mixed-replace的內容類型和設為"frame"的邊界字符串。
gen()函數進入一個循環,其中連續的從camera返回幀作為響應塊。如上所示,這個函數通過調用camera.get_frame()方法要求camera提供幀,然后生成幀,使用image/jpeg內容類型將該幀格式化為響應塊。
看完了這篇文章,相信你對使用Flask實現視頻的流媒體傳輸的方法有了一定的了解,想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。