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
->s_pipe
= screen
->context_create(screen
, priv
->screen
, 0);
185 return OMX_ErrorInsufficientResources
;
187 if (!vl_compositor_init(&priv
->compositor
, priv
->s_pipe
)) {
188 priv
->s_pipe
->destroy(priv
->s_pipe
);
190 return OMX_ErrorInsufficientResources
;
193 if (!vl_compositor_init_state(&priv
->cstate
, priv
->s_pipe
)) {
194 vl_compositor_cleanup(&priv
->compositor
);
195 priv
->s_pipe
->destroy(priv
->s_pipe
);
197 return OMX_ErrorInsufficientResources
;
200 priv
->t_pipe
= screen
->context_create(screen
, priv
->screen
, 0);
202 return OMX_ErrorInsufficientResources
;
204 priv
->sPortTypesParam
[OMX_PortDomainVideo
].nStartPortNumber
= 0;
205 priv
->sPortTypesParam
[OMX_PortDomainVideo
].nPorts
= 2;
206 priv
->ports
= CALLOC(2, sizeof(omx_base_PortType
*));
208 return OMX_ErrorInsufficientResources
;
210 for (i
= 0; i
< 2; ++i
) {
211 priv
->ports
[i
] = CALLOC(1, sizeof(omx_base_video_PortType
));
213 return OMX_ErrorInsufficientResources
;
215 base_video_port_Constructor(comp
, &priv
->ports
[i
], i
, i
== 0);
218 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
219 port
->sPortParam
.format
.video
.nFrameWidth
= 176;
220 port
->sPortParam
.format
.video
.nFrameHeight
= 144;
221 port
->sPortParam
.format
.video
.eColorFormat
= OMX_COLOR_FormatYUV420SemiPlanar
;
222 port
->sVideoParam
.eColorFormat
= OMX_COLOR_FormatYUV420SemiPlanar
;
223 port
->sPortParam
.nBufferCountActual
= 8;
224 port
->sPortParam
.nBufferCountMin
= 4;
226 port
->Port_SendBufferFunction
= vid_enc_EncodeFrame
;
227 port
->Port_AllocateBuffer
= vid_enc_AllocateInBuffer
;
228 port
->Port_UseBuffer
= vid_enc_UseInBuffer
;
229 port
->Port_FreeBuffer
= vid_enc_FreeInBuffer
;
231 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
];
232 strcpy(port
->sPortParam
.format
.video
.cMIMEType
,"video/H264");
233 port
->sPortParam
.format
.video
.nFrameWidth
= 176;
234 port
->sPortParam
.format
.video
.nFrameHeight
= 144;
235 port
->sPortParam
.format
.video
.eCompressionFormat
= OMX_VIDEO_CodingAVC
;
236 port
->sVideoParam
.eCompressionFormat
= OMX_VIDEO_CodingAVC
;
238 port
->Port_AllocateBuffer
= vid_enc_AllocateOutBuffer
;
239 port
->Port_FreeBuffer
= vid_enc_FreeOutBuffer
;
241 priv
->bitrate
.eControlRate
= OMX_Video_ControlRateDisable
;
242 priv
->bitrate
.nTargetBitrate
= 0;
244 priv
->quant
.nQpI
= OMX_VID_ENC_QUANT_I_FRAMES_DEFAULT
;
245 priv
->quant
.nQpP
= OMX_VID_ENC_QUANT_P_FRAMES_DEFAULT
;
246 priv
->quant
.nQpB
= OMX_VID_ENC_QUANT_B_FRAMES_DEFAULT
;
248 priv
->profile_level
.eProfile
= OMX_VIDEO_AVCProfileBaseline
;
249 priv
->profile_level
.eLevel
= OMX_VIDEO_AVCLevel42
;
251 priv
->force_pic_type
.IntraRefreshVOP
= OMX_FALSE
;
253 priv
->pic_order_cnt
= 0;
254 priv
->restricted_b_frames
= debug_get_bool_option("OMX_USE_RESTRICTED_B_FRAMES", FALSE
);
256 priv
->scale
.xWidth
= OMX_VID_ENC_SCALING_WIDTH_DEFAULT
;
257 priv
->scale
.xHeight
= OMX_VID_ENC_SCALING_WIDTH_DEFAULT
;
259 LIST_INITHEAD(&priv
->free_tasks
);
260 LIST_INITHEAD(&priv
->used_tasks
);
261 LIST_INITHEAD(&priv
->b_frames
);
262 LIST_INITHEAD(&priv
->stacked_tasks
);
264 return OMX_ErrorNone
;
267 static OMX_ERRORTYPE
vid_enc_Destructor(OMX_COMPONENTTYPE
*comp
)
269 vid_enc_PrivateType
* priv
= comp
->pComponentPrivate
;
272 enc_ReleaseTasks(&priv
->free_tasks
);
273 enc_ReleaseTasks(&priv
->used_tasks
);
274 enc_ReleaseTasks(&priv
->b_frames
);
275 enc_ReleaseTasks(&priv
->stacked_tasks
);
278 for (i
= 0; i
< priv
->sPortTypesParam
[OMX_PortDomainVideo
].nPorts
; ++i
) {
280 priv
->ports
[i
]->PortDestructor(priv
->ports
[i
]);
286 for (i
= 0; i
< OMX_VID_ENC_NUM_SCALING_BUFFERS
; ++i
)
287 if (priv
->scale_buffer
[i
])
288 priv
->scale_buffer
[i
]->destroy(priv
->scale_buffer
[i
]);
291 vl_compositor_cleanup_state(&priv
->cstate
);
292 vl_compositor_cleanup(&priv
->compositor
);
293 priv
->s_pipe
->destroy(priv
->s_pipe
);
297 priv
->t_pipe
->destroy(priv
->t_pipe
);
302 return omx_workaround_Destructor(comp
);
305 static OMX_ERRORTYPE
enc_AllocateBackTexture(omx_base_PortType
*port
,
306 struct pipe_resource
**resource
,
307 struct pipe_transfer
**transfer
,
310 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
311 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
312 struct pipe_resource buf_templ
;
313 struct pipe_box box
= {};
316 memset(&buf_templ
, 0, sizeof buf_templ
);
317 buf_templ
.target
= PIPE_TEXTURE_2D
;
318 buf_templ
.format
= PIPE_FORMAT_I8_UNORM
;
319 buf_templ
.bind
= PIPE_BIND_LINEAR
;
320 buf_templ
.usage
= PIPE_USAGE_STAGING
;
322 buf_templ
.width0
= port
->sPortParam
.format
.video
.nFrameWidth
;
323 buf_templ
.height0
= port
->sPortParam
.format
.video
.nFrameHeight
* 3 / 2;
324 buf_templ
.depth0
= 1;
325 buf_templ
.array_size
= 1;
327 *resource
= priv
->s_pipe
->screen
->resource_create(priv
->s_pipe
->screen
, &buf_templ
);
329 return OMX_ErrorInsufficientResources
;
331 box
.width
= (*resource
)->width0
;
332 box
.height
= (*resource
)->height0
;
333 box
.depth
= (*resource
)->depth0
;
334 ptr
= priv
->s_pipe
->transfer_map(priv
->s_pipe
, *resource
, 0, PIPE_TRANSFER_WRITE
, &box
, transfer
);
338 return OMX_ErrorNone
;
341 static OMX_ERRORTYPE
vid_enc_SetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
)
343 OMX_COMPONENTTYPE
*comp
= handle
;
344 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
348 return OMX_ErrorBadParameter
;
351 case OMX_IndexParamPortDefinition
: {
352 OMX_PARAM_PORTDEFINITIONTYPE
*def
= param
;
354 r
= omx_base_component_SetParameter(handle
, idx
, param
);
358 if (def
->nPortIndex
== OMX_BASE_FILTER_INPUTPORT_INDEX
) {
359 omx_base_video_PortType
*port
;
361 struct pipe_resource
*resource
;
362 struct pipe_transfer
*transfer
;
364 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
365 enc_AllocateBackTexture(priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
],
366 &resource
, &transfer
, NULL
);
367 port
->sPortParam
.format
.video
.nStride
= transfer
->stride
;
368 pipe_transfer_unmap(priv
->s_pipe
, transfer
);
369 pipe_resource_reference(&resource
, NULL
);
371 framesize
= port
->sPortParam
.format
.video
.nStride
*
372 port
->sPortParam
.format
.video
.nFrameHeight
;
373 port
->sPortParam
.format
.video
.nSliceHeight
= port
->sPortParam
.format
.video
.nFrameHeight
;
374 port
->sPortParam
.nBufferSize
= framesize
* 3 / 2;
376 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
];
377 port
->sPortParam
.nBufferSize
= framesize
* 512 / (16*16);
379 priv
->frame_rate
= def
->format
.video
.xFramerate
;
381 priv
->callbacks
->EventHandler(comp
, priv
->callbackData
, OMX_EventPortSettingsChanged
,
382 OMX_BASE_FILTER_OUTPUTPORT_INDEX
, 0, NULL
);
386 case OMX_IndexParamStandardComponentRole
: {
387 OMX_PARAM_COMPONENTROLETYPE
*role
= param
;
389 r
= checkHeader(param
, sizeof(OMX_PARAM_COMPONENTROLETYPE
));
393 if (strcmp((char *)role
->cRole
, OMX_VID_ENC_AVC_ROLE
)) {
394 return OMX_ErrorBadParameter
;
399 case OMX_IndexParamVideoBitrate
: {
400 OMX_VIDEO_PARAM_BITRATETYPE
*bitrate
= param
;
402 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_BITRATETYPE
));
406 priv
->bitrate
= *bitrate
;
410 case OMX_IndexParamVideoQuantization
: {
411 OMX_VIDEO_PARAM_QUANTIZATIONTYPE
*quant
= param
;
413 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE
));
417 priv
->quant
= *quant
;
421 case OMX_IndexParamVideoProfileLevelCurrent
: {
422 OMX_VIDEO_PARAM_PROFILELEVELTYPE
*profile_level
= param
;
424 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE
));
428 priv
->profile_level
= *profile_level
;
433 return omx_base_component_SetParameter(handle
, idx
, param
);
435 return OMX_ErrorNone
;
438 static OMX_ERRORTYPE
vid_enc_GetParameter(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR param
)
440 OMX_COMPONENTTYPE
*comp
= handle
;
441 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
445 return OMX_ErrorBadParameter
;
448 case OMX_IndexParamStandardComponentRole
: {
449 OMX_PARAM_COMPONENTROLETYPE
*role
= param
;
451 r
= checkHeader(param
, sizeof(OMX_PARAM_COMPONENTROLETYPE
));
455 strcpy((char *)role
->cRole
, OMX_VID_ENC_AVC_ROLE
);
458 case OMX_IndexParamVideoInit
:
459 r
= checkHeader(param
, sizeof(OMX_PORT_PARAM_TYPE
));
463 memcpy(param
, &priv
->sPortTypesParam
[OMX_PortDomainVideo
], sizeof(OMX_PORT_PARAM_TYPE
));
466 case OMX_IndexParamVideoPortFormat
: {
467 OMX_VIDEO_PARAM_PORTFORMATTYPE
*format
= param
;
468 omx_base_video_PortType
*port
;
470 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
474 if (format
->nPortIndex
> 1)
475 return OMX_ErrorBadPortIndex
;
477 port
= (omx_base_video_PortType
*)priv
->ports
[format
->nPortIndex
];
478 memcpy(format
, &port
->sVideoParam
, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE
));
481 case OMX_IndexParamVideoBitrate
: {
482 OMX_VIDEO_PARAM_BITRATETYPE
*bitrate
= param
;
484 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_BITRATETYPE
));
488 bitrate
->eControlRate
= priv
->bitrate
.eControlRate
;
489 bitrate
->nTargetBitrate
= priv
->bitrate
.nTargetBitrate
;
493 case OMX_IndexParamVideoQuantization
: {
494 OMX_VIDEO_PARAM_QUANTIZATIONTYPE
*quant
= param
;
496 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE
));
500 quant
->nQpI
= priv
->quant
.nQpI
;
501 quant
->nQpP
= priv
->quant
.nQpP
;
502 quant
->nQpB
= priv
->quant
.nQpB
;
506 case OMX_IndexParamVideoProfileLevelCurrent
: {
507 OMX_VIDEO_PARAM_PROFILELEVELTYPE
*profile_level
= param
;
509 r
= checkHeader(param
, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE
));
513 profile_level
->eProfile
= priv
->profile_level
.eProfile
;
514 profile_level
->eLevel
= priv
->profile_level
.eLevel
;
519 return omx_base_component_GetParameter(handle
, idx
, param
);
521 return OMX_ErrorNone
;
524 static OMX_ERRORTYPE
vid_enc_SetConfig(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR config
)
526 OMX_COMPONENTTYPE
*comp
= handle
;
527 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
532 return OMX_ErrorBadParameter
;
535 case OMX_IndexConfigVideoIntraVOPRefresh
: {
536 OMX_CONFIG_INTRAREFRESHVOPTYPE
*type
= config
;
538 r
= checkHeader(config
, sizeof(OMX_CONFIG_INTRAREFRESHVOPTYPE
));
542 priv
->force_pic_type
= *type
;
546 case OMX_IndexConfigCommonScale
: {
547 OMX_CONFIG_SCALEFACTORTYPE
*scale
= config
;
549 r
= checkHeader(config
, sizeof(OMX_CONFIG_SCALEFACTORTYPE
));
553 if (scale
->xWidth
< 176 || scale
->xHeight
< 144)
554 return OMX_ErrorBadParameter
;
556 for (i
= 0; i
< OMX_VID_ENC_NUM_SCALING_BUFFERS
; ++i
) {
557 if (priv
->scale_buffer
[i
]) {
558 priv
->scale_buffer
[i
]->destroy(priv
->scale_buffer
[i
]);
559 priv
->scale_buffer
[i
] = NULL
;
563 priv
->scale
= *scale
;
564 if (priv
->scale
.xWidth
!= 0xffffffff && priv
->scale
.xHeight
!= 0xffffffff) {
565 struct pipe_video_buffer templat
= {};
567 templat
.buffer_format
= PIPE_FORMAT_NV12
;
568 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
569 templat
.width
= priv
->scale
.xWidth
;
570 templat
.height
= priv
->scale
.xHeight
;
571 templat
.interlaced
= false;
572 for (i
= 0; i
< OMX_VID_ENC_NUM_SCALING_BUFFERS
; ++i
) {
573 priv
->scale_buffer
[i
] = priv
->s_pipe
->create_video_buffer(priv
->s_pipe
, &templat
);
574 if (!priv
->scale_buffer
[i
])
575 return OMX_ErrorInsufficientResources
;
582 return omx_base_component_SetConfig(handle
, idx
, config
);
585 return OMX_ErrorNone
;
588 static OMX_ERRORTYPE
vid_enc_GetConfig(OMX_HANDLETYPE handle
, OMX_INDEXTYPE idx
, OMX_PTR config
)
590 OMX_COMPONENTTYPE
*comp
= handle
;
591 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
595 return OMX_ErrorBadParameter
;
598 case OMX_IndexConfigCommonScale
: {
599 OMX_CONFIG_SCALEFACTORTYPE
*scale
= config
;
601 r
= checkHeader(config
, sizeof(OMX_CONFIG_SCALEFACTORTYPE
));
605 scale
->xWidth
= priv
->scale
.xWidth
;
606 scale
->xHeight
= priv
->scale
.xHeight
;
611 return omx_base_component_GetConfig(handle
, idx
, config
);
614 return OMX_ErrorNone
;
617 static enum pipe_video_profile
enc_TranslateOMXProfileToPipe(unsigned omx_profile
)
619 switch (omx_profile
) {
620 case OMX_VIDEO_AVCProfileBaseline
:
621 return PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE
;
622 case OMX_VIDEO_AVCProfileMain
:
623 return PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN
;
624 case OMX_VIDEO_AVCProfileExtended
:
625 return PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED
;
626 case OMX_VIDEO_AVCProfileHigh
:
627 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
;
628 case OMX_VIDEO_AVCProfileHigh10
:
629 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10
;
630 case OMX_VIDEO_AVCProfileHigh422
:
631 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH422
;
632 case OMX_VIDEO_AVCProfileHigh444
:
633 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH444
;
635 return PIPE_VIDEO_PROFILE_UNKNOWN
;
639 static unsigned enc_TranslateOMXLevelToPipe(unsigned omx_level
)
642 case OMX_VIDEO_AVCLevel1
:
643 case OMX_VIDEO_AVCLevel1b
:
645 case OMX_VIDEO_AVCLevel11
:
647 case OMX_VIDEO_AVCLevel12
:
649 case OMX_VIDEO_AVCLevel13
:
651 case OMX_VIDEO_AVCLevel2
:
653 case OMX_VIDEO_AVCLevel21
:
655 case OMX_VIDEO_AVCLevel22
:
657 case OMX_VIDEO_AVCLevel3
:
659 case OMX_VIDEO_AVCLevel31
:
661 case OMX_VIDEO_AVCLevel32
:
663 case OMX_VIDEO_AVCLevel4
:
665 case OMX_VIDEO_AVCLevel41
:
668 case OMX_VIDEO_AVCLevel42
:
670 case OMX_VIDEO_AVCLevel5
:
672 case OMX_VIDEO_AVCLevel51
:
677 static OMX_ERRORTYPE
vid_enc_MessageHandler(OMX_COMPONENTTYPE
* comp
, internalRequestMessageType
*msg
)
679 vid_enc_PrivateType
* priv
= comp
->pComponentPrivate
;
681 if (msg
->messageType
== OMX_CommandStateSet
) {
682 if ((msg
->messageParam
== OMX_StateIdle
) && (priv
->state
== OMX_StateLoaded
)) {
684 struct pipe_video_codec templat
= {};
685 omx_base_video_PortType
*port
;
687 port
= (omx_base_video_PortType
*)priv
->ports
[OMX_BASE_FILTER_INPUTPORT_INDEX
];
689 templat
.profile
= enc_TranslateOMXProfileToPipe(priv
->profile_level
.eProfile
);
690 templat
.level
= enc_TranslateOMXLevelToPipe(priv
->profile_level
.eLevel
);
691 templat
.entrypoint
= PIPE_VIDEO_ENTRYPOINT_ENCODE
;
692 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
693 templat
.width
= priv
->scale_buffer
[priv
->current_scale_buffer
] ?
694 priv
->scale
.xWidth
: port
->sPortParam
.format
.video
.nFrameWidth
;
695 templat
.height
= priv
->scale_buffer
[priv
->current_scale_buffer
] ?
696 priv
->scale
.xHeight
: port
->sPortParam
.format
.video
.nFrameHeight
;
698 if (templat
.profile
== PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE
) {
699 struct pipe_screen
*screen
= priv
->screen
->pscreen
;
700 templat
.max_references
= 1;
701 priv
->stacked_frames_num
=
702 screen
->get_video_param(screen
,
703 PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
,
704 PIPE_VIDEO_ENTRYPOINT_ENCODE
,
705 PIPE_VIDEO_CAP_STACKED_FRAMES
);
707 templat
.max_references
= OMX_VID_ENC_P_PERIOD_DEFAULT
;
708 priv
->stacked_frames_num
= 1;
710 priv
->codec
= priv
->s_pipe
->create_video_codec(priv
->s_pipe
, &templat
);
712 } else if ((msg
->messageParam
== OMX_StateLoaded
) && (priv
->state
== OMX_StateIdle
)) {
714 priv
->codec
->destroy(priv
->codec
);
720 return omx_base_component_MessageHandler(comp
, msg
);
723 static OMX_ERRORTYPE
vid_enc_AllocateInBuffer(omx_base_PortType
*port
, OMX_INOUT OMX_BUFFERHEADERTYPE
**buf
,
724 OMX_IN OMX_U32 idx
, OMX_IN OMX_PTR
private, OMX_IN OMX_U32 size
)
726 struct input_buf_private
*inp
;
729 r
= base_port_AllocateBuffer(port
, buf
, idx
, private, size
);
733 inp
= (*buf
)->pInputPortPrivate
= CALLOC_STRUCT(input_buf_private
);
735 base_port_FreeBuffer(port
, idx
, *buf
);
736 return OMX_ErrorInsufficientResources
;
739 LIST_INITHEAD(&inp
->tasks
);
741 FREE((*buf
)->pBuffer
);
742 r
= enc_AllocateBackTexture(port
, &inp
->resource
, &inp
->transfer
, &(*buf
)->pBuffer
);
745 base_port_FreeBuffer(port
, idx
, *buf
);
749 return OMX_ErrorNone
;
752 static OMX_ERRORTYPE
vid_enc_UseInBuffer(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
**buf
, OMX_U32 idx
,
753 OMX_PTR
private, OMX_U32 size
, OMX_U8
*mem
)
755 struct input_buf_private
*inp
;
758 r
= base_port_UseBuffer(port
, buf
, idx
, private, size
, mem
);
762 inp
= (*buf
)->pInputPortPrivate
= CALLOC_STRUCT(input_buf_private
);
764 base_port_FreeBuffer(port
, idx
, *buf
);
765 return OMX_ErrorInsufficientResources
;
768 LIST_INITHEAD(&inp
->tasks
);
770 return OMX_ErrorNone
;
773 static OMX_ERRORTYPE
vid_enc_FreeInBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
)
775 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
776 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
777 struct input_buf_private
*inp
= buf
->pInputPortPrivate
;
780 enc_ReleaseTasks(&inp
->tasks
);
782 pipe_transfer_unmap(priv
->s_pipe
, inp
->transfer
);
783 pipe_resource_reference(&inp
->resource
, NULL
);
788 return base_port_FreeBuffer(port
, idx
, buf
);
791 static OMX_ERRORTYPE
vid_enc_AllocateOutBuffer(omx_base_PortType
*port
, OMX_INOUT OMX_BUFFERHEADERTYPE
**buf
,
792 OMX_IN OMX_U32 idx
, OMX_IN OMX_PTR
private, OMX_IN OMX_U32 size
)
796 r
= base_port_AllocateBuffer(port
, buf
, idx
, private, size
);
800 FREE((*buf
)->pBuffer
);
801 (*buf
)->pBuffer
= NULL
;
802 (*buf
)->pOutputPortPrivate
= CALLOC(1, sizeof(struct output_buf_private
));
803 if (!(*buf
)->pOutputPortPrivate
) {
804 base_port_FreeBuffer(port
, idx
, *buf
);
805 return OMX_ErrorInsufficientResources
;
808 return OMX_ErrorNone
;
811 static OMX_ERRORTYPE
vid_enc_FreeOutBuffer(omx_base_PortType
*port
, OMX_U32 idx
, OMX_BUFFERHEADERTYPE
*buf
)
813 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
814 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
816 if (buf
->pOutputPortPrivate
) {
817 struct output_buf_private
*outp
= buf
->pOutputPortPrivate
;
819 pipe_transfer_unmap(priv
->t_pipe
, outp
->transfer
);
820 pipe_resource_reference(&outp
->bitstream
, NULL
);
822 buf
->pOutputPortPrivate
= NULL
;
826 return base_port_FreeBuffer(port
, idx
, buf
);
829 static struct encode_task
*enc_NeedTask(omx_base_PortType
*port
)
831 OMX_VIDEO_PORTDEFINITIONTYPE
*def
= &port
->sPortParam
.format
.video
;
832 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
833 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
835 struct pipe_video_buffer templat
= {};
836 struct encode_task
*task
;
838 if (!LIST_IS_EMPTY(&priv
->free_tasks
)) {
839 task
= LIST_ENTRY(struct encode_task
, priv
->free_tasks
.next
, list
);
840 LIST_DEL(&task
->list
);
844 /* allocate a new one */
845 task
= CALLOC_STRUCT(encode_task
);
849 templat
.buffer_format
= PIPE_FORMAT_NV12
;
850 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
851 templat
.width
= def
->nFrameWidth
;
852 templat
.height
= def
->nFrameHeight
;
853 templat
.interlaced
= false;
855 task
->buf
= priv
->s_pipe
->create_video_buffer(priv
->s_pipe
, &templat
);
864 static void enc_MoveTasks(struct list_head
*from
, struct list_head
*to
)
866 to
->prev
->next
= from
->next
;
867 from
->next
->prev
= to
->prev
;
868 from
->prev
->next
= to
;
869 to
->prev
= from
->prev
;
873 static void enc_ReleaseTasks(struct list_head
*head
)
875 struct encode_task
*i
, *next
;
880 LIST_FOR_EACH_ENTRY_SAFE(i
, next
, head
, list
) {
881 pipe_resource_reference(&i
->bitstream
, NULL
);
882 i
->buf
->destroy(i
->buf
);
887 static OMX_ERRORTYPE
enc_LoadImage(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
*buf
,
888 struct pipe_video_buffer
*vbuf
)
890 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
891 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
892 OMX_VIDEO_PORTDEFINITIONTYPE
*def
= &port
->sPortParam
.format
.video
;
893 struct pipe_box box
= {};
894 struct input_buf_private
*inp
= buf
->pInputPortPrivate
;
896 if (!inp
->resource
) {
897 struct pipe_sampler_view
**views
;
900 views
= vbuf
->get_sampler_view_planes(vbuf
);
902 return OMX_ErrorInsufficientResources
;
905 box
.width
= def
->nFrameWidth
;
906 box
.height
= def
->nFrameHeight
;
908 priv
->s_pipe
->transfer_inline_write(priv
->s_pipe
, views
[0]->texture
, 0,
909 PIPE_TRANSFER_WRITE
, &box
,
910 ptr
, def
->nStride
, 0);
911 ptr
= ((uint8_t*)buf
->pBuffer
) + (def
->nStride
* box
.height
);
912 box
.width
= def
->nFrameWidth
/ 2;
913 box
.height
= def
->nFrameHeight
/ 2;
915 priv
->s_pipe
->transfer_inline_write(priv
->s_pipe
, views
[1]->texture
, 0,
916 PIPE_TRANSFER_WRITE
, &box
,
917 ptr
, def
->nStride
, 0);
919 struct pipe_blit_info blit
;
920 struct vl_video_buffer
*dst_buf
= (struct vl_video_buffer
*)vbuf
;
922 pipe_transfer_unmap(priv
->s_pipe
, inp
->transfer
);
924 box
.width
= def
->nFrameWidth
;
925 box
.height
= def
->nFrameHeight
;
928 priv
->s_pipe
->resource_copy_region(priv
->s_pipe
,
929 dst_buf
->resources
[0],
930 0, 0, 0, 0, inp
->resource
, 0, &box
);
932 memset(&blit
, 0, sizeof(blit
));
933 blit
.src
.resource
= inp
->resource
;
934 blit
.src
.format
= inp
->resource
->format
;
937 blit
.src
.box
.y
= def
->nFrameHeight
;
938 blit
.src
.box
.width
= def
->nFrameWidth
;
939 blit
.src
.box
.height
= def
->nFrameHeight
/ 2 ;
940 blit
.src
.box
.depth
= 1;
942 blit
.dst
.resource
= dst_buf
->resources
[1];
943 blit
.dst
.format
= blit
.dst
.resource
->format
;
945 blit
.dst
.box
.width
= def
->nFrameWidth
/ 2;
946 blit
.dst
.box
.height
= def
->nFrameHeight
/ 2;
947 blit
.dst
.box
.depth
= 1;
948 blit
.filter
= PIPE_TEX_FILTER_NEAREST
;
950 blit
.mask
= PIPE_MASK_G
;
951 priv
->s_pipe
->blit(priv
->s_pipe
, &blit
);
954 blit
.mask
= PIPE_MASK_R
;
955 priv
->s_pipe
->blit(priv
->s_pipe
, &blit
);
956 priv
->s_pipe
->flush(priv
->s_pipe
, NULL
, 0);
958 box
.width
= inp
->resource
->width0
;
959 box
.height
= inp
->resource
->height0
;
960 box
.depth
= inp
->resource
->depth0
;
961 buf
->pBuffer
= priv
->s_pipe
->transfer_map(priv
->s_pipe
, inp
->resource
, 0,
962 PIPE_TRANSFER_WRITE
, &box
,
966 return OMX_ErrorNone
;
969 static void enc_ScaleInput(omx_base_PortType
*port
, struct pipe_video_buffer
**vbuf
, unsigned *size
)
971 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
972 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
973 OMX_VIDEO_PORTDEFINITIONTYPE
*def
= &port
->sPortParam
.format
.video
;
974 struct pipe_video_buffer
*src_buf
= *vbuf
;
975 struct vl_compositor
*compositor
= &priv
->compositor
;
976 struct vl_compositor_state
*s
= &priv
->cstate
;
977 struct pipe_sampler_view
**views
;
978 struct pipe_surface
**dst_surface
;
981 if (!priv
->scale_buffer
[priv
->current_scale_buffer
])
984 views
= src_buf
->get_sampler_view_planes(src_buf
);
985 dst_surface
= priv
->scale_buffer
[priv
->current_scale_buffer
]->get_surfaces
986 (priv
->scale_buffer
[priv
->current_scale_buffer
]);
987 vl_compositor_clear_layers(s
);
989 for (i
= 0; i
< VL_MAX_SURFACES
; ++i
) {
990 struct u_rect src_rect
;
991 if (!views
[i
] || !dst_surface
[i
])
995 src_rect
.x1
= def
->nFrameWidth
;
996 src_rect
.y1
= def
->nFrameHeight
;
1001 vl_compositor_set_rgba_layer(s
, compositor
, 0, views
[i
], &src_rect
, NULL
, NULL
);
1002 vl_compositor_render(s
, compositor
, dst_surface
[i
], NULL
, false);
1004 *size
= priv
->scale
.xWidth
* priv
->scale
.xHeight
* 2;
1005 *vbuf
= priv
->scale_buffer
[priv
->current_scale_buffer
++];
1006 priv
->current_scale_buffer
%= OMX_VID_ENC_NUM_SCALING_BUFFERS
;
1009 static void enc_GetPictureParamPreset(struct pipe_h264_enc_picture_desc
*picture
)
1011 picture
->motion_est
.enc_disable_sub_mode
= 0x000000fe;
1012 picture
->motion_est
.enc_ime2_search_range_x
= 0x00000001;
1013 picture
->motion_est
.enc_ime2_search_range_y
= 0x00000001;
1014 picture
->pic_ctrl
.enc_constraint_set_flags
= 0x00000040;
1017 static void enc_ControlPicture(omx_base_PortType
*port
, struct pipe_h264_enc_picture_desc
*picture
)
1019 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
1020 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
1021 struct pipe_h264_enc_rate_control
*rate_ctrl
= &picture
->rate_ctrl
;
1023 switch (priv
->bitrate
.eControlRate
) {
1024 case OMX_Video_ControlRateVariable
:
1025 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE
;
1027 case OMX_Video_ControlRateConstant
:
1028 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT
;
1030 case OMX_Video_ControlRateVariableSkipFrames
:
1031 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP
;
1033 case OMX_Video_ControlRateConstantSkipFrames
:
1034 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP
;
1037 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_DISABLE
;
1041 rate_ctrl
->frame_rate_den
= OMX_VID_ENC_CONTROL_FRAME_RATE_DEN_DEFAULT
;
1042 rate_ctrl
->frame_rate_num
= ((priv
->frame_rate
) >> 16) * rate_ctrl
->frame_rate_den
;
1044 if (rate_ctrl
->rate_ctrl_method
!= PIPE_H264_ENC_RATE_CONTROL_METHOD_DISABLE
) {
1045 if (priv
->bitrate
.nTargetBitrate
< OMX_VID_ENC_BITRATE_MIN
)
1046 rate_ctrl
->target_bitrate
= OMX_VID_ENC_BITRATE_MIN
;
1047 else if (priv
->bitrate
.nTargetBitrate
< OMX_VID_ENC_BITRATE_MAX
)
1048 rate_ctrl
->target_bitrate
= priv
->bitrate
.nTargetBitrate
;
1050 rate_ctrl
->target_bitrate
= OMX_VID_ENC_BITRATE_MAX
;
1051 rate_ctrl
->peak_bitrate
= rate_ctrl
->target_bitrate
;
1052 if (rate_ctrl
->target_bitrate
< OMX_VID_ENC_BITRATE_MEDIAN
)
1053 rate_ctrl
->vbv_buffer_size
= MIN2((rate_ctrl
->target_bitrate
* 2.75), OMX_VID_ENC_BITRATE_MEDIAN
);
1055 rate_ctrl
->vbv_buffer_size
= rate_ctrl
->target_bitrate
;
1057 if (rate_ctrl
->frame_rate_num
) {
1058 unsigned long long t
= rate_ctrl
->target_bitrate
;
1059 t
*= rate_ctrl
->frame_rate_den
;
1060 rate_ctrl
->target_bits_picture
= t
/ rate_ctrl
->frame_rate_num
;
1062 rate_ctrl
->target_bits_picture
= rate_ctrl
->target_bitrate
;
1064 rate_ctrl
->peak_bits_picture_integer
= rate_ctrl
->target_bits_picture
;
1065 rate_ctrl
->peak_bits_picture_fraction
= 0;
1068 picture
->quant_i_frames
= priv
->quant
.nQpI
;
1069 picture
->quant_p_frames
= priv
->quant
.nQpP
;
1070 picture
->quant_b_frames
= priv
->quant
.nQpB
;
1072 picture
->frame_num
= priv
->frame_num
;
1073 picture
->ref_idx_l0
= priv
->ref_idx_l0
;
1074 picture
->ref_idx_l1
= priv
->ref_idx_l1
;
1075 picture
->enable_vui
= (picture
->rate_ctrl
.frame_rate_num
!= 0);
1076 enc_GetPictureParamPreset(picture
);
1079 static void enc_HandleTask(omx_base_PortType
*port
, struct encode_task
*task
,
1080 enum pipe_h264_enc_picture_type picture_type
)
1082 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
1083 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
1084 unsigned size
= priv
->ports
[OMX_BASE_FILTER_OUTPUTPORT_INDEX
]->sPortParam
.nBufferSize
;
1085 struct pipe_video_buffer
*vbuf
= task
->buf
;
1086 struct pipe_h264_enc_picture_desc picture
= {};
1088 /* -------------- scale input image --------- */
1089 enc_ScaleInput(port
, &vbuf
, &size
);
1090 priv
->s_pipe
->flush(priv
->s_pipe
, NULL
, 0);
1092 /* -------------- allocate output buffer --------- */
1093 task
->bitstream
= pipe_buffer_create(priv
->s_pipe
->screen
, PIPE_BIND_VERTEX_BUFFER
,
1094 PIPE_USAGE_STREAM
, size
);
1096 picture
.picture_type
= picture_type
;
1097 picture
.pic_order_cnt
= task
->pic_order_cnt
;
1098 if (priv
->restricted_b_frames
&& picture_type
== PIPE_H264_ENC_PICTURE_TYPE_B
)
1099 picture
.not_referenced
= true;
1100 enc_ControlPicture(port
, &picture
);
1102 /* -------------- encode frame --------- */
1103 priv
->codec
->begin_frame(priv
->codec
, vbuf
, &picture
.base
);
1104 priv
->codec
->encode_bitstream(priv
->codec
, vbuf
, task
->bitstream
, &task
->feedback
);
1105 priv
->codec
->end_frame(priv
->codec
, vbuf
, &picture
.base
);
1108 static void enc_ClearBframes(omx_base_PortType
*port
, struct input_buf_private
*inp
)
1110 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
1111 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
1112 struct encode_task
*task
;
1114 if (LIST_IS_EMPTY(&priv
->b_frames
))
1117 task
= LIST_ENTRY(struct encode_task
, priv
->b_frames
.prev
, list
);
1118 LIST_DEL(&task
->list
);
1120 /* promote last from to P frame */
1121 priv
->ref_idx_l0
= priv
->ref_idx_l1
;
1122 enc_HandleTask(port
, task
, PIPE_H264_ENC_PICTURE_TYPE_P
);
1123 LIST_ADDTAIL(&task
->list
, &inp
->tasks
);
1124 priv
->ref_idx_l1
= priv
->frame_num
++;
1126 /* handle B frames */
1127 LIST_FOR_EACH_ENTRY(task
, &priv
->b_frames
, list
) {
1128 enc_HandleTask(port
, task
, PIPE_H264_ENC_PICTURE_TYPE_B
);
1129 if (!priv
->restricted_b_frames
)
1130 priv
->ref_idx_l0
= priv
->frame_num
;
1134 enc_MoveTasks(&priv
->b_frames
, &inp
->tasks
);
1137 static OMX_ERRORTYPE
vid_enc_EncodeFrame(omx_base_PortType
*port
, OMX_BUFFERHEADERTYPE
*buf
)
1139 OMX_COMPONENTTYPE
* comp
= port
->standCompContainer
;
1140 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
1141 struct input_buf_private
*inp
= buf
->pInputPortPrivate
;
1142 enum pipe_h264_enc_picture_type picture_type
;
1143 struct encode_task
*task
;
1144 unsigned stacked_num
= 0;
1147 enc_MoveTasks(&inp
->tasks
, &priv
->free_tasks
);
1148 task
= enc_NeedTask(port
);
1150 return OMX_ErrorInsufficientResources
;
1152 if (buf
->nFilledLen
== 0) {
1153 if (buf
->nFlags
& OMX_BUFFERFLAG_EOS
) {
1154 buf
->nFilledLen
= buf
->nAllocLen
;
1155 enc_ClearBframes(port
, inp
);
1156 enc_MoveTasks(&priv
->stacked_tasks
, &inp
->tasks
);
1157 priv
->codec
->flush(priv
->codec
);
1159 return base_port_SendBufferFunction(port
, buf
);
1162 if (buf
->pOutputPortPrivate
) {
1163 struct pipe_video_buffer
*vbuf
= buf
->pOutputPortPrivate
;
1164 buf
->pOutputPortPrivate
= task
->buf
;
1167 /* ------- load input image into video buffer ---- */
1168 err
= enc_LoadImage(port
, buf
, task
->buf
);
1169 if (err
!= OMX_ErrorNone
) {
1175 /* -------------- determine picture type --------- */
1176 if (!(priv
->pic_order_cnt
% OMX_VID_ENC_IDR_PERIOD_DEFAULT
) ||
1177 priv
->force_pic_type
.IntraRefreshVOP
) {
1178 enc_ClearBframes(port
, inp
);
1179 picture_type
= PIPE_H264_ENC_PICTURE_TYPE_IDR
;
1180 priv
->force_pic_type
.IntraRefreshVOP
= OMX_FALSE
;
1181 priv
->frame_num
= 0;
1182 } else if (priv
->codec
->profile
== PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE
||
1183 !(priv
->pic_order_cnt
% OMX_VID_ENC_P_PERIOD_DEFAULT
) ||
1184 (buf
->nFlags
& OMX_BUFFERFLAG_EOS
)) {
1185 picture_type
= PIPE_H264_ENC_PICTURE_TYPE_P
;
1187 picture_type
= PIPE_H264_ENC_PICTURE_TYPE_B
;
1190 task
->pic_order_cnt
= priv
->pic_order_cnt
++;
1192 if (picture_type
== PIPE_H264_ENC_PICTURE_TYPE_B
) {
1193 /* put frame at the tail of the queue */
1194 LIST_ADDTAIL(&task
->list
, &priv
->b_frames
);
1196 /* handle I or P frame */
1197 priv
->ref_idx_l0
= priv
->ref_idx_l1
;
1198 enc_HandleTask(port
, task
, picture_type
);
1199 LIST_ADDTAIL(&task
->list
, &priv
->stacked_tasks
);
1200 LIST_FOR_EACH_ENTRY(task
, &priv
->stacked_tasks
, list
) {
1203 if (stacked_num
== priv
->stacked_frames_num
) {
1204 struct encode_task
*t
;
1205 t
= LIST_ENTRY(struct encode_task
, priv
->stacked_tasks
.next
, list
);
1207 LIST_ADDTAIL(&t
->list
, &inp
->tasks
);
1209 priv
->ref_idx_l1
= priv
->frame_num
++;
1211 /* handle B frames */
1212 LIST_FOR_EACH_ENTRY(task
, &priv
->b_frames
, list
) {
1213 enc_HandleTask(port
, task
, PIPE_H264_ENC_PICTURE_TYPE_B
);
1214 if (!priv
->restricted_b_frames
)
1215 priv
->ref_idx_l0
= priv
->frame_num
;
1219 enc_MoveTasks(&priv
->b_frames
, &inp
->tasks
);
1222 if (LIST_IS_EMPTY(&inp
->tasks
))
1223 return port
->ReturnBufferFunction(port
, buf
);
1225 return base_port_SendBufferFunction(port
, buf
);
1228 static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE
*comp
, OMX_BUFFERHEADERTYPE
* input
, OMX_BUFFERHEADERTYPE
* output
)
1230 vid_enc_PrivateType
*priv
= comp
->pComponentPrivate
;
1231 struct output_buf_private
*outp
= output
->pOutputPortPrivate
;
1232 struct input_buf_private
*inp
= input
->pInputPortPrivate
;
1233 struct encode_task
*task
;
1234 struct pipe_box box
= {};
1237 if (!inp
|| LIST_IS_EMPTY(&inp
->tasks
)) {
1238 input
->nFilledLen
= 0; /* mark buffer as empty */
1239 enc_MoveTasks(&priv
->used_tasks
, &inp
->tasks
);
1243 task
= LIST_ENTRY(struct encode_task
, inp
->tasks
.next
, list
);
1244 LIST_DEL(&task
->list
);
1245 LIST_ADDTAIL(&task
->list
, &priv
->used_tasks
);
1247 if (!task
->bitstream
)
1250 /* ------------- map result buffer ----------------- */
1253 pipe_transfer_unmap(priv
->t_pipe
, outp
->transfer
);
1255 pipe_resource_reference(&outp
->bitstream
, task
->bitstream
);
1256 pipe_resource_reference(&task
->bitstream
, NULL
);
1258 box
.width
= outp
->bitstream
->width0
;
1259 box
.height
= outp
->bitstream
->height0
;
1260 box
.depth
= outp
->bitstream
->depth0
;
1262 output
->pBuffer
= priv
->t_pipe
->transfer_map(priv
->t_pipe
, outp
->bitstream
, 0,
1263 PIPE_TRANSFER_READ_WRITE
,
1264 &box
, &outp
->transfer
);
1266 /* ------------- get size of result ----------------- */
1268 priv
->codec
->get_feedback(priv
->codec
, task
->feedback
, &size
);
1270 output
->nOffset
= 0;
1271 output
->nFilledLen
= size
; /* mark buffer as full */