Я пытаюсь обернуть небольшой удобный фрагмент кода C ++, который предназначен для генерации видео + аудио в окнах с использованием VFW, библиотека C ++ живет здесь , а в описании написано:
Использует видео для Windows (поэтому оно не переносимо). Удобно, если вы хотите
быстро записать видео где-нибудь и не хочется пробираться
VfW самостоятельно.
Я бы хотел использовать эту библиотеку C ++ на Python, поэтому я решил обернуть ее с помощью swig.
Дело в том, что у меня возникают некоторые проблемы, когда дело доходит до кодирования аудио, по какой-то причине я пытаюсь понять, почему сгенерированное видео повреждено, кажется, что аудио не было записано должным образом в видеофайле. Это означает, что если я попытаюсь открыть видео с помощью VLC или любого другого аналогичного видеопроигрывателя, я получу сообщение о том, что видеопроигрыватель не может идентифицировать аудио- или видеокодек. Видеоизображения в порядке, так что это определенно проблема с тем, как я записываю аудио в файл.
Я прилагаю и интерфейс Swig, и небольшой тест Python, который пытается быть портом оригинального теста c ++ .
aviwriter.i
%module aviwriter
%{
#include "aviwriter.h"
%}
%typemap(in) (const unsigned char* buffer) (char* buffer, Py_ssize_t length) %{
if(PyBytes_AsStringAndSize($input,&buffer,&length) == -1)
SWIG_fail;
$1 = (unsigned char*)buffer;
%}
%typemap(in) (const void* buffer) (char* buffer, Py_ssize_t length) %{
if(PyBytes_AsStringAndSize($input,&buffer,&length) == -1)
SWIG_fail;
$1 = (void*)buffer;
%}
%include "aviwriter.h"
test.py
import argparse
import sys
import struct
from distutils.util import strtobool
from aviwriter import AVIWriter
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-audio", action="store", default="1")
parser.add_argument('-width', action="store",
dest="width", type=int, default=400)
parser.add_argument('-height', action="store",
dest="height", type=int, default=300)
parser.add_argument('-numframes', action="store",
dest="numframes", type=int, default=256)
parser.add_argument('-framerate', action="store",
dest="framerate", type=int, default=60)
parser.add_argument('-output', action="store",
dest="output", type=str, default="checker.avi")
args = parser.parse_args()
audio = strtobool(args.audio)
framerate = args.framerate
num_frames = args.numframes
width = args.width
height = args.height
output = args.output
writer = AVIWriter()
if not writer.Init(output, framerate):
print("Couldn't open video file!")
sys.exit(1)
writer.SetSize(width, height)
data = [0]*width*height
sampleRate = 44100
samples_per_frame = 44100 / framerate
samples = [0]*int(samples_per_frame)
c1, s1, f1 = 24000.0, 0.0, 0.03
c2, s2, f2 = 1.0, 0.0, 0.0013
for frame in range(num_frames):
print(f"frame {frame}")
i = 0
for y in range(height):
for x in range(width):
on = ((x + frame) & 32) ^ ((y+frame) & 32)
data[i] = 0xffffffff if on else 0xff000000
i += 1
writer.WriteFrame(
struct.pack(f'{len(data)}L', *data),
width*4
)
if audio:
for i in range(int(samples_per_frame)):
c1 -= f1*s1
s1 += f1*c1
c2 += f2*s2
s2 -= f2*c2
val = s1 * (0.75 + 0.25 * c2)
if(frame == num_frames - 1):
val *= 1.0 * (samples_per_frame - 1 - i) / \
samples_per_frame
samples[i] = int(val)
if frame==0:
print(f"i={i} val={int(val)}")
writer.WriteAudioFrame(
struct.pack(f'{len(samples)}i', *samples),
int(samples_per_frame)
)
writer.Exit()
Я не думаю, что samples
генерируется неправильно, так как я уже сравнил значения, сгенерированные на стороне python, со значениями, сгенерированными на стороне c ++, но только пакет, написанный для кадра 0.
Некоторые из моих подозрений о том, что не так, это то, как я создал карту типов на swig, может быть, это нехорошо ... или, возможно, проблема в строке writer.WriteAudioFrame(struct.pack(f'{len(samples)}i', *samples), int(samples_per_frame))
, я не знаю, что может быть, определенно, способ отправки аудио-буфера из Python в оболочку C ++ не очень хорош.
Итак, знаете ли вы, как исправить прикрепленный код, чтобы test.py мог генерировать видео с правильным звуком, аналогично тесту c ++?
Когда сгенерировано нормально, видео отобразит волшебную прокручиваемую шахматную доску с гипнотическими синусоидами в качестве звукового фона: D
Дополнительные примечания:
1) Кажется, в приведенном выше коде не используется writer.SetAudioFormat
, который необходим для функций AVIFileCreateStreamA
и AVIStreamSetFormat
. Проблема в том, что я не знаю, как экспортировать эту структуру на swig, поэтому я мог бы использовать ее на Python так же, как test.cpp
, из Mmreg.h. Я видел, что структура выглядит так:
typedef struct tWAVEFORMATEX
{
WORD wFormatTag; /* format type */
WORD nChannels; /* number of channels (i.e. mono, stereo...) */
DWORD nSamplesPerSec; /* sample rate */
DWORD nAvgBytesPerSec; /* for buffer estimation */
WORD nBlockAlign; /* block size of data */
WORD wBitsPerSample; /* Number of bits per sample of mono data */
WORD cbSize; /* The count in bytes of the size of
extra information (after cbSize) */
} WAVEFORMATEX;
К сожалению, я не знаю, как обернуть это на aviwriter.i? Я попытался использовать% include windows.i и включить материал непосредственно в блок %{
... %}
, но все, что я получил, было кучей ошибок: /
2) Я бы предпочел не изменять ни aviwriter.h && aviwriter.cpp, так как это в основном внешний рабочий код.
3) Если я могу обернуть WAVEFORMATEX
, чтобы использовать его на Python, как бы вы использовали memset аналогично test.cpp
? т.е.: memset(&wfx,0,sizeof(wfx));