Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

phAvcodecSource.cpp

Go to the documentation of this file.
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
SourceForge.net Logo

Generated on Sat Jun 16 02:44:03 2007 for phission by  doxygen 1.4.4