Stream from IP Camera very jittery on VLC

3

This question is a prologue to the one I previously asked here. I'm working on an IP camera project that is based on TI OMAP-L138. All in all, the H264 encoded video is streamed via live555 libraries over RTSP. For Live555 I'm using deviceSource based framed source. However, when I start the stream over vlc, it is very jittery with sufficient frame loss. The code for deviceSource.cpp is shown below:

#include "DeviceSource.hh"
#include <GroupsockHelper.hh> // for "gettimeofday()"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sstream>
#include<iostream>
#include<math.h>
//static uint8_t buf[131072];
static uint8_t buf[131072];
//uint8_t * buf = (uint8_t *)malloc(131072);
int upp_stream; 
int upp_write;

DeviceSource*
DeviceSource::createNew(UsageEnvironment& env)
{

  return new DeviceSource(env);
}

EventTriggerId DeviceSource::eventTriggerId = 0;

unsigned DeviceSource::referenceCount = 0;

DeviceSource::DeviceSource(UsageEnvironment& env):FramedSource(env) 
{ 

  if (referenceCount == 0) 
  {

      upp_stream = open("/dev/upp",O_RDWR);
      //upp_write = open("output_16Jan.264", O_RDWR|O_CREAT);

  }
  ++referenceCount;

  if (eventTriggerId == 0) 
  {
    eventTriggerId = envir().taskScheduler().createEventTrigger(deliverFrame0);
  }
}

DeviceSource::~DeviceSource(void) {
  --referenceCount;
  envir().taskScheduler().deleteEventTrigger(eventTriggerId);
  eventTriggerId = 0;

  if (referenceCount == 0) 
  {

  }
}
void DeviceSource::doGetNextFrame() 
{
    read(upp_stream,buf, 131072);
    //write(upp_write,buf, sizeof(buf));
    deliverFrame();

}


void DeviceSource::deliverFrame0(void* clientData) 
{
  ((DeviceSource*)clientData)->deliverFrame();
}

void DeviceSource::deliverFrame() 
{

  if (!isCurrentlyAwaitingData()) return; // we're not ready for the data yet


    //Bitwise Shift hex from buf[12] to buf[15] to get data count  
    unsigned int data_count2 = (buf[12] << 24)|(buf[13]<<16)|(buf[14]<<8)|buf[15];

    u_int8_t* newFrameDataStart = (uint8_t*)buf;
    unsigned newFrameSize = sizeof(buf);//f_size; 
    // Deliver the data here:
    if (newFrameSize > fMaxSize) 
    {
        fFrameSize = fMaxSize;
        fNumTruncatedBytes = newFrameSize - fMaxSize;
    }   
    else 
    {
        fFrameSize = newFrameSize;
    }
  gettimeofday(&fPresentationTime, NULL); //chk this 
  memmove(fTo, newFrameDataStart, fFrameSize);
  FramedSource::afterGetting(this);



}

and testH264VideoStreamer:

#include <liveMedia.hh>
#include <BasicUsageEnvironment.hh>
#include <GroupsockHelper.hh>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <string.h>
#include <unistd.h> //to allow read() function

UsageEnvironment* env;

H264VideoStreamFramer* videoSource;
RTPSink* videoSink;

void play(); // forward
//-------------------------------------------------------------------------
//Entry Point -> Main FUNCTION  
//-------------------------------------------------------------------------

int main(int argc, char** argv) {
  // Begin by setting up our usage environment:
  TaskScheduler* scheduler = BasicTaskScheduler::createNew();
  env = BasicUsageEnvironment::createNew(*scheduler);

  // Create 'groupsocks' for RTP and RTCP:
  struct in_addr destinationAddress;
  destinationAddress.s_addr = chooseRandomIPv4SSMAddress(*env);
  // Note: This is a multicast address.  If you wish instead to stream
  // using unicast, then you should use the "testOnDemandRTSPServer"
  // test program - not this test program - as a model.

  const unsigned short rtpPortNum = 18888;
  const unsigned short rtcpPortNum = rtpPortNum+1;
  const unsigned char ttl = 255;

  const Port rtpPort(rtpPortNum);
  const Port rtcpPort(rtcpPortNum);

  Groupsock rtpGroupsock(*env, destinationAddress, rtpPort, ttl);
  rtpGroupsock.multicastSendOnly(); // we're a SSM source
  Groupsock rtcpGroupsock(*env, destinationAddress, rtcpPort, ttl);
  rtcpGroupsock.multicastSendOnly(); // we're a SSM source

  // Create a 'H264 Video RTP' sink from the RTP 'groupsock':
  OutPacketBuffer::maxSize = 600000;
  videoSink = H264VideoRTPSink::createNew(*env, &rtpGroupsock, 96);

  // Create (and start) a 'RTCP instance' for this RTP sink:
  const unsigned estimatedSessionBandwidth = 2048; // in kbps; for RTCP b/w share
  const unsigned maxCNAMElen = 100;
  unsigned char CNAME[maxCNAMElen+1];
  gethostname((char*)CNAME, maxCNAMElen);
  CNAME[maxCNAMElen] = '\0'; // just in case
  RTCPInstance* rtcp
  = RTCPInstance::createNew(*env, &rtcpGroupsock,
                estimatedSessionBandwidth, CNAME,
                videoSink, NULL /* we're a server */,
                True /* we're a SSM source */);
  // Note: This starts RTCP running automatically

  RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554);
  if (rtspServer == NULL) {
    *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
    exit(1);
  }
  ServerMediaSession* sms
    = ServerMediaSession::createNew(*env, "ipcamera","Using DeviceSource" ,
           "Session streamed by \"testH264VideoStreamer\"",
                       True /*SSM*/);
  sms->addSubsession(PassiveServerMediaSubsession::createNew(*videoSink, rtcp));
  rtspServer->addServerMediaSession(sms);

  char* url = rtspServer->rtspURL(sms);
  *env << "Play this stream using the URL \"" << url << "\"\n";
  delete[] url;

  // Start the streaming:
  *env << "Beginning streaming...\n";
  play();

  env->taskScheduler().doEventLoop(); // does not return

  return 0; // only to prevent compiler warning
}
//----------------------------------------------------------------------
//AFTER PLAY FUNCTION CALLED HERE
//----------------------------------------------------------------------
void afterPlaying(void* /*clientData*/) 
{

    play();
}
//------------------------------------------------------------------------
//PLAY FUNCTION () 
//------------------------------------------------------------------------
void play()
{


      // Open the input file as with Device as the source:
    DeviceSource* devSource
        = DeviceSource::createNew(*env);
    if (devSource == NULL) 
    {

          *env << "Unable to read from\"" << "Buffer"
           << "\" as a byte-stream source\n";
          exit(1);
    }

    FramedSource* videoES = devSource;

    // Create a framer for the Video Elementary Stream:
    videoSource = H264VideoStreamFramer::createNew(*env, videoES,False);

    // Finally, start playing:
    *env << "Beginning to read from UPP...\n";
    videoSink->startPlaying(*videoSource, afterPlaying, videoSink);
}

uPP driver source:

/* 
 *   A device driver for the Texas Instruments
 *   Universal Parallel Port (UPP)
 *  
 *   Modified by: Ali Shehryar <github.com/sshehryar>
 *
 */

#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/fs.h>      
#include <linux/delay.h>      //for "mdelay(...)"
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include <linux/moduleparam.h>
#include <mach/da8xx.h>
#include <asm/sizes.h>
#include <asm/io.h>       
#include <mach/mux.h>
#include <linux/gpio.h>
#include <mach/gpio.h>
#include <asm/gpio.h>

//SPRUH77A.PDF, Table 12-1. The Interrupt number assigned to the UPP module.
#define UPP_INTERRUPT   91

//SPRS586D.PDF, Table 2-4
#define DA850_UPP_BASE  0x01E16000

//SPRS586D.PDF, Table 5-117. Offsets from DA850_UPP_BASE
#define UPPCR           0x00000004
#define UPDLB           0x00000008
#define UPCTL           0x00000010
#define UPICR           0x00000014
#define UPIVR           0x00000018
#define UPTCR           0x0000001C
#define UPIER           0x00000024
#define UPIES           0x00000028
#define UPIEC           0x0000002C
#define UPEOI           0x00000030
#define UPID0           0x00000040
#define UPID1           0x00000044
#define UPID2           0x00000048
#define UPIS0           0x00000050
#define UPIS1           0x00000054
#define UPIS2           0x00000058


//SPRS586D.PDF, Table 2-4
#define DA850_PSC1_BASE 0x01E27000 

//SPRUH77A.PDF, Table 9-7. 
//"Power and Sleep Controller 1" (PSC1)  Revision ID Register.
#define PSC_REVID       0x00000000

//SPRUH77A.PDF, Table 9-7. 
//"Power Domain Transition Status" Register.
#define PSC_PTSTAT      0x00000128

//SPRUH77A.PDF, Table 9-2, Table 9-7. 
//NOTE that in Table 9-2, UPP module has an LPSC number of 19...
#define PSC1_MDCTL_19   0x00000A4C  //0xA00 + (19*4). 

//SPRUH77A.PDF, Table 9-7. 
//"Power Domain Transition Command Register" Register.
#define PSC_PTCMD       0x00000120
//DMA Status Register bitmasks used in the ISR handler.... 
#define EOLI   16
#define EOWI   8
#define ERRI   4
#define UORI   2 
#define DPEI   1

#define UPIES_MASK 0x0000001F
//The DMA PARAMETERS 
#define UPP_BUF_SIZE       131072 //Changed 6-Jan-2015
#define UPP_RX_LINE_COUNT  128    //Changed from 8 on 6-Jan-2015 
#define UPP_RX_LINE_SIZE   1024
#define UPP_RX_LINE_OFFSET 1024 



#define DA850_GPIO_BASE       0x01E26000



//MODIFIED BY: SHEHRYAR. Offsets from GPIO_Base (SPRS653C.PDF TABLE 5-134)

#define DIR67       0x00000088
#define OUT_DATA67  0x0000008C
#define SET_DATA67  0x00000090
#define CLR_DATA67  0x00000094  

static void *rxBuf; 
static void __iomem *pinmux_base = 0;
static void __iomem *upp_base    = 0;
static void __iomem *psc1_base   = 0;
static void __iomem *gpio_base   = 0;

static DECLARE_WAIT_QUEUE_HEAD(read_queue);
static int32_t read_pending = 0; // changed from static int



static int loopbackMode = 0;

module_param( loopbackMode, int, S_IRUGO);

int EOWI_Count = 0; int UORI_count =0;



   //SPRUGJ5B.PDF, Section 2.6.4
static irqreturn_t upp_ISR_handler(int irq, void *dev_id)
{
   uint32_t regVal, status;

   if (pinmux_base == 0) 
   {
      return IRQ_HANDLED;
   }

   status = ioread32( upp_base + UPIER );


   while (status &  0x0000001F )  //0x1F1F is an interrupt bit-mask 
   {
      //
      //DMA Channel I (Channel A), Receiving data (We Need A (DMA Ch I ) to Rx Data instead of Tx ; 27th Nov 2014 - 10:38am)
      //
      if (status & EOLI) 
      {
    //Clear the interrupt. WRITING ZERO to any other bit has NO effect,
    //per SPRUH77A.PDF, section 33.3.9.
    iowrite32(EOLI, upp_base + UPIER );

    //printk(KERN_INFO "DMA:  EOLI\n");
    //printk(KERN_INFO "DMA:EOLI.  UPP_RX_LINE_SIZE[%d] UPP_RX_LINE_OFFSET[%d] UPP_RX_LINE_COUNT[%d] \n",       UPP_RX_LINE_SIZE,UPP_RX_LINE_OFFSET,UPP_RX_LINE_COUNT );
    //dump_Channel_regs();
    }

    if (status & EOWI) 
    {
         //Clear the interrupt. WRITING ZERO to any other bit has NO effect,
         //per SPRUH77A.PDF, section 33.3.9.
        //printk(KERN_INFO "DMA:  EOWI\n");
        iowrite32(EOWI, upp_base + UPIER );

        read_pending = 131072; //Changed 6-Jan-2015
        wake_up_interruptible(&read_queue);
        //add 1 to EOWI counter
        EOWI_Count += 1;

     //    dump_Channel_regs();
    }

    if (status & ERRI) 
    {
         //Clear the interrupt. WRITING ZERO to any other bit has NO effect,
         //per SPRUH77A.PDF, section 33.3.9.
         iowrite32(ERRI, upp_base + UPIER );


         //dump_Channel_regs();
      }
      if (status & UORI) 
      {
         //Clear the interrupt. WRITING ZERO to any other bit has NO effect,
         //per SPRUH77A.PDF, section 33.3.9.
         iowrite32(UORI, upp_base + UPIER );
         UORI_count +=1;

         //dump_Channel_regs();
      }
      if (status & DPEI) 
      {
         //Clear the interrupt. WRITING ZERO to any other bit has NO effect,
         //per SPRUH77A.PDF, section 33.3.9.
         iowrite32(DPEI, upp_base + UPIER );


         //dump_Channel_regs();
      }
    //read again, and process if necessary.
      status = ioread32( upp_base + UPIER );
   }    
   //Clear UPEOI to allow future calls to this function.
   regVal = ioread32( upp_base + UPEOI);
   regVal &= 0xFFFFFF00;
   regVal = 0;// End of Interrupt

   iowrite32(regVal, upp_base + UPEOI);

   return IRQ_HANDLED;
}

static void pin_mux_set( int index, unsigned int bits )
{
   static DEFINE_SPINLOCK(mux_spin_lock);
   unsigned long flags;
   unsigned int offset;

   if ((index < 0) || (index > 19))
   {
      printk(KERN_INFO "pin_mux_set:index is out of range.\n");
      return;
   }

   if (!pinmux_base) 
   {
      //SRPUH77A.PDF,Table 11-3
      if ((pinmux_base = ioremap(DA8XX_SYSCFG0_BASE, SZ_4K)) == 0) 
      {
         printk(KERN_INFO "pin_mux_set:Cannot fetch pinmux_base.\n");
         return;
      }
   }

   offset = 0x120 + (index * 4);
   spin_lock_irqsave(&mux_spin_lock, flags);
   iowrite32(bits, pinmux_base + offset);
   spin_unlock_irqrestore(&mux_spin_lock, flags);

   //NOTE: do NOT "iounmap" the pinmux_base pointer, as it is used
   //      in the ISR_handler.....
}



static void upp_pin_mux_init(void)
{
   pin_mux_set( 13, 0x44440000 );
   pin_mux_set( 14, 0x44444480 ); 
   pin_mux_set( 15, 0x44444444 );
   pin_mux_set( 16, 0x44444444 );
   pin_mux_set( 17, 0x44444444 );
   pin_mux_set( 18, 0x00444444 );
   pin_mux_set( 19, 0x08888800 );   
   //pin_mux_print() ;
}



static void upp_power_and_clocks( void )
{

    int regVal;


    if (!psc1_base) 
    {
       if ((psc1_base = ioremap(DA850_PSC1_BASE, SZ_4K)) == 0)
       {
          printk(KERN_INFO "upp_power_and_clocks:Cannot fetch psc1_base.\n");
          return;
       }
    }

    regVal = ioread32(psc1_base + PSC_REVID);

    //PSC Revision ID should be "44825A00" per SPRUH77A.PDF, section 9.6.1
    if (regVal == 0x44825A00) 
    {
       printk( KERN_INFO "PSC_REVID = 0x%08X....OK\n", regVal); 
    }
    else
    {
       printk( KERN_INFO "********ERROR: PSC_REVID = 0x%08X********\n", regVal); 
    }

    // SPRUH77A.PDF, 9.3.2.1, Table 9-6, 9.6.10 
    // wait for GOSTAT[0] in PSTAT to clear to 0 ("No transition in progress")
    while ( ioread32(psc1_base + PSC_PTSTAT) & 0x00000001 )
    ;   

    //
    //SPRUH77A.PDF, 9.3.2.2,  9.6.19.
    //Set NEXT bit in MDCTL19 to Enable(3h).
    regVal  = ioread32( psc1_base + PSC1_MDCTL_19 );
    regVal |= 0x00000003;
    iowrite32(regVal, psc1_base + PSC1_MDCTL_19);


    //
    //SPRUH77A.PDF, 9.3.2.3,  9.6.9. 
    //Set the GO[0] bit in PTCMD to 1 to initiate power-domain transition
    regVal  = ioread32(psc1_base + PSC_PTCMD);
    regVal |= 0x00000001;
    iowrite32(regVal, psc1_base + PSC_PTCMD);

    //
    // SPRUH77A.PDF, 9.3.2.4 
    // Wait for GOSTAT[0] in PTSTAT to clear to 0
    while ( ioread32(psc1_base + PSC_PTSTAT) & 0x00000001 )
    ;  

    iounmap( psc1_base );
    psc1_base = 0;


}

   //SPRUGJ5B.PDF, Section 2.6.1.3, 2.6.1.4
static void upp_swrst( void )
{
    int32_t reg_val;

    if (!upp_base)
    {
       if ((upp_base = ioremap(DA850_UPP_BASE, SZ_4K)) == 0) 
       {
          printk(KERN_INFO "upp_swrst:Cannot fetch upp_base.\n");
          return;
       }
    }

    reg_val = ioread32( upp_base + 0 );
    if (reg_val == 0x44231100 ) 
    {
       printk(KERN_INFO "UPP_UPPID = 0x%08X....OK\n", reg_val);
    }
    else
    {
       printk( KERN_INFO "********ERROR: UPP_UPPID = 0x%08X********\n", reg_val); 
    }




    reg_val = ioread32( upp_base + UPPCR );
    reg_val &= ~(1 << 3);             //0xfffffff7;
    iowrite32( reg_val, upp_base + UPPCR );

    //poll "DMA Burst" (DB) bit of UPPCR to ensure DMA controller is idle
    while ( ioread32( upp_base + UPPCR ) & (1 << 7) )
        ;


    // SPRUH77A.PDF, Section 33.2.7.1.3, Table 33-12.
    // assert SWRST bit (bit 4) of UPPCR
    reg_val  = ioread32( upp_base + UPPCR );
    reg_val |= 0x00000010;
    iowrite32( reg_val, upp_base + UPPCR );

    //
    // wait at least 200 clock cycles 
    // (SPRUGJ5B.PDF, 2.6.1.4)
    mdelay( 200 );  // abitrary choice of 200ms


    // SPRUH77A.PDF, Section 33.2.7.1.4  --AND--
    // SPRUGJ5B.PDF, 2.6.1.4
    // clear SWRST bit (bit 4) of UPPCR
    reg_val = ioread32( upp_base + UPPCR );
    reg_val &= 0xffffffef;
    iowrite32( reg_val, upp_base + UPPCR );


}


   //SPRUGJ5B.PDF, Section 2.6.1.5
static void upp_config( void )
{
   int32_t regVal;

   //-------------------------------------------------------------------------
   // UPPCTL - UPP Interface Channel Settings....SPRUH77A.PDF, Section 33.3.4.
   //        
   //        - DATA and XDATA Pin assignments to Channels A & B:
   //          Refer to SPRUGJ5B.PDF, Table 3: 
   //              
   //        ____PHYSICAL_PINS___|____CHANNEL_ASSIGNMENT___
   //          * DATA[7:0]       |       A[7:0]
   //          * DATA[15:8]      |       B[7:0]
   //-------------------------------------------------------------------------
   regVal = 0;
   regVal |= 1 << 17;       // IWA  - CHANNEL A 8/16bit MODE: Set Channel A to 16 bit mode


   iowrite32( regVal, upp_base + UPCTL );

   regVal  = 0;        //Channel A: START is active-high

   regVal |= 1<<3;  //Channel A:STARTA is honored in Rev Mode
   regVal |= 1<<4;  //Channel A:ENABLEA is honored in Rev Mode
   regVal |= 1<<12;  //Channel A:(CLKINVA) Signal on rising edge of clock
   regVal |= 1<<13;  //Channel A:(TRISA) pins are High-impedence while idle

   iowrite32( regVal, upp_base + UPICR );



   regVal = 0;
   regVal |= 0xab00;   //Channel B Idle Value
   regVal |= 0x00cd;   //Channel A Idle Value
   iowrite32( regVal, upp_base + UPIVR );



   regVal  = 0x00000003;            //DMA Channel I READ-threshold. 256 bytes (max)

   iowrite32(regVal, upp_base + UPTCR );
}

//SPRUGJ5B.PDF, Section 2.6.1.6
static void upp_interrupt_enable( void )
{
   int32_t regVal, status;

   // Register the ISR before enabling the interrupts....
   status = request_irq( UPP_INTERRUPT, upp_ISR_handler, 0, "upp_ISR", 0 );
   if( status < 0 ) 
   {

        return;
   }

   // clear all interrupts
   iowrite32( UPIES_MASK, upp_base + UPIEC );


   // regVal  = 0x17;            //Enable ALL interrupts (but EOWI) for DMA Channel I
   //regVal |= 0x17 << 8;       //Enable ALL interrupts (but EOWQ) for DMA Channel Q 
   regVal = UPIES_MASK;
   iowrite32( regVal, upp_base + UPIES );


}


//SPRUGJ5B.PDF, Section 2.6.1.7
static void upp_enable( void )
{
    int32_t reg_val;

    // set EN bit in UPPCR. 
    // The EN bit (effectively disabling the UPP peripheral)...
    // was cleared in "upp_swrst()" function
    reg_val = ioread32( upp_base + UPPCR );
    reg_val |=  1 << 3;  
    iowrite32( reg_val, upp_base + UPPCR );


}

static void upp_disable( void )
{
    int32_t reg_val;

    reg_val = ioread32( upp_base + UPPCR );
    reg_val &= ~(1 << 3);             //0xfffffff7;
    iowrite32( reg_val, upp_base + UPPCR );


}


static void setpin_GPIO (void)
{

    int32_t reg_val=0;

    if ((gpio_base = ioremap(DA850_GPIO_BASE, SZ_4K)) == 0) 
      {

         return;
      } 
    //reg_val = ioread32(gpio_base + SET_DATA67);
    reg_val |= (1<<6); ///Set Pin 6 of Bank 6 GP6P6 to 1 to drive GPIO high
    iowrite32(reg_val,gpio_base + SET_DATA67);
}

static void clrpin_GPIO(void)
{

    int32_t reg_val=0;
    if ((gpio_base = ioremap(DA850_GPIO_BASE, SZ_4K)) == 0) 
    {
        return;
    }   
//reg_val = ioread32(gpio_base + CLR_DATA67);
/*reg_val |= ~(1<<0);
reg_val |= ~(1<<1);
reg_val |= ~(1<<2);
reg_val |= ~(1<<3);
reg_val |= ~(1<<4);*/
reg_val |= (1<<6); //Set Pin 6 of bank 6 GP6P6 of CLR_DATA67 Register to High to drive GPIO signals low

    iowrite32(reg_val,gpio_base + CLR_DATA67);

}


static void Config_GPIO(void)
{
     int32_t reg_val;   

     if ((gpio_base = ioremap(DA850_GPIO_BASE, SZ_4K)) == 0) 
     {
        return;
     }  
    //set dir 
    reg_val = ioread32(gpio_base + DIR67);
    reg_val &= ~(1<<0); 
    reg_val &= ~(1<<1);
    reg_val &= ~(1<<2);
    reg_val &= ~(1<<3);
    reg_val &= ~(1<<4);
    reg_val &= ~(1<<6);
    iowrite32(reg_val,gpio_base + DIR67);
    printk(KERN_INFO "DIR67 => [0x%08X]\n", reg_val);
    //set to high
    reg_val = ioread32(gpio_base + SET_DATA67);
    reg_val |= (1<<0); 
    reg_val |= (1<<1);
    reg_val |= (1<<2);
    reg_val |= (1<<3);
    reg_val |= (1<<4);
    iowrite32(reg_val,gpio_base + SET_DATA67);

}


// Return false on error
static bool upp_mem_alloc( void )
{
    //rxBuf2 = kcalloc( 1 , UPP_BUF_SIZE, GFP_KERNEL | GFP_DMA  );   
    rxBuf = kcalloc( 1 , UPP_BUF_SIZE, GFP_KERNEL | GFP_DMA  );
    if (!rxBuf) //|| (!rxBuf2)
    {
        return false;
    }

    return true;
}

static void upp_program_DMA_channelA( void )
{
    while ( ioread32( upp_base + UPIS2 ) & 0x00000002 );

    iowrite32( rxBuf, upp_base + UPID0);  
    iowrite32( ( (UPP_RX_LINE_COUNT << 16) | UPP_RX_LINE_SIZE ), upp_base + UPID1);
    iowrite32( UPP_RX_LINE_OFFSET, upp_base + UPID2);
}

 int upp_open( struct inode *iPtr, struct file *fPtr )
{
    int minor,major;
    read_pending  = 0;

    minor=iminor(iPtr);
    major=imajor(iPtr);
    printk( KERN_INFO "upp_open: MAJOR(%d), MINOR(%d)\n", major, minor);

    upp_disable();
    upp_enable();

    return 0;

}

ssize_t upp_read( struct file *fPtr, char __user *buffer, size_t size, loff_t *offset )
{

    int readBytes = 0;
    int retVal=0; 
    void *bPtr = (void *)buffer;

    if (!bPtr) {return -1; printk(KERN_INFO "ERROR: bPtr not initilized\n");}

    //printk(KERN_INFO "\n Begin Reading [%d] Bytes ...\n",size );

    while (readBytes<size)  
    {
        //read_flag+=1;     
        read_pending = 0;   
        //mdelay(10);   

        //memset(rxBuf,255,131072);


        upp_program_DMA_channelA();

        clrpin_GPIO(); 

        wait_event_interruptible( read_queue, read_pending > 0 );

        while ( ioread32( upp_base + UPIS2 ) & 0x00000001 )        
        {
            printk (KERN_INFO "DMA IS STILL ACTIVE! \n");       
        }
        setpin_GPIO(); // Set High 

        retVal = copy_to_user(bPtr,rxBuf,read_pending);
        /*  retVal = copy_to_user(bPtr,rxBuf,size);
            Jan 5 2015 - Upon using size which tranfers 16k, we get copy  to user failed */
        if(retVal)
        {
            printk(KERN_INFO "ERROR: Copy to user failed!\n");
            return readBytes;
        }
        readBytes += read_pending;

        bPtr +=  131072;

    } //end of while loop



    return readBytes;
    //read_flag += 1;


}


int upp_release( struct inode *iPtr, struct file *fPtr )
{

   return 0;
   printk(KERN_INFO "upp_release completed.\n");
}


static struct cdev *UPP_cdev;
static dev_t UPP_MajorMinorNumbers;

struct file_operations upp_fops = { 
    .owner      = THIS_MODULE,
  //.llseek     = no_llseek,
  //.poll       = upp_poll,
    .read       = upp_read,
  //.write      = upp_write,
  //.ioctl  = upp_ioctl,
    .open       = upp_open,
  //.release    = upp_release,
};


/*
 *  Return ZERO on success.
 *  
 */
static int __init upp_init(void)
{
   int retVal;


   if (upp_mem_alloc() == false)
   {
      printk(KERN_INFO "******ERROR: Could not allocate buffers. Bailing!******\n");
      return -1;
   }

   upp_pin_mux_init();
   upp_power_and_clocks();
   upp_swrst();
   upp_config();

   upp_interrupt_enable();

   upp_enable();
   //SETTING GPIOS  
   Config_GPIO();
   setpin_GPIO(); // Set High 


   UPP_MajorMinorNumbers = MKDEV( 0, 0);
   if ( (retVal = alloc_chrdev_region( &UPP_MajorMinorNumbers, 0, 1, "UPP" )) < 0)
   {
      printk(KERN_INFO "ERROR: Major/Minor number allocation failed.\n");
      return retVal;
   }


   UPP_cdev        = cdev_alloc();
   UPP_cdev->ops   = &upp_fops; 
   UPP_cdev->owner = THIS_MODULE;

   if (cdev_add( UPP_cdev, UPP_MajorMinorNumbers, 1) != 0) 
   {
      printk(KERN_INFO "ERROR: UPP driver NOT loaded. CDEV registration failed.\n");
   }
   else
   {
      printk(KERN_INFO "\nUPP Major: %d , Minor: %d \n", MAJOR(UPP_MajorMinorNumbers), MINOR(UPP_MajorMinorNumbers));
   }

   printk("UPP driver (1.8.0 - 5/January/2015) succesfully installed.\n"); 

   return 0;
}

/*
 * 
 *  
 *  
 */
static void __exit upp_exit(void)
{
   uint32_t regVal;
   printk(KERN_INFO "Exiting..Initializing upp_exit call......\n");

   // clear EN bit of UPPCR to disable the UPP. 
   regVal = ioread32( upp_base + UPPCR );
   regVal &= 0xfffffff7;
   iowrite32( regVal, upp_base + UPPCR );


   free_irq( UPP_INTERRUPT, 0);


   if (rxBuf) 
   {
      kfree( rxBuf );
      rxBuf = 0;
   }


   cdev_del( UPP_cdev );
   unregister_chrdev_region( UPP_MajorMinorNumbers, 1);
   clrpin_GPIO(); //added 2-Dec-2014
   printk(KERN_INFO "UPP driver unloaded (Successful Exit). \n");
}


MODULE_AUTHOR("Ali Shehryar & Umair Ali");
MODULE_DESCRIPTION("OMAP-L138/AM-1808 UPP bus driver");
MODULE_LICENSE("GPL");
module_init(upp_init)
module_exit(upp_exit)

What could be causing this jitter and loss in my stream? I've spent alot of time figuring out what could be wrong but all attempts were futile. I'm a noob and would deeply appreciate help in this regard.

c++
algorithm
h.264
live555
asked on Stack Overflow Jan 20, 2015 by Shehryar • edited May 23, 2017 by Community

1 Answer

0

Because read is a blocking call, you should either manage non-blocking read or use a thread. But your kernel module doesn't seems to implement select/poll callback.

Then a first step could be to call the read outside from the live555 mainloop using an additionnal thread like this :

#include "DeviceSource.hh"
#include <GroupsockHelper.hh> // for "gettimeofday()"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

static uint8_t buf[131072];
int upp_stream; 
EventTriggerId DeviceSource::eventTriggerId = 0;
unsigned DeviceSource::referenceCount = 0;
pthread_t thid;
bool stop = false;

static void* thread(void* clientData) 
{
    DeviceSource* This = ((DeviceSource*)clientData);
    while (!stop) 
    {
        if (This->isCurrentlyAwaitingData())
        {
            ::read(upp_stream, buf, sizeof(buf));
            This->envir().taskScheduler().triggerEvent(DeviceSource::eventTriggerId, This);
        }
    }
    return NULL;
}

DeviceSource* DeviceSource::createNew(UsageEnvironment& env) { return new DeviceSource(env); }
DeviceSource::DeviceSource(UsageEnvironment& env):FramedSource(env) 
{ 
    if (referenceCount == 0) 
    {
        upp_stream = open("/dev/upp",O_RDWR);
        pthread_create(&thid, NULL, thread, this);
        eventTriggerId = envir().taskScheduler().createEventTrigger(deliverFrame0);
    }
    ++referenceCount;
}

DeviceSource::~DeviceSource(void) {
    --referenceCount;
    if (referenceCount == 0) 
    {
        stop=true;
        pthread_join(thid, NULL);

        envir().taskScheduler().deleteEventTrigger(eventTriggerId);
        eventTriggerId = 0;
        ::close(upp_stream);
    }
}

void DeviceSource::doGetNextFrame() {}

void DeviceSource::deliverFrame0(void* clientData) { ((DeviceSource*)clientData)->deliverFrame(); }
void DeviceSource::deliverFrame() 
{
    if (!isCurrentlyAwaitingData()) return; // we're not ready for the data yet
    //Bitwise Shift hex from buf[12] to buf[15] to get data count  
    unsigned int data_count2 = (buf[12] << 24)|(buf[13]<<16)|(buf[14]<<8)|buf[15];

    u_int8_t* newFrameDataStart = (uint8_t*)buf;
    unsigned newFrameSize = sizeof(buf);//f_size; 
    // Deliver the data here:
    if (newFrameSize > fMaxSize) 
    {
        fFrameSize = fMaxSize;
        fNumTruncatedBytes = newFrameSize - fMaxSize;
    }   
    else 
    {
        fFrameSize = newFrameSize;
    }
    gettimeofday(&fPresentationTime, NULL); //chk this 
    memmove(fTo, newFrameDataStart, fFrameSize);
    FramedSource::afterGetting(this);
}

As you notice this simple sample doesnot read frame in background. This needs to implement a FIFO between the two threads.

UPDATE
It could be build using :

CPPFLAGS=-pthread LDFLAGS=-pthread make
answered on Stack Overflow Feb 1, 2015 by mpromonet • edited Feb 15, 2015 by mpromonet

User contributions licensed under CC BY-SA 3.0