Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Win32 Drivers for Digital/Video Camcorders


Jun99: Win32 Drivers for Digital/Video Camcorders

Thomas is a software engineer at Sequoia Advanced Technologies Inc., which specializes in 1394 software development. He can be reached at thomas [email protected].


Walk into any consumer electronic store and, faster than you can say "I don't want the service agreement," digital video camcorders from the likes of Sony, Panasonic, Sharp, Canon, Samsung, and JVC, are thrust into your hands. After examining a few of these gadgets, the engineer in me had some questions:

  • Are all digital camcorders compatible with one another? (Mostly.)

  • Do they all use the same tapes? (If they sport a DV logo they do.)

  • What outputs (and/or inputs) are on these cameras? (On most, analog video out, analog audio out, and digital I/O.)

  • What is the digital I/O format? (IEEE 1394, also known as "FireWire" or "ILink.")

IEEE 1394. Now there's something I know about (see, for instance, my article "FireWire: The IEEE 1394 Serial Bus" DDJ, September 1997). Based on my experience with 1394, I bought Sony's DCR-PC10, a digital video (DV) camcorder that uses a cassette slightly smaller than a DAT tape to store 1.5 hours of video/audio. The audio is 16-bit stereo sampled at 44.1 kHz. The video format is NTSC with 720×480 resolution stored at 30 frames per second. The camera has both analog (which can be directly connected to any TV or VCR) and digital outputs. It does not have analog inputs, which prevents you from making some really good copies of The Lion King. However, the PC10 does let you input digital data, which lets you edit video on a PC, then rerecord it using the camcorder. (For more information on the PC10, see http://www.sel.sony.com/SEL/ consumer/ss5/office/camcorder/digit- alvideoproducts/dcr-pc10_specs.shtml.)

Because my PC has a 1394 card and the Sony PC10 a 1394 port, it seemed I should be able to connect the camcorder to the PC and grab pictures -- especially since Windows 98 boasts "embedded" 1394 software support. I plugged the PC10 into the 1394 card (which requires a special 4-pin-to-6-pin cable) and Windows 98 reported "New Hardware Found." With my heart racing (I told you I was an engineer), I waited for Windows 98 to continue loading so I could get on with the task of grabbing pictures from my PC10.

Alas, that was the peak of my consumer electronic "high," as Windows 98 popped up a dialog box saying "Add New Hardware Wizard 1394\A02D&-10001." I pressed the Next button and was instructed to "Search for the best driver for your device." It turns out that the "best driver" wasn't on my Windows 98 CD-ROM. Three hours later I realized that Windows 98 didn't come with the software I needed to make my PC10 work -- even though it does come with a DirectShow DV Codec for converting DV frames into pictures. I eventually found the DV Codec (QDV.DLL) -- written to encode/decode DV data from camcorders like the PC10 -- in the Windows\System directory. What was going on? Three days later and enough phone calls to make AT&T smile, I got my answer from a Microsoft support person who told me I needed a DV camcorder device driver. It turns out that the DV Codec only decodes DV frames -- it doesn't grab them from the 1394 bus. Feeling somewhat sheepish, I asked where to get a DV camcorder device driver. "I'm not sure," came the reply, "but that is definitely what you need."

Now, I am an engineer -- a software engineer -- and this sounded like a challenge. Consequently, I decided then and there to write my own 1394 DV camcorder driver. With nothing but the driver source code I present here, you will be able to connect a DV camera to a Windows 98/1394-equipped PC and grab pictures. Along the way, I'll share the trials and tribulations of what it's like to develop DV-based software.

In designing the code, I partitioned the process into several distinct pieces:

  • Writing a skeleton WDM 1394 driver that simply establishes communication with the camcorder.
  • Capturing DV video frames from the 1394 bus.

  • Sending those DV video frames on to the DV Codec to be turned into pictures.

The resultant software is a WDM 1394 DV camcorder driver called "DDJDVCAP.SYS," with a corresponding .INF file and a Win32 console utility that controls the DV camcorder driver. In this article, I'll present the WDM 1394 driver and all the files necessary for a complete 1394 class driver package (available electronically; see "Resource Center, page 5). In future articles, I'll present the code for capturing DV video data and sending a DV frame to a Win32 application.

DDJDVCAP.SYS: A Guided Tour

In addition to a Windows 98-based PC, the hardware consists of a Texas Instruments OpenHCI 1394 PCI bus controller and a Sony DCR-PC10 camcorder. When I plug the camcorder into the bus controller, the 1394 bus resets -- normal for whenever a device connects to the bus.

IEEE 1394 is completely plug-and-play (PnP). You can connect/disconnect a device at any time. The bus reset causes the 1394 bus driver (1394BUS.SYS) to check what has been connected/disconnected from the 1394 bus. Whenever 1394BUS.SYS finds a new 1394 device, it creates a DeviceObject (an official WDM driver structure through which all device communication becomes possible), then registers the device with the PnP system. The PnP system checks in the registry under My Computer\ HKEY_LOCAL_MACHINE\Enum\1394 for an entry that matches the 1394 device's signature. If the 1394 device's signature is found in the registry, it looks in the key labeled "Driver" and loads the specific device driver indirectly pointed there. If it does not find the 1394 device's signature in the registry, it pops up a dialog box and asks you to insert a disk, CD-ROM, or path where the appropriate device driver can be found.

The first step to writing a 1394 WDM driver is creating an .INF file that contains specific information regarding the targeted 1394 device. This .INF file is used by the PnP system to copy the device driver to the appropriate directory (\WINDOWS\SYSTEM32\DRIVERS) and update the appropriate registry entries needed to load the driver once the Sony PC10 is connected to the system. You need to specify what "Class" you wish to be installed under, as well as the PnP ID. In the case of the Sony PC10, the PnP ID is 1394\ A02D&10001, and you are creating a new class called DDJDVCap for our project (see DDJDVCAP.INF; available electronically, for more details).

There are a few mandatory routines that you must supply as a WDM driver. The first is DriverEntry, which is the first function called after a driver is loaded. The driver loader creates and supplies a DriverObject as a parameter to the DriverEntry routine. A DriverObject is another one of those "official" WDM driver structures. For the most part, DriverObject is a table of pointers to the various routines in your WDM device driver. The next two mandatory routines (mandatory for a PnP WDM driver) that we fill out in the skeleton driver are DriverObject->DriverExtension->AddDevice and DriverObject-> MajorFunction[IRP_MJ_PNP].

The AddDevice routine is called when the 1394 device specified in the driver's corresponding registry entry is plugged into the 1394 bus controller. It is in Add-Device that you create the symbolic link that lets Win32 applications call the driver. The symbolic name for my driver is \DosDevices\DDJDVCAP. To open this driver, the Win32 application will use the Win32 function CreateFile with "\\\\ .\\DDJDVCAP" as the name parameter (see DDJDVCAP.C, available electronically). AddDevice then creates a DeviceObject, the structure used to represent our device to the I/O Manager. I then attach DeviceObject to the 1394 camcorder DeviceObject supplied to my AddDevice routine.

As mentioned previously, my AddDevice routine is called whenever a Sony PC10 is connected to the 1394 bus. Add-Device is called with a DeviceObject as one of its arguments. This particular DeviceObject is the DeviceObject created by 1394BUS.SYS when it detected the Sony PC10 on the 1394 bus. I must use this DeviceObject whenever I send a 1394 request/command to the Sony PC10. It is important to note that since each enumerated 1394 device has only a single entry in the registry, there will be only one driver to which this DeviceObject will be passed via PnP. While architecturally there is nothing that prevents multiple drivers from using the same DeviceObject to execute 1394 requests to a particular device, there is no realistic mechanism that allows a driver -- under the context of the WDM PnP system -- to get passed a DeviceObject for a particular 1394 device that has already been assigned and passed to an existing 1394 driver. In short, one 1394 device, one WDM driver.

Once the 1394BUS.SYS has generated the DeviceObject, you will attach it to the local DeviceObject that you will create for your driver so you can field all of the PnP messages intended for the Sony PC10. I could use the 1394BUS.SYS generated DeviceObject for the PC10 directly if I just wanted to send requests to the PC10, but since I want to intercept requests from other drivers (like the PnP system), I must attach the PC10's DeviceObject to the local DeviceObject. This is done by creating a local DeviceObject with IoCreateDevice(), then by using IoAttachDeviceToDeviceStack(OurDeviceObject, SonyPC10DeviceObject). The new DeviceObject returned from the IoAttachDeviceToDeviceStack is what I now use as my Sony PC10 DeviceObject whenever I execute 1394 requests.

At this point, I have the DeviceObject that I can use to send 1394 requests/commands to the Sony PC10. What commands can I send? Table 1 lists the 1394 functions available from the WDM 1394 driver interface.

For the Sony PC10 video capture driver, I will only use a small subset of these 1394 functions. In fact, I could get away with only using six of them (highlighted in red), but will probably end up using 10 (additional four highlighted in green). The basic structure used to execute 1394 requests is called the I/O Request Block (IRB). The IRB (and all other 1394 pertinent information) can be found in the file 1394.H, located in the \98ddk\inc\ win98 directory of the Windows 98 DDK. The IRB is filled out and shipped off via an I/O Request Packet (IRP). IRPs and I/O Stack Locations are the primary driver communication structures of WDM. IRBs were created specifically for the 1394 WDM driver interface. Example 1, for instance, sends the IRP (with IRB in tow) to 1394BUS.SYS for 1394 request execution.

The Win32 Interface

The DriverObject->MajorFunction[IRP_ MJ_DEVICE_CONTROL] field contains the pointer to the function that DDJDVCAP.SYS uses to field Win32 application requests. This entry point in my driver is called DDJDV_Dispatch. When the Win32 test utility DDJDVTST.C (Listing One) issues requests to DDJDVCAP.SYS via the DeviceIoControl() function, DDJDV_Dispatch fields the request. My driver receives an IRP which contains the information necessary for us to carry out the request. An IRP is the most basic of I/O Manager structures and is the way WDM drivers communicate. Irp->AssociatedIrp.SystemBuffer contains the incoming data structure that corresponds to the lpInBuffer and lpOutBuffer parameters of DeviceIoControl().

The data supplied in these buffers is doubly buffered between Ring 3 (Win32) and Ring 0 (WDM). The data supplied via lpInBuffer of DeviceIoControl() is copied into an intermediate memory space and supplied to DDJDV_Dispatch by way of the Irp->AssociatedIrp.SystemBuffer field. When you return from the function, any data that you wrote to Irp->AssociatedIrp.SystemBuffer is then copied into the lpOutBuffer supplied via DeviceIoControl. In this manner, WDM drivers can communicate data back and forth between Ring 3 and Ring 0. (In future articles, I'll examine other ways of facilitating data exchange that don't require the use of an intermediate buffer.)

Currently, the only Win32 function that DDJDVCAP.SYS supports is GET_NODE _UNIQUE_ID_CODE, a custom command that simply issues a 1394 Async Read command to the DV camcorder's config ROM space to fetch its serial number. This number is really defined as a 1394-specific 64-bit node unique identifier in the format in Example 2. This node unique identifier is returned to the caller and then displayed via the DDJDVTST utility (Listing One).

The Binaries

The code provided here (available electronically in both source and executable form) is a fully functional skeleton 1394 WDM driver. When you plug a 1394 camcorder into the 1394 card for the first time, Windows 98 will ask for the driver. Insert a floppy with the .INF and .SYS file and answer all the questions. The DV driver will then load. You can then run the .EXE file, which will read the serial number from the DV camcorder and display it on the screen. The device driver is completely PnP, loaded whenever a 1394 DV camcorder is plugged in, and unloaded when the 1394 DV camcorder is unplugged or turned off. I've also included the Win32 console application that calls the driver to get the serial number and prints it out to the screen.

The files available electronically include DDJDVCAP.C (the 1394 WDM camcorder driver); DDJDVCAP.H (the 1394 WDM camcorder driver header file); DDJDVW32.H (the header file used by Win32 applications that wish to communicate with the DV driver); DDJDVCAP.RC (the resource file for the camcorder driver); DDJDVCAP.INF (the .INF file used to install the driver whenever a DV camcorder is connected to the system); and DDJDVTST.C (a Win32 console application that interfaces to the DV camcorder driver).

These files constitute the pieces necessary for a complete 1394 class driver package. These source files are completely operational. In future articles, I'll examine what DV video frames look like, and what you have to do to capture them before sending a DV frame to a Win32 application for conversion into a picture.

DDJ

Listing One

/*----------------------------------------------------------------------- */
/* Filename: DDJDVTST.C                                                   */
/* Description: Dr. Dobb's Journal DV Frame Capture Driver Project        */
/*              Win32 Console Application for testing the DV Driver       */
/*----------------------------------------------------------------------- */
/* (C) Copyright 1994-1998 by Sequoia Advanced Technologies, Inc.         */
/* http://www.seqadvtech.com                                              */
/* All Rights Reserved.                                                   */
/*----------------------------------------------------------------------- */
#define STRICT
#include <stdlib.h>
#include <stdio.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winioctl.h>
#include "ddjdvw32.h"

bswap(ULONG value)
{
    __asm mov eax, value
    __asm bswap eax
}
main(int argc, char *argv[])
{
    HANDLE hDev;
    DWORD dwOutCount;
    DWORD inBuffer[2];
    DWORD dwRet;
    printf("Dr. Dobb's DV Camcorder Driver Test Utility\n\n");
    //-----------------------------------------------------------------
    // Open our DV Camcorder driver, if it is loaded.
    // This will result in DDJDV_Create being called in the driver.
    //-----------------------------------------------------------------
    hDev = CreateFile("\\\\.\\DDJDVCAP", GENERIC_WRITE | GENERIC_READ,
          FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    if(hDev == INVALID_HANDLE_VALUE)
    {
        printf("DDJDVCAP Driver Not Loaded!!\n\n");
        exit(1);
    }
    //------------------------------------------------------------------
    // Send command to DV Driver to read Node Unique ID from Camcorder. 
    // This will result in DDJDV_Dispatch being called in driver.
    //-------------------------------------------------------------------
    dwRet = DeviceIoControl(hDev, GET_NODE_UNIQUE_ID_CODE, NULL, 0, 
                                         inBuffer, 8, &dwOutCount, NULL);
    //-------------------------------------------------------------------
    // Put in little-endian numeric format
    //--------------------------------------------------------------------
    inBuffer[0] = bswap(inBuffer[0]);
    inBuffer[1] = bswap(inBuffer[1]);

    printf("Camcorder Vendor ID = %x\n",(inBuffer[0] >> 8));
    printf("Camcorder Model ID = %x%.8x\n",(inBuffer[0] & 0xFF),inBuffer[1]);

    //-------------------------------------------------------------------
    // Close DV Driver. Will result in DDJDV_Close being called in driver.
    //--------------------------------------------------------------------
    CloseHandle(hDev);
    return(0);
}


Back to Article


Copyright © 1999, Dr. Dobb's Journal

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.