从 IP 摄像机流式传输在 VLC 上非常抖动.

Stream from IP Camera very jittery on VLC

本文关键字:VLC 非常 抖动 传输 IP 摄像机      更新时间:2023-10-16

这个问题是我之前在这里问的序言。我正在从事一个基于 TI OMAP-L138 的 IP 摄像机项目。总而言之,H264 编码的视频通过 RTSP 通过 live555 库进行流式传输。对于 Live555,我使用的是基于设备源的帧源。但是,当我通过 vlc 启动流时,它非常抖动,帧丢失足够。设备源.cpp的代码如下所示:

#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);

}

和测试H264视频流:

#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] = ''; // 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 sourcen";
          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 驱动程序来源:

/* 
 *   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:  EOLIn");
    //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:  EOWIn");
        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....OKn", 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....OKn", 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 initilizedn");}
    //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)

是什么原因导致我的流出现这种抖动和丢失?我花了很多时间弄清楚可能出错的地方,但所有的尝试都是徒劳的。我是一个菜鸟,非常感谢这方面的帮助。

由于读取是阻塞调用,因此应管理非阻塞读取或使用线程。但是您的内核模块似乎没有实现选择/轮询回调。

那么第一步可能是使用如下所示的附加线程从 live555 主循环调用外部读取:

#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);
}

正如您注意到的,这个简单的示例不会在后台读取帧。这需要在两个线程之间实现 FIFO。

更新
它可以使用以下方法构建:

CPPFLAGS=-pthread LDFLAGS=-pthread make