1 /* GStreamer JPEG 2000 Parser
2 * Copyright (C) <2016> Grok Image Compession Inc.
3 * @author Aaron Boxer <boxerab@gmail.com>
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.
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.
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.
25 #include "gstjpeg2000parse.h"
26 #include <gst/base/base.h>
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));
32 static gboolean gst_jpeg2000_parse_is_storage(guint16 rsiz) {
33 return (rsiz == GST_JPEG2000_PARSE_PROFILE_CINEMA_LTS);
37 gst_jpeg2000_parse_is_broadcast (guint16 rsiz)
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));
45 gst_jpeg2000_parse_is_imf (guint16 rsiz)
47 return ((rsiz >= GST_JPEG2000_PARSE_PROFILE_IMF_2K)
48 && (rsiz <= ((GST_JPEG2000_PARSE_PROFILE_IMF_8K_R) | (0x009b))));
52 gst_jpeg2000_parse_is_part_2 (guint16 rsiz)
54 return (rsiz & GST_JPEG2000_PARSE_PROFILE_PART2);
60 gst_jpeg2000_parse_get_subsampling (GstJPEG2000Sampling sampling, guint8 * dx,
65 if (sampling == GST_JPEG2000_SAMPLING_YBR422) {
67 } else if (sampling == GST_JPEG2000_SAMPLING_YBR420) {
70 } else if (sampling == GST_JPEG2000_SAMPLING_YBR410) {
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
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)
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)
87 #define GST_JPEG2000_PARSE_J2K_MAGIC 0xFF4FFF51
89 GST_DEBUG_CATEGORY (jpeg2000_parse_debug);
90 #define GST_CAT_DEFAULT jpeg2000_parse_debug
92 static GstStaticPadTemplate srctemplate =
93 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC,
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;"
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")
108 static GstStaticPadTemplate sinktemplate =
109 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK,
111 GST_STATIC_CAPS ("image/x-jpc;image/x-j2c")
114 #define parent_class gst_jpeg2000_parse_parent_class
115 G_DEFINE_TYPE (GstJPEG2000Parse, gst_jpeg2000_parse, GST_TYPE_BASE_PARSE);
117 static gboolean gst_jpeg2000_parse_start (GstBaseParse * parse);
118 static gboolean gst_jpeg2000_parse_event (GstBaseParse * parse,
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,
126 gst_jpeg2000_parse_class_init (GstJPEG2000ParseClass * klass)
128 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
129 GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
131 GST_DEBUG_CATEGORY_INIT (jpeg2000_parse_debug, "jpeg2000parse", 0,
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>");
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);
150 gst_jpeg2000_parse_start (GstBaseParse * parse)
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);
156 jpeg2000parse->width = 0;
157 jpeg2000parse->height = 0;
159 jpeg2000parse->sampling = GST_JPEG2000_SAMPLING_NONE;
160 jpeg2000parse->colorspace = GST_JPEG2000_COLORSPACE_NONE;
161 jpeg2000parse->codec_format = GST_JPEG2000_PARSE_NO_CODEC;
167 gst_jpeg2000_parse_init (GstJPEG2000Parse * jpeg2000parse)
169 GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (jpeg2000parse));
170 GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (jpeg2000parse));
174 gst_jpeg2000_parse_set_sink_caps (GstBaseParse * parse, GstCaps * caps)
176 GstJPEG2000Parse *jpeg2000parse = GST_JPEG2000_PARSE (parse);
177 GstStructure *caps_struct = gst_caps_get_structure (caps, 0);
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;
191 gst_jpeg2000_parse_event (GstBaseParse * parse, GstEvent * event)
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);
205 static GstJPEG2000ParseFormats
206 format_from_media_type (const GstStructure * structure)
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;
218 /* check downstream caps to configure media type */
220 gst_jpeg2000_parse_negotiate (GstJPEG2000Parse * parse, GstCaps * in_caps)
223 guint codec_format = GST_JPEG2000_PARSE_NO_CODEC;
225 g_return_if_fail ((in_caps == NULL) || gst_caps_is_fixed (in_caps));
227 caps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (parse));
228 GST_DEBUG_OBJECT (parse, "allowed caps: %" GST_PTR_FORMAT, caps);
230 /* concentrate on leading structure, since decodebin parser
231 * capsfilter always includes parser template caps */
233 caps = gst_caps_truncate (caps);
234 GST_DEBUG_OBJECT (parse, "negotiating with caps: %" GST_PTR_FORMAT, caps);
237 if (in_caps && caps) {
238 if (gst_caps_can_intersect (in_caps, caps)) {
239 GST_DEBUG_OBJECT (parse, "downstream accepts upstream caps");
241 format_from_media_type (gst_caps_get_structure (in_caps, 0));
242 gst_caps_unref (caps);
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));
253 GST_DEBUG_OBJECT (parse, "selected codec format %d", codec_format);
255 parse->codec_format = codec_format;
258 gst_caps_unref (caps);
262 media_type_from_codec_format (GstJPEG2000ParseFormats 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";
272 g_assert_not_reached ();
273 return "invalid/x-invalid";
278 gst_jpeg2000_parse_handle_frame (GstBaseParse * parse,
279 GstBaseParseFrame * frame, gint * skipsize)
281 GstJPEG2000Parse *jpeg2000parse = GST_JPEG2000_PARSE (parse);
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];
294 guint16 capabilities = 0;
296 gboolean validate_main_level = FALSE;
297 guint8 main_level = 0;
298 guint8 sub_level = 0;
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;
310 gboolean parsed_j2c_4cc = FALSE;
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;
316 gst_byte_reader_init (&reader, map.data, map.size);
318 /* try to get from caps */
319 if (jpeg2000parse->codec_format == GST_JPEG2000_PARSE_NO_CODEC)
320 gst_jpeg2000_parse_negotiate (jpeg2000parse, NULL);
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;
335 is_j2c = jpeg2000parse->codec_format == GST_JPEG2000_PARSE_J2C;
338 num_prefix_bytes = GST_JPEG2000_MARKER_SIZE;
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) {
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));
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;
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;
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 */
372 *skipsize -= GST_JPEG2000_PARSE_SIZE_OF_J2C_PREFIX_BYTES;
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;
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;
392 if (!gst_byte_reader_skip (&reader,
393 j2c_box_id_offset - GST_JPEG2000_JP2_SIZE_OF_BOX_LEN))
396 /* read the box length, and adjust num_prefix_bytes accordingly */
397 if (!gst_byte_reader_get_uint32_be (&reader, &frame_size))
399 num_prefix_bytes -= GST_JPEG2000_JP2_SIZE_OF_BOX_LEN;
401 /* bail out if not enough data for frame */
402 if ((gst_byte_reader_get_size (&reader) < frame_size))
406 /* 2 to skip marker size */
407 if (!gst_byte_reader_skip (&reader, num_prefix_bytes + 2))
410 if (!gst_byte_reader_get_uint16_be (&reader, &capabilities))
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;
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;
431 GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
432 ("Sub level %d is invalid", sub_level));
433 ret = GST_FLOW_ERROR;
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;
447 if (!gst_byte_reader_get_uint32_be (&reader, &x1))
450 if (!gst_byte_reader_get_uint32_be (&reader, &y1))
453 if (!gst_byte_reader_get_uint32_be (&reader, &x0))
456 if (!gst_byte_reader_get_uint32_be (&reader, &y0))
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;
470 GST_DEBUG_OBJECT (jpeg2000parse, "Parsed image dimensions %d,%d", width,
473 /* skip tile dimensions */
474 if (!gst_byte_reader_skip (&reader, 4 * 4))
477 /* read number of components */
478 if (!gst_byte_reader_get_uint16_be (&reader, &numcomps))
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;
488 current_caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (parse));
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;
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);
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;
518 3) ? GST_JPEG2000_COLORSPACE_RGB : GST_JPEG2000_COLORSPACE_GRAY;
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");
530 for (compno = 0; compno < numcomps; ++compno) {
532 /* skip Ssiz (precision and signed/unsigned bit ) */
533 if (!gst_byte_reader_skip (&reader, 1))
536 if (!gst_byte_reader_get_uint8 (&reader, dx + compno))
539 if (!gst_byte_reader_get_uint8 (&reader, dy + compno))
542 GST_DEBUG_OBJECT (jpeg2000parse,
543 "Parsed sub-sampling %d,%d for component %d", dx[compno], dy[compno],
547 /*** sanity check on sub-sampling *****/
548 if (dx[0] != 1 || dy[0] != 1) {
549 GST_WARNING_OBJECT (jpeg2000parse, "Sub-sampled luma channel");
551 if (dx[1] != dx[2] || dy[1] != dy[2]) {
552 GST_WARNING_OBJECT (jpeg2000parse,
553 "Chroma channel sub-sampling factors are not equal");
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");
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;
579 inferred_colorspace = colorspace;
580 if (inferred_colorspace != GST_JPEG2000_COLORSPACE_NONE) {
581 sink_sampling = GST_JPEG2000_SAMPLING_NONE;
582 colorspace = inferred_colorspace;
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;
594 /*************************************/
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) {
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");
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;
618 GST_WARNING_OBJECT (jpeg2000parse,
619 "Unsupported sub-sampling factors %d,%d", dx[1], dy[1]);
621 parsed_sampling = GST_JPEG2000_SAMPLING_YBR444;
624 } else if (colorspace == GST_JPEG2000_COLORSPACE_GRAY) {
625 parsed_sampling = GST_JPEG2000_SAMPLING_GRAYSCALE;
629 4) ? GST_JPEG2000_SAMPLING_RGBA : GST_JPEG2000_SAMPLING_RGB;
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;
638 colorspace = GST_JPEG2000_COLORSPACE_YUV;
642 gst_jpeg2000_parse_negotiate (jpeg2000parse, current_caps);
644 /* now we can set the source caps, if something has changed */
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;
653 jpeg2000parse->width = width;
654 jpeg2000parse->height = height;
655 jpeg2000parse->sampling = source_sampling;
656 jpeg2000parse->colorspace = colorspace;
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);
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,
672 if (gst_jpeg2000_parse_is_imf (capabilities)) {
673 gst_caps_set_simple (src_caps, "sub-level", G_TYPE_UINT, sub_level,
678 if (current_caps_struct &&
679 gst_structure_get_fraction (current_caps_struct, "framerate", &fr_num,
681 gst_caps_set_simple (src_caps, "framerate", GST_TYPE_FRACTION, fr_num,
684 GST_WARNING_OBJECT (jpeg2000parse, "No framerate set");
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);
693 gst_caps_unref (src_caps);
695 /*************************************************/
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));
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,
709 /* bail out if not enough data for frame */
710 if (gst_byte_reader_get_size (&reader) < eoc_frame_size)
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);
718 frame_size = eoc_frame_size;
723 /* clean up and finish frame */
725 gst_caps_unref (current_caps);
726 gst_buffer_unmap (frame->buffer, &map);
727 return gst_base_parse_finish_frame (parse, frame, frame_size);
731 gst_caps_unref (current_caps);
732 gst_buffer_unmap (frame->buffer, &map);