1 /* GStreamer
2  *
3  * unit test for jpegparse
4  *
5  * Copyright (C) <2009> Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 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  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #include <unistd.h>
24 
25 #include <gst/check/gstcheck.h>
26 
27 /* This test doesn't use actual JPEG data, but some fake data that we know
28    will trigger certain paths in jpegparse. */
29 
30 guint8 test_data_garbage[] = { 0x00, 0x01, 0xff, 0x32, 0x00, 0xff };
31 guint8 test_data_short_frame[] = { 0xff, 0xd8, 0xff, 0xd9 };
32 
33 guint8 test_data_normal_frame[] = { 0xff, 0xd8, 0xff, 0x12, 0x00, 0x03, 0x33,
34   0xff, 0xd9
35 };
36 
37 guint8 test_data_entropy[] = { 0xff, 0xd8, 0xff, 0xda, 0x00, 0x04, 0x22, 0x33,
38   0x44, 0xff, 0x00, 0x55, 0xff, 0x04, 0x00, 0x04, 0x22, 0x33, 0xff, 0xd9
39 };
40 guint8 test_data_ff[] = { 0xff, 0xff };
41 
42 guint8 test_data_extra_ff[] = { 0xff, 0xd8, 0xff, 0xff, 0xff, 0x12, 0x00, 0x03,
43   0x33, 0xff, 0xff, 0xff, 0xd9
44 };
45 
46 guint8 test_data_soi[] = { 0xff, 0xd8 };
47 
48 guint8 test_data_app1_exif[] = {
49   0xff, 0xe1,
50   0x00, 0xd2,                   /* length = 210 */
51   0x45, 0x78, 0x69, 0x66, 0x00, /* Exif */
52   0x00,
53   0x49, 0x49,
54   0x2a, 0x00,
55   0x08,
56   0x00, 0x00, 0x00,
57   0x09,                         /* number of entries */
58   0x00,
59   0x0e, 0x01,                   /* tag 0x10e */
60   0x02, 0x00,                   /* type 2 */
61   0x0b, 0x00,                   /* count 11 */
62   0x00, 0x00,
63   0x7a,                         /* offset 122 (0x7a) */
64   0x00, 0x00, 0x00,
65   0x0f, 0x01,                   /* tag 0x10f */
66   0x02, 0x00,                   /* type 2 */
67   0x06, 0x00,                   /* count 6 */
68   0x00, 0x00,
69   0x85,                         /* offset 133 (0x85) */
70   0x00, 0x00, 0x00,
71   0x10, 0x01,                   /* tag 0x110 */
72   0x02, 0x00,                   /* type 2 */
73   0x05, 0x00,                   /* count 5 */
74   0x00, 0x00,
75   0x8b,                         /* offset 139 (0x8b) */
76   0x00, 0x00, 0x00,
77   0x12, 0x01,                   /* tag 0x112 */
78   0x03, 0x00,                   /* type 3 */
79   0x01, 0x00,                   /* count 1 */
80   0x00, 0x00,
81   0x01, 0x00, 0x30, 0x2c,       /* offset (0x2c300001) */
82   0x1a, 0x01,                   /* tag 0x11a */
83   0x05, 0x00,                   /* type 5 */
84   0x01, 0x00,                   /* count 1 */
85   0x00, 0x00,
86   0x90,                         /* offset 144 (0x90) */
87   0x00, 0x00, 0x00,
88   0x1b, 0x01,                   /* tag 0x11b */
89   0x05, 0x00,                   /* type 5 */
90   0x01, 0x00,                   /* count 1 */
91   0x00, 0x00,
92   0x98,                         /* offset 152 (0x98) */
93   0x00, 0x00, 0x00,
94   0x28, 0x01,                   /* tag 0x128 */
95   0x03, 0x00,                   /* type 3 */
96   0x01, 0x00,                   /* count 1 */
97   0x00, 0x00,
98   0x02, 0x00, 0x31, 0x2f,       /* offset (0x2f310002) */
99   0x31, 0x01,                   /* tag 0x131 */
100   0x02, 0x00,                   /* type 2 */
101   0x08, 0x00,                   /* count 8 */
102   0x00, 0x00,
103   0xa0,                         /* offset 160 (0xa0) */
104   0x00, 0x00, 0x00,
105   0x32, 0x01,                   /* tag 0x132 */
106   0x02, 0x00,                   /* type 2 */
107   0x14, 0x00,                   /* count 20 */
108   0x00, 0x00,
109   0xa8,                         /* offset 168 (0xa8)  */
110   0x00, 0x00, 0x00,
111   0x00, 0x00, 0x00,
112   0x00,
113   /* string */
114   /* 122: */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
115   /* string (NIKON) */
116   /* 133: */ 0x4e, 0x49, 0x4b, 0x4f, 0x4e, 0x00,
117   /* string (E800) */
118   /* 139: */ 0x45, 0x38, 0x30, 0x30, 0x00,
119   /* 144: */ 0x00, 0x00, 0x80, 0x25, /* / */ 0x00, 0x00, 0x20, 0x00,
120   /* 152: */ 0x00, 0x00, 0x80, 0x25, /* / */ 0x00, 0x00, 0x20, 0x00,
121   /* string (v984-75) */
122   /* 160: */ 0x76, 0x39, 0x38, 0x34, 0x2d, 0x37, 0x35, 0x00,
123   /* string (2001:08:18 21:44:21) */
124   /* 168: */ 0x32, 0x30, 0x30, 0x31, 0x3a, 0x30, 0x38, 0x3a,
125   0x31, 0x38, 0x20, 0x32, 0x31, 0x3a, 0x34, 0x34,
126   0x3a, 0x32, 0x31, 0x00,
127 
128   0x1e, 0x21, 0x1f, 0x1e, 0x21, 0x1c, 0x20, 0x21, 0x22, 0x24, 0x24, 0x27,
129   0x22, 0x20,
130 };
131 
132 guint8 test_data_comment[] = {
133   0xff, 0xfe,
134   0x00, 0x08,                   /* size */
135   /* xxxxx */
136   0x78, 0x78, 0x78, 0x78, 0x78, 0x00,
137 };
138 
139 guint8 test_data_sof0[] = {
140   0xff, 0xc0,                   /* baseline dct-based */
141   0x00, 0x11,                   /* size */
142   0x08,                         /* precision */
143   0x00, 0x3c,                   /* width */
144   0x00, 0x50,                   /* height */
145   0x03,                         /* number of components */
146   0x01, 0x22, 0x00,             /* component 1 */
147   0x02, 0x11, 0x01,             /* component 2 */
148   0x03, 0x11, 0x01,             /* component 3 */
149 };
150 
151 guint8 test_data_eoi[] = { 0xff, 0xd9 };
152 
153 static GList *
_make_buffers_in(GList * buffer_in,guint8 * test_data,gsize test_data_size)154 _make_buffers_in (GList * buffer_in, guint8 * test_data, gsize test_data_size)
155 {
156   GstBuffer *buffer;
157   gsize i;
158 
159   for (i = 0; i < test_data_size; i++) {
160     buffer =
161         gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, test_data + i, 1,
162         0, 1, NULL, NULL);
163     buffer_in = g_list_append (buffer_in, buffer);
164   }
165   return buffer_in;
166 }
167 
168 #define make_buffers_in(buffer_in, test_data) \
169     _make_buffers_in(buffer_in, test_data, sizeof(test_data))
170 
171 static GList *
_make_buffers_out(GList * buffer_out,guint8 * test_data,gsize test_data_size)172 _make_buffers_out (GList * buffer_out, guint8 * test_data, gsize test_data_size)
173 {
174   GstBuffer *buffer;
175 
176   buffer =
177       gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, test_data,
178       test_data_size, 0, test_data_size, NULL, NULL);
179   buffer_out = g_list_append (buffer_out, buffer);
180 
181   return buffer_out;
182 }
183 
184 #define make_buffers_out(buffer_out, test_data) \
185     _make_buffers_out(buffer_out, test_data, sizeof(test_data))
186 
GST_START_TEST(test_parse_single_byte)187 GST_START_TEST (test_parse_single_byte)
188 {
189   GList *buffer_in = NULL, *buffer_out = NULL;
190   GstCaps *caps_in, *caps_out;
191 
192   caps_in = gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, FALSE,
193       NULL);
194   caps_out = gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
195       "framerate", GST_TYPE_FRACTION, 1, 1, NULL);
196 
197   /* Push the data byte by byte, injecting some garbage. */
198   buffer_in = make_buffers_in (buffer_in, test_data_garbage);
199   buffer_in = make_buffers_in (buffer_in, test_data_short_frame);
200   buffer_in = make_buffers_in (buffer_in, test_data_garbage);
201   buffer_in = make_buffers_in (buffer_in, test_data_normal_frame);
202   buffer_in = make_buffers_in (buffer_in, test_data_ff);
203   buffer_in = make_buffers_in (buffer_in, test_data_entropy);
204   buffer_in = make_buffers_in (buffer_in, test_data_extra_ff);
205 
206   buffer_out = make_buffers_out (buffer_out, test_data_short_frame);
207   buffer_out = make_buffers_out (buffer_out, test_data_normal_frame);
208   buffer_out = make_buffers_out (buffer_out, test_data_entropy);
209   buffer_out = make_buffers_out (buffer_out, test_data_extra_ff);
210   gst_check_element_push_buffer_list ("jpegparse", buffer_in, caps_in,
211       buffer_out, caps_out, GST_FLOW_OK);
212 
213   gst_caps_unref (caps_in);
214   gst_caps_unref (caps_out);
215 }
216 
217 GST_END_TEST;
218 
219 
220 
GST_START_TEST(test_parse_all_in_one_buf)221 GST_START_TEST (test_parse_all_in_one_buf)
222 {
223   GList *buffer_in = NULL, *buffer_out = NULL;
224   GstBuffer *buffer = NULL;
225   gsize total_size = 0;
226   gsize offset = 0;
227   GstCaps *caps_in, *caps_out;
228 
229   /* Push the data in a single buffer, injecting some garbage. */
230   total_size += sizeof (test_data_garbage);
231   total_size += sizeof (test_data_short_frame);
232   total_size += sizeof (test_data_garbage);
233   total_size += sizeof (test_data_normal_frame);
234   total_size += sizeof (test_data_ff);
235   total_size += sizeof (test_data_entropy);
236   total_size += sizeof (test_data_extra_ff);
237   buffer = gst_buffer_new_and_alloc (total_size);
238   gst_buffer_fill (buffer, offset, test_data_garbage,
239       sizeof (test_data_garbage));
240   offset += sizeof (test_data_garbage);
241   gst_buffer_fill (buffer, offset, test_data_short_frame,
242       sizeof (test_data_short_frame));
243   offset += sizeof (test_data_short_frame);
244   gst_buffer_fill (buffer, offset, test_data_garbage,
245       sizeof (test_data_garbage));
246   offset += sizeof (test_data_garbage);
247   gst_buffer_fill (buffer, offset, test_data_normal_frame,
248       sizeof (test_data_normal_frame));
249   offset += sizeof (test_data_normal_frame);
250   gst_buffer_fill (buffer, offset, test_data_ff, sizeof (test_data_ff));
251   offset += sizeof (test_data_ff);
252   gst_buffer_fill (buffer, offset, test_data_entropy,
253       sizeof (test_data_entropy));
254   offset += sizeof (test_data_entropy);
255   gst_buffer_fill (buffer, offset, test_data_extra_ff,
256       sizeof (test_data_extra_ff));
257   offset += sizeof (test_data_extra_ff);
258 
259   caps_in = gst_caps_new_simple ("image/jpeg", "parsed",
260       G_TYPE_BOOLEAN, FALSE, NULL);
261   GST_LOG ("Pushing single buffer of %u bytes.", (guint) total_size);
262   buffer_in = g_list_append (buffer_in, buffer);
263 
264   caps_out = gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
265       "framerate", GST_TYPE_FRACTION, 1, 1, NULL);
266   buffer_out = make_buffers_out (buffer_out, test_data_short_frame);
267   buffer_out = make_buffers_out (buffer_out, test_data_normal_frame);
268   buffer_out = make_buffers_out (buffer_out, test_data_entropy);
269   buffer_out = make_buffers_out (buffer_out, test_data_extra_ff);
270 
271   gst_check_element_push_buffer_list ("jpegparse", buffer_in, caps_in,
272       buffer_out, caps_out, GST_FLOW_OK);
273 
274   gst_caps_unref (caps_in);
275   gst_caps_unref (caps_out);
276 }
277 
278 GST_END_TEST;
279 
280 static inline GstBuffer *
make_my_input_buffer(guint8 * test_data_header,gsize test_data_size)281 make_my_input_buffer (guint8 * test_data_header, gsize test_data_size)
282 {
283   GstBuffer *buffer;
284   gsize total_size = 0, offset = 0;
285 
286   total_size += sizeof (test_data_soi);
287   total_size += test_data_size;
288   total_size += sizeof (test_data_sof0);
289   total_size += sizeof (test_data_eoi);
290 
291   buffer = gst_buffer_new_and_alloc (total_size);
292 
293   gst_buffer_fill (buffer, offset, test_data_soi, sizeof (test_data_soi));
294   offset += sizeof (test_data_soi);
295   gst_buffer_fill (buffer, offset, test_data_header, test_data_size);
296   offset += test_data_size;
297   gst_buffer_fill (buffer, offset, test_data_sof0, sizeof (test_data_sof0));
298   offset += sizeof (test_data_sof0);
299   gst_buffer_fill (buffer, offset, test_data_eoi, sizeof (test_data_eoi));
300   offset += sizeof (test_data_eoi);
301 
302   return buffer;
303 }
304 
305 static inline GstBuffer *
make_my_output_buffer(GstBuffer * buffer_in)306 make_my_output_buffer (GstBuffer * buffer_in)
307 {
308   GstBuffer *buffer;
309   GstMapInfo map;
310 
311   gst_buffer_map (buffer_in, &map, GST_MAP_READ);
312   buffer = gst_buffer_new_and_alloc (map.size);
313   gst_buffer_fill (buffer, 0, map.data, map.size);
314   gst_buffer_unmap (buffer_in, &map);
315 
316   return buffer;
317 }
318 
319 
GST_START_TEST(test_parse_app1_exif)320 GST_START_TEST (test_parse_app1_exif)
321 {
322   GstBuffer *buffer_in, *buffer_out;
323   GstCaps *caps_in, *caps_out;
324 
325   caps_in = gst_caps_new_simple ("image/jpeg", "parsed",
326       G_TYPE_BOOLEAN, FALSE, NULL);
327 
328   caps_out = gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
329       "framerate", GST_TYPE_FRACTION, 1, 1, "format", G_TYPE_STRING,
330       "I420", "width", G_TYPE_INT, 80, "height", G_TYPE_INT, 60, NULL);
331 
332   buffer_in = make_my_input_buffer (test_data_app1_exif,
333       sizeof (test_data_app1_exif));
334   buffer_out = make_my_output_buffer (buffer_in);
335 
336   gst_check_element_push_buffer ("jpegparse", buffer_in, caps_in, buffer_out,
337       caps_out);
338 
339   gst_caps_unref (caps_in);
340   gst_caps_unref (caps_out);
341 }
342 
343 GST_END_TEST;
344 
GST_START_TEST(test_parse_comment)345 GST_START_TEST (test_parse_comment)
346 {
347   GstBuffer *buffer_in, *buffer_out;
348   GstCaps *caps_in, *caps_out;
349 
350   caps_in = gst_caps_new_simple ("image/jpeg", "parsed",
351       G_TYPE_BOOLEAN, FALSE, NULL);
352 
353   caps_out = gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
354       "framerate", GST_TYPE_FRACTION, 1, 1, "format", G_TYPE_STRING,
355       "I420", "width", G_TYPE_INT, 80, "height", G_TYPE_INT, 60, NULL);
356 
357   buffer_in = make_my_input_buffer (test_data_comment,
358       sizeof (test_data_comment));
359   buffer_out = make_my_output_buffer (buffer_in);
360 
361   gst_check_element_push_buffer ("jpegparse", buffer_in, caps_in, buffer_out,
362       caps_out);
363 
364   gst_caps_unref (caps_in);
365   gst_caps_unref (caps_out);
366 }
367 
368 GST_END_TEST;
369 
370 static Suite *
jpegparse_suite(void)371 jpegparse_suite (void)
372 {
373   Suite *s = suite_create ("jpegparse");
374   TCase *tc_chain = tcase_create ("jpegparse");
375 
376   suite_add_tcase (s, tc_chain);
377   tcase_add_test (tc_chain, test_parse_single_byte);
378   tcase_add_test (tc_chain, test_parse_all_in_one_buf);
379   tcase_add_test (tc_chain, test_parse_app1_exif);
380   tcase_add_test (tc_chain, test_parse_comment);
381 
382   return s;
383 }
384 
385 GST_CHECK_MAIN (jpegparse);
386