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 **************************************************************************/
30 * Christian König <christian.koenig@amd.com>
37 #include <OMX_Video.h>
39 /* bellagio defines a DEBUG macro that we don't want */
41 #include <bellagio/omxcore.h>
44 #include <bellagio/omxcore.h>
47 #include <bellagio/omx_base_video_port.h>
49 #include "pipe/p_screen.h"
50 #include "pipe/p_video_codec.h"
51 #include "util/u_memory.h"
52 #include "util/u_surface.h"
53 #include "vl/vl_vlc.h"
55 #include "entrypoint.h"
58 static OMX_ERRORTYPE
vid_dec_Constructor(OMX_COMPONENTTYPE
*comp
, OMX_STRING name
);
59 static OMX_ERRORTYPE
vid_dec_Destructor(OMX_COMPONENTTYPE
*comp
);
60 static OMX_ERRORTYPE
vid_dec_SetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
);
61 static OMX_ERRORTYPE
vid_dec_GetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
);
62 static OMX_ERRORTYPE
vid_dec_MessageHandler(OMX_COMPONENTTYPE
*comp
, internalRequestMessageType
*msg
);
63 static OMX_ERRORTYPE
vid_dec_DecodeBuffer(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
*buf
);
64 static OMX_ERRORTYPE
vid_dec_FreeDecBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
);
65 static void vid_dec_FrameDecoded(OMX_COMPONENTTYPE
*comp
, OMX_BUFFERHEADERTYPE
* input
, OMX_BUFFERHEADERTYPE
* output
);
67 OMX_ERRORTYPE
vid_dec_LoaderComponent(stLoaderComponentType
*comp
)
69 comp
->componentVersion
.s
.nVersionMajor
= 0;
70 comp
->componentVersion
.s
.nVersionMinor
= 0;
71 comp
->componentVersion
.s
.nRevision
= 0;
72 comp
->componentVersion
.s
.nStep
= 1;
73 comp
->name_specific_length
= 2;
75 comp
->name
= CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
76 if (comp
->name
== NULL
)
79 comp
->name_specific
= CALLOC(comp
->name_specific_length
, sizeof(char *));
80 if (comp
->name_specific
== NULL
)
83 comp
->role_specific
= CALLOC(comp
->name_specific_length
, sizeof(char *));
84 if (comp
->role_specific
== NULL
)
87 comp
->name_specific
[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
88 if (comp
->name_specific
[0] == NULL
)
91 comp
->name_specific
[1] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
92 if (comp
->name_specific
[1] == NULL
)
95 comp
->role_specific
[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
96 if (comp
->role_specific
[0] == NULL
)
99 comp
->role_specific
[1] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
100 if (comp
->role_specific
[1] == NULL
)
103 strcpy(comp
->name
, OMX_VID_DEC_BASE_NAME
);
104 strcpy(comp
->name_specific
[0], OMX_VID_DEC_MPEG2_NAME
);
105 strcpy(comp
->name_specific
[1], OMX_VID_DEC_AVC_NAME
);
107 strcpy(comp
->role_specific
[0], OMX_VID_DEC_MPEG2_ROLE
);
108 strcpy(comp
->role_specific
[1], OMX_VID_DEC_AVC_ROLE
);
110 comp
->constructor
= vid_dec_Constructor
;
112 return OMX_ErrorNone
;
115 FREE(comp
->role_specific
[1]);
116 FREE(comp
->role_specific
[0]);
117 FREE(comp
->name_specific
[1]);
118 FREE(comp
->name_specific
[0]);
121 FREE(comp
->role_specific
);
122 FREE(comp
->name_specific
);
126 return OMX_ErrorInsufficientResources
;
129 static OMX_ERRORTYPE
vid_dec_Constructor(OMX_COMPONENTTYPE
*comp
, OMX_STRING name
)
131 vid_dec_PrivateType
*priv
;
132 omx_base_video_PortType
*port
;
133 struct pipe_screen
*screen
;
137 assert(!comp
->pComponentPrivate
);
139 priv
= comp
->pComponentPrivate
= CALLOC(1, sizeof(vid_dec_PrivateType
));
141 return OMX_ErrorInsufficientResources
;
143 r
= omx_base_filter_Constructor(comp
, name
);
147 priv
->profile
= PIPE_VIDEO_PROFILE_UNKNOWN
;
149 if (!strcmp(name
, OMX_VID_DEC_MPEG2_NAME
))
150 priv
->profile
= PIPE_VIDEO_PROFILE_MPEG2_MAIN
;
152 if (!strcmp(name
, OMX_VID_DEC_AVC_NAME
))
153 priv
->profile
= PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
;
155 priv
->BufferMgmtCallback
= vid_dec_FrameDecoded
;
156 priv
->messageHandler
= vid_dec_MessageHandler
;
157 priv
->destructor
= vid_dec_Destructor
;
159 comp
->SetParameter
= vid_dec_SetParameter
;
160 comp
->GetParameter
= vid_dec_GetParameter
;
162 priv
->screen
= omx_get_screen();
164 return OMX_ErrorInsufficientResources
;
166 screen
= priv
->screen
->pscreen
;
167 priv
->pipe
= screen
->context_create(screen
, priv
->screen
);
169 return OMX_ErrorInsufficientResources
;
171 priv
->sPortTypesParam
[OMX_PortDomainVideo
].nStartPortNumber
= 0;
172 priv
->sPortTypesParam
[OMX_PortDomainVideo
].nPorts
= 2;
173 priv
->ports
= CALLOC(2, sizeof(omx_base_PortType
*));
175 return OMX_ErrorInsufficientResources
;
177 for (i
= 0; i
< 2; ++i
) {
178 priv
->ports
[i
] = CALLOC(1, sizeof(omx_base_video_PortType
));
180 return OMX_ErrorInsufficientResources
;
182 base_video_port_Constructor(comp
, &priv
->ports
[i
], i
, i
== 0);
185 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
186 strcpy(port
->sPortParam
.format
.video
.cMIMEType
,"video/MPEG2");
187 port
->sPortParam
.nBufferCountMin
= 8;
188 port
->sPortParam
.nBufferCountActual
= 8;
189 port
->sPortParam
.nBufferSize
= DEFAULT_OUT_BUFFER_SIZE
;
190 port
->sPortParam
.format
.video
.nFrameWidth
= 176;
191 port
->sPortParam
.format
.video
.nFrameHeight
= 144;
192 port
->sPortParam
.format
.video
.eCompressionFormat
= OMX_VIDEO_CodingMPEG2
;
193 port
->sVideoParam
.eCompressionFormat
= OMX_VIDEO_CodingMPEG2
;
194 port
->Port_SendBufferFunction
= vid_dec_DecodeBuffer
;
195 port
->Port_FreeBuffer
= vid_dec_FreeDecBuffer
;
197 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
];
198 port
->sPortParam
.nBufferCountActual
= 8;
199 port
->sPortParam
.nBufferCountMin
= 4;
200 port
->sPortParam
.format
.video
.nFrameWidth
= 176;
201 port
->sPortParam
.format
.video
.nFrameHeight
= 144;
202 port
->sPortParam
.format
.video
.eColorFormat
= OMX_COLOR_FormatYUV420SemiPlanar
;
203 port
->sVideoParam
.eColorFormat
= OMX_COLOR_FormatYUV420SemiPlanar
;
205 return OMX_ErrorNone
;
208 static OMX_ERRORTYPE
vid_dec_Destructor(OMX_COMPONENTTYPE
*comp
)
210 vid_dec_PrivateType
* priv
= comp
->pComponentPrivate
;
214 for (i
= 0; i
< priv
->sPortTypesParam
[OMX_PortDomainVideo
].nPorts
; ++i
) {
216 priv
->ports
[i
]->PortDestructor(priv
->ports
[i
]);
223 priv
->pipe
->destroy(priv
->pipe
);
228 return omx_workaround_Destructor(comp
);
231 static OMX_ERRORTYPE
vid_dec_SetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
)
233 OMX_COMPONENTTYPE
*comp
= handle
;
234 vid_dec_PrivateType
*priv
= comp
->pComponentPrivate
;
238 return OMX_ErrorBadParameter
;
241 case OMX_IndexParamPortDefinition
: {
242 OMX_PARAM_PORTDEFINITIONTYPE
*def
= param
;
244 r
= omx_base_component_SetParameter(handle
, idx
, param
);
248 if (def
->nPortIndex
== OMX_BASE_FILTER_INPUTPORT_INDEX
) {
249 omx_base_video_PortType
*port
;
250 unsigned framesize
= def
->format
.video
.nFrameWidth
* def
->format
.video
.nFrameHeight
;
252 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
253 port
->sPortParam
.nBufferSize
= framesize
* 512 / (16*16);
255 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
];
256 port
->sPortParam
.format
.video
.nFrameWidth
= def
->format
.video
.nFrameWidth
;
257 port
->sPortParam
.format
.video
.nFrameHeight
= def
->format
.video
.nFrameHeight
;
258 port
->sPortParam
.format
.video
.nStride
= def
->format
.video
.nFrameWidth
;
259 port
->sPortParam
.format
.video
.nSliceHeight
= def
->format
.video
.nFrameHeight
;
260 port
->sPortParam
.nBufferSize
= framesize
*3/2;
262 priv
->callbacks
->EventHandler(comp
, priv
->callbackData
, OMX_EventPortSettingsChanged
,
263 OMX_BASE_FILTER_OUTPUTPORT_INDEX
, 0, NULL
);
267 case OMX_IndexParamStandardComponentRole
: {
268 OMX_PARAM_COMPONENTROLETYPE
*role
= param
;
270 r
= checkHeader(param
, sizeof(OMX_PARAM_COMPONENTROLETYPE
));
274 if (!strcmp((char *)role
->cRole
, OMX_VID_DEC_MPEG2_ROLE
)) {
275 priv
->profile
= PIPE_VIDEO_PROFILE_MPEG2_MAIN
;
276 } else if (!strcmp((char *)role
->cRole
, OMX_VID_DEC_AVC_ROLE
)) {
277 priv
->profile
= PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
;
279 return OMX_ErrorBadParameter
;
284 case OMX_IndexParamVideoPortFormat
: {
285 OMX_VIDEO_PARAM_PORTFORMATTYPE
*format
= param
;
286 omx_base_video_PortType
*port
;
288 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
292 if (format
->nPortIndex
> 1)
293 return OMX_ErrorBadPortIndex
;
295 port
= (omx_base_video_PortType
*)priv
->ports
[format
->nPortIndex
];
296 memcpy(&port
->sVideoParam
, format
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
300 return omx_base_component_SetParameter(handle
, idx
, param
);
302 return OMX_ErrorNone
;
305 static OMX_ERRORTYPE
vid_dec_GetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
)
307 OMX_COMPONENTTYPE
*comp
= handle
;
308 vid_dec_PrivateType
*priv
= comp
->pComponentPrivate
;
312 return OMX_ErrorBadParameter
;
315 case OMX_IndexParamStandardComponentRole
: {
316 OMX_PARAM_COMPONENTROLETYPE
*role
= param
;
318 r
= checkHeader(param
, sizeof(OMX_PARAM_COMPONENTROLETYPE
));
322 if (priv
->profile
== PIPE_VIDEO_PROFILE_MPEG2_MAIN
)
323 strcpy((char *)role
->cRole
, OMX_VID_DEC_MPEG2_ROLE
);
324 else if (priv
->profile
== PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
)
325 strcpy((char *)role
->cRole
, OMX_VID_DEC_AVC_ROLE
);
330 case OMX_IndexParamVideoInit
:
331 r
= checkHeader(param
, sizeof(OMX_PORT_PARAM_TYPE
));
335 memcpy(param
, &priv
->sPortTypesParam
[OMX_PortDomainVideo
], sizeof(OMX_PORT_PARAM_TYPE
));
338 case OMX_IndexParamVideoPortFormat
: {
339 OMX_VIDEO_PARAM_PORTFORMATTYPE
*format
= param
;
340 omx_base_video_PortType
*port
;
342 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
346 if (format
->nPortIndex
> 1)
347 return OMX_ErrorBadPortIndex
;
349 port
= (omx_base_video_PortType
*)priv
->ports
[format
->nPortIndex
];
350 memcpy(format
, &port
->sVideoParam
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
355 return omx_base_component_GetParameter(handle
, idx
, param
);
358 return OMX_ErrorNone
;
361 static OMX_ERRORTYPE
vid_dec_MessageHandler(OMX_COMPONENTTYPE
* comp
, internalRequestMessageType
*msg
)
363 vid_dec_PrivateType
* priv
= comp
->pComponentPrivate
;
365 if (msg
->messageType
== OMX_CommandStateSet
) {
366 if ((msg
->messageParam
== OMX_StateIdle
) && (priv
->state
== OMX_StateLoaded
)) {
368 struct pipe_video_codec templat
= {};
369 omx_base_video_PortType
*port
;
371 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
373 templat
.profile
= priv
->profile
;
374 templat
.entrypoint
= PIPE_VIDEO_ENTRYPOINT_BITSTREAM
;
375 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
376 templat
.width
= port
->sPortParam
.format
.video
.nFrameWidth
;
377 templat
.height
= port
->sPortParam
.format
.video
.nFrameHeight
;
378 templat
.max_references
= 2;
379 templat
.expect_chunked_decode
= true;
381 priv
->codec
= priv
->pipe
->create_video_codec(priv
->pipe
, &templat
);
383 if (priv
->profile
== PIPE_VIDEO_PROFILE_MPEG2_MAIN
)
384 vid_dec_mpeg12_Init(priv
);
385 else if (priv
->profile
== PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
)
386 vid_dec_h264_Init(priv
);
388 } else if ((msg
->messageParam
== OMX_StateLoaded
) && (priv
->state
== OMX_StateIdle
)) {
390 priv
->shadow
->destroy(priv
->shadow
);
394 priv
->codec
->destroy(priv
->codec
);
400 return omx_base_component_MessageHandler(comp
, msg
);
403 void vid_dec_NeedTarget(vid_dec_PrivateType
*priv
)
405 struct pipe_video_buffer templat
= {};
406 omx_base_video_PortType
*port
;
408 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
411 templat
.buffer_format
= PIPE_FORMAT_NV12
;
412 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
413 templat
.width
= port
->sPortParam
.format
.video
.nFrameWidth
;
414 templat
.height
= port
->sPortParam
.format
.video
.nFrameHeight
;
415 templat
.interlaced
= false;
416 priv
->target
= priv
->pipe
->create_video_buffer(priv
->pipe
, &templat
);
420 static void vid_dec_FreeInputPortPrivate(OMX_BUFFERHEADERTYPE
*buf
)
422 struct pipe_video_buffer
*vbuf
= buf
->pInputPortPrivate
;
427 buf
->pInputPortPrivate
= NULL
;
430 static OMX_ERRORTYPE
vid_dec_DecodeBuffer(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
*buf
)
432 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
433 vid_dec_PrivateType
*priv
= comp
->pComponentPrivate
;
434 unsigned i
= priv
->num_in_buffers
++;
437 priv
->in_buffers
[i
] = buf
;
438 priv
->sizes
[i
] = buf
->nFilledLen
;
439 priv
->inputs
[i
] = buf
->pBuffer
;
441 while (priv
->num_in_buffers
> (!!(buf
->nFlags
& OMX_BUFFERFLAG_EOS
) ? 0 : 1)) {
442 bool eos
= !!(priv
->in_buffers
[0]->nFlags
& OMX_BUFFERFLAG_EOS
);
443 unsigned min_bits_left
= eos
? 32 : MAX2(buf
->nFilledLen
* 8, 32);
446 vl_vlc_init(&vlc
, priv
->num_in_buffers
, priv
->inputs
, priv
->sizes
);
449 priv
->bytes_left
= vl_vlc_bits_left(&vlc
) / 8;
451 while (vl_vlc_bits_left(&vlc
) > min_bits_left
) {
452 priv
->Decode(priv
, &vlc
, min_bits_left
);
453 vl_vlc_fillbits(&vlc
);
457 unsigned bytes
= priv
->bytes_left
- vl_vlc_bits_left(&vlc
) / 8;
459 priv
->codec
->decode_bitstream(priv
->codec
, priv
->target
, &priv
->picture
.base
,
460 1, &priv
->slice
, &bytes
);
462 if (priv
->num_in_buffers
)
463 priv
->slice
= priv
->inputs
[1];
468 if (eos
&& priv
->frame_started
)
469 priv
->EndFrame(priv
);
471 if (priv
->frame_finished
) {
472 priv
->frame_finished
= false;
473 priv
->in_buffers
[0]->nFilledLen
= priv
->in_buffers
[0]->nAllocLen
;
474 r
= base_port_SendBufferFunction(port
, priv
->in_buffers
[0]);
476 vid_dec_FreeInputPortPrivate(priv
->in_buffers
[0]);
477 priv
->in_buffers
[0]->nFilledLen
= priv
->in_buffers
[0]->nAllocLen
;
478 r
= base_port_SendBufferFunction(port
, priv
->in_buffers
[0]);
480 priv
->in_buffers
[0]->nFilledLen
= 0;
481 r
= port
->ReturnBufferFunction(port
, priv
->in_buffers
[0]);
484 if (--priv
->num_in_buffers
) {
485 unsigned delta
= MIN2((min_bits_left
- vl_vlc_bits_left(&vlc
)) / 8, priv
->sizes
[1]);
487 priv
->in_buffers
[0] = priv
->in_buffers
[1];
488 priv
->sizes
[0] = priv
->sizes
[1] - delta
;
489 priv
->inputs
[0] = priv
->inputs
[1] + delta
;
496 return OMX_ErrorNone
;
499 static OMX_ERRORTYPE
vid_dec_FreeDecBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
)
501 vid_dec_FreeInputPortPrivate(buf
);
502 return base_port_FreeBuffer(port
, idx
, buf
);
505 static void vid_dec_FillOutput(vid_dec_PrivateType
*priv
, struct pipe_video_buffer
*buf
,
506 OMX_BUFFERHEADERTYPE
* output
)
508 omx_base_PortType
*port
= priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
];
509 OMX_VIDEO_PORTDEFINITIONTYPE
*def
= &port
->sPortParam
.format
.video
;
511 struct pipe_sampler_view
**views
;
512 struct pipe_transfer
*transfer
;
513 struct pipe_box box
= { };
516 views
= buf
->get_sampler_view_planes(buf
);
518 dst
= output
->pBuffer
;
520 box
.width
= def
->nFrameWidth
;
521 box
.height
= def
->nFrameHeight
;
524 src
= priv
->pipe
->transfer_map(priv
->pipe
, views
[0]->texture
, 0,
525 PIPE_TRANSFER_READ
, &box
, &transfer
);
526 util_copy_rect(dst
, views
[0]->texture
->format
, def
->nStride
, 0, 0,
527 box
.width
, box
.height
, src
, transfer
->stride
, 0, 0);
528 pipe_transfer_unmap(priv
->pipe
, transfer
);
530 dst
= ((uint8_t*)output
->pBuffer
) + (def
->nStride
* box
.height
);
532 box
.width
= def
->nFrameWidth
/ 2;
533 box
.height
= def
->nFrameHeight
/ 2;
535 src
= priv
->pipe
->transfer_map(priv
->pipe
, views
[1]->texture
, 0,
536 PIPE_TRANSFER_READ
, &box
, &transfer
);
537 util_copy_rect(dst
, views
[1]->texture
->format
, def
->nStride
, 0, 0,
538 box
.width
, box
.height
, src
, transfer
->stride
, 0, 0);
539 pipe_transfer_unmap(priv
->pipe
, transfer
);
542 static void vid_dec_FrameDecoded(OMX_COMPONENTTYPE
*comp
, OMX_BUFFERHEADERTYPE
* input
,
543 OMX_BUFFERHEADERTYPE
* output
)
545 vid_dec_PrivateType
*priv
= comp
->pComponentPrivate
;
546 bool eos
= !!(input
->nFlags
& OMX_BUFFERFLAG_EOS
);
548 if (!input
->pInputPortPrivate
)
549 input
->pInputPortPrivate
= priv
->Flush(priv
);
551 if (input
->pInputPortPrivate
) {
552 if (output
->pInputPortPrivate
) {
553 struct pipe_video_buffer
*tmp
= output
->pOutputPortPrivate
;
554 output
->pOutputPortPrivate
= input
->pInputPortPrivate
;
555 input
->pInputPortPrivate
= tmp
;
557 vid_dec_FillOutput(priv
, input
->pInputPortPrivate
, output
);
559 output
->nFilledLen
= output
->nAllocLen
;
562 if (eos
&& input
->pInputPortPrivate
)
563 vid_dec_FreeInputPortPrivate(input
);
565 input
->nFilledLen
= 0;