Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / sys / v4l / v4lmjpegsink_calls.c
1 /* GStreamer
2  *
3  * v4lmjpegsink_calls.c: functions for hardware MJPEG video sink
4  *
5  * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
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 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <sys/ioctl.h>
32 #include <sys/mman.h>
33 #include <string.h>
34 #include <errno.h>
35 #include "v4lmjpegsink_calls.h"
36
37 /* On some systems MAP_FAILED seems to be missing */
38 #ifndef MAP_FAILED
39 #define MAP_FAILED ( (caddr_t) -1 )
40 #endif
41
42 GST_DEBUG_CATEGORY_EXTERN (v4lmjpegsink_debug);
43 #define GST_CAT_DEFAULT v4lmjpegsink_debug
44
45 /******************************************************
46  * gst_v4lmjpegsink_sync_thread()
47  *   thread keeps track of played frames
48  ******************************************************/
49
50 static void *
51 gst_v4lmjpegsink_sync_thread (void *arg)
52 {
53   GstV4lMjpegSink *v4lmjpegsink = GST_V4LMJPEGSINK (arg);
54   gint frame = 0;               /* frame that we're currently syncing on */
55
56   GST_DEBUG_OBJECT (v4lmjpegsink, "starting sync thread");
57
58 #if 0
59   /* Allow easy shutting down by other processes... */
60   pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
61   pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
62 #endif
63
64   while (1) {
65     g_mutex_lock (v4lmjpegsink->mutex_queued_frames);
66     if (!v4lmjpegsink->isqueued_queued_frames[frame]) {
67       g_cond_wait (v4lmjpegsink->cond_queued_frames[frame],
68           v4lmjpegsink->mutex_queued_frames);
69     }
70     if (v4lmjpegsink->isqueued_queued_frames[frame] != 1) {
71       g_mutex_unlock (v4lmjpegsink->mutex_queued_frames);
72       goto end;
73     }
74     g_mutex_unlock (v4lmjpegsink->mutex_queued_frames);
75
76     GST_DEBUG_OBJECT (v4lmjpegsink, "thread-syncing on next frame");
77     if (ioctl (GST_V4LELEMENT (v4lmjpegsink)->video_fd, MJPIOC_SYNC,
78             &(v4lmjpegsink->bsync)) < 0) {
79       GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, SYNC, (NULL),
80           ("Failed to sync on frame %d: %s", frame, g_strerror (errno)));
81       g_mutex_lock (v4lmjpegsink->mutex_queued_frames);
82       v4lmjpegsink->isqueued_queued_frames[frame] = -1;
83       g_cond_broadcast (v4lmjpegsink->cond_queued_frames[frame]);
84       g_mutex_unlock (v4lmjpegsink->mutex_queued_frames);
85       goto end;
86     } else {
87       /* be sure that we're not confusing */
88       if (frame != v4lmjpegsink->bsync.frame) {
89         GST_ELEMENT_ERROR (v4lmjpegsink, CORE, TOO_LAZY, (NULL),
90             ("Internal error: frame number confusion"));
91         goto end;
92       }
93       g_mutex_lock (v4lmjpegsink->mutex_queued_frames);
94       v4lmjpegsink->isqueued_queued_frames[frame] = 0;
95       g_cond_broadcast (v4lmjpegsink->cond_queued_frames[frame]);
96       g_mutex_unlock (v4lmjpegsink->mutex_queued_frames);
97     }
98
99     frame = (frame + 1) % v4lmjpegsink->breq.count;
100   }
101
102 end:
103   GST_DEBUG_OBJECT (v4lmjpegsink, "Sync thread got signalled to exit");
104   g_thread_exit (NULL);
105   return NULL;
106 }
107
108
109 /******************************************************
110  * gst_v4lmjpegsink_queue_frame()
111  *   queue a frame for playback
112  * return value: TRUE on success, FALSE on error
113  ******************************************************/
114
115 static gboolean
116 gst_v4lmjpegsink_queue_frame (GstV4lMjpegSink * v4lmjpegsink, gint num)
117 {
118   GST_DEBUG_OBJECT (v4lmjpegsink, "queueing frame %d", num);
119
120   /* queue on this frame */
121   if (ioctl (GST_V4LELEMENT (v4lmjpegsink)->video_fd, MJPIOC_QBUF_PLAY,
122           &num) < 0) {
123     GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, WRITE, (NULL),
124         ("Failed to queue frame %d: %s", num, g_strerror (errno)));
125     return FALSE;
126   }
127
128   g_mutex_lock (v4lmjpegsink->mutex_queued_frames);
129   v4lmjpegsink->isqueued_queued_frames[num] = 1;
130   g_cond_broadcast (v4lmjpegsink->cond_queued_frames[num]);
131   g_mutex_unlock (v4lmjpegsink->mutex_queued_frames);
132
133   return TRUE;
134 }
135
136
137 /******************************************************
138  * gst_v4lmjpegsink_sync_frame()
139  *   wait for a frame to be finished playing
140  * return value: TRUE on success, FALSE on error
141  ******************************************************/
142
143 static gboolean
144 gst_v4lmjpegsink_sync_frame (GstV4lMjpegSink * v4lmjpegsink, gint * num)
145 {
146   GST_DEBUG_OBJECT (v4lmjpegsink, "syncing on next frame");
147
148   /* calculate next frame */
149   v4lmjpegsink->current_frame =
150       (v4lmjpegsink->current_frame + 1) % v4lmjpegsink->breq.count;
151   *num = v4lmjpegsink->current_frame;
152
153   g_mutex_lock (v4lmjpegsink->mutex_queued_frames);
154   if (v4lmjpegsink->isqueued_queued_frames[*num] == 1) {
155     g_cond_wait (v4lmjpegsink->cond_queued_frames[*num],
156         v4lmjpegsink->mutex_queued_frames);
157   }
158   if (v4lmjpegsink->isqueued_queued_frames[*num] != 0) {
159     g_mutex_unlock (v4lmjpegsink->mutex_queued_frames);
160     return FALSE;
161   } else
162     g_mutex_unlock (v4lmjpegsink->mutex_queued_frames);
163
164   return TRUE;
165 }
166
167
168 /******************************************************
169  * gst_v4lmjpegsink_set_buffer()
170  *   set buffer options
171  * return value: TRUE on success, FALSE on error
172  ******************************************************/
173
174 gboolean
175 gst_v4lmjpegsink_set_buffer (GstV4lMjpegSink * v4lmjpegsink,
176     gint numbufs, gint bufsize)
177 {
178   GST_DEBUG_OBJECT (v4lmjpegsink,
179       "setting buffer info to numbufs = %d, bufsize = %d KB", numbufs, bufsize);
180   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink));
181   GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lmjpegsink));
182
183   v4lmjpegsink->breq.size = bufsize * 1024;
184   v4lmjpegsink->breq.count = numbufs;
185
186   return TRUE;
187 }
188
189
190 /******************************************************
191  * gst_v4lmjpegsink_set_playback()
192  *   set playback options (video, interlacing, etc.)
193  * return value: TRUE on success, FALSE on error
194  ******************************************************/
195
196 gboolean
197 gst_v4lmjpegsink_set_playback (GstV4lMjpegSink * v4lmjpegsink,
198     gint width,
199     gint height, gint x_offset, gint y_offset, gint norm, gint interlacing)
200 {
201   gint mw, mh;
202   struct mjpeg_params bparm;
203
204   GST_DEBUG_OBJECT (v4lmjpegsink,
205       "setting size=%dx%d, X/Y offsets=%d/%d, norm=%d, interlacing=%d\n",
206       width, height, x_offset, y_offset, norm, interlacing);
207   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink));
208   /*GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lmjpegsink)); */
209
210   if (ioctl (GST_V4LELEMENT (v4lmjpegsink)->video_fd, MJPIOC_G_PARAMS,
211           &bparm) < 0) {
212     GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, SETTINGS, (NULL),
213         GST_ERROR_SYSTEM);
214     return FALSE;
215   }
216
217   bparm.input = 0;
218   bparm.norm = norm;
219   bparm.decimation = 0;         /* we'll set proper values later on */
220
221   /* maxwidth is broken on marvel cards */
222   mw = GST_V4LELEMENT (v4lmjpegsink)->vcap.maxwidth;
223   if (mw != 768 && mw != 640)
224     mw = 720;
225   mh = (norm == VIDEO_MODE_NTSC ? 480 : 576);
226
227   if (width > mw || height > mh) {
228     GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, TOO_LAZY, (NULL),
229         ("Video dimensions (%dx%d) are larger than device max (%dx%d)",
230             width, height, mw, mh));
231     return FALSE;
232   }
233
234   if (width <= mw / 4)
235     bparm.HorDcm = 4;
236   else if (width <= mw / 2)
237     bparm.HorDcm = 2;
238   else
239     bparm.HorDcm = 1;
240
241   /* TODO: add proper interlacing handling */
242 #if 0
243   if (interlacing != INTERLACING_NOT_INTERLACED) {
244     bparm.field_per_buff = 2;
245     bparm.TmpDcm = 1;
246
247     if (height <= mh / 2)
248       bparm.VerDcm = 2;
249     else
250       bparm.VerDcm = 1;
251   } else
252 #endif
253   {
254     if (height > mh / 2) {
255       GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, TOO_LAZY, (NULL),
256           ("Video dimensions (%dx%d) too large for non-interlaced playback (%dx%d)",
257               width, height, mw, mh / 2));
258       return FALSE;
259     }
260
261     bparm.field_per_buff = 1;
262     bparm.TmpDcm = 2;
263
264     if (height <= mh / 4)
265       bparm.VerDcm = 2;
266     else
267       bparm.VerDcm = 1;
268   }
269
270   /* TODO: add proper interlacing handling */
271 #if 0
272   bparm.odd_even = (interlacing == INTERLACING_TOP_FIRST);
273 #endif
274
275   bparm.quality = 100;
276   bparm.img_width = bparm.HorDcm * width;
277   bparm.img_height = bparm.VerDcm * height / bparm.field_per_buff;
278
279   /* image X/Y offset on device */
280   if (x_offset < 0)
281     bparm.img_x = (mw - bparm.img_width) / 2;
282   else {
283     if (x_offset + bparm.img_width > mw)
284       bparm.img_x = mw - bparm.img_width;
285     else
286       bparm.img_x = x_offset;
287   }
288
289   if (y_offset < 0)
290     bparm.img_y = (mh / 2 - bparm.img_height) / 2;
291   else {
292     if (y_offset + bparm.img_height * 2 > mh)
293       bparm.img_y = mh / 2 - bparm.img_height;
294     else
295       bparm.img_y = y_offset / 2;
296   }
297
298   if (ioctl (GST_V4LELEMENT (v4lmjpegsink)->video_fd, MJPIOC_S_PARAMS,
299           &bparm) < 0) {
300     GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, SETTINGS, (NULL),
301         GST_ERROR_SYSTEM);
302     return FALSE;
303   }
304
305   return TRUE;
306 }
307
308
309 /******************************************************
310  * gst_v4lmjpegsink_playback_init()
311  *   initialize playback system, set up buffer, etc.
312  * return value: TRUE on success, FALSE on error
313  ******************************************************/
314
315 gboolean
316 gst_v4lmjpegsink_playback_init (GstV4lMjpegSink * v4lmjpegsink)
317 {
318   gint n;
319
320   GST_DEBUG_OBJECT (v4lmjpegsink, "initting playback subsystem");
321   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink));
322   GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lmjpegsink));
323
324   /* Request buffers */
325   if (ioctl (GST_V4LELEMENT (v4lmjpegsink)->video_fd, MJPIOC_REQBUFS,
326           &(v4lmjpegsink->breq)) < 0) {
327     GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
328     return FALSE;
329   }
330
331   GST_INFO_OBJECT (v4lmjpegsink, "Got %ld buffers of size %ld KB",
332       v4lmjpegsink->breq.count, v4lmjpegsink->breq.size / 1024);
333
334   /* Map the buffers */
335   GST_V4LELEMENT (v4lmjpegsink)->buffer = mmap (0,
336       v4lmjpegsink->breq.count * v4lmjpegsink->breq.size,
337       PROT_READ | PROT_WRITE, MAP_SHARED,
338       GST_V4LELEMENT (v4lmjpegsink)->video_fd, 0);
339   if (GST_V4LELEMENT (v4lmjpegsink)->buffer == MAP_FAILED) {
340     GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, TOO_LAZY, (NULL),
341         ("Error mapping video buffers: %s", g_strerror (errno)));
342     GST_V4LELEMENT (v4lmjpegsink)->buffer = NULL;
343     return FALSE;
344   }
345
346   /* allocate/init the GThread thingies */
347   v4lmjpegsink->mutex_queued_frames = g_mutex_new ();
348   v4lmjpegsink->isqueued_queued_frames = (gint8 *)
349       malloc (sizeof (gint8) * v4lmjpegsink->breq.count);
350   if (!v4lmjpegsink->isqueued_queued_frames) {
351     GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, TOO_LAZY, (NULL),
352         ("Failed to create queue tracker: %s", g_strerror (errno)));
353     return FALSE;
354   }
355   v4lmjpegsink->cond_queued_frames = (GCond **)
356       malloc (sizeof (GCond *) * v4lmjpegsink->breq.count);
357   if (!v4lmjpegsink->cond_queued_frames) {
358     GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, TOO_LAZY, (NULL),
359         ("Failed to create queue condition holders: %s", g_strerror (errno)));
360     return FALSE;
361   }
362   for (n = 0; n < v4lmjpegsink->breq.count; n++)
363     v4lmjpegsink->cond_queued_frames[n] = g_cond_new ();
364
365   return TRUE;
366 }
367
368
369 /******************************************************
370  * gst_v4lmjpegsink_playback_start()
371  *   start playback system
372  * return value: TRUE on success, FALSE on error
373  ******************************************************/
374
375 gboolean
376 gst_v4lmjpegsink_playback_start (GstV4lMjpegSink * v4lmjpegsink)
377 {
378   GError *error;
379   gint n;
380
381   GST_DEBUG_OBJECT (v4lmjpegsink, "starting playback");
382   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink));
383   GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsink));
384
385   /* mark all buffers as unqueued */
386   for (n = 0; n < v4lmjpegsink->breq.count; n++)
387     v4lmjpegsink->isqueued_queued_frames[n] = 0;
388
389   v4lmjpegsink->current_frame = -1;
390
391   /* create sync() thread */
392   v4lmjpegsink->thread_queued_frames =
393       g_thread_create (gst_v4lmjpegsink_sync_thread, (void *) v4lmjpegsink,
394       TRUE, &error);
395   if (!v4lmjpegsink->thread_queued_frames) {
396     GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, TOO_LAZY, (NULL),
397         ("Failed to create sync thread: %s", error->message));
398     return FALSE;
399   }
400
401   return TRUE;
402 }
403
404
405 /******************************************************
406  * gst_v4lmjpegsink_get_buffer()
407  *   get address of a buffer
408  * return value: buffer's address or NULL
409  ******************************************************/
410
411 guint8 *
412 gst_v4lmjpegsink_get_buffer (GstV4lMjpegSink * v4lmjpegsink, gint num)
413 {
414   /*GST_DEBUG_OBJECT (v4lmjpegsink, gst_v4lmjpegsink_get_buffer(), num = %d", num); */
415
416   if (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsink)) ||
417       !GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lmjpegsink)))
418     return NULL;
419
420   if (num < 0 || num >= v4lmjpegsink->breq.count)
421     return NULL;
422
423   return GST_V4LELEMENT (v4lmjpegsink)->buffer +
424       (v4lmjpegsink->breq.size * num);
425 }
426
427
428 /******************************************************
429  * gst_v4lmjpegsink_play_frame()
430  *   queue a new buffer
431  * return value: TRUE on success, FALSE on error
432  ******************************************************/
433
434 gboolean
435 gst_v4lmjpegsink_play_frame (GstV4lMjpegSink * v4lmjpegsink, gint num)
436 {
437   GST_DEBUG_OBJECT (v4lmjpegsink, "playing frame %d", num);
438   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink));
439   GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsink));
440
441   if (!gst_v4lmjpegsink_queue_frame (v4lmjpegsink, num))
442     return FALSE;
443
444   return TRUE;
445 }
446
447
448 /******************************************************
449  * gst_v4lmjpegsink_wait_frame()
450  *   wait for buffer to be actually played
451  * return value: TRUE on success, FALSE on error
452  ******************************************************/
453
454 gboolean
455 gst_v4lmjpegsink_wait_frame (GstV4lMjpegSink * v4lmjpegsink, gint * num)
456 {
457   GST_DEBUG_OBJECT (v4lmjpegsink,
458       "waiting for next frame to be finished playing");
459   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink));
460   GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsink));
461
462   if (!gst_v4lmjpegsink_sync_frame (v4lmjpegsink, num))
463     return FALSE;
464
465   return TRUE;
466 }
467
468
469 /******************************************************
470  * gst_v4lmjpegsink_playback_stop()
471  *   stop playback system and sync on remaining frames
472  * return value: TRUE on success, FALSE on error
473  ******************************************************/
474
475 gboolean
476 gst_v4lmjpegsink_playback_stop (GstV4lMjpegSink * v4lmjpegsink)
477 {
478   gint num;
479
480   GST_DEBUG_OBJECT (v4lmjpegsink, "stopping playback");
481   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink));
482   GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsink));
483
484   /* mark next buffer as wrong */
485   if (!gst_v4lmjpegsink_sync_frame (v4lmjpegsink, &num) ||
486       !gst_v4lmjpegsink_queue_frame (v4lmjpegsink, num)) {
487     return FALSE;
488   }
489
490   /* .. and wait for all buffers to be queued on */
491   g_thread_join (v4lmjpegsink->thread_queued_frames);
492
493   return TRUE;
494 }
495
496
497 /******************************************************
498  * gst_v4lmjpegsink_playback_deinit()
499  *   deinitialize the playback system and unmap buffer
500  * return value: TRUE on success, FALSE on error
501  ******************************************************/
502
503 gboolean
504 gst_v4lmjpegsink_playback_deinit (GstV4lMjpegSink * v4lmjpegsink)
505 {
506   int n;
507
508   GST_DEBUG_OBJECT (v4lmjpegsink, "quitting playback subsystem");
509   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink));
510   GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsink));
511
512   /* free GThread thingies */
513   g_mutex_free (v4lmjpegsink->mutex_queued_frames);
514   for (n = 0; n < v4lmjpegsink->breq.count; n++)
515     g_cond_free (v4lmjpegsink->cond_queued_frames[n]);
516   free (v4lmjpegsink->cond_queued_frames);
517   free (v4lmjpegsink->isqueued_queued_frames);
518
519   /* unmap the buffer */
520   munmap (GST_V4LELEMENT (v4lmjpegsink)->buffer,
521       v4lmjpegsink->breq.size * v4lmjpegsink->breq.count);
522   GST_V4LELEMENT (v4lmjpegsink)->buffer = NULL;
523
524   return TRUE;
525 }