player/track: check invalid index param
[platform/core/multimedia/libmm-player.git] / src / server / 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_attrs_private.h>
25 #include "mm_player_utils.h"
26 #include "mm_player_tracks.h"
27
28 /*---------------------------------------------------------------------------------------
29 |    LOCAL FUNCTION PROTOTYPES:                                                                               |
30 ---------------------------------------------------------------------------------------*/
31 static int __mmplayer_track_get_language(mm_player_t* player, MMPlayerTrackType type, gint stream_index, gchar **code);
32
33
34 /*=======================================================================================
35 |  FUNCTION DEFINITIONS                                                                                      |
36 =======================================================================================*/
37 int _mmplayer_get_track_count(MMHandleType hplayer,  MMPlayerTrackType type, int *count)
38 {
39         mm_player_t* player = (mm_player_t*) hplayer;
40         MMHandleType attrs = 0;
41         int ret = MM_ERROR_NONE;
42
43         MMPLAYER_FENTER();
44
45         /* check player handle */
46         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
47         MMPLAYER_RETURN_VAL_IF_FAIL(count, MM_ERROR_COMMON_INVALID_ARGUMENT);
48         MMPLAYER_RETURN_VAL_IF_FAIL((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
49                  ||(MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING),
50                 MM_ERROR_PLAYER_INVALID_STATE);
51
52         attrs = MMPLAYER_GET_ATTRS(player);
53         if ( !attrs )
54         {
55                 LOGE("cannot get content attribute");
56                 return MM_ERROR_PLAYER_INTERNAL;
57         }
58
59         switch (type)
60         {
61                 case MM_PLAYER_TRACK_TYPE_AUDIO:
62                         {
63                                 /*if function called for normal file [no multi audio] */
64                                 if(player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0)
65                                 {
66                                         *count = 0;
67                                         break;
68                                 }
69                                 ret = mm_attrs_get_int_by_name(attrs, "content_audio_track_num", count);
70                         }
71                         break;
72                 case MM_PLAYER_TRACK_TYPE_TEXT:
73                         ret = mm_attrs_get_int_by_name(attrs, "content_text_track_num", count);
74                         break;
75                 default:
76                         ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
77                         break;
78         }
79
80         LOGD ("%d track num : %d\n", type, *count);
81
82         MMPLAYER_FLEAVE();
83
84         return ret;
85 }
86
87 int _mmplayer_select_track(MMHandleType hplayer, MMPlayerTrackType type, int index)
88 {
89         int ret = MM_ERROR_NONE;
90         mm_player_t* player = (mm_player_t*) hplayer;
91         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
92         MMPLAYER_FENTER();
93
94
95         if (type == MM_PLAYER_TRACK_TYPE_TEXT && player->subtitle_language_list)
96         {
97                 GstElement *subparse = NULL;
98                 MMPlayerLangStruct *temp = NULL;
99                 unsigned long cur_time = 0;
100                 guint num_of_list = 0;
101
102                 if(!player->pipeline || !player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst)
103                 {
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                 {
111                         LOGE("req track index is wrong");
112                         ret = MM_ERROR_INVALID_ARGUMENT;
113                         goto EXIT;
114                 }
115
116                 _mmplayer_get_position (hplayer, MM_PLAYER_POS_FORMAT_TIME, &cur_time);
117                 temp = g_list_nth_data (player->subtitle_language_list, index);
118
119                 subparse = player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst;
120                 LOGD("setting to language %s", temp->language_code);
121                 g_object_set (G_OBJECT (subparse), "current-language", temp->language_key, NULL);
122
123                 _mmplayer_sync_subtitle_pipeline(player);
124
125         }
126         else
127         {
128                 ret = _mmplayer_change_track_language (hplayer, type, index);
129         }
130
131 EXIT:
132         MMPLAYER_FLEAVE();
133         return ret;
134 }
135
136 #ifdef _MULTI_TRACK
137 int _mmplayer_track_add_subtitle_language(MMHandleType hplayer, int index)
138 {
139         int ret = MM_ERROR_NONE;
140         mm_player_t* player = (mm_player_t*) hplayer;
141         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
142         MMPLAYER_FENTER();
143
144         if(!player->pipeline || !player->pipeline->mainbin[MMPLAYER_M_T_SUBMUX_EXTERNAL].gst)
145         {
146                 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
147                 goto EXIT;
148         }
149
150         if (player->subtitle_language_list)
151         {
152                 GstElement *subparse = NULL;
153                 MMPlayerLangStruct *temp = NULL;
154
155                 temp = g_list_nth_data (player->subtitle_language_list, index);
156                 temp->active = TRUE;
157
158                 subparse = player->pipeline->mainbin[MMPLAYER_M_T_SUBMUX_EXTERNAL].gst;
159                 LOGD("adding to language %s", temp->language_code);
160                 g_object_set (G_OBJECT (subparse), "current-language", temp->language_key, NULL);
161                 g_object_set (G_OBJECT (subparse), "lang-list", player->subtitle_language_list, NULL);
162
163                 _mmplayer_sync_subtitle_pipeline(player);
164         }
165         else
166         {
167                 LOGW("It is for just subtitle track");
168                 ret = MM_ERROR_PLAYER_NO_OP;
169                 goto EXIT;
170         }
171
172 EXIT:
173         MMPLAYER_FLEAVE();
174         return ret;
175 }
176
177 int _mmplayer_track_remove_subtitle_language(MMHandleType hplayer, int index)
178 {
179         int ret = MM_ERROR_NONE;
180         mm_player_t* player = (mm_player_t*) hplayer;
181         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
182         MMPLAYER_FENTER();
183
184         if(!player->pipeline || !player->pipeline->mainbin[MMPLAYER_M_T_SUBMUX_EXTERNAL].gst)
185         {
186                 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
187                 goto EXIT;
188         }
189
190         if (player->subtitle_language_list)
191         {
192                 GstElement *subparse = NULL;
193                 MMPlayerLangStruct *temp = NULL;
194
195                 temp = g_list_nth_data (player->subtitle_language_list, index);
196                 temp->active = FALSE;
197
198                 subparse = player->pipeline->mainbin[MMPLAYER_M_T_SUBMUX_EXTERNAL].gst;
199                 LOGD("removing to language %s", temp->language_code);
200                 g_object_set (G_OBJECT (subparse), "current-language", temp->language_key, NULL);
201                 g_object_set (G_OBJECT (subparse), "lang-list", player->subtitle_language_list, NULL);
202
203                 _mmplayer_sync_subtitle_pipeline(player);
204         }
205         else
206         {
207                 LOGW("It is for just subtitle track");
208                 ret = MM_ERROR_PLAYER_NO_OP;
209                 goto EXIT;
210         }
211
212 EXIT:
213         MMPLAYER_FLEAVE();
214         return ret;
215 }
216 #endif
217 int _mmplayer_get_current_track(MMHandleType hplayer, MMPlayerTrackType type, int *index)
218 {
219         int ret = MM_ERROR_NONE;
220         mm_player_t* player = (mm_player_t*) hplayer;
221         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
222         MMPLAYER_FENTER();
223
224         if (type >= MM_PLAYER_TRACK_TYPE_MAX)
225         {
226                 ret = MM_ERROR_INVALID_ARGUMENT;
227                 LOGD("Not a proper type [type:%d] \n", type);
228                 goto EXIT;
229         }
230
231         if (type == MM_PLAYER_TRACK_TYPE_TEXT && player->subtitle_language_list)
232         {
233                 GstElement *subparse = NULL;
234                 int total_track_count = 0;
235                 gchar* current_language = NULL;
236                 MMPlayerLangStruct *temp = NULL;
237                 MMHandleType attrs = 0;
238
239                 attrs = MMPLAYER_GET_ATTRS(player);
240                 if (!attrs)
241                 {
242                         LOGE("cannot get content attribute");
243                         ret = MM_ERROR_PLAYER_INTERNAL;
244                         goto EXIT;
245                 }
246
247                 mm_attrs_get_int_by_name(attrs, "content_text_track_num", &total_track_count);
248
249                 subparse = player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst;
250                 g_object_get (G_OBJECT (subparse), "current-language", &current_language, NULL);
251                 LOGD("current language is %s ",current_language);
252                 while (total_track_count)
253                 {
254                         temp = g_list_nth_data (player->subtitle_language_list, total_track_count - 1);
255                         if (temp)
256                         {
257                                 LOGD("find the list");
258                                 if (!strcmp(temp->language_key, current_language))
259                                 {
260                                         *index = total_track_count - 1;
261                                         LOGD("current lang index  is %d", *index);
262                                         break;
263                                 }
264                         }
265                         total_track_count--;
266                 }
267         }
268         else
269         {
270                 if (player->selector[type].total_track_num <= 0)
271                 {
272                         ret = MM_ERROR_PLAYER_NO_OP;
273                         LOGD("there is no track information [type:%d] \n", type);
274                         goto EXIT;
275                 }
276
277                 *index = player->selector[type].active_pad_index;
278         }
279
280 EXIT:
281         MMPLAYER_FLEAVE();
282         return ret;
283 }
284
285 int _mmplayer_get_track_language_code(MMHandleType hplayer, MMPlayerTrackType type, int index, char **code)
286 {
287         int ret = MM_ERROR_NONE;
288
289         MMPLAYER_RETURN_VAL_IF_FAIL(hplayer, MM_ERROR_PLAYER_NOT_INITIALIZED);
290         mm_player_t* player = (mm_player_t*) hplayer;
291         MMPLAYER_FENTER();
292
293         if (type == MM_PLAYER_TRACK_TYPE_TEXT && player->subtitle_language_list)
294         {
295                 int language_code_size = 3;/*Size of ISO-639-1*/
296                 MMPlayerLangStruct *language_list = NULL;
297
298                 *code = (char*)malloc(language_code_size * sizeof(char));
299                 if (*code == NULL)
300                 {
301                         ret = MM_ERROR_PLAYER_INTERNAL;
302                         goto EXIT;
303                 }
304                 memset(*code, 0, language_code_size * sizeof(char));
305
306                 language_list = g_list_nth_data (player->subtitle_language_list, index);
307                 if (language_list == NULL)
308                 {
309                         LOGD ("%d is not a proper index \n", index);
310                         goto EXIT;
311                 }
312                 strncpy(*code, language_list->language_code, language_code_size);
313         }
314         else
315         {
316                 if (player->selector[type].total_track_num <= 0)
317                 {
318                         ret = MM_ERROR_PLAYER_NO_OP;
319                         LOGD("language list is not available. [type:%d] \n", type);
320                         goto EXIT;
321                 }
322
323                 if(index < 0 || index >= player->selector[type].total_track_num)
324                 {
325                         ret = MM_ERROR_INVALID_ARGUMENT;
326                         LOGD("Not a proper index : %d \n", index);
327                         goto EXIT;
328                 }
329
330                 ret = __mmplayer_track_get_language(player, type, index, code);
331         }
332
333 EXIT:
334         MMPLAYER_FLEAVE();
335         return ret;
336 }
337
338 void _mmplayer_track_initialize(mm_player_t* player)
339 {
340         MMPlayerTrackType type = MM_PLAYER_TRACK_TYPE_AUDIO;
341
342         MMPLAYER_FENTER();
343
344         for (;type<MM_PLAYER_TRACK_TYPE_MAX ; type++)
345         {
346                 /* active_pad_index is initialized when player is created or destroyed.
347                    and the value can be set by calling _mmplayer_change_track_language()
348                    before pipeline is created.*/
349                 player->selector[type].total_track_num = 0;
350                 player->selector[type].channels = g_ptr_array_new();
351         }
352 }
353
354 void _mmplayer_track_destroy(mm_player_t* player)
355 {
356         MMPlayerTrackType type = MM_PLAYER_TRACK_TYPE_AUDIO;
357         MMHandleType attrs = 0;
358         MMPLAYER_FENTER();
359
360         attrs = MMPLAYER_GET_ATTRS(player);
361         if (attrs)
362         {
363                 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 0);
364                 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 0);
365                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 0);
366
367                 if (mmf_attrs_commit (attrs))
368                         LOGE("failed to commit.\n");
369         }
370
371         for (;type<MM_PLAYER_TRACK_TYPE_MAX ; type++)
372         {
373                 player->selector[type].active_pad_index = 0;
374                 player->selector[type].total_track_num = 0;
375
376                 if (player->selector[type].channels)
377                         g_ptr_array_free (player->selector[type].channels, TRUE);
378                 player->selector[type].channels = NULL;
379         }
380 }
381
382 void _mmplayer_track_update_info(mm_player_t* player, MMPlayerTrackType type, GstPad *sinkpad)
383 {
384         MMPLAYER_FENTER();
385
386         player->selector[type].total_track_num++;
387         g_ptr_array_add (player->selector[type].channels, sinkpad);
388
389         LOGD ("type:%d, total track:%d\n", type, player->selector[type].total_track_num);
390 }
391
392 static int __mmplayer_track_get_language(mm_player_t* player, MMPlayerTrackType type, gint stream_index, gchar **code)
393 {
394         int ret = MM_ERROR_NONE;
395
396         GstTagList *tag_list = NULL;
397         gchar* tag = NULL;
398         GstPad *sinkpad = NULL;
399         gint language_code_size = 3; /*Size of ISO-639-1*/
400
401         MMPLAYER_FENTER();
402
403         *code = (char *)malloc(language_code_size*sizeof(char));
404         if(*code == NULL)
405         {
406                 ret = MM_ERROR_PLAYER_INTERNAL;
407                 goto EXIT;
408         }
409         memset(*code,0,language_code_size*sizeof(char));
410
411         LOGD ("total track num : %d , req idx : %d\n", player->selector[type].total_track_num, stream_index);
412
413         if (stream_index < player->selector[type].total_track_num)
414         {
415                 sinkpad = g_ptr_array_index (player->selector[type].channels, stream_index);
416         }
417         else
418         {
419                 ret = MM_ERROR_INVALID_ARGUMENT;
420                 goto EXIT;
421         }
422
423         g_object_get (sinkpad, "tags", &tag_list, NULL);
424         //SECURE_LOGD ("[%s]\n", gst_tag_list_to_string(tag_list));
425
426         gst_tag_list_get_string (tag_list, GST_TAG_LANGUAGE_CODE, &tag);
427
428         if(!tag)
429         {
430                 LOGD("there is no lang info - und\n");
431                 strncpy(*code, "und", language_code_size);
432         }
433         else
434         {
435                 LOGD("language information[%d] code: %s, len: %d \n", type, tag, strlen(tag));
436                 strncpy(*code, tag, /*strlen(tag)*/language_code_size);
437                 g_free (tag);
438         }
439
440         if (tag_list)
441                 gst_tag_list_free (tag_list);
442
443 EXIT:
444         MMPLAYER_FLEAVE();
445         return ret;
446 }
447 #ifdef _MULTI_TRACK
448 int _mmplayer_track_foreach_selected_subtitle_language(MMHandleType hplayer,_mmplayer_track_selected_subtitle_language_cb foreach_cb, void *user_data)
449 {
450         int ret = MM_ERROR_NONE;
451         mm_player_t* player = (mm_player_t*) hplayer;
452         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
453         MMPLAYER_FENTER();
454
455         int index = -1;
456
457         if (player->subtitle_language_list)
458         {
459                 int total_track_count = 0;
460                 MMPlayerLangStruct *temp = NULL;
461                 MMHandleType attrs = 0;
462
463                 attrs = MMPLAYER_GET_ATTRS(player);
464                 if (!attrs)
465                 {
466                         LOGE("cannot get content attribute");
467                         ret = MM_ERROR_PLAYER_INTERNAL;
468                         goto EXIT;
469                 }
470                 mm_attrs_get_int_by_name(attrs, "content_text_track_num", &total_track_count);
471
472                 if(!total_track_count)
473                 {
474                         LOGW("There are no subtitle track selected.");
475                         ret = MM_ERROR_PLAYER_NO_OP;
476                         goto EXIT;
477                 }
478
479                 while (total_track_count)
480                 {
481                         temp = g_list_nth_data (player->subtitle_language_list, total_track_count - 1);
482                         if (temp)
483                         {
484                                 LOGD("find the list");
485                                 if (temp->active)
486                                 {
487                                         index = total_track_count - 1;
488                                         LOGD("active subtitle track index is %d", index);
489                                         if (!foreach_cb(index, user_data))
490                                         {
491                                                 ret = MM_ERROR_PLAYER_INTERNAL;
492                                                 goto CALLBACK_ERROR;
493                                         }
494                                 }
495                         }
496                         total_track_count--;
497                 }
498
499                 LOGD("we will return -1 for notifying the end to user");
500
501                 /* After returning all selected indexs, we will return -1 for notifying the end to user */
502                 if (!foreach_cb(-1, user_data))
503                 {
504                         ret = MM_ERROR_PLAYER_INTERNAL;
505                         goto CALLBACK_ERROR;
506                 }
507         }
508
509 CALLBACK_ERROR:
510         LOGE("foreach callback returned error");
511
512 EXIT:
513         MMPLAYER_FLEAVE();
514         return ret;
515
516
517 }
518 #endif