Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-cloud-platform/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将碎片MP4转换为MP4_Python_Web Scraping_Websocket_Java Websocket_Fmp4 - Fatal编程技术网

Python 将碎片MP4转换为MP4

Python 将碎片MP4转换为MP4,python,web-scraping,websocket,java-websocket,fmp4,Python,Web Scraping,Websocket,Java Websocket,Fmp4,我试图从trafficview.org上抓取视频帧,但似乎不知道如何解码数据 我根据这方面的教程编写了几行代码,以访问实时流媒体websocket并直接接收消息 我已经通过Chrome上的网络标签监控了进来的消息,并深入研究了下面代码的输出,我相当确定这些数据是以碎片化的MP4形式流入的。以下是前100个左右字节/消息: \x0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\\x00

我试图从trafficview.org上抓取视频帧,但似乎不知道如何解码数据

我根据这方面的教程编写了几行代码,以访问实时流媒体websocket并直接接收消息

我已经通过Chrome上的网络标签监控了进来的消息,并深入研究了下面代码的输出,我相当确定这些数据是以碎片化的MP4形式流入的。以下是前100个左右字节/消息:

\x0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\\x00\\\x0\\\\x0\\x0\\x0\x0\x0\x0\\x0\x0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0\x00\x0\x00\\x0 0 0 0\\\\x0 0 0 0 0 0 0 0 0 0 0\\x0 0 0 0 0 0 0\\\\x0 0 0 0 0 0 0 0 0 0 0 0 0 0\\\x0 0 0 0 0\\\\x0 0 0 0 0 0 0 0 0 0 0 0 0\\\\x0 0 0 0 0 0 0\\\\\\\\\\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

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

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报头(也在下面),但无法解码任何字节

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的输出:

[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的流时,我意识到每个消息都以一个特定的整数开头,该整数在trafficview的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流中,因此我认为需要使用此标记信息从头构建正确的文件格式

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_开始和PBT_结束)都有4字节的特定于播放器的数据。只需要清理每条消息并按正确的顺序放置。然后将原始字节保存为mp4,瞧,这是在vlc中播放的视频。

您可以尝试对处理websocket数据的javascript代码进行反向工程。运行美化程序(例如),使其更具可读性,然后查看函数EvoWsPlayer.prototype.play和EvoPlayer.prototype.parseData。感谢您指出这一点。看起来这个脚本是写好的,然后故意把它弄得一团糟,使反向工程几乎不可能(有意义)。我也不懂JavaScript,所以它更像是一项任务。