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
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
198 templat
.width
= def
->nFrameWidth
;
199 templat
.height
= def
->nFrameHeight
;
200 templat
.interlaced
= false;
202 task
->buf
= priv
->s_pipe
->create_video_buffer(priv
->s_pipe
, &templat
);
211 void enc_ScaleInput_common(vid_enc_PrivateType
* priv
, OMX_VIDEO_PORTDEFINITIONTYPE
*def
,
212 struct pipe_video_buffer
**vbuf
, unsigned *size
)
214 struct pipe_video_buffer
*src_buf
= *vbuf
;
215 struct vl_compositor
*compositor
= &priv
->compositor
;
216 struct vl_compositor_state
*s
= &priv
->cstate
;
217 struct pipe_sampler_view
**views
;
218 struct pipe_surface
**dst_surface
;
221 if (!priv
->scale_buffer
[priv
->current_scale_buffer
])
224 views
= src_buf
->get_sampler_view_planes(src_buf
);
225 dst_surface
= priv
->scale_buffer
[priv
->current_scale_buffer
]->get_surfaces
226 (priv
->scale_buffer
[priv
->current_scale_buffer
]);
227 vl_compositor_clear_layers(s
);
229 for (i
= 0; i
< VL_MAX_SURFACES
; ++i
) {
230 struct u_rect src_rect
;
231 if (!views
[i
] || !dst_surface
[i
])
235 src_rect
.x1
= def
->nFrameWidth
;
236 src_rect
.y1
= def
->nFrameHeight
;
241 vl_compositor_set_rgba_layer(s
, compositor
, 0, views
[i
], &src_rect
, NULL
, NULL
);
242 vl_compositor_render(s
, compositor
, dst_surface
[i
], NULL
, false);
244 *size
= priv
->scale
.xWidth
* priv
->scale
.xHeight
* 2;
245 *vbuf
= priv
->scale_buffer
[priv
->current_scale_buffer
++];
246 priv
->current_scale_buffer
%= OMX_VID_ENC_NUM_SCALING_BUFFERS
;
249 void enc_ControlPicture_common(vid_enc_PrivateType
* priv
, struct pipe_h264_enc_picture_desc
*picture
)
251 struct pipe_h264_enc_rate_control
*rate_ctrl
= &picture
->rate_ctrl
;
253 /* Get bitrate from port */
254 switch (priv
->bitrate
.eControlRate
) {
255 case OMX_Video_ControlRateVariable
:
256 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE
;
258 case OMX_Video_ControlRateConstant
:
259 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT
;
261 case OMX_Video_ControlRateVariableSkipFrames
:
262 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP
;
264 case OMX_Video_ControlRateConstantSkipFrames
:
265 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP
;
268 rate_ctrl
->rate_ctrl_method
= PIPE_H264_ENC_RATE_CONTROL_METHOD_DISABLE
;
272 rate_ctrl
->frame_rate_den
= OMX_VID_ENC_CONTROL_FRAME_RATE_DEN_DEFAULT
;
273 rate_ctrl
->frame_rate_num
= ((priv
->frame_rate
) >> 16) * rate_ctrl
->frame_rate_den
;
275 if (rate_ctrl
->rate_ctrl_method
!= PIPE_H264_ENC_RATE_CONTROL_METHOD_DISABLE
) {
276 if (priv
->bitrate
.nTargetBitrate
< OMX_VID_ENC_BITRATE_MIN
)
277 rate_ctrl
->target_bitrate
= OMX_VID_ENC_BITRATE_MIN
;
278 else if (priv
->bitrate
.nTargetBitrate
< OMX_VID_ENC_BITRATE_MAX
)
279 rate_ctrl
->target_bitrate
= priv
->bitrate
.nTargetBitrate
;
281 rate_ctrl
->target_bitrate
= OMX_VID_ENC_BITRATE_MAX
;
282 rate_ctrl
->peak_bitrate
= rate_ctrl
->target_bitrate
;
283 if (rate_ctrl
->target_bitrate
< OMX_VID_ENC_BITRATE_MEDIAN
)
284 rate_ctrl
->vbv_buffer_size
= MIN2((rate_ctrl
->target_bitrate
* 2.75), OMX_VID_ENC_BITRATE_MEDIAN
);
286 rate_ctrl
->vbv_buffer_size
= rate_ctrl
->target_bitrate
;
288 if (rate_ctrl
->frame_rate_num
) {
289 unsigned long long t
= rate_ctrl
->target_bitrate
;
290 t
*= rate_ctrl
->frame_rate_den
;
291 rate_ctrl
->target_bits_picture
= t
/ rate_ctrl
->frame_rate_num
;
293 rate_ctrl
->target_bits_picture
= rate_ctrl
->target_bitrate
;
295 rate_ctrl
->peak_bits_picture_integer
= rate_ctrl
->target_bits_picture
;
296 rate_ctrl
->peak_bits_picture_fraction
= 0;
299 picture
->quant_i_frames
= priv
->quant
.nQpI
;
300 picture
->quant_p_frames
= priv
->quant
.nQpP
;
301 picture
->quant_b_frames
= priv
->quant
.nQpB
;
303 picture
->frame_num
= priv
->frame_num
;
304 picture
->ref_idx_l0
= priv
->ref_idx_l0
;
305 picture
->ref_idx_l1
= priv
->ref_idx_l1
;
306 picture
->enable_vui
= (picture
->rate_ctrl
.frame_rate_num
!= 0);
307 enc_GetPictureParamPreset(picture
);
310 static void *create_compute_state(struct pipe_context
*pipe
,
313 struct tgsi_token tokens
[1024];
314 struct pipe_compute_state state
= {0};
316 if (!tgsi_text_translate(source
, tokens
, ARRAY_SIZE(tokens
))) {
321 state
.ir_type
= PIPE_SHADER_IR_TGSI
;
324 return pipe
->create_compute_state(pipe
, &state
);
327 void enc_InitCompute_common(vid_enc_PrivateType
*priv
)
329 struct pipe_context
*pipe
= priv
->s_pipe
;
330 struct pipe_screen
*screen
= pipe
->screen
;
332 /* We need the partial last block support. */
333 if (!screen
->get_param(screen
, PIPE_CAP_COMPUTE_GRID_INFO_LAST_BLOCK
))
336 static const char *copy_y
=
338 "PROPERTY CS_FIXED_BLOCK_WIDTH 64\n"
339 "PROPERTY CS_FIXED_BLOCK_HEIGHT 1\n"
340 "PROPERTY CS_FIXED_BLOCK_DEPTH 1\n"
341 "DCL SV[0], THREAD_ID\n"
342 "DCL SV[1], BLOCK_ID\n"
343 "DCL IMAGE[0], 2D, PIPE_FORMAT_R8_UINT\n"
344 "DCL IMAGE[1], 2D, PIPE_FORMAT_R8_UINT, WR\n"
346 "IMM[0] UINT32 {64, 0, 0, 0}\n"
348 "UMAD TEMP[0].x, SV[1], IMM[0], SV[0]\n"
349 "MOV TEMP[0].y, SV[1]\n"
350 "LOAD TEMP[1].x, IMAGE[0], TEMP[0], 2D, PIPE_FORMAT_R8_UINT\n"
351 "STORE IMAGE[1].x, TEMP[0], TEMP[1], 2D, PIPE_FORMAT_R8_UINT\n"
354 static const char *copy_uv
=
356 "PROPERTY CS_FIXED_BLOCK_WIDTH 64\n"
357 "PROPERTY CS_FIXED_BLOCK_HEIGHT 1\n"
358 "PROPERTY CS_FIXED_BLOCK_DEPTH 1\n"
359 "DCL SV[0], THREAD_ID\n"
360 "DCL SV[1], BLOCK_ID\n"
361 "DCL IMAGE[0], 2D, PIPE_FORMAT_R8_UINT\n"
362 "DCL IMAGE[2], 2D, PIPE_FORMAT_R8G8_UINT, WR\n"
363 "DCL CONST[0][0]\n" /* .x = offset of the UV portion in the y direction */
365 "IMM[0] UINT32 {64, 0, 2, 1}\n"
366 /* Destination R8G8 coordinates */
367 "UMAD TEMP[0].x, SV[1], IMM[0], SV[0]\n"
368 "MOV TEMP[0].y, SV[1]\n"
369 /* Source R8 coordinates of U */
370 "UMUL TEMP[1].x, TEMP[0], IMM[0].zzzz\n"
371 "UADD TEMP[1].y, TEMP[0], CONST[0].xxxx\n"
372 /* Source R8 coordinates of V */
373 "UADD TEMP[2].x, TEMP[1], IMM[0].wwww\n"
374 "MOV TEMP[2].y, TEMP[1]\n"
376 "LOAD TEMP[3].x, IMAGE[0], TEMP[1], 2D, PIPE_FORMAT_R8_UINT\n"
377 "LOAD TEMP[4].x, IMAGE[0], TEMP[2], 2D, PIPE_FORMAT_R8_UINT\n"
378 "MOV TEMP[3].y, TEMP[4].xxxx\n"
379 "STORE IMAGE[2], TEMP[0], TEMP[3], 2D, PIPE_FORMAT_R8G8_UINT\n"
382 priv
->copy_y_shader
= create_compute_state(pipe
, copy_y
);
383 priv
->copy_uv_shader
= create_compute_state(pipe
, copy_uv
);
386 void enc_ReleaseCompute_common(vid_enc_PrivateType
*priv
)
388 struct pipe_context
*pipe
= priv
->s_pipe
;
390 if (priv
->copy_y_shader
)
391 pipe
->delete_compute_state(pipe
, priv
->copy_y_shader
);
392 if (priv
->copy_uv_shader
)
393 pipe
->delete_compute_state(pipe
, priv
->copy_uv_shader
);
396 OMX_ERRORTYPE
enc_LoadImage_common(vid_enc_PrivateType
* priv
, OMX_VIDEO_PORTDEFINITIONTYPE
*def
,
397 OMX_BUFFERHEADERTYPE
*buf
,
398 struct pipe_video_buffer
*vbuf
)
400 struct pipe_context
*pipe
= priv
->s_pipe
;
401 struct pipe_box box
= {};
402 struct input_buf_private
*inp
= buf
->pInputPortPrivate
;
404 if (!inp
->resource
) {
405 struct pipe_sampler_view
**views
;
408 views
= vbuf
->get_sampler_view_planes(vbuf
);
410 return OMX_ErrorInsufficientResources
;
413 box
.width
= def
->nFrameWidth
;
414 box
.height
= def
->nFrameHeight
;
416 pipe
->texture_subdata(pipe
, views
[0]->texture
, 0,
417 PIPE_TRANSFER_WRITE
, &box
,
418 ptr
, def
->nStride
, 0);
419 ptr
= ((uint8_t*)buf
->pBuffer
) + (def
->nStride
* box
.height
);
420 box
.width
= def
->nFrameWidth
/ 2;
421 box
.height
= def
->nFrameHeight
/ 2;
423 pipe
->texture_subdata(pipe
, views
[1]->texture
, 0,
424 PIPE_TRANSFER_WRITE
, &box
,
425 ptr
, def
->nStride
, 0);
427 struct vl_video_buffer
*dst_buf
= (struct vl_video_buffer
*)vbuf
;
429 pipe_transfer_unmap(pipe
, inp
->transfer
);
431 /* inp->resource uses PIPE_FORMAT_I8 and the layout looks like this:
433 * def->nFrameWidth = 4, def->nFrameHeight = 4:
443 * The copy has 2 steps:
444 * - Copy Y to dst_buf->resources[0] as R8.
445 * - Copy UV to dst_buf->resources[1] as R8G8.
447 if (priv
->copy_y_shader
&& priv
->copy_uv_shader
) {
449 /* Set shader images for both copies. */
450 struct pipe_image_view image
[3] = {0};
451 image
[0].resource
= inp
->resource
;
452 image
[0].shader_access
= image
[0].access
= PIPE_IMAGE_ACCESS_READ
;
453 image
[0].format
= PIPE_FORMAT_R8_UINT
;
455 image
[1].resource
= dst_buf
->resources
[0];
456 image
[1].shader_access
= image
[1].access
= PIPE_IMAGE_ACCESS_WRITE
;
457 image
[1].format
= PIPE_FORMAT_R8_UINT
;
459 image
[2].resource
= dst_buf
->resources
[1];
460 image
[2].shader_access
= image
[1].access
= PIPE_IMAGE_ACCESS_WRITE
;
461 image
[2].format
= PIPE_FORMAT_R8G8_UINT
;
463 pipe
->set_shader_images(pipe
, PIPE_SHADER_COMPUTE
, 0, 3, image
);
465 /* Set the constant buffer. */
466 uint32_t constants
[4] = {def
->nFrameHeight
};
467 struct pipe_constant_buffer cb
= {};
469 cb
.buffer_size
= sizeof(constants
);
470 cb
.user_buffer
= constants
;
471 pipe
->set_constant_buffer(pipe
, PIPE_SHADER_COMPUTE
, 0, &cb
);
473 /* Use the optimal block size for the linear image layout. */
474 struct pipe_grid_info info
= {};
481 pipe
->bind_compute_state(pipe
, priv
->copy_y_shader
);
483 info
.grid
[0] = DIV_ROUND_UP(def
->nFrameWidth
, 64);
484 info
.grid
[1] = def
->nFrameHeight
;
485 info
.last_block
[0] = def
->nFrameWidth
% 64;
486 pipe
->launch_grid(pipe
, &info
);
489 pipe
->bind_compute_state(pipe
, priv
->copy_uv_shader
);
491 info
.grid
[0] = DIV_ROUND_UP(def
->nFrameWidth
/ 2, 64);
492 info
.grid
[1] = def
->nFrameHeight
/ 2;
493 info
.last_block
[0] = (def
->nFrameWidth
/ 2) % 64;
494 pipe
->launch_grid(pipe
, &info
);
496 /* Make the result visible to all clients. */
497 pipe
->memory_barrier(pipe
, PIPE_BARRIER_ALL
);
500 pipe
->set_shader_images(pipe
, PIPE_SHADER_COMPUTE
, 0, 3, NULL
);
501 pipe
->set_constant_buffer(pipe
, PIPE_SHADER_COMPUTE
, 0, NULL
);
502 pipe
->bind_compute_state(pipe
, NULL
);
505 struct pipe_blit_info blit
;
507 box
.width
= def
->nFrameWidth
;
508 box
.height
= def
->nFrameHeight
;
512 pipe
->resource_copy_region(pipe
,
513 dst_buf
->resources
[0],
514 0, 0, 0, 0, inp
->resource
, 0, &box
);
517 memset(&blit
, 0, sizeof(blit
));
518 blit
.src
.resource
= inp
->resource
;
519 blit
.src
.format
= inp
->resource
->format
;
522 blit
.src
.box
.y
= def
->nFrameHeight
;
523 blit
.src
.box
.width
= def
->nFrameWidth
;
524 blit
.src
.box
.height
= def
->nFrameHeight
/ 2 ;
525 blit
.src
.box
.depth
= 1;
527 blit
.dst
.resource
= dst_buf
->resources
[1];
528 blit
.dst
.format
= blit
.dst
.resource
->format
;
530 blit
.dst
.box
.width
= def
->nFrameWidth
/ 2;
531 blit
.dst
.box
.height
= def
->nFrameHeight
/ 2;
532 blit
.dst
.box
.depth
= 1;
533 blit
.filter
= PIPE_TEX_FILTER_NEAREST
;
535 blit
.mask
= PIPE_MASK_R
;
536 pipe
->blit(pipe
, &blit
);
540 blit
.mask
= PIPE_MASK_G
;
541 pipe
->blit(pipe
, &blit
);
544 pipe
->flush(pipe
, NULL
, 0);
546 box
.width
= inp
->resource
->width0
;
547 box
.height
= inp
->resource
->height0
;
548 box
.depth
= inp
->resource
->depth0
;
549 buf
->pBuffer
= pipe
->transfer_map(pipe
, inp
->resource
, 0,
550 PIPE_TRANSFER_WRITE
, &box
,
554 return OMX_ErrorNone
;