Быстрое считывание значения PID MPEG Transport steam (двоичный файл) в Python

#python #python-3.x #mpeg #mpeg2-ts #transport-stream

Вопрос:

У меня большой двоичный файл MPEG (.ts), обычно кратный 188 байтам, я использую python3,когда я каждый раз читаю 188 байт и анализирую, чтобы получить требуемое значение, я обнаружил, что это очень медленно. Я должен пройти через каждый пакет размером 188 байт, чтобы получить значение PID (двоичные данные).

  • В то же время, когда я использую любой профессиональный анализатор MPEG offline, они получают список всех значений PID и их общее количество в течение 45 секунд в течение 5 минут в файле TS, где моей программе требуется > 10 минут, чтобы получить то же самое.
  • Я не понимаю, как быстро они могут найти, даже если они могут быть написаны на c или c .
  • Я пробовал многопроцессорную обработку python, но это не очень помогает. это означает, что мой метод анализа и обработки 188 байтов данных не является правильным и вызывает огромную задержку.

 `with open(file2,'rb') as f:
data=f.read(188)
if len(data)==0: break
b=BitStream(data)
...   #parse b to get the required value 
...   # and increase count when needed
...
cnt=cnt 188 
f.seek(cnt)`
 

Ответ №1:

Это твой кодовый человек.

Я тоже некоторое время пробовал Bitstream, он медленный.

Модуль cProfile — ваш друг.

С помощью pypy3 я могу проанализировать 3,7 ГБ mpeg-файлов за 2,9 секунды, один процесс.

С Go-lang я могу разобрать 3,7 ГБ за 1,2 секунды.

Комментарии:

1. да, наконец-то я написал код на c , и это довольно быстро, для 24 ГБ это заняло менее 3 минут. Я постараюсь с помощью модуля cProfile получить анализ. позвольте мне проверить pypy3

2. Ты классный мужик.pypy3 быстро глупеет Вот как это сделать на Python

Ответ №2:

Ты классный парень. Попробуй вот так:

 ```import sys
from functools import partial


PACKET_SIZE= 188

def do():
    args = sys.argv[1:]
    for arg in args:
        print(f'next file: {arg}')
        pkt_num=0
        with open(arg,'rb') as vid:
             for pkt in iter(partial(vid.read, PACKET_SIZE), b""):
                 pkt_num  =1
                 pid =(pkt[1] << 8 | pkt[2]) amp; 0x01FFF
                 print(f'Packet: {pkt_num} Pid: {pid}', end='r')
         
if __name__ == "__main__":
    do()
 

имейте в виду, что печать каждого pid будет; замедлять вас, в 3,7 ГБ mpeg-файлов содержится 20 миллионов пакетов

 a@fumatica:~/threefive$ time pypy3 cli2.py plp0.ts 
next file: plp0.ts
Packet: 20859290 Pid: 1081
real    1m22.976s
user    0m48.331s
sys     0m34.323s
 

печать каждого pid
занимает 1m22.976s

если я прокомментирую

    #print(f'Packet: {pkt_num} Pid: {pid}', end='r')
 

это происходит гораздо быстрее

 a@fumatica:~/threefive$ time pypy3 no_print.py plp0.ts 
next file: plp0.ts

real    0m3.080s
user    0m2.237s
sys     0m0.816s

 

если я изменю вызов печати на

                  print(f'Packet: {pkt_num} Pid: {pid}')
 

и перенаправить вывод в файл,

для анализа 3,7 ГБ требуется всего 9 секунд

 a@fumatica:~/threefive$ time pypy3 cli2.py plp0.ts > out.pids

real    0m9.228s
user    0m7.820s
sys     0m1.229s

a@fumatica:~/threefive$ wc -l out.pids 
20859291 out.pids
 

надеюсь, это поможет тебе, парень.

Комментарии:

1. Большое вам спасибо, одна ошибка, которую я допустил, заключается в том, что я использовал f.seek (), который не был нужен, я понял, когда использовал c . Pypy быстрее, чем python, c занял почти половину времени, которое занимает pypy. Я даже слышал о «нумбе». Вы пробовали?

2. Я не пробовал numba, я не собирался использовать pypy3, но я рад, что сделал это. Мой код работает в среднем в 4 раза быстрее. Сейчас я собираюсь проверить нумбу. 🙂