blob: b8dcecfa98f294af265fa179dc74ed4c49abd3f7
1 | /* |
2 | * libzvbi raw VBI output example |
3 | * |
4 | * Copyright (C) 2006 Michael H. Schimek |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions |
8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in |
13 | * the documentation and/or other materials provided with the |
14 | * distribution. |
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
19 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
20 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
21 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | |
28 | /* $Id: rawout.c,v 1.8 2008/02/19 00:52:04 mschimek Exp $ */ |
29 | |
30 | /* This example shows how to convert VBI data in a DVB PES stream |
31 | to raw VBI data. |
32 | |
33 | gcc -o rawout rawout.c `pkg-config zvbi-0.2 --cflags --libs` |
34 | |
35 | ./rawout <pes | mplayer - -rawvideo on:w=720:h=34:format=0x32595559 */ |
36 | |
37 | #undef NDEBUG |
38 | #include <assert.h> |
39 | #include <stdio.h> |
40 | #include <stdlib.h> |
41 | #include <string.h> |
42 | #include <unistd.h> |
43 | |
44 | #include <libzvbi.h> |
45 | |
46 | static vbi_dvb_demux * dvb; |
47 | static uint8_t pes_buffer[2048]; |
48 | static vbi_sampling_par sp; |
49 | static uint8_t * image; |
50 | static unsigned int image_size; |
51 | static unsigned int pixel_mask; |
52 | static int64_t last_pts; |
53 | static vbi_raw_decoder rd; |
54 | |
55 | static void |
56 | raw_test (const vbi_sliced * expect_sliced, |
57 | unsigned int expect_n_lines) |
58 | { |
59 | vbi_sliced sliced[50]; |
60 | unsigned int n_lines; |
61 | unsigned int i; |
62 | |
63 | n_lines = vbi_raw_decode (&rd, image, sliced); |
64 | assert (n_lines == expect_n_lines); |
65 | |
66 | for (i = 0; i < n_lines; ++i) { |
67 | unsigned int payload; |
68 | |
69 | assert (sliced[i].id == expect_sliced[i].id); |
70 | assert (sliced[i].line == expect_sliced[i].line); |
71 | |
72 | payload = (vbi_sliced_payload_bits (sliced[i].id) + 7) / 8; |
73 | assert (0 == memcmp (sliced[i].data, |
74 | expect_sliced[i].data, |
75 | payload)); |
76 | } |
77 | } |
78 | |
79 | static vbi_bool |
80 | convert (vbi_dvb_demux * dx, |
81 | void * user_data, |
82 | const vbi_sliced * sliced, |
83 | unsigned int n_lines, |
84 | int64_t pts) |
85 | { |
86 | vbi_bool success; |
87 | ssize_t actual; |
88 | |
89 | dx = dx; /* unused */ |
90 | user_data = user_data; |
91 | |
92 | pts &= ((int64_t) 1 << 33) - 1; |
93 | |
94 | /* Handle PTS wrap-around. */ |
95 | if (0 == last_pts) { |
96 | last_pts = pts; |
97 | } else if (pts < last_pts) { |
98 | last_pts -= (int64_t) 1 << 33; |
99 | } |
100 | |
101 | while (pts - last_pts > 90000 / 25 * 3 / 2) { |
102 | /* No data for this frame. */ |
103 | |
104 | success = vbi_raw_video_image (image, image_size, &sp, |
105 | 0, 0, 0, pixel_mask, FALSE, |
106 | NULL, /* n_lines */ 0); |
107 | assert (success); |
108 | |
109 | raw_test (NULL, 0); |
110 | |
111 | actual = write (STDOUT_FILENO, image, image_size); |
112 | assert (actual == (ssize_t) image_size); |
113 | |
114 | last_pts += 90000 / 25; |
115 | } |
116 | |
117 | success = vbi_raw_video_image (image, image_size, &sp, |
118 | /* blank_level: default */ 0, |
119 | /* black_level: default */ 0, |
120 | /* white_level: default */ 0, |
121 | pixel_mask, |
122 | /* swap_fields */ FALSE, |
123 | sliced, n_lines); |
124 | assert (success); |
125 | |
126 | raw_test (sliced, n_lines); |
127 | |
128 | actual = write (STDOUT_FILENO, image, image_size); |
129 | assert (actual == (ssize_t) image_size); |
130 | |
131 | last_pts = pts; |
132 | |
133 | return TRUE; /* success */ |
134 | } |
135 | |
136 | static void |
137 | mainloop (void) |
138 | { |
139 | while (1 == fread (pes_buffer, sizeof (pes_buffer), 1, stdin)) { |
140 | vbi_bool success; |
141 | |
142 | success = vbi_dvb_demux_feed (dvb, |
143 | pes_buffer, |
144 | sizeof (pes_buffer)); |
145 | assert (success); |
146 | } |
147 | |
148 | fprintf (stderr, "End of stream.\n"); |
149 | } |
150 | |
151 | int |
152 | main (void) |
153 | { |
154 | if (isatty (STDIN_FILENO)) { |
155 | fprintf (stderr, "No DVB PES on standard input.\n"); |
156 | exit (EXIT_FAILURE); |
157 | } |
158 | |
159 | if (isatty (STDOUT_FILENO)) { |
160 | fprintf (stderr, "Output is binary image data. Pipe to " |
161 | "another tool or redirect to a file.\n"); |
162 | exit (EXIT_FAILURE); |
163 | } |
164 | |
165 | /* Helps debugging. */ |
166 | vbi_set_log_fn ((VBI_LOG_NOTICE | |
167 | VBI_LOG_WARNING | |
168 | VBI_LOG_ERROR), |
169 | vbi_log_on_stderr, |
170 | /* user_data */ NULL); |
171 | |
172 | dvb = vbi_dvb_pes_demux_new (convert, /* user_data */ NULL); |
173 | assert (NULL != dvb); |
174 | |
175 | memset (&sp, 0, sizeof (sp)); |
176 | |
177 | #if 1 |
178 | /* ITU BT.601 YUYV. */ |
179 | |
180 | sp.scanning = 625; /* PAL/SECAM */ |
181 | sp.sampling_format = VBI_PIXFMT_YUYV; |
182 | sp.sampling_rate = 13.5e6; |
183 | sp.bytes_per_line = 720 * 2; /* 2 bpp */ |
184 | sp.offset = 9.5e-6 * 13.5e6; |
185 | sp.start[0] = 6; |
186 | sp.count[0] = 17; |
187 | sp.start[1] = 319; |
188 | sp.count[1] = 17; |
189 | sp.interlaced = TRUE; |
190 | sp.synchronous = TRUE; |
191 | |
192 | /* Other bytes are left unmodified. */ |
193 | pixel_mask = 0x000000FF; /* 0xAAVVUUYY */ |
194 | #else |
195 | /* PAL square pixels BGRA32. */ |
196 | |
197 | sp.scanning = 625; /* PAL/SECAM */ |
198 | sp.sampling_format = VBI_PIXFMT_BGRA32_LE; |
199 | sp.sampling_rate = 14.75e6; |
200 | sp.bytes_per_line = 768 * 4; /* 4 bpp */ |
201 | sp.offset = 10.2e-6 * 14.75e6; |
202 | sp.start[0] = 6; |
203 | sp.count[0] = 17; |
204 | sp.start[1] = 319; |
205 | sp.count[1] = 17; |
206 | sp.interlaced = TRUE; |
207 | sp.synchronous = TRUE; |
208 | |
209 | pixel_mask = 0x0000FF00; /* 0xAABBGGRR */ |
210 | #endif |
211 | |
212 | image_size = (sp.count[0] + sp.count[1]) * sp.bytes_per_line; |
213 | image = malloc (image_size); |
214 | assert (NULL != image); |
215 | |
216 | if (VBI_PIXFMT_YUYV == sp.sampling_format) { |
217 | /* Reset Cb/Cr bytes. */ |
218 | memset (image, 0x80, image_size); |
219 | } else { |
220 | memset (image, 0x00, image_size); |
221 | } |
222 | |
223 | /* To verify the generated raw VBI data we feed it back |
224 | into a decoder and compare the sliced VBI data. */ |
225 | |
226 | vbi_raw_decoder_init (&rd); |
227 | |
228 | rd.scanning = sp.scanning; |
229 | rd.sampling_format = sp.sampling_format; |
230 | rd.sampling_rate = sp.sampling_rate; |
231 | rd.bytes_per_line = sp.bytes_per_line; |
232 | rd.offset = sp.offset; |
233 | rd.start[0] = sp.start[0]; |
234 | rd.start[1] = sp.start[1]; |
235 | rd.count[0] = sp.count[0]; |
236 | rd.count[1] = sp.count[1]; |
237 | rd.interlaced = sp.interlaced; |
238 | rd.synchronous = sp.synchronous; |
239 | |
240 | /* Strict 0 because the function would consider the |
241 | square pixel timing too tight to reliably decode |
242 | Teletext. */ |
243 | vbi_raw_decoder_add_services (&rd, |
244 | (VBI_SLICED_TELETEXT_B | |
245 | VBI_SLICED_VPS | |
246 | VBI_SLICED_CAPTION_625), |
247 | /* strict */ 0); |
248 | |
249 | mainloop (); |
250 | |
251 | vbi_dvb_demux_delete (dvb); |
252 | |
253 | exit (EXIT_SUCCESS); |
254 | |
255 | return 0; |
256 | } |
257 |