[Live-devel] Buffered MPEG2-TS to RTP how-to

Russell Brennan rjbrennn at gmail.com
Mon Jun 25 12:28:04 PDT 2007


I have figured out how to do this, so here is the basis of my code, and some
hanging unanswered questions... the code is mostly
testMPEG2TransportStreamer.cpp.

#include <fstream>
#include <math.h>
#include <vector>

#include "liveMedia.hh"
#include "BasicUsageEnvironment.hh"
#include "GroupsockHelper.hh"
// To stream using "source-specific multicast" (SSM), uncomment the
following:
//#define USE_SSM 1
#ifdef USE_SSM
Boolean const isSSM = True;
#else
Boolean const isSSM = False;
#endif

// To set up an internal RTSP server, uncomment the following:
//#define IMPLEMENT_RTSP_SERVER 1
// (Note that this RTSP server works for multicast only)

#define TRANSPORT_PACKET_SIZE 188
#define TRANSPORT_PACKETS_PER_NETWORK_PACKET 7

class pipeToRTP {
    public:
    // Constructor and destructor
        pipeToRTP();

    // Primitive execution method
        void execute();

    protected:

//-----------------------------------------------------------------------
    // Variable Declarations

//-----------------------------------------------------------------------

        char rtpFileName_[L_tmpnam];
        string destAddressStr_;
        unsigned short rtpPortNum_;


//-----------------------------------------------------------------------
    // Method Declarations

//-----------------------------------------------------------------------
        void preamble();
        void setupRTP();
        void compute();
        void play();
        void postamble();

    // Buffers
        char cBuffer_[MAX_GRAB]; // Ouput of FEC is a type 1000 SB


    // RTP objects
        UsageEnvironment* env;
        FramedSource* videoSource;
        RTPSink* videoSink;
        BasicTaskScheduler* scheduler;
        ByteStreamFileSource* Source;
        ofstream outPipe_;

};


/**
 * pipeToRTP Constructor
 */
pipeToRTP::pipeToRTP() {
    tmpnam(rtpFileName_); // make a random filename
}


/**
 * Class Execution
 */
void pipeToRTP::execute() {
    preamble();
    m_sync();
    setupRTP();
    //compute(); // Called via setupRTP()
    postamble();
}


/**
 * Preamble
 * Initializes file headers, variables, and buffers
 */
void pipeToRTP::preamble() {}


/**
 * Main loop
 * This is where the data packets are pushed to a file stream
 */
void pipeToRTP::compute() {

     while (m_do(lper_, hin_.xfer_len)) {
       // Grab to our unix pipe
         m_grabx(hin_, cBuffer_, ngot_);
         if (ngot_ > 0) {
         // Send out the packet to Unix pipe
           outPipe_.write(cBuffer_, ngot_); // write a block of data
           scheduler->SingleStep(0); // Made this guy public
        }
    }

}


/**
 * Postamble
 * Performs post-processing tasks such as closing file headers and freeing
 * memory.
 */
void pipeToRTP::postamble() {
#ifdef DEBUG
  *env << "...done reading from file\n";
#endif

  Medium::close(videoSource);
  // Note that this also closes the input file that this source read from.

  outPipe_.close();

  exit(1);
}


/**
 * Main Routine
 * Instantiates an instance of the class and calls the execution method
 */
void mainroutine() {
    pipeToRTP p;

    try {
        p.execute();
    }
    catch (...) {
        m_error("Primitive execution failed (pipeToRTP)");
    }
}



/**
 * setupRTP
 * Initializes RTP environment.
 */
void pipeToRTP::setupRTP() {
  // Begin by setting up our usage environment:
    scheduler = BasicTaskScheduler::createNew();
    env = BasicUsageEnvironment::createNew(*scheduler);

 ...

#ifdef DEBUG
    *env << "Beginning streaming...\n";
#endif

    outPipe_.open(rtpFileName_); // Open the file
    if (!outPipe_) {
      cerr << "Could not open fifo for output" << endl;
      exit(1);
    }

    play();
    compute();
}



void afterPlaying(void* /*clientData*/) {
  // Just for the compiler
}



void pipeToRTP::play() {
  unsigned const inputDataChunkSize
      = TRANSPORT_PACKETS_PER_NETWORK_PACKET*TRANSPORT_PACKET_SIZE;

  // Open the input as a 'byte-stream file source':
  Source = ByteStreamFileSource::createNew(*env, rtpFileName_,
inputDataChunkSize);
  if (Source == NULL) {
    *env << "Unable to open file \"" << rtpFileName_
        << "\" as a byte-stream file source\n";
    exit(1);
  }

  // Create a 'framer' for the input source (to give us proper inter-packet
gaps):
  videoSource = MPEG2TransportStreamFramer::createNew(*env, Source);

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



Right, so the only way I could manage to get this working was to use an
ofstream object to write my data to, using a random filename which was
passed to ByteStreamFileSource::createNew. Also, teh above functions play()
and compute() HAD to be withing setupRTP() or else I would get a bad file
descriptor error from select()... this probably has something to do with
scope, but I will not investigate this further.  Performace seems to be
good, this uses minimal cpu cycles on my machine.

If anyone has a better alternative to ofstream, I would be happy to hear it!

Russell



On 6/19/07, Russell Brennan <rjbrennn at gmail.com> wrote:
>
> Hello,
>
> I am trying to take a buffer of MPEG2-TS data which is constantly written
> to, and hook it up to live555 for output via RTP.  I am currently basing my
> work on the testMEPG2TransportStreamer code, but obviously this was designed
> to stream a file.
> My current idea is not really panning out, due to the fact that I am
> apparently confused...  ByteStreamFileSource is used in the test program,
> but it seems that I will need to use a different type of source.  Is there
> an existing MediaSource that will work, or will I need to create my own?
>
> Also, MPEG2TransportStreamFramer is used as the videosource to
> videoSink->startPlaying . This would seem to still be valid for what I am
> doing, correct?
>
> Lastly, doEventLoop seems to continuously call SingleStep(), and from what
> I can make of this function, it seems that in some way this is where the
> data to be sent out is packaged and sent.  Assuming that I get
> acknowledgement each time my buffer is ready to be sent out, can I simply
> call SingleStep() each time I have data to send?
>
> I hope I was clear enough... Thanks in advance!
>
> --
> Russell Brennan
>
>



-- 
Russell Brennan
RJBrennn at gmail.com
(708) 699-7314
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.live555.com/pipermail/live-devel/attachments/20070625/e6ea7dbf/attachment.html 


More information about the live-devel mailing list