[Live-devel] bug found and corrected

roor0735-ml at yahoo.fr roor0735-ml at yahoo.fr
Fri Feb 1 04:15:29 PST 2008


Hi

I try to stream MPEG2 TS DVB-T channel using your library (through the MediaPortal TV Server project) and I have problem with some particular channels. 
In VLC, I get a lot of "PTS out of range" messages, the video is choppy and most of the time stops. I have tested with the mediaServer application distributed with the library and the same problem occurs, so I think the problem comes from incompatibility between the streaming server and the TS recordings.
I suspected that the problem comes from the way the PCR is broadcast inside the Transport stream. I have enabled the DEBUG_PCR in the MPEG2TransportStreamFramer.cpp file to check the evolution of time. As you can see, the packet duration estimation is not good and leads to a accumulate delays. I think the problem comes from the fact the PCR is not periodically announced in the Transport Stream. Sometimes, there is very few packets between two PCR announcements. In this case, the calculation made two estimate the packet duration (fTSPacketDurationEstimate) is not reliable. 
So I added a new test in MPEG2TransportStreamFramer::updateTSPacketDurationEstimate method in order to check there are enough packets between two packet duration estimation. With at least 20 packets, it seems the estimation converges to the right value and there is no more problem in VLC :)

That's the code and my log in attached file. 
It would be better to add a new define value for the minimum number of packets that must be processed before re-estimating the packet duration.

Thank you
Romain


void MPEG2TransportStreamFramer
::updateTSPacketDurationEstimate(unsigned char* pkt, double timeNow) {
  // Sanity check: Make sure we start with the sync byte:
  if (pkt[0] != TRANSPORT_SYNC_BYTE) {
    envir() << "Missing sync byte!\n";
    return;
  }

  ++fTSPacketCount;

  // If this packet doesn't  contain a PCR, then we're not interested in it:
  u_int8_t const adaptation_field_control = (pkt[3]&0x30)>>4;
  if (adaptation_field_control != 2 && adaptation_field_control != 3) return;
      // there's no adaptation_field

  u_int8_t const adaptation_field_length = pkt[4];
  if (adaptation_field_length == 0) return;

  u_int8_t const discontinuity_indicator = pkt[5]&0x80;
  u_int8_t const pcrFlag = pkt[5]&0x10;
  if (pcrFlag == 0) return; // no PCR

  // There's a PCR.  Get it, and the PID:
  u_int32_t pcrBaseHigh = (pkt[6]<<24)|(pkt[7]<<16)|(pkt[8]<<8)|pkt[9];
  double clock = pcrBaseHigh/45000.0;
  if ((pkt[10]&0x80) != 0) clock += 1/90000.0; // add in low-bit (if set)
  unsigned short pcrExt = ((pkt[10]&0x01)<<8) | pkt[11];
  clock += pcrExt/27000000.0;

   unsigned pid = ((pkt[1]&0x1F)<<8) | pkt[2];

  // Check whether we already have a record of a PCR for this PID:
  PIDStatus* pidStatus = (PIDStatus*)(fPIDStatusTable->Lookup((char*)pid));
  

  if (pidStatus == NULL) {
    // We're seeing this PID's PCR for the first time:
    pidStatus = new PIDStatus(clock, timeNow);
    fPIDStatusTable->Add((char*)pid, pidStatus);
#ifdef DEBUG_PCR
    fprintf(stderr, "PID 0x%x, FIRST PCR 0x%08x+%d:%03x == %f @ %f, pkt #%lu\n", pid, pcrBaseHigh, pkt[10]>>7, pcrExt, clock, timeNow, fTSPacketCount);
#endif
  } else {
    // We've seen this PID's PCR before; update our per-packet duration estimate:
    double durationPerPacket
      = (clock - pidStatus->lastClock)/(fTSPacketCount -  pidStatus->lastPacketNum);

==>     if (fTSPacketCount - pidStatus->lastPacketNum<=20) // The new test
==>         return;

    if (fTSPacketDurationEstimate == 0.0) { // we've just started
      fTSPacketDurationEstimate = durationPerPacket;
    } else if (discontinuity_indicator == 0 && durationPerPacket >= 0.0) {
      fTSPacketDurationEstimate
    = durationPerPacket*NEW_DURATION_WEIGHT
    + fTSPacketDurationEstimate*(1-NEW_DURATION_WEIGHT);

      // Also adjust the duration estimate to try to ensure that the transmission
      // rate matches the playout rate:
      double transmitDuration = timeNow - pidStatus->firstRealTime;
       double playoutDuration = clock - pidStatus->firstClock;
      if (transmitDuration > playoutDuration) {
    fTSPacketDurationEstimate *= TIME_ADJUSTMENT_FACTOR; // reduce estimate
      } else if (transmitDuration + MAX_PLAYOUT_BUFFER_DURATION < playoutDuration) {
    fTSPacketDurationEstimate /= TIME_ADJUSTMENT_FACTOR; // increase estimate
      }
    } else {
      // the PCR has a discontinuity from its previous value; don't use it now,
      // but reset our PCR and real-time values to compensate:
      pidStatus->firstClock = clock;
      pidStatus->firstRealTime = timeNow;
    }
#ifdef DEBUG_PCR
    fprintf(stderr, "PID 0x%x, PCR 0x%08x+%d:%03x == %f @ %f (diffs %f @ %f), pkt #%lu, discon %d => this duration %f, new estimate %f\n", pid, pcrBaseHigh, pkt[10]>>7, pcrExt, clock, timeNow, clock - pidStatus->firstClock, timeNow - pidStatus->firstRealTime, fTSPacketCount, discontinuity_indicator != 0, durationPerPacket, fTSPacketDurationEstimate);
#endif
  }

  pidStatus->lastClock = clock;
  pidStatus->lastRealTime = timeNow;
  pidStatus->lastPacketNum = fTSPacketCount;
}





       
---------------------------------
 Ne gardez plus qu'une seule adresse mail ! Copiez vos mails vers Yahoo! Mail 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.live555.com/pipermail/live-devel/attachments/20080201/8423b140/attachment.html 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: log.zip
Type: application/x-zip-compressed
Size: 4642 bytes
Desc: 2822840594-log.zip
Url : http://lists.live555.com/pipermail/live-devel/attachments/20080201/8423b140/attachment.bin 


More information about the live-devel mailing list