<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Hi all<div class=""><br class=""></div><div class="">Based on the FAQ for live input, I wrote my own subclasses for FramedSource and OnDemandServerMediaSubsession to implement a unicast server that can stream a live input. My live input source is a H264 encoded frame grab of my desktop using the Nvidia GRID SDK (which internally uses Nvenc.) </div><div class=""><br class=""></div><div class="">Before passing the frames to live555 I also removed the start codes in every frame and created a queue of NAL units. The first frame of every stream contains 3 NALs. And a single NAL in every subsequent frame. An example of the output:</div><div class=""><div class=""><br class=""></div><div class="">Start code found in frame 1</div><div class="">NAL size: 24</div><div class="">67 42 C0 0D 95 A0 D3 F9 67 C0 52 83 02 03 20 00 00 7D 00 00 1D 4C 10 80</div><div class=""><br class=""></div><div class="">Start code found in frame 1</div><div class="">NAL size: 4</div><div class="">68 CE 3C 80</div><div class=""><br class=""></div><div class="">Start code found in frame 1</div><div class="">NAL size: 3228</div><div class="">65 B8 04 7F C4 44 D4 08 00 0C 07 8A 00 02 01 D3 58 0E 93 93 00 2D 11 F3 D9 04 BA</div><div class=""> 48 99 6A 65 D3 81 79 07 92 B2 95 81 1D BD CF E4 70 86 7E F1 41 B9 35 76 9C 28 2</div><div class="">A E6 3D 30 6A 2E C0 99 91 99 2F 22 3E FF 19 54 3B 13 4C C0 38 15 7F F2 7E FB CD</div><div class="">… //a lot of data, removed for readability</div><div class="">5B 5B 5B 5B 5F 6B FF FF C1 54 20 04 E7 38 40 25 29 41 C0 04 00 43 3C 1C 00 40 08</div><div class=""> 67 </div><div class=""><br class=""></div><div class="">Start code found in frame 2 // Note: second frame here</div><div class="">NAL size: 1820</div><div class="">61 E0 20 BF C6 C1 23 80 78 54 98 07 2C C0 09 50 7A A4 C0 72 CA 91 8F 2D E5 00 4E</div><div class=""> 82 01 04 03 A1 8B 24 A2 9C B5 F1 98 E0 3E 08 0C 0A 85 00 CF 12 05 E3 B1 36 82 F0</div><div class=""> … //a lot of data, removed for readability</div><div class=""> CC 65 72 DF FF D8 83 F3 A6 53 3F C4 2E 21 71 0B 88 5C 42 E2 17 10 BF 70 1C 43 2</div><div class="">A 4B 03 88 65 49 6F</div><div class=""><br class=""></div></div><div class="">//Third frame.. and so forth</div><div class=""><br class=""></div><div class="">Upon playing the RTSP stream using VLC my output is blank. VLC is receiving data because the seconds clock in VLC starts ticking as soon as the stream is played but the output is completely blank. I tried a lot of combinations in sending the data including the start codes, sending individual/multiple NALs per frame, but nothing is working. I was not sure if my data was correct, so I wrote it to a file (with start codes) and the file played back successfully. I even streamed the file using the “testOnDemandRTSPServer” test program and that worked too. There is definitely something that isn’t right and I’m not able to figure it out. Would appreciate if somebody could point me in the right direction. I am including some of my source code below for reference.</div><div class=""><br class=""></div><div class="">Thanks,</div><div class="">Shubham</div><div class=""><br class=""></div><div class=""><b class="">——testOnDemandRTSPServer.cpp—— </b></div><div class=""><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; color: rgb(0, 143, 0);" class=""><span style="color: #000000" class=""> </span>//Live h264 based GRID stream</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; color: rgb(0, 143, 0);" class="">//Note: This is only a part of the file, not the entire file</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> <span style="color: #0433ff" class="">char</span> <span style="color: #0433ff" class="">const</span>* streamName = <span style="color: #b4261a" class="">"grid"</span>;</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> ServerMediaSession* sms</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> = ServerMediaSession::createNew(*env, streamName, streamName,</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span class="Apple-tab-span" style="white-space:pre"> </span> descriptionString);</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> sms->addSubsession(GridServerMediaSubsession::createNew(*env, reuseFirstSource));</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> rtspServer->addServerMediaSession(sms);</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> announceStream(rtspServer, sms, streamName, <span style="color: #b4261a" class="">"no file"</span>);</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> }</div></div><div class=""><b class="">——testOnDemandRTSPServer.cpp—— </b></div><div class=""><br class=""></div><div class=""><b class="">——GridServerMediaSubsession.cpp——</b></div><div class=""><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; color: rgb(180, 38, 26);" class=""><span style="color: #0433ff" class="">#include</span><span style="color: #000000" class=""> </span>"GridServerMediaSubsession.hh"</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; color: rgb(180, 38, 26);" class=""><span style="color: #0433ff" class="">#include</span><span style="color: #000000" class=""> </span>"H264VideoRTPSink.hh"</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; color: rgb(180, 38, 26);" class=""><span style="color: #0433ff" class="">#include</span><span style="color: #000000" class=""> </span>"GridSource.hh"</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; color: rgb(180, 38, 26);" class=""><span style="color: #0433ff" class="">#include</span><span style="color: #000000" class=""> </span>"H264VideoStreamDiscreteFramer.hh"</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">GridServerMediaSubsession*</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">GridServerMediaSubsession::createNew(UsageEnvironment& env,</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span class="Apple-tab-span" style="white-space:pre"> </span> Boolean reuseFirstSource) {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> <span style="color: #0433ff" class="">return</span> <span style="color: #0433ff" class="">new</span> GridServerMediaSubsession(env, reuseFirstSource);</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">}</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">GridServerMediaSubsession::GridServerMediaSubsession(UsageEnvironment& env, Boolean reuseFirstSource)</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> : OnDemandServerMediaSubsession(env, reuseFirstSource) {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">}</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">GridServerMediaSubsession::~GridServerMediaSubsession() {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">}</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">FramedSource* GridServerMediaSubsession::createNewStreamSource(<span style="color: #0433ff" class="">unsigned</span> <span style="color: #008f00" class="">/*clientSessionId*/</span>, <span style="color: #0433ff" class="">unsigned</span>& estBitrate) {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> estBitrate = 700; <span style="color: #008f00" class="">// kbps, estimate</span></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; color: rgb(0, 143, 0);" class=""><span style="color: #000000" class=""> </span>// Create the video source:</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> GridSource* liveSource = GridSource::createNew(envir());</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; color: rgb(0, 143, 0);" class=""><span style="color: #000000" class=""> </span>// Create a framer for the Video Elementary Stream:</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> <span style="color: #0433ff" class="">return</span> H264VideoStreamDiscreteFramer::createNew(envir(), liveSource);</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">}</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">RTPSink* GridServerMediaSubsession</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">::createNewRTPSink(Groupsock* rtpGroupsock,</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span class="Apple-tab-span" style="white-space:pre"> </span> <span style="color: #0433ff" class="">unsigned</span> <span style="color: #0433ff" class="">char</span> rtpPayloadTypeIfDynamic,</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span class="Apple-tab-span" style="white-space:pre"> </span> FramedSource* <span style="color: #008f00" class="">/*inputSource*/</span>) {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> <span style="color: #0433ff" class="">return</span> H264VideoRTPSink::createNew(envir(), rtpGroupsock, rtpPayloadTypeIfDynamic);</div></div><div class=""><b class="">——GridServerMediaSubsession.cpp——</b></div><div class=""><br class=""></div><div class=""><b class="">—— GridSource.cpp ——</b></div><div class=""><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">GridSource*</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">GridSource::createNew(UsageEnvironment& env) {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span class="Apple-tab-span" style="white-space:pre"> </span>AppArguments args; <span style="color: rgb(0, 143, 0);" class="">//for input configuration</span></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span style="color: rgb(0, 143, 0);" class=""><span class="Apple-tab-span" style="white-space:pre"> </span>//some code removed for readability</span></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> <span style="color: #0433ff" class="">return</span> <span style="color: #0433ff" class="">new</span> GridSource(env, args);</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">}</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">EventTriggerId GridSource::eventTriggerId = 0;</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span style="color: #0433ff" class="">unsigned</span> GridSource::referenceCount = 0;</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span style="color: #0433ff" class="">unsigned</span> GridSource::frameCount = 0;</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">GridSource::GridSource(UsageEnvironment& env,</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span class="Apple-tab-span" style="white-space:pre"> </span> AppArguments args)</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> : FramedSource(env), fargs(args) {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> <span style="color: #0433ff" class="">if</span> (referenceCount == 0) {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> <span style="color: rgb(0, 143, 0);" class="">//encoder is initialised here. Some code removed for readability </span></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span style="color: rgb(0, 143, 0);" class=""> </span>}</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> ++referenceCount;</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> <span style="color: #0433ff" class="">if</span> (eventTriggerId == 0) {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> eventTriggerId = envir().taskScheduler().createEventTrigger(deliverFrame0);</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> }</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">}</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">GridSource::~GridSource() {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> --referenceCount;</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> <span style="color: #0433ff" class="">if</span> (referenceCount == 0) {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span class="Apple-tab-span" style="white-space:pre"> </span><span style="color: #0433ff" class="">if</span> (encoder)</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> encoder->NvFBCH264Release();</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> }</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; color: rgb(0, 143, 0);" class=""><span style="color: #000000" class=""> </span>// Reclaim our 'event trigger'</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> envir().taskScheduler().deleteEventTrigger(eventTriggerId);</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> eventTriggerId = 0;</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> }</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">}</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span style="color: #0433ff" class="">void</span> GridSource::doGetNextFrame() {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><br class=""></div><div style="margin: 0px;" class=""><span class="Apple-tab-span" style="font-family: Consolas; font-size: 9.5px; white-space: pre;"> </span><font color="#008f00" face="Consolas" class=""><span style="font-size: 9.5px;" class="">//Note: next frame is read only after previous frame</span></font><font color="#008f00" face="Consolas" size="1" class="">’</font><font color="#008f00" face="Consolas" class=""><span style="font-size: 9.5px;" class="">s NALs have been delivered.</span></font></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span class="Apple-tab-span" style="white-space:pre"> </span><span style="color: #0433ff" class="">if</span>(nalQ.isEmpty()){</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span class="Apple-tab-span" style="white-space:pre"> </span> frameCount++;</div><div style="margin: 0px;" class=""><span style="font-family: Consolas; font-size: 9.5px;" class=""><span class="Apple-tab-span" style="white-space:pre"> </span> populateQ(); </span><font color="#008f00" face="Consolas" class=""><span style="font-size: 9.5px;" class="">//load the NALs for each frame. NALs </span></font><font color="#008f00" face="Consolas" size="1" class="">stored</font><font color="#008f00" face="Consolas" class=""><span style="font-size: 9.5px;" class=""> in nalQ</span></font></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span class="Apple-tab-span" style="white-space:pre"> </span>deliverFrame();</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">}</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span style="color: #0433ff" class="">void</span> GridSource::deliverFrame0(<span style="color: #0433ff" class="">void</span>* clientData) {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> ((GridSource*)clientData)->deliverFrame();</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">}</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span style="color: #0433ff" class="">void</span> GridSource::populateQ(){</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span style="color: rgb(0, 143, 0);" class="">//frame is grabbed by the GRID SDK</span></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span style="color: rgb(0, 143, 0);" class="">//NALs for every frame are pushed to nalQ</span></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span style="color: rgb(0, 143, 0);" class="">//Some code removed for readability</span></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span style="color: rgb(0, 143, 0);" class=""><br class=""></span></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">while(<font color="#008f00" class="">/*frame data is available in frame buffer*/</font>){</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> if(<span style="color: rgb(0, 143, 0);" class="">/*star code found in frame buffer*/</span>)</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span style="color: rgb(0, 143, 0);" class=""><span class="Apple-tab-span" style="white-space:pre"> </span></span><span style="font-size: 9.5px;" class="">nalQ.pushNAL(outputPtr,byteSize); </span><span style="color: rgb(0, 143, 0);" class="">//data until next start code or until end of buffer - Note: data excludes start codes</span></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> }</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><div class=""><br class=""></div></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">}</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""><span style="color: #0433ff" class="">void</span> GridSource::deliverFrame() {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; color: rgb(0, 143, 0);" class=""><span style="color: #000000" class=""> </span><span style="color: #0433ff" class="">if</span><span style="color: #000000" class=""> (!isCurrentlyAwaitingData()) </span><span style="color: #0433ff" class="">return</span><span style="color: #000000" class="">; </span>// we're not ready for the data yet</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> NAL* nal = nalQ.popNAL();</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> nal->print();</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; color: rgb(0, 143, 0);" class=""><span style="color: #000000" class=""> </span>// Deliver the data here:</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> <span style="color: #0433ff" class="">if</span> (nal->getSize() > fMaxSize) {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> fFrameSize = fMaxSize;</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> fNumTruncatedBytes = nal->getSize() - fMaxSize;</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> } <span style="color: #0433ff" class="">else</span> {</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> fFrameSize = nal->getSize();</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> }</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; color: rgb(0, 143, 0);" class=""><span style="color: #000000" class=""> gettimeofday(&fPresentationTime, NULL); </span></div><p style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""> </p><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> fDurationInMicroseconds = 1000000/30; <span style="color: rgb(0, 143, 0);" class="">//30 fps</span></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> memmove(fTo, nal->getPayload(), fFrameSize);</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas; color: rgb(0, 143, 0);" class=""><span style="color: #000000" class=""> </span>// After delivering the data, inform the reader that it is now available:</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class=""> FramedSource::afterGetting(<span style="color: #0433ff" class="">this</span>);</div><div style="margin: 0px; font-size: 9.5px; font-family: Consolas;" class="">}</div></div><div class=""><br class=""></div><div class=""><b class="">——GridSource.cpp—— </b></div><div class=""><br class=""></div></body></html>