Skip to content

Instantly share code, notes, and snippets.

@w495
Created May 17, 2015 22:21
Show Gist options
  • Save w495/173534c1de5e969cbd7e to your computer and use it in GitHub Desktop.
Save w495/173534c1de5e969cbd7e to your computer and use it in GitHub Desktop.
Простой символьный консольный видео-плеер. Написан с помощью библиотеки PyAV http://mikeboers.github.io/PyAV/
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Простой текстовый консольный видео-плеер.
Выводит кадры в символьном представлении на стандартный вывод.
Поддержки звука нет.
Как пользоваться:
$> simple-console-video-player.py /путь/до/видео-файла.mp4
'''
import sys
##
## Импортируем библиотеку PyAV (http://mikeboers.github.io/PyAV/).
## Библиотека была установлено командой
## $> conda install -c danielballan pyav.
##
import av
from av.video.frame import VideoFrame
##
## Масштаб видео.
##
SCALE_MEASURE = 0.5
##
## Формат видео.
## В данном случае оттенки серого цвета от 0 до 2¹⁶ (65536).
##
FORMAT = 'gray16'
FORMAT_GRAY16_SIZE = 65536
##
## Представление пикселей с помощью символов псевдографики.
##
TEXT_PIXEL_LIST = u' .-+#'
##
## Видео-файл по-умолчанию.
##
DEFAULT_FILE_NAME = 'video1.mp4'
def main():
## Получаем имя видео-файла.
video_file_name = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_FILE_NAME
## Открываем его как видео-контейнер.
video_container = av.open(video_file_name)
## Извлекаем пакеты из видео-контейнера — получаем список.
packet_list = video_container.demux()
## Выполняем для каждого пакета.
for packet in packet_list:
# Получаем список кадров из пакета.
frame_list = packet.decode()
## Выполняем для каждого кадра из списка.
for frame in frame_list:
## Если кадры — это видео
## (а могут быть еще аудио, например).
if(type(frame) == VideoFrame):
new_width = int(SCALE_MEASURE * frame.width)
new_height = int(SCALE_MEASURE * frame.height)
## Создаем временную кадр-структуру в нужном нам формате.
tmp_frame = frame.reformat(
width = new_width,
height = new_height,
format = FORMAT
)
## Получаем из временного кадра двумерный массив пикселей.
nd_array = tmp_frame.to_nd_array()
## Печатаем массив точек.
for nd_array1 in nd_array:
for x in nd_array1:
## Рисуем пиксель в консоль без перевода строки.
print get_gray16_text_pixel(x),
## Строка пикселей кончилась,
## делаем перевод строки.
print '\n'
## Конец кадра рисуем ограничитель
print '\n\n'
print '==' * (new_width)
print '\n\n'
print 'Fin!'
def get_gray16_text_pixel(pixel):
'''
Возвращает символ-пиксель, который соответствует,
настоящему пикселю-числу формата «gray16».
'''
## Получаем размер диапазона оттенков,
## который будет представлен одним нашим текстовым «пикселем»
step = FORMAT_GRAY16_SIZE / len(TEXT_PIXEL_LIST)
## Вычисляем номер нашего текстового пикселя.
text_pixel_index = pixel / step
## Возвращаем символ из списка текстовых «пикселей»
return TEXT_PIXEL_LIST[text_pixel_index]
if (__name__ == '__main__'):
main()
@w495
Copy link
Author

w495 commented May 31, 2015

Для сравнения аналогичный пример на Go (Golang):
https://gist.github.com/w495/1a40a09bfe50b8841602

@vldanch
Copy link

vldanch commented Jun 7, 2018

Выдает ошибку:

Traceback (most recent call last):
  File "./simple-console-video-player.py", line 104, in <module>
    main()
  File "./simple-console-video-player.py", line 74, in main
    nd_array = tmp_frame.to_nd_array()
  File "av/video/frame.pyx", line 259, in av.video.frame.VideoFrame.to_nd_array
ValueError: Cannot conveniently get numpy array from gray16le format

Как решить?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment