video_v4l_source.cpp
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:15k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is MPEG4IP.
  13.  * 
  14.  * The Initial Developer of the Original Code is Cisco Systems Inc.
  15.  * Portions created by Cisco Systems Inc. are
  16.  * Copyright (C) Cisco Systems Inc. 2000, 2001.  All Rights Reserved.
  17.  * 
  18.  * Contributor(s): 
  19.  * Dave Mackie dmackie@cisco.com
  20.  * Bill May  wmay@cisco.com
  21.  */
  22. #include "mp4live.h"
  23. #include <sys/mman.h>
  24. #include "video_v4l_source.h"
  25. #include "video_util_rgb.h"
  26. int CV4LVideoSource::ThreadMain(void) 
  27. {
  28. while (true) {
  29. int rc;
  30. if (m_source) {
  31. rc = SDL_SemTryWait(m_myMsgQueueSemaphore);
  32. } else {
  33. rc = SDL_SemWait(m_myMsgQueueSemaphore);
  34. }
  35. // semaphore error
  36. if (rc == -1) {
  37. break;
  38. // message pending
  39. if (rc == 0) {
  40. CMsg* pMsg = m_myMsgQueue.get_message();
  41. if (pMsg != NULL) {
  42. switch (pMsg->get_value()) {
  43. case MSG_NODE_STOP_THREAD:
  44. DoStopCapture(); // ensure things get cleaned up
  45. delete pMsg;
  46. return 0;
  47. case MSG_NODE_START:
  48. case MSG_SOURCE_START_VIDEO:
  49. DoStartCapture();
  50. break;
  51. case MSG_NODE_STOP:
  52. DoStopCapture();
  53. break;
  54. case MSG_SOURCE_KEY_FRAME:
  55. DoGenerateKeyFrame();
  56. break;
  57. }
  58. delete pMsg;
  59. }
  60. }
  61. if (m_source) {
  62. try {
  63. ProcessVideo();
  64. }
  65. catch (...) {
  66. DoStopCapture();
  67. break;
  68. }
  69. }
  70. }
  71. return -1;
  72. }
  73. void CV4LVideoSource::DoStartCapture(void)
  74. {
  75. if (m_source) {
  76. return;
  77. }
  78. if (!Init()) {
  79. return;
  80. }
  81. m_source = true;
  82. }
  83. void CV4LVideoSource::DoStopCapture(void)
  84. {
  85. if (!m_source) {
  86. return;
  87. }
  88. DoStopVideo();
  89. ReleaseDevice();
  90. m_source = false;
  91. }
  92. bool CV4LVideoSource::Init(void)
  93. {
  94. if (!InitDevice()) {
  95. return false;
  96. }
  97. CalculateVideoFrameSize(m_pConfig);
  98. InitVideo(
  99. (m_pConfig->m_videoNeedRgbToYuv ?
  100. CMediaFrame::RgbVideoFrame :
  101. CMediaFrame::YuvVideoFrame),
  102. true);
  103. SetVideoSrcSize(
  104. m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH),
  105. m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_HEIGHT),
  106. m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH),
  107. true);
  108. m_maxPasses = (u_int8_t)(m_videoSrcFrameRate + 0.5);
  109. return true;
  110. }
  111. bool CV4LVideoSource::InitDevice(void)
  112. {
  113. int rc;
  114. char* deviceName = m_pConfig->GetStringValue(CONFIG_VIDEO_SOURCE_NAME);
  115. u_int16_t format;
  116. // open the video device
  117. m_videoDevice = open(deviceName, O_RDWR);
  118. if (m_videoDevice < 0) {
  119. error_message("Failed to open %s: %s", 
  120. deviceName, strerror(errno));
  121. return false;
  122. }
  123. // get device capabilities
  124. struct video_capability videoCapability;
  125. rc = ioctl(m_videoDevice, VIDIOCGCAP, &videoCapability);
  126. if (rc < 0) {
  127. error_message("Failed to get video capabilities for %s",
  128. deviceName);
  129. goto failure;
  130. }
  131. if (!(videoCapability.type & VID_TYPE_CAPTURE)) {
  132. error_message("Device %s is not capable of video capture!",
  133. deviceName);
  134. goto failure;
  135. }
  136. // N.B. "channel" here is really an input source
  137. struct video_channel videoChannel;
  138. videoChannel.channel = m_pConfig->GetIntegerValue(CONFIG_VIDEO_INPUT);
  139. rc = ioctl(m_videoDevice, VIDIOCGCHAN, &videoChannel);
  140. if (rc < 0) {
  141. error_message("Failed to get video channel info for %s",
  142. deviceName);
  143. goto failure;
  144. }
  145. // select video input and signal type
  146. videoChannel.norm = m_pConfig->GetIntegerValue(CONFIG_VIDEO_SIGNAL);
  147. rc = ioctl(m_videoDevice, VIDIOCSCHAN, &videoChannel);
  148. if (rc < 0) {
  149. error_message("Failed to set video channel info for %s",
  150. deviceName);
  151. goto failure;
  152. }
  153. if (m_pConfig->GetIntegerValue(CONFIG_VIDEO_SIGNAL) == VIDEO_MODE_NTSC) {
  154. m_videoSrcFrameRate = VIDEO_NTSC_FRAME_RATE;
  155. } else {
  156. m_videoSrcFrameRate = VIDEO_PAL_FRAME_RATE;
  157. }
  158. // input source has a TV tuner
  159. if (videoChannel.flags & VIDEO_VC_TUNER) {
  160. struct video_tuner videoTuner;
  161. // get tuner info
  162. if ((int32_t)m_pConfig->GetIntegerValue(CONFIG_VIDEO_TUNER) == -1) {
  163. m_pConfig->SetIntegerValue(CONFIG_VIDEO_TUNER, 0);
  164. }
  165. videoTuner.tuner = m_pConfig->GetIntegerValue(CONFIG_VIDEO_TUNER);
  166. rc = ioctl(m_videoDevice, VIDIOCGTUNER, &videoTuner);
  167. if (rc < 0) {
  168. error_message("Failed to get video tuner info for %s",
  169. deviceName);
  170. }
  171. // set tuner and signal type
  172. videoTuner.mode = m_pConfig->GetIntegerValue(CONFIG_VIDEO_SIGNAL);
  173. rc = ioctl(m_videoDevice, VIDIOCSTUNER, &videoTuner);
  174. if (rc < 0) {
  175. error_message("Failed to set video tuner info for %s",
  176. deviceName);
  177. }
  178. // tune in the desired frequency (channel)
  179. struct CHANNEL_LIST* pChannelList = ListOfChannelLists[
  180. m_pConfig->GetIntegerValue(CONFIG_VIDEO_SIGNAL)];
  181. struct CHANNEL* pChannel = pChannelList[
  182. m_pConfig->GetIntegerValue(CONFIG_VIDEO_CHANNEL_LIST_INDEX)].list;
  183. unsigned long videoFrequencyKHz = pChannel[
  184. m_pConfig->GetIntegerValue(CONFIG_VIDEO_CHANNEL_INDEX)].freq;
  185. unsigned long videoFrequencyTuner =
  186. ((videoFrequencyKHz / 1000) << 4) 
  187. | ((videoFrequencyKHz % 1000) >> 6);
  188. rc = ioctl(m_videoDevice, VIDIOCSFREQ, &videoFrequencyTuner);
  189. if (rc < 0) {
  190. error_message("Failed to set video tuner frequency for %s",
  191. deviceName);
  192. }
  193. }
  194. // get info on video capture buffers 
  195. rc = ioctl(m_videoDevice, VIDIOCGMBUF, &m_videoMbuf);
  196. if (rc < 0) {
  197. error_message("Failed to get video capture info for %s", 
  198. deviceName);
  199. goto failure;
  200. }
  201. // map the video capture buffers
  202. m_videoMap = mmap(0, m_videoMbuf.size, 
  203. PROT_READ | PROT_WRITE, MAP_SHARED, m_videoDevice, 0);
  204. if (m_videoMap == MAP_FAILED) {
  205. error_message("Failed to map video capture memory for %s", 
  206. deviceName);
  207. goto failure;
  208. }
  209. // allocate enough frame maps
  210. m_videoFrameMap = (struct video_mmap*)
  211. malloc(m_videoMbuf.frames * sizeof(struct video_mmap));
  212. if (m_videoFrameMap == NULL) {
  213. error_message("Failed to allocate enough memory"); 
  214. goto failure;
  215. }
  216. m_captureHead = 0;
  217. m_encodeHead = -1;
  218. format = VIDEO_PALETTE_YUV420P;
  219. for (int i = 0; i < m_videoMbuf.frames; i++) {
  220. // initialize frame map
  221. m_videoFrameMap[i].frame = i;
  222. m_videoFrameMap[i].width = 
  223. m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH);
  224. m_videoFrameMap[i].height = 
  225. m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_HEIGHT);
  226. m_videoFrameMap[i].format = format;
  227. // give frame to the video capture device
  228. rc = ioctl(m_videoDevice, VIDIOCMCAPTURE, &m_videoFrameMap[i]);
  229. if (rc < 0) {
  230. // try RGB24 palette instead
  231. if (i == 0 && format == VIDEO_PALETTE_YUV420P) {
  232. format = VIDEO_PALETTE_RGB24;
  233. i--;
  234. continue;
  235. error_message("Failed to allocate video capture buffer for %s", 
  236. deviceName);
  237. goto failure;
  238. }
  239. }
  240. if (format == VIDEO_PALETTE_RGB24) {
  241. m_pConfig->m_videoNeedRgbToYuv = true;
  242. }
  243. if (videoCapability.audios) {
  244. SetVideoAudioMute(false);
  245. }
  246. return true;
  247. failure:
  248. free(m_videoFrameMap);
  249. if (m_videoMap) {
  250. munmap(m_videoMap, m_videoMbuf.size);
  251. m_videoMap = NULL;
  252. }
  253. close(m_videoDevice);
  254. m_videoDevice = -1;
  255. return false;
  256. }
  257. void CV4LVideoSource::ReleaseDevice()
  258. {
  259. SetVideoAudioMute(true);
  260. // release device resources
  261. munmap(m_videoMap, m_videoMbuf.size);
  262. m_videoMap = NULL;
  263. close(m_videoDevice);
  264. m_videoDevice = -1;
  265. }
  266. void CV4LVideoSource::SetVideoAudioMute(bool mute)
  267. {
  268. if (!m_pConfig->m_videoCapabilities
  269.   || !m_pConfig->m_videoCapabilities->m_hasAudio) {
  270. return;
  271. }
  272. int rc;
  273. struct video_audio videoAudio;
  274. rc = ioctl(m_videoDevice, VIDIOCGAUDIO, &videoAudio);
  275. if (rc == 0 && (videoAudio.flags & VIDEO_AUDIO_MUTABLE)) {
  276. if (mute) {
  277. videoAudio.flags |= VIDEO_AUDIO_MUTE;
  278. } else {
  279. videoAudio.flags &= ~VIDEO_AUDIO_MUTE;
  280. }
  281. rc = ioctl(m_videoDevice, VIDIOCSAUDIO, &videoAudio);
  282. if (rc < 0) {
  283. debug_message("Can't set video audio for %s",
  284. m_pConfig->m_videoCapabilities->m_deviceName);
  285. }
  286. }
  287. }
  288. void CalculateVideoFrameSize(CLiveConfig* pConfig)
  289. {
  290. u_int16_t frameHeight;
  291. float aspectRatio = pConfig->GetFloatValue(CONFIG_VIDEO_ASPECT_RATIO);
  292. // crop video to appropriate aspect ratio modulo 16 pixels
  293. if ((aspectRatio - VIDEO_STD_ASPECT_RATIO) < 0.1) {
  294. frameHeight = pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_HEIGHT);
  295. } else {
  296. frameHeight = (u_int16_t)(
  297. (float)pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH) 
  298. / aspectRatio);
  299. if ((frameHeight % 16) != 0) {
  300. frameHeight += 16 - (frameHeight % 16);
  301. }
  302. if (frameHeight > pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_HEIGHT)) {
  303. // OPTION might be better to insert black lines 
  304. // to pad image but for now we crop down
  305. frameHeight = pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_HEIGHT);
  306. if ((frameHeight % 16) != 0) {
  307. frameHeight -= (frameHeight % 16);
  308. }
  309. }
  310. }
  311. pConfig->m_videoWidth = pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH);
  312. pConfig->m_videoHeight = frameHeight;
  313. pConfig->m_ySize = pConfig->m_videoWidth * pConfig->m_videoHeight;
  314. pConfig->m_uvSize = pConfig->m_ySize / 4;
  315. pConfig->m_yuvSize = (pConfig->m_ySize * 3) / 2;
  316. }
  317. int8_t CV4LVideoSource::AcquireFrame(void)
  318. {
  319. int rc;
  320. rc = ioctl(m_videoDevice, VIDIOCSYNC, &m_videoFrameMap[m_captureHead]);
  321. if (rc != 0) {
  322. return -1;
  323. }
  324. int8_t capturedFrame = m_captureHead;
  325. m_captureHead = (m_captureHead + 1) % m_videoMbuf.frames;
  326. if (m_captureHead == m_encodeHead) {
  327. debug_message("Video capture buffer overflow");
  328. return -1;
  329. }
  330. return capturedFrame;
  331. }
  332. void CV4LVideoSource::ProcessVideo(void)
  333. {
  334. // for efficiency, process ~1 second before returning to check for commands
  335. for (int pass = 0; pass < m_maxPasses; pass++) {
  336. // get next frame from video capture device
  337. m_encodeHead = AcquireFrame();
  338. if (m_encodeHead == -1) {
  339. continue;
  340. }
  341. Timestamp frameTimestamp = GetTimestamp();
  342. u_int8_t* mallocedYuvImage = NULL;
  343. u_int8_t* pY;
  344. u_int8_t* pU;
  345. u_int8_t* pV;
  346. // perform colorspace conversion if necessary
  347. if (m_videoSrcType == CMediaFrame::RgbVideoFrame) {
  348. mallocedYuvImage = (u_int8_t*)Malloc(m_videoSrcYUVSize);
  349. pY = mallocedYuvImage;
  350. pU = pY + m_videoSrcYSize;
  351. pV = pU + m_videoSrcUVSize,
  352. RGB2YUV(
  353. m_videoSrcWidth,
  354. m_videoSrcHeight,
  355. (u_int8_t*)m_videoMap + m_videoMbuf.offsets[m_encodeHead],
  356. pY,
  357. pU,
  358. pV,
  359. 1);
  360. } else {
  361. pY = (u_int8_t*)m_videoMap + m_videoMbuf.offsets[m_encodeHead];
  362. pU = pY + m_videoSrcYSize;
  363. pV = pU + m_videoSrcUVSize;
  364. }
  365. ProcessVideoYUVFrame(
  366. pY, 
  367. pU, 
  368. pV,
  369. m_videoSrcWidth,
  370. m_videoSrcWidth >> 1,
  371. frameTimestamp);
  372. // release video frame buffer back to video capture device
  373. if (ReleaseFrame(m_encodeHead)) {
  374. m_encodeHead = (m_encodeHead + 1) % m_videoMbuf.frames;
  375. } else {
  376. debug_message("Couldn't release capture buffer!");
  377. }
  378. free(mallocedYuvImage);
  379. }
  380. }
  381. bool CV4LVideoSource::InitialVideoProbe(CLiveConfig* pConfig)
  382. {
  383. static char* devices[] = {
  384. "/dev/video", 
  385. "/dev/video0", 
  386. "/dev/video1", 
  387. "/dev/video2", 
  388. "/dev/video3"
  389. };
  390. char* deviceName = pConfig->GetStringValue(CONFIG_VIDEO_SOURCE_NAME);
  391. CVideoCapabilities* pVideoCaps;
  392. // first try the device we're configured with
  393. pVideoCaps = new CVideoCapabilities(deviceName);
  394. if (pVideoCaps->IsValid()) {
  395. pConfig->m_videoCapabilities = pVideoCaps;
  396. return true;
  397. }
  398. delete pVideoCaps;
  399. // no luck, go searching
  400. for (u_int32_t i = 0; i < sizeof(devices) / sizeof(char*); i++) {
  401. // don't waste time trying something that's already failed
  402. if (!strcmp(devices[i], deviceName)) {
  403. continue;
  404. pVideoCaps = new CVideoCapabilities(devices[i]);
  405. if (pVideoCaps->IsValid()) {
  406. pConfig->SetStringValue(CONFIG_VIDEO_SOURCE_NAME, devices[i]);
  407. pConfig->m_videoCapabilities = pVideoCaps;
  408. return true;
  409. }
  410. delete pVideoCaps;
  411. }
  412. return false;
  413. }
  414. bool CVideoCapabilities::ProbeDevice()
  415. {
  416. int rc;
  417. int videoDevice = open(m_deviceName, O_RDWR);
  418. if (videoDevice < 0) {
  419. return false;
  420. }
  421. m_canOpen = true;
  422. // get device capabilities
  423. struct video_capability videoCapability;
  424. rc = ioctl(videoDevice, VIDIOCGCAP, &videoCapability);
  425. if (rc < 0) {
  426. debug_message("Failed to get video capabilities for %s", m_deviceName);
  427. m_canCapture = false;
  428. close(videoDevice);
  429. return false;
  430. }
  431. if (!(videoCapability.type & VID_TYPE_CAPTURE)) {
  432. debug_message("Device %s is not capable of video capture!", 
  433. m_deviceName);
  434. m_canCapture = false;
  435. close(videoDevice);
  436. return false;
  437. }
  438. m_canCapture = true;
  439. m_driverName = stralloc(videoCapability.name);
  440. m_numInputs = videoCapability.channels;
  441. m_minWidth = videoCapability.minwidth;
  442. m_minHeight = videoCapability.minheight;
  443. m_maxWidth = videoCapability.maxwidth;
  444. m_maxHeight = videoCapability.maxheight;
  445. m_hasAudio = videoCapability.audios;
  446. m_inputNames = (char**)malloc(m_numInputs * sizeof(char*));
  447. memset(m_inputNames, 0, m_numInputs * sizeof(char*));
  448. m_inputSignalTypes = (u_int8_t*)malloc(m_numInputs * sizeof(u_int8_t));
  449. memset(m_inputSignalTypes, 0, m_numInputs * sizeof(u_int8_t));
  450. m_inputHasTuners = (bool*)malloc(m_numInputs * sizeof(bool));
  451. memset(m_inputHasTuners, 0, m_numInputs * sizeof(bool));
  452. m_inputTunerSignalTypes = (u_int8_t*)malloc(m_numInputs * sizeof(u_int8_t));
  453. memset(m_inputTunerSignalTypes, 0, m_numInputs * sizeof(u_int8_t));
  454. for (int i = 0; i < m_numInputs; i++) {
  455. // N.B. "channel" here is really an input source
  456. struct video_channel videoChannel;
  457. videoChannel.channel = i;
  458. rc = ioctl(videoDevice, VIDIOCGCHAN, &videoChannel);
  459. if (rc < 0) {
  460. debug_message("Failed to get video channel info for %s:%u",
  461. m_deviceName, i);
  462. continue;
  463. }
  464. m_inputNames[i] = stralloc(videoChannel.name);
  465. m_inputSignalTypes[i] = videoChannel.norm;
  466. if (videoChannel.flags & VIDEO_VC_TUNER) {
  467. // ignore videoChannel.tuners for now
  468. // current bt drivers only support 1 tuner per input port
  469. struct video_tuner videoTuner;
  470. videoTuner.tuner = 0;
  471. rc = ioctl(videoDevice, VIDIOCGTUNER, &videoTuner);
  472. if (rc < 0) {
  473. debug_message("Failed to get video tuner info for %s:%u",
  474. m_deviceName, i);
  475. continue;
  476. }
  477. m_inputHasTuners[i] = true;
  478. m_inputTunerSignalTypes[i] = videoTuner.flags & 0x7;
  479. }
  480. }
  481. close(videoDevice);
  482. return true;
  483. }