📄 video_v4l2_source.cpp
字号:
/* * Use the m_release_index_mask to indicate which indexes need to * be released - note - there may be a problem if we don't release * in order given. */void CV4LVideoSource::ReleaseFrames (void){ uint8_t index = 0; uint32_t index_mask = 1; uint32_t released_mask; int rc; SDL_LockMutex(m_v4l_mutex); released_mask = m_release_index_mask; m_release_index_mask = 0; SDL_UnlockMutex(m_v4l_mutex); while (released_mask != 0 && index < 32) { if ((index_mask & released_mask) != 0) { if (m_waiting_frames_return) { m_waiting_frames_return = false; error_message("frame return"); } struct v4l2_buffer buffer; m_buffers[index].in_use = false; if (m_source) { buffer.index = index; buffer.memory = V4L2_MEMORY_MMAP; buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buffer.flags = 0; // it appears that some cards, some drivers require a QUERYBUF // before the QBUF. This code is designed to do so, but only if // we need to if (m_use_alternate_release) { rc = ioctl(m_videoDevice, VIDIOC_QUERYBUF, &buffer); if (rc < 0) { error_message("Failed to query video capture buffer status"); } } rc = ioctl(m_videoDevice, VIDIOC_QBUF, &buffer); if (rc < 0) { if (m_use_alternate_release) { error_message("Could not enqueue buffer to video capture queue"); } else { rc = ioctl(m_videoDevice, VIDIOC_QUERYBUF, &buffer); if (rc < 0) { error_message("Failed to query video capture buffer status"); } rc = ioctl(m_videoDevice, VIDIOC_QBUF, &buffer); if (rc < 0) { error_message("Failed to query video capture buffer status"); } else { m_use_alternate_release = true; } } } // debug_message("rel %d", index); } } index_mask <<= 1; index++; }}void CV4LVideoSource::ProcessVideo(void){ // for efficiency, process ~1 second before returning to check for commands Timestamp frameTimestamp; for (int pass = 0; pass < m_maxPasses && m_stop_thread == false; pass++) { // dequeue next frame from video capture buffer int index = AcquireFrame(frameTimestamp); if (index == -1) { return; } m_buffers[index].in_use = true; //debug_message("buffer %u in use", index); u_int8_t* mallocedYuvImage = NULL; u_int8_t* pY; u_int8_t* pU; u_int8_t* pV; // perform colorspace conversion if necessary switch (m_format) { case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: mallocedYuvImage = (u_int8_t*)Malloc(m_videoSrcYUVSize); debug_message("converting to YUV420P from RGB"); pY = mallocedYuvImage; pV = pY + m_videoSrcYSize; pU = pV + m_videoSrcUVSize, RGB2YUV( m_videoSrcWidth, m_videoSrcHeight, (u_int8_t*)m_buffers[index].start, pY, pU, pV, 1, m_format == V4L2_PIX_FMT_RGB24); break; case V4L2_PIX_FMT_YUYV: mallocedYuvImage = (u_int8_t*)Malloc(m_videoSrcYUVSize); //debug_message("converting to YUV420P from YUYV"); pY = mallocedYuvImage; pU = pY + m_videoSrcYSize; pV = pU + m_videoSrcUVSize; convert_yuyv_to_yuv420p(pY, (const uint8_t *)m_buffers[index].start, m_videoSrcWidth, m_videoSrcHeight); break; case V4L2_PIX_FMT_UYVY: mallocedYuvImage = (u_int8_t*)Malloc(m_videoSrcYUVSize); //debug_message("converting to YUV420P from YUYV"); pY = mallocedYuvImage; pU = pY + m_videoSrcYSize; pV = pU + m_videoSrcUVSize; convert_uyvy_to_yuv420p(pY, (const uint8_t *)m_buffers[index].start, m_videoSrcWidth, m_videoSrcHeight); break; case V4L2_PIX_FMT_YYUV: mallocedYuvImage = (u_int8_t*)Malloc(m_videoSrcYUVSize); //debug_message("converting to YUV420P from YUYV"); pY = mallocedYuvImage; pU = pY + m_videoSrcYSize; pV = pU + m_videoSrcUVSize; convert_yyuv_to_yuv420p(pY, (const uint8_t *)m_buffers[index].start, m_videoSrcWidth, m_videoSrcHeight); break; case V4L2_PIX_FMT_NV12: mallocedYuvImage = (u_int8_t*)Malloc(m_videoSrcYUVSize); //debug_message("converting to YUV420P from YUYV"); pY = mallocedYuvImage; pU = pY + m_videoSrcYSize; pV = pU + m_videoSrcUVSize; convert_nv12_to_yuv420p(pY, (const uint8_t *)m_buffers[index].start, m_videoSrcYSize, m_videoSrcWidth, m_videoSrcHeight); break; default:#if 0 // we would need the below if we were going to switch // video - this is a problem with the mallocedYuvImage = (u_int8_t*)Malloc(m_videoSrcYUVSize); pY = (u_int8_t*)mallocedYuvImage; memcpy(pY, m_buffers[index].start, m_videoSrcYUVSize);#else pY = (u_int8_t*)m_buffers[index].start;#endif pU = pY + m_u_offset; pV = pY + m_v_offset; } if (m_decimate_filter) { video_filter_decimate(pY, m_videoSrcWidth, m_videoSrcHeight); } yuv_media_frame_t *yuv = MALLOC_STRUCTURE(yuv_media_frame_t); yuv->y = pY; yuv->u = pU; yuv->v = pV; yuv->y_stride = m_videoSrcWidth; yuv->uv_stride = m_videoSrcWidth >> 1; yuv->w = m_videoSrcWidth; yuv->h = m_videoSrcHeight; yuv->hardware = this; yuv->hardware_version = m_hardware_version; yuv->hardware_index = index; if (m_videoWantKeyFrame && frameTimestamp >= m_audioStartTimestamp) { yuv->force_iframe = true; m_videoWantKeyFrame = false; debug_message("Frame "U64" request key frame", frameTimestamp); } else yuv->force_iframe = false; yuv->free_y = (mallocedYuvImage != NULL); CMediaFrame *frame = new CMediaFrame(YUVVIDEOFRAME, yuv, 0, frameTimestamp); frame->SetMediaFreeFunction(c_ReleaseFrame); ForwardFrame(frame); //debug_message("video source forward"); // enqueue the frame to video capture buffer if (mallocedYuvImage != NULL) { IndicateReleaseFrame(index); } }}bool CV4LVideoSource::InitialVideoProbe(CLiveConfig* pConfig){ static const char* devices[] = { "/dev/video", "/dev/video0", "/dev/video1", "/dev/video2", "/dev/video3" }; const char* deviceName = pConfig->GetStringValue(CONFIG_VIDEO_SOURCE_NAME); CVideoCapabilities* pVideoCaps; // first try the device we're configured with pVideoCaps = new CVideoCapabilities(deviceName); if (pVideoCaps->IsValid()) { pConfig->m_videoCapabilities = pVideoCaps; return true; } delete pVideoCaps; // no luck, go searching for (unsigned int i = 0; i < sizeof(devices) / sizeof(*devices); i++) { // don't waste time trying something that's already failed if (!strcmp(devices[i], deviceName)) { continue; } pVideoCaps = new CVideoCapabilities(devices[i]); if (pVideoCaps->IsValid()) { pConfig->SetStringValue(CONFIG_VIDEO_SOURCE_NAME, devices[i]); pConfig->m_videoCapabilities = pVideoCaps; return true; } delete pVideoCaps; } return false;}bool CVideoCapabilities::ProbeDevice(){ int rc, i; // open the video device int videoDevice = open(m_deviceName, O_RDWR); if (videoDevice < 0) return false; m_canOpen = true; // query device capabilities struct v4l2_capability capability; memset(&capability, 0, sizeof(capability)); rc = ioctl(videoDevice, VIDIOC_QUERYCAP, &capability); if (rc < 0) { error_message("Failed to query video capabilities for %s", m_deviceName); close(videoDevice); return false; } // make sure device supports video capture if (!(capability.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { error_message("Device %s is not capable of video capture!", m_deviceName); close(videoDevice); return false; } m_canCapture = true; m_driverName = strdup((char*)capability.driver); m_hasAudio = capability.capabilities & (V4L2_CAP_AUDIO | V4L2_CAP_TUNER); struct v4l2_input input; memset(&input, 0, sizeof(input)); // get the number of inputs for(i=0; ; i++) { input.index = i; rc = ioctl(videoDevice, VIDIOC_ENUMINPUT, &input); if (rc < 0) { if (errno == EINVAL) break; } } m_numInputs = i; m_inputNames = (char**)malloc(m_numInputs * sizeof(char*)); memset(m_inputNames, 0, m_numInputs * sizeof(char*)); m_inputHasTuners = (bool*)malloc(m_numInputs * sizeof(bool)); memset(m_inputHasTuners, 0, m_numInputs * sizeof(bool)); m_inputTunerSignalTypes = (u_int8_t*)malloc(m_numInputs * sizeof(u_int8_t)); memset(m_inputTunerSignalTypes, 0, m_numInputs * sizeof(u_int8_t)); // enumerate all inputs for(i=0; i<m_numInputs; i++) { input.index = i; rc = ioctl(videoDevice, VIDIOC_ENUMINPUT, &input); if (rc >= 0) { m_inputNames[i] = strdup((char*)input.name); } else { m_inputNames[i] = strdup("Unknown input"); error_message("Failed to enumerate video input %d for %s", i, m_deviceName); continue; } error_message("type %d %s type %x", i, m_inputNames[i], input.type); if (input.type == V4L2_INPUT_TYPE_TUNER) { error_message("Has tuner"); m_inputHasTuners[i] = true; if (input.std & V4L2_STD_PAL) m_inputTunerSignalTypes[i] |= 0x1; if (input.std & V4L2_STD_NTSC) m_inputTunerSignalTypes[i] |= 0x2; if (input.std & V4L2_STD_SECAM) m_inputTunerSignalTypes[i] |= 0x4; } } close(videoDevice); return true;}static const char *signals[] = { "PAL", "NTSC", "SECAM",};void CVideoCapabilities::Display (CLiveConfig *pConfig, char *msg, uint32_t max_len){ uint32_t port = pConfig->GetIntegerValue(CONFIG_VIDEO_INPUT); if (port >= m_numInputs) { snprintf(msg, max_len, "Video port has illegal value"); return; } if (m_inputHasTuners[port] == false) { snprintf(msg, max_len, "%s, %ux%u, %s, %s", pConfig->GetStringValue(CONFIG_VIDEO_SOURCE_NAME), pConfig->m_videoWidth, pConfig->m_videoHeight, signals[pConfig->GetIntegerValue(CONFIG_VIDEO_SIGNAL)], m_inputNames[port]); } else { snprintf(msg, max_len, "%s, %ux%u, %s, %s, %s, channel %s", pConfig->GetStringValue(CONFIG_VIDEO_SOURCE_NAME), pConfig->m_videoWidth, pConfig->m_videoHeight, signals[pConfig->GetIntegerValue(CONFIG_VIDEO_SIGNAL)], m_inputNames[port], chanlists[pConfig->GetIntegerValue(CONFIG_VIDEO_CHANNEL_LIST_INDEX)].name, chanlists[pConfig->GetIntegerValue(CONFIG_VIDEO_CHANNEL_LIST_INDEX)].list[pConfig->GetIntegerValue(CONFIG_VIDEO_CHANNEL_INDEX)].name ); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -