首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将分段MP4转换为MP4

将分段MP4转换为MP4
EN

Stack Overflow用户
提问于 2020-09-09 21:41:21
回答 1查看 1.6K关注 0票数 2

我试图从trafficview.org中抓取视频帧,但似乎找不出如何解码这些数据。

我根据这个客户端上的教程编写了几行代码,以访问一个直播的websocket并直接接收消息。

我已经监控了通过Chrome上的网络选项卡输入的消息,还挖掘了下面代码的输出,并且相当肯定数据正在以一个零碎的MP4的形式流进来。下面是大约100个字节/消息:

b'\xfa\x00\x02\x86\xf1B\xc0\x1e\x00\x00\x00\x18ftypiso5\x00\x00\x02\x00iso6mp41\x00\x00\x02jmoov\x00\x00\x00lmvhd\x00\x00\x00\x00\xdb\x7f\xeb\xb2\xdb\x7f\xeb\xb2\x00\x00\x03\xe8\x00\x00\x00\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00‘

在整个输出过程中,有大量的moof和mdat对。假设我让这些代码运行30秒,如何将这个原始字节字符串转换为mp4文件?

代码语言:javascript
复制
import json

from websocket import create_connection

url = 'wss://cctv.trafficview.org:8420/DDOT_CAPTOP_13.vod?progressive'

headers = json.dumps({
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'en-US,en;q=0.9',
    'Cache-Control': 'no-cache',
    'Connection': 'Upgrade',
    'Host': 'cctv.trafficview.org:8420',
    'Origin': 'https://trafficview.org',
    'Pragma': 'no-cache',
    'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits',
    'Sec-WebSocket-Key': 'FzWbrsoHFsJWzvWGJ04ffw==',
    'Sec-WebSocket-Version': '13',
    'Upgrade': 'websocket',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36',
})

ws = create_connection(url, headers=headers)

# Then send a message through the tunnel
ws.send('ping')

# Here you will view the message return from the tunnel
flag = 3000
output = b''
while flag > 0:
    output += ws.recv()
    flag -= 1

更新:我已经对堆栈溢出的一些代码进行了修改,使之能够在fmp4数据中使用管道,并将其转换为框架。为了达到这个目的,我注意到websocket输出的前16个字节与我检查过的其他mp4文件不一致。所以我首先修剪前16个字节。我也不知道其中一个文件应该如何结束,所以我削减到文件的最后一个moof。

下面的代码可以很好地读取mp4头(也在下面),但是无法解码任何字节。

代码语言:javascript
复制
output = output[8:]

import re
moof_locs = [m.start() for m in re.finditer(b'moof', output)]

output = output[:moof_locs[-1]-1]

import subprocess as sp
import shlex

width, height = 640, 480

# FFmpeg input PIPE: WebM encoded data as stream of bytes.
# FFmpeg output PIPE: decoded video frames in BGR format.
process = sp.Popen(shlex.split('/usr/bin/ffmpeg -i pipe: -f hls -hls_segment_type fmp4 -c h264 -an -sn pipe:'), stdin=sp.PIPE, stdout=sp.PIPE, bufsize=10**8)
process.stdin.write(output)
process.stdin.close()
in_bytes = process.stdout.read(width * height * 3)
in_frame = (np.frombuffer(in_bytes, np.uint8).reshape([height, width, 3]))

来自ffmpeg的产出:

代码语言:javascript
复制
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x994600] Could not find codec parameters for stream 0 (Video: h264 (avc1 / 0x31637661), none, 640x480): unspecified pixel format
Consider increasing the value for the 'analyzeduration' and 'probesize' options
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'pipe:':
  Metadata:
    major_brand     : iso5
    minor_version   : 512
    compatible_brands: iso6mp41
    creation_time   : 2020-09-11T13:40:21.000000Z
  Duration: N/A, bitrate: N/A
    Stream #0:0(und): Video: h264 (avc1 / 0x31637661), none, 640x480, 1k tbr, 1k tbn, 2k tbc (default)
    Metadata:
      creation_time   : 2020-09-11T13:40:21.000000Z
      encoder         : EvoStream Media Server
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
Finishing stream 0:0 without any data written to it.
Nothing was written into output file 0 (pipe:), because at least one of its streams received no packets.
frame=    0 fps=0.0 q=0.0 Lsize=       0kB time=-577014:32:22.77 bitrate=  -0.0kbits/s speed=N/A    
video:0kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
Output file is empty, nothing was encoded (check -ss / -t / -frames parameters if used)

更新2:

在检查来自websocket的流时,我意识到每条消息都以一个特定的整数开头,该整数是在流量视图的javascript代码中定义的。这些代码的顺序总是相同的,它们的顺序如下:

代码语言:javascript
复制
Header MOOV (250)
    PBT Begin (249)
        Video Buffer (252)
        Header MOOF (251)
        Header MOOF (251)
        Header MOOF (251)
        Header MDAT (254)
    PBT End (255)

    PBT Begin (249)
    Continues Forever

其中一些标记总是相同的,例如249个消息总是f900 0000,而255个消息总是ff00 0000。

我猜想249和255条消息通常不在一个分段的mp4或hls流中,因此我认为我需要使用这些标记信息从零开始构建正确的文件格式。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-09-15 22:07:48

代码语言:javascript
复制
ws = create_connection(url, headers=headers)
# Then send a message through the tunnel
ws.send('ping')

start = timeit.default_timer()
flag = True
output = []
while flag:
    output.append(ws.recv())
    if timeit.default_timer() - start > 90:
        flag = False

result = output[0][8:]

for msg in output[1:]:
    if msg[0] == 249:
        moofmdat = b''
        moof = b''
        continue

    if msg[0] == 252:
        vidbuf = msg[4:]

    if msg[0] == 251:
        moof += msg[4:]

    if msg[0] == 254:
        mdat = msg[4:]

    if msg[0] == 255:
        moofmdat += moof
        moofmdat += mdat
        moofmdat += vidbuf
        result += moofmdat

with open('test.mp4', 'wb') as file:
    file.write(result)

弄明白了。MOOV报头有8个字节的不必要信息,必须删除。每个附加消息(除了PBT_Begin和PBT_End)都有4个字节的特定于播放器的数据。只需要清理每一条信息,并按正确的顺序放置。然后将原始字节保存为mp4和vlc中播放的视频。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63819924

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档