Getting a snapshot from a webcam with Delphi
 

I need to get a regular snapshot from a webcam in Delphi. Speed is not a problem (once a second is fine). I have tried demo code from based on stuff from http://delphi.pjh2.de but I can't get it to work. It compiles and runs OK but the callback function never fires.

I don't have a real webcam but am running instead a simulator. The simulator works (I can see the video using Skype) but not with the test app. I don't really know where to start looking...

Can anyone be bothered to try this code? (Apologies for the voluminous post - couldn't find how or if you can attach files - a zip file is available here.)

Alternatively, any webcam demo code would be appreciated, preferably with a known good EXE as well as source.

program WebCamTest;

uses
  Forms,
  WebCamMainForm in 'WebCamMainForm.pas' {Form1},
  yuvconverts in 'yuvconverts.pas';

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.


unit WebCamMainForm;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, YUVConverts, StdCtrls, JPeg {, TntStdCtrls} ;

const
  WM_CAP_START = WM_USER;
  WM_CAP_DRIVER_CONNECT       = WM_CAP_START+ 10;

  WM_CAP_SET_PREVIEW          = WM_CAP_START+ 50;
  WM_CAP_SET_OVERLAY          = WM_CAP_START+ 51;
  WM_CAP_SET_PREVIEWRATE      = WM_CAP_START+ 52;

  WM_CAP_GRAB_FRAME_NOSTOP    = WM_CAP_START+ 61;
  WM_CAP_SET_CALLBACK_FRAME   = WM_CAP_START+ 5;
  WM_CAP_GET_VIDEOFORMAT      = WM_CAP_START+ 44;

  WM_CAP_DLG_VIDEOFORMAT      = WM_CAP_START+ 41;

  PICWIDTH= 640;
  PICHEIGHT= 480;
  SUBLINEHEIGHT= 18;
  EXTRAHEIGHT= 400;

type
  TVIDEOHDR= record
    lpData: Pointer; // address of video buffer
    dwBufferLength: DWord; // size, in bytes, of the Data buffer
    dwBytesUsed: DWord; // see below
    dwTimeCaptured: DWord; // see below
    dwUser: DWord; // user-specific data
    dwFlags: DWord; // see below
    dwReserved1, dwReserved2, dwReserved3: DWord; // reserved; do not use
  end;
  TVIDEOHDRPtr= ^TVideoHDR;

  DWordDim= array[1..PICWIDTH] of DWord;

  TForm1 = class(TForm)
    Timer1: TTimer;
    Panel1: TPanel;
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    FCapHandle: THandle;
    FCodec: TVideoCodec;
    FBuf1, FBuf2: array[1..PICHEIGHT] of DWordDim;
    FBitmap: TBitmap;
    FJpeg: TJPegImage;
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


function capCreateCaptureWindow(lpszWindowName: LPCSTR;
  dwStyle: DWORD;
  x, y,
  nWidth,
  nHeight: integer;
  hwndParent: HWND;
  nID: integer): HWND; stdcall;
  external 'AVICAP32.DLL' name 'capCreateCaptureWindowA';


function FrameCallbackFunction(AHandle: hWnd; VIDEOHDR: TVideoHDRPtr): bool; stdcall;
var
  I: integer;
begin
  result:= true;

  with form1 do begin
  try
    ConvertCodecToRGB(FCodec, VideoHDR^.lpData, @FBuf2, PICWIDTH, PICHEIGHT);

    for I:= 1 to PICHEIGHT do FBuf1[I]:= FBuf2[PICHEIGHT- (I- 1)];
    SetBitmapBits(FBitmap.Handle, PICWIDTH* PICHEIGHT* SizeOf(DWord), @FBuf1);

    FBitmap.Canvas.Brush.Color:= clWhite;
    FBitmap.Canvas.Font.Color:= clRed;

    FJpeg.Assign(FBitmap);

    FJpeg.CompressionQuality:= 85;
    FJpeg.ProgressiveEncoding:= true;
    FJpeg.SaveToFile('c:\webcam.jpg');

    SendMessage(FCapHandle, WM_CAP_SET_CALLBACK_FRAME, 0, 0);
  except
  end;
  end;
end;

//------------------------------------------------------------------------------

procedure TForm1.FormCreate(Sender: TObject);
var  BitmapInfo: TBitmapInfo;
begin
  Timer1.Enabled := false;

  FBitmap:= TBitmap.Create;
  FBitmap.Width:= PICWIDTH;
  FBitmap.Height:= PICHEIGHT+ SUBLINEHEIGHT+ EXTRAHEIGHT;
  FBitmap.PixelFormat:= pf32Bit;
  FBitmap.Canvas.Font.Assign(Panel1.Font);
  FBitmap.Canvas.Brush.Style:= bssolid;
  FBitmap.Canvas.Rectangle(0, PICHEIGHT, PICWIDTH, PICHEIGHT+ SUBLINEHEIGHT);

  FJpeg:= TJpegImage.Create;

  FCapHandle:= capCreateCaptureWindow('Video', WS_CHILD or WS_VISIBLE, 0, 0, PICWIDTH, PICHEIGHT, Panel1.Handle, 1);
  SendMessage(FCapHandle, WM_CAP_DRIVER_CONNECT, 0, 0);
  SendMessage(FCapHandle, WM_CAP_SET_PREVIEWRATE, 15000, 0);
  sendMessage(FCapHandle, WM_CAP_SET_OVERLAY, 1, 0);
  SendMessage(FCapHandle, WM_CAP_SET_PREVIEW, 1, 0);

  // SendMessage(FCapHandle, WM_CAP_DLG_VIDEOFORMAT,1,0);     // -this was commented out

  FillChar(BitmapInfo, SizeOf(BitmapInfo), 0);
  SendMessage(FCapHandle, WM_CAP_GET_VIDEOFORMAT, SizeOf(BitmapInfo), Integer(@BitmapInfo));
  FCodec:= BICompressionToVideoCodec(bitmapinfo.bmiHeader.biCompression);
  if FCodec<> vcUnknown then begin
    Timer1.Enabled:= true;
  end;
end;


procedure TForm1.FormDestroy(Sender: TObject);
begin
  FBitmap.Free;
  FJpeg.Free;
end;


procedure TForm1.FormActivate(Sender: TObject);
begin
  if FCodec= vcUnknown then
    showMessage('unknown compression');
  FBitmap.Height:= PICHEIGHT+ SUBLINEHEIGHT;
end;

//------------------------------------------------------------------------------

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  SendMessage(FCapHandle, WM_CAP_SET_CALLBACK_FRAME, 0, integer(@FrameCallbackFunction));
  SendMessage(FCapHandle, WM_CAP_GRAB_FRAME_NOSTOP, 1, 0); // ist hintergrundlauff?hig
end;

end.

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 301
  ClientWidth = 562
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnActivate = FormActivate
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object Panel1: TPanel
    Left = 48
    Top = 16
    Width = 185
    Height = 145
    Caption = 'Panel1'
    TabOrder = 0
  end
  object Timer1: TTimer
    OnTimer = Timer1Timer
    Left = 464
    Top = 24
  end
end

{**************************************************************************************************}
{                                                                                                  }
{  YUVConverts                                                                                     }
{                                                                                                  }
{  The contents of this file are subject to the Y Library Public License Version 1.0 (the          }
{  "License"); you may not use this file except in compliance with the License. You may obtain a   }
{  copy of the License at http://delphi.pjh2.de/                                                   }
{                                                                                                  }
{  Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF  }
{  ANY KIND, either express or implied. See the License for the specific language governing        }
{  rights and limitations under the License.                                                       }
{                                                                                                  }
{  The Original Code is: YUVConverts.pas, part of CapDemoC.dpr.                                    }
{  The Initial Developer of the Original Code is Peter J. Haas (libs@pjh2.de). Portions created    }
{  by Peter J. Haas are Copyright (C) 2000-2005 Peter J. Haas. All Rights Reserved.                }
{                                                                                                  }
{  Contributor(s):                                                                                 }
{                                                                                                  }
{  You may retrieve the latest version of this file at the homepage of Peter J. Haas, located at   }
{  http://delphi.pjh2.de/                                                                          }
{                                                                                                  }
{**************************************************************************************************}

// For history see end of file

{$ALIGN ON, $BOOLEVAL OFF, $LONGSTRINGS ON, $IOCHECKS ON, $WRITEABLECONST OFF, $OVERFLOWCHECKS OFF}
{$RANGECHECKS OFF, $TYPEDADDRESS ON, $MINENUMSIZE 1}

unit yuvconverts;

interface
uses
  Windows;

type
  TVideoCodec = (vcUnknown, vcRGB, vcYUY2, vcUYVY, vcBTYUV, vcYVU9, vcYUV12, vcY8, vcY211);

const
  BI_YUY2  = $32595559;  // 'YUY2'
  BI_UYVY  = $59565955;  // 'UYVY'
  BI_BTYUV = $50313459;  // 'Y41P'
  BI_YVU9  = $39555659;  // 'YVU9'  planar
  BI_YUV12 = $30323449;  // 'I420'  planar
  BI_Y8    = $20203859;  // 'Y8  '
  BI_Y211  = $31313259;  // 'Y211'

function BICompressionToVideoCodec(Value: DWord): TVideoCodec;

function ConvertCodecToRGB(Codec: TVideoCodec; Src, Dst: Pointer; AWidth, AHeight: Integer): Boolean;

implementation

function BICompressionToVideoCodec(Value: DWord): TVideoCodec;
begin
  case Value of
    BI_RGB, BI_BITFIELDS: Result := vcRGB;   // no RLE
    BI_YUY2:              Result := vcYUY2 ;
    BI_UYVY:              Result := vcUYVY ;
    BI_BTYUV:             Result := vcBTYUV;
    BI_YVU9:              Result := vcYVU9;
    BI_YUV12:             Result := vcYUV12;
    BI_Y8:                Result := vcY8;
    BI_Y211:              Result := vcY211;
  else
    Result := vcUnknown;
  end;
end;

const
  // RGB255 ColorFAQ
  fY  =  298.082 / 256;
  fRU =  0;
  fGU = -100.291 / 256;
  fBU =  516.411 / 256;
  fRV =  408.583 / 256;
  fGV = -208.120 / 256;
  fBV =  0;

{  // RGB219 ColorFAQ           too dark
  fY  =  256 / 256;
  fRU =  0;
  fGU =  -86.132 / 256;
  fBU =  443.506 / 256;
  fRV =  350.901 / 256;
  fGV = -178.738 / 256;
  fBV =  0; }

{  // Earl            same like RGB255
  fY  =  1.164;
  fRU =  0;
  fGU = -0.392;
  fBU =  2.017;
  fRV =  1.596;
  fGV = -0.813;
  fBV =  0;
}

// |R|   |fY fRU fRV|   |Y|   | 16|
// |G| = |fY fGU fGV| * |U| - |128|
// |B|   |fY fBU fBV|   |V|   |128|

type
  TYUV = packed record
    Y, U, V, F1: Byte;
  end;

  PBGR32 = ^TBGR32;
  TBGR32 = packed record
    B, G, R, A: Byte;
  end;

function YUVtoBGRAPixel(AYUV: DWord): DWord;
var
  ValueY, ValueU, ValueV: Integer;
  ValueB, ValueG, ValueR: Integer;
begin
  ValueY := TYUV(AYUV).Y - 16;
  ValueU := TYUV(AYUV).U - 128;
  ValueV := TYUV(AYUV).V - 128;

  ValueB := Trunc(fY * ValueY + fBU * ValueU);  // fBV = 0
  if ValueB > 255 then
    ValueB := 255;
  if ValueB <   0 then
    ValueB :=   0;

  ValueG := Trunc(fY * ValueY + fGU * ValueU + fGV * ValueV);
  if ValueG > 255 then
    ValueG := 255;
  if ValueG <   0 then
    ValueG :=   0;

  ValueR := Trunc(fY * ValueY + fRV * ValueV);  // fRU = 0
  if ValueR > 255 then
    ValueR := 255;
  if ValueR <   0 then
    ValueR :=   0;

  with TBGR32(Result) do begin
    B := ValueB;
    G := ValueG;
    R := ValueR;
    A := 0;
  end;
end;

type
  TDWordRec = packed record
  case Integer of
    0: (B0, B1, B2, B3: Byte);
    1: (W0, W1: Word);
  end;

// UYVY
// YUV 4:2:2 (Y sample at every pixel, U and V sampled at every second pixel
// horizontally on each line). A macropixel contains 2 pixels in 1 DWord.
// 16 Bits per Pixel, 4 Byte Macropixel
// U0 Y0 V0 Y1
procedure UYVYtoRGB(Src, Dst: Pointer; AWidth, AHeight: Integer);
type
  PUYVY = ^TUYVY;
  TUYVY = packed record
    U, Y0, V, Y1: Byte;
  end;

var
  x, y: Integer;
  w: Integer;
  SrcPtr: PDWord;
  DstPtr: PDWord;
  SrcLineSize: Integer;
  DstLineSize: Integer;
  YUV: DWord;
  b: Byte;
begin
  SrcLineSize := AWidth * 2;
  DstLineSize := AWidth * 4;

  // Dst is Bottom Top Bitmap
  Inc(PByte(Dst), (AHeight - 1) * DstLineSize);

  w := (AWidth div 2) - 1;      { TODO : bei ungeraden Breiten fehlt letztes Pixel }
  for y := 0 to AHeight - 1 do begin
    SrcPtr := Src;
    DstPtr := Dst;
    for x := 0 to w do begin
      YUV := SrcPtr^;
      // First Pixel
      b := TDWordRec(YUV).B0;
      TDWordRec(YUV).B0 := TDWordRec(YUV).B1;
      TDWordRec(YUV).B1 := b;

      DstPtr^ := YUVtoBGRAPixel(YUV);
      Inc(DstPtr);
      // Second Pixel
      TDWordRec(YUV).B0 := TDWordRec(YUV).B3;
      DstPtr^ := YUVtoBGRAPixel(YUV);
      Inc(DstPtr);
      Inc(SrcPtr);
    end;
    Dec(PByte(Dst), DstLineSize);
    Inc(PByte(Src), SrcLineSize);
  end;
end;

// YUY2, YUNV, V422
// YUV 4:2:2 as for UYVY but with different component ordering within the DWord
// macropixel.
// 16 Bits per Pixel, 4 Byte Macropixel
// Y0 U0 Y1 V0
procedure YUY2toRGB(Src, Dst: Pointer; AWidth, AHeight: Integer);
var
  x, y: Integer;
  w: Integer;
  SrcPtr: PDWord;
  DstPtr: PDWord;
  SrcLineSize: Integer;
  DstLineSize: Integer;
  YUV: DWord;
  b: Byte;
begin
  SrcLineSize := AWidth * 2;
  DstLineSize := AWidth * 4;

  // Dst is Bottom Top Bitmap
  Inc(PByte(Dst), (AHeight - 1) * DstLineSize);

  w := (AWidth div 2) - 1;      { TODO : bei ungeraden Breiten fehlt letztes Pixel }
  for y := 0 to AHeight - 1 do begin
    SrcPtr := Src;
    DstPtr := Dst;
    for x := 0 to w do begin
      YUV := SrcPtr^;
      // First Pixel
      b := TDWordRec(YUV).B2;                  //  Y0 U Y1 V -> Y0 U V Y1
      TDWordRec(YUV).B2 := TDWordRec(YUV).B3;
      TDWordRec(YUV).B3 := b;

      DstPtr^ := YUVtoBGRAPixel(YUV);
      Inc(DstPtr);
      // Second Pixel
      TDWordRec(YUV).B0 := TDWordRec(YUV).B3;
      DstPtr^ := YUVtoBGRAPixel(YUV);
      Inc(DstPtr);
      Inc(SrcPtr);
    end;
    Dec(PByte(Dst), DstLineSize);
    Inc(PByte(Src), SrcLineSize);
  end;
end;

// BTYUV, I42P
// YUV 4:1:1 (Y sample at every pixel, U and V sampled at every fourth pixel
// horizontally on each line). A macropixel contains 8 pixels in 3 DWords.
// 16 Bits per Pixel, 12 Byte Macropixel
// U0 Y0 V0 Y1 U4 Y2 V4 Y3 Y4 Y5 Y6 Y7
procedure BTYUVtoRGB(Src, Dst: Pointer; AWidth, AHeight: Integer);
type
  PBTYUVPixel = ^TBTYUVPixel;
  TBTYUVPixel = packed record
    U0, Y0, V0, Y1, U4, Y2, V4, Y3, Y4, Y5, Y6, Y7: Byte;
  end;

var
  x, y: Integer;
  w: Integer;
  SrcPtr: PBTYUVPixel;
  DstPtr: PDWord;
  SrcLineSize: Integer;
  DstLineSize: Integer;
  YUV: DWord;
  SrcPixel: TBTYUVPixel;
begin
  SrcLineSize := ((AWidth + 7) div 8) * (3 * 4);
  DstLineSize := AWidth * 4;

  w := AWidth - 1;
  for y := 0 to AHeight - 1 do begin
    SrcPtr := Src;
    DstPtr := Dst;
    x := w;
    while x > 0 do begin
      // read macropixel
      SrcPixel := SrcPtr^;
      // First 4 Pixel
      TYUV(YUV).U := SrcPixel.U0;
      TYUV(YUV).V := SrcPixel.V0;

      TYUV(YUV).Y := SrcPixel.Y0;
      DstPtr^ := YUVtoBGRAPixel(YUV);
      Inc(DstPtr);
      Dec(x);
      if x <= 0 then
        Break;

      TYUV(YUV).Y := SrcPixel.Y1;
      DstPtr^ := YUVtoBGRAPixel(YUV);
      Inc(DstPtr);
      Dec(x);
      if x <= 0 then
        Break;

      TYUV(YUV).Y := SrcPixel.Y2;
      DstPtr^ := YUVtoBGRAPixel(YUV);
      Inc(DstPtr);
      Dec(x);
      if x <= 0 then
        Break;

      TYUV(YUV).Y := SrcPixel.Y3;
      DstPtr^ := YUVtoBGRAPixel(YUV);
      Inc(DstPtr);
      Dec(x);
      if x <= 0 then
        Break;

      // Second 4 Pixel
      TYUV(YUV).U := SrcPixel.U4;
      TYUV(YUV).V := SrcPixel.V4;

      TYUV(YUV).Y := SrcPixel.Y4;
      DstPtr^ := YUVtoBGRAPixel(YUV);
      Inc(DstPtr);
      Dec(x);
      if x <= 0 then
        Break;

      TYUV(YUV).Y := SrcPixel.Y5;
      DstPtr^ := YUVtoBGRAPixel(YUV);
      Inc(DstPtr);
      Dec(x);
      if x <= 0 then
        Break;

      TYUV(YUV).Y := SrcPixel.Y6;
      DstPtr^ := YUVtoBGRAPixel(YUV);
      Inc(DstPtr);
      Dec(x);
      if x <= 0 then
        Break;

      TYUV(YUV).Y := SrcPixel.Y7;
      DstPtr^ := YUVtoBGRAPixel(YUV);
      Inc(DstPtr);

      Inc(SrcPtr);
    end;
    Inc(PByte(Dst), DstLineSize);
    Inc(PByte(Src), SrcLineSize);
  end;
end;

// YVU9
// 8 bit Y plane followed by 8 bit 4x4 subsampled V and U planes.
// 9 Bits per Pixel, planar format
procedure YVU9toRGB(Src, Dst: Pointer; AWidth, AHeight: Integer);
var
  x, y, r, l: Integer;
  w: Integer;
  SrcYPtr: PByte;
  SrcUPtr: PByte;
  SrcVPtr: PByte;
  DstPtr: PDWord;
  SrcYLineSize: Integer;
  SrcUVLineSize: Integer;
  DstLineSize: Integer;
  YUV: DWord;
begin
  DstLineSize := AWidth * 4;

  SrcYLineSize := AWidth;
  SrcUVLineSize := (AWidth + 3) div 4;

  // Dst is Bottom Top Bitmap
  Inc(PByte(Dst), (AHeight - 1) * DstLineSize);

  SrcYPtr := Src;
  SrcVPtr := PByte(LongInt(SrcYPtr) + SrcYLineSize * AHeight);
  SrcUPtr := PByte(LongInt(SrcVPtr) + SrcUVLineSize * ((AHeight + 3) div 4));

  w := (AWidth div 4) - 1;      { TODO : bei ungeraden Breiten fehlt letztes Pixel }
  for y := 0 to (AHeight div 4) - 1 do begin  { TODO : bei ungeraden H?hen fehlt letzte Reihe }
    for l := 0 to 3 do begin
      DstPtr := Dst;
      for x := 0 to w do begin
        // U and V
        YUV := (SrcUPtr^ shl 8) or (SrcVPtr^ shl 16);
        for r := 0 to 3 do begin
          YUV := (YUV and $00FFFF00) or SrcYPtr^;
          DstPtr^ := YUVtoBGRAPixel(YUV);
          Inc(DstPtr);
          Inc(SrcYPtr);
        end;
        Inc(SrcUPtr);
        Inc(SrcVPtr);
      end;
      Dec(PByte(Dst), DstLineSize);
      if l < 3 then begin
        Dec(SrcUPtr, SrcUVLineSize);
        Dec(SrcVPtr, SrcUVLineSize);
      end;
    end;
  end;
end;

// YUV12, I420, IYUV
// 8 bit Y plane followed by 8 bit 2x2 subsampled U and V planes.
// 12 Bits per Pixel, planar format
procedure YUV12toRGB(Src, Dst: Pointer; AWidth, AHeight: Integer);  // I420, IYUV
var
  x, y, l: Integer;
  w: Integer;
  SrcYPtr: PByte;
  SrcUPtr: PByte;
  SrcVPtr: PByte;
  DstPtr: PDWord;
  SrcYLineSize: Integer;
  SrcUVLineSize: Integer;
  DstLineSize: Integer;
  YUV: DWord;
begin
  DstLineSize := AWidth * 4;

  SrcYLineSize := AWidth;
  SrcUVLineSize := (AWidth + 1) div 2;

  // Dst is Bottom Top Bitmap
  Inc(PByte(Dst), (AHeight - 1) * DstLineSize);

  SrcYPtr := Src;
  SrcUPtr := PByte(LongInt(SrcYPtr) + SrcYLineSize * AHeight);
  SrcVPtr := PByte(LongInt(SrcUPtr) + SrcUVLineSize * ((AHeight + 1) div 2));

  w := (AWidth div 2) - 1;      { TODO : bei ungeraden Breiten fehlt letztes Pixel }
  for y := 0 to (AHeight div 2) - 1 do begin  { TODO : bei ungeraden H?hen fehlt letzte Reihe }
    for l := 0 to 1 do begin
      DstPtr := Dst;
      for x := 0 to w do begin
        // First Pixel
        YUV := SrcYPtr^ or (SrcUPtr^ shl 8) or (SrcVPtr^ shl 16);
        DstPtr^ := YUVtoBGRAPixel(YUV);
        Inc(DstPtr);
        Inc(SrcYPtr);
        // Second Pixel
        YUV := (YUV and $00FFFF00) or SrcYPtr^;
        DstPtr^ := YUVtoBGRAPixel(YUV);
        Inc(DstPtr);
        Inc(SrcYPtr);
        Inc(SrcUPtr);
        Inc(SrcVPtr);
      end;
      Dec(PByte(Dst), DstLineSize);
      if l = 0 then begin
        Dec(SrcUPtr, SrcUVLineSize);
        Dec(SrcVPtr, SrcUVLineSize);
      end;
    end;
  end;
end;

// Y8, Y800
// Simple, single Y plane for monochrome images.
// 8 Bits per Pixel, planar format
procedure Y8toRGB(Src, Dst: Pointer; AWidth, AHeight: Integer);
var
  x, y: Integer;
  w: Integer;
  SrcPtr: PByte;
  DstPtr: PDWord;
  SrcLineSize: Integer;
  DstLineSize: Integer;
  Pixel: DWord;
begin
  SrcLineSize := AWidth;
  DstLineSize := AWidth * 4;

  // Dst is Bottom Top Bitmap
  Inc(PByte(Dst), (AHeight - 1) * DstLineSize);

  w := (AWidth) - 1;
  for y := 0 to AHeight - 1 do begin
    SrcPtr := Src;
    DstPtr := Dst;
    for x := 0 to w do begin
      Pixel := SrcPtr^;
      TDWordRec(Pixel).B1 := TDWordRec(Pixel).B0;
      TDWordRec(Pixel).B2 := TDWordRec(Pixel).B0;
      TDWordRec(Pixel).B3 := 0;
      DstPtr^ := Pixel;
      Inc(DstPtr);
      Inc(SrcPtr);
    end;
    Dec(PByte(Dst), DstLineSize);
    Inc(PByte(Src), SrcLineSize);
  end;
end;

// Y211
// Packed YUV format with Y sampled at every second pixel across each line
// and U and V sampled at every fourth pixel.
// 8 Bits per Pixel, 4 Byte Macropixel
// Y0, U0, Y2, V0
procedure Y211toRGB(Src, Dst: Pointer; AWidth, AHeight: Integer);
type
  PYUYV = ^TYUYV;
  TYUYV = packed record
    Y0, U, Y2, V: Byte;
  end;

var
  x, y: Integer;
  w : Integer;
  SrcPtr : PDWord;
  DstPtr : PDWord;
  SrcLineSize : Integer;
  DstLineSize : Integer;
  YUV: DWord;
  BGR: DWord;
  b: Byte;
begin
  SrcLineSize := ((AWidth + 3) div 4) * 4;
  DstLineSize := AWidth * 4;

  // Dst is Bottom Top Bitmap
  Inc(PByte(Dst), (AHeight - 1) * DstLineSize);

  w := (AWidth div 4) - 1;      { TODO : bei ungeraden Breiten fehlt letztes Pixel }
  for y := 0 to AHeight - 1 do begin
    SrcPtr := Src;
    DstPtr := Dst;
    for x := 0 to w do begin
      // Y0 U Y2 V
      YUV := SrcPtr^;
      // First and second Pixel
      b := TDWordRec(YUV).B2;                   // Y0 U Y2 V -> Y0 U V Y2
      TDWordRec(YUV).B2 := TDWordRec(YUV).B3;
      TDWordRec(YUV).B3 := b;
      BGR := YUVtoBGRAPixel(YUV);
      DstPtr^ := BGR;
      Inc(DstPtr);
      DstPtr^ := BGR;
      Inc(DstPtr);

      // third and fourth
      TDWordRec(YUV).B0 := TDWordRec(YUV).B3;   // Y0 U V Y2 -> Y2 U V Y2
      BGR := YUVtoBGRAPixel(YUV);
      DstPtr^ := BGR;
      Inc(DstPtr);
      DstPtr^ := BGR;
      Inc(DstPtr);

      Inc(SrcPtr);
    end;
    Dec(PByte(Dst), DstLineSize);
    Inc(PByte(Src), SrcLineSize);
  end;
end;

function ConvertCodecToRGB(Codec: TVideoCodec; Src, Dst: Pointer; AWidth, AHeight: Integer): Boolean;
begin
  Result := True;
  case Codec of
    vcYUY2:  YUY2toRGB (Src, Dst, AWidth, AHeight);
    vcUYVY:  UYVYtoRGB (Src, Dst, AWidth, AHeight);
    vcBTYUV: BTYUVtoRGB(Src, Dst, AWidth, AHeight);
    vcYVU9:  YVU9toRGB (Src, Dst, AWidth, AHeight);
    vcYUV12: YUV12toRGB(Src, Dst, AWidth, AHeight);
    vcY8:    Y8toRGB   (Src, Dst, AWidth, AHeight);
    vcY211:  Y211toRGB (Src, Dst, AWidth, AHeight);
  else
    Result := False;
  end;
end;

//  History:
//  2005-02-12, Peter J. Haas
//
//  2002-02-22, Peter J. Haas
//   - add YVU9, YUV12 (I420)
//   - add Y211 (untested)
//
//  2001-06-14, Peter J. Haas
//   - First public version
//   - YUY2, UYVY, BTYUV (Y41P), Y8

end.

Some message results:

var
    MsgResult : Integer ;

procedure TForm1.FormCreate(Sender: TObject);
var  BitmapInfo: TBitmapInfo;

begin
  Timer1.Enabled := false;

  FBitmap:= TBitmap.Create;
  FBitmap.Width:= PICWIDTH;
  FBitmap.Height:= PICHEIGHT+ SUBLINEHEIGHT+ EXTRAHEIGHT;
  FBitmap.PixelFormat:= pf32Bit;
  FBitmap.Canvas.Font.Assign(Panel1.Font);
  FBitmap.Canvas.Brush.Style:= bssolid;
  FBitmap.Canvas.Rectangle(0, PICHEIGHT, PICWIDTH, PICHEIGHT+ SUBLINEHEIGHT);

  FJpeg:= TJpegImage.Create;

  FCapHandle:= capCreateCaptureWindow('Video', WS_CHILD or WS_VISIBLE, 0, 0, PICWIDTH, PICHEIGHT, Panel1.Handle, 1);   // returns 2558326
  MsgResult := SendMessage(FCapHandle, WM_CAP_DRIVER_CONNECT, 0, 0);                                                   // returns 0
  MsgResult := SendMessage(FCapHandle, WM_CAP_SET_PREVIEWRATE, 15000, 0);                                              // returns 1
  MsgResult := sendMessage(FCapHandle, WM_CAP_SET_OVERLAY, 1, 0);                                                      // returns 0
  MsgResult := SendMessage(FCapHandle, WM_CAP_SET_PREVIEW, 1, 0);                                                      // returns 0

  // SendMessage(FCapHandle, WM_CAP_DLG_VIDEOFORMAT,1,0);     // -this was commented out

  FillChar(BitmapInfo, SizeOf(BitmapInfo), 0);
  MsgResult := SendMessage(FCapHandle, WM_CAP_GET_VIDEOFORMAT, SizeOf(BitmapInfo), Integer(@BitmapInfo));              // returns 0
  FCodec:= BICompressionToVideoCodec(bitmapinfo.bmiHeader.biCompression);                                              // returns vcRGB
  if FCodec<> vcUnknown then begin
    Timer1.Enabled:= true;
  end;
end;


procedure TForm1.FormDestroy(Sender: TObject);
begin
  FBitmap.Free;
  FJpeg.Free;
end;


procedure TForm1.FormActivate(Sender: TObject);
begin
  if FCodec= vcUnknown then
    showMessage('unknown compression');
  FBitmap.Height:= PICHEIGHT+ SUBLINEHEIGHT;
end;

//------------------------------------------------------------------------------

procedure TForm1.Timer1Timer(Sender: TObject);
begin
MsgResult := SendMessage(FCapHandle, WM_CAP_SET_CALLBACK_FRAME, 0, integer(@FrameCallbackFunction));         // returns 0
MsgResult := SendMessage(FCapHandle, WM_CAP_GRAB_FRAME_NOSTOP, 1, 0); // ist hintergrundlauff?hig            // returns 0
end;

http://www.stackoverflow.com/questions/3454688/

        

There are 2 answer(s) to this question.


I use a component called TVideoCap. It is for 3, 4, and 5 but it includes source so it is easy to update. It will do exactly what you want. Just do a search for 'TVideoCap'.


Your program works for me on Win7 32bits with D2010.

What it does though is raising an exception:

---------------------------
Project WebCamTest.exe raised exception class EFCreateError with message 
'Cannot create file "c:\webcam.jpg". Access is denied'.
---------------------------

which can be corrected by changing

FJpeg.SaveToFile('c:\webcam.jpg');

to

FJpeg.SaveToFile(TPath.GetTempPath + '\webcam.jpg');

And also, it does not display the whole available image, you'd have to enlarge your Panel, recenter or shrink the webcam output.

Update with some code modifications that would make it work per your comments...

  // introducing the RGB array and a buffer
  TVideoArray = array[1..PICHEIGHT] of array[1..PICWIDTH] of TRGBTriple;
  PVideoArray = ^TVideoArray;

  TForm1 = class(TForm)
[...]
  FBuf24_1: TVideoArray;
[...]

function FrameCallbackFunction(AHandle: hWnd; VIDEOHDR: TVideoHDRPtr): bool; stdcall;
var
  I: integer;
begin
  result:= true;

  with form1 do begin
  try
    if ConvertCodecToRGB(FCodec, VideoHDR^.lpData, @FBuf2, PICWIDTH, PICHEIGHT) then
    begin
      for I:= 1 to PICHEIGHT do FBuf1[I]:= FBuf2[PICHEIGHT- (I- 1)];
      SetBitmapBits(FBitmap.Handle, PICWIDTH* PICHEIGHT* SizeOf(DWord), @FBuf1);
    end
    else
    begin  // assume RGB
      for I:= 1 to PICHEIGHT do
        FBuf24_1[I] := PVideoArray(VideoHDR^.lpData)^[PICHEIGHT-I+1];
      SetBitmapBits(FBitmap.Handle, PICWIDTH* PICHEIGHT* SizeOf(RGBTriple), @FBuf24_1);
    end;
[...]

Related Questions

Related delphi Video tutorials from Youtube.


Delphi Training Series: Progra
Ever wanted to become a programmer? The Delphi Training Series: Programming 101 is a sequence of tra
Delphi Training Series: Programming 101 - Episode 2
Ever wanted to become a programmer? The Delphi Training Series: Programming 101 is a sequence of training videos designed to teach the complete beginner how to become a programmer using Delphi.

Delphi Training Series: Progra
Ever wanted to become a programmer? The Delphi Training Series: Programming 101 is a sequence of tra
Delphi Training Series: Programming 101 - Episode 3
Ever wanted to become a programmer? The Delphi Training Series: Programming 101 is a sequence of training videos designed to teach the complete beginner how to become a programmer using Delphi. Episode 3 explores simple game design!

Delphi Training Series: Progra
Ever wanted to become a programmer? The Delphi Training Series: Programming 101 is a sequence of tra
Delphi Training Series: Programming 101 - Episode 5
Ever wanted to become a programmer? The Delphi Training Series: Programming 101 is a sequence of training videos designed to teach the complete beginner how to become a programmer using Delphi. In this episode, the viewer is exposed to the world of Procedures and Functions. This video continues the series with focus on writing your own mp3 player.

Find Files Taking Up The Most
Windows www.delphiforfun.org It takes a little while to scan so be patient. Also see to clear search
Find Files Taking Up The Most Disk Space (Win/Mac)
Windows www.delphiforfun.org It takes a little while to scan so be patient. Also see to clear search / personal history: www.ccleaner.com www.stevengould.org This thing lets you see how big your folders are foldersize.sourceforge.net Shinigami37 recommends windirstat.info Adamgooday Recommends w3.win.tue.nl MAC grandperspectiv.sourceforge.net www.jgoodies.com www.id-design.com Also all the programs in delphi for fun's site contain the sourcecode so if you're looking to learn delphi it's an awesome site. www.delphiforfun.org Also in windows when you go to add or remove programs in the control panel you can order by size. %%howto

Delphi Training Series: Supple
Supplemental Delphi training video giving a sneak peek at the enhancements made to the simple MP3 pl
Delphi Training Series: Supplemental Video 1
Supplemental Delphi training video giving a sneak peek at the enhancements made to the simple MP3 player.

Delphi Training Series: Progra
Ever wanted to become a programmer? The Delphi Training Series: Programming 101 is a sequence of tra
Delphi Training Series: Programming 101 - Episode 4
Ever wanted to become a programmer? The Delphi Training Series: Programming 101 is a sequence of training videos designed to teach the complete beginner how to become a programmer using Delphi. In this episode, the viewer is introduced to the concept of variables. This video is the first in a mini-series aimed at the creation of your own MP3 player.

Delphi Training Series: Progra
Ever wanted to become a programmer? The Delphi Training Series: Programming 101 is a sequence of tra
Delphi Training Series: Programming 101 - Episode 8
Ever wanted to become a programmer? The Delphi Training Series: Programming 101 is a sequence of training videos designed to teach the complete beginner how to become a programmer using Delphi. In the eighth installment of the Delphi Training Series, we take a short break away from the MP3 player we were writing to introduce you to a new aspect of programming: The IF statement.

Delphi Training Series: Progra
Ever wanted to become a programmer? The Delphi Training Series: Programming 101 is a sequence of tra
Delphi Training Series: Programming 101 - Episode 9
Ever wanted to become a programmer? The Delphi Training Series: Programming 101 is a sequence of training videos designed to teach the complete beginner how to become a programmer using Delphi. The ninth episode of the Delphi Training Series is another theory-driven exploration, stepping away from the MP3 player to take a look at looping and how it works inside of Object Pascal.

Rotating Circles Form - CodeGe
This is a demonstration of how Windows applications built with Delphi can have more dynamic and inte
Rotating Circles Form - CodeGear Delphi
This is a demonstration of how Windows applications built with Delphi can have more dynamic and interactive user interfaces. This video is part of the CodeGear Video Competition. Please vote!

Delphi Programming Tutorial #2
In this Delphi tutorial we are going to look at how to take advantage of the OnDrawColumnCell event
Delphi Programming Tutorial #24 - DBGrid OnDrawColumnCell
In this Delphi tutorial we are going to look at how to take advantage of the OnDrawColumnCell event on the TDBGrid component. In particular we are going to examine how to make every second row a different colour (Sky Blue) and how we can change the appearance of the text depending on the data. PS. Sky Blue is not compulsory (and perhaps not even recommended)

Delphi Programming Tutorial #3
This is an introduction to using Dockable Forms with Delphi. In it we create some multi-coloured for
Delphi Programming Tutorial #32 - Dockable Forms
This is an introduction to using Dockable Forms with Delphi. In it we create some multi-coloured forms and dock them into a TPageControl and a TPanel.

how to host boot with metus de
this is not a virus it is hacking software and all hacking software comes up as virus but it doesnt
how to host boot with metus delphi 2.8 (voice tut)
this is not a virus it is hacking software and all hacking software comes up as virus but it doesnt do anything to your computer. extract the files to your desktop for them to work properly and run as admin when using the programs!!!!!!!!!! metus and cain and able download: www.megaupload.com i am not responsible for what you do with this program all credit goes to HackingProducts www.youtube.com

Delphi Programming Tutorial #3
In this Delphi training guide we look further into Form Docking. In particular we look at the Manual
Delphi Programming Tutorial #33 - Dockable Forms 2
In this Delphi training guide we look further into Form Docking. In particular we look at the ManualFloat and ManualDock methods to dock and undock forms in code (rather than Drag & Dock).

Conhecendo o Delphi
Conheça um pouco do Delphi nesta video aula. Professor Neri Aldoir Neitzke - instrutor da Ulbra - Un
Conhecendo o Delphi
Conheça um pouco do Delphi nesta video aula. Professor Neri Aldoir Neitzke - instrutor da Ulbra - Universidade Luterana do Brasil www.informaticon.com.br - neri@informaticon.com.br Phone: (55) 0xx54 3330-1222) Obs.: aqui no youtube as video aulas não ficaram muito nítidas, mas posso enviar por cd mais e melhores video aulas

Delphi Programming Tutorial #1
In this movie we look at how you can use Align and Margins to control how your visual controls behav
Delphi Programming Tutorial #13 - Align and Margins
In this movie we look at how you can use Align and Margins to control how your visual controls behave when you resize your form. You can download a copy of Delphi from turboexplorer.com, and view a high resolution version of this movie at codegearguru.com

Creating a Webbrowser in Delph
I will show you how to create a basic webbrowser in borland delphi, i am using delphi 7 in this vide
Creating a Webbrowser in Delphi
I will show you how to create a basic webbrowser in borland delphi, i am using delphi 7 in this video. But i will post now where to download Delphi and the mozilla firefox component. Delphi: rapidshare.com Firefox component: www.iol.ie Thanks for watching. Tutorial 2 will be out sometime next week or two.

My Snake Game (programmed with
features: - Single Player/Multi Player - Level Editor - Highscores - different colors and background
My Snake Game (programmed with Delphi)
features: - Single Player/Multi Player - Level Editor - Highscores - different colors and backgrounds My self-made Snake game programmed with Delphi. It has many features like a 2-Player-Mode, different colors and backgrounds and a Level Editor! Download here (English and German; new: now all in one program!): lumpiluk.000space.com

Delphi Programming Tutorial #5
In this Delphi programming tutorial we start with an application that loads and saves some settings
Delphi Programming Tutorial #52 - TINIFile
In this Delphi programming tutorial we start with an application that loads and saves some settings out of an ini-file. We then tidy up the code a bit by creating a new class inheriting from TIniFile that uses properties with getter and setter methods to change the settings rather than ReadString / WriteString. This makes the code much nicer as you get code completion and error insight. We also make use of the Initialization and Finalization sections of a unit to create and free our new class.

How to make a Text Editor in D
Shows you how to make a simple text editor. I will try 2 answer all questions about the text editor.
How to make a Text Editor in Delphi 7
Shows you how to make a simple text editor. I will try 2 answer all questions about the text editor.

Auto-Typer Tutorial [C#]
www.Decayed-Asylum.net C# Tutorial Programming Auto Typer Talker Autotalker Runescape Autotyper C++
Auto-Typer Tutorial [C#]
www.Decayed-Asylum.net C# Tutorial Programming Auto Typer Talker Autotalker Runescape Autotyper C++ C Visual Basic .Net Delphi Scar Help Code Hack Bot Puzzle Pirates Bot Bilge BilgeBuddy Pure bilger purebilger Auto Hacks Hack Hacker Mod Modder ypp !YPP Y!

Able Builders for the Radio Sh
A shareware game similar to Kaboom! or Popcorn I downloaded from Delphi.
Able Builders for the Radio Shack Color Computer.
A shareware game similar to Kaboom! or Popcorn I downloaded from Delphi.

BlitzBasic development, my bes
Please help us to finance the Projects. It costs nothing for you and you get a big chance to win big
BlitzBasic development, my best self-programmed Software ;)
Please help us to finance the Projects. It costs nothing for you and you get a big chance to win big money: sev4ifmxa.com Thank you alot and now have a lot fun with my Video :) hi, in this movie you can see a few projects i've made. I used BlitzBasic, Delphi, 3d-Gamstudio with wdl, some Excel with VBA, ClickExe and some old Qbasic and a little JavaScript. Music by Hooverphonic: World is mine ^^

Delphi Programming Movie #37 -
In this quick Delphi programming tutorial we take a look at two ways of doing a for loop
Delphi Programming Movie #37 - For Loop Ramblings
In this quick Delphi programming tutorial we take a look at two ways of doing a for loop

Delphi - HelloWorld
Dieses Video dient nur zur Demonstration. In einem weiterem Tutorial werde ich alle wichtigen Grundl
Delphi - HelloWorld
Dieses Video dient nur zur Demonstration. In einem weiterem Tutorial werde ich alle wichtigen Grundlagen erläutern. Also bliebt am Ball und probiert das Programm vielleicht mal mit dem Turbo Explorer von turboexplorer.com nachzuprogrammieren. Verzeiht mir auch bitte meine Verspreche - ist mein erstes Video-Tutorial. Ich würde mich sehr über viel Feedback freuen. Wenn ihr eigene Tutorialwünsche bezüglich Delphi habt, könnt ihr euch gerne ein Videotut wünschen

Criando a primeira aplicação
Veja nessa video aula como criar uma aplicação em Delphi. Desenv. por Neri Aldoir Neitzke, neri@info
Criando a primeira aplicação
Veja nessa video aula como criar uma aplicação em Delphi. Desenv. por Neri Aldoir Neitzke, neri@informaticon.com.br, www.informaticon.com.br - Phone 55 0xx54 3330 1222 - Carazinho-RS. Obs.: no you tube as video aulas não ficaram nítidas, posso envir por email o cd com todas as video aulas.

Free Pascal Tutorial 22 - Syst
This tutorial uses the Free Pascal Compiler and Lazarus IDE Mac port. Windows programmers can follow
Free Pascal Tutorial 22 - System Timer - Lazarus - Programming On The Mac
This tutorial uses the Free Pascal Compiler and Lazarus IDE Mac port. Windows programmers can follow along without complication since both IDEs are almost 100% identical. Programmers looking to port Delphi applications to the Mac, should take a look at using Lazarus since Delphi for Mac X does not exist, at this time. Also, these tools are useful when porting Turbo Pascal programs to the Macintosh since Turbo Pascal For Mac is no longer offered by Borland. The code, for the second part of this tutorial, can be downloaded for free at www.schoolfreeware.com. Have Fun Programming.

Delphi Programming Tutorial #3
In this delphi programming tutorial we look at using TeeChart (TChart) to produce a graph of Jpeg qu
Delphi Programming Tutorial #38 - Charting Jpeg Compression
In this delphi programming tutorial we look at using TeeChart (TChart) to produce a graph of Jpeg quality verses file size.

Presentation Program for CRT,
This is a quick demonstration of what is possible with my presentation application for different scr
Presentation Program for CRT, LCD/TFT, Plasma
This is a quick demonstration of what is possible with my presentation application for different screen types. It is programmed in Delphi and OpenGL (source is included) and already tested on Windows XP, Vista and 7. I've made it for a German physics presentation and translated it to English afterwards, so please tell me if I've made any mistakes. You can download it here: sourceforge.net

Delphi Programming Tutorial #5
Delphi is a statically typed language, but there are some tricks you can use if you want to be able
Delphi Programming Tutorial #54 - Dynamic Typing
Delphi is a statically typed language, but there are some tricks you can use if you want to be able to do some dynamically typed coding. In this Delphi programming tutorial we create a custom variant type (descending from TInvokeableVariantType). We then override Get and SetProperty to handle arbitary properties (that don't exist at design time).

Delphi Programming Tutorial #4
In this Delphi Programming Tutorial we introduce the basics of Drag and Drop. We also look at how we
Delphi Programming Tutorial #44 - Drag and Drop
In this Delphi Programming Tutorial we introduce the basics of Drag and Drop. We also look at how we can drag and drop between pages in a TPageControl

Delphi Programming Tutorial #2
In this programming tutorial we'll learn about the ScaleBy Method to resize controls and their child
Delphi Programming Tutorial #20 - ScaleBy
In this programming tutorial we'll learn about the ScaleBy Method to resize controls and their children. This can be useful in creating Forms that are resolution indepenand

[Delphi Tutorial] Snake #1 - F
Dieses Video ist der Anfang einer Tutorial-Serie in welcher ich die Entwicklung eines einfachen Snak
[Delphi Tutorial] Snake #1 - Fenster und die Snake Klasse
Dieses Video ist der Anfang einer Tutorial-Serie in welcher ich die Entwicklung eines einfachen Snake entwickel. Als Sprache wird Delphi 7 Personal eingesetzt. Andere Versionen von Delphi sollten jedoch auch funktionieren. In diesem Teil erkläre ich ein paar Grundlagen, passe das Fenster an und erstelle den ersten Schritt der Snake-Klasse. Die Thema des nächsten Tutorials werden die erste Erweiterung der Snake-Klasse und ein erstes Rendering umfassen. Download von Teil 1: anihex.chaos-rai.com

Delphi Programming Tutorial #2
In this Delphi training movie we take a look at how to create forms, yes I know Delphi can do this f
Delphi Programming Tutorial #26 - Form Creation
In this Delphi training movie we take a look at how to create forms, yes I know Delphi can do this for you automatically - but sometimes you will want to do it for yourself. Creating forms as they are needed can make your application start faster and take up less resources.

Ligando um formulário Delphi c
Desenv. por Neri Aldoir Neitzke, neri@informaticon.com.br www.informaticon.com.br - 0xx54 3330 1222
Ligando um formulário Delphi com o Banco de dados
Desenv. por Neri Aldoir Neitzke, neri@informaticon.com.br www.informaticon.com.br - 0xx54 3330 1222 - Carazinho-RS Obs.: no you tube as video aulas não ficaram nítidas, posso envir por email o cd com todas as video aulas.

Criando uma barra de status no
Aprenda a criar uma barra de status no Delphi.Desenvolvido por Neri Aldoir Neitzke - www.informatico
Criando uma barra de status no Delphi
Aprenda a criar uma barra de status no Delphi.Desenvolvido por Neri Aldoir Neitzke - www.informaticon.com.br - neri@informaticon.com.br Phone: 55 0xx54 3330 1222 Obs.: no youtube as video aulas não ficaram nítidas, se quiser, tenho em cd mais e melhores video aulas.

Delphi Programming Tutorial #1
Delphi controls have an owner and parent property, find out what the difference.
Delphi Programming Tutorial #17 - Owner vs. Parent
Delphi controls have an owner and parent property, find out what the difference.

Post you comment here

Your Name (*) :
Your Email :
Subject (*):
Your Comment (*):
  Reload Image
 
 

There are 0 comment(s) to this page.



The questions and answers taken from stackoverflow.com's public data dump which is licensed under the cc-wiki license.
Logo, website design and layout ©2011 CodingTiger.com