📄 video_v4l2_source.cpp
字号:
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * 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 MPEG4IP. * * The Initial Developer of the Original Code is Cisco Systems Inc. * Portions created by Cisco Systems Inc. are * Copyright (C) Cisco Systems Inc. 2003-2005. All Rights Reserved. * * Contributor(s): * Waqar Mohsin wmohsin@cisco.com * Bill May wmay@cisco.com * Charlie Normand charlienormand@cantab.net alias cpn24 */#include "mp4live.h"#include <sys/mman.h>#include "video_v4l_source.h"#include "video_util_rgb.h"#include "video_util_filter.h"#include "video_util_convert.h"const char *get_linux_video_type (void){ return "V4L2";}int CV4LVideoSource::ThreadMain(void) { debug_message("v4l2 thread start"); m_v4l_mutex = NULL; m_waiting_frames_return = false; while (true) { int rc; if (m_source && m_waiting_frames_return == false) { rc = SDL_SemTryWait(m_myMsgQueueSemaphore); } else { rc = SDL_SemWait(m_myMsgQueueSemaphore); } // semaphore error if (rc == -1) { break; } // message pending if (rc == 0) { CMsg* pMsg = m_myMsgQueue.get_message(); if (pMsg != NULL) { switch (pMsg->get_value()) { case MSG_NODE_STOP_THREAD: while (DoStopCapture() == false) { SDL_Delay(10); // ensure things get cleaned up debug_message("waiting for stop thread"); } delete pMsg; debug_message("v4l2 thread exit"); return 0; case MSG_NODE_START: DoStartCapture(); debug_message("v4l2 thread start capture"); break; case MSG_NODE_STOP: debug_message("v4l2 thread stop capture"); DoStopCapture(); break; } delete pMsg; } } if (m_source) { try { ProcessVideo(); } catch (...) { DoStopCapture(); break; } } else { DoStopCapture(); } } debug_message("v4l2 thread exit"); return -1;}void CV4LVideoSource::DoStartCapture(void){ if (m_source) { return; } if (m_v4l_mutex == NULL) m_v4l_mutex = SDL_CreateMutex(); if (!Init()) return; m_source = true;}bool CV4LVideoSource::DoStopCapture(void){ if (m_source) { debug_message("dostopcapture - releasing device"); ReleaseDevice(); } m_source = false; if (ReleaseBuffers() == false) { debug_message("releasebuffers false"); return false; } SDL_DestroyMutex(m_v4l_mutex); m_v4l_mutex = NULL; return true;}bool CV4LVideoSource::Init(void){ m_pConfig->CalculateVideoFrameSize(); InitVideo(true); SetVideoSrcSize( m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH), m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_HEIGHT), m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH)); if (!InitDevice()) return false; m_maxPasses = (u_int8_t)(m_videoSrcFrameRate + 0.5); return true;}static const uint32_t formats[] = { V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YYUV, V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_BGR24,};bool CV4LVideoSource::InitDevice(void){ int rc; SDL_LockMutex(m_v4l_mutex); if (m_buffers != NULL) { unreleased_capture_buffers_t *p = MALLOC_STRUCTURE(unreleased_capture_buffers_t); debug_message("creating unreleased capture buffer, version %u", m_hardware_version); p->buffer_list = m_buffers; m_buffers = NULL; p->hardware_version = m_hardware_version; p->next = m_unreleased_buffers_list; m_unreleased_buffers_list = p; } m_hardware_version++; SDL_UnlockMutex(m_v4l_mutex); const char* deviceName = m_pConfig->GetStringValue(CONFIG_VIDEO_SOURCE_NAME); int buftype = V4L2_BUF_TYPE_VIDEO_CAPTURE; bool pass = false; v4l2_std_id std; if (m_videoDevice != -1) debug_message("video device already open !!!"); // open the video device m_videoDevice = open(deviceName, O_RDWR); if (m_videoDevice < 0) { error_message("Failed to open %s: %s", deviceName, strerror(errno)); return false; } // query device capabilities struct v4l2_capability capability; memset(&capability, 0, sizeof(capability)); rc = ioctl(m_videoDevice, VIDIOC_QUERYCAP, &capability); if (rc < 0) { error_message("Failed to query video capabilities for %s", deviceName); goto failure; } // make sure device supports video capture if (!(capability.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { error_message("Device %s is not capable of video capture!", deviceName); goto failure; } // query attributes of video input struct v4l2_input input; memset(&input, 0, sizeof(input)); uint input_value; input_value = m_pConfig->GetIntegerValue(CONFIG_VIDEO_INPUT); if (m_pConfig->m_videoCapabilities != NULL) { uint compare_value = m_pConfig->m_videoCapabilities->m_numInputs; if (compare_value > 0) compare_value--; if (input_value > compare_value) { input_value = 0; m_pConfig->SetIntegerValue(CONFIG_VIDEO_INPUT, input_value); error_message("Video input value exceed capabilities; replacing with 0"); } } input.index = input_value; rc = ioctl(m_videoDevice, VIDIOC_ENUMINPUT, &input); if (rc < 0) { error_message("Failed to enumerate video input %d for %s", input.index, deviceName); //goto failure; } // select video input rc = ioctl(m_videoDevice, VIDIOC_S_INPUT, &input.index); if (rc < 0) { error_message("Failed to select video input %d for %s", input.index, deviceName); //goto failure; } // select video input standard type switch(m_pConfig->GetIntegerValue(CONFIG_VIDEO_SIGNAL)) { case VIDEO_SIGNAL_PAL: std = V4L2_STD_PAL; break; case VIDEO_SIGNAL_NTSC: std = V4L2_STD_NTSC; break; case VIDEO_SIGNAL_SECAM: std = V4L2_STD_SECAM; break; } rc = ioctl(m_videoDevice, VIDIOC_S_STD, &std); if (rc < 0) { error_message("Failed to select video standard for %s", deviceName); //goto failure; } if (m_pConfig->GetIntegerValue(CONFIG_VIDEO_SIGNAL) == VIDEO_SIGNAL_NTSC) { m_videoSrcFrameRate = VIDEO_NTSC_FRAME_RATE; } else { m_videoSrcFrameRate = VIDEO_PAL_FRAME_RATE; } // input source has a tuner if (input.type == V4L2_INPUT_TYPE_TUNER) { // get tuner info if ((int32_t)m_pConfig->GetIntegerValue(CONFIG_VIDEO_TUNER) == -1) { m_pConfig->SetIntegerValue(CONFIG_VIDEO_TUNER, 0); } // query tuner attributes struct v4l2_tuner tuner; memset(&tuner, 0, sizeof(tuner)); tuner.index = m_pConfig->GetIntegerValue(CONFIG_VIDEO_TUNER); //tuner.index = input.tuner; rc = ioctl(m_videoDevice, VIDIOC_G_TUNER, &tuner); if (rc < 0) { error_message("Failed to query tuner attributes for %s", deviceName); } // tuner is an analog TV tuner if (tuner.type == V4L2_TUNER_ANALOG_TV) { // tune in the desired frequency (channel) struct CHANLISTS* pChannelList = chanlists; struct CHANLIST* pChannel = pChannelList[m_pConfig->GetIntegerValue(CONFIG_VIDEO_CHANNEL_LIST_INDEX)].list; unsigned long videoFrequencyKHz = pChannel[m_pConfig->GetIntegerValue(CONFIG_VIDEO_CHANNEL_INDEX)].freq; unsigned long videoFrequencyTuner = ((videoFrequencyKHz / 1000) << 4) | ((videoFrequencyKHz % 1000) >> 6); struct v4l2_frequency frequency; memset(&frequency, 0, sizeof(frequency)); frequency.tuner = tuner.index; frequency.type = tuner.type; frequency.frequency = videoFrequencyTuner; rc = ioctl(m_videoDevice, VIDIOC_S_FREQUENCY, &frequency); if (rc < 0) { error_message("Failed to set video tuner frequency for %s", deviceName); } } } // query image format // select image format uint32_t width, height; width = m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH); height = m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_HEIGHT); if (strncasecmp(m_pConfig->GetStringValue(CONFIG_VIDEO_FILTER), VIDEO_FILTER_DECIMATE, strlen(VIDEO_FILTER_DECIMATE)) == 0) { uint32_t max_width, max_height; switch (m_pConfig->GetIntegerValue(CONFIG_VIDEO_SIGNAL)) { case VIDEO_SIGNAL_NTSC: max_width = 720; max_height = 480; break; case VIDEO_SIGNAL_PAL: case VIDEO_SIGNAL_SECAM: default: max_width = 768; max_height = 576; break; } if (max_width < width * 2 || max_height < height * 2) { error_message("Decimate filter choosen with too large video size - %ux%u max %ux%u", width, height, max_width / 2, max_height / 2); } else { m_decimate_filter = true; width *= 2; height *= 2; } } for (uint ix = 0; pass == false && ix < NUM_ELEMENTS_IN_ARRAY(formats); ix++) { struct v4l2_format format; memset(&format, 0, sizeof(format)); format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; rc = ioctl(m_videoDevice, VIDIOC_G_FMT, &format); if (rc < 0) { error_message("Failed to query video image format for %s", deviceName); goto failure; } format.fmt.pix.width = width; format.fmt.pix.height = height; format.fmt.pix.pixelformat = formats[ix]; rc = ioctl(m_videoDevice, VIDIOC_S_FMT, &format); if (rc == 0 && format.fmt.pix.pixelformat == formats[ix]) { m_format = formats[ix]; pass = true; } else { debug_message("format %c%c%c%c return code %d", formats[ix] & 0xff, formats[ix] >> 8, formats[ix] >> 16, formats[ix] >> 24, rc); } if (format.fmt.pix.width != width) { error_message("format %u - returned width %u not selected %u", formats[ix], format.fmt.pix.width, width); } if (format.fmt.pix.height != height) { error_message("format %u - returned height %u not selected %u",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -