【问题标题】:Serving a .mp4 file with Flask and playing it on an Objective-C app causes Broken pipe and no play使用 Flask 提供 .mp4 文件并在 Objective-C 应用程序上播放会导致管道损坏且无法播放
【发布时间】:2018-04-24 12:11:20
【问题描述】:

我正在尝试在我的 iOS 应用程序上播放由 Flask 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];

Python

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,则视频已正确加载。

我该如何解决我的问题?

提前谢谢你!

【问题讨论】:

  • 你终于可以在IOS玩了吗?我有同样的问题

标签: python objective-c video flask avplayer


【解决方案1】:

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

我遵循https://codeburst.io/the-taste-of-media-streaming-with-flask-cdce35908a50 的示例,Flask 服务器代码需要使用“部分内容”(HTTP 状态代码 206)构建响应,并且需要处理请求中的“范围”标头。相关代码如下所示:

  1. 在 Flask 应用 after_request 中添加“Accept-Ranges”,以便客户端知道支持“range”:
@app.after_request
def after_request(response):
    response.headers.add('Accept-Ranges', 'bytes')
    return response
  1. 在提供 mp4 文件的函数中,假设文件路径为“full_path”:
    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

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

【讨论】:

  • 我在烧瓶上有完全相同的代码,但不工作。我认为 AVPlayer 不支持部分内容
【解决方案2】:

你有两个选择:

  1. 打开文件并以块的形式读取它,而不是像在您的代码中那样将其作为单个 blob 读取。跟随示例来自:https://stackoverflow.com/a/24318158/1955346:

    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")
    
  2. 使用来自How do I stream a file using werkzeug? 的直接方法: return Response(file("/root/media_assets/" + file["path"]), direct_passthrough=True)

【讨论】:

  • 这两种解决方案都无法解决我的问题。第一个使我的视频无休止地加载,第二个并没有改变问题。如果有帮助的话,我发现不仅 iOS,Mac 版 Safari 也有这个问题,而任何操作系统(包括 macOS)和 Firefox 的 Chrome 都没有问题。
猜你喜欢
  • 1970-01-01
  • 2017-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-24
  • 2013-05-17
  • 1970-01-01
相关资源
最近更新 更多