• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include <gst/gst.h>
25 #include <gst/video/video.h>
26 
27 #include "gstvideosegmentclip.h"
28 
29 static GstStaticPadTemplate sink_pad_template =
30 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
31     GST_STATIC_CAPS ("video/x-raw, framerate=" GST_VIDEO_FPS_RANGE));
32 
33 static GstStaticPadTemplate src_pad_template =
34 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
35     GST_STATIC_CAPS ("video/x-raw, framerate=" GST_VIDEO_FPS_RANGE));
36 
37 static void gst_video_segment_clip_reset (GstSegmentClip * self);
38 static GstFlowReturn gst_video_segment_clip_clip_buffer (GstSegmentClip * self,
39     GstBuffer * buffer, GstBuffer ** outbuf);
40 static gboolean gst_video_segment_clip_set_caps (GstSegmentClip * self,
41     GstCaps * caps);
42 
43 GST_DEBUG_CATEGORY_STATIC (gst_video_segment_clip_debug);
44 #define GST_CAT_DEFAULT gst_video_segment_clip_debug
45 
46 G_DEFINE_TYPE (GstVideoSegmentClip, gst_video_segment_clip,
47     GST_TYPE_SEGMENT_CLIP);
48 GST_ELEMENT_REGISTER_DEFINE (videosegmentclip, "videosegmentclip",
49     GST_RANK_NONE, GST_TYPE_VIDEO_SEGMENT_CLIP);
50 
51 static void
gst_video_segment_clip_class_init(GstVideoSegmentClipClass * klass)52 gst_video_segment_clip_class_init (GstVideoSegmentClipClass * klass)
53 {
54   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
55   GstSegmentClipClass *segment_clip_klass = GST_SEGMENT_CLIP_CLASS (klass);
56 
57   GST_DEBUG_CATEGORY_INIT (gst_video_segment_clip_debug, "videosegmentclip", 0,
58       "videosegmentclip element");
59 
60   gst_element_class_set_static_metadata (element_class,
61       "Video buffer segment clipper",
62       "Filter/Video",
63       "Clips video buffers to the configured segment",
64       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
65 
66   gst_element_class_add_static_pad_template (element_class, &sink_pad_template);
67   gst_element_class_add_static_pad_template (element_class, &src_pad_template);
68 
69   segment_clip_klass->reset = GST_DEBUG_FUNCPTR (gst_video_segment_clip_reset);
70   segment_clip_klass->set_caps =
71       GST_DEBUG_FUNCPTR (gst_video_segment_clip_set_caps);
72   segment_clip_klass->clip_buffer =
73       GST_DEBUG_FUNCPTR (gst_video_segment_clip_clip_buffer);
74 }
75 
76 static void
gst_video_segment_clip_init(GstVideoSegmentClip * self)77 gst_video_segment_clip_init (GstVideoSegmentClip * self)
78 {
79 }
80 
81 static void
gst_video_segment_clip_reset(GstSegmentClip * base)82 gst_video_segment_clip_reset (GstSegmentClip * base)
83 {
84   GstVideoSegmentClip *self = GST_VIDEO_SEGMENT_CLIP (base);
85 
86   GST_DEBUG_OBJECT (self, "Resetting internal state");
87 
88   self->fps_n = self->fps_d = 0;
89 }
90 
91 
92 static GstFlowReturn
gst_video_segment_clip_clip_buffer(GstSegmentClip * base,GstBuffer * buffer,GstBuffer ** outbuf)93 gst_video_segment_clip_clip_buffer (GstSegmentClip * base, GstBuffer * buffer,
94     GstBuffer ** outbuf)
95 {
96   GstVideoSegmentClip *self = GST_VIDEO_SEGMENT_CLIP (base);
97   GstSegment *segment = &base->segment;
98   GstClockTime timestamp, duration;
99   guint64 cstart, cstop;
100   gboolean in_seg;
101 
102   if (!self->fps_d) {
103     GST_ERROR_OBJECT (self, "Not negotiated yet");
104     gst_buffer_unref (buffer);
105     return GST_FLOW_NOT_NEGOTIATED;
106   }
107 
108   if (segment->format != GST_FORMAT_TIME) {
109     GST_DEBUG_OBJECT (self, "Unsupported segment format %s",
110         gst_format_get_name (segment->format));
111     *outbuf = buffer;
112     return GST_FLOW_OK;
113   }
114 
115   if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
116     GST_WARNING_OBJECT (self, "Buffer without valid timestamp");
117     *outbuf = buffer;
118     return GST_FLOW_OK;
119   }
120 
121   if (self->fps_n == 0) {
122     *outbuf = buffer;
123     return GST_FLOW_OK;
124   }
125 
126   timestamp = GST_BUFFER_TIMESTAMP (buffer);
127   duration = GST_BUFFER_DURATION (buffer);
128   if (!GST_CLOCK_TIME_IS_VALID (duration))
129     duration = gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
130 
131   in_seg =
132       gst_segment_clip (segment, GST_FORMAT_TIME, timestamp,
133       timestamp + duration, &cstart, &cstop);
134   if (in_seg) {
135     if (timestamp != cstart || timestamp + duration != cstop) {
136       *outbuf = gst_buffer_make_writable (buffer);
137 
138       GST_BUFFER_TIMESTAMP (*outbuf) = cstart;
139       GST_BUFFER_DURATION (*outbuf) = cstop - cstart;
140     } else {
141       *outbuf = buffer;
142     }
143   } else {
144     GST_DEBUG_OBJECT (self, "Buffer outside the configured segment");
145 
146     gst_buffer_unref (buffer);
147     if (segment->rate >= 0) {
148       if (segment->stop != -1 && timestamp >= segment->stop)
149         return GST_FLOW_EOS;
150     } else {
151       if (segment->start != -1 && timestamp + duration <= segment->start)
152         return GST_FLOW_EOS;
153     }
154   }
155 
156 
157   return GST_FLOW_OK;
158 }
159 
160 static gboolean
gst_video_segment_clip_set_caps(GstSegmentClip * base,GstCaps * caps)161 gst_video_segment_clip_set_caps (GstSegmentClip * base, GstCaps * caps)
162 {
163   GstVideoSegmentClip *self = GST_VIDEO_SEGMENT_CLIP (base);
164   gboolean ret;
165   GstStructure *s;
166   gint fps_n, fps_d;
167 
168   s = gst_caps_get_structure (caps, 0);
169 
170   ret = gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d)
171       && (fps_d != 0);
172 
173   if (ret) {
174     GST_DEBUG_OBJECT (self, "Configured framerate %d/%d", fps_n, fps_d);
175     self->fps_n = fps_n;
176     self->fps_d = fps_d;
177   }
178 
179   return ret;
180 }
181