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 "vl/vl_video_buffer.h"
54 #include "entrypoint.h"
58 struct list_head list
;
60 struct pipe_video_buffer
*buf
;
61 unsigned pic_order_cnt
;
62 struct pipe_resource
*bitstream
;
66 struct input_buf_private
{
67 struct list_head tasks
;
69 struct pipe_resource
*resource
;
70 struct pipe_transfer
*transfer
;
73 struct output_buf_private
{
74 struct pipe_resource
*bitstream
;
75 struct pipe_transfer
*transfer
;
78 static OMX_ERRORTYPE
vid_enc_Constructor(OMX_COMPONENTTYPE
*comp
, OMX_STRING name
);
79 static OMX_ERRORTYPE
vid_enc_Destructor(OMX_COMPONENTTYPE
*comp
);
80 static OMX_ERRORTYPE
vid_enc_SetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
);
81 static OMX_ERRORTYPE
vid_enc_GetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
);
82 static OMX_ERRORTYPE
vid_enc_SetConfig(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR config
);
83 static OMX_ERRORTYPE
vid_enc_GetConfig(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR config
);
84 static OMX_ERRORTYPE
vid_enc_MessageHandler(OMX_COMPONENTTYPE
*comp
, internalRequestMessageType
*msg
);
85 static OMX_ERRORTYPE
vid_enc_AllocateInBuffer(omx_base_PortType
*port
, OMX_INOUT OMX_BUFFERHEADERTYPE
**buf
,
86 OMX_IN OMX_U32 idx
, OMX_IN OMX_PTR
private, OMX_IN OMX_U32 size
);
87 static OMX_ERRORTYPE
vid_enc_UseInBuffer(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
**buf
, OMX_U32 idx
,
88 OMX_PTR
private, OMX_U32 size
, OMX_U8
*mem
);
89 static OMX_ERRORTYPE
vid_enc_FreeInBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
);
90 static OMX_ERRORTYPE
vid_enc_EncodeFrame(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
*buf
);
91 static OMX_ERRORTYPE
vid_enc_AllocateOutBuffer(omx_base_PortType
*comp
, OMX_INOUT OMX_BUFFERHEADERTYPE
**buf
,
92 OMX_IN OMX_U32 idx
, OMX_IN OMX_PTR
private, OMX_IN OMX_U32 size
);
93 static OMX_ERRORTYPE
vid_enc_FreeOutBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
);
94 static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE
*comp
, OMX_BUFFERHEADERTYPE
* input
, OMX_BUFFERHEADERTYPE
* output
);
96 static void enc_ReleaseTasks(struct list_head
*head
);
98 OMX_ERRORTYPE
vid_enc_LoaderComponent(stLoaderComponentType
*comp
)
100 comp
->componentVersion
.s
.nVersionMajor
= 0;
101 comp
->componentVersion
.s
.nVersionMinor
= 0;
102 comp
->componentVersion
.s
.nRevision
= 0;
103 comp
->componentVersion
.s
.nStep
= 1;
104 comp
->name_specific_length
= 1;
105 comp
->constructor
= vid_enc_Constructor
;
107 comp
->name
= CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
109 return OMX_ErrorInsufficientResources
;
111 comp
->name_specific
= CALLOC(1, sizeof(char *));
112 if (!comp
->name_specific
)
115 comp
->role_specific
= CALLOC(1, sizeof(char *));
116 if (!comp
->role_specific
)
119 comp
->name_specific
[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
120 if (comp
->name_specific
[0] == NULL
)
123 comp
->role_specific
[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
124 if (comp
->role_specific
[0] == NULL
)
127 strcpy(comp
->name
, OMX_VID_ENC_BASE_NAME
);
128 strcpy(comp
->name_specific
[0], OMX_VID_ENC_AVC_NAME
);
129 strcpy(comp
->role_specific
[0], OMX_VID_ENC_AVC_ROLE
);
131 return OMX_ErrorNone
;
134 FREE(comp
->role_specific
[0]);
135 FREE(comp
->name_specific
[0]);
138 FREE(comp
->role_specific
);
139 FREE(comp
->name_specific
);
143 return OMX_ErrorInsufficientResources
;
146 static OMX_ERRORTYPE
vid_enc_Constructor(OMX_COMPONENTTYPE
*comp
, OMX_STRING name
)
148 vid_enc_PrivateType
*priv
;
149 omx_base_video_PortType
*port
;
150 struct pipe_screen
*screen
;
154 assert(!comp
->pComponentPrivate
);
156 priv
= comp
->pComponentPrivate
= CALLOC(1, sizeof(vid_enc_PrivateType
));
158 return OMX_ErrorInsufficientResources
;
160 r
= omx_base_filter_Constructor(comp
, name
);
164 priv
->BufferMgmtCallback
= vid_enc_BufferEncoded
;
165 priv
->messageHandler
= vid_enc_MessageHandler
;
166 priv
->destructor
= vid_enc_Destructor
;
168 comp
->SetParameter
= vid_enc_SetParameter
;
169 comp
->GetParameter
= vid_enc_GetParameter
;
170 comp
->GetConfig
= vid_enc_GetConfig
;
171 comp
->SetConfig
= vid_enc_SetConfig
;
173 priv
->screen
= omx_get_screen();
175 return OMX_ErrorInsufficientResources
;
177 screen
= priv
->screen
->pscreen
;
178 if (!screen
->get_video_param(screen
, PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
,
179 PIPE_VIDEO_ENTRYPOINT_ENCODE
, PIPE_VIDEO_CAP_SUPPORTED
))
180 return OMX_ErrorBadParameter
;
182 priv
->s_pipe
= screen
->context_create(screen
, NULL
, 0);
184 return OMX_ErrorInsufficientResources
;
186 if (!vl_compositor_init(&priv
->compositor
, priv
->s_pipe
)) {
187 priv
->s_pipe
->destroy(priv
->s_pipe
);
189 return OMX_ErrorInsufficientResources
;
192 if (!vl_compositor_init_state(&priv
->cstate
, priv
->s_pipe
)) {
193 vl_compositor_cleanup(&priv
->compositor
);
194 priv
->s_pipe
->destroy(priv
->s_pipe
);
196 return OMX_ErrorInsufficientResources
;
199 priv
->t_pipe
= screen
->context_create(screen
, NULL
, 0);
201 return OMX_ErrorInsufficientResources
;
203 priv
->sPortTypesParam
[OMX_PortDomainVideo
].nStartPortNumber
= 0;
204 priv
->sPortTypesParam
[OMX_PortDomainVideo
].nPorts
= 2;
205 priv
->ports
= CALLOC(2, sizeof(omx_base_PortType
*));
207 return OMX_ErrorInsufficientResources
;
209 for (i
= 0; i
< 2; ++i
) {
210 priv
->ports
[i
] = CALLOC(1, sizeof(omx_base_video_PortType
));
212 return OMX_ErrorInsufficientResources
;
214 base_video_port_Constructor(comp
, &priv
->ports
[i
], i
, i
== 0);
217 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
218 port
->sPortParam
.format
.video
.nFrameWidth
= 176;
219 port
->sPortParam
.format
.video
.nFrameHeight
= 144;
220 port
->sPortParam
.format
.video
.eColorFormat
= OMX_COLOR_FormatYUV420SemiPlanar
;
221 port
->sVideoParam
.eColorFormat
= OMX_COLOR_FormatYUV420SemiPlanar
;
222 port
->sPortParam
.nBufferCountActual
= 8;
223 port
->sPortParam
.nBufferCountMin
= 4;
225 port
->Port_SendBufferFunction
= vid_enc_EncodeFrame
;
226 port
->Port_AllocateBuffer
= vid_enc_AllocateInBuffer
;
227 port
->Port_UseBuffer
= vid_enc_UseInBuffer
;
228 port
->Port_FreeBuffer
= vid_enc_FreeInBuffer
;
230 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
];
231 strcpy(port
->sPortParam
.format
.video
.cMIMEType
,"video/H264");
232 port
->sPortParam
.format
.video
.nFrameWidth
= 176;
233 port
->sPortParam
.format
.video
.nFrameHeight
= 144;
234 port
->sPortParam
.format
.video
.eCompressionFormat
= OMX_VIDEO_CodingAVC
;
235 port
->sVideoParam
.eCompressionFormat
= OMX_VIDEO_CodingAVC
;
237 port
->Port_AllocateBuffer
= vid_enc_AllocateOutBuffer
;
238 port
->Port_FreeBuffer
= vid_enc_FreeOutBuffer
;
240 priv
->bitrate
.eControlRate
= OMX_Video_ControlRateDisable
;
241 priv
->bitrate
.nTargetBitrate
= 0;
243 priv
->quant
.nQpI
= OMX_VID_ENC_QUANT_I_FRAMES_DEFAULT
;
244 priv
->quant
.nQpP
= OMX_VID_ENC_QUANT_P_FRAMES_DEFAULT
;
245 priv
->quant
.nQpB
= OMX_VID_ENC_QUANT_B_FRAMES_DEFAULT
;
247 priv
->profile_level
.eProfile
= OMX_VIDEO_AVCProfileBaseline
;
248 priv
->profile_level
.eLevel
= OMX_VIDEO_AVCLevel51
;
250 priv
->force_pic_type
.IntraRefreshVOP
= OMX_FALSE
;
252 priv
->pic_order_cnt
= 0;
253 priv
->restricted_b_frames
= debug_get_bool_option("OMX_USE_RESTRICTED_B_FRAMES", FALSE
);
255 priv
->scale
.xWidth
= OMX_VID_ENC_SCALING_WIDTH_DEFAULT
;
256 priv
->scale
.xHeight
= OMX_VID_ENC_SCALING_WIDTH_DEFAULT
;
258 LIST_INITHEAD(&priv
->free_tasks
);
259 LIST_INITHEAD(&priv
->used_tasks
);
260 LIST_INITHEAD(&priv
->b_frames
);
261 LIST_INITHEAD(&priv
->stacked_tasks
);
263 return OMX_ErrorNone
;
266 static OMX_ERRORTYPE
vid_enc_Destructor(OMX_COMPONENTTYPE
*comp
)
268 vid_enc_PrivateType
* priv
= comp
->pComponentPrivate
;
271 enc_ReleaseTasks(&priv
->free_tasks
);
272 enc_ReleaseTasks(&priv
->used_tasks
);
273 enc_ReleaseTasks(&priv
->b_frames
);
274 enc_ReleaseTasks(&priv
->stacked_tasks
);
277 for (i
= 0; i
< priv
->sPortTypesParam
[OMX_PortDomainVideo
].nPorts
; ++i
) {
279 priv
->ports
[i
]->PortDestructor(priv
->ports
[i
]);
285 for (i
= 0; i
< OMX_VID_ENC_NUM_SCALING_BUFFERS
; ++i
)
286 if (priv
->scale_buffer
[i
])
287 priv
->scale_buffer
[i
]->destroy(priv
->scale_buffer
[i
]);
290 vl_compositor_cleanup_state(&priv
->cstate
);
291 vl_compositor_cleanup(&priv
->compositor
);
292 priv
->s_pipe
->destroy(priv
->s_pipe
);
296 priv
->t_pipe
->destroy(priv
->t_pipe
);
301 return omx_workaround_Destructor(comp
);
304 static OMX_ERRORTYPE
enc_AllocateBackTexture(omx_base_PortType
*port
,
305 struct pipe_resource
**resource
,
306 struct pipe_transfer
**transfer
,
309 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
310 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
311 struct pipe_resource buf_templ
;
312 struct pipe_box box
= {};
315 memset(&buf_templ
, 0, sizeof buf_templ
);
316 buf_templ
.target
= PIPE_TEXTURE_2D
;
317 buf_templ
.format
= PIPE_FORMAT_I8_UNORM
;
318 buf_templ
.bind
= PIPE_BIND_LINEAR
;
319 buf_templ
.usage
= PIPE_USAGE_STAGING
;
321 buf_templ
.width0
= port
->sPortParam
.format
.video
.nFrameWidth
;
322 buf_templ
.height0
= port
->sPortParam
.format
.video
.nFrameHeight
* 3 / 2;
323 buf_templ
.depth0
= 1;
324 buf_templ
.array_size
= 1;
326 *resource
= priv
->s_pipe
->screen
->resource_create(priv
->s_pipe
->screen
, &buf_templ
);
328 return OMX_ErrorInsufficientResources
;
330 box
.width
= (*resource
)->width0
;
331 box
.height
= (*resource
)->height0
;
332 box
.depth
= (*resource
)->depth0
;
333 ptr
= priv
->s_pipe
->transfer_map(priv
->s_pipe
, *resource
, 0, PIPE_TRANSFER_WRITE
, &box
, transfer
);
337 return OMX_ErrorNone
;
340 static OMX_ERRORTYPE
vid_enc_SetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
)
342 OMX_COMPONENTTYPE
*comp
= handle
;
343 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
347 return OMX_ErrorBadParameter
;
350 case OMX_IndexParamPortDefinition
: {
351 OMX_PARAM_PORTDEFINITIONTYPE
*def
= param
;
353 r
= omx_base_component_SetParameter(handle
, idx
, param
);
357 if (def
->nPortIndex
== OMX_BASE_FILTER_INPUTPORT_INDEX
) {
358 omx_base_video_PortType
*port
;
360 struct pipe_resource
*resource
;
361 struct pipe_transfer
*transfer
;
363 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
364 enc_AllocateBackTexture(priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
],
365 &resource
, &transfer
, NULL
);
366 port
->sPortParam
.format
.video
.nStride
= transfer
->stride
;
367 pipe_transfer_unmap(priv
->s_pipe
, transfer
);
368 pipe_resource_reference(&resource
, NULL
);
370 framesize
= port
->sPortParam
.format
.video
.nStride
*
371 port
->sPortParam
.format
.video
.nFrameHeight
;
372 port
->sPortParam
.format
.video
.nSliceHeight
= port
->sPortParam
.format
.video
.nFrameHeight
;
373 port
->sPortParam
.nBufferSize
= framesize
* 3 / 2;
375 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
];
376 port
->sPortParam
.nBufferSize
= framesize
* 512 / (16*16);
378 priv
->frame_rate
= def
->format
.video
.xFramerate
;
380 priv
->callbacks
->EventHandler(comp
, priv
->callbackData
, OMX_EventPortSettingsChanged
,
381 OMX_BASE_FILTER_OUTPUTPORT_INDEX
, 0, NULL
);
385 case OMX_IndexParamStandardComponentRole
: {
386 OMX_PARAM_COMPONENTROLETYPE
*role
= param
;
388 r
= checkHeader(param
, sizeof(OMX_PARAM_COMPONENTROLETYPE
));
392 if (strcmp((char *)role
->cRole
, OMX_VID_ENC_AVC_ROLE
)) {
393 return OMX_ErrorBadParameter
;
398 case OMX_IndexParamVideoBitrate
: {
399 OMX_VIDEO_PARAM_BITRATETYPE
*bitrate
= param
;
401 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_BITRATETYPE
));
405 priv
->bitrate
= *bitrate
;
409 case OMX_IndexParamVideoQuantization
: {
410 OMX_VIDEO_PARAM_QUANTIZATIONTYPE
*quant
= param
;
412 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE
));
416 priv
->quant
= *quant
;
420 case OMX_IndexParamVideoProfileLevelCurrent
: {
421 OMX_VIDEO_PARAM_PROFILELEVELTYPE
*profile_level
= param
;
423 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE
));
427 priv
->profile_level
= *profile_level
;
432 return omx_base_component_SetParameter(handle
, idx
, param
);
434 return OMX_ErrorNone
;
437 static OMX_ERRORTYPE
vid_enc_GetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
)
439 OMX_COMPONENTTYPE
*comp
= handle
;
440 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
444 return OMX_ErrorBadParameter
;
447 case OMX_IndexParamStandardComponentRole
: {
448 OMX_PARAM_COMPONENTROLETYPE
*role
= param
;
450 r
= checkHeader(param
, sizeof(OMX_PARAM_COMPONENTROLETYPE
));
454 strcpy((char *)role
->cRole
, OMX_VID_ENC_AVC_ROLE
);
457 case OMX_IndexParamVideoInit
:
458 r
= checkHeader(param
, sizeof(OMX_PORT_PARAM_TYPE
));
462 memcpy(param
, &priv
->sPortTypesParam
[OMX_PortDomainVideo
], sizeof(OMX_PORT_PARAM_TYPE
));
465 case OMX_IndexParamVideoPortFormat
: {
466 OMX_VIDEO_PARAM_PORTFORMATTYPE
*format
= param
;
467 omx_base_video_PortType
*port
;
469 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
473 if (format
->nPortIndex
> 1)
474 return OMX_ErrorBadPortIndex
;
475 if (format
->nIndex
>= 1)
476 return OMX_ErrorNoMore
;
478 port
= (omx_base_video_PortType
*)priv
->ports
[format
->nPortIndex
];
479 memcpy(format
, &port
->sVideoParam
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
482 case OMX_IndexParamVideoBitrate
: {
483 OMX_VIDEO_PARAM_BITRATETYPE
*bitrate
= param
;
485 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_BITRATETYPE
));
489 bitrate
->eControlRate
= priv
->bitrate
.eControlRate
;
490 bitrate
->nTargetBitrate
= priv
->bitrate
.nTargetBitrate
;
494 case OMX_IndexParamVideoQuantization
: {
495 OMX_VIDEO_PARAM_QUANTIZATIONTYPE
*quant
= param
;
497 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE
));
501 quant
->nQpI
= priv
->quant
.nQpI
;
502 quant
->nQpP
= priv
->quant
.nQpP
;
503 quant
->nQpB
= priv
->quant
.nQpB
;
507 case OMX_IndexParamVideoProfileLevelCurrent
: {
508 OMX_VIDEO_PARAM_PROFILELEVELTYPE
*profile_level
= param
;
510 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE
));
514 profile_level
->eProfile
= priv
->profile_level
.eProfile
;
515 profile_level
->eLevel
= priv
->profile_level
.eLevel
;
520 return omx_base_component_GetParameter(handle
, idx
, param
);
522 return OMX_ErrorNone
;
525 static OMX_ERRORTYPE
vid_enc_SetConfig(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR config
)
527 OMX_COMPONENTTYPE
*comp
= handle
;
528 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
533 return OMX_ErrorBadParameter
;
536 case OMX_IndexConfigVideoIntraVOPRefresh
: {
537 OMX_CONFIG_INTRAREFRESHVOPTYPE
*type
= config
;
539 r
= checkHeader(config
, sizeof(OMX_CONFIG_INTRAREFRESHVOPTYPE
));
543 priv
->force_pic_type
= *type
;
547 case OMX_IndexConfigCommonScale
: {
548 OMX_CONFIG_SCALEFACTORTYPE
*scale
= config
;
550 r
= checkHeader(config
, sizeof(OMX_CONFIG_SCALEFACTORTYPE
));
554 if (scale
->xWidth
< 176 || scale
->xHeight
< 144)
555 return OMX_ErrorBadParameter
;
557 for (i
= 0; i
< OMX_VID_ENC_NUM_SCALING_BUFFERS
; ++i
) {
558 if (priv
->scale_buffer
[i
]) {
559 priv
->scale_buffer
[i
]->destroy(priv
->scale_buffer
[i
]);
560 priv
->scale_buffer
[i
] = NULL
;
564 priv
->scale
= *scale
;
565 if (priv
->scale
.xWidth
!= 0xffffffff && priv
->scale
.xHeight
!= 0xffffffff) {
566 struct pipe_video_buffer templat
= {};
568 templat
.buffer_format
= PIPE_FORMAT_NV12
;
569 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
570 templat
.width
= priv
->scale
.xWidth
;
571 templat
.height
= priv
->scale
.xHeight
;
572 templat
.interlaced
= false;
573 for (i
= 0; i
< OMX_VID_ENC_NUM_SCALING_BUFFERS
; ++i
) {
574 priv
->scale_buffer
[i
] = priv
->s_pipe
->create_video_buffer(priv
->s_pipe
, &templat
);
575 if (!priv
->scale_buffer
[i
])
576 return OMX_ErrorInsufficientResources
;
583 return omx_base_component_SetConfig(handle
, idx
, config
);
586 return OMX_ErrorNone
;
589 static OMX_ERRORTYPE
vid_enc_GetConfig(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR config
)
591 OMX_COMPONENTTYPE
*comp
= handle
;
592 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
596 return OMX_ErrorBadParameter
;
599 case OMX_IndexConfigCommonScale
: {
600 OMX_CONFIG_SCALEFACTORTYPE
*scale
= config
;
602 r
= checkHeader(config
, sizeof(OMX_CONFIG_SCALEFACTORTYPE
));
606 scale
->xWidth
= priv
->scale
.xWidth
;
607 scale
->xHeight
= priv
->scale
.xHeight
;
612 return omx_base_component_GetConfig(handle
, idx
, config
);
615 return OMX_ErrorNone
;
618 static enum pipe_video_profile
enc_TranslateOMXProfileToPipe(unsigned omx_profile
)
620 switch (omx_profile
) {
621 case OMX_VIDEO_AVCProfileBaseline
:
622 return PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE
;
623 case OMX_VIDEO_AVCProfileMain
:
624 return PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN
;
625 case OMX_VIDEO_AVCProfileExtended
:
626 return PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED
;
627 case OMX_VIDEO_AVCProfileHigh
:
628 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
;
629 case OMX_VIDEO_AVCProfileHigh10
:
630 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10
;
631 case OMX_VIDEO_AVCProfileHigh422
:
632 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH422
;
633 case OMX_VIDEO_AVCProfileHigh444
:
634 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH444
;
636 return PIPE_VIDEO_PROFILE_UNKNOWN
;
640 static unsigned enc_TranslateOMXLevelToPipe(unsigned omx_level
)
643 case OMX_VIDEO_AVCLevel1
:
644 case OMX_VIDEO_AVCLevel1b
:
646 case OMX_VIDEO_AVCLevel11
:
648 case OMX_VIDEO_AVCLevel12
:
650 case OMX_VIDEO_AVCLevel13
:
652 case OMX_VIDEO_AVCLevel2
:
654 case OMX_VIDEO_AVCLevel21
:
656 case OMX_VIDEO_AVCLevel22
:
658 case OMX_VIDEO_AVCLevel3
:
660 case OMX_VIDEO_AVCLevel31
:
662 case OMX_VIDEO_AVCLevel32
:
664 case OMX_VIDEO_AVCLevel4
:
666 case OMX_VIDEO_AVCLevel41
:
669 case OMX_VIDEO_AVCLevel42
:
671 case OMX_VIDEO_AVCLevel5
:
673 case OMX_VIDEO_AVCLevel51
:
678 static OMX_ERRORTYPE
vid_enc_MessageHandler(OMX_COMPONENTTYPE
* comp
, internalRequestMessageType
*msg
)
680 vid_enc_PrivateType
* priv
= comp
->pComponentPrivate
;
682 if (msg
->messageType
== OMX_CommandStateSet
) {
683 if ((msg
->messageParam
== OMX_StateIdle
) && (priv
->state
== OMX_StateLoaded
)) {
685 struct pipe_video_codec templat
= {};
686 omx_base_video_PortType
*port
;
688 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
690 templat
.profile
= enc_TranslateOMXProfileToPipe(priv
->profile_level
.eProfile
);
691 templat
.level
= enc_TranslateOMXLevelToPipe(priv
->profile_level
.eLevel
);
692 templat
.entrypoint
= PIPE_VIDEO_ENTRYPOINT_ENCODE
;
693 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
694 templat
.width
= priv
->scale_buffer
[priv
->current_scale_buffer
] ?
695 priv
->scale
.xWidth
: port
->sPortParam
.format
.video
.nFrameWidth
;
696 templat
.height
= priv
->scale_buffer
[priv
->current_scale_buffer
] ?
697 priv
->scale
.xHeight
: port
->sPortParam
.format
.video
.nFrameHeight
;
699 if (templat
.profile
== PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE
) {
700 struct pipe_screen
*screen
= priv
->screen
->pscreen
;
701 templat
.max_references
= 1;
702 priv
->stacked_frames_num
=
703 screen
->get_video_param(screen
,
704 PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
,
705 PIPE_VIDEO_ENTRYPOINT_ENCODE
,
706 PIPE_VIDEO_CAP_STACKED_FRAMES
);
708 templat
.max_references
= OMX_VID_ENC_P_PERIOD_DEFAULT
;
709 priv
->stacked_frames_num
= 1;
711 priv
->codec
= priv
->s_pipe
->create_video_codec(priv
->s_pipe
, &templat
);
713 } else if ((msg
->messageParam
== OMX_StateLoaded
) && (priv
->state
== OMX_StateIdle
)) {
715 priv
->codec
->destroy(priv
->codec
);
721 return omx_base_component_MessageHandler(comp
, msg
);
724 static OMX_ERRORTYPE
vid_enc_AllocateInBuffer(omx_base_PortType
*port
, OMX_INOUT OMX_BUFFERHEADERTYPE
**buf
,
725 OMX_IN OMX_U32 idx
, OMX_IN OMX_PTR
private, OMX_IN OMX_U32 size
)
727 struct input_buf_private
*inp
;
730 r
= base_port_AllocateBuffer(port
, buf
, idx
, private, size
);
734 inp
= (*buf
)->pInputPortPrivate
= CALLOC_STRUCT(input_buf_private
);
736 base_port_FreeBuffer(port
, idx
, *buf
);
737 return OMX_ErrorInsufficientResources
;
740 LIST_INITHEAD(&inp
->tasks
);
742 FREE((*buf
)->pBuffer
);
743 r
= enc_AllocateBackTexture(port
, &inp
->resource
, &inp
->transfer
, &(*buf
)->pBuffer
);
746 base_port_FreeBuffer(port
, idx
, *buf
);
750 return OMX_ErrorNone
;
753 static OMX_ERRORTYPE
vid_enc_UseInBuffer(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
**buf
, OMX_U32 idx
,
754 OMX_PTR
private, OMX_U32 size
, OMX_U8
*mem
)
756 struct input_buf_private
*inp
;
759 r
= base_port_UseBuffer(port
, buf
, idx
, private, size
, mem
);
763 inp
= (*buf
)->pInputPortPrivate
= CALLOC_STRUCT(input_buf_private
);
765 base_port_FreeBuffer(port
, idx
, *buf
);
766 return OMX_ErrorInsufficientResources
;
769 LIST_INITHEAD(&inp
->tasks
);
771 return OMX_ErrorNone
;
774 static OMX_ERRORTYPE
vid_enc_FreeInBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
)
776 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
777 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
778 struct input_buf_private
*inp
= buf
->pInputPortPrivate
;
781 enc_ReleaseTasks(&inp
->tasks
);
783 pipe_transfer_unmap(priv
->s_pipe
, inp
->transfer
);
784 pipe_resource_reference(&inp
->resource
, NULL
);
789 return base_port_FreeBuffer(port
, idx
, buf
);
792 static OMX_ERRORTYPE
vid_enc_AllocateOutBuffer(omx_base_PortType
*port
, OMX_INOUT OMX_BUFFERHEADERTYPE
**buf
,
793 OMX_IN OMX_U32 idx
, OMX_IN OMX_PTR
private, OMX_IN OMX_U32 size
)
797 r
= base_port_AllocateBuffer(port
, buf
, idx
, private, size
);
801 FREE((*buf
)->pBuffer
);
802 (*buf
)->pBuffer
= NULL
;
803 (*buf
)->pOutputPortPrivate
= CALLOC(1, sizeof(struct output_buf_private
));
804 if (!(*buf
)->pOutputPortPrivate
) {
805 base_port_FreeBuffer(port
, idx
, *buf
);
806 return OMX_ErrorInsufficientResources
;
809 return OMX_ErrorNone
;
812 static OMX_ERRORTYPE
vid_enc_FreeOutBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
)
814 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
815 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
817 if (buf
->pOutputPortPrivate
) {
818 struct output_buf_private
*outp
= buf
->pOutputPortPrivate
;
820 pipe_transfer_unmap(priv
->t_pipe
, outp
->transfer
);
821 pipe_resource_reference(&outp
->bitstream
, NULL
);
823 buf
->pOutputPortPrivate
= NULL
;
827 return base_port_FreeBuffer(port
, idx
, buf
);
830 static struct encode_task
*enc_NeedTask(omx_base_PortType
*port
)
832 OMX_VIDEO_PORTDEFINITIONTYPE
*def
= &port
->sPortParam
.format
.video
;
833 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
834 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
836 struct pipe_video_buffer templat
= {};
837 struct encode_task
*task
;
839 if (!LIST_IS_EMPTY(&priv
->free_tasks
)) {
840 task
= LIST_ENTRY(struct encode_task
, priv
->free_tasks
.next
, list
);
841 LIST_DEL(&task
->list
);
845 /* allocate a new one */
846 task
= CALLOC_STRUCT(encode_task
);
850 templat
.buffer_format
= PIPE_FORMAT_NV12
;
851 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
852 templat
.width
= def
->nFrameWidth
;
853 templat
.height
= def
->nFrameHeight
;
854 templat
.interlaced
= false;
856 task
->buf
= priv
->s_pipe
->create_video_buffer(priv
->s_pipe
, &templat
);
865 static void enc_MoveTasks(struct list_head
*from
, struct list_head
*to
)
867 to
->prev
->next
= from
->next
;
868 from
->next
->prev
= to
->prev
;
869 from
->prev
->next
= to
;
870 to
->prev
= from
->prev
;
874 static void enc_ReleaseTasks(struct list_head
*head
)
876 struct encode_task
*i
, *next
;
878 if (!head
|| !head
->next
)
881 LIST_FOR_EACH_ENTRY_SAFE(i
, next
, head
, list
) {
882 pipe_resource_reference(&i
->bitstream
, NULL
);
883 i
->buf
->destroy(i
->buf
);
888 static OMX_ERRORTYPE
enc_LoadImage(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
*buf
,
889 struct pipe_video_buffer
*vbuf
)
891 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
892 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
893 OMX_VIDEO_PORTDEFINITIONTYPE
*def
= &port
->sPortParam
.format
.video
;
894 struct pipe_box box
= {};
895 struct input_buf_private
*inp
= buf
->pInputPortPrivate
;
897 if (!inp
->resource
) {
898 struct pipe_sampler_view
**views
;
901 views
= vbuf
->get_sampler_view_planes(vbuf
);
903 return OMX_ErrorInsufficientResources
;
906 box
.width
= def
->nFrameWidth
;
907 box
.height
= def
->nFrameHeight
;
909 priv
->s_pipe
->texture_subdata(priv
->s_pipe
, views
[0]->texture
, 0,
910 PIPE_TRANSFER_WRITE
, &box
,
911 ptr
, def
->nStride
, 0);
912 ptr
= ((uint8_t*)buf
->pBuffer
) + (def
->nStride
* box
.height
);
913 box
.width
= def
->nFrameWidth
/ 2;
914 box
.height
= def
->nFrameHeight
/ 2;
916 priv
->s_pipe
->texture_subdata(priv
->s_pipe
, views
[1]->texture
, 0,
917 PIPE_TRANSFER_WRITE
, &box
,
918 ptr
, def
->nStride
, 0);
920 struct pipe_blit_info blit
;
921 struct vl_video_buffer
*dst_buf
= (struct vl_video_buffer
*)vbuf
;
923 pipe_transfer_unmap(priv
->s_pipe
, inp
->transfer
);
925 box
.width
= def
->nFrameWidth
;
926 box
.height
= def
->nFrameHeight
;
929 priv
->s_pipe
->resource_copy_region(priv
->s_pipe
,
930 dst_buf
->resources
[0],
931 0, 0, 0, 0, inp
->resource
, 0, &box
);
933 memset(&blit
, 0, sizeof(blit
));
934 blit
.src
.resource
= inp
->resource
;
935 blit
.src
.format
= inp
->resource
->format
;
938 blit
.src
.box
.y
= def
->nFrameHeight
;
939 blit
.src
.box
.width
= def
->nFrameWidth
;
940 blit
.src
.box
.height
= def
->nFrameHeight
/ 2 ;
941 blit
.src
.box
.depth
= 1;
943 blit
.dst
.resource
= dst_buf
->resources
[1];
944 blit
.dst
.format
= blit
.dst
.resource
->format
;
946 blit
.dst
.box
.width
= def
->nFrameWidth
/ 2;
947 blit
.dst
.box
.height
= def
->nFrameHeight
/ 2;
948 blit
.dst
.box
.depth
= 1;
949 blit
.filter
= PIPE_TEX_FILTER_NEAREST
;
951 blit
.mask
= PIPE_MASK_G
;
952 priv
->s_pipe
->blit(priv
->s_pipe
, &blit
);
955 blit
.mask
= PIPE_MASK_R
;
956 priv
->s_pipe
->blit(priv
->s_pipe
, &blit
);
957 priv
->s_pipe
->flush(priv
->s_pipe
, NULL
, 0);
959 box
.width
= inp
->resource
->width0
;
960 box
.height
= inp
->resource
->height0
;
961 box
.depth
= inp
->resource
->depth0
;
962 buf
->pBuffer
= priv
->s_pipe
->transfer_map(priv
->s_pipe
, inp
->resource
, 0,
963 PIPE_TRANSFER_WRITE
, &box
,
967 return OMX_ErrorNone
;
970 static void enc_ScaleInput(omx_base_PortType
*port
, struct pipe_video_buffer
**vbuf
, unsigned *size
)
972 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
973 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
974 OMX_VIDEO_PORTDEFINITIONTYPE
*def
= &port
->sPortParam
.format
.video
;
975 struct pipe_video_buffer
*src_buf
= *vbuf
;
976 struct vl_compositor
*compositor
= &priv
->compositor
;
977 struct vl_compositor_state
*s
= &priv
->cstate
;
978 struct pipe_sampler_view
**views
;
979 struct pipe_surface
**dst_surface
;
982 if (!priv
->scale_buffer
[priv
->current_scale_buffer
])
985 views
= src_buf
->get_sampler_view_planes(src_buf
);
986 dst_surface
= priv
->scale_buffer
[priv
->current_scale_buffer
]->get_surfaces
987 (priv
->scale_buffer
[priv
->current_scale_buffer
]);
988 vl_compositor_clear_layers(s
);
990 for (i
= 0; i
< VL_MAX_SURFACES
; ++i
) {
991 struct u_rect src_rect
;
992 if (!views
[i
] || !dst_surface
[i
])
996 src_rect
.x1
= def
->nFrameWidth
;
997 src_rect
.y1
= def
->nFrameHeight
;
1002 vl_compositor_set_rgba_layer(s
, compositor
, 0, views
[i
], &src_rect
, NULL
, NULL
);
1003 vl_compositor_render(s
, compositor
, dst_surface
[i
], NULL
, false);
1005 *size
= priv
->scale
.xWidth
* priv
->scale
.xHeight
* 2;
1006 *vbuf
= priv
->scale_buffer
[priv
->current_scale_buffer
++];
1007 priv
->current_scale_buffer
%= OMX_VID_ENC_NUM_SCALING_BUFFERS
;
1010 static void enc_GetPictureParamPreset(struct pipe_h264_enc_picture_desc
*picture
)
1012 picture
->motion_est
.enc_disable_sub_mode
= 0x000000fe;
1013 picture
->motion_est
.enc_ime2_search_range_x
= 0x00000001;
1014 picture
->motion_est
.enc_ime2_search_range_y
= 0x00000001;
1015 picture
->pic_ctrl
.enc_constraint_set_flags
= 0x00000040;
1018 static void enc_ControlPicture(omx_base_PortType
*port
, struct pipe_h264_enc_picture_desc
*picture
)
1020 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
1021 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
1022 struct pipe_h264_enc_rate_control
*rate_ctrl
= &picture
->rate_ctrl
;
1024 switch (priv
->bitrate
.eControlRate
) {
1025 case OMX_Video_ControlRateVariable
:
1026 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE
;
1028 case OMX_Video_ControlRateConstant
:
1029 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT
;
1031 case OMX_Video_ControlRateVariableSkipFrames
:
1032 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP
;
1034 case OMX_Video_ControlRateConstantSkipFrames
:
1035 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP
;
1038 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_DISABLE
;
1042 rate_ctrl
->frame_rate_den
= OMX_VID_ENC_CONTROL_FRAME_RATE_DEN_DEFAULT
;
1043 rate_ctrl
->frame_rate_num
= ((priv
->frame_rate
) >> 16) * rate_ctrl
->frame_rate_den
;
1045 if (rate_ctrl
->rate_ctrl_method
!= PIPE_H264_ENC_RATE_CONTROL_METHOD_DISABLE
) {
1046 if (priv
->bitrate
.nTargetBitrate
< OMX_VID_ENC_BITRATE_MIN
)
1047 rate_ctrl
->target_bitrate
= OMX_VID_ENC_BITRATE_MIN
;
1048 else if (priv
->bitrate
.nTargetBitrate
< OMX_VID_ENC_BITRATE_MAX
)
1049 rate_ctrl
->target_bitrate
= priv
->bitrate
.nTargetBitrate
;
1051 rate_ctrl
->target_bitrate
= OMX_VID_ENC_BITRATE_MAX
;
1052 rate_ctrl
->peak_bitrate
= rate_ctrl
->target_bitrate
;
1053 if (rate_ctrl
->target_bitrate
< OMX_VID_ENC_BITRATE_MEDIAN
)
1054 rate_ctrl
->vbv_buffer_size
= MIN2((rate_ctrl
->target_bitrate
* 2.75), OMX_VID_ENC_BITRATE_MEDIAN
);
1056 rate_ctrl
->vbv_buffer_size
= rate_ctrl
->target_bitrate
;
1058 if (rate_ctrl
->frame_rate_num
) {
1059 unsigned long long t
= rate_ctrl
->target_bitrate
;
1060 t
*= rate_ctrl
->frame_rate_den
;
1061 rate_ctrl
->target_bits_picture
= t
/ rate_ctrl
->frame_rate_num
;
1063 rate_ctrl
->target_bits_picture
= rate_ctrl
->target_bitrate
;
1065 rate_ctrl
->peak_bits_picture_integer
= rate_ctrl
->target_bits_picture
;
1066 rate_ctrl
->peak_bits_picture_fraction
= 0;
1069 picture
->quant_i_frames
= priv
->quant
.nQpI
;
1070 picture
->quant_p_frames
= priv
->quant
.nQpP
;
1071 picture
->quant_b_frames
= priv
->quant
.nQpB
;
1073 picture
->frame_num
= priv
->frame_num
;
1074 picture
->ref_idx_l0
= priv
->ref_idx_l0
;
1075 picture
->ref_idx_l1
= priv
->ref_idx_l1
;
1076 picture
->enable_vui
= (picture
->rate_ctrl
.frame_rate_num
!= 0);
1077 enc_GetPictureParamPreset(picture
);
1080 static void enc_HandleTask(omx_base_PortType
*port
, struct encode_task
*task
,
1081 enum pipe_h264_enc_picture_type picture_type
)
1083 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
1084 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
1085 unsigned size
= priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
]->sPortParam
.nBufferSize
;
1086 struct pipe_video_buffer
*vbuf
= task
->buf
;
1087 struct pipe_h264_enc_picture_desc picture
= {};
1089 /* -------------- scale input image --------- */
1090 enc_ScaleInput(port
, &vbuf
, &size
);
1091 priv
->s_pipe
->flush(priv
->s_pipe
, NULL
, 0);
1093 /* -------------- allocate output buffer --------- */
1094 task
->bitstream
= pipe_buffer_create(priv
->s_pipe
->screen
,
1095 PIPE_BIND_VERTEX_BUFFER
,
1096 PIPE_USAGE_STAGING
, /* map for read */
1099 picture
.picture_type
= picture_type
;
1100 picture
.pic_order_cnt
= task
->pic_order_cnt
;
1101 picture
.base
.profile
= enc_TranslateOMXProfileToPipe(priv
->profile_level
.eProfile
);
1102 picture
.base
.entry_point
= PIPE_VIDEO_ENTRYPOINT_ENCODE
;
1103 if (priv
->restricted_b_frames
&& picture_type
== PIPE_H264_ENC_PICTURE_TYPE_B
)
1104 picture
.not_referenced
= true;
1105 enc_ControlPicture(port
, &picture
);
1107 /* -------------- encode frame --------- */
1108 priv
->codec
->begin_frame(priv
->codec
, vbuf
, &picture
.base
);
1109 priv
->codec
->encode_bitstream(priv
->codec
, vbuf
, task
->bitstream
, &task
->feedback
);
1110 priv
->codec
->end_frame(priv
->codec
, vbuf
, &picture
.base
);
1113 static void enc_ClearBframes(omx_base_PortType
*port
, struct input_buf_private
*inp
)
1115 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
1116 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
1117 struct encode_task
*task
;
1119 if (LIST_IS_EMPTY(&priv
->b_frames
))
1122 task
= LIST_ENTRY(struct encode_task
, priv
->b_frames
.prev
, list
);
1123 LIST_DEL(&task
->list
);
1125 /* promote last from to P frame */
1126 priv
->ref_idx_l0
= priv
->ref_idx_l1
;
1127 enc_HandleTask(port
, task
, PIPE_H264_ENC_PICTURE_TYPE_P
);
1128 LIST_ADDTAIL(&task
->list
, &inp
->tasks
);
1129 priv
->ref_idx_l1
= priv
->frame_num
++;
1131 /* handle B frames */
1132 LIST_FOR_EACH_ENTRY(task
, &priv
->b_frames
, list
) {
1133 enc_HandleTask(port
, task
, PIPE_H264_ENC_PICTURE_TYPE_B
);
1134 if (!priv
->restricted_b_frames
)
1135 priv
->ref_idx_l0
= priv
->frame_num
;
1139 enc_MoveTasks(&priv
->b_frames
, &inp
->tasks
);
1142 static OMX_ERRORTYPE
vid_enc_EncodeFrame(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
*buf
)
1144 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
1145 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
1146 struct input_buf_private
*inp
= buf
->pInputPortPrivate
;
1147 enum pipe_h264_enc_picture_type picture_type
;
1148 struct encode_task
*task
;
1149 unsigned stacked_num
= 0;
1152 enc_MoveTasks(&inp
->tasks
, &priv
->free_tasks
);
1153 task
= enc_NeedTask(port
);
1155 return OMX_ErrorInsufficientResources
;
1157 if (buf
->nFilledLen
== 0) {
1158 if (buf
->nFlags
& OMX_BUFFERFLAG_EOS
) {
1159 buf
->nFilledLen
= buf
->nAllocLen
;
1160 enc_ClearBframes(port
, inp
);
1161 enc_MoveTasks(&priv
->stacked_tasks
, &inp
->tasks
);
1162 priv
->codec
->flush(priv
->codec
);
1164 return base_port_SendBufferFunction(port
, buf
);
1167 if (buf
->pOutputPortPrivate
) {
1168 struct pipe_video_buffer
*vbuf
= buf
->pOutputPortPrivate
;
1169 buf
->pOutputPortPrivate
= task
->buf
;
1172 /* ------- load input image into video buffer ---- */
1173 err
= enc_LoadImage(port
, buf
, task
->buf
);
1174 if (err
!= OMX_ErrorNone
) {
1180 /* -------------- determine picture type --------- */
1181 if (!(priv
->pic_order_cnt
% OMX_VID_ENC_IDR_PERIOD_DEFAULT
) ||
1182 priv
->force_pic_type
.IntraRefreshVOP
) {
1183 enc_ClearBframes(port
, inp
);
1184 picture_type
= PIPE_H264_ENC_PICTURE_TYPE_IDR
;
1185 priv
->force_pic_type
.IntraRefreshVOP
= OMX_FALSE
;
1186 priv
->frame_num
= 0;
1187 } else if (priv
->codec
->profile
== PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE
||
1188 !(priv
->pic_order_cnt
% OMX_VID_ENC_P_PERIOD_DEFAULT
) ||
1189 (buf
->nFlags
& OMX_BUFFERFLAG_EOS
)) {
1190 picture_type
= PIPE_H264_ENC_PICTURE_TYPE_P
;
1192 picture_type
= PIPE_H264_ENC_PICTURE_TYPE_B
;
1195 task
->pic_order_cnt
= priv
->pic_order_cnt
++;
1197 if (picture_type
== PIPE_H264_ENC_PICTURE_TYPE_B
) {
1198 /* put frame at the tail of the queue */
1199 LIST_ADDTAIL(&task
->list
, &priv
->b_frames
);
1201 /* handle I or P frame */
1202 priv
->ref_idx_l0
= priv
->ref_idx_l1
;
1203 enc_HandleTask(port
, task
, picture_type
);
1204 LIST_ADDTAIL(&task
->list
, &priv
->stacked_tasks
);
1205 LIST_FOR_EACH_ENTRY(task
, &priv
->stacked_tasks
, list
) {
1208 if (stacked_num
== priv
->stacked_frames_num
) {
1209 struct encode_task
*t
;
1210 t
= LIST_ENTRY(struct encode_task
, priv
->stacked_tasks
.next
, list
);
1212 LIST_ADDTAIL(&t
->list
, &inp
->tasks
);
1214 priv
->ref_idx_l1
= priv
->frame_num
++;
1216 /* handle B frames */
1217 LIST_FOR_EACH_ENTRY(task
, &priv
->b_frames
, list
) {
1218 enc_HandleTask(port
, task
, PIPE_H264_ENC_PICTURE_TYPE_B
);
1219 if (!priv
->restricted_b_frames
)
1220 priv
->ref_idx_l0
= priv
->frame_num
;
1224 enc_MoveTasks(&priv
->b_frames
, &inp
->tasks
);
1227 if (LIST_IS_EMPTY(&inp
->tasks
))
1228 return port
->ReturnBufferFunction(port
, buf
);
1230 return base_port_SendBufferFunction(port
, buf
);
1233 static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE
*comp
, OMX_BUFFERHEADERTYPE
* input
, OMX_BUFFERHEADERTYPE
* output
)
1235 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
1236 struct output_buf_private
*outp
= output
->pOutputPortPrivate
;
1237 struct input_buf_private
*inp
= input
->pInputPortPrivate
;
1238 struct encode_task
*task
;
1239 struct pipe_box box
= {};
1242 if (!inp
|| LIST_IS_EMPTY(&inp
->tasks
)) {
1243 input
->nFilledLen
= 0; /* mark buffer as empty */
1244 enc_MoveTasks(&priv
->used_tasks
, &inp
->tasks
);
1248 task
= LIST_ENTRY(struct encode_task
, inp
->tasks
.next
, list
);
1249 LIST_DEL(&task
->list
);
1250 LIST_ADDTAIL(&task
->list
, &priv
->used_tasks
);
1252 if (!task
->bitstream
)
1255 /* ------------- map result buffer ----------------- */
1258 pipe_transfer_unmap(priv
->t_pipe
, outp
->transfer
);
1260 pipe_resource_reference(&outp
->bitstream
, task
->bitstream
);
1261 pipe_resource_reference(&task
->bitstream
, NULL
);
1263 box
.width
= outp
->bitstream
->width0
;
1264 box
.height
= outp
->bitstream
->height0
;
1265 box
.depth
= outp
->bitstream
->depth0
;
1267 output
->pBuffer
= priv
->t_pipe
->transfer_map(priv
->t_pipe
, outp
->bitstream
, 0,
1268 PIPE_TRANSFER_READ_WRITE
,
1269 &box
, &outp
->transfer
);
1271 /* ------------- get size of result ----------------- */
1273 priv
->codec
->get_feedback(priv
->codec
, task
->feedback
, &size
);
1275 output
->nOffset
= 0;
1276 output
->nFilledLen
= size
; /* mark buffer as full */
1278 /* all output buffers contain exactly one frame */
1279 output
->nFlags
= OMX_BUFFERFLAG_ENDOFFRAME
;