Python 使用烧瓶提供.mp4文件并在Objective-C应用程序上播放会导致管道破裂和无法播放

Python 使用烧瓶提供.mp4文件并在Objective-C应用程序上播放会导致管道破裂和无法播放,python,objective-c,video,flask,avplayer,Python,Objective C,Video,Flask,Avplayer,我正在尝试播放由iOS应用程序上的Flask web应用程序提供服务的视频。虽然我可以播放“传统”web服务器(如Apache)提供的任何视频,但我不能播放Flask提供的视频。以下是相关代码: 目标-C NSURL *videoURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@",videourltemp]]; AVPlayer *player = [AVPlayer playerWithURL:videoURL]; play

我正在尝试播放由iOS应用程序上的Flask web应用程序提供服务的视频。虽然我可以播放“传统”web服务器(如Apache)提供的任何视频,但我不能播放Flask提供的视频。以下是相关代码:

目标-C

NSURL *videoURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@",videourltemp]];
AVPlayer *player = [AVPlayer playerWithURL:videoURL];

playerViewController.player = player;
[self.view addSubview:playerViewController.view];
[self.navigationController pushViewController:playerViewController animated:YES];
蟒蛇

from flask import Response, ...

def get_img(imgid):
    # private code hidden - file["path"] contains the path relative to /root/media_assets directory

    return Response(open("/root/media_assets/" + file["path"], "rb"), mimetype="video/mp4")
旁注:如果我试图从浏览器访问我的URL,则视频已正确加载

我怎样才能解决我的问题


提前谢谢你

您有两个选择:

  • 打开文件并将其分块读取,而不是像代码中那样将其作为单个blob读取。下面的例子来自:

  • 使用以下直接方法:
    
    返回响应(文件(“/root/media\u assets/”+文件[“path”]),direct\u passthrough=True)
    


  • 我遇到了同样的问题,最终发现真正的问题是视频播放器客户端(至少在Objective-CIOS中)在响应中使用了“range”头(您可以打印出Flask
    request.headers
    进行检查)。换句话说,流实际上是使用HTTP中的“范围”支持实现的

    我在上进行了示例,Flask服务器代码需要使用“部分内容”(HTTP状态代码206)构建响应,并且需要处理请求中的“范围”头。相关代码如下所示:

  • 在请求后在Flask app中添加“接受范围”,以便客户知道支持“范围”:
  • 在为mp4文件提供服务的函数中,假设文件路径为“full_path”:
  • file\u size=os.stat(完整路径).st\u size
    开始=0
    长度=10240#可以是您想要的任何默认长度
    range\u header=request.headers.get('range',None)
    如果范围_标题:
    m=重新搜索(“([0-9]+)-([0-9]*)”,范围(U标题)#示例:0-1000或1250-
    g=m.群()
    字节1,字节2=0,无
    如果g[0]:
    字节1=int(g[0])
    如果g[1]:
    字节2=int(g[1])
    如果字节1<文件大小:
    开始=字节1
    如果字节2:
    长度=字节2+1-字节1
    其他:
    长度=文件大小-开始
    打开(完整路径,'rb')作为f:
    f、 搜索(开始)
    chunk=f.read(长度)
    rv=响应(chunk,206,mimetype='video/mp4',content\u type='video/mp4',direct\u passthrough=True)
    add('Content-Range','bytes{0}-{1}/{2}'。格式(start,start+length-1,文件大小))
    返回rv
    

    在我的测试中,上述Flask代码适用于iOS objective-C客户端以及用于.mp4文件的Chrome、Firefox浏览器。

    这两种解决方案都无法解决我的问题。第一个使我的视频加载无休止,第二个并没有改变问题。如果有帮助的话,我已经看到,不仅iOS,Mac版的Safari都有这个问题,而任何操作系统(包括macOS)和Firefox版的Chrome都没有问题。
    from flask import stream_with_context, Response
    
    @app.route('/stream_data')
    def stream_data():
        def generate():
            with open("/root/media_assets/" + file["path"], "rb") as f:
                while True:
                    chunk = ... # read each chunk or break if EOF
                    yield chunk
    
        return Response(stream_with_context(generate()), mimetype="video/mp4")
    
    @app.after_request
    def after_request(response):
        response.headers.add('Accept-Ranges', 'bytes')
        return response
    
        file_size = os.stat(full_path).st_size
        start = 0
        length = 10240  # can be any default length you want
    
        range_header = request.headers.get('Range', None)
        if range_header:
            m = re.search('([0-9]+)-([0-9]*)', range_header)  # example: 0-1000 or 1250-
            g = m.groups()
            byte1, byte2 = 0, None
            if g[0]:
                byte1 = int(g[0])
            if g[1]:
                byte2 = int(g[1])
            if byte1 < file_size:
                start = byte1
            if byte2:
                length = byte2 + 1 - byte1
            else:
                length = file_size - start
    
        with open(full_path, 'rb') as f:
            f.seek(start)
            chunk = f.read(length)
    
        rv = Response(chunk, 206, mimetype='video/mp4', content_type='video/mp4', direct_passthrough=True)
        rv.headers.add('Content-Range', 'bytes {0}-{1}/{2}'.format(start, start + length - 1, file_size))
        return rv