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 "pipe/p_screen.h"
48 #include "pipe/p_video_codec.h"
49 #include "util/u_memory.h"
50 #include "util/u_surface.h"
51 #include "vl/vl_video_buffer.h"
52 #include "vl/vl_vlc.h"
54 #include "entrypoint.h"
56 #include "vid_omx_common.h"
57 #include "vid_dec_h264_common.h"
59 static OMX_ERRORTYPE
vid_dec_Constructor(OMX_COMPONENTTYPE
*comp
, OMX_STRING name
);
60 static OMX_ERRORTYPE
vid_dec_Destructor(OMX_COMPONENTTYPE
*comp
);
61 static OMX_ERRORTYPE
vid_dec_SetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
);
62 static OMX_ERRORTYPE
vid_dec_GetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
);
63 static OMX_ERRORTYPE
vid_dec_MessageHandler(OMX_COMPONENTTYPE
*comp
, internalRequestMessageType
*msg
);
64 static OMX_ERRORTYPE
vid_dec_DecodeBuffer(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
*buf
);
65 static OMX_ERRORTYPE
vid_dec_FreeDecBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
);
66 static void vid_dec_FrameDecoded(OMX_COMPONENTTYPE
*comp
, OMX_BUFFERHEADERTYPE
* input
, OMX_BUFFERHEADERTYPE
* output
);
68 OMX_ERRORTYPE
vid_dec_LoaderComponent(stLoaderComponentType
*comp
)
70 comp
->componentVersion
.s
.nVersionMajor
= 0;
71 comp
->componentVersion
.s
.nVersionMinor
= 0;
72 comp
->componentVersion
.s
.nRevision
= 0;
73 comp
->componentVersion
.s
.nStep
= 1;
74 comp
->name_specific_length
= 3;
76 comp
->name
= CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
77 if (comp
->name
== NULL
)
80 comp
->name_specific
= CALLOC(comp
->name_specific_length
, sizeof(char *));
81 if (comp
->name_specific
== NULL
)
84 comp
->role_specific
= CALLOC(comp
->name_specific_length
, sizeof(char *));
85 if (comp
->role_specific
== NULL
)
88 comp
->name_specific
[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
89 if (comp
->name_specific
[0] == NULL
)
92 comp
->name_specific
[1] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
93 if (comp
->name_specific
[1] == NULL
)
96 comp
->name_specific
[2] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
97 if (comp
->name_specific
[2] == NULL
)
100 comp
->role_specific
[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
101 if (comp
->role_specific
[0] == NULL
)
104 comp
->role_specific
[1] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
105 if (comp
->role_specific
[1] == NULL
)
108 comp
->role_specific
[2] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
109 if (comp
->role_specific
[2] == NULL
)
112 strcpy(comp
->name
, OMX_VID_DEC_BASE_NAME
);
113 strcpy(comp
->name_specific
[0], OMX_VID_DEC_MPEG2_NAME
);
114 strcpy(comp
->name_specific
[1], OMX_VID_DEC_AVC_NAME
);
115 strcpy(comp
->name_specific
[2], OMX_VID_DEC_HEVC_NAME
);
117 strcpy(comp
->role_specific
[0], OMX_VID_DEC_MPEG2_ROLE
);
118 strcpy(comp
->role_specific
[1], OMX_VID_DEC_AVC_ROLE
);
119 strcpy(comp
->role_specific
[2], OMX_VID_DEC_HEVC_ROLE
);
121 comp
->constructor
= vid_dec_Constructor
;
123 return OMX_ErrorNone
;
126 FREE(comp
->role_specific
[2]);
127 FREE(comp
->role_specific
[1]);
128 FREE(comp
->role_specific
[0]);
129 FREE(comp
->name_specific
[2]);
130 FREE(comp
->name_specific
[1]);
131 FREE(comp
->name_specific
[0]);
134 FREE(comp
->role_specific
);
135 FREE(comp
->name_specific
);
139 return OMX_ErrorInsufficientResources
;
142 static OMX_ERRORTYPE
vid_dec_Constructor(OMX_COMPONENTTYPE
*comp
, OMX_STRING name
)
144 vid_dec_PrivateType
*priv
;
145 omx_base_video_PortType
*port
;
146 struct pipe_screen
*screen
;
150 assert(!comp
->pComponentPrivate
);
152 priv
= comp
->pComponentPrivate
= CALLOC(1, sizeof(vid_dec_PrivateType
));
154 return OMX_ErrorInsufficientResources
;
156 r
= omx_base_filter_Constructor(comp
, name
);
160 priv
->profile
= PIPE_VIDEO_PROFILE_UNKNOWN
;
162 if (!strcmp(name
, OMX_VID_DEC_MPEG2_NAME
))
163 priv
->profile
= PIPE_VIDEO_PROFILE_MPEG2_MAIN
;
165 if (!strcmp(name
, OMX_VID_DEC_AVC_NAME
))
166 priv
->profile
= PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
;
168 if (!strcmp(name
, OMX_VID_DEC_HEVC_NAME
))
169 priv
->profile
= PIPE_VIDEO_PROFILE_HEVC_MAIN
;
171 priv
->BufferMgmtCallback
= vid_dec_FrameDecoded
;
172 priv
->messageHandler
= vid_dec_MessageHandler
;
173 priv
->destructor
= vid_dec_Destructor
;
175 comp
->SetParameter
= vid_dec_SetParameter
;
176 comp
->GetParameter
= vid_dec_GetParameter
;
178 priv
->screen
= omx_get_screen();
180 return OMX_ErrorInsufficientResources
;
182 screen
= priv
->screen
->pscreen
;
183 priv
->pipe
= pipe_create_multimedia_context(screen
);
185 return OMX_ErrorInsufficientResources
;
187 if (!vl_compositor_init(&priv
->compositor
, priv
->pipe
)) {
188 priv
->pipe
->destroy(priv
->pipe
);
190 return OMX_ErrorInsufficientResources
;
193 if (!vl_compositor_init_state(&priv
->cstate
, priv
->pipe
)) {
194 vl_compositor_cleanup(&priv
->compositor
);
195 priv
->pipe
->destroy(priv
->pipe
);
197 return OMX_ErrorInsufficientResources
;
200 priv
->sPortTypesParam
[OMX_PortDomainVideo
].nStartPortNumber
= 0;
201 priv
->sPortTypesParam
[OMX_PortDomainVideo
].nPorts
= 2;
202 priv
->ports
= CALLOC(2, sizeof(omx_base_PortType
*));
204 return OMX_ErrorInsufficientResources
;
206 for (i
= 0; i
< 2; ++i
) {
207 priv
->ports
[i
] = CALLOC(1, sizeof(omx_base_video_PortType
));
209 return OMX_ErrorInsufficientResources
;
211 base_video_port_Constructor(comp
, &priv
->ports
[i
], i
, i
== 0);
214 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
215 strcpy(port
->sPortParam
.format
.video
.cMIMEType
,"video/MPEG2");
216 port
->sPortParam
.nBufferCountMin
= 8;
217 port
->sPortParam
.nBufferCountActual
= 8;
218 port
->sPortParam
.nBufferSize
= DEFAULT_OUT_BUFFER_SIZE
;
219 port
->sPortParam
.format
.video
.nFrameWidth
= 176;
220 port
->sPortParam
.format
.video
.nFrameHeight
= 144;
221 port
->sPortParam
.format
.video
.eCompressionFormat
= OMX_VIDEO_CodingMPEG2
;
222 port
->sVideoParam
.eCompressionFormat
= OMX_VIDEO_CodingMPEG2
;
223 port
->Port_SendBufferFunction
= vid_dec_DecodeBuffer
;
224 port
->Port_FreeBuffer
= vid_dec_FreeDecBuffer
;
226 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
];
227 port
->sPortParam
.nBufferCountActual
= 8;
228 port
->sPortParam
.nBufferCountMin
= 4;
229 port
->sPortParam
.format
.video
.nFrameWidth
= 176;
230 port
->sPortParam
.format
.video
.nFrameHeight
= 144;
231 port
->sPortParam
.format
.video
.eColorFormat
= OMX_COLOR_FormatYUV420SemiPlanar
;
232 port
->sVideoParam
.eColorFormat
= OMX_COLOR_FormatYUV420SemiPlanar
;
234 return OMX_ErrorNone
;
237 static OMX_ERRORTYPE
vid_dec_Destructor(OMX_COMPONENTTYPE
*comp
)
239 vid_dec_PrivateType
* priv
= comp
->pComponentPrivate
;
243 for (i
= 0; i
< priv
->sPortTypesParam
[OMX_PortDomainVideo
].nPorts
; ++i
) {
245 priv
->ports
[i
]->PortDestructor(priv
->ports
[i
]);
252 vl_compositor_cleanup_state(&priv
->cstate
);
253 vl_compositor_cleanup(&priv
->compositor
);
254 priv
->pipe
->destroy(priv
->pipe
);
260 return omx_workaround_Destructor(comp
);
263 static OMX_ERRORTYPE
vid_dec_SetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
)
265 OMX_COMPONENTTYPE
*comp
= handle
;
266 vid_dec_PrivateType
*priv
= comp
->pComponentPrivate
;
270 return OMX_ErrorBadParameter
;
273 case OMX_IndexParamPortDefinition
: {
274 OMX_PARAM_PORTDEFINITIONTYPE
*def
= param
;
276 r
= omx_base_component_SetParameter(handle
, idx
, param
);
280 if (def
->nPortIndex
== OMX_BASE_FILTER_INPUTPORT_INDEX
) {
281 omx_base_video_PortType
*port
;
282 unsigned framesize
= def
->format
.video
.nFrameWidth
* def
->format
.video
.nFrameHeight
;
284 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
285 port
->sPortParam
.nBufferSize
= framesize
* 512 / (16*16);
287 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
];
288 port
->sPortParam
.format
.video
.nFrameWidth
= def
->format
.video
.nFrameWidth
;
289 port
->sPortParam
.format
.video
.nFrameHeight
= def
->format
.video
.nFrameHeight
;
290 port
->sPortParam
.format
.video
.nStride
= def
->format
.video
.nFrameWidth
;
291 port
->sPortParam
.format
.video
.nSliceHeight
= def
->format
.video
.nFrameHeight
;
292 port
->sPortParam
.nBufferSize
= framesize
*3/2;
294 priv
->callbacks
->EventHandler(comp
, priv
->callbackData
, OMX_EventPortSettingsChanged
,
295 OMX_BASE_FILTER_OUTPUTPORT_INDEX
, 0, NULL
);
299 case OMX_IndexParamStandardComponentRole
: {
300 OMX_PARAM_COMPONENTROLETYPE
*role
= param
;
302 r
= checkHeader(param
, sizeof(OMX_PARAM_COMPONENTROLETYPE
));
306 if (!strcmp((char *)role
->cRole
, OMX_VID_DEC_MPEG2_ROLE
)) {
307 priv
->profile
= PIPE_VIDEO_PROFILE_MPEG2_MAIN
;
308 } else if (!strcmp((char *)role
->cRole
, OMX_VID_DEC_AVC_ROLE
)) {
309 priv
->profile
= PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
;
310 } else if (!strcmp((char *)role
->cRole
, OMX_VID_DEC_HEVC_ROLE
)) {
311 priv
->profile
= PIPE_VIDEO_PROFILE_HEVC_MAIN
;
313 return OMX_ErrorBadParameter
;
318 case OMX_IndexParamVideoPortFormat
: {
319 OMX_VIDEO_PARAM_PORTFORMATTYPE
*format
= param
;
320 omx_base_video_PortType
*port
;
322 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
326 if (format
->nPortIndex
> 1)
327 return OMX_ErrorBadPortIndex
;
329 port
= (omx_base_video_PortType
*)priv
->ports
[format
->nPortIndex
];
330 memcpy(&port
->sVideoParam
, format
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
334 return omx_base_component_SetParameter(handle
, idx
, param
);
336 return OMX_ErrorNone
;
339 static OMX_ERRORTYPE
vid_dec_GetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
)
341 OMX_COMPONENTTYPE
*comp
= handle
;
342 vid_dec_PrivateType
*priv
= comp
->pComponentPrivate
;
346 return OMX_ErrorBadParameter
;
349 case OMX_IndexParamStandardComponentRole
: {
350 OMX_PARAM_COMPONENTROLETYPE
*role
= param
;
352 r
= checkHeader(param
, sizeof(OMX_PARAM_COMPONENTROLETYPE
));
356 if (priv
->profile
== PIPE_VIDEO_PROFILE_MPEG2_MAIN
)
357 strcpy((char *)role
->cRole
, OMX_VID_DEC_MPEG2_ROLE
);
358 else if (priv
->profile
== PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
)
359 strcpy((char *)role
->cRole
, OMX_VID_DEC_AVC_ROLE
);
360 else if (priv
->profile
== PIPE_VIDEO_PROFILE_HEVC_MAIN
)
361 strcpy((char *)role
->cRole
, OMX_VID_DEC_HEVC_ROLE
);
366 case OMX_IndexParamVideoInit
:
367 r
= checkHeader(param
, sizeof(OMX_PORT_PARAM_TYPE
));
371 memcpy(param
, &priv
->sPortTypesParam
[OMX_PortDomainVideo
], sizeof(OMX_PORT_PARAM_TYPE
));
374 case OMX_IndexParamVideoPortFormat
: {
375 OMX_VIDEO_PARAM_PORTFORMATTYPE
*format
= param
;
376 omx_base_video_PortType
*port
;
378 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
382 if (format
->nPortIndex
> 1)
383 return OMX_ErrorBadPortIndex
;
385 port
= (omx_base_video_PortType
*)priv
->ports
[format
->nPortIndex
];
386 memcpy(format
, &port
->sVideoParam
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
391 return omx_base_component_GetParameter(handle
, idx
, param
);
394 return OMX_ErrorNone
;
397 static OMX_ERRORTYPE
vid_dec_MessageHandler(OMX_COMPONENTTYPE
* comp
, internalRequestMessageType
*msg
)
399 vid_dec_PrivateType
* priv
= comp
->pComponentPrivate
;
401 if (msg
->messageType
== OMX_CommandStateSet
) {
402 if ((msg
->messageParam
== OMX_StateIdle
) && (priv
->state
== OMX_StateLoaded
)) {
403 if (priv
->profile
== PIPE_VIDEO_PROFILE_MPEG2_MAIN
)
404 vid_dec_mpeg12_Init(priv
);
405 else if (priv
->profile
== PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
)
406 vid_dec_h264_Init(priv
);
407 else if (priv
->profile
== PIPE_VIDEO_PROFILE_HEVC_MAIN
)
408 vid_dec_h265_Init(priv
);
410 } else if ((msg
->messageParam
== OMX_StateLoaded
) && (priv
->state
== OMX_StateIdle
)) {
412 priv
->shadow
->destroy(priv
->shadow
);
416 priv
->codec
->destroy(priv
->codec
);
422 return omx_base_component_MessageHandler(comp
, msg
);
425 static OMX_ERRORTYPE
vid_dec_DecodeBuffer(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
*buf
)
427 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
428 vid_dec_PrivateType
*priv
= comp
->pComponentPrivate
;
429 unsigned i
= priv
->num_in_buffers
++;
432 priv
->in_buffers
[i
] = buf
;
433 priv
->sizes
[i
] = buf
->nFilledLen
;
434 priv
->inputs
[i
] = buf
->pBuffer
;
435 priv
->timestamps
[i
] = buf
->nTimeStamp
;
437 while (priv
->num_in_buffers
> (!!(buf
->nFlags
& OMX_BUFFERFLAG_EOS
) ? 0 : 1)) {
438 bool eos
= !!(priv
->in_buffers
[0]->nFlags
& OMX_BUFFERFLAG_EOS
);
439 unsigned min_bits_left
= eos
? 32 : MAX2(buf
->nFilledLen
* 8, 32);
442 vl_vlc_init(&vlc
, priv
->num_in_buffers
, priv
->inputs
, priv
->sizes
);
445 priv
->bytes_left
= vl_vlc_bits_left(&vlc
) / 8;
447 while (vl_vlc_bits_left(&vlc
) > min_bits_left
) {
448 priv
->Decode(priv
, &vlc
, min_bits_left
);
449 vl_vlc_fillbits(&vlc
);
453 unsigned bytes
= priv
->bytes_left
- vl_vlc_bits_left(&vlc
) / 8;
455 priv
->codec
->decode_bitstream(priv
->codec
, priv
->target
, &priv
->picture
.base
,
456 1, &priv
->slice
, &bytes
);
458 if (priv
->num_in_buffers
)
459 priv
->slice
= priv
->inputs
[1];
464 if (eos
&& priv
->frame_started
)
465 priv
->EndFrame(priv
);
467 if (priv
->frame_finished
) {
468 priv
->frame_finished
= false;
469 priv
->in_buffers
[0]->nFilledLen
= priv
->in_buffers
[0]->nAllocLen
;
470 r
= base_port_SendBufferFunction(port
, priv
->in_buffers
[0]);
472 vid_dec_FreeInputPortPrivate(priv
->in_buffers
[0]);
473 priv
->in_buffers
[0]->nFilledLen
= priv
->in_buffers
[0]->nAllocLen
;
474 r
= base_port_SendBufferFunction(port
, priv
->in_buffers
[0]);
476 priv
->in_buffers
[0]->nFilledLen
= 0;
477 r
= port
->ReturnBufferFunction(port
, priv
->in_buffers
[0]);
480 if (--priv
->num_in_buffers
) {
481 unsigned delta
= MIN2((min_bits_left
- vl_vlc_bits_left(&vlc
)) / 8, priv
->sizes
[1]);
483 priv
->in_buffers
[0] = priv
->in_buffers
[1];
484 priv
->sizes
[0] = priv
->sizes
[1] - delta
;
485 priv
->inputs
[0] = priv
->inputs
[1] + delta
;
486 priv
->timestamps
[0] = priv
->timestamps
[1];
493 return OMX_ErrorNone
;
496 static OMX_ERRORTYPE
vid_dec_FreeDecBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
)
498 vid_dec_FreeInputPortPrivate(buf
);
499 return base_port_FreeBuffer(port
, idx
, buf
);
502 static void vid_dec_FrameDecoded(OMX_COMPONENTTYPE
*comp
, OMX_BUFFERHEADERTYPE
* input
,
503 OMX_BUFFERHEADERTYPE
* output
)
505 vid_dec_PrivateType
*priv
= comp
->pComponentPrivate
;
507 vid_dec_FrameDecoded_common(priv
, input
, output
);