📄 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"#include <sys/mman.h>#include "video_v4l_source.h"#include "video_util_rgb.h"//#define DEBUG_TIMESTAMPS 1int CV4LVideoSource::ThreadMain(void) { 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: case MSG_SOURCE_START_VIDEO: DoStartCapture(); break; case MSG_NODE_STOP: DoStopCapture(); break; case MSG_SOURCE_KEY_FRAME: DoGenerateKeyFrame(); 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; } DoStopVideo(); ReleaseDevice(); m_source = false;}bool CV4LVideoSource::Init(void){ if (!InitDevice()) { return false; } m_pConfig->CalculateVideoFrameSize(); InitVideo( (m_pConfig->m_videoNeedRgbToYuv ? RGBVIDEOFRAME : YUVVIDEOFRAME), true); SetVideoSrcSize( m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH), m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_HEIGHT), m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH), true); m_maxPasses = (u_int8_t)(m_videoSrcFrameRate + 0.5); return true;}bool CV4LVideoSource::InitDevice(void){ int rc; 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 videoChannel.norm = m_pConfig->GetIntegerValue(CONFIG_VIDEO_SIGNAL); 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_MODE_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; } for (int i = 0; i < m_videoMbuf.frames; i++) { // initialize frame map m_videoFrameMap[i].frame = i; m_videoFrameMap[i].width = m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH); m_videoFrameMap[i].height = m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_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", deviceName); goto failure; } if (i == 0) { m_videoCaptureStartTimestamp = GetTimestamp(); } m_lastVideoFrameMapFrameLoaded = m_videoFrameMapFrame[i] = i; m_lastVideoFrameMapTimestampLoaded = m_videoFrameMapTimestamp[i] = CalculateVideoTimestampFromFrames(i); } if (format == VIDEO_PALETTE_RGB24) { m_pConfig->m_videoNeedRgbToYuv = true; } SetPictureControls(); if (videoCapability.audios) { SetVideoAudioMute(false); } return true;failure: free(m_videoFrameMap); if (m_videoMap) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -