Initialize Tizen 2.3
[framework/multimedia/gstreamer0.10-ffmpeg.git] / ext / ffmpeg / gstffmpegaudioresample.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * This file:
4  * Copyright (C) 2005 Luca Ognibene <luogni@tin.it>
5  * Copyright (C) 2006 Martin Zlomek <martin.zlomek@itonis.tv>
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., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #ifdef HAVE_FFMPEG_UNINSTALLED
28 #include <avcodec.h>
29 #else
30 #include <libavcodec/avcodec.h>
31 #endif
32
33 #include <gst/gst.h>
34 #include <gst/base/gstbasetransform.h>
35 #include <gst/video/video.h>
36
37 #include "gstffmpeg.h"
38 #include "gstffmpegcodecmap.h"
39
40 typedef struct _GstFFMpegAudioResample
41 {
42   GstBaseTransform element;
43
44   GstPad *sinkpad, *srcpad;
45
46   gint in_rate, out_rate;
47   gint in_channels, out_channels;
48
49   ReSampleContext *res;
50 } GstFFMpegAudioResample;
51
52 typedef struct _GstFFMpegAudioResampleClass
53 {
54   GstBaseTransformClass parent_class;
55 } GstFFMpegAudioResampleClass;
56
57 #define GST_TYPE_FFMPEGAUDIORESAMPLE \
58         (gst_ffmpegaudioresample_get_type())
59 #define GST_FFMPEGAUDIORESAMPLE(obj) \
60         (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGAUDIORESAMPLE,GstFFMpegAudioResample))
61 #define GST_FFMPEGAUDIORESAMPLE_CLASS(klass) \
62         (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGAUDIORESAMPLE,GstFFMpegAudioResampleClass))
63 #define GST_IS_FFMPEGAUDIORESAMPLE(obj) \
64         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGAUDIORESAMPLE))
65 #define GST_IS_FFMPEGAUDIORESAMPLE_CLASS(klass) \
66         (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGAUDIORESAMPLE))
67
68 GType gst_ffmpegaudioresample_get_type (void);
69
70 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
71     GST_PAD_SRC,
72     GST_PAD_ALWAYS,
73     GST_STATIC_CAPS
74     ("audio/x-raw-int, endianness = (int) BYTE_ORDER, signed = (boolean) true, width = (int) 16, depth = (int) 16, channels = (int) { 1 , 2 }, rate = (int) [1, MAX ]")
75     );
76
77 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
78     GST_PAD_SINK,
79     GST_PAD_ALWAYS,
80     GST_STATIC_CAPS
81     ("audio/x-raw-int, endianness = (int) BYTE_ORDER, signed = (boolean) true, width = (int) 16, depth = (int) 16, channels = (int) [ 1 , 6 ], rate = (int) [1, MAX ]")
82     );
83
84 GST_BOILERPLATE (GstFFMpegAudioResample, gst_ffmpegaudioresample,
85     GstBaseTransform, GST_TYPE_BASE_TRANSFORM);
86
87 static void gst_ffmpegaudioresample_finalize (GObject * object);
88
89 static GstCaps *gst_ffmpegaudioresample_transform_caps (GstBaseTransform *
90     trans, GstPadDirection direction, GstCaps * caps);
91 static gboolean gst_ffmpegaudioresample_transform_size (GstBaseTransform *
92     trans, GstPadDirection direction, GstCaps * caps, guint size,
93     GstCaps * othercaps, guint * othersize);
94 static gboolean gst_ffmpegaudioresample_get_unit_size (GstBaseTransform * trans,
95     GstCaps * caps, guint * size);
96 static gboolean gst_ffmpegaudioresample_set_caps (GstBaseTransform * trans,
97     GstCaps * incaps, GstCaps * outcaps);
98 static GstFlowReturn gst_ffmpegaudioresample_transform (GstBaseTransform *
99     trans, GstBuffer * inbuf, GstBuffer * outbuf);
100
101 static void
102 gst_ffmpegaudioresample_base_init (gpointer g_class)
103 {
104   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
105
106   gst_element_class_add_pad_template (element_class,
107       gst_static_pad_template_get (&src_factory));
108   gst_element_class_add_pad_template (element_class,
109       gst_static_pad_template_get (&sink_factory));
110   gst_element_class_set_details_simple (element_class,
111       "FFMPEG Audio resampling element", "Filter/Converter/Audio",
112       "Converts audio from one samplerate to another",
113       "Edward Hervey <bilboed@bilboed.com>");
114 }
115
116 static void
117 gst_ffmpegaudioresample_class_init (GstFFMpegAudioResampleClass * klass)
118 {
119   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
120   GstBaseTransformClass *trans_class = GST_BASE_TRANSFORM_CLASS (klass);
121
122   gobject_class->finalize = gst_ffmpegaudioresample_finalize;
123
124   trans_class->transform_caps =
125       GST_DEBUG_FUNCPTR (gst_ffmpegaudioresample_transform_caps);
126   trans_class->get_unit_size =
127       GST_DEBUG_FUNCPTR (gst_ffmpegaudioresample_get_unit_size);
128   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_ffmpegaudioresample_set_caps);
129   trans_class->transform =
130       GST_DEBUG_FUNCPTR (gst_ffmpegaudioresample_transform);
131   trans_class->transform_size =
132       GST_DEBUG_FUNCPTR (gst_ffmpegaudioresample_transform_size);
133
134   trans_class->passthrough_on_same_caps = TRUE;
135 }
136
137 static void
138 gst_ffmpegaudioresample_init (GstFFMpegAudioResample * resample,
139     GstFFMpegAudioResampleClass * klass)
140 {
141   GstBaseTransform *trans = GST_BASE_TRANSFORM (resample);
142
143   gst_pad_set_bufferalloc_function (trans->sinkpad, NULL);
144
145   resample->res = NULL;
146 }
147
148 static void
149 gst_ffmpegaudioresample_finalize (GObject * object)
150 {
151   GstFFMpegAudioResample *resample = GST_FFMPEGAUDIORESAMPLE (object);
152
153   if (resample->res != NULL)
154     audio_resample_close (resample->res);
155
156   G_OBJECT_CLASS (parent_class)->finalize (object);
157 }
158
159 static GstCaps *
160 gst_ffmpegaudioresample_transform_caps (GstBaseTransform * trans,
161     GstPadDirection direction, GstCaps * caps)
162 {
163   GstCaps *retcaps;
164   GstStructure *struc;
165
166   retcaps = gst_caps_copy (caps);
167   struc = gst_caps_get_structure (retcaps, 0);
168   gst_structure_set (struc, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
169
170   GST_LOG_OBJECT (trans, "returning caps %" GST_PTR_FORMAT, retcaps);
171
172   return retcaps;
173 }
174
175 static gboolean
176 gst_ffmpegaudioresample_transform_size (GstBaseTransform * trans,
177     GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps,
178     guint * othersize)
179 {
180   gint inrate, outrate;
181   gint inchanns, outchanns;
182   GstStructure *ins, *outs;
183   gboolean ret;
184   guint64 conv;
185
186   ins = gst_caps_get_structure (caps, 0);
187   outs = gst_caps_get_structure (othercaps, 0);
188
189   /* Get input/output sample rate and channels */
190   ret = gst_structure_get_int (ins, "rate", &inrate);
191   ret &= gst_structure_get_int (ins, "channels", &inchanns);
192   ret &= gst_structure_get_int (outs, "rate", &outrate);
193   ret &= gst_structure_get_int (outs, "channels", &outchanns);
194
195   if (!ret)
196     return FALSE;
197
198   conv = gst_util_uint64_scale (size, outrate * outchanns, inrate * inchanns);
199   /* Adding padding to the output buffer size, since audio_resample's internal
200    * methods might write a bit further. */
201   *othersize = (guint) conv + 64;
202
203   GST_DEBUG_OBJECT (trans, "Transformed size from %d to %d", size, *othersize);
204
205   return TRUE;
206 }
207
208 static gboolean
209 gst_ffmpegaudioresample_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
210     guint * size)
211 {
212   gint channels;
213   GstStructure *structure;
214   gboolean ret;
215
216   g_assert (size);
217
218   structure = gst_caps_get_structure (caps, 0);
219   ret = gst_structure_get_int (structure, "channels", &channels);
220   g_return_val_if_fail (ret, FALSE);
221
222   *size = 2 * channels;
223
224   return TRUE;
225 }
226
227 static gboolean
228 gst_ffmpegaudioresample_set_caps (GstBaseTransform * trans, GstCaps * incaps,
229     GstCaps * outcaps)
230 {
231   GstFFMpegAudioResample *resample = GST_FFMPEGAUDIORESAMPLE (trans);
232   GstStructure *instructure = gst_caps_get_structure (incaps, 0);
233   GstStructure *outstructure = gst_caps_get_structure (outcaps, 0);
234
235   GST_LOG_OBJECT (resample, "incaps:%" GST_PTR_FORMAT, incaps);
236
237   GST_LOG_OBJECT (resample, "outcaps:%" GST_PTR_FORMAT, outcaps);
238
239   if (!gst_structure_get_int (instructure, "channels", &resample->in_channels))
240     return FALSE;
241   if (!gst_structure_get_int (instructure, "rate", &resample->in_rate))
242     return FALSE;
243
244   if (!gst_structure_get_int (outstructure, "channels",
245           &resample->out_channels))
246     return FALSE;
247   if (!gst_structure_get_int (outstructure, "rate", &resample->out_rate))
248     return FALSE;
249
250   resample->res =
251       audio_resample_init (resample->out_channels, resample->in_channels,
252       resample->out_rate, resample->in_rate);
253   if (resample->res == NULL)
254     return FALSE;
255
256   return TRUE;
257 }
258
259 static GstFlowReturn
260 gst_ffmpegaudioresample_transform (GstBaseTransform * trans, GstBuffer * inbuf,
261     GstBuffer * outbuf)
262 {
263   GstFFMpegAudioResample *resample = GST_FFMPEGAUDIORESAMPLE (trans);
264   gint nbsamples;
265   gint ret;
266
267   gst_buffer_copy_metadata (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS);
268   nbsamples = GST_BUFFER_SIZE (inbuf) / (2 * resample->in_channels);
269
270   GST_LOG_OBJECT (resample, "input buffer duration:%" GST_TIME_FORMAT,
271       GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)));
272
273   GST_DEBUG_OBJECT (resample,
274       "audio_resample(ctx, output:%p [size:%d], input:%p [size:%d], nbsamples:%d",
275       GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf),
276       GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf), nbsamples);
277
278   ret = audio_resample (resample->res, (short *) GST_BUFFER_DATA (outbuf),
279       (short *) GST_BUFFER_DATA (inbuf), nbsamples);
280
281   GST_DEBUG_OBJECT (resample, "audio_resample returned %d", ret);
282
283   GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale (ret, GST_SECOND,
284       resample->out_rate);
285   GST_BUFFER_SIZE (outbuf) = ret * 2 * resample->out_channels;
286
287   GST_LOG_OBJECT (resample, "Output buffer duration:%" GST_TIME_FORMAT,
288       GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
289
290   return GST_FLOW_OK;
291 }
292
293 gboolean
294 gst_ffmpegaudioresample_register (GstPlugin * plugin)
295 {
296   return gst_element_register (plugin, "ffaudioresample",
297       GST_RANK_NONE, GST_TYPE_FFMPEGAUDIORESAMPLE);
298 }