gst: remove unnecessary GLIB_DISABLE_DEPRECATION_WARNINGS
[platform/upstream/gstreamer.git] / gst / rawparse / gstrawparse.c
1 /* GStreamer
2  * Copyright (C) 2006 David A. Schleef <ds@schleef.org>
3  * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
4  *
5  * gstrawparse.c:
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 /* TODO: - Add locking where appropiate
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #  include "config.h"
28 #endif
29
30 #include <string.h>
31
32 #include <gst/gst.h>
33 #include <gst/base/gstbasetransform.h>
34 #include <gst/base/gstadapter.h>
35
36 #include "gstrawparse.h"
37
38 static void gst_raw_parse_dispose (GObject * object);
39
40 static gboolean gst_raw_parse_sink_activate (GstPad * sinkpad,
41     GstObject * parent);
42 static gboolean gst_raw_parse_sink_activatemode (GstPad * sinkpad,
43     GstObject * parent, GstPadMode mode, gboolean active);
44 static void gst_raw_parse_loop (GstElement * element);
45 static GstStateChangeReturn gst_raw_parse_change_state (GstElement * element,
46     GstStateChange transition);
47 static GstFlowReturn gst_raw_parse_chain (GstPad * pad, GstObject * parent,
48     GstBuffer * buffer);
49 static gboolean gst_raw_parse_sink_event (GstPad * pad, GstObject * parent,
50     GstEvent * event);
51 static gboolean gst_raw_parse_src_event (GstPad * pad, GstObject * parent,
52     GstEvent * event);
53 static gboolean gst_raw_parse_src_query (GstPad * pad, GstObject * parent,
54     GstQuery * query);
55 static gboolean gst_raw_parse_convert (GstRawParse * rp, GstFormat src_format,
56     gint64 src_value, GstFormat dest_format, gint64 * dest_value);
57 static gboolean gst_raw_parse_handle_seek_pull (GstRawParse * rp,
58     GstEvent * event);
59
60 static void gst_raw_parse_reset (GstRawParse * rp);
61
62 static GstStaticPadTemplate gst_raw_parse_sink_pad_template =
63 GST_STATIC_PAD_TEMPLATE ("sink",
64     GST_PAD_SINK,
65     GST_PAD_ALWAYS,
66     GST_STATIC_CAPS_ANY);
67
68 GST_DEBUG_CATEGORY_STATIC (gst_raw_parse_debug);
69 #define GST_CAT_DEFAULT gst_raw_parse_debug
70
71 static void gst_raw_parse_class_init (GstRawParseClass * klass);
72 static void gst_raw_parse_init (GstRawParse * clip, GstRawParseClass * g_class);
73
74 static GstElementClass *parent_class;
75
76 /* we can't use G_DEFINE_ABSTRACT_TYPE because we need the klass in the _init
77  * method to get to the padtemplates */
78 GType
79 gst_raw_parse_get_type (void)
80 {
81   static volatile gsize raw_parse_type = 0;
82
83   if (g_once_init_enter (&raw_parse_type)) {
84     GType _type;
85
86     _type = g_type_register_static_simple (GST_TYPE_ELEMENT,
87         "GstRawParse", sizeof (GstRawParseClass),
88         (GClassInitFunc) gst_raw_parse_class_init, sizeof (GstRawParse),
89         (GInstanceInitFunc) gst_raw_parse_init, G_TYPE_FLAG_ABSTRACT);
90
91     g_once_init_leave (&raw_parse_type, _type);
92   }
93   return raw_parse_type;
94 }
95
96 static void
97 gst_raw_parse_class_init (GstRawParseClass * klass)
98 {
99   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
100   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
101
102   parent_class = g_type_class_peek_parent (klass);
103
104   gobject_class->dispose = gst_raw_parse_dispose;
105
106   gstelement_class->change_state =
107       GST_DEBUG_FUNCPTR (gst_raw_parse_change_state);
108
109   gst_element_class_add_pad_template (gstelement_class,
110       gst_static_pad_template_get (&gst_raw_parse_sink_pad_template));
111
112   GST_DEBUG_CATEGORY_INIT (gst_raw_parse_debug, "rawparse", 0,
113       "rawparse element");
114 }
115
116 static void
117 gst_raw_parse_init (GstRawParse * rp, GstRawParseClass * g_class)
118 {
119   GstPadTemplate *src_pad_template;
120   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
121
122   rp->sinkpad =
123       gst_pad_new_from_static_template (&gst_raw_parse_sink_pad_template,
124       "sink");
125   gst_pad_set_chain_function (rp->sinkpad,
126       GST_DEBUG_FUNCPTR (gst_raw_parse_chain));
127   gst_pad_set_event_function (rp->sinkpad,
128       GST_DEBUG_FUNCPTR (gst_raw_parse_sink_event));
129   gst_pad_set_activate_function (rp->sinkpad,
130       GST_DEBUG_FUNCPTR (gst_raw_parse_sink_activate));
131   gst_pad_set_activatemode_function (rp->sinkpad,
132       GST_DEBUG_FUNCPTR (gst_raw_parse_sink_activatemode));
133   gst_element_add_pad (GST_ELEMENT (rp), rp->sinkpad);
134
135   src_pad_template = gst_element_class_get_pad_template (element_class, "src");
136
137   if (src_pad_template) {
138     rp->srcpad = gst_pad_new_from_template (src_pad_template, "src");
139   } else {
140     g_warning ("Subclass didn't specify a src pad template");
141     g_assert_not_reached ();
142   }
143
144   gst_pad_set_event_function (rp->srcpad,
145       GST_DEBUG_FUNCPTR (gst_raw_parse_src_event));
146   gst_pad_set_query_function (rp->srcpad,
147       GST_DEBUG_FUNCPTR (gst_raw_parse_src_query));
148   gst_element_add_pad (GST_ELEMENT (rp), rp->srcpad);
149
150   rp->adapter = gst_adapter_new ();
151
152   rp->fps_n = 1;
153   rp->fps_d = 0;
154   rp->framesize = 1;
155
156   gst_raw_parse_reset (rp);
157 }
158
159 static void
160 gst_raw_parse_dispose (GObject * object)
161 {
162   GstRawParse *rp = GST_RAW_PARSE (object);
163
164   if (rp->adapter) {
165     g_object_unref (rp->adapter);
166     rp->adapter = NULL;
167   }
168
169   G_OBJECT_CLASS (parent_class)->dispose (object);
170 }
171
172 void
173 gst_raw_parse_class_set_src_pad_template (GstRawParseClass * klass,
174     const GstCaps * allowed_caps)
175 {
176   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
177
178   g_return_if_fail (GST_IS_RAW_PARSE_CLASS (klass));
179   g_return_if_fail (allowed_caps != NULL);
180   g_return_if_fail (GST_IS_CAPS (allowed_caps));
181
182   gst_element_class_add_pad_template (element_class,
183       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
184           gst_caps_copy (allowed_caps)));
185 }
186
187 void
188 gst_raw_parse_class_set_multiple_frames_per_buffer (GstRawParseClass * klass,
189     gboolean multiple_frames)
190 {
191   g_return_if_fail (GST_IS_RAW_PARSE_CLASS (klass));
192
193   klass->multiple_frames_per_buffer = multiple_frames;
194 }
195
196 static void
197 gst_raw_parse_reset (GstRawParse * rp)
198 {
199   rp->n_frames = 0;
200   rp->discont = TRUE;
201   rp->negotiated = FALSE;
202
203   gst_segment_init (&rp->segment, GST_FORMAT_TIME);
204   gst_adapter_clear (rp->adapter);
205 }
206
207 static gboolean
208 gst_raw_parse_set_src_caps (GstRawParse * rp)
209 {
210   GstRawParseClass *rp_class = GST_RAW_PARSE_GET_CLASS (rp);
211   GstCaps *caps;
212
213   if (rp->negotiated)
214     return TRUE;
215
216   if (rp_class->get_caps) {
217     caps = rp_class->get_caps (rp);
218   } else {
219     GST_WARNING
220         ("Subclass doesn't implement get_caps() method, using ANY caps");
221     caps = gst_caps_new_any ();
222   }
223
224   rp->negotiated = gst_pad_set_caps (rp->srcpad, caps);
225   gst_caps_unref (caps);
226
227   return rp->negotiated;
228 }
229
230 static GstFlowReturn
231 gst_raw_parse_push_buffer (GstRawParse * rp, GstBuffer * buffer)
232 {
233   GstFlowReturn ret;
234   gint nframes;
235   GstRawParseClass *rpclass;
236
237   rpclass = GST_RAW_PARSE_GET_CLASS (rp);
238
239   nframes = gst_buffer_get_size (buffer) / rp->framesize;
240
241   if (rp->segment.rate < 0) {
242     rp->n_frames -= nframes;
243     rp->discont = TRUE;
244   }
245
246   GST_BUFFER_OFFSET (buffer) = rp->n_frames;
247   GST_BUFFER_OFFSET_END (buffer) = rp->n_frames + nframes;
248
249   if (rp->fps_n) {
250     GST_BUFFER_TIMESTAMP (buffer) =
251         gst_util_uint64_scale (rp->n_frames, GST_SECOND * rp->fps_d, rp->fps_n);
252     GST_BUFFER_DURATION (buffer) =
253         gst_util_uint64_scale ((rp->n_frames + nframes) * GST_SECOND, rp->fps_d,
254         rp->fps_n) - GST_BUFFER_TIMESTAMP (buffer);
255   } else {
256     GST_BUFFER_TIMESTAMP (buffer) = rp->segment.start;
257     GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
258   }
259
260   if (rpclass->set_buffer_flags) {
261     rpclass->set_buffer_flags (rp, buffer);
262   }
263
264   if (rp->discont) {
265     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
266     rp->discont = FALSE;
267   }
268
269   if (rp->segment.rate >= 0) {
270     rp->offset += gst_buffer_get_size (buffer);
271     rp->n_frames += nframes;
272   }
273
274   rp->segment.position = GST_BUFFER_TIMESTAMP (buffer);
275
276   GST_LOG_OBJECT (rp, "Pushing buffer with time %" GST_TIME_FORMAT,
277       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
278
279   ret = gst_pad_push (rp->srcpad, buffer);
280
281   return ret;
282 }
283
284 static GstFlowReturn
285 gst_raw_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
286 {
287   GstRawParse *rp = GST_RAW_PARSE (parent);
288   GstFlowReturn ret = GST_FLOW_OK;
289   GstRawParseClass *rp_class = GST_RAW_PARSE_GET_CLASS (rp);
290   guint buffersize;
291
292   if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))) {
293     GST_DEBUG_OBJECT (rp, "received DISCONT buffer");
294     gst_adapter_clear (rp->adapter);
295     rp->discont = TRUE;
296   }
297
298   if (!gst_raw_parse_set_src_caps (rp))
299     goto no_caps;
300
301   if (rp->start_segment) {
302     GST_DEBUG_OBJECT (rp, "sending start segment");
303     gst_pad_push_event (rp->srcpad, rp->start_segment);
304     rp->start_segment = NULL;
305   }
306
307   gst_adapter_push (rp->adapter, buffer);
308
309   if (rp_class->multiple_frames_per_buffer) {
310     buffersize = gst_adapter_available (rp->adapter);
311     buffersize -= buffersize % rp->framesize;
312   } else {
313     buffersize = rp->framesize;
314   }
315
316   while (gst_adapter_available (rp->adapter) >= buffersize) {
317     buffer = gst_adapter_take_buffer (rp->adapter, buffersize);
318
319     ret = gst_raw_parse_push_buffer (rp, buffer);
320     if (ret != GST_FLOW_OK)
321       break;
322   }
323 done:
324
325   return ret;
326
327   /* ERRORS */
328 no_caps:
329   {
330     GST_ERROR_OBJECT (rp, "could not set caps");
331     ret = GST_FLOW_NOT_NEGOTIATED;
332     goto done;
333   }
334 }
335
336 static void
337 gst_raw_parse_loop (GstElement * element)
338 {
339   GstRawParse *rp = GST_RAW_PARSE (element);
340   GstRawParseClass *rp_class = GST_RAW_PARSE_GET_CLASS (rp);
341   GstFlowReturn ret;
342   GstBuffer *buffer;
343   gint size;
344
345   if (G_UNLIKELY (rp->push_stream_start)) {
346     gchar *stream_id;
347     GstEvent *event;
348
349     stream_id =
350         gst_pad_create_stream_id (rp->srcpad, GST_ELEMENT_CAST (rp), NULL);
351
352     event = gst_event_new_stream_start (stream_id);
353     gst_event_set_group_id (event, gst_util_group_id_next ());
354
355     GST_DEBUG_OBJECT (rp, "Pushing STREAM_START");
356     gst_pad_push_event (rp->srcpad, event);
357     rp->push_stream_start = FALSE;
358     g_free (stream_id);
359   }
360
361   if (!gst_raw_parse_set_src_caps (rp))
362     goto no_caps;
363
364   if (rp->start_segment) {
365     GST_DEBUG_OBJECT (rp, "sending start segment");
366     gst_pad_push_event (rp->srcpad, rp->start_segment);
367     rp->start_segment = NULL;
368   }
369
370   if (rp_class->multiple_frames_per_buffer && rp->framesize < 4096)
371     size = 4096 - (4096 % rp->framesize);
372   else
373     size = rp->framesize;
374
375   if (rp->segment.rate >= 0) {
376     if (rp->offset + size > rp->upstream_length) {
377       GstFormat fmt = GST_FORMAT_BYTES;
378
379       if (!gst_pad_peer_query_duration (rp->sinkpad, fmt, &rp->upstream_length)) {
380         GST_WARNING_OBJECT (rp,
381             "Could not get upstream duration, trying to pull frame by frame");
382         size = rp->framesize;
383       } else if (rp->upstream_length < rp->offset + rp->framesize) {
384         ret = GST_FLOW_EOS;
385         goto pause;
386       } else if (rp->offset + size > rp->upstream_length) {
387         size = rp->upstream_length - rp->offset;
388         size -= size % rp->framesize;
389       }
390     }
391   } else {
392     if (rp->offset == 0) {
393       ret = GST_FLOW_EOS;
394       goto pause;
395     } else if (rp->offset < size) {
396       size -= rp->offset;
397     }
398     rp->offset -= size;
399   }
400
401   buffer = NULL;
402   ret = gst_pad_pull_range (rp->sinkpad, rp->offset, size, &buffer);
403
404   if (ret != GST_FLOW_OK) {
405     GST_DEBUG_OBJECT (rp, "pull_range (%" G_GINT64_FORMAT ", %u) "
406         "failed, flow: %s", rp->offset, size, gst_flow_get_name (ret));
407     buffer = NULL;
408     goto pause;
409   }
410
411   if (gst_buffer_get_size (buffer) < size) {
412     GST_DEBUG_OBJECT (rp, "Short read at offset %" G_GINT64_FORMAT
413         ", got only %" G_GSIZE_FORMAT " of %u bytes", rp->offset,
414         gst_buffer_get_size (buffer), size);
415
416     if (size > rp->framesize) {
417       gst_buffer_set_size (buffer, gst_buffer_get_size (buffer) -
418           gst_buffer_get_size (buffer) % rp->framesize);
419     } else {
420       gst_buffer_unref (buffer);
421       buffer = NULL;
422       ret = GST_FLOW_EOS;
423       goto pause;
424     }
425   }
426
427   ret = gst_raw_parse_push_buffer (rp, buffer);
428   if (ret != GST_FLOW_OK)
429     goto pause;
430
431   return;
432
433   /* ERRORS */
434 no_caps:
435   {
436     GST_ERROR_OBJECT (rp, "could not negotiate caps");
437     ret = GST_FLOW_NOT_NEGOTIATED;
438     goto pause;
439   }
440 pause:
441   {
442     const gchar *reason = gst_flow_get_name (ret);
443
444     GST_LOG_OBJECT (rp, "pausing task, reason %s", reason);
445     gst_pad_pause_task (rp->sinkpad);
446
447     if (ret == GST_FLOW_EOS) {
448       if (rp->segment.flags & GST_SEEK_FLAG_SEGMENT) {
449         GstClockTime stop;
450
451         GST_LOG_OBJECT (rp, "Sending segment done");
452
453         if ((stop = rp->segment.stop) == -1)
454           stop = rp->segment.duration;
455
456         gst_element_post_message (GST_ELEMENT_CAST (rp),
457             gst_message_new_segment_done (GST_OBJECT_CAST (rp),
458                 rp->segment.format, stop));
459         gst_pad_push_event (rp->srcpad,
460             gst_event_new_segment_done (rp->segment.format, stop));
461       } else {
462         GST_LOG_OBJECT (rp, "Sending EOS, at end of stream");
463         gst_pad_push_event (rp->srcpad, gst_event_new_eos ());
464       }
465     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
466       GST_ELEMENT_ERROR (rp, STREAM, FAILED,
467           ("Internal data stream error."),
468           ("stream stopped, reason %s", reason));
469       gst_pad_push_event (rp->srcpad, gst_event_new_eos ());
470     }
471     return;
472   }
473 }
474
475 static gboolean
476 gst_raw_parse_sink_activate (GstPad * sinkpad, GstObject * parent)
477 {
478   GstQuery *query;
479   gboolean pull_mode = FALSE;
480
481   query = gst_query_new_scheduling ();
482
483   if (gst_pad_peer_query (sinkpad, query))
484     pull_mode = gst_query_has_scheduling_mode_with_flags (query,
485         GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
486
487   gst_query_unref (query);
488
489   if (pull_mode) {
490     GST_DEBUG ("going to pull mode");
491     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
492   } else {
493     GST_DEBUG ("going to push (streaming) mode");
494     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
495   }
496 }
497
498 static gboolean
499 gst_raw_parse_sink_activatemode (GstPad * sinkpad, GstObject * parent,
500     GstPadMode mode, gboolean active)
501 {
502   GstRawParse *rp = GST_RAW_PARSE (parent);
503   gboolean result;
504
505   switch (mode) {
506     case GST_PAD_MODE_PULL:
507       if (active) {
508         GstFormat format;
509         gint64 duration;
510
511         /* get the duration in bytes */
512         format = GST_FORMAT_BYTES;
513         result = gst_pad_peer_query_duration (sinkpad, format, &duration);
514         if (result) {
515           GST_DEBUG_OBJECT (rp, "got duration %" GST_TIME_FORMAT,
516               GST_TIME_ARGS (duration));
517           rp->upstream_length = duration;
518           /* convert to time */
519           gst_raw_parse_convert (rp, format, duration, GST_FORMAT_TIME,
520               &duration);
521         } else {
522           rp->upstream_length = -1;
523           duration = -1;
524         }
525         rp->segment.duration = duration;
526
527         rp->push_stream_start = TRUE;
528
529         result = gst_raw_parse_handle_seek_pull (rp, NULL);
530         rp->mode = mode;
531       } else {
532         result = gst_pad_stop_task (sinkpad);
533       }
534       return result;
535     case GST_PAD_MODE_PUSH:
536       rp->mode = mode;
537       return TRUE;
538     default:
539       return FALSE;
540   }
541 }
542
543 static GstStateChangeReturn
544 gst_raw_parse_change_state (GstElement * element, GstStateChange transition)
545 {
546   GstRawParse *rp = GST_RAW_PARSE (element);
547   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
548
549   switch (transition) {
550     case GST_STATE_CHANGE_READY_TO_PAUSED:
551       gst_segment_init (&rp->segment, GST_FORMAT_TIME);
552       rp->segment.position = 0;
553     default:
554       break;
555   }
556
557   if (GST_ELEMENT_CLASS (parent_class)->change_state)
558     ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
559
560   switch (transition) {
561     case GST_STATE_CHANGE_PAUSED_TO_READY:
562       gst_raw_parse_reset (rp);
563       break;
564     default:
565       break;
566   }
567
568   return ret;
569 }
570
571 static gboolean
572 gst_raw_parse_convert (GstRawParse * rp,
573     GstFormat src_format, gint64 src_value,
574     GstFormat dest_format, gint64 * dest_value)
575 {
576   gboolean ret = FALSE;
577
578   GST_DEBUG ("converting value %" G_GINT64_FORMAT " from %s (%d) to %s (%d)",
579       src_value, gst_format_get_name (src_format), src_format,
580       gst_format_get_name (dest_format), dest_format);
581
582   if (src_format == dest_format) {
583     *dest_value = src_value;
584     ret = TRUE;
585     goto done;
586   }
587
588   if (src_value == -1) {
589     *dest_value = -1;
590     ret = TRUE;
591     goto done;
592   }
593
594   /* bytes to frames */
595   if (src_format == GST_FORMAT_BYTES && dest_format == GST_FORMAT_DEFAULT) {
596     if (rp->framesize != 0) {
597       *dest_value = gst_util_uint64_scale_int (src_value, 1, rp->framesize);
598     } else {
599       GST_ERROR ("framesize is 0");
600       *dest_value = 0;
601     }
602     ret = TRUE;
603     goto done;
604   }
605
606   /* frames to bytes */
607   if (src_format == GST_FORMAT_DEFAULT && dest_format == GST_FORMAT_BYTES) {
608     *dest_value = gst_util_uint64_scale_int (src_value, rp->framesize, 1);
609     ret = TRUE;
610     goto done;
611   }
612
613   /* time to frames */
614   if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_DEFAULT) {
615     if (rp->fps_d != 0) {
616       *dest_value = gst_util_uint64_scale (src_value,
617           rp->fps_n, GST_SECOND * rp->fps_d);
618     } else {
619       GST_ERROR ("framerate denominator is 0");
620       *dest_value = 0;
621     }
622     ret = TRUE;
623     goto done;
624   }
625
626   /* frames to time */
627   if (src_format == GST_FORMAT_DEFAULT && dest_format == GST_FORMAT_TIME) {
628     if (rp->fps_n != 0) {
629       *dest_value = gst_util_uint64_scale (src_value,
630           GST_SECOND * rp->fps_d, rp->fps_n);
631     } else {
632       GST_ERROR ("framerate numerator is 0");
633       *dest_value = 0;
634     }
635     ret = TRUE;
636     goto done;
637   }
638
639   /* time to bytes */
640   if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_BYTES) {
641     if (rp->fps_d != 0) {
642       *dest_value = gst_util_uint64_scale (src_value,
643           rp->fps_n * rp->framesize, GST_SECOND * rp->fps_d);
644     } else {
645       GST_ERROR ("framerate denominator is 0");
646       *dest_value = 0;
647     }
648     ret = TRUE;
649     goto done;
650   }
651
652   /* bytes to time */
653   if (src_format == GST_FORMAT_BYTES && dest_format == GST_FORMAT_TIME) {
654     if (rp->fps_n != 0 && rp->framesize != 0) {
655       *dest_value = gst_util_uint64_scale (src_value,
656           GST_SECOND * rp->fps_d, rp->fps_n * rp->framesize);
657     } else {
658       GST_ERROR ("framerate denominator and/or framesize is 0");
659       *dest_value = 0;
660     }
661     ret = TRUE;
662   }
663
664 done:
665
666   GST_DEBUG ("ret=%d result %" G_GINT64_FORMAT, ret, *dest_value);
667
668   return ret;
669 }
670
671
672 static gboolean
673 gst_raw_parse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
674 {
675   GstRawParse *rp = GST_RAW_PARSE (parent);
676   gboolean ret;
677
678   switch (GST_EVENT_TYPE (event)) {
679     case GST_EVENT_EOS:
680     case GST_EVENT_FLUSH_STOP:
681       /* Only happens in push mode */
682       gst_raw_parse_reset (rp);
683       ret = gst_pad_push_event (rp->srcpad, event);
684       break;
685     case GST_EVENT_SEGMENT:
686     {
687       GstSegment segment;
688
689       /* Only happens in push mode */
690
691       gst_event_copy_segment (event, &segment);
692
693       if (segment.format != GST_FORMAT_TIME) {
694         gst_event_unref (event);
695
696         segment.format = GST_FORMAT_TIME;
697
698         ret =
699             gst_raw_parse_convert (rp, segment.format, segment.start,
700             GST_FORMAT_TIME, (gint64 *) & segment.start);
701         ret &= gst_raw_parse_convert (rp, segment.format, segment.time,
702             GST_FORMAT_TIME, (gint64 *) & segment.time);
703         ret &= gst_raw_parse_convert (rp, segment.format, segment.stop,
704             GST_FORMAT_TIME, (gint64 *) & segment.stop);
705         if (!ret) {
706           GST_ERROR_OBJECT (rp,
707               "Failed converting to GST_FORMAT_TIME format (%d)",
708               segment.format);
709           break;
710         }
711
712         event = gst_event_new_segment (&segment);
713       }
714
715       gst_segment_copy_into (&segment, &rp->segment);
716
717       if (rp->start_segment)
718         gst_event_unref (rp->start_segment);
719       rp->start_segment = event;
720       ret = TRUE;
721       break;
722     }
723     default:
724       ret = gst_pad_event_default (pad, parent, event);
725       break;
726   }
727
728   return ret;
729 }
730
731
732 static gboolean
733 gst_raw_parse_handle_seek_push (GstRawParse * rp, GstEvent * event)
734 {
735   GstFormat format;
736   gdouble rate;
737   GstSeekFlags flags;
738   GstSeekType start_type, stop_type;
739   gint64 start, stop;
740   gboolean ret = FALSE;
741
742   gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
743       &stop_type, &stop);
744
745   /* can't seek backwards yet */
746   if (rate <= 0.0)
747     goto wrong_rate;
748
749   /* First try if upstream handles the seek */
750   ret = gst_pad_push_event (rp->sinkpad, event);
751   if (ret)
752     return ret;
753
754   /* Otherwise convert to bytes and push upstream */
755   if (format == GST_FORMAT_TIME || format == GST_FORMAT_DEFAULT) {
756     ret = gst_raw_parse_convert (rp, format, start, GST_FORMAT_BYTES, &start);
757     ret &= gst_raw_parse_convert (rp, format, stop, GST_FORMAT_BYTES, &stop);
758
759     if (ret) {
760       /* Seek on a frame boundary */
761       start -= start % rp->framesize;
762       if (stop != -1)
763         stop += rp->framesize - stop % rp->framesize;
764
765       event =
766           gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, start_type,
767           start, stop_type, stop);
768
769       ret = gst_pad_push_event (rp->sinkpad, event);
770     } else {
771       GST_DEBUG_OBJECT (rp, "Seek failed: couldn't convert to byte positions");
772     }
773   } else {
774     GST_DEBUG_OBJECT (rp,
775         "seeking is only supported in TIME or DEFAULT format");
776   }
777   return ret;
778
779   /* ERRORS */
780 wrong_rate:
781   {
782     GST_DEBUG_OBJECT (rp, "Seek failed: negative rates not supported yet");
783     return FALSE;
784   }
785 }
786
787 static gboolean
788 gst_raw_parse_handle_seek_pull (GstRawParse * rp, GstEvent * event)
789 {
790   gdouble rate;
791   GstFormat format;
792   GstSeekFlags flags;
793   GstSeekType start_type, stop_type;
794   gint64 start, stop;
795   gint64 last_stop;
796   gboolean ret = FALSE;
797   gboolean flush;
798   GstSegment seeksegment;
799
800   if (event) {
801     gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
802         &stop_type, &stop);
803
804     /* convert input offsets to time */
805     ret = gst_raw_parse_convert (rp, format, start, GST_FORMAT_TIME, &start);
806     ret &= gst_raw_parse_convert (rp, format, stop, GST_FORMAT_TIME, &stop);
807     if (!ret)
808       goto convert_failed;
809
810     GST_DEBUG_OBJECT (rp, "converted start - stop to time");
811
812     format = GST_FORMAT_TIME;
813
814     gst_event_unref (event);
815   } else {
816     format = GST_FORMAT_TIME;
817     flags = 0;
818   }
819
820   flush = ((flags & GST_SEEK_FLAG_FLUSH) != 0);
821
822   /* start flushing up and downstream so that the loop function pauses and we
823    * can acquire the STREAM_LOCK. */
824   if (flush) {
825     GST_LOG_OBJECT (rp, "flushing");
826     gst_pad_push_event (rp->sinkpad, gst_event_new_flush_start ());
827     gst_pad_push_event (rp->srcpad, gst_event_new_flush_start ());
828   } else {
829     GST_LOG_OBJECT (rp, "pause task");
830     gst_pad_pause_task (rp->sinkpad);
831   }
832
833   GST_PAD_STREAM_LOCK (rp->sinkpad);
834
835   memcpy (&seeksegment, &rp->segment, sizeof (GstSegment));
836
837   if (event) {
838     /* configure the seek values */
839     gst_segment_do_seek (&seeksegment, rate, format, flags,
840         start_type, start, stop_type, stop, NULL);
841   }
842
843   /* get the desired position */
844   last_stop = seeksegment.position;
845
846   GST_LOG_OBJECT (rp, "seeking to %" GST_TIME_FORMAT,
847       GST_TIME_ARGS (last_stop));
848
849   /* convert the desired position to bytes */
850   ret =
851       gst_raw_parse_convert (rp, format, last_stop, GST_FORMAT_BYTES,
852       &last_stop);
853
854   /* prepare for streaming */
855   if (flush) {
856     GST_LOG_OBJECT (rp, "stop flush");
857     gst_pad_push_event (rp->sinkpad, gst_event_new_flush_stop (TRUE));
858     gst_pad_push_event (rp->srcpad, gst_event_new_flush_stop (TRUE));
859   }
860
861   if (ret) {
862     /* seek done */
863
864     /* Seek on a frame boundary */
865     last_stop -= last_stop % rp->framesize;
866
867     rp->offset = last_stop;
868     rp->n_frames = last_stop / rp->framesize;
869
870     GST_LOG_OBJECT (rp, "seeking to bytes %" G_GINT64_FORMAT, last_stop);
871
872     memcpy (&rp->segment, &seeksegment, sizeof (GstSegment));
873
874     if (rp->segment.flags & GST_SEEK_FLAG_SEGMENT) {
875       gst_element_post_message (GST_ELEMENT_CAST (rp),
876           gst_message_new_segment_start (GST_OBJECT_CAST (rp),
877               rp->segment.format, rp->segment.position));
878     }
879
880     /* for deriving a stop position for the playback segment from the seek
881      * segment, we must take the duration when the stop is not set */
882     if ((stop = rp->segment.stop) == -1)
883       stop = rp->segment.duration;
884
885     GST_DEBUG_OBJECT (rp, "preparing newsegment from %" G_GINT64_FORMAT
886         " to %" G_GINT64_FORMAT, rp->segment.start, stop);
887
888     /* now replace the old segment so that we send it in the stream thread the
889      * next time it is scheduled. */
890     if (rp->start_segment)
891       gst_event_unref (rp->start_segment);
892     rp->start_segment = gst_event_new_segment (&rp->segment);
893   }
894   rp->discont = TRUE;
895
896   GST_LOG_OBJECT (rp, "start streaming");
897   gst_pad_start_task (rp->sinkpad, (GstTaskFunction) gst_raw_parse_loop, rp,
898       NULL);
899
900   GST_PAD_STREAM_UNLOCK (rp->sinkpad);
901
902   return ret;
903
904   /* ERRORS */
905 convert_failed:
906   {
907     GST_DEBUG_OBJECT (rp, "Seek failed: couldn't convert to byte positions");
908     return FALSE;
909   }
910 }
911
912 static gboolean
913 gst_raw_parse_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
914 {
915   GstRawParse *rp = GST_RAW_PARSE (parent);
916   gboolean ret;
917
918   switch (GST_EVENT_TYPE (event)) {
919     case GST_EVENT_SEEK:
920       if (rp->mode == GST_PAD_MODE_PUSH)
921         ret = gst_raw_parse_handle_seek_push (rp, event);
922       else
923         ret = gst_raw_parse_handle_seek_pull (rp, event);
924       break;
925     default:
926       ret = gst_pad_event_default (pad, parent, event);
927       break;
928   }
929
930   return ret;
931 }
932
933 static gboolean
934 gst_raw_parse_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
935 {
936   GstRawParse *rp = GST_RAW_PARSE (parent);
937   gboolean ret = FALSE;
938
939   GST_DEBUG ("src_query %s", gst_query_type_get_name (GST_QUERY_TYPE (query)));
940
941   switch (GST_QUERY_TYPE (query)) {
942     case GST_QUERY_POSITION:
943     {
944       GstFormat format;
945       gint64 time, value;
946
947       GST_LOG ("query position");
948
949       gst_query_parse_position (query, &format, NULL);
950
951       time = rp->segment.position;
952       ret = gst_raw_parse_convert (rp, GST_FORMAT_TIME, time, format, &value);
953
954       gst_query_set_position (query, format, value);
955
956       break;
957     }
958     case GST_QUERY_DURATION:{
959       gint64 duration;
960       GstFormat format;
961       GstQuery *bquery;
962
963       GST_LOG ("query duration");
964       ret = gst_pad_peer_query (rp->sinkpad, query);
965       if (ret)
966         goto done;
967
968       gst_query_parse_duration (query, &format, NULL);
969       /* We only handle TIME and DEFAULT format */
970       if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT)
971         goto error;
972
973       bquery = gst_query_new_duration (GST_FORMAT_BYTES);
974       ret = gst_pad_peer_query (rp->sinkpad, bquery);
975       if (!ret) {
976         gst_query_unref (bquery);
977         goto error;
978       }
979
980       gst_query_parse_duration (bquery, NULL, &duration);
981       gst_query_unref (bquery);
982
983       ret =
984           gst_raw_parse_convert (rp, GST_FORMAT_BYTES, duration, format,
985           &duration);
986       if (ret)
987         gst_query_set_duration (query, format, duration);
988
989       break;
990     }
991     case GST_QUERY_CONVERT:
992     {
993       GstFormat src_fmt, dest_fmt;
994       gint64 src_val, dest_val;
995
996       GST_LOG ("query convert");
997
998       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
999       ret = gst_raw_parse_convert (rp, src_fmt, src_val, dest_fmt, &dest_val);
1000       if (!ret)
1001         goto error;
1002       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
1003       break;
1004     }
1005     case GST_QUERY_SEEKING:{
1006       GstFormat fmt;
1007
1008       ret = TRUE;
1009       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
1010       if (fmt != GST_FORMAT_TIME && fmt != GST_FORMAT_DEFAULT
1011           && fmt != GST_FORMAT_BYTES) {
1012         gst_query_set_seeking (query, fmt, FALSE, -1, -1);
1013       } else if (rp->mode == GST_PAD_MODE_PUSH) {
1014         GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
1015         gboolean seekable;
1016
1017         seekable = gst_pad_peer_query (rp->sinkpad, peerquery);
1018         if (seekable)
1019           gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
1020
1021         gst_query_unref (peerquery);
1022         gst_query_set_seeking (query, fmt, seekable, seekable ? 0 : -1, -1);
1023       } else {
1024         gst_query_set_seeking (query, fmt, TRUE, 0, -1);
1025       }
1026       break;
1027     }
1028     default:
1029       /* else forward upstream */
1030       ret = gst_pad_query_default (pad, parent, query);
1031       break;
1032   }
1033
1034 done:
1035   return ret;
1036
1037   /* ERRORS */
1038 error:
1039   {
1040     GST_DEBUG_OBJECT (rp, "query failed");
1041     goto done;
1042   }
1043 }
1044
1045 void
1046 gst_raw_parse_set_framesize (GstRawParse * rp, int framesize)
1047 {
1048   g_return_if_fail (GST_IS_RAW_PARSE (rp));
1049   g_return_if_fail (!rp->negotiated);
1050
1051   GST_DEBUG_OBJECT (rp, "framesize %d", framesize);
1052   rp->framesize = framesize;
1053 }
1054
1055 void
1056 gst_raw_parse_set_fps (GstRawParse * rp, int fps_n, int fps_d)
1057 {
1058   g_return_if_fail (GST_IS_RAW_PARSE (rp));
1059   g_return_if_fail (!rp->negotiated);
1060
1061   rp->fps_n = fps_n;
1062   rp->fps_d = fps_d;
1063 }
1064
1065 void
1066 gst_raw_parse_get_fps (GstRawParse * rp, int *fps_n, int *fps_d)
1067 {
1068   g_return_if_fail (GST_IS_RAW_PARSE (rp));
1069
1070   if (fps_n)
1071     *fps_n = rp->fps_n;
1072   if (fps_d)
1073     *fps_d = rp->fps_d;
1074 }
1075
1076 gboolean
1077 gst_raw_parse_is_negotiated (GstRawParse * rp)
1078 {
1079   g_return_val_if_fail (GST_IS_RAW_PARSE (rp), FALSE);
1080
1081   return rp->negotiated;
1082 }