Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / gst / subenc / gstsrtenc.c
1 /* GStreamer
2  * Copyright (C) <2008> Thijs Vermeir <thijsvermeir@gmail.com>
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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include "string.h"
24
25 #include "gstsrtenc.h"
26 #include <gst/controller/gstcontroller.h>
27
28 GST_DEBUG_CATEGORY_STATIC (srtenc_debug);
29 #define GST_CAT_DEFAULT srtenc_debug
30
31 enum
32 {
33   ARG_0,
34   ARG_TIMESTAMP,
35   ARG_DURATION
36 };
37
38 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
39     GST_PAD_SRC,
40     GST_PAD_ALWAYS,
41     GST_STATIC_CAPS ("application/x-subtitle"));
42
43 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
44     GST_PAD_SINK,
45     GST_PAD_ALWAYS,
46     GST_STATIC_CAPS ("text/plain; text/x-pango-markup"));
47
48 static GstFlowReturn gst_srt_enc_chain (GstPad * pad, GstBuffer * buf);
49 static gchar *gst_srt_enc_timeconvertion (GstSrtEnc * srtenc, GstBuffer * buf);
50 static gchar *gst_srt_enc_timestamp_to_string (GstClockTime timestamp);
51 static void gst_srt_enc_get_property (GObject * object, guint prop_id,
52     GValue * value, GParamSpec * pspec);
53 static void gst_srt_enc_reset (GstSrtEnc * srtenc);
54 static void gst_srt_enc_set_property (GObject * object, guint prop_id,
55     const GValue * value, GParamSpec * pspec);
56
57 GST_BOILERPLATE (GstSrtEnc, gst_srt_enc, GstElement, GST_TYPE_ELEMENT);
58
59 static gchar *
60 gst_srt_enc_timestamp_to_string (GstClockTime timestamp)
61 {
62   guint h, m, s, ms;
63
64   h = timestamp / (3600 * GST_SECOND);
65
66   timestamp -= h * 3600 * GST_SECOND;
67   m = timestamp / (60 * GST_SECOND);
68
69   timestamp -= m * 60 * GST_SECOND;
70   s = timestamp / GST_SECOND;
71
72   timestamp -= s * GST_SECOND;
73   ms = timestamp / GST_MSECOND;
74
75   return g_strdup_printf ("%.2d:%.2d:%.2d,%.3d", h, m, s, ms);
76 }
77
78 static gchar *
79 gst_srt_enc_timeconvertion (GstSrtEnc * srtenc, GstBuffer * buf)
80 {
81   gchar *start_time =
82       gst_srt_enc_timestamp_to_string (GST_BUFFER_TIMESTAMP (buf) +
83       srtenc->timestamp);
84   gchar *stop_time =
85       gst_srt_enc_timestamp_to_string (GST_BUFFER_TIMESTAMP (buf) +
86       srtenc->timestamp + GST_BUFFER_DURATION (buf) + srtenc->duration);
87   gchar *string = g_strdup_printf ("%s --> %s\n", start_time, stop_time);
88
89   g_free (start_time);
90   g_free (stop_time);
91   return string;
92 }
93
94 static GstFlowReturn
95 gst_srt_enc_chain (GstPad * pad, GstBuffer * buf)
96 {
97   GstSrtEnc *srtenc;
98   GstBuffer *new_buffer;
99   gchar *timing;
100   gchar *string;
101
102   srtenc = GST_SRT_ENC (gst_pad_get_parent_element (pad));
103   gst_object_sync_values (G_OBJECT (srtenc), GST_BUFFER_TIMESTAMP (buf));
104   timing = gst_srt_enc_timeconvertion (srtenc, buf);
105   string = g_strdup_printf ("%d\n%s", srtenc->counter++, timing);
106   g_free (timing);
107   new_buffer =
108       gst_buffer_new_and_alloc (strlen (string) + GST_BUFFER_SIZE (buf) + 2);
109   memcpy (GST_BUFFER_DATA (new_buffer), string, strlen (string));
110   memcpy (GST_BUFFER_DATA (new_buffer) + strlen (string), GST_BUFFER_DATA (buf),
111       GST_BUFFER_SIZE (buf));
112   memcpy (GST_BUFFER_DATA (new_buffer) + GST_BUFFER_SIZE (new_buffer) - 2,
113       "\n\n", 2);
114   g_free (string);
115
116   gst_buffer_unref (buf);
117
118   return gst_pad_push (srtenc->srcpad, new_buffer);
119 }
120
121 static void
122 gst_srt_enc_base_init (gpointer klass)
123 {
124   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
125
126   gst_element_class_add_static_pad_template (element_class,
127       &sink_template);
128   gst_element_class_add_static_pad_template (element_class, &src_template);
129
130   gst_element_class_set_details_simple (element_class,
131       "Srt encoder", "Codec/Encoder/Subtitle",
132       "Srt subtitle encoder", "Thijs Vermeir <thijsvermeir@gmail.com>");
133 }
134
135 static void
136 gst_srt_enc_reset (GstSrtEnc * srtenc)
137 {
138   srtenc->counter = 1;
139 }
140
141 static GstStateChangeReturn
142 gst_srt_enc_change_state (GstElement * element, GstStateChange transition)
143 {
144   GstStateChangeReturn ret;
145   GstSrtEnc *srtenc = GST_SRT_ENC (element);
146
147   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
148   if (ret == GST_STATE_CHANGE_FAILURE)
149     return ret;
150
151   switch (transition) {
152     case GST_STATE_CHANGE_PAUSED_TO_READY:
153       gst_srt_enc_reset (srtenc);
154       break;
155     default:
156       break;
157   }
158
159   return ret;
160 }
161
162 static void
163 gst_srt_enc_get_property (GObject * object,
164     guint prop_id, GValue * value, GParamSpec * pspec)
165 {
166   GstSrtEnc *srtenc;
167
168   srtenc = GST_SRT_ENC (object);
169
170   switch (prop_id) {
171     case ARG_TIMESTAMP:
172       g_value_set_int64 (value, srtenc->timestamp);
173       break;
174     case ARG_DURATION:
175       g_value_set_int64 (value, srtenc->duration);
176       break;
177     default:
178       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
179       break;
180   }
181 }
182
183 static void
184 gst_srt_enc_set_property (GObject * object,
185     guint prop_id, const GValue * value, GParamSpec * pspec)
186 {
187
188   GstSrtEnc *srtenc;
189
190   srtenc = GST_SRT_ENC (object);
191
192   switch (prop_id) {
193     case ARG_TIMESTAMP:
194       srtenc->timestamp = g_value_get_int64 (value);
195       break;
196     case ARG_DURATION:
197       srtenc->duration = g_value_get_int64 (value);
198       break;
199     default:
200       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
201       break;
202   }
203 }
204
205 static void
206 gst_srt_enc_class_init (GstSrtEncClass * klass)
207 {
208   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
209   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
210
211   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_srt_enc_set_property);
212   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_srt_enc_get_property);
213
214   element_class->change_state = GST_DEBUG_FUNCPTR (gst_srt_enc_change_state);
215
216   g_object_class_install_property (gobject_class, ARG_TIMESTAMP,
217       g_param_spec_int64 ("timestamp", "Offset for the starttime",
218           "Offset for the starttime for the subtitles", G_MININT64, G_MAXINT64,
219           0,
220           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
221   g_object_class_install_property (gobject_class, ARG_DURATION,
222       g_param_spec_int64 ("duration", "Offset for the duration",
223           "Offset for the duration of the subtitles", G_MININT64, G_MAXINT64,
224           0,
225           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
226
227   GST_DEBUG_CATEGORY_INIT (srtenc_debug, "srtenc", 0,
228       "SubRip subtitle encoder");
229 }
230
231 static void
232 gst_srt_enc_init (GstSrtEnc * srtenc, GstSrtEncClass * klass)
233 {
234   gst_srt_enc_reset (srtenc);
235
236   srtenc->srcpad = gst_pad_new_from_static_template (&src_template, "src");
237   gst_element_add_pad (GST_ELEMENT (srtenc), srtenc->srcpad);
238   srtenc->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
239   gst_element_add_pad (GST_ELEMENT (srtenc), srtenc->sinkpad);
240   gst_pad_set_chain_function (srtenc->sinkpad, gst_srt_enc_chain);
241 }