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 "state_tracker/drm_driver.h"
52 #include "util/u_memory.h"
53 #include "vl/vl_video_buffer.h"
55 #include "entrypoint.h"
59 struct list_head list
;
61 struct pipe_video_buffer
*buf
;
62 unsigned pic_order_cnt
;
63 struct pipe_resource
*bitstream
;
67 struct input_buf_private
{
68 struct list_head tasks
;
70 struct pipe_resource
*resource
;
71 struct pipe_transfer
*transfer
;
74 struct output_buf_private
{
75 struct pipe_resource
*bitstream
;
76 struct pipe_transfer
*transfer
;
79 static OMX_ERRORTYPE
vid_enc_Constructor(OMX_COMPONENTTYPE
*comp
, OMX_STRING name
);
80 static OMX_ERRORTYPE
vid_enc_Destructor(OMX_COMPONENTTYPE
*comp
);
81 static OMX_ERRORTYPE
vid_enc_SetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
);
82 static OMX_ERRORTYPE
vid_enc_GetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
);
83 static OMX_ERRORTYPE
vid_enc_SetConfig(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR config
);
84 static OMX_ERRORTYPE
vid_enc_GetConfig(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR config
);
85 static OMX_ERRORTYPE
vid_enc_MessageHandler(OMX_COMPONENTTYPE
*comp
, internalRequestMessageType
*msg
);
86 static OMX_ERRORTYPE
vid_enc_AllocateInBuffer(omx_base_PortType
*port
, OMX_INOUT OMX_BUFFERHEADERTYPE
**buf
,
87 OMX_IN OMX_U32 idx
, OMX_IN OMX_PTR
private, OMX_IN OMX_U32 size
);
88 static OMX_ERRORTYPE
vid_enc_UseInBuffer(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
**buf
, OMX_U32 idx
,
89 OMX_PTR
private, OMX_U32 size
, OMX_U8
*mem
);
90 static OMX_ERRORTYPE
vid_enc_FreeInBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
);
91 static OMX_ERRORTYPE
vid_enc_EncodeFrame(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
*buf
);
92 static OMX_ERRORTYPE
vid_enc_AllocateOutBuffer(omx_base_PortType
*comp
, OMX_INOUT OMX_BUFFERHEADERTYPE
**buf
,
93 OMX_IN OMX_U32 idx
, OMX_IN OMX_PTR
private, OMX_IN OMX_U32 size
);
94 static OMX_ERRORTYPE
vid_enc_FreeOutBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
);
95 static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE
*comp
, OMX_BUFFERHEADERTYPE
* input
, OMX_BUFFERHEADERTYPE
* output
);
97 static void enc_ReleaseTasks(struct list_head
*head
);
99 OMX_ERRORTYPE
vid_enc_LoaderComponent(stLoaderComponentType
*comp
)
101 comp
->componentVersion
.s
.nVersionMajor
= 0;
102 comp
->componentVersion
.s
.nVersionMinor
= 0;
103 comp
->componentVersion
.s
.nRevision
= 0;
104 comp
->componentVersion
.s
.nStep
= 1;
105 comp
->name_specific_length
= 1;
106 comp
->constructor
= vid_enc_Constructor
;
108 comp
->name
= CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
110 return OMX_ErrorInsufficientResources
;
112 comp
->name_specific
= CALLOC(1, sizeof(char *));
113 if (!comp
->name_specific
)
116 comp
->role_specific
= CALLOC(1, sizeof(char *));
117 if (!comp
->role_specific
)
120 comp
->name_specific
[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
121 if (comp
->name_specific
[0] == NULL
)
124 comp
->role_specific
[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE
);
125 if (comp
->role_specific
[0] == NULL
)
128 strcpy(comp
->name
, OMX_VID_ENC_BASE_NAME
);
129 strcpy(comp
->name_specific
[0], OMX_VID_ENC_AVC_NAME
);
130 strcpy(comp
->role_specific
[0], OMX_VID_ENC_AVC_ROLE
);
132 return OMX_ErrorNone
;
135 FREE(comp
->role_specific
[0]);
136 FREE(comp
->name_specific
[0]);
139 FREE(comp
->role_specific
);
140 FREE(comp
->name_specific
);
144 return OMX_ErrorInsufficientResources
;
147 static OMX_ERRORTYPE
vid_enc_Constructor(OMX_COMPONENTTYPE
*comp
, OMX_STRING name
)
149 vid_enc_PrivateType
*priv
;
150 omx_base_video_PortType
*port
;
151 struct pipe_screen
*screen
;
155 assert(!comp
->pComponentPrivate
);
157 priv
= comp
->pComponentPrivate
= CALLOC(1, sizeof(vid_enc_PrivateType
));
159 return OMX_ErrorInsufficientResources
;
161 r
= omx_base_filter_Constructor(comp
, name
);
165 priv
->BufferMgmtCallback
= vid_enc_BufferEncoded
;
166 priv
->messageHandler
= vid_enc_MessageHandler
;
167 priv
->destructor
= vid_enc_Destructor
;
169 comp
->SetParameter
= vid_enc_SetParameter
;
170 comp
->GetParameter
= vid_enc_GetParameter
;
171 comp
->GetConfig
= vid_enc_GetConfig
;
172 comp
->SetConfig
= vid_enc_SetConfig
;
174 priv
->screen
= omx_get_screen();
176 return OMX_ErrorInsufficientResources
;
178 screen
= priv
->screen
->pscreen
;
179 if (!screen
->get_video_param(screen
, PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
,
180 PIPE_VIDEO_ENTRYPOINT_ENCODE
, PIPE_VIDEO_CAP_SUPPORTED
))
181 return OMX_ErrorBadParameter
;
183 priv
->stacked_frames_num
= screen
->get_video_param(screen
,
184 PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
,
185 PIPE_VIDEO_ENTRYPOINT_ENCODE
,
186 PIPE_VIDEO_CAP_STACKED_FRAMES
);
188 priv
->s_pipe
= screen
->context_create(screen
, priv
->screen
);
190 return OMX_ErrorInsufficientResources
;
192 if (!vl_compositor_init(&priv
->compositor
, priv
->s_pipe
)) {
193 priv
->s_pipe
->destroy(priv
->s_pipe
);
195 return OMX_ErrorInsufficientResources
;
198 if (!vl_compositor_init_state(&priv
->cstate
, priv
->s_pipe
)) {
199 vl_compositor_cleanup(&priv
->compositor
);
200 priv
->s_pipe
->destroy(priv
->s_pipe
);
202 return OMX_ErrorInsufficientResources
;
205 priv
->t_pipe
= screen
->context_create(screen
, priv
->screen
);
207 return OMX_ErrorInsufficientResources
;
209 priv
->sPortTypesParam
[OMX_PortDomainVideo
].nStartPortNumber
= 0;
210 priv
->sPortTypesParam
[OMX_PortDomainVideo
].nPorts
= 2;
211 priv
->ports
= CALLOC(2, sizeof(omx_base_PortType
*));
213 return OMX_ErrorInsufficientResources
;
215 for (i
= 0; i
< 2; ++i
) {
216 priv
->ports
[i
] = CALLOC(1, sizeof(omx_base_video_PortType
));
218 return OMX_ErrorInsufficientResources
;
220 base_video_port_Constructor(comp
, &priv
->ports
[i
], i
, i
== 0);
223 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
224 port
->sPortParam
.format
.video
.nFrameWidth
= 176;
225 port
->sPortParam
.format
.video
.nFrameHeight
= 144;
226 port
->sPortParam
.format
.video
.eColorFormat
= OMX_COLOR_FormatYUV420SemiPlanar
;
227 port
->sVideoParam
.eColorFormat
= OMX_COLOR_FormatYUV420SemiPlanar
;
228 port
->sPortParam
.nBufferCountActual
= 8;
229 port
->sPortParam
.nBufferCountMin
= 4;
231 port
->Port_SendBufferFunction
= vid_enc_EncodeFrame
;
232 port
->Port_AllocateBuffer
= vid_enc_AllocateInBuffer
;
233 port
->Port_UseBuffer
= vid_enc_UseInBuffer
;
234 port
->Port_FreeBuffer
= vid_enc_FreeInBuffer
;
236 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
];
237 strcpy(port
->sPortParam
.format
.video
.cMIMEType
,"video/H264");
238 port
->sPortParam
.format
.video
.nFrameWidth
= 176;
239 port
->sPortParam
.format
.video
.nFrameHeight
= 144;
240 port
->sPortParam
.format
.video
.eCompressionFormat
= OMX_VIDEO_CodingAVC
;
241 port
->sVideoParam
.eCompressionFormat
= OMX_VIDEO_CodingAVC
;
243 port
->Port_AllocateBuffer
= vid_enc_AllocateOutBuffer
;
244 port
->Port_FreeBuffer
= vid_enc_FreeOutBuffer
;
246 priv
->bitrate
.eControlRate
= OMX_Video_ControlRateDisable
;
247 priv
->bitrate
.nTargetBitrate
= 0;
249 priv
->quant
.nQpI
= OMX_VID_ENC_QUANT_I_FRAMES_DEFAULT
;
250 priv
->quant
.nQpP
= OMX_VID_ENC_QUANT_P_FRAMES_DEFAULT
;
251 priv
->quant
.nQpB
= OMX_VID_ENC_QUANT_B_FRAMES_DEFAULT
;
253 priv
->profile_level
.eProfile
= OMX_VIDEO_AVCProfileBaseline
;
254 priv
->profile_level
.eLevel
= OMX_VIDEO_AVCLevel42
;
256 priv
->force_pic_type
.IntraRefreshVOP
= OMX_FALSE
;
258 priv
->pic_order_cnt
= 0;
259 priv
->restricted_b_frames
= debug_get_bool_option("OMX_USE_RESTRICTED_B_FRAMES", FALSE
);
261 priv
->scale
.xWidth
= OMX_VID_ENC_SCALING_WIDTH_DEFAULT
;
262 priv
->scale
.xHeight
= OMX_VID_ENC_SCALING_WIDTH_DEFAULT
;
264 LIST_INITHEAD(&priv
->free_tasks
);
265 LIST_INITHEAD(&priv
->used_tasks
);
266 LIST_INITHEAD(&priv
->b_frames
);
267 LIST_INITHEAD(&priv
->stacked_tasks
);
269 return OMX_ErrorNone
;
272 static OMX_ERRORTYPE
vid_enc_Destructor(OMX_COMPONENTTYPE
*comp
)
274 vid_enc_PrivateType
* priv
= comp
->pComponentPrivate
;
277 enc_ReleaseTasks(&priv
->free_tasks
);
278 enc_ReleaseTasks(&priv
->used_tasks
);
279 enc_ReleaseTasks(&priv
->b_frames
);
280 enc_ReleaseTasks(&priv
->stacked_tasks
);
283 for (i
= 0; i
< priv
->sPortTypesParam
[OMX_PortDomainVideo
].nPorts
; ++i
) {
285 priv
->ports
[i
]->PortDestructor(priv
->ports
[i
]);
291 for (i
= 0; i
< OMX_VID_ENC_NUM_SCALING_BUFFERS
; ++i
)
292 if (priv
->scale_buffer
[i
])
293 priv
->scale_buffer
[i
]->destroy(priv
->scale_buffer
[i
]);
296 vl_compositor_cleanup_state(&priv
->cstate
);
297 vl_compositor_cleanup(&priv
->compositor
);
298 priv
->s_pipe
->destroy(priv
->s_pipe
);
302 priv
->t_pipe
->destroy(priv
->t_pipe
);
307 return omx_workaround_Destructor(comp
);
310 static OMX_ERRORTYPE
enc_AllocateBackTexture(omx_base_PortType
*port
,
311 struct pipe_resource
**resource
,
312 struct pipe_transfer
**transfer
,
315 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
316 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
317 struct pipe_resource buf_templ
;
318 struct pipe_box box
= {};
321 memset(&buf_templ
, 0, sizeof buf_templ
);
322 buf_templ
.target
= PIPE_TEXTURE_2D
;
323 buf_templ
.format
= PIPE_FORMAT_I8_UNORM
;
324 buf_templ
.bind
= PIPE_BIND_LINEAR
;
325 buf_templ
.usage
= PIPE_USAGE_STAGING
;
327 buf_templ
.width0
= port
->sPortParam
.format
.video
.nFrameWidth
;
328 buf_templ
.height0
= port
->sPortParam
.format
.video
.nFrameHeight
* 3 / 2;
329 buf_templ
.depth0
= 1;
330 buf_templ
.array_size
= 1;
332 *resource
= priv
->s_pipe
->screen
->resource_create(priv
->s_pipe
->screen
, &buf_templ
);
334 return OMX_ErrorInsufficientResources
;
336 box
.width
= (*resource
)->width0
;
337 box
.height
= (*resource
)->height0
;
338 box
.depth
= (*resource
)->depth0
;
339 ptr
= priv
->s_pipe
->transfer_map(priv
->s_pipe
, *resource
, 0, PIPE_TRANSFER_WRITE
, &box
, transfer
);
343 return OMX_ErrorNone
;
346 static OMX_ERRORTYPE
vid_enc_SetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
)
348 OMX_COMPONENTTYPE
*comp
= handle
;
349 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
353 return OMX_ErrorBadParameter
;
356 case OMX_IndexParamPortDefinition
: {
357 OMX_PARAM_PORTDEFINITIONTYPE
*def
= param
;
359 r
= omx_base_component_SetParameter(handle
, idx
, param
);
363 if (def
->nPortIndex
== OMX_BASE_FILTER_INPUTPORT_INDEX
) {
364 omx_base_video_PortType
*port
;
366 struct pipe_resource
*resource
;
367 struct pipe_transfer
*transfer
;
369 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
370 enc_AllocateBackTexture(priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
],
371 &resource
, &transfer
, NULL
);
372 port
->sPortParam
.format
.video
.nStride
= transfer
->stride
;
373 pipe_transfer_unmap(priv
->s_pipe
, transfer
);
374 pipe_resource_reference(&resource
, NULL
);
376 framesize
= port
->sPortParam
.format
.video
.nStride
*
377 port
->sPortParam
.format
.video
.nFrameHeight
;
378 port
->sPortParam
.format
.video
.nSliceHeight
= port
->sPortParam
.format
.video
.nFrameHeight
;
379 port
->sPortParam
.nBufferSize
= framesize
* 3 / 2;
381 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
];
382 port
->sPortParam
.nBufferSize
= framesize
* 512 / (16*16);
384 priv
->frame_rate
= def
->format
.video
.xFramerate
;
386 priv
->callbacks
->EventHandler(comp
, priv
->callbackData
, OMX_EventPortSettingsChanged
,
387 OMX_BASE_FILTER_OUTPUTPORT_INDEX
, 0, NULL
);
391 case OMX_IndexParamStandardComponentRole
: {
392 OMX_PARAM_COMPONENTROLETYPE
*role
= param
;
394 r
= checkHeader(param
, sizeof(OMX_PARAM_COMPONENTROLETYPE
));
398 if (strcmp((char *)role
->cRole
, OMX_VID_ENC_AVC_ROLE
)) {
399 return OMX_ErrorBadParameter
;
404 case OMX_IndexParamVideoBitrate
: {
405 OMX_VIDEO_PARAM_BITRATETYPE
*bitrate
= param
;
407 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_BITRATETYPE
));
411 priv
->bitrate
= *bitrate
;
415 case OMX_IndexParamVideoQuantization
: {
416 OMX_VIDEO_PARAM_QUANTIZATIONTYPE
*quant
= param
;
418 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE
));
422 priv
->quant
= *quant
;
426 case OMX_IndexParamVideoProfileLevelCurrent
: {
427 OMX_VIDEO_PARAM_PROFILELEVELTYPE
*profile_level
= param
;
429 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE
));
433 priv
->profile_level
= *profile_level
;
438 return omx_base_component_SetParameter(handle
, idx
, param
);
440 return OMX_ErrorNone
;
443 static OMX_ERRORTYPE
vid_enc_GetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
)
445 OMX_COMPONENTTYPE
*comp
= handle
;
446 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
450 return OMX_ErrorBadParameter
;
453 case OMX_IndexParamStandardComponentRole
: {
454 OMX_PARAM_COMPONENTROLETYPE
*role
= param
;
456 r
= checkHeader(param
, sizeof(OMX_PARAM_COMPONENTROLETYPE
));
460 strcpy((char *)role
->cRole
, OMX_VID_ENC_AVC_ROLE
);
463 case OMX_IndexParamVideoInit
:
464 r
= checkHeader(param
, sizeof(OMX_PORT_PARAM_TYPE
));
468 memcpy(param
, &priv
->sPortTypesParam
[OMX_PortDomainVideo
], sizeof(OMX_PORT_PARAM_TYPE
));
471 case OMX_IndexParamVideoPortFormat
: {
472 OMX_VIDEO_PARAM_PORTFORMATTYPE
*format
= param
;
473 omx_base_video_PortType
*port
;
475 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
479 if (format
->nPortIndex
> 1)
480 return OMX_ErrorBadPortIndex
;
482 port
= (omx_base_video_PortType
*)priv
->ports
[format
->nPortIndex
];
483 memcpy(format
, &port
->sVideoParam
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
486 case OMX_IndexParamVideoBitrate
: {
487 OMX_VIDEO_PARAM_BITRATETYPE
*bitrate
= param
;
489 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_BITRATETYPE
));
493 bitrate
->eControlRate
= priv
->bitrate
.eControlRate
;
494 bitrate
->nTargetBitrate
= priv
->bitrate
.nTargetBitrate
;
498 case OMX_IndexParamVideoQuantization
: {
499 OMX_VIDEO_PARAM_QUANTIZATIONTYPE
*quant
= param
;
501 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE
));
505 quant
->nQpI
= priv
->quant
.nQpI
;
506 quant
->nQpP
= priv
->quant
.nQpP
;
507 quant
->nQpB
= priv
->quant
.nQpB
;
511 case OMX_IndexParamVideoProfileLevelCurrent
: {
512 OMX_VIDEO_PARAM_PROFILELEVELTYPE
*profile_level
= param
;
514 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE
));
518 profile_level
->eProfile
= priv
->profile_level
.eProfile
;
519 profile_level
->eLevel
= priv
->profile_level
.eLevel
;
524 return omx_base_component_GetParameter(handle
, idx
, param
);
526 return OMX_ErrorNone
;
529 static OMX_ERRORTYPE
vid_enc_SetConfig(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR config
)
531 OMX_COMPONENTTYPE
*comp
= handle
;
532 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
537 return OMX_ErrorBadParameter
;
540 case OMX_IndexConfigVideoIntraVOPRefresh
: {
541 OMX_CONFIG_INTRAREFRESHVOPTYPE
*type
= config
;
543 r
= checkHeader(config
, sizeof(OMX_CONFIG_INTRAREFRESHVOPTYPE
));
547 priv
->force_pic_type
= *type
;
551 case OMX_IndexConfigCommonScale
: {
552 OMX_CONFIG_SCALEFACTORTYPE
*scale
= config
;
554 r
= checkHeader(config
, sizeof(OMX_CONFIG_SCALEFACTORTYPE
));
558 if (scale
->xWidth
< 176 || scale
->xHeight
< 144)
559 return OMX_ErrorBadParameter
;
561 for (i
= 0; i
< OMX_VID_ENC_NUM_SCALING_BUFFERS
; ++i
) {
562 if (priv
->scale_buffer
[i
]) {
563 priv
->scale_buffer
[i
]->destroy(priv
->scale_buffer
[i
]);
564 priv
->scale_buffer
[i
] = NULL
;
568 priv
->scale
= *scale
;
569 if (priv
->scale
.xWidth
!= 0xffffffff && priv
->scale
.xHeight
!= 0xffffffff) {
570 struct pipe_video_buffer templat
= {};
572 templat
.buffer_format
= PIPE_FORMAT_NV12
;
573 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
574 templat
.width
= priv
->scale
.xWidth
;
575 templat
.height
= priv
->scale
.xHeight
;
576 templat
.interlaced
= false;
577 for (i
= 0; i
< OMX_VID_ENC_NUM_SCALING_BUFFERS
; ++i
) {
578 priv
->scale_buffer
[i
] = priv
->s_pipe
->create_video_buffer(priv
->s_pipe
, &templat
);
579 if (!priv
->scale_buffer
[i
])
580 return OMX_ErrorInsufficientResources
;
587 return omx_base_component_SetConfig(handle
, idx
, config
);
590 return OMX_ErrorNone
;
593 static OMX_ERRORTYPE
vid_enc_GetConfig(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR config
)
595 OMX_COMPONENTTYPE
*comp
= handle
;
596 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
600 return OMX_ErrorBadParameter
;
603 case OMX_IndexConfigCommonScale
: {
604 OMX_CONFIG_SCALEFACTORTYPE
*scale
= config
;
606 r
= checkHeader(config
, sizeof(OMX_CONFIG_SCALEFACTORTYPE
));
610 scale
->xWidth
= priv
->scale
.xWidth
;
611 scale
->xHeight
= priv
->scale
.xHeight
;
616 return omx_base_component_GetConfig(handle
, idx
, config
);
619 return OMX_ErrorNone
;
622 static enum pipe_video_profile
enc_TranslateOMXProfileToPipe(unsigned omx_profile
)
624 switch (omx_profile
) {
625 case OMX_VIDEO_AVCProfileBaseline
:
626 return PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE
;
627 case OMX_VIDEO_AVCProfileMain
:
628 return PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN
;
629 case OMX_VIDEO_AVCProfileExtended
:
630 return PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED
;
631 case OMX_VIDEO_AVCProfileHigh
:
632 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
;
633 case OMX_VIDEO_AVCProfileHigh10
:
634 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10
;
635 case OMX_VIDEO_AVCProfileHigh422
:
636 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH422
;
637 case OMX_VIDEO_AVCProfileHigh444
:
638 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH444
;
640 return PIPE_VIDEO_PROFILE_UNKNOWN
;
644 static unsigned enc_TranslateOMXLevelToPipe(unsigned omx_level
)
647 case OMX_VIDEO_AVCLevel1
:
648 case OMX_VIDEO_AVCLevel1b
:
650 case OMX_VIDEO_AVCLevel11
:
652 case OMX_VIDEO_AVCLevel12
:
654 case OMX_VIDEO_AVCLevel13
:
656 case OMX_VIDEO_AVCLevel2
:
658 case OMX_VIDEO_AVCLevel21
:
660 case OMX_VIDEO_AVCLevel22
:
662 case OMX_VIDEO_AVCLevel3
:
664 case OMX_VIDEO_AVCLevel31
:
666 case OMX_VIDEO_AVCLevel32
:
668 case OMX_VIDEO_AVCLevel4
:
670 case OMX_VIDEO_AVCLevel41
:
673 case OMX_VIDEO_AVCLevel42
:
675 case OMX_VIDEO_AVCLevel5
:
677 case OMX_VIDEO_AVCLevel51
:
682 static OMX_ERRORTYPE
vid_enc_MessageHandler(OMX_COMPONENTTYPE
* comp
, internalRequestMessageType
*msg
)
684 vid_enc_PrivateType
* priv
= comp
->pComponentPrivate
;
686 if (msg
->messageType
== OMX_CommandStateSet
) {
687 if ((msg
->messageParam
== OMX_StateIdle
) && (priv
->state
== OMX_StateLoaded
)) {
689 struct pipe_video_codec templat
= {};
690 omx_base_video_PortType
*port
;
692 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
694 templat
.profile
= enc_TranslateOMXProfileToPipe(priv
->profile_level
.eProfile
);
695 templat
.level
= enc_TranslateOMXLevelToPipe(priv
->profile_level
.eLevel
);
696 templat
.entrypoint
= PIPE_VIDEO_ENTRYPOINT_ENCODE
;
697 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
698 templat
.width
= priv
->scale_buffer
[priv
->current_scale_buffer
] ?
699 priv
->scale
.xWidth
: port
->sPortParam
.format
.video
.nFrameWidth
;
700 templat
.height
= priv
->scale_buffer
[priv
->current_scale_buffer
] ?
701 priv
->scale
.xHeight
: port
->sPortParam
.format
.video
.nFrameHeight
;
702 templat
.max_references
= (templat
.profile
== PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE
) ?
703 1 : OMX_VID_ENC_P_PERIOD_DEFAULT
;
705 priv
->codec
= priv
->s_pipe
->create_video_codec(priv
->s_pipe
, &templat
);
707 } else if ((msg
->messageParam
== OMX_StateLoaded
) && (priv
->state
== OMX_StateIdle
)) {
709 priv
->codec
->destroy(priv
->codec
);
715 return omx_base_component_MessageHandler(comp
, msg
);
718 static OMX_ERRORTYPE
vid_enc_AllocateInBuffer(omx_base_PortType
*port
, OMX_INOUT OMX_BUFFERHEADERTYPE
**buf
,
719 OMX_IN OMX_U32 idx
, OMX_IN OMX_PTR
private, OMX_IN OMX_U32 size
)
721 struct input_buf_private
*inp
;
724 r
= base_port_AllocateBuffer(port
, buf
, idx
, private, size
);
728 inp
= (*buf
)->pInputPortPrivate
= CALLOC_STRUCT(input_buf_private
);
730 base_port_FreeBuffer(port
, idx
, *buf
);
731 return OMX_ErrorInsufficientResources
;
734 LIST_INITHEAD(&inp
->tasks
);
736 FREE((*buf
)->pBuffer
);
737 r
= enc_AllocateBackTexture(port
, &inp
->resource
, &inp
->transfer
, &(*buf
)->pBuffer
);
740 base_port_FreeBuffer(port
, idx
, *buf
);
744 return OMX_ErrorNone
;
747 static OMX_ERRORTYPE
vid_enc_UseInBuffer(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
**buf
, OMX_U32 idx
,
748 OMX_PTR
private, OMX_U32 size
, OMX_U8
*mem
)
750 struct input_buf_private
*inp
;
753 r
= base_port_UseBuffer(port
, buf
, idx
, private, size
, mem
);
757 inp
= (*buf
)->pInputPortPrivate
= CALLOC_STRUCT(input_buf_private
);
759 base_port_FreeBuffer(port
, idx
, *buf
);
760 return OMX_ErrorInsufficientResources
;
763 LIST_INITHEAD(&inp
->tasks
);
765 return OMX_ErrorNone
;
768 static OMX_ERRORTYPE
vid_enc_FreeInBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
)
770 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
771 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
772 struct input_buf_private
*inp
= buf
->pInputPortPrivate
;
775 enc_ReleaseTasks(&inp
->tasks
);
777 pipe_transfer_unmap(priv
->s_pipe
, inp
->transfer
);
778 pipe_resource_reference(&inp
->resource
, NULL
);
783 return base_port_FreeBuffer(port
, idx
, buf
);
786 static OMX_ERRORTYPE
vid_enc_AllocateOutBuffer(omx_base_PortType
*port
, OMX_INOUT OMX_BUFFERHEADERTYPE
**buf
,
787 OMX_IN OMX_U32 idx
, OMX_IN OMX_PTR
private, OMX_IN OMX_U32 size
)
791 r
= base_port_AllocateBuffer(port
, buf
, idx
, private, size
);
795 FREE((*buf
)->pBuffer
);
796 (*buf
)->pBuffer
= NULL
;
797 (*buf
)->pOutputPortPrivate
= CALLOC(1, sizeof(struct output_buf_private
));
798 if (!(*buf
)->pOutputPortPrivate
) {
799 base_port_FreeBuffer(port
, idx
, *buf
);
800 return OMX_ErrorInsufficientResources
;
803 return OMX_ErrorNone
;
806 static OMX_ERRORTYPE
vid_enc_FreeOutBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
)
808 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
809 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
811 if (buf
->pOutputPortPrivate
) {
812 struct output_buf_private
*outp
= buf
->pOutputPortPrivate
;
814 pipe_transfer_unmap(priv
->t_pipe
, outp
->transfer
);
815 pipe_resource_reference(&outp
->bitstream
, NULL
);
817 buf
->pOutputPortPrivate
= NULL
;
821 return base_port_FreeBuffer(port
, idx
, buf
);
824 static struct encode_task
*enc_NeedTask(omx_base_PortType
*port
)
826 OMX_VIDEO_PORTDEFINITIONTYPE
*def
= &port
->sPortParam
.format
.video
;
827 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
828 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
830 struct pipe_video_buffer templat
= {};
831 struct encode_task
*task
;
833 if (!LIST_IS_EMPTY(&priv
->free_tasks
)) {
834 task
= LIST_ENTRY(struct encode_task
, priv
->free_tasks
.next
, list
);
835 LIST_DEL(&task
->list
);
839 /* allocate a new one */
840 task
= CALLOC_STRUCT(encode_task
);
844 templat
.buffer_format
= PIPE_FORMAT_NV12
;
845 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
846 templat
.width
= def
->nFrameWidth
;
847 templat
.height
= def
->nFrameHeight
;
848 templat
.interlaced
= false;
850 task
->buf
= priv
->s_pipe
->create_video_buffer(priv
->s_pipe
, &templat
);
859 static void enc_MoveTasks(struct list_head
*from
, struct list_head
*to
)
861 to
->prev
->next
= from
->next
;
862 from
->next
->prev
= to
->prev
;
863 from
->prev
->next
= to
;
864 to
->prev
= from
->prev
;
868 static void enc_ReleaseTasks(struct list_head
*head
)
870 struct encode_task
*i
, *next
;
872 LIST_FOR_EACH_ENTRY_SAFE(i
, next
, head
, list
) {
873 pipe_resource_reference(&i
->bitstream
, NULL
);
874 i
->buf
->destroy(i
->buf
);
879 static OMX_ERRORTYPE
enc_LoadImage(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
*buf
,
880 struct pipe_video_buffer
*vbuf
)
882 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
883 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
884 OMX_VIDEO_PORTDEFINITIONTYPE
*def
= &port
->sPortParam
.format
.video
;
885 struct pipe_box box
= {};
886 struct input_buf_private
*inp
= buf
->pInputPortPrivate
;
888 if (!inp
->resource
) {
889 struct pipe_sampler_view
**views
;
892 views
= vbuf
->get_sampler_view_planes(vbuf
);
894 return OMX_ErrorInsufficientResources
;
897 box
.width
= def
->nFrameWidth
;
898 box
.height
= def
->nFrameHeight
;
900 priv
->s_pipe
->transfer_inline_write(priv
->s_pipe
, views
[0]->texture
, 0,
901 PIPE_TRANSFER_WRITE
, &box
,
902 ptr
, def
->nStride
, 0);
903 ptr
= ((uint8_t*)buf
->pBuffer
) + (def
->nStride
* box
.height
);
904 box
.width
= def
->nFrameWidth
/ 2;
905 box
.height
= def
->nFrameHeight
/ 2;
907 priv
->s_pipe
->transfer_inline_write(priv
->s_pipe
, views
[1]->texture
, 0,
908 PIPE_TRANSFER_WRITE
, &box
,
909 ptr
, def
->nStride
, 0);
911 struct pipe_blit_info blit
;
912 struct vl_video_buffer
*dst_buf
= (struct vl_video_buffer
*)vbuf
;
914 pipe_transfer_unmap(priv
->s_pipe
, inp
->transfer
);
916 box
.width
= def
->nFrameWidth
;
917 box
.height
= def
->nFrameHeight
;
920 priv
->s_pipe
->resource_copy_region(priv
->s_pipe
,
921 dst_buf
->resources
[0],
922 0, 0, 0, 0, inp
->resource
, 0, &box
);
924 memset(&blit
, 0, sizeof(blit
));
925 blit
.src
.resource
= inp
->resource
;
926 blit
.src
.format
= inp
->resource
->format
;
929 blit
.src
.box
.y
= def
->nFrameHeight
;
930 blit
.src
.box
.width
= def
->nFrameWidth
;
931 blit
.src
.box
.height
= def
->nFrameHeight
/ 2 ;
932 blit
.src
.box
.depth
= 1;
934 blit
.dst
.resource
= dst_buf
->resources
[1];
935 blit
.dst
.format
= blit
.dst
.resource
->format
;
937 blit
.dst
.box
.width
= def
->nFrameWidth
/ 2;
938 blit
.dst
.box
.height
= def
->nFrameHeight
/ 2;
939 blit
.dst
.box
.depth
= 1;
940 blit
.filter
= PIPE_TEX_FILTER_NEAREST
;
942 blit
.mask
= PIPE_MASK_G
;
943 priv
->s_pipe
->blit(priv
->s_pipe
, &blit
);
946 blit
.mask
= PIPE_MASK_R
;
947 priv
->s_pipe
->blit(priv
->s_pipe
, &blit
);
948 priv
->s_pipe
->flush(priv
->s_pipe
, NULL
, 0);
950 box
.width
= inp
->resource
->width0
;
951 box
.height
= inp
->resource
->height0
;
952 box
.depth
= inp
->resource
->depth0
;
953 buf
->pBuffer
= priv
->s_pipe
->transfer_map(priv
->s_pipe
, inp
->resource
, 0,
954 PIPE_TRANSFER_WRITE
, &box
,
958 return OMX_ErrorNone
;
961 static void enc_ScaleInput(omx_base_PortType
*port
, struct pipe_video_buffer
**vbuf
, unsigned *size
)
963 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
964 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
965 OMX_VIDEO_PORTDEFINITIONTYPE
*def
= &port
->sPortParam
.format
.video
;
966 struct pipe_video_buffer
*src_buf
= *vbuf
;
967 struct vl_compositor
*compositor
= &priv
->compositor
;
968 struct vl_compositor_state
*s
= &priv
->cstate
;
969 struct pipe_sampler_view
**views
;
970 struct pipe_surface
**dst_surface
;
973 if (!priv
->scale_buffer
[priv
->current_scale_buffer
])
976 views
= src_buf
->get_sampler_view_planes(src_buf
);
977 dst_surface
= priv
->scale_buffer
[priv
->current_scale_buffer
]->get_surfaces
978 (priv
->scale_buffer
[priv
->current_scale_buffer
]);
979 vl_compositor_clear_layers(s
);
981 for (i
= 0; i
< VL_MAX_SURFACES
; ++i
) {
982 struct u_rect src_rect
;
983 if (!views
[i
] || !dst_surface
[i
])
987 src_rect
.x1
= def
->nFrameWidth
;
988 src_rect
.y1
= def
->nFrameHeight
;
993 vl_compositor_set_rgba_layer(s
, compositor
, 0, views
[i
], &src_rect
, NULL
, NULL
);
994 vl_compositor_render(s
, compositor
, dst_surface
[i
], NULL
, false);
996 *size
= priv
->scale
.xWidth
* priv
->scale
.xHeight
* 2;
997 *vbuf
= priv
->scale_buffer
[priv
->current_scale_buffer
++];
998 priv
->current_scale_buffer
%= OMX_VID_ENC_NUM_SCALING_BUFFERS
;
1001 static void enc_ControlPicture(omx_base_PortType
*port
, struct pipe_h264_enc_picture_desc
*picture
)
1003 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
1004 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
1005 struct pipe_h264_enc_rate_control
*rate_ctrl
= &picture
->rate_ctrl
;
1007 switch (priv
->bitrate
.eControlRate
) {
1008 case OMX_Video_ControlRateVariable
:
1009 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE
;
1011 case OMX_Video_ControlRateConstant
:
1012 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT
;
1014 case OMX_Video_ControlRateVariableSkipFrames
:
1015 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP
;
1017 case OMX_Video_ControlRateConstantSkipFrames
:
1018 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP
;
1021 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_DISABLE
;
1025 rate_ctrl
->frame_rate_den
= OMX_VID_ENC_CONTROL_FRAME_RATE_DEN_DEFAULT
;
1026 rate_ctrl
->frame_rate_num
= ((priv
->frame_rate
) >> 16) * rate_ctrl
->frame_rate_den
;
1028 if (rate_ctrl
->rate_ctrl_method
!= PIPE_H264_ENC_RATE_CONTROL_METHOD_DISABLE
) {
1029 if (priv
->bitrate
.nTargetBitrate
< OMX_VID_ENC_BITRATE_MIN
)
1030 rate_ctrl
->target_bitrate
= OMX_VID_ENC_BITRATE_MIN
;
1031 else if (priv
->bitrate
.nTargetBitrate
< OMX_VID_ENC_BITRATE_MAX
)
1032 rate_ctrl
->target_bitrate
= priv
->bitrate
.nTargetBitrate
;
1034 rate_ctrl
->target_bitrate
= OMX_VID_ENC_BITRATE_MAX
;
1035 rate_ctrl
->peak_bitrate
= rate_ctrl
->target_bitrate
;
1036 if (rate_ctrl
->target_bitrate
< OMX_VID_ENC_BITRATE_MEDIAN
)
1037 rate_ctrl
->vbv_buffer_size
= MIN2((rate_ctrl
->target_bitrate
* 2.75), OMX_VID_ENC_BITRATE_MEDIAN
);
1039 rate_ctrl
->vbv_buffer_size
= rate_ctrl
->target_bitrate
;
1041 if (rate_ctrl
->frame_rate_num
) {
1042 unsigned long long t
= rate_ctrl
->target_bitrate
;
1043 t
*= rate_ctrl
->frame_rate_den
;
1044 rate_ctrl
->target_bits_picture
= t
/ rate_ctrl
->frame_rate_num
;
1046 rate_ctrl
->target_bits_picture
= rate_ctrl
->target_bitrate
;
1048 rate_ctrl
->peak_bits_picture_integer
= rate_ctrl
->target_bits_picture
;
1049 rate_ctrl
->peak_bits_picture_fraction
= 0;
1052 picture
->quant_i_frames
= priv
->quant
.nQpI
;
1053 picture
->quant_p_frames
= priv
->quant
.nQpP
;
1054 picture
->quant_b_frames
= priv
->quant
.nQpB
;
1056 picture
->frame_num
= priv
->frame_num
;
1057 picture
->ref_idx_l0
= priv
->ref_idx_l0
;
1058 picture
->ref_idx_l1
= priv
->ref_idx_l1
;
1061 static void enc_HandleTask(omx_base_PortType
*port
, struct encode_task
*task
,
1062 enum pipe_h264_enc_picture_type picture_type
)
1064 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
1065 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
1066 unsigned size
= priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
]->sPortParam
.nBufferSize
;
1067 struct pipe_video_buffer
*vbuf
= task
->buf
;
1068 struct pipe_h264_enc_picture_desc picture
= {};
1070 /* -------------- scale input image --------- */
1071 enc_ScaleInput(port
, &vbuf
, &size
);
1072 priv
->s_pipe
->flush(priv
->s_pipe
, NULL
, 0);
1074 /* -------------- allocate output buffer --------- */
1075 task
->bitstream
= pipe_buffer_create(priv
->s_pipe
->screen
, PIPE_BIND_VERTEX_BUFFER
,
1076 PIPE_USAGE_STREAM
, size
);
1078 picture
.picture_type
= picture_type
;
1079 picture
.pic_order_cnt
= task
->pic_order_cnt
;
1080 if (priv
->restricted_b_frames
&& picture_type
== PIPE_H264_ENC_PICTURE_TYPE_B
)
1081 picture
.not_referenced
= true;
1082 enc_ControlPicture(port
, &picture
);
1084 /* -------------- encode frame --------- */
1085 priv
->codec
->begin_frame(priv
->codec
, vbuf
, &picture
.base
);
1086 priv
->codec
->encode_bitstream(priv
->codec
, vbuf
, task
->bitstream
, &task
->feedback
);
1087 priv
->codec
->end_frame(priv
->codec
, vbuf
, &picture
.base
);
1090 static void enc_ClearBframes(omx_base_PortType
*port
, struct input_buf_private
*inp
)
1092 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
1093 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
1094 struct encode_task
*task
;
1096 if (LIST_IS_EMPTY(&priv
->b_frames
))
1099 task
= LIST_ENTRY(struct encode_task
, priv
->b_frames
.prev
, list
);
1100 LIST_DEL(&task
->list
);
1102 /* promote last from to P frame */
1103 priv
->ref_idx_l0
= priv
->ref_idx_l1
;
1104 enc_HandleTask(port
, task
, PIPE_H264_ENC_PICTURE_TYPE_P
);
1105 LIST_ADDTAIL(&task
->list
, &inp
->tasks
);
1106 priv
->ref_idx_l1
= priv
->frame_num
++;
1108 /* handle B frames */
1109 LIST_FOR_EACH_ENTRY(task
, &priv
->b_frames
, list
) {
1110 enc_HandleTask(port
, task
, PIPE_H264_ENC_PICTURE_TYPE_B
);
1111 if (!priv
->restricted_b_frames
)
1112 priv
->ref_idx_l0
= priv
->frame_num
;
1116 enc_MoveTasks(&priv
->b_frames
, &inp
->tasks
);
1119 static OMX_ERRORTYPE
vid_enc_EncodeFrame(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
*buf
)
1121 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
1122 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
1123 struct input_buf_private
*inp
= buf
->pInputPortPrivate
;
1124 enum pipe_h264_enc_picture_type picture_type
;
1125 struct encode_task
*task
;
1126 unsigned stacked_num
= 0;
1129 enc_MoveTasks(&inp
->tasks
, &priv
->free_tasks
);
1130 task
= enc_NeedTask(port
);
1132 return OMX_ErrorInsufficientResources
;
1134 if (buf
->nFilledLen
== 0) {
1135 if (buf
->nFlags
& OMX_BUFFERFLAG_EOS
) {
1136 buf
->nFilledLen
= buf
->nAllocLen
;
1137 enc_ClearBframes(port
, inp
);
1138 enc_MoveTasks(&priv
->stacked_tasks
, &inp
->tasks
);
1139 priv
->codec
->flush(priv
->codec
);
1141 return base_port_SendBufferFunction(port
, buf
);
1144 if (buf
->pOutputPortPrivate
) {
1145 struct pipe_video_buffer
*vbuf
= buf
->pOutputPortPrivate
;
1146 buf
->pOutputPortPrivate
= task
->buf
;
1149 /* ------- load input image into video buffer ---- */
1150 err
= enc_LoadImage(port
, buf
, task
->buf
);
1151 if (err
!= OMX_ErrorNone
)
1155 /* -------------- determine picture type --------- */
1156 if (!(priv
->pic_order_cnt
% OMX_VID_ENC_IDR_PERIOD_DEFAULT
) ||
1157 priv
->force_pic_type
.IntraRefreshVOP
) {
1158 enc_ClearBframes(port
, inp
);
1159 picture_type
= PIPE_H264_ENC_PICTURE_TYPE_IDR
;
1160 priv
->force_pic_type
.IntraRefreshVOP
= OMX_FALSE
;
1161 priv
->frame_num
= 0;
1162 } else if (priv
->codec
->profile
== PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE
||
1163 !(priv
->pic_order_cnt
% OMX_VID_ENC_P_PERIOD_DEFAULT
) ||
1164 (buf
->nFlags
& OMX_BUFFERFLAG_EOS
)) {
1165 picture_type
= PIPE_H264_ENC_PICTURE_TYPE_P
;
1167 picture_type
= PIPE_H264_ENC_PICTURE_TYPE_B
;
1170 task
->pic_order_cnt
= priv
->pic_order_cnt
++;
1172 if (picture_type
== PIPE_H264_ENC_PICTURE_TYPE_B
) {
1173 /* put frame at the tail of the queue */
1174 LIST_ADDTAIL(&task
->list
, &priv
->b_frames
);
1176 /* handle I or P frame */
1177 priv
->ref_idx_l0
= priv
->ref_idx_l1
;
1178 enc_HandleTask(port
, task
, picture_type
);
1179 LIST_ADDTAIL(&task
->list
, &priv
->stacked_tasks
);
1180 LIST_FOR_EACH_ENTRY(task
, &priv
->stacked_tasks
, list
) {
1183 if (stacked_num
== priv
->stacked_frames_num
) {
1184 struct encode_task
*t
;
1185 t
= LIST_ENTRY(struct encode_task
, priv
->stacked_tasks
.next
, list
);
1187 LIST_ADDTAIL(&t
->list
, &inp
->tasks
);
1189 priv
->ref_idx_l1
= priv
->frame_num
++;
1191 /* handle B frames */
1192 LIST_FOR_EACH_ENTRY(task
, &priv
->b_frames
, list
) {
1193 enc_HandleTask(port
, task
, PIPE_H264_ENC_PICTURE_TYPE_B
);
1194 if (!priv
->restricted_b_frames
)
1195 priv
->ref_idx_l0
= priv
->frame_num
;
1199 enc_MoveTasks(&priv
->b_frames
, &inp
->tasks
);
1202 if (LIST_IS_EMPTY(&inp
->tasks
))
1203 return port
->ReturnBufferFunction(port
, buf
);
1205 return base_port_SendBufferFunction(port
, buf
);
1208 static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE
*comp
, OMX_BUFFERHEADERTYPE
* input
, OMX_BUFFERHEADERTYPE
* output
)
1210 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
1211 struct output_buf_private
*outp
= output
->pOutputPortPrivate
;
1212 struct input_buf_private
*inp
= input
->pInputPortPrivate
;
1213 struct encode_task
*task
;
1214 struct pipe_box box
= {};
1217 if (!inp
|| LIST_IS_EMPTY(&inp
->tasks
)) {
1218 input
->nFilledLen
= 0; /* mark buffer as empty */
1219 enc_MoveTasks(&priv
->used_tasks
, &inp
->tasks
);
1223 task
= LIST_ENTRY(struct encode_task
, inp
->tasks
.next
, list
);
1224 LIST_DEL(&task
->list
);
1225 LIST_ADDTAIL(&task
->list
, &priv
->used_tasks
);
1227 if (!task
->bitstream
)
1230 /* ------------- map result buffer ----------------- */
1233 pipe_transfer_unmap(priv
->t_pipe
, outp
->transfer
);
1235 pipe_resource_reference(&outp
->bitstream
, task
->bitstream
);
1236 pipe_resource_reference(&task
->bitstream
, NULL
);
1238 box
.width
= outp
->bitstream
->width0
;
1239 box
.height
= outp
->bitstream
->height0
;
1240 box
.depth
= outp
->bitstream
->depth0
;
1242 output
->pBuffer
= priv
->t_pipe
->transfer_map(priv
->t_pipe
, outp
->bitstream
, 0,
1243 PIPE_TRANSFER_READ_WRITE
,
1244 &box
, &outp
->transfer
);
1246 /* ------------- get size of result ----------------- */
1248 priv
->codec
->get_feedback(priv
->codec
, task
->feedback
, &size
);
1250 output
->nOffset
= 0;
1251 output
->nFilledLen
= size
; /* mark buffer as full */