Macro qtTrIdx() replaced by tr() and QT_TRANSLATE_NOOP()
[mafwsubrenderer] / qmafw-gst-subtitles-renderer / src / mafw-gst-renderer-utils.c
1 /*
2  * This file is a part of MAFW
3  *
4  * Copyright (C) 2007, 2008, 2009 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Visa Smolander <visa.smolander@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <glib.h>
30
31 #include <string.h>
32 #include <gio/gio.h>
33
34 #include <gst/gst.h>
35
36 #include "mafw-gst-renderer-utils.h"
37
38 #undef  G_LOG_DOMAIN
39 #define G_LOG_DOMAIN "mafw-gst-renderer-utils"
40
41 /**
42  * convert_utf8:
43  * @src: string.
44  * @dst: location for utf8 version of @src.
45  *
46  * Tries to convert @src into UTF-8, placing it into @dst.
47  *
48  * Returns: TRUE on success.
49  */
50 gboolean convert_utf8(const gchar *src, gchar **dst)
51 {
52     GError *error;
53
54     if (!src || !dst)
55         return FALSE;
56     if (g_utf8_validate(src, -1, NULL)) {
57         *dst = g_strdup(src);
58         return TRUE;
59     }
60     error = NULL;
61     *dst = g_locale_to_utf8(src, -1, NULL, NULL, &error);
62     if (error) {
63         g_warning("utf8 conversion failed '%s' (%d: %s)",
64               src, error->code, error->message);
65         g_error_free(error);
66         return FALSE;
67     }
68     return TRUE;
69 }
70
71 /**
72  * uri_is_stream:
73  * @uri: the URI to be checked.
74  *
75  * Check if given URI is a stream (not a local resource).  To not depend on
76  * gnomevfs for this, we assume everything that doesn't start with "file://" is
77  * a stream.
78  *
79  * Returns: TRUE if the URI is not local.
80  */
81 gboolean uri_is_stream(const gchar *uri)
82 {
83     if (uri == NULL) {
84         return FALSE;
85     } else {
86         return !g_str_has_prefix(uri, "file://");
87     }
88 }
89
90 /** remap_gst_error_code:
91  *
92  * @error: pointer to error
93  * 
94  * Maps a Gst error to worker errror code,
95  * mapping follows roughly the one from FMAFW gst-renderer.
96  *
97  * Returns: possibly remapped ecode if the domain was certain Gst domain.
98 */
99 gint remap_gst_error_code(const GError *error)
100 {
101
102     gint new_err_code;
103
104     if (error->domain == GST_RESOURCE_ERROR)
105     {
106         /* handle RESOURCE errors */
107         switch (error->code)
108         {
109             case GST_RESOURCE_ERROR_READ:
110                 new_err_code = WORKER_ERROR_STREAM_DISCONNECTED;
111                 break;
112             case GST_RESOURCE_ERROR_NOT_FOUND:
113             case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
114             case GST_RESOURCE_ERROR_OPEN_READ:
115                 new_err_code = WORKER_ERROR_MEDIA_NOT_FOUND;
116                 break;
117             case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
118                 new_err_code = WORKER_ERROR_UNABLE_TO_PERFORM;
119                 break;
120             case GST_RESOURCE_ERROR_WRITE:
121                 /* DSP renderers send ERROR_WRITE when they find
122                    corrupted data */
123                 new_err_code = WORKER_ERROR_CORRUPTED_FILE;
124                 break;
125             case GST_RESOURCE_ERROR_SEEK:
126                 new_err_code = WORKER_ERROR_CANNOT_SET_POSITION;
127                 break;
128             default:
129                 /* Unknown RESOURCE error */
130                 new_err_code = WORKER_ERROR_UNABLE_TO_PERFORM;
131                 break;
132         }
133     }
134     else if (error->domain == GST_STREAM_ERROR)
135     {
136         /* handle STREAM errors */
137         switch (error->code) {
138             case GST_STREAM_ERROR_TYPE_NOT_FOUND:
139                 new_err_code = WORKER_ERROR_TYPE_NOT_AVAILABLE;
140                 break;
141             case GST_STREAM_ERROR_FORMAT:
142             case GST_STREAM_ERROR_WRONG_TYPE:
143             case GST_STREAM_ERROR_FAILED:
144                 new_err_code = WORKER_ERROR_UNSUPPORTED_TYPE;
145                 break;
146             case GST_STREAM_ERROR_DECODE:
147             case GST_STREAM_ERROR_DEMUX:
148                 new_err_code = WORKER_ERROR_CORRUPTED_FILE;
149                 break;
150             case GST_STREAM_ERROR_CODEC_NOT_FOUND:
151                 new_err_code = WORKER_ERROR_CODEC_NOT_FOUND;
152                 break;
153             case GST_STREAM_ERROR_DECRYPT:
154             case GST_STREAM_ERROR_DECRYPT_NOKEY:
155                 new_err_code = WORKER_ERROR_DRM_NOT_ALLOWED;
156                 break;
157             case WORKER_ERROR_POSSIBLY_PLAYLIST_TYPE:
158                 new_err_code = WORKER_ERROR_POSSIBLY_PLAYLIST_TYPE;
159                 break;
160             default:
161                 /* Unknown STREAM error */
162                 new_err_code = WORKER_ERROR_UNABLE_TO_PERFORM;
163                 break;
164         }
165     }
166     else if( error->domain == GST_CORE_ERROR )
167     {
168         switch( error->code ) {
169             case GST_CORE_ERROR_MISSING_PLUGIN:
170                 new_err_code = WORKER_ERROR_UNSUPPORTED_TYPE;
171                 break;
172             default:
173                 new_err_code = error->code;
174         }
175     }
176     else
177     {
178         /* by default return the original code */
179         new_err_code = error->code;
180     }
181
182     return new_err_code;
183
184 }
185
186 /*
187  * Imported from totem-uri.c
188  * Copyright (C) 2004 Bastien Nocera
189  */
190
191 /* List from xine-lib's demux_sputext.c */
192 static const char subtitle_ext[][4] = {
193     "sub",
194     "srt",
195     "smi",
196     "ssa",
197     "ass",
198     "asc"
199 };
200
201 static inline gboolean
202 uri_exists (const char *uri)
203 {
204     GFile *file = g_file_new_for_uri (uri);
205     if (file != NULL) {
206         if (g_file_query_exists (file, NULL)) {
207             g_object_unref (file);
208                 return TRUE;
209         }
210         g_object_unref (file);
211     }
212     return FALSE;
213 }
214
215 static char *
216 uri_get_subtitle_for_uri (const char *uri)
217 {
218     char *subtitle;
219     guint len, i;
220     gint suffix;
221
222     /* Find the filename suffix delimiter */
223     len = strlen (uri);
224     for (suffix = len - 1; suffix > 0; suffix--) {
225         if (uri[suffix] == G_DIR_SEPARATOR ||
226             (uri[suffix] == '/')) {
227                 /* This filename has no extension; we'll need to 
228                  * add one */
229                 suffix = len;
230                 break;
231         }
232         if (uri[suffix] == '.') {
233             /* Found our extension marker */
234             break;
235         }
236     }
237     if (suffix < 0)
238         return NULL;
239
240     /* Generate a subtitle string with room at the end to store the
241      * 3 character extensions for which we want to search */
242     subtitle = g_malloc0 (suffix + 4 + 1);
243     g_return_val_if_fail (subtitle != NULL, NULL);
244     g_strlcpy (subtitle, uri, suffix + 4 + 1);
245     g_strlcpy (subtitle + suffix, ".???", 5);
246
247     /* Search for any files with one of our known subtitle extensions */
248     for (i = 0; i < G_N_ELEMENTS (subtitle_ext) ; i++) {
249         char *subtitle_ext_upper;
250         memcpy (subtitle + suffix + 1, subtitle_ext[i], 3);
251
252         if (uri_exists (subtitle))
253             return subtitle;
254
255         /* Check with upper-cased extension */
256         subtitle_ext_upper = g_ascii_strup (subtitle_ext[i], -1);
257         memcpy (subtitle + suffix + 1, subtitle_ext_upper, 3);
258         g_free (subtitle_ext_upper);
259
260         if (uri_exists (subtitle))
261             return subtitle;
262     }
263     g_free (subtitle);
264     return NULL;
265 }
266
267 static char *
268 uri_get_subtitle_in_subdir (GFile *file, const char *subdir)
269 {
270     char *filename, *subtitle, *full_path_str;
271     GFile *parent, *full_path, *directory;
272
273     /* Get the sibling directory @subdir of the file @file */
274     parent = g_file_get_parent (file);
275     directory = g_file_get_child (parent, subdir);
276     g_object_unref (parent);
277
278     /* Get the file of the same name as @file in the @subdir directory */
279     filename = g_file_get_basename (file);
280     full_path = g_file_get_child (directory, filename);
281     g_object_unref (directory);
282     g_free (filename);
283
284     /* Get the subtitles from that URI */
285     full_path_str = g_file_get_uri (full_path);
286     g_object_unref (full_path);
287     subtitle = uri_get_subtitle_for_uri (full_path_str);
288     g_free (full_path_str);
289
290     return subtitle;
291 }
292
293 char *
294 uri_get_subtitle_uri (const char *uri)
295 {
296     GFile *file;
297     char *subtitle;
298
299     if (g_str_has_prefix (uri, "http") != FALSE)
300         return NULL;
301
302     /* Has the user specified a subtitle file manually? */
303     if (strstr (uri, "#subtitle:") != NULL)
304         return NULL;
305
306     /* Does the file exist? */
307     file = g_file_new_for_uri (uri);
308     if (g_file_query_exists (file, NULL) != TRUE) {
309         g_object_unref (file);
310         return NULL;
311     }
312
313     /* Try in the current directory */
314     subtitle = uri_get_subtitle_for_uri (uri);
315     if (subtitle != NULL) {
316         g_object_unref (file);
317         return subtitle;
318     }
319
320     subtitle = uri_get_subtitle_in_subdir (file, "subtitles");
321     g_object_unref (file);
322
323     return subtitle;
324 }