]> git.sesse.net Git - vlc/blob - modules/access/v4l2/vbi.c
stream_filter: smooth: minor optimization
[vlc] / modules / access / v4l2 / vbi.c
1 /*****************************************************************************
2  * vbi.c : Video4Linux2 VBI input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2012 the VideoLAN team
5  *
6  * Author: Devin Heitmueller <dheitmueller at kernellabs dot com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <fcntl.h>
30 #include <vlc_common.h>
31 #include <vlc_block.h>
32 #include <vlc_fs.h>
33 #include <vlc_demux.h>
34
35 #include "v4l2.h"
36
37 #ifdef ZVBI_COMPILED
38 # include <libzvbi.h>
39 # define VBI_NUM_CC_STREAMS 4
40
41 struct vlc_v4l2_vbi
42 {
43     vbi_capture *cap;
44     es_out_id_t *es[VBI_NUM_CC_STREAMS];
45 };
46
47 vlc_v4l2_vbi_t *OpenVBI (demux_t *demux, const char *psz_device)
48 {
49     vlc_v4l2_vbi_t *vbi = malloc (sizeof (*vbi));
50     if (unlikely(vbi == NULL))
51         return NULL;
52
53     int rawfd = vlc_open (psz_device, O_RDWR);
54     if (rawfd == -1)
55     {
56         msg_Err (demux, "cannot open device '%s': %s", psz_device,
57                  vlc_strerror_c(errno));
58         goto err;
59     }
60
61     //Can put more in here. See osd.c in zvbi package.
62     unsigned int services = VBI_SLICED_CAPTION_525;
63     char *errstr = NULL;
64
65     vbi->cap = vbi_capture_v4l2k_new (psz_device, rawfd,
66                                       /* buffers */ 5,
67                                       &services,
68                                       /* strict */ 1,
69                                       &errstr,
70                                       /* verbose */ 1);
71     if (vbi->cap == NULL)
72     {
73         msg_Err (demux, "cannot capture VBI data: %s", errstr);
74         free (errstr);
75         close (rawfd);
76         goto err;
77     }
78
79     for (unsigned i = 0; i < VBI_NUM_CC_STREAMS; i++)
80     {
81         es_format_t fmt;
82
83         es_format_Init (&fmt, SPU_ES, VLC_FOURCC('c', 'c', '1' + i, ' '));
84         if (asprintf (&fmt.psz_description, "Closed captions %d", i + 1) >= 0)
85         {
86             msg_Dbg (demux, "new spu es %4.4s", (char *)&fmt.i_codec);
87             vbi->es[i] = es_out_Add (demux->out, &fmt);
88         }
89     }
90
91     /* Do a single read and throw away the results so that ZVBI calls
92        the STREAMON ioctl() */
93     GrabVBI(demux, vbi);
94
95     return vbi;
96 err:
97     free (vbi);
98     return NULL;
99 }
100
101 int GetFdVBI (vlc_v4l2_vbi_t *vbi)
102 {
103     return vbi_capture_fd(vbi->cap);
104 }
105
106 void GrabVBI (demux_t *p_demux, vlc_v4l2_vbi_t *vbi)
107 {
108     vbi_capture_buffer *sliced_bytes;
109     struct timeval timeout={0,0}; /* poll */
110     int canc = vlc_savecancel ();
111
112     int r = vbi_capture_pull_sliced (vbi->cap, &sliced_bytes, &timeout);
113     switch (r) {
114         case -1:
115             msg_Err (p_demux, "error reading VBI: %s", vlc_strerror_c(errno));
116         case  0: /* nothing avail */
117             break;
118         case  1: /* got data */
119         {
120             int n_lines = sliced_bytes->size / sizeof(vbi_sliced);
121             if (!n_lines)
122                 break;
123
124             int sliced_size = 2; /* Number of bytes per sliced line */
125             int size = (sliced_size + 1) * n_lines;
126             block_t *p_block = block_Alloc (size);
127             if (unlikely(p_block == NULL))
128                 break;
129
130             uint8_t* data = p_block->p_buffer;
131             vbi_sliced *sliced_array = sliced_bytes->data;
132             for (int field = 0; field < n_lines; field++)
133             {
134                 *data = field;
135                 data++;
136                 memcpy(data, sliced_array[field].data, sliced_size);
137                 data += sliced_size;
138             }
139             p_block->i_pts = mdate();
140
141             for (unsigned i = 0; i < VBI_NUM_CC_STREAMS; i++)
142             {
143                 if (vbi->es[i] == NULL)
144                     continue;
145
146                 block_t *dup = block_Duplicate(p_block);
147                 if (likely(dup != NULL))
148                     es_out_Send(p_demux->out, vbi->es[i], dup);
149             }
150             block_Release(p_block);
151         }
152     }
153     vlc_restorecancel (canc);
154 }
155
156 void CloseVBI (vlc_v4l2_vbi_t *vbi)
157 {
158     close (vbi_capture_fd (vbi->cap));
159     vbi_capture_delete (vbi->cap);
160     free (vbi);
161 }
162 #endif