00001 /* --------------------------------------------------------------------------- 00002 Phission : 00003 Realtime Vision Processing System 00004 00005 Copyright (C) 2003-2006 Philip D.S. Thoren (pthoren@cs.uml.edu) 00006 University of Massachusetts at Lowell, 00007 Laboratory for Artificial Intelligence and Robotics 00008 00009 This file is part of Phission. 00010 00011 Phission is free software; you can redistribute it and/or modify 00012 it under the terms of the GNU Lesser General Public License as published by 00013 the Free Software Foundation; either version 2 of the License, or 00014 (at your option) any later version. 00015 00016 Phission is distributed in the hope that it will be useful, 00017 but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 GNU Lesser General Public License for more details. 00020 00021 You should have received a copy of the GNU Lesser General Public License 00022 along with Phission; if not, write to the Free Software 00023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00024 00025 ---------------------------------------------------------------------------*/ 00026 #ifdef HAVE_CONFIG_H 00027 #include <phissionconfig.h> 00028 #endif 00029 00030 /* ---------------------------------------------------------------------- */ 00031 #if defined(HAVE_STDIO_H) 00032 #include <stdio.h> 00033 #endif 00034 #if defined(HAVE_STDLIB_H) 00035 #include <stdlib.h> 00036 #endif 00037 #if defined(HAVE_STRING_H) 00038 #include <string.h> 00039 #endif 00040 00041 /* ---------------------------------------------------------------------- */ 00042 #include <avcodec.h> 00043 #include <avformat.h> 00044 00045 #include <phStandard.h> 00046 #include <ImageConversions.h> 00047 00048 #include <phObject.h> 00049 #include <phMutex.h> 00050 #include <phSemaphore.h> 00051 #include <phCondition.h> 00052 #include <phRWLock.h> 00053 #include <phThread.h> 00054 #include <phList.h> 00055 #include <phTimeStamp.h> 00056 #include <phTimeInterval.h> 00057 #include <phLiveObject.h> 00058 #include <phDataObject.h> 00059 #include <phImage.h> 00060 #include <phCaptureInterface.h> 00061 #include <phImageCapture.h> 00062 00063 #include <phAvcodecSource.h> 00064 00065 #include <phError.h> 00066 #include <phMemory.h> 00067 #include <phPrint.h> 00068 00069 /* ---------------------------------------------------------------------- */ 00070 /* TODO: check object's m_info for != NULL everywhere */ 00071 struct phAvcodecSourceInfo_t 00072 { 00073 AVFormatContext *m_pFormatCtx; 00074 AVCodecContext *m_pCodecCtx; 00075 AVStream *m_pStream; 00076 AVCodec *m_pCodec; 00077 AVFrame *m_pFrame; 00078 AVFrame *m_pFrameRGB; 00079 00080 int m_videoStream; 00081 int m_numBytes; 00082 00083 int m_avcodec_format; 00084 00085 int m_width; 00086 int m_height; 00087 00088 uint8_t *m_buffer; 00089 00090 double m_frate; 00091 double m_frate_base; 00092 00093 int32_t m_sleeptime; 00094 }; 00095 00096 /* ---------------------------------------------------------------------- * 00097 * ---------------------------------------------------------------------- */ 00098 phAvcodecSource::phAvcodecSource(char *path) 00099 { 00100 phFUNCTION("phAvcodecSource::phAvcodecSource") 00101 00102 rc = this->lock(); 00103 phPRINT_RC(rc,NULL,"this->lock()"); 00104 00105 /* register all formats and codecs */ 00106 av_register_all(); 00107 00108 this->setName("phAvcodecSource"); 00109 00110 this->m_info = (struct phAvcodecSourceInfo_t *)phCalloc(1, 00111 sizeof(struct phAvcodecSourceInfo_t)); 00112 phPRINT_PTR(this->m_info,"phCalloc", 00113 "phCalloc failed to alloc phAvcodecSourceInfo"); 00114 00115 rc = this->resetInfo(); 00116 phPRINT_RC(rc,NULL,"this->resetInfo"); 00117 00118 this->m_buffers_open= 0; 00119 this->m_codec_open = 0; 00120 this->m_stream_open = 0; 00121 00122 this->m_user_fps = 0; 00123 this->m_user_delay = 0; 00124 this->m_loop = 0; 00125 this->m_is_open = 0; 00126 this->m_device_fd = 0; 00127 00128 if (path != NULL) 00129 { 00130 this->setPath(path); 00131 } 00132 else 00133 { 00134 this->setPath("test.mpg"); 00135 } 00136 00137 this->setFormat(phImageBGRA32); 00138 00139 /* This applies the default (1) picture/image settings[w,h,format,etc.] 00140 * (2) channel settings */ 00141 this->applySettings(); 00142 00143 /* opening the device must be explicitly done */ 00144 /* capturing must be explicitly done. */ 00145 error: 00146 rc = this->unlock(); 00147 phPRINT_RC(rc,NULL,"this->unlock()"); 00148 00149 return; 00150 } 00151 00152 /* ---------------------------------------------------------------------- * 00153 * ---------------------------------------------------------------------- */ 00154 phAvcodecSource::~phAvcodecSource () 00155 { 00156 phFUNCTION("phAvcodecSource::~phAvcodecSource") 00157 00158 rc = this->lock(); 00159 phPRINT_RC(rc,NULL,"this->lock()"); 00160 00161 if (this->isRunning()) 00162 { 00163 rc = this->stop(); 00164 phPRINT_RC(rc,NULL,"this->stop()"); 00165 } 00166 00167 if (this->isOpen()) 00168 { 00169 rc = this->close(); 00170 phPRINT_RC(rc,NULL,"this->close()"); 00171 } 00172 00173 phFree(this->m_info); 00174 00175 rc = this->unlock(); 00176 phPRINT_RC(rc,NULL,"this->unlock()"); 00177 } 00178 00179 /* ---------------------------------------------------------------------- */ 00180 int phAvcodecSource::resetInfo() 00181 { 00182 phFUNCTION("phAvcodecSource::resetInfo") 00183 int locked = 0; 00184 00185 phTHIS_LOCK(locked); 00186 00187 if ((this->m_info != NULL) && (this != NULL)) 00188 { 00189 /* TODO: free memory too ?? */ 00190 this->m_info->m_pFormatCtx = NULL; 00191 this->m_info->m_pCodecCtx = NULL; 00192 this->m_info->m_pStream = NULL; 00193 this->m_info->m_width = 0; 00194 this->m_info->m_height = 0; 00195 00196 this->m_info->m_pCodec = NULL; 00197 this->m_info->m_pFrame = NULL; 00198 this->m_info->m_pFrameRGB = NULL; 00199 this->m_info->m_videoStream = -1; 00200 this->m_info->m_numBytes = -1; 00201 this->m_info->m_avcodec_format = PIX_FMT_RGBA32; 00202 00203 this->m_info->m_buffer = NULL; 00204 this->m_info->m_frate = 0.0; 00205 this->m_info->m_frate_base = 0.0; 00206 this->m_info->m_sleeptime = 0; 00207 } 00208 phTHIS_UNLOCK_RET(locked,phSUCCESS,phFAIL); 00209 } 00210 00211 /* ---------------------------------------------------------------------- */ 00212 int phAvcodecSource::freeInfo() 00213 { 00214 phFUNCTION("phAvcodecSource::freeInfo") 00215 int locked = 0; 00216 00217 phTHIS_LOCK(locked); 00218 00219 if (this->m_info != NULL) 00220 { 00221 rc = this->closeBuffers(); 00222 phPRINT_RC(rc,NULL,"this->closeBuffers"); 00223 00224 rc = this->closeCodec(); 00225 phPRINT_RC(rc,NULL,"this->closeCodec"); 00226 00227 rc = this->closeStream(); 00228 phPRINT_RC(rc,NULL,"this->closeStream"); 00229 } 00230 00231 phTHIS_UNLOCK_RET(locked,phSUCCESS,phFAIL); 00232 } 00233 00234 /* ---------------------------------------------------------------------- */ 00235 void phAvcodecSource::calculateRates() 00236 { 00237 phFUNCTION("phAvcodecSource::calculateRates") 00238 00239 double frate = 0.0; 00240 double frate_base = 0.0; 00241 unsigned int sleeptime = 0; 00242 00243 if (this->m_info != NULL) 00244 { 00245 #if LIBAVCODEC_BUILD < 4752 00246 if (this->m_info->m_pCodecCtx) 00247 { 00248 /* Figure out how much to sleep */ 00249 frate = this->m_info->m_pCodecCtx->frame_rate; 00250 frate_base = this->m_info->m_pCodecCtx->frame_rate_base; 00251 } 00252 #endif 00253 00254 #if LIBAVFORMAT_BUILD > 4627 00255 if (this->m_info->m_pStream != NULL) 00256 { 00257 /* Figure out how much to sleep */ 00258 frate = this->m_info->m_pStream->r_frame_rate.num; 00259 frate_base = this->m_info->m_pStream->r_frame_rate.den; 00260 } 00261 #endif 00262 /* 00263 phPROGRESS("frate:%u frate_base:%u\n",frate,frate_base); 00264 */ 00265 } 00266 00267 if ((this->m_user_fps == 0) && (this->m_user_delay == 0)) 00268 { 00269 /* set the frame rate for cases where the frame rate gets a 00270 * bad value from some codecs */ 00271 if (((frate >= 1000) && (frate_base == 1)) || 00272 ((frate == 1) && (frate_base == 1)) || 00273 ((frate == 0) && (frate_base == 0))) 00274 /* 30 fps... it's a guess */ 00275 sleeptime = 33366; 00276 else 00277 /* Calculate the sleep time from the frate and base */ 00278 sleeptime = (int)((1.0/(frate / frate_base))*1000000.0); 00279 } 00280 00281 /* if the user specified a fps value, calc the sleeptime based on it */ 00282 if (this->m_user_fps != 0) 00283 sleeptime = (int)((1.0 / this->m_user_fps) * 1000000.0); 00284 00285 /* if the user gave a delay time, use it */ 00286 if (this->m_user_delay != 0) 00287 sleeptime = this->m_user_delay; 00288 00289 /* if for some reason the sleeptime is <=0, set it to 30 fps */ 00290 if (sleeptime <= 0) sleeptime = 33366; 00291 00292 if (this->m_info != NULL) 00293 { 00294 this->m_info->m_frate = frate; 00295 this->m_info->m_frate_base = frate_base; 00296 this->m_info->m_sleeptime = sleeptime; 00297 } 00298 } 00299 00300 /* ---------------------------------------------------------------------- */ 00301 int phAvcodecSource::openStream(int quiet) 00302 { 00303 phFUNCTION("phAvcodecSource::openStream") 00304 00305 AVFormatContext *pFormatCtx = NULL; 00306 AVCodecContext *pCodecCtx = NULL; 00307 AVStream *pStream = NULL; 00308 int videoStream = -1; 00309 int width = 0; 00310 int height = 0; 00311 00312 00313 int i = 0; 00314 00315 if (this->m_stream_open) 00316 { 00317 rc = this->closeStream(); 00318 phCHECK_RC(rc,NULL,"this->closeStream"); 00319 } 00320 00321 if ((this->m_info != NULL) && 00322 (this->getPath() != NULL) && 00323 (strcmp(this->getPath(),"") != 0)) 00324 { 00325 /* open the file */ 00326 rc = av_open_input_file(&pFormatCtx, 00327 this->getPath(), 00328 NULL, 00329 0, 00330 NULL); 00331 if (!quiet) 00332 { 00333 phCHECK_RC(rc,NULL,"av_open_input_file(%s)",this->getPath()); 00334 } 00335 else 00336 { 00337 if (rc < 0) goto error; 00338 } 00339 00340 /* retrieve the stream information */ 00341 rc = av_find_stream_info(pFormatCtx); 00342 /* no stream information in there */ 00343 if (!quiet) 00344 { 00345 phCHECK_RC(rc,NULL,"av_find_stream_info"); 00346 } 00347 else 00348 { 00349 if (rc < 0) goto error; 00350 } 00351 00352 #if 0 00353 /* dump the file information to stderr */ 00354 dump_format(pFormatCtx, 0, this->getPath(), false); 00355 #endif 00356 /* we want the first video stream */ 00357 videoStream = -1; 00358 for ( i = 0; i < pFormatCtx->nb_streams; i++) 00359 { 00360 /* in CVS build 4629, they changed to AVCodecContext * */ 00361 #if LIBAVFORMAT_BUILD < 4629 00362 if (pFormatCtx->streams[i]->codec.codec_type == CODEC_TYPE_VIDEO) 00363 #else /* new API */ 00364 if (pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) 00365 #endif 00366 { 00367 videoStream = i; 00368 break; 00369 } 00370 } 00371 /* no video stream in there... */ 00372 if (!quiet) 00373 { 00374 phCHECK_RC(videoStream,NULL,"no video stream"); 00375 } 00376 else 00377 { 00378 if (rc < 0) goto error; 00379 } 00380 00381 /* get a pointer to the codec context for the video stream */ 00382 pStream = pFormatCtx->streams[videoStream]; 00383 00384 /* in CVS build 4629, they changed to AVCodecContext * */ 00385 #if LIBAVFORMAT_BUILD < 4629 00386 pCodecCtx = &(pStream->codec); 00387 #else /* new API */ 00388 pCodecCtx = pStream->codec; 00389 #endif 00390 /* we need to save the width and height because it sometimes changes 00391 * in the GetNextFrame function after a call to avcodec_decode_video */ 00392 width = pCodecCtx->width; 00393 height = pCodecCtx->height; 00394 00395 this->m_info->m_pFormatCtx = pFormatCtx; 00396 this->m_info->m_pCodecCtx = pCodecCtx; 00397 this->m_info->m_pStream = pStream; 00398 this->m_info->m_videoStream = videoStream; 00399 this->m_info->m_width = width; 00400 this->m_info->m_height = height; 00401 00402 this->m_stream_open = 1; 00403 } 00404 00405 return phSUCCESS; 00406 error: 00407 00408 /* close the video file */ 00409 if (pFormatCtx != NULL) 00410 { 00411 av_close_input_file(pFormatCtx); 00412 } 00413 00414 rc = this->freeInfo(); 00415 if (!quiet) 00416 { 00417 phPRINT_RC(rc,NULL,"this->freeInfo()"); 00418 } 00419 00420 return phFAIL; 00421 } 00422 00423 /* ---------------------------------------------------------------------- */ 00424 int phAvcodecSource::openCodec() 00425 { 00426 phFUNCTION("phAvcodecSource::openCodec") 00427 00428 AVCodec *pCodec = NULL; 00429 double frate = 0.0; 00430 double frate_base = 0.0; 00431 unsigned int sleeptime = 0; 00432 00433 if (this->m_codec_open) 00434 { 00435 rc = this->closeCodec(); 00436 phCHECK_RC(rc,NULL,"this->closeCodec"); 00437 } 00438 00439 if ((this->m_info != NULL) && 00440 (this->m_info->m_pFormatCtx != NULL) && 00441 (this->m_info->m_pCodecCtx != NULL)) 00442 { 00443 /* get the super secret decoder ring for the video 00444 * stream (include 5 box tops) */ 00445 pCodec = avcodec_find_decoder(this->m_info->m_pCodecCtx->codec_id); 00446 /* no decoder ring in the box, ask for your money back! */ 00447 phCHECK_PTR(pCodec,NULL,"avcodec_find_decoder"); 00448 00449 /* tell the decoder that truncated bitstreams are doable */ 00450 if (pCodec->capabilities & CODEC_CAP_TRUNCATED) 00451 { 00452 this->m_info->m_pCodecCtx->flags |= CODEC_FLAG_TRUNCATED; 00453 } 00454 00455 /* open the codec */ 00456 rc = avcodec_open(this->m_info->m_pCodecCtx, pCodec); 00457 /* something bad happened and the codec wouldn't open */ 00458 phCHECK_RC(rc,NULL,"avcodec_open"); 00459 00460 this->m_info->m_pCodec = pCodec; 00461 00462 this->m_codec_open = 1; 00463 } 00464 00465 return phSUCCESS; 00466 error: 00467 00468 /* close the codec */ 00469 if ((this->m_info->m_pCodecCtx != NULL) && 00470 (pCodec != NULL)) 00471 { 00472 avcodec_close(this->m_info->m_pCodecCtx); 00473 } 00474 00475 rc = this->freeInfo(); 00476 phPRINT_RC(rc,NULL,"this->freeInfo()"); 00477 00478 return phFAIL; 00479 } 00480 00481 /* ---------------------------------------------------------------------- */ 00482 int phAvcodecSource::openBuffers() 00483 { 00484 phFUNCTION("phAvcodecSource::openBuffers") 00485 00486 AVFrame *pFrame = NULL; 00487 AVFrame *pFrameRGB = NULL; 00488 int avcodec_format = PIX_FMT_RGBA32; 00489 int numBytes = 0; 00490 uint8_t *buffer = NULL; 00491 00492 00493 if (this->m_buffers_open) 00494 { 00495 rc = this->closeBuffers(); 00496 phCHECK_RC(rc,NULL,"this->closeBuffers()"); 00497 } 00498 00499 if ((this->m_info != NULL) && 00500 (this->m_info->m_pFormatCtx != NULL) && 00501 (this->m_info->m_pCodecCtx != NULL) && 00502 (this->m_info->m_pCodec != NULL) && 00503 (this->m_info->m_width > 0) && 00504 (this->m_info->m_height > 0)) 00505 { 00506 /* get a video frame ready */ 00507 pFrame = avcodec_alloc_frame(); 00508 phCHECK_PTR(pFrame,NULL,"avcodec_alloc_frame"); 00509 00510 pFrameRGB = avcodec_alloc_frame(); 00511 phCHECK_PTR(pFrameRGB,NULL,"avcodec_alloc_frame"); 00512 00513 /* determine how big our buffer needs to be and oh yeah, 00514 * allocate the darn thing... */ 00515 numBytes = avpicture_get_size( avcodec_format, 00516 this->m_info->m_width, 00517 this->m_info->m_height); 00518 00519 buffer = (uint8_t *)phCalloc(numBytes,sizeof(uint8_t)); 00520 phCHECK_PTR(buffer,"phCalloc", "phCalloc failed."); 00521 00522 avpicture_fill((AVPicture *)pFrameRGB, 00523 buffer, 00524 avcodec_format, 00525 this->m_info->m_width, 00526 this->m_info->m_height ); 00527 00528 this->m_info->m_pFrame = pFrame; 00529 this->m_info->m_pFrameRGB = pFrameRGB; 00530 this->m_info->m_avcodec_format = avcodec_format; 00531 this->m_info->m_numBytes = numBytes; 00532 this->m_info->m_buffer = buffer; 00533 00534 this->m_buffers_open = 1; 00535 } 00536 00537 return phSUCCESS; 00538 error: 00539 00540 /* free up the image buffer allocation */ 00541 phFree(buffer); 00542 00543 /* free up the RGB frame */ 00544 if (pFrameRGB != NULL) 00545 { 00546 av_free(pFrameRGB); 00547 } 00548 00549 /* free up the YUV frame */ 00550 if (pFrame != NULL) 00551 { 00552 av_free(pFrame); 00553 } 00554 00555 rc = this->freeInfo(); 00556 phPRINT_RC(rc,NULL,"this->freeInfo()"); 00557 00558 return phFAIL; 00559 } 00560 00561 /* ---------------------------------------------------------------------- */ 00562 int phAvcodecSource::closeStream() 00563 { 00564 phFUNCTION("phAvcodecSource::closeStream") 00565 00566 if (this->m_info != NULL) 00567 { 00568 /* close the video file */ 00569 if (this->m_info->m_pFormatCtx != NULL) 00570 { 00571 av_close_input_file(this->m_info->m_pFormatCtx); 00572 } 00573 00574 this->m_info->m_pFormatCtx = NULL; 00575 this->m_info->m_pCodecCtx = NULL; 00576 this->m_info->m_pStream = NULL; 00577 this->m_info->m_videoStream = -1; 00578 this->m_info->m_width = 0; 00579 this->m_info->m_height = 0; 00580 00581 this->m_stream_open = 0; 00582 } 00583 00584 return phSUCCESS; 00585 } 00586 00587 /* ---------------------------------------------------------------------- */ 00588 int phAvcodecSource::closeCodec() 00589 { 00590 phFUNCTION("phAvcodecSource::closeCodec") 00591 00592 if (this->m_info != NULL) 00593 { 00594 /* close the codec */ 00595 if ((this->m_info->m_pCodecCtx != NULL) && 00596 (this->m_info->m_pCodec != NULL)) 00597 { 00598 avcodec_close(this->m_info->m_pCodecCtx); 00599 } 00600 00601 this->m_info->m_pCodec = NULL; 00602 this->m_codec_open = 0; 00603 } 00604 00605 return phSUCCESS; 00606 } 00607 00608 /* ---------------------------------------------------------------------- */ 00609 int phAvcodecSource::closeBuffers() 00610 { 00611 phFUNCTION("phAvcodecSource::closeBuffers") 00612 00613 if (this->m_info != NULL) 00614 { 00615 /* free up the image buffer allocation */ 00616 phFree(this->m_info->m_buffer); 00617 00618 /* free up the RGB frame */ 00619 if (this->m_info->m_pFrameRGB != NULL) 00620 { 00621 av_free(this->m_info->m_pFrameRGB); 00622 } 00623 00624 /* free up the YUV frame */ 00625 if (this->m_info->m_pFrame != NULL) 00626 { 00627 av_free(this->m_info->m_pFrame); 00628 } 00629 00630 this->m_info->m_pFrame = NULL; 00631 this->m_info->m_pFrameRGB = NULL; 00632 this->m_info->m_numBytes = 0; 00633 this->m_info->m_buffer = NULL; 00634 00635 this->m_buffers_open = 0; 00636 } 00637 00638 return phSUCCESS; 00639 } 00640 00641 /* ---------------------------------------------------------------------- */ 00642 int phAvcodecSource::open(char *path) 00643 { 00644 phFUNCTION("phAvcodecSource::open") 00645 00646 int locked = 0; 00647 00648 phTHIS_LOCK(locked); 00649 00650 /* device is already open, close it */ 00651 if (this->isOpen()) 00652 { 00653 rc = this->close(); 00654 phPRINT_RC(rc,NULL,"this->close()"); 00655 } 00656 00657 if (path != NULL) 00658 { 00659 rc = this->setPath( path ); 00660 phPRINT_RC(rc,NULL,"this->setPath( path:%s )",path); 00661 } 00662 00663 if (!this->m_is_open) 00664 { 00665 rc = this->openStream(); 00666 phCHECK_RC(rc,NULL,"this->openStream()"); 00667 00668 rc = this->openCodec(); 00669 phCHECK_RC(rc,NULL,"this->openCodec()"); 00670 00671 rc = this->openBuffers(); 00672 phCHECK_RC(rc,NULL,"this->openBuffers()"); 00673 00674 /* Try to apply all the settings to the V4L device */ 00675 ph_int32_array_append(this->m_changed_array,phCHANGE_INIT); 00676 this->applySettings(); 00677 00678 this->calculateRates(); 00679 00680 this->m_is_open = 1; 00681 } 00682 00683 phTHIS_UNLOCK(locked); 00684 00685 return phSUCCESS; 00686 error: 00687 00688 phTHIS_ERROR_UNLOCK(locked); 00689 00690 return phFAIL; 00691 } 00692 00693 /* ---------------------------------------------------------------------- */ 00694 int phAvcodecSource::isOpen() 00695 { 00696 return ((this->m_is_open > 0) ? 1 : 0); 00697 } 00698 00699 /* ---------------------------------------------------------------------- */ 00700 int phAvcodecSource::close() 00701 { 00702 phFUNCTION("phAvcodecSource::close") 00703 int locked = 0; 00704 00705 phTHIS_LOCK(locked); 00706 00707 /* Close can be called from userspace/applications, close the thread */ 00708 if (this->isRunning()) 00709 { 00710 rc = this->stop(); 00711 phPRINT_RC(rc,NULL,"this->stop()"); 00712 } 00713 00714 rc = this->freeInfo(); 00715 phPRINT_RC(rc,NULL,"this->freeInfo"); 00716 00717 this->m_is_open = 0; 00718 00719 rc = this->resetInfo(); 00720 phPRINT_RC(rc,NULL,"this->resetInfo"); 00721 00722 phTHIS_UNLOCK_RET(locked,phSUCCESS,phFAIL); 00723 } 00724 00725 /* ---------------------------------------------------------------------- */ 00726 int phAvcodecSource::setFps( int fps ) 00727 { 00728 phFUNCTION("phAvcodecSource::setFps()") 00729 int locked = 0; 00730 00731 phTHIS_LOCK(locked); 00732 00733 this->m_user_fps = fps; 00734 00735 phTHIS_UNLOCK_RET(locked,phSUCCESS,phFAIL); 00736 } 00737 00738 /* ---------------------------------------------------------------------- */ 00739 int phAvcodecSource::getFps( ) 00740 { 00741 phFUNCTION("phAvcodecSource::getFps()") 00742 int locked = 0; 00743 int retval = 0; 00744 00745 phTHIS_LOCK(locked); 00746 00747 retval = this->m_user_fps; 00748 00749 phTHIS_UNLOCK_RET(locked,retval,phFAIL); 00750 } 00751 00752 /* ---------------------------------------------------------------------- */ 00753 int phAvcodecSource::setDelay( int delay ) 00754 { 00755 phFUNCTION("phAvcodecSource::setDelay()") 00756 int locked = 0; 00757 00758 phTHIS_LOCK(locked); 00759 00760 this->m_user_delay = delay; 00761 00762 phTHIS_UNLOCK_RET(locked,phSUCCESS,phFAIL); 00763 } 00764 00765 /* ---------------------------------------------------------------------- */ 00766 int phAvcodecSource::getDelay( ) 00767 { 00768 phFUNCTION("phAvcodecSource::getDelay()") 00769 int locked = 0; 00770 int retval = 0; 00771 00772 phTHIS_LOCK(locked); 00773 00774 retval = this->m_user_delay; 00775 00776 phTHIS_UNLOCK_RET(locked,retval,phFAIL); 00777 } 00778 00779 /* ---------------------------------------------------------------------- */ 00780 int phAvcodecSource::setLoop( int loop ) 00781 { 00782 phFUNCTION("phAvcodecSource::setLoop()") 00783 int locked = 0; 00784 00785 phTHIS_LOCK(locked); 00786 00787 this->m_loop = loop; 00788 00789 phTHIS_UNLOCK_RET(locked,phSUCCESS,phFAIL); 00790 } 00791 00792 /* ---------------------------------------------------------------------- */ 00793 int phAvcodecSource::getLoop( ) 00794 { 00795 phFUNCTION("phAvcodecSource::getLoop()") 00796 int locked = 0; 00797 int retval = 0; 00798 00799 phTHIS_LOCK(locked); 00800 00801 retval = this->m_loop; 00802 00803 phTHIS_UNLOCK_RET(locked,retval,phFAIL); 00804 } 00805 00806 00807 /* ---------------------------------------------------------------------- */ 00808 int phAvcodecSource::onApplySettings() 00809 { 00810 phFUNCTION("phAvcodecSource::onApplySettings") 00811 int retrc = phSUCCESS; 00812 00813 uint32_t i = 0; 00814 00815 int ch_init = 0; 00816 int ch_b = 0; 00817 int ch_hue = 0; 00818 int ch_color = 0; 00819 int ch_con = 0; 00820 int ch_white = 0; 00821 int ch_channel = 0; 00822 int ch_h = 0; 00823 int ch_w = 0; 00824 int ch_f = 0; 00825 int ch_p = 0; 00826 00827 ch_init = ph_int32_array_find(this->m_changed_array, phCHANGE_INIT,NULL); 00828 /* 00829 * this->m_changed_array contains the list of changes that are to 00830 * be applied. 00831 * 00832 * This method will call phImageCapture::onApplySettings which will empty 00833 * the array so that settings are applied only once. 00834 */ 00835 00836 #if 0 00837 /* Copy the image settings into the V4L structure */ 00838 ch_b = ph_int32_array_find(this->m_changed_array, phCHANGE_BRIGHTNESS, 00839 NULL); 00840 ch_hue = ph_int32_array_find(this->m_changed_array, phCHANGE_HUE, 00841 NULL); 00842 ch_color = ph_int32_array_find(this->m_changed_array, phCHANGE_COLOR, 00843 NULL); 00844 ch_con = ph_int32_array_find(this->m_changed_array, phCHANGE_CONTRAST, 00845 NULL); 00846 ch_white = ph_int32_array_find(this->m_changed_array, phCHANGE_WHITENESS, 00847 NULL); 00848 if (ch_init > 0) ch_b = ch_hue = ch_color = ch_con = ch_white = 1; 00849 if ((ch_b > 0) || (ch_hue > 0) || (ch_color > 0) || 00850 (ch_con > 0) || (ch_white > 0)) 00851 { 00852 } 00853 00854 /*--------------------------------------------------------------------* 00855 * From linux/Documentation/video4linux/API.html: 00856 * 00857 * "Each channel can be queries with the VIDIOCGCHAN ioctl call. 00858 * Before invoking this function the caller must set the channel 00859 * field to the channel that is being queried. On return the 00860 * struct video_channel is filled in with information about the 00861 * nature of the channel itself." 00862 *--------------------------------------------------------------------*/ 00863 ch_channel = ph_int32_array_find(this->m_changed_array,phCHANGE_CHANNEL, 00864 NULL); 00865 if ((ch_channel > 0) || (ch_init > 0)) 00866 { 00867 } 00868 /* else, the channel is < 0 or the current chn # */ 00869 00870 /* settings that require the capture to not be in progress for the 00871 * phAvcodecSource settings changes to be applied */ 00872 ch_h = ph_int32_array_find(this->m_changed_array, phCHANGE_HEIGHT, NULL); 00873 ch_w = ph_int32_array_find(this->m_changed_array, phCHANGE_WIDTH, NULL); 00874 ch_f = ph_int32_array_find(this->m_changed_array, phCHANGE_FORMAT, NULL); 00875 00876 if (ch_init > 0) ch_h = ch_w = ch_f = 1; 00877 00878 if ((ch_h > 0) || (ch_w > 0) || (ch_f > 0)) 00879 { 00880 } 00881 #endif 00882 00883 /* update internal information when the path is given */ 00884 /* Only do this when the thread isn't running and the stream isn't open */ 00885 ch_p = ph_int32_array_find(this->m_changed_array, phCHANGE_PATH, NULL); 00886 /* 00887 i = ph_int32_array_get_length(this->m_changed_array); 00888 phPROGRESS("ch_p:%d ch_init:%d running:%d open:%d length:%u\n", 00889 ch_p,ch_init,this->isRunning(),this->m_stream_open,i); 00890 */ 00891 if (((ch_p > 0) || (ch_init > 0)) && 00892 ((!(this->isRunning())) && (!(this->m_stream_open)))) 00893 { 00894 /* Copy the width and height settings into the object */ 00895 rc = this->openStream(1); 00896 00897 if ((this->m_info != NULL) && (this->m_stream_open)) 00898 { 00899 if (this->m_info->m_width > 0) 00900 { 00901 this->m_width = this->m_info->m_width; 00902 } 00903 if (this->m_info->m_height > 0) 00904 { 00905 this->m_height = this->m_info->m_height; 00906 } 00907 } 00908 /*phPRINT("rc:%d %u:%u\n",rc,this->m_width,this->m_height);*/ 00909 rc = this->closeStream(); 00910 00911 retrc = 1; 00912 } 00913 00914 rc = this->phImageCapture::onApplySettings(); 00915 phCHECK_RC(rc,NULL,"this->phImageCapture::onApplySettings() failed."); 00916 00917 return retrc; 00918 error: 00919 00920 return phFAIL; 00921 } 00922 00923 /* ------------------------------------------------------------------------ */ 00924 /* GetNextFrame 00925 * 00926 * retrieves a frame from the AVI stream 00927 * 00928 */ 00929 /* ------------------------------------------------------------------------ */ 00930 static bool GetNextFrame( AVFormatContext *pFormatCtx, 00931 AVCodecContext *pCodecCtx, 00932 int videoStream, 00933 AVFrame *pFrame, 00934 bool *fFirstTime, 00935 uint8_t **rawData, 00936 AVPacket *packet, 00937 int *bytesRemaining 00938 ) 00939 { 00940 phFUNCTION("GetNextFrame") 00941 00942 int bytesDecoded; 00943 int frameFinished; 00944 00945 // First time through, set packet data to NULL 00946 if (*fFirstTime) 00947 { 00948 *fFirstTime = false; 00949 packet->data = NULL; 00950 } 00951 00952 // decode packets until we have a complete frame 00953 while(true) 00954 { 00955 // make sure we get all of the current packet 00956 while (*bytesRemaining > 0) 00957 { 00958 // decode the next chunk of the packet 00959 bytesDecoded = avcodec_decode_video(pCodecCtx, 00960 pFrame, 00961 &frameFinished, 00962 *rawData, 00963 *bytesRemaining); 00964 00965 // error? 00966 if (bytesDecoded < 0) 00967 { 00968 fprintf(stderr, "Error while decoding frame\n"); 00969 return false; 00970 } 00971 00972 *bytesRemaining -= bytesDecoded; 00973 *rawData += bytesDecoded; 00974 00975 // if the frame is finished then we're all done, otherwise keep on chunking... 00976 if (frameFinished) 00977 return true; 00978 } 00979 00980 // read the next packet, but skip it if it isn't owned by the current stream 00981 do 00982 { 00983 // first free the old packet 00984 if (packet->data != NULL) 00985 { 00986 av_free_packet( packet); 00987 } 00988 00989 // now read a new packet 00990 if (av_read_packet( pFormatCtx, packet ) < 0) 00991 goto loop_exit; 00992 00993 } while (packet->stream_index != videoStream); 00994 00995 *bytesRemaining = packet->size; 00996 *rawData = packet->data; 00997 } 00998 00999 loop_exit: 01000 01001 // decode the rest of the last frame 01002 bytesDecoded = avcodec_decode_video(pCodecCtx, 01003 pFrame, 01004 &frameFinished, 01005 *rawData, 01006 *bytesRemaining); 01007 01008 // make sure to free the last packet 01009 if (packet->data != NULL) 01010 { 01011 av_free_packet(packet); 01012 } 01013 01014 return (frameFinished != 0); 01015 } 01016 01017 /* ---------------------------------------------------------------------- */ 01018 int phAvcodecSource::cleanup() 01019 { 01020 phFUNCTION("phAvcodecSource::cleanup()") 01021 01022 rc = this->lock(); 01023 phPRINT_RC(rc,NULL,"this->lock()"); 01024 01025 rc = this->phImageCapture::cleanup(); 01026 phPRINT_RC(rc,NULL,"this->phImageCapture::cleanup()"); 01027 01028 rc = this->unlock(); 01029 phPRINT_RC(rc,NULL,"this->unlock()"); 01030 01031 return phSUCCESS; 01032 } 01033 01034 /* ---------------------------------------------------------------------- */ 01035 int phAvcodecSource::run() 01036 { 01037 phFUNCTION("phAvcodecSource::run") 01038 01039 /* Timer routines to get desired framerate */ 01040 phTimeInterval timer; 01041 int timeleft = 0; 01042 01043 AVFormatContext *pFormatCtx = NULL; 01044 AVCodecContext *pCodecCtx = NULL; 01045 AVFrame *pFrame = NULL; 01046 AVFrame *pFrameRGB = NULL; 01047 int videoStream = 0; 01048 int orig_width = 0; 01049 int orig_height = 0; 01050 int orig_size = 0; 01051 01052 /* Returned value from GetNextFrame and a loop count */ 01053 bool brc = false; 01054 bool fFirstTime = true; 01055 uint8_t *rawData = NULL; 01056 AVPacket packet; 01057 int bytesRemaining = 0; 01058 uint32_t orig_format = phImageBGRA32; 01059 01060 phImage *output_buffer = this->getImage(); 01061 01062 /* local copies of phAvcodecSource object's member vars */ 01063 phImage *image = new phImage(); 01064 uint32_t cur_image_size = 0; 01065 int32_t cur_format = 0; 01066 uint32_t cur_width = 0; 01067 uint32_t cur_height = 0; 01068 01069 /* Setup */ 01070 cur_format = this->m_format; 01071 cur_width = this->m_width; 01072 cur_height = this->m_height; 01073 01074 pFormatCtx = this->m_info->m_pFormatCtx; 01075 pCodecCtx = this->m_info->m_pCodecCtx; 01076 pFrame = this->m_info->m_pFrame; 01077 pFrameRGB = this->m_info->m_pFrameRGB; 01078 videoStream = this->m_info->m_videoStream; 01079 orig_width = this->m_info->m_width; 01080 orig_height = this->m_info->m_height; 01081 orig_size = this->m_info->m_numBytes; 01082 01083 /* Release the thread that spawned this one */ 01084 /* Everything has been copied and everything is ready to start */ 01085 rc = this->signal_running(); 01086 phPRINT_RC(rc,NULL,"this->signal_running"); 01087 01088 DEBUG_PRINT("Thread Started\n"); 01089 DEBUG_PRINT("output_buffer: %p\n",output_buffer); 01090 01091 while (this->isRunning()) 01092 { 01093 rc = this->m_settings_lock.trylock(); 01094 phPRINT_RC(rc,NULL,"this->m_settings_lock.trylock();"); 01095 01096 if (rc == phSUCCESS) 01097 { 01098 cur_width = this->m_width; 01099 cur_height = this->m_height; 01100 cur_format = this->m_format; 01101 01102 rc = this->m_settings_lock.unlock(); 01103 phPRINT_RC(rc,NULL,"this->m_settings_lock.unlock()"); 01104 } 01105 01106 /* Get next frame */ 01107 brc = GetNextFrame(pFormatCtx, 01108 pCodecCtx, 01109 videoStream, 01110 pFrame, 01111 &fFirstTime, 01112 &rawData, 01113 &packet, 01114 &bytesRemaining ); 01115 01116 /* \/ ORIGINAL CODE \/ */ 01117 rc = img_convert((AVPicture *)pFrameRGB, 01118 this->m_info->m_avcodec_format, 01119 (AVPicture *)pFrame, 01120 pCodecCtx->pix_fmt, 01121 orig_width, 01122 orig_height); 01123 phCHECK_RC(rc,NULL,"img_convert"); 01124 01125 rc = image->setImage(orig_width, 01126 orig_height, 01127 orig_format, 01128 orig_size, 01129 pFrameRGB->data[0]); 01130 phCHECK_RC(rc,NULL,"image->setImage"); 01131 01132 01133 /* Convert to the output format */ 01134 /* Setup the image according to desired output format */ 01135 rc = image->resize(cur_width,cur_height); 01136 phPRINT_RC(rc,NULL,"image->resize(%d,%d)", 01137 cur_width,cur_height); 01138 01139 rc = image->convert(cur_format); 01140 phPRINT_RC(rc,NULL,"image->convert(%s)", 01141 phImageFormatToString(cur_format)); 01142 01143 /* if (output_buffer->tryWritelock() == 0) */ 01144 if (output_buffer->writeLock() == 0) 01145 { 01146 rc = output_buffer->swapImage(*image); 01147 phCHECK_RC(rc,NULL,"output_buffer->swapImage(*image)"); 01148 01149 output_buffer->rwUnlock(); 01150 } 01151 01152 /* Check to see if there are more frames or an error */ 01153 if (brc) 01154 { 01155 /* Get a time stop stamp */ 01156 timer.stop(); 01157 /* Figure out the time to sleep */ 01158 /* The very first elapsed() value will be 0 */ 01159 timeleft = this->m_info->m_sleeptime - 01160 timer.elapsed().getMicroseconds(); 01161 /* 01162 phPROGRESS("timeleft:%u sleeptime:%u elapsed:%u\n", 01163 timeleft,this->m_info->m_sleeptime, 01164 timer.elapsed().getMicroseconds()); 01165 */ 01166 /* sleep for an amount to achieve the desired frame rate */ 01167 if (timeleft > 0) phUSleep(timeleft); 01168 /* get a time start stamp */ 01169 timer.start(); 01170 } 01171 else 01172 { 01173 if (this->m_loop) 01174 { 01175 rc = this->freeInfo(); 01176 phPRINT_RC(rc,NULL,"this->freeInfo"); 01177 01178 rc = this->resetInfo(); 01179 phPRINT_RC(rc,NULL,"this->resetInfo"); 01180 01181 rc = this->openStream(); 01182 phPRINT_RC(rc,NULL,"this->openStream()"); 01183 01184 rc = this->openCodec(); 01185 phPRINT_RC(rc,NULL,"this->openCodec()"); 01186 01187 rc = this->openBuffers(); 01188 phCHECK_RC(rc,NULL,"this->openBuffers()"); 01189 01190 this->calculateRates(); 01191 01192 fFirstTime = true; 01193 rawData = NULL; 01194 bytesRemaining = 0; 01195 phMemset(&packet,0,sizeof(AVPacket)); 01196 01197 cur_format = this->m_format; 01198 cur_width = this->m_width; 01199 cur_height = this->m_height; 01200 01201 pFormatCtx = this->m_info->m_pFormatCtx; 01202 pCodecCtx = this->m_info->m_pCodecCtx; 01203 pFrame = this->m_info->m_pFrame; 01204 pFrameRGB = this->m_info->m_pFrameRGB; 01205 videoStream = this->m_info->m_videoStream; 01206 orig_width = this->m_info->m_width; 01207 orig_height = this->m_info->m_height; 01208 orig_size = this->m_info->m_numBytes; 01209 } 01210 else 01211 { 01212 this->setRunning(0); 01213 } 01214 } 01215 } 01216 01217 phDelete(image); 01218 01219 DEBUG_PRINT("Thread returning cleanly\n"); 01220 01221 return phSUCCESS; 01222 01223 error: 01224 phDelete(image); 01225 phPROGRESS("Thread returning with error\n"); 01226 01227 rc = this->signal_error(); 01228 phPRINT_RC(rc,NULL,"this->signal_error"); 01229 01230 return phFAIL; 01231 } 01232
Copyright (C) 2002 - 2007 |
Philip D.S. Thoren ( pthoren@users.sourceforge.net ) University Of Massachusetts at Lowell Robotics Lab |