📄 video_v4l_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. 2000, 2001. All Rights Reserved. * * Contributor(s): * Dave Mackie dmackie@cisco.com * Bill May wmay@cisco.com */#include "mp4live.h"#ifndef HAVE_LINUX_VIDEODEV2_H#include <sys/mman.h>#include "video_v4l_source.h"#include "video_util_rgb.h"#include "video_util_filter.h"const char *get_linux_video_type (void){ return "V4L";}//#define DEBUG_TIMESTAMPS 1int CV4LVideoSource::ThreadMain(void) { m_v4l_mutex = SDL_CreateMutex(); while (true) { int rc; if (m_source) { 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: DoStopCapture(); // ensure things get cleaned up delete pMsg; return 0; case MSG_NODE_START: DoStartCapture(); break; case MSG_NODE_STOP: DoStopCapture(); break; } delete pMsg; } } if (m_source) { try { ProcessVideo(); } catch (...) { DoStopCapture(); break; } } } return -1;}void CV4LVideoSource::DoStartCapture(void){ if (m_source) { return; } if (!Init()) { return; } m_source = true;}void CV4LVideoSource::DoStopCapture(void){ if (!m_source) { return; } ReleaseDevice(); m_source = false; SDL_DestroyMutex(m_v4l_mutex);}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;}bool CV4LVideoSource::InitDevice(void){ int rc; const char* deviceName = m_pConfig->GetStringValue(CONFIG_VIDEO_SOURCE_NAME); u_int16_t format; // 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; } // get device capabilities struct video_capability videoCapability; rc = ioctl(m_videoDevice, VIDIOCGCAP, &videoCapability); if (rc < 0) { error_message("Failed to get video capabilities for %s", deviceName); goto failure; } if (!(videoCapability.type & VID_TYPE_CAPTURE)) { error_message("Device %s is not capable of video capture!", deviceName); goto failure; } // N.B. "channel" here is really an input source struct video_channel videoChannel; videoChannel.channel = m_pConfig->GetIntegerValue(CONFIG_VIDEO_INPUT); rc = ioctl(m_videoDevice, VIDIOCGCHAN, &videoChannel); if (rc < 0) { error_message("Failed to get video channel info for %s", deviceName); goto failure; } // select video input and signal type switch(m_pConfig->GetIntegerValue(CONFIG_VIDEO_SIGNAL)) { case VIDEO_SIGNAL_PAL: videoChannel.norm = VIDEO_MODE_PAL; break; case VIDEO_SIGNAL_NTSC: videoChannel.norm = VIDEO_MODE_NTSC; break; case VIDEO_SIGNAL_SECAM: videoChannel.norm = VIDEO_MODE_SECAM; break; } rc = ioctl(m_videoDevice, VIDIOCSCHAN, &videoChannel); if (rc < 0) { error_message("Failed to set video channel info 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 TV tuner if (videoChannel.flags & VIDEO_VC_TUNER) { struct video_tuner videoTuner; // get tuner info if ((int32_t)m_pConfig->GetIntegerValue(CONFIG_VIDEO_TUNER) == -1) { m_pConfig->SetIntegerValue(CONFIG_VIDEO_TUNER, 0); } videoTuner.tuner = m_pConfig->GetIntegerValue(CONFIG_VIDEO_TUNER); rc = ioctl(m_videoDevice, VIDIOCGTUNER, &videoTuner); if (rc < 0) { error_message("Failed to get video tuner info for %s", deviceName); } // set tuner and signal type videoTuner.mode = m_pConfig->GetIntegerValue(CONFIG_VIDEO_SIGNAL); rc = ioctl(m_videoDevice, VIDIOCSTUNER, &videoTuner); if (rc < 0) { error_message("Failed to set video tuner info for %s", deviceName); } // 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); rc = ioctl(m_videoDevice, VIDIOCSFREQ, &videoFrequencyTuner); if (rc < 0) { error_message("Failed to set video tuner frequency for %s", deviceName); } } // get info on video capture buffers rc = ioctl(m_videoDevice, VIDIOCGMBUF, &m_videoMbuf); if (rc < 0) { error_message("Failed to get video capture info for %s", deviceName); goto failure; } // map the video capture buffers m_videoMap = mmap(0, m_videoMbuf.size, PROT_READ | PROT_WRITE, MAP_SHARED, m_videoDevice, 0); if (m_videoMap == MAP_FAILED) { error_message("Failed to map video capture memory for %s", deviceName); goto failure; } // allocate enough frame maps m_videoFrameMap = (struct video_mmap*) malloc(m_videoMbuf.frames * sizeof(struct video_mmap)); if (m_videoFrameMap == NULL) { error_message("Failed to allocate enough memory"); goto failure; } m_videoFrameMapFrame = (uint64_t *)malloc(m_videoMbuf.frames * sizeof(uint64_t)); m_videoFrameMapTimestamp = (uint64_t *)malloc(m_videoMbuf.frames * sizeof(Timestamp)); m_captureHead = 0; m_encodeHead = -1; format = VIDEO_PALETTE_YUV420P; m_videoFrames = 0; m_videoSrcFrameDuration = (Duration)(((float)TimestampTicks / m_videoSrcFrameRate) + 0.5); m_cacheTimestamp = true; if (m_pConfig->GetBoolValue(CONFIG_V4L_CACHE_TIMESTAMP) == false) { m_videoMbuf.frames = 2; m_cacheTimestamp = false; } 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 - max %ux%u", max_width / 2, max_height / 2); } else { m_decimate_filter = true; width *= 2; height *= 2; } } for (int i = 0; i < m_videoMbuf.frames; i++) { // initialize frame map m_videoFrameMap[i].frame = i; m_videoFrameMap[i].width = width; m_videoFrameMap[i].height = height; m_videoFrameMap[i].format = format; // give frame to the video capture device rc = ioctl(m_videoDevice, VIDIOCMCAPTURE, &m_videoFrameMap[i]); if (rc < 0) { // try RGB24 palette instead if (i == 0 && format == VIDEO_PALETTE_YUV420P) { format = VIDEO_PALETTE_RGB24; i--; continue; } error_message("Failed to allocate video capture buffer for %s - frame %d max %d rc %d errno %d format %d", deviceName, i, m_videoMbuf.frames, rc, errno, format); goto failure; } if (i == 0) { m_videoCaptureStartTimestamp = GetTimestamp(); } m_lastVideoFrameMapFrameLoaded = m_videoFrameMapFrame[i] = i; m_lastVideoFrameMapTimestampLoaded = m_videoFrameMapTimestamp[i] = CalculateVideoTimestampFromFrames(i); } m_videoNeedRgbToYuv = (format == VIDEO_PALETTE_RGB24); SetPictureControls(); if (videoCapability.audios) { SetVideoAudioMute(false); } return true;failure: free(m_videoFrameMap); if (m_videoMap) { munmap(m_videoMap, m_videoMbuf.size); m_videoMap = NULL; } close(m_videoDevice); m_videoDevice = -1; return false;}void CV4LVideoSource::ReleaseDevice(){ SetVideoAudioMute(true); // release device resources munmap(m_videoMap, m_videoMbuf.size); m_videoMap = NULL; close(m_videoDevice); m_videoDevice = -1;} void CV4LVideoSource::SetVideoAudioMute(bool mute){ if (!m_pConfig->m_videoCapabilities) return; CVideoCapabilities *vc = (CVideoCapabilities *)m_pConfig->m_videoCapabilities; if ( !vc->m_hasAudio) { return; } int rc; struct video_audio videoAudio;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -