liveMedia/MPEG1or2VideoRTPSink.cpp

Go to the documentation of this file.
00001 /**********
00002 This library is free software; you can redistribute it and/or modify it under
00003 the terms of the GNU Lesser General Public License as published by the
00004 Free Software Foundation; either version 2.1 of the License, or (at your
00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
00006 
00007 This library is distributed in the hope that it will be useful, but WITHOUT
00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00009 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
00010 more details.
00011 
00012 You should have received a copy of the GNU Lesser General Public License
00013 along with this library; if not, write to the Free Software Foundation, Inc.,
00014 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 **********/
00016 // "liveMedia"
00017 // Copyright (c) 1996-2013 Live Networks, Inc.  All rights reserved.
00018 // RTP sink for MPEG video (RFC 2250)
00019 // Implementation
00020 
00021 #include "MPEG1or2VideoRTPSink.hh"
00022 #include "MPEG1or2VideoStreamFramer.hh"
00023 
00024 MPEG1or2VideoRTPSink::MPEG1or2VideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs)
00025   : VideoRTPSink(env, RTPgs, 32, 90000, "MPV") {
00026   fPictureState.temporal_reference = 0;
00027   fPictureState.picture_coding_type = fPictureState.vector_code_bits = 0;
00028 }
00029 
00030 MPEG1or2VideoRTPSink::~MPEG1or2VideoRTPSink() {
00031 }
00032 
00033 MPEG1or2VideoRTPSink*
00034 MPEG1or2VideoRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs) {
00035   return new MPEG1or2VideoRTPSink(env, RTPgs);
00036 }
00037 
00038 Boolean MPEG1or2VideoRTPSink::sourceIsCompatibleWithUs(MediaSource& source) {
00039   // Our source must be an appropriate framer:
00040   return source.isMPEG1or2VideoStreamFramer();
00041 }
00042 
00043 Boolean MPEG1or2VideoRTPSink::allowFragmentationAfterStart() const {
00044   return True;
00045 }
00046 
00047 Boolean MPEG1or2VideoRTPSink
00048 ::frameCanAppearAfterPacketStart(unsigned char const* frameStart,
00049                                  unsigned numBytesInFrame) const {
00050   // A 'frame' (which in this context can mean a header or a slice as well as a
00051   // complete picture) can appear at other than the first position in a packet
00052   // in all situations, EXCEPT when it follows the end of (i.e., the last slice
00053   // of) a picture.  I.e., the headers at the beginning of a picture must
00054   // appear at the start of a RTP packet.
00055   if (!fPreviousFrameWasSlice) return True;
00056 
00057   // A slice is already packed into this packet.  We allow this new 'frame'
00058   // to be packed after it, provided that it is also a slice:
00059   return numBytesInFrame >= 4
00060     && frameStart[0] == 0 && frameStart[1] == 0 && frameStart[2] == 1
00061     && frameStart[3] >= 1 && frameStart[3] <= 0xAF;
00062 }
00063 
00064 #define VIDEO_SEQUENCE_HEADER_START_CODE 0x000001B3
00065 #define PICTURE_START_CODE               0x00000100
00066 
00067 void MPEG1or2VideoRTPSink
00068 ::doSpecialFrameHandling(unsigned fragmentationOffset,
00069                          unsigned char* frameStart,
00070                          unsigned numBytesInFrame,
00071                          struct timeval framePresentationTime,
00072                          unsigned numRemainingBytes) {
00073   Boolean thisFrameIsASlice = False; // until we learn otherwise
00074   if (isFirstFrameInPacket()) {
00075     fSequenceHeaderPresent = fPacketBeginsSlice = fPacketEndsSlice = False;
00076   }
00077 
00078   if (fragmentationOffset == 0) {
00079     // Begin by inspecting the 4-byte code at the start of the frame:
00080     if (numBytesInFrame < 4) return; // shouldn't happen
00081     unsigned startCode = (frameStart[0]<<24) | (frameStart[1]<<16)
00082                        | (frameStart[2]<<8) | frameStart[3];
00083 
00084     if (startCode == VIDEO_SEQUENCE_HEADER_START_CODE) {
00085       // This is a video sequence header
00086       fSequenceHeaderPresent = True;
00087     } else if (startCode == PICTURE_START_CODE) {
00088       // This is a picture header
00089 
00090       // Record the parameters of this picture:
00091       if (numBytesInFrame < 8) return; // shouldn't happen
00092       unsigned next4Bytes = (frameStart[4]<<24) | (frameStart[5]<<16)
00093                           | (frameStart[6]<<8) | frameStart[7];
00094       unsigned char byte8 = numBytesInFrame == 8 ? 0 : frameStart[8];
00095 
00096       fPictureState.temporal_reference = (next4Bytes&0xFFC00000)>>(32-10);
00097       fPictureState.picture_coding_type = (next4Bytes&0x00380000)>>(32-(10+3));
00098 
00099       unsigned char FBV, BFC, FFV, FFC;
00100       FBV = BFC = FFV = FFC = 0;
00101       switch (fPictureState.picture_coding_type) {
00102       case 3:
00103         FBV = (byte8&0x40)>>6;
00104         BFC = (byte8&0x38)>>3;
00105         // fall through to:
00106       case 2:
00107         FFV = (next4Bytes&0x00000004)>>2;
00108         FFC = ((next4Bytes&0x00000003)<<1) | ((byte8&0x80)>>7);
00109       }
00110 
00111       fPictureState.vector_code_bits = (FBV<<7) | (BFC<<4) | (FFV<<3) | FFC;
00112     } else if ((startCode&0xFFFFFF00) == 0x00000100) {
00113       unsigned char lastCodeByte = startCode&0xFF;
00114 
00115       if (lastCodeByte <= 0xAF) {
00116         // This is (the start of) a slice
00117         thisFrameIsASlice = True;
00118       } else {
00119         // This is probably a GOP header; we don't do anything with this
00120       }
00121     } else {
00122       // The first 4 bytes aren't a code that we recognize.
00123       envir() << "Warning: MPEG1or2VideoRTPSink::doSpecialFrameHandling saw strange first 4 bytes "
00124               << (void*)startCode << ", but we're not a fragment\n";
00125     }
00126   } else {
00127     // We're a fragment (other than the first) of a slice.
00128     thisFrameIsASlice = True;
00129   }
00130 
00131   if (thisFrameIsASlice) {
00132     // This packet begins a slice iff there's no fragmentation offset:
00133     fPacketBeginsSlice = (fragmentationOffset == 0);
00134 
00135     // This packet also ends a slice iff there are no fragments remaining:
00136     fPacketEndsSlice = (numRemainingBytes == 0);
00137   }
00138 
00139   // Set the video-specific header based on the parameters that we've seen.
00140   // Note that this may get done more than once, if several frames appear
00141   // in the packet.  That's OK, because this situation happens infrequently,
00142   // and we want the video-specific header to reflect the most up-to-date
00143   // information (in particular, from a Picture Header) anyway.
00144   unsigned videoSpecificHeader =
00145     // T == 0
00146     (fPictureState.temporal_reference<<16) |
00147     // AN == N == 0
00148     (fSequenceHeaderPresent<<13) |
00149     (fPacketBeginsSlice<<12) |
00150     (fPacketEndsSlice<<11) |
00151     (fPictureState.picture_coding_type<<8) |
00152     fPictureState.vector_code_bits;
00153   setSpecialHeaderWord(videoSpecificHeader);
00154 
00155   // Also set the RTP timestamp.  (As above, we do this for each frame
00156   // in the packet.)
00157   setTimestamp(framePresentationTime);
00158 
00159   // Set the RTP 'M' (marker) bit iff this frame ends (i.e., is the last
00160   // slice of) a picture (and there are no fragments remaining).
00161   // This relies on the source being a "MPEG1or2VideoStreamFramer".
00162   MPEG1or2VideoStreamFramer* framerSource = (MPEG1or2VideoStreamFramer*)fSource;
00163   if (framerSource != NULL && framerSource->pictureEndMarker()
00164       && numRemainingBytes == 0) {
00165     setMarkerBit();
00166     framerSource->pictureEndMarker() = False;
00167   }
00168 
00169   fPreviousFrameWasSlice = thisFrameIsASlice;
00170 }
00171 
00172 unsigned MPEG1or2VideoRTPSink::specialHeaderSize() const {
00173   // There's a 4 byte special video header:
00174   return 4;
00175 }

Generated on Mon Apr 29 13:28:02 2013 for live by  doxygen 1.5.2