Merge branch 'tizen' into tizen_gst_1.19.2
authorEunhye Choi <eunhae1.choi@samsung.com>
Mon, 17 Jan 2022 18:37:57 +0000 (03:37 +0900)
committerEunhye Choi <eunhae1.choi@samsung.com>
Mon, 17 Jan 2022 19:42:54 +0000 (04:42 +0900)
Change-Id: I1eb8ccf3e811415df3c7828ebafc22d5dabe6a7f

48 files changed:
1  2 
ext/pulse/meson.build
ext/pulse/pulsesink.c
ext/pulse/pulsesink.h
ext/pulse/pulsesrc.c
ext/pulse/pulsesrc.h
ext/soup/gstsouphttpsrc.c
ext/vpx/gstvpxdec.c
gst/audioparsers/gstaacparse.c
gst/audioparsers/gstmpegaudioparse.c
gst/audioparsers/gstmpegaudioparse.h
gst/avi/gstavidemux.c
gst/flv/gstflvdemux.c
gst/flx/gstflxdec.c
gst/isomp4/fourcc.h
gst/isomp4/gstqtmux.c
gst/isomp4/gstqtmux.h
gst/isomp4/qtdemux.c
gst/isomp4/qtdemux.h
gst/matroska/matroska-demux.c
gst/replaygain/gstrgvolume.c
gst/replaygain/gstrgvolume.h
gst/rtpmanager/gstrtpbin.c
gst/rtpmanager/gstrtpbin.h
gst/rtpmanager/rtpjitterbuffer.c
gst/rtpmanager/rtpstats.c
gst/rtsp/gstrtsp.c
gst/rtsp/gstrtspsrc.c
gst/rtsp/gstrtspsrc.h
gst/videofilter/gstvideobalance.c
gst/wavparse/gstwavparse.c
meson.build
meson_options.txt
packaging/gst-plugins-good.manifest
packaging/gst-plugins-good.spec
sys/v4l2/ext/videodev2.h
sys/v4l2/gstv4l2.c
sys/v4l2/gstv4l2allocator.c
sys/v4l2/gstv4l2bufferpool.c
sys/v4l2/gstv4l2bufferpool.h
sys/v4l2/gstv4l2object.c
sys/v4l2/gstv4l2object.h
sys/v4l2/gstv4l2src.c
sys/v4l2/gstv4l2src.h
sys/v4l2/gstv4l2videodec.c
sys/v4l2/gstv4l2videoenc.c
sys/v4l2/meson.build
sys/v4l2/v4l2_calls.c
sys/waveform/gstwaveformsink.c

@@@ -14,7 -13,7 +14,7 @@@ if libpulse_dep.found(
      pulse_sources,
      c_args : gst_plugins_good_args,
      include_directories : [configinc, libsinc],
--    dependencies : [gst_dep, gstbase_dep, gstaudio_dep, gstpbutils_dep, libpulse_dep],
++    dependencies : [gst_dep, gstbase_dep, gstaudio_dep, gstpbutils_dep, libpulse_dep, gio_dep],
      install : true,
      install_dir : plugins_install_dir,
    )
  #include <gst/pbutils/pbutils.h>        /* only used for GST_PLUGINS_BASE_VERSION_* */
  
  #include <gst/glib-compat-private.h>
 +
 +#include "gstpulseelements.h"
+ #if defined(__TIZEN__) && defined(PCM_DUMP_ENABLE)
+ #include <vconf.h>
+ #endif /* __TIZEN__ && PCM_DUMP_ENABLE */
  #include "pulsesink.h"
  #include "pulseutil.h"
  
Simple merge
Simple merge
  #include <pulse/pulseaudio.h>
  #include <pulse/thread-mainloop.h>
  
+ #if defined(__TIZEN__) && defined(PCM_DUMP_ENABLE)
+ #include <stdio.h>
+ #endif
  G_BEGIN_DECLS
  
 -#define GST_TYPE_PULSESRC \
 -  (gst_pulsesrc_get_type())
 -#define GST_PULSESRC(obj) \
 -  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PULSESRC,GstPulseSrc))
 -#define GST_PULSESRC_CLASS(klass) \
 -  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PULSESRC,GstPulseSrcClass))
 -#define GST_IS_PULSESRC(obj) \
 -  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PULSESRC))
 -#define GST_IS_PULSESRC_CLASS(obj) \
 -  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PULSESRC))
 -#define GST_PULSESRC_CAST(obj) \
 -  ((GstPulseSrc *)(obj))
 -
 -typedef struct _GstPulseSrc GstPulseSrc;
 -typedef struct _GstPulseSrcClass GstPulseSrcClass;
 +#define GST_TYPE_PULSESRC (gst_pulsesrc_get_type())
 +G_DECLARE_FINAL_TYPE (GstPulseSrc, gst_pulsesrc, GST, PULSESRC, GstAudioSrc)
 +#define GST_PULSESRC_CAST(obj) ((GstPulseSrc *)(obj))
  
  struct _GstPulseSrc
  {
    gboolean paused:1;
    gboolean in_read:1;
  
+ #ifdef __TIZEN__
+   gchar *latency;
+ #endif /* __TIZEN__ */
    GstStructure *properties;
    pa_proplist *proplist;
+ #if defined(__TIZEN__) && defined(PCM_DUMP_ENABLE)
+   gint need_dump_output;
+   FILE *dump_fd_output;
+ #endif
  };
  
 -struct _GstPulseSrcClass
 -{
 -  GstAudioSrcClass parent_class;
 -};
 -
 -GType gst_pulsesrc_get_type (void);
 -
  G_END_DECLS
  
  #endif /* __GST_PULSESRC_H__ */
@@@ -1175,12 -1229,68 +1233,69 @@@ gst_soup_http_src_got_headers (GstSoupH
    gst_event_replace (&src->http_headers_event, http_headers_event);
    gst_event_unref (http_headers_event);
  
+ #ifdef TIZEN_FEATURE_SOUP_MODIFICATION
+   /* Parse DLNA OP CODE */
+   if ((value = soup_message_headers_get_one
+         (msg->response_headers, "contentFeatures.dlna.org")) != NULL) {
+     gchar **token = NULL;
+     gchar **ptr = NULL;
+     GST_DEBUG_OBJECT (src, "DLNA server response");
+     token = g_strsplit (value, ";", 0);
+     for (ptr = token ; *ptr ; ptr++) {
+       gchar *tmp = NULL;
+       gchar *op_code = NULL;
+       if (!strlen (*ptr))
+         continue;
+       tmp = g_ascii_strup (*ptr, strlen (*ptr));
+       if (!strstr (tmp, "DLNA.ORG_OP")) {
+         g_free (tmp);
+         continue;
+       }
+       g_free (tmp);
+       op_code = strchr (*ptr, '=');
+       if (op_code) {
+         op_code++;
+         src->dlna_opt = (atoi (op_code) / 10 << 1) | (atoi (op_code) % 10);
+         GST_DEBUG_OBJECT (src, "dlna op code: %s (0x%X)", op_code, src->dlna_opt);
+         break;
+       }
+     }
+     g_strfreev (token);
+   }
+ #endif
    /* Parse Content-Length. */
 -  if (soup_message_headers_get_encoding (msg->response_headers) ==
 -      SOUP_ENCODING_CONTENT_LENGTH) {
 +  if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code) &&
 +      (soup_message_headers_get_encoding (msg->response_headers) ==
 +          SOUP_ENCODING_CONTENT_LENGTH)) {
+ #ifdef TIZEN_FEATURE_SOUP_MODIFICATION
+       if (msg->status_code == SOUP_STATUS_PARTIAL_CONTENT) {
+         newsize = src->request_position +
+             soup_message_headers_get_content_length (msg->response_headers);
+       } else {
+         if (soup_message_headers_get_content_range(msg->response_headers, &start, &stop, &total) && (total > 0)) {
+           GST_DEBUG_OBJECT (src, "get range header : %" G_GINT64_FORMAT
+                                   "~%" G_GINT64_FORMAT"/%"G_GINT64_FORMAT, start, stop, total);
+           newsize = (guint64)total;
+         } else {
+           if ((src->have_size) && (src->content_size <= src->request_position)) {
+             newsize = src->content_size;
+           } else {
+             newsize = soup_message_headers_get_content_length (msg->response_headers);
+           }
+         }
+       }
+ #else
 -      newsize = src->request_position +
 -          soup_message_headers_get_content_length (msg->response_headers);
 +    newsize = src->request_position +
 +        soup_message_headers_get_content_length (msg->response_headers);
+ #endif
      if (!src->have_size || (src->content_size != newsize)) {
        src->content_size = newsize;
        src->have_size = TRUE;
Simple merge
@@@ -109,9 -127,21 +128,23 @@@ static void gst_aac_parse_check_byte_se
  
  #define gst_aac_parse_parent_class parent_class
  G_DEFINE_TYPE (GstAacParse, gst_aac_parse, GST_TYPE_BASE_PARSE);
 +GST_ELEMENT_REGISTER_DEFINE (aacparse, "aacparse",
 +    GST_RANK_PRIMARY + 1, GST_TYPE_AAC_PARSE);
  
+ #ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
+ static inline gint
+ gst_aac_parse_get_sample_rate_from_index (guint sr_idx)
+ {
+   static const guint aac_sample_rates[] = { 96000, 88200, 64000, 48000, 44100,
+     32000, 24000, 22050, 16000, 12000, 11025, 8000
+   };
+   if (sr_idx < G_N_ELEMENTS (aac_sample_rates))
+     return aac_sample_rates[sr_idx];
+   GST_WARNING ("Invalid sample rate index %u", sr_idx);
+   return 0;
+ }
+ #endif
  /**
   * gst_aac_parse_class_init:
   * @klass: #GstAacParseClass.
@@@ -229,8 -263,21 +266,21 @@@ gst_aac_parse_set_src_caps (GstAacPars
    if (stream_format)
      gst_structure_set (s, "stream-format", G_TYPE_STRING, stream_format, NULL);
  
 -  allowed = gst_pad_get_allowed_caps (GST_BASE_PARSE (aacparse)->srcpad);
 -  if (allowed && !gst_caps_can_intersect (src_caps, allowed)) {
+ #ifdef TIZEN_FEATURE_AACPARSE_MODIFICATION
+   if (!gst_structure_get_value (s, "codec_data")) {
+     GstBuffer *codec_data_buffer;
+     GST_WARNING("Insert codec_data to src_caps");
+     /* The codec_data data is according to AudioSpecificConfig,
+        ISO/IEC 14496-3, 1.6.2.1 */
+     codec_data_buffer = gst_buffer_new_and_alloc (2);
+     gst_buffer_fill (codec_data_buffer, 0, codec_data, 2);
+     gst_caps_set_simple (src_caps, "codec_data", GST_TYPE_BUFFER, codec_data_buffer, NULL);
+     gst_buffer_unref (codec_data_buffer);
+   }
+ #endif
 +  peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (aacparse), NULL);
 +  if (peercaps && !gst_caps_can_intersect (src_caps, peercaps)) {
      GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad,
          "Caps can not intersect");
      if (aacparse->header_type == DSPAAC_HEADER_ADTS) {
Simple merge
Simple merge
Simple merge
@@@ -992,11 -978,18 +992,20 @@@ gst_flv_demux_push_tags (GstFlvDemux * 
  
    GST_DEBUG_OBJECT (demux, "pushing %" GST_PTR_FORMAT, demux->taglist);
  
 -  gst_flv_demux_push_src_event (demux,
 -      gst_event_new_tag (gst_tag_list_copy (demux->taglist)));
 +  tag_event = gst_event_new_tag (gst_tag_list_copy (demux->taglist));
 +  if (demux->segment_seqnum != GST_SEQNUM_INVALID)
 +    gst_event_set_seqnum (tag_event, demux->segment_seqnum);
 +  gst_flv_demux_push_src_event (demux, tag_event);
  
+ #ifdef TIZEN_FEATURE_FLVDEMUX_MODIFICATION
+   GST_DEBUG_OBJECT (demux, "post tag msg %" GST_PTR_FORMAT, demux->taglist);
+   /* post message flv tag (for early recive application) */
+   gst_element_post_message (GST_ELEMENT_CAST (demux),
+       gst_message_new_tag (GST_OBJECT_CAST (demux),
+         gst_tag_list_copy (demux->taglist)));
+ #endif
    if (demux->audio_pad) {
      GST_DEBUG_OBJECT (demux->audio_pad, "pushing audio %" GST_PTR_FORMAT,
          demux->audio_tags);
index 1016876,37d552a..1016876
mode 100644,100755..100755
@@@ -402,12 -390,12 +402,17 @@@ G_BEGIN_DECL
  #define FOURCC_pssh     GST_MAKE_FOURCC('p','s','s','h')
  #define FOURCC_tenc     GST_MAKE_FOURCC('t','e','n','c')
  #define FOURCC_cenc     GST_MAKE_FOURCC('c','e','n','c')
 +#define FOURCC_cbcs     GST_MAKE_FOURCC('c','b','c','s')
 +
 +/* Audible AAX encrypted audio */
 +#define FOURCC_aavd     GST_MAKE_FOURCC('a','a','v','d')
 +#define FOURCC_adrm     GST_MAKE_FOURCC('a','d','r','m')
  
+ #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
+ /* Spatial Audio */
+ #define FOURCC_SA3D     GST_MAKE_FOURCC('S','A','3','D')
+ #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
  G_END_DECLS
  
  #endif /* __FOURCC_H__ */
@@@ -326,11 -396,11 +326,14 @@@ enu
    PROP_DO_CTTS,
    PROP_INTERLEAVE_BYTES,
    PROP_INTERLEAVE_TIME,
 +  PROP_FORCE_CHUNKS,
    PROP_MAX_RAW_AUDIO_DRIFT,
    PROP_START_GAP_THRESHOLD,
 +  PROP_FORCE_CREATE_TIMECODE_TRAK,
 +  PROP_FRAGMENT_MODE,
+ #ifdef TIZEN_FEATURE_GST_MUX_ENHANCEMENT
+   PROP_EXPECTED_TRAILER_SIZE,
+ #endif /* TIZEN_FEATURE_GST_MUX_ENHANCEMENT */  
  };
  
  /* some spare for header size as well */
@@@ -399,10 -457,229 +402,231 @@@ gst_qt_mux_robust_recording_rewrite_moo
  static void gst_qt_mux_update_global_statistics (GstQTMux * qtmux);
  static void gst_qt_mux_update_edit_lists (GstQTMux * qtmux);
  
 +static GstFlowReturn gst_qtmux_push_mdat_stored_buffers (GstQTMux * qtmux);
 +
  static GstElementClass *parent_class = NULL;
  
 -gst_qt_mux_update_expected_trailer_size (GstQTMux *qtmux, GstQTPad *pad)
+ #ifdef TIZEN_FEATURE_GST_MUX_ENHANCEMENT
+ /*
+      [[ Metadata Size ]]
+      1. Common
+        free = 8
+        moov = 8
+          mvhd = 108
+        -------------
+        total : 124
+      2. Video
+        i. Video common
+          trak = 8
+            tkhd = 92
+            mdia = 8
+              mdhd = 32
+              hdlr = 45
+              minf = 8
+                vmhd = 20
+                dinf = 36 (8, dref : 16 , url : 12)
+                stbl = 8
+          ---------------
+          total : 257
+        ii. Variation in file format
+          - MP4
+              ftyp = 32
+              udta = 61
+          - 3GP
+              ftyp = 28
+              udta = 8
+        iii. Variation in codec
+          - MPEG4
+            stsd = 137(16, mp4v : 86, esds : 35)
+          - H.264 = 487(or 489) + (8*stts_count) + (8*frame) + (4*I-frame)
+            stsd = 134 (SPS 9, PPS 4) or 136 (SPS 111, PPS 4)
+          - H.263 = 470 + + (8*stts_count) + (8*frame) + (4*I-frame)
+            stsd = 102 -> different from H.264
+        iv. Variation in frame
+          stts = 16 + (8*stts_count)
+          stss = 16 + (4*I-frame)
+          stsc = 28
+          stsz = 20 + (4*frame)
+          stco = 16 + (4*frame)
+      3. Audio
+        i. Audio common
+          trak = 8
+            tkhd = 92
+            mdia = 8
+              mdhd = 32
+              hdlr = 45
+              minf = 8
+                smhd = 16
+                dinf = 36 (8, dref : 16, url : 12)
+                stbl = 8
+          ---------------
+          total : 253
+                  stts = 16
+                  stsz = 20
+                  stco = 16
+                  ------------
+                  total : 52
+        ii. Variation in file format
+          - MP4
+              udta = 61
+          - 3GP
+              udta = 8
+        iii. Variation in codec
+          - Common
+              stts = 16 + (8*stts_count)
+              stsc = 28
+              stsz = 20 + (4*frame)
+              stco = 16 + (4*frame)
+          - AAC
+              stsd = 94 (16, mp4a : 78(36 ,esds : 42))
+          - AMR
+              stsd = 69 (16, samr : 53(36, damr : 17))
+ */
+ /* trailer entry size */
+ #define ENTRY_SIZE_VIDEO_STTS         8
+ #define ENTRY_SIZE_VIDEO_STSS         4
+ #define ENTRY_SIZE_VIDEO_STSZ         4
+ #define ENTRY_SIZE_VIDEO_STCO         4
+ #define ENTRY_SIZE_AUDIO_STTS         8
+ #define ENTRY_SIZE_AUDIO_STSZ         4
+ #define ENTRY_SIZE_AUDIO_STCO         4
+ #define ENTRY_SIZE_VIDEO_MPEG4_STSD   137
+ #define ENTRY_SIZE_VIDEO_H263P_STSD   102
+ #define ENTRY_SIZE_AUDIO_AAC_STSD     94
+ #define ENTRY_SIZE_AUDIO_AMR_STSD     69
+ #define ENTRY_SIZE_STSC               28
+ #define ENTRY_SIZE_VIDEO_ST           68        /*atom size (stss + stts + stsc + stsz + stco ) * (size + atom + version + flags + sample count)+stsz(sample size) */
+ #define ENTRY_SIZE_AUDIO_ST           52        /*atom size (stss + stsc + stsz + stco ) * (size + atom + version + flags + sample count)+stsz(sample size) */
+ /* common */
+ #define MUX_COMMON_SIZE_HEADER             124   /* free + moov + moov.mvhd*/
+ #define MUX_COMMON_SIZE_VIDEO_HEADER       257
+ #define MUX_COMMON_SIZE_AUDIO_HEADER       253
+ #define MUX_COMMON_SIZE_MP4_FTYP           32
+ #define MUX_COMMON_SIZE_3GP_FTYP           28
+ #define MUX_COMMON_SIZE_MP4_UDTA           61
+ #define MUX_COMMON_SIZE_3GP_UDTA           8
+ static void
++gst_qt_mux_update_expected_trailer_size (GstQTMux *qtmux, GstQTMuxPad *pad)
+ {
+   guint nb_video_frames = 0;
+   guint nb_video_i_frames = 0;
+   guint nb_video_stts_entry = 0;
+   guint nb_audio_frames = 0;
+   guint nb_audio_stts_entry = 0;
+   gboolean video_stream = FALSE;
+   gboolean audio_stream = FALSE;
+   guint exp_size = 0;
+   GstQTMuxClass *qtmux_klass = NULL;
+   if (qtmux == NULL || pad == NULL) {
+     GST_ERROR_OBJECT (qtmux, "Invalid parameter");
+     return;
+   }
+   qtmux_klass = (GstQTMuxClass *)(G_OBJECT_GET_CLASS(qtmux));
+   if (!strncmp(GST_PAD_NAME(pad->collect.pad), "video", 5)) {
+     nb_video_frames += pad->trak->mdia.minf.stbl.stsz.table_size;
+     nb_video_i_frames += pad->trak->mdia.minf.stbl.stss.entries.len;
+     nb_video_stts_entry += pad->trak->mdia.minf.stbl.stts.entries.len;
+     video_stream = TRUE;
+   } else if (!strncmp(GST_PAD_NAME(pad->collect.pad), "audio", 5)) {
+     nb_audio_frames += pad->trak->mdia.minf.stbl.stsz.table_size;
+     nb_audio_stts_entry += pad->trak->mdia.minf.stbl.stts.entries.len;
+     audio_stream = TRUE;
+   }
+   /* free + moov + mvhd */
+   qtmux->expected_trailer_size = MUX_COMMON_SIZE_HEADER;
+   /* ftyp + udta * 3 (There is 3 udta fields and it's same size) */
+   switch (qtmux_klass->format) {
+   case GST_QT_MUX_FORMAT_MP4:
+     qtmux->expected_trailer_size += MUX_COMMON_SIZE_MP4_FTYP + MUX_COMMON_SIZE_MP4_UDTA * 3;
+     break;
+   case GST_QT_MUX_FORMAT_3GP:
+     qtmux->expected_trailer_size += MUX_COMMON_SIZE_3GP_FTYP + MUX_COMMON_SIZE_3GP_UDTA * 3;
+     break;
+   default:
+     break;
+   }
+   /* Calculate trailer size for video stream */
+   if (video_stream) {
+     switch (pad->fourcc) {
+     case FOURCC_h263:
+     case FOURCC_s263:
+       exp_size += MUX_COMMON_SIZE_VIDEO_HEADER + ENTRY_SIZE_VIDEO_H263P_STSD;
+       break;
+     case FOURCC_mp4v:
+     case FOURCC_MP4V:
+     case FOURCC_fmp4:
+     case FOURCC_FMP4:
+     case FOURCC_3gp4:
+     case FOURCC_3gp6:
+     case FOURCC_3gg6:
+       exp_size += MUX_COMMON_SIZE_VIDEO_HEADER + ENTRY_SIZE_VIDEO_MPEG4_STSD;
+       break;
+     default:
+       break;
+     }
+     /* frame related */
+     exp_size += ENTRY_SIZE_VIDEO_ST + (ENTRY_SIZE_VIDEO_STTS * nb_video_stts_entry) +
+                 (ENTRY_SIZE_VIDEO_STSS * nb_video_i_frames) + (ENTRY_SIZE_STSC) +
+                 ((ENTRY_SIZE_VIDEO_STSZ + ENTRY_SIZE_VIDEO_STCO) * nb_video_frames);
+     qtmux->video_expected_trailer_size = exp_size;
+   }
+   /* Calculate trailer size for audio stream */
+   if (audio_stream) {
+     exp_size += MUX_COMMON_SIZE_AUDIO_HEADER + ENTRY_SIZE_AUDIO_ST + (ENTRY_SIZE_AUDIO_STTS * nb_audio_stts_entry) +
+                 (ENTRY_SIZE_STSC) + ((ENTRY_SIZE_AUDIO_STSZ + ENTRY_SIZE_AUDIO_STCO) * nb_audio_frames);
+     if (pad->fourcc == FOURCC_samr)
+       exp_size += ENTRY_SIZE_AUDIO_AMR_STSD;
+     else
+       exp_size += ENTRY_SIZE_AUDIO_AAC_STSD;
+     qtmux->audio_expected_trailer_size = exp_size;
+   }
+   qtmux->expected_trailer_size += qtmux->video_expected_trailer_size + qtmux->audio_expected_trailer_size;
+   /*
+   GST_INFO_OBJECT (qtmux, "pad type %s", GST_PAD_NAME(pad->collect.pad));
+   GST_INFO_OBJECT (qtmux, "VIDEO : stts-entry=[%d], i-frame=[%d], video-sample=[%d]", nb_video_stts_entry, nb_video_i_frames, nb_video_frames);
+   GST_INFO_OBJECT (qtmux, "AUDIO : stts-entry=[%d], audio-sample=[%d]", nb_audio_stts_entry, nb_audio_frames);
+   GST_INFO_OBJECT (qtmux, "expected trailer size %d", qtmux->expected_trailer_size);
+   */
+   return;
+ }
+ #endif /* TIZEN_FEATURE_GST_MUX_ENHANCEMENT */
  static void
  gst_qt_mux_base_init (gpointer g_class)
  {
@@@ -471,7 -747,14 +695,10 @@@ gst_qt_mux_class_init (GstQTMuxClass * 
  {
    GObjectClass *gobject_class;
    GstElementClass *gstelement_class;
 -  GParamFlags streamable_flags;
 -  const gchar *streamable_desc;
 -  gboolean streamable;
 +  GstAggregatorClass *gstagg_class = GST_AGGREGATOR_CLASS (klass);
+ #ifdef TIZEN_FEATURE_GST_MUX_ENHANCEMENT
+   GParamSpec *tspec = NULL;
+ #endif /* TIZEN_FEATURE_GST_MUX_ENHANCEMENT */
 -#define STREAMABLE_DESC "If set to true, the output should be as if it is to "\
 -  "be streamed and hence no indexes written or duration written."
  
    gobject_class = (GObjectClass *) klass;
    gstelement_class = (GstElementClass *) klass;
            "Threshold for creating an edit list for gaps at the start in nanoseconds",
            0, G_MAXUINT64, DEFAULT_START_GAP_THRESHOLD,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 +  g_object_class_install_property (gobject_class,
 +      PROP_FORCE_CREATE_TIMECODE_TRAK,
 +      g_param_spec_boolean ("force-create-timecode-trak",
 +          "Force Create Timecode Trak",
 +          "Create a timecode trak even in unsupported flavors",
 +          DEFAULT_FORCE_CREATE_TIMECODE_TRAK,
 +          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
 +
 +  /**
 +   * GstBaseQTMux:fragment-mode:
 +   *
 +   * Influence how fragmented files are produces.  Only has any affect when the
 +   * the 'fragment-duration' property is set to a value greater than '0'
 +   *
 +   * Currently, two options exist:
 +   * - "dash-or-mss": for the original fragmented mode that supports dash or
 +   *   mocrosoft smoothstreaming with a single input stream
 +   * - "first-moov-then-finalise" is a fragmented mode that will start with a
 +   *   self-contained 'moov' atom fo the first fragment, then produce fragments.
 +   *   When the file is finalised, the initial 'moov' is invalidated and a
 +   *   new 'moov' is written covering the entire file.
 +   *
 +   * Since: 1.20
 +   */
 +  g_object_class_install_property (gobject_class, PROP_FRAGMENT_MODE,
 +      g_param_spec_enum ("fragment-mode", "Fragment Mode",
 +          "How to to write fragments to the file.  Only used when "
 +          "\'fragment-duration\' is greather than 0",
 +          GST_TYPE_QT_MUX_FRAGMENT_MODE, DEFAULT_FRAGMENT_MODE,
 +          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  
+ #ifdef TIZEN_FEATURE_GST_MUX_ENHANCEMENT
+   tspec = g_param_spec_uint("expected-trailer-size", "Expected Trailer Size",
+     "Expected trailer size (bytes)",
+     0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+   if (tspec)
+     g_object_class_install_property(gobject_class, PROP_EXPECTED_TRAILER_SIZE, tspec);
+   else
+     GST_ERROR("g_param_spec failed for \"expected-trailer-size\"");
+ #endif /* TIZEN_FEATURE_GST_MUX_ENHANCEMENT */
    gstelement_class->request_new_pad =
        GST_DEBUG_FUNCPTR (gst_qt_mux_request_new_pad);
 -  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qt_mux_change_state);
    gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_qt_mux_release_pad);
 +
 +  gstagg_class->sink_event = gst_qt_mux_sink_event;
 +  gstagg_class->sink_event_pre_queue = gst_qt_mux_sink_event_pre_queue;
 +  gstagg_class->aggregate = gst_qt_mux_aggregate;
 +  gstagg_class->clip = gst_qt_mux_clip_running_time;
 +  gstagg_class->start = gst_qt_mux_start;
 +  gstagg_class->stop = gst_qt_mux_stop;
 +  gstagg_class->create_new_pad = gst_qt_mux_create_new_pad;
 +
 +  gst_type_mark_as_plugin_api (GST_TYPE_QT_MUX_PAD, 0);
 +  gst_type_mark_as_plugin_api (GST_TYPE_QT_MUX_DTS_METHOD, 0);
 +  gst_type_mark_as_plugin_api (GST_TYPE_QT_MUX_FRAGMENT_MODE, 0);
  }
  
  static void
@@@ -757,18 -1013,16 +994,20 @@@ gst_qt_mux_reset (GstQTMux * qtmux, gbo
  
    if (alloc) {
      qtmux->moov = atom_moov_new (qtmux->context);
+ #ifndef TIZEN_FEATURE_GST_MUX_ENHANCEMENT
      /* ensure all is as nice and fresh as request_new_pad would provide it */
 -    for (walk = qtmux->sinkpads; walk; walk = g_slist_next (walk)) {
 -      GstQTPad *qtpad = (GstQTPad *) walk->data;
 +    for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) {
 +      GstQTMuxPad *qtpad = (GstQTMuxPad *) l->data;
  
        qtpad->trak = atom_trak_new (qtmux->context);
        atom_moov_add_trak (qtmux->moov, qtpad->trak);
      }
+ #endif
    }
 +  GST_OBJECT_UNLOCK (qtmux);
 +
 +  g_list_free_full (qtmux->output_buffers, (GDestroyNotify) gst_buffer_unref);
 +  qtmux->output_buffers = NULL;
  
    qtmux->current_pad = NULL;
    qtmux->current_chunk_size = 0;
    qtmux->last_moov_update = GST_CLOCK_TIME_NONE;
    qtmux->muxed_since_last_update = 0;
    qtmux->reserved_duration_remaining = GST_CLOCK_TIME_NONE;
+ #ifdef TIZEN_FEATURE_GST_MUX_ENHANCEMENT
+   qtmux->expected_trailer_size = 0;
+   qtmux->video_expected_trailer_size = 0;
+   qtmux->audio_expected_trailer_size = 0;
+ #endif /* TIZEN_FEATURE_GST_MUX_ENHANCEMENT */
  }
  
 +static GstBuffer *
 +gst_qt_mux_clip_running_time (GstAggregator * agg,
 +    GstAggregatorPad * agg_pad, GstBuffer * buf)
 +{
 +  GstQTMuxPad *qtpad = GST_QT_MUX_PAD (agg_pad);
 +  GstBuffer *outbuf = buf;
 +
 +  /* invalid left alone and passed */
 +  if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS_OR_PTS (buf)))) {
 +    GstClockTime time;
 +    GstClockTime buf_dts, abs_dts;
 +    gint dts_sign;
 +
 +    time = GST_BUFFER_PTS (buf);
 +
 +    if (GST_CLOCK_TIME_IS_VALID (time)) {
 +      time =
 +          gst_segment_to_running_time (&agg_pad->segment, GST_FORMAT_TIME,
 +          time);
 +      if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
 +        GST_DEBUG_OBJECT (agg_pad, "clipping buffer on pad outside segment %"
 +            GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (buf)));
 +        gst_buffer_unref (buf);
 +        return NULL;
 +      }
 +    }
 +
 +    GST_LOG_OBJECT (agg_pad, "buffer pts %" GST_TIME_FORMAT " -> %"
 +        GST_TIME_FORMAT " running time",
 +        GST_TIME_ARGS (GST_BUFFER_PTS (buf)), GST_TIME_ARGS (time));
 +    outbuf = gst_buffer_make_writable (buf);
 +    GST_BUFFER_PTS (outbuf) = time;
 +
 +    dts_sign = gst_segment_to_running_time_full (&agg_pad->segment,
 +        GST_FORMAT_TIME, GST_BUFFER_DTS (outbuf), &abs_dts);
 +    buf_dts = GST_BUFFER_DTS (outbuf);
 +    if (dts_sign > 0) {
 +      GST_BUFFER_DTS (outbuf) = abs_dts;
 +      qtpad->dts = abs_dts;
 +    } else if (dts_sign < 0) {
 +      GST_BUFFER_DTS (outbuf) = GST_CLOCK_TIME_NONE;
 +      qtpad->dts = -((gint64) abs_dts);
 +    } else {
 +      GST_BUFFER_DTS (outbuf) = GST_CLOCK_TIME_NONE;
 +      qtpad->dts = GST_CLOCK_STIME_NONE;
 +    }
 +
 +    GST_LOG_OBJECT (agg_pad, "buffer dts %" GST_TIME_FORMAT " -> %"
 +        GST_STIME_FORMAT " running time", GST_TIME_ARGS (buf_dts),
 +        GST_STIME_ARGS (qtpad->dts));
 +  }
 +
 +  return outbuf;
 +}
 +
  static void
  gst_qt_mux_init (GstQTMux * qtmux, GstQTMuxClass * qtmux_klass)
  {
@@@ -7170,16 -6703,11 +7419,21 @@@ gst_qt_mux_get_property (GObject * obje
      case PROP_START_GAP_THRESHOLD:
        g_value_set_uint64 (value, qtmux->start_gap_threshold);
        break;
 +    case PROP_FORCE_CREATE_TIMECODE_TRAK:
 +      g_value_set_boolean (value, qtmux->force_create_timecode_trak);
 +      break;
 +    case PROP_FRAGMENT_MODE:{
 +      GstQTMuxFragmentMode mode = qtmux->fragment_mode;
 +      if (mode == GST_QT_MUX_FRAGMENT_STREAMABLE)
 +        mode = GST_QT_MUX_FRAGMENT_DASH_OR_MSS;
 +      g_value_set_enum (value, mode);
 +      break;
 +    }
+ #ifdef TIZEN_FEATURE_GST_MUX_ENHANCEMENT
+     case PROP_EXPECTED_TRAILER_SIZE:
+       g_value_set_uint(value, qtmux->expected_trailer_size);
+       break;
+ #endif /* TIZEN_FEATURE_GST_MUX_ENHANCEMENT */          
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
@@@ -348,10 -291,14 +348,16 @@@ struct _GstQTMu
  
    GstClockTime start_gap_threshold;
  
 +  gboolean force_create_timecode_trak;
 +
    /* for request pad naming */
    guint video_pads, audio_pads, subtitle_pads, caption_pads;
+ #ifdef TIZEN_FEATURE_GST_MUX_ENHANCEMENT
+   guint expected_trailer_size;
+   guint audio_expected_trailer_size;
+   guint video_expected_trailer_size;
+ #endif /* TIZEN_FEATURE_GST_MUX_ENHANCEMENT */  
  };
  
  struct _GstQTMuxClass
  GST_DEBUG_CATEGORY (qtdemux_debug);
  #define GST_CAT_DEFAULT qtdemux_debug
  
 -typedef struct _QtDemuxSegment QtDemuxSegment;
 -typedef struct _QtDemuxSample QtDemuxSample;
 -
  typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
 -
 -struct _QtDemuxSample
 -{
 -  guint32 size;
 -  gint32 pts_offset;            /* Add this value to timestamp to get the pts */
 -  guint64 offset;
 -  guint64 timestamp;            /* DTS In mov time */
 -  guint32 duration;             /* In mov time */
 -  gboolean keyframe;            /* TRUE when this packet is a keyframe */
 -};
 +typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo;
  
+ #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
+ typedef struct _QtDemuxSphericalMetadata QtDemuxSphericalMetadata;
+ struct _QtDemuxSphericalMetadata
+ {
+   gboolean is_spherical;
+   gboolean is_stitched;
+   char *stitching_software;
+   char *projection_type;
+   char *stereo_mode;
+   int source_count;
+   int init_view_heading;
+   int init_view_pitch;
+   int init_view_roll;
+   int timestamp;
+   int full_pano_width_pixels;
+   int full_pano_height_pixels;
+   int cropped_area_image_width;
+   int cropped_area_image_height;
+   int cropped_area_left;
+   int cropped_area_top;
+   QTDEMUX_AMBISONIC_TYPE ambisonic_type;
+   QTDEMUX_AMBISONIC_FORMAT ambisonic_format;
+   QTDEMUX_AMBISONIC_ORDER ambisonic_order;
+ };
+ #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
  /* Macros for converting to/from timescale */
  #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
  #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
@@@ -2682,12 -2888,500 +2765,481 @@@ qtdemux_parse_ftyp (GstQTDemux * qtdemu
    }
  }
  
 -static void
 -qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
 -    GstTagList * xmptaglist)
 -{
 -  /* Strip out bogus fields */
 -  if (xmptaglist) {
 -    if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
 -      gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
 -      gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
 -    } else {
 -      gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
 -    }
 -
 -    GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
 -
 -    /* prioritize native tags using _KEEP mode */
 -    gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
 -    gst_tag_list_unref (xmptaglist);
 -  }
 -}
 -
+ #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
+ static void
+ _get_int_value_from_xml_string (GstQTDemux * qtdemux,
+     const char *xml_str, const char *param_name, int *value)
+ {
+   char *value_start, *value_end, *endptr;
+   const short value_length_max = 12;
+   char init_view_ret[12];
+   int value_length = 0;
+   int i = 0;
+   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
+   if (!value_start) {
+     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
+         param_name);
+     return;
+   }
+   value_start += strlen (param_name);
+   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
+     value_start++;
+   value_end = strchr (value_start, '<');
+   if (!value_end) {
+     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
+     return;
+   }
+   value_length = value_end - value_start;
+   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
+           || (value_start[value_length - 1] == '\t')))
+     value_length--;
+   if (value_start[i] == '+' || value_start[i] == '-')
+     i++;
+   while (i < value_length) {
+     if (value_start[i] < '0' || value_start[i] > '9') {
+       GST_ERROR_OBJECT (qtdemux,
+           "error: incorrect value, integer was expected\n");
+       return;
+     }
+     i++;
+   }
+   if (value_length >= value_length_max || value_length < 1) {
+     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
+     return;
+   }
+   strncpy (init_view_ret, value_start, value_length_max);
+   init_view_ret[value_length] = '\0';
+   *value = strtol (init_view_ret, &endptr, 10);
+   if (endptr == init_view_ret) {
+     GST_ERROR_OBJECT (qtdemux, "error: no digits were found\n");
+     return;
+   }
+   return;
+ }
+ static void
+ _get_string_value_from_xml_string (GstQTDemux * qtdemux,
+     const char *xml_str, const char *param_name, char **value)
+ {
+   char *value_start, *value_end;
+   const short value_length_max = 256;
+   int value_length = 0;
+   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
+   if (!value_start) {
+     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
+         param_name);
+     return;
+   }
+   value_start += strlen (param_name);
+   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
+     value_start++;
+   value_end = strchr (value_start, '<');
+   if (!value_end) {
+     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
+     return;
+   }
+   value_length = value_end - value_start;
+   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
+           || (value_start[value_length - 1] == '\t')))
+     value_length--;
+   if (value_length >= value_length_max || value_length < 1) {
+     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
+     return;
+   }
+   *value = strndup(value_start, value_length);
+   return;
+ }
+ static void
+ _get_bool_value_from_xml_string (GstQTDemux * qtdemux,
+     const char *xml_str, const char *param_name, gboolean * value)
+ {
+   char *value_start, *value_end;
+   int value_length = 0;
+   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
+   if (!value_start) {
+     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
+         param_name);
+     return;
+   }
+   value_start += strlen (param_name);
+   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
+     value_start++;
+   value_end = strchr (value_start, '<');
+   if (!value_end) {
+     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
+     return;
+   }
+   value_length = value_end - value_start;
+   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
+           || (value_start[value_length - 1] == '\t')))
+     value_length--;
+   if (value_length < 1) {
+     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
+     return;
+   }
+   *value = g_strstr_len(value_start, value_length, "true") ? TRUE : FALSE;
+   return;
+ }
+ static void
+ _parse_spatial_video_metadata_from_xml_string (GstQTDemux * qtdemux, const char *xmlStr)
+ {
+   const char is_spherical_str[] = "<GSpherical:Spherical>";
+   const char is_stitched_str[] = "<GSpherical:Stitched>";
+   const char stitching_software_str[] = "<GSpherical:StitchingSoftware>";
+   const char projection_type_str[] = "<GSpherical:ProjectionType>";
+   const char stereo_mode_str[] = "<GSpherical:StereoMode>";
+   const char source_count_str[] = "<GSpherical:SourceCount>";
+   const char init_view_heading_str[] = "<GSpherical:InitialViewHeadingDegrees>";
+   const char init_view_pitch_str[] = "<GSpherical:InitialViewPitchDegrees>";
+   const char init_view_roll_str[] = "<GSpherical:InitialViewRollDegrees>";
+   const char timestamp_str[] = "<GSpherical:Timestamp>";
+   const char full_pano_width_str[] = "<GSpherical:FullPanoWidthPixels>";
+   const char full_pano_height_str[] = "<GSpherical:FullPanoHeightPixels>";
+   const char cropped_area_image_width_str[] =
+       "<GSpherical:CroppedAreaImageWidthPixels>";
+   const char cropped_area_image_height_str[] =
+       "<GSpherical:CroppedAreaImageHeightPixels>";
+   const char cropped_area_left_str[] = "<GSpherical:CroppedAreaLeftPixels>";
+   const char cropped_area_top_str[] = "<GSpherical:CroppedAreaTopPixels>";
+   QtDemuxSphericalMetadata * spherical_metadata = qtdemux->spherical_metadata;
+   _get_bool_value_from_xml_string (qtdemux, xmlStr, is_spherical_str,
+       (gboolean *) & spherical_metadata->is_spherical);
+   _get_bool_value_from_xml_string (qtdemux, xmlStr, is_stitched_str,
+       (gboolean *) & spherical_metadata->is_stitched);
+   if (spherical_metadata->is_spherical && spherical_metadata->is_stitched) {
+     _get_string_value_from_xml_string (qtdemux, xmlStr,
+         stitching_software_str, &spherical_metadata->stitching_software);
+     _get_string_value_from_xml_string (qtdemux, xmlStr,
+         projection_type_str, &spherical_metadata->projection_type);
+     _get_string_value_from_xml_string (qtdemux, xmlStr, stereo_mode_str,
+         &spherical_metadata->stereo_mode);
+     _get_int_value_from_xml_string (qtdemux, xmlStr, source_count_str,
+         &spherical_metadata->source_count);
+     _get_int_value_from_xml_string (qtdemux, xmlStr,
+         init_view_heading_str, &spherical_metadata->init_view_heading);
+     _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_pitch_str,
+         &spherical_metadata->init_view_pitch);
+     _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_roll_str,
+         &spherical_metadata->init_view_roll);
+     _get_int_value_from_xml_string (qtdemux, xmlStr, timestamp_str,
+         &spherical_metadata->timestamp);
+     _get_int_value_from_xml_string (qtdemux, xmlStr, full_pano_width_str,
+         &spherical_metadata->full_pano_width_pixels);
+     _get_int_value_from_xml_string (qtdemux, xmlStr,
+         full_pano_height_str, &spherical_metadata->full_pano_height_pixels);
+     _get_int_value_from_xml_string (qtdemux, xmlStr,
+         cropped_area_image_width_str,
+         &spherical_metadata->cropped_area_image_width);
+     _get_int_value_from_xml_string (qtdemux, xmlStr,
+         cropped_area_image_height_str,
+         &spherical_metadata->cropped_area_image_height);
+     _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_left_str,
+         &spherical_metadata->cropped_area_left);
+     _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_top_str,
+         &spherical_metadata->cropped_area_top);
+   }
+   return;
+ }
+ static void
+ gst_tag_register_spherical_tags (void) {
+   gst_tag_register ("is_spherical", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-spherical"),
+       _("Flag indicating if the video is a spherical video"),
+       NULL);
+   gst_tag_register ("is_stitched", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-stitched"),
+       _("Flag indicating if the video is stitched"),
+       NULL);
+   gst_tag_register ("stitching_software", GST_TAG_FLAG_META,
+       G_TYPE_STRING,
+       _("tag-stitching-software"),
+       _("Software used to stitch the spherical video"),
+       NULL);
+   gst_tag_register ("projection_type", GST_TAG_FLAG_META,
+       G_TYPE_STRING,
+       _("tag-projection-type"),
+       _("Projection type used in the video frames"),
+       NULL);
+   gst_tag_register ("stereo_mode", GST_TAG_FLAG_META,
+       G_TYPE_STRING,
+       _("tag-stereo-mode"),
+       _("Description of stereoscopic 3D layout"),
+       NULL);
+   gst_tag_register ("source_count", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-source-count"),
+       _("Number of cameras used to create the spherical video"),
+       NULL);
+   gst_tag_register ("init_view_heading", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-init-view-heading"),
+       _("The heading angle of the initial view in degrees"),
+       NULL);
+   gst_tag_register ("init_view_pitch", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-init-view-pitch"),
+       _("The pitch angle of the initial view in degrees"),
+       NULL);
+   gst_tag_register ("init_view_roll", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-init-view-roll"),
+       _("The roll angle of the initial view in degrees"),
+       NULL);
+   gst_tag_register ("timestamp", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-timestamp"),
+       _("Epoch timestamp of when the first frame in the video was recorded"),
+       NULL);
+   gst_tag_register ("full_pano_width_pixels", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-full-pano-width"),
+       _("Width of the encoded video frame in pixels"),
+       NULL);
+   gst_tag_register ("full_pano_height_pixels", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-full-pano-height"),
+       _("Height of the encoded video frame in pixels"),
+       NULL);
+   gst_tag_register ("cropped_area_image_width", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-cropped-area-image-width"),
+       _("Width of the video frame to display (e.g. cropping)"),
+       NULL);
+   gst_tag_register ("cropped_area_image_height", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-cropped-area-image-height"),
+       _("Height of the video frame to display (e.g. cropping)"),
+       NULL);
+   gst_tag_register ("cropped_area_left", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-cropped-area-left"),
+       _("Column where the left edge of the image was cropped from the"
+           " full sized panorama"),
+       NULL);
+   gst_tag_register ("cropped_area_top", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-cropped-area-top"),
+       _("Row where the top edge of the image was cropped from the"
+           " full sized panorama"),
+       NULL);
+   gst_tag_register ("ambisonic_type", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-ambisonic-type"),
+       _("Specifies the type of ambisonic audio represented"),
+       NULL);
+   gst_tag_register ("ambisonic_format", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-ambisonic-format"),
+       _("Specifies the ambisonic audio format"),
+       NULL);
+   gst_tag_register ("ambisonic_order", GST_TAG_FLAG_META,
+       G_TYPE_INT,
+       _("tag-ambisonic-order"),
+       _("Specifies the ambisonic audio channel order"),
+       NULL);
+   return;
+ }
+ static void
+ _send_spherical_metadata_msg_to_bus (GstQTDemux * qtdemux)
+ {
+   GstTagList *taglist;
+   QtDemuxSphericalMetadata *spherical_metadata = qtdemux->spherical_metadata;
+   GST_DEBUG_OBJECT (qtdemux, "is_spherical = %d",
+       spherical_metadata->is_spherical);
+   GST_DEBUG_OBJECT (qtdemux, "is_stitched = %d",
+       spherical_metadata->is_stitched);
+   GST_DEBUG_OBJECT (qtdemux, "stitching_software = %s",
+       spherical_metadata->stitching_software);
+   GST_DEBUG_OBJECT (qtdemux, "projection_type = %s",
+       spherical_metadata->projection_type);
+   GST_DEBUG_OBJECT (qtdemux, "stereo_mode = %s",
+       spherical_metadata->stereo_mode);
+   GST_DEBUG_OBJECT (qtdemux, "source_count %d",
+       spherical_metadata->source_count);
+   GST_DEBUG_OBJECT (qtdemux, "init_view_heading = %d",
+       spherical_metadata->init_view_heading);
+   GST_DEBUG_OBJECT (qtdemux, "init_view_pitch = %d",
+       spherical_metadata->init_view_pitch);
+   GST_DEBUG_OBJECT (qtdemux, "init_view_roll = %d",
+       spherical_metadata->init_view_roll);
+   GST_DEBUG_OBJECT (qtdemux, "timestamp = %d", spherical_metadata->timestamp);
+   GST_DEBUG_OBJECT (qtdemux, "full_pano_width_pixels = %d",
+       spherical_metadata->full_pano_width_pixels);
+   GST_DEBUG_OBJECT (qtdemux, "full_pano_height_pixels = %d",
+       spherical_metadata->full_pano_height_pixels);
+   GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_width = %d",
+       spherical_metadata->cropped_area_image_width);
+   GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_height = %d",
+       spherical_metadata->cropped_area_image_height);
+   GST_DEBUG_OBJECT (qtdemux, "cropped_area_left = %d",
+       spherical_metadata->cropped_area_left);
+   GST_DEBUG_OBJECT (qtdemux, "cropped_area_top = %d",
+       spherical_metadata->cropped_area_top);
+   GST_DEBUG_OBJECT (qtdemux, "ambisonic_type = %d",
+       spherical_metadata->ambisonic_type);
+   GST_DEBUG_OBJECT (qtdemux, "ambisonic_order = %d",
+       spherical_metadata->ambisonic_order);
+   GST_DEBUG_OBJECT (qtdemux, "ambisonic_format = %d",
+       spherical_metadata->ambisonic_format);
+   taglist = gst_tag_list_new_empty ();
+   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
+       "is_spherical", spherical_metadata->is_spherical,
+       "is_stitched", spherical_metadata->is_stitched,
+       "source_count", spherical_metadata->source_count,
+       "init_view_heading", spherical_metadata->init_view_heading,
+       "init_view_pitch", spherical_metadata->init_view_pitch,
+       "init_view_roll", spherical_metadata->init_view_roll,
+       "timestamp", spherical_metadata->timestamp,
+       "full_pano_width_pixels", spherical_metadata->full_pano_width_pixels,
+       "full_pano_height_pixels", spherical_metadata->full_pano_height_pixels,
+       "cropped_area_image_width", spherical_metadata->cropped_area_image_width,
+       "cropped_area_image_height", spherical_metadata->cropped_area_image_height,
+       "cropped_area_left", spherical_metadata->cropped_area_left,
+       "cropped_area_top", spherical_metadata->cropped_area_top,
+       "ambisonic_type", spherical_metadata->ambisonic_type,
+       "ambisonic_format", spherical_metadata->ambisonic_format,
+       "ambisonic_order", spherical_metadata->ambisonic_order,
+       NULL);
+   if (spherical_metadata->stitching_software)
+     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
+         "stitching_software", spherical_metadata->stitching_software,
+         NULL);
+   if (spherical_metadata->projection_type)
+     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
+         "projection_type", spherical_metadata->projection_type,
+         NULL);
+   if (spherical_metadata->stereo_mode)
+     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
+         "stereo_mode", spherical_metadata->stereo_mode,
+         NULL);
+   gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
+           gst_message_new_tag (GST_OBJECT_CAST (qtdemux),
+                   gst_tag_list_copy (taglist)));
+   gst_tag_list_unref(taglist);
+   return;
+ }
+ static void
+ qtdemux_parse_SA3D (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
+ {
+   guint offset = 0;
+   guint8 version = 0;
+   guint8 ambisonic_type  = 0;
+   guint32 ambisonic_order = 0;
+   guint8 ambisonic_channel_ordering = 0;
+   guint8 ambisonic_normalization = 0;
+   guint32 num_channels = 0;
+   guint32 channel_map[49] = { 0 };      /* Up to 6th order */
+   int i;
+   GST_DEBUG_OBJECT (qtdemux, "qtdemux_parse_SA3D");
+   qtdemux->header_size += length;
+   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
+   if (length <= offset + 16) {
+     GST_DEBUG_OBJECT (qtdemux, "SA3D atom is too short, skipping");
+     return;
+   }
+   version = QT_UINT8 (buffer + offset);
+   ambisonic_type = QT_UINT8 (buffer + offset + 1);
+   ambisonic_order = QT_UINT32 (buffer + offset + 2);
+   ambisonic_channel_ordering = QT_UINT8 (buffer + offset + 6);
+   ambisonic_normalization = QT_UINT8 (buffer + offset + 7);
+   num_channels = QT_UINT32 (buffer + offset + 8);
+   for (i = 0; i < num_channels; ++i)
+     channel_map[i] = QT_UINT32 (buffer + offset + 12 + i * 4);
+   GST_DEBUG_OBJECT (qtdemux, "version: %d", version);
+   GST_DEBUG_OBJECT (qtdemux, "ambisonic_type: %d", ambisonic_type);
+   GST_DEBUG_OBJECT (qtdemux, "ambisonic_order: %d", ambisonic_order);
+   GST_DEBUG_OBJECT (qtdemux, "ambisonic_channel_ordering: %d",
+       ambisonic_channel_ordering);
+   GST_DEBUG_OBJECT (qtdemux, "ambisonic_normalization: %d",
+       ambisonic_normalization);
+   GST_DEBUG_OBJECT (qtdemux, "num_channels: %d", num_channels);
+   for (i = 0; i < num_channels; ++i)
+     GST_DEBUG_OBJECT (qtdemux, "channel_map: %d", channel_map[i]);
+   if (version == RFC_AMBISONIC_SA3DBOX_VERSION_SUPPORTED) {
+     if (ambisonic_type == RFC_AMBISONIC_TYPE_PERIPHONIC)
+       qtdemux->spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_PERIPHONIC;
+     if (ambisonic_order == RFC_AMBISONIC_ORDER_FOA) {
+       if (num_channels == 4) {
+         qtdemux->spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_FOA;
+         if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN)
+             && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D)
+             && (channel_map[0] == 0) && (channel_map[1] == 1)
+             && (channel_map[2] == 2) && (channel_map[3] == 3))
+           qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMBIX;
+         if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA)
+             && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA)
+             && (channel_map[0] == 0) && (channel_map[1] == 3)
+             && (channel_map[2] == 1) && (channel_map[3] == 2))
+           qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMB;
+       }
+     }
+   }
+   return;
+ }
+ #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
  static void
 -qtdemux_update_default_sample_encryption_settings (GstQTDemux * qtdemux,
 -    QtDemuxCencSampleSetInfo * info, guint32 is_encrypted, guint8 iv_size,
 -    const guint8 * kid)
 +qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
 +    QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
 +    guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
 +    guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
 +    const guint8 * constant_iv)
  {
    GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
    gst_buffer_fill (kid_buf, 0, kid, 16);
@@@ -13088,9 -13278,12 +13700,12 @@@ static GstFlowRetur
  qtdemux_prepare_streams (GstQTDemux * qtdemux)
  {
    GstFlowReturn ret = GST_FLOW_OK;
+ #ifdef TIZEN_FEATURE_QTDEMUX_DURATION
+   guint64 tkhd_max_duration = 0;
+ #endif
    gint i;
  
 -  GST_DEBUG_OBJECT (qtdemux, "prepare streams");
 +  GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
  
    for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
      QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
  
      /* parse the initial sample for use in setting the frame rate cap */
      while (sample_num == 0 && sample_num < stream->n_samples) {
 -      if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
 -        break;
 -      ++sample_num;
 -    }
 -  }
 -
 -#ifdef TIZEN_FEATURE_QTDEMUX_DURATION
 -  if (!qtdemux->fragmented && (qtdemux->duration > tkhd_max_duration)) {
 -    GST_INFO_OBJECT (qtdemux,
 -        "Update duration: %" G_GUINT64_FORMAT " -> %" G_GUINT64_FORMAT,
 -        qtdemux->duration, tkhd_max_duration);
 -    qtdemux->duration = tkhd_max_duration;
 -  }
 -#endif
 -
 -  return ret;
 -}
 -
 -static gboolean
 -_stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
 -{
 -  return g_strcmp0 (stream->stream_id, stream_id) == 0;
 -}
 -
 -static gboolean
 -qtdemux_is_streams_update (GstQTDemux * qtdemux)
 -{
 -  gint i;
 -
 -  /* Different length, updated */
 -  if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
 -    return TRUE;
 -
 -  /* streams in list are sorted in track-id order */
 -  for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
 -    /* Different stream-id, updated */
 -    if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
 -            QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
 -      return TRUE;
 -  }
 -
 -  return FALSE;
 -}
 -
 -static gboolean
 -qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
 -    QtDemuxStream * oldstream, QtDemuxStream * newstream)
 -{
 -  /* Connect old stream's srcpad to new stream */
 -  newstream->pad = oldstream->pad;
 -  oldstream->pad = NULL;
 -
 -  /* unset new_stream to prevent stream-start event */
 -  newstream->new_stream = FALSE;
 -
 -  return gst_qtdemux_configure_stream (qtdemux, newstream);
 -}
 -
 -/* g_ptr_array_find_with_equal_func is available since 2.54,
 - * replacement until we can depend unconditionally on the real one in GLib */
 -#if !GLIB_CHECK_VERSION(2,54,0)
 -#define g_ptr_array_find_with_equal_func qtdemux_ptr_array_find_with_equal_func
 -static gboolean
 -qtdemux_ptr_array_find_with_equal_func (GPtrArray * haystack,
 -    gconstpointer needle, GEqualFunc equal_func, guint * index_)
 -{
 -  guint i;
 -
 -  g_return_val_if_fail (haystack != NULL, FALSE);
 -
 -  if (equal_func == NULL)
 -    equal_func = g_direct_equal;
 -
 -  for (i = 0; i < haystack->len; i++) {
 -    if (equal_func (g_ptr_array_index (haystack, i), needle)) {
 -      if (index_ != NULL)
 -        *index_ = i;
 -      return TRUE;
 -    }
 -  }
 -
 -  return FALSE;
 -}
 -#endif
 -
 -static gboolean
 -qtdemux_update_streams (GstQTDemux * qtdemux)
 -{
 -  gint i;
 -  g_assert (qtdemux->streams_aware);
 -
 -  /* At below, figure out which stream in active_streams has identical stream-id
 -   * with that of in old_streams. If there is matching stream-id,
 -   * corresponding newstream will not be exposed again,
 -   * but demux will reuse srcpad of matched old stream
 -   *
 -   * active_streams : newly created streams from the latest moov
 -   * old_streams : existing streams (belong to previous moov)
 -   */
 -
 -  for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
 -    QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
 -    QtDemuxStream *oldstream = NULL;
 -    guint target;
 -
 -    GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
 -        stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
 -
 -    if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
 -            stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
 -      oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
 -
 -      /* null pad stream cannot be reused */
 -      if (oldstream->pad == NULL)
 -        oldstream = NULL;
 -    }
 -
 -    if (oldstream) {
 -      GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
 -
 -      if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
 -        return FALSE;
 -
 -      /* we don't need to preserve order of old streams */
 -      g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
 -    } else {
 -      GstTagList *list;
 -
 -      /* now we have all info and can expose */
 -      list = stream->stream_tags;
 -      stream->stream_tags = NULL;
 -      if (!gst_qtdemux_add_stream (qtdemux, stream, list))
 -        return FALSE;
 -    }
 -  }
 -
 -  return TRUE;
 -}
 -
 -/* Must be called with expose lock */
 -static GstFlowReturn
 -qtdemux_expose_streams (GstQTDemux * qtdemux)
 -{
 -  gint i;
 -
 -  GST_DEBUG_OBJECT (qtdemux, "exposing streams");
 -
 -  if (!qtdemux_is_streams_update (qtdemux)) {
 -    GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
 -    for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
 -      QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
 -      QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
 -      if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
 -        return GST_FLOW_ERROR;
 -    }
 -
 -    g_ptr_array_set_size (qtdemux->old_streams, 0);
 -    qtdemux->need_segment = TRUE;
 -
 -    return GST_FLOW_OK;
 -  }
 -
 -  if (qtdemux->streams_aware) {
 -    if (!qtdemux_update_streams (qtdemux))
 -      return GST_FLOW_ERROR;
 -  } else {
 -    for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
 -      QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
 -      GstTagList *list;
 -
 -      /* now we have all info and can expose */
 -      list = stream->stream_tags;
 -      stream->stream_tags = NULL;
 -      if (!gst_qtdemux_add_stream (qtdemux, stream, list))
 -        return GST_FLOW_ERROR;
 -
 -    }
 -  }
 -
 -  gst_qtdemux_guess_bitrate (qtdemux);
 -
 -  gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
 -
 -  /* If we have still old_streams, it's no more used stream */
 -  for (i = 0; i < qtdemux->old_streams->len; i++) {
 -    QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
 -
 -    if (stream->pad) {
 -      GstEvent *event;
 -
 -      event = gst_event_new_eos ();
 -      if (qtdemux->segment_seqnum)
 -        gst_event_set_seqnum (event, qtdemux->segment_seqnum);
 -
 -      gst_pad_push_event (stream->pad, event);
 -    }
 -  }
 -
 -  g_ptr_array_set_size (qtdemux->old_streams, 0);
 -
 -  /* check if we should post a redirect in case there is a single trak
 -   * and it is a redirecting trak */
 -  if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
 -      QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
 -    GstMessage *m;
 -
 -    GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
 -        "an external content");
 -    m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
 -        gst_structure_new ("redirect",
 -            "new-location", G_TYPE_STRING,
 -            QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
 -    gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
 -    qtdemux->posted_redirect = TRUE;
 -  }
 -
 -  g_ptr_array_foreach (qtdemux->active_streams,
 -      (GFunc) qtdemux_do_allocation, qtdemux);
 -
 -  qtdemux->need_segment = TRUE;
 -
 -  qtdemux->exposed = TRUE;
 -  return GST_FLOW_OK;
 -}
 -
 -/* check if major or compatible brand is 3GP */
 -static inline gboolean
 -qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
 -{
 -  if (major) {
 -    return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
 -        FOURCC_3g__);
 -  } else if (qtdemux->comp_brands != NULL) {
 -    GstMapInfo map;
 -    guint8 *data;
 -    gsize size;
 -    gboolean res = FALSE;
 -
 -    gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
 -    data = map.data;
 -    size = map.size;
 -    while (size >= 4) {
 -      res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
 -          FOURCC_3g__);
 -      data += 4;
 -      size -= 4;
 -    }
 -    gst_buffer_unmap (qtdemux->comp_brands, &map);
 -    return res;
 -  } else {
 -    return FALSE;
 -  }
 -}
 -
 -/* check if tag is a spec'ed 3GP tag keyword storing a string */
 -static inline gboolean
 -qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
 -{
 -  return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
 -      || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
 -      || fourcc == FOURCC_albm;
 -}
 -
 -static void
 -qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
 -    const char *tag, const char *dummy, GNode * node)
 -{
 -  const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
 -  int offset;
 -  char *name;
 -  gchar *data;
 -  gdouble longitude, latitude, altitude;
 -  gint len;
 -
 -  len = QT_UINT32 (node->data);
 -  if (len <= 14)
 -    goto short_read;
 -
 -  data = node->data;
 -  offset = 14;
 -
 -  /* TODO: language code skipped */
 -
 -  name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
 -
 -  if (!name) {
 -    /* do not alarm in trivial case, but bail out otherwise */
 -    if (*(data + offset) != 0) {
 -      GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
 -          "giving up", tag);
 -    }
 -  } else {
 -    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
 -        GST_TAG_GEO_LOCATION_NAME, name, NULL);
 -    offset += strlen (name);
 -    g_free (name);
 -  }
 -
 -  if (len < offset + 2 + 4 + 4 + 4)
 -    goto short_read;
 -
 -  /* +1 +1 = skip null-terminator and location role byte */
 -  offset += 1 + 1;
 -  /* table in spec says unsigned, semantics say negative has meaning ... */
 -  longitude = QT_SFP32 (data + offset);
 -
 -  offset += 4;
 -  latitude = QT_SFP32 (data + offset);
 -
 -  offset += 4;
 -  altitude = QT_SFP32 (data + offset);
 -
 -  /* one invalid means all are invalid */
 -  if (longitude >= -180.0 && longitude <= 180.0 &&
 -      latitude >= -90.0 && latitude <= 90.0) {
 -    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
 -        GST_TAG_GEO_LOCATION_LATITUDE, latitude,
 -        GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
 -        GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
 -  }
 -
 -  /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
 -
 -  return;
 -
 -  /* ERRORS */
 -short_read:
 -  {
 -    GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
 -    return;
 -  }
 -}
 -
 -
 -static void
 -qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
 -    const char *tag, const char *dummy, GNode * node)
 -{
 -  guint16 y;
 -  GDate *date;
 -  gint len;
 -
 -  len = QT_UINT32 (node->data);
 -  if (len < 14)
 -    return;
 -
 -  y = QT_UINT16 ((guint8 *) node->data + 12);
 -  if (y == 0) {
 -    GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
 -    return;
 -  }
 -  GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
 -
 -  date = g_date_new_dmy (1, 1, y);
 -  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
 -  g_date_free (date);
 -}
 -
 -static void
 -qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
 -    const char *tag, const char *dummy, GNode * node)
 -{
 -  int offset;
 -  char *tag_str = NULL;
 -  guint8 *entity;
 -  guint16 table;
 -  gint len;
 -
 -  len = QT_UINT32 (node->data);
 -  if (len <= 20)
 -    goto short_read;
 -
 -  offset = 12;
 -  entity = (guint8 *) node->data + offset;
 -  if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
 -    GST_DEBUG_OBJECT (qtdemux,
 -        "classification info: %c%c%c%c invalid classification entity",
 -        entity[0], entity[1], entity[2], entity[3]);
 -    return;
 -  }
 -
 -  offset += 4;
 -  table = QT_UINT16 ((guint8 *) node->data + offset);
 -
 -  /* Language code skipped */
 -
 -  offset += 4;
 -
 -  /* Tag format: "XXXX://Y[YYYY]/classification info string"
 -   * XXXX: classification entity, fixed length 4 chars.
 -   * Y[YYYY]: classification table, max 5 chars.
 -   */
 -  tag_str = g_strdup_printf ("----://%u/%s",
 -      table, (char *) node->data + offset);
 -
 -  /* memcpy To be sure we're preserving byte order */
 -  memcpy (tag_str, entity, 4);
 -  GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
 -
 -  gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
 -
 -  g_free (tag_str);
 -
 -  return;
 -
 -  /* ERRORS */
 -short_read:
 -  {
 -    GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
 -    return;
 -  }
 -}
 -
 -static gboolean
 -qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
 -    const char *tag, const char *dummy, GNode * node)
 -{
 -  const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
 -  GNode *data;
 -  char *s;
 -  int len;
 -  guint32 type;
 -  int offset;
 -  gboolean ret = TRUE;
 -  const gchar *charset = NULL;
 -
 -  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
 -  if (data) {
 -    len = QT_UINT32 (data->data);
 -    type = QT_UINT32 ((guint8 *) data->data + 8);
 -    if (type == 0x00000001 && len > 16) {
 -      s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
 -          env_vars);
 -      if (s) {
 -        GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
 -        gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
 -        g_free (s);
 -      } else {
 -        GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
 -      }
 -    }
 -  } else {
 -    len = QT_UINT32 (node->data);
 -    type = QT_UINT32 ((guint8 *) node->data + 4);
 -    if ((type >> 24) == 0xa9 && len > 8 + 4) {
 -      gint str_len;
 -      gint lang_code;
 -
 -      /* Type starts with the (C) symbol, so the next data is a list
 -       * of (string size(16), language code(16), string) */
 -
 -      str_len = QT_UINT16 ((guint8 *) node->data + 8);
 -      lang_code = QT_UINT16 ((guint8 *) node->data + 10);
 -
 -      /* the string + fourcc + size + 2 16bit fields,
 -       * means that there are more tags in this atom */
 -      if (len > str_len + 8 + 4) {
 -        /* TODO how to represent the same tag in different languages? */
 -        GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
 -            "text alternatives, reading only first one");
 -      }
 -
 -      offset = 12;
 -      len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
 -      GST_DEBUG_OBJECT (qtdemux, "found international text tag");
 -
 -      if (lang_code < 0x800) {  /* MAC encoded string */
 -        charset = "mac";
 -      }
 -    } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
 -            QT_FOURCC ((guint8 *) node->data + 4))) {
 -      guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
 -
 -      /* we go for 3GP style encoding if major brands claims so,
 -       * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
 -      if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
 -          (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
 -              ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
 -        offset = 14;
 -        /* 16-bit Language code is ignored here as well */
 -        GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
 -      } else {
 -        goto normal;
 -      }
 -    } else {
 -    normal:
 -      offset = 8;
 -      GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
 -      ret = FALSE;              /* may have to fallback */
 -    }
 -    if (charset) {
 -      GError *err = NULL;
 -
 -      s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
 -          charset, NULL, NULL, &err);
 -      if (err) {
 -        GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
 -            " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
 -            err->message);
 -        g_error_free (err);
 -      }
 -    } else {
 -      s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
 -          len - offset, env_vars);
 -    }
 -    if (s) {
 -      GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
 -      gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
 -      g_free (s);
 -      ret = TRUE;
 -    } else {
 -      GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
 -    }
 -  }
 -  return ret;
 -}
 -
 -static void
 -qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
 -    const char *tag, const char *dummy, GNode * node)
 -{
 -  qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
 -}
 -
 -static void
 -qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
 -    const char *tag, const char *dummy, GNode * node)
 -{
 -  const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
 -  guint8 *data;
 -  char *s, *t, *k = NULL;
 -  int len;
 -  int offset;
 -  int count;
 -
 -  /* first try normal string tag if major brand not 3GP */
 -  if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
 -    if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
 -      /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
 -       * let's try it 3gpp way after minor safety check */
 -      data = node->data;
 -      if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
 -        return;
 -    } else
 -      return;
 -  }
 -
 -  GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
 -
 -  data = node->data;
 -
 -  len = QT_UINT32 (data);
 -  if (len < 15)
 -    goto short_read;
 -
 -  count = QT_UINT8 (data + 14);
 -  offset = 15;
 -  for (; count; count--) {
 -    gint slen;
 -
 -    if (offset + 1 > len)
 -      goto short_read;
 -    slen = QT_UINT8 (data + offset);
 -    offset += 1;
 -    if (offset + slen > len)
 -      goto short_read;
 -    s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
 -        slen, env_vars);
 -    if (s) {
 -      GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
 -      if (k) {
 -        t = g_strjoin (",", k, s, NULL);
 -        g_free (s);
 -        g_free (k);
 -        k = t;
 -      } else {
 -        k = s;
 -      }
 -    } else {
 -      GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
 -    }
 -    offset += slen;
 -  }
 -
 -done:
 -  if (k) {
 -    GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
 -    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
 -  }
 -  g_free (k);
 -
 -  return;
 -
 -  /* ERRORS */
 -short_read:
 -  {
 -    GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
 -    goto done;
 -  }
 -}
 -
 -static void
 -qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
 -    const char *tag1, const char *tag2, GNode * node)
 -{
 -  GNode *data;
 -  int len;
 -  int type;
 -  int n1, n2;
 -
 -  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
 -  if (data) {
 -    len = QT_UINT32 (data->data);
 -    type = QT_UINT32 ((guint8 *) data->data + 8);
 -    if (type == 0x00000000 && len >= 22) {
 -      n1 = QT_UINT16 ((guint8 *) data->data + 18);
 -      n2 = QT_UINT16 ((guint8 *) data->data + 20);
 -      if (n1 > 0) {
 -        GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
 -        gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
 -      }
 -      if (n2 > 0) {
 -        GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
 -        gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
 -      }
 -    }
 -  }
 -}
 -
 -static void
 -qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
 -    const char *tag1, const char *dummy, GNode * node)
 -{
 -  GNode *data;
 -  int len;
 -  int type;
 -  int n1;
 -
 -  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
 -  if (data) {
 -    len = QT_UINT32 (data->data);
 -    type = QT_UINT32 ((guint8 *) data->data + 8);
 -    GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
 -    /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
 -    if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
 -      n1 = QT_UINT16 ((guint8 *) data->data + 16);
 -      if (n1) {
 -        /* do not add bpm=0 */
 -        GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
 -        gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
 -            NULL);
 -      }
 -    }
 -  }
 -}
 -
 -static void
 -qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
 -    const char *tag1, const char *dummy, GNode * node)
 -{
 -  GNode *data;
 -  int len;
 -  int type;
 -  guint32 num;
 -
 -  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
 -  if (data) {
 -    len = QT_UINT32 (data->data);
 -    type = QT_UINT32 ((guint8 *) data->data + 8);
 -    GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
 -    /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
 -    if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
 -      num = QT_UINT32 ((guint8 *) data->data + 16);
 -      if (num) {
 -        /* do not add num=0 */
 -        GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
 -        gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
 -      }
 -    }
 -  }
 -}
 -
 -static void
 -qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
 -    const char *tag1, const char *dummy, GNode * node)
 -{
 -  GNode *data;
 -  int len;
 -  int type;
 -  GstSample *sample;
 -
 -  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
 -  if (data) {
 -    len = QT_UINT32 (data->data);
 -    type = QT_UINT32 ((guint8 *) data->data + 8);
 -    GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
 -    if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
 -      GstTagImageType image_type;
 -
 -      if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
 -        image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
 -      else
 -        image_type = GST_TAG_IMAGE_TYPE_NONE;
 -
 -      if ((sample =
 -              gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
 -                  len - 16, image_type))) {
 -        GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
 -        gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
 -        gst_sample_unref (sample);
 -      }
 +      if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
 +        break;
 +      ++sample_num;
      }
    }
 +
++#ifdef TIZEN_FEATURE_QTDEMUX_DURATION
++  if (!qtdemux->fragmented && (qtdemux->duration > tkhd_max_duration)) {
++    GST_INFO_OBJECT (qtdemux,
++        "Update duration: %" G_GUINT64_FORMAT " -> %" G_GUINT64_FORMAT,
++        qtdemux->duration, tkhd_max_duration);
++    qtdemux->duration = tkhd_max_duration;
++  }
++#endif
++
 +  return ret;
  }
  
 -static void
 -qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
 -    const char *tag, const char *dummy, GNode * node)
 +static gboolean
 +_stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
  {
 -  GNode *data;
 -  GstDateTime *datetime = NULL;
 -  char *s;
 -  int len;
 -  int type;
 -
 -  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
 -  if (data) {
 -    len = QT_UINT32 (data->data);
 -    type = QT_UINT32 ((guint8 *) data->data + 8);
 -    if (type == 0x00000001 && len > 16) {
 -      guint y, m = 1, d = 1;
 -      gint ret;
 -
 -      s = g_strndup ((char *) data->data + 16, len - 16);
 -      GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
 -      datetime = gst_date_time_new_from_iso8601_string (s);
 -      if (datetime != NULL) {
 -        gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME,
 -            datetime, NULL);
 -        gst_date_time_unref (datetime);
 -      }
 -
 -      ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
 -      if (ret >= 1 && y > 1500 && y < 3000) {
 -        GDate *date;
 -
 -        date = g_date_new_dmy (d, m, y);
 -        gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
 -        g_date_free (date);
 -      } else {
 -        GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
 -      }
 -      g_free (s);
 -    }
 -  }
 +  return g_strcmp0 (stream->stream_id, stream_id) == 0;
  }
  
 -static void
 -qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
 -    const char *tag, const char *dummy, GNode * node)
 +static gboolean
 +qtdemux_is_streams_update (GstQTDemux * qtdemux)
  {
 -  GNode *data;
 +  gint i;
  
 -  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
 +  /* Different length, updated */
 +  if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
 +    return TRUE;
  
 -  /* re-route to normal string tag if major brand says so
 -   * or no data atom and compatible brand suggests so */
 -  if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
 -      (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
 -    qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
 -    return;
 +  /* streams in list are sorted in track-id order */
 +  for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
 +    /* Different stream-id, updated */
 +    if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
 +            QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
 +      return TRUE;
    }
  
 -  if (data) {
 -    guint len, type, n;
 -
 -    len = QT_UINT32 (data->data);
 -    type = QT_UINT32 ((guint8 *) data->data + 8);
 -    if (type == 0x00000000 && len >= 18) {
 -      n = QT_UINT16 ((guint8 *) data->data + 16);
 -      if (n > 0) {
 -        const gchar *genre;
 -
 -        genre = gst_tag_id3_genre_get (n - 1);
 -        if (genre != NULL) {
 -          GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
 -          gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
 -        }
 -      }
 -    }
 -  }
 +  return FALSE;
  }
  
 -static void
 -qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
 -    const gchar * tag, guint8 * data, guint32 datasize)
 +static gboolean
 +qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
 +    QtDemuxStream * oldstream, QtDemuxStream * newstream)
  {
 -  gdouble value;
 -  gchar *datacopy;
 +  /* Connect old stream's srcpad to new stream */
 +  newstream->pad = oldstream->pad;
 +  oldstream->pad = NULL;
  
 -  /* make a copy to have \0 at the end */
 -  datacopy = g_strndup ((gchar *) data, datasize);
 +  /* unset new_stream to prevent stream-start event, unless we are EOS in which
 +   * case we need to force one through */
 +  newstream->new_stream = GST_PAD_IS_EOS (newstream->pad);
  
 -  /* convert the str to double */
 -  if (sscanf (datacopy, "%lf", &value) == 1) {
 -    GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
 -    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
 -  } else {
 -    GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
 -        datacopy);
 -  }
 -  g_free (datacopy);
 +  return gst_qtdemux_configure_stream (qtdemux, newstream);
  }
  
 +static gboolean
 +qtdemux_update_streams (GstQTDemux * qtdemux)
 +{
 +  gint i;
 +  g_assert (qtdemux->streams_aware);
  
 -static void
 -qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
 -    const char *tag, const char *tag_bis, GNode * node)
 -{
 -  GNode *mean;
 -  GNode *name;
 -  GNode *data;
 -  guint32 meansize;
 -  guint32 namesize;
 -  guint32 datatype;
 -  guint32 datasize;
 -  const gchar *meanstr;
 -  const gchar *namestr;
 -
 -  /* checking the whole ---- atom size for consistency */
 -  if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
 -    GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
 -    return;
 -  }
 -
 -  mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
 -  if (!mean) {
 -    GST_WARNING_OBJECT (demux, "No 'mean' atom found");
 -    return;
 -  }
 -
 -  meansize = QT_UINT32 (mean->data);
 -  if (meansize <= 12) {
 -    GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
 -    return;
 -  }
 -  meanstr = ((gchar *) mean->data) + 12;
 -  meansize -= 12;
 +  /* At below, figure out which stream in active_streams has identical stream-id
 +   * with that of in old_streams. If there is matching stream-id,
 +   * corresponding newstream will not be exposed again,
 +   * but demux will reuse srcpad of matched old stream
 +   *
 +   * active_streams : newly created streams from the latest moov
 +   * old_streams : existing streams (belong to previous moov)
 +   */
  
 -  name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
 -  if (!name) {
 -    GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
 -    return;
 -  }
 +  for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
 +    QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
 +    QtDemuxStream *oldstream = NULL;
 +    guint target;
  
 -  namesize = QT_UINT32 (name->data);
 -  if (namesize <= 12) {
 -    GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
 -    return;
 -  }
 -  namestr = ((gchar *) name->data) + 12;
 -  namesize -= 12;
 +    GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
 +        stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
  
 -  /*
 -   * Data atom is:
 -   * uint32 - size
 -   * uint32 - name
 -   * uint8  - version
 -   * uint24 - data type
 -   * uint32 - all 0
 -   * rest   - the data
 -   */
 -  data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
 -  if (!data) {
 -    GST_WARNING_OBJECT (demux, "No data atom in this tag");
 -    return;
 -  }
 -  datasize = QT_UINT32 (data->data);
 -  if (datasize <= 16) {
 -    GST_WARNING_OBJECT (demux, "Data atom too small");
 -    return;
 -  }
 -  datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
 +    if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
 +            stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
 +      oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
  
 -  if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
 -      (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
 -    static const struct
 -    {
 -      const gchar name[28];
 -      const gchar tag[28];
 -    } tags[] = {
 -      {
 -      "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
 -      "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
 -      "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
 -      "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
 -      "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
 -      "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
 -      "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
 -      "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
 -    };
 -    int i;
 -
 -    for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
 -      if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
 -        switch (gst_tag_get_type (tags[i].tag)) {
 -          case G_TYPE_DOUBLE:
 -            qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
 -                ((guint8 *) data->data) + 16, datasize - 16);
 -            break;
 -          case G_TYPE_STRING:
 -            qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
 -            break;
 -          default:
 -            /* not reached */
 -            break;
 -        }
 -        break;
 -      }
 +      /* null pad stream cannot be reused */
 +      if (oldstream->pad == NULL)
 +        oldstream = NULL;
      }
 -    if (i == G_N_ELEMENTS (tags))
 -      goto unknown_tag;
 -  } else {
 -    goto unknown_tag;
 -  }
 -
 -  return;
  
 -/* errors */
 -unknown_tag:
 -#ifndef GST_DISABLE_GST_DEBUG
 -  {
 -    gchar *namestr_dbg;
 -    gchar *meanstr_dbg;
 +    if (oldstream) {
 +      GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
  
 -    meanstr_dbg = g_strndup (meanstr, meansize);
 -    namestr_dbg = g_strndup (namestr, namesize);
 +      if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
 +        return FALSE;
  
 -    GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
 -        "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
 +      /* we don't need to preserve order of old streams */
 +      g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
 +    } else {
 +      GstTagList *list;
  
 -    g_free (namestr_dbg);
 -    g_free (meanstr_dbg);
 +      /* now we have all info and can expose */
 +      list = stream->stream_tags;
 +      stream->stream_tags = NULL;
 +      if (!gst_qtdemux_add_stream (qtdemux, stream, list))
 +        return FALSE;
 +    }
    }
 -#endif
 -  return;
 +
 +  return TRUE;
  }
  
 -static void
 -qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
 -    const char *tag_bis, GNode * node)
 +/* Must be called with expose lock */
 +static GstFlowReturn
 +qtdemux_expose_streams (GstQTDemux * qtdemux)
  {
 -  guint8 *data;
 -  GstBuffer *buf;
 -  guint len;
 -  GstTagList *id32_taglist = NULL;
 -
 -  GST_LOG_OBJECT (demux, "parsing ID32");
 +  gint i;
  
 -  data = node->data;
 -  len = GST_READ_UINT32_BE (data);
 +  GST_DEBUG_OBJECT (qtdemux, "exposing streams");
  
 -  /* need at least full box and language tag */
 -  if (len < 12 + 2)
 -    return;
 +  if (!qtdemux_is_streams_update (qtdemux)) {
 +    GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
 +    for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
 +      QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
 +      QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
 +      if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
 +        return GST_FLOW_ERROR;
 +    }
  
 -  buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
 -  gst_buffer_fill (buf, 0, data + 14, len - 14);
 +    g_ptr_array_set_size (qtdemux->old_streams, 0);
 +    qtdemux->need_segment = TRUE;
  
 -  id32_taglist = gst_tag_list_from_id3v2_tag (buf);
 -  if (id32_taglist) {
 -    GST_LOG_OBJECT (demux, "parsing ok");
 -    gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
 -    gst_tag_list_unref (id32_taglist);
 -  } else {
 -    GST_LOG_OBJECT (demux, "parsing failed");
 +    return GST_FLOW_OK;
    }
  
 -  gst_buffer_unref (buf);
 -}
 -
 -typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
 -    const char *tag, const char *tag_bis, GNode * node);
 -
 -/* unmapped tags
 -FOURCC_pcst -> if media is a podcast -> bool
 -FOURCC_cpil -> if media is part of a compilation -> bool
 -FOURCC_pgap -> if media is part of a gapless context -> bool
 -FOURCC_tven -> the tv episode id e.g. S01E23 -> str
 -*/
 -
 -static const struct
 -{
 -  guint32 fourcc;
 -  const gchar *gst_tag;
 -  const gchar *gst_tag_bis;
 -  const GstQTDemuxAddTagFunc func;
 -} add_funcs[] = {
 -  {
 -  FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
 -  FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
 -  FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
 -  FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
 -  FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
 -  FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
 -  FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
 -  FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
 -  FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
 -  FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
 -  FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
 -  FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
 -  FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
 -  FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
 -        qtdemux_tag_add_num}, {
 -  FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
 -        qtdemux_tag_add_num}, {
 -  FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
 -  FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
 -  FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
 -  FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
 -  FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
 -  FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
 -  FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
 -  FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
 -  FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
 -  FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
 -        qtdemux_tag_add_classification}, {
 -  FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
 -  FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
 -  FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
 -
 -    /* This is a special case, some tags are stored in this
 -     * 'reverse dns naming', according to:
 -     * http://atomicparsley.sourceforge.net/mpeg-4files.html and
 -     * bug #614471
 -     */
 -  FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
 -    /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
 -  FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
 -};
 -
 -struct _GstQtDemuxTagList
 -{
 -  GstQTDemux *demux;
 -  GstTagList *taglist;
 -};
 -typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
 +  if (qtdemux->streams_aware) {
 +    if (!qtdemux_update_streams (qtdemux))
 +      return GST_FLOW_ERROR;
 +  } else {
 +    for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
 +      QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
 +      GstTagList *list;
  
 -static void
 -qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
 -{
 -  gint len;
 -  guint8 *data;
 -  GstBuffer *buf;
 -  gchar *media_type;
 -  const gchar *style;
 -  GstSample *sample;
 -  GstStructure *s;
 -  guint i;
 -  guint8 ndata[4];
 -  GstQTDemux *demux = qtdemuxtaglist->demux;
 -  GstTagList *taglist = qtdemuxtaglist->taglist;
 -
 -  data = node->data;
 -  len = QT_UINT32 (data);
 -  buf = gst_buffer_new_and_alloc (len);
 -  gst_buffer_fill (buf, 0, data, len);
 -
 -  /* heuristic to determine style of tag */
 -  if (QT_FOURCC (data + 4) == FOURCC_____ ||
 -      (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
 -    style = "itunes";
 -  else if (demux->major_brand == FOURCC_qt__)
 -    style = "quicktime";
 -  /* fall back to assuming iso/3gp tag style */
 -  else
 -    style = "iso";
 +      /* now we have all info and can expose */
 +      list = stream->stream_tags;
 +      stream->stream_tags = NULL;
 +      if (!gst_qtdemux_add_stream (qtdemux, stream, list))
 +        return GST_FLOW_ERROR;
  
 -  /* santize the name for the caps. */
 -  for (i = 0; i < 4; i++) {
 -    guint8 d = data[4 + i];
 -    if (g_ascii_isalnum (d))
 -      ndata[i] = g_ascii_tolower (d);
 -    else
 -      ndata[i] = '_';
 +    }
    }
  
 -  media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
 -      ndata[0], ndata[1], ndata[2], ndata[3]);
 -  GST_DEBUG_OBJECT (demux, "media type %s", media_type);
 -
 -  s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
 -  sample = gst_sample_new (buf, NULL, NULL, s);
 -  gst_buffer_unref (buf);
 -  g_free (media_type);
 -
 -  GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
 -      len, s);
 +  gst_qtdemux_guess_bitrate (qtdemux);
  
 -  gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
 -      GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
 +  gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
  
 -  gst_sample_unref (sample);
 -}
 +  /* If we have still old_streams, it's no more used stream */
 +  for (i = 0; i < qtdemux->old_streams->len; i++) {
 +    QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
  
 -static void
 -qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
 -{
 -  GNode *meta;
 -  GNode *ilst;
 -  GNode *xmp_;
 -  GNode *node;
 -  gint i;
 -  GstQtDemuxTagList demuxtaglist;
 +    if (stream->pad) {
 +      GstEvent *event;
  
 -  demuxtaglist.demux = qtdemux;
 -  demuxtaglist.taglist = taglist;
 +      event = gst_event_new_eos ();
 +      if (qtdemux->segment_seqnum)
 +        gst_event_set_seqnum (event, qtdemux->segment_seqnum);
  
 -  meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
 -  if (meta != NULL) {
 -    ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
 -    if (ilst == NULL) {
 -      GST_LOG_OBJECT (qtdemux, "no ilst");
 -      return;
 +      gst_pad_push_event (stream->pad, event);
      }
 -  } else {
 -    ilst = udta;
 -    GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
    }
  
 -  i = 0;
 -  while (i < G_N_ELEMENTS (add_funcs)) {
 -    node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
 -    if (node) {
 -      gint len;
 +  g_ptr_array_set_size (qtdemux->old_streams, 0);
  
 -      len = QT_UINT32 (node->data);
 -      if (len < 12) {
 -        GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
 -            GST_FOURCC_ARGS (add_funcs[i].fourcc));
 -      } else {
 -        add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
 -            add_funcs[i].gst_tag_bis, node);
 -      }
 -      g_node_destroy (node);
 -    } else {
 -      i++;
 -    }
 -  }
 +  /* check if we should post a redirect in case there is a single trak
 +   * and it is a redirecting trak */
 +  if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
 +      QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
 +    GstMessage *m;
  
 -  /* parsed nodes have been removed, pass along remainder as blob */
 -  g_node_children_foreach (ilst, G_TRAVERSE_ALL,
 -      (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
 +    GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
 +        "an external content");
 +    m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
 +        gst_structure_new ("redirect",
 +            "new-location", G_TYPE_STRING,
 +            QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
 +    gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
 +    g_free (qtdemux->redirect_location);
 +    qtdemux->redirect_location =
 +        g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
 +  }
  
 -  /* parse up XMP_ node if existing */
 -  xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
 -  if (xmp_ != NULL) {
 -    GstBuffer *buf;
 -    GstTagList *xmptaglist;
 +  g_ptr_array_foreach (qtdemux->active_streams,
 +      (GFunc) qtdemux_do_allocation, qtdemux);
  
 -    buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
 -        QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
 -    xmptaglist = gst_tag_list_from_xmp_buffer (buf);
 -    gst_buffer_unref (buf);
 +  qtdemux->need_segment = TRUE;
  
 -    qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
 -  } else {
 -    GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
 -  }
 +  qtdemux->exposed = TRUE;
 +  return GST_FLOW_OK;
  }
  
  typedef struct
@@@ -267,241 -265,6 +274,245 @@@ struct _GstQTDemuxClass 
  
  GType gst_qtdemux_get_type (void);
  
 +struct _QtDemuxStreamStsdEntry
 +{
 +  GstCaps *caps;
 +  guint32 fourcc;
 +  gboolean sparse;
 +
 +  /* video info */
 +  gint width;
 +  gint height;
 +  gint par_w;
 +  gint par_h;
 +  /* Numerator/denominator framerate */
 +  gint fps_n;
 +  gint fps_d;
 +  GstVideoColorimetry colorimetry;
 +  guint16 bits_per_sample;
 +  guint16 color_table_id;
 +  GstMemory *rgb8_palette;
 +  guint interlace_mode;
 +  guint field_order;
 +
 +  /* audio info */
 +  gdouble rate;
 +  gint n_channels;
 +  guint samples_per_packet;
 +  guint samples_per_frame;
 +  guint bytes_per_packet;
 +  guint bytes_per_sample;
 +  guint bytes_per_frame;
 +  guint compression;
 +
 +  /* if we use chunks or samples */
 +  gboolean sampled;
 +  guint padding;
 +
 +};
 +
 +struct _QtDemuxSample
 +{
 +  guint32 size;
 +  gint32 pts_offset;            /* Add this value to timestamp to get the pts */
 +  guint64 offset;
 +  guint64 timestamp;            /* DTS In mov time */
 +  guint32 duration;             /* In mov time */
 +  gboolean keyframe;            /* TRUE when this packet is a keyframe */
 +};
 +
 +struct _QtDemuxStream
 +{
 +  GstPad *pad;
 +
 +  GstQTDemux *demux;
 +  gchar *stream_id;
 +
 +  QtDemuxStreamStsdEntry *stsd_entries;
 +  guint stsd_entries_length;
 +  guint cur_stsd_entry_index;
 +
 +  /* stream type */
 +  guint32 subtype;
 +
 +  gboolean new_caps;            /* If TRUE, caps need to be generated (by
 +                                 * calling _configure_stream()) This happens
 +                                 * for MSS and fragmented streams */
 +
 +  gboolean new_stream;          /* signals that a stream_start is required */
 +  gboolean on_keyframe;         /* if this stream last pushed buffer was a
 +                                 * keyframe. This is important to identify
 +                                 * where to stop pushing buffers after a
 +                                 * segment stop time */
 +
 +  /* if the stream has a redirect URI in its headers, we store it here */
 +  gchar *redirect_uri;
 +
 +  /* track id */
 +  guint track_id;
 +
++#ifdef TIZEN_FEATURE_QTDEMUX_DURATION
++  guint64 tkhd_duration;
++#endif
++
 +  /* duration/scale */
 +  guint64 duration;             /* in timescale units */
 +  guint32 timescale;
 +
 +  /* language */
 +  gchar lang_id[4];             /* ISO 639-2T language code */
 +
 +  /* our samples */
 +  guint32 n_samples;
 +  QtDemuxSample *samples;
 +  gboolean all_keyframe;        /* TRUE when all samples are keyframes (no stss) */
 +  guint32 n_samples_moof;       /* sample count in a moof */
 +  guint64 duration_moof;        /* duration in timescale of a moof, used for figure out
 +                                 * the framerate of fragmented format stream */
 +  guint64 duration_last_moof;
 +
 +  guint32 offset_in_sample;     /* Offset in the current sample, used for
 +                                 * streams which have got exceedingly big
 +                                 * sample size (such as 24s of raw audio).
 +                                 * Only used when max_buffer_size is non-NULL */
 +  guint32 min_buffer_size;      /* Minimum allowed size for output buffers.
 +                                 * Currently only set for raw audio streams*/
 +  guint32 max_buffer_size;      /* Maximum allowed size for output buffers.
 +                                 * Currently only set for raw audio streams*/
 +
 +  /* video info */
 +  /* aspect ratio */
 +  gint display_width;
 +  gint display_height;
 +
 +  /* allocation */
 +  gboolean use_allocator;
 +  GstAllocator *allocator;
 +  GstAllocationParams params;
 +
 +  gsize alignment;
 +
 +  /* when a discontinuity is pending */
 +  gboolean discont;
 +
 +  /* list of buffers to push first */
 +  GSList *buffers;
 +
 +  /* if we need to clip this buffer. This is only needed for uncompressed
 +   * data */
 +  gboolean need_clip;
 +
 +  /* buffer needs some custom processing, e.g. subtitles */
 +  gboolean need_process;
 +  /* buffer needs potentially be split, e.g. CEA608 subtitles */
 +  gboolean need_split;
 +
 +  /* current position */
 +  guint32 segment_index;
 +  guint32 sample_index;
 +  GstClockTime time_position;   /* in gst time */
 +  guint64 accumulated_base;
 +
 +  /* the Gst segment we are processing out, used for clipping */
 +  GstSegment segment;
 +
 +  /* quicktime segments */
 +  guint32 n_segments;
 +  QtDemuxSegment *segments;
 +  gboolean dummy_segment;
 +  guint32 from_sample;
 +  guint32 to_sample;
 +
 +  gboolean sent_eos;
 +  GstTagList *stream_tags;
 +  gboolean send_global_tags;
 +
 +  GstEvent *pending_event;
 +
 +  GstByteReader stco;
 +  GstByteReader stsz;
 +  GstByteReader stsc;
 +  GstByteReader stts;
 +  GstByteReader stss;
 +  GstByteReader stps;
 +  GstByteReader ctts;
 +
 +  gboolean chunks_are_samples;  /* TRUE means treat chunks as samples */
 +  gint64 stbl_index;
 +  /* stco */
 +  guint co_size;
 +  GstByteReader co_chunk;
 +  guint32 first_chunk;
 +  guint32 current_chunk;
 +  guint32 last_chunk;
 +  guint32 samples_per_chunk;
 +  guint32 stsd_sample_description_id;
 +  guint32 stco_sample_index;
 +  /* stsz */
 +  guint32 sample_size;          /* 0 means variable sizes are stored in stsz */
 +  /* stsc */
 +  guint32 stsc_index;
 +  guint32 n_samples_per_chunk;
 +  guint32 stsc_chunk_index;
 +  guint32 stsc_sample_index;
 +  guint64 chunk_offset;
 +  /* stts */
 +  guint32 stts_index;
 +  guint32 stts_samples;
 +  guint32 n_sample_times;
 +  guint32 stts_sample_index;
 +  guint64 stts_time;
 +  guint32 stts_duration;
 +  /* stss */
 +  gboolean stss_present;
 +  guint32 n_sample_syncs;
 +  guint32 stss_index;
 +  /* stps */
 +  gboolean stps_present;
 +  guint32 n_sample_partial_syncs;
 +  guint32 stps_index;
 +  QtDemuxRandomAccessEntry *ra_entries;
 +  guint n_ra_entries;
 +
 +  const QtDemuxRandomAccessEntry *pending_seek;
 +
 +  /* ctts */
 +  gboolean ctts_present;
 +  guint32 n_composition_times;
 +  guint32 ctts_index;
 +  guint32 ctts_sample_index;
 +  guint32 ctts_count;
 +  gint32 ctts_soffset;
 +
 +  /* cslg */
 +  guint32 cslg_shift;
 +
 +  /* fragmented */
 +  gboolean parsed_trex;
 +  guint32 def_sample_description_index; /* index is 1-based */
 +  guint32 def_sample_duration;
 +  guint32 def_sample_size;
 +  guint32 def_sample_flags;
 +
 +  gboolean disabled;
 +
 +  /* stereoscopic video streams */
 +  GstVideoMultiviewMode multiview_mode;
 +  GstVideoMultiviewFlags multiview_flags;
 +
 +  /* protected streams */
 +  gboolean protected;
 +  guint32 protection_scheme_type;
 +  guint32 protection_scheme_version;
 +  gpointer protection_scheme_info;      /* specific to the protection scheme */
 +  GQueue protection_scheme_event_queue;
 +
 +  /* KEY_UNITS trickmode with an interval */
 +  GstClockTime last_keyframe_dts;
 +
 +  gint ref_count;               /* atomic */
 +};
 +
  G_END_DECLS
  
  #endif /* __GST_QTDEMUX_H__ */
Simple merge
Simple merge
Simple merge
@@@ -379,8 -347,9 +382,11 @@@ enu
    PROP_MAX_STREAMS,
    PROP_MAX_TS_OFFSET_ADJUSTMENT,
    PROP_MAX_TS_OFFSET,
 +  PROP_FEC_DECODERS,
 +  PROP_FEC_ENCODERS,
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+   PROP_USE_RTSP_BUFFERING       /* use for player RTSP buffering */
+ #endif
  };
  
  #define GST_RTP_BIN_RTCP_SYNC_TYPE (gst_rtp_bin_rtcp_sync_get_type())
@@@ -1873,7 -1848,8 +1920,7 @@@ create_stream (GstRtpBinSession * sessi
    if (demux)
      gst_element_link_pads_full (buffer, "src", demux, "sink",
          GST_PAD_LINK_CHECK_NOTHING);
--
+ #endif
    if (rtpbin->buffering) {
      guint64 last_out;
  
@@@ -2729,42 -2706,14 +2790,50 @@@ gst_rtp_bin_class_init (GstRtpBinClass 
            "changed to 0 (no limit)", 0, G_MAXINT64, DEFAULT_MAX_TS_OFFSET,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  
 +  /**
 +   * GstRtpBin:fec-decoders:
 +   *
 +   * Used to provide a factory used to build the FEC decoder for a
 +   * given session, as a command line alternative to
 +   * #GstRtpBin::request-fec-decoder.
 +   *
 +   * Expects a GstStructure in the form session_id (gint) -> factory (string)
 +   *
 +   * Since: 1.20
 +   */
 +  g_object_class_install_property (gobject_class, PROP_FEC_DECODERS,
 +      g_param_spec_boxed ("fec-decoders", "Fec Decoders",
 +          "GstStructure mapping from session index to FEC decoder "
 +          "factory, eg "
 +          "fec-decoders='fec,0=\"rtpst2022-1-fecdec\\ size-time\\=1000000000\";'",
 +          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 +
 +  /**
 +   * GstRtpBin:fec-encoders:
 +   *
 +   * Used to provide a factory used to build the FEC encoder for a
 +   * given session, as a command line alternative to
 +   * #GstRtpBin::request-fec-encoder.
 +   *
 +   * Expects a GstStructure in the form session_id (gint) -> factory (string)
 +   *
 +   * Since: 1.20
 +   */
 +  g_object_class_install_property (gobject_class, PROP_FEC_ENCODERS,
 +      g_param_spec_boxed ("fec-encoders", "Fec Encoders",
 +          "GstStructure mapping from session index to FEC encoder "
 +          "factory, eg "
 +          "fec-encoders='fec,0=\"rtpst2022-1-fecenc\\ rows\\=5\\ columns\\=5\";'",
 +          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 +
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+   g_object_class_install_property (gobject_class, PROP_USE_RTSP_BUFFERING,
+       g_param_spec_boolean ("use-rtsp-buffering", "Use RTSP buffering",
+           "Use RTSP buffering in RTP_JITTER_BUFFER_MODE_SLAVE buffer mode",
+           DEFAULT_RTSP_USE_BUFFERING,
+           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ #endif
    gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_bin_change_state);
    gstelement_class->request_new_pad =
        GST_DEBUG_FUNCPTR (gst_rtp_bin_request_new_pad);
Simple merge
Simple merge
Simple merge
  #include "config.h"
  #endif
  
 -#include "gst/gst-i18n-plugin.h"
 -
 -#include "gstrtpdec.h"
 +#include "gstrtspelements.h"
++#ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+ #include "gstrtspsrc.h"
 -
++#endif
  static gboolean
  plugin_init (GstPlugin * plugin)
  {
 -#ifdef ENABLE_NLS
 -  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
 -  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 -#endif /* ENABLE_NLS */
 +  gboolean ret = FALSE;
  
 -  if (!gst_element_register (plugin, "rtspsrc", GST_RANK_NONE,
 -          GST_TYPE_RTSPSRC))
 -    return FALSE;
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+   if (!gst_element_register (plugin, "rtspsrc", GST_RANK_PRIMARY,
+           GST_TYPE_RTSPSRC))
+     return FALSE;
+ #else
 -  if (!gst_element_register (plugin, "rtpdec", GST_RANK_NONE, GST_TYPE_RTP_DEC))
 -    return FALSE;
 +  ret |= GST_ELEMENT_REGISTER (rtspsrc, plugin);
+ #endif
 -  return TRUE;
 +  ret |= GST_ELEMENT_REGISTER (rtpdec, plugin);
 +
 +  return ret;
  }
  
  GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
@@@ -289,11 -280,11 +289,15 @@@ gst_rtsp_backchannel_get_type (void
  #define DEFAULT_VERSION         GST_RTSP_VERSION_1_0
  #define DEFAULT_BACKCHANNEL  GST_RTSP_BACKCHANNEL_NONE
  #define DEFAULT_TEARDOWN_TIMEOUT  (100 * GST_MSECOND)
 +#define DEFAULT_ONVIF_MODE FALSE
 +#define DEFAULT_ONVIF_RATE_CONTROL TRUE
 +#define DEFAULT_IS_LIVE TRUE
 +#define DEFAULT_IGNORE_X_SERVER_REPLY FALSE
  
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+ #define DEFAULT_START_POSITION   0
+ #endif
  enum
  {
    PROP_0,
@@@ -1445,12 -1389,11 +1498,16 @@@ gst_rtspsrc_init (GstRTSPSrc * src
    src->default_version = DEFAULT_VERSION;
    src->version = GST_RTSP_VERSION_INVALID;
    src->teardown_timeout = DEFAULT_TEARDOWN_TIMEOUT;
 +  src->onvif_mode = DEFAULT_ONVIF_MODE;
 +  src->onvif_rate_control = DEFAULT_ONVIF_RATE_CONTROL;
 +  src->is_live = DEFAULT_IS_LIVE;
 +  src->seek_seqnum = GST_SEQNUM_INVALID;
 +  src->group_id = GST_GROUP_ID_INVALID;
  
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+   g_mutex_init (&(src)->pause_lock);
+   g_cond_init (&(src)->open_end);
+ #endif
    /* get a list of all extensions */
    src->extensions = gst_rtsp_ext_list_get ();
  
@@@ -1819,9 -1792,23 +1907,17 @@@ gst_rtspsrc_get_property (GObject * obj
      case PROP_TIMEOUT:
        g_value_set_uint64 (value, rtspsrc->udp_timeout);
        break;
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+     case PROP_START_POSITION:
+       g_value_set_uint64 (value, rtspsrc->start_position);
+       break;
+     case PROP_RESUME_POSITION:
+       g_value_set_uint64 (value, rtspsrc->last_pos);
+       break;
+ #endif
      case PROP_TCP_TIMEOUT:
 -    {
 -      guint64 timeout;
 -
 -      timeout = ((guint64) rtspsrc->tcp_timeout.tv_sec) * G_USEC_PER_SEC +
 -          rtspsrc->tcp_timeout.tv_usec;
 -      g_value_set_uint64 (value, timeout);
 +      g_value_set_uint64 (value, rtspsrc->tcp_timeout);
        break;
 -    }
      case PROP_LATENCY:
        g_value_set_uint (value, rtspsrc->latency);
        break;
@@@ -7723,15 -7809,22 +8030,26 @@@ gst_rtspsrc_parse_range (GstRTSPSrc * s
  
    /* we need to start playback without clipping from the position reported by
     * the server */
 -  segment->start = seconds;
 +  if (segment->rate > 0.0)
 +    segment->start = seconds;
 +  else
 +    segment->stop = seconds;
 +
+ #ifndef TIZEN_FEATURE_RTSP_MODIFICATION
+ /*
+ The range-min points to the start of the segment , not the current position.
+ After getting the current position from MSL during normal pause/resume or during seek , we should not
+ update the segment->position again with the rtp header npt timestamp.
+ */
    segment->position = seconds;
+ #endif
  
    if (therange->max.type == GST_RTSP_TIME_NOW)
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+     seconds = 0;
+ #else
      seconds = -1;
+ #endif
    else if (therange->max.type == GST_RTSP_TIME_END)
      seconds = -1;
    else
@@@ -8660,46 -8732,34 +9039,65 @@@ restart
        /* store the newsegment event so it can be sent from the streaming thread. */
        src->need_segment = TRUE;
      }
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+     else {
+ /*
+  Updating position with the MSL current position as gst_rtspsrc_get_position() does not return correct position.
+ */
+       GST_DEBUG_OBJECT (src,
+           " During normal pause-resume , segment->position=%" GST_TIME_FORMAT
+           ",src->start_position=%" GST_TIME_FORMAT,
+           GST_TIME_ARGS (segment->position),
+           GST_TIME_ARGS (src->start_position));
+       segment->position = src->last_pos;
+     }
+ /*
+  Sending the npt range request for each play request for updating the segment position properly.
+ */
+     hval = gen_range_header (src, segment);
+     gst_rtsp_message_take_header (&request, GST_RTSP_HDR_RANGE, hval);
+ #endif
  
      if (segment->rate != 1.0) {
 -      gchar hval[G_ASCII_DTOSTR_BUF_SIZE];
 +      gchar scale_val[G_ASCII_DTOSTR_BUF_SIZE];
 +      gchar speed_val[G_ASCII_DTOSTR_BUF_SIZE];
 +
 +      if (src->server_side_trickmode) {
 +        g_ascii_dtostr (scale_val, sizeof (scale_val), segment->rate);
 +        gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SCALE, scale_val);
 +      } else if (segment->rate < 0.0) {
 +        g_ascii_dtostr (scale_val, sizeof (scale_val), -1.0);
 +        gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SCALE, scale_val);
 +
 +        if (ABS (segment->rate) != 1.0) {
 +          g_ascii_dtostr (speed_val, sizeof (speed_val), ABS (segment->rate));
 +          gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SPEED, speed_val);
 +        }
 +      } else {
 +        g_ascii_dtostr (speed_val, sizeof (speed_val), segment->rate);
 +        gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SPEED, speed_val);
 +      }
 +    }
  
 -      g_ascii_dtostr (hval, sizeof (hval), segment->rate);
 -      if (src->skip)
 -        gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SCALE, hval);
 -      else
 -        gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SPEED, hval);
 +    if (src->onvif_mode) {
 +      if (segment->flags & GST_SEEK_FLAG_TRICKMODE_KEY_UNITS) {
 +        gchar *hval;
 +
 +        if (src->trickmode_interval)
 +          hval =
 +              g_strdup_printf ("intra/%" G_GUINT64_FORMAT,
 +              src->trickmode_interval / GST_MSECOND);
 +        else
 +          hval = g_strdup ("intra");
 +
 +        gst_rtsp_message_add_header (&request, GST_RTSP_HDR_FRAMES, hval);
 +
 +        g_free (hval);
 +      } else if (segment->flags & GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED) {
 +        gst_rtsp_message_add_header (&request, GST_RTSP_HDR_FRAMES,
 +            "predicted");
 +      }
      }
  
      if (seek_style)
@@@ -9297,14 -9351,22 +9721,26 @@@ gst_rtspsrc_change_state (GstElement * 
        ret = GST_STATE_CHANGE_SUCCESS;
        break;
      case GST_STATE_CHANGE_READY_TO_PAUSED:
 -      ret = GST_STATE_CHANGE_NO_PREROLL;
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+       /* don't change to PAUSE state before complete stream opend.
+          see gst_rtspsrc_loop_complete_cmd() */
+       g_mutex_lock (&(rtspsrc)->pause_lock);
+       end_time = g_get_monotonic_time () + 10 * G_TIME_SPAN_SECOND;
+       if (!g_cond_wait_until (&(rtspsrc)->open_end, &(rtspsrc)->pause_lock,
+               end_time)) {
+         GST_WARNING_OBJECT (rtspsrc,
+             "time out: stream opend is not completed yet..");
+       }
+       g_mutex_unlock (&(rtspsrc)->pause_lock);
+ #endif
 +      if (rtspsrc->is_live)
 +        ret = GST_STATE_CHANGE_NO_PREROLL;
 +      else
 +        ret = GST_STATE_CHANGE_SUCCESS;
        break;
      case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
 -      gst_rtspsrc_loop_send_cmd (rtspsrc, CMD_PLAY, 0);
 +      if (rtspsrc->is_live)
 +        gst_rtspsrc_loop_send_cmd (rtspsrc, CMD_PLAY, 0);
        ret = GST_STATE_CHANGE_SUCCESS;
        break;
      case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
@@@ -324,10 -378,11 +385,16 @@@ struct _GstRTSPSrc 
    GstRTSPVersion default_version;
    GstRTSPVersion version;
  
 -#endif  
 +  GstEvent *initial_seek;
 +
 +  guint group_id;
 +  GMutex group_lock;
++
+ #ifdef TIZEN_FEATURE_RTSP_MODIFICATION
+   GCond open_end;
+   GMutex pause_lock;
+   guint64 start_position;
++#endif
  };
  
  struct _GstRTSPSrcClass {
Simple merge
Simple merge
diff --cc meson.build
@@@ -369,46 -334,6 +369,57 @@@ els
    cdata.set('DISABLE_ORC', 1)
  endif
  
 +have_nasm = false
 +# FIXME: nasm path needs testing on non-Linux, esp. Windows
 +host_cpu = host_machine.cpu_family()
 +if host_cpu == 'x86_64'
 +  if cc.get_define('__ILP32__') == '1'
 +    message('Nasm disabled on x32')
 +  else
 +    asm_option = get_option('asm')
 +    nasm = find_program('nasm', native: true, required: asm_option)
 +    if nasm.found()
 +      # We can't use the version: kwarg for find_program because old versions
 +      # of nasm don't support --version
 +      ret = run_command(nasm, '-v')
 +      if ret.returncode() == 0
 +        nasm_version = ret.stdout().strip().split()[2]
 +        nasm_req = '>=2.13'
 +        if nasm_version.version_compare(nasm_req)
 +          message('nasm found on x86-64')
 +          cdata.set('HAVE_NASM', 1)
 +          have_nasm = true
 +        else
 +          if asm_option.enabled()
 +            error('asm option is enabled, and nasm @0@ was found, but @1@ is required'.format(nasm_version, nasm_req))
 +          endif
 +          message('nasm @0@ was found, but @1@ is required'.format(nasm_version, nasm_req))
 +        endif
 +      else
 +        if asm_option.enabled()
 +          error('asm option is enabled, but nasm is not usable: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
 +        endif
 +        message('nasm was found, but it\'s not usable')
 +      endif
 +      # Unset nasm to not be 'found'
 +      if not have_nasm
 +        nasm = disabler()
 +      endif
 +    endif
 +  endif
 +endif
 +
++# TIZEN_BUILD_OPTION
++
++tbm_dep = dependency('libtbm', required : get_option('tbm'))
++if tbm_dep.found()
++  cdata.set('TIZEN_FEATURE_V4L2_TBM_SUPPORT', 1)
++endif
++
++gio_dep = dependency('gio-2.0')
++
++# TIZEN_BUILD_OPTION end
++
  # Disable compiler warnings for unused variables and args if gst debug system is disabled
  if gst_dep.type_name() == 'internal'
    gst_debug_disabled = not subproject('gstreamer').get_variable('gst_debug')
@@@ -109,5 -103,3 +109,9 @@@ option('package-name', type : 'string'
         description : 'package name to use in plugins')
  option('package-origin', type : 'string', value : 'Unknown package origin', yield : true,
         description : 'package origin URL to use in plugins')
 +option('doc', type : 'feature', value : 'auto', yield: true,
 +       description: 'Enable documentation.')
++
++# Tizen Options
++option('tbm', type : 'boolean', value : true,
++       description : 'tizen buffer manager')
index 0000000,97e8c31..97e8c31
mode 000000,100644..100644
--- /dev/null
index 0000000,3bd4bcc..a77f0a1
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,228 +1,229 @@@
 -Version:        1.16.2
 -Release:        32
+ %bcond_with x
+ %define gst_branch 1.0
+ Name:           gst-plugins-good
 -Source100:      common.tar.gz
 -BuildRequires:  gcc-c++
++Version:        1.19.2
++Release:        0
+ License:        LGPL-2.1+
+ Summary:        GStreamer Streaming-Media Framework Plug-Ins
+ Url:            http://gstreamer.freedesktop.org/
+ Group:          Multimedia/Framework
+ Source:         http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-%{version}.tar.xz
 -BuildRequires:  pkgconfig(gstreamer-1.0)
 -BuildRequires:  pkgconfig(gstreamer-plugins-base-1.0)
++Source1001:     gst-plugins-good.manifest
++
+ BuildRequires:  gettext-tools
+ BuildRequires:  pkgconfig(glib-2.0) >= 2.32
 -Requires:       gst-plugins-base >= 1.0.0
 -Requires:       gstreamer >= 1.0.5
++#BuildRequires:  pkgconfig(gstreamer-1.0)
++#BuildRequires:  pkgconfig(gstreamer-plugins-base-1.0)
++BuildRequires:  gstreamer-devel >= %{version}
++BuildRequires:  gst-plugins-base-devel >= %{version}
+ BuildRequires:  libjpeg-devel
+ BuildRequires:  orc >= 0.4.16
+ BuildRequires:  python
++BuildRequires:  meson >= 0.48.0
+ BuildRequires:  xsltproc
+ BuildRequires:  pkgconfig(bzip2)
+ BuildRequires:  pkgconfig(libpng) >= 1.2
+ BuildRequires:  pkgconfig(libpulse) >= 1.0
+ BuildRequires:  pkgconfig(libsoup-2.4)
+ BuildRequires:  pkgconfig(libxml-2.0) >= 2.4.9
+ # TODO find where process.h comes from, not kernel-devel and not wxWidgets so far.
+ %if %{with x}
+ BuildRequires:  pkgconfig(ice)
+ BuildRequires:  pkgconfig(sm)
+ BuildRequires:  pkgconfig(xdamage)
+ BuildRequires:  pkgconfig(xfixes)
+ # used by libgstvideo4linux2.so
+ BuildRequires:  pkgconfig(xv)
+ %endif
+ BuildRequires:  pkgconfig(vpx)
+ BuildRequires:  pkgconfig(zlib)
+ %if "%{tizen_profile_name}" != "tv"
+ BuildRequires:  pkgconfig(libv4l2)
+ %endif
+ BuildRequires:  pkgconfig(vconf)
+ BuildRequires:  pkgconfig(gio-2.0)
+ BuildRequires:  pkgconfig(libtbm)
+ BuildRequires:  pkgconfig(cairo)
+ BuildRequires:  pkgconfig(cairo-gobject)
 -%setup -q -T -D -a 100
++Requires:       gst-plugins-base >= %{version}
++Requires:       gstreamer >= %{version}
+ %description
+ GStreamer is a streaming media framework based on graphs of filters
+ that operate on media data. Applications using this library can do
+ anything media-related, from real-time sound processing to playing
+ videos. Its plug-in-based architecture means that new data types or
+ processing capabilities can be added simply by installing new plug-ins.
+ %package extra
+ Summary:        Complementary plugins for %{name}
+ Group:          Productivity/Multimedia/Other
+ Requires:       %{name} = %{version}
+ Enhances:       gst-plugins-good
+ %description extra
+ This package provides complementary plugins for %{name} and
+ plugins not included in official Tizen images, which may be used for development / experimental purposes.
+ %prep
+ %setup -q -n gst-plugins-good-%{version}
 -# FIXME:
 -# warning: failed to load external entity "xml/element-v4l2src-details.xml"
 -# warning: failed to load external entity "xml/plugin-video4linux2.xml"
 -export V=1
 -NOCONFIGURE=1 ./autogen.sh
++cp %{SOURCE1001} .
+ %build
 -      -DTIZEN_FEATURE_GST_UPSTREAM_AVOID_BUILD_BREAK\
++mkdir -p build
+ export CFLAGS+=" \
+       -DTIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE\
+       -DTIZEN_FEATURE_V4L2SRC_SUPPORT_CAMERA_ID\
+       -DTIZEN_FEATURE_V4L2VIDEO_ADJ_RANK\
+       -DTIZEN_FEATURE_WAVPARSE_MODIFICATION\
+       -DTIZEN_FEATURE_MP3PARSE_MODIFICATION\
+       -DTIZEN_FEATURE_AACPARSE_MODIFICATION\
+       -DTIZEN_FEATURE_QTDEMUX_MODIFICATION\
+       -DTIZEN_FEATURE_QTDEMUX_DURATION\
+       -DTIZEN_FEATURE_FLVDEMUX_MODIFICATION\
 -      -DTIZEN_FEATURE_GST_MUX_ENHANCEMENT\
+       -DTIZEN_FEATURE_RTSP_MODIFICATION\
 -      -DTIZEN_FEATURE_V4L2_TBM_SUPPORT\
+       -DTIZEN_FEATURE_SOUP_MODIFICATION\
+       -DTIZEN_FEATURE_RGVOLUME_MODIFICATION\
+       -DTIZEN_FEATURE_DISABLE_V4L2_DEPENDENCY\
+       -DTIZEN_FEATURE_AVIDEMUX_MODIFICATION\
+       -DTIZEN_FEATURE_USE_LIBV4L2\
+       -DTIZEN_FEATURE_V4L2_ADDITIONAL_CID_SUPPORT\
 -%configure\
+       -D__TIZEN__\
+       -fstack-protector-strong\
+       -Wl,-z,relro\
++      -Wno-error\
+       -D_FORTIFY_SOURCE=2"
 -      --disable-aalib\
++export CXXFLAGS+=" -Wno-error"
++
++meson --auto-feature=auto --prefix=/usr --libdir=%{_libdir} --datadir=%{_datadir} \
+ %if ! 0%{?ENABLE_AALIB}
 -      --with-libv4l2 \
++    -D aalib=disabled \
+ %endif
+ %if "%{tizen_profile_name}" != "tv"
 -      --enable-v4l2-probe\
 -      --disable-gtk-doc\
 -      --with-gtk=3.0\
 -      --disable-monoscope\
 -      --disable-y4m\
 -      --disable-taglib\
 -      --disable-wavpack\
 -      --enable-experimental\
 -      --disable-equalizer\
++    -D v4l2-libv4l2=enabled \
+ %endif
 -      --disable-flv\
 -      --disable-videobox\
 -      --disable-videomixer\
++    -D v4l2-probe=true \
++    -D monoscope=disabled \
++    -D y4m=disabled \
++    -D taglib=disabled \
++    -D wavpack=disabled \
++    -D equalizer=disabled \
+ %if "%{tizen_profile_name}" == "tv"
 -      --disable-alpha\
 -      --disable-auparse\
 -      --disable-flx\
 -      --disable-goom\
 -      --disable-goom2k1\
 -      --disable-level\
 -      --disable-multipart\
 -      --disable-spectrum\
 -      --disable-cutter\
 -      --disable-dtmf\
 -      --disable-oss4\
 -      --disable-oss\
 -      --disable-shapewipe
++    -D flv=disabled \
++    -D videobox=disabled \
++    -D videomixer=disabled \
++    -D lame=disabled \
+ %endif
 -make %{?_smp_mflags} CFLAGS+="-Wno-error" CXXFLAGS+="-Wno-error"
++    -D alpha=disabled \
++    -D auparse=disabled \
++    -D flx=disabled \
++    -D goom=disabled \
++    -D goom2k1=disabled \
++    -D level=disabled \
++    -D multipart=disabled \
++    -D spectrum=disabled \
++    -D cutter=disabled \
++    -D dtmf=disabled \
++    -D oss4=disabled \
++    -D oss=disabled \
++    -D shapewipe=disabled \
++    -D twolame=disabled \
++    -D tbm=true build
 -%make_install
++ninja -C build all %{?_smp_mflags}
+ %install
++export DESTDIR=%{buildroot}
++ninja -C build install
++
+ %find_lang %{name}-%{gst_branch}
+ %lang_package -f %{name}-%{gst_branch}
+ %files
+ %manifest %{name}.manifest
+ %defattr(-, root, root)
+ %license COPYING
+ %{_libdir}/gstreamer-%{gst_branch}/libgstalaw.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstalpha.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstalphacolor.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstapetag.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstaudiofx.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstaudioparsers.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstauparse.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstautodetect.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstavi.so
+ # Not yet ported
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstcutter.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstdebug.so
+ # Not yet ported
+ %{_libdir}/gstreamer-%{gst_branch}/libgstdeinterlace.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgsteffectv.so
+ #%{_datadir}/gstreamer-%{gst_branch}/presets/GstVP8Enc.prs
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstflxdec.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstgoom.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstgoom2k1.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgsticydemux.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstid3demux.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstinterleave.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstisomp4.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstjpeg.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstlevel.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstmatroska.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstmonoscope.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstmulaw.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstmultifile.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstmultipart.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstnavigationtest.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstoss4audio.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstossaudio.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstpulseaudio.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstreplaygain.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstrtp.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstrtpmanager.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstrtsp.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstshapewipe.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstsmpte.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstspectrum.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstspeex.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstudp.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstvideo4linux2.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstvideocrop.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstvideofilter.so
+ %if "%{tizen_profile_name}" != "tv"
+ %{_libdir}/gstreamer-%{gst_branch}/libgstflv.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstequalizer.so
+ #%{_datadir}/gstreamer-%{gst_branch}/presets/GstIirEqualizer10Bands.prs
+ #%{_datadir}/gstreamer-%{gst_branch}/presets/GstIirEqualizer3Bands.prs
+ %{_datadir}/gstreamer-%{gst_branch}/presets/GstQTMux.prs
+ %{_libdir}/gstreamer-%{gst_branch}/libgstvideobox.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstvideomixer.so
+ %endif
+ %{_libdir}/gstreamer-%{gst_branch}/libgstwavenc.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstwavparse.so
+ %if %{with x}
+ %{_libdir}/gstreamer-%{gst_branch}/libgstximagesrc.so
+ %endif
+ #%{_libdir}/gstreamer-%{gst_branch}/libgsty4menc.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstcairo.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstsoup.so
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstflac.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstvpx.so
+ %{_datadir}/gstreamer-%{gst_branch}/presets/GstVP8Enc.prs
+ #%{_libdir}/gstreamer-%{gst_branch}/libgstdtmf.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstimagefreeze.so
+ %files extra
+ %manifest %{name}.manifest
+ %defattr(-, root, root)
+ %if 0%{?ENABLE_AALIB}
+ %{_libdir}/gstreamer-%{gst_branch}/libgstaasink.so
+ %endif
+ %{_libdir}/gstreamer-%{gst_branch}/libgstpng.so
+ %{_libdir}/gstreamer-%{gst_branch}/libgstimagefreeze.so
@@@ -771,8 -726,9 +771,10 @@@ struct v4l2_pix_format 
  #define V4L2_META_FMT_VSP1_HGT    v4l2_fourcc('V', 'S', 'P', 'T') /* R-Car VSP1 2-D Histogram */
  #define V4L2_META_FMT_UVC         v4l2_fourcc('U', 'V', 'C', 'H') /* UVC Payload Header metadata */
  #define V4L2_META_FMT_D4XX        v4l2_fourcc('D', '4', 'X', 'X') /* D4XX Payload Header metadata */
 +#define V4L2_META_FMT_VIVID     v4l2_fourcc('V', 'I', 'V', 'D') /* Vivid Metadata */
  
+ #define V4L2_PIX_FMT_INVZ     v4l2_fourcc('I', 'N', 'V', 'Z') /* Intel Planar Depth 16-bit */
  /* priv field value to indicates that subsequent fields are valid. */
  #define V4L2_PIX_FMT_PRIV_MAGIC               0xfeedcafe
  
@@@ -249,25 -258,40 +259,27 @@@ gst_v4l2_probe_and_register (GstPlugin 
  static gboolean
  plugin_init (GstPlugin * plugin)
  {
 +  gboolean ret = FALSE;
+ #ifndef TIZEN_FEATURE_DISABLE_V4L2_DEPENDENCY
    const gchar *paths[] = { "/dev", "/dev/v4l2", NULL };
    const gchar *names[] = { "video", NULL };
 -#endif /* TIZEN_FEATURE_DISABLE_V4L2_DEPENDENCY */
  
 -  GST_DEBUG_CATEGORY_INIT (v4l2_debug, "v4l2", 0, "V4L2 API calls");
 -#ifndef TIZEN_FEATURE_DISABLE_V4L2_DEPENDENCY
 -  /* Add some depedency, so the dynamic features get updated upon changes in
 +  /* Add some dependency, so the dynamic features get updated upon changes in
     * /dev/video* */
    gst_plugin_add_dependency (plugin,
        NULL, paths, names, GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX);
+ #endif /* TIZEN_FEATURE_DISABLE_V4L2_DEPENDENCY */
  
 -  if (!gst_element_register (plugin, "v4l2src", GST_RANK_PRIMARY,
 -          GST_TYPE_V4L2SRC) ||
 -      !gst_element_register (plugin, "v4l2sink", GST_RANK_NONE,
 -          GST_TYPE_V4L2SINK) ||
 -      !gst_element_register (plugin, "v4l2radio", GST_RANK_NONE,
 -          GST_TYPE_V4L2RADIO) ||
 -      !gst_device_provider_register (plugin, "v4l2deviceprovider",
 -          GST_RANK_PRIMARY, GST_TYPE_V4L2_DEVICE_PROVIDER)
 -      /* etc. */
  #ifdef GST_V4L2_ENABLE_PROBE
 -      || !gst_v4l2_probe_and_register (plugin)
 +  ret |= gst_v4l2_probe_and_register (plugin);
  #endif
 -      )
 -    return FALSE;
  
 -#ifdef ENABLE_NLS
 -  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
 -  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 -#endif /* ENABLE_NLS */
 +  ret |= GST_ELEMENT_REGISTER (v4l2src, plugin);
 +  ret |= GST_ELEMENT_REGISTER (v4l2sink, plugin);
 +  ret |= GST_ELEMENT_REGISTER (v4l2radio, plugin);
 +  ret |= GST_DEVICE_PROVIDER_REGISTER (v4l2deviceprovider, plugin);
  
 -  return TRUE;
 +  return ret;
  }
  
  GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
Simple merge
Simple merge
Simple merge
@@@ -1859,10 -1825,9 +1897,13 @@@ gst_v4l2_object_get_caps_info (GstV4l2O
        case GST_VIDEO_FORMAT_GRAY16_BE:
          fourcc = V4L2_PIX_FMT_Y16_BE;
          break;
 +      case GST_VIDEO_FORMAT_BGR15:
 +        fourcc = V4L2_PIX_FMT_RGB555X;
 +        fourcc_nc = V4L2_PIX_FMT_XRGB555X;
 +        break;
+       case GST_VIDEO_FORMAT_INVZ:
+         fourcc = V4L2_PIX_FMT_INVZ;
+         break;
        default:
          break;
      }
@@@ -4515,14 -4284,28 +4556,33 @@@ gst_v4l2_object_probe_caps (GstV4l2Obje
  
      tmp = gst_v4l2_object_probe_caps_for_format (v4l2object,
          format->pixelformat, template);
 -    if (tmp)
 +    if (tmp) {
        gst_caps_append (ret, tmp);
  
 +      /* Add a variant of the caps with the Interlaced feature so we can negotiate it if needed */
 +      add_alternate_variant (v4l2object, ret, gst_caps_get_structure (ret,
 +              gst_caps_get_size (ret) - 1));
 +    }
 +
+ #ifdef TIZEN_FEATURE_V4L2_TBM_SUPPORT
+     if (format->pixelformat == V4L2_PIX_FMT_NV12 ||
+         format->pixelformat == V4L2_PIX_FMT_YUV420) {
+       GstStructure *alt_s = gst_structure_copy (template);
+       if (format->pixelformat == V4L2_PIX_FMT_NV12)
+         gst_structure_set (alt_s, "format", G_TYPE_STRING, "SN12", NULL);
+       else
+         gst_structure_set (alt_s, "format", G_TYPE_STRING, "S420", NULL);
+       tmp = gst_v4l2_object_probe_caps_for_format (v4l2object,
+           format->pixelformat, alt_s);
+       if (tmp)
+         gst_caps_append (ret, tmp);
+       gst_structure_free (alt_s);
+     }
+ #endif /* TIZEN_FEATURE_V4L2_TBM_SUPPORT */
      gst_structure_free (template);
    }
  
@@@ -4786,9 -4352,13 +4846,14 @@@ gst_v4l2_object_decide_allocation (GstV
    gboolean can_share_own_pool, pushing_from_our_pool = FALSE;
    GstAllocator *allocator = NULL;
    GstAllocationParams params = { 0 };
 +  guint video_idx;
  
+ #ifdef TIZEN_FEATURE_V4L2_TBM_SUPPORT
+   GST_INFO_OBJECT (obj->dbg_obj, "decide allocation - %s",
+       V4L2_TYPE_IS_OUTPUT (obj->type) ? "output" : "capture");
+ #else /* TIZEN_FEATURE_V4L2_TBM_SUPPORT */
    GST_DEBUG_OBJECT (obj->dbg_obj, "decide allocation");
+ #endif /* TIZEN_FEATURE_V4L2_TBM_SUPPORT */
  
    g_return_val_if_fail (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
        obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, FALSE);
Simple merge
Simple merge
@@@ -69,8 -68,10 +69,13 @@@ struct _GstV4l2Sr
    GstClockTime last_timestamp;
    gboolean has_bad_timestamp;
  
 +  /* maintain signal status, updated during negotiation */
 +  gboolean no_signal;
++
+ #ifdef TIZEN_FEATURE_V4L2SRC_SUPPORT_CAMERA_ID
+   /* Properties */
+   guint camera_id;
+ #endif /* TIZEN_FEATURE_V4L2SRC_SUPPORT_CAMERA_ID */
  };
  
  struct _GstV4l2SrcClass
Simple merge
Simple merge
@@@ -64,7 -56,7 +64,7 @@@ if have_v4l
      v4l2_sources,
      c_args : gst_plugins_good_args,
      include_directories : [configinc, libsinc],
--    dependencies : [gstbase_dep, gstvideo_dep, gstallocators_dep, gudev_dep, libv4l2_dep],
++    dependencies : [gstbase_dep, gstvideo_dep, gstallocators_dep, gudev_dep, libv4l2_dep, tbm_dep],
      install : true,
      install_dir : plugins_install_dir,
    )
Simple merge
Simple merge