2 * Copyright (C) 2012 Collabora Ltd.
3 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
4 * Copyright (C) 2013 Sebastian Dröge <slomo@circular-chaos.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
27 #include "gstopenjpegenc.h"
28 #include <gst/codecparsers/gstjpeg2000sampling.h>
33 GST_DEBUG_CATEGORY_STATIC (gst_openjpeg_enc_debug);
34 #define GST_CAT_DEFAULT gst_openjpeg_enc_debug
36 #define GST_OPENJPEG_ENC_TYPE_PROGRESSION_ORDER (gst_openjpeg_enc_progression_order_get_type())
38 gst_openjpeg_enc_progression_order_get_type (void)
40 static const GEnumValue values[] = {
41 {OPJ_LRCP, "LRCP", "lrcp"},
42 {OPJ_RLCP, "RLCP", "rlcp"},
43 {OPJ_RPCL, "RPCL", "rpcl"},
44 {OPJ_PCRL, "PCRL", "pcrl"},
45 {OPJ_CPRL, "CPRL", "crpl"},
48 static volatile GType id = 0;
50 if (g_once_init_enter ((gsize *) & id)) {
53 _id = g_enum_register_static ("GstOpenJPEGEncProgressionOrder", values);
55 g_once_init_leave ((gsize *) & id, _id);
66 PROP_PROGRESSION_ORDER,
75 #define DEFAULT_NUM_LAYERS 1
76 #define DEFAULT_NUM_RESOLUTIONS 6
77 #define DEFAULT_PROGRESSION_ORDER OPJ_LRCP
78 #define DEFAULT_TILE_OFFSET_X 0
79 #define DEFAULT_TILE_OFFSET_Y 0
80 #define DEFAULT_TILE_WIDTH 0
81 #define DEFAULT_TILE_HEIGHT 0
82 #define GST_OPENJPEG_ENC_DEFAULT_NUM_STRIPES 1
84 static void gst_openjpeg_enc_set_property (GObject * object, guint prop_id,
85 const GValue * value, GParamSpec * pspec);
86 static void gst_openjpeg_enc_get_property (GObject * object, guint prop_id,
87 GValue * value, GParamSpec * pspec);
89 static gboolean gst_openjpeg_enc_start (GstVideoEncoder * encoder);
90 static gboolean gst_openjpeg_enc_stop (GstVideoEncoder * encoder);
91 static gboolean gst_openjpeg_enc_set_format (GstVideoEncoder * encoder,
92 GstVideoCodecState * state);
93 static GstFlowReturn gst_openjpeg_enc_handle_frame (GstVideoEncoder * encoder,
94 GstVideoCodecFrame * frame);
95 static gboolean gst_openjpeg_enc_propose_allocation (GstVideoEncoder * encoder,
98 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
99 #define GRAY16 "GRAY16_LE"
100 #define YUV10 "Y444_10LE, I422_10LE, I420_10LE"
102 #define GRAY16 "GRAY16_BE"
103 #define YUV10 "Y444_10BE, I422_10BE, I420_10BE"
106 static GstStaticPadTemplate gst_openjpeg_enc_sink_template =
107 GST_STATIC_PAD_TEMPLATE ("sink",
110 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ ARGB64, ARGB, xRGB, "
111 "AYUV64, " YUV10 ", "
112 "AYUV, Y444, Y42B, I420, Y41B, YUV9, " "GRAY8, " GRAY16 " }"))
115 static GstStaticPadTemplate gst_openjpeg_enc_src_template =
116 GST_STATIC_PAD_TEMPLATE ("src",
119 GST_STATIC_CAPS ("image/x-j2c, "
120 "width = (int) [1, MAX], "
121 "height = (int) [1, MAX], "
122 "num-components = (int) [1, 4], "
123 "num-stripes = (int) [1, MAX], "
124 GST_JPEG2000_SAMPLING_LIST ","
125 GST_JPEG2000_COLORSPACE_LIST "; "
127 "width = (int) [1, MAX], "
128 "height = (int) [1, MAX], "
129 "num-components = (int) [1, 4], "
130 GST_JPEG2000_SAMPLING_LIST ","
131 GST_JPEG2000_COLORSPACE_LIST "; "
132 "image/jp2, " "width = (int) [1, MAX], " "height = (int) [1, MAX]")
135 #define parent_class gst_openjpeg_enc_parent_class
136 G_DEFINE_TYPE (GstOpenJPEGEnc, gst_openjpeg_enc, GST_TYPE_VIDEO_ENCODER);
139 gst_openjpeg_enc_class_init (GstOpenJPEGEncClass * klass)
141 GObjectClass *gobject_class;
142 GstElementClass *element_class;
143 GstVideoEncoderClass *video_encoder_class;
145 gobject_class = (GObjectClass *) klass;
146 element_class = (GstElementClass *) klass;
147 video_encoder_class = (GstVideoEncoderClass *) klass;
149 gobject_class->set_property = gst_openjpeg_enc_set_property;
150 gobject_class->get_property = gst_openjpeg_enc_get_property;
152 g_object_class_install_property (gobject_class, PROP_NUM_LAYERS,
153 g_param_spec_int ("num-layers", "Number of layers",
154 "Number of layers", 1, 10, DEFAULT_NUM_LAYERS,
155 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
157 g_object_class_install_property (gobject_class, PROP_NUM_RESOLUTIONS,
158 g_param_spec_int ("num-resolutions", "Number of resolutions",
159 "Number of resolutions", 1, 10, DEFAULT_NUM_RESOLUTIONS,
160 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
162 g_object_class_install_property (gobject_class, PROP_PROGRESSION_ORDER,
163 g_param_spec_enum ("progression-order", "Progression Order",
164 "Progression order", GST_OPENJPEG_ENC_TYPE_PROGRESSION_ORDER,
165 DEFAULT_PROGRESSION_ORDER,
166 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
168 g_object_class_install_property (gobject_class, PROP_TILE_OFFSET_X,
169 g_param_spec_int ("tile-offset-x", "Tile Offset X",
170 "Tile Offset X", G_MININT, G_MAXINT, DEFAULT_TILE_OFFSET_X,
171 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
173 g_object_class_install_property (gobject_class, PROP_TILE_OFFSET_Y,
174 g_param_spec_int ("tile-offset-y", "Tile Offset Y",
175 "Tile Offset Y", G_MININT, G_MAXINT, DEFAULT_TILE_OFFSET_Y,
176 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
178 g_object_class_install_property (gobject_class, PROP_TILE_WIDTH,
179 g_param_spec_int ("tile-width", "Tile Width",
180 "Tile Width", 0, G_MAXINT, DEFAULT_TILE_WIDTH,
181 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
183 g_object_class_install_property (gobject_class, PROP_TILE_HEIGHT,
184 g_param_spec_int ("tile-height", "Tile Height",
185 "Tile Height", 0, G_MAXINT, DEFAULT_TILE_HEIGHT,
186 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
189 * GstOpenJPEGEnc:num-stripes:
191 * Number of stripes to use for low latency encoding . (1 = low latency disabled)
195 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NUM_STRIPES,
196 g_param_spec_int ("num-stripes", "Number of stripes",
197 "Number of stripes for low latency encoding. (1 = low latency disabled)",
198 1, G_MAXINT, GST_OPENJPEG_ENC_DEFAULT_NUM_STRIPES,
199 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
201 gst_element_class_add_static_pad_template (element_class,
202 &gst_openjpeg_enc_src_template);
203 gst_element_class_add_static_pad_template (element_class,
204 &gst_openjpeg_enc_sink_template);
206 gst_element_class_set_static_metadata (element_class,
207 "OpenJPEG JPEG2000 encoder",
208 "Codec/Encoder/Video",
209 "Encode JPEG2000 streams",
210 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
212 video_encoder_class->start = GST_DEBUG_FUNCPTR (gst_openjpeg_enc_start);
213 video_encoder_class->stop = GST_DEBUG_FUNCPTR (gst_openjpeg_enc_stop);
214 video_encoder_class->set_format =
215 GST_DEBUG_FUNCPTR (gst_openjpeg_enc_set_format);
216 video_encoder_class->handle_frame =
217 GST_DEBUG_FUNCPTR (gst_openjpeg_enc_handle_frame);
218 video_encoder_class->propose_allocation = gst_openjpeg_enc_propose_allocation;
220 GST_DEBUG_CATEGORY_INIT (gst_openjpeg_enc_debug, "openjpegenc", 0,
223 gst_type_mark_as_plugin_api (GST_OPENJPEG_ENC_TYPE_PROGRESSION_ORDER, 0);
227 gst_openjpeg_enc_init (GstOpenJPEGEnc * self)
229 GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_ENCODER_SINK_PAD (self));
231 opj_set_default_encoder_parameters (&self->params);
233 self->params.cp_fixed_quality = 1;
234 self->params.cp_disto_alloc = 0;
235 self->params.cp_fixed_alloc = 0;
238 * TODO: Add properties / caps fields for these
241 * self->params.tcp_rates;
242 * self->params.tcp_distoratio;
244 * self->params.irreversible;
245 * self->params.cp_cinema;
246 * self->params.cp_rsiz;
249 self->params.tcp_numlayers = DEFAULT_NUM_LAYERS;
250 self->params.numresolution = DEFAULT_NUM_RESOLUTIONS;
251 self->params.prog_order = DEFAULT_PROGRESSION_ORDER;
252 self->params.cp_tx0 = DEFAULT_TILE_OFFSET_X;
253 self->params.cp_ty0 = DEFAULT_TILE_OFFSET_Y;
254 self->params.cp_tdx = DEFAULT_TILE_WIDTH;
255 self->params.cp_tdy = DEFAULT_TILE_HEIGHT;
256 self->params.tile_size_on = (self->params.cp_tdx != 0
257 && self->params.cp_tdy != 0);
259 self->num_stripes = GST_OPENJPEG_ENC_DEFAULT_NUM_STRIPES;
263 gst_openjpeg_enc_set_property (GObject * object, guint prop_id,
264 const GValue * value, GParamSpec * pspec)
266 GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (object);
269 case PROP_NUM_LAYERS:
270 self->params.tcp_numlayers = g_value_get_int (value);
272 case PROP_NUM_RESOLUTIONS:
273 self->params.numresolution = g_value_get_int (value);
275 case PROP_PROGRESSION_ORDER:
276 self->params.prog_order = g_value_get_enum (value);
278 case PROP_TILE_OFFSET_X:
279 self->params.cp_tx0 = g_value_get_int (value);
281 case PROP_TILE_OFFSET_Y:
282 self->params.cp_ty0 = g_value_get_int (value);
284 case PROP_TILE_WIDTH:
285 self->params.cp_tdx = g_value_get_int (value);
286 self->params.tile_size_on = (self->params.cp_tdx != 0
287 && self->params.cp_tdy != 0);
289 case PROP_TILE_HEIGHT:
290 self->params.cp_tdy = g_value_get_int (value);
291 self->params.tile_size_on = (self->params.cp_tdx != 0
292 && self->params.cp_tdy != 0);
294 case PROP_NUM_STRIPES:
295 self->num_stripes = g_value_get_int (value);
298 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
304 gst_openjpeg_enc_get_property (GObject * object, guint prop_id, GValue * value,
307 GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (object);
310 case PROP_NUM_LAYERS:
311 g_value_set_int (value, self->params.tcp_numlayers);
313 case PROP_NUM_RESOLUTIONS:
314 g_value_set_int (value, self->params.numresolution);
316 case PROP_PROGRESSION_ORDER:
317 g_value_set_enum (value, self->params.prog_order);
319 case PROP_TILE_OFFSET_X:
320 g_value_set_int (value, self->params.cp_tx0);
322 case PROP_TILE_OFFSET_Y:
323 g_value_set_int (value, self->params.cp_ty0);
325 case PROP_TILE_WIDTH:
326 g_value_set_int (value, self->params.cp_tdx);
328 case PROP_TILE_HEIGHT:
329 g_value_set_int (value, self->params.cp_tdy);
331 case PROP_NUM_STRIPES:
332 g_value_set_int (value, self->num_stripes);
335 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
341 gst_openjpeg_enc_start (GstVideoEncoder * encoder)
343 GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (encoder);
345 GST_DEBUG_OBJECT (self, "Starting");
351 gst_openjpeg_enc_stop (GstVideoEncoder * video_encoder)
353 GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (video_encoder);
355 GST_DEBUG_OBJECT (self, "Stopping");
357 if (self->output_state) {
358 gst_video_codec_state_unref (self->output_state);
359 self->output_state = NULL;
362 if (self->input_state) {
363 gst_video_codec_state_unref (self->input_state);
364 self->input_state = NULL;
367 GST_DEBUG_OBJECT (self, "Stopped");
373 get_stripe_height (GstOpenJPEGEnc * self, guint slice_num, guint frame_height)
375 guint nominal_stripe_height = frame_height / self->num_stripes;
378 1) ? nominal_stripe_height : frame_height -
379 (slice_num * nominal_stripe_height);
383 fill_image_packed16_4 (opj_image_t * image, GstVideoFrame * frame)
386 const guint16 *data_in, *tmp;
390 w = GST_VIDEO_FRAME_WIDTH (frame);
391 h = image->y1 - image->y0;
392 sstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) / 2;
394 (guint16 *) GST_VIDEO_FRAME_PLANE_DATA (frame, 0) + image->y0 * sstride;
396 data_out[0] = image->comps[0].data;
397 data_out[1] = image->comps[1].data;
398 data_out[2] = image->comps[2].data;
399 data_out[3] = image->comps[3].data;
401 for (y = 0; y < h; y++) {
404 for (x = 0; x < w; x++) {
405 *data_out[3] = tmp[0];
406 *data_out[0] = tmp[1];
407 *data_out[1] = tmp[2];
408 *data_out[2] = tmp[3];
421 fill_image_packed8_4 (opj_image_t * image, GstVideoFrame * frame)
424 const guint8 *data_in, *tmp;
428 w = GST_VIDEO_FRAME_WIDTH (frame);
429 h = image->y1 - image->y0;
430 sstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
432 (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (frame, 0) + image->y0 * sstride;
434 data_out[0] = image->comps[0].data;
435 data_out[1] = image->comps[1].data;
436 data_out[2] = image->comps[2].data;
437 data_out[3] = image->comps[3].data;
439 for (y = 0; y < h; y++) {
442 for (x = 0; x < w; x++) {
443 *data_out[3] = tmp[0];
444 *data_out[0] = tmp[1];
445 *data_out[1] = tmp[2];
446 *data_out[2] = tmp[3];
459 fill_image_packed8_3 (opj_image_t * image, GstVideoFrame * frame)
462 const guint8 *data_in, *tmp;
466 w = GST_VIDEO_FRAME_WIDTH (frame);
467 h = image->y1 - image->y0;
468 sstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
470 (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (frame, 0) + image->y0 * sstride;
472 data_out[0] = image->comps[0].data;
473 data_out[1] = image->comps[1].data;
474 data_out[2] = image->comps[2].data;
476 for (y = 0; y < h; y++) {
479 for (x = 0; x < w; x++) {
480 *data_out[0] = tmp[1];
481 *data_out[1] = tmp[2];
482 *data_out[2] = tmp[3];
494 fill_image_planar16_3 (opj_image_t * image, GstVideoFrame * frame)
497 const guint16 *data_in, *tmp;
501 for (c = 0; c < 3; c++) {
502 opj_image_comp_t *comp = image->comps + c;
504 w = GST_VIDEO_FRAME_COMP_WIDTH (frame, c);
506 sstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, c) / 2;
508 (guint16 *) GST_VIDEO_FRAME_COMP_DATA (frame,
509 c) + (image->y0 / comp->dy) * sstride;
510 data_out = comp->data;
512 for (y = 0; y < h; y++) {
514 for (x = 0; x < w; x++) {
525 fill_image_planar8_3 (opj_image_t * image, GstVideoFrame * frame)
528 const guint8 *data_in, *tmp;
532 for (c = 0; c < 3; c++) {
533 opj_image_comp_t *comp = image->comps + c;
535 w = GST_VIDEO_FRAME_COMP_WIDTH (frame, c);
537 sstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, c);
539 (guint8 *) GST_VIDEO_FRAME_COMP_DATA (frame,
540 c) + (image->y0 / comp->dy) * sstride;
541 data_out = comp->data;
543 for (y = 0; y < h; y++) {
545 for (x = 0; x < w; x++) {
556 fill_image_planar8_1 (opj_image_t * image, GstVideoFrame * frame)
559 const guint8 *data_in, *tmp;
562 opj_image_comp_t *comp = image->comps;
564 w = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0);
566 sstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
568 (guint8 *) GST_VIDEO_FRAME_COMP_DATA (frame,
569 0) + (image->y0 / comp->dy) * sstride;
570 data_out = image->comps[0].data;
572 for (y = 0; y < h; y++) {
574 for (x = 0; x < w; x++) {
584 fill_image_planar16_1 (opj_image_t * image, GstVideoFrame * frame)
587 const guint16 *data_in, *tmp;
590 opj_image_comp_t *comp = image->comps;
592 w = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0);
594 sstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) / 2;
596 (guint16 *) GST_VIDEO_FRAME_COMP_DATA (frame,
597 0) + (image->y0 / comp->dy) * sstride;
598 data_out = comp->data;
600 for (y = 0; y < h; y++) {
602 for (x = 0; x < w; x++) {
612 gst_openjpeg_enc_set_format (GstVideoEncoder * encoder,
613 GstVideoCodecState * state)
615 GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (encoder);
616 GstCaps *allowed_caps, *caps;
618 const gchar *colorspace = NULL;
619 GstJPEG2000Sampling sampling = GST_JPEG2000_SAMPLING_NONE;
621 gboolean stripe_mode =
622 self->num_stripes != GST_OPENJPEG_ENC_DEFAULT_NUM_STRIPES;
624 GST_DEBUG_OBJECT (self, "Setting format: %" GST_PTR_FORMAT, state->caps);
626 if (self->input_state)
627 gst_video_codec_state_unref (self->input_state);
628 self->input_state = gst_video_codec_state_ref (state);
630 allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
631 allowed_caps = gst_caps_truncate (allowed_caps);
632 s = gst_caps_get_structure (allowed_caps, 0);
633 if (gst_structure_has_name (s, "image/jp2")) {
634 self->codec_format = OPJ_CODEC_JP2;
635 self->is_jp2c = FALSE;
636 } else if (gst_structure_has_name (s, "image/x-j2c")) {
637 self->codec_format = OPJ_CODEC_J2K;
638 self->is_jp2c = TRUE;
639 } else if (gst_structure_has_name (s, "image/x-jpc")) {
640 self->codec_format = OPJ_CODEC_J2K;
641 self->is_jp2c = FALSE;
643 g_return_val_if_reached (FALSE);
646 switch (state->info.finfo->format) {
647 case GST_VIDEO_FORMAT_ARGB64:
648 self->fill_image = fill_image_packed16_4;
651 case GST_VIDEO_FORMAT_ARGB:
652 case GST_VIDEO_FORMAT_AYUV:
653 self->fill_image = fill_image_packed8_4;
656 case GST_VIDEO_FORMAT_xRGB:
657 self->fill_image = fill_image_packed8_3;
660 case GST_VIDEO_FORMAT_AYUV64:
661 self->fill_image = fill_image_packed16_4;
664 case GST_VIDEO_FORMAT_Y444_10LE:
665 case GST_VIDEO_FORMAT_Y444_10BE:
666 case GST_VIDEO_FORMAT_I422_10LE:
667 case GST_VIDEO_FORMAT_I422_10BE:
668 case GST_VIDEO_FORMAT_I420_10LE:
669 case GST_VIDEO_FORMAT_I420_10BE:
670 self->fill_image = fill_image_planar16_3;
673 case GST_VIDEO_FORMAT_Y444:
674 case GST_VIDEO_FORMAT_Y42B:
675 case GST_VIDEO_FORMAT_I420:
676 case GST_VIDEO_FORMAT_Y41B:
677 case GST_VIDEO_FORMAT_YUV9:
678 self->fill_image = fill_image_planar8_3;
681 case GST_VIDEO_FORMAT_GRAY8:
682 self->fill_image = fill_image_planar8_1;
685 case GST_VIDEO_FORMAT_GRAY16_LE:
686 case GST_VIDEO_FORMAT_GRAY16_BE:
687 self->fill_image = fill_image_planar16_1;
691 g_assert_not_reached ();
696 /* note: encoder re-orders channels so that alpha channel is encoded as the last channel */
697 switch (state->info.finfo->format) {
698 case GST_VIDEO_FORMAT_ARGB64:
699 case GST_VIDEO_FORMAT_ARGB:
700 sampling = GST_JPEG2000_SAMPLING_RGBA;
702 case GST_VIDEO_FORMAT_AYUV64:
703 case GST_VIDEO_FORMAT_AYUV:
704 sampling = GST_JPEG2000_SAMPLING_YBRA4444_EXT;
706 case GST_VIDEO_FORMAT_xRGB:
707 sampling = GST_JPEG2000_SAMPLING_RGB;
709 case GST_VIDEO_FORMAT_Y444_10LE:
710 case GST_VIDEO_FORMAT_Y444_10BE:
711 case GST_VIDEO_FORMAT_Y444:
712 sampling = GST_JPEG2000_SAMPLING_YBR444;
715 case GST_VIDEO_FORMAT_I422_10LE:
716 case GST_VIDEO_FORMAT_I422_10BE:
717 case GST_VIDEO_FORMAT_Y42B:
718 sampling = GST_JPEG2000_SAMPLING_YBR422;
720 case GST_VIDEO_FORMAT_YUV9:
721 sampling = GST_JPEG2000_SAMPLING_YBR410;
723 case GST_VIDEO_FORMAT_I420_10LE:
724 case GST_VIDEO_FORMAT_I420_10BE:
725 case GST_VIDEO_FORMAT_I420:
726 sampling = GST_JPEG2000_SAMPLING_YBR420;
728 case GST_VIDEO_FORMAT_GRAY8:
729 case GST_VIDEO_FORMAT_GRAY16_LE:
730 case GST_VIDEO_FORMAT_GRAY16_BE:
731 sampling = GST_JPEG2000_SAMPLING_GRAYSCALE;
737 if ((state->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_YUV)) {
739 } else if ((state->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_RGB)) {
741 } else if ((state->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_GRAY)) {
744 g_return_val_if_reached (FALSE);
746 if (sampling != GST_JPEG2000_SAMPLING_NONE) {
747 caps = gst_caps_new_simple (gst_structure_get_name (s),
748 "colorspace", G_TYPE_STRING, colorspace,
749 "sampling", G_TYPE_STRING, gst_jpeg2000_sampling_to_string (sampling),
750 "num-components", G_TYPE_INT, ncomps,
751 "alignment", G_TYPE_STRING,
752 stripe_mode ? "stripe" : "frame",
753 "num-stripes", G_TYPE_INT, self->num_stripes, NULL);
755 caps = gst_caps_new_simple (gst_structure_get_name (s),
756 "colorspace", G_TYPE_STRING, colorspace,
757 "num-components", G_TYPE_INT, ncomps,
758 "alignment", G_TYPE_STRING,
759 stripe_mode ? "stripe" : "frame",
760 "num-stripes", G_TYPE_INT, self->num_stripes, NULL);
762 gst_caps_unref (allowed_caps);
764 if (self->output_state)
765 gst_video_codec_state_unref (self->output_state);
767 gst_video_encoder_set_output_state (encoder, caps, state);
769 gst_video_encoder_negotiate (GST_VIDEO_ENCODER (encoder));
775 gst_openjpeg_enc_fill_image (GstOpenJPEGEnc * self, GstVideoFrame * frame,
778 gint i, ncomps, temp, min_height = INT_MAX;
779 opj_image_cmptparm_t *comps;
780 OPJ_COLOR_SPACE colorspace;
783 ncomps = GST_VIDEO_FRAME_N_COMPONENTS (frame);
784 comps = g_new0 (opj_image_cmptparm_t, ncomps);
786 for (i = 0; i < ncomps; i++) {
787 comps[i].prec = GST_VIDEO_FRAME_COMP_DEPTH (frame, i);
788 comps[i].bpp = GST_VIDEO_FRAME_COMP_DEPTH (frame, i);
790 comps[i].w = GST_VIDEO_FRAME_COMP_WIDTH (frame, i);
792 (guint) ((float) GST_VIDEO_FRAME_WIDTH (frame) /
793 GST_VIDEO_FRAME_COMP_WIDTH (frame, i) + 0.5f);
795 (guint) ((float) GST_VIDEO_FRAME_HEIGHT (frame) /
796 GST_VIDEO_FRAME_COMP_HEIGHT (frame, i) + 0.5f);
798 (GST_VIDEO_FRAME_COMP_HEIGHT (frame,
799 i) / self->num_stripes) * comps[i].dy;
800 if (temp < min_height)
804 for (i = 0; i < ncomps; i++) {
805 gint nominal_height = min_height / comps[i].dy;
807 comps[i].h = (slice_num < self->num_stripes - 1) ?
809 : GST_VIDEO_FRAME_COMP_HEIGHT (frame,
810 i) - (self->num_stripes - 1) * nominal_height;
814 if ((frame->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_YUV))
815 colorspace = OPJ_CLRSPC_SYCC;
816 else if ((frame->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_RGB))
817 colorspace = OPJ_CLRSPC_SRGB;
818 else if ((frame->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_GRAY))
819 colorspace = OPJ_CLRSPC_GRAY;
821 g_return_val_if_reached (NULL);
823 image = opj_image_create (ncomps, comps, colorspace);
825 GST_WARNING_OBJECT (self,
826 "Unable to create a JPEG image. first component height=%d",
827 ncomps ? comps[0].h : 0);
834 image->x1 = GST_VIDEO_FRAME_WIDTH (frame);
835 image->y0 = slice_num * min_height;
838 self->num_stripes - 1) ? image->y0 +
839 min_height : GST_VIDEO_FRAME_HEIGHT (frame);
840 self->fill_image (image, frame);
846 gst_openjpeg_enc_opj_error (const char *msg, void *userdata)
848 GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (userdata);
849 gchar *trimmed = g_strchomp (g_strdup (msg));
850 GST_TRACE_OBJECT (self, "openjpeg error: %s", trimmed);
855 gst_openjpeg_enc_opj_warning (const char *msg, void *userdata)
857 GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (userdata);
858 gchar *trimmed = g_strchomp (g_strdup (msg));
859 GST_TRACE_OBJECT (self, "openjpeg warning: %s", trimmed);
864 gst_openjpeg_enc_opj_info (const char *msg, void *userdata)
866 GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (userdata);
867 gchar *trimmed = g_strchomp (g_strdup (msg));
868 GST_TRACE_OBJECT (self, "openjpeg info: %s", trimmed);
881 read_fn (void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
883 g_return_val_if_reached (-1);
887 write_fn (void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
889 MemStream *mstream = p_user_data;
891 if (mstream->offset + p_nb_bytes > mstream->allocsize) {
892 while (mstream->offset + p_nb_bytes > mstream->allocsize)
893 mstream->allocsize *= 2;
894 mstream->data = g_realloc (mstream->data, mstream->allocsize);
897 memcpy (mstream->data + mstream->offset, p_buffer, p_nb_bytes);
899 if (mstream->offset + p_nb_bytes > mstream->size)
900 mstream->size = mstream->offset + p_nb_bytes;
901 mstream->offset += p_nb_bytes;
907 skip_fn (OPJ_OFF_T p_nb_bytes, void *p_user_data)
909 MemStream *mstream = p_user_data;
911 if (mstream->offset + p_nb_bytes > mstream->allocsize) {
912 while (mstream->offset + p_nb_bytes > mstream->allocsize)
913 mstream->allocsize *= 2;
914 mstream->data = g_realloc (mstream->data, mstream->allocsize);
917 if (mstream->offset + p_nb_bytes > mstream->size)
918 mstream->size = mstream->offset + p_nb_bytes;
920 mstream->offset += p_nb_bytes;
926 seek_fn (OPJ_OFF_T p_nb_bytes, void *p_user_data)
928 MemStream *mstream = p_user_data;
930 if (p_nb_bytes > mstream->size)
933 mstream->offset = p_nb_bytes;
939 gst_openjpeg_enc_handle_frame (GstVideoEncoder * encoder,
940 GstVideoCodecFrame * frame)
942 GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (encoder);
943 GstFlowReturn ret = GST_FLOW_OK;
945 opj_stream_t *stream;
948 GstVideoFrame vframe;
950 GstCaps *current_caps;
952 gboolean stripe_mode =
953 self->num_stripes != GST_OPENJPEG_ENC_DEFAULT_NUM_STRIPES;
955 GST_DEBUG_OBJECT (self, "Handling frame");
957 current_caps = gst_pad_get_current_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
958 s = gst_caps_get_structure (current_caps, 0);
961 const gchar *str = gst_structure_get_string (s, "alignment");
964 if (g_strcmp0 (str, "stripe") != 0) {
965 GST_ERROR_OBJECT (self,
966 "Number of stripes set to %d, but alignment=stripe not supported downstream",
968 gst_video_codec_frame_unref (frame);
969 ret = GST_FLOW_NOT_NEGOTIATED;
973 /* due to limitations in openjpeg library,
974 * number of wavelet resolutions must not exceed floor(log(stripe height)) + 1 */
975 if (!gst_video_frame_map (&vframe, &self->input_state->info,
976 frame->input_buffer, GST_MAP_READ)) {
977 gst_video_codec_frame_unref (frame);
978 GST_ELEMENT_ERROR (self, CORE, FAILED,
979 ("Failed to map input buffer"), (NULL));
980 return GST_FLOW_ERROR;
982 /* find stripe with least height */
984 get_stripe_height (self, self->num_stripes - 1,
985 GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 0));
986 min_res = MIN (min_res, get_stripe_height (self, 0,
987 GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 0)));
988 /* take log to find correct number of wavelet resolutions */
989 min_res = min_res > 1 ? (gint) log (min_res) + 1 : 1;
990 self->params.numresolution = MIN (min_res + 1, self->params.numresolution);
991 gst_video_frame_unmap (&vframe);
995 for (i = 0; i < self->num_stripes; ++i) {
996 enc = opj_create_compress (self->codec_format);
998 goto initialization_error;
1000 if (G_UNLIKELY (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >=
1002 opj_set_info_handler (enc, gst_openjpeg_enc_opj_info, self);
1003 opj_set_warning_handler (enc, gst_openjpeg_enc_opj_warning, self);
1004 opj_set_error_handler (enc, gst_openjpeg_enc_opj_error, self);
1006 opj_set_info_handler (enc, NULL, NULL);
1007 opj_set_warning_handler (enc, NULL, NULL);
1008 opj_set_error_handler (enc, NULL, NULL);
1011 if (!gst_video_frame_map (&vframe, &self->input_state->info,
1012 frame->input_buffer, GST_MAP_READ))
1013 goto map_read_error;
1015 image = gst_openjpeg_enc_fill_image (self, &vframe, i);
1017 goto fill_image_error;
1018 gst_video_frame_unmap (&vframe);
1020 if (vframe.info.finfo->flags & GST_VIDEO_FORMAT_FLAG_RGB) {
1021 self->params.tcp_mct = 1;
1023 opj_setup_encoder (enc, &self->params, image);
1024 stream = opj_stream_create (4096, OPJ_FALSE);
1028 mstream.allocsize = 4096;
1029 mstream.data = g_malloc (mstream.allocsize);
1033 opj_stream_set_read_function (stream, read_fn);
1034 opj_stream_set_write_function (stream, write_fn);
1035 opj_stream_set_skip_function (stream, skip_fn);
1036 opj_stream_set_seek_function (stream, seek_fn);
1037 opj_stream_set_user_data (stream, &mstream, NULL);
1038 opj_stream_set_user_data_length (stream, mstream.size);
1040 if (!opj_start_compress (enc, image, stream))
1043 if (!opj_encode (enc, stream))
1046 if (!opj_end_compress (enc, stream))
1049 opj_image_destroy (image);
1050 opj_stream_destroy (stream);
1051 opj_destroy_codec (enc);
1053 frame->output_buffer = gst_buffer_new ();
1055 if (self->is_jp2c) {
1059 mem = gst_allocator_alloc (NULL, 8, NULL);
1060 gst_memory_map (mem, &map, GST_MAP_WRITE);
1061 GST_WRITE_UINT32_BE (map.data, mstream.size + 8);
1062 GST_WRITE_UINT32_BE (map.data + 4, GST_MAKE_FOURCC ('j', 'p', '2', 'c'));
1063 gst_memory_unmap (mem, &map);
1064 gst_buffer_append_memory (frame->output_buffer, mem);
1067 gst_buffer_append_memory (frame->output_buffer,
1068 gst_memory_new_wrapped (0, mstream.data, mstream.allocsize, 0,
1069 mstream.size, mstream.data, (GDestroyNotify) g_free));
1071 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
1075 1) ? gst_video_encoder_finish_frame (encoder,
1076 frame) : gst_video_encoder_finish_subframe (encoder, frame);
1082 gst_caps_unref (current_caps);
1085 initialization_error:
1087 gst_video_codec_frame_unref (frame);
1088 GST_ELEMENT_ERROR (self, LIBRARY, INIT,
1089 ("Failed to initialize OpenJPEG encoder"), (NULL));
1090 return GST_FLOW_ERROR;
1094 opj_destroy_codec (enc);
1095 gst_video_codec_frame_unref (frame);
1097 GST_ELEMENT_ERROR (self, CORE, FAILED,
1098 ("Failed to map input buffer"), (NULL));
1099 return GST_FLOW_ERROR;
1103 opj_destroy_codec (enc);
1104 gst_video_frame_unmap (&vframe);
1105 gst_video_codec_frame_unref (frame);
1107 GST_ELEMENT_ERROR (self, LIBRARY, INIT,
1108 ("Failed to fill OpenJPEG image"), (NULL));
1109 return GST_FLOW_ERROR;
1113 opj_image_destroy (image);
1114 opj_destroy_codec (enc);
1115 gst_video_codec_frame_unref (frame);
1117 GST_ELEMENT_ERROR (self, LIBRARY, INIT,
1118 ("Failed to open OpenJPEG data"), (NULL));
1119 return GST_FLOW_ERROR;
1123 opj_stream_destroy (stream);
1124 g_free (mstream.data);
1125 opj_image_destroy (image);
1126 opj_destroy_codec (enc);
1127 gst_video_codec_frame_unref (frame);
1129 GST_ELEMENT_ERROR (self, STREAM, ENCODE,
1130 ("Failed to encode OpenJPEG stream"), (NULL));
1131 return GST_FLOW_ERROR;
1136 gst_openjpeg_enc_propose_allocation (GstVideoEncoder * encoder,
1139 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
1141 return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,