2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * @file mediademuxer_port_gst.c
19 * @brief Handling for GStreamer Port, defined function and there implementation
24 #include <mediademuxer_error.h>
25 #include <mediademuxer_private.h>
26 #include <mediademuxer_port.h>
27 #include <mediademuxer_port_gst.h>
28 #include <media_packet_internal.h>
30 static int gst_demuxer_init(MMHandleType *pHandle);
31 static int gst_demuxer_prepare(MMHandleType pHandle, char *uri);
32 static int gst_demuxer_get_data_count(MMHandleType pHandle, int *count);
33 static int gst_demuxer_set_track(MMHandleType pHandle, int track);
34 static int gst_demuxer_start(MMHandleType pHandle);
35 static int gst_demuxer_read_sample(MMHandleType pHandle,
36 media_packet_h *outbuf, int track_indx);
37 static int gst_demuxer_get_track_info(MMHandleType pHandle,
38 media_format_h *format, int index);
39 static int gst_demuxer_seek(MMHandleType pHandle, gint64 pos1);
40 static int gst_demuxer_unset_track(MMHandleType pHandle, int track);
41 static int gst_demuxer_stop(MMHandleType pHandle);
42 static int gst_demuxer_unprepare(MMHandleType pHandle);
43 static int gst_demuxer_destroy(MMHandleType pHandle);
44 static int gst_set_error_cb(MMHandleType pHandle,
45 gst_error_cb callback, void* user_data);
47 /* Media Demuxer API common */
48 static media_port_demuxer_ops def_demux_ops = {
50 .init = gst_demuxer_init,
51 .prepare = gst_demuxer_prepare,
52 .get_track_count = gst_demuxer_get_data_count,
53 .set_track = gst_demuxer_set_track,
54 .start = gst_demuxer_start,
55 .get_track_info = gst_demuxer_get_track_info,
56 .read_sample = gst_demuxer_read_sample,
57 .seek = gst_demuxer_seek,
58 .unset_track = gst_demuxer_unset_track,
59 .stop = gst_demuxer_stop,
60 .unprepare = gst_demuxer_unprepare,
61 .destroy = gst_demuxer_destroy,
62 .set_error_cb = gst_set_error_cb,
65 int gst_port_register(media_port_demuxer_ops *pOps)
67 MEDIADEMUXER_FENTER();
68 int ret = MD_ERROR_NONE;
69 MEDIADEMUXER_CHECK_NULL(pOps);
70 def_demux_ops.n_size = sizeof(def_demux_ops);
72 memcpy((char *)pOps + sizeof(pOps->n_size),
73 (char *)&def_demux_ops + sizeof(def_demux_ops.n_size),
74 pOps->n_size - sizeof(pOps->n_size));
76 MEDIADEMUXER_FLEAVE();
80 static int gst_demuxer_init(MMHandleType *pHandle)
82 MEDIADEMUXER_FENTER();
83 int ret = MD_ERROR_NONE;
84 mdgst_handle_t *new_mediademuxer = NULL;
85 new_mediademuxer = (mdgst_handle_t *) g_malloc(sizeof(mdgst_handle_t));
86 MD_I("gst_demuxer_init allocating new_mediademuxer:%p\n", new_mediademuxer);
87 if (!new_mediademuxer) {
88 MD_E("Cannot allocate memory for demuxer\n");
92 memset(new_mediademuxer, 0, sizeof(mdgst_handle_t));
93 new_mediademuxer->is_prepared = false;
94 (new_mediademuxer->info).num_audio_track = 0;
95 (new_mediademuxer->info).num_video_track = 0;
96 (new_mediademuxer->info).num_subtitle_track = 0;
97 (new_mediademuxer->info).num_other_track = 0;
98 (new_mediademuxer->info).head = NULL;
99 *pHandle = (MMHandleType) new_mediademuxer;
100 new_mediademuxer->total_tracks = 0;
101 MEDIADEMUXER_FLEAVE();
104 MEDIADEMUXER_FLEAVE();
108 gboolean __gst_bus_call(GstBus *bus, GstMessage *msg, gpointer data)
110 MEDIADEMUXER_FENTER();
111 int ret = MD_ERROR_NONE;
112 switch (GST_MESSAGE_TYPE(msg)) {
113 case GST_MESSAGE_EOS: {
117 case GST_MESSAGE_ERROR: {
118 GError *error = NULL;
119 gst_message_parse_error(msg, &error, NULL);
121 MD_I("GST error message parsing failed");
124 MD_E("Error: %s\n", error->message);
131 MEDIADEMUXER_FLEAVE();
135 static void __gst_no_more_pad(GstElement *element, gpointer data)
137 MEDIADEMUXER_FENTER();
138 mdgst_handle_t *gst_handle = (mdgst_handle_t *) data;
140 track_info *head_track = &(gst_handle->info);
141 track *head = head_track->head;
142 gst_handle->selected_tracks =
143 (bool *) g_malloc(sizeof(bool) * (gst_handle->total_tracks));
144 MD_I("Allocating %p to core->selected_tracks \n", gst_handle->selected_tracks);
145 if (!gst_handle->selected_tracks) {
146 MD_E("[%s]Memory allocation failed\n", __FUNCTION__);
149 for (loop_track = 0; loop_track < gst_handle->total_tracks;
151 gst_handle->selected_tracks[loop_track] = false;
153 MD_I("Number of video tracks are %d\n", head_track->num_video_track);
154 MD_I("Number of audio tracks are %d\n", head_track->num_audio_track);
155 MD_I("Number of subtitle tracks are %d\n",
156 head_track->num_subtitle_track);
157 MD_I("Number of other tracks are %d\n", head_track->num_other_track);
159 MD_I("track caps[%s]\n", head->name);
162 gst_handle->is_prepared = true;
163 MD_I("core->is_prepared: ");
164 gst_handle->is_prepared ? MD_I("true\n") : MD_I("false\n");
165 MEDIADEMUXER_FLEAVE();
168 void __gst_free_stuct(track **head)
170 MEDIADEMUXER_FENTER();
176 MD_I("deallocate GST_PAD %p\n", temp->pad);
177 gst_object_unref(temp->pad);
180 MD_I("deallocate GST_PAD name %p\n", temp->name);
183 if (temp->caps_string) {
184 MD_I("deallocate GST_PAD caps_string %p\n",
186 g_free(temp->caps_string);
189 MD_I("deallocate GST_PAD caps_ %p\n", temp->caps);
190 gst_caps_unref(temp->caps);
194 track *next = temp->next;
195 MD_I("deallocate memory %p\n", temp);
199 MD_I("deallocate memory %p\n", temp);
205 MEDIADEMUXER_FLEAVE();
208 int __gst_add_track_info(GstPad *pad, gchar *name, track **head,
209 GstElement *pipeline)
211 MEDIADEMUXER_FENTER();
212 GstPad *apppad = NULL;
213 GstCaps *outcaps = NULL;
214 GstPad *parse_sink_pad = NULL;
215 GstElement *parse_element = NULL;
218 temp = (track *)(g_malloc(sizeof(track)));
220 MD_E("Not able to allocate memory");
223 MD_I("allocate memory %p", temp);
226 temp->caps = gst_pad_get_current_caps(pad);
228 temp->caps_string = gst_caps_to_string(temp->caps);
230 temp->appsink = gst_element_factory_make("appsink", NULL);
231 if (!temp->appsink) {
232 MD_E("factory not able to make appsink");
233 __gst_free_stuct(head);
236 gst_bin_add_many(GST_BIN(pipeline), temp->appsink, NULL);
237 gst_app_sink_set_max_buffers((GstAppSink *) temp->appsink, MAX_APP_BUFFER);
238 MEDIADEMUXER_SET_STATE(temp->appsink, GST_STATE_PAUSED, ERROR);
239 apppad = gst_element_get_static_pad(temp->appsink, "sink");
241 MD_E("sink pad of appsink not avaible");
242 __gst_free_stuct(head);
245 /* Check for type video and it should be h264 */
246 if (strstr(name, "video") && strstr(temp->caps_string, "h264")) {
247 parse_element = gst_element_factory_make("h264parse", NULL);
248 if (!parse_element) {
249 MD_E("factory not able to make h264parse");
250 __gst_free_stuct(head);
251 gst_object_unref(apppad);
254 gst_bin_add_many(GST_BIN(pipeline), parse_element, NULL);
255 MEDIADEMUXER_SET_STATE(parse_element, GST_STATE_PAUSED, ERROR);
257 parse_sink_pad = gst_element_get_static_pad(parse_element, "sink");
258 if (!parse_sink_pad) {
259 MD_E("sink pad of h264parse not available");
260 __gst_free_stuct(head);
261 gst_object_unref(apppad);
265 /* Link demuxer pad with sink pad of parse element */
266 MEDIADEMUXER_LINK_PAD(pad, parse_sink_pad, ERROR);
268 outcaps = gst_caps_new_simple("video/x-h264", "stream-format", G_TYPE_STRING, "byte-stream", NULL);
269 gst_element_link_filtered(parse_element, temp->appsink, outcaps);
271 MEDIADEMUXER_LINK_PAD(pad, apppad, ERROR);
273 /* gst_pad_link(pad, fpad) */
282 gst_object_unref(apppad);
283 MEDIADEMUXER_FLEAVE();
284 return MD_ERROR_NONE;
287 gst_object_unref(apppad);
288 __gst_free_stuct(head);
289 MEDIADEMUXER_FLEAVE();
293 static void __gst_on_pad_added(GstElement *element, GstPad *pad, gpointer data)
295 MEDIADEMUXER_FENTER();
296 MD_I("Dynamic pad created, linking demuxer/decoder\n");
298 mdgst_handle_t *gst_handle = (mdgst_handle_t *) data;
299 track_info *head_track = &(gst_handle->info);
300 gchar *name = gst_pad_get_name(pad);
301 gst_handle->total_tracks++;
302 if (__gst_add_track_info(pad, name, &(head_track->head), gst_handle->pipeline)
304 MD_E("unable to added track info");
305 head_track->num_audio_track = 0;
306 head_track->num_video_track = 0;
307 head_track->num_subtitle_track = 0;
308 head_track->num_other_track = 0;
309 __gst_free_stuct(&(head_track->head));
312 tmp = head_track->head;
315 if (tmp->caps_string[0] == 'v') {
316 MD_I("found Video Pad\n");
317 (head_track->num_video_track)++;
318 } else if (tmp->caps_string[0] == 'a') {
319 MD_I("found Audio Pad\n");
320 (head_track->num_audio_track)++;
321 } else if (tmp->caps_string[0] == 's') {
322 MD_I("found subtitle(or Text) Pad\n");
323 (head_track->num_subtitle_track)++;
325 MD_W("found Pad %s\n", name);
326 (head_track->num_other_track)++;
328 MEDIADEMUXER_FLEAVE();
331 static int __gst_create_audio_only_pipeline(gpointer data, GstCaps *caps)
333 MEDIADEMUXER_FENTER();
334 mdgst_handle_t *gst_handle = (mdgst_handle_t *) data;
336 GstPad *aud_pad = NULL;
337 GstPad *queue_srcpad = NULL;
338 GstPad *queue_sinkpad = NULL;
339 GstPad *aud_srcpad = NULL;
340 GstPad *fake_pad = NULL;
341 GstElement *id3tag = NULL;
342 GstElement *adif_queue = NULL;
345 track_info *head_track = &(gst_handle->info);
347 gst_handle->is_valid_container = true;
348 type = gst_caps_to_string(caps);
349 if (strstr(type, "adts") || strstr(type, "adif")) {
350 gst_handle->demux = gst_element_factory_make("aacparse", NULL);
351 } else if (strstr(type, "audio/mpeg")) {
352 gst_handle->demux = gst_element_factory_make("mpegaudioparse", NULL);
353 } else if (strstr(type, "application/x-id3")) {
354 id3tag = gst_element_factory_make("id3demux", NULL);
355 gst_handle->demux = gst_element_factory_make("mpegaudioparse", NULL);
356 } else if (strstr(type, "audio/x-amr-nb-sh")
357 || strstr(type, "audio/x-amr-wb-sh")) {
358 gst_handle->demux = gst_element_factory_make("amrparse", NULL);
359 } else if (strstr(type, "audio/x-wav")) {
360 gst_handle->demux = gst_element_factory_make("wavparse", NULL);
361 } else if (strstr(type, "audio/x-flac")) {
362 gst_handle->demux = gst_element_factory_make("flacparse", NULL);
365 if (!gst_handle->demux) {
366 gst_handle->is_valid_container = false;
367 MD_E("factory not able to create audio parse element\n");
370 gst_bin_add_many(GST_BIN(gst_handle->pipeline),
371 gst_handle->demux, id3tag, NULL);
372 pad = gst_element_get_static_pad(gst_handle->typefind, "src");
374 MD_E("fail to get typefind src pad.\n");
378 aud_pad = gst_element_get_static_pad(gst_handle->demux, "sink");
380 aud_pad = gst_element_get_static_pad(id3tag, "sink");
382 MD_E("fail to get audio parse sink pad.\n");
385 fake_pad = gst_element_get_static_pad(gst_handle->fakesink, "sink");
387 MD_E("fail to get fakesink sink pad.\n");
390 gst_pad_unlink(pad, fake_pad);
391 if (strstr(type, "adif")) {
392 adif_queue = gst_element_factory_make("queue", NULL);
394 MD_E("factory not able to make queue in case of adif aac\n");
397 /* Add this queue to the pipeline */
398 gst_bin_add_many(GST_BIN(gst_handle->pipeline), adif_queue, NULL);
399 queue_srcpad = gst_element_get_static_pad(adif_queue, "src");
401 MD_E("fail to get queue src pad for adif aac.\n");
404 queue_sinkpad = gst_element_get_static_pad(adif_queue, "sink");
405 if (!queue_sinkpad) {
406 MD_E("fail to get queue sink pad for adif aac.\n");
409 /* link typefind with queue */
410 MEDIADEMUXER_LINK_PAD(pad, queue_sinkpad, ERROR);
411 /* link queue with aacparse */
412 MEDIADEMUXER_LINK_PAD(queue_srcpad, aud_pad, ERROR);
414 MEDIADEMUXER_LINK_PAD(pad, aud_pad, ERROR);
418 MEDIADEMUXER_SET_STATE(gst_handle->demux,
419 GST_STATE_PAUSED, ERROR);
421 MEDIADEMUXER_SET_STATE(id3tag, GST_STATE_PAUSED, ERROR);
422 MEDIADEMUXER_SET_STATE(gst_handle->demux,
423 GST_STATE_PAUSED, ERROR);
424 gst_element_link(id3tag, gst_handle->demux);
428 MEDIADEMUXER_SET_STATE(adif_queue, GST_STATE_PAUSED, ERROR);
431 gst_object_unref(pad);
433 gst_object_unref(aud_pad);
435 gst_object_unref(fake_pad);
437 gst_object_unref(queue_sinkpad);
439 gst_object_unref(queue_srcpad);
443 /* calling "on_pad_added" function to set the caps */
444 aud_srcpad = gst_element_get_static_pad(gst_handle->demux, "src");
446 MD_E("fail to get audioparse source pad.\n");
449 gst_handle->total_tracks++;
450 name = gst_pad_get_name(aud_srcpad);
451 if (__gst_add_track_info(aud_srcpad, name, &(head_track->head), gst_handle->pipeline)
453 MD_E("unable to added track info");
454 head_track->num_audio_track = 0;
455 head_track->num_video_track = 0;
456 head_track->num_subtitle_track = 0;
457 head_track->num_other_track = 0;
458 __gst_free_stuct(&(head_track->head));
462 gst_object_unref(aud_srcpad);
464 trck = head_track->head;
465 while (trck != NULL && aud_srcpad != trck->pad)
469 trck->caps_string = gst_caps_to_string(trck->caps);
470 MD_I("caps set to %s\n", trck->caps_string);
471 g_strlcpy(name, "audio", strlen(name));
474 (head_track->num_audio_track)++;
475 __gst_no_more_pad(gst_handle->demux, data);
476 MEDIADEMUXER_FLEAVE();
477 return MD_ERROR_NONE;
479 gst_handle->is_valid_container = false;
480 if (gst_handle->demux)
481 gst_object_unref(gst_handle->demux);
483 gst_object_unref(pad);
485 gst_object_unref(aud_pad);
487 gst_object_unref(fake_pad);
489 gst_object_unref(aud_srcpad);
491 gst_object_unref(queue_sinkpad);
493 gst_object_unref(queue_srcpad);
495 MEDIADEMUXER_FLEAVE();
499 static void __gst_cb_typefind(GstElement *tf, guint probability,
500 GstCaps *caps, gpointer data)
502 MEDIADEMUXER_FENTER();
503 mdgst_handle_t *gst_handle = (mdgst_handle_t *) data;
505 GstPad *demuxer_pad = NULL;
506 GstPad *fake_pad = NULL;
508 type = gst_caps_to_string(caps);
510 MD_I("Media type %s found, probability %d%%\n", type, probability);
511 if (strstr(type, "quicktime") || (strstr(type, "audio/x-m4a")) || strstr(type, "x-3gp")
512 || strstr(type, "ogg")) {
513 gst_handle->is_valid_container = true;
514 if (strstr(type, "ogg"))
515 gst_handle->demux = gst_element_factory_make("oggdemux", NULL);
517 gst_handle->demux = gst_element_factory_make("qtdemux", NULL);
519 if (!gst_handle->demux) {
520 gst_handle->is_valid_container = false;
521 MD_E("factory not able to create qtdemux\n");
524 g_signal_connect(gst_handle->demux, "pad-added",
525 G_CALLBACK(__gst_on_pad_added), gst_handle);
526 g_signal_connect(gst_handle->demux, "no-more-pads",
527 G_CALLBACK(__gst_no_more_pad), gst_handle);
528 gst_bin_add_many(GST_BIN(gst_handle->pipeline),
529 gst_handle->demux, NULL);
530 pad = gst_element_get_static_pad(gst_handle->typefind, "src");
532 MD_E("fail to get typefind src pad.\n");
535 demuxer_pad = gst_element_get_static_pad(gst_handle->demux, "sink");
537 MD_E("fail to get qtdemuc sink pad.\n");
540 fake_pad = gst_element_get_static_pad(gst_handle->fakesink, "sink");
542 MD_E("fail to get fakesink sink pad.\n");
545 gst_pad_unlink(pad, fake_pad);
546 MEDIADEMUXER_LINK_PAD(pad, demuxer_pad, ERROR);
547 MEDIADEMUXER_SET_STATE(gst_handle->demux,
548 GST_STATE_PAUSED, ERROR);
550 gst_object_unref(pad);
552 gst_object_unref(demuxer_pad);
554 gst_object_unref(fake_pad);
556 } else if ((strstr(type, "adts"))
557 || (strstr(type, "audio/mpeg"))
558 || (strstr(type, "audio/x-wav"))
559 || (strstr(type, "audio/x-flac"))
560 || (strstr(type, "application/x-id3"))
561 || (strstr(type, "audio/x-amr-nb-sh"))
562 || (strstr(type, "audio/x-amr-wb-sh"))) {
563 MD_I("Audio only format is found\n");
564 __gst_create_audio_only_pipeline(data, caps);
566 gst_handle->is_valid_container = false;
567 MD_E("Not supported container %s\n", type);
571 MEDIADEMUXER_FLEAVE();
574 gst_handle->is_valid_container = false;
575 if (gst_handle->demux)
576 gst_object_unref(gst_handle->demux);
580 gst_object_unref(pad);
582 gst_object_unref(demuxer_pad);
584 gst_object_unref(fake_pad);
585 MEDIADEMUXER_FLEAVE();
589 static int _gst_create_pipeline(mdgst_handle_t *gst_handle, char *uri)
591 MEDIADEMUXER_FENTER();
592 int ret = MD_ERROR_NONE;
595 /* Initialize GStreamer */
596 /* Note: Replace the arguments of gst_init to pass the command line args to GStreamer. */
597 gst_init(NULL, NULL);
599 /* Create the empty pipeline */
600 gst_handle->pipeline = gst_pipeline_new("Demuxer Gst pipeline");
601 if (!gst_handle->pipeline) {
602 MD_E("pipeline create fail");
607 /* Create the elements */
608 gst_handle->filesrc = gst_element_factory_make("filesrc", NULL);
609 if (!gst_handle->filesrc) {
610 MD_E("filesrc creation failed");
615 /* Modify the source's properties */
616 g_object_set(G_OBJECT(gst_handle->filesrc), "location", uri + 7, NULL);
617 gst_handle->typefind = gst_element_factory_make("typefind", NULL);
618 if (!gst_handle->typefind) {
619 MD_E("typefind creation failed");
623 g_signal_connect(gst_handle->typefind, "have-type",
624 G_CALLBACK(__gst_cb_typefind), gst_handle);
625 gst_handle->fakesink = gst_element_factory_make("fakesink", NULL);
626 if (!gst_handle->fakesink) {
627 MD_E("fakesink creation failed");
632 /* Build the pipeline */
633 gst_bin_add_many(GST_BIN(gst_handle->pipeline),
635 gst_handle->typefind,
636 gst_handle->fakesink,
638 gst_element_link_many(gst_handle->filesrc,
639 gst_handle->typefind,
640 gst_handle->fakesink,
643 /* connect signals, bus watcher */
644 bus = gst_pipeline_get_bus(GST_PIPELINE(gst_handle->pipeline));
645 gst_handle->bus_whatch_id = gst_bus_add_watch(bus, __gst_bus_call, gst_handle);
646 gst_object_unref(bus);
648 /* set pipeline state to PAUSED */
649 MEDIADEMUXER_SET_STATE(gst_handle->pipeline, GST_STATE_PAUSED, ERROR);
652 while (gst_handle->is_prepared != true) {
654 usleep(POLLING_INTERVAL);
655 MD_I("Inside while loop\n");
656 if (count > POLLING_INTERVAL) {
657 MD_E("Error occure\n");
662 MEDIADEMUXER_FLEAVE();
665 MEDIADEMUXER_FLEAVE();
669 static int gst_demuxer_prepare(MMHandleType pHandle, char *uri)
671 MEDIADEMUXER_FENTER();
672 int ret = MD_ERROR_NONE;
673 MEDIADEMUXER_CHECK_NULL(pHandle);
674 mdgst_handle_t *new_mediademuxer = (mdgst_handle_t *) pHandle;
676 MD_I("gst_demuxer_prepare Creating pipeline %p", new_mediademuxer);
677 ret = _gst_create_pipeline(new_mediademuxer, uri);
678 if (ret != MD_ERROR_NONE) {
679 MD_E("_gst_create_pipeline() failed. returned %d\n", ret);
682 MEDIADEMUXER_FLEAVE();
685 MEDIADEMUXER_FLEAVE();
689 static int gst_demuxer_get_data_count(MMHandleType pHandle, int *count)
691 MEDIADEMUXER_FENTER();
692 int ret = MD_ERROR_NONE;
693 MEDIADEMUXER_CHECK_NULL(pHandle);
694 mdgst_handle_t *new_mediademuxer = (mdgst_handle_t *) pHandle;
696 *count = (new_mediademuxer->info).num_video_track +
697 (new_mediademuxer->info).num_audio_track +
698 (new_mediademuxer->info).num_subtitle_track +
699 (new_mediademuxer->info).num_other_track;
700 MEDIADEMUXER_FLEAVE();
704 int _gst_set_appsink(track *temp, int index, int loop)
706 MEDIADEMUXER_FENTER();
707 int ret = MD_ERROR_NONE;
710 while (count != index) {
714 gst_app_sink_set_max_buffers((GstAppSink *)(temp->appsink), (guint) MAX_APP_BUFFER);
715 gst_app_sink_set_drop((GstAppSink *)(temp->appsink), false);
716 MEDIADEMUXER_FLEAVE();
720 static int gst_demuxer_set_track(MMHandleType pHandle, int track)
722 MEDIADEMUXER_FENTER();
723 int ret = MD_ERROR_NONE;
724 MEDIADEMUXER_CHECK_NULL(pHandle);
725 mdgst_handle_t *new_mediademuxer = (mdgst_handle_t *) pHandle;
727 MD_I("total_tracks (%d) :: selected track (%d)", new_mediademuxer->total_tracks, track);
728 if (track >= new_mediademuxer->total_tracks || track < 0) {
729 MD_E("total_tracks is less then selected track, So not support this track");
730 ret = MD_ERROR_INVALID_ARGUMENT;
733 new_mediademuxer->selected_tracks[track] = true;
734 _gst_set_appsink((((mdgst_handle_t *) pHandle)->info).head, track,
735 new_mediademuxer->total_tracks);
736 MEDIADEMUXER_FLEAVE();
737 return MD_ERROR_NONE;
739 MEDIADEMUXER_FLEAVE();
743 static int gst_demuxer_start(MMHandleType pHandle)
745 MEDIADEMUXER_FENTER();
746 int ret = MD_ERROR_NONE;
747 MEDIADEMUXER_CHECK_NULL(pHandle);
748 mdgst_handle_t *gst_handle = (mdgst_handle_t *) pHandle;
751 for (indx = 0; indx < gst_handle->total_tracks; indx++) {
752 MD_I("track indx[%d] is marked as [%d]. (0- not selected, 1= selected)\n",
753 indx, gst_handle->selected_tracks[indx]);
755 if (gst_handle->selected_tracks[indx] == false)
756 _gst_demuxer_unset(pHandle, indx);
760 track_info *head_track = &(gst_handle->info);
761 MD_I("Total Audio track=%d, Video track=%d, text track=%d\n",
762 head_track->num_audio_track, head_track->num_video_track,
763 head_track->num_subtitle_track);
765 track *temp = head_track->head;
768 MD_I("Got one element %p\n", temp->appsink);
769 if (gst_element_set_state(temp->appsink, GST_STATE_PLAYING) ==
770 GST_STATE_CHANGE_FAILURE) {
771 MD_E("Failed to set into PLAYING state");
772 ret = MD_INTERNAL_ERROR;
775 MD_I("set the state to playing\n");
778 track *next = temp->next;
785 MD_I("gst_demuxer_start pipeine %p", gst_handle);
786 MEDIADEMUXER_FLEAVE();
789 MEDIADEMUXER_FLEAVE();
793 int _set_mime_video(media_format_h format, track *head)
795 MEDIADEMUXER_FENTER();
796 int ret = MD_ERROR_NONE;
797 GstStructure *struc = NULL;
800 struc = gst_caps_get_structure(head->caps, 0);
802 MD_E("cannot get structure from caps.\n");
805 if (gst_structure_has_name(struc, "video/x-h264")) {
806 const gchar *version = gst_structure_get_string(struc, "stream-format");
807 if (strncmp(version, "avc", 3) == 0) {
808 gst_structure_get_int(struc, "width", &src_width);
809 gst_structure_get_int(struc, "height", &src_height);
810 if (media_format_set_video_mime(format, MEDIA_FORMAT_H264_SP))
812 if (media_format_set_video_width(format, src_width))
814 if (media_format_set_video_height(format, src_height))
817 } else if (gst_structure_has_name(struc, "video/x-h263")) {
818 gst_structure_get_int(struc, "width", &src_width);
819 gst_structure_get_int(struc, "height", &src_height);
820 if (media_format_set_video_mime(format, MEDIA_FORMAT_H263))
822 if (media_format_set_video_width(format, src_width))
824 if (media_format_set_video_height(format, src_height))
827 MD_I("Video mime not supported so far\n");
830 MEDIADEMUXER_FLEAVE();
833 MEDIADEMUXER_FLEAVE();
837 int _set_mime_audio(media_format_h format, track *head)
839 MEDIADEMUXER_FENTER();
840 int ret = MD_ERROR_NONE;
841 GstStructure *struc = NULL;
846 const gchar *stream_format;
848 struc = gst_caps_get_structure(head->caps, 0);
850 MD_E("cannot get structure from caps.\n");
854 if (gst_structure_has_name(struc, "application/x-id3"))
856 if (gst_structure_has_name(struc, "audio/mpeg") || id3_flag) {
859 gst_structure_get_int(struc, "mpegversion", &mpegversion);
860 if (mpegversion == 4 || mpegversion == 2) {
861 gst_structure_get_int(struc, "channels", &channels);
862 gst_structure_get_int(struc, "rate", &rate);
863 gst_structure_get_int(struc, "bit", &bit);
864 stream_format = gst_structure_get_string(struc, "stream-format");
865 if (media_format_set_audio_mime(format, MEDIA_FORMAT_AAC_LC))
868 channels = 2; /* default */
869 if (media_format_set_audio_channel(format, channels))
872 rate = 44100; /* default */
873 if (media_format_set_audio_samplerate(format, rate))
876 bit = 16; /* default */
877 if (media_format_set_audio_bit(format, bit))
879 if (strncmp(stream_format, "adts", 4) == 0)
880 media_format_set_audio_aac_type(format, 1);
882 media_format_set_audio_aac_type(format, 0);
884 if (mpegversion == 1 || id3_flag) {
885 gst_structure_get_int(struc, "layer", &layer);
886 if ((layer == 3) || (id3_flag == 1)) {
887 gst_structure_get_int(struc, "channels", &channels);
888 gst_structure_get_int(struc, "rate", &rate);
889 gst_structure_get_int(struc, "bit", &bit);
890 if (media_format_set_audio_mime(format, MEDIA_FORMAT_MP3))
893 channels = 2; /* default */
894 if (media_format_set_audio_channel(format, channels))
897 rate = 44100; /* default */
899 bit = 16; /* default */
900 if (media_format_set_audio_samplerate(format, rate))
902 if (media_format_set_audio_bit(format, bit))
905 MD_I("No Support for MPEG%d Layer %d media\n", mpegversion, layer);
909 } else if (gst_structure_has_name(struc, "audio/x-amr-nb-sh") ||
910 gst_structure_has_name(struc, "audio/x-amr-wb-sh")) {
911 media_format_mimetype_e mime_type;
912 gst_structure_get_int(struc, "channels", &channels);
913 gst_structure_get_int(struc, "rate", &rate);
914 if (gst_structure_has_name(struc, "audio/x-amr-nb-sh")) {
915 mime_type = MEDIA_FORMAT_AMR_NB;
918 mime_type = MEDIA_FORMAT_AMR_WB;
921 if (media_format_set_audio_mime(format, mime_type))
924 channels = 1; /* default */
926 bit = 16; /* default */
927 if (media_format_set_audio_channel(format, channels))
929 if (media_format_set_audio_samplerate(format, rate))
931 if (media_format_set_audio_bit(format, bit))
933 } else if (gst_structure_has_name(struc, "audio/AMR")) {
934 gst_structure_get_int(struc, "channels", &channels);
935 gst_structure_get_int(struc, "rate", &rate);
936 gst_structure_get_int(struc, "bit", &bit);
937 if (media_format_set_audio_mime(format, MEDIA_FORMAT_AMR_NB))
940 channels = 1; /* default */
941 if (media_format_set_audio_channel(format, channels))
943 if (media_format_set_audio_samplerate(format, rate))
946 bit = 16; /* default */
947 if (media_format_set_audio_bit(format, bit))
949 } else if (gst_structure_has_name(struc, "audio/AMR-WB")) {
950 gst_structure_get_int(struc, "channels", &channels);
951 gst_structure_get_int(struc, "rate", &rate);
952 gst_structure_get_int(struc, "bit", &bit);
953 if (media_format_set_audio_mime(format, MEDIA_FORMAT_AMR_WB))
956 channels = 1; /* default */
957 if (media_format_set_audio_channel(format, channels))
959 if (media_format_set_audio_samplerate(format, rate))
962 bit = 16; /* default */
963 if (media_format_set_audio_bit(format, bit))
965 } else if (gst_structure_has_name(struc, "audio/x-wav")) {
966 gst_structure_get_int(struc, "channels", &channels);
967 gst_structure_get_int(struc, "rate", &rate);
968 gst_structure_get_int(struc, "bit", &bit);
969 if (media_format_set_audio_mime(format, MEDIA_FORMAT_PCM))
972 channels = 2; /* default */
973 if (media_format_set_audio_channel(format, channels))
976 rate = 44100; /* default */
977 if (media_format_set_audio_samplerate(format, rate))
980 bit = 16; /* default */
981 if (media_format_set_audio_bit(format, bit))
983 } else if (gst_structure_has_name(struc, "audio/x-flac")) {
984 gst_structure_get_int(struc, "channels", &channels);
985 gst_structure_get_int(struc, "rate", &rate);
986 gst_structure_get_int(struc, "bit", &bit);
987 if (media_format_set_audio_mime(format, MEDIA_FORMAT_FLAC))
990 channels = 2; /* default */
991 if (media_format_set_audio_channel(format, channels))
994 rate = 44100; /* default */
995 if (media_format_set_audio_samplerate(format, rate))
998 bit = 16; /* default */
999 if (media_format_set_audio_bit(format, bit))
1001 } else if (gst_structure_has_name(struc, "audio/x-vorbis")) {
1002 gst_structure_get_int(struc, "channels", &channels);
1003 gst_structure_get_int(struc, "rate", &rate);
1004 gst_structure_get_int(struc, "bit", &bit);
1005 if (media_format_set_audio_mime(format, MEDIA_FORMAT_VORBIS))
1008 channels = 2; /* default */
1009 if (media_format_set_audio_channel(format, channels))
1012 rate = 44100; /* default */
1013 if (media_format_set_audio_samplerate(format, rate))
1016 bit = 16; /* default */
1017 if (media_format_set_audio_bit(format, bit))
1020 MD_I("Audio mime not supported so far\n");
1023 MEDIADEMUXER_FLEAVE();
1026 MEDIADEMUXER_FLEAVE();
1030 static int gst_demuxer_get_track_info(MMHandleType pHandle,
1031 media_format_h *format, int index)
1033 MEDIADEMUXER_FENTER();
1034 int ret = MD_ERROR_NONE;
1035 MEDIADEMUXER_CHECK_NULL(pHandle);
1036 mdgst_handle_t *new_mediademuxer = (mdgst_handle_t *) pHandle;
1041 temp = (new_mediademuxer->info).head;
1042 loop = (new_mediademuxer->info).num_video_track +
1043 (new_mediademuxer->info).num_audio_track +
1044 (new_mediademuxer->info).num_subtitle_track +
1045 (new_mediademuxer->info).num_other_track;
1046 if (index >= loop || index < 0) {
1047 MD_E("total tracks(loop) is less then selected track(index), So not support this track");
1052 while (count != index) {
1057 ret = media_format_create(&(temp->format));
1058 if (ret != MEDIA_FORMAT_ERROR_NONE) {
1059 MD_E("Mediaformat creation failed. returned %d\n", ret);
1060 ret = MD_INTERNAL_ERROR;
1064 MD_I("CAPS for selected track [%d] is [%s]\n", index, temp->caps_string);
1065 MD_I("format ptr[%p]\n", temp->format);
1066 if (temp->caps_string[0] == 'a') {
1067 MD_I("Setting for Audio \n");
1068 _set_mime_audio(temp->format, temp);
1069 } else if (temp->caps_string[0] == 'v') {
1070 MD_I("Setting for Video \n");
1071 _set_mime_video(temp->format, temp);
1073 MD_W("Not supported so far (except audio and video)\n");
1075 ret = media_format_ref(temp->format); /* increment the ref to retain the original content */
1076 if (ret != MEDIA_FORMAT_ERROR_NONE) {
1077 MD_E("Mediaformat reference count increment failed. returned %d\n", ret);
1078 ret = MD_INTERNAL_ERROR;
1081 ret = media_format_make_writable(temp->format, format); /* copy the content */
1082 if (ret != MEDIA_FORMAT_ERROR_NONE) {
1083 MD_E("Mediaformat create copy failed. returned %d\n", ret);
1084 media_format_unref(temp->format);
1085 ret = MD_INTERNAL_ERROR;
1089 MEDIADEMUXER_FLEAVE();
1092 MEDIADEMUXER_FLEAVE();
1096 static int _gst_copy_buf_to_media_packet(media_packet_h out_pkt,
1097 GstBuffer *buffer, char *codec_data)
1099 MEDIADEMUXER_FENTER();
1100 int ret = MD_ERROR_NONE;
1101 MEDIADEMUXER_CHECK_NULL(out_pkt);
1106 if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) {
1107 MD_E("gst_buffer_map failed\n");
1108 ret = MD_ERROR_UNKNOWN;
1112 media_packet_get_buffer_size(out_pkt, &size);
1113 MD_I("Media packet Buffer capacity: %llu GST Buffer size = %d\n", size, map.size);
1114 if (size < (uint64_t)map.size) {
1115 MD_W("Media packet Buffer capacity[%llu] is \
1116 less than the GST Buffer size[%d]. Resizing...\n", size, map.size);
1117 ret = media_packet_set_buffer_size(out_pkt, (uint64_t)map.size);
1118 media_packet_get_buffer_size(out_pkt, &size);
1119 MD_I("Media packet Buffer NEW capacity: %llu \n", size);
1121 if (media_packet_get_buffer_data_ptr(out_pkt, &pkt_data)) {
1122 MD_E("unable to get the buffer pointer from media_packet_get_buffer_data_ptr\n");
1123 ret = MD_ERROR_UNKNOWN;
1126 memcpy((char *)pkt_data, map.data, map.size);
1127 if (media_packet_set_pts(out_pkt, GST_BUFFER_PTS(buffer))) {
1128 MD_E("unable to set the pts\n");
1129 ret = MD_ERROR_UNKNOWN;
1132 if (media_packet_set_dts(out_pkt, GST_BUFFER_DTS(buffer))) {
1133 MD_E("unable to set the dts\n");
1134 ret = MD_ERROR_UNKNOWN;
1137 if (media_packet_set_duration(out_pkt, GST_BUFFER_DURATION(buffer))) {
1138 MD_E("unable to set the duration\n");
1139 ret = MD_ERROR_UNKNOWN;
1142 if (media_packet_set_buffer_size(out_pkt, gst_buffer_get_size(buffer))) {
1143 MD_E("unable to set the buffer size\n");
1144 ret = MD_ERROR_UNKNOWN;
1147 if (media_packet_set_flags(out_pkt, GST_BUFFER_FLAGS(buffer))) {
1148 MD_E("unable to set the buffer size\n");
1149 ret = MD_ERROR_UNKNOWN;
1153 if (media_packet_set_codec_data(out_pkt, (void*) codec_data, strlen(codec_data))) {
1154 MD_E("unable to set the codec data\n");
1155 ret = MD_ERROR_UNKNOWN;
1160 gst_buffer_unmap(buffer, &map);
1161 MEDIADEMUXER_FLEAVE();
1165 static int gst_demuxer_read_sample(MMHandleType pHandle,
1166 media_packet_h *outbuf, int track_indx)
1168 MEDIADEMUXER_FENTER();
1169 int ret = MD_ERROR_NONE;
1170 MEDIADEMUXER_CHECK_NULL(pHandle);
1171 mdgst_handle_t *demuxer = (mdgst_handle_t *) pHandle;
1173 media_packet_h mediabuf = NULL;
1175 char *codec_data = NULL;
1176 char *temp_codec_data = NULL;
1179 track *atrack = demuxer->info.head;
1180 if ((demuxer->selected_tracks)[track_indx] == false) {
1181 MD_E("Track Not selected\n");
1186 if (indx == track_indx) /* Got the requird track details */
1189 track *next = atrack->next;
1192 MD_E("Invalid track Index\n");
1193 ret = MD_ERROR_INVALID_ARGUMENT;
1199 if (media_packet_create_alloc(atrack->format, NULL, NULL, &mediabuf)) {
1200 MD_E("media_packet_create_alloc failed\n");
1205 if (indx != track_indx) {
1206 MD_E("Invalid track Index\n");
1207 ret = MD_ERROR_INVALID_ARGUMENT;
1210 GstElement *sink = atrack->appsink;
1211 GstSample *sample = NULL;
1212 if (gst_app_sink_is_eos((GstAppSink *) sink)) {
1213 MD_W("End of stream (EOS) reached\n");
1218 sample = gst_app_sink_pull_sample((GstAppSink *) sink);
1219 if (sample == NULL) {
1220 MD_E("gst_demuxer_read_sample failed\n");
1221 ret = MD_ERROR_UNKNOWN;
1224 GstBuffer *buffer = gst_sample_get_buffer(sample);
1225 if (buffer == NULL) {
1226 MD_E("gst_sample_get_buffer returned NULL pointer\n");
1227 ret = MD_ERROR_UNKNOWN;
1231 /* Create the codec data and pass to _gst_copy_buf_to_media_packet() to add into the media packet */
1232 temp_codec_data = strstr(atrack->caps_string, "codec_data");
1233 if (temp_codec_data != NULL) {
1234 while (*temp_codec_data != ')')
1236 temp_codec_data++; /* to esacpe ')' */
1237 codec_data = (char*) malloc(sizeof(char)*strlen(temp_codec_data));
1238 if (codec_data != NULL) {
1239 while (*temp_codec_data != ',') {
1240 codec_data[index++] = *temp_codec_data;
1243 codec_data[index] = '\0';
1247 /* Fill the media_packet with proper information */
1248 ret = _gst_copy_buf_to_media_packet(mediabuf, buffer, codec_data);
1249 gst_sample_unref(sample);
1254 MEDIADEMUXER_FLEAVE();
1257 MEDIADEMUXER_FLEAVE();
1261 static int gst_demuxer_seek(MMHandleType pHandle, gint64 pos1)
1263 MEDIADEMUXER_FENTER();
1264 MEDIADEMUXER_CHECK_NULL(pHandle);
1265 mdgst_handle_t *gst_handle = (mdgst_handle_t *) pHandle;
1267 gint64 pos = 0, len = 0;
1269 if (gst_element_query_position(gst_handle->pipeline, GST_FORMAT_TIME, &pos) &&
1270 gst_element_query_duration(gst_handle->pipeline, GST_FORMAT_TIME, &len)) {
1271 MD_I("Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r",
1273 GST_TIME_ARGS(len));
1275 pos1 = pos + (pos1 * GST_SECOND);
1278 MD_I("NEW Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r",
1279 GST_TIME_ARGS(pos1), GST_TIME_ARGS(len));
1281 track_info *head_track = &(gst_handle->info);
1282 track *temp = head_track->head;
1285 MD_I("Got one element %p\n", temp->appsink);
1286 if (gst_handle->selected_tracks[indx] == true) {
1287 if (!gst_element_seek(temp->appsink, rate, GST_FORMAT_TIME,
1288 GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, pos1,
1289 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
1290 MD_E("Seek failed!\n");
1293 MD_I("Seek success\n");
1298 track *next = temp->next;
1304 MEDIADEMUXER_FLEAVE();
1305 return MD_ERROR_NONE;
1307 MEDIADEMUXER_FLEAVE();
1311 int _gst_unset_appsink(track *temp, int index, int loop)
1313 MEDIADEMUXER_FENTER();
1314 int ret = MD_ERROR_NONE;
1317 while (count != index) {
1321 gst_app_sink_set_max_buffers((GstAppSink *)(temp->appsink), (guint) 0);
1322 gst_app_sink_set_drop((GstAppSink *)(temp->appsink), true);
1323 MEDIADEMUXER_FLEAVE();
1327 static int gst_demuxer_unset_track(MMHandleType pHandle, int track)
1329 MEDIADEMUXER_FENTER();
1330 int ret = MD_ERROR_NONE;
1331 MEDIADEMUXER_CHECK_NULL(pHandle);
1332 mdgst_handle_t *new_mediademuxer = (mdgst_handle_t *) pHandle;
1334 if (track >= new_mediademuxer->total_tracks || track < 0) {
1335 MD_E("total tracks is less then unselected track, So not support this track");
1336 ret = MD_ERROR_INVALID_ARGUMENT;
1339 new_mediademuxer->selected_tracks[track] = false;
1340 _gst_unset_appsink((((mdgst_handle_t *) pHandle)->info).head, track,
1341 new_mediademuxer->total_tracks);
1342 MEDIADEMUXER_FLEAVE();
1345 MEDIADEMUXER_FLEAVE();
1349 static int gst_demuxer_stop(MMHandleType pHandle)
1351 MEDIADEMUXER_FENTER();
1352 int ret = MD_ERROR_NONE;
1353 MEDIADEMUXER_CHECK_NULL(pHandle);
1354 mdgst_handle_t *gst_handle = (mdgst_handle_t *) pHandle;
1356 MD_I("gst_demuxer_stop pipeine %p", gst_handle);
1357 if (gst_element_set_state(gst_handle->pipeline, GST_STATE_PAUSED) ==
1358 GST_STATE_CHANGE_FAILURE) {
1359 MD_E("Failed to set into PAUSE state");
1360 ret = MD_INTERNAL_ERROR;
1363 MEDIADEMUXER_FLEAVE();
1366 MEDIADEMUXER_FLEAVE();
1370 void _gst_clear_struct(mdgst_handle_t *gst_handle)
1372 MEDIADEMUXER_FENTER();
1373 if (gst_handle->selected_tracks) {
1374 MD_I("Deallocating gst_handle->selected_tracks %p\n",
1375 gst_handle->selected_tracks);
1376 g_free(gst_handle->selected_tracks);
1377 gst_handle->selected_tracks = NULL;
1379 if ((gst_handle->info).head)
1380 __gst_free_stuct(&(gst_handle->info).head);
1381 MEDIADEMUXER_FLEAVE();
1384 int _md_gst_destroy_pipeline(GstElement *pipeline)
1386 MEDIADEMUXER_FENTER();
1387 int ret = MD_ERROR_NONE;
1389 MEDIADEMUXER_SET_STATE(pipeline, GST_STATE_NULL, ERROR);
1390 MEDIADEMUXER_FLEAVE();
1394 gst_object_unref(GST_OBJECT(pipeline));
1395 MEDIADEMUXER_FLEAVE();
1399 static int gst_demuxer_unprepare(MMHandleType pHandle)
1401 MEDIADEMUXER_FENTER();
1402 int ret = MD_ERROR_NONE;
1403 MEDIADEMUXER_CHECK_NULL(pHandle);
1404 mdgst_handle_t *gst_handle = (mdgst_handle_t *) pHandle;
1406 _gst_clear_struct(gst_handle);
1407 MD_I("gst_demuxer_stop pipeine %p\n", gst_handle->pipeline);
1408 if (_md_gst_destroy_pipeline(gst_handle->pipeline) != MD_ERROR_NONE) {
1412 MEDIADEMUXER_FLEAVE();
1415 MEDIADEMUXER_FLEAVE();
1419 static int gst_demuxer_destroy(MMHandleType pHandle)
1421 MEDIADEMUXER_FENTER();
1422 int ret = MD_ERROR_NONE;
1423 MEDIADEMUXER_CHECK_NULL(pHandle);
1424 mdgst_handle_t *new_mediademuxer = (mdgst_handle_t *) pHandle;
1426 MD_I("gst_demuxer_destroy deallocating new_mediademuxer:%p\n",
1428 g_free(new_mediademuxer);
1429 MEDIADEMUXER_FLEAVE();
1433 int gst_set_error_cb(MMHandleType pHandle,
1434 gst_error_cb callback, void *user_data)
1436 MEDIADEMUXER_FENTER();
1437 int ret = MD_ERROR_NONE;
1438 MEDIADEMUXER_CHECK_NULL(pHandle);
1439 mdgst_handle_t *gst_handle = (mdgst_handle_t *) pHandle;
1442 MD_E("fail invaild param (gst_handle)\n");
1443 ret = MD_INVALID_ARG;
1447 if (gst_handle->user_cb[_GST_EVENT_TYPE_ERROR]) {
1448 MD_E("Already set mediademuxer_error_cb\n");
1449 ret = MD_ERROR_INVALID_ARGUMENT;
1453 MD_E("fail invaild argument (callback)\n");
1454 ret = MD_ERROR_INVALID_ARGUMENT;
1459 MD_I("Set event handler callback(cb = %p, data = %p)\n", callback, user_data);
1461 gst_handle->user_cb[_GST_EVENT_TYPE_ERROR] = (gst_error_cb) callback;
1462 gst_handle->user_data[_GST_EVENT_TYPE_ERROR] = user_data;
1463 MEDIADEMUXER_FLEAVE();
1464 return MD_ERROR_NONE;
1466 MEDIADEMUXER_FLEAVE();