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