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