f20aea0f1f076a644b3696dc43f84c1742117214
[platform/upstream/gstreamer.git] / gst / videoparsers / gstjpeg2000parse.c
1 /* GStreamer JPEG 2000 Parser
2  * Copyright (C) <2016> Grok Image Compession Inc.
3  *  @author Aaron Boxer <boxerab@gmail.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
25 #include "gstjpeg2000parse.h"
26 #include <gst/base/base.h>
27
28 /* Not used at the moment
29 static gboolean gst_jpeg2000_parse_is_cinema(guint16 rsiz)   {
30         return ((rsiz >= GST_JPEG2000_PARSE_PROFILE_CINEMA_2K) && (rsiz <= GST_JPEG2000_PARSE_PROFILE_CINEMA_S4K));
31 }
32 static gboolean gst_jpeg2000_parse_is_storage(guint16 rsiz)   {
33         return (rsiz == GST_JPEG2000_PARSE_PROFILE_CINEMA_LTS);
34 }
35 */
36 static gboolean
37 gst_jpeg2000_parse_is_broadcast (guint16 rsiz)
38 {
39   return ((rsiz >= GST_JPEG2000_PARSE_PROFILE_BC_SINGLE) &&
40       (rsiz <= ((GST_JPEG2000_PARSE_PROFILE_BC_MULTI_R) | (0x000b)))
41       && ((rsiz & (~GST_JPEG2000_PARSE_PROFILE_BC_MASK)) == 0));
42 }
43
44 static gboolean
45 gst_jpeg2000_parse_is_imf (guint16 rsiz)
46 {
47   return ((rsiz >= GST_JPEG2000_PARSE_PROFILE_IMF_2K)
48       && (rsiz <= ((GST_JPEG2000_PARSE_PROFILE_IMF_8K_R) | (0x009b))));
49 }
50
51 static gboolean
52 gst_jpeg2000_parse_is_part_2 (guint16 rsiz)
53 {
54   return (rsiz & GST_JPEG2000_PARSE_PROFILE_PART2);
55 }
56
57
58
59 static void
60 gst_jpeg2000_parse_get_subsampling (GstJPEG2000Sampling sampling, guint8 * dx,
61     guint8 * dy)
62 {
63   *dx = 1;
64   *dy = 1;
65   if (sampling == GST_JPEG2000_SAMPLING_YBR422) {
66     *dx = 2;
67   } else if (sampling == GST_JPEG2000_SAMPLING_YBR420) {
68     *dx = 2;
69     *dy = 2;
70   } else if (sampling == GST_JPEG2000_SAMPLING_YBR410) {
71     *dx = 4;
72     *dy = 2;
73   }
74 }
75
76 #define GST_JPEG2000_JP2_SIZE_OF_BOX_ID         4
77 #define GST_JPEG2000_JP2_SIZE_OF_BOX_LEN        4
78 #define GST_JPEG2000_MARKER_SIZE        4
79
80
81 /* J2C has 8 bytes preceding J2K magic: 4 for size of box, and 4 for fourcc */
82 #define GST_JPEG2000_PARSE_SIZE_OF_J2C_PREFIX_BYTES (GST_JPEG2000_JP2_SIZE_OF_BOX_LEN +  GST_JPEG2000_JP2_SIZE_OF_BOX_ID)
83
84 /* SOC marker plus minimum size of SIZ marker */
85 #define GST_JPEG2000_PARSE_MIN_FRAME_SIZE (GST_JPEG2000_MARKER_SIZE + GST_JPEG2000_PARSE_SIZE_OF_J2C_PREFIX_BYTES + 36)
86
87 #define GST_JPEG2000_PARSE_J2K_MAGIC 0xFF4FFF51
88
89 GST_DEBUG_CATEGORY (jpeg2000_parse_debug);
90 #define GST_CAT_DEFAULT jpeg2000_parse_debug
91
92 static GstStaticPadTemplate srctemplate =
93     GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC,
94     GST_PAD_ALWAYS,
95     GST_STATIC_CAPS ("image/x-jpc,"
96         " width = (int)[1, MAX], height = (int)[1, MAX],"
97         GST_JPEG2000_SAMPLING_LIST ","
98         GST_JPEG2000_COLORSPACE_LIST ","
99         " profile = (int)[0, 49151],"
100         " parsed = (boolean) true;"
101         "image/x-j2c,"
102         " width = (int)[1, MAX], height = (int)[1, MAX],"
103         GST_JPEG2000_SAMPLING_LIST ","
104         GST_JPEG2000_COLORSPACE_LIST ","
105         " profile = (int)[0, 49151]," " parsed = (boolean) true")
106     );
107
108 static GstStaticPadTemplate sinktemplate =
109     GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK,
110     GST_PAD_ALWAYS,
111     GST_STATIC_CAPS ("image/x-jpc,"
112         GST_JPEG2000_SAMPLING_LIST ";"
113         "image/x-jpc, "
114         GST_JPEG2000_COLORSPACE_LIST ";"
115         "image/x-j2c,"
116         GST_JPEG2000_SAMPLING_LIST ";"
117         "image/x-j2c, " GST_JPEG2000_COLORSPACE_LIST)
118     );
119
120 #define parent_class gst_jpeg2000_parse_parent_class
121 G_DEFINE_TYPE (GstJPEG2000Parse, gst_jpeg2000_parse, GST_TYPE_BASE_PARSE);
122
123 static gboolean gst_jpeg2000_parse_start (GstBaseParse * parse);
124 static gboolean gst_jpeg2000_parse_event (GstBaseParse * parse,
125     GstEvent * event);
126 static GstFlowReturn gst_jpeg2000_parse_handle_frame (GstBaseParse * parse,
127     GstBaseParseFrame * frame, gint * skipsize);
128 static gboolean gst_jpeg2000_parse_set_sink_caps (GstBaseParse * parse,
129     GstCaps * caps);
130
131 static void
132 gst_jpeg2000_parse_class_init (GstJPEG2000ParseClass * klass)
133 {
134   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
135   GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
136
137   GST_DEBUG_CATEGORY_INIT (jpeg2000_parse_debug, "jpeg2000parse", 0,
138       "jpeg 2000 parser");
139
140   gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
141   gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
142   gst_element_class_set_static_metadata (gstelement_class, "JPEG 2000 parser",
143       "Codec/Parser/Video/Image",
144       "Parses JPEG 2000 files", "Aaron Boxer <boxerab@gmail.com>");
145
146   /* Override BaseParse vfuncs */
147   parse_class->set_sink_caps =
148       GST_DEBUG_FUNCPTR (gst_jpeg2000_parse_set_sink_caps);
149   parse_class->start = GST_DEBUG_FUNCPTR (gst_jpeg2000_parse_start);
150   parse_class->sink_event = GST_DEBUG_FUNCPTR (gst_jpeg2000_parse_event);
151   parse_class->handle_frame =
152       GST_DEBUG_FUNCPTR (gst_jpeg2000_parse_handle_frame);
153 }
154
155 static gboolean
156 gst_jpeg2000_parse_start (GstBaseParse * parse)
157 {
158   GstJPEG2000Parse *jpeg2000parse = GST_JPEG2000_PARSE (parse);
159   GST_DEBUG_OBJECT (jpeg2000parse, "start");
160   gst_base_parse_set_min_frame_size (parse, GST_JPEG2000_PARSE_MIN_FRAME_SIZE);
161
162   jpeg2000parse->width = 0;
163   jpeg2000parse->height = 0;
164
165   jpeg2000parse->sampling = GST_JPEG2000_SAMPLING_NONE;
166   jpeg2000parse->colorspace = GST_JPEG2000_COLORSPACE_NONE;
167   jpeg2000parse->codec_format = GST_JPEG2000_PARSE_NO_CODEC;
168   return TRUE;
169 }
170
171
172 static void
173 gst_jpeg2000_parse_init (GstJPEG2000Parse * jpeg2000parse)
174 {
175   GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (jpeg2000parse));
176   GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (jpeg2000parse));
177 }
178
179 static gboolean
180 gst_jpeg2000_parse_set_sink_caps (GstBaseParse * parse, GstCaps * caps)
181 {
182   GstJPEG2000Parse *jpeg2000parse = GST_JPEG2000_PARSE (parse);
183   GstStructure *caps_struct = gst_caps_get_structure (caps, 0);
184
185   if (gst_structure_has_name (caps_struct, "image/jp2")) {
186     jpeg2000parse->codec_format = GST_JPEG2000_PARSE_JP2;
187   } else if (gst_structure_has_name (caps_struct, "image/x-j2c")) {
188     jpeg2000parse->codec_format = GST_JPEG2000_PARSE_J2C;
189   } else if (gst_structure_has_name (caps_struct, "image/x-jpc")) {
190     jpeg2000parse->codec_format = GST_JPEG2000_PARSE_JPC;
191   }
192
193   return TRUE;
194 }
195
196 static gboolean
197 gst_jpeg2000_parse_event (GstBaseParse * parse, GstEvent * event)
198 {
199   gboolean res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (parse, event);
200   switch (GST_EVENT_TYPE (event)) {
201     case GST_EVENT_FLUSH_STOP:
202       gst_base_parse_set_min_frame_size (parse,
203           GST_JPEG2000_PARSE_MIN_FRAME_SIZE);
204       break;
205     default:
206       break;
207   }
208   return res;
209 }
210
211 static GstJPEG2000ParseFormats
212 format_from_media_type (const GstStructure * structure)
213 {
214   const char *media_type = gst_structure_get_name (structure);
215   if (!strcmp (media_type, "image/x-j2c"))
216     return GST_JPEG2000_PARSE_J2C;
217   if (!strcmp (media_type, "image/x-jpc"))
218     return GST_JPEG2000_PARSE_JPC;
219   if (!strcmp (media_type, "image/x-jp2"))
220     return GST_JPEG2000_PARSE_JP2;
221   return GST_JPEG2000_PARSE_NO_CODEC;
222 }
223
224 /* check downstream caps to configure media type */
225 static void
226 gst_jpeg2000_parse_negotiate (GstJPEG2000Parse * parse, GstCaps * in_caps)
227 {
228   GstCaps *caps;
229   guint codec_format = GST_JPEG2000_PARSE_NO_CODEC;
230
231   g_return_if_fail ((in_caps == NULL) || gst_caps_is_fixed (in_caps));
232
233   caps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (parse));
234   GST_DEBUG_OBJECT (parse, "allowed caps: %" GST_PTR_FORMAT, caps);
235
236   /* concentrate on leading structure, since decodebin parser
237    * capsfilter always includes parser template caps */
238   if (caps) {
239     caps = gst_caps_truncate (caps);
240     GST_DEBUG_OBJECT (parse, "negotiating with caps: %" GST_PTR_FORMAT, caps);
241   }
242
243   if (in_caps && caps) {
244     if (gst_caps_can_intersect (in_caps, caps)) {
245       GST_DEBUG_OBJECT (parse, "downstream accepts upstream caps");
246       codec_format =
247           format_from_media_type (gst_caps_get_structure (in_caps, 0));
248       gst_caps_unref (caps);
249       caps = NULL;
250     }
251   }
252
253   /* FIXME We could fail the negotiation immediatly if caps are empty */
254   if (caps && !gst_caps_is_empty (caps)) {
255     /* fixate to avoid ambiguity with lists when parsing */
256     caps = gst_caps_fixate (caps);
257     codec_format = format_from_media_type (gst_caps_get_structure (caps, 0));
258   }
259
260   /* default */
261   if (codec_format == GST_JPEG2000_PARSE_NO_CODEC)
262     codec_format = GST_JPEG2000_PARSE_J2C;
263
264   GST_DEBUG_OBJECT (parse, "selected codec format %d", codec_format);
265
266   parse->codec_format = codec_format;
267
268   if (caps)
269     gst_caps_unref (caps);
270 }
271
272 static const char *
273 media_type_from_codec_format (GstJPEG2000ParseFormats f)
274 {
275   switch (f) {
276     case GST_JPEG2000_PARSE_J2C:
277       return "image/x-j2c";
278     case GST_JPEG2000_PARSE_JP2:
279       return "image/x-jp2";
280     case GST_JPEG2000_PARSE_JPC:
281       return "image/x-jpc";
282     default:
283       g_assert_not_reached ();
284       return "invalid/x-invalid";
285   }
286 }
287
288 static GstFlowReturn
289 gst_jpeg2000_parse_handle_frame (GstBaseParse * parse,
290     GstBaseParseFrame * frame, gint * skipsize)
291 {
292   GstJPEG2000Parse *jpeg2000parse = GST_JPEG2000_PARSE (parse);
293   GstMapInfo map;
294   GstByteReader reader;
295   GstFlowReturn ret = GST_FLOW_OK;
296   guint eoc_offset = 0;
297   GstCaps *current_caps = NULL;
298   GstStructure *current_caps_struct = NULL;
299   const gchar *colorspace_string = NULL;
300   GstJPEG2000Colorspace colorspace = GST_JPEG2000_COLORSPACE_NONE;
301   guint x0, y0, x1, y1;
302   guint width = 0, height = 0;
303   guint8 dx[GST_JPEG2000_PARSE_MAX_SUPPORTED_COMPONENTS];
304   guint8 dy[GST_JPEG2000_PARSE_MAX_SUPPORTED_COMPONENTS];
305   guint16 numcomps;
306   guint16 capabilities = 0;
307   guint16 profile = 0;
308   gboolean validate_main_level = FALSE;
309   guint8 main_level = 0;
310   guint8 sub_level = 0;
311   guint16 compno;
312   GstJPEG2000Sampling parsed_sampling = GST_JPEG2000_SAMPLING_NONE;
313   const gchar *sink_sampling_string = NULL;
314   GstJPEG2000Sampling sink_sampling = GST_JPEG2000_SAMPLING_NONE;
315   GstJPEG2000Sampling source_sampling = GST_JPEG2000_SAMPLING_NONE;
316   guint magic_offset = 0;
317   guint j2c_box_id_offset = 0;
318   guint num_prefix_bytes = 0;   /* number of bytes to skip before actual code stream */
319   GstCaps *src_caps = NULL;
320   guint frame_size = 0;
321   gboolean is_j2c;
322
323   if (!gst_buffer_map (frame->buffer, &map, GST_MAP_READ)) {
324     GST_ERROR_OBJECT (jpeg2000parse, "Unable to map buffer");
325     return GST_FLOW_ERROR;
326   }
327
328   if (jpeg2000parse->codec_format == GST_JPEG2000_PARSE_NO_CODEC)
329     gst_jpeg2000_parse_negotiate (jpeg2000parse, NULL);
330
331   is_j2c = jpeg2000parse->codec_format == GST_JPEG2000_PARSE_J2C;
332
333   gst_byte_reader_init (&reader, map.data, map.size);
334   num_prefix_bytes = GST_JPEG2000_MARKER_SIZE;
335
336   if (is_j2c) {
337     num_prefix_bytes +=
338         GST_JPEG2000_JP2_SIZE_OF_BOX_LEN + GST_JPEG2000_JP2_SIZE_OF_BOX_ID;
339     /* check for "jp2c" */
340     j2c_box_id_offset = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff,
341         GST_MAKE_FOURCC ('j', 'p', '2', 'c'), 0,
342         gst_byte_reader_get_remaining (&reader));
343
344     if (j2c_box_id_offset == -1) {
345       GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
346           ("Missing contiguous code stream box for j2c stream"));
347       ret = GST_FLOW_ERROR;
348       goto beach;
349     }
350   }
351
352   /* Look for magic. If found, skip to beginning of frame */
353   magic_offset = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff,
354       GST_JPEG2000_PARSE_J2K_MAGIC, 0, gst_byte_reader_get_remaining (&reader));
355   if (magic_offset == -1) {
356     *skipsize = gst_byte_reader_get_size (&reader) - num_prefix_bytes;
357     goto beach;
358   }
359
360   /* see if we need to skip any bytes at beginning of frame */
361   GST_DEBUG_OBJECT (jpeg2000parse, "Found magic at offset = %d", magic_offset);
362   if (magic_offset > 0) {
363     *skipsize = magic_offset;
364     /* J2C has 8 bytes preceding J2K magic */
365     if (is_j2c)
366       *skipsize -= GST_JPEG2000_PARSE_SIZE_OF_J2C_PREFIX_BYTES;
367     if (*skipsize > 0)
368       goto beach;
369   }
370
371   if (is_j2c) {
372     /* sanity check on box id offset */
373     if (j2c_box_id_offset + GST_JPEG2000_JP2_SIZE_OF_BOX_ID != magic_offset) {
374       GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
375           ("Corrupt contiguous code stream box for j2c stream"));
376       ret = GST_FLOW_ERROR;
377       goto beach;
378     }
379
380     /* check that we have enough bytes for the J2C box length */
381     if (j2c_box_id_offset < GST_JPEG2000_JP2_SIZE_OF_BOX_LEN) {
382       *skipsize = gst_byte_reader_get_size (&reader) - num_prefix_bytes;
383       goto beach;
384     }
385
386     if (!gst_byte_reader_skip (&reader,
387             j2c_box_id_offset - GST_JPEG2000_JP2_SIZE_OF_BOX_LEN))
388       goto beach;
389
390     /* read the box length, and adjust num_prefix_bytes accordingly  */
391     if (!gst_byte_reader_get_uint32_be (&reader, &frame_size))
392       goto beach;
393     num_prefix_bytes -= GST_JPEG2000_JP2_SIZE_OF_BOX_LEN;
394
395     /* bail out if not enough data for frame */
396     if ((gst_byte_reader_get_size (&reader) < frame_size))
397       goto beach;
398   }
399
400   /* 2 to skip marker size */
401   if (!gst_byte_reader_skip (&reader, num_prefix_bytes + 2))
402     goto beach;
403
404   if (!gst_byte_reader_get_uint16_be (&reader, &capabilities))
405     goto beach;
406
407   profile = capabilities & GST_JPEG2000_PARSE_PROFILE_MASK;
408   if (!gst_jpeg2000_parse_is_part_2 (capabilities)) {
409     if ((profile > GST_JPEG2000_PARSE_PROFILE_CINEMA_LTS)
410         && !gst_jpeg2000_parse_is_broadcast (profile)
411         && !gst_jpeg2000_parse_is_imf (profile)) {
412       GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
413           ("Unrecognized JPEG 2000 profile %d", profile));
414       ret = GST_FLOW_ERROR;
415       goto beach;
416     }
417     if (gst_jpeg2000_parse_is_broadcast (profile)) {
418       main_level = capabilities & 0xF;
419       validate_main_level = TRUE;
420     } else if (gst_jpeg2000_parse_is_imf (profile)) {
421       main_level = capabilities & 0xF;
422       validate_main_level = TRUE;
423       sub_level = (capabilities >> 4) & 0xF;
424       if (sub_level > 9) {
425         GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
426             ("Sub level %d is invalid", sub_level));
427         ret = GST_FLOW_ERROR;
428         goto beach;
429       }
430     }
431     if (validate_main_level && main_level > 11) {
432       GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
433           ("Main level %d is invalid", main_level));
434       ret = GST_FLOW_ERROR;
435       goto beach;
436
437     }
438   }
439
440
441   if (!gst_byte_reader_get_uint32_be (&reader, &x1))
442     goto beach;
443
444   if (!gst_byte_reader_get_uint32_be (&reader, &y1))
445     goto beach;
446
447   if (!gst_byte_reader_get_uint32_be (&reader, &x0))
448     goto beach;
449
450   if (!gst_byte_reader_get_uint32_be (&reader, &y0))
451     goto beach;
452
453   /* sanity check on image dimensions */
454   if (x1 < x0 || y1 < y0) {
455     GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
456         ("Nonsensical image dimensions %d,%d,%d,%d", x0, y0, x1, y1));
457     ret = GST_FLOW_ERROR;
458     goto beach;
459   }
460
461   width = x1 - x0;
462   height = y1 - y0;
463
464   GST_DEBUG_OBJECT (jpeg2000parse, "Parsed image dimensions %d,%d", width,
465       height);
466
467   /* skip tile dimensions */
468   if (!gst_byte_reader_skip (&reader, 4 * 4))
469     goto beach;
470
471   /* read number of components */
472   if (!gst_byte_reader_get_uint16_be (&reader, &numcomps))
473     goto beach;
474
475   if (numcomps == 2 || numcomps > GST_JPEG2000_PARSE_MAX_SUPPORTED_COMPONENTS) {
476     GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
477         ("Unsupported number of components %d", numcomps));
478     ret = GST_FLOW_NOT_NEGOTIATED;
479     goto beach;
480   }
481
482   current_caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (parse));
483   if (!current_caps) {
484     GST_ERROR_OBJECT (jpeg2000parse, "Unable to get current caps");
485     ret = GST_FLOW_NOT_NEGOTIATED;
486     goto beach;
487   }
488
489   current_caps_struct = gst_caps_get_structure (current_caps, 0);
490   if (!current_caps_struct) {
491     GST_ERROR_OBJECT (jpeg2000parse,
492         "Unable to get structure of current caps struct");
493     ret = GST_FLOW_NOT_NEGOTIATED;
494     goto beach;
495   }
496
497   colorspace_string = gst_structure_get_string
498       (current_caps_struct, "colorspace");
499   if (colorspace_string)
500     colorspace = gst_jpeg2000_colorspace_from_string (colorspace_string);
501   sink_sampling_string = gst_structure_get_string
502       (current_caps_struct, "sampling");
503   if (sink_sampling_string)
504     sink_sampling = gst_jpeg2000_sampling_from_string (sink_sampling_string);
505
506   for (compno = 0; compno < numcomps; ++compno) {
507
508     /* skip Ssiz (precision and signed/unsigned bit )  */
509     if (!gst_byte_reader_skip (&reader, 1))
510       goto beach;
511
512     if (!gst_byte_reader_get_uint8 (&reader, dx + compno))
513       goto beach;
514
515     if (!gst_byte_reader_get_uint8 (&reader, dy + compno))
516       goto beach;
517
518     GST_DEBUG_OBJECT (jpeg2000parse,
519         "Parsed sub-sampling %d,%d for component %d", dx[compno], dy[compno],
520         compno);
521   }
522
523   /*** sanity check on sub-sampling *****/
524   if (dx[0] != 1 || dy[0] != 1) {
525     GST_WARNING_OBJECT (jpeg2000parse, "Sub-sampled luma channel");
526   }
527   if (dx[1] != dx[2] || dy[1] != dy[2]) {
528     GST_WARNING_OBJECT (jpeg2000parse,
529         "Chroma channel sub-sampling factors are not equal");
530   }
531   for (compno = 0; compno < numcomps; ++compno) {
532     if (colorspace != GST_JPEG2000_COLORSPACE_NONE
533         && (colorspace != GST_JPEG2000_COLORSPACE_YUV)
534         && (dx[compno] > 1 || dy[compno] > 1)) {
535       GST_WARNING_OBJECT (jpeg2000parse,
536           "Sub-sampled RGB or monochrome color spaces");
537     }
538     if (sink_sampling != GST_JPEG2000_SAMPLING_NONE) {
539       guint8 dx_caps, dy_caps;
540       gst_jpeg2000_parse_get_subsampling (sink_sampling, &dx_caps, &dy_caps);
541       if (dx_caps != dx[compno] || dy_caps != dy[compno]) {
542         GstJPEG2000Colorspace inferred_colorspace =
543             GST_JPEG2000_COLORSPACE_NONE;
544         GST_WARNING_OBJECT (jpeg2000parse,
545             "Sink caps sub-sampling %d,%d for channel %d does not match stream sub-sampling %d,%d",
546             dx_caps, dy_caps, compno, dx[compno], dy[compno]);
547         /* try to guess correct color space */
548         if (gst_jpeg2000_sampling_is_mono (sink_sampling))
549           inferred_colorspace = GST_JPEG2000_COLORSPACE_GRAY;
550         else if (gst_jpeg2000_sampling_is_rgb (sink_sampling))
551           inferred_colorspace = GST_JPEG2000_COLORSPACE_RGB;
552         else if (gst_jpeg2000_sampling_is_yuv (sink_sampling))
553           inferred_colorspace = GST_JPEG2000_COLORSPACE_YUV;
554         else if (colorspace)
555           inferred_colorspace = colorspace;
556         if (inferred_colorspace != GST_JPEG2000_COLORSPACE_NONE) {
557           sink_sampling = GST_JPEG2000_SAMPLING_NONE;
558           colorspace = inferred_colorspace;
559           break;
560         } else {
561           /* unrecognized sink_sampling and no colorspace */
562           GST_ERROR_OBJECT (jpeg2000parse,
563               "Unrecognized sink sampling field and no sink colorspace field");
564           ret = GST_FLOW_NOT_NEGOTIATED;
565           goto beach;
566         }
567       }
568     }
569   }
570   /*************************************/
571
572   /* if colorspace is present, we can work out the parsed_sampling field */
573   if (colorspace != GST_JPEG2000_COLORSPACE_NONE) {
574     if (colorspace == GST_JPEG2000_COLORSPACE_YUV) {
575       if (numcomps == 4) {
576         guint i;
577         parsed_sampling = GST_JPEG2000_SAMPLING_YBRA4444_EXT;
578         for (i = 0; i < 4; ++i) {
579           if (dx[i] > 1 || dy[i] > 1) {
580             GST_WARNING_OBJECT (jpeg2000parse, "Sub-sampled YUVA images");
581           }
582         }
583       } else if (numcomps == 3) {
584         /* use sub-sampling from U chroma channel */
585         if (dx[1] == 1 && dy[1] == 1) {
586           parsed_sampling = GST_JPEG2000_SAMPLING_YBR444;
587         } else if (dx[1] == 2 && dy[1] == 2) {
588           parsed_sampling = GST_JPEG2000_SAMPLING_YBR420;
589         } else if (dx[1] == 4 && dy[1] == 2) {
590           parsed_sampling = GST_JPEG2000_SAMPLING_YBR410;
591         } else if (dx[1] == 2 && dy[1] == 1) {
592           parsed_sampling = GST_JPEG2000_SAMPLING_YBR422;
593         } else {
594           GST_WARNING_OBJECT (jpeg2000parse,
595               "Unsupported sub-sampling factors %d,%d", dx[1], dy[1]);
596           /* best effort */
597           parsed_sampling = GST_JPEG2000_SAMPLING_YBR444;
598         }
599       }
600     } else if (colorspace == GST_JPEG2000_COLORSPACE_GRAY) {
601       parsed_sampling = GST_JPEG2000_SAMPLING_GRAYSCALE;
602     } else {
603       parsed_sampling =
604           (numcomps ==
605           4) ? GST_JPEG2000_SAMPLING_RGBA : GST_JPEG2000_SAMPLING_RGB;
606     }
607   } else {
608     if (gst_jpeg2000_sampling_is_mono (sink_sampling)) {
609       colorspace = GST_JPEG2000_COLORSPACE_GRAY;
610     } else if (gst_jpeg2000_sampling_is_rgb (sink_sampling)) {
611       colorspace = GST_JPEG2000_COLORSPACE_RGB;
612     } else {
613       /* best effort */
614       colorspace = GST_JPEG2000_COLORSPACE_YUV;
615     }
616   }
617
618   gst_jpeg2000_parse_negotiate (jpeg2000parse, current_caps);
619
620   /* now we can set the source caps, if something has changed */
621   source_sampling =
622       sink_sampling !=
623       GST_JPEG2000_SAMPLING_NONE ? sink_sampling : parsed_sampling;
624   if (width != jpeg2000parse->width || height != jpeg2000parse->height
625       || jpeg2000parse->sampling != source_sampling
626       || jpeg2000parse->colorspace != colorspace) {
627     gint fr_num = 0, fr_denom = 0;
628
629     jpeg2000parse->width = width;
630     jpeg2000parse->height = height;
631     jpeg2000parse->sampling = source_sampling;
632     jpeg2000parse->colorspace = colorspace;
633
634     src_caps =
635         gst_caps_new_simple (media_type_from_codec_format
636         (jpeg2000parse->codec_format),
637         "width", G_TYPE_INT, width,
638         "height", G_TYPE_INT, height,
639         "colorspace", G_TYPE_STRING,
640         gst_jpeg2000_colorspace_to_string (colorspace), "sampling",
641         G_TYPE_STRING, gst_jpeg2000_sampling_to_string (source_sampling),
642         "profile", G_TYPE_UINT, profile, NULL);
643
644     if (gst_jpeg2000_parse_is_broadcast (capabilities)
645         || gst_jpeg2000_parse_is_imf (capabilities)) {
646       gst_caps_set_simple (src_caps, "main-level", G_TYPE_UINT, main_level,
647           NULL);
648       if (gst_jpeg2000_parse_is_imf (capabilities)) {
649         gst_caps_set_simple (src_caps, "sub-level", G_TYPE_UINT, sub_level,
650             NULL);
651       }
652     }
653
654     if (gst_structure_get_fraction (current_caps_struct, "framerate", &fr_num,
655             &fr_denom)) {
656       gst_caps_set_simple (src_caps, "framerate", GST_TYPE_FRACTION, fr_num,
657           fr_denom, NULL);
658     } else {
659       GST_WARNING_OBJECT (jpeg2000parse, "No framerate set");
660     }
661     if (!gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), src_caps)) {
662       GST_ERROR_OBJECT (jpeg2000parse, "Unable to set source caps");
663       ret = GST_FLOW_NOT_NEGOTIATED;
664       gst_caps_unref (src_caps);
665       goto beach;
666     }
667     gst_caps_unref (src_caps);
668   }
669   /*************************************************/
670
671   /* look for EOC to mark frame end */
672   /* look for EOC end of codestream marker  */
673   eoc_offset = gst_byte_reader_masked_scan_uint32 (&reader, 0x0000ffff,
674       0xFFD9, 0, gst_byte_reader_get_remaining (&reader));
675
676   if (eoc_offset != -1) {
677     /* add 4 for eoc marker and eoc marker size */
678     guint eoc_frame_size = gst_byte_reader_get_pos (&reader) + eoc_offset + 4;
679     GST_DEBUG_OBJECT (jpeg2000parse,
680         "Found EOC at offset = %d, frame size = %d", eoc_offset,
681         eoc_frame_size);
682
683     /* bail out if not enough data for frame */
684     if (gst_byte_reader_get_size (&reader) < eoc_frame_size)
685       goto beach;
686
687     if (frame_size && frame_size != eoc_frame_size) {
688       GST_WARNING_OBJECT (jpeg2000parse,
689           "Frame size %d from contiguous code size does not equal frame size %d signalled by eoc",
690           frame_size, eoc_frame_size);
691     }
692     frame_size = eoc_frame_size;
693   }
694
695   /* clean up and finish frame */
696   if (current_caps)
697     gst_caps_unref (current_caps);
698   gst_buffer_unmap (frame->buffer, &map);
699   return gst_base_parse_finish_frame (parse, frame, frame_size);
700
701 beach:
702   if (current_caps)
703     gst_caps_unref (current_caps);
704   gst_buffer_unmap (frame->buffer, &map);
705   return ret;
706 }