首页 > 代码库 > live555 播放视频 play 不能推送rtp数据

live555 播放视频 play 不能推送rtp数据

      在项目开发过程中遇到一个问题,play之后,不能推送rtp数据包,跟踪代码调试发现,在获取H264视频数据,封包,发送,这条循环的链断开了,导致该问题的原因是:

在H264VideoStreamFramer.cpp中


unsigned H264VideoStreamParser::parse()
{
#if DEBUG_SHOWCHN
    printf("Parser() chn:%d\n", fchn);
#endif
    
    try{
        // The stream must start with a 0x00000001:
        if (!fHaveSeenFirstStartCode) 
        {
            // Skip over any input bytes that precede the first 0x00000001:
            u_int32_t first4Bytes;
            while ((first4Bytes = test4Bytes()) != 0x00000001) 
            {
            get1Byte(); setParseState(); // ensures that we progress over bad data
            
            }
            skipBytes(4); // skip this initial code

            setParseState();
            fHaveSeenFirstStartCode = True; // from now on
        }

        if (fOutputStartCodeSize > 0 && curFrameSize() == 0 && !haveSeenEOF())
        {
            // Include a start code in the output:
            save4Bytes(0x00000001);
        }

        // Then save everything up until the next 0x00000001 (4 bytes) or 0x000001 (3 bytes), or we hit EOF.
        // Also make note of the first byte, because it contains the "nal_unit_type": 
        if (haveSeenEOF()) 
        {
            // We hit EOF the last time that we tried to parse this data, so we know that any remaining unparsed data
            // forms a complete NAL unit, and that there's no 'start code' at the end:
            unsigned remainingDataSize = totNumValidBytes() - curOffset();
#ifdef DEBUG
            unsigned const trailingNALUnitSize = remainingDataSize;
#endif
            while (remainingDataSize > 0)
            {
                u_int8_t nextByte = get1Byte();
                if (!fHaveSeenFirstByteOfNALUnit)
                {
                    fFirstByteOfNALUnit = nextByte;
                    fHaveSeenFirstByteOfNALUnit = True;
                }
                saveByte(nextByte);
                --remainingDataSize;
            }

#ifdef DEBUG
            u_int8_t nal_ref_idc = (fFirstByteOfNALUnit&0x60)>>5;
            u_int8_t nal_unit_type = fFirstByteOfNALUnit&0x1F;
            fprintf(stderr, "Parsed trailing %d-byte NAL-unit (nal_ref_idc: %d, nal_unit_type: %d (\"%s\"))\n",
            trailingNALUnitSize, nal_ref_idc, nal_unit_type, nal_unit_type_description[nal_unit_type]);
#endif

            (void)get1Byte(); // forces another read, which will cause EOF to get handled for real this time

            return 0;
        } 
        else
        {
            u_int32_t next4Bytes = test4Bytes();
            if (!fHaveSeenFirstByteOfNALUnit)
            {
                fFirstByteOfNALUnit = next4Bytes>>24;
                fHaveSeenFirstByteOfNALUnit = True;
            }

            ///////////////////////////////////////////////////////////////////////
            ///////////////////////////////////////////////////////////////////////
            //如果获取的H264数据不完整或错误 只有帧头 没有帧体curFrameSize()会等于0
            while (next4Bytes != 0x00000001 && (next4Bytes&0xFFFFFF00) != 0x00000100)
            {
                // We save at least some of "next4Bytes".
                if ((unsigned)(next4Bytes&0xFF) > 1) 
                {
                    // Common case: 0x00000001 or 0x000001 definitely doesn't begin anywhere in "next4Bytes", so we save all of it:
                    save4Bytes(next4Bytes);
                    skipBytes(4);
                } 
                else
                {
                    // Save the first byte, and continue testing the rest:
                    saveByte(next4Bytes>>24);
                    skipBytes(1);
                }
                setParseState(); // ensures forward progress
                next4Bytes = test4Bytes();
            }
 
            // Assert: next4Bytes starts with 0x00000001 or 0x000001, and we've saved all previous bytes (forming a complete NAL unit).
            // Skip over these remaining bytes, up until the start of the next NAL unit:
            if (next4Bytes == 0x00000001) 
            {
                skipBytes(4);
            } 
            else 
            {
                skipBytes(3);
            }
        }

        u_int8_t nal_ref_idc = (fFirstByteOfNALUnit&0x60)>>5;
        u_int8_t nal_unit_type = fFirstByteOfNALUnit&0x1F;
        fHaveSeenFirstByteOfNALUnit = False; // for the next NAL unit that we parse
#ifdef DEBUG
        fprintf(stderr, "Parsed %d-byte NAL-unit (nal_ref_idc: %d, nal_unit_type: %d (\"%s\"))\n",
        curFrameSize()-fOutputStartCodeSize, nal_ref_idc, nal_unit_type, nal_unit_type_description[nal_unit_type]);
#endif

        switch (nal_unit_type) 
        {
            case 6: 
            { 
                // Supplemental enhancement information (SEI)
                analyze_sei_data();
                // Later, perhaps adjust "fPresentationTime" if we saw a "pic_timing" SEI payload??? #####
                break;
            }
            case 7: 
            { 
                // Sequence parameter set
                // First, save a copy of this NAL unit, in case the downstream object wants to see it:
                usingSource()->saveCopyOfSPS(fStartOfFrame + fOutputStartCodeSize, fTo - fStartOfFrame - fOutputStartCodeSize);

                // Parse this NAL unit to check whether frame rate information is present:
                unsigned num_units_in_tick, time_scale, fixed_frame_rate_flag;
                analyze_seq_parameter_set_data(num_units_in_tick, time_scale, fixed_frame_rate_flag);
                if (time_scale > 0 && num_units_in_tick > 0) 
                {
                    usingSource()->fFrameRate = time_scale/(2.0*num_units_in_tick);
#ifdef DEBUG
                    fprintf(stderr, "Set frame rate to %f fps\n", usingSource()->fFrameRate);
                    if (fixed_frame_rate_flag == 0) 
                    {
                        fprintf(stderr, "\tWARNING: \"fixed_frame_rate_flag\" was not set\n");
                    }
#endif
                }
                else 
                {
#ifdef DEBUG
                    fprintf(stderr, "\tThis \"Sequence Parameter Set\" NAL unit contained no frame rate information, so we use a default frame rate of %f fps\n", usingSource()->fFrameRate);
#endif
                }
                break;
            }
            case 8: 
            { 
                // Picture parameter set
                // Save a copy of this NAL unit, in case the downstream object wants to see it:
                usingSource()->saveCopyOfPPS(fStartOfFrame + fOutputStartCodeSize, fTo - fStartOfFrame - fOutputStartCodeSize);
            }
        }

        usingSource()->setPresentationTime();
#ifdef DEBUG
        unsigned long secs = (unsigned long)usingSource()->fPresentationTime.tv_sec;
        unsigned uSecs = (unsigned)usingSource()->fPresentationTime.tv_usec;
        //fprintf(stderr, "\tPresentation time: %lu.%06u\n", secs, uSecs);
#endif

        // We check whether this NAL unit ends an 'access unit'.
        // (RTP streamers need to know this in order to figure out whether or not to set the "M" bit.)
        Boolean thisNALUnitEndsAccessUnit;
        if (haveSeenEOF() || nal_unit_type == 11/*End of stream*/) 
        {
            // There is no next NAL unit, so we assume that this one ends the current 'access unit':
            thisNALUnitEndsAccessUnit = True;
        } 
        else if ((nal_unit_type >= 6 && nal_unit_type <= 9) || (nal_unit_type >= 14 && nal_unit_type <= 18)) 
        {
            // These NAL units usually *begin* an access unit, so we assume that they don't end one here:
            thisNALUnitEndsAccessUnit = False;
        } 
        else 
        {
            // We need to check the *next* NAL unit to figure out whether the current NAL unit ends an 'access unit':
            u_int8_t firstBytesOfNextNALUnit[2];
            testBytes(firstBytesOfNextNALUnit, 2);

            u_int8_t const& next_nal_unit_type = firstBytesOfNextNALUnit[0]&0x1F;
            Boolean const nextNALUnitIsVCL = next_nal_unit_type <= 5 && nal_unit_type > 0;
            if (nextNALUnitIsVCL)
            {
                // The high-order bit of the 2nd byte tells us whether this is the start of a new 'access unit':
                thisNALUnitEndsAccessUnit = (firstBytesOfNextNALUnit[1]&0x80) != 0;
            } 
            else if ((next_nal_unit_type >= 6 && next_nal_unit_type <= 9) || (next_nal_unit_type >= 14 && next_nal_unit_type <= 18))
            {
                // The next NAL unit's type is one that usually appears at the start of an 'access unit',
                // so we assume that the current NAL unit ends an 'access unit':
                thisNALUnitEndsAccessUnit = True;
            } 
            else 
            {
                // The next NAL unit definitely doesn't start a new 'access unit', which means that the current NAL unit doesn't end one:
                thisNALUnitEndsAccessUnit = False;
            }
        }

        if (thisNALUnitEndsAccessUnit)
        {
#ifdef DEBUG
            fprintf(stderr, "*****This NAL unit ends the current access unit*****\n");
#endif
            usingSource()->fPictureEndMarker = True;
            ++usingSource()->fPictureCount;

            // Note that the presentation time for the next NAL unit will be different:
            struct timeval& nextPT = usingSource()->fNextPresentationTime; // alias
            nextPT = usingSource()->fPresentationTime;
            double nextFraction = nextPT.tv_usec/1000000.0 + 1/usingSource()->fFrameRate;
            unsigned nextSecsIncrement = (long)nextFraction;
            nextPT.tv_sec += (long)nextSecsIncrement;
            nextPT.tv_usec = (long)((nextFraction - nextSecsIncrement)*1000000);
        }
        setParseState();

#if DEBUG_SHOWCHN
        printf("parse() return curFrameSize()=%d chn:%d\n", curFrameSize(), fchn);
#endif

        ///////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////
        //如果返回的curFrameSize()等于0, 获取视频 封包 发送 这个循环的过程就终止了
        //返回后使程序能循环转起来的回调函数调用不到了 所以增加如下代码        
        if (0 == curFrameSize())
        {   
#if DEBUG_SHOWCHN        
            printf("curFrameSize = 0 parse again chn:%d\n", fchn);
#endif
            
            fHaveSeenFirstStartCode = false;
            parse();
        }
        
        return curFrameSize();
    } 
    catch (int /*e*/) 
    {
#ifdef DEBUG
        //fprintf(stderr, "H264VideoStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n");
#endif
        return 0;  // the parsing got interrupted
    }
}


live555 播放视频 play 不能推送rtp数据