title: Bug writing audio using custom video writer library
body: <p>I'm trying to wrap a little handy piece of C++ code that is intended to generate video+audio on windows using VFW, the C++ library lives <a href="http://www.farbrausch.de/~fg/code/aviwriter/" rel="nofollow noreferrer">here</a> and the descriptions says: </p>
  
  <blockquote>
    <p>Uses Video for Windows (so it's not portable). Handy if you want to
    quickly record a video somewhere and don't feel like wading through
    the VfW docs yourself.</p>
  </blockquote>
  
  <p>I'd like to use that C++ library on Python so I've decided to wrap it up using swig.</p>
  
  <p>Thing is, I'm having some problems when it comes to encode the audio, for some reason I'm trying to understand why the generated video is broken, it seems the audio has not been written properly in the video file. That means, if I try to open the video with VLC or any similar video player I'll get a message saying the video player can't identify the audio or video codec. The video images are fine so it's definitely a problem with the way I'm writing the audio to the file.</p>
  
  <p>I'm attaching both the swig interface and a little Python test that's trying to be a port of the original <a href="http://www.farbrausch.de/~fg/code/aviwriter/test.cpp" rel="nofollow noreferrer">c++ test</a>.</p>
  
  <p><strong>aviwriter.i</strong></p>
  
  <pre><code>%module aviwriter
  
  %{
  #include "aviwriter.h"
  %}
  
  %typemap(in) (const unsigned char* buffer) (char* buffer, Py_ssize_t length) %{
    if(PyBytes_AsStringAndSize($input,&amp;buffer,&amp;length) == -1)
      SWIG_fail;
    $1 = (unsigned char*)buffer;
  %}
  
  %typemap(in) (const void* buffer) (char* buffer, Py_ssize_t length) %{
    if(PyBytes_AsStringAndSize($input,&amp;buffer,&amp;length) == -1)
      SWIG_fail;
    $1 = (void*)buffer;
  %}
  
  
  %include "aviwriter.h"
  </code></pre>
  
  <p><strong>test.py</strong></p>
  
  <pre><code>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) &amp; 32) ^ ((y+frame) &amp; 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()
  </code></pre>
  
  <p>I don't think <code>samples</code> is being generated incorrectly as I've already compared the values generated on the python side with the values generated on the c++ side, just the packet written for frame 0 though. </p>
  
  <p>Some of my suspicions about what's wrong is the way I've created the typemap on swig, maybe that's not good... or maybe the problem lives in the line <code>writer.WriteAudioFrame(struct.pack(f'{len(samples)}i', *samples), int(samples_per_frame))</code>, I don't know what could be, definitely the way I'm sending the audio buffer from Python to the C++ wrapper is not good.</p>
  
  <p>So, would you know how to fix the attached code so test.py will be able to generate a video with the right audio similarly to the c++ test? </p>
  
  <p>When generated ok, the video will display a magic scrolling checkerboard with hypnotic sinewaves as audio backdrop :D</p>
  
  <p><strong>Additional notes:</strong></p>
  
  <p>1) It seems the above code is not using <code>writer.SetAudioFormat</code> wich is needed for the functions <code>AVIFileCreateStreamA</code> and <code>AVIStreamSetFormat</code>. Problem is I don't know how to export this structure on swig, that way I'd be able to use it on Python the same way than <code>test.cpp</code>, from Mmreg.h I've seen the structure looks like this:</p>
  
  <pre><code>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;
  </code></pre>
  
  <p>Unfortunately I don't know how to wrap that stuff on aviwriter.i? I've tried using %include windows.i and include the stuff directly on a block <code>%{</code>...<code>%}</code> but all I've got were a bunch of errors :/</p>
  
  <p>2) I'd prefer not modifying neither aviwriter.h &amp;&amp; aviwriter.cpp at all as that's basically external working code.</p>
  
  <p>3) Assuming I'm able to wrap the <code>WAVEFORMATEX</code> so I can use it on Python, how'd you use memset similarly to <code>test.cpp</code>? ie: <code>memset(&amp;wfx,0,sizeof(wfx));</code></p>