1 /**************************************************************************
3 * Copyright 2013 Advanced Micro Devices, Inc.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
28 #include <tizplatform.h>
29 #include <tizkernel.h>
32 #include "entrypoint.h"
35 #include "vid_omx_common.h"
36 #include "vid_dec_common.h"
37 #include "vid_dec_h264_common.h"
39 #include "vl/vl_video_buffer.h"
40 #include "vl/vl_compositor.h"
41 #include "util/u_hash_table.h"
42 #include "util/u_surface.h"
44 #include "dri_screen.h"
47 unsigned dec_frame_delta
;
49 #define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x)))
51 static unsigned handle_hash(void *key
)
53 return PTR_TO_UINT(key
);
56 static int handle_compare(void *key1
, void *key2
)
58 return PTR_TO_UINT(key1
) != PTR_TO_UINT(key2
);
61 static enum pipe_error
hash_table_clear_item_callback(void *key
, void *value
, void *data
)
63 struct pipe_video_buffer
*video_buffer
= (struct pipe_video_buffer
*)value
;
64 video_buffer
->destroy(video_buffer
);
68 static void release_input_headers(vid_dec_PrivateType
* priv
) {
70 for (i
= 0; i
< priv
->num_in_buffers
; i
++) {
71 assert(!priv
->in_port_disabled_
);
72 if (priv
->in_buffers
[i
]->pInputPortPrivate
) {
73 vid_dec_FreeInputPortPrivate(priv
->in_buffers
[i
]);
75 (void) tiz_krn_release_buffer (tiz_get_krn (handleOf (priv
)),
76 OMX_VID_DEC_AVC_INPUT_PORT_INDEX
,
78 priv
->in_buffers
[i
] = NULL
;
80 priv
->p_inhdr_
= NULL
;
81 priv
->num_in_buffers
= 0;
84 static void release_output_header(vid_dec_PrivateType
* priv
) {
85 if (priv
->p_outhdr_
) {
86 assert(!priv
->out_port_disabled_
);
87 (void) tiz_krn_release_buffer (tiz_get_krn (handleOf (priv
)),
88 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
,
90 priv
->p_outhdr_
= NULL
;
94 static OMX_ERRORTYPE
h264d_release_all_headers(vid_dec_PrivateType
* priv
)
97 release_input_headers(priv
);
98 release_output_header(priv
);
100 return OMX_ErrorNone
;
103 static void h264d_buffer_emptied(vid_dec_PrivateType
* priv
, OMX_BUFFERHEADERTYPE
* p_hdr
)
106 assert(priv
->in_buffers
[0] == p_hdr
);
108 if (!priv
->out_port_disabled_
) {
109 assert (p_hdr
->nFilledLen
== 0);
112 if ((p_hdr
->nFlags
& OMX_BUFFERFLAG_EOS
) != 0) {
116 (void) tiz_krn_release_buffer (tiz_get_krn (handleOf (priv
)), 0, p_hdr
);
117 priv
->p_inhdr_
= NULL
;
118 priv
->in_buffers
[0] = NULL
;
122 static void h264d_buffer_filled(vid_dec_PrivateType
* priv
, OMX_BUFFERHEADERTYPE
* p_hdr
)
126 assert(priv
->p_outhdr_
== p_hdr
);
128 if (!priv
->in_port_disabled_
) {
132 /* EOS has been received and all the input data has been consumed
133 * already, so its time to propagate the EOS flag */
134 priv
->p_outhdr_
->nFlags
|= OMX_BUFFERFLAG_EOS
;
138 (void) tiz_krn_release_buffer(tiz_get_krn (handleOf (priv
)),
139 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
,
141 priv
->p_outhdr_
= NULL
;
145 static bool h264d_shift_buffers_left(vid_dec_PrivateType
* priv
) {
146 if (--priv
->num_in_buffers
) {
147 priv
->in_buffers
[0] = priv
->in_buffers
[1];
148 priv
->sizes
[0] = priv
->sizes
[1] - dec_frame_delta
;
149 priv
->inputs
[0] = priv
->inputs
[1] + dec_frame_delta
;
150 priv
->timestamps
[0] = priv
->timestamps
[1];
157 static OMX_BUFFERHEADERTYPE
* get_input_buffer(vid_dec_PrivateType
* priv
) {
160 if (priv
->in_port_disabled_
) {
164 if (priv
->num_in_buffers
> 1) {
165 /* The input buffer wasn't cleared last time. */
166 h264d_buffer_emptied(priv
, priv
->in_buffers
[0]);
167 if (priv
->in_buffers
[0]) {
168 /* Failed to release buffer */
171 h264d_shift_buffers_left(priv
);
174 /* Decode_frame expects new buffers each time */
175 assert(priv
->p_inhdr_
|| priv
->first_buf_in_frame
);
176 tiz_krn_claim_buffer(tiz_get_krn (handleOf (priv
)),
177 OMX_VID_DEC_AVC_INPUT_PORT_INDEX
, 0,
179 return priv
->p_inhdr_
;
182 static struct pipe_resource
* st_omx_pipe_texture_from_eglimage(EGLDisplay egldisplay
,
185 _EGLDisplay
*disp
= egldisplay
;
186 struct dri2_egl_display
*dri2_egl_dpy
= disp
->DriverData
;
187 __DRIscreen
*_dri_screen
= dri2_egl_dpy
->dri_screen
;
188 struct dri_screen
*st_dri_screen
= dri_screen(_dri_screen
);
189 __DRIimage
*_dri_image
= st_dri_screen
->lookup_egl_image(st_dri_screen
, eglimage
);
191 return _dri_image
->texture
;
194 static void get_eglimage(vid_dec_PrivateType
* priv
) {
195 OMX_PTR p_eglimage
= NULL
;
196 OMX_NATIVE_WINDOWTYPE
* p_egldisplay
= NULL
;
197 const tiz_port_t
* p_port
= NULL
;
198 struct pipe_video_buffer templat
= {};
199 struct pipe_video_buffer
*video_buffer
= NULL
;
200 struct pipe_resource
* p_res
= NULL
;
201 struct pipe_resource
*resources
[VL_NUM_COMPONENTS
];
204 tiz_krn_claim_eglimage(tiz_get_krn (handleOf (priv
)),
205 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
,
206 priv
->p_outhdr_
, &p_eglimage
)) {
207 priv
->use_eglimage
= true;
208 p_port
= tiz_krn_get_port(tiz_get_krn (handleOf (priv
)),
209 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
);
210 p_egldisplay
= p_port
->portdef_
.format
.video
.pNativeWindow
;
212 if (!util_hash_table_get(priv
->video_buffer_map
, priv
->p_outhdr_
)) {
213 p_res
= st_omx_pipe_texture_from_eglimage(p_egldisplay
, p_eglimage
);
217 memset(&templat
, 0, sizeof(templat
));
218 templat
.buffer_format
= p_res
->format
;
219 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_NONE
;
220 templat
.width
= p_res
->width0
;
221 templat
.height
= p_res
->height0
;
222 templat
.interlaced
= 0;
224 memset(resources
, 0, sizeof(resources
));
225 pipe_resource_reference(&resources
[0], p_res
);
227 video_buffer
= vl_video_buffer_create_ex2(priv
->pipe
, &templat
, resources
);
229 assert(video_buffer
);
230 assert(video_buffer
->buffer_format
== p_res
->format
);
232 util_hash_table_set(priv
->video_buffer_map
, priv
->p_outhdr_
, video_buffer
);
235 (void) tiz_krn_release_buffer(tiz_get_krn (handleOf (priv
)),
236 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
,
238 priv
->p_outhdr_
= NULL
;
242 static OMX_BUFFERHEADERTYPE
* get_output_buffer(vid_dec_PrivateType
* priv
) {
245 if (priv
->out_port_disabled_
) {
249 if (!priv
->p_outhdr_
) {
251 == tiz_krn_claim_buffer(tiz_get_krn (handleOf (priv
)),
252 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
, 0,
254 if (priv
->p_outhdr_
) {
255 /* Check pBuffer nullity to know if an eglimage has been registered. */
256 if (!priv
->p_outhdr_
->pBuffer
) {
262 return priv
->p_outhdr_
;
265 static void reset_stream_parameters(vid_dec_PrivateType
* apriv
)
268 TIZ_INIT_OMX_PORT_STRUCT(apriv
->out_port_def_
,
269 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
);
271 tiz_api_GetParameter (tiz_get_krn (handleOf (apriv
)), handleOf (apriv
),
272 OMX_IndexParamPortDefinition
, &(apriv
->out_port_def_
));
275 apriv
->num_in_buffers
= 0;
276 apriv
->first_buf_in_frame
= true;
278 apriv
->frame_finished
= false;
279 apriv
->frame_started
= false;
280 apriv
->picture
.h264
.field_order_cnt
[0] = apriv
->picture
.h264
.field_order_cnt
[1] = INT_MAX
;
284 /* Replacement for bellagio's omx_base_filter_BufferMgmtFunction */
285 static void h264d_manage_buffers(vid_dec_PrivateType
* priv
) {
286 bool next_is_eos
= priv
->num_in_buffers
== 2 ? !!(priv
->in_buffers
[1]->nFlags
& OMX_BUFFERFLAG_EOS
) : false;
287 vid_dec_FrameDecoded_common(priv
, priv
->in_buffers
[0], priv
->p_outhdr_
);
289 priv
->p_outhdr_
->nTimeStamp
= priv
->in_buffers
[0]->nTimeStamp
;
291 /* Realase output buffer if filled or eos
292 Keep if two input buffers are being decoded */
293 if ((!next_is_eos
) && ((priv
->p_outhdr_
->nFilledLen
> 0) || priv
->use_eglimage
|| priv
->eos_
)) {
294 h264d_buffer_filled(priv
, priv
->p_outhdr_
);
297 /* Release input buffer if possible */
298 if (priv
->in_buffers
[0]->nFilledLen
== 0) {
299 h264d_buffer_emptied(priv
, priv
->in_buffers
[0]);
303 static OMX_ERRORTYPE
decode_frame(vid_dec_PrivateType
*priv
,
304 OMX_BUFFERHEADERTYPE
*in_buf
)
306 unsigned i
= priv
->num_in_buffers
++;
307 priv
->in_buffers
[i
] = in_buf
;
308 priv
->sizes
[i
] = in_buf
->nFilledLen
;
309 priv
->inputs
[i
] = in_buf
->pBuffer
;
310 priv
->timestamps
[i
] = in_buf
->nTimeStamp
;
312 while (priv
->num_in_buffers
> (!!(in_buf
->nFlags
& OMX_BUFFERFLAG_EOS
) ? 0 : 1)) {
313 priv
->eos_
= !!(priv
->in_buffers
[0]->nFlags
& OMX_BUFFERFLAG_EOS
);
314 unsigned min_bits_left
= priv
->eos_
? 32 : MAX2(in_buf
->nFilledLen
* 8, 32);
317 vl_vlc_init(&vlc
, priv
->num_in_buffers
, priv
->inputs
, priv
->sizes
);
320 priv
->bytes_left
= vl_vlc_bits_left(&vlc
) / 8;
322 while (vl_vlc_bits_left (&vlc
) > min_bits_left
) {
323 vid_dec_h264_Decode(priv
, &vlc
, min_bits_left
);
324 vl_vlc_fillbits(&vlc
);
328 unsigned bytes
= priv
->bytes_left
- vl_vlc_bits_left(&vlc
) / 8;
330 priv
->codec
->decode_bitstream(priv
->codec
, priv
->target
, &priv
->picture
.base
,
331 1, &priv
->slice
, &bytes
);
333 if (priv
->num_in_buffers
)
334 priv
->slice
= priv
->inputs
[1];
339 if (priv
->eos_
&& priv
->frame_started
)
340 vid_dec_h264_EndFrame(priv
);
342 if (priv
->frame_finished
) {
343 priv
->frame_finished
= false;
344 h264d_manage_buffers(priv
);
345 } else if (priv
->eos_
) {
346 vid_dec_FreeInputPortPrivate(priv
->in_buffers
[0]);
347 h264d_manage_buffers(priv
);
349 priv
->in_buffers
[0]->nFilledLen
= 0;
350 h264d_buffer_emptied(priv
, priv
->in_buffers
[0]);
353 if (priv
->out_port_disabled_
) {
354 /* In case out port is disabled, h264d_buffer_emptied will fail to release input port.
355 * We need to wait before shifting the buffers in that case and check in
356 * get_input_buffer when out port is enabled to release and shift the buffers.
357 * Infinite looping occurs if buffer is not released */
358 if (priv
->num_in_buffers
== 2) {
359 /* Set the delta value for use in get_input_buffer before exiting */
360 dec_frame_delta
= MIN2((min_bits_left
- vl_vlc_bits_left(&vlc
)) / 8, priv
->sizes
[1]);
365 h264d_shift_buffers_left(priv
);
368 return OMX_ErrorNone
;
375 static void * h264d_prc_ctor(void *ap_obj
, va_list * app
)
377 vid_dec_PrivateType
*priv
= super_ctor(typeOf (ap_obj
, "h264dprc"), ap_obj
, app
);
381 priv
->first_buf_in_frame
= true;
383 priv
->in_port_disabled_
= false;
384 priv
->out_port_disabled_
= false;
385 priv
->picture
.base
.profile
= PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
;
386 priv
->profile
= PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
;
387 reset_stream_parameters(priv
);
392 static void * h264d_prc_dtor(void *ap_obj
)
394 return super_dtor(typeOf(ap_obj
, "h264dprc"), ap_obj
);
397 static OMX_ERRORTYPE
h264d_prc_allocate_resources(void *ap_obj
, OMX_U32 a_pid
)
399 vid_dec_PrivateType
*priv
= ap_obj
;
400 struct pipe_screen
*screen
;
405 priv
->screen
= omx_get_screen();
407 return OMX_ErrorInsufficientResources
;
409 screen
= priv
->screen
->pscreen
;
410 priv
->pipe
= pipe_create_multimedia_context(screen
);
412 return OMX_ErrorInsufficientResources
;
414 if (!vl_compositor_init(&priv
->compositor
, priv
->pipe
)) {
415 priv
->pipe
->destroy(priv
->pipe
);
417 return OMX_ErrorInsufficientResources
;
420 if (!vl_compositor_init_state(&priv
->cstate
, priv
->pipe
)) {
421 vl_compositor_cleanup(&priv
->compositor
);
422 priv
->pipe
->destroy(priv
->pipe
);
424 return OMX_ErrorInsufficientResources
;
427 vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601
, NULL
, true, &csc
);
428 if (!vl_compositor_set_csc_matrix(&priv
->cstate
, (const vl_csc_matrix
*)&csc
, 1.0f
, 0.0f
)) {
429 vl_compositor_cleanup(&priv
->compositor
);
430 priv
->pipe
->destroy(priv
->pipe
);
432 return OMX_ErrorInsufficientResources
;
435 LIST_INITHEAD(&priv
->codec_data
.h264
.dpb_list
);
437 priv
->video_buffer_map
= util_hash_table_create(handle_hash
, handle_compare
);
439 return OMX_ErrorNone
;
442 static OMX_ERRORTYPE
h264d_prc_deallocate_resources(void *ap_obj
)
444 vid_dec_PrivateType
*priv
= ap_obj
;
447 /* Clear hash table */
448 util_hash_table_foreach(priv
->video_buffer_map
,
449 &hash_table_clear_item_callback
,
451 util_hash_table_destroy(priv
->video_buffer_map
);
454 vl_compositor_cleanup_state(&priv
->cstate
);
455 vl_compositor_cleanup(&priv
->compositor
);
456 priv
->pipe
->destroy(priv
->pipe
);
462 return OMX_ErrorNone
;
465 static OMX_ERRORTYPE
h264d_prc_prepare_to_transfer(void *ap_obj
, OMX_U32 a_pid
)
467 vid_dec_PrivateType
*priv
= ap_obj
;
470 TIZ_INIT_OMX_PORT_STRUCT(priv
->out_port_def_
,
471 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
);
473 tiz_api_GetParameter(tiz_get_krn(handleOf(priv
)), handleOf(priv
),
474 OMX_IndexParamPortDefinition
, &(priv
->out_port_def_
)));
476 priv
->first_buf_in_frame
= true;
478 return OMX_ErrorNone
;
481 static OMX_ERRORTYPE
h264d_prc_transfer_and_process(void *ap_obj
, OMX_U32 a_pid
)
483 return OMX_ErrorNone
;
486 static OMX_ERRORTYPE
h264d_prc_stop_and_return(void *ap_obj
)
488 vid_dec_PrivateType
*priv
= (vid_dec_PrivateType
*) ap_obj
;
489 return h264d_release_all_headers (priv
);
492 static OMX_ERRORTYPE
h264d_prc_buffers_ready(const void *ap_obj
)
494 vid_dec_PrivateType
*priv
= (vid_dec_PrivateType
*) ap_obj
;
495 OMX_BUFFERHEADERTYPE
*in_buf
= NULL
;
496 OMX_BUFFERHEADERTYPE
*out_buf
= NULL
;
500 /* Set parameters if start of stream */
501 if (!priv
->eos_
&& priv
->first_buf_in_frame
&& (in_buf
= get_input_buffer(priv
))) {
502 decode_frame(priv
, in_buf
);
505 /* Don't get input buffer if output buffer not found */
506 while (!priv
->eos_
&& (out_buf
= get_output_buffer(priv
)) && (in_buf
= get_input_buffer(priv
))) {
507 if (!priv
->out_port_disabled_
) {
508 decode_frame(priv
, in_buf
);
512 return OMX_ErrorNone
;
515 static OMX_ERRORTYPE
h264d_prc_port_flush(const void *ap_obj
, OMX_U32 a_pid
)
517 vid_dec_PrivateType
*priv
= (vid_dec_PrivateType
*) ap_obj
;
518 if (OMX_ALL
== a_pid
|| OMX_VID_DEC_AVC_INPUT_PORT_INDEX
== a_pid
) {
519 release_input_headers(priv
);
520 reset_stream_parameters(priv
);
522 if (OMX_ALL
== a_pid
|| OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
== a_pid
) {
523 release_output_header(priv
);
525 return OMX_ErrorNone
;
528 static OMX_ERRORTYPE
h264d_prc_port_disable(const void *ap_obj
, OMX_U32 a_pid
)
530 vid_dec_PrivateType
*priv
= (vid_dec_PrivateType
*) ap_obj
;
532 if (OMX_ALL
== a_pid
|| OMX_VID_DEC_AVC_INPUT_PORT_INDEX
== a_pid
) {
533 /* Release all buffers */
534 h264d_release_all_headers(priv
);
535 reset_stream_parameters(priv
);
536 priv
->in_port_disabled_
= true;
538 if (OMX_ALL
== a_pid
|| OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
== a_pid
) {
539 release_output_header(priv
);
540 priv
->out_port_disabled_
= true;
542 return OMX_ErrorNone
;
545 static OMX_ERRORTYPE
h264d_prc_port_enable(const void *ap_obj
, OMX_U32 a_pid
)
547 vid_dec_PrivateType
* priv
= (vid_dec_PrivateType
*) ap_obj
;
549 if (OMX_ALL
== a_pid
|| OMX_VID_DEC_AVC_INPUT_PORT_INDEX
== a_pid
) {
550 if (priv
->in_port_disabled_
) {
551 reset_stream_parameters(priv
);
552 priv
->in_port_disabled_
= false;
555 if (OMX_ALL
== a_pid
|| OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
== a_pid
) {
556 priv
->out_port_disabled_
= false;
558 return OMX_ErrorNone
;
565 static void * h264d_prc_class_ctor(void *ap_obj
, va_list * app
)
567 /* NOTE: Class methods might be added in the future. None for now. */
568 return super_ctor(typeOf(ap_obj
, "h264dprc_class"), ap_obj
, app
);
575 void * h264d_prc_class_init(void * ap_tos
, void * ap_hdl
)
577 void * tizprc
= tiz_get_type(ap_hdl
, "tizprc");
578 void * h264dprc_class
= factory_new
579 /* TIZ_CLASS_COMMENT: class type, class name, parent, size */
580 (classOf(tizprc
), "h264dprc_class", classOf(tizprc
),
581 sizeof(h264d_prc_class_t
),
582 /* TIZ_CLASS_COMMENT: */
584 /* TIZ_CLASS_COMMENT: class constructor */
585 ctor
, h264d_prc_class_ctor
,
586 /* TIZ_CLASS_COMMENT: stop value*/
588 return h264dprc_class
;
591 void * h264d_prc_init(void * ap_tos
, void * ap_hdl
)
593 void * tizprc
= tiz_get_type(ap_hdl
, "tizprc");
594 void * h264dprc_class
= tiz_get_type(ap_hdl
, "h264dprc_class");
595 TIZ_LOG_CLASS (h264dprc_class
);
596 void * h264dprc
= factory_new
597 /* TIZ_CLASS_COMMENT: class type, class name, parent, size */
598 (h264dprc_class
, "h264dprc", tizprc
, sizeof(vid_dec_PrivateType
),
599 /* TIZ_CLASS_COMMENT: */
601 /* TIZ_CLASS_COMMENT: class constructor */
602 ctor
, h264d_prc_ctor
,
603 /* TIZ_CLASS_COMMENT: class destructor */
604 dtor
, h264d_prc_dtor
,
605 /* TIZ_CLASS_COMMENT: */
606 tiz_srv_allocate_resources
, h264d_prc_allocate_resources
,
607 /* TIZ_CLASS_COMMENT: */
608 tiz_srv_deallocate_resources
, h264d_prc_deallocate_resources
,
609 /* TIZ_CLASS_COMMENT: */
610 tiz_srv_prepare_to_transfer
, h264d_prc_prepare_to_transfer
,
611 /* TIZ_CLASS_COMMENT: */
612 tiz_srv_transfer_and_process
, h264d_prc_transfer_and_process
,
613 /* TIZ_CLASS_COMMENT: */
614 tiz_srv_stop_and_return
, h264d_prc_stop_and_return
,
615 /* TIZ_CLASS_COMMENT: */
616 tiz_prc_buffers_ready
, h264d_prc_buffers_ready
,
617 /* TIZ_CLASS_COMMENT: */
618 tiz_prc_port_flush
, h264d_prc_port_flush
,
619 /* TIZ_CLASS_COMMENT: */
620 tiz_prc_port_disable
, h264d_prc_port_disable
,
621 /* TIZ_CLASS_COMMENT: */
622 tiz_prc_port_enable
, h264d_prc_port_enable
,
623 /* TIZ_CLASS_COMMENT: stop value*/