1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3 * Libbrasero-burn
4 * Copyright (C) Philippe Rouquier 2005-2009 <bonfire-app@wanadoo.fr>
5 *
6 * Libbrasero-burn is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * The Libbrasero-burn authors hereby grant permission for non-GPL compatible
12 * GStreamer plugins to be used and distributed together with GStreamer
13 * and Libbrasero-burn. This permission is above and beyond the permissions granted
14 * by the GPL license by which Libbrasero-burn is covered. If you modify this code
15 * you may extend this exception to your version of the code, but you are not
16 * obligated to do so. If you do not wish to do so, delete this exception
17 * statement from your version.
18 *
19 * Libbrasero-burn is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to:
26 * The Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor
28 * Boston, MA 02110-1301, USA.
29 */
30
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34
35 #include <string.h>
36
37 #include <glib.h>
38
39 #include "brasero-media.h"
40 #include "brasero-media-private.h"
41
42 #include "burn-caps.h"
43 #include "burn-debug.h"
44
45 #include "brasero-plugin-private.h"
46 #include "brasero-plugin-information.h"
47
48 #define SUBSTRACT(a, b) ((a) &= ~((b)&(a)))
49
50 /**
51 * the following functions are used to register new caps
52 */
53
54 static BraseroCapsLink *
brasero_caps_find_link_for_input(BraseroCaps * caps,BraseroCaps * input)55 brasero_caps_find_link_for_input (BraseroCaps *caps,
56 BraseroCaps *input)
57 {
58 GSList *links;
59
60 for (links = caps->links; links; links = links->next) {
61 BraseroCapsLink *link;
62
63 link = links->data;
64 if (link->caps == input)
65 return link;
66 }
67
68 return NULL;
69 }
70
71 static gint
brasero_burn_caps_sort(gconstpointer a,gconstpointer b)72 brasero_burn_caps_sort (gconstpointer a, gconstpointer b)
73 {
74 const BraseroCaps *caps_a = a;
75 const BraseroCaps *caps_b = b;
76 gint result;
77
78 /* First put DISC (the most used caps) then AUDIO then IMAGE type; these
79 * two types are the ones that most often searched. At the end of the
80 * list we put DATA.
81 * Another (sub)rule is that for DATA, DISC, AUDIO we put a caps that is
82 * encompassed by another before.
83 */
84
85 result = caps_b->type.type - caps_a->type.type;
86 if (result)
87 return result;
88
89 switch (caps_a->type.type) {
90 case BRASERO_TRACK_TYPE_DISC:
91 if (BRASERO_MEDIUM_TYPE (caps_a->type.subtype.media) !=
92 BRASERO_MEDIUM_TYPE (caps_b->type.subtype.media))
93 return ((gint32) BRASERO_MEDIUM_TYPE (caps_a->type.subtype.media) -
94 (gint32) BRASERO_MEDIUM_TYPE (caps_b->type.subtype.media));
95
96 if ((caps_a->type.subtype.media & BRASERO_MEDIUM_DVD)
97 && BRASERO_MEDIUM_SUBTYPE (caps_a->type.subtype.media) !=
98 BRASERO_MEDIUM_SUBTYPE (caps_b->type.subtype.media))
99 return ((gint32) BRASERO_MEDIUM_SUBTYPE (caps_a->type.subtype.media) -
100 (gint32) BRASERO_MEDIUM_SUBTYPE (caps_b->type.subtype.media));
101
102 if (BRASERO_MEDIUM_ATTR (caps_a->type.subtype.media) !=
103 BRASERO_MEDIUM_ATTR (caps_b->type.subtype.media))
104 return BRASERO_MEDIUM_ATTR (caps_a->type.subtype.media) -
105 BRASERO_MEDIUM_ATTR (caps_b->type.subtype.media);
106
107 if (BRASERO_MEDIUM_STATUS (caps_a->type.subtype.media) !=
108 BRASERO_MEDIUM_STATUS (caps_b->type.subtype.media))
109 return BRASERO_MEDIUM_STATUS (caps_a->type.subtype.media) -
110 BRASERO_MEDIUM_STATUS (caps_b->type.subtype.media);
111
112 return (BRASERO_MEDIUM_INFO (caps_a->type.subtype.media) -
113 BRASERO_MEDIUM_INFO (caps_b->type.subtype.media));
114
115 case BRASERO_TRACK_TYPE_IMAGE:
116 /* This way BIN subtype is always sorted at the end */
117 return caps_a->type.subtype.img_format - caps_b->type.subtype.img_format;
118
119 case BRASERO_TRACK_TYPE_STREAM:
120 if (caps_a->type.subtype.stream_format != caps_b->type.subtype.stream_format) {
121 result = (caps_a->type.subtype.stream_format & caps_b->type.subtype.stream_format);
122 if (result == caps_a->type.subtype.stream_format)
123 return -1;
124 else if (result == caps_b->type.subtype.stream_format)
125 return 1;
126
127 return (gint32) caps_a->type.subtype.stream_format -
128 (gint32) caps_b->type.subtype.stream_format;
129 }
130 break;
131
132 case BRASERO_TRACK_TYPE_DATA:
133 result = (caps_a->type.subtype.fs_type & caps_b->type.subtype.fs_type);
134 if (result == caps_a->type.subtype.fs_type)
135 return -1;
136 else if (result == caps_b->type.subtype.fs_type)
137 return 1;
138
139 return (caps_a->type.subtype.fs_type - caps_b->type.subtype.fs_type);
140
141 default:
142 break;
143 }
144
145 return 0;
146 }
147
148 static BraseroCapsLink *
brasero_caps_link_copy(BraseroCapsLink * link)149 brasero_caps_link_copy (BraseroCapsLink *link)
150 {
151 BraseroCapsLink *retval;
152
153 retval = g_new0 (BraseroCapsLink, 1);
154 retval->plugins = g_slist_copy (link->plugins);
155 retval->caps = link->caps;
156
157 return retval;
158 }
159
160 static void
brasero_caps_link_list_duplicate(BraseroCaps * dest,BraseroCaps * src)161 brasero_caps_link_list_duplicate (BraseroCaps *dest, BraseroCaps *src)
162 {
163 GSList *iter;
164
165 for (iter = src->links; iter; iter = iter->next) {
166 BraseroCapsLink *link;
167
168 link = iter->data;
169 dest->links = g_slist_prepend (dest->links, brasero_caps_link_copy (link));
170 }
171 }
172
173 static BraseroCaps *
brasero_caps_duplicate(BraseroCaps * caps)174 brasero_caps_duplicate (BraseroCaps *caps)
175 {
176 BraseroCaps *retval;
177
178 retval = g_new0 (BraseroCaps, 1);
179 retval->flags = caps->flags;
180 memcpy (&retval->type, &caps->type, sizeof (BraseroTrackType));
181 retval->modifiers = g_slist_copy (caps->modifiers);
182
183 return retval;
184 }
185
186 static void
brasero_caps_replicate_modifiers(BraseroCaps * dest,BraseroCaps * src)187 brasero_caps_replicate_modifiers (BraseroCaps *dest, BraseroCaps *src)
188 {
189 GSList *iter;
190
191 for (iter = src->modifiers; iter; iter = iter->next) {
192 BraseroPlugin *plugin;
193
194 plugin = iter->data;
195
196 if (g_slist_find (dest->modifiers, plugin))
197 continue;
198
199 dest->modifiers = g_slist_prepend (dest->modifiers, plugin);
200 }
201 }
202
203 static void
brasero_caps_replicate_links(BraseroBurnCaps * self,BraseroCaps * dest,BraseroCaps * src)204 brasero_caps_replicate_links (BraseroBurnCaps *self,
205 BraseroCaps *dest,
206 BraseroCaps *src)
207 {
208 GSList *iter;
209
210 brasero_caps_link_list_duplicate (dest, src);
211
212 for (iter = self->priv->caps_list; iter; iter = iter->next) {
213 BraseroCaps *iter_caps;
214 GSList *links;
215
216 iter_caps = iter->data;
217 if (iter_caps == src)
218 continue;
219
220 for (links = iter_caps->links; links; links = links->next) {
221 BraseroCapsLink *link;
222
223 link = links->data;
224 if (link->caps == src) {
225 BraseroCapsLink *copy;
226
227 copy = brasero_caps_link_copy (link);
228 copy->caps = dest;
229 iter_caps->links = g_slist_prepend (iter_caps->links, copy);
230 }
231 }
232 }
233 }
234
235 static void
brasero_caps_replicate_tests(BraseroBurnCaps * self,BraseroCaps * dest,BraseroCaps * src)236 brasero_caps_replicate_tests (BraseroBurnCaps *self,
237 BraseroCaps *dest,
238 BraseroCaps *src)
239 {
240 GSList *iter;
241
242 for (iter = self->priv->tests; iter; iter = iter->next) {
243 BraseroCapsTest *test;
244 GSList *links;
245
246 test = iter->data;
247 for (links = test->links; links; links = links->next) {
248 BraseroCapsLink *link;
249
250 link = links->data;
251 if (link->caps == src) {
252 BraseroCapsLink *copy;
253
254 copy = brasero_caps_link_copy (link);
255 copy->caps = dest;
256 test->links = g_slist_prepend (test->links, copy);
257 }
258 }
259 }
260 }
261
262 static void
brasero_caps_copy_deep(BraseroBurnCaps * self,BraseroCaps * dest,BraseroCaps * src)263 brasero_caps_copy_deep (BraseroBurnCaps *self,
264 BraseroCaps *dest,
265 BraseroCaps *src)
266 {
267 brasero_caps_replicate_links (self, dest, src);
268 brasero_caps_replicate_tests (self, dest, src);
269 brasero_caps_replicate_modifiers (dest,src);
270 }
271
272 static BraseroCaps *
brasero_caps_duplicate_deep(BraseroBurnCaps * self,BraseroCaps * caps)273 brasero_caps_duplicate_deep (BraseroBurnCaps *self,
274 BraseroCaps *caps)
275 {
276 BraseroCaps *retval;
277
278 retval = brasero_caps_duplicate (caps);
279 brasero_caps_copy_deep (self, retval, caps);
280 return retval;
281 }
282
283 static GSList *
brasero_caps_list_check_io(BraseroBurnCaps * self,GSList * list,BraseroPluginIOFlag flags)284 brasero_caps_list_check_io (BraseroBurnCaps *self,
285 GSList *list,
286 BraseroPluginIOFlag flags)
287 {
288 GSList *iter;
289
290 /* in this function we create the caps with the missing IO. All in the
291 * list have something in common with flags. */
292 for (iter = list; iter; iter = iter->next) {
293 BraseroCaps *caps;
294 BraseroPluginIOFlag common;
295
296 caps = iter->data;
297 common = caps->flags & flags;
298 if (common != caps->flags) {
299 BraseroCaps *new_caps;
300
301 /* (common == flags) && common != caps->flags
302 * caps->flags encompasses flags: Split the caps in two
303 * and only keep the interesting part */
304 caps->flags &= ~common;
305
306 /* this caps has changed and needs to be sorted again */
307 self->priv->caps_list = g_slist_sort (self->priv->caps_list,
308 brasero_burn_caps_sort);
309
310 new_caps = brasero_caps_duplicate_deep (self, caps);
311 new_caps->flags = common;
312
313 self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
314 new_caps,
315 brasero_burn_caps_sort);
316
317 list = g_slist_prepend (list, new_caps);
318 }
319 else if (common != flags) {
320 GSList *node, *next;
321 BraseroPluginIOFlag complement = flags;
322
323 complement &= ~common;
324 for (node = list; node; node = next) {
325 BraseroCaps *tmp;
326
327 tmp = node->data;
328 next = node->next;
329
330 if (node == iter)
331 continue;
332
333 if (caps->type.type != tmp->type.type
334 || caps->type.subtype.media != tmp->type.subtype.media)
335 continue;
336
337 /* substract the flags and relocate them at the
338 * head of the list since we don't need to look
339 * them up again */
340 complement &= ~(tmp->flags);
341 list = g_slist_remove (list, tmp);
342 list = g_slist_prepend (list, tmp);
343 }
344
345 if (complement != BRASERO_PLUGIN_IO_NONE) {
346 BraseroCaps *new_caps;
347
348 /* common == caps->flags && common != flags.
349 * Flags encompasses caps->flags. So we need to
350 * create a new caps for this type with the
351 * substraction of flags if the other part isn't
352 * in the list */
353 new_caps = brasero_caps_duplicate (caps);
354 new_caps->flags = flags & (~common);
355 self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
356 new_caps,
357 brasero_burn_caps_sort);
358
359 list = g_slist_prepend (list, new_caps);
360 }
361 }
362 }
363
364 return list;
365 }
366
367 GSList *
brasero_caps_image_new(BraseroPluginIOFlag flags,BraseroImageFormat format)368 brasero_caps_image_new (BraseroPluginIOFlag flags,
369 BraseroImageFormat format)
370 {
371 BraseroImageFormat remaining_format;
372 BraseroBurnCaps *self;
373 GSList *retval = NULL;
374 GSList *iter;
375
376 BRASERO_BURN_LOG_WITH_FULL_TYPE (BRASERO_TRACK_TYPE_IMAGE,
377 format,
378 flags,
379 "New caps required");
380
381 self = brasero_burn_caps_get_default ();
382
383 remaining_format = format;
384
385 /* We have to search all caps with or related to the format */
386 for (iter = self->priv->caps_list; iter; iter = iter->next) {
387 BraseroCaps *caps;
388 BraseroImageFormat common;
389 BraseroPluginIOFlag common_io;
390
391 caps = iter->data;
392 if (caps->type.type != BRASERO_TRACK_TYPE_IMAGE)
393 continue;
394
395 common_io = caps->flags & flags;
396 if (common_io == BRASERO_PLUGIN_IO_NONE)
397 continue;
398
399 common = (caps->type.subtype.img_format & format);
400 if (common == BRASERO_IMAGE_FORMAT_NONE)
401 continue;
402
403 if (common != caps->type.subtype.img_format) {
404 /* img_format encompasses format. Split it in two and
405 * keep caps with common format */
406 SUBSTRACT (caps->type.subtype.img_format, common);
407 self->priv->caps_list = g_slist_sort (self->priv->caps_list,
408 brasero_burn_caps_sort);
409
410 caps = brasero_caps_duplicate_deep (self, caps);
411 caps->type.subtype.img_format = common;
412
413 self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
414 caps,
415 brasero_burn_caps_sort);
416 }
417
418 retval = g_slist_prepend (retval, caps);
419 remaining_format &= ~common;
420 }
421
422 /* Now we make sure that all these new or already
423 * existing caps have the proper IO Flags */
424 retval = brasero_caps_list_check_io (self, retval, flags);
425
426 if (remaining_format != BRASERO_IMAGE_FORMAT_NONE) {
427 BraseroCaps *caps;
428
429 caps = g_new0 (BraseroCaps, 1);
430 caps->flags = flags;
431 caps->type.subtype.img_format = remaining_format;
432 caps->type.type = BRASERO_TRACK_TYPE_IMAGE;
433
434 self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
435 caps,
436 brasero_burn_caps_sort);
437 retval = g_slist_prepend (retval, caps);
438
439 BRASERO_BURN_LOG_TYPE (&caps->type, "Created new caps");
440 }
441
442 g_object_unref (self);
443 return retval;
444 }
445
446 GSList *
brasero_caps_audio_new(BraseroPluginIOFlag flags,BraseroStreamFormat format)447 brasero_caps_audio_new (BraseroPluginIOFlag flags,
448 BraseroStreamFormat format)
449 {
450 GSList *iter;
451 GSList *retval = NULL;
452 BraseroBurnCaps *self;
453 GSList *encompassing = NULL;
454 gboolean have_the_one = FALSE;
455
456 BRASERO_BURN_LOG_WITH_FULL_TYPE (BRASERO_TRACK_TYPE_STREAM,
457 format,
458 flags,
459 "New caps required");
460
461 self = brasero_burn_caps_get_default ();
462
463 for (iter = self->priv->caps_list; iter; iter = iter->next) {
464 BraseroCaps *caps;
465 BraseroStreamFormat common;
466 BraseroPluginIOFlag common_io;
467 BraseroStreamFormat common_audio;
468 BraseroStreamFormat common_video;
469
470 caps = iter->data;
471
472 if (caps->type.type != BRASERO_TRACK_TYPE_STREAM)
473 continue;
474
475 common_io = (flags & caps->flags);
476 if (common_io == BRASERO_PLUGIN_IO_NONE)
477 continue;
478
479 if (caps->type.subtype.stream_format == format) {
480 /* that's the perfect fit */
481 have_the_one = TRUE;
482 retval = g_slist_prepend (retval, caps);
483 continue;
484 }
485
486 /* Search caps strictly encompassed or encompassing our format
487 * NOTE: make sure that if there is a VIDEO stream in one of
488 * them, the other does have a VIDEO stream too. */
489 common_audio = BRASERO_STREAM_FORMAT_AUDIO (caps->type.subtype.stream_format) &
490 BRASERO_STREAM_FORMAT_AUDIO (format);
491 if (common_audio == BRASERO_AUDIO_FORMAT_NONE
492 && (BRASERO_STREAM_FORMAT_AUDIO (caps->type.subtype.stream_format)
493 || BRASERO_STREAM_FORMAT_AUDIO (format)))
494 continue;
495
496 common_video = BRASERO_STREAM_FORMAT_VIDEO (caps->type.subtype.stream_format) &
497 BRASERO_STREAM_FORMAT_VIDEO (format);
498
499 if (common_video == BRASERO_AUDIO_FORMAT_NONE
500 && (BRASERO_STREAM_FORMAT_VIDEO (caps->type.subtype.stream_format)
501 || BRASERO_STREAM_FORMAT_VIDEO (format)))
502 continue;
503
504 /* Likewise... that must be common */
505 if ((caps->type.subtype.stream_format & BRASERO_METADATA_INFO) != (format & BRASERO_METADATA_INFO))
506 continue;
507
508 common = common_audio|common_video|(format & BRASERO_METADATA_INFO);
509
510 /* encompassed caps just add it to retval */
511 if (caps->type.subtype.stream_format == common)
512 retval = g_slist_prepend (retval, caps);
513
514 /* encompassing caps keep it if we need to create perfect fit */
515 if (format == common)
516 encompassing = g_slist_prepend (encompassing, caps);
517 }
518
519 /* Now we make sure that all these new or already
520 * existing caps have the proper IO Flags */
521 retval = brasero_caps_list_check_io (self, retval, flags);
522
523 if (!have_the_one) {
524 BraseroCaps *caps;
525
526 caps = g_new0 (BraseroCaps, 1);
527 caps->flags = flags;
528 caps->type.subtype.stream_format = format;
529 caps->type.type = BRASERO_TRACK_TYPE_STREAM;
530
531 if (encompassing) {
532 for (iter = encompassing; iter; iter = iter->next) {
533 BraseroCaps *iter_caps;
534
535 iter_caps = iter->data;
536 brasero_caps_copy_deep (self, caps, iter_caps);
537 }
538 }
539
540 self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
541 caps,
542 brasero_burn_caps_sort);
543 retval = g_slist_prepend (retval, caps);
544
545 BRASERO_BURN_LOG_TYPE (&caps->type, "Created new caps");
546 }
547
548 g_slist_free (encompassing);
549
550 g_object_unref (self);
551
552 return retval;
553 }
554
555 GSList *
brasero_caps_data_new(BraseroImageFS fs_type)556 brasero_caps_data_new (BraseroImageFS fs_type)
557 {
558 GSList *iter;
559 GSList *retval = NULL;
560 BraseroBurnCaps *self;
561 GSList *encompassing = NULL;
562 gboolean have_the_one = FALSE;
563
564 BRASERO_BURN_LOG_WITH_FULL_TYPE (BRASERO_TRACK_TYPE_DATA,
565 fs_type,
566 BRASERO_PLUGIN_IO_NONE,
567 "New caps required");
568
569 self = brasero_burn_caps_get_default ();
570
571 for (iter = self->priv->caps_list; iter; iter = iter->next) {
572 BraseroCaps *caps;
573 BraseroImageFS common;
574
575 caps = iter->data;
576
577 if (caps->type.type != BRASERO_TRACK_TYPE_DATA)
578 continue;
579
580 if (caps->type.subtype.fs_type == fs_type) {
581 /* that's the perfect fit */
582 have_the_one = TRUE;
583 retval = g_slist_prepend (retval, caps);
584 continue;
585 }
586
587 /* search caps strictly encompassing our format ... */
588 common = caps->type.subtype.fs_type & fs_type;
589 if (common == BRASERO_IMAGE_FS_NONE)
590 continue;
591
592 /* encompassed caps just add it to retval */
593 if (caps->type.subtype.fs_type == common)
594 retval = g_slist_prepend (retval, caps);
595
596 /* encompassing caps keep it if we need to create perfect fit */
597 if (fs_type == common)
598 encompassing = g_slist_prepend (encompassing, caps);
599 }
600
601 if (!have_the_one) {
602 BraseroCaps *caps;
603
604 caps = g_new0 (BraseroCaps, 1);
605 caps->flags = BRASERO_PLUGIN_IO_ACCEPT_FILE;
606 caps->type.type = BRASERO_TRACK_TYPE_DATA;
607 caps->type.subtype.fs_type = fs_type;
608
609 if (encompassing) {
610 for (iter = encompassing; iter; iter = iter->next) {
611 BraseroCaps *iter_caps;
612
613 iter_caps = iter->data;
614 brasero_caps_copy_deep (self, caps, iter_caps);
615 }
616 }
617
618 self->priv->caps_list = g_slist_insert_sorted (self->priv->caps_list,
619 caps,
620 brasero_burn_caps_sort);
621 retval = g_slist_prepend (retval, caps);
622 }
623
624 g_slist_free (encompassing);
625
626 g_object_unref (self);
627
628 return retval;
629 }
630
631 static GSList *
brasero_caps_disc_lookup_or_create(BraseroBurnCaps * self,GSList * retval,BraseroMedia media)632 brasero_caps_disc_lookup_or_create (BraseroBurnCaps *self,
633 GSList *retval,
634 BraseroMedia media)
635 {
636 GSList *iter;
637 BraseroCaps *caps;
638
639 for (iter = self->priv->caps_list; iter; iter = iter->next) {
640 caps = iter->data;
641
642 if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
643 continue;
644
645 if (caps->type.subtype.media == media) {
646 BRASERO_BURN_LOG_WITH_TYPE (&caps->type,
647 caps->flags,
648 "Retrieved");
649 return g_slist_prepend (retval, caps);
650 }
651 }
652
653 caps = g_new0 (BraseroCaps, 1);
654 caps->flags = BRASERO_PLUGIN_IO_ACCEPT_FILE;
655 caps->type.type = BRASERO_TRACK_TYPE_DISC;
656 caps->type.subtype.media = media;
657
658 BRASERO_BURN_LOG_WITH_TYPE (&caps->type,
659 caps->flags,
660 "Created");
661
662 self->priv->caps_list = g_slist_prepend (self->priv->caps_list, caps);
663
664 return g_slist_prepend (retval, caps);
665 }
666
667 GSList *
brasero_caps_disc_new(BraseroMedia type)668 brasero_caps_disc_new (BraseroMedia type)
669 {
670 BraseroBurnCaps *self;
671 GSList *retval = NULL;
672 GSList *list;
673 GSList *iter;
674
675 self = brasero_burn_caps_get_default ();
676
677 list = brasero_media_get_all_list (type);
678 for (iter = list; iter; iter = iter->next) {
679 BraseroMedia medium;
680
681 medium = GPOINTER_TO_INT (iter->data);
682 retval = brasero_caps_disc_lookup_or_create (self, retval, medium);
683 }
684 g_slist_free (list);
685
686 g_object_unref (self);
687 return retval;
688 }
689
690 /**
691 * these functions are to create links
692 */
693
694 static void
brasero_caps_create_links(BraseroCaps * output,GSList * inputs,BraseroPlugin * plugin)695 brasero_caps_create_links (BraseroCaps *output,
696 GSList *inputs,
697 BraseroPlugin *plugin)
698 {
699 for (; inputs; inputs = inputs->next) {
700 BraseroCaps *input;
701 BraseroCapsLink *link;
702
703 input = inputs->data;
704
705 if (output == input) {
706 BRASERO_BURN_LOG ("Same input and output for link. Dropping");
707 continue;
708 }
709
710 if (input->flags == output->flags
711 && input->type.type == output->type.type
712 && input->type.subtype.media == output->type.subtype.media)
713 BRASERO_BURN_LOG ("Recursive link");
714
715 link = brasero_caps_find_link_for_input (output, input);
716
717 #if 0
718
719 /* Mainly for extra debugging */
720 BRASERO_BURN_LOG_TYPE (&output->type, "Linking");
721 BRASERO_BURN_LOG_TYPE (&input->type, "to");
722 BRASERO_BURN_LOG ("with %s", brasero_plugin_get_name (plugin));
723
724 #endif
725
726 if (!link) {
727 link = g_new0 (BraseroCapsLink, 1);
728 link->caps = input;
729 link->plugins = g_slist_prepend (NULL, plugin);
730
731 output->links = g_slist_prepend (output->links, link);
732 }
733 else
734 link->plugins = g_slist_prepend (link->plugins, plugin);
735 }
736 }
737
738 void
brasero_plugin_link_caps(BraseroPlugin * plugin,GSList * outputs,GSList * inputs)739 brasero_plugin_link_caps (BraseroPlugin *plugin,
740 GSList *outputs,
741 GSList *inputs)
742 {
743 /* we make sure the caps exists and if not we create them */
744 for (; outputs; outputs = outputs->next) {
745 BraseroCaps *output;
746
747 output = outputs->data;
748 brasero_caps_create_links (output, inputs, plugin);
749 }
750 }
751
752 void
brasero_plugin_blank_caps(BraseroPlugin * plugin,GSList * caps_list)753 brasero_plugin_blank_caps (BraseroPlugin *plugin,
754 GSList *caps_list)
755 {
756 for (; caps_list; caps_list = caps_list->next) {
757 BraseroCaps *caps;
758 BraseroCapsLink *link;
759
760 caps = caps_list->data;
761
762 if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
763 continue;
764
765 BRASERO_BURN_LOG_WITH_TYPE (&caps->type,
766 caps->flags,
767 "Adding blank caps for");
768
769 /* we need to find the link whose caps is NULL */
770 link = brasero_caps_find_link_for_input (caps, NULL);
771 if (!link) {
772 link = g_new0 (BraseroCapsLink, 1);
773 link->caps = NULL;
774 link->plugins = g_slist_prepend (NULL, plugin);
775
776 caps->links = g_slist_prepend (caps->links, link);
777 }
778 else
779 link->plugins = g_slist_prepend (link->plugins, plugin);
780 }
781 }
782
783 void
brasero_plugin_process_caps(BraseroPlugin * plugin,GSList * caps_list)784 brasero_plugin_process_caps (BraseroPlugin *plugin,
785 GSList *caps_list)
786 {
787 for (; caps_list; caps_list = caps_list->next) {
788 BraseroCaps *caps;
789
790 caps = caps_list->data;
791 caps->modifiers = g_slist_prepend (caps->modifiers, plugin);
792 }
793 }
794
795 void
brasero_plugin_check_caps(BraseroPlugin * plugin,BraseroChecksumType type,GSList * caps_list)796 brasero_plugin_check_caps (BraseroPlugin *plugin,
797 BraseroChecksumType type,
798 GSList *caps_list)
799 {
800 BraseroCapsTest *test = NULL;
801 BraseroBurnCaps *self;
802 GSList *iter;
803
804 /* Find the the BraseroCapsTest for this type; if none create it */
805 self = brasero_burn_caps_get_default ();
806
807 for (iter = self->priv->tests; iter; iter = iter->next) {
808 BraseroCapsTest *tmp;
809
810 tmp = iter->data;
811 if (tmp->type == type) {
812 test = tmp;
813 break;
814 }
815 }
816
817 if (!test) {
818 test = g_new0 (BraseroCapsTest, 1);
819 test->type = type;
820 self->priv->tests = g_slist_prepend (self->priv->tests, test);
821 }
822
823 g_object_unref (self);
824
825 for (; caps_list; caps_list = caps_list->next) {
826 GSList *links;
827 BraseroCaps *caps;
828 BraseroCapsLink *link;
829
830 caps = caps_list->data;
831
832 /* try to find a link for the above caps, if none create one */
833 link = NULL;
834 for (links = test->links; links; links = links->next) {
835 BraseroCapsLink *tmp;
836
837 tmp = links->data;
838 if (tmp->caps == caps) {
839 link = tmp;
840 break;
841 }
842 }
843
844 if (!link) {
845 link = g_new0 (BraseroCapsLink, 1);
846 link->caps = caps;
847 test->links = g_slist_prepend (test->links, link);
848 }
849
850 link->plugins = g_slist_prepend (link->plugins, plugin);
851 }
852 }
853
854 void
brasero_plugin_register_group(BraseroPlugin * plugin,const gchar * name)855 brasero_plugin_register_group (BraseroPlugin *plugin,
856 const gchar *name)
857 {
858 guint retval;
859 BraseroBurnCaps *self;
860
861 if (!name) {
862 brasero_plugin_set_group (plugin, 0);
863 return;
864 }
865
866 self = brasero_burn_caps_get_default ();
867
868 if (!self->priv->groups)
869 self->priv->groups = g_hash_table_new_full (g_str_hash,
870 g_str_equal,
871 g_free,
872 NULL);
873
874 retval = GPOINTER_TO_INT (g_hash_table_lookup (self->priv->groups, name));
875 if (retval) {
876 brasero_plugin_set_group (plugin, retval);
877 g_object_unref (self);
878 return;
879 }
880
881 g_hash_table_insert (self->priv->groups,
882 g_strdup (name),
883 GINT_TO_POINTER (g_hash_table_size (self->priv->groups) + 1));
884
885 /* see if we have a group id now */
886 if (!self->priv->group_id
887 && self->priv->group_str
888 && !strcmp (name, self->priv->group_str))
889 self->priv->group_id = g_hash_table_size (self->priv->groups) + 1;
890
891 brasero_plugin_set_group (plugin, g_hash_table_size (self->priv->groups) + 1);
892
893 g_object_unref (self);
894 }
895
896 /**
897 * This is to find out what are the capacities of a plugin
898 * Declared in brasero-plugin-private.h
899 */
900
901 BraseroBurnResult
brasero_plugin_can_burn(BraseroPlugin * plugin)902 brasero_plugin_can_burn (BraseroPlugin *plugin)
903 {
904 GSList *iter;
905 BraseroBurnCaps *self;
906
907 self = brasero_burn_caps_get_default ();
908
909 for (iter = self->priv->caps_list; iter; iter = iter->next) {
910 BraseroCaps *caps;
911 GSList *links;
912
913 caps = iter->data;
914 if (caps->type.type != BRASERO_TRACK_TYPE_DISC)
915 continue;
916
917 for (links = caps->links; links; links = links->next) {
918 BraseroCapsLink *link;
919 GSList *plugins;
920
921 link = links->data;
922
923 /* see if the plugin is in the link by going through the list */
924 for (plugins = link->plugins; plugins; plugins = plugins->next) {
925 BraseroPlugin *tmp;
926
927 tmp = plugins->data;
928 if (tmp == plugin) {
929 g_object_unref (self);
930 return BRASERO_BURN_OK;
931 }
932 }
933 }
934 }
935
936 g_object_unref (self);
937 return BRASERO_BURN_NOT_SUPPORTED;
938 }
939
940 BraseroBurnResult
brasero_plugin_can_image(BraseroPlugin * plugin)941 brasero_plugin_can_image (BraseroPlugin *plugin)
942 {
943 GSList *iter;
944 BraseroBurnCaps *self;
945
946 self = brasero_burn_caps_get_default ();
947 for (iter = self->priv->caps_list; iter; iter = iter->next) {
948 BraseroTrackDataType destination;
949 BraseroCaps *caps;
950 GSList *links;
951
952 caps = iter->data;
953 if (caps->type.type != BRASERO_TRACK_TYPE_IMAGE
954 && caps->type.type != BRASERO_TRACK_TYPE_STREAM
955 && caps->type.type != BRASERO_TRACK_TYPE_DATA)
956 continue;
957
958 destination = caps->type.type;
959 for (links = caps->links; links; links = links->next) {
960 BraseroCapsLink *link;
961 GSList *plugins;
962
963 link = links->data;
964 if (!link->caps
965 || link->caps->type.type == destination)
966 continue;
967
968 /* see if the plugin is in the link by going through the list */
969 for (plugins = link->plugins; plugins; plugins = plugins->next) {
970 BraseroPlugin *tmp;
971
972 tmp = plugins->data;
973 if (tmp == plugin) {
974 g_object_unref (self);
975 return BRASERO_BURN_OK;
976 }
977 }
978 }
979 }
980
981 g_object_unref (self);
982 return BRASERO_BURN_NOT_SUPPORTED;
983 }
984
985 BraseroBurnResult
brasero_plugin_can_convert(BraseroPlugin * plugin)986 brasero_plugin_can_convert (BraseroPlugin *plugin)
987 {
988 GSList *iter;
989 BraseroBurnCaps *self;
990
991 self = brasero_burn_caps_get_default ();
992
993 for (iter = self->priv->caps_list; iter; iter = iter->next) {
994 BraseroTrackDataType destination;
995 BraseroCaps *caps;
996 GSList *links;
997
998 caps = iter->data;
999 if (caps->type.type != BRASERO_TRACK_TYPE_IMAGE
1000 && caps->type.type != BRASERO_TRACK_TYPE_STREAM)
1001 continue;
1002
1003 destination = caps->type.type;
1004 for (links = caps->links; links; links = links->next) {
1005 BraseroCapsLink *link;
1006 GSList *plugins;
1007
1008 link = links->data;
1009 if (!link->caps
1010 || link->caps->type.type != destination)
1011 continue;
1012
1013 /* see if the plugin is in the link by going through the list */
1014 for (plugins = link->plugins; plugins; plugins = plugins->next) {
1015 BraseroPlugin *tmp;
1016
1017 tmp = plugins->data;
1018 if (tmp == plugin) {
1019 g_object_unref (self);
1020 return BRASERO_BURN_OK;
1021 }
1022 }
1023 }
1024 }
1025
1026 g_object_unref (self);
1027
1028 return BRASERO_BURN_NOT_SUPPORTED;
1029 }
1030
1031