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"
53 #include "entrypoint.h"
55 #include "vid_omx_common.h"
56 #include "vid_enc_common.h"
58 static OMX_ERRORTYPE
vid_enc_Constructor(OMX_COMPONENTTYPE
*comp
, OMX_STRING name
);
59 static OMX_ERRORTYPE
vid_enc_Destructor(OMX_COMPONENTTYPE
*comp
);
60 static OMX_ERRORTYPE
vid_enc_SetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
);
61 static OMX_ERRORTYPE
vid_enc_GetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
);
62 static OMX_ERRORTYPE
vid_enc_SetConfig(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR config
);
63 static OMX_ERRORTYPE
vid_enc_GetConfig(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR config
);
64 static OMX_ERRORTYPE
vid_enc_MessageHandler(OMX_COMPONENTTYPE
*comp
, internalRequestMessageType
*msg
);
65 static OMX_ERRORTYPE
vid_enc_AllocateInBuffer(omx_base_PortType
*port
, OMX_INOUT OMX_BUFFERHEADERTYPE
**buf
,
66 OMX_IN OMX_U32 idx
, OMX_IN OMX_PTR
private, OMX_IN OMX_U32 size
);
67 static OMX_ERRORTYPE
vid_enc_UseInBuffer(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
**buf
, OMX_U32 idx
,
68 OMX_PTR
private, OMX_U32 size
, OMX_U8
*mem
);
69 static OMX_ERRORTYPE
vid_enc_FreeInBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
);
70 static OMX_ERRORTYPE
vid_enc_EncodeFrame(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
*buf
);
71 static OMX_ERRORTYPE
vid_enc_AllocateOutBuffer(omx_base_PortType
*comp
, OMX_INOUT OMX_BUFFERHEADERTYPE
**buf
,
72 OMX_IN OMX_U32 idx
, OMX_IN OMX_PTR
private, OMX_IN OMX_U32 size
);
73 static OMX_ERRORTYPE
vid_enc_FreeOutBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
);
74 static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE
*comp
, OMX_BUFFERHEADERTYPE
* input
, OMX_BUFFERHEADERTYPE
* output
);
76 OMX_ERRORTYPE
vid_enc_LoaderComponent(stLoaderComponentType
*comp
)
78 comp
->componentVersion
.s
.nVersionMajor
= 0;
79 comp
->componentVersion
.s
.nVersionMinor
= 0;
80 comp
->componentVersion
.s
.nRevision
= 0;
81 comp
->componentVersion
.s
.nStep
= 1;
82 comp
->name_specific_length
= 1;
83 comp
->constructor
= vid_enc_Constructor
;
85 comp
->name
= CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
87 return OMX_ErrorInsufficientResources
;
89 comp
->name_specific
= CALLOC(1, sizeof(char *));
90 if (!comp
->name_specific
)
93 comp
->role_specific
= CALLOC(1, sizeof(char *));
94 if (!comp
->role_specific
)
97 comp
->name_specific
[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
98 if (comp
->name_specific
[0] == NULL
)
101 comp
->role_specific
[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
102 if (comp
->role_specific
[0] == NULL
)
105 strcpy(comp
->name
, OMX_VID_ENC_BASE_NAME
);
106 strcpy(comp
->name_specific
[0], OMX_VID_ENC_AVC_NAME
);
107 strcpy(comp
->role_specific
[0], OMX_VID_ENC_AVC_ROLE
);
109 return OMX_ErrorNone
;
112 FREE(comp
->role_specific
[0]);
113 FREE(comp
->name_specific
[0]);
116 FREE(comp
->role_specific
);
117 FREE(comp
->name_specific
);
121 return OMX_ErrorInsufficientResources
;
124 static OMX_ERRORTYPE
vid_enc_Constructor(OMX_COMPONENTTYPE
*comp
, OMX_STRING name
)
126 vid_enc_PrivateType
*priv
;
127 omx_base_video_PortType
*port
;
128 struct pipe_screen
*screen
;
132 assert(!comp
->pComponentPrivate
);
134 priv
= comp
->pComponentPrivate
= CALLOC(1, sizeof(vid_enc_PrivateType
));
136 return OMX_ErrorInsufficientResources
;
138 r
= omx_base_filter_Constructor(comp
, name
);
142 priv
->BufferMgmtCallback
= vid_enc_BufferEncoded
;
143 priv
->messageHandler
= vid_enc_MessageHandler
;
144 priv
->destructor
= vid_enc_Destructor
;
146 comp
->SetParameter
= vid_enc_SetParameter
;
147 comp
->GetParameter
= vid_enc_GetParameter
;
148 comp
->GetConfig
= vid_enc_GetConfig
;
149 comp
->SetConfig
= vid_enc_SetConfig
;
151 priv
->screen
= omx_get_screen();
153 return OMX_ErrorInsufficientResources
;
155 screen
= priv
->screen
->pscreen
;
156 if (!screen
->get_video_param(screen
, PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
,
157 PIPE_VIDEO_ENTRYPOINT_ENCODE
, PIPE_VIDEO_CAP_SUPPORTED
))
158 return OMX_ErrorBadParameter
;
160 priv
->s_pipe
= pipe_create_multimedia_context(screen
);
162 return OMX_ErrorInsufficientResources
;
164 enc_InitCompute_common(priv
);
166 if (!vl_compositor_init(&priv
->compositor
, priv
->s_pipe
)) {
167 priv
->s_pipe
->destroy(priv
->s_pipe
);
169 return OMX_ErrorInsufficientResources
;
172 if (!vl_compositor_init_state(&priv
->cstate
, priv
->s_pipe
)) {
173 vl_compositor_cleanup(&priv
->compositor
);
174 priv
->s_pipe
->destroy(priv
->s_pipe
);
176 return OMX_ErrorInsufficientResources
;
179 priv
->t_pipe
= pipe_create_multimedia_context(screen
);
181 return OMX_ErrorInsufficientResources
;
183 priv
->sPortTypesParam
[OMX_PortDomainVideo
].nStartPortNumber
= 0;
184 priv
->sPortTypesParam
[OMX_PortDomainVideo
].nPorts
= 2;
185 priv
->ports
= CALLOC(2, sizeof(omx_base_PortType
*));
187 return OMX_ErrorInsufficientResources
;
189 for (i
= 0; i
< 2; ++i
) {
190 priv
->ports
[i
] = CALLOC(1, sizeof(omx_base_video_PortType
));
192 return OMX_ErrorInsufficientResources
;
194 base_video_port_Constructor(comp
, &priv
->ports
[i
], i
, i
== 0);
197 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
198 port
->sPortParam
.format
.video
.nFrameWidth
= 176;
199 port
->sPortParam
.format
.video
.nFrameHeight
= 144;
200 port
->sPortParam
.format
.video
.eColorFormat
= OMX_COLOR_FormatYUV420SemiPlanar
;
201 port
->sVideoParam
.eColorFormat
= OMX_COLOR_FormatYUV420SemiPlanar
;
202 port
->sPortParam
.nBufferCountActual
= 8;
203 port
->sPortParam
.nBufferCountMin
= 4;
205 port
->Port_SendBufferFunction
= vid_enc_EncodeFrame
;
206 port
->Port_AllocateBuffer
= vid_enc_AllocateInBuffer
;
207 port
->Port_UseBuffer
= vid_enc_UseInBuffer
;
208 port
->Port_FreeBuffer
= vid_enc_FreeInBuffer
;
210 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
];
211 strcpy(port
->sPortParam
.format
.video
.cMIMEType
,"video/H264");
212 port
->sPortParam
.format
.video
.nFrameWidth
= 176;
213 port
->sPortParam
.format
.video
.nFrameHeight
= 144;
214 port
->sPortParam
.format
.video
.eCompressionFormat
= OMX_VIDEO_CodingAVC
;
215 port
->sVideoParam
.eCompressionFormat
= OMX_VIDEO_CodingAVC
;
217 port
->Port_AllocateBuffer
= vid_enc_AllocateOutBuffer
;
218 port
->Port_FreeBuffer
= vid_enc_FreeOutBuffer
;
220 priv
->bitrate
.eControlRate
= OMX_Video_ControlRateDisable
;
221 priv
->bitrate
.nTargetBitrate
= 0;
223 priv
->quant
.nQpI
= OMX_VID_ENC_QUANT_I_FRAMES_DEFAULT
;
224 priv
->quant
.nQpP
= OMX_VID_ENC_QUANT_P_FRAMES_DEFAULT
;
225 priv
->quant
.nQpB
= OMX_VID_ENC_QUANT_B_FRAMES_DEFAULT
;
227 priv
->profile_level
.eProfile
= OMX_VIDEO_AVCProfileBaseline
;
228 priv
->profile_level
.eLevel
= OMX_VIDEO_AVCLevel51
;
230 priv
->force_pic_type
.IntraRefreshVOP
= OMX_FALSE
;
232 priv
->pic_order_cnt
= 0;
233 priv
->restricted_b_frames
= debug_get_bool_option("OMX_USE_RESTRICTED_B_FRAMES", FALSE
);
235 priv
->scale
.xWidth
= OMX_VID_ENC_SCALING_WIDTH_DEFAULT
;
236 priv
->scale
.xHeight
= OMX_VID_ENC_SCALING_WIDTH_DEFAULT
;
238 LIST_INITHEAD(&priv
->free_tasks
);
239 LIST_INITHEAD(&priv
->used_tasks
);
240 LIST_INITHEAD(&priv
->b_frames
);
241 LIST_INITHEAD(&priv
->stacked_tasks
);
243 return OMX_ErrorNone
;
246 static OMX_ERRORTYPE
vid_enc_Destructor(OMX_COMPONENTTYPE
*comp
)
248 vid_enc_PrivateType
* priv
= comp
->pComponentPrivate
;
251 enc_ReleaseTasks(&priv
->free_tasks
);
252 enc_ReleaseTasks(&priv
->used_tasks
);
253 enc_ReleaseTasks(&priv
->b_frames
);
254 enc_ReleaseTasks(&priv
->stacked_tasks
);
257 for (i
= 0; i
< priv
->sPortTypesParam
[OMX_PortDomainVideo
].nPorts
; ++i
) {
259 priv
->ports
[i
]->PortDestructor(priv
->ports
[i
]);
265 for (i
= 0; i
< OMX_VID_ENC_NUM_SCALING_BUFFERS
; ++i
)
266 if (priv
->scale_buffer
[i
])
267 priv
->scale_buffer
[i
]->destroy(priv
->scale_buffer
[i
]);
270 vl_compositor_cleanup_state(&priv
->cstate
);
271 vl_compositor_cleanup(&priv
->compositor
);
272 enc_ReleaseCompute_common(priv
);
273 priv
->s_pipe
->destroy(priv
->s_pipe
);
277 priv
->t_pipe
->destroy(priv
->t_pipe
);
282 return omx_workaround_Destructor(comp
);
285 static OMX_ERRORTYPE
enc_AllocateBackTexture(omx_base_PortType
*port
,
286 struct pipe_resource
**resource
,
287 struct pipe_transfer
**transfer
,
290 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
291 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
292 struct pipe_resource buf_templ
;
293 struct pipe_box box
= {};
296 memset(&buf_templ
, 0, sizeof buf_templ
);
297 buf_templ
.target
= PIPE_TEXTURE_2D
;
298 buf_templ
.format
= PIPE_FORMAT_I8_UNORM
;
299 buf_templ
.bind
= PIPE_BIND_LINEAR
;
300 buf_templ
.usage
= PIPE_USAGE_STAGING
;
302 buf_templ
.width0
= port
->sPortParam
.format
.video
.nFrameWidth
;
303 buf_templ
.height0
= port
->sPortParam
.format
.video
.nFrameHeight
* 3 / 2;
304 buf_templ
.depth0
= 1;
305 buf_templ
.array_size
= 1;
307 *resource
= priv
->s_pipe
->screen
->resource_create(priv
->s_pipe
->screen
, &buf_templ
);
309 return OMX_ErrorInsufficientResources
;
311 box
.width
= (*resource
)->width0
;
312 box
.height
= (*resource
)->height0
;
313 box
.depth
= (*resource
)->depth0
;
314 ptr
= priv
->s_pipe
->transfer_map(priv
->s_pipe
, *resource
, 0, PIPE_TRANSFER_WRITE
, &box
, transfer
);
318 return OMX_ErrorNone
;
321 static OMX_ERRORTYPE
vid_enc_SetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
)
323 OMX_COMPONENTTYPE
*comp
= handle
;
324 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
328 return OMX_ErrorBadParameter
;
331 case OMX_IndexParamPortDefinition
: {
332 OMX_PARAM_PORTDEFINITIONTYPE
*def
= param
;
334 r
= omx_base_component_SetParameter(handle
, idx
, param
);
338 if (def
->nPortIndex
== OMX_BASE_FILTER_INPUTPORT_INDEX
) {
339 omx_base_video_PortType
*port
;
341 struct pipe_resource
*resource
;
342 struct pipe_transfer
*transfer
;
344 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
345 enc_AllocateBackTexture(priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
],
346 &resource
, &transfer
, NULL
);
347 port
->sPortParam
.format
.video
.nStride
= transfer
->stride
;
348 pipe_transfer_unmap(priv
->s_pipe
, transfer
);
349 pipe_resource_reference(&resource
, NULL
);
351 framesize
= port
->sPortParam
.format
.video
.nStride
*
352 port
->sPortParam
.format
.video
.nFrameHeight
;
353 port
->sPortParam
.format
.video
.nSliceHeight
= port
->sPortParam
.format
.video
.nFrameHeight
;
354 port
->sPortParam
.nBufferSize
= framesize
* 3 / 2;
356 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
];
357 port
->sPortParam
.nBufferSize
= framesize
* 512 / (16*16);
359 priv
->frame_rate
= def
->format
.video
.xFramerate
;
361 priv
->callbacks
->EventHandler(comp
, priv
->callbackData
, OMX_EventPortSettingsChanged
,
362 OMX_BASE_FILTER_OUTPUTPORT_INDEX
, 0, NULL
);
366 case OMX_IndexParamStandardComponentRole
: {
367 OMX_PARAM_COMPONENTROLETYPE
*role
= param
;
369 r
= checkHeader(param
, sizeof(OMX_PARAM_COMPONENTROLETYPE
));
373 if (strcmp((char *)role
->cRole
, OMX_VID_ENC_AVC_ROLE
)) {
374 return OMX_ErrorBadParameter
;
379 case OMX_IndexParamVideoBitrate
: {
380 OMX_VIDEO_PARAM_BITRATETYPE
*bitrate
= param
;
382 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_BITRATETYPE
));
386 priv
->bitrate
= *bitrate
;
390 case OMX_IndexParamVideoQuantization
: {
391 OMX_VIDEO_PARAM_QUANTIZATIONTYPE
*quant
= param
;
393 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE
));
397 priv
->quant
= *quant
;
401 case OMX_IndexParamVideoProfileLevelCurrent
: {
402 OMX_VIDEO_PARAM_PROFILELEVELTYPE
*profile_level
= param
;
404 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE
));
408 priv
->profile_level
= *profile_level
;
413 return omx_base_component_SetParameter(handle
, idx
, param
);
415 return OMX_ErrorNone
;
418 static OMX_ERRORTYPE
vid_enc_GetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
)
420 OMX_COMPONENTTYPE
*comp
= handle
;
421 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
425 return OMX_ErrorBadParameter
;
428 case OMX_IndexParamStandardComponentRole
: {
429 OMX_PARAM_COMPONENTROLETYPE
*role
= param
;
431 r
= checkHeader(param
, sizeof(OMX_PARAM_COMPONENTROLETYPE
));
435 strcpy((char *)role
->cRole
, OMX_VID_ENC_AVC_ROLE
);
438 case OMX_IndexParamVideoInit
:
439 r
= checkHeader(param
, sizeof(OMX_PORT_PARAM_TYPE
));
443 memcpy(param
, &priv
->sPortTypesParam
[OMX_PortDomainVideo
], sizeof(OMX_PORT_PARAM_TYPE
));
446 case OMX_IndexParamVideoPortFormat
: {
447 OMX_VIDEO_PARAM_PORTFORMATTYPE
*format
= param
;
448 omx_base_video_PortType
*port
;
450 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
454 if (format
->nPortIndex
> 1)
455 return OMX_ErrorBadPortIndex
;
456 if (format
->nIndex
>= 1)
457 return OMX_ErrorNoMore
;
459 port
= (omx_base_video_PortType
*)priv
->ports
[format
->nPortIndex
];
460 memcpy(format
, &port
->sVideoParam
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
463 case OMX_IndexParamVideoBitrate
: {
464 OMX_VIDEO_PARAM_BITRATETYPE
*bitrate
= param
;
466 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_BITRATETYPE
));
470 bitrate
->eControlRate
= priv
->bitrate
.eControlRate
;
471 bitrate
->nTargetBitrate
= priv
->bitrate
.nTargetBitrate
;
475 case OMX_IndexParamVideoQuantization
: {
476 OMX_VIDEO_PARAM_QUANTIZATIONTYPE
*quant
= param
;
478 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE
));
482 quant
->nQpI
= priv
->quant
.nQpI
;
483 quant
->nQpP
= priv
->quant
.nQpP
;
484 quant
->nQpB
= priv
->quant
.nQpB
;
488 case OMX_IndexParamVideoProfileLevelCurrent
: {
489 OMX_VIDEO_PARAM_PROFILELEVELTYPE
*profile_level
= param
;
491 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE
));
495 profile_level
->eProfile
= priv
->profile_level
.eProfile
;
496 profile_level
->eLevel
= priv
->profile_level
.eLevel
;
501 return omx_base_component_GetParameter(handle
, idx
, param
);
503 return OMX_ErrorNone
;
506 static OMX_ERRORTYPE
vid_enc_SetConfig(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR config
)
508 OMX_COMPONENTTYPE
*comp
= handle
;
509 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
514 return OMX_ErrorBadParameter
;
517 case OMX_IndexConfigVideoIntraVOPRefresh
: {
518 OMX_CONFIG_INTRAREFRESHVOPTYPE
*type
= config
;
520 r
= checkHeader(config
, sizeof(OMX_CONFIG_INTRAREFRESHVOPTYPE
));
524 priv
->force_pic_type
= *type
;
528 case OMX_IndexConfigCommonScale
: {
529 OMX_CONFIG_SCALEFACTORTYPE
*scale
= config
;
531 r
= checkHeader(config
, sizeof(OMX_CONFIG_SCALEFACTORTYPE
));
535 if (scale
->xWidth
< 176 || scale
->xHeight
< 144)
536 return OMX_ErrorBadParameter
;
538 for (i
= 0; i
< OMX_VID_ENC_NUM_SCALING_BUFFERS
; ++i
) {
539 if (priv
->scale_buffer
[i
]) {
540 priv
->scale_buffer
[i
]->destroy(priv
->scale_buffer
[i
]);
541 priv
->scale_buffer
[i
] = NULL
;
545 priv
->scale
= *scale
;
546 if (priv
->scale
.xWidth
!= 0xffffffff && priv
->scale
.xHeight
!= 0xffffffff) {
547 struct pipe_video_buffer templat
= {};
549 templat
.buffer_format
= PIPE_FORMAT_NV12
;
550 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
551 templat
.width
= priv
->scale
.xWidth
;
552 templat
.height
= priv
->scale
.xHeight
;
553 templat
.interlaced
= false;
554 for (i
= 0; i
< OMX_VID_ENC_NUM_SCALING_BUFFERS
; ++i
) {
555 priv
->scale_buffer
[i
] = priv
->s_pipe
->create_video_buffer(priv
->s_pipe
, &templat
);
556 if (!priv
->scale_buffer
[i
])
557 return OMX_ErrorInsufficientResources
;
564 return omx_base_component_SetConfig(handle
, idx
, config
);
567 return OMX_ErrorNone
;
570 static OMX_ERRORTYPE
vid_enc_GetConfig(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR config
)
572 OMX_COMPONENTTYPE
*comp
= handle
;
573 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
577 return OMX_ErrorBadParameter
;
580 case OMX_IndexConfigCommonScale
: {
581 OMX_CONFIG_SCALEFACTORTYPE
*scale
= config
;
583 r
= checkHeader(config
, sizeof(OMX_CONFIG_SCALEFACTORTYPE
));
587 scale
->xWidth
= priv
->scale
.xWidth
;
588 scale
->xHeight
= priv
->scale
.xHeight
;
593 return omx_base_component_GetConfig(handle
, idx
, config
);
596 return OMX_ErrorNone
;
599 static OMX_ERRORTYPE
vid_enc_MessageHandler(OMX_COMPONENTTYPE
* comp
, internalRequestMessageType
*msg
)
601 vid_enc_PrivateType
* priv
= comp
->pComponentPrivate
;
603 if (msg
->messageType
== OMX_CommandStateSet
) {
604 if ((msg
->messageParam
== OMX_StateIdle
) && (priv
->state
== OMX_StateLoaded
)) {
606 struct pipe_video_codec templat
= {};
607 omx_base_video_PortType
*port
;
609 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
611 templat
.profile
= enc_TranslateOMXProfileToPipe(priv
->profile_level
.eProfile
);
612 templat
.level
= enc_TranslateOMXLevelToPipe(priv
->profile_level
.eLevel
);
613 templat
.entrypoint
= PIPE_VIDEO_ENTRYPOINT_ENCODE
;
614 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
615 templat
.width
= priv
->scale_buffer
[priv
->current_scale_buffer
] ?
616 priv
->scale
.xWidth
: port
->sPortParam
.format
.video
.nFrameWidth
;
617 templat
.height
= priv
->scale_buffer
[priv
->current_scale_buffer
] ?
618 priv
->scale
.xHeight
: port
->sPortParam
.format
.video
.nFrameHeight
;
620 if (templat
.profile
== PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE
) {
621 struct pipe_screen
*screen
= priv
->screen
->pscreen
;
622 templat
.max_references
= 1;
623 priv
->stacked_frames_num
=
624 screen
->get_video_param(screen
,
625 PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
,
626 PIPE_VIDEO_ENTRYPOINT_ENCODE
,
627 PIPE_VIDEO_CAP_STACKED_FRAMES
);
629 templat
.max_references
= OMX_VID_ENC_P_PERIOD_DEFAULT
;
630 priv
->stacked_frames_num
= 1;
632 priv
->codec
= priv
->s_pipe
->create_video_codec(priv
->s_pipe
, &templat
);
634 } else if ((msg
->messageParam
== OMX_StateLoaded
) && (priv
->state
== OMX_StateIdle
)) {
636 priv
->codec
->destroy(priv
->codec
);
642 return omx_base_component_MessageHandler(comp
, msg
);
645 static OMX_ERRORTYPE
vid_enc_AllocateInBuffer(omx_base_PortType
*port
, OMX_INOUT OMX_BUFFERHEADERTYPE
**buf
,
646 OMX_IN OMX_U32 idx
, OMX_IN OMX_PTR
private, OMX_IN OMX_U32 size
)
648 struct input_buf_private
*inp
;
651 r
= base_port_AllocateBuffer(port
, buf
, idx
, private, size
);
655 inp
= (*buf
)->pInputPortPrivate
= CALLOC_STRUCT(input_buf_private
);
657 base_port_FreeBuffer(port
, idx
, *buf
);
658 return OMX_ErrorInsufficientResources
;
661 LIST_INITHEAD(&inp
->tasks
);
663 FREE((*buf
)->pBuffer
);
664 r
= enc_AllocateBackTexture(port
, &inp
->resource
, &inp
->transfer
, &(*buf
)->pBuffer
);
667 base_port_FreeBuffer(port
, idx
, *buf
);
671 return OMX_ErrorNone
;
674 static OMX_ERRORTYPE
vid_enc_UseInBuffer(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
**buf
, OMX_U32 idx
,
675 OMX_PTR
private, OMX_U32 size
, OMX_U8
*mem
)
677 struct input_buf_private
*inp
;
680 r
= base_port_UseBuffer(port
, buf
, idx
, private, size
, mem
);
684 inp
= (*buf
)->pInputPortPrivate
= CALLOC_STRUCT(input_buf_private
);
686 base_port_FreeBuffer(port
, idx
, *buf
);
687 return OMX_ErrorInsufficientResources
;
690 LIST_INITHEAD(&inp
->tasks
);
692 return OMX_ErrorNone
;
695 static OMX_ERRORTYPE
vid_enc_FreeInBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
)
697 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
698 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
699 struct input_buf_private
*inp
= buf
->pInputPortPrivate
;
702 enc_ReleaseTasks(&inp
->tasks
);
704 pipe_transfer_unmap(priv
->s_pipe
, inp
->transfer
);
705 pipe_resource_reference(&inp
->resource
, NULL
);
710 return base_port_FreeBuffer(port
, idx
, buf
);
713 static OMX_ERRORTYPE
vid_enc_AllocateOutBuffer(omx_base_PortType
*port
, OMX_INOUT OMX_BUFFERHEADERTYPE
**buf
,
714 OMX_IN OMX_U32 idx
, OMX_IN OMX_PTR
private, OMX_IN OMX_U32 size
)
718 r
= base_port_AllocateBuffer(port
, buf
, idx
, private, size
);
722 FREE((*buf
)->pBuffer
);
723 (*buf
)->pBuffer
= NULL
;
724 (*buf
)->pOutputPortPrivate
= CALLOC(1, sizeof(struct output_buf_private
));
725 if (!(*buf
)->pOutputPortPrivate
) {
726 base_port_FreeBuffer(port
, idx
, *buf
);
727 return OMX_ErrorInsufficientResources
;
730 return OMX_ErrorNone
;
733 static OMX_ERRORTYPE
vid_enc_FreeOutBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
)
735 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
736 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
738 if (buf
->pOutputPortPrivate
) {
739 struct output_buf_private
*outp
= buf
->pOutputPortPrivate
;
741 pipe_transfer_unmap(priv
->t_pipe
, outp
->transfer
);
742 pipe_resource_reference(&outp
->bitstream
, NULL
);
744 buf
->pOutputPortPrivate
= NULL
;
748 return base_port_FreeBuffer(port
, idx
, buf
);
751 static struct encode_task
*enc_NeedTask(omx_base_PortType
*port
)
753 OMX_VIDEO_PORTDEFINITIONTYPE
*def
= &port
->sPortParam
.format
.video
;
754 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
755 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
757 return enc_NeedTask_common(priv
, def
);
760 static OMX_ERRORTYPE
enc_LoadImage(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
*buf
,
761 struct pipe_video_buffer
*vbuf
)
763 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
764 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
765 OMX_VIDEO_PORTDEFINITIONTYPE
*def
= &port
->sPortParam
.format
.video
;
766 return enc_LoadImage_common(priv
, def
, buf
, vbuf
);
769 static void enc_ScaleInput(omx_base_PortType
*port
, struct pipe_video_buffer
**vbuf
, unsigned *size
)
771 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
772 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
773 OMX_VIDEO_PORTDEFINITIONTYPE
*def
= &port
->sPortParam
.format
.video
;
774 enc_ScaleInput_common(priv
, def
, vbuf
, size
);
777 static void enc_ControlPicture(omx_base_PortType
*port
, struct pipe_h264_enc_picture_desc
*picture
)
779 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
780 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
781 enc_ControlPicture_common(priv
, picture
);
784 static void enc_HandleTask(omx_base_PortType
*port
, struct encode_task
*task
,
785 enum pipe_h264_enc_picture_type picture_type
)
787 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
788 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
789 unsigned size
= priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
]->sPortParam
.nBufferSize
;
790 struct pipe_video_buffer
*vbuf
= task
->buf
;
791 struct pipe_h264_enc_picture_desc picture
= {};
793 /* -------------- scale input image --------- */
794 enc_ScaleInput(port
, &vbuf
, &size
);
795 priv
->s_pipe
->flush(priv
->s_pipe
, NULL
, 0);
797 /* -------------- allocate output buffer --------- */
798 task
->bitstream
= pipe_buffer_create(priv
->s_pipe
->screen
,
799 PIPE_BIND_VERTEX_BUFFER
,
800 PIPE_USAGE_STAGING
, /* map for read */
803 picture
.picture_type
= picture_type
;
804 picture
.pic_order_cnt
= task
->pic_order_cnt
;
805 picture
.base
.profile
= enc_TranslateOMXProfileToPipe(priv
->profile_level
.eProfile
);
806 picture
.base
.entry_point
= PIPE_VIDEO_ENTRYPOINT_ENCODE
;
807 if (priv
->restricted_b_frames
&& picture_type
== PIPE_H264_ENC_PICTURE_TYPE_B
)
808 picture
.not_referenced
= true;
809 enc_ControlPicture(port
, &picture
);
811 /* -------------- encode frame --------- */
812 priv
->codec
->begin_frame(priv
->codec
, vbuf
, &picture
.base
);
813 priv
->codec
->encode_bitstream(priv
->codec
, vbuf
, task
->bitstream
, &task
->feedback
);
814 priv
->codec
->end_frame(priv
->codec
, vbuf
, &picture
.base
);
817 static void enc_ClearBframes(omx_base_PortType
*port
, struct input_buf_private
*inp
)
819 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
820 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
821 struct encode_task
*task
;
823 if (LIST_IS_EMPTY(&priv
->b_frames
))
826 task
= LIST_ENTRY(struct encode_task
, priv
->b_frames
.prev
, list
);
827 LIST_DEL(&task
->list
);
829 /* promote last from to P frame */
830 priv
->ref_idx_l0
= priv
->ref_idx_l1
;
831 enc_HandleTask(port
, task
, PIPE_H264_ENC_PICTURE_TYPE_P
);
832 LIST_ADDTAIL(&task
->list
, &inp
->tasks
);
833 priv
->ref_idx_l1
= priv
->frame_num
++;
835 /* handle B frames */
836 LIST_FOR_EACH_ENTRY(task
, &priv
->b_frames
, list
) {
837 enc_HandleTask(port
, task
, PIPE_H264_ENC_PICTURE_TYPE_B
);
838 if (!priv
->restricted_b_frames
)
839 priv
->ref_idx_l0
= priv
->frame_num
;
843 enc_MoveTasks(&priv
->b_frames
, &inp
->tasks
);
846 static OMX_ERRORTYPE
vid_enc_EncodeFrame(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
*buf
)
848 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
849 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
850 struct input_buf_private
*inp
= buf
->pInputPortPrivate
;
851 enum pipe_h264_enc_picture_type picture_type
;
852 struct encode_task
*task
;
853 unsigned stacked_num
= 0;
856 enc_MoveTasks(&inp
->tasks
, &priv
->free_tasks
);
857 task
= enc_NeedTask(port
);
859 return OMX_ErrorInsufficientResources
;
861 if (buf
->nFilledLen
== 0) {
862 if (buf
->nFlags
& OMX_BUFFERFLAG_EOS
) {
863 buf
->nFilledLen
= buf
->nAllocLen
;
864 enc_ClearBframes(port
, inp
);
865 enc_MoveTasks(&priv
->stacked_tasks
, &inp
->tasks
);
866 priv
->codec
->flush(priv
->codec
);
868 return base_port_SendBufferFunction(port
, buf
);
871 if (buf
->pOutputPortPrivate
) {
872 struct pipe_video_buffer
*vbuf
= buf
->pOutputPortPrivate
;
873 buf
->pOutputPortPrivate
= task
->buf
;
876 /* ------- load input image into video buffer ---- */
877 err
= enc_LoadImage(port
, buf
, task
->buf
);
878 if (err
!= OMX_ErrorNone
) {
884 /* -------------- determine picture type --------- */
885 if (!(priv
->pic_order_cnt
% OMX_VID_ENC_IDR_PERIOD_DEFAULT
) ||
886 priv
->force_pic_type
.IntraRefreshVOP
) {
887 enc_ClearBframes(port
, inp
);
888 picture_type
= PIPE_H264_ENC_PICTURE_TYPE_IDR
;
889 priv
->force_pic_type
.IntraRefreshVOP
= OMX_FALSE
;
891 } else if (priv
->codec
->profile
== PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE
||
892 !(priv
->pic_order_cnt
% OMX_VID_ENC_P_PERIOD_DEFAULT
) ||
893 (buf
->nFlags
& OMX_BUFFERFLAG_EOS
)) {
894 picture_type
= PIPE_H264_ENC_PICTURE_TYPE_P
;
896 picture_type
= PIPE_H264_ENC_PICTURE_TYPE_B
;
899 task
->pic_order_cnt
= priv
->pic_order_cnt
++;
901 if (picture_type
== PIPE_H264_ENC_PICTURE_TYPE_B
) {
902 /* put frame at the tail of the queue */
903 LIST_ADDTAIL(&task
->list
, &priv
->b_frames
);
905 /* handle I or P frame */
906 priv
->ref_idx_l0
= priv
->ref_idx_l1
;
907 enc_HandleTask(port
, task
, picture_type
);
908 LIST_ADDTAIL(&task
->list
, &priv
->stacked_tasks
);
909 LIST_FOR_EACH_ENTRY(task
, &priv
->stacked_tasks
, list
) {
912 if (stacked_num
== priv
->stacked_frames_num
) {
913 struct encode_task
*t
;
914 t
= LIST_ENTRY(struct encode_task
, priv
->stacked_tasks
.next
, list
);
916 LIST_ADDTAIL(&t
->list
, &inp
->tasks
);
918 priv
->ref_idx_l1
= priv
->frame_num
++;
920 /* handle B frames */
921 LIST_FOR_EACH_ENTRY(task
, &priv
->b_frames
, list
) {
922 enc_HandleTask(port
, task
, PIPE_H264_ENC_PICTURE_TYPE_B
);
923 if (!priv
->restricted_b_frames
)
924 priv
->ref_idx_l0
= priv
->frame_num
;
928 enc_MoveTasks(&priv
->b_frames
, &inp
->tasks
);
931 if (LIST_IS_EMPTY(&inp
->tasks
))
932 return port
->ReturnBufferFunction(port
, buf
);
934 return base_port_SendBufferFunction(port
, buf
);
937 static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE
*comp
, OMX_BUFFERHEADERTYPE
* input
, OMX_BUFFERHEADERTYPE
* output
)
939 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
940 vid_enc_BufferEncoded_common(priv
, input
, output
);