#!/usr/local/bin/python2.7
# -*- coding: latin-1; -*-
#
# dvrecv
# Grab a DV stream into a file
# Version 1.2
#
# Copyright (c) 2004
#      Henri Michelon
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. Neither the name of the author nor the names of its contributors
#    may be used to endorse or promote products derived from this software
#    without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# 
# $Id: dvrecv,v 1.4 2004/12/09 20:37:04 hmichelon Exp $
#
import os
import sys
import string
import firewire
import avc_crom


def start_callback(context, system_name):
  """Called by firewire.dvrec() when starting"""
  context.set_system(system_name)


def frame_callback(context, data):
  """Called by firewire.dvrec() when data is available"""
  context.add(data)


def eagain_callback(context):
  """Called by firewire.dvrec() when no data is available"""
  print("waiting for DV data, please press 'play' on the camcorder...")


class Context:
  """Context class for object passed to firewire.dvrec() callbacks"""
  def __init__(self, filename):
    self._total = 0
    self._frames = 0
    self.wfd = open(filename, "w")

  def set_system(self, system):
    self._system = system
    self._bpf = avc_crom.BPF[system]
    self._fps = avc_crom.FPS[system]
    print("system : " + system)

  def frames(self):
    return self._frames - 1

  def system(self):
    return self._system

  def add(self, data):
    for buf in data:
      self._total += len(buf)
      self.wfd.write(buf)
    self._frames = self._total / self._bpf
    if ((self._frames % self._fps) == 0):
      print(str(self._frames) + " frames received")

  def total(self):
    return self._total


class DVRecv:
  def __init__(self):
    self.open_dev()
    self.find_avc()
    self.print_desc()
    self.recv()

  def open_dev(self):  
    """Open the firewire device"""
    self.fd = firewire.open_dev("/dev/fw0")
    if (self.fd is None) :
      print("error opening /dev/fw0")
      sys.exit(1)
  
  def find_avc(self):
    """search for a AV/C device"""
    data = firewire.get_dev(self.fd)
    self.dev = avc_crom.find_avc(self.fd, data['dev'])
    if (self.dev is None):
      print("No AV/C device found")
      sys.exit(0)

  def print_desc(self):
    """print description of the AV/C device found"""
    print("Found AV/C device")
    print("Vendor: " + avc_crom.get_vendor(self.fd, self.dev))
    print("Model: " + avc_crom.get_model(self.fd, self.dev))

  def recv(self):
    # use the given filename or "out.dv"
    if (len(sys.argv) > 1):
      filename = sys.argv[1]
    else:
      filename = "out.dv"
    # receive the DV stream
    context = Context(filename)
    firewire.recv(self.fd, context, start_callback, frame_callback, eagain_callback)
    print("total : " + str(context.frames()) + " frames (" + str(context.total()) + " Bytes)" )


try:
  DVRecv()
except KeyboardInterrupt:
  pass

