⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vidinput_avc.cxx

📁 安装 H323需要的pwlib库
💻 CXX
字号:
/* * This file is essentially a rewrite of video4dc1394.cxx * Check that one for more explanations * * A lot of code "borrowed" from * - dvgrab.c from libdv (http://libdv.sf.net/) * - kino (http://kino.schirmacher.de/) * - video4dc1394.cxx from ptlib * - ... probably others too * * The code is highly experimental. * You should expect any of : * - plenty of segfaults * - loss of performance * - not working at all for you *  * Known Bugs / Limitations / Room for improvement (feel free to patch/suggest) * - Colors are no good after a Convert  *   Can someone look at the code and tell me what I have to tell the convert function *   that my source colors are? I thought it is pure RGB24, but obviously not. *   Dumping the binary data directly to a PPM file works like a charm, though :-/ * - Occasional segfaults (I think these are fixed, but don't be surprised if it works not) * - grabs first camera by default (not sure how to go about selection of cameras/ports) * - still haven't figured what the channel parameter in start_iso_rcv(handle,channel) means, *   but it seems that we are in for a long wait if channel != 63 * - code depends on libavc1394 to figure out if a device is a camera *   I am not really sure there isn't a smarter way of going about it *   since capturing video only requires libraw1394 (for the moment) *   Maybe we can drop that dependency? * - Still not sure how to go about setting frame size. *   Resizing manually at the moment, since the frame size of a captured frame *   from an AVC camera is not settable. *   An AVC camera supports either NTSC (720x480) or PAL (720x576) resolution *   and the only way to check which one it is, seems to be to parse the header *   of a captured frame. Will wait for a suggestion on the proper way to handle it. * - bus resets not handled (yet?) * - Still not sure what to use the device name for (beats me :( ) * - not sure if TRY_1394AVC and TRY_1394DC will not break something if used at the same time * - Overuse of PTRACE? * - I am not sure how most of the stuff works * - ... everything else * * Technical Notes * ------------------------------------------------------------ * * Test Environment: * This module was tested against: * Hardware: *   AthlonXP 1800+ *   Asus A7S333 *   Sony DCR-TRV20 NTSC (http://www.sony.jp/products/Consumer/VD/DCR-TRV20/) *   Texas Instruments TSB12LV26 IEEE-1394 Controller  * Software: *   Linux vanilla kernel 2.4.20 *   libraw1394 0.9.0 *   libavc1394 0.4.1 *   libdv 0.98 * * Author: Georgi Georgiev <chutz@gg3.net> * */#pragma implementation "vidinput_avc.h"#include "vidinput_avc.h"#ifndef RAW_BUFFER_SIZE#define RAW_BUFFER_SIZE 512#endif PCREATE_VIDINPUT_PLUGIN(AVC, PVideoInput1394AvcDevice);static PMutex mutex;static PDictionary<PString, PString> *dico;static u_int8_t raw_buffer[RAW_BUFFER_SIZE];///////////////////////////////////////////////////////////////////////////////// PVideoInput1394AVCPVideoInput1394AvcDevice::PVideoInput1394AvcDevice(){  handle = NULL;  is_capturing = FALSE;  dv_decoder = NULL;}PVideoInput1394AvcDevice::~PVideoInput1394AvcDevice(){  Close();}BOOL PVideoInput1394AvcDevice::Open(const PString & devName, BOOL startImmediate){  PTRACE(3, "trying to open " << devName);  if (IsOpen())    Close();  UseDMA = TRUE; // FIXME: useful?  handle = raw1394_new_handle();  if (handle == NULL) {    PTRACE(3, "No handle.");    return FALSE;  }    mutex.Wait();  if(dico != NULL && sscanf((char *)dico->GetAt(devName), "%d", &port) == 1)    ; // well, got it  else    port = 0;  mutex.Signal();    if(raw1394_set_port(handle, port) != 0) {    PTRACE(3, "couldn't set the port");    Close();    return FALSE;  }    frameWidth = CIFWidth;  frameHeight = CIFHeight;  colourFormat = "RGB24F";  desiredFrameHeight = CIFHeight;  desiredFrameWidth = CIFWidth;  desiredColourFormat = "RGB24F";    deviceName = devName; // FIXME: looks useless    if (!SetChannel(channelNumber)      || !SetVideoFormat(videoFormat)) {    PTRACE(3, "SetChannel() or SetVideoFormat() failed");    Close();    return FALSE;  }    if (startImmediate && !Start()) {    Close();    return FALSE;  }    PTRACE(3, "Successfully opened avc1394");  return TRUE;}BOOL PVideoInput1394AvcDevice::IsOpen() {  return handle != NULL;}BOOL PVideoInput1394AvcDevice::Close(){  PTRACE(3, "Close()");  if (IsOpen()) {    if (IsCapturing())      Stop();    raw1394_destroy_handle(handle);    handle = NULL;    return TRUE;  }  else    return FALSE;}BOOL PVideoInput1394AvcDevice::Start(){  if (!IsOpen()) return FALSE;  if (IsCapturing()) return TRUE;    if (raw1394_set_iso_handler(handle, 63, &RawISOHandler)!= NULL) {    PTRACE (3, "Cannot set_iso_handler");    return FALSE;  }    is_capturing = TRUE;  return TRUE;}BOOL PVideoInput1394AvcDevice::Stop(){  if (IsCapturing()) {    is_capturing = FALSE;    return TRUE;  }  else    return FALSE;}BOOL PVideoInput1394AvcDevice::IsCapturing(){  return is_capturing;}PStringList PVideoInput1394AvcDevice::GetInputDeviceNames(){  PStringList Result;  raw1394handle_t hdl = NULL;    hdl = raw1394_new_handle();    if(hdl == NULL)    return Result;    // scan all nodes of all ports, check the real name of the device  int nb_ports = raw1394_get_port_info(hdl, NULL, 0);  for(int pt = 0; pt < nb_ports; pt++) {    if(raw1394_set_port(hdl, pt) >= 0) {      int nb_nodes = raw1394_get_nodecount(hdl);      for(int nd = 0; nd < nb_nodes; nd++) {	rom1394_directory dir;	rom1394_get_directory(hdl, nd, &dir);	if(rom1394_get_node_type(&dir) == ROM1394_NODE_TYPE_AVC) {	  PString ufname = (PString)dir.label;	  PString *devname = new PString(pt);	  mutex.Wait();	  if(dico == NULL)	    dico = new PDictionary<PString, PString>;	  if(dico->Contains(ufname)	     && *dico->GetAt(ufname) != *devname) {		      PString altname = ufname+ " (2)";		      int i = 2;		      while(dico->Contains(altname) && *dico->GetAt(altname) != *devname) {			i++;			altname = ufname+ " ("+(PString)i+")";		      }		      dico->SetAt(altname, devname);		      Result.AppendString(altname);	  }	  else {	    dico->SetAt(ufname, devname);	    Result.AppendString(ufname);	  }	  mutex.Signal();	}      }    }      }    raw1394_destroy_handle(hdl);  return Result;}BOOL PVideoInput1394AvcDevice::SetVideoFormat(VideoFormat newFormat){  // FIXME: isn't it inherited from PVideoDevice anyway?  if (!PVideoDevice::SetVideoFormat(newFormat)) {    PTRACE(3,"PVideoDevice::SetVideoFormat failed");    return FALSE;  }  else    return TRUE;}int PVideoInput1394AvcDevice::GetBrightness(){  return -1;}BOOL PVideoInput1394AvcDevice::SetBrightness(unsigned newBrightness){  return FALSE;}int PVideoInput1394AvcDevice::GetHue(){  return -1;}BOOL PVideoInput1394AvcDevice::SetHue(unsigned newHue){  return FALSE;}int PVideoInput1394AvcDevice::GetContrast(){  return -1;}BOOL PVideoInput1394AvcDevice::SetContrast(unsigned newContrast){  return FALSE;}BOOL PVideoInput1394AvcDevice::SetColour(unsigned newColour) {  return -1;}int PVideoInput1394AvcDevice::GetColour(){  return -1;}BOOL PVideoInput1394AvcDevice::SetWhiteness(unsigned newWhiteness) {  return FALSE;}int PVideoInput1394AvcDevice::GetWhiteness(){  return -1;}BOOL PVideoInput1394AvcDevice::GetParameters (int *whiteness, int *brightness,                                       int *colour, int *contrast, int *hue){  *whiteness = -1;  *brightness = -1;  *colour = -1;  *hue = -1;  return FALSE;}int PVideoInput1394AvcDevice::GetNumChannels() {  int Result;  mutex.Wait();  if(dico != NULL)    Result = dico->GetSize();  else    Result = 0;  mutex.Signal();  return Result;}BOOL PVideoInput1394AvcDevice::SetChannel(int newChannel){  if (PVideoDevice::SetChannel(newChannel) == FALSE)    return FALSE;  if(IsCapturing()) {    Stop();    Start();  }    return TRUE;}BOOL PVideoInput1394AvcDevice::SetFrameRate(unsigned rate){  return PVideoDevice::SetFrameRate(rate);}BOOL PVideoInput1394AvcDevice::GetFrameSizeLimits(unsigned & minWidth,						  unsigned & minHeight,						  unsigned & maxWidth,						  unsigned & maxHeight) {  minWidth = 160;  maxWidth = 320;  minHeight = 120;  maxHeight = 240;  return TRUE;}BOOL PVideoInput1394AvcDevice::GetFrame(PBYTEArray & frame){  PINDEX returned;  if (!GetFrameData(frame.GetPointer(GetMaxFrameBytes()), &returned))    return FALSE;  frame.SetSize(returned);  return TRUE;}PINDEX PVideoInput1394AvcDevice::GetMaxFrameBytes(){    if(converter == NULL)    return frameBytes;    PINDEX bytes = converter->GetMaxDstFrameBytes();  if (bytes > frameBytes)    return bytes;  else    return frameBytes;  }BOOL PVideoInput1394AvcDevice::GetFrameDataNoDelay(BYTE * buffer,						   PINDEX * bytesReturned){  if (!IsCapturing()) return FALSE;  BOOL frame_complete = FALSE;  BOOL found_first_frame = FALSE;  int skipped = 0;  int broken_frames = 0;  BYTE capture_buffer[150000];  BYTE * capture_buffer_end = capture_buffer;    // this starts the bytes' rain  if (raw1394_start_iso_rcv(handle, 63) < 0) {    PTRACE(3, "Cannot receive data on channel 63");    return FALSE;  }  // calling the raw1394 event manager, to get a frame:  while(!frame_complete) {    raw1394_loop_iterate(handle);    if (*(uint32_t *)raw_buffer >= 492) {      if (!found_first_frame) {	if (raw_buffer[16] == 0x1f && raw_buffer[17] == 0x07)	  found_first_frame = TRUE;	else	  skipped ++;      }      if (skipped > 500) {	PTRACE (3, "Skipped much too many frames");	return FALSE;      }      if (found_first_frame) {	if (raw_buffer[16] == 0x1f	    && raw_buffer[17] == 0x07	    && (capture_buffer_end - capture_buffer > 480)) {	  // check for a short read. check if we read less	  // than a NTSC frame because it is the smaller one.	  // still not sure how to handle NTSC vs. PAL	  if (capture_buffer_end - capture_buffer < 120000) {	    broken_frames++;	    capture_buffer_end = capture_buffer;	  }	  else	    frame_complete = TRUE;	}	if (!frame_complete) {	  memcpy (capture_buffer_end, raw_buffer+16, 480);	  capture_buffer_end += 480;	}      } // found_first_frame      if (broken_frames > 30) {	PTRACE(3, "Too many broken frames!");	return FALSE;      }    }  }  // stops the bytes from coming at us!  raw1394_stop_iso_rcv(handle, 63);    dv_decoder_t *dv;  dv = dv_decoder_new(TRUE, FALSE, FALSE);  dv->quality = DV_QUALITY_BEST; // FIXME: best!?  if(dv_parse_header(dv, capture_buffer) < 0) {    PTRACE(3, "cannot parse dv frame header");    return FALSE;  }    dv_color_space_t color_space;  BYTE * pixels[3];  int  pitches[3];    pitches[0] = dv->width * 3;  pitches[1] = pitches[2] = 0;    pixels[0] = (uint8_t *)malloc(dv->width * dv->height * 3);  pixels[1] = NULL;  pixels[2] = NULL;  color_space = e_dv_color_rgb;    dv_decode_full_frame(dv, capture_buffer, color_space, pixels, pitches);    // FIXME: this is a manual resize ; the original author wondered about it  float xRatio = dv->width / (float)frameWidth;  float yRatio = dv->height/ (float)frameHeight;  for(uint y = 0; y < frameHeight; y++)    for (uint x = 0; x < frameWidth; x++) {      uint16_t sourceX = (uint16_t) (x * xRatio);      uint16_t sourceY = (uint16_t) (y * yRatio);      memcpy (pixels[0]+3*(y*frameWidth+x),	      pixels[0]+3*(sourceY*dv->width+sourceX),	      3);            // FIXME: BGR <-> RGB done by hand      BYTE temp;      int offset= (y*frameWidth+x)*3;      temp = pixels[0][offset+0];      pixels[0][offset+0] = pixels[0][offset+2];      pixels[0][offset+2] = temp;    }  if (converter != NULL) {    converter->Convert((const BYTE *)pixels[0], buffer, bytesReturned);    if (pixels[0] != NULL)      free(pixels[0]);  }  else {    PTRACE(3, "Converter must exist. Something goes wrong.");    return FALSE;  }    return TRUE;  }BOOL PVideoInput1394AvcDevice::GetFrameData(BYTE * buffer,					    PINDEX * bytesReturned){  int capturing_duration = 10000; // FIXME: what is it for?  // notice: funny things happen when it is set too low!    if(frameRate>0) {    if(msBetweenFrames > capturing_duration)      PThread::Current()->Sleep(msBetweenFrames - capturing_duration);    PTime start;    if(!GetFrameDataNoDelay(buffer, bytesReturned))      return FALSE;    PTime end;    capturing_duration = (int)((end-start).GetMilliSeconds());    return TRUE;  }  return GetFrameDataNoDelay(buffer, bytesReturned);}void PVideoInput1394AvcDevice::ClearMapping(){  // do nothing...}BOOL PVideoInput1394AvcDevice::TestAllFormats(){  return TRUE;}BOOL PVideoInput1394AvcDevice::SetColourFormat(const PString & newFormat){  if (newFormat != colourFormat)    return FALSE;    return TRUE;}BOOL PVideoInput1394AvcDevice::SetFrameSize(unsigned width, unsigned height){  // FIXME: shouldn't it return FALSE when asked an unsupported frame size?   frameWidth = width;  frameHeight = height;  colourFormat = "RGB24F";  frameBytes = PVideoDevice::CalculateFrameBytes(frameWidth,						 frameHeight, colourFormat);    return TRUE;}BOOL PVideoInput1394AvcDevice::SetFrameSizeConverter(unsigned width,						     unsigned height,						     BOOL bScaleNotCrop){  SetFrameSize(width, height);  if (converter != NULL)     delete converter;    desiredFrameWidth = width;  desiredFrameHeight = height;  converter = PColourConverter::Create(colourFormat,				       desiredColourFormat, width, height);  if (converter == NULL) {    PTRACE(3, "Failed to make a converter.");    return FALSE;  }  if (converter->SetSrcFrameSize(width,height) == FALSE) {    PTRACE(3, "Failed to set source frame size of a converter.");    return FALSE;  }    if (converter->SetDstFrameSize(desiredFrameWidth,				 desiredFrameHeight, FALSE) == FALSE) {    PTRACE(3, "Failed to set destination frame size (+scaling) of a converter.");    return FALSE;  }    return TRUE;}BOOL PVideoInput1394AvcDevice::SetColourFormatConverter(const PString &colourFmt){  desiredColourFormat = colourFmt;  return SetFrameSizeConverter(desiredFrameWidth, desiredFrameHeight, FALSE);}int RawISOHandler (raw1394handle_t handle, int channel, size_t length, u_int32_t * data){	if (length < RAW_BUFFER_SIZE) {	  *(u_int32_t *) raw_buffer = length;	  memcpy (raw_buffer + 4, data, length);	}	return 0;}// End Of File ///////////////////////////////////////////////////////////////

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -