int op(int op_id, int arg) { int r; // lock operation mutex pthread_mutex_lock(&m_op_lock); mlt_log_debug( getConsumer(), "%s: op_id=%d\n", __FUNCTION__, op_id ); // notify op id pthread_mutex_lock(&m_op_arg_mutex); m_op_id = op_id; m_op_arg = arg; pthread_cond_signal(&m_op_arg_cond); pthread_mutex_unlock(&m_op_arg_mutex); // wait op done pthread_mutex_lock(&m_op_arg_mutex); while(OP_NONE != m_op_id) pthread_cond_wait(&m_op_arg_cond, &m_op_arg_mutex); pthread_mutex_unlock(&m_op_arg_mutex); // save result r = m_op_res; mlt_log_debug( getConsumer(), "%s: r=%d\n", __FUNCTION__, r ); // unlock operation mutex pthread_mutex_unlock(&m_op_lock); return r; }
void createFrame() { m_videoFrame = 0; // Generate a DeckLink video frame if ( S_OK != m_deckLinkOutput->CreateVideoFrame( m_width, m_height, m_width * 2, bmdFormat8BitYUV, bmdFrameFlagDefault, &m_videoFrame ) ) { mlt_log_verbose( &m_consumer, "Failed to create video frame\n" ); stop(); return; } // Make the first line black for field order correction. uint8_t *buffer = 0; if ( S_OK == m_videoFrame->GetBytes( (void**) &buffer ) && buffer ) { for ( int i = 0; i < m_width; i++ ) { *buffer++ = 128; *buffer++ = 16; } } mlt_log_debug( &m_consumer, "created video frame\n" ); mlt_deque_push_back( m_videoFrameQ, m_videoFrame ); }
static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; mlt_profile profile = (mlt_profile) mlt_frame_pop_get_image( frame ); mlt_properties properties = MLT_FRAME_PROPERTIES(frame); mlt_image_format format_from = *format; mlt_image_format format_to = mlt_image_rgb24; error = mlt_frame_get_image( frame, image, format, width, height, writable ); int frame_colorspace = mlt_properties_get_int( properties, "colorspace" ); if ( !error && *format == mlt_image_yuv422 && profile->colorspace > 0 && frame_colorspace > 0 && frame_colorspace != profile->colorspace ) { mlt_log_debug( NULL, "[filter avcolor_space] colorspace %d -> %d\n", frame_colorspace, profile->colorspace ); // Convert to RGB using frame's colorspace error = convert_image( frame, image, &format_from, format_to ); // Convert to YUV using profile's colorspace if ( !error ) { *image = mlt_properties_get_data( properties, "image", NULL ); format_from = mlt_image_rgb24; format_to = *format; mlt_properties_set_int( properties, "colorspace", profile->colorspace ); error = convert_image( frame, image, &format_from, format_to ); *image = mlt_properties_get_data( properties, "image", NULL ); } } return error; }
GlslManager::~GlslManager() { mlt_log_debug(get_service(), "%s\n", __FUNCTION__); cleanupContext(); delete initEvent; delete closeEvent; }
static void vdpau_fini( producer_avformat self ) { if ( !self->vdpau ) return; mlt_log_debug( NULL, "vdpau_fini (%x)\n", self->vdpau->device ); if ( self->vdpau->decoder != VDP_INVALID_HANDLE ) vdp_decoder_destroy( self->vdpau->decoder ); if ( self->vdpau->device != VDP_INVALID_HANDLE ) vdp_device_destroy( self->vdpau->device ); free( self->vdpau ); self->vdpau = NULL; }
void GlslManager::onInit( mlt_properties owner, GlslManager* filter ) { mlt_log_debug( filter->get_service(), "%s\n", __FUNCTION__ ); #ifdef WIN32 std::string path = std::string(mlt_environment("MLT_APPDIR")).append("\\share\\movit"); #elif defined(__DARWIN__) && defined(RELOCATABLE) std::string path = std::string(mlt_environment("MLT_APPDIR")).append("/share/movit"); #else std::string path = std::string(getenv("MLT_MOVIT_PATH") ? getenv("MLT_MOVIT_PATH") : SHADERDIR); #endif ::init_movit( path, mlt_log_get_level() == MLT_LOG_DEBUG? MOVIT_DEBUG_ON : MOVIT_DEBUG_OFF ); filter->set( "glsl_supported", movit_initialized ); }
static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { /* Obtain properties of frame */ mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); /* Obtain the producer for this frame */ producer_ktitle this = mlt_properties_get_data( properties, "producer_kdenlivetitle", NULL ); /* Obtain properties of producer */ mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( &this->parent ); *width = mlt_properties_get_int( properties, "rescale_width" ); *height = mlt_properties_get_int( properties, "rescale_height" ); /* Allocate the image */ int size = *width * ( *height ) * 4; /* Allocate the image */ *format = mlt_image_rgb24a; mlt_position time = mlt_producer_position( &this->parent ) + mlt_producer_get_in( &this->parent ); if ( mlt_properties_get_int( producer_props, "force_reload" ) ) { if (mlt_properties_get_int( producer_props, "force_reload" ) > 1) read_xml(producer_props); mlt_properties_set_int( producer_props, "force_reload", 0 ); drawKdenliveTitle( this, frame, *width, *height, time, 1); } else drawKdenliveTitle( this, frame, *width, *height, time, 0); // Get width and height (may have changed during the refresh) *width = mlt_properties_get_int( properties, "width" ); *height = mlt_properties_get_int( properties, "height" ); if ( this->current_image ) { // Clone the image and the alpha int image_size = this->current_width * ( this->current_height ) * 4; uint8_t *image_copy = mlt_pool_alloc( image_size ); memcpy( image_copy, this->current_image, image_size ); // Now update properties so we free the copy after mlt_properties_set_data( properties, "image", image_copy, image_size, mlt_pool_release, NULL ); // We're going to pass the copy on *buffer = image_copy; /* Update the frame */ mlt_properties_set_data( properties, "image", *buffer, size, mlt_pool_release, NULL ); mlt_log_debug( MLT_PRODUCER_SERVICE( &this->parent ), "width:%d height:%d %s\n", *width, *height, mlt_image_format_name( *format ) ); } return 0; }
virtual ~DeckLinkConsumer() { mlt_log_debug( getConsumer(), "%s: entering\n", __FUNCTION__ ); SAFE_RELEASE( m_displayMode ); SAFE_RELEASE( m_deckLinkKeyer ); SAFE_RELEASE( m_deckLinkOutput ); SAFE_RELEASE( m_deckLink ); mlt_deque_close( m_aqueue ); mlt_deque_close( m_frames ); op(OP_EXIT, 0); mlt_log_debug( getConsumer(), "%s: waiting for op thread\n", __FUNCTION__ ); pthread_join(m_op_thread, NULL); mlt_log_debug( getConsumer(), "%s: finished op thread\n", __FUNCTION__ ); pthread_mutex_destroy(&m_op_lock); pthread_mutex_destroy(&m_op_arg_mutex); pthread_cond_destroy(&m_op_arg_cond); mlt_log_debug( getConsumer(), "%s: exiting\n", __FUNCTION__ ); }
void mlt_slices_close( mlt_slices ctx ) { int j; pthread_mutex_lock( &g_lock ); mlt_log_debug( NULL, "%s:%d: ctx=[%p][%s] closing\n", __FUNCTION__, __LINE__, ctx, ctx->name ); /* check reference count */ if ( ctx->ref ) { ctx->ref--; mlt_log_debug( NULL, "%s:%d: ctx=[%p][%s] new ref=%d\n", __FUNCTION__, __LINE__, ctx, ctx->name, ctx->ref ); pthread_mutex_unlock( &g_lock ); return; } pthread_mutex_unlock( &g_lock ); /* notify to exit */ ctx->f_exit = 1; pthread_mutex_lock( &ctx->cond_mutex ); pthread_cond_broadcast( &ctx->cond_var_job); pthread_cond_broadcast( &ctx->cond_var_ready); pthread_mutex_unlock( &ctx->cond_mutex ); /* wait for threads exit */ for ( j = 0; j < ctx->count; j++ ) pthread_join ( ctx->threads[j], NULL ); /* destroy vars */ pthread_cond_destroy ( &ctx->cond_var_ready ); pthread_cond_destroy ( &ctx->cond_var_job ); pthread_mutex_destroy ( &ctx->cond_mutex ); /* free context */ free ( ctx ); }
static void vdpau_release_buffer( AVCodecContext *codec_context, AVFrame *frame ) { producer_avformat self = codec_context->opaque; if ( self->vdpau ) { struct vdpau_render_state *render = (struct vdpau_render_state*) frame->data[0]; mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_release_buffer (%x)\n", render->surface ); int i; render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE; for ( i = 0; i < 4; i++ ) frame->data[i] = NULL; mlt_deque_push_back( self->vdpau->deque, render ); } }
static int vdpau_get_buffer( AVCodecContext *codec_context, AVFrame *frame ) { int error = 0; producer_avformat self = codec_context->opaque; mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_get_buffer\n" ); if ( self->vdpau && mlt_deque_count( self->vdpau->deque ) ) { struct vdpau_render_state *render = mlt_deque_pop_front( self->vdpau->deque ); if ( render ) { frame->data[0] = (uint8_t*) render; frame->data[1] = (uint8_t*) render; frame->data[2] = (uint8_t*) render; frame->linesize[0] = 0; frame->linesize[1] = 0; frame->linesize[2] = 0; frame->type = FF_BUFFER_TYPE_USER; render->state = FF_VDPAU_STATE_USED_FOR_REFERENCE; frame->reordered_opaque = codec_context->reordered_opaque; if ( frame->reference ) { self->vdpau->ip_age[0] = self->vdpau->ip_age[1] + 1; self->vdpau->ip_age[1] = 1; self->vdpau->b_age++; } else { self->vdpau->ip_age[0] ++; self->vdpau->ip_age[1] ++; self->vdpau->b_age = 1; } } else { mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "VDPAU surface underrun\n" ); error = -1; } } else { mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "VDPAU surface underrun\n" ); error = -1; } return error; }
void mlt_slices_run( mlt_slices ctx, int jobs, mlt_slices_proc proc, void* cookie ) { struct mlt_slices_runtime_s runtime, *r = &runtime; /* lock */ pthread_mutex_lock( &ctx->cond_mutex); /* check jobs count */ if ( jobs < 0 ) jobs = (-jobs) * ctx->count; if ( !jobs ) jobs = ctx->count; /* setup runtime args */ r->jobs = jobs; r->done = 0; r->curr = 0; r->proc = proc; r->cookie = cookie; r->next = NULL; /* attach job */ if ( ctx->tail ) { ctx->tail->next = r; ctx->tail = r; } else { ctx->head = ctx->tail = r; } /* notify workers */ pthread_cond_broadcast( &ctx->cond_var_job ); /* wait for end of task */ while( !ctx->f_exit && ( r->done < r->jobs ) ) { pthread_cond_wait( &ctx->cond_var_ready, &ctx->cond_mutex ); mlt_log_debug( NULL, "%s:%d: ctx=[%p][%s] signalled\n", __FUNCTION__, __LINE__ , ctx, ctx->name ); } pthread_mutex_unlock( &ctx->cond_mutex); }
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = mlt_frame_pop_service( frame ); *format = mlt_image_rgb24a; mlt_log_debug( MLT_FILTER_SERVICE( filter ), "frei0r %dx%d\n", *width, *height ); int error = mlt_frame_get_image( frame, image, format, width, height, 0 ); if ( error == 0 && *image ) { double position = mlt_filter_get_position( filter, frame ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); double time = position / mlt_profile_fps( profile ); int length = mlt_filter_get_length2( filter, frame ); process_frei0r_item( MLT_FILTER_SERVICE(filter), position, time, length, frame, image, width, height ); } return error; }
static void vdpau_producer_close( producer_avformat self ) { if ( self->vdpau ) { mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_producer_close\n" ); int i; for ( i = 0; i < MAX_VDPAU_SURFACES; i++ ) { if ( self->vdpau->render_states[i].surface != VDP_INVALID_HANDLE ) vdp_surface_destroy( self->vdpau->render_states[i].surface ); self->vdpau->render_states[i].surface = VDP_INVALID_HANDLE; } mlt_deque_close( self->vdpau->deque ); if ( self->vdpau->buffer ) mlt_pool_release( self->vdpau->buffer ); self->vdpau->buffer = NULL; vdpau_fini( self ); } }
static int jack_sync( jack_transport_state_t state, jack_position_t *jack_pos, void *arg ) { mlt_filter filter = (mlt_filter) arg; mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE(filter) ); mlt_position position = mlt_profile_fps( profile ) * jack_pos->frame / jack_pos->frame_rate + 0.5; int result = 1; mlt_log_debug( MLT_FILTER_SERVICE(filter), "%s frame %u rate %u pos %d last_pos %d\n", JACKSTATE(state), jack_pos->frame, jack_pos->frame_rate, position, mlt_properties_get_position( properties, "_last_pos" ) ); if ( state == JackTransportStopped ) { mlt_events_fire( properties, "jack-stopped", &position, NULL ); mlt_properties_set_int( properties, "_sync_guard", 0 ); } else if ( state == JackTransportStarting ) { result = 0; if ( !mlt_properties_get_int( properties, "_sync_guard" ) ) { mlt_properties_set_int( properties, "_sync_guard", 1 ); mlt_events_fire( properties, "jack-started", &position, NULL ); } else if ( position >= mlt_properties_get_position( properties, "_last_pos" ) - 2 ) { mlt_properties_set_int( properties, "_sync_guard", 0 ); result = 1; } } else { mlt_properties_set_int( properties, "_sync_guard", 0 ); } return result; }
static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, mlt_image_format output_format ) { // Nothing to do! if ( *format == output_format ) return 0; mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_log_debug( NULL, "filter_movit_convert: %s -> %s\n", mlt_image_format_name( *format ), mlt_image_format_name( output_format ) ); // Use CPU if glsl not initialized or not supported. GlslManager* glsl = GlslManager::get_instance(); if ( !glsl || !glsl->get_int("glsl_supported" ) ) return convert_on_cpu( frame, image, format, output_format ); // Do non-GL image conversions on a CPU-based image converter. if ( *format != mlt_image_glsl && output_format != mlt_image_glsl && output_format != mlt_image_glsl_texture ) return convert_on_cpu( frame, image, format, output_format ); int error = 0; int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); int img_size = mlt_image_format_size( *format, width, height, NULL ); mlt_producer producer = mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ); mlt_service service = MLT_PRODUCER_SERVICE(producer); GlslManager::get_instance()->lock_service( frame ); EffectChain* chain = GlslManager::get_chain( service ); MltInput* input = GlslManager::get_input( service ); if ( !chain || !input ) { GlslManager::get_instance()->unlock_service( frame ); return 2; } if ( *format != mlt_image_glsl ) { bool finalize_chain = false; if ( output_format == mlt_image_glsl_texture ) { // We might already have a texture from a previous conversion from mlt_image_glsl. glsl_texture texture = (glsl_texture) mlt_properties_get_data( properties, "movit.convert.texture", NULL ); // XXX: requires a special property set on the frame by the app for now // because we do not have reliable way to clear the texture property // when a downstream filter has changed image. if ( texture && mlt_properties_get_int( properties, "movit.convert.use_texture") ) { *image = (uint8_t*) &texture->texture; mlt_frame_set_image( frame, *image, 0, NULL ); mlt_properties_set_int( properties, "format", output_format ); *format = output_format; GlslManager::get_instance()->unlock_service( frame ); return error; } else { // Use a separate chain to convert image in RAM to OpenGL texture. // Use cached chain if available and compatible. Mlt::Producer producer( mlt_producer_cut_parent( mlt_frame_get_original_producer( frame ) ) ); chain = (EffectChain*) producer.get_data( "movit.convert.chain" ); input = (MltInput*) producer.get_data( "movit.convert.input" ); int w = producer.get_int( "movit.convert.width" ); int h = producer.get_int( "movit.convert.height" ); mlt_image_format f = (mlt_image_format) producer.get_int( "movit.convert.format" ); if ( !chain || width != w || height != h || output_format != f ) { chain = new EffectChain( width, height ); input = new MltInput( width, height ); chain->add_input( input ); chain->add_effect( new Mlt::VerticalFlip() ); finalize_chain = true; producer.set( "movit.convert.chain", chain, 0, (mlt_destructor) delete_chain ); producer.set( "movit.convert.input", input, 0 ); producer.set( "movit.convert.width", width ); producer.set( "movit.convert.height", height ); producer.set( "movit.convert.format", output_format ); } } } if ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) { input->useFlatInput( chain, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, width, height ); input->set_pixel_data( *image ); } else if ( *format == mlt_image_rgb24 ) { input->useFlatInput( chain, FORMAT_RGB, width, height ); input->set_pixel_data( *image ); } else if ( *format == mlt_image_yuv420p ) { ImageFormat image_format; YCbCrFormat ycbcr_format; if ( 709 == mlt_properties_get_int( properties, "colorspace" ) ) { image_format.color_space = COLORSPACE_REC_709; image_format.gamma_curve = GAMMA_REC_709; ycbcr_format.luma_coefficients = YCBCR_REC_709; } else if ( 576 == mlt_properties_get_int( properties, "height" ) ) { image_format.color_space = COLORSPACE_REC_601_625; image_format.gamma_curve = GAMMA_REC_601; ycbcr_format.luma_coefficients = YCBCR_REC_601; } else { image_format.color_space = COLORSPACE_REC_601_525; image_format.gamma_curve = GAMMA_REC_601; ycbcr_format.luma_coefficients = YCBCR_REC_601; } ycbcr_format.full_range = mlt_properties_get_int( properties, "force_full_luma" ); ycbcr_format.chroma_subsampling_x = ycbcr_format.chroma_subsampling_y = 2; // TODO: make new frame properties set by producers ycbcr_format.cb_x_position = ycbcr_format.cr_x_position = 0.0f; ycbcr_format.cb_y_position = ycbcr_format.cr_y_position = 0.5f; input->useYCbCrInput( chain, image_format, ycbcr_format, width, height ); input->set_pixel_data( *image ); } else if ( *format == mlt_image_yuv422 ) { ImageFormat image_format; YCbCrFormat ycbcr_format; if ( 709 == mlt_properties_get_int( properties, "colorspace" ) ) { image_format.color_space = COLORSPACE_REC_709; image_format.gamma_curve = GAMMA_REC_709; ycbcr_format.luma_coefficients = YCBCR_REC_709; } else if ( 576 == height ) { image_format.color_space = COLORSPACE_REC_601_625; image_format.gamma_curve = GAMMA_REC_601; ycbcr_format.luma_coefficients = YCBCR_REC_601; } else { image_format.color_space = COLORSPACE_REC_601_525; image_format.gamma_curve = GAMMA_REC_601; ycbcr_format.luma_coefficients = YCBCR_REC_601; } ycbcr_format.full_range = mlt_properties_get_int( properties, "force_full_luma" ); ycbcr_format.chroma_subsampling_x = 2; ycbcr_format.chroma_subsampling_y = 1; // TODO: make new frame properties set by producers ycbcr_format.cb_x_position = ycbcr_format.cr_x_position = 0.0f; ycbcr_format.cb_y_position = ycbcr_format.cr_y_position = 0.5f; input->useYCbCrInput( chain, image_format, ycbcr_format, width, height ); // convert chunky to planar uint8_t* planar = (uint8_t*) mlt_pool_alloc( img_size ); yuv422_to_yuv422p( *image, planar, width, height ); input->set_pixel_data( planar ); mlt_frame_set_image( frame, planar, img_size, mlt_pool_release ); } // Finalize the separate conversion chain if needed. if ( finalize_chain ) chain->finalize(); } if ( output_format != mlt_image_glsl ) { glsl_fbo fbo = glsl->get_fbo( width, height ); if ( output_format == mlt_image_glsl_texture ) { glsl_texture texture = glsl->get_texture( width, height, GL_RGBA ); glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo ); check_error(); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 ); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); GlslManager::render( service, chain, fbo->fbo, width, height ); glFinish(); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); *image = (uint8_t*) &texture->texture; mlt_frame_set_image( frame, *image, 0, NULL ); mlt_properties_set_data( properties, "movit.convert.texture", texture, 0, (mlt_destructor) GlslManager::release_texture, NULL ); mlt_properties_set_int( properties, "format", output_format ); *format = output_format; } else { // Use a PBO to hold the data we read back with glReadPixels() // (Intel/DRI goes into a slow path if we don't read to PBO) GLenum gl_format = ( output_format == mlt_image_rgb24a || output_format == mlt_image_opengl )? GL_RGBA : GL_RGB; img_size = width * height * ( gl_format == GL_RGB? 3 : 4 ); glsl_pbo pbo = glsl->get_pbo( img_size ); glsl_texture texture = glsl->get_texture( width, height, gl_format ); if ( fbo && pbo && texture ) { // Set the FBO glBindFramebuffer( GL_FRAMEBUFFER, fbo->fbo ); check_error(); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 ); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); GlslManager::render( service, chain, fbo->fbo, width, height ); // Read FBO into PBO glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, pbo->pbo ); check_error(); glBufferData( GL_PIXEL_PACK_BUFFER_ARB, img_size, NULL, GL_STREAM_READ ); check_error(); glReadPixels( 0, 0, width, height, gl_format, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0) ); check_error(); // Copy from PBO uint8_t* buf = (uint8_t*) glMapBuffer( GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY ); check_error(); *image = (uint8_t*) mlt_pool_alloc( img_size ); mlt_frame_set_image( frame, *image, img_size, mlt_pool_release ); memcpy( *image, buf, img_size ); if ( output_format == mlt_image_yuv422 || output_format == mlt_image_yuv420p ) { *format = mlt_image_rgb24; error = convert_on_cpu( frame, image, format, output_format ); } // Release PBO and FBO glUnmapBuffer( GL_PIXEL_PACK_BUFFER_ARB ); check_error(); glBindBuffer( GL_PIXEL_PACK_BUFFER_ARB, 0 ); check_error(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); check_error(); glBindTexture( GL_TEXTURE_2D, 0 ); check_error(); mlt_properties_set_data( properties, "movit.convert.texture", texture, 0, (mlt_destructor) GlslManager::release_texture, NULL); mlt_properties_set_int( properties, "format", output_format ); *format = output_format; } else { error = 1; } } if ( fbo ) GlslManager::release_fbo( fbo ); } else { mlt_properties_set_int( properties, "format", output_format ); *format = output_format; } GlslManager::get_instance()->unlock_service( frame ); return error; }
virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( IDeckLinkVideoInputFrame* video, IDeckLinkAudioInputPacket* audio ) { if ( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "preview" ) && mlt_producer_get_speed( getProducer() ) == 0.0 && !mlt_deque_count( m_queue )) { pthread_cond_broadcast( &m_condition ); return S_OK; } // Create mlt_frame mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( getProducer() ) ); // Copy video if ( video ) { if ( !( video->GetFlags() & bmdFrameHasNoInputSource ) ) { int size = video->GetRowBytes() * ( video->GetHeight() + m_vancLines ); void* image = mlt_pool_alloc( size ); void* buffer = 0; unsigned char* p = (unsigned char*) image; int n = size / 2; \ // Initialize VANC lines to nominal black while ( --n ) { *p ++ = 16; *p ++ = 128; } // Capture VANC if ( m_vancLines > 0 ) { IDeckLinkVideoFrameAncillary* vanc = 0; if ( video->GetAncillaryData( &vanc ) == S_OK && vanc ) { for ( int i = 1; i < m_vancLines + 1; i++ ) { if ( vanc->GetBufferForVerticalBlankingLine( i, &buffer ) == S_OK ) swab( (char*) buffer, (char*) image + ( i - 1 ) * video->GetRowBytes(), video->GetRowBytes() ); else mlt_log_debug( getProducer(), "failed capture vanc line %d\n", i ); } SAFE_RELEASE(vanc); } } // Capture image video->GetBytes( &buffer ); if ( image && buffer ) { size = video->GetRowBytes() * video->GetHeight(); swab( (char*) buffer, (char*) image + m_vancLines * video->GetRowBytes(), size ); mlt_frame_set_image( frame, (uint8_t*) image, size, mlt_pool_release ); } else if ( image ) { mlt_log_verbose( getProducer(), "no video\n" ); mlt_pool_release( image ); } } else { mlt_log_verbose( getProducer(), "no signal\n" ); mlt_frame_close( frame ); frame = 0; } // Get timecode IDeckLinkTimecode* timecode = 0; if ( video->GetTimecode( bmdTimecodeVITC, &timecode ) == S_OK && timecode ) { DLString timecodeString = 0; if ( timecode->GetString( &timecodeString ) == S_OK ) { char* s = getCString( timecodeString ); mlt_properties_set( MLT_FRAME_PROPERTIES( frame ), "meta.attr.vitc.markup", s ); mlt_log_debug( getProducer(), "timecode %s\n", s ); freeCString( s ); } freeDLString( timecodeString ); SAFE_RELEASE( timecode ); } } else { mlt_log_verbose( getProducer(), "no video\n" ); mlt_frame_close( frame ); frame = 0; } // Copy audio if ( frame && audio ) { int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ); int size = audio->GetSampleFrameCount() * channels * sizeof(int16_t); mlt_audio_format format = mlt_audio_s16; void* pcm = mlt_pool_alloc( size ); void* buffer = 0; audio->GetBytes( &buffer ); if ( buffer ) { memcpy( pcm, buffer, size ); mlt_frame_set_audio( frame, pcm, format, size, mlt_pool_release ); mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "audio_samples", audio->GetSampleFrameCount() ); } else { mlt_log_verbose( getProducer(), "no audio\n" ); mlt_pool_release( pcm ); } } else { mlt_log_verbose( getProducer(), "no audio\n" ); } // Put frame in queue if ( frame ) { int queueMax = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" ); pthread_mutex_lock( &m_mutex ); if ( mlt_deque_count( m_queue ) < queueMax ) { mlt_deque_push_back( m_queue, frame ); pthread_cond_broadcast( &m_condition ); } else { mlt_frame_close( frame ); mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", ++m_dropped ); mlt_log_warning( getProducer(), "frame dropped %d\n", m_dropped ); } pthread_mutex_unlock( &m_mutex ); } return S_OK; }
static int jack_process (jack_nframes_t frames, void * data) { mlt_filter filter = (mlt_filter) data; mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); int channels = mlt_properties_get_int( properties, "channels" ); int frame_size = mlt_properties_get_int( properties, "_samples" ) * sizeof(float); int sync = mlt_properties_get_int( properties, "_sync" ); int err = 0; int i; static int total_size = 0; jack_ringbuffer_t **output_buffers = mlt_properties_get_data( properties, "output_buffers", NULL ); if ( output_buffers == NULL ) return 0; jack_ringbuffer_t **input_buffers = mlt_properties_get_data( properties, "input_buffers", NULL ); jack_port_t **jack_output_ports = mlt_properties_get_data( properties, "jack_output_ports", NULL ); jack_port_t **jack_input_ports = mlt_properties_get_data( properties, "jack_input_ports", NULL ); float **jack_output_buffers = mlt_properties_get_data( properties, "jack_output_buffers", NULL ); float **jack_input_buffers = mlt_properties_get_data( properties, "jack_input_buffers", NULL ); pthread_mutex_t *output_lock = mlt_properties_get_data( properties, "output_lock", NULL ); pthread_cond_t *output_ready = mlt_properties_get_data( properties, "output_ready", NULL ); for ( i = 0; i < channels; i++ ) { size_t jack_size = ( frames * sizeof(float) ); size_t ring_size; // Send audio through out port jack_output_buffers[i] = jack_port_get_buffer( jack_output_ports[i], frames ); if ( ! jack_output_buffers[i] ) { mlt_log_error( MLT_FILTER_SERVICE(filter), "no buffer for output port %d\n", i ); err = 1; break; } ring_size = jack_ringbuffer_read_space( output_buffers[i] ); jack_ringbuffer_read( output_buffers[i], ( char * )jack_output_buffers[i], ring_size < jack_size ? ring_size : jack_size ); if ( ring_size < jack_size ) memset( &jack_output_buffers[i][ring_size], 0, jack_size - ring_size ); // Return audio through in port jack_input_buffers[i] = jack_port_get_buffer( jack_input_ports[i], frames ); if ( ! jack_input_buffers[i] ) { mlt_log_error( MLT_FILTER_SERVICE(filter), "no buffer for input port %d\n", i ); err = 1; break; } // Do not start returning audio until we have sent first mlt frame if ( sync && i == 0 && frame_size > 0 ) total_size += ring_size; mlt_log_debug( MLT_FILTER_SERVICE(filter), "sync %d frame_size %d ring_size %zu jack_size %zu\n", sync, frame_size, ring_size, jack_size ); if ( ! sync || ( frame_size > 0 && total_size >= frame_size ) ) { ring_size = jack_ringbuffer_write_space( input_buffers[i] ); jack_ringbuffer_write( input_buffers[i], ( char * )jack_input_buffers[i], ring_size < jack_size ? ring_size : jack_size ); if ( sync ) { // Tell mlt that audio is available pthread_mutex_lock( output_lock); pthread_cond_signal( output_ready ); pthread_mutex_unlock( output_lock); // Clear sync phase mlt_properties_set_int( properties, "_sync", 0 ); } } } // Often jackd does not send the stopped event through the JackSyncCallback jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); jack_position_t jack_pos; jack_transport_state_t state = jack_transport_query( jack_client, &jack_pos ); int transport_state = mlt_properties_get_int( properties, "_transport_state" ); if ( state != transport_state ) { mlt_properties_set_int( properties, "_transport_state", state ); if ( state == JackTransportStopped ) jack_sync( state, &jack_pos, filter ); } return err; }
static int convert_audio( mlt_frame frame, void **audio, mlt_audio_format *format, mlt_audio_format requested_format ) { int error = 1; mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); int channels = mlt_properties_get_int( properties, "audio_channels" ); int samples = mlt_properties_get_int( properties, "audio_samples" ); int size = mlt_audio_format_size( requested_format, samples, channels ); if ( *format != requested_format ) { mlt_log_debug( NULL, "[filter audioconvert] %s -> %s %d channels %d samples\n", mlt_audio_format_name( *format ), mlt_audio_format_name( requested_format ), channels, samples ); switch ( *format ) { case mlt_audio_s16: switch ( requested_format ) { case mlt_audio_s32: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; int c; for ( c = 0; c < channels; c++ ) { int16_t *q = (int16_t*) *audio + c; int i = samples + 1; while ( --i ) { *p++ = (int32_t) *q << 16; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_float: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int c; for ( c = 0; c < channels; c++ ) { int16_t *q = (int16_t*) *audio + c; int i = samples + 1; while ( --i ) { *p++ = (float)( *q ) / 32768.0; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_s32le: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; int16_t *q = (int16_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = (int32_t) *q++ << 16; *audio = buffer; error = 0; break; } case mlt_audio_f32le: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int16_t *q = (int16_t*) *audio; int i = samples * channels + 1; while ( --i ) { float f = (float)( *q++ ) / 32768.0; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = f; } *audio = buffer; error = 0; break; } case mlt_audio_u8: { uint8_t *buffer = mlt_pool_alloc( size ); uint8_t *p = buffer; int16_t *q = (int16_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = ( *q++ >> 8 ) + 128; *audio = buffer; error = 0; break; } default: break; } break; case mlt_audio_s32: switch ( requested_format ) { case mlt_audio_s16: { int16_t *buffer = mlt_pool_alloc( size ); int16_t *p = buffer; int32_t *q = (int32_t*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) *p++ = *( q + c * samples + s ) >> 16; *audio = buffer; error = 0; break; } case mlt_audio_float: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int32_t *q = (int32_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = (float)( *q++ ) / 2147483648.0; *audio = buffer; error = 0; break; } case mlt_audio_s32le: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; int32_t *q = (int32_t*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) *p++ = *( q + c * samples + s ); *audio = buffer; error = 0; break; } case mlt_audio_f32le: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int32_t *q = (int32_t*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) { float f = (float)( *( q + c * samples + s ) ) / 2147483648.0; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = f; } *audio = buffer; error = 0; break; } case mlt_audio_u8: { uint8_t *buffer = mlt_pool_alloc( size ); uint8_t *p = buffer; int32_t *q = (int32_t*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) *p++ = ( q[c * samples + s] >> 24 ) + 128; *audio = buffer; error = 0; break; } default: break; } break; case mlt_audio_float: switch ( requested_format ) { case mlt_audio_s16: { int16_t *buffer = mlt_pool_alloc( size ); int16_t *p = buffer; float *q = (float*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) { float f = *( q + c * samples + s ); f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = 32767 * f; } *audio = buffer; error = 0; break; } case mlt_audio_s32: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; float *q = (float*) *audio; int i = samples * channels + 1; while ( --i ) { float f = *q++; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = ( f > 0 ? 2147483647LL : 2147483648LL ) * f; } *audio = buffer; error = 0; break; } case mlt_audio_s32le: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; float *q = (float*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) { float f = *( q + c * samples + s ); f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = ( f > 0 ? 2147483647LL : 2147483648LL ) * f; } *audio = buffer; error = 0; break; } case mlt_audio_f32le: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; float *q = (float*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) *p++ = *( q + c * samples + s ); *audio = buffer; error = 0; break; } case mlt_audio_u8: { uint8_t *buffer = mlt_pool_alloc( size ); uint8_t *p = buffer; float *q = (float*) *audio; int s, c; for ( s = 0; s < samples; s++ ) for ( c = 0; c < channels; c++ ) { float f = *( q + c * samples + s ); f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = ( 127 * f ) + 128; } *audio = buffer; error = 0; break; } default: break; } break; case mlt_audio_s32le: switch ( requested_format ) { case mlt_audio_s16: { int16_t *buffer = mlt_pool_alloc( size ); int16_t *p = buffer; int32_t *q = (int32_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = *q++ >> 16; *audio = buffer; error = 0; break; } case mlt_audio_s32: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; int c; for ( c = 0; c < channels; c++ ) { int32_t *q = (int32_t*) *audio + c; int i = samples + 1; while ( --i ) { *p++ = *q; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_float: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int c; for ( c = 0; c < channels; c++ ) { int32_t *q = (int32_t*) *audio + c; int i = samples + 1; while ( --i ) { *p++ = (float)( *q ) / 2147483648.0; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_f32le: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int32_t *q = (int32_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = (float)( *q++ ) / 2147483648.0; *audio = buffer; error = 0; break; } case mlt_audio_u8: { uint8_t *buffer = mlt_pool_alloc( size ); uint8_t *p = buffer; int32_t *q = (int32_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = ( *q++ >> 24 ) + 128; *audio = buffer; error = 0; break; } default: break; } break; case mlt_audio_f32le: switch ( requested_format ) { case mlt_audio_s16: { int16_t *buffer = mlt_pool_alloc( size ); int16_t *p = buffer; float *q = (float*) *audio; int i = samples * channels + 1; while ( --i ) { float f = *q++; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = 32767 * f; } *audio = buffer; error = 0; break; } case mlt_audio_float: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int c; for ( c = 0; c < channels; c++ ) { float *q = (float*) *audio + c; int i = samples + 1; while ( --i ) { *p++ = *q; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_s32: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; int c; for ( c = 0; c < channels; c++ ) { float *q = (float*) *audio + c; int i = samples + 1; while ( --i ) { float f = *q; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = ( f > 0 ? 2147483647LL : 2147483648LL ) * f; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_s32le: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; float *q = (float*) *audio; int i = samples * channels + 1; while ( --i ) { float f = *q++; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = ( f > 0 ? 2147483647LL : 2147483648LL ) * f; } *audio = buffer; error = 0; break; } case mlt_audio_u8: { uint8_t *buffer = mlt_pool_alloc( size ); uint8_t *p = buffer; float *q = (float*) *audio; int i = samples * channels + 1; while ( --i ) { float f = *q++; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = ( 127 * f ) + 128; } *audio = buffer; error = 0; break; } default: break; } break; case mlt_audio_u8: switch ( requested_format ) { case mlt_audio_s32: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; int c; for ( c = 0; c < channels; c++ ) { uint8_t *q = (uint8_t*) *audio + c; int i = samples + 1; while ( --i ) { *p++ = ( (int32_t) *q - 128 ) << 24; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_float: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; int c; for ( c = 0; c < channels; c++ ) { uint8_t *q = (uint8_t*) *audio + c; int i = samples + 1; while ( --i ) { *p++ = ( (float) *q - 128 ) / 256.0f; q += channels; } } *audio = buffer; error = 0; break; } case mlt_audio_s16: { int16_t *buffer = mlt_pool_alloc( size ); int16_t *p = buffer; uint8_t *q = (uint8_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = ( (int16_t) *q++ - 128 ) << 8; *audio = buffer; error = 0; break; } case mlt_audio_s32le: { int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; uint8_t *q = (uint8_t*) *audio; int i = samples * channels + 1; while ( --i ) *p++ = ( (int32_t) *q++ - 128 ) << 24; *audio = buffer; error = 0; break; } case mlt_audio_f32le: { float *buffer = mlt_pool_alloc( size ); float *p = buffer; uint8_t *q = (uint8_t*) *audio; int i = samples * channels + 1; while ( --i ) { float f = ( (float) *q++ - 128 ) / 256.0f; f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f; *p++ = f; } *audio = buffer; error = 0; break; } default: break; } break; default: break; } }
static void *consumer_worker_thread( void *arg ) { // The argument is the consumer mlt_consumer self = arg; // Get the properties of the consumer mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Get the width and height int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); mlt_image_format format = self->format; // See if video is turned off int video_off = mlt_properties_get_int( properties, "video_off" ); int preview_off = mlt_properties_get_int( properties, "preview_off" ); int preview_format = mlt_properties_get_int( properties, "preview_format" ); // General frame variable mlt_frame frame = NULL; uint8_t *image = NULL; if ( preview_off && preview_format != 0 ) format = preview_format; // Continue to read ahead while ( self->ahead ) { // Get the next unprocessed frame from the work queue pthread_mutex_lock( &self->queue_mutex ); int index = first_unprocessed_frame( self ); while ( self->ahead && index >= mlt_deque_count( self->queue ) ) { mlt_log_debug( MLT_CONSUMER_SERVICE(self), "waiting in worker index = %d queue count = %d\n", index, mlt_deque_count( self->queue ) ); pthread_cond_wait( &self->queue_cond, &self->queue_mutex ); index = first_unprocessed_frame( self ); } // Mark the frame for processing frame = mlt_deque_peek( self->queue, index ); if ( frame ) { mlt_log_debug( MLT_CONSUMER_SERVICE(self), "worker processing index = %d frame %d queue count = %d\n", index, mlt_frame_get_position(frame), mlt_deque_count( self->queue ) ); frame->is_processing = 1; mlt_properties_inc_ref( MLT_FRAME_PROPERTIES( frame ) ); } pthread_mutex_unlock( &self->queue_mutex ); // If there's no frame, we're probably stopped... if ( frame == NULL ) continue; #ifdef DEINTERLACE_ON_NOT_NORMAL_SPEED // All non normal playback frames should be shown if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "_speed" ) != 1 ) mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 ); #endif // Get the image if ( !video_off ) { // Fetch width/height again width = mlt_properties_get_int( properties, "width" ); height = mlt_properties_get_int( properties, "height" ); mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-frame-render", frame, NULL ); mlt_frame_get_image( frame, &image, &format, &width, &height, 0 ); } mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 ); mlt_frame_close( frame ); // Tell a waiting thread (non-realtime main consumer thread) that we are done. pthread_mutex_lock( &self->done_mutex ); pthread_cond_broadcast( &self->done_cond ); pthread_mutex_unlock( &self->done_mutex ); } return NULL; }
static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; mlt_profile profile = mlt_frame_pop_service( frame ); // Get the properties from the frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Correct Width/height if necessary if ( *width == 0 || *height == 0 ) { *width = profile->width; *height = profile->height; } int left = mlt_properties_get_int( properties, "crop.left" ); int right = mlt_properties_get_int( properties, "crop.right" ); int top = mlt_properties_get_int( properties, "crop.top" ); int bottom = mlt_properties_get_int( properties, "crop.bottom" ); // Request the image at its original resolution if ( left || right || top || bottom ) { mlt_properties_set_int( properties, "rescale_width", mlt_properties_get_int( properties, "crop.original_width" ) ); mlt_properties_set_int( properties, "rescale_height", mlt_properties_get_int( properties, "crop.original_height" ) ); } // Now get the image error = mlt_frame_get_image( frame, image, format, width, height, writable ); int owidth = *width - left - right; int oheight = *height - top - bottom; owidth = owidth < 0 ? 0 : owidth; oheight = oheight < 0 ? 0 : oheight; if ( ( owidth != *width || oheight != *height ) && error == 0 && *image != NULL && owidth > 0 && oheight > 0 ) { int bpp; // Subsampled YUV is messy and less precise. if ( *format == mlt_image_yuv422 && frame->convert_image ) { mlt_image_format requested_format = mlt_image_rgb24; frame->convert_image( frame, image, format, requested_format ); } mlt_log_debug( NULL, "[filter crop] %s %dx%d -> %dx%d\n", mlt_image_format_name(*format), *width, *height, owidth, oheight); // Provides a manual override for misreported field order if ( mlt_properties_get( properties, "meta.top_field_first" ) ) { mlt_properties_set_int( properties, "top_field_first", mlt_properties_get_int( properties, "meta.top_field_first" ) ); mlt_properties_set_int( properties, "meta.top_field_first", 0 ); } if ( top % 2 ) mlt_properties_set_int( properties, "top_field_first", !mlt_properties_get_int( properties, "top_field_first" ) ); // Create the output image int size = mlt_image_format_size( *format, owidth, oheight, &bpp ); uint8_t *output = mlt_pool_alloc( size ); if ( output ) { // Call the generic resize crop( *image, output, bpp, *width, *height, left, right, top, bottom ); // Now update the frame mlt_frame_set_image( frame, output, size, mlt_pool_release ); *image = output; } // We should resize the alpha too uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); int alpha_size = 0; mlt_properties_get_data( properties, "alpha", &alpha_size ); if ( alpha && alpha_size >= ( *width * *height ) ) { uint8_t *newalpha = mlt_pool_alloc( owidth * oheight ); if ( newalpha ) { crop( alpha, newalpha, 1, *width, *height, left, right, top, bottom ); mlt_frame_set_alpha( frame, newalpha, owidth * oheight, mlt_pool_release ); } } *width = owidth; *height = oheight; } return error; }
static jack_rack_t* initialise_jack_rack( mlt_properties properties, int channels ) { jack_rack_t *jackrack = NULL; char *resource = mlt_properties_get( properties, "resource" ); if ( !resource && mlt_properties_get( properties, "src" ) ) resource = mlt_properties_get( properties, "src" ); // Start JackRack if ( resource || mlt_properties_get_int64( properties, "_pluginid" ) ) { // Create JackRack without Jack client name so that it only uses LADSPA jackrack = jack_rack_new( NULL, channels ); mlt_properties_set_data( properties, "jackrack", jackrack, 0, (mlt_destructor) jack_rack_destroy, NULL ); if ( resource ) // Load JACK Rack XML file jack_rack_open_file( jackrack, resource ); else if ( mlt_properties_get_int64( properties, "_pluginid" ) ) { // Load one LADSPA plugin by its UniqueID unsigned long id = mlt_properties_get_int64( properties, "_pluginid" ); plugin_desc_t *desc = plugin_mgr_get_any_desc( jackrack->plugin_mgr, id ); plugin_t *plugin; if ( desc && ( plugin = jack_rack_instantiate_plugin( jackrack, desc ) ) ) { plugin->enabled = TRUE; process_add_plugin( jackrack->procinfo, plugin ); mlt_properties_set_int( properties, "instances", plugin->copies ); } else { mlt_log_error( properties, "failed to load plugin %lu\n", id ); return jackrack; } if ( plugin && plugin->desc && plugin->copies == 0 ) { // Calculate the number of channels that will work with this plugin int request_channels = plugin->desc->channels; while ( request_channels < channels ) request_channels += plugin->desc->channels; if ( request_channels != channels ) { // Try to load again with a compatible number of channels. mlt_log_warning( properties, "Not compatible with %d channels. Requesting %d channels instead.\n", channels, request_channels ); jack_rack_destroy( jackrack ); jackrack = initialise_jack_rack( properties, request_channels ); } else { mlt_log_error( properties, "Invalid plugin configuration: %lu\n", id ); return jackrack; } } if ( plugin && plugin->desc && plugin->copies ) mlt_log_debug( properties, "Plugin Initialized. Channels: %lu\tCopies: %d\tTotal: %lu\n", plugin->desc->channels, plugin->copies, jackrack->channels ); } } return jackrack; }
static int vdpau_decoder_init( producer_avformat self ) { mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_decoder_init\n" ); int success = 1; self->video_codec->opaque = self; self->video_codec->get_format = vdpau_get_format; self->video_codec->get_buffer = vdpau_get_buffer; self->video_codec->release_buffer = vdpau_release_buffer; self->video_codec->draw_horiz_band = vdpau_draw_horiz; self->video_codec->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD; self->video_codec->pix_fmt = PIX_FMT_VDPAU_H264; VdpDecoderProfile profile = VDP_DECODER_PROFILE_H264_HIGH; uint32_t max_references = self->video_codec->refs; pthread_mutex_lock( &mlt_sdl_mutex ); VdpStatus status = vdp_decoder_create( self->vdpau->device, profile, self->video_codec->width, self->video_codec->height, max_references, &self->vdpau->decoder ); pthread_mutex_unlock( &mlt_sdl_mutex ); if ( status == VDP_STATUS_OK ) { int i, n = FFMIN( self->video_codec->refs + 2, MAX_VDPAU_SURFACES ); self->vdpau->deque = mlt_deque_init(); for ( i = 0; i < n; i++ ) { if ( VDP_STATUS_OK == vdp_surface_create( self->vdpau->device, VDP_CHROMA_TYPE_420, self->video_codec->width, self->video_codec->height, &self->vdpau->render_states[i].surface ) ) { mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "successfully created VDPAU surface %x\n", self->vdpau->render_states[i].surface ); mlt_deque_push_back( self->vdpau->deque, &self->vdpau->render_states[i] ); } else { mlt_log_info( MLT_PRODUCER_SERVICE(self->parent), "failed to create VDPAU surface %dx%d\n", self->video_codec->width, self->video_codec->height ); while ( mlt_deque_count( self->vdpau->deque ) ) { struct vdpau_render_state *render = mlt_deque_pop_front( self->vdpau->deque ); vdp_surface_destroy( render->surface ); } mlt_deque_close( self->vdpau->deque ); success = 0; break; } } if ( self->vdpau ) self->vdpau->b_age = self->vdpau->ip_age[0] = self->vdpau->ip_age[1] = 256*256*256*64; // magic from Avidemux } else { success = 0; self->vdpau->decoder = VDP_INVALID_HANDLE; mlt_log_error( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to initialize decoder (%s)\n", vdp_get_error_string( status ) ); } return success; }
static int resample_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); // Get the resample information int output_rate = mlt_properties_get_int( filter_properties, "frequency" ); // If no resample frequency is specified, default to requested value if ( output_rate == 0 ) output_rate = *frequency; // Get the producer's audio int error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); if ( error ) return error; // Return now if no work to do if ( output_rate != *frequency && *frequency > 0 && *channels > 0 ) { mlt_log_debug( MLT_FILTER_SERVICE(filter), "channels %d samples %d frequency %d -> %d\n", *channels, *samples, *frequency, output_rate ); // Do not convert to float unless we need to change the rate if ( *format != mlt_audio_f32le ) frame->convert_audio( frame, buffer, format, mlt_audio_f32le ); mlt_service_lock( MLT_FILTER_SERVICE(filter) ); SRC_DATA data; data.data_in = *buffer; data.data_out = mlt_properties_get_data( filter_properties, "output_buffer", NULL ); data.src_ratio = ( float ) output_rate / ( float ) *frequency; data.input_frames = *samples; data.output_frames = BUFFER_LEN / *channels; data.end_of_input = 0; SRC_STATE *state = mlt_properties_get_data( filter_properties, "state", NULL ); if ( !state || mlt_properties_get_int( filter_properties, "channels" ) != *channels ) { // Recreate the resampler if the number of channels changed state = src_new( RESAMPLE_TYPE, *channels, &error ); mlt_properties_set_data( filter_properties, "state", state, 0, (mlt_destructor) src_delete, NULL ); mlt_properties_set_int( filter_properties, "channels", *channels ); } // Resample the audio error = src_process( state, &data ); if ( !error ) { // Update output variables *samples = data.output_frames_gen; *frequency = output_rate; *buffer = data.data_out; } else { mlt_log_error( MLT_FILTER_SERVICE( filter ), "%s %d,%d,%d\n", src_strerror( error ), *frequency, *samples, output_rate ); } mlt_service_unlock( MLT_FILTER_SERVICE(filter) ); } return error; }
static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; // Obtain properties of frame and producer mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); producer_qimage self = mlt_properties_get_data( properties, "producer_qimage", NULL ); mlt_producer producer = &self->parent; *width = mlt_properties_get_int( properties, "rescale_width" ); *height = mlt_properties_get_int( properties, "rescale_height" ); mlt_service_lock( MLT_PRODUCER_SERVICE( &self->parent ) ); // Refresh the image self->qimage_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.qimage" ); self->qimage = mlt_cache_item_data( self->qimage_cache, NULL ); self->image_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.image" ); self->current_image = mlt_cache_item_data( self->image_cache, NULL ); self->alpha_cache = mlt_service_cache_get( MLT_PRODUCER_SERVICE( producer ), "qimage.alpha" ); self->current_alpha = mlt_cache_item_data( self->alpha_cache, NULL ); refresh_image( self, frame, *format, *width, *height ); // Get width and height (may have changed during the refresh) *width = mlt_properties_get_int( properties, "width" ); *height = mlt_properties_get_int( properties, "height" ); *format = self->format; // NB: Cloning is necessary with this producer (due to processing of images ahead of use) // The fault is not in the design of mlt, but in the implementation of the qimage producer... if ( self->current_image ) { // Clone the image and the alpha int image_size = mlt_image_format_size( self->format, self->current_width, self->current_height, NULL ); uint8_t *image_copy = mlt_pool_alloc( image_size ); memcpy( image_copy, self->current_image, image_size ); // Now update properties so we free the copy after mlt_frame_set_image( frame, image_copy, image_size, mlt_pool_release ); // We're going to pass the copy on *buffer = image_copy; mlt_log_debug( MLT_PRODUCER_SERVICE( &self->parent ), "%dx%d (%s)\n", self->current_width, self->current_height, mlt_image_format_name( *format ) ); // Clone the alpha channel if ( self->current_alpha ) { image_copy = mlt_pool_alloc( self->current_width * self->current_height ); memcpy( image_copy, self->current_alpha, self->current_width * self->current_height ); mlt_frame_set_alpha( frame, image_copy, self->current_width * self->current_height, mlt_pool_release ); } } else { error = 1; } // Release references and locks mlt_cache_item_close( self->qimage_cache ); mlt_cache_item_close( self->image_cache ); mlt_cache_item_close( self->alpha_cache ); mlt_service_unlock( MLT_PRODUCER_SERVICE( &self->parent ) ); return error; }
static void *consumer_read_ahead_thread( void *arg ) { // The argument is the consumer mlt_consumer self = arg; // Get the properties of the consumer mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Get the width and height int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); // See if video is turned off int video_off = mlt_properties_get_int( properties, "video_off" ); int preview_off = mlt_properties_get_int( properties, "preview_off" ); int preview_format = mlt_properties_get_int( properties, "preview_format" ); // Get the audio settings mlt_audio_format afmt = mlt_audio_s16; const char *format = mlt_properties_get( properties, "mlt_audio_format" ); if ( format ) { if ( !strcmp( format, "none" ) ) afmt = mlt_audio_none; else if ( !strcmp( format, "s32" ) ) afmt = mlt_audio_s32; else if ( !strcmp( format, "s32le" ) ) afmt = mlt_audio_s32le; else if ( !strcmp( format, "float" ) ) afmt = mlt_audio_float; else if ( !strcmp( format, "f32le" ) ) afmt = mlt_audio_f32le; else if ( !strcmp( format, "u8" ) ) afmt = mlt_audio_u8; } int counter = 0; double fps = mlt_properties_get_double( properties, "fps" ); int channels = mlt_properties_get_int( properties, "channels" ); int frequency = mlt_properties_get_int( properties, "frequency" ); int samples = 0; void *audio = NULL; // See if audio is turned off int audio_off = mlt_properties_get_int( properties, "audio_off" ); // Get the maximum size of the buffer int buffer = mlt_properties_get_int( properties, "buffer" ) + 1; // General frame variable mlt_frame frame = NULL; uint8_t *image = NULL; // Time structures struct timeval ante; // Average time for get_frame and get_image int count = 0; int skipped = 0; int64_t time_process = 0; int skip_next = 0; mlt_position pos = 0; mlt_position start_pos = 0; mlt_position last_pos = 0; int frame_duration = mlt_properties_get_int( properties, "frame_duration" ); int drop_max = mlt_properties_get_int( properties, "drop_max" ); if ( preview_off && preview_format != 0 ) self->format = preview_format; // Get the first frame frame = mlt_consumer_get_frame( self ); if ( frame ) { // Get the image of the first frame if ( !video_off ) { mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-frame-render", frame, NULL ); mlt_frame_get_image( frame, &image, &self->format, &width, &height, 0 ); } if ( !audio_off ) { samples = mlt_sample_calculator( fps, frequency, counter++ ); mlt_frame_get_audio( frame, &audio, &afmt, &frequency, &channels, &samples ); } // Mark as rendered mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 ); last_pos = start_pos = pos = mlt_frame_get_position( frame ); } // Get the starting time (can ignore the times above) gettimeofday( &ante, NULL ); // Continue to read ahead while ( self->ahead ) { // Put the current frame into the queue pthread_mutex_lock( &self->queue_mutex ); while( self->ahead && mlt_deque_count( self->queue ) >= buffer ) pthread_cond_wait( &self->queue_cond, &self->queue_mutex ); mlt_deque_push_back( self->queue, frame ); pthread_cond_broadcast( &self->queue_cond ); pthread_mutex_unlock( &self->queue_mutex ); // Get the next frame frame = mlt_consumer_get_frame( self ); // If there's no frame, we're probably stopped... if ( frame == NULL ) continue; pos = mlt_frame_get_position( frame ); // Increment the counter used for averaging processing cost count ++; // All non-normal playback frames should be shown if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "_speed" ) != 1 ) { #ifdef DEINTERLACE_ON_NOT_NORMAL_SPEED mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 ); #endif // Indicate seeking or trick-play start_pos = pos; } // If skip flag not set or frame-dropping disabled if ( !skip_next || self->real_time == -1 ) { if ( !video_off ) { // Reset width/height - could have been changed by previous mlt_frame_get_image width = mlt_properties_get_int( properties, "width" ); height = mlt_properties_get_int( properties, "height" ); // Get the image mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-frame-render", frame, NULL ); mlt_frame_get_image( frame, &image, &self->format, &width, &height, 0 ); } // Indicate the rendered image is available. mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 ); // Reset consecutively-skipped counter skipped = 0; } else // Skip image processing { // Increment the number of consecutively-skipped frames skipped++; // If too many (1 sec) consecutively-skipped frames if ( skipped > drop_max ) { // Reset cost tracker time_process = 0; count = 1; mlt_log_verbose( self, "too many frames dropped - forcing next frame\n" ); } } // Always process audio if ( !audio_off ) { samples = mlt_sample_calculator( fps, frequency, counter++ ); mlt_frame_get_audio( frame, &audio, &afmt, &frequency, &channels, &samples ); } // Get the time to process this frame int64_t time_current = time_difference( &ante ); // If the current time is not suddenly some large amount if ( time_current < time_process / count * 20 || !time_process || count < 5 ) { // Accumulate the cost for processing this frame time_process += time_current; } else { mlt_log_debug( self, "current %"PRId64" threshold %"PRId64" count %d\n", time_current, (int64_t) (time_process / count * 20), count ); // Ignore the cost of this frame's time count--; } // Determine if we started, resumed, or seeked if ( pos != last_pos + 1 ) start_pos = pos; last_pos = pos; // Do not skip the first 20% of buffer at start, resume, or seek if ( pos - start_pos <= buffer / 5 + 1 ) { // Reset cost tracker time_process = 0; count = 1; } // Reset skip flag skip_next = 0; // Only consider skipping if the buffer level is low (or really small) if ( mlt_deque_count( self->queue ) <= buffer / 5 + 1 ) { // Skip next frame if average cost exceeds frame duration. if ( time_process / count > frame_duration ) skip_next = 1; if ( skip_next ) mlt_log_debug( self, "avg usec %"PRId64" (%"PRId64"/%d) duration %d\n", time_process/count, time_process, count, frame_duration); } } // Remove the last frame mlt_frame_close( frame ); return NULL; }
static void* mlt_slices_worker( void* p ) { int id, idx; struct mlt_slices_runtime_s* r; mlt_slices ctx = (mlt_slices)p; mlt_log_debug( NULL, "%s:%d: ctx=[%p][%s] entering\n", __FUNCTION__, __LINE__ , ctx, ctx->name ); pthread_mutex_lock( &ctx->cond_mutex ); id = ctx->readys; ctx->readys++; while ( 1 ) { mlt_log_debug( NULL, "%s:%d: ctx=[%p][%s] waiting\n", __FUNCTION__, __LINE__ , ctx, ctx->name ); /* wait for new jobs */ while( !ctx->f_exit && !( r = ctx->head ) ) pthread_cond_wait( &ctx->cond_var_job, &ctx->cond_mutex ); if ( ctx->f_exit ) break; if ( !r ) continue; /* check if no new job */ if ( r->curr == r->jobs ) { ctx->head = ctx->head->next; if ( !ctx->head ) ctx->tail = NULL; mlt_log_debug( NULL, "%s:%d: new ctx->head=%p\n", __FUNCTION__, __LINE__, ctx->head ); continue; }; /* new job id */ idx = r->curr; r->curr++; /* run job */ pthread_mutex_unlock( &ctx->cond_mutex ); mlt_log_debug( NULL, "%s:%d: running job: id=%d, idx=%d/%d, pool=[%s]\n", __FUNCTION__, __LINE__, id, idx, r->jobs, ctx->name ); r->proc( id, idx, r->jobs, r->cookie ); pthread_mutex_lock( &ctx->cond_mutex ); /* increase done jobs counter */ r->done++; /* notify we fininished last job */ if ( r->done == r->jobs ) { mlt_log_debug( NULL, "%s:%d: pthread_cond_signal( &ctx->cond_var_ready )\n", __FUNCTION__, __LINE__ ); pthread_cond_broadcast( &ctx->cond_var_ready ); } } pthread_mutex_unlock( &ctx->cond_mutex ); return NULL; }
static int resample_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); // Get the resample information int output_rate = mlt_properties_get_int( filter_properties, "frequency" ); int16_t *sample_buffer = mlt_properties_get_data( filter_properties, "buffer", NULL ); // Obtain the resample context if it exists ReSampleContext *resample = mlt_properties_get_data( filter_properties, "audio_resample", NULL ); // If no resample frequency is specified, default to requested value if ( output_rate == 0 ) output_rate = *frequency; // Get the producer's audio int error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); if ( error ) return error; // Return now if no work to do if ( output_rate != *frequency ) { // Will store number of samples created int used = 0; mlt_log_debug( MLT_FILTER_SERVICE(filter), "channels %d samples %d frequency %d -> %d\n", *channels, *samples, *frequency, output_rate ); // Do not convert to s16 unless we need to change the rate if ( *format != mlt_audio_s16 ) { *format = mlt_audio_s16; mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); } // Create a resampler if nececessary if ( resample == NULL || *frequency != mlt_properties_get_int( filter_properties, "last_frequency" ) ) { // Create the resampler resample = av_audio_resample_init( *channels, *channels, output_rate, *frequency, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16, 16, 10, 0, 0.8 ); // And store it on properties mlt_properties_set_data( filter_properties, "audio_resample", resample, 0, ( mlt_destructor )audio_resample_close, NULL ); // And remember what it was created for mlt_properties_set_int( filter_properties, "last_frequency", *frequency ); } mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); // Resample the audio used = audio_resample( resample, sample_buffer, *buffer, *samples ); int size = used * *channels * sizeof( int16_t ); // Resize if necessary if ( used > *samples ) { *buffer = mlt_pool_realloc( *buffer, size ); mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); } // Copy samples memcpy( *buffer, sample_buffer, size ); // Update output variables *samples = used; *frequency = output_rate; } else { mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); } return error; }
static int vdpau_init( producer_avformat self ) { if ( !vdpau_supported ) return 0; mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_init\n" ); int success = 0; mlt_properties properties = MLT_PRODUCER_PROPERTIES( self->parent ); Display *display = XOpenDisplay( NULL ); if ( !display || mlt_properties_get_int( properties, "novdpau" ) || ( getenv( "MLT_NO_VDPAU" ) && strcmp( getenv( "MLT_NO_VDPAU" ), "1" ) == 0 ) ) return success; void *object = NULL; if ( !vdpau_init_done ) { int flags = RTLD_NOW; object = dlopen( "/usr/lib/libvdpau.so", flags ); #ifdef ARCH_X86_64 if ( !object ) object = dlopen( "/usr/lib64/libvdpau.so", flags ); if ( !object ) object = dlopen( "/usr/lib/x86_64-linux-gnu/libvdpau.so.1", flags ); #elif ARCH_X86 if ( !object ) object = dlopen( "/usr/lib/i386-linux-gnu/libvdpau.so.1", flags ); #endif if ( !object ) object = dlopen( "/usr/local/lib/libvdpau.so", flags ); if ( object ) vdpau_device_create_x11 = dlsym( object, "vdp_device_create_x11" ); else { mlt_log( MLT_PRODUCER_SERVICE(self->parent), MLT_LOG_WARNING, "%s: failed to dlopen libvdpau.so\n (%s)\n", __FUNCTION__, dlerror() ); // Don't try again. vdpau_supported = 0; return success; } } if ( vdpau_device_create_x11 ) { int screen = mlt_properties_get_int( properties, "x11_screen" ); self->vdpau = calloc( 1, sizeof( *self->vdpau ) ); self->vdpau->device = VDP_INVALID_HANDLE; self->vdpau->decoder = VDP_INVALID_HANDLE; mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "X11 Display = %p\n", display ); if ( VDP_STATUS_OK == vdpau_device_create_x11( display, screen, &self->vdpau->device, &vdp_get_proc_address ) ) { if ( !vdpau_init_done ) { vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_GET_ERROR_STRING, (void**) &vdp_get_error_string ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_GET_API_VERSION, (void**) &vdp_get_api_version ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_GET_INFORMATION_STRING, (void**) &vdp_get_information_string ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_CREATE, (void**) &vdp_surface_create ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, (void**) &vdp_surface_destroy ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR, (void**) &vdp_surface_get_bits ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DECODER_CREATE, (void**) &vdp_decoder_create ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DECODER_DESTROY, (void**) &vdp_decoder_destroy ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DECODER_RENDER, (void**) &vdp_decoder_render ); vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DEVICE_DESTROY, (void**) &vdp_device_destroy ); vdpau_init_done = 1; } success = 1; } } if ( !success ) { mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to initialize device\n" ); if ( object ) dlclose( object ); free( self->vdpau ); self->vdpau = NULL; } return success; }
static int convert_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, mlt_image_format output_format ) { mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); int width = mlt_properties_get_int( properties, "width" ); int height = mlt_properties_get_int( properties, "height" ); int error = 0; if ( *format != output_format ) { mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( mlt_frame_get_original_producer( frame ) ) ); int profile_colorspace = profile ? profile->colorspace : 601; int colorspace = mlt_properties_get_int( properties, "colorspace" ); int force_full_luma = 0; mlt_log_debug( NULL, "[filter avcolor_space] %s -> %s @ %dx%d space %d->%d\n", mlt_image_format_name( *format ), mlt_image_format_name( output_format ), width, height, colorspace, profile_colorspace ); int in_fmt = convert_mlt_to_av_cs( *format ); int out_fmt = convert_mlt_to_av_cs( output_format ); int size = FFMAX( avpicture_get_size( out_fmt, width, height ), mlt_image_format_size( output_format, width, height, NULL ) ); uint8_t *output = mlt_pool_alloc( size ); if ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) { register int len = width * height; uint8_t *alpha = mlt_pool_alloc( len ); if ( alpha ) { // Extract the alpha mask from the RGBA image using Duff's Device register uint8_t *s = *image + 3; // start on the alpha component register uint8_t *d = alpha; register int n = ( len + 7 ) / 8; switch ( len % 8 ) { case 0: do { *d++ = *s; s += 4; case 7: *d++ = *s; s += 4; case 6: *d++ = *s; s += 4; case 5: *d++ = *s; s += 4; case 4: *d++ = *s; s += 4; case 3: *d++ = *s; s += 4; case 2: *d++ = *s; s += 4; case 1: *d++ = *s; s += 4; } while ( --n > 0 ); } mlt_frame_set_alpha( frame, alpha, len, mlt_pool_release ); } } // Update the output if ( !av_convert_image( output, *image, out_fmt, in_fmt, width, height, colorspace, profile_colorspace, force_full_luma ) ) { // The new colorspace is only valid if destination is YUV. if ( output_format == mlt_image_yuv422 || output_format == mlt_image_yuv420p ) mlt_properties_set_int( properties, "colorspace", profile_colorspace ); } *image = output; *format = output_format; mlt_frame_set_image( frame, output, size, mlt_pool_release ); mlt_properties_set_int( properties, "format", output_format ); if ( output_format == mlt_image_rgb24a || output_format == mlt_image_opengl ) { register int len = width * height; int alpha_size = 0; uint8_t *alpha = mlt_frame_get_alpha( frame ); mlt_properties_get_data( properties, "alpha", &alpha_size ); if ( alpha && alpha_size >= len ) { // Merge the alpha mask from into the RGBA image using Duff's Device register uint8_t *s = alpha; register uint8_t *d = *image + 3; // start on the alpha component register int n = ( len + 7 ) / 8; switch ( len % 8 ) { case 0: do { *d = *s++; d += 4; case 7: *d = *s++; d += 4; case 6: *d = *s++; d += 4; case 5: *d = *s++; d += 4; case 4: *d = *s++; d += 4; case 3: *d = *s++; d += 4; case 2: *d = *s++; d += 4; case 1: *d = *s++; d += 4; } while ( --n > 0 ); } } } } return error; }