static int get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { context cx = mlt_frame_pop_audio( frame ); mlt_frame nested_frame = mlt_frame_pop_audio( frame ); int result = 0; // if not repeating last frame if ( mlt_frame_get_position( nested_frame ) != cx->audio_position ) { double fps = mlt_profile_fps( cx->profile ); if ( mlt_producer_get_fps( cx->self ) < fps ) fps = mlt_producer_get_fps( cx->self ); *samples = mlt_sample_calculator( fps, *frequency, cx->audio_counter++ ); result = mlt_frame_get_audio( nested_frame, buffer, format, frequency, channels, samples ); int size = mlt_audio_format_size( *format, *samples, *channels ); int16_t *new_buffer = mlt_pool_alloc( size ); mlt_frame_set_audio( frame, new_buffer, *format, size, mlt_pool_release ); memcpy( new_buffer, *buffer, size ); *buffer = new_buffer; cx->audio_position = mlt_frame_get_position( nested_frame ); } else { // otherwise return no samples *samples = 0; *buffer = NULL; } return result; }
static int producer_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { mlt_properties properties = MLT_FRAME_PROPERTIES( self ); mlt_frame frame = mlt_frame_pop_audio( self ); mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); mlt_frame_set_audio( self, *buffer, *format, mlt_audio_format_size( *format, *samples, *channels ), NULL ); mlt_properties_set_int( properties, "audio_frequency", *frequency ); mlt_properties_set_int( properties, "audio_channels", *channels ); mlt_properties_set_int( properties, "audio_samples", *samples ); return 0; }
static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Used to return number of channels in the source int channels_avail = *channels; // Get the producer's audio int error = mlt_frame_get_audio( frame, buffer, format, frequency, &channels_avail, samples ); if ( error ) return error; if ( channels_avail < *channels ) { int size = mlt_audio_format_size( *format, *samples, *channels ); int16_t *new_buffer = mlt_pool_alloc( size ); // Duplicate the existing channels if ( *format == mlt_audio_s16 ) { int i, j, k = 0; for ( i = 0; i < *samples; i++ ) { for ( j = 0; j < *channels; j++ ) { new_buffer[ ( i * *channels ) + j ] = ((int16_t*)(*buffer))[ ( i * channels_avail ) + k ]; k = ( k + 1 ) % channels_avail; } } } else if ( *format == mlt_audio_s32le || *format == mlt_audio_f32le ) { int32_t *p = (int32_t*) new_buffer; int i, j, k = 0; for ( i = 0; i < *samples; i++ ) { for ( j = 0; j < *channels; j++ ) { p[ ( i * *channels ) + j ] = ((int32_t*)(*buffer))[ ( i * channels_avail ) + k ]; k = ( k + 1 ) % channels_avail; } } } else { // non-interleaved - s32 or float int size_avail = mlt_audio_format_size( *format, *samples, channels_avail ); int32_t *p = (int32_t*) new_buffer; int i = *channels / channels_avail; while ( i-- ) { memcpy( p, *buffer, size_avail ); p += size_avail / sizeof(*p); } i = *channels % channels_avail; if ( i ) { size_avail = mlt_audio_format_size( *format, *samples, i ); memcpy( p, *buffer, size_avail ); } } // Update the audio buffer now - destroys the old mlt_frame_set_audio( frame, new_buffer, *format, size, mlt_pool_release ); *buffer = new_buffer; } else if ( channels_avail > *channels ) { int size = mlt_audio_format_size( *format, *samples, *channels ); int16_t *new_buffer = mlt_pool_alloc( size ); // Drop all but the first *channels if ( *format == mlt_audio_s16 ) { int i, j; for ( i = 0; i < *samples; i++ ) for ( j = 0; j < *channels; j++ ) new_buffer[ ( i * *channels ) + j ] = ((int16_t*)(*buffer))[ ( i * channels_avail ) + j ]; } else { // non-interleaved memcpy( new_buffer, *buffer, size ); } // Update the audio buffer now - destroys the old mlt_frame_set_audio( frame, new_buffer, *format, size, mlt_pool_release ); *buffer = new_buffer; } return error; }
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 foreach_consumer_put( mlt_consumer consumer, mlt_frame frame ) { mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); mlt_consumer nested = NULL; char key[30]; int index = 0; do { snprintf( key, sizeof(key), "%d.consumer", index++ ); nested = mlt_properties_get_data( properties, key, NULL ); if ( nested ) { mlt_properties nested_props = MLT_CONSUMER_PROPERTIES(nested); double self_fps = mlt_properties_get_double( properties, "fps" ); double nested_fps = mlt_properties_get_double( nested_props, "fps" ); mlt_position nested_pos = mlt_properties_get_position( nested_props, "_multi_position" ); mlt_position self_pos = mlt_frame_get_position( frame ); double self_time = self_pos / self_fps; double nested_time = nested_pos / nested_fps; // get the audio for the current frame uint8_t *buffer = NULL; mlt_audio_format format = mlt_audio_s16; int channels = mlt_properties_get_int( properties, "channels" ); int frequency = mlt_properties_get_int( properties, "frequency" ); int current_samples = mlt_sample_calculator( self_fps, frequency, self_pos ); mlt_frame_get_audio( frame, (void**) &buffer, &format, &frequency, &channels, ¤t_samples ); int current_size = mlt_audio_format_size( format, current_samples, channels ); // get any leftover audio int prev_size = 0; uint8_t *prev_buffer = mlt_properties_get_data( nested_props, "_multi_audio", &prev_size ); uint8_t *new_buffer = NULL; if ( prev_size > 0 ) { new_buffer = mlt_pool_alloc( prev_size + current_size ); memcpy( new_buffer, prev_buffer, prev_size ); memcpy( new_buffer + prev_size, buffer, current_size ); buffer = new_buffer; } current_size += prev_size; current_samples += mlt_properties_get_int( nested_props, "_multi_samples" ); while ( nested_time <= self_time ) { // put ideal number of samples into cloned frame int deeply = index > 1 ? 1 : 0; mlt_frame clone_frame = mlt_frame_clone( frame, deeply ); int nested_samples = mlt_sample_calculator( nested_fps, frequency, nested_pos ); // -10 is an optimization to avoid tiny amounts of leftover samples nested_samples = nested_samples > current_samples - 10 ? current_samples : nested_samples; int nested_size = mlt_audio_format_size( format, nested_samples, channels ); if ( nested_size > 0 ) { prev_buffer = mlt_pool_alloc( nested_size ); memcpy( prev_buffer, buffer, nested_size ); } else { prev_buffer = NULL; nested_size = 0; } mlt_frame_set_audio( clone_frame, prev_buffer, format, nested_size, mlt_pool_release ); mlt_properties_set_int( MLT_FRAME_PROPERTIES(clone_frame), "audio_samples", nested_samples ); mlt_properties_set_int( MLT_FRAME_PROPERTIES(clone_frame), "audio_frequency", frequency ); mlt_properties_set_int( MLT_FRAME_PROPERTIES(clone_frame), "audio_channels", channels ); // chomp the audio current_samples -= nested_samples; current_size -= nested_size; buffer += nested_size; // send frame to nested consumer mlt_consumer_put_frame( nested, clone_frame ); mlt_properties_set_position( nested_props, "_multi_position", ++nested_pos ); nested_time = nested_pos / nested_fps; } // save any remaining audio if ( current_size > 0 ) { prev_buffer = mlt_pool_alloc( current_size ); memcpy( prev_buffer, buffer, current_size ); } else { prev_buffer = NULL; current_size = 0; } mlt_pool_release( new_buffer ); mlt_properties_set_data( nested_props, "_multi_audio", prev_buffer, current_size, mlt_pool_release, NULL ); mlt_properties_set_int( nested_props, "_multi_samples", current_samples ); } } while ( nested ); }
static int ladspa_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { int error = 0; // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); // Check if the channel configuration has changed int prev_channels = mlt_properties_get_int( filter_properties, "_prev_channels" ); if ( prev_channels != *channels ) { if( prev_channels ) { mlt_log_info( MLT_FILTER_SERVICE(filter), "Channel configuration changed. Old: %d New: %d.\n", prev_channels, *channels ); mlt_properties_set_data( filter_properties, "jackrack", NULL, 0, (mlt_destructor) NULL, NULL ); } mlt_properties_set_int( filter_properties, "_prev_channels", *channels ); } // Initialise LADSPA if needed jack_rack_t *jackrack = mlt_properties_get_data( filter_properties, "jackrack", NULL ); if ( jackrack == NULL ) { sample_rate = *frequency; // global inside jack_rack jackrack = initialise_jack_rack( filter_properties, *channels ); } if ( jackrack && jackrack->procinfo && jackrack->procinfo->chain && mlt_properties_get_int64( filter_properties, "_pluginid" ) ) { plugin_t *plugin = jackrack->procinfo->chain; LADSPA_Data value; int i, c; mlt_position position = mlt_filter_get_position( filter, frame ); mlt_position length = mlt_filter_get_length2( filter, frame ); // Get the producer's audio *format = mlt_audio_float; mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); // Resize the buffer if necessary. if ( *channels < jackrack->channels ) { // Add extra channels to satisfy the plugin. // Extra channels in the buffer will be ignored by downstream services. int old_size = mlt_audio_format_size( *format, *samples, *channels ); int new_size = mlt_audio_format_size( *format, *samples, jackrack->channels ); uint8_t* new_buffer = mlt_pool_alloc( new_size ); memcpy( new_buffer, *buffer, old_size ); // Put silence in extra channels. memset( new_buffer + old_size, 0, new_size - old_size ); mlt_frame_set_audio( frame, new_buffer, *format, new_size, mlt_pool_release ); *buffer = new_buffer; } for ( i = 0; i < plugin->desc->control_port_count; i++ ) { // Apply the control port values char key[20]; value = plugin_desc_get_default_control_value( plugin->desc, i, sample_rate ); snprintf( key, sizeof(key), "%d", i ); if ( mlt_properties_get( filter_properties, key ) ) value = mlt_properties_anim_get_double( filter_properties, key, position, length ); for ( c = 0; c < plugin->copies; c++ ) plugin->holders[c].control_memory[i] = value; } plugin->wet_dry_enabled = mlt_properties_get( filter_properties, "wetness" ) != NULL; if ( plugin->wet_dry_enabled ) { value = mlt_properties_anim_get_double( filter_properties, "wetness", position, length ); for ( c = 0; c < jackrack->channels; c++ ) plugin->wet_dry_values[c] = value; } // Configure the buffers LADSPA_Data **input_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * jackrack->channels ); LADSPA_Data **output_buffers = mlt_pool_alloc( sizeof( LADSPA_Data* ) * jackrack->channels ); // Some plugins crash with too many frames (samples). // So, feed the plugin with N samples per loop iteration. int samples_offset = 0; int sample_count = MIN(*samples, MAX_SAMPLE_COUNT); for (i = 0; samples_offset < *samples; i++) { int j = 0; for (; j < jackrack->channels; j++) output_buffers[j] = input_buffers[j] = (LADSPA_Data*) *buffer + j * (*samples) + samples_offset; sample_count = MIN(*samples - samples_offset, MAX_SAMPLE_COUNT); // Do LADSPA processing error = process_ladspa( jackrack->procinfo, sample_count, input_buffers, output_buffers ); samples_offset += MAX_SAMPLE_COUNT; } mlt_pool_release( input_buffers ); mlt_pool_release( output_buffers ); // read the status port values for ( i = 0; i < plugin->desc->status_port_count; i++ ) { char key[20]; int p = plugin->desc->status_port_indicies[i]; for ( c = 0; c < plugin->copies; c++ ) { snprintf( key, sizeof(key), "%d[%d]", p, c ); value = plugin->holders[c].status_memory[i]; mlt_properties_set_double( filter_properties, key, value ); } } } else { // Nothing to do. error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); } return error; }
mlt_frame mlt_frame_clone( mlt_frame self, int is_deep ) { mlt_frame new_frame = mlt_frame_init( NULL ); mlt_properties properties = MLT_FRAME_PROPERTIES( self ); mlt_properties new_props = MLT_FRAME_PROPERTIES( new_frame ); void *data, *copy; int size; mlt_properties_inherit( new_props, properties ); // Carry over some special data properties for the multi consumer. mlt_properties_set_data( new_props, "_producer", mlt_frame_get_original_producer( self ), 0, NULL, NULL ); mlt_properties_set_data( new_props, "movit.convert", mlt_properties_get_data( properties, "movit.convert", NULL), 0, NULL, NULL ); if ( is_deep ) { data = mlt_properties_get_data( properties, "audio", &size ); if ( data ) { if ( !size ) size = mlt_audio_format_size( mlt_properties_get_int( properties, "audio_format" ), mlt_properties_get_int( properties, "audio_samples" ), mlt_properties_get_int( properties, "audio_channels" ) ); copy = mlt_pool_alloc( size ); memcpy( copy, data, size ); mlt_properties_set_data( new_props, "audio", copy, size, mlt_pool_release, NULL ); } data = mlt_properties_get_data( properties, "image", &size ); if ( data ) { if ( ! size ) size = mlt_image_format_size( mlt_properties_get_int( properties, "format" ), mlt_properties_get_int( properties, "width" ), mlt_properties_get_int( properties, "height" ), NULL ); copy = mlt_pool_alloc( size ); memcpy( copy, data, size ); mlt_properties_set_data( new_props, "image", copy, size, mlt_pool_release, NULL ); data = mlt_properties_get_data( properties, "alpha", &size ); if ( data ) { if ( ! size ) size = mlt_properties_get_int( properties, "width" ) * mlt_properties_get_int( properties, "height" ); copy = mlt_pool_alloc( size ); memcpy( copy, data, size ); mlt_properties_set_data( new_props, "alpha", copy, size, mlt_pool_release, NULL ); }; } } else { // This frame takes a reference on the original frame since the data is a shallow copy. mlt_properties_inc_ref( properties ); mlt_properties_set_data( new_props, "_cloned_frame", self, 0, (mlt_destructor) mlt_frame_close, NULL ); // Copy properties data = mlt_properties_get_data( properties, "audio", &size ); mlt_properties_set_data( new_props, "audio", data, size, NULL, NULL ); data = mlt_properties_get_data( properties, "image", &size ); mlt_properties_set_data( new_props, "image", data, size, NULL, NULL ); data = mlt_properties_get_data( properties, "alpha", &size ); mlt_properties_set_data( new_props, "alpha", data, size, NULL, NULL ); } return new_frame; }
static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the properties of the a frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); int channels_out = mlt_properties_get_int( properties, "mono.channels" ); int i, j, size; // Get the producer's audio mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); if ( channels_out == -1 ) channels_out = *channels; size = mlt_audio_format_size( *format, *samples, channels_out ); switch ( *format ) { case mlt_audio_u8: { uint8_t *new_buffer = mlt_pool_alloc( size ); for ( i = 0; i < *samples; i++ ) { uint8_t mixdown = 0; for ( j = 0; j < *channels; j++ ) mixdown += ((uint8_t*) *buffer)[ ( i * *channels ) + j ]; for ( j = 0; j < channels_out; j++ ) new_buffer[ ( i * channels_out ) + j ] = mixdown; } *buffer = new_buffer; break; } case mlt_audio_s16: { int16_t *new_buffer = mlt_pool_alloc( size ); for ( i = 0; i < *samples; i++ ) { int16_t mixdown = 0; for ( j = 0; j < *channels; j++ ) mixdown += ((int16_t*) *buffer)[ ( i * *channels ) + j ]; for ( j = 0; j < channels_out; j++ ) new_buffer[ ( i * channels_out ) + j ] = mixdown; } *buffer = new_buffer; break; } case mlt_audio_s32le: { int32_t *new_buffer = mlt_pool_alloc( size ); for ( i = 0; i < *samples; i++ ) { int32_t mixdown = 0; for ( j = 0; j < *channels; j++ ) mixdown += ((int32_t*) *buffer)[ ( i * *channels ) + j ]; for ( j = 0; j < channels_out; j++ ) new_buffer[ ( i * channels_out ) + j ] = mixdown; } *buffer = new_buffer; break; } case mlt_audio_f32le: { float *new_buffer = mlt_pool_alloc( size ); for ( i = 0; i < *samples; i++ ) { float mixdown = 0; for ( j = 0; j < *channels; j++ ) mixdown += ((float*) *buffer)[ ( i * *channels ) + j ]; for ( j = 0; j < channels_out; j++ ) new_buffer[ ( i * channels_out ) + j ] = mixdown; } *buffer = new_buffer; break; } case mlt_audio_s32: { int32_t *new_buffer = mlt_pool_alloc( size ); for ( i = 0; i < *samples; i++ ) { int32_t mixdown = 0; for ( j = 0; j < *channels; j++ ) mixdown += ((int32_t*) *buffer)[ ( j * *channels ) + i ]; for ( j = 0; j < channels_out; j++ ) new_buffer[ ( j * *samples ) + i ] = mixdown; } *buffer = new_buffer; break; } case mlt_audio_float: { float *new_buffer = mlt_pool_alloc( size ); for ( i = 0; i < *samples; i++ ) { float mixdown = 0; for ( j = 0; j < *channels; j++ ) mixdown += ((float*) *buffer)[ ( j * *channels ) + i ]; for ( j = 0; j < channels_out; j++ ) new_buffer[ ( j * *samples ) + i ] = mixdown; } *buffer = new_buffer; break; } default: mlt_log_error( NULL, "[filter mono] Invalid audio format\n" ); break; } if ( size > *samples * channels_out ) { mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); *channels = channels_out; } return 0; }
int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { mlt_get_audio get_audio = mlt_frame_pop_audio( self ); mlt_properties properties = MLT_FRAME_PROPERTIES( self ); int hide = mlt_properties_get_int( properties, "test_audio" ); mlt_audio_format requested_format = *format; if ( hide == 0 && get_audio != NULL ) { get_audio( self, buffer, format, frequency, channels, samples ); mlt_properties_set_int( properties, "audio_frequency", *frequency ); mlt_properties_set_int( properties, "audio_channels", *channels ); mlt_properties_set_int( properties, "audio_samples", *samples ); mlt_properties_set_int( properties, "audio_format", *format ); if ( self->convert_audio && *buffer && requested_format != mlt_audio_none ) self->convert_audio( self, buffer, format, requested_format ); } else if ( mlt_properties_get_data( properties, "audio", NULL ) ) { *buffer = mlt_properties_get_data( properties, "audio", NULL ); *format = mlt_properties_get_int( properties, "audio_format" ); *frequency = mlt_properties_get_int( properties, "audio_frequency" ); *channels = mlt_properties_get_int( properties, "audio_channels" ); *samples = mlt_properties_get_int( properties, "audio_samples" ); if ( self->convert_audio && *buffer && requested_format != mlt_audio_none ) self->convert_audio( self, buffer, format, requested_format ); } else { int size = 0; *samples = *samples <= 0 ? 1920 : *samples; *channels = *channels <= 0 ? 2 : *channels; *frequency = *frequency <= 0 ? 48000 : *frequency; mlt_properties_set_int( properties, "audio_frequency", *frequency ); mlt_properties_set_int( properties, "audio_channels", *channels ); mlt_properties_set_int( properties, "audio_samples", *samples ); mlt_properties_set_int( properties, "audio_format", *format ); size = mlt_audio_format_size( *format, *samples, *channels ); if ( size ) *buffer = mlt_pool_alloc( size ); else *buffer = NULL; if ( *buffer ) memset( *buffer, 0, size ); mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL ); mlt_properties_set_int( properties, "test_audio", 1 ); } // TODO: This does not belong here if ( *format == mlt_audio_s16 && mlt_properties_get( properties, "meta.volume" ) && *buffer ) { double value = mlt_properties_get_double( properties, "meta.volume" ); if ( value == 0.0 ) { memset( *buffer, 0, *samples * *channels * 2 ); } else if ( value != 1.0 ) { int total = *samples * *channels; int16_t *p = *buffer; while ( total -- ) { *p = *p * value; p ++; } } mlt_properties_set( properties, "meta.volume", NULL ); } return 0; }