Esempio n. 1
0
OSErr qQuickTimeEncoderCallback(void *encodedFrameOutputRefCon,
                                ICMCompressionSessionRef session,
                                OSStatus error,
                                ICMEncodedFrameRef frame,
                                void *reserved)
{
    QEncoder* encoder = (QEncoder*)encodedFrameOutputRefCon;
    QCallbackData *cbd = &(encoder->callbackData);
    char* buf;

    int frameDataSize = ICMEncodedFrameGetDataSize(frame);
    ICMFrameType frameType = ICMEncodedFrameGetFrameType(frame);  // is this a keyframe?

    ImageDescriptionHandle handle;
    OSStatus err;
    long count;

    // XXXX DEBUGGGING: let's see if this mofo has any extensions
    /*
    err = ICMEncodedFrameGetImageDescription(frame, &handle);
    if (err != noErr) {
    	fprintf(QSTDERR, "\nqQuickTimeEncoderCallback(): cannot get an image description of the frame");
    	fprintf(QSTDERR, "\n\tQUICKTIME ERROR CODE: %d", err);
    	return noErr; // I don't know what the QuickTime error code should be (or how QT would interpret it)
    }
    err = CountImageDescriptionExtensionType(handle, 'avcC', &count);
    if (err != noErr) {
    	fprintf(QSTDERR, "\nqQuickTimeEncoderCallback(): cannot get extension count for type 'avcC'");
    	fprintf(QSTDERR, "\n\tQUICKTIME ERROR CODE: %d", err);
    	return noErr; // I don't know what the QuickTime error code should be (or how QT would interpret it)
    }
    fprintf(QSTDERR, "\ncount for extension type 'avcC': %d", count);
    */

    int dataErr = qPrepareCallbackDataForWrite(cbd, frameDataSize+1);
    if (dataErr) {
        fprintf(QSTDERR, "\nqQuickTimeEncoderCallback: cannot get a callback buffer");
        return noErr; // I don't know what the QuickTime error code should be (or how QT would interpret it)
    }
    buf = cbd->data;

    // QwaqMediaPlugin-V1: first byte denotes whether the frame is a keyframe or not.
    if (frameType == kICMFrameType_I) buf[0] = 1;  // yep, that's a keyframe
    else buf[0] = 0;                              // nosirree, that ain't no keyframe

//XXXX: debugging: is the frame a keyframe?
//fprintf(QSTDERR, "\nkeyframe value: %d", frameType);

    // Store the data.
    memcpy(buf+1, ICMEncodedFrameGetDataPtr(frame), frameDataSize);

    interpreterProxy->signalSemaphoreWithIndex(encoder->semaIndex);
    return noErr;
}
Esempio n. 2
0
static OSStatus
_frame_compressed(void *efRefCon, ICMCompressionSessionRef session,
                  OSStatus err, ICMEncodedFrameRef ef, void *reserved)
{
    dbg_printf("[ vOE]  >> [%08lx] :: _frame_compressed()\n", (UInt32) -1);
    if (!err) {
        StreamInfoPtr si = (StreamInfoPtr) efRefCon;
        ImageDescriptionHandle imgDesc = NULL;
        ImageDescription *id;
        UInt32 enc_size = ICMEncodedFrameGetDataSize(ef);

        err = ICMEncodedFrameGetImageDescription(ef, &imgDesc);
        if (!err) {
            id = *imgDesc;

            dbg_printf("[ vOE]  f> [%08lx] :: _frame_compressed() = %ld, '%4.4s'"
                       " %08lx %08lx [%d x %d] [%f x %f] %ld %d %d %d\n",
                       (UInt32) -1, err, (char *) &id->cType,
                       id->temporalQuality, id->spatialQuality, id->width,
                       id->height, id->hRes / 65536.0, id->vRes / 65536.0,
                       id->dataSize, id->frameCount, id->depth, id->clutID);
            dbg_printf("[ vOE]  fi [%08lx] :: _frame_compressed() = %lld %ld %ld\n",
                       (UInt32) -1, ICMEncodedFrameGetDecodeDuration(ef),
                       enc_size, ICMEncodedFrameGetBufferSize(ef));
        }

        if (si->si_v.cs_imdsc == NULL)
            si->si_v.cs_imdsc = imgDesc;

        if (si->si_v.op_buffer_size < enc_size) {
            si->si_v.op_buffer = realloc(si->si_v.op_buffer, enc_size);
            si->si_v.op_buffer_size = enc_size;
        }
        memcpy(si->si_v.op_buffer, ICMEncodedFrameGetDataPtr(ef), enc_size);

        /* skip one byte (pre-padding);
           see TheoraEncoder.c, Theora_ImageEncoderEncodeFrame() */
        si->si_v.op.packet = si->si_v.op_buffer + 1;
        si->si_v.op.bytes = enc_size - 1;
        //si->si_v.op.packetno = si->packets_total++;
        //si->si_v.op.granulepos = si->last_grpos++;
        si->si_v.op_flags = ICMEncodedFrameGetMediaSampleFlags(ef);
    }

    dbg_printf("[ vOE] <   [%08lx] :: _frame_compressed() = %ld\n",
               (UInt32) -1, err);
    return err;
}
static ComponentResult emitEncodedFrame(VP8EncoderGlobals glob, const vpx_codec_cx_pkt_t *pkt)
{
  ICMMutableEncodedFrameRef encodedFrame = NULL;
  unsigned char *dataPtr;
  size_t dataSize = 0;
  ComponentResult err= noErr;
  MediaSampleFlags mediaSampleFlags;

  Boolean keyFrame = false;
  Boolean droppableFrame = false;
  Boolean invisibleFrame = false;

  //get the source frame off the queue
  //for an alt-ref frame this won't work.
  ICMCompressorSourceFrameRef sourceFrame = NULL;
  dbg_printf("[VP8E] emitEncodedFrame frames out %ld, pts %ld,  frames in queue %d\n",
             glob->sourceQueue.frames_out, pkt->data.frame.pts, glob->sourceQueue.size);

  if (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE)
  {
    dbg_printf("[VP8E] Keeping Altref Frame data %ld\n", pkt->data.frame.sz);
    //This indicates an alt -ref frame, instead of popping the frame I'm just going to hold on to data and append.
    if (glob->altRefFrame.buf != NULL)
    {
      //this shouldn't happen
      dbg_printf("[VP8E]  Errror: possible memory leak in alt ref frame data\n");
    }
    glob->altRefFrame.buf = malloc(pkt->data.frame.sz);
    memcpy(glob->altRefFrame.buf, pkt->data.frame.buf, pkt->data.frame.sz);
    glob->altRefFrame.size = pkt->data.frame.sz;
    return noErr;
  }


  while (glob->sourceQueue.size > 0)
  {
    //time is in timeBase *2
    UInt32 expectedTime = glob->sourceQueue.frames_out  * 2 ;
    dbg_printf("Expected time = %lu\n", expectedTime);
    sourceFrame = popSourceFrame(glob);
    if (expectedTime >= pkt->data.frame.pts)
    {
      break;
    }
    else //frames_out < pts
    {
      dbg_printf("[VP8E] Dropping frame %ld, Queue size  %ld\n",
                 glob->sourceQueue.frames_out, glob->sourceQueue.size);
      ICMCompressorSessionDropFrame(glob->session, sourceFrame);
    }
    sourceFrame = NULL;
  }
  if (sourceFrame == NULL && (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE) == 0)
  {
    dbg_printf("[VP8e] Error: asked to output a frame at time %ld but last frame in was %ld\n",
               pkt->data.frame.pts, glob->sourceQueue.frames_in);
    return qErr;
  }
  TimeValue64 frameDisplayDuration = 0;
  TimeScale timescale = 0;
  ICMValidTimeFlags validTimeFlags = 0;
  unsigned int bitrate = 0;
  TimeValue64 timeStamp=0,decodeTimeStamp=0;
  TimeScale timeScale =0;

  //use the time stamp of the input frame for the output frame
  err = ICMCompressorSourceFrameGetDisplayTimeStampAndDuration(sourceFrame, &timeStamp,NULL, &timeScale, NULL);
  decodeTimeStamp = timeStamp;
  dbg_printf("[VP8e] ICMCompressorSourceFrameGetDisplayTimeStampAndDuration(%lld,%lld)\n" ,timeStamp, timeScale );

  err = ICMEncodedFrameCreateMutable(glob->session, sourceFrame,
                                     glob->maxEncodedDataSize, &encodedFrame);
  if (err) goto bail;
  dataPtr = ICMEncodedFrameGetDataPtr(encodedFrame);
  dbg_printf("[vp8e - %08lx] getDataPtr %x\n", (UInt32)glob, dataPtr);

  //paranoid check to make sure I don't write past my buffer
  if (pkt->data.frame.sz + dataSize >=  glob->maxEncodedDataSize)
  {
    dbg_printf("[vp8e - %08lx] Error: buffer overload.  Encoded frame larger than raw frame\n", (UInt32)glob);
    goto bail;
  }

  //if we have an altref frame, prepend that data.
  if (glob->altRefFrame.buf != NULL)
  {
    //This method prepends the altref size and altref data to the following interframe.
    // I've also tried sending in bogus source frames, and sending back altref via those (has major implementation issues)
    // Also I've tried reading altref size from the data... Seems as though I can't though in the future that may be better.
    //Quicktime and altref frames are difficult because of paramErr failures that occur when trying to use sourceframes 2x

    memcpy(&(dataPtr[dataSize]), &glob->altRefFrame.size, sizeof(glob->altRefFrame.size));
    dataSize += sizeof(glob->altRefFrame.size);
    dbg_printf("[VP8e] Appended altrefsize %ld bytes %lu\n", glob->altRefFrame.size, dataSize);

    memcpy(&(dataPtr[dataSize]), glob->altRefFrame.buf, glob->altRefFrame.size);
    dataSize += glob->altRefFrame.size;
    dbg_printf("[VP8e] Appended altref frame bytes %lu\n", dataSize);
  }

  dbg_printf("[vp8e - %08lx] copying %d bytes of data to output dataBuffer\n", (UInt32)glob, pkt->data.frame.sz);
  memcpy(&(dataPtr[dataSize]), pkt->data.frame.buf, pkt->data.frame.sz);
  dataSize += pkt->data.frame.sz;

  dbg_printf("[vp8e - %08lx]  Encoded frame %d with %d bytes of data\n", (UInt32)glob, glob->frameCount, dataSize);

  keyFrame = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
  dbg_printf(keyFrame ? "Key Packet\n" : "Non Key Packet\n");
  droppableFrame = pkt->data.frame.flags & VPX_FRAME_IS_DROPPABLE;
  dbg_printf(droppableFrame ? "Droppable frame\n" : "Not droppable frame\n");
  invisibleFrame = pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE;

  // Update the encoded frame to reflect the actual frame size, sample flags and frame type.
  err = ICMEncodedFrameSetDataSize(encodedFrame, dataSize);

  if (err) goto bail;

  mediaSampleFlags = 0;

  if (! keyFrame)
  {
    mediaSampleFlags |= mediaSampleNotSync;

    if (droppableFrame)
      mediaSampleFlags |= mediaSampleDroppable;
  }

  ICMFrameType frameType = keyFrame ? kICMFrameType_I : kICMFrameType_P;
  if (glob->altRefFrame.buf != NULL)
  {
    frameType = kICMFrameType_Unknown;
    free(glob->altRefFrame.buf);
    glob->altRefFrame.buf =NULL;
    glob->altRefFrame.size =0;
    dbg_printf("[vp8e - %08lx] frame type set to Unknown\n", (UInt32)glob);
  }
  else
    dbg_printf("[vp8e - %08lx] frame type set to %c\n", (UInt32)glob, keyFrame ? 'I' : 'P');

  if (kICMFrameType_I == frameType)
    mediaSampleFlags |= mediaSampleDoesNotDependOnOthers;

  err = ICMEncodedFrameSetMediaSampleFlags(encodedFrame, mediaSampleFlags);

  if (err)
    goto bail;

  err = ICMEncodedFrameSetFrameType(encodedFrame, frameType);
  if (err)
    goto bail;

  if (timeStamp == 0)
  {
    timeStamp = pkt->data.frame.pts * glob->cfg.g_timebase.num * timeScale / 2 /glob->cfg.g_timebase.den ;  //pts is timebase *2 2
  }

  dbg_printf("[vp8e]setting ICMEncodedFrameSetDisplayTimeStamp %lld\n", timeStamp);
  err= ICMEncodedFrameSetDisplayTimeStamp(encodedFrame, timeStamp);

  // Output the encoded frame.
  dbg_printf("[vp8e - %08lx]  Emit Encoded Frames\n", (UInt32)glob);
  err = ICMCompressorSessionEmitEncodedFrame(glob->session, encodedFrame, 1, &sourceFrame);

  if (err)
    goto bail;

bail:
  // Since we created this, we must also release it.
  if (encodedFrame)
  {
    ICMEncodedFrameRelease(encodedFrame);
  }
  if (err)
    dbg_printf("[VP8e] EmitEncodedFrame Error = %d\n", err);
  return err;
}