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 **************************************************************************/
28 #include "vid_enc_common.h"
30 #include "vl/vl_video_buffer.h"
31 #include "tgsi/tgsi_text.h"
33 void enc_ReleaseTasks(struct list_head
*head
)
35 struct encode_task
*i
, *next
;
37 if (!head
|| !head
->next
)
40 LIST_FOR_EACH_ENTRY_SAFE(i
, next
, head
, list
) {
41 pipe_resource_reference(&i
->bitstream
, NULL
);
42 i
->buf
->destroy(i
->buf
);
47 void enc_MoveTasks(struct list_head
*from
, struct list_head
*to
)
49 to
->prev
->next
= from
->next
;
50 from
->next
->prev
= to
->prev
;
51 from
->prev
->next
= to
;
52 to
->prev
= from
->prev
;
56 static void enc_GetPictureParamPreset(struct pipe_h264_enc_picture_desc
*picture
)
58 picture
->motion_est
.enc_disable_sub_mode
= 0x000000fe;
59 picture
->motion_est
.enc_ime2_search_range_x
= 0x00000001;
60 picture
->motion_est
.enc_ime2_search_range_y
= 0x00000001;
61 picture
->pic_ctrl
.enc_constraint_set_flags
= 0x00000040;
64 enum pipe_video_profile
enc_TranslateOMXProfileToPipe(unsigned omx_profile
)
66 switch (omx_profile
) {
67 case OMX_VIDEO_AVCProfileBaseline
:
68 return PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE
;
69 case OMX_VIDEO_AVCProfileMain
:
70 return PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN
;
71 case OMX_VIDEO_AVCProfileExtended
:
72 return PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED
;
73 case OMX_VIDEO_AVCProfileHigh
:
74 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
;
75 case OMX_VIDEO_AVCProfileHigh10
:
76 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10
;
77 case OMX_VIDEO_AVCProfileHigh422
:
78 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH422
;
79 case OMX_VIDEO_AVCProfileHigh444
:
80 return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH444
;
82 return PIPE_VIDEO_PROFILE_UNKNOWN
;
86 unsigned enc_TranslateOMXLevelToPipe(unsigned omx_level
)
89 case OMX_VIDEO_AVCLevel1
:
90 case OMX_VIDEO_AVCLevel1b
:
92 case OMX_VIDEO_AVCLevel11
:
94 case OMX_VIDEO_AVCLevel12
:
96 case OMX_VIDEO_AVCLevel13
:
98 case OMX_VIDEO_AVCLevel2
:
100 case OMX_VIDEO_AVCLevel21
:
102 case OMX_VIDEO_AVCLevel22
:
104 case OMX_VIDEO_AVCLevel3
:
106 case OMX_VIDEO_AVCLevel31
:
108 case OMX_VIDEO_AVCLevel32
:
110 case OMX_VIDEO_AVCLevel4
:
112 case OMX_VIDEO_AVCLevel41
:
115 case OMX_VIDEO_AVCLevel42
:
117 case OMX_VIDEO_AVCLevel5
:
119 case OMX_VIDEO_AVCLevel51
:
124 void vid_enc_BufferEncoded_common(vid_enc_PrivateType
* priv
, OMX_BUFFERHEADERTYPE
* input
, OMX_BUFFERHEADERTYPE
* output
)
126 struct output_buf_private
*outp
= output
->pOutputPortPrivate
;
127 struct input_buf_private
*inp
= input
->pInputPortPrivate
;
128 struct encode_task
*task
;
129 struct pipe_box box
= {};
132 #if ENABLE_ST_OMX_BELLAGIO
133 if (!inp
|| list_is_empty(&inp
->tasks
)) {
134 input
->nFilledLen
= 0; /* mark buffer as empty */
135 enc_MoveTasks(&priv
->used_tasks
, &inp
->tasks
);
140 task
= LIST_ENTRY(struct encode_task
, inp
->tasks
.next
, list
);
141 list_del(&task
->list
);
142 list_addtail(&task
->list
, &priv
->used_tasks
);
144 if (!task
->bitstream
)
147 /* ------------- map result buffer ----------------- */
150 pipe_transfer_unmap(priv
->t_pipe
, outp
->transfer
);
152 pipe_resource_reference(&outp
->bitstream
, task
->bitstream
);
153 pipe_resource_reference(&task
->bitstream
, NULL
);
155 box
.width
= outp
->bitstream
->width0
;
156 box
.height
= outp
->bitstream
->height0
;
157 box
.depth
= outp
->bitstream
->depth0
;
159 output
->pBuffer
= priv
->t_pipe
->transfer_map(priv
->t_pipe
, outp
->bitstream
, 0,
160 PIPE_TRANSFER_READ_WRITE
,
161 &box
, &outp
->transfer
);
163 /* ------------- get size of result ----------------- */
165 priv
->codec
->get_feedback(priv
->codec
, task
->feedback
, &size
);
168 output
->nFilledLen
= size
; /* mark buffer as full */
170 /* all output buffers contain exactly one frame */
171 output
->nFlags
= OMX_BUFFERFLAG_ENDOFFRAME
;
173 #if ENABLE_ST_OMX_TIZONIA
174 input
->nFilledLen
= 0; /* mark buffer as empty */
175 enc_MoveTasks(&priv
->used_tasks
, &inp
->tasks
);
180 struct encode_task
*enc_NeedTask_common(vid_enc_PrivateType
* priv
, OMX_VIDEO_PORTDEFINITIONTYPE
*def
)
182 struct pipe_video_buffer templat
= {};
183 struct encode_task
*task
;
185 if (!list_is_empty(&priv
->free_tasks
)) {
186 task
= LIST_ENTRY(struct encode_task
, priv
->free_tasks
.next
, list
);
187 list_del(&task
->list
);
191 /* allocate a new one */
192 task
= CALLOC_STRUCT(encode_task
);
196 templat
.buffer_format
= PIPE_FORMAT_NV12
;
197 templat
.width
= def
->nFrameWidth
;
198 templat
.height
= def
->nFrameHeight
;
199 templat
.interlaced
= false;
201 task
->buf
= priv
->s_pipe
->create_video_buffer(priv
->s_pipe
, &templat
);
210 void enc_ScaleInput_common(vid_enc_PrivateType
* priv
, OMX_VIDEO_PORTDEFINITIONTYPE
*def
,
211 struct pipe_video_buffer
**vbuf
, unsigned *size
)
213 struct pipe_video_buffer
*src_buf
= *vbuf
;
214 struct vl_compositor
*compositor
= &priv
->compositor
;
215 struct vl_compositor_state
*s
= &priv
->cstate
;
216 struct pipe_sampler_view
**views
;
217 struct pipe_surface
**dst_surface
;
220 if (!priv
->scale_buffer
[priv
->current_scale_buffer
])
223 views
= src_buf
->get_sampler_view_planes(src_buf
);
224 dst_surface
= priv
->scale_buffer
[priv
->current_scale_buffer
]->get_surfaces
225 (priv
->scale_buffer
[priv
->current_scale_buffer
]);
226 vl_compositor_clear_layers(s
);
228 for (i
= 0; i
< VL_MAX_SURFACES
; ++i
) {
229 struct u_rect src_rect
;
230 if (!views
[i
] || !dst_surface
[i
])
234 src_rect
.x1
= def
->nFrameWidth
;
235 src_rect
.y1
= def
->nFrameHeight
;
240 vl_compositor_set_rgba_layer(s
, compositor
, 0, views
[i
], &src_rect
, NULL
, NULL
);
241 vl_compositor_render(s
, compositor
, dst_surface
[i
], NULL
, false);
243 *size
= priv
->scale
.xWidth
* priv
->scale
.xHeight
* 2;
244 *vbuf
= priv
->scale_buffer
[priv
->current_scale_buffer
++];
245 priv
->current_scale_buffer
%= OMX_VID_ENC_NUM_SCALING_BUFFERS
;
248 void enc_ControlPicture_common(vid_enc_PrivateType
* priv
, struct pipe_h264_enc_picture_desc
*picture
)
250 struct pipe_h264_enc_rate_control
*rate_ctrl
= &picture
->rate_ctrl
;
252 /* Get bitrate from port */
253 switch (priv
->bitrate
.eControlRate
) {
254 case OMX_Video_ControlRateVariable
:
255 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE
;
257 case OMX_Video_ControlRateConstant
:
258 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT
;
260 case OMX_Video_ControlRateVariableSkipFrames
:
261 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP
;
263 case OMX_Video_ControlRateConstantSkipFrames
:
264 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP
;
267 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_DISABLE
;
271 rate_ctrl
->frame_rate_den
= OMX_VID_ENC_CONTROL_FRAME_RATE_DEN_DEFAULT
;
272 rate_ctrl
->frame_rate_num
= ((priv
->frame_rate
) >> 16) * rate_ctrl
->frame_rate_den
;
274 if (rate_ctrl
->rate_ctrl_method
!= PIPE_H264_ENC_RATE_CONTROL_METHOD_DISABLE
) {
275 if (priv
->bitrate
.nTargetBitrate
< OMX_VID_ENC_BITRATE_MIN
)
276 rate_ctrl
->target_bitrate
= OMX_VID_ENC_BITRATE_MIN
;
277 else if (priv
->bitrate
.nTargetBitrate
< OMX_VID_ENC_BITRATE_MAX
)
278 rate_ctrl
->target_bitrate
= priv
->bitrate
.nTargetBitrate
;
280 rate_ctrl
->target_bitrate
= OMX_VID_ENC_BITRATE_MAX
;
281 rate_ctrl
->peak_bitrate
= rate_ctrl
->target_bitrate
;
282 if (rate_ctrl
->target_bitrate
< OMX_VID_ENC_BITRATE_MEDIAN
)
283 rate_ctrl
->vbv_buffer_size
= MIN2((rate_ctrl
->target_bitrate
* 2.75), OMX_VID_ENC_BITRATE_MEDIAN
);
285 rate_ctrl
->vbv_buffer_size
= rate_ctrl
->target_bitrate
;
287 if (rate_ctrl
->frame_rate_num
) {
288 unsigned long long t
= rate_ctrl
->target_bitrate
;
289 t
*= rate_ctrl
->frame_rate_den
;
290 rate_ctrl
->target_bits_picture
= t
/ rate_ctrl
->frame_rate_num
;
292 rate_ctrl
->target_bits_picture
= rate_ctrl
->target_bitrate
;
294 rate_ctrl
->peak_bits_picture_integer
= rate_ctrl
->target_bits_picture
;
295 rate_ctrl
->peak_bits_picture_fraction
= 0;
298 picture
->quant_i_frames
= priv
->quant
.nQpI
;
299 picture
->quant_p_frames
= priv
->quant
.nQpP
;
300 picture
->quant_b_frames
= priv
->quant
.nQpB
;
302 picture
->frame_num
= priv
->frame_num
;
303 picture
->ref_idx_l0
= priv
->ref_idx_l0
;
304 picture
->ref_idx_l1
= priv
->ref_idx_l1
;
305 picture
->enable_vui
= (picture
->rate_ctrl
.frame_rate_num
!= 0);
306 enc_GetPictureParamPreset(picture
);
309 static void *create_compute_state(struct pipe_context
*pipe
,
312 struct tgsi_token tokens
[1024];
313 struct pipe_compute_state state
= {0};
315 if (!tgsi_text_translate(source
, tokens
, ARRAY_SIZE(tokens
))) {
320 state
.ir_type
= PIPE_SHADER_IR_TGSI
;
323 return pipe
->create_compute_state(pipe
, &state
);
326 void enc_InitCompute_common(vid_enc_PrivateType
*priv
)
328 struct pipe_context
*pipe
= priv
->s_pipe
;
329 struct pipe_screen
*screen
= pipe
->screen
;
331 /* We need the partial last block support. */
332 if (!screen
->get_param(screen
, PIPE_CAP_COMPUTE_GRID_INFO_LAST_BLOCK
))
335 static const char *copy_y
=
337 "PROPERTY CS_FIXED_BLOCK_WIDTH 64\n"
338 "PROPERTY CS_FIXED_BLOCK_HEIGHT 1\n"
339 "PROPERTY CS_FIXED_BLOCK_DEPTH 1\n"
340 "DCL SV[0], THREAD_ID\n"
341 "DCL SV[1], BLOCK_ID\n"
342 "DCL IMAGE[0], 2D, PIPE_FORMAT_R8_UINT\n"
343 "DCL IMAGE[1], 2D, PIPE_FORMAT_R8_UINT, WR\n"
345 "IMM[0] UINT32 {64, 0, 0, 0}\n"
347 "UMAD TEMP[0].x, SV[1], IMM[0], SV[0]\n"
348 "MOV TEMP[0].y, SV[1]\n"
349 "LOAD TEMP[1].x, IMAGE[0], TEMP[0], 2D, PIPE_FORMAT_R8_UINT\n"
350 "STORE IMAGE[1].x, TEMP[0], TEMP[1], 2D, PIPE_FORMAT_R8_UINT\n"
353 static const char *copy_uv
=
355 "PROPERTY CS_FIXED_BLOCK_WIDTH 64\n"
356 "PROPERTY CS_FIXED_BLOCK_HEIGHT 1\n"
357 "PROPERTY CS_FIXED_BLOCK_DEPTH 1\n"
358 "DCL SV[0], THREAD_ID\n"
359 "DCL SV[1], BLOCK_ID\n"
360 "DCL IMAGE[0], 2D, PIPE_FORMAT_R8_UINT\n"
361 "DCL IMAGE[2], 2D, PIPE_FORMAT_R8G8_UINT, WR\n"
362 "DCL CONST[0][0]\n" /* .x = offset of the UV portion in the y direction */
364 "IMM[0] UINT32 {64, 0, 2, 1}\n"
365 /* Destination R8G8 coordinates */
366 "UMAD TEMP[0].x, SV[1], IMM[0], SV[0]\n"
367 "MOV TEMP[0].y, SV[1]\n"
368 /* Source R8 coordinates of U */
369 "UMUL TEMP[1].x, TEMP[0], IMM[0].zzzz\n"
370 "UADD TEMP[1].y, TEMP[0], CONST[0].xxxx\n"
371 /* Source R8 coordinates of V */
372 "UADD TEMP[2].x, TEMP[1], IMM[0].wwww\n"
373 "MOV TEMP[2].y, TEMP[1]\n"
375 "LOAD TEMP[3].x, IMAGE[0], TEMP[1], 2D, PIPE_FORMAT_R8_UINT\n"
376 "LOAD TEMP[4].x, IMAGE[0], TEMP[2], 2D, PIPE_FORMAT_R8_UINT\n"
377 "MOV TEMP[3].y, TEMP[4].xxxx\n"
378 "STORE IMAGE[2], TEMP[0], TEMP[3], 2D, PIPE_FORMAT_R8G8_UINT\n"
381 priv
->copy_y_shader
= create_compute_state(pipe
, copy_y
);
382 priv
->copy_uv_shader
= create_compute_state(pipe
, copy_uv
);
385 void enc_ReleaseCompute_common(vid_enc_PrivateType
*priv
)
387 struct pipe_context
*pipe
= priv
->s_pipe
;
389 if (priv
->copy_y_shader
)
390 pipe
->delete_compute_state(pipe
, priv
->copy_y_shader
);
391 if (priv
->copy_uv_shader
)
392 pipe
->delete_compute_state(pipe
, priv
->copy_uv_shader
);
395 OMX_ERRORTYPE
enc_LoadImage_common(vid_enc_PrivateType
* priv
, OMX_VIDEO_PORTDEFINITIONTYPE
*def
,
396 OMX_BUFFERHEADERTYPE
*buf
,
397 struct pipe_video_buffer
*vbuf
)
399 struct pipe_context
*pipe
= priv
->s_pipe
;
400 struct pipe_box box
= {};
401 struct input_buf_private
*inp
= buf
->pInputPortPrivate
;
403 if (!inp
->resource
) {
404 struct pipe_sampler_view
**views
;
407 views
= vbuf
->get_sampler_view_planes(vbuf
);
409 return OMX_ErrorInsufficientResources
;
412 box
.width
= def
->nFrameWidth
;
413 box
.height
= def
->nFrameHeight
;
415 pipe
->texture_subdata(pipe
, views
[0]->texture
, 0,
416 PIPE_TRANSFER_WRITE
, &box
,
417 ptr
, def
->nStride
, 0);
418 ptr
= ((uint8_t*)buf
->pBuffer
) + (def
->nStride
* box
.height
);
419 box
.width
= def
->nFrameWidth
/ 2;
420 box
.height
= def
->nFrameHeight
/ 2;
422 pipe
->texture_subdata(pipe
, views
[1]->texture
, 0,
423 PIPE_TRANSFER_WRITE
, &box
,
424 ptr
, def
->nStride
, 0);
426 struct vl_video_buffer
*dst_buf
= (struct vl_video_buffer
*)vbuf
;
428 pipe_transfer_unmap(pipe
, inp
->transfer
);
430 /* inp->resource uses PIPE_FORMAT_I8 and the layout looks like this:
432 * def->nFrameWidth = 4, def->nFrameHeight = 4:
442 * The copy has 2 steps:
443 * - Copy Y to dst_buf->resources[0] as R8.
444 * - Copy UV to dst_buf->resources[1] as R8G8.
446 if (priv
->copy_y_shader
&& priv
->copy_uv_shader
) {
448 /* Set shader images for both copies. */
449 struct pipe_image_view image
[3] = {0};
450 image
[0].resource
= inp
->resource
;
451 image
[0].shader_access
= image
[0].access
= PIPE_IMAGE_ACCESS_READ
;
452 image
[0].format
= PIPE_FORMAT_R8_UINT
;
454 image
[1].resource
= dst_buf
->resources
[0];
455 image
[1].shader_access
= image
[1].access
= PIPE_IMAGE_ACCESS_WRITE
;
456 image
[1].format
= PIPE_FORMAT_R8_UINT
;
458 image
[2].resource
= dst_buf
->resources
[1];
459 image
[2].shader_access
= image
[1].access
= PIPE_IMAGE_ACCESS_WRITE
;
460 image
[2].format
= PIPE_FORMAT_R8G8_UINT
;
462 pipe
->set_shader_images(pipe
, PIPE_SHADER_COMPUTE
, 0, 3, image
);
464 /* Set the constant buffer. */
465 uint32_t constants
[4] = {def
->nFrameHeight
};
466 struct pipe_constant_buffer cb
= {};
468 cb
.buffer_size
= sizeof(constants
);
469 cb
.user_buffer
= constants
;
470 pipe
->set_constant_buffer(pipe
, PIPE_SHADER_COMPUTE
, 0, &cb
);
472 /* Use the optimal block size for the linear image layout. */
473 struct pipe_grid_info info
= {};
480 pipe
->bind_compute_state(pipe
, priv
->copy_y_shader
);
482 info
.grid
[0] = DIV_ROUND_UP(def
->nFrameWidth
, 64);
483 info
.grid
[1] = def
->nFrameHeight
;
484 info
.last_block
[0] = def
->nFrameWidth
% 64;
485 pipe
->launch_grid(pipe
, &info
);
488 pipe
->bind_compute_state(pipe
, priv
->copy_uv_shader
);
490 info
.grid
[0] = DIV_ROUND_UP(def
->nFrameWidth
/ 2, 64);
491 info
.grid
[1] = def
->nFrameHeight
/ 2;
492 info
.last_block
[0] = (def
->nFrameWidth
/ 2) % 64;
493 pipe
->launch_grid(pipe
, &info
);
495 /* Make the result visible to all clients. */
496 pipe
->memory_barrier(pipe
, PIPE_BARRIER_ALL
);
499 pipe
->set_shader_images(pipe
, PIPE_SHADER_COMPUTE
, 0, 3, NULL
);
500 pipe
->set_constant_buffer(pipe
, PIPE_SHADER_COMPUTE
, 0, NULL
);
501 pipe
->bind_compute_state(pipe
, NULL
);
504 struct pipe_blit_info blit
;
506 box
.width
= def
->nFrameWidth
;
507 box
.height
= def
->nFrameHeight
;
511 pipe
->resource_copy_region(pipe
,
512 dst_buf
->resources
[0],
513 0, 0, 0, 0, inp
->resource
, 0, &box
);
516 memset(&blit
, 0, sizeof(blit
));
517 blit
.src
.resource
= inp
->resource
;
518 blit
.src
.format
= inp
->resource
->format
;
521 blit
.src
.box
.y
= def
->nFrameHeight
;
522 blit
.src
.box
.width
= def
->nFrameWidth
;
523 blit
.src
.box
.height
= def
->nFrameHeight
/ 2 ;
524 blit
.src
.box
.depth
= 1;
526 blit
.dst
.resource
= dst_buf
->resources
[1];
527 blit
.dst
.format
= blit
.dst
.resource
->format
;
529 blit
.dst
.box
.width
= def
->nFrameWidth
/ 2;
530 blit
.dst
.box
.height
= def
->nFrameHeight
/ 2;
531 blit
.dst
.box
.depth
= 1;
532 blit
.filter
= PIPE_TEX_FILTER_NEAREST
;
534 blit
.mask
= PIPE_MASK_R
;
535 pipe
->blit(pipe
, &blit
);
539 blit
.mask
= PIPE_MASK_G
;
540 pipe
->blit(pipe
, &blit
);
543 pipe
->flush(pipe
, NULL
, 0);
545 box
.width
= inp
->resource
->width0
;
546 box
.height
= inp
->resource
->height0
;
547 box
.depth
= inp
->resource
->depth0
;
548 buf
->pBuffer
= pipe
->transfer_map(pipe
, inp
->resource
, 0,
549 PIPE_TRANSFER_WRITE
, &box
,
553 return OMX_ErrorNone
;