1 /* GStreamer
2 *
3 * Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.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., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include <gst/gst.h>
25 #include <gst/check/gstcheck.h>
26 #include <gst/check/gstharness.h>
27
28 #include <string.h>
29
GST_START_TEST(cdp_requires_framerate)30 GST_START_TEST (cdp_requires_framerate)
31 {
32 GstHarness *h;
33 GstBuffer *buffer;
34 GstMapInfo map;
35
36 h = gst_harness_new ("ccconverter");
37
38 /* Enforce conversion to CDP */
39 gst_harness_set_sink_caps_str (h,
40 "closedcaption/x-cea-708,format=(string)cdp");
41
42 /* Try without a framerate first, this has to fail */
43 gst_harness_set_src_caps_str (h,
44 "closedcaption/x-cea-708,format=(string)cc_data");
45
46 buffer = gst_buffer_new_and_alloc (3);
47 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
48 map.data[0] = 0xfc;
49 map.data[1] = 0x80;
50 map.data[2] = 0x80;
51 gst_buffer_unmap (buffer, &map);
52 fail_unless_equals_int (gst_harness_push (h, gst_buffer_ref (buffer)),
53 GST_FLOW_NOT_NEGOTIATED);
54
55 /* Now set a framerate only on the sink caps, this should still fail:
56 * We can't do framerate conversion!
57 */
58 gst_harness_set_sink_caps_str (h,
59 "closedcaption/x-cea-708,format=(string)cdp,framerate=(fraction)30/1");
60
61 fail_unless_equals_int (gst_harness_push (h, gst_buffer_ref (buffer)),
62 GST_FLOW_NOT_NEGOTIATED);
63
64 /* Then try with a framerate, this should work now */
65 gst_harness_set_sink_caps_str (h,
66 "closedcaption/x-cea-708,format=(string)cdp");
67 gst_harness_set_src_caps_str (h,
68 "closedcaption/x-cea-708,format=(string)cc_data,framerate=(fraction)30/1");
69
70 fail_unless_equals_int (gst_harness_push (h, buffer), GST_FLOW_OK);
71
72 gst_harness_teardown (h);
73 }
74
75 GST_END_TEST;
76
GST_START_TEST(framerate_passthrough)77 GST_START_TEST (framerate_passthrough)
78 {
79 GstHarness *h;
80 GstBuffer *buffer;
81 GstMapInfo map;
82 GstCaps *caps, *expected_caps;
83
84 h = gst_harness_new ("ccconverter");
85
86 gst_harness_set_src_caps_str (h,
87 "closedcaption/x-cea-608,format=(string)s334-1a,framerate=(fraction)30/1");
88
89 gst_harness_set_sink_caps_str (h,
90 "closedcaption/x-cea-708,format=(string)cc_data");
91
92 buffer = gst_buffer_new_and_alloc (3);
93 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
94 map.data[0] = 0x00;
95 map.data[1] = 0x80;
96 map.data[2] = 0x80;
97 gst_buffer_unmap (buffer, &map);
98
99 fail_unless_equals_int (gst_harness_push (h, gst_buffer_ref (buffer)),
100 GST_FLOW_OK);
101
102 caps = gst_pad_get_current_caps (h->sinkpad);
103 fail_unless (caps);
104 expected_caps =
105 gst_caps_from_string
106 ("closedcaption/x-cea-708,format=(string)cc_data,framerate=(fraction)30/1");
107 gst_check_caps_equal (caps, expected_caps);
108 gst_caps_unref (caps);
109 gst_caps_unref (expected_caps);
110
111 /* Now try between the same formats, should still pass through */
112 gst_harness_set_src_caps_str (h,
113 "closedcaption/x-cea-708,format=(string)cc_data,framerate=(fraction)30/1");
114
115 gst_harness_set_sink_caps_str (h,
116 "closedcaption/x-cea-708,format=(string)cc_data");
117
118 fail_unless_equals_int (gst_harness_push (h, gst_buffer_ref (buffer)),
119 GST_FLOW_OK);
120
121 caps = gst_pad_get_current_caps (h->sinkpad);
122 fail_unless (caps);
123 expected_caps =
124 gst_caps_from_string
125 ("closedcaption/x-cea-708,format=(string)cc_data,framerate=(fraction)30/1");
126 gst_check_caps_equal (caps, expected_caps);
127 gst_caps_unref (caps);
128 gst_caps_unref (expected_caps);
129
130 /* And another time with the same format but only framerate on the output
131 * side. This should fail as we can't just come up with a framerate! */
132 gst_harness_set_src_caps_str (h,
133 "closedcaption/x-cea-708,format=(string)cc_data");
134
135 gst_harness_set_sink_caps_str (h,
136 "closedcaption/x-cea-708,format=(string)cc_data,framerate=(fraction)30/1");
137
138 fail_unless_equals_int (gst_harness_push (h, buffer),
139 GST_FLOW_NOT_NEGOTIATED);
140
141 gst_harness_teardown (h);
142 }
143
144 GST_END_TEST;
145
146 static void
check_conversion(const guint8 * in,guint in_len,const guint8 * out,guint out_len,const gchar * in_caps,const gchar * out_caps)147 check_conversion (const guint8 * in, guint in_len, const guint8 * out,
148 guint out_len, const gchar * in_caps, const gchar * out_caps)
149 {
150 GstHarness *h;
151 GstBuffer *buffer;
152
153 h = gst_harness_new ("ccconverter");
154
155 gst_harness_set_src_caps_str (h, in_caps);
156 gst_harness_set_sink_caps_str (h, out_caps);
157
158 buffer =
159 gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, (gpointer) in,
160 in_len, 0, in_len, NULL, NULL);
161
162 buffer = gst_harness_push_and_pull (h, buffer);
163
164 fail_unless (buffer != NULL);
165 gst_check_buffer_data (buffer, out, out_len);
166 gst_buffer_unref (buffer);
167
168 gst_harness_teardown (h);
169 }
170
GST_START_TEST(convert_cea608_raw_cea608_s334_1a)171 GST_START_TEST (convert_cea608_raw_cea608_s334_1a)
172 {
173 const guint8 in[] = { 0x80, 0x80 };
174 const guint8 out[] = { 0x80, 0x80, 0x80 };
175 check_conversion (in, sizeof (in), out, sizeof (out),
176 "closedcaption/x-cea-608,format=(string)raw",
177 "closedcaption/x-cea-608,format=(string)s334-1a");
178 }
179
180 GST_END_TEST;
181
GST_START_TEST(convert_cea608_raw_cea708_cc_data)182 GST_START_TEST (convert_cea608_raw_cea708_cc_data)
183 {
184 const guint8 in[] = { 0x80, 0x80 };
185 const guint8 out[] = { 0xfc, 0x80, 0x80 };
186 check_conversion (in, sizeof (in), out, sizeof (out),
187 "closedcaption/x-cea-608,format=(string)raw",
188 "closedcaption/x-cea-708,format=(string)cc_data");
189 }
190
191 GST_END_TEST;
192
GST_START_TEST(convert_cea608_raw_cea708_cdp)193 GST_START_TEST (convert_cea608_raw_cea708_cdp)
194 {
195 const guint8 in[] = { 0x80, 0x80 };
196 const guint8 out[] =
197 { 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x00, 0x72, 0xea, 0xfc, 0x80, 0x80,
198 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x38
201 };
202 check_conversion (in, sizeof (in), out, sizeof (out),
203 "closedcaption/x-cea-608,format=(string)raw,framerate=(fraction)60/1",
204 "closedcaption/x-cea-708,format=(string)cdp");
205 }
206
207 GST_END_TEST;
208
GST_START_TEST(convert_cea608_s334_1a_cea608_raw)209 GST_START_TEST (convert_cea608_s334_1a_cea608_raw)
210 {
211 const guint8 in[] = { 0x80, 0x80, 0x80, 0x00, 0x80, 0x80 };
212 const guint8 out[] = { 0x80, 0x80 };
213 check_conversion (in, sizeof (in), out, sizeof (out),
214 "closedcaption/x-cea-608,format=(string)s334-1a",
215 "closedcaption/x-cea-608,format=(string)raw");
216 }
217
218 GST_END_TEST;
219
GST_START_TEST(convert_cea608_s334_1a_cea708_cc_data)220 GST_START_TEST (convert_cea608_s334_1a_cea708_cc_data)
221 {
222 const guint8 in[] = { 0x80, 0x80, 0x80, 0x00, 0x80, 0x80 };
223 const guint8 out[] = { 0xfc, 0x80, 0x80, 0xfd, 0x80, 0x80 };
224 check_conversion (in, sizeof (in), out, sizeof (out),
225 "closedcaption/x-cea-608,format=(string)s334-1a",
226 "closedcaption/x-cea-708,format=(string)cc_data");
227 }
228
229 GST_END_TEST;
230
GST_START_TEST(convert_cea608_s334_1a_cea708_cdp)231 GST_START_TEST (convert_cea608_s334_1a_cea708_cdp)
232 {
233 const guint8 in[] = { 0x80, 0x80, 0x80, 0x00, 0x80, 0x80 };
234 const guint8 out[] =
235 { 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x00, 0x72, 0xea, 0xfc, 0x80, 0x80,
236 0xfd, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x3b
239 };
240 check_conversion (in, sizeof (in), out, sizeof (out),
241 "closedcaption/x-cea-608,format=(string)s334-1a,framerate=(fraction)60/1",
242 "closedcaption/x-cea-708,format=(string)cdp");
243 }
244
245 GST_END_TEST;
246
GST_START_TEST(convert_cea708_cc_data_cea608_raw)247 GST_START_TEST (convert_cea708_cc_data_cea608_raw)
248 {
249 const guint8 in[] = { 0xfc, 0x80, 0x80, 0xfe, 0x80, 0x80 };
250 const guint8 out[] = { 0x80, 0x80 };
251 check_conversion (in, sizeof (in), out, sizeof (out),
252 "closedcaption/x-cea-708,format=(string)cc_data",
253 "closedcaption/x-cea-608,format=(string)raw");
254 }
255
256 GST_END_TEST;
257
GST_START_TEST(convert_cea708_cc_data_cea608_s334_1a)258 GST_START_TEST (convert_cea708_cc_data_cea608_s334_1a)
259 {
260 const guint8 in[] = { 0xfc, 0x80, 0x80, 0xfe, 0x80, 0x80 };
261 const guint8 out[] = { 0x80, 0x80, 0x80 };
262 check_conversion (in, sizeof (in), out, sizeof (out),
263 "closedcaption/x-cea-708,format=(string)cc_data",
264 "closedcaption/x-cea-608,format=(string)s334-1a");
265 }
266
267 GST_END_TEST;
268
GST_START_TEST(convert_cea708_cc_data_cea708_cdp)269 GST_START_TEST (convert_cea708_cc_data_cea708_cdp)
270 {
271 const guint8 in[] = { 0xfc, 0x80, 0x80, 0xfe, 0x80, 0x80 };
272 const guint8 out[] =
273 { 0x96, 0x69, 0x2b, 0x8f, 0x43, 0x00, 0x00, 0x72, 0xea, 0xfc, 0x80, 0x80,
274 0xfe, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
275 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
276 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x3a
277 };
278 check_conversion (in, sizeof (in), out, sizeof (out),
279 "closedcaption/x-cea-708,format=(string)cc_data,framerate=(fraction)60/1",
280 "closedcaption/x-cea-708,format=(string)cdp");
281 }
282
283 GST_END_TEST;
284
GST_START_TEST(convert_cea708_cdp_cea608_raw)285 GST_START_TEST (convert_cea708_cdp_cea608_raw)
286 {
287 const guint8 in[] =
288 { 0x96, 0x69, 0x13, 0x5f, 0x43, 0x00, 0x00, 0x72, 0xe2, 0xfc, 0x80, 0x80,
289 0xfe, 0x80, 0x80, 0x74, 0x00, 0x00, 0x8a
290 };
291 const guint8 out[] = { 0x80, 0x80 };
292 check_conversion (in, sizeof (in), out, sizeof (out),
293 "closedcaption/x-cea-708,format=(string)cdp",
294 "closedcaption/x-cea-608,format=(string)raw");
295 }
296
297 GST_END_TEST;
298
GST_START_TEST(convert_cea708_cdp_cea608_s334_1a)299 GST_START_TEST (convert_cea708_cdp_cea608_s334_1a)
300 {
301 const guint8 in[] =
302 { 0x96, 0x69, 0x13, 0x5f, 0x43, 0x00, 0x00, 0x72, 0xe2, 0xfc, 0x80, 0x80,
303 0xfe, 0x80, 0x80, 0x74, 0x00, 0x00, 0x8a
304 };
305 const guint8 out[] = { 0x80, 0x80, 0x80 };
306 check_conversion (in, sizeof (in), out, sizeof (out),
307 "closedcaption/x-cea-708,format=(string)cdp",
308 "closedcaption/x-cea-608,format=(string)s334-1a");
309 }
310
311 GST_END_TEST;
312
GST_START_TEST(convert_cea708_cdp_cea708_cc_data)313 GST_START_TEST (convert_cea708_cdp_cea708_cc_data)
314 {
315 const guint8 in[] =
316 { 0x96, 0x69, 0x13, 0x5f, 0x43, 0x00, 0x00, 0x72, 0xe2, 0xfc, 0x80, 0x80,
317 0xfe, 0x80, 0x80, 0x74, 0x00, 0x00, 0x8a
318 };
319 const guint8 out[] = { 0xfc, 0x80, 0x80, 0xfe, 0x80, 0x80 };
320 check_conversion (in, sizeof (in), out, sizeof (out),
321 "closedcaption/x-cea-708,format=(string)cdp",
322 "closedcaption/x-cea-708,format=(string)cc_data");
323 }
324
325 GST_END_TEST;
326
327 static Suite *
ccextractor_suite(void)328 ccextractor_suite (void)
329 {
330 Suite *s = suite_create ("ccconverter");
331 TCase *tc = tcase_create ("general");
332
333 suite_add_tcase (s, tc);
334
335 tcase_add_test (tc, cdp_requires_framerate);
336 tcase_add_test (tc, framerate_passthrough);
337 tcase_add_test (tc, convert_cea608_raw_cea608_s334_1a);
338 tcase_add_test (tc, convert_cea608_raw_cea708_cc_data);
339 tcase_add_test (tc, convert_cea608_raw_cea708_cdp);
340 tcase_add_test (tc, convert_cea608_s334_1a_cea608_raw);
341 tcase_add_test (tc, convert_cea608_s334_1a_cea708_cc_data);
342 tcase_add_test (tc, convert_cea608_s334_1a_cea708_cdp);
343 tcase_add_test (tc, convert_cea708_cc_data_cea608_raw);
344 tcase_add_test (tc, convert_cea708_cc_data_cea608_s334_1a);
345 tcase_add_test (tc, convert_cea708_cc_data_cea708_cdp);
346 tcase_add_test (tc, convert_cea708_cdp_cea608_raw);
347 tcase_add_test (tc, convert_cea708_cdp_cea608_s334_1a);
348 tcase_add_test (tc, convert_cea708_cdp_cea708_cc_data);
349
350 return s;
351 }
352
353 GST_CHECK_MAIN (ccextractor);
354