[Live-devel] Framed Source Issue

Mukherjee, Debargha debargha.mukherjee at hp.com
Thu Mar 26 17:37:03 PDT 2009


HI Ross,

Thanks for the pointers, but I am still struggling with the issue of audio being called much more often than it needs to be.

Please find below my derived audio encoding class implementation.
My constructor takes in a structure with encoding parameters, along with two pointers to external functions that I use to fill the buffers and check if there is enough data to read. I am using MPEG1or2AudioStreamFramer with MP3 encoding (single channel at 16000 KHz). Also it seems to me that the MPEG1or2AudioStreamFramer class does not use the fDurationInMicroseconds parameter at all.

Any help will be appreciated.

-----------------------------------------------------------------------------

#include "AudioEncSource.hh"

void doGetNextFrame_AudioEncSource(void* clientData) {
  AudioEncSource *a = (AudioEncSource*)clientData;
  a->doGetNextFrame();
}

AudioEncSource*
AudioEncSource::createNew(UsageEnvironment& env,
                        AudioEncParameters params, int (*auReadFn)(short *, int), int (*auIsOpenFn)()) {
  return new AudioEncSource(env, params, auReadFn, auIsOpenFn);
}

AudioEncSource::AudioEncSource(UsageEnvironment& env,
                           AudioEncParameters params, int (*auReadFn)(short *, int), int (*auIsOpenFn)())
  : FramedSource(env), fParams(params), audio_buf(NULL), audioReadData(auReadFn), audioIsOpen(auIsOpenFn) {

  // Any initialization of the device would be done here
    //avcodec_init();
        // Register all formats and codecs
    //av_register_all();

    c= avcodec_alloc_context();
        avcodec_get_context_defaults2(c, CODEC_TYPE_AUDIO);

        c->codec_id=params.codec_id;
        /* put sample parameters */
    c->bit_rate = params.bitrate;

    c->channels = fParams.numchannels;
    c->sample_rate = fParams.sampfreq;

    /* frames per second */

        codec = avcodec_find_encoder(c->codec_id);
        if(codec==NULL) {
                printf("Audio encoder could not be found\n");
                av_free(c);
                c=NULL;
                exit(1);
        }
        if(avcodec_open(c, codec)<0) {
                printf("Audio encoder could not be opened\n");
                av_free(c);
                c=NULL;
                codec=NULL;
                exit(1);
        }
        if (c) {
                framesize = c->frame_size * c->channels;
                audio_buf = (short*)malloc(2 * framesize);
                outbuf_size = 100000;
                outbuf = (uint8_t*)malloc(outbuf_size);
                frameDurationInMicroseconds = (unsigned int)(1000000.0*c->frame_size/c->sample_rate+0.5);
        }
}

AudioEncSource::~AudioEncSource() {
        if (c) {
                avcodec_close(c);
                av_free(c);
                free(audio_buf);
                free(outbuf);
        }
}


void AudioEncSource::doGetNextFrame() {
  // Arrange here for our "deliverFrame" member function to be called
  // when the next frame of data becomes available from the device.
  // This must be done in a non-blocking fashion - i.e., so that we
  // return immediately from this function even if no data is
  // currently available.
  //
  // If the device can be implemented as a readable socket, then one easy
  // way to do this is using a call to
  //     envir().taskScheduler().turnOnBackgroundReadHandling( ... )
  // (See examples of this call in the "liveMedia" directory.)

  // If, for some reason, the source device stops being readable
  // (e.g., it gets closed), then you do the following:
  if (audioIsOpen) {
          if (!audioIsOpen() /* the source stops being readable */) {
                handleClosure(this);
                return;
          }
  }
  deliverFrame();
}

void AudioEncSource::deliverFrame() {
  // This would be called when new frame data is available from the device.
  // This function should deliver the next frame of data from the device,
  // using the following parameters (class members):
  // 'in' parameters (these should *not* be modified by this function):
  //     fTo: The frame data is copied to this address.
  //         (Note that the variable "fTo" is *not* modified.  Instead,
  //          the frame data is copied to the address pointed to by "fTo".)
  //     fMaxSize: This is the maximum number of bytes that can be copied
  //         (If the actual frame is larger than this, then it should
  //          be truncated, and "fNumTruncatedBytes" set accordingly.)
  // 'out' parameters (these are modified by this function):
  //     fFrameSize: Should be set to the delivered frame size (<= fMaxSize).
  //     fNumTruncatedBytes: Should be set iff the delivered frame would have been
  //         bigger than "fMaxSize", in which case it's set to the number of bytes
  //         that have been omitted.
  //     fPresentationTime: Should be set to the frame's presentation time
  //         (seconds, microseconds).
  //     fDurationInMicroseconds: Should be set to the frame's duration, if known.

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

  //Deliver the data here:
  //fread(audio_buf,1,framesize,fInFid);

  gettimeofday(&fPresentationTime, NULL);
  int x = audioReadData(audio_buf, framesize);
  if (!x) {
          printf("Audio read zero at time %lu.%lu (%d)\n", fPresentationTime.tv_sec, fPresentationTime.tv_usec, frameDurationInMicroseconds);
          envir().taskScheduler().scheduleDelayedTask(frameDurationInMicroseconds>>2, (TaskFunc*)doGetNextFrame_AudioEncSource, (void*)this);
          return;
  }
  int out_size = avcodec_encode_audio(c, outbuf, outbuf_size, audio_buf);

  fFrameSize=(out_size<=fMaxSize?out_size:fMaxSize);

  memcpy(fTo, outbuf, fFrameSize);
  fNumTruncatedBytes = out_size-fFrameSize;

  fDurationInMicroseconds = frameDurationInMicroseconds;

  //After delivering the data, inform the reader that it is now available:
  printf("Audio %d in, %d out at time %lu.%lu (%d)\n",x, fFrameSize, fPresentationTime.tv_sec, fPresentationTime.tv_usec, fDurationInMicroseconds);

  FramedSource::afterGetting(this);
}


> -----Original Message-----
> From: live-devel-bounces at ns.live555.com
> [mailto:live-devel-bounces at ns.live555.com] On Behalf Of Ross Finlayson
> Sent: Thursday, March 19, 2009 4:58 PM
> To: LIVE555 Streaming Media - development & use
> Subject: Re: [Live-devel] Framed Source Issue
>
> >First, is it possible to explain using
> >TaskScheduler::scheduleDelayedTask(), as you suggested, a little
> >better?
>
> In your implementation of "doGetNextFrame()", if no input data is
> currently available to be delivered to the downstream object, then
> you could just call "TaskScheduler::scheduleDelayedTask()" with a
> delay parameter of 10000 (i.e., 10 ms), and passing a pointer to a
> function (that you would write) that would call "doGetNextFrame()"
> once again, to retry.  Then, after calling
> "TaskScheduler::scheduleDelayedTask()", just return.
>
> For example, you could look at the code on lines 58-74 of
> "liveMedia/MPEG4VideoFileServerMediaSubsession.cpp", which does
> something slightly similar.
>
>
> >Second, I also suspect that the freezing issue has to do with the
> >timestamps and the duration.
> >I am setting the duration in microsecs as 26122 (for 44.1 KHz, MP3
> >frames of 1152 samples) for audio, and 33333 (30 fps) for video. The
> >presentation time is obtained from gettimeofday(). However, I find
> >that the audio is called much more often than 26122 microsecs. Audio
> >is called only at intervals of a few thousand microsecs (about 10
> >times more than what it should be). Can you explain what may be
> >going on. I am using MP3 in MPEG1or2AudioRTPSink.
>
> Are you *sure* your "doGetFrame()" implementation is setting the
> "fDurationInMicroseconds" (and "fFrameSize" and "fPresentationTime")
> variable, before it calls "FramedSource::afterGetting()"?  One way
> you can check this is by looking at the parameters to the
> (subsequent) call to "MultiFramedRTPSink:: ::afterGettingFrame()",
> and checking that they are correct.
> --
>
> Ross Finlayson
> Live Networks, Inc.
> http://www.live555.com/
> _______________________________________________
> live-devel mailing list
> live-devel at lists.live555.com
> http://lists.live555.com/mailman/listinfo/live-devel
>


More information about the live-devel mailing list