void jit_gl_hap_draw_frame(void *jitob, CVImageBufferRef frame) { t_jit_gl_hap * x = (t_jit_gl_hap*)jitob; CFTypeID imageType = CFGetTypeID(frame); if(x->validframe) return; if (imageType == CVPixelBufferGetTypeID()) { // Update the texture CVBufferRetain(frame); if(x->buffer) { CVPixelBufferUnlockBaseAddress(x->buffer, kCVPixelBufferLock_ReadOnly); CVBufferRelease(x->buffer); } x->buffer = frame; CVPixelBufferLockBaseAddress(x->buffer, kCVPixelBufferLock_ReadOnly); x->dim[0] = CVPixelBufferGetWidth(x->buffer); x->dim[1] = CVPixelBufferGetHeight(x->buffer); if(x->buffer) { size_t extraRight, extraBottom; OSType newPixelFormat; unsigned int bitsPerPixel; size_t bytesPerRow; size_t actualBufferSize; CVPixelBufferGetExtendedPixels(x->buffer, NULL, &extraRight, NULL, &extraBottom); x->roundedWidth = x->dim[0] + extraRight; x->roundedHeight = x->dim[1] + extraBottom; if (x->roundedWidth % 4 != 0 || x->roundedHeight % 4 != 0) { x->validframe = 0; return; } newPixelFormat = CVPixelBufferGetPixelFormatType(x->buffer); switch (newPixelFormat) { case kHapPixelFormatTypeRGB_DXT1: x->newInternalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; bitsPerPixel = 4; break; case kHapPixelFormatTypeRGBA_DXT5: case kHapPixelFormatTypeYCoCg_DXT5: x->newInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; bitsPerPixel = 8; break; default: // we don't support non-DXT pixel buffers x->validframe = 0; return; break; } x->useshader = (newPixelFormat == kHapPixelFormatTypeYCoCg_DXT5); bytesPerRow = (x->roundedWidth * bitsPerPixel) / 8; x->newDataLength = bytesPerRow * x->roundedHeight; // usually not the full length of the buffer actualBufferSize = CVPixelBufferGetDataSize(x->buffer); // Check the buffer is as large as we expect it to be if (x->newDataLength > actualBufferSize) { x->validframe = 0; return; } // If we got this far we're good to go x->validframe = 1; x->target = GL_TEXTURE_2D; if(!x->drawhap) { jit_attr_setlong(x->texoutput, gensym("flip"), 1); x->drawhap = 1; } } } else { #ifdef MAC_VERSION CGSize imageSize = CVImageBufferGetEncodedSize(frame); x->texture = CVOpenGLTextureGetName(frame); x->useshader = 0; x->dim[0] = (t_atom_long)imageSize.width; x->dim[1] = (t_atom_long)imageSize.height; x->validframe = 1; x->target = GL_TEXTURE_RECTANGLE_ARB; if(x->drawhap) { jit_attr_setlong(x->texoutput, gensym("flip"), 0); x->drawhap = 0; } #endif } }
GstBuffer * gst_core_video_buffer_new (CVBufferRef cvbuf, GstVideoInfo * vinfo) { CVPixelBufferRef pixbuf = NULL; GstBuffer *buf; GstCoreVideoMeta *meta; guint n_planes; gsize offset[GST_VIDEO_MAX_PLANES]; gint stride[GST_VIDEO_MAX_PLANES]; if (CFGetTypeID (cvbuf) != CVPixelBufferGetTypeID ()) /* TODO: Do we need to handle other buffer types? */ goto error; pixbuf = (CVPixelBufferRef) cvbuf; if (CVPixelBufferLockBaseAddress (pixbuf, 0) != kCVReturnSuccess) { goto error; } buf = gst_buffer_new (); /* add the corevideo meta to free the underlying corevideo buffer */ meta = (GstCoreVideoMeta *) gst_buffer_add_meta (buf, gst_core_video_meta_get_info (), NULL); meta->cvbuf = CVBufferRetain (cvbuf); meta->pixbuf = pixbuf; /* set stride, offset and size */ memset (&offset, 0, sizeof (offset)); memset (&stride, 0, sizeof (stride)); if (CVPixelBufferIsPlanar (pixbuf)) { int i, size, off; n_planes = CVPixelBufferGetPlaneCount (pixbuf); off = 0; for (i = 0; i < n_planes; ++i) { stride[i] = CVPixelBufferGetBytesPerRowOfPlane (pixbuf, i); size = stride[i] * CVPixelBufferGetHeightOfPlane (pixbuf, i); offset[i] = off; off += size; gst_buffer_append_memory (buf, gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, CVPixelBufferGetBaseAddressOfPlane (pixbuf, i), size, 0, size, NULL, NULL)); } } else { int size; n_planes = 1; stride[0] = CVPixelBufferGetBytesPerRow (pixbuf); offset[0] = 0; size = stride[0] * CVPixelBufferGetHeight (pixbuf); gst_buffer_append_memory (buf, gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, CVPixelBufferGetBaseAddress (pixbuf), size, 0, size, NULL, NULL)); } if (vinfo) { GstVideoMeta *video_meta; video_meta = gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE, vinfo->finfo->format, CVPixelBufferGetWidth (pixbuf), CVPixelBufferGetHeight (pixbuf), n_planes, offset, stride); } return buf; error: return NULL; }
void CDVDVideoCodecVDA::VDADecoderCallback( void *decompressionOutputRefCon, CFDictionaryRef frameInfo, OSStatus status, uint32_t infoFlags, CVImageBufferRef imageBuffer) { CCocoaAutoPool pool; // Warning, this is an async callback. There can be multiple frames in flight. CDVDVideoCodecVDA *ctx = (CDVDVideoCodecVDA*)decompressionOutputRefCon; if (imageBuffer == NULL) { //CLog::Log(LOGDEBUG, "%s - imageBuffer is NULL", __FUNCTION__); return; } OSType format_type = CVPixelBufferGetPixelFormatType(imageBuffer); if ((format_type != kCVPixelFormatType_422YpCbCr8) && (format_type != kCVPixelFormatType_32BGRA) ) { CLog::Log(LOGERROR, "%s - imageBuffer format is not '2vuy' or 'BGRA',is reporting 0x%x", __FUNCTION__, (unsigned int)format_type); return; } if (kVDADecodeInfo_FrameDropped & infoFlags) { CLog::Log(LOGDEBUG, "%s - frame dropped", __FUNCTION__); return; } // allocate a new frame and populate it with some information. // this pointer to a frame_queue type keeps track of the newest decompressed frame // and is then inserted into a linked list of frame pointers depending on the display time // parsed out of the bitstream and stored in the frameInfo dictionary by the client frame_queue *newFrame = (frame_queue*)calloc(sizeof(frame_queue), 1); newFrame->nextframe = NULL; newFrame->pixel_buffer_format = format_type; newFrame->pixel_buffer_ref = CVBufferRetain(imageBuffer); GetFrameDisplayTimeFromDictionary(frameInfo, newFrame); // since the frames we get may be in decode order rather than presentation order // our hypothetical callback places them in a queue of frames which will // hold them in display order for display on another thread pthread_mutex_lock(&ctx->m_queue_mutex); frame_queue base; base.nextframe = ctx->m_display_queue; frame_queue *ptr = &base; for(; ptr->nextframe; ptr = ptr->nextframe) { if(ptr->nextframe->pts == DVD_NOPTS_VALUE || newFrame->pts == DVD_NOPTS_VALUE) continue; if(ptr->nextframe->pts > newFrame->pts) break; } /* insert after ptr */ newFrame->nextframe = ptr->nextframe; ptr->nextframe = newFrame; /* update anchor if needed */ if(newFrame->nextframe == ctx->m_display_queue) ctx->m_display_queue = newFrame; ctx->m_queue_depth++; // pthread_mutex_unlock(&ctx->m_queue_mutex); }