V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
acbot
V2EX  ›  JavaScript

MSE 流媒体录取的的问题

  •  
  •   acbot · 2022-12-05 12:01:35 +08:00 · 1196 次点击
    这是一个创建于 751 天前的主题,其中的信息可能已经有所发展或是发生改变。

    MediaSource.prototype.addSourceBuffer = function (mime) { ... }

    目前很多油猴脚本通过上述代码实现网页 m3u8 视频录取,测试过几个脚本基本上录取视频都没有问题,但是音频方面大多时候有问题。在不修改 video 标签 playbackRate 属性的情况下,音频部分脚本在部分网页能正常录取(不失真);但修改 video 标签的 playbackRate 属性的情况下(加速播放),基本音频都失真了,请问这个原因是什么:

    1. 本身这种录取实现就有问题,比如:包顺序,或者说要相应的设置音频 playbackRate 等
    2. 因为录取后音频和视频是分开的,那么有没有可能是 mp4a 格式的音频在其他播放器解码问题造成的失真,因为 PotPlayer 播放好像不失真
    第 1 条附言  ·  2022-12-05 15:26:38 +08:00
    核心代码片段

    (function (addSourceBuffer) {
    MediaSource.prototype.addSourceBuffer = function (mime) {
    console.log(mime)
    switch (mime.substr(0, 5)){
    case "audio":
    window.ams = addSourceBuffer.call(this, mime);
    return window.ams
    window.audioBuffer = [];
    break;
    case "video":
    window.vms = addSourceBuffer.call(this, mime);
    return window.vms
    window.videoBuffer = [];
    break;
    default:
    return addSourceBuffer.call(this, mime);
    }
    };
    })(MediaSource.prototype.addSourceBuffer);

    window.videoBuffer = [];
    window.audioBuffer = [];

    (function (appendBuffer) {
    SourceBuffer.prototype.appendBuffer = function (source) {
    if(this == window.ams){
    console.log("audio buffer get")
    window.audioBuffer[window.audioBuffer.length] = source
    }
    if(this == window.vms){
    console.log("video buffer get")
    window.videoBuffer[window.videoBuffer.length] = source
    }
    appendBuffer.call(this, source);
    };
    })(SourceBuffer.prototype.appendBuffer);
    9 条回复    2022-12-10 11:07:02 +08:00
    mxT52CRuqR6o5
        1
    mxT52CRuqR6o5  
       2022-12-05 12:35:53 +08:00 via Android
    不失真是因为用特殊算法处理过了,原始音频直接在时域上变速必失真的
    acbot
        2
    acbot  
    OP
       2022-12-05 13:17:43 +08:00
    @mxT52CRuqR6o5 "...原始音频直接在时域上变速必失真的.." 没太看懂,能说详细一点吗!加速播放过程仅仅是为了把视频音频读取到本地,这个过程加速音频失真很正常,我说的是缓存的音频文件也是失真的,而同样加速播放视频缓存文件确实正常的
    wanacry
        3
    wanacry  
       2022-12-05 13:52:31 +08:00
    可能的原因是,在修改 video 标签的 playbackRate 属性之后,音频部分没有相应地调整其采样率和帧率,导致在播放器中解码时出现失真。这种情况下,视频部分可能会正常播放,但是音频部分可能会出现失真的情况。为了避免这种情况的发生,需要在修改 video 标签的 playbackRate 属性之后,相应地调整音频采样率和帧率,以保证音频能够正常播放。
    hu8245
        4
    hu8245  
       2022-12-05 15:08:20 +08:00
    音频倍速必须重采样才能不失真,你直接拿肯定有问题啊。1 楼说的是正确
    acbot
        5
    acbot  
    OP
       2022-12-05 15:25:54 +08:00
    @hu8245
    @wanacry

    代码如下,应该在什么位置调整呢?

    (function (addSourceBuffer) {
    MediaSource.prototype.addSourceBuffer = function (mime) {
    console.log(mime)
    switch (mime.substr(0, 5)){
    case "audio":
    window.ams = addSourceBuffer.call(this, mime);
    return window.ams
    window.audioBuffer = [];
    break;
    case "video":
    window.vms = addSourceBuffer.call(this, mime);
    return window.vms
    window.videoBuffer = [];
    break;
    default:
    return addSourceBuffer.call(this, mime);
    }
    };
    })(MediaSource.prototype.addSourceBuffer);

    window.videoBuffer = [];
    window.audioBuffer = [];

    (function (appendBuffer) {
    SourceBuffer.prototype.appendBuffer = function (source) {
    if(this == window.ams){
    console.log("audio buffer get")
    window.audioBuffer[window.audioBuffer.length] = source
    }
    if(this == window.vms){
    console.log("video buffer get")
    window.videoBuffer[window.videoBuffer.length] = source
    }
    appendBuffer.call(this, source);
    };
    })(SourceBuffer.prototype.appendBuffer);
    wanacry
        6
    wanacry  
       2022-12-05 15:58:59 +08:00
    在这段代码中,可以在 MediaSource.prototype.addSourceBuffer 函数中添加调整逻辑,例如在区分不同 mime 类型后,根据当前 mime 类型设置不同的播放速度,从而解决音频失真问题。

    具体代码如下:

    (function (addSourceBuffer) {
    MediaSource.prototype.addSourceBuffer = function (mime) {
    console.log(mime)
    switch (mime.substr(0, 5)){
    case "audio":
    // 设置音频播放速度
    window.ams = addSourceBuffer.call(this, mime);
    ams.playbackRate = 1;
    return window.ams
    window.audioBuffer = [];
    break;
    case "video":
    window.vms = addSourceBuffer.call(this, mime);
    return window.vms
    window.videoBuffer = [];
    break;
    default:
    return addSourceBuffer.call(this, mime);
    }
    };
    })(MediaSource.prototype.addSourceBuffer);

    window.videoBuffer = [];
    window.audioBuffer = [];

    (function (appendBuffer) {
    SourceBuffer.prototype.appendBuffer = function (source) {
    if(this == window.ams){
    console.log("audio buffer get")
    window.audioBuffer[window.audioBuffer.length] = source
    }
    if(this == window.vms){
    console.log("video buffer get")
    window.videoBuffer[window.videoBuffer.length] = source
    }
    appendBuffer.call(this, source);
    };
    })(SourceBuffer.prototype.appendBuffer);
    acbot
        7
    acbot  
    OP
       2022-12-05 17:01:24 +08:00
    @wanacry 谢谢指教,我试试!
    acbot
        8
    acbot  
    OP
       2022-12-05 17:04:30 +08:00
    @wanacry 我还有一个问题,位什么视频不在这里添加处理逻辑 而直接设置标签的属性就可以呢,是音频和视频本身不一样,还是这里应该区获取音频,或者说 video 标签的 playbackRate 属性不能设置音频 比如:let video = document.querySelector('video'); video.playbackRate = 10
    acbot
        9
    acbot  
    OP
       2022-12-10 11:07:02 +08:00
    @wanacry 很遗憾 修改后音频直接是错误的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1621 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 16:51 · PVG 00:51 · LAX 08:51 · JFK 11:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.