Krita Source Code Documentation
Loading...
Searching...
No Matches
KisMLTProducerKrita.cpp File Reference
#include "KisMLTProducerKrita.h"
#include <framework/mlt.h>
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "kis_assert.h"
#include <framework/mlt_factory.h>
#include <framework/mlt_frame.h>
#include <framework/mlt_producer.h>
#include <framework/mlt_property.h>
#include <framework/mlt_service.h>

Go to the source code of this file.

Classes

struct  private_data
 

Functions

static int is_valid_range (const int frame_start, const int frame_end)
 
static void producer_close (mlt_producer producer)
 
static int producer_generate_silent_audio (mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples)
 
static int producer_get_audio (mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples)
 
static int producer_get_frame (mlt_producer producer, mlt_frame_ptr frame, int index)
 
voidproducer_krita_init (mlt_profile profile, mlt_service_type type, const char *id, const void *arg)
 
static void producer_property_changed (mlt_service owner, mlt_producer self, mlt_event_data event_data)
 
static int producer_seek (mlt_producer producer, mlt_position position)
 
void registerKritaMLTProducer (Mlt::Repository *repository)
 
static int restrict_range (int index, int min, int max)
 
void scale_audio_frequency (mlt_producer producer, mlt_audio audio)
 

Function Documentation

◆ is_valid_range()

static int is_valid_range ( const int frame_start,
const int frame_end )
static

Definition at line 55 of file KisMLTProducerKrita.cpp.

56{
57 const bool NON_NEGATIVE = frame_start >= 0 && frame_end >= 0;
58 const bool NON_INVERTED = frame_end > frame_start;
59
60 return NON_NEGATIVE && NON_INVERTED;
61}

◆ producer_close()

static void producer_close ( mlt_producer producer)
static

Definition at line 257 of file KisMLTProducerKrita.cpp.

258{
259 private_data *pdata = (private_data *) producer->child;
260
261 if (pdata) {
262 mlt_producer_close(pdata->producer_internal);
263 free(pdata);
264 }
265
266 producer->close = NULL;
267 mlt_producer_close(producer);
268 free(producer);
269}

References private_data::producer_internal.

◆ producer_generate_silent_audio()

static int producer_generate_silent_audio ( mlt_frame frame,
void ** buffer,
mlt_audio_format * format,
int * frequency,
int * channels,
int * samples )
static

Save the generated audio into the frame itself, since this overloaded function will not be called on the further calls to mlt_frame_get_audio (the pointer to the function was placed on the stack, which has already been taken)

Definition at line 124 of file KisMLTProducerKrita.cpp.

130{
131 mlt_producer producer = static_cast<mlt_producer>(mlt_frame_pop_audio(frame));
132 private_data *pdata = (private_data *) producer->child;
133
134 {
135 // Get the producer fps
136 double fps = mlt_producer_get_fps(producer);
137
138 if (mlt_properties_get(MLT_FRAME_PROPERTIES(frame), "producer_consumer_fps"))
139 fps = mlt_properties_get_double(MLT_FRAME_PROPERTIES(frame), "producer_consumer_fps");
140
141 mlt_position position = mlt_properties_get_position(MLT_FRAME_PROPERTIES(frame), "_position");
142
143 int size = 0;
144 *channels = *channels <= 0 ? 2 : *channels;
145 *frequency = pdata->audio_sample_rate > 0 ? pdata->audio_sample_rate : 44100;
146 *samples = mlt_audio_calculate_frame_samples(fps, *frequency, position); //NOTE: Audio BUFFER_SIZE
147 *format = *format == mlt_audio_none ? mlt_audio_s16 : *format;
148
149 size = mlt_audio_format_size(*format, *samples, *channels);
150 if (size)
151 *buffer = mlt_pool_alloc(size);
152 else
153 *buffer = NULL;
154
162 mlt_frame_set_audio(frame, *buffer, *format, size, mlt_pool_release);
163 }
164
165 struct mlt_audio_s audio;
166 mlt_audio_set_values(&audio, *buffer, *frequency, *format, *samples, *channels);
167 mlt_audio_silence(&audio, *samples, 0);
168
169 scale_audio_frequency(producer, &audio);
170
171 mlt_audio_get_values(&audio, buffer, frequency, format, samples, channels);
172
173 return 0;
174}
void scale_audio_frequency(mlt_producer producer, mlt_audio audio)
int size(const Forest< T > &forest)
Definition KisForest.h:1232

References private_data::audio_sample_rate, and scale_audio_frequency().

◆ producer_get_audio()

static int producer_get_audio ( mlt_frame frame,
void ** buffer,
mlt_audio_format * format,
int * frequency,
int * channels,
int * samples )
static

MLT doesn't reset the requested frequency on every call, that is, if the underlying producer just passes through the frequency, it will eventually drop to zero and crash. AVformat resets the frequency every time to the value of the underlying media. Count producer doesn't reset the frequency by default, so we should reset it manually by passing negative values.

Definition at line 85 of file KisMLTProducerKrita.cpp.

91{
92 mlt_producer producer = static_cast<mlt_producer>(mlt_frame_pop_audio(frame));
93 private_data *pdata = (private_data *) producer->child;
94
95 struct mlt_audio_s audio;
96
104 if (pdata->force_reset_audio_frequency_for_frames) {
105 *frequency = -1;
106 *samples = -1;
107 }
108
109 mlt_audio_set_values(&audio, *buffer, *frequency, *format, *samples, *channels);
110
111 int error = mlt_frame_get_audio(frame,
112 &audio.data,
113 &audio.format,
114 &audio.frequency,
115 &audio.channels,
116 &audio.samples);
117
118 scale_audio_frequency(producer, &audio);
119 mlt_audio_get_values(&audio, buffer, frequency, format, samples, channels);
120
121 return error;
122}

References private_data::force_reset_audio_frequency_for_frames, and scale_audio_frequency().

◆ producer_get_frame()

static int producer_get_frame ( mlt_producer producer,
mlt_frame_ptr frame,
int index )
static

Generate a slowed-down silence frame and reset the test_audio flag

When the data stream ends, the AVformat library returns and empty frame, flagged with "test_audio" tag. Later on, when the consumer reads this frame, mlt_frame_get_audio() generates a frame of silence with 48kHz resolution. We cannot use this variant of silence, since it is not scaled. We need to generate our own version of silence, which is scaled according to our format.

Definition at line 176 of file KisMLTProducerKrita.cpp.

177{
178 mlt_properties props = MLT_PRODUCER_PROPERTIES(producer);
179 const int FRAME_START = mlt_properties_get_int(props, "start_frame");
180 const int FRAME_END = mlt_properties_get_int(props, "end_frame");
181 const bool IS_RANGE_LIMITED = mlt_properties_get_int(props, "limit_enabled");
182
183 private_data *pdata = (private_data *) producer->child;
184 const int POSITION = mlt_producer_position(pdata->producer_internal);
185
186 if (IS_RANGE_LIMITED && is_valid_range(FRAME_START, FRAME_END)) {
187 mlt_properties_set_position(MLT_PRODUCER_PROPERTIES(pdata->producer_internal),
188 "_position",
189 restrict_range(POSITION, FRAME_START, FRAME_END));
190 }
191
192 int retval = mlt_service_get_frame((mlt_service) pdata->producer_internal, frame, index);
193
194 if (!mlt_frame_is_test_audio(*frame)) {
195 mlt_frame_push_audio(*frame, producer);
196 mlt_frame_push_audio(*frame, (void*)producer_get_audio);
197 } else {
211 mlt_frame_push_audio(*frame, producer);
212 mlt_frame_push_audio(*frame, (void*)producer_generate_silent_audio);
213
214 mlt_properties properties = MLT_FRAME_PROPERTIES(*frame);
215 mlt_properties_set_int(properties, "test_audio", 0);
216 }
217
218 return retval;
219}
static int restrict_range(int index, int min, int max)
static int is_valid_range(const int frame_start, const int frame_end)
static int producer_get_audio(mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples)
static int producer_generate_silent_audio(mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples)

References is_valid_range(), producer_generate_silent_audio(), producer_get_audio(), private_data::producer_internal, and restrict_range().

◆ producer_krita_init()

void * producer_krita_init ( mlt_profile profile,
mlt_service_type type,
const char * id,
const void * arg )

Constructor for the producer.

We permanently set the EOF mode to "continue", because other modes have weird effects, like clipping the data when seeking or resetting the producer speed to null.

Disable caching of frames in avformat producer

Caching in MLT library is broken. When a frame is taken from the cache its "audio" property is not restored. It breaks the work of "read-ahead" consumer thread, which also temporarily stores this frame.

Fetch media sample rate to be able to generate correct silence stream

Definition at line 273 of file KisMLTProducerKrita.cpp.

277{
278 // Create a new producer object
279 mlt_producer producer = mlt_producer_new(profile);
280 private_data *pdata = (private_data *) calloc(1, sizeof(private_data));
281
282 if (arg && producer && pdata) {
283 mlt_properties producer_properties = MLT_PRODUCER_PROPERTIES(producer);
284
285 // Initialize the producer
286 mlt_properties_set(producer_properties, "resource", (char*)arg);
287 producer->child = pdata;
288 producer->get_frame = producer_get_frame;
289 producer->seek = producer_seek;
290 producer->close = (mlt_destructor) producer_close;
291
292 // Get the resource to be passed to the clip producer
293 char *resource = (char*)arg;
294
295 // Create internal producer
296 pdata->producer_internal = mlt_factory_producer(profile, "abnormal", resource);
297
298 if (pdata->producer_internal) {
299 mlt_producer_set_speed(pdata->producer_internal, 1.0);
300 mlt_properties internalProducerProps = MLT_PRODUCER_PROPERTIES(pdata->producer_internal);
301
307 mlt_properties_set_string(internalProducerProps, "eof", "continue");
308
309 const char *serviceName = mlt_properties_get(internalProducerProps, "mlt_service");
310
311 if (!strcmp(serviceName, "avformat")) {
320 mlt_properties_set_int(internalProducerProps, "noimagecache", 1);
321
327 char key[200];
328 const int numberOfStreams = mlt_properties_get_int(internalProducerProps, "meta.media.nb_streams");
329
330 for (int i = 0; i < numberOfStreams; i++) {
331 snprintf(key, sizeof(key), "meta.media.%u.stream.type", i);
332
333 const char* type = mlt_properties_get(internalProducerProps, key);
334 if (type && !strcmp(type, "audio")) {
335 snprintf(key, sizeof(key), "meta.media.%u.codec.sample_rate", i);
336 pdata->audio_sample_rate = mlt_properties_get_int(internalProducerProps, key);
337 }
338 }
339 } else if (!strcmp(serviceName, "count")) {
340 pdata->audio_sample_rate = 48000;
342 } else {
343 KIS_SAFE_ASSERT_RECOVER_NOOP(0 && "mlt_service used for media is unknown!");
344 }
345 }
346
347 mlt_properties_set_string(producer_properties, "eof", "continue");
348
349 mlt_events_listen( producer_properties, producer, "property-changed", ( mlt_listener )producer_property_changed );
350 }
351
352 const bool INVALID_CONTEXT = !producer || !pdata || !pdata->producer_internal;
353 if (INVALID_CONTEXT) { // Clean up early...
354 if (pdata) {
355 mlt_producer_close(pdata->producer_internal);
356 free(pdata);
357 }
358
359 if (producer) {
360 producer->child = NULL;
361 producer->close = NULL;
362 mlt_producer_close(producer);
363 free(producer);
364 producer = NULL;
365 }
366 }
367
368 return producer;
369}
static void producer_property_changed(mlt_service owner, mlt_producer self, mlt_event_data event_data)
static int producer_seek(mlt_producer producer, mlt_position position)
static int producer_get_frame(mlt_producer producer, mlt_frame_ptr frame, int index)
static void producer_close(mlt_producer producer)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
bool force_reset_audio_frequency_for_frames
mlt_producer producer_internal

References private_data::audio_sample_rate, private_data::force_reset_audio_frequency_for_frames, KIS_SAFE_ASSERT_RECOVER_NOOP, producer_close(), producer_get_frame(), private_data::producer_internal, producer_property_changed(), and producer_seek().

◆ producer_property_changed()

static void producer_property_changed ( mlt_service owner,
mlt_producer self,
mlt_event_data event_data )
static

We don't use MLT's "speed" value for anything, but some MLT's functions may adjust the speed of the producer, e.g. when seeking. So we should keep the two values in sync.

Definition at line 221 of file KisMLTProducerKrita.cpp.

222{
223 const char *name = mlt_event_data_to_string(event_data);
224 if (!name) return;
225
231 if (strcmp(name, "_speed") == 0) {
232 const double speed = mlt_producer_get_speed(self);
233 private_data* pdata = (private_data*)self->child;
234 mlt_producer_set_speed(pdata->producer_internal, speed);
235 }
236}
const char * name(StandardAction id)

References private_data::producer_internal.

◆ producer_seek()

static int producer_seek ( mlt_producer producer,
mlt_position position )
static

Update the position values of the parent producer

Definition at line 238 of file KisMLTProducerKrita.cpp.

239{
240 private_data *pdata = (private_data *) producer->child;
241
242 int retval = mlt_producer_seek(pdata->producer_internal, position);
243
247 mlt_properties_set_position(MLT_PRODUCER_PROPERTIES(producer),
248 "_position",
249 position);
250 mlt_properties_set_position(MLT_PRODUCER_PROPERTIES(producer),
251 "_frame",
252 position);
253
254 return retval;
255}

References private_data::producer_internal.

◆ registerKritaMLTProducer()

void registerKritaMLTProducer ( Mlt::Repository * repository)

Definition at line 371 of file KisMLTProducerKrita.cpp.

372{
373 repository->register_service(mlt_service_producer_type, "krita_play_chunk", producer_krita_init);
374}
void * producer_krita_init(mlt_profile profile, mlt_service_type type, const char *id, const void *arg)

References producer_krita_init().

◆ restrict_range()

static int restrict_range ( int index,
int min,
int max )
static

Restricts frame index to within range by modulus wrapping (not clamping).

Definition at line 49 of file KisMLTProducerKrita.cpp.

50{
51 const int span = max - min;
52 return (MAX(index - min, 0) % (span + 1)) + min;
53}
#define MAX(a, b)
T min(T a, T b, T c)
constexpr std::enable_if< sizeof...(values)==0, size_t >::type max()

References MAX.

◆ scale_audio_frequency()

void scale_audio_frequency ( mlt_producer producer,
mlt_audio audio )

Definition at line 63 of file KisMLTProducerKrita.cpp.

64{
65 mlt_properties props = MLT_PRODUCER_PROPERTIES(producer);
66
67 // Scale the frequency to account for the dynamic speed (normalized).
68 double SPEED = mlt_properties_get_double(props, "speed");
69
71 SPEED = 1.0;
72 }
73
74 audio->frequency = (double) audio->frequency * fabs(SPEED);
75
76 KIS_SAFE_ASSERT_RECOVER(audio->frequency > 0) {
77 audio->frequency = 1;
78 }
79
80 if (SPEED < 0.0) {
81 mlt_audio_reverse(audio);
82 }
83}
static bool qFuzzyIsNull(half h)
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126

References KIS_SAFE_ASSERT_RECOVER, and qFuzzyIsNull().