RtspFileHandler.cxx
上传用户:sy_wanhua
上传日期:2013-07-25
资源大小:3048k
文件大小:19k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

C/C++

  1. /* ====================================================================
  2.  * The Vovida Software License, Version 1.0 
  3.  * 
  4.  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
  5.  * 
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 
  10.  * 1. Redistributions of source code must retain the above copyright
  11.  *    notice, this list of conditions and the following disclaimer.
  12.  * 
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in
  15.  *    the documentation and/or other materials provided with the
  16.  *    distribution.
  17.  * 
  18.  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
  19.  *    and "Vovida Open Communication Application Library (VOCAL)" must
  20.  *    not be used to endorse or promote products derived from this
  21.  *    software without prior written permission. For written
  22.  *    permission, please contact vocal@vovida.org.
  23.  *
  24.  * 4. Products derived from this software may not be called "VOCAL", nor
  25.  *    may "VOCAL" appear in their name, without prior written
  26.  *    permission of Vovida Networks, Inc.
  27.  * 
  28.  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
  29.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
  31.  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
  32.  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
  33.  * IN EXCESS OF 281421,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
  34.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  35.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  36.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  37.  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  38.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  39.  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  40.  * DAMAGE.
  41.  * 
  42.  * ====================================================================
  43.  * 
  44.  * This software consists of voluntary contributions made by Vovida
  45.  * Networks, Inc. and many individuals on behalf of Vovida Networks,
  46.  * Inc.  For more information on Vovida Networks, Inc., please see
  47.  * <http://www.vovida.org/>.
  48.  *
  49.  */
  50. static const char* const RtspFileHandler_cxx_version =
  51.     "$Id: RtspFileHandler.cxx,v 1.57 2001/07/26 21:47:01 kle Exp $";
  52. #include "RtspFileHandler.hxx"
  53. #include "RtspConfiguration.hxx"
  54. #include "RtspFileManager.hxx"
  55. #include "RtpFileTypes.hxx"
  56. #include "RtspRangeHdr.hxx"
  57. #include "RtspFileAu.hxx"
  58. #include "RtspFileWav.hxx"
  59. #include "RtspFileRaw.hxx"
  60. #include "RtspFileRtp.hxx"
  61. #include <fcntl.h>
  62. #include <unistd.h>
  63. #include <sys/stat.h>
  64. RtspFileHandler::RtspFileHandler( const Data& filename, const Data& contentBase )
  65.     : myContentBase ( contentBase.getData() ),
  66.       myFileExtension( UNKNOWN_EXT ),
  67.       myRtspSdp(),
  68.       m_xRtspFile( 0 ),
  69.       myReadWrite( 0 ),
  70.       myFtIndex( 0 ),
  71.       myCodec( -1 ),
  72.       myPacketInterval( -1 ),
  73.       myPacketSize( -1 )
  74. {
  75.     cpLog( LOG_DEBUG, "File handler created for %s", filename.getData() );
  76.     string name = filename.getData();
  77.     while(1)
  78.     {
  79.         // determine file extension
  80.         // has default value if none found
  81.         myFileExtension = UNKNOWN_EXT;
  82.         string::size_type size = name.size();
  83.         if( size>2 && name[size-3]=='.' )
  84.         {
  85.             if( ( (name[size-2]=='a') || (name[size-2]=='A') ) &&
  86.                 ( (name[size-1]=='u') || (name[size-1]=='U') )   )
  87.             {
  88.                 myFileExtension = AU_EXT;
  89.                 name = name.substr( 0, size-3 );
  90.             }
  91.         }
  92.         else
  93.         {
  94.             if(size>3 && name[size-4]=='.')
  95.             {
  96.                 if( ( (name[size-3]=='r') || (name[size-3]=='R') ) &&
  97.                     ( (name[size-2]=='a') || (name[size-2]=='A') ) &&
  98.                     ( (name[size-1]=='w') || (name[size-1]=='W') )   )
  99.                 {
  100.                     myFileExtension = RAW_EXT;
  101.                     name = name.substr( 0, size-4 );
  102.                 }
  103.                 else if( ( (name[size-3]=='r') || (name[size-3]=='R') ) &&
  104.                          ( (name[size-2]=='t') || (name[size-2]=='T') ) &&
  105.                          ( (name[size-1]=='p') || (name[size-1]=='P') )   )
  106.                 {
  107.                     myFileExtension = RTP_EXT;
  108.                     name = name.substr( 0, size-4 );
  109.                 }
  110.                 else if( ( (name[size-3]=='w') || (name[size-3]=='W') ) &&
  111.                          ( (name[size-2]=='a') || (name[size-2]=='A') ) &&
  112.                          ( (name[size-1]=='v') || (name[size-1]=='V') )   )
  113.                 {
  114.                     myFileExtension = WAV_EXT;
  115.                     name = name.substr( 0, size-4 );
  116.                 }
  117.             }
  118.         }
  119.         if( myFileExtension == UNKNOWN_EXT )
  120.         {
  121.             // real networks hack
  122.             // try strip junk like streamid=0
  123.             string::size_type pos = name.find( "/streamid", string::npos );
  124.             if( pos != string::npos )
  125.             {
  126.                 name=name.substr( 0, pos );
  127.                 cpLog( LOG_DEBUG, "Stripped name: %s", name.c_str());
  128.             }
  129.             else
  130.             {
  131.                 cpLog( LOG_DEBUG, "Setting file extension to default value" );
  132.                 myFileExtension = (RtspFileHandler::eExtension)
  133.                     ( RtspConfiguration::instance().defaultFileExtension );
  134.                 break;
  135.             }
  136.         }
  137.         else
  138.         {
  139.             break;
  140.         }
  141.     }
  142.     switch( myFileExtension )
  143.     {
  144.         case AU_EXT:
  145.         {
  146.             cpLog( LOG_DEBUG, "Opening %s as *.au", name.c_str() );
  147.             m_xRtspFile = new RtspFileAu( name );
  148.             assert( m_xRtspFile );
  149.             break;
  150.         }
  151.         case WAV_EXT:
  152.         {
  153.             cpLog( LOG_DEBUG, "Opening %s as *.wav", name.c_str() );
  154.             m_xRtspFile = new RtspFileWav( name );
  155.             assert( m_xRtspFile );
  156.             break;
  157.         }
  158.         case RAW_EXT:
  159.         {
  160.             cpLog( LOG_DEBUG, "Opening %s as *.raw", name.c_str() );
  161.             m_xRtspFile = new RtspFileRaw( name );
  162.             assert( m_xRtspFile );
  163.             break;
  164.         }
  165.         case RTP_EXT:
  166.         {
  167.             cpLog( LOG_DEBUG, "Opening %s as *.rtp", name.c_str() );
  168.             m_xRtspFile = new RtspFileRtp( name );
  169.             assert( m_xRtspFile );
  170.             break;
  171.         }
  172.         default:
  173.             assert( 0 );
  174.     }
  175. }
  176. RtspFileHandler::~RtspFileHandler()
  177. {
  178. }
  179. bool
  180. RtspFileHandler::writeAudioHeader( const Data& sdp )
  181. {
  182.     // build sdp object
  183.     myRtspSdp.decode( sdp );
  184.     if( !myRtspSdp.isValid() )
  185.     {
  186.         cpLog( LOG_ERR, "Sdp block is invalid" );
  187.         return false;
  188.     }
  189.     // read codec number
  190.     int codec = myRtspSdp.getMediaFormatList()->front();
  191.     // read codec string
  192.     string codecString = "UNKNOWN";
  193.     SdpRtpMapAttribute* rtpMapAttribute = 0;
  194.     vector<SdpRtpMapAttribute*>* rtpMapList = myRtspSdp.getRtpmapList();
  195.     if( rtpMapList == 0 )
  196.     {
  197.         if( RtspConfiguration::instance().rtpMapRequired )
  198.         {
  199.             cpLog( LOG_ERR, "RtpMap not found" );
  200.             return false;
  201.         }
  202.         else
  203.         {
  204.             cpLog( LOG_DEBUG, "Assuming rtp map values" );
  205.         }
  206.     }
  207.     else
  208.     {
  209.         rtpMapAttribute = rtpMapList->front();
  210.         assert( rtpMapAttribute );
  211.         if( codec != rtpMapAttribute->getPayloadType() ||
  212.             8000 != rtpMapAttribute->getClockRate() )
  213.         {
  214.             cpLog( LOG_ERR, "Sdp data is incorrect in codec(%d/%d) or clock rate(%d)",
  215.                    codec, rtpMapAttribute->getPayloadType(),
  216.                    rtpMapAttribute->getClockRate() );
  217.             return false;
  218.         }
  219.         codecString = rtpMapAttribute->getEncodingName();
  220.     }
  221.     // reindex myFtIndex with codec name from sdp
  222.     // find exact name matchin first if possible
  223.     bool supported = false;
  224.     for( int i = 0; i< myNumberOfCodecs; i++ )
  225.     {
  226.         if( rtpFileTypeInfo[i].payloadType == codec &&
  227.             rtpFileTypeInfo[i].name == codecString )
  228.         {
  229.             myFtIndex = i;
  230.             supported = true;
  231.             break;
  232.         }
  233.     }
  234.     // do first codec matching if no name can be matched
  235.     if( !supported && !RtspConfiguration::instance().rtpMapRequired )
  236.     {
  237.         for( int i = 0; i< myNumberOfCodecs; i++ )
  238.         {
  239.             if( rtpFileTypeInfo[i].payloadType == codec )
  240.             {
  241.                 myFtIndex = i;
  242.                 supported = true;
  243.                 break;
  244.             }
  245.         }
  246.     }
  247.     if( !supported )
  248.     {
  249.         cpLog( LOG_DEBUG, "Codec %d/%s not found in RtpFileTypeInfo map",
  250.                codec, codecString.c_str() );
  251.         return false;
  252.     }
  253.     // add rtpmap if none was set
  254.     if( rtpMapAttribute == 0 )
  255.     {
  256.         codecString = rtpFileTypeInfo[myFtIndex].name;
  257.         myRtspSdp.addRtpmap( codec, codecString.c_str(), 8000 );
  258.         vector<SdpRtpMapAttribute*>* rtpMapList = myRtspSdp.getRtpmapList();
  259.         assert( rtpMapList);
  260.         rtpMapAttribute = rtpMapList->front();
  261.     }
  262.     cpLog( LOG_DEBUG, "Codec %d/%s index as %d",
  263.            codec, codecString.c_str(), myFtIndex );
  264. #ifdef SDP_FILE
  265.     if( !m_xRtspFile->writeSdpFile( myRtspSdp ) )
  266.     {
  267.         cpLog( LOG_ERR, "Error in writeSdpFile()" );
  268.         return false;
  269.     }
  270. #ifndef REAL_AUDIO
  271.     Data controlData = "a=control:rtsp://";
  272.     controlData += filenameUrl();
  273.     controlData += "rn";
  274.     m_xRtspFile->deleteLineSdpFile( "a=control:" );
  275.     m_xRtspFile->appendSdpFile( controlData.getData(), controlData.length() );
  276. #endif
  277. #endif
  278.     // create audio file with audio header
  279.     cpLog( LOG_DEBUG, "Saving new audio file header" );
  280.     if( !m_xRtspFile->saveHeader( myFtIndex, myRtspSdp ) )
  281.     {
  282.         cpLog( LOG_DEBUG, "Failed to write audio file header" );
  283.         return false;
  284.     }
  285.     return true;
  286. }
  287. bool RtspFileHandler::loadAudioHeader()
  288. {
  289.     cpLog( LOG_DEBUG, "Generating sdp for audio file %s",
  290.            m_xRtspFile->filename().getData() );
  291. #ifdef SDP_FILE
  292.     if( m_xRtspFile->readSdpFile( myRtspSdp ) )
  293.     {
  294.         // read codec number
  295.         vector<int>* formatList = myRtspSdp.getMediaFormatList();
  296.         if( !formatList )
  297.         {
  298.             return false;
  299.         }
  300.         int codec = formatList->front();
  301.         // read codec string
  302.         SdpRtpMapAttribute* rtpMapAttribute =
  303.                             myRtspSdp.getRtpmapList()->front();
  304.         if( codec != rtpMapAttribute->getPayloadType() ||
  305.             8000 != rtpMapAttribute->getClockRate() )
  306.         {
  307.             cpLog( LOG_ERR, "Sdp data is incorrect in codec or clock rate" );
  308.             return false;
  309.         }
  310.         string codecString = rtpMapAttribute->getEncodingName();
  311.         
  312.         // reindex myFtIndex with codec name from sdp
  313.         // find exact name matchin first if possible
  314.         bool supported = false;
  315.         for( int i = 0; i< myNumberOfCodecs; i++ )
  316.         {
  317.             if( rtpFileTypeInfo[i].payloadType == codec &&
  318.                 rtpFileTypeInfo[i].name == codecString )
  319.             {
  320.                 myFtIndex = i;
  321.                 supported = true;
  322.                 break;
  323.             }
  324.         }
  325.         // do first codec matching if no name can be matched
  326.         if( !supported && !RtspConfiguration::instance().rtpMapRequired )
  327.         {
  328.             for( int i = 0; i< myNumberOfCodecs; i++ )
  329.             {
  330.                 if( rtpFileTypeInfo[i].payloadType == codec )
  331.                 {
  332.                     myFtIndex = i;
  333.                     supported = true;
  334.                     break;
  335.                 }
  336.             }
  337.         }
  338.         if( !supported )
  339.         {
  340.             cpLog( LOG_DEBUG, "Codec %d/%s not found in RtpFileTypeInfo map",
  341.                    codec, codecString.c_str() );
  342.             return false;
  343.         }
  344.         cpLog( LOG_DEBUG, "Codec %d/%s index as %d",
  345.            codec, codecString.c_str(), myFtIndex );
  346.         //TODO update myLength from "a=range:ntp=0.0-10.0"
  347.         return true;
  348.     }
  349. #endif
  350.     // read information from audio file
  351.     if( !m_xRtspFile->loadHeader( &myFtIndex, &myLength ) )
  352.     {
  353.         cpLog( LOG_ERR, "Fail to load header info from audio file" );
  354.         return false;
  355.     }
  356.     cpLog( LOG_DEBUG, "Sdp was created from audio header" );
  357.     // build sdp block
  358.     int codec = rtpFileTypeInfo[myFtIndex].payloadType;
  359.     myRtspSdp.setSessionName( RtspConfiguration::instance().serverName );
  360.     myRtspSdp.setMediaPort( 0 );
  361.     myRtspSdp.addMediaFormat( codec );
  362.     myRtspSdp.addRtpmap( codec,
  363.                          rtpFileTypeInfo[myFtIndex].name, 8000 ); 
  364. #ifndef REAL_AUDIO
  365.     Data controlData = "rtsp://";
  366.     controlData += filenameUrl();
  367.     myRtspSdp.addMediaAttribute( "control", controlData.getData() );
  368. #endif
  369.     char rangeBuffer[20];
  370.     float nptEnd = myLength / 1000.0;
  371.     sprintf( rangeBuffer, "npt=0.0-%.3f", nptEnd ); 
  372.     myRtspSdp.addMediaAttribute( "range", rangeBuffer );
  373.     return true;
  374. }
  375. RtspSdp&
  376. RtspFileHandler::readAudioHeader()
  377. {
  378.     if( myFtIndex == 0 )
  379.     {
  380.         cpLog( LOG_ERR, "myFtIndex was unset" );
  381.         assert(0);
  382.     }
  383.     return myRtspSdp;
  384. }
  385. bool
  386. RtspFileHandler::openAudioFile( bool mode, int packetSize )
  387. {
  388.     myReadWrite = mode;
  389.     if( myFtIndex == 0 || myLength == 0 )
  390.     {
  391.         /* why did mera want this?
  392.         if( !loadAudioHeader() )
  393.         {
  394.             cpLog( LOG_ERR, "Fail to load header info from audio header" );
  395.             return false;
  396.         }
  397.         */
  398.         if( !m_xRtspFile->loadHeader( &myFtIndex, &myLength) )
  399.         {
  400.             cpLog( LOG_ERR, "Fail to load header info from audio file" );
  401.             return false;
  402.         }
  403.     }
  404.     // open audio file
  405.     if( !myReadWrite ) //read mode
  406.     {
  407.         cpLog( LOG_DEBUG, "Opening %s for reading",
  408.                m_xRtspFile->filename().getData() );
  409.         // check file is unlocked
  410.         if( RtspConfiguration::instance().lockRecordingFiles )
  411.         {
  412.             if( RtspFileManager::instance().find(
  413.                 m_xRtspFile->filename().getData() ) )
  414.             {
  415.                 cpLog( LOG_ERR, "File is locked" );
  416.                 return false;
  417.             }
  418.         }
  419.         // open audio file
  420.         if( !m_xRtspFile->open( myReadWrite, myFtIndex ) )
  421.         {
  422.             cpLog( LOG_ERR, "open for read %s - failed",
  423.                    m_xRtspFile->filename().getData() );
  424.             return false;
  425.         }
  426.     }
  427.     else  //write mode
  428.     {
  429.         cpLog( LOG_DEBUG, "Opening %s for writing",
  430.                m_xRtspFile->filename().getData() );;
  431.         // lock audio file
  432.         if( RtspConfiguration::instance().lockRecordingFiles )
  433.         {
  434.             if( !RtspFileManager::instance().add(
  435.                 m_xRtspFile->filename().getData() ) )
  436.             {
  437.                 cpLog( LOG_ERR, "File already locked" );
  438.                 return false;
  439.             }
  440.         }
  441.         // open audio file
  442.         if( !m_xRtspFile->open( myReadWrite, myFtIndex ) )
  443.         {
  444.             cpLog( LOG_ERR, "Opening %s for writing - failed",
  445.                    m_xRtspFile->filename().getData() );
  446.             return false;
  447.         }
  448.     }
  449.     
  450.     // set private data members for rtp processor
  451.     myCodec = rtpFileTypeInfo[myFtIndex].payloadType;
  452.     if( packetSize <= 0 )
  453.     {
  454.         packetSize = rtpFileTypeInfo[myFtIndex].packetSize;
  455.     }
  456.     else
  457.     {
  458.         // reindex myFtIndex with desired packet size
  459.         while( ( myFtIndex < myNumberOfCodecs ) &&
  460.                ( rtpFileTypeInfo[myFtIndex].payloadType == myCodec ) &&
  461.                ( rtpFileTypeInfo[myFtIndex].packetSize != packetSize ) )
  462.         {
  463.             myFtIndex++;
  464.         }
  465.         if( ( rtpFileTypeInfo[myFtIndex].packetSize != packetSize ) ||
  466.             ( rtpFileTypeInfo[myFtIndex].payloadType != myCodec ) )
  467.         {
  468.             cpLog( LOG_ERR, "Codec %d doesn't support packetSize %d",
  469.                    myCodec, packetSize );
  470.         }
  471.     }
  472.     myPacketInterval = rtpFileTypeInfo[myFtIndex].intervalMs;
  473.     myPacketSize = rtpFileTypeInfo[myFtIndex].packetSize;
  474.     cpLog( LOG_DEBUG, "Setting packetSize to %d for %d ms interval",
  475.            myPacketSize, myPacketInterval );
  476.     //seek to beginning
  477.     if( m_xRtspFile->seek( 0, SEEK_SET ) < 0 )
  478.     {
  479.         cpLog( LOG_ERR, "Fail to seek to beginning of file" );
  480.     }
  481.     return true;
  482. }
  483. bool
  484. RtspFileHandler::closeAudioFile()
  485. {
  486.     cpLog( LOG_DEBUG, "Closing audio file %s",
  487.            m_xRtspFile->filename().getData() );
  488.     m_xRtspFile->close();
  489.     if( myReadWrite )  // recording mode
  490.     {
  491.         // unlock audio file
  492.         if( RtspConfiguration::instance().lockRecordingFiles )
  493.         {
  494.             if( !RtspFileManager::instance().del(
  495.                 m_xRtspFile->filename().getData() ) )
  496.             {
  497.                 cpLog( LOG_ERR, "File was not locked" );
  498.             }
  499.         }
  500.     }
  501.     return true;
  502. }
  503. int
  504. RtspFileHandler::read( void* data, size_t max,
  505.                        unsigned short* pSeqNum, unsigned int* pTS )
  506. {
  507.     if( myPacketSize > (int)max )
  508.     {
  509.         cpLog( LOG_DEBUG,
  510.                "Read buffer(%d) not large enough for given codec(%d) and packet size (%d)",
  511.                max, myCodec, myPacketSize );
  512.         return -1;
  513.     }
  514.     int cc = m_xRtspFile->read( data, myPacketSize, pSeqNum, pTS );
  515. #ifdef INFINITE_READ
  516.     if( cc < myPacketSize )
  517.     {
  518.         cpLog( LOG_DEBUG_HB, "Infinite read hack" );
  519.         m_xRtspFile->seek( 0, SEEK_SET );
  520.         cc = m_xRtspFile->read( data, myPacketSize, pSeqNum, pTS );
  521.         if( cc < myPacketSize )
  522.         {
  523.             cpLog( LOG_ERR, "Infinite read hack didn't work" );
  524.             assert(0);
  525.             return -1;
  526.         }
  527.     }
  528. #endif
  529.     if( cpLogGetPriority() >= LOG_DEBUG_HB )
  530.     {
  531.         cerr<<"r";
  532.     }
  533.     return cc;
  534. }
  535. int RtspFileHandler::write( void* data, size_t max,
  536.                             unsigned short uSeqNum, unsigned int uTS )
  537. {
  538. #ifdef DUMB_WRITE
  539.     int cc = max;
  540. #else
  541.     int cc = m_xRtspFile->write( data, max, uSeqNum, uTS );
  542. #endif
  543.     
  544.     if( cpLogGetPriority() >= LOG_DEBUG_HB )
  545.     {
  546.         cerr<<"w";
  547.     }
  548.     return cc;
  549. }
  550. long RtspFileHandler::seek( long npt )
  551. {
  552.     //long samples = (int)( (float)npt * rtpFileTypeInfo[myFtIndex].sizePerMs 
  553.     //               / (float)rtpFileTypeInfo[myFtIndex].blockSize );
  554.     long samples = npt / rtpFileTypeInfo[myFtIndex].intervalMs;
  555.     long result = m_xRtspFile->seek( samples, SEEK_SET );
  556.     cpLog( LOG_DEBUG, "Seeking to %dms result in %dms", npt, result );
  557.     return result;
  558. }
  559. Data 
  560. RtspFileHandler::filename() const
  561. {
  562.     return m_xRtspFile->filename();
  563. }
  564. Data
  565. RtspFileHandler::filenameUrl() const
  566. {
  567.     Data result = myContentBase;
  568.     result += m_xRtspFile->filename();
  569.     return result;
  570. }
  571. /* Local Variables: */
  572. /* c-file-style: "stroustrup" */
  573. /* indent-tabs-mode: nil */
  574. /* c-file-offsets: ((access-label . -) (inclass . ++)) */
  575. /* c-basic-offset: 4 */
  576. /* End: */