static void emit_frame(vda_decoder_t *vdad, vda_frame_t *vf, media_queue_t *mq) { int i; CGSize siz; frame_info_t fi; memset(&fi, 0, sizeof(fi)); CVPixelBufferLockBaseAddress(vf->vf_buf, 0); for(i = 0; i < 3; i++ ) { fi.fi_data[i] = CVPixelBufferGetBaseAddressOfPlane(vf->vf_buf, i); fi.fi_pitch[i] = CVPixelBufferGetBytesPerRowOfPlane(vf->vf_buf, i); } if(vdad->vdad_last_pts != PTS_UNSET && vf->vf_pts != PTS_UNSET) { int64_t d = vf->vf_pts - vdad->vdad_last_pts; if(d > 1000 && d < 1000000) vdad->vdad_estimated_duration = d; } siz = CVImageBufferGetEncodedSize(vf->vf_buf); fi.fi_type = 'YUVP'; fi.fi_width = siz.width; fi.fi_height = siz.height; fi.fi_duration = vf->vf_duration > 10000 ? vf->vf_duration : vdad->vdad_estimated_duration; siz = CVImageBufferGetDisplaySize(vf->vf_buf); fi.fi_dar_num = siz.width; fi.fi_dar_den = siz.height; fi.fi_pts = vf->vf_pts; fi.fi_color_space = -1; fi.fi_epoch = vf->vf_epoch; fi.fi_drive_clock = 1; fi.fi_vshift = 1; fi.fi_hshift = 1; video_decoder_t *vd = vdad->vdad_vd; vd->vd_estimated_duration = fi.fi_duration; // For bitrate calculations if(fi.fi_duration > 0) video_deliver_frame(vd, &fi); CVPixelBufferUnlockBaseAddress(vf->vf_buf, 0); vdad->vdad_last_pts = vf->vf_pts; char fmt[64]; snprintf(fmt, sizeof(fmt), "h264 (VDA) %d x %d", fi.fi_width, fi.fi_height); prop_set_string(mq->mq_prop_codec, fmt); }
static void h264_dec_output_cb(VTH264DecCtx *ctx, void *sourceFrameRefCon, OSStatus status, VTDecodeInfoFlags infoFlags, CVImageBufferRef imageBuffer, CMTime presentationTimeStamp, CMTime presentationDuration ) { CGSize vsize; MSPicture pixbuf_desc; mblk_t *pixbuf = NULL; uint8_t *src_planes[4] = { NULL }; int src_strides[4] = { 0 }; size_t i; if(status != noErr || imageBuffer == NULL) { ms_error("VideoToolboxDecoder: fail to decode one frame: error %d", status); ms_filter_notify_no_arg(ctx->f, MS_VIDEO_DECODER_DECODING_ERRORS); ms_filter_lock(ctx->f); if(ctx->enable_avpf) { ms_error("VideoToolboxDecoder: sending PLI"); ms_filter_notify_no_arg(ctx->f, MS_VIDEO_DECODER_SEND_PLI); } ms_filter_unlock(ctx->f); return; } vsize = CVImageBufferGetEncodedSize(imageBuffer); ctx->vsize.width = (int)vsize.width; ctx->vsize.height = (int)vsize.height; pixbuf = ms_yuv_buf_allocator_get(ctx->pixbuf_allocator, &pixbuf_desc, (int)vsize.width, (int)vsize.height); CVPixelBufferLockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly); for(i=0; i<3; i++) { src_planes[i] = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, i); src_strides[i] = (int)CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, i); } ms_yuv_buf_copy(src_planes, src_strides, pixbuf_desc.planes, pixbuf_desc.strides, ctx->vsize); CVPixelBufferUnlockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly); ms_mutex_lock(&ctx->mutex); ms_queue_put(&ctx->queue, pixbuf); ms_mutex_unlock(&ctx->mutex); }
static void emit_frame(vtb_decoder_t *vtbd, vtb_frame_t *vf, media_queue_t *mq) { CGSize siz; frame_info_t fi; memset(&fi, 0, sizeof(fi)); if(vtbd->vtbd_last_pts != PTS_UNSET && vf->vf_mbm.mbm_pts != PTS_UNSET) { int64_t d = vf->vf_mbm.mbm_pts - vtbd->vtbd_last_pts; if(d > 1000 && d < 1000000) vtbd->vtbd_estimated_duration = d; } siz = CVImageBufferGetDisplaySize(vf->vf_buf); fi.fi_dar_num = siz.width; fi.fi_dar_den = siz.height; fi.fi_pts = vf->vf_mbm.mbm_pts; fi.fi_color_space = -1; fi.fi_epoch = vf->vf_mbm.mbm_epoch; fi.fi_drive_clock = vf->vf_mbm.mbm_drive_clock; fi.fi_user_time = vf->vf_mbm.mbm_user_time; fi.fi_vshift = 1; fi.fi_hshift = 1; fi.fi_duration = vf->vf_mbm.mbm_duration > 10000 ? vf->vf_mbm.mbm_duration : vtbd->vtbd_estimated_duration; siz = CVImageBufferGetEncodedSize(vf->vf_buf); fi.fi_width = siz.width; fi.fi_height = siz.height; video_decoder_t *vd = vtbd->vtbd_vd; vd->vd_estimated_duration = fi.fi_duration; // For bitrate calculations switch(vtbd->vtbd_pixel_format) { case kCVPixelFormatType_420YpCbCr8Planar: fi.fi_type = 'YUVP'; CVPixelBufferLockBaseAddress(vf->vf_buf, 0); for(int i = 0; i < 3; i++ ) { fi.fi_data[i] = CVPixelBufferGetBaseAddressOfPlane(vf->vf_buf, i); fi.fi_pitch[i] = CVPixelBufferGetBytesPerRowOfPlane(vf->vf_buf, i); } if(fi.fi_duration > 0) video_deliver_frame(vd, &fi); CVPixelBufferUnlockBaseAddress(vf->vf_buf, 0); break; case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange: fi.fi_type = 'CVPB'; fi.fi_data[0] = (void *)vf->vf_buf; if(fi.fi_duration > 0) video_deliver_frame(vd, &fi); break; } vtbd->vtbd_last_pts = vf->vf_mbm.mbm_pts; char fmt[64]; snprintf(fmt, sizeof(fmt), "h264 (VTB) %d x %d", fi.fi_width, fi.fi_height); prop_set_string(mq->mq_prop_codec, fmt); }
void jit_gl_hap_draw_frame(void *jitob, CVImageBufferRef frame) { t_jit_gl_hap * x = (t_jit_gl_hap*)jitob; CFTypeID imageType = CFGetTypeID(frame); OSType newPixelFormat; 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); newPixelFormat = CVPixelBufferGetPixelFormatType(x->buffer); if(x->buffer && x->hap_format==JIT_GL_HAP_PF_HAP) { size_t extraRight, extraBottom; 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; } 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->flipped) { jit_attr_setlong(x->texoutput, gensym("flip"), 1); x->flipped = 1; } //x->drawhap = 1; } else if(x->buffer) {// && x->hap_format==JIT_GL_HAP_PF_HAP) { if( newPixelFormat == k24RGBPixelFormat ) x->newInternalFormat = GL_RGB8; else if( newPixelFormat == k32BGRAPixelFormat ) x->newInternalFormat = GL_RGBA8; else { x->validframe = 0; return; } x->roundedWidth = x->dim[0]; x->roundedHeight = x->dim[1]; x->newDataLength = CVPixelBufferGetDataSize(x->buffer); x->rowLength = CVPixelBufferGetBytesPerRow( x->buffer ) / (x->hap_format==JIT_GL_HAP_PF_RGB ? 3 : 4); x->target = GL_TEXTURE_RECTANGLE_EXT; if(!x->flipped) { jit_attr_setlong(x->texoutput, gensym("flip"), 1); x->flipped = 1; } x->validframe = 1; } } else { #ifdef MAC_VERSION CGSize imageSize = CVImageBufferGetEncodedSize(frame); bool flipped = CVOpenGLTextureIsFlipped(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->flipped!=flipped) { jit_attr_setlong(x->texoutput, gensym("flip"), flipped); x->flipped = flipped; } #endif } }