1 /* OGMRip - A library for DVD ripping and encoding
2 * Copyright (C) 2004-2012 Olivier Rolland <billl@users.sourceforge.net>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "ogmrip-container.h"
24 #include "ogmrip-fs.h"
25 #include "ogmrip-mplayer.h"
26 #include "ogmrip-plugin.h"
27 #include "ogmrip-version.h"
28
29 #include "ogmjob-exec.h"
30 #include "ogmjob-queue.h"
31
32 #include <errno.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <glib/gi18n-lib.h>
37 #include <glib/gstdio.h>
38
39 #define PROGRAM "mp4box"
40
41 #define OGMRIP_TYPE_MP4 (ogmrip_mp4_get_type ())
42 #define OGMRIP_MP4(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), OGMRIP_TYPE_MP4, OGMRipMp4))
43 #define OGMRIP_MP4_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), OGMRIP_TYPE_MP4, OGMRipMp4Class))
44 #define OGMRIP_IS_MP4(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OGMRIP_TYPE_MP4))
45 #define OGMRIP_IS_MP4_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), OGMRIP_TYPE_MP4))
46 #define OGMRIP_MP4_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), OGMRIP_TYPE_MP4, OGMRipMp4Class))
47
48 typedef struct _OGMRipMp4 OGMRipMp4;
49 typedef struct _OGMRipMp4Class OGMRipMp4Class;
50
51 struct _OGMRipMp4
52 {
53 OGMRipContainer parent_instance;
54
55 guint nstreams;
56 guint streams;
57 guint old_percent;
58
59 guint nsplits;
60 guint splits;
61 guint split_percent;
62 };
63
64 struct _OGMRipMp4Class
65 {
66 OGMRipContainerClass parent_class;
67 };
68
69 GType ogmrip_mp4_get_type (void);
70 static gint ogmrip_mp4_run (OGMJobSpawn *spawn);
71
72 static void
ogmrip_mp4_append_audio_file(OGMRipContainer * mp4,const gchar * filename,gint format,gint language,GPtrArray * argv)73 ogmrip_mp4_append_audio_file (OGMRipContainer *mp4, const gchar *filename,
74 gint format, gint language, GPtrArray *argv)
75 {
76 struct stat buf;
77
78 if (g_stat (filename, &buf) == 0 && buf.st_size > 0)
79 {
80 const gchar *fmt;
81
82 switch (format)
83 {
84 case OGMRIP_FORMAT_AAC:
85 fmt = "aac";
86 break;
87 case OGMRIP_FORMAT_MP3:
88 fmt = "mp3";
89 break;
90 case OGMRIP_FORMAT_VORBIS:
91 fmt = "ogg";
92 break;
93 case OGMRIP_FORMAT_AC3:
94 case OGMRIP_FORMAT_COPY:
95 fmt = "ac3";
96 break;
97 default:
98 fmt = NULL;
99 break;
100 }
101
102 if (fmt)
103 {
104 const gchar *iso639_2 = NULL;
105
106 g_ptr_array_add (argv, g_strdup ("-add"));
107 if (language > -1)
108 iso639_2 = ogmdvd_get_language_iso639_2 (language);
109 if (iso639_2)
110 g_ptr_array_add (argv, g_strdup_printf ("%s:fmt=%s:lang=%s:group=1:#audio", filename, fmt, iso639_2));
111 else
112 g_ptr_array_add (argv, g_strdup_printf ("%s:fmt=%s:group=1:#audio", filename, fmt));
113 }
114 }
115 }
116
117 static void
ogmrip_mp4_append_subp_file(OGMRipContainer * mp4,const gchar * filename,gint format,gint language,GPtrArray * argv)118 ogmrip_mp4_append_subp_file (OGMRipContainer *mp4, const gchar *filename,
119 gint format, gint language, GPtrArray *argv)
120 {
121 struct stat buf;
122
123 if (g_stat (filename, &buf) == 0 && buf.st_size > 0)
124 {
125 const gchar *fmt;
126
127 switch (format)
128 {
129 case OGMRIP_FORMAT_SRT:
130 fmt = "srt";
131 break;
132 case OGMRIP_FORMAT_VOBSUB:
133 fmt = "vobsub";
134 break;
135 default:
136 fmt = NULL;
137 break;
138 }
139
140 if (fmt)
141 {
142 const gchar *iso639_2 = NULL;
143
144 g_ptr_array_add (argv, g_strdup ("-add"));
145 if (language > -1)
146 iso639_2 = ogmdvd_get_language_iso639_2 (language);
147 if (iso639_2)
148 g_ptr_array_add (argv, g_strdup_printf ("%s:fmt=%s:lang=%s", filename, fmt, iso639_2));
149 else
150 g_ptr_array_add (argv, g_strdup_printf ("%s:fmt=%s", filename, fmt));
151 }
152 }
153 }
154
155 static void
ogmrip_mp4_foreach_audio(OGMRipContainer * mp4,OGMRipCodec * codec,guint demuxer,gint language,GPtrArray * argv)156 ogmrip_mp4_foreach_audio (OGMRipContainer *mp4,
157 OGMRipCodec *codec, guint demuxer, gint language, GPtrArray *argv)
158 {
159 const gchar *input;
160 gint format;
161
162 input = ogmrip_codec_get_output (codec);
163 format = ogmrip_plugin_get_audio_codec_format (G_TYPE_FROM_INSTANCE (codec));
164
165 ogmrip_mp4_append_audio_file (mp4, input, format, language, argv);
166 }
167
168 static void
ogmrip_mp4_foreach_subp(OGMRipContainer * mp4,OGMRipCodec * codec,guint demuxer,gint language,GPtrArray * argv)169 ogmrip_mp4_foreach_subp (OGMRipContainer *mp4,
170 OGMRipCodec *codec, guint demuxer, gint language, GPtrArray *argv)
171 {
172 const gchar *input;
173 gint format;
174
175 input = ogmrip_codec_get_output (codec);
176 format = ogmrip_plugin_get_subp_codec_format (G_TYPE_FROM_INSTANCE (codec));
177
178 ogmrip_mp4_append_subp_file (mp4, input, format, language, argv);
179 }
180
181 static void
ogmrip_mp4_foreach_chapters(OGMRipContainer * mp4,OGMRipCodec * codec,guint demuxer,gint language,GPtrArray * argv)182 ogmrip_mp4_foreach_chapters (OGMRipContainer *mp4,
183 OGMRipCodec *codec, guint demuxer, gint language, GPtrArray *argv)
184 {
185 const gchar *input;
186 struct stat buf;
187
188 input = ogmrip_codec_get_output (codec);
189 if (g_stat (input, &buf) == 0 && buf.st_size > 0)
190 {
191 g_ptr_array_add (argv, g_strdup ("-chap"));
192 g_ptr_array_add (argv, g_strdup (input));
193 }
194 }
195
196 static void
ogmrip_mp4_foreach_file(OGMRipContainer * mp4,OGMRipFile * file,GPtrArray * argv)197 ogmrip_mp4_foreach_file (OGMRipContainer *mp4, OGMRipFile *file, GPtrArray *argv)
198 {
199 gchar *filename;
200
201 filename = ogmrip_file_get_filename (file);
202 if (filename)
203 {
204 gint format, language;
205
206 format = ogmrip_file_get_format (file);
207 language = ogmrip_file_get_language (file);
208
209 switch (ogmrip_file_get_type (file))
210 {
211 case OGMRIP_FILE_TYPE_AUDIO:
212 ogmrip_mp4_append_audio_file (mp4, filename, format, language, argv);
213 break;
214 case OGMRIP_FILE_TYPE_SUBP:
215 ogmrip_mp4_append_subp_file (mp4, filename, format, language, argv);
216 break;
217 default:
218 g_assert_not_reached ();
219 break;
220 }
221 }
222 g_free (filename);
223 }
224
225 static gdouble
ogmrip_mp4_get_output_fps(OGMRipCodec * codec)226 ogmrip_mp4_get_output_fps (OGMRipCodec *codec)
227 {
228 guint output_rate_numerator, output_rate_denominator;
229
230 if (ogmrip_codec_get_telecine (codec) || ogmrip_codec_get_progressive (codec))
231 {
232 output_rate_numerator = 24000;
233 output_rate_denominator = 1001;
234 }
235 else
236 ogmrip_codec_get_framerate (codec, &output_rate_numerator, &output_rate_denominator);
237
238 return output_rate_numerator / (gdouble) (output_rate_denominator * ogmrip_codec_get_framestep (codec));
239 }
240
241 static gchar **
ogmrip_mp4box_extract_command(OGMRipVideoCodec * video)242 ogmrip_mp4box_extract_command (OGMRipVideoCodec *video)
243 {
244 GPtrArray *argv;
245 const gchar *filename;
246
247 argv = g_ptr_array_new ();
248 g_ptr_array_add (argv, g_strdup (PROGRAM));
249 g_ptr_array_add (argv, g_strdup ("-aviraw"));
250 g_ptr_array_add (argv, g_strdup ("video"));
251
252 filename = ogmrip_codec_get_output (OGMRIP_CODEC (video));
253 g_ptr_array_add (argv, g_strdup (filename));
254
255 g_ptr_array_add (argv, NULL);
256
257 return (gchar **) g_ptr_array_free (argv, FALSE);
258 }
259
260 static gdouble
ogmrip_mp4box_extract_watch(OGMJobExec * exec,const gchar * buffer,OGMRipContainer * mp4)261 ogmrip_mp4box_extract_watch (OGMJobExec *exec, const gchar *buffer, OGMRipContainer *mp4)
262 {
263 gchar *sep;
264 guint percent;
265
266 if ((sep = strrchr (buffer, '(')) && sscanf (sep, "(%u/100)", &percent) == 1)
267 return percent / 100.0;
268
269 return -1.0;
270 }
271
272 static gchar **
ogmrip_mencoder_extract_command(OGMRipVideoCodec * video,const gchar * output)273 ogmrip_mencoder_extract_command (OGMRipVideoCodec *video, const gchar *output)
274 {
275 GPtrArray *argv;
276 const gchar *filename;
277
278 argv = g_ptr_array_new ();
279 g_ptr_array_add (argv, g_strdup ("mencoder"));
280 g_ptr_array_add (argv, g_strdup ("-nocache"));
281 g_ptr_array_add (argv, g_strdup ("-noskip"));
282
283 if (MPLAYER_CHECK_VERSION (1,0,3,0))
284 {
285 g_ptr_array_add (argv, g_strdup ("-noconfig"));
286 g_ptr_array_add (argv, g_strdup ("all"));
287 }
288
289 g_ptr_array_add (argv, g_strdup ("-mc"));
290 g_ptr_array_add (argv, g_strdup ("0"));
291
292 g_ptr_array_add (argv, g_strdup ("-nosound"));
293
294 if (ogmrip_check_mplayer_nosub ())
295 g_ptr_array_add (argv, g_strdup ("-nosub"));
296
297 g_ptr_array_add (argv, g_strdup ("-ovc"));
298 g_ptr_array_add (argv, g_strdup ("copy"));
299
300 g_ptr_array_add (argv, g_strdup ("-of"));
301 g_ptr_array_add (argv, g_strdup ("lavf"));
302 g_ptr_array_add (argv, g_strdup ("-lavfopts"));
303 g_ptr_array_add (argv, g_strdup ("format=mp4"));
304
305 g_ptr_array_add (argv, g_strdup ("-o"));
306 g_ptr_array_add (argv, g_strdup (output));
307
308 filename = ogmrip_codec_get_output (OGMRIP_CODEC (video));
309 g_ptr_array_add (argv, g_strdup (filename));
310
311 g_ptr_array_add (argv, NULL);
312
313 return (gchar **) g_ptr_array_free (argv, FALSE);
314 }
315
316 static gint
ogmrip_mp4_get_n_audio_files(OGMRipContainer * mp4)317 ogmrip_mp4_get_n_audio_files (OGMRipContainer *mp4)
318 {
319 GSList *files, *file;
320 guint n_audio = 0;
321
322 files = ogmrip_container_get_files (mp4);
323 for (file = files; file; file = file->next)
324 {
325 if (ogmrip_file_get_type (OGMRIP_FILE (file->data)) == OGMRIP_FILE_TYPE_AUDIO)
326 n_audio ++;
327 }
328
329 g_slist_free (files);
330
331 return n_audio;
332 }
333
334 static gint
ogmrip_mp4_get_n_subp_files(OGMRipContainer * mp4)335 ogmrip_mp4_get_n_subp_files (OGMRipContainer *mp4)
336 {
337 GSList *files, *file;
338 guint n_subp = 0;
339
340 files = ogmrip_container_get_files (mp4);
341 for (file = files; file; file = file->next)
342 {
343 if (ogmrip_file_get_type (OGMRIP_FILE (file->data)) == OGMRIP_FILE_TYPE_SUBP)
344 n_subp ++;
345 }
346
347 g_slist_free (files);
348
349 return n_subp;
350 }
351
352 static gchar **
ogmrip_mp4_create_command(OGMRipContainer * mp4,const gchar * input,const gchar * output)353 ogmrip_mp4_create_command (OGMRipContainer *mp4, const gchar *input, const gchar *output)
354 {
355 GPtrArray *argv;
356 OGMRipVideoCodec *video;
357 const gchar *label, *fmt = NULL;
358 gchar fps[8];
359
360 if ((video = ogmrip_container_get_video (mp4)))
361 {
362 gint format;
363
364 format = ogmrip_plugin_get_video_codec_format (G_TYPE_FROM_INSTANCE (video));
365 switch (format)
366 {
367 case OGMRIP_FORMAT_MPEG4:
368 fmt = "mpeg4-video";
369 break;
370 case OGMRIP_FORMAT_MPEG2:
371 fmt = "mpeg2-video";
372 break;
373 case OGMRIP_FORMAT_H264:
374 fmt = "h264";
375 break;
376 case OGMRIP_FORMAT_THEORA:
377 fmt = "ogg";
378 break;
379 default:
380 fmt = NULL;
381 break;
382 }
383
384 if (!fmt)
385 return NULL;
386 }
387
388 argv = g_ptr_array_new ();
389 g_ptr_array_add (argv, g_strdup (PROGRAM));
390
391 if (ogmrip_container_get_n_audio (mp4) + ogmrip_mp4_get_n_audio_files (mp4) <= 1 &&
392 ogmrip_container_get_n_subp (mp4) + ogmrip_mp4_get_n_subp_files (mp4) < 1)
393 g_ptr_array_add (argv, g_strdup ("-isma"));
394
395 g_ptr_array_add (argv, g_strdup ("-nodrop"));
396 g_ptr_array_add (argv, g_strdup ("-new"));
397
398 g_ptr_array_add (argv, g_strdup ("-brand"));
399 g_ptr_array_add (argv, g_strdup ("mp42"));
400
401 g_ptr_array_add (argv, g_strdup ("-tmp"));
402 g_ptr_array_add (argv, g_strdup (ogmrip_fs_get_tmp_dir ()));
403
404 label = ogmrip_container_get_label (mp4);
405 if (label)
406 {
407 g_ptr_array_add (argv, g_strdup ("-itags"));
408 g_ptr_array_add (argv, g_strdup_printf ("name=%s", label));
409 }
410
411 if (fmt)
412 {
413 if (!input)
414 input = ogmrip_codec_get_output (OGMRIP_CODEC (video));
415
416 g_ascii_formatd (fps, 8, "%.3f",
417 ogmrip_mp4_get_output_fps (OGMRIP_CODEC (video)));
418
419 g_ptr_array_add (argv, g_strdup ("-add"));
420 g_ptr_array_add (argv, g_strdup_printf ("%s:fmt=%s:fps=%s#video", input, fmt, fps));
421 }
422
423 ogmrip_container_foreach_audio (mp4,
424 (OGMRipContainerCodecFunc) ogmrip_mp4_foreach_audio, argv);
425 ogmrip_container_foreach_subp (mp4,
426 (OGMRipContainerCodecFunc) ogmrip_mp4_foreach_subp, argv);
427 ogmrip_container_foreach_chapters (mp4,
428 (OGMRipContainerCodecFunc) ogmrip_mp4_foreach_chapters, argv);
429 ogmrip_container_foreach_file (mp4,
430 (OGMRipContainerFileFunc) ogmrip_mp4_foreach_file, argv);
431
432 g_ptr_array_add (argv, g_strdup (output));
433
434 g_ptr_array_add (argv, NULL);
435
436 return (gchar **) g_ptr_array_free (argv, FALSE);
437 }
438
439 static gdouble
ogmrip_mp4_create_watch(OGMJobExec * exec,const gchar * buffer,OGMRipMp4 * mp4)440 ogmrip_mp4_create_watch (OGMJobExec *exec, const gchar *buffer, OGMRipMp4 *mp4)
441 {
442 guint percent;
443 gchar *sep;
444
445 if ((sep = strrchr (buffer, '(')) && sscanf (sep, "(%u/100)", &percent) == 1)
446 {
447 if (percent < mp4->old_percent)
448 mp4->streams ++;
449
450 mp4->old_percent = percent;
451
452 return mp4->streams / (gdouble) mp4->nstreams + percent / (mp4->nstreams * 100.0);
453 }
454
455 return -1.0;
456 }
457
458 static gchar **
ogmrip_mp4_split_command(OGMRipContainer * mp4,const gchar * input)459 ogmrip_mp4_split_command (OGMRipContainer *mp4, const gchar *input)
460 {
461 GPtrArray *argv;
462 guint tsize;
463
464 argv = g_ptr_array_new ();
465 g_ptr_array_add (argv, g_strdup (PROGRAM));
466
467 g_ptr_array_add (argv, g_strdup ("-tmp"));
468 g_ptr_array_add (argv, g_strdup (ogmrip_fs_get_tmp_dir ()));
469
470 ogmrip_container_get_split (OGMRIP_CONTAINER (mp4), NULL, &tsize);
471 g_ptr_array_add (argv, g_strdup ("-splits"));
472 g_ptr_array_add (argv, g_strdup_printf ("%d", tsize));
473
474 g_ptr_array_add (argv, g_strdup (input));
475
476 g_ptr_array_add (argv, NULL);
477
478 return (gchar **) g_ptr_array_free (argv, FALSE);
479 }
480
481 static gdouble
ogmrip_mp4_split_watch(OGMJobExec * exec,const gchar * buffer,OGMRipMp4 * mp4)482 ogmrip_mp4_split_watch (OGMJobExec *exec, const gchar *buffer, OGMRipMp4 *mp4)
483 {
484 gchar *sep;
485 guint percent;
486
487 if ((sep = strrchr (buffer, '(')) && sscanf (sep, "(%u/100)", &percent) == 1)
488 {
489 if (g_str_has_prefix (buffer, "Splitting:"))
490 {
491 mp4->split_percent = percent;
492
493 return (percent + 100 * mp4->splits) / (100.0 * (mp4->nsplits + 1));
494 }
495 else if (g_str_has_prefix (buffer, "ISO File Writing:"))
496 {
497 if (percent < mp4->split_percent)
498 mp4->splits ++;
499
500 return (percent + mp4->split_percent + 100 * mp4->splits) / (100.0 * (mp4->nsplits + 1));
501 }
502 }
503
504 return -1.0;
505 }
506
G_DEFINE_TYPE(OGMRipMp4,ogmrip_mp4,OGMRIP_TYPE_CONTAINER)507 G_DEFINE_TYPE (OGMRipMp4, ogmrip_mp4, OGMRIP_TYPE_CONTAINER)
508
509 static void
510 ogmrip_mp4_class_init (OGMRipMp4Class *klass)
511 {
512 OGMJobSpawnClass *spawn_class;
513
514 spawn_class = OGMJOB_SPAWN_CLASS (klass);
515 spawn_class->run = ogmrip_mp4_run;
516 }
517
518 static void
ogmrip_mp4_init(OGMRipMp4 * mp4)519 ogmrip_mp4_init (OGMRipMp4 *mp4)
520 {
521 }
522
523 static gchar *
ogmrip_mp4_get_h264_filename(OGMRipVideoCodec * video)524 ogmrip_mp4_get_h264_filename (OGMRipVideoCodec *video)
525 {
526 const gchar *name;
527 gchar *dot, *filename;
528
529 name = ogmrip_codec_get_output (OGMRIP_CODEC (video));
530 dot = strrchr (name, '.');
531
532 filename = g_new0 (gchar, dot - name + 12);
533 strncpy (filename, name, dot - name);
534 strcat (filename, "_video.h264");
535
536 return filename;
537 }
538
539 static void
ogmrip_mp4_get_n_vobsub(OGMRipContainer * container,OGMRipCodec * codec,guint demuxer,gint language,gint * nvobsub)540 ogmrip_mp4_get_n_vobsub (OGMRipContainer *container, OGMRipCodec *codec, guint demuxer, gint language, gint *nvobsub)
541 {
542 if (ogmrip_plugin_get_subp_codec_format (G_TYPE_FROM_INSTANCE (codec)) == OGMRIP_FORMAT_VOBSUB)
543 (*nvobsub) ++;
544 }
545
546 static gint
ogmrip_mp4_run(OGMJobSpawn * spawn)547 ogmrip_mp4_run (OGMJobSpawn *spawn)
548 {
549 OGMJobSpawn *queue, *child;
550 OGMRipVideoCodec *video;
551 OGMRipMp4 *mp4;
552
553 gchar **argv, *filename = NULL;
554 const gchar *output;
555
556 gint result = OGMJOB_RESULT_ERROR;
557
558 g_return_val_if_fail (OGMRIP_IS_MP4 (spawn), OGMJOB_RESULT_ERROR);
559
560 mp4 = OGMRIP_MP4 (spawn);
561
562 output = ogmrip_container_get_output (OGMRIP_CONTAINER (spawn));
563 ogmrip_container_get_split (OGMRIP_CONTAINER (spawn), &mp4->nsplits, NULL);
564
565 queue = ogmjob_queue_new ();
566 ogmjob_container_add (OGMJOB_CONTAINER (spawn), queue);
567 g_object_unref (queue);
568
569 video = ogmrip_container_get_video (OGMRIP_CONTAINER (spawn));
570 if (ogmrip_plugin_get_video_codec_format (G_TYPE_FROM_INSTANCE (video)) == OGMRIP_FORMAT_H264)
571 {
572 gboolean global_header = FALSE;
573
574 if (g_object_class_find_property (G_OBJECT_GET_CLASS (video), "global_header"))
575 g_object_get (video, "global_header", &global_header, NULL);
576
577 if (global_header)
578 {
579 filename = ogmrip_fs_mktemp ("video.XXXXXX", NULL);
580
581 argv = ogmrip_mencoder_extract_command (video, filename);
582 if (!argv)
583 {
584 g_free (filename);
585 return OGMJOB_RESULT_ERROR;
586 }
587
588 child = ogmjob_exec_newv (argv);
589 ogmjob_exec_add_watch_full (OGMJOB_EXEC (child), (OGMJobWatch) ogmrip_mencoder_container_watch, spawn, TRUE, FALSE, FALSE);
590 }
591 else
592 {
593 argv = ogmrip_mp4box_extract_command (video);
594 if (!argv)
595 return OGMJOB_RESULT_ERROR;
596
597 child = ogmjob_exec_newv (argv);
598 ogmjob_exec_add_watch_full (OGMJOB_EXEC (child), (OGMJobWatch) ogmrip_mp4box_extract_watch, spawn, TRUE, FALSE, FALSE);
599
600 filename = ogmrip_mp4_get_h264_filename (video);
601 }
602
603 ogmjob_container_add (OGMJOB_CONTAINER (queue), child);
604 g_object_unref (child);
605 }
606
607 argv = ogmrip_mp4_create_command (OGMRIP_CONTAINER (spawn), filename, output);
608 if (argv)
609 {
610 gint nvobsub = 0;
611
612 ogmrip_container_foreach_subp (OGMRIP_CONTAINER (spawn), (OGMRipContainerCodecFunc) ogmrip_mp4_get_n_vobsub, &nvobsub);
613
614 mp4->old_percent = 0;
615 mp4->nstreams = 2 + ogmrip_container_get_n_audio (OGMRIP_CONTAINER (spawn)) + nvobsub;
616 mp4->streams = 0;
617
618 child = ogmjob_exec_newv (argv);
619 ogmjob_exec_add_watch_full (OGMJOB_EXEC (child), (OGMJobWatch) ogmrip_mp4_create_watch, spawn, TRUE, FALSE, FALSE);
620 ogmjob_container_add (OGMJOB_CONTAINER (queue), child);
621 g_object_unref (child);
622
623 if (mp4->nsplits > 1 && result == OGMJOB_RESULT_SUCCESS)
624 {
625 argv = ogmrip_mp4_split_command (OGMRIP_CONTAINER (spawn), output);
626 if (argv)
627 {
628 mp4->split_percent = 0;
629 mp4->splits = 0;
630
631 child = ogmjob_exec_newv (argv);
632 ogmjob_exec_add_watch_full (OGMJOB_EXEC (child), (OGMJobWatch) ogmrip_mp4_split_watch, spawn, TRUE, FALSE, FALSE);
633 ogmjob_container_add (OGMJOB_CONTAINER (queue), child);
634 g_object_unref (child);
635 }
636 }
637
638 result = OGMJOB_SPAWN_CLASS (ogmrip_mp4_parent_class)->run (spawn);
639 }
640
641 ogmjob_container_remove (OGMJOB_CONTAINER (spawn), queue);
642
643 if (filename)
644 ogmrip_fs_unref (filename, TRUE);
645
646 if (mp4->nsplits > 1)
647 ogmrip_fs_unref (g_strdup (output), TRUE);
648
649 return result;
650 }
651
652 static OGMRipContainerPlugin mp4_plugin =
653 {
654 NULL,
655 G_TYPE_NONE,
656 "mp4",
657 N_("Mpeg-4 Media (MP4)"),
658 FALSE,
659 TRUE,
660 G_MAXINT,
661 G_MAXINT,
662 NULL
663 };
664
665 static gint formats[] =
666 {
667 OGMRIP_FORMAT_MPEG4,
668 OGMRIP_FORMAT_MPEG2,
669 OGMRIP_FORMAT_H264,
670 OGMRIP_FORMAT_THEORA,
671 OGMRIP_FORMAT_AAC,
672 OGMRIP_FORMAT_MP3,
673 OGMRIP_FORMAT_VORBIS,
674 OGMRIP_FORMAT_SRT,
675 OGMRIP_FORMAT_VOBSUB,
676 -1,
677 -1,
678 -1
679 };
680
681 OGMRipContainerPlugin *
ogmrip_init_plugin(GError ** error)682 ogmrip_init_plugin (GError **error)
683 {
684 gchar *output;
685 gint major_version = 0, minor_version = 0, micro_version = 0;
686
687 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
688
689 if (!g_spawn_command_line_sync (PROGRAM " -version", &output, NULL, NULL, NULL))
690 {
691 g_set_error (error, OGMRIP_PLUGIN_ERROR, OGMRIP_PLUGIN_ERROR_REQ, _("MP4Box is missing"));
692 return NULL;
693 }
694
695 if (g_str_has_prefix (output, "MP4Box - GPAC version "))
696 {
697 gchar *end;
698
699 errno = 0;
700 major_version = strtoul (output + 22, &end, 10);
701 if (!errno && *end == '.')
702 minor_version = strtoul (end + 1, NULL, 10);
703 if (!errno && *end == '.')
704 micro_version = strtoul (end + 1, NULL, 10);
705 }
706 g_free (output);
707
708 if ((major_version > 0) ||
709 (major_version == 0 && minor_version > 4) ||
710 (major_version == 0 && minor_version == 4 && micro_version >= 5))
711 {
712 guint i = 0;
713
714 while (formats[i] != -1)
715 i++;
716
717 formats[i] = OGMRIP_FORMAT_AC3;
718 formats[i+1] = OGMRIP_FORMAT_COPY;
719 }
720
721 mp4_plugin.type = OGMRIP_TYPE_MP4;
722 mp4_plugin.formats = formats;
723
724 return &mp4_plugin;
725 }
726
727