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
    }
}
时间: 2024-10-13 10:41:11

live555 播放视频 play 不能推送rtp数据的相关文章

socket.io-直播视频的消息推送

近日接到需求,需要在"直播后台监控系统"里监控直播间的消息.刚接到需求时一脸懵逼,好在队友给力,Google强大,需求已经上线.现将我完成需求的过程与查阅了解到的知识整理出来,仅供参考,若错误请指教~~ 一.什么是WebSocket WebSocket一种在单个TCP连接上进行全双工通讯的协议.WebSocket通信协议于2011年被IETF定为标准RFC 6455,并被RFC7936所补充规范,WebSocketAPI被W3C定为标准. WebSocket 是独立的.创建在 TCP

C# 数据推送 实时数据推送 轻量级消息订阅发布 多级消息推送 分布式推送

前言 本文将使用一个NuGet公开的组件技术来实现数据订阅推送功能,由服务器进行推送数据,客户端订阅指定的数据后,即可以接收服务器推送过来的数据,包含了自动重连功能,使用非常方便 nuget地址:https://www.nuget.org/packages/HslCommunication/            github地址:https://github.com/dathlin/HslCommunication                                 如果喜欢可以s

使用dwr3.0实现服务端向浏览器做消息推送,做滚动评论或弹幕效果,而且根据视频id做推送消息拦截功能

最近项目要实现视频播放时做弹幕和评论滚动,使用flash做sockt编程不会,就想到使用服务器消息推送做,翻找资料发现使用html5的websocket可以实现,但是ie8是不支持websocket的,最终确定使用dwr3做消息推送,普通的dwr3做消息推送会把消息推送到所有打开的页面,这样针对某一个视频的评论就会弹出到其他的视频中去,实现每个视频弹出各自的评论,就需要做dwr3的消息推送做过滤处理,经过一天的研究终于搞定了 贴出完整的代码demo 1 使用dwr3的web.xml的配置 <se

干货:如何实现RTSP推送H.264、RTSP推送H.265(hevc)

rtsp推送相关的资料和测试软件比较少,本文介绍rtsp推送相关信令和测试效果: 1. rtsp推送流程. 主要分两部分:第一部分先发送信令:第二部分发送rtp包. ?信令流程: ?1.1?先发送OPTIONS, OPTIONS比较常用,就不做详细说明了. 1.2 发送ANNOUNCE, 发送ANNOUNCE主要是把要推送的音视频信息通过sdp格式传给服务器.关于sdp信息如何构造,对于h264请参考rfc6184. h265请参考rfc7798. 下面举两个例子. h264+aac ANNOU

android 用signalr 实现推送服务

我做的app需要实现signalr 推送服务 有两种方法 一种人家已经给我们集成了还有视频教程 地址为 https://www.youtube.com/watch?v=f9ih_M7PC10  下载的程序在这 按照视频做,但是更新了我没成功完成 https://www.youtube.com/watch?v=f9ih_M7PC10 第二种自己集成 一共分两步 第一步我是在activity 里面实现接收服务器推送的数据 首先 google上面下载 java-client 地址 https://gi

Shuttle ESB实现局域网消息推送

ESB全称Enterprise Service Bus,即企业服务总线.它是传统中间件技术与XML.Web服务等技术结合的产物. ESB的出现改变了传统的软件架构,可以提供比传统中间件产品更为廉价的解决方案,同时它还可以消除不同应用之间的技术差异,让不同的应用服务器协调运作,实现了不同服务之间的通信与整合. 看吧,ESB的功能是如此强大.在java中常用的是Mule ESB,而到了.Net,Shuttle ESB作为一种新生的ESB正在慢慢的被人们所接受.下面通过一个实例讲解Shuttle ES

Webserver推送技术

server推送(Server Push) 推送技术的基础思想是将浏览器主动查询信息改为server主动发送信息.server发送一批数据,浏览器显示这些数据,同一时候保证与server的连接.当server须要再次发送一批数据时,浏览器显示数据并保持连接.以后,server仍然能够发送批量数据,浏览器继续显示数据,依次类推. client拉曳(Client Pull) 在client拖曳技术中,server发送一批数据,在HTTP响应或文档头标记中插入指令,让浏览器"在5秒内再次装入这些数据&

基于ajax与msmq技术的消息推送功能实现

周末在家捣鼓了一下消息推送的简单例子,其实也没什么技术含量,欢迎大伙拍砖.我设计的这个推送demo是基于ajax长轮询+msmq消息队列来实现的,具体交互过程如下图: 先说说这个ajax长轮询,多长时间才算长呢?这个还真不好界定.这里是相对普通ajax请求来说的,通常处理一个请求也就是毫秒级别的时间.但是这里的长轮询方式在ajax发送请求给服务器之后,服务器给调用端返回数据的时间多长那可还真不好说.嘿嘿,这关键要看我们啥时候往msmq队列中推送数据了,先看看推送的效果图吧..... 抱歉,没弄张

策略模式+简单工厂模式+单例模式:简单推送服务

一.功能: 实现  获取数据  —>根据用户订阅清单进行推送 —> 这里的推送方式:QQ.Email.App.插件等等 用户可多选推送方式. 二.实现 1.推送方式—枚举(位运算): [Flags] public enum PushType { QQ = 0, Email = 2 } 2.策略模式:抽象推送策略 public interface IPush { bool Push(object data); } 3.QQ推送+Email推送 QQ推送:单例模式—静态创建QQ推送服务,线程安全.