[1.1.0] Enable resource manager commonization
[platform/core/multimedia/libmm-player.git] / src / mm_player_tracks.c
1 /*
2  * libmm-player
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, naveen cherukuri <naveen.ch@samsung.com>,
7  * YeJin Cho <cho.yejin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22 #include <dlog.h>
23 #include <mm_error.h>
24 #include "mm_player_utils.h"
25 #include "mm_player_tracks.h"
26 #include "mm_player_attrs.h"
27
28 #define LANGUAGE_CODE_SIZE (3 + 1) /* Size of ISO-639-1, and considering the nul-terminator */
29
30 /*---------------------------------------------------------------------------------------
31 |    LOCAL FUNCTION PROTOTYPES:                                                                               |
32 ---------------------------------------------------------------------------------------*/
33 static int __mmplayer_track_get_language(mmplayer_t *player, mmplayer_track_type_e type, gint stream_index, gchar **code);
34
35
36 /*=======================================================================================
37 |  FUNCTION DEFINITIONS                                                                                      |
38 =======================================================================================*/
39 int
40 _mmplayer_get_track_count(MMHandleType hplayer,  mmplayer_track_type_e type, int *count)
41 {
42         int ret = MM_ERROR_NONE;
43         mmplayer_t *player = (mmplayer_t *)hplayer;
44         MMHandleType attrs = 0;
45
46         MMPLAYER_FENTER();
47
48         /* check player handle */
49         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
50         MMPLAYER_RETURN_VAL_IF_FAIL(type < MM_PLAYER_TRACK_TYPE_MAX, MM_ERROR_INVALID_ARGUMENT);
51         MMPLAYER_RETURN_VAL_IF_FAIL(count, MM_ERROR_INVALID_ARGUMENT);
52         MMPLAYER_RETURN_VAL_IF_FAIL((MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)
53                  || (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING),
54                 MM_ERROR_PLAYER_INVALID_STATE);
55
56         attrs = MMPLAYER_GET_ATTRS(player);
57         if (!attrs) {
58                 LOGE("cannot get content attribute");
59                 return MM_ERROR_PLAYER_INTERNAL;
60         }
61
62         *count = 0;
63
64         switch (type) {
65         case MM_PLAYER_TRACK_TYPE_AUDIO:
66                 if (player->track[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num > 0)
67                         *count = player->track[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num;
68                 break;
69         case MM_PLAYER_TRACK_TYPE_TEXT: /* internal or external */
70                 ret = mm_attrs_get_int_by_name(attrs, "content_text_track_num", count);
71                 break;
72         default:
73                 ret = MM_ERROR_INVALID_ARGUMENT;
74                 break;
75         }
76
77         LOGD("type: %d, the num of track: %d", type, *count);
78
79         MMPLAYER_FLEAVE();
80
81         return ret;
82 }
83
84 int
85 _mmplayer_select_track(MMHandleType hplayer, mmplayer_track_type_e type, int index)
86 {
87         int ret = MM_ERROR_NONE;
88         mmplayer_t *player = (mmplayer_t *)hplayer;
89
90         MMPLAYER_FENTER();
91         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
92         MMPLAYER_RETURN_VAL_IF_FAIL(type < MM_PLAYER_TRACK_TYPE_MAX, MM_ERROR_INVALID_ARGUMENT);
93
94         LOGD("track type: %d, index: %d", type, index);
95
96         MMPLAYER_SUBTITLE_INFO_LOCK(player);
97
98         if (type == MM_PLAYER_TRACK_TYPE_TEXT && player->subtitle_language_list) { /* external subtitle */
99                 GstElement *subparse = NULL;
100                 mmplayer_lang_info_t *temp = NULL;
101                 guint num_of_list = 0;
102
103                 if (!player->pipeline || !player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst) {
104                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
105                         goto EXIT;
106                 }
107
108                 num_of_list = g_list_length(player->subtitle_language_list);
109                 if (index < 0 || index >= num_of_list) {
110                         LOGE("req track index is wrong");
111                         ret = MM_ERROR_INVALID_ARGUMENT;
112                         goto EXIT;
113                 }
114
115                 temp = g_list_nth_data(player->subtitle_language_list, index);
116                 if (!temp) {
117                         LOGE("fail to get lang from list");
118                         ret = MM_ERROR_PLAYER_INTERNAL;
119                         goto EXIT;
120                 }
121                 subparse = player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst;
122                 LOGD("setting to language %s", temp->language_code);
123                 g_object_set(G_OBJECT(subparse), "current-language", temp->language_key, NULL);
124
125                 _mmplayer_sync_subtitle_pipeline(player);
126
127         } else { /* audio or internal subtitle */
128                 ret = _mmplayer_change_track_language(hplayer, type, index);
129                 if (ret != MM_ERROR_NONE) {
130                         LOGE("failed to change track");
131                         goto EXIT;
132                 }
133         }
134
135         if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
136                 if (mm_player_set_attribute(hplayer, NULL,
137                                 "current_text_track_index", index, NULL) != MM_ERROR_NONE) {
138                         LOGE("failed to set text track index");
139                         ret = MM_ERROR_PLAYER_INTERNAL;
140                         goto EXIT;
141                 }
142         }
143
144         LOGD("current index is updated");
145
146 EXIT:
147         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
148         MMPLAYER_FLEAVE();
149         return ret;
150 }
151
152 int
153 _mmplayer_get_current_track(MMHandleType hplayer, mmplayer_track_type_e type, int *index)
154 {
155         int ret = MM_ERROR_NONE;
156         mmplayer_t *player = (mmplayer_t *)hplayer;
157         MMHandleType attrs = 0;
158         gint count = 0;
159
160         MMPLAYER_FENTER();
161         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
162         MMPLAYER_RETURN_VAL_IF_FAIL(type < MM_PLAYER_TRACK_TYPE_MAX, MM_ERROR_INVALID_ARGUMENT);
163         MMPLAYER_RETURN_VAL_IF_FAIL(index, MM_ERROR_INVALID_ARGUMENT);
164
165         attrs = MMPLAYER_GET_ATTRS(player);
166         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
167
168         MMPLAYER_SUBTITLE_INFO_LOCK(player);
169
170         LOGD("track type: %d", type);
171
172         *index = INVALID_TRACK_INDEX;
173
174         switch (type) {
175         case MM_PLAYER_TRACK_TYPE_AUDIO:
176                 if (player->track[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) {
177                         LOGW("there is no audio track");
178                         ret = MM_ERROR_PLAYER_NO_OP;
179                         goto EXIT;
180                 }
181
182                 *index = player->track[MM_PLAYER_TRACK_TYPE_AUDIO].active_track_index;
183                 break;
184         case MM_PLAYER_TRACK_TYPE_TEXT: /* internal or external */
185                 mm_attrs_get_int_by_name(attrs, "content_text_track_num", &count);
186                 if (count <= 0) {
187                         LOGD("there is no text track");
188                         ret = MM_ERROR_PLAYER_NO_OP;
189                         goto EXIT;
190                 }
191
192                 mm_attrs_get_int_by_name(attrs, "current_text_track_index", index);
193                 break;
194         default:
195                 LOGD("invalid input type");
196                 ret = MM_ERROR_INVALID_ARGUMENT;
197                 goto EXIT;
198         }
199
200         if (*index < 0) {
201                 LOGE("invalid track index");
202                 ret = MM_ERROR_PLAYER_INTERNAL;
203                 goto EXIT;
204         }
205
206         LOGD("current track index: %d", *index);
207
208 EXIT:
209         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
210         MMPLAYER_FLEAVE();
211         return ret;
212 }
213
214 int
215 _mmplayer_get_track_language_code(MMHandleType hplayer, mmplayer_track_type_e type, int index, char **code)
216 {
217         int ret = MM_ERROR_NONE;
218         mmplayer_t *player = (mmplayer_t *)hplayer;
219         gchar *lang_code = NULL;
220
221         MMPLAYER_FENTER();
222         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
223         MMPLAYER_RETURN_VAL_IF_FAIL(type < MM_PLAYER_TRACK_TYPE_MAX, MM_ERROR_INVALID_ARGUMENT);
224         MMPLAYER_RETURN_VAL_IF_FAIL(code, MM_ERROR_INVALID_ARGUMENT);
225
226         MMPLAYER_SUBTITLE_INFO_LOCK(player);
227
228         if (type == MM_PLAYER_TRACK_TYPE_TEXT && player->subtitle_language_list) { /* external subtitle */
229                 mmplayer_lang_info_t *language_list = NULL;
230
231                 lang_code = (gchar *)g_malloc0(LANGUAGE_CODE_SIZE * sizeof(char));
232
233                 language_list = g_list_nth_data(player->subtitle_language_list, index);
234                 if (language_list == NULL) {
235                         LOGE("invalid index %d", index);
236                         ret = MM_ERROR_INVALID_ARGUMENT;
237                         goto EXIT;
238                 }
239                 g_strlcpy(lang_code, language_list->language_code, LANGUAGE_CODE_SIZE);
240         } else { /* audio or internal subtitle */
241                 if (player->track[type].total_track_num <= 0) {
242                         LOGW("language list is not available. [type:%d]", type);
243                         ret = MM_ERROR_PLAYER_NO_OP;
244                         goto EXIT;
245                 }
246
247                 ret = __mmplayer_track_get_language(player, type, index, &lang_code);
248         }
249
250 EXIT:
251         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
252
253         *code = NULL;
254         if (ret == MM_ERROR_NONE) {
255                 if (g_strcmp0(lang_code, "und"))
256                         *code = strndup(lang_code, 2);
257                 else
258                         *code = strndup("und", 3);
259         }
260         MMPLAYER_FREEIF(lang_code);
261
262         MMPLAYER_FLEAVE();
263         return ret;
264 }
265
266 void
267 _mmplayer_track_initialize(mmplayer_t *player)
268 {
269         mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_AUDIO;
270
271         MMPLAYER_FENTER();
272
273         for (; type < MM_PLAYER_TRACK_TYPE_MAX ; type++) {
274                 player->track[type].active_track_index = INVALID_TRACK_INDEX;
275                 player->track[type].total_track_num = 0;
276                 player->track[type].streams = g_ptr_array_new_with_free_func(gst_object_unref);
277         }
278 }
279
280 void
281 _mmplayer_track_destroy(mmplayer_t *player)
282 {
283         mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_AUDIO;
284         MMPLAYER_FENTER();
285
286         if (mm_player_set_attribute((MMHandleType)player, NULL, "content_text_track_num", 0,
287                         "current_text_track_index", INVALID_TRACK_INDEX, NULL) != MM_ERROR_NONE)
288                 LOGE("failed to reset track attr");
289
290         for (; type < MM_PLAYER_TRACK_TYPE_MAX ; type++) {
291                 player->track[type].active_track_index = 0;
292                 player->track[type].total_track_num = 0;
293
294                 if (player->track[type].streams)
295                         g_ptr_array_free(player->track[type].streams, TRUE);
296                 player->track[type].streams = NULL;
297         }
298 }
299
300 int
301 _mmplayer_get_track_index(mmplayer_t *player, mmplayer_track_type_e type, void* stream, int *index)
302 {
303         guint found_index = 0;
304
305         MMPLAYER_FENTER();
306         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
307         MMPLAYER_RETURN_VAL_IF_FAIL(type < MM_PLAYER_TRACK_TYPE_MAX, MM_ERROR_INVALID_ARGUMENT);
308         MMPLAYER_RETURN_VAL_IF_FAIL(index, MM_ERROR_INVALID_ARGUMENT);
309
310         if (g_ptr_array_find(player->track[type].streams, stream, &found_index)) {
311                 LOGD("Find same stream (%u)", found_index);
312                 *index = (int)found_index;
313                 return MM_ERROR_NONE;
314         }
315
316         *index = INVALID_TRACK_INDEX;
317         LOGD("Stream not found : type %d, stream %p", type, stream);
318         return MM_ERROR_PLAYER_INTERNAL;
319 }
320
321 static gboolean
322 __mmplayer_stream_equal(gconstpointer stream1, gconstpointer stream2)
323 {
324         return (g_strcmp0(gst_stream_get_stream_id((GstStream *)stream1),
325                 gst_stream_get_stream_id((GstStream *)stream2)) == 0);
326 }
327
328 void
329 _mmplayer_track_update_stream(mmplayer_t *player, mmplayer_track_type_e type, void *stream)
330 {
331         MMPLAYER_FENTER();
332         MMPLAYER_RETURN_IF_FAIL(player);
333         MMPLAYER_RETURN_IF_FAIL(type < MM_PLAYER_TRACK_TYPE_MAX);
334
335         if (g_ptr_array_find_with_equal_func(player->track[type].streams, stream, __mmplayer_stream_equal, NULL)) {
336                 LOGD("Already added stream, not updated");
337                 return;
338         }
339
340         player->track[type].total_track_num++;
341         g_ptr_array_add(player->track[type].streams, gst_object_ref(stream));
342
343         LOGD("type: %d, track cnt: %d", type, player->track[type].total_track_num);
344 }
345
346 void
347 _mmplayer_track_update_text_attr_info(mmplayer_t *player, GstMessage *msg)
348 {
349          const GValue *lang_list = NULL;
350          mmplayer_lang_info_t *temp = NULL;
351          gchar *current_lang = NULL;
352          gint  track_index = INVALID_TRACK_INDEX;
353          guint track_count = 0, index = 0;
354
355          MMPLAYER_FENTER();
356          MMPLAYER_RETURN_IF_FAIL(player && msg);
357
358         if (!gst_message_get_structure(msg)) {
359                 LOGE("failed to get msg structure");
360                 return;
361         }
362
363         lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
364         if (!lang_list) {
365                 LOGW("language list is null");
366                 return;
367         }
368
369         track_count = g_list_length((GList *)g_value_get_pointer(lang_list));
370         if (track_count == 0) {
371                 LOGW("track count is zero");
372                 return;
373         }
374
375         MMPLAYER_SUBTITLE_INFO_LOCK(player);
376         player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
377         mm_player_set_attribute((MMHandleType)player, NULL,
378                         "content_text_track_num", (gint)track_count, NULL);
379         g_object_get(G_OBJECT(msg->src), "current-language", &current_lang, NULL);
380
381         LOGI("track count: %d, current track lang: %s", track_count, current_lang);
382         if (!current_lang)
383                 goto EXIT;
384
385         for (index = 0 ; index < track_count ; index++) {
386                 temp = g_list_nth_data(player->subtitle_language_list, index);
387                 if (temp) {
388                         LOGI("[%d] lang_key: %s, lang_code: %s",
389                                 index, temp->language_key, temp->language_code);
390
391                         if (!g_strcmp0(temp->language_key, current_lang)) {
392                                 LOGD("current track index : %d", index);
393                                 track_index = index;
394                                 break;
395                         }
396                 }
397         }
398
399         if (track_index > INVALID_TRACK_INDEX)
400                 mm_player_set_attribute((MMHandleType)player, NULL,
401                                 "current_text_track_index", track_index, NULL);
402         else
403                 LOGE("failed to find current track index");
404
405 EXIT:
406         MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
407         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
408
409         MMPLAYER_FLEAVE();
410 }
411
412 static int
413 __mmplayer_track_get_language(mmplayer_t *player, mmplayer_track_type_e type, gint stream_index, gchar **code)
414 {
415         GstTagList *tag_list = NULL;
416         gchar *tag = NULL;
417
418         MMPLAYER_FENTER();
419         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
420         MMPLAYER_RETURN_VAL_IF_FAIL(type < MM_PLAYER_TRACK_TYPE_MAX, MM_ERROR_INVALID_ARGUMENT);
421         MMPLAYER_RETURN_VAL_IF_FAIL((code && (stream_index >= 0) &&
422                 (stream_index < player->track[type].total_track_num)), MM_ERROR_INVALID_ARGUMENT);
423
424         LOGD("type: %d, track count: %d, input idx: %d", type, player->track[type].total_track_num, stream_index);
425
426         *code = (gchar *)g_malloc0(LANGUAGE_CODE_SIZE * sizeof(char));
427
428         if (MMPLAYER_USE_DECODEBIN(player)) {
429                 GstPad *sinkpad = g_ptr_array_index(player->track[type].streams, stream_index);
430                 g_object_get(sinkpad, "tags", &tag_list, NULL);
431         } else {
432                 GstStream *stream = g_ptr_array_index(player->track[type].streams, stream_index);
433                 tag_list = gst_stream_get_tags (stream);
434         }
435
436         if (tag_list)
437                 gst_tag_list_get_string(tag_list, GST_TAG_LANGUAGE_CODE, &tag);
438
439         if (tag) {
440                 LOGD("language code: %s, len: %zu", tag, strlen(tag));
441                 g_strlcpy(*code, tag, LANGUAGE_CODE_SIZE);
442                 MMPLAYER_FREEIF(tag);
443         } else {
444                 LOGD("no language code info - und");
445                 g_strlcpy(*code, "und", LANGUAGE_CODE_SIZE);
446         }
447
448         if (tag_list)
449                 gst_tag_list_unref(tag_list);
450
451         MMPLAYER_FLEAVE();
452         return MM_ERROR_NONE;
453 }