gst-indent
[platform/upstream/gst-plugins-good.git] / ext / raw1394 / gstdv1394src.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *               <2000> Daniel Fischer <dan@f3c.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include <gst/gst.h>
25 #include <string.h>
26 #include "gstdv1394src.h"
27
28 #define N_BUFFERS_IN_POOL 3
29
30 #define PAL_FRAMESIZE 144000
31 #define NTSC_FRAMESIZE 120000
32
33 /* Filter signals and args */
34 enum
35 {
36   /* FILL ME */
37   LAST_SIGNAL
38 };
39
40 enum
41 {
42   ARG_0,
43   ARG_CONSECUTIVE,
44   ARG_SKIP,
45   ARG_DROP_INCOMPLETE,
46 };
47
48 static GstElementDetails gst_dv1394src_details =
49 GST_ELEMENT_DETAILS ("Firewire (1394) DV Source",
50     "Source/Video",
51     "Source for DV video data from firewire port",
52     "Erik Walthinsen <omega@temple-baptist.com>\n"
53     "Daniel Fischer <dan@f3c.com>");
54
55 #if 0
56 static GstPadTemplate *
57 gst_dv1394src_factory (void)
58 {
59   static GstPadTemplate *template = NULL;
60
61   if (!template) {
62     template = gst_pad_template_new ("src",
63         GST_PAD_SRC,
64         GST_PAD_ALWAYS,
65         GST_STATIC_CAPS ("dv1394src",
66             "video/dv",
67             gst_props_new ("format", GST_PROPS_LIST (G_TYPE_STRING ("NTSC"),
68                     G_TYPE_STRING ("PAL")
69                 ), NULL)
70         ), NULL);
71   }
72   return template;
73 }
74 #endif
75
76 static void gst_dv1394src_base_init (gpointer g_class);
77 static void gst_dv1394src_class_init (GstDV1394SrcClass * klass);
78 static void gst_dv1394src_init (GstDV1394Src * filter);
79
80 static void gst_dv1394src_set_property (GObject * object, guint prop_id,
81     const GValue * value, GParamSpec * pspec);
82 static void gst_dv1394src_get_property (GObject * object, guint prop_id,
83     GValue * value, GParamSpec * pspec);
84
85 static GstElementStateReturn gst_dv1394src_change_state (GstElement * element);
86
87 static GstData *gst_dv1394src_get (GstPad * pad);
88
89 static GstElementClass *parent_class = NULL;
90
91 /*static guint gst_filter_signals[LAST_SIGNAL] = { 0 }; */
92
93 GType
94 gst_dv1394src_get_type (void)
95 {
96   static GType gst_dv1394src_type = 0;
97
98   if (!gst_dv1394src_type) {
99     static const GTypeInfo gst_dv1394src_info = {
100       sizeof (GstDV1394Src),
101       gst_dv1394src_base_init,
102       NULL,
103       (GClassInitFunc) gst_dv1394src_class_init,
104       NULL,
105       NULL,
106       sizeof (GstDV1394Src),
107       0,
108       (GInstanceInitFunc) gst_dv1394src_init,
109     };
110     gst_dv1394src_type =
111         g_type_register_static (GST_TYPE_ELEMENT, "DV1394Src",
112         &gst_dv1394src_info, 0);
113   }
114   return gst_dv1394src_type;
115 }
116
117 static void
118 gst_dv1394src_base_init (gpointer g_class)
119 {
120   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
121
122   gst_element_class_set_details (element_class, &gst_dv1394src_details);
123 }
124
125 static void
126 gst_dv1394src_class_init (GstDV1394SrcClass * klass)
127 {
128   GObjectClass *gobject_class;
129   GstElementClass *gstelement_class;
130
131   gobject_class = (GObjectClass *) klass;
132   gstelement_class = (GstElementClass *) klass;
133
134   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CONSECUTIVE,
135       g_param_spec_int ("consecutive", "consecutive frames",
136           "send n consecutive frames after skipping", 1, G_MAXINT, 1,
137           G_PARAM_READWRITE));
138   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SKIP,
139       g_param_spec_int ("skip", "skip frames", "skip n frames", 0, G_MAXINT, 1,
140           G_PARAM_READWRITE));
141   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DROP_INCOMPLETE,
142       g_param_spec_boolean ("drop_incomplete", "drop_incomplete",
143           "drop incomplete frames", TRUE, G_PARAM_READWRITE));
144
145   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
146
147   gobject_class->set_property = gst_dv1394src_set_property;
148   gobject_class->get_property = gst_dv1394src_get_property;
149
150   gstelement_class->change_state = gst_dv1394src_change_state;
151 }
152
153 static void
154 gst_dv1394src_init (GstDV1394Src * dv1394src)
155 {
156   dv1394src->srcpad = gst_pad_new ("src", GST_PAD_SRC);
157   gst_pad_set_get_function (dv1394src->srcpad, gst_dv1394src_get);
158   gst_element_add_pad (GST_ELEMENT (dv1394src), dv1394src->srcpad);
159
160   dv1394src->card = 0;
161   dv1394src->port = 0;
162   dv1394src->channel = 63;
163
164   dv1394src->consecutive = 1;
165   dv1394src->skip = 0;
166   dv1394src->drop_incomplete = TRUE;
167
168   /* initialized when first header received */
169   dv1394src->frameSize = 0;
170
171   dv1394src->buf = NULL;
172   dv1394src->frame = NULL;
173   dv1394src->frameSequence = 0;
174 }
175
176 static void
177 gst_dv1394src_set_property (GObject * object, guint prop_id,
178     const GValue * value, GParamSpec * pspec)
179 {
180   GstDV1394Src *filter;
181
182   /* it's not null if we got it, but it might not be ours */
183   g_return_if_fail (GST_IS_DV1394SRC (object));
184   filter = GST_DV1394SRC (object);
185
186   switch (prop_id) {
187     case ARG_SKIP:
188       filter->skip = g_value_get_int (value);
189       break;
190     case ARG_CONSECUTIVE:
191       filter->consecutive = g_value_get_int (value);
192       break;
193     case ARG_DROP_INCOMPLETE:
194       filter->drop_incomplete = g_value_get_boolean (value);
195       break;
196     default:
197       break;
198   }
199 }
200
201 static void
202 gst_dv1394src_get_property (GObject * object, guint prop_id, GValue * value,
203     GParamSpec * pspec)
204 {
205   GstDV1394Src *filter;
206
207   /* it's not null if we got it, but it might not be ours */
208   g_return_if_fail (GST_IS_DV1394SRC (object));
209   filter = GST_DV1394SRC (object);
210
211   switch (prop_id) {
212     case ARG_SKIP:
213       g_value_set_int (value, filter->skip);
214       break;
215     case ARG_CONSECUTIVE:
216       g_value_set_int (value, filter->consecutive);
217       break;
218     case ARG_DROP_INCOMPLETE:
219       g_value_set_boolean (value, filter->drop_incomplete);
220       break;
221     default:
222       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
223       break;
224   }
225 }
226
227 static int
228 gst_dv1394src_iso_receive (raw1394handle_t handle, int channel, size_t len,
229     quadlet_t * data)
230 {
231   GstDV1394Src *dv1394src = GST_DV1394SRC (raw1394_get_userdata (handle));
232
233   if (len > 16) {
234     /*
235        the following code taken from kino-0.51 (Dan Dennedy/Charles Yates)
236      */
237     unsigned char *p = (unsigned char *) &data[3];
238     int section_type = p[0] >> 5;       /* section type is in bits 5 - 7 */
239     int dif_sequence = p[1] >> 4;       /* dif sequence number is in bits 4 - 7 */
240     int dif_block = p[2];
241
242     /* if we are at the beginning of a frame, 
243        we set buf=frame, and alloc a new buffer for frame
244      */
245
246     if (section_type == 0 && dif_sequence == 0) {       // dif header
247
248       if (!dv1394src->negotiated) {
249         // figure format (NTSC/PAL)
250         if (p[3] & 0x80) {
251           // PAL
252           dv1394src->frameSize = PAL_FRAMESIZE;
253           GST_DEBUG ("PAL data");
254           if (gst_pad_try_set_caps (dv1394src->srcpad,
255                   gst_caps_new_simple ("video/dv",
256                       "format", G_TYPE_STRING, "PAL", NULL)) <= 0) {
257             GST_ELEMENT_ERROR (dv1394src, CORE, NEGOTIATION, (NULL),
258                 ("Could not set source caps for PAL"));
259             return 0;
260           }
261         } else {
262           // NTSC (untested)
263           dv1394src->frameSize = NTSC_FRAMESIZE;
264           GST_DEBUG
265               ("NTSC data [untested] - please report success/failure to <dan@f3c.com>");
266           if (gst_pad_try_set_caps (dv1394src->srcpad,
267                   gst_caps_new_simple ("video/dv", "format", G_TYPE_STRING,
268                       "NTSC", NULL)) <= 0) {
269             GST_ELEMENT_ERROR (dv1394src, CORE, NEGOTIATION, (NULL),
270                 ("Could not set source caps for NTSC"));
271             return 0;
272           }
273         }
274         dv1394src->negotiated = TRUE;
275       }
276       // drop last frame when not complete
277       if (!dv1394src->drop_incomplete
278           || dv1394src->bytesInFrame == dv1394src->frameSize) {
279         dv1394src->buf = dv1394src->frame;
280       } else {
281         GST_INFO_OBJECT (GST_ELEMENT (dv1394src), "incomplete frame dropped");
282       }
283       dv1394src->frame = NULL;
284
285       dv1394src->frameSequence++;
286
287       if (dv1394src->frameSequence % (dv1394src->skip +
288               dv1394src->consecutive) < dv1394src->consecutive) {
289         dv1394src->frame = gst_buffer_new_and_alloc (dv1394src->frameSize);
290       }
291       dv1394src->bytesInFrame = 0;
292     }
293
294     if (dv1394src->frame != NULL) {
295       void *data = GST_BUFFER_DATA (dv1394src->frame);
296
297
298       switch (section_type) {
299         case 0:         /* 1 Header block */
300           /* p[3] |= 0x80; // hack to force PAL data */
301           memcpy (data + dif_sequence * 150 * 80, p, 480);
302           break;
303
304         case 1:         /* 2 Subcode blocks */
305           memcpy (data + dif_sequence * 150 * 80 + (1 + dif_block) * 80, p,
306               480);
307           break;
308
309         case 2:         /* 3 VAUX blocks */
310           memcpy (data + dif_sequence * 150 * 80 + (3 + dif_block) * 80, p,
311               480);
312           break;
313
314         case 3:         /* 9 Audio blocks interleaved with video */
315           memcpy (data + dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80, p,
316               480);
317           break;
318
319         case 4:         /* 135 Video blocks interleaved with audio */
320           memcpy (data + dif_sequence * 150 * 80 + (7 + (dif_block / 15) +
321                   dif_block) * 80, p, 480);
322           break;
323
324         default:                /* we canĀ“t handle any other data */
325           break;
326       }
327       dv1394src->bytesInFrame += 480;
328     }
329   }
330
331   return 0;
332 }
333
334 static int
335 gst_dv1394src_bus_reset (raw1394handle_t handle, unsigned int generation)
336 {
337   GST_INFO_OBJECT (GST_DV1394SRC (raw1394_get_userdata (handle)),
338       "have bus reset");
339   return 0;
340 }
341
342 static GstData *
343 gst_dv1394src_get (GstPad * pad)
344 {
345   GstDV1394Src *dv1394src = GST_DV1394SRC (GST_PAD_PARENT (pad));
346
347   dv1394src->buf = NULL;
348   while (dv1394src->buf == NULL)
349     raw1394_loop_iterate (dv1394src->handle);
350
351   return GST_DATA (dv1394src->buf);
352 }
353
354 static GstElementStateReturn
355 gst_dv1394src_change_state (GstElement * element)
356 {
357   GstDV1394Src *dv1394src;
358
359   g_return_val_if_fail (GST_IS_DV1394SRC (element), GST_STATE_FAILURE);
360   dv1394src = GST_DV1394SRC (element);
361
362   switch (GST_STATE_TRANSITION (element)) {
363     case GST_STATE_NULL_TO_READY:
364       if ((dv1394src->handle = raw1394_new_handle ()) == NULL) {
365         GST_INFO_OBJECT (dv1394src, "can't get raw1394 handle");
366         return GST_STATE_FAILURE;
367       }
368       raw1394_set_userdata (dv1394src->handle, dv1394src);
369       dv1394src->numcards =
370           raw1394_get_port_info (dv1394src->handle, dv1394src->pinfo, 16);
371       if (dv1394src->numcards == 0) {
372         GST_INFO_OBJECT (dv1394src, "no cards available for raw1394");
373         return GST_STATE_FAILURE;
374       }
375       if (dv1394src->pinfo[dv1394src->card].nodes <= 1) {
376         GST_INFO_OBJECT (dv1394src, "there are no nodes on the 1394 bus");
377         return GST_STATE_FAILURE;
378       }
379       if (raw1394_set_port (dv1394src->handle, dv1394src->port) < 0) {
380         GST_INFO_OBJECT (dv1394src, "can't set 1394 port %d", dv1394src->port);
381         return GST_STATE_FAILURE;
382       }
383       raw1394_set_iso_handler (dv1394src->handle, dv1394src->channel,
384           gst_dv1394src_iso_receive);
385       raw1394_set_bus_reset_handler (dv1394src->handle,
386           gst_dv1394src_bus_reset);
387       dv1394src->started = FALSE;
388       GST_DEBUG ("successfully opened up 1394 connection");
389       break;
390     case GST_STATE_PAUSED_TO_PLAYING:
391       if (raw1394_start_iso_rcv (dv1394src->handle, dv1394src->channel) < 0) {
392         GST_INFO_OBJECT (dv1394src, "can't start 1394 iso receive");
393         return GST_STATE_FAILURE;
394       }
395       break;
396     case GST_STATE_PLAYING_TO_PAUSED:
397       raw1394_stop_iso_rcv (dv1394src->handle, dv1394src->channel);
398       break;
399     case GST_STATE_READY_TO_NULL:
400       raw1394_destroy_handle (dv1394src->handle);
401       break;
402     default:
403       break;
404   }
405
406   /* if we haven't failed already, give the parent class a chance to ;-) */
407   if (GST_ELEMENT_CLASS (parent_class)->change_state)
408     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
409
410   return GST_STATE_SUCCESS;
411 }