• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2013 Advanced Micro Devices, Inc.
4  * All Rights Reserved.
5  *
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:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
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.
25  *
26  **************************************************************************/
27 
28 /*
29  * Authors:
30  *      Christian König <christian.koenig@amd.com>
31  *
32  */
33 
34 
35 #include <assert.h>
36 
37 #include <OMX_Video.h>
38 
39 /* bellagio defines a DEBUG macro that we don't want */
40 #ifndef DEBUG
41 #include <bellagio/omxcore.h>
42 #undef DEBUG
43 #else
44 #include <bellagio/omxcore.h>
45 #endif
46 
47 #include <bellagio/omx_base_video_port.h>
48 
49 #include "pipe/p_screen.h"
50 #include "pipe/p_video_codec.h"
51 #include "util/u_memory.h"
52 
53 #include "vl/vl_codec.h"
54 
55 #include "entrypoint.h"
56 #include "vid_enc.h"
57 #include "vid_omx_common.h"
58 #include "vid_enc_common.h"
59 
60 static OMX_ERRORTYPE vid_enc_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING name);
61 static OMX_ERRORTYPE vid_enc_Destructor(OMX_COMPONENTTYPE *comp);
62 static OMX_ERRORTYPE vid_enc_SetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param);
63 static OMX_ERRORTYPE vid_enc_GetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param);
64 static OMX_ERRORTYPE vid_enc_SetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config);
65 static OMX_ERRORTYPE vid_enc_GetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config);
66 static OMX_ERRORTYPE vid_enc_MessageHandler(OMX_COMPONENTTYPE *comp, internalRequestMessageType *msg);
67 static OMX_ERRORTYPE vid_enc_AllocateInBuffer(omx_base_PortType *port, OMX_INOUT OMX_BUFFERHEADERTYPE **buf,
68                                               OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size);
69 static OMX_ERRORTYPE vid_enc_UseInBuffer(omx_base_PortType *port, OMX_BUFFERHEADERTYPE **buf, OMX_U32 idx,
70                                          OMX_PTR private, OMX_U32 size, OMX_U8 *mem);
71 static OMX_ERRORTYPE vid_enc_FreeInBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf);
72 static OMX_ERRORTYPE vid_enc_EncodeFrame(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf);
73 static OMX_ERRORTYPE vid_enc_AllocateOutBuffer(omx_base_PortType *comp, OMX_INOUT OMX_BUFFERHEADERTYPE **buf,
74                                                OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size);
75 static OMX_ERRORTYPE vid_enc_FreeOutBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf);
76 static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input, OMX_BUFFERHEADERTYPE* output);
77 
vid_enc_LoaderComponent(stLoaderComponentType * comp)78 OMX_ERRORTYPE vid_enc_LoaderComponent(stLoaderComponentType *comp)
79 {
80    comp->componentVersion.s.nVersionMajor = 0;
81    comp->componentVersion.s.nVersionMinor = 0;
82    comp->componentVersion.s.nRevision = 0;
83    comp->componentVersion.s.nStep = 1;
84    comp->name_specific_length = 1;
85    comp->constructor = vid_enc_Constructor;
86 
87    comp->name = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);
88    if (!comp->name)
89       return OMX_ErrorInsufficientResources;
90 
91    comp->name_specific = CALLOC(1, sizeof(char *));
92    if (!comp->name_specific)
93       goto error_arrays;
94 
95    comp->role_specific = CALLOC(1, sizeof(char *));
96    if (!comp->role_specific)
97       goto error_arrays;
98 
99    comp->name_specific[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);
100    if (comp->name_specific[0] == NULL)
101       goto error_specific;
102 
103    comp->role_specific[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);
104    if (comp->role_specific[0] == NULL)
105       goto error_specific;
106 
107    strcpy(comp->name, OMX_VID_ENC_BASE_NAME);
108    strcpy(comp->name_specific[0], OMX_VID_ENC_AVC_NAME);
109    strcpy(comp->role_specific[0], OMX_VID_ENC_AVC_ROLE);
110 
111    return OMX_ErrorNone;
112 
113 error_specific:
114    FREE(comp->role_specific[0]);
115    FREE(comp->name_specific[0]);
116 
117 error_arrays:
118    FREE(comp->role_specific);
119    FREE(comp->name_specific);
120 
121    FREE(comp->name);
122 
123    return OMX_ErrorInsufficientResources;
124 }
125 
vid_enc_Constructor(OMX_COMPONENTTYPE * comp,OMX_STRING name)126 static OMX_ERRORTYPE vid_enc_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING name)
127 {
128    vid_enc_PrivateType *priv;
129    omx_base_video_PortType *port;
130    struct pipe_screen *screen;
131    OMX_ERRORTYPE r;
132    int i;
133 
134    assert(!comp->pComponentPrivate);
135 
136    priv = comp->pComponentPrivate = CALLOC(1, sizeof(vid_enc_PrivateType));
137    if (!priv)
138       return OMX_ErrorInsufficientResources;
139 
140    r = omx_base_filter_Constructor(comp, name);
141    if (r)
142        return r;
143 
144    priv->BufferMgmtCallback = vid_enc_BufferEncoded;
145    priv->messageHandler = vid_enc_MessageHandler;
146    priv->destructor = vid_enc_Destructor;
147 
148    comp->SetParameter = vid_enc_SetParameter;
149    comp->GetParameter = vid_enc_GetParameter;
150    comp->GetConfig = vid_enc_GetConfig;
151    comp->SetConfig = vid_enc_SetConfig;
152 
153    priv->screen = omx_get_screen();
154    if (!priv->screen)
155       return OMX_ErrorInsufficientResources;
156 
157    screen = priv->screen->pscreen;
158    if (!vl_codec_supported(screen, PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH, true))
159       return OMX_ErrorBadParameter;
160 
161    priv->s_pipe = pipe_create_multimedia_context(screen);
162    if (!priv->s_pipe)
163       return OMX_ErrorInsufficientResources;
164 
165    enc_InitCompute_common(priv);
166 
167    if (!vl_compositor_init(&priv->compositor, priv->s_pipe)) {
168       priv->s_pipe->destroy(priv->s_pipe);
169       priv->s_pipe = NULL;
170       return OMX_ErrorInsufficientResources;
171    }
172 
173    if (!vl_compositor_init_state(&priv->cstate, priv->s_pipe)) {
174       vl_compositor_cleanup(&priv->compositor);
175       priv->s_pipe->destroy(priv->s_pipe);
176       priv->s_pipe = NULL;
177       return OMX_ErrorInsufficientResources;
178    }
179 
180    priv->t_pipe = pipe_create_multimedia_context(screen);
181    if (!priv->t_pipe)
182       return OMX_ErrorInsufficientResources;
183 
184    priv->sPortTypesParam[OMX_PortDomainVideo].nStartPortNumber = 0;
185    priv->sPortTypesParam[OMX_PortDomainVideo].nPorts = 2;
186    priv->ports = CALLOC(2, sizeof(omx_base_PortType *));
187    if (!priv->ports)
188       return OMX_ErrorInsufficientResources;
189 
190    for (i = 0; i < 2; ++i) {
191       priv->ports[i] = CALLOC(1, sizeof(omx_base_video_PortType));
192       if (!priv->ports[i])
193          return OMX_ErrorInsufficientResources;
194 
195       base_video_port_Constructor(comp, &priv->ports[i], i, i == 0);
196    }
197 
198    port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];
199    port->sPortParam.format.video.nFrameWidth = 176;
200    port->sPortParam.format.video.nFrameHeight = 144;
201    port->sPortParam.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
202    port->sVideoParam.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
203    port->sPortParam.nBufferCountActual = 8;
204    port->sPortParam.nBufferCountMin = 4;
205 
206    port->Port_SendBufferFunction = vid_enc_EncodeFrame;
207    port->Port_AllocateBuffer = vid_enc_AllocateInBuffer;
208    port->Port_UseBuffer = vid_enc_UseInBuffer;
209    port->Port_FreeBuffer = vid_enc_FreeInBuffer;
210 
211    port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX];
212    strcpy(port->sPortParam.format.video.cMIMEType,"video/H264");
213    port->sPortParam.format.video.nFrameWidth = 176;
214    port->sPortParam.format.video.nFrameHeight = 144;
215    port->sPortParam.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
216    port->sVideoParam.eCompressionFormat = OMX_VIDEO_CodingAVC;
217 
218    port->Port_AllocateBuffer = vid_enc_AllocateOutBuffer;
219    port->Port_FreeBuffer = vid_enc_FreeOutBuffer;
220 
221    priv->bitrate.eControlRate = OMX_Video_ControlRateDisable;
222    priv->bitrate.nTargetBitrate = 0;
223 
224    priv->quant.nQpI = OMX_VID_ENC_QUANT_I_FRAMES_DEFAULT;
225    priv->quant.nQpP = OMX_VID_ENC_QUANT_P_FRAMES_DEFAULT;
226    priv->quant.nQpB = OMX_VID_ENC_QUANT_B_FRAMES_DEFAULT;
227 
228    priv->profile_level.eProfile = OMX_VIDEO_AVCProfileBaseline;
229    priv->profile_level.eLevel = OMX_VIDEO_AVCLevel51;
230 
231    priv->force_pic_type.IntraRefreshVOP = OMX_FALSE;
232    priv->frame_num = 0;
233    priv->pic_order_cnt = 0;
234    priv->restricted_b_frames = debug_get_bool_option("OMX_USE_RESTRICTED_B_FRAMES", FALSE);
235 
236    priv->scale.xWidth = OMX_VID_ENC_SCALING_WIDTH_DEFAULT;
237    priv->scale.xHeight = OMX_VID_ENC_SCALING_WIDTH_DEFAULT;
238 
239    list_inithead(&priv->free_tasks);
240    list_inithead(&priv->used_tasks);
241    list_inithead(&priv->b_frames);
242    list_inithead(&priv->stacked_tasks);
243 
244    return OMX_ErrorNone;
245 }
246 
vid_enc_Destructor(OMX_COMPONENTTYPE * comp)247 static OMX_ERRORTYPE vid_enc_Destructor(OMX_COMPONENTTYPE *comp)
248 {
249    vid_enc_PrivateType* priv = comp->pComponentPrivate;
250    int i;
251 
252    enc_ReleaseTasks(&priv->free_tasks);
253    enc_ReleaseTasks(&priv->used_tasks);
254    enc_ReleaseTasks(&priv->b_frames);
255    enc_ReleaseTasks(&priv->stacked_tasks);
256 
257    if (priv->ports) {
258       for (i = 0; i < priv->sPortTypesParam[OMX_PortDomainVideo].nPorts; ++i) {
259          if(priv->ports[i])
260             priv->ports[i]->PortDestructor(priv->ports[i]);
261       }
262       FREE(priv->ports);
263       priv->ports=NULL;
264    }
265 
266    for (i = 0; i < OMX_VID_ENC_NUM_SCALING_BUFFERS; ++i)
267       if (priv->scale_buffer[i])
268          priv->scale_buffer[i]->destroy(priv->scale_buffer[i]);
269 
270    if (priv->s_pipe) {
271       vl_compositor_cleanup_state(&priv->cstate);
272       vl_compositor_cleanup(&priv->compositor);
273       enc_ReleaseCompute_common(priv);
274       priv->s_pipe->destroy(priv->s_pipe);
275    }
276 
277    if (priv->t_pipe)
278       priv->t_pipe->destroy(priv->t_pipe);
279 
280    if (priv->screen)
281       omx_put_screen();
282 
283    return omx_workaround_Destructor(comp);
284 }
285 
enc_AllocateBackTexture(omx_base_PortType * port,struct pipe_resource ** resource,struct pipe_transfer ** transfer,OMX_U8 ** map)286 static OMX_ERRORTYPE enc_AllocateBackTexture(omx_base_PortType *port,
287                                              struct pipe_resource **resource,
288                                              struct pipe_transfer **transfer,
289                                              OMX_U8 **map)
290 {
291    OMX_COMPONENTTYPE* comp = port->standCompContainer;
292    vid_enc_PrivateType *priv = comp->pComponentPrivate;
293    struct pipe_resource buf_templ;
294    struct pipe_box box = {};
295    OMX_U8 *ptr;
296 
297    memset(&buf_templ, 0, sizeof buf_templ);
298    buf_templ.target = PIPE_TEXTURE_2D;
299    buf_templ.format = PIPE_FORMAT_I8_UNORM;
300    buf_templ.bind = PIPE_BIND_LINEAR;
301    buf_templ.usage = PIPE_USAGE_STAGING;
302    buf_templ.flags = 0;
303    buf_templ.width0 = port->sPortParam.format.video.nFrameWidth;
304    buf_templ.height0 = port->sPortParam.format.video.nFrameHeight * 3 / 2;
305    buf_templ.depth0 = 1;
306    buf_templ.array_size = 1;
307 
308    *resource = priv->s_pipe->screen->resource_create(priv->s_pipe->screen, &buf_templ);
309    if (!*resource)
310       return OMX_ErrorInsufficientResources;
311 
312    box.width = (*resource)->width0;
313    box.height = (*resource)->height0;
314    box.depth = (*resource)->depth0;
315    ptr = priv->s_pipe->texture_map(priv->s_pipe, *resource, 0, PIPE_MAP_WRITE, &box, transfer);
316    if (map)
317       *map = ptr;
318 
319    return OMX_ErrorNone;
320 }
321 
vid_enc_SetParameter(OMX_HANDLETYPE handle,OMX_INDEXTYPE idx,OMX_PTR param)322 static OMX_ERRORTYPE vid_enc_SetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param)
323 {
324    OMX_COMPONENTTYPE *comp = handle;
325    vid_enc_PrivateType *priv = comp->pComponentPrivate;
326    OMX_ERRORTYPE r;
327 
328    if (!param)
329       return OMX_ErrorBadParameter;
330 
331    switch(idx) {
332    case OMX_IndexParamPortDefinition: {
333       OMX_PARAM_PORTDEFINITIONTYPE *def = param;
334 
335       r = omx_base_component_SetParameter(handle, idx, param);
336       if (r)
337          return r;
338 
339       if (def->nPortIndex == OMX_BASE_FILTER_INPUTPORT_INDEX) {
340          omx_base_video_PortType *port;
341          unsigned framesize;
342          struct pipe_resource *resource;
343          struct pipe_transfer *transfer;
344 
345          port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];
346          enc_AllocateBackTexture(priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX],
347                                  &resource, &transfer, NULL);
348          port->sPortParam.format.video.nStride = transfer->stride;
349          pipe_texture_unmap(priv->s_pipe, transfer);
350          pipe_resource_reference(&resource, NULL);
351 
352          framesize = port->sPortParam.format.video.nStride *
353                      port->sPortParam.format.video.nFrameHeight;
354          port->sPortParam.format.video.nSliceHeight = port->sPortParam.format.video.nFrameHeight;
355          port->sPortParam.nBufferSize = framesize * 3 / 2;
356 
357          port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX];
358          port->sPortParam.nBufferSize = framesize * 512 / (16*16);
359 
360          priv->frame_rate = def->format.video.xFramerate;
361 
362          priv->callbacks->EventHandler(comp, priv->callbackData, OMX_EventPortSettingsChanged,
363                                        OMX_BASE_FILTER_OUTPUTPORT_INDEX, 0, NULL);
364       }
365       break;
366    }
367    case OMX_IndexParamStandardComponentRole: {
368       OMX_PARAM_COMPONENTROLETYPE *role = param;
369 
370       r = checkHeader(param, sizeof(OMX_PARAM_COMPONENTROLETYPE));
371       if (r)
372          return r;
373 
374       if (strcmp((char *)role->cRole, OMX_VID_ENC_AVC_ROLE)) {
375          return OMX_ErrorBadParameter;
376       }
377 
378       break;
379    }
380    case OMX_IndexParamVideoBitrate: {
381       OMX_VIDEO_PARAM_BITRATETYPE *bitrate = param;
382 
383       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_BITRATETYPE));
384       if (r)
385          return r;
386 
387       priv->bitrate = *bitrate;
388 
389       break;
390    }
391    case OMX_IndexParamVideoQuantization: {
392       OMX_VIDEO_PARAM_QUANTIZATIONTYPE *quant = param;
393 
394       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE));
395       if (r)
396          return r;
397 
398       priv->quant = *quant;
399 
400       break;
401    }
402    case OMX_IndexParamVideoProfileLevelCurrent: {
403       OMX_VIDEO_PARAM_PROFILELEVELTYPE *profile_level = param;
404 
405       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE));
406       if (r)
407          return r;
408 
409       priv->profile_level = *profile_level;
410 
411       break;
412    }
413    default:
414       return omx_base_component_SetParameter(handle, idx, param);
415    }
416    return OMX_ErrorNone;
417 }
418 
vid_enc_GetParameter(OMX_HANDLETYPE handle,OMX_INDEXTYPE idx,OMX_PTR param)419 static OMX_ERRORTYPE vid_enc_GetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param)
420 {
421    OMX_COMPONENTTYPE *comp = handle;
422    vid_enc_PrivateType *priv = comp->pComponentPrivate;
423    OMX_ERRORTYPE r;
424 
425    if (!param)
426       return OMX_ErrorBadParameter;
427 
428    switch(idx) {
429    case OMX_IndexParamStandardComponentRole: {
430       OMX_PARAM_COMPONENTROLETYPE *role = param;
431 
432       r = checkHeader(param, sizeof(OMX_PARAM_COMPONENTROLETYPE));
433       if (r)
434          return r;
435 
436       strcpy((char *)role->cRole, OMX_VID_ENC_AVC_ROLE);
437       break;
438    }
439    case OMX_IndexParamVideoInit:
440       r = checkHeader(param, sizeof(OMX_PORT_PARAM_TYPE));
441       if (r)
442          return r;
443 
444       memcpy(param, &priv->sPortTypesParam[OMX_PortDomainVideo], sizeof(OMX_PORT_PARAM_TYPE));
445       break;
446 
447    case OMX_IndexParamVideoPortFormat: {
448       OMX_VIDEO_PARAM_PORTFORMATTYPE *format = param;
449       omx_base_video_PortType *port;
450 
451       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
452       if (r)
453          return r;
454 
455       if (format->nPortIndex > 1)
456          return OMX_ErrorBadPortIndex;
457       if (format->nIndex >= 1)
458          return OMX_ErrorNoMore;
459 
460       port = (omx_base_video_PortType *)priv->ports[format->nPortIndex];
461       memcpy(format, &port->sVideoParam, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
462       break;
463    }
464    case OMX_IndexParamVideoBitrate: {
465       OMX_VIDEO_PARAM_BITRATETYPE *bitrate = param;
466 
467       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_BITRATETYPE));
468       if (r)
469          return r;
470 
471       bitrate->eControlRate = priv->bitrate.eControlRate;
472       bitrate->nTargetBitrate = priv->bitrate.nTargetBitrate;
473 
474       break;
475    }
476    case OMX_IndexParamVideoQuantization: {
477       OMX_VIDEO_PARAM_QUANTIZATIONTYPE *quant = param;
478 
479       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE));
480       if (r)
481          return r;
482 
483       quant->nQpI = priv->quant.nQpI;
484       quant->nQpP = priv->quant.nQpP;
485       quant->nQpB = priv->quant.nQpB;
486 
487       break;
488    }
489    case OMX_IndexParamVideoProfileLevelCurrent: {
490       OMX_VIDEO_PARAM_PROFILELEVELTYPE *profile_level = param;
491 
492       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE));
493       if (r)
494          return r;
495 
496       profile_level->eProfile = priv->profile_level.eProfile;
497       profile_level->eLevel = priv->profile_level.eLevel;
498 
499       break;
500    }
501    default:
502       return omx_base_component_GetParameter(handle, idx, param);
503    }
504    return OMX_ErrorNone;
505 }
506 
vid_enc_SetConfig(OMX_HANDLETYPE handle,OMX_INDEXTYPE idx,OMX_PTR config)507 static OMX_ERRORTYPE vid_enc_SetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config)
508 {
509    OMX_COMPONENTTYPE *comp = handle;
510    vid_enc_PrivateType *priv = comp->pComponentPrivate;
511    OMX_ERRORTYPE r;
512    int i;
513 
514    if (!config)
515       return OMX_ErrorBadParameter;
516 
517    switch(idx) {
518    case OMX_IndexConfigVideoIntraVOPRefresh: {
519       OMX_CONFIG_INTRAREFRESHVOPTYPE *type = config;
520 
521       r = checkHeader(config, sizeof(OMX_CONFIG_INTRAREFRESHVOPTYPE));
522       if (r)
523          return r;
524 
525       priv->force_pic_type = *type;
526 
527       break;
528    }
529    case OMX_IndexConfigCommonScale: {
530       OMX_CONFIG_SCALEFACTORTYPE *scale = config;
531 
532       r = checkHeader(config, sizeof(OMX_CONFIG_SCALEFACTORTYPE));
533       if (r)
534          return r;
535 
536       if (scale->xWidth < 176 || scale->xHeight < 144)
537          return OMX_ErrorBadParameter;
538 
539       for (i = 0; i < OMX_VID_ENC_NUM_SCALING_BUFFERS; ++i) {
540          if (priv->scale_buffer[i]) {
541             priv->scale_buffer[i]->destroy(priv->scale_buffer[i]);
542             priv->scale_buffer[i] = NULL;
543          }
544       }
545 
546       priv->scale = *scale;
547       if (priv->scale.xWidth != 0xffffffff && priv->scale.xHeight != 0xffffffff) {
548          struct pipe_video_buffer templat = {};
549 
550          templat.buffer_format = PIPE_FORMAT_NV12;
551          templat.width = priv->scale.xWidth;
552          templat.height = priv->scale.xHeight;
553          templat.interlaced = false;
554          for (i = 0; i < OMX_VID_ENC_NUM_SCALING_BUFFERS; ++i) {
555             priv->scale_buffer[i] = priv->s_pipe->create_video_buffer(priv->s_pipe, &templat);
556             if (!priv->scale_buffer[i])
557                return OMX_ErrorInsufficientResources;
558          }
559       }
560 
561       break;
562    }
563    default:
564       return omx_base_component_SetConfig(handle, idx, config);
565    }
566 
567    return OMX_ErrorNone;
568 }
569 
vid_enc_GetConfig(OMX_HANDLETYPE handle,OMX_INDEXTYPE idx,OMX_PTR config)570 static OMX_ERRORTYPE vid_enc_GetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config)
571 {
572    OMX_COMPONENTTYPE *comp = handle;
573    vid_enc_PrivateType *priv = comp->pComponentPrivate;
574    OMX_ERRORTYPE r;
575 
576    if (!config)
577       return OMX_ErrorBadParameter;
578 
579    switch(idx) {
580    case OMX_IndexConfigCommonScale: {
581       OMX_CONFIG_SCALEFACTORTYPE *scale = config;
582 
583       r = checkHeader(config, sizeof(OMX_CONFIG_SCALEFACTORTYPE));
584       if (r)
585          return r;
586 
587       scale->xWidth = priv->scale.xWidth;
588       scale->xHeight = priv->scale.xHeight;
589 
590       break;
591    }
592    default:
593       return omx_base_component_GetConfig(handle, idx, config);
594    }
595 
596    return OMX_ErrorNone;
597 }
598 
vid_enc_MessageHandler(OMX_COMPONENTTYPE * comp,internalRequestMessageType * msg)599 static OMX_ERRORTYPE vid_enc_MessageHandler(OMX_COMPONENTTYPE* comp, internalRequestMessageType *msg)
600 {
601    vid_enc_PrivateType* priv = comp->pComponentPrivate;
602 
603    if (msg->messageType == OMX_CommandStateSet) {
604       if ((msg->messageParam == OMX_StateIdle ) && (priv->state == OMX_StateLoaded)) {
605 
606          struct pipe_video_codec templat = {};
607          omx_base_video_PortType *port;
608 
609          port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];
610 
611          templat.profile = enc_TranslateOMXProfileToPipe(priv->profile_level.eProfile);
612          templat.level = enc_TranslateOMXLevelToPipe(priv->profile_level.eLevel);
613          templat.entrypoint = PIPE_VIDEO_ENTRYPOINT_ENCODE;
614          templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
615          templat.width = priv->scale_buffer[priv->current_scale_buffer] ?
616                             priv->scale.xWidth : port->sPortParam.format.video.nFrameWidth;
617          templat.height = priv->scale_buffer[priv->current_scale_buffer] ?
618                             priv->scale.xHeight : port->sPortParam.format.video.nFrameHeight;
619 
620          if (templat.profile == PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE) {
621             struct pipe_screen *screen = priv->screen->pscreen;
622             templat.max_references = 1;
623             priv->stacked_frames_num =
624                screen->get_video_param(screen,
625                                        PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH,
626                                        PIPE_VIDEO_ENTRYPOINT_ENCODE,
627                                        PIPE_VIDEO_CAP_STACKED_FRAMES);
628          } else {
629             templat.max_references = OMX_VID_ENC_P_PERIOD_DEFAULT;
630             priv->stacked_frames_num = 1;
631          }
632          priv->codec = priv->s_pipe->create_video_codec(priv->s_pipe, &templat);
633 
634       } else if ((msg->messageParam == OMX_StateLoaded) && (priv->state == OMX_StateIdle)) {
635          if (priv->codec) {
636             priv->codec->destroy(priv->codec);
637             priv->codec = NULL;
638          }
639       }
640    }
641 
642    return omx_base_component_MessageHandler(comp, msg);
643 }
644 
vid_enc_AllocateInBuffer(omx_base_PortType * port,OMX_INOUT OMX_BUFFERHEADERTYPE ** buf,OMX_IN OMX_U32 idx,OMX_IN OMX_PTR private,OMX_IN OMX_U32 size)645 static OMX_ERRORTYPE vid_enc_AllocateInBuffer(omx_base_PortType *port, OMX_INOUT OMX_BUFFERHEADERTYPE **buf,
646                                               OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size)
647 {
648    struct input_buf_private *inp;
649    OMX_ERRORTYPE r;
650 
651    r = base_port_AllocateBuffer(port, buf, idx, private, size);
652    if (r)
653       return r;
654 
655    inp = (*buf)->pInputPortPrivate = CALLOC_STRUCT(input_buf_private);
656    if (!inp) {
657       base_port_FreeBuffer(port, idx, *buf);
658       return OMX_ErrorInsufficientResources;
659    }
660 
661    list_inithead(&inp->tasks);
662 
663    FREE((*buf)->pBuffer);
664    r = enc_AllocateBackTexture(port, &inp->resource, &inp->transfer, &(*buf)->pBuffer);
665    if (r) {
666       FREE(inp);
667       base_port_FreeBuffer(port, idx, *buf);
668       return r;
669    }
670 
671    return OMX_ErrorNone;
672 }
673 
vid_enc_UseInBuffer(omx_base_PortType * port,OMX_BUFFERHEADERTYPE ** buf,OMX_U32 idx,OMX_PTR private,OMX_U32 size,OMX_U8 * mem)674 static OMX_ERRORTYPE vid_enc_UseInBuffer(omx_base_PortType *port, OMX_BUFFERHEADERTYPE **buf, OMX_U32 idx,
675                                          OMX_PTR private, OMX_U32 size, OMX_U8 *mem)
676 {
677    struct input_buf_private *inp;
678    OMX_ERRORTYPE r;
679 
680    r = base_port_UseBuffer(port, buf, idx, private, size, mem);
681    if (r)
682       return r;
683 
684    inp = (*buf)->pInputPortPrivate = CALLOC_STRUCT(input_buf_private);
685    if (!inp) {
686       base_port_FreeBuffer(port, idx, *buf);
687       return OMX_ErrorInsufficientResources;
688    }
689 
690    list_inithead(&inp->tasks);
691 
692    return OMX_ErrorNone;
693 }
694 
vid_enc_FreeInBuffer(omx_base_PortType * port,OMX_U32 idx,OMX_BUFFERHEADERTYPE * buf)695 static OMX_ERRORTYPE vid_enc_FreeInBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf)
696 {
697    OMX_COMPONENTTYPE* comp = port->standCompContainer;
698    vid_enc_PrivateType *priv = comp->pComponentPrivate;
699    struct input_buf_private *inp = buf->pInputPortPrivate;
700 
701    if (inp) {
702       enc_ReleaseTasks(&inp->tasks);
703       if (inp->transfer)
704          pipe_texture_unmap(priv->s_pipe, inp->transfer);
705       pipe_resource_reference(&inp->resource, NULL);
706       FREE(inp);
707    }
708    buf->pBuffer = NULL;
709 
710    return base_port_FreeBuffer(port, idx, buf);
711 }
712 
vid_enc_AllocateOutBuffer(omx_base_PortType * port,OMX_INOUT OMX_BUFFERHEADERTYPE ** buf,OMX_IN OMX_U32 idx,OMX_IN OMX_PTR private,OMX_IN OMX_U32 size)713 static OMX_ERRORTYPE vid_enc_AllocateOutBuffer(omx_base_PortType *port, OMX_INOUT OMX_BUFFERHEADERTYPE **buf,
714                                                OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size)
715 {
716    OMX_ERRORTYPE r;
717 
718    r = base_port_AllocateBuffer(port, buf, idx, private, size);
719    if (r)
720       return r;
721 
722    FREE((*buf)->pBuffer);
723    (*buf)->pBuffer = NULL;
724    (*buf)->pOutputPortPrivate = CALLOC(1, sizeof(struct output_buf_private));
725    if (!(*buf)->pOutputPortPrivate) {
726       base_port_FreeBuffer(port, idx, *buf);
727       return OMX_ErrorInsufficientResources;
728    }
729 
730    return OMX_ErrorNone;
731 }
732 
vid_enc_FreeOutBuffer(omx_base_PortType * port,OMX_U32 idx,OMX_BUFFERHEADERTYPE * buf)733 static OMX_ERRORTYPE vid_enc_FreeOutBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf)
734 {
735    OMX_COMPONENTTYPE* comp = port->standCompContainer;
736    vid_enc_PrivateType *priv = comp->pComponentPrivate;
737 
738    if (buf->pOutputPortPrivate) {
739       struct output_buf_private *outp = buf->pOutputPortPrivate;
740       if (outp->transfer)
741          pipe_buffer_unmap(priv->t_pipe, outp->transfer);
742       pipe_resource_reference(&outp->bitstream, NULL);
743       FREE(outp);
744       buf->pOutputPortPrivate = NULL;
745    }
746    buf->pBuffer = NULL;
747 
748    return base_port_FreeBuffer(port, idx, buf);
749 }
750 
enc_NeedTask(omx_base_PortType * port)751 static struct encode_task *enc_NeedTask(omx_base_PortType *port)
752 {
753    OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video;
754    OMX_COMPONENTTYPE* comp = port->standCompContainer;
755    vid_enc_PrivateType *priv = comp->pComponentPrivate;
756 
757    return enc_NeedTask_common(priv, def);
758 }
759 
enc_LoadImage(omx_base_PortType * port,OMX_BUFFERHEADERTYPE * buf,struct pipe_video_buffer * vbuf)760 static OMX_ERRORTYPE enc_LoadImage(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf,
761                                    struct pipe_video_buffer *vbuf)
762 {
763    OMX_COMPONENTTYPE* comp = port->standCompContainer;
764    vid_enc_PrivateType *priv = comp->pComponentPrivate;
765    OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video;
766    return enc_LoadImage_common(priv, def, buf, vbuf);
767 }
768 
enc_ScaleInput(omx_base_PortType * port,struct pipe_video_buffer ** vbuf,unsigned * size)769 static void enc_ScaleInput(omx_base_PortType *port, struct pipe_video_buffer **vbuf, unsigned *size)
770 {
771    OMX_COMPONENTTYPE* comp = port->standCompContainer;
772    vid_enc_PrivateType *priv = comp->pComponentPrivate;
773    OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video;
774    enc_ScaleInput_common(priv, def, vbuf, size);
775 }
776 
enc_ControlPicture(omx_base_PortType * port,struct pipe_h264_enc_picture_desc * picture)777 static void enc_ControlPicture(omx_base_PortType *port, struct pipe_h264_enc_picture_desc *picture)
778 {
779    OMX_COMPONENTTYPE* comp = port->standCompContainer;
780    vid_enc_PrivateType *priv = comp->pComponentPrivate;
781    enc_ControlPicture_common(priv, picture);
782 }
783 
enc_HandleTask(omx_base_PortType * port,struct encode_task * task,enum pipe_h2645_enc_picture_type picture_type)784 static void enc_HandleTask(omx_base_PortType *port, struct encode_task *task,
785                            enum pipe_h2645_enc_picture_type picture_type)
786 {
787    OMX_COMPONENTTYPE* comp = port->standCompContainer;
788    vid_enc_PrivateType *priv = comp->pComponentPrivate;
789    unsigned size = priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX]->sPortParam.nBufferSize;
790    struct pipe_video_buffer *vbuf = task->buf;
791    struct pipe_h264_enc_picture_desc picture = {};
792 
793    /* -------------- scale input image --------- */
794    enc_ScaleInput(port, &vbuf, &size);
795    priv->s_pipe->flush(priv->s_pipe, NULL, 0);
796 
797    /* -------------- allocate output buffer --------- */
798    task->bitstream = pipe_buffer_create(priv->s_pipe->screen,
799                                         PIPE_BIND_VERTEX_BUFFER,
800                                         PIPE_USAGE_STAGING, /* map for read */
801                                         size);
802 
803    picture.picture_type = picture_type;
804    picture.pic_order_cnt = task->pic_order_cnt;
805    picture.base.profile = enc_TranslateOMXProfileToPipe(priv->profile_level.eProfile);
806    picture.base.entry_point = PIPE_VIDEO_ENTRYPOINT_ENCODE;
807    if (priv->restricted_b_frames && picture_type == PIPE_H2645_ENC_PICTURE_TYPE_B)
808       picture.not_referenced = true;
809    enc_ControlPicture(port, &picture);
810 
811    /* -------------- encode frame --------- */
812    priv->codec->begin_frame(priv->codec, vbuf, &picture.base);
813    priv->codec->encode_bitstream(priv->codec, vbuf, task->bitstream, &task->feedback);
814    priv->codec->end_frame(priv->codec, vbuf, &picture.base);
815 }
816 
enc_ClearBframes(omx_base_PortType * port,struct input_buf_private * inp)817 static void enc_ClearBframes(omx_base_PortType *port, struct input_buf_private *inp)
818 {
819    OMX_COMPONENTTYPE* comp = port->standCompContainer;
820    vid_enc_PrivateType *priv = comp->pComponentPrivate;
821    struct encode_task *task;
822 
823    if (list_is_empty(&priv->b_frames))
824       return;
825 
826    task = list_entry(priv->b_frames.prev, struct encode_task, list);
827    list_del(&task->list);
828 
829    /* promote last from to P frame */
830    priv->ref_idx_l0 = priv->ref_idx_l1;
831    enc_HandleTask(port, task, PIPE_H2645_ENC_PICTURE_TYPE_P);
832    list_addtail(&task->list, &inp->tasks);
833    priv->ref_idx_l1 = priv->frame_num++;
834 
835    /* handle B frames */
836    LIST_FOR_EACH_ENTRY(task, &priv->b_frames, list) {
837       enc_HandleTask(port, task, PIPE_H2645_ENC_PICTURE_TYPE_B);
838       if (!priv->restricted_b_frames)
839          priv->ref_idx_l0 = priv->frame_num;
840       priv->frame_num++;
841    }
842 
843    enc_MoveTasks(&priv->b_frames, &inp->tasks);
844 }
845 
vid_enc_EncodeFrame(omx_base_PortType * port,OMX_BUFFERHEADERTYPE * buf)846 static OMX_ERRORTYPE vid_enc_EncodeFrame(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf)
847 {
848    OMX_COMPONENTTYPE* comp = port->standCompContainer;
849    vid_enc_PrivateType *priv = comp->pComponentPrivate;
850    struct input_buf_private *inp = buf->pInputPortPrivate;
851    enum pipe_h2645_enc_picture_type picture_type;
852    struct encode_task *task;
853    unsigned stacked_num = 0;
854    OMX_ERRORTYPE err;
855 
856    enc_MoveTasks(&inp->tasks, &priv->free_tasks);
857    task = enc_NeedTask(port);
858    if (!task)
859       return OMX_ErrorInsufficientResources;
860 
861    if (buf->nFilledLen == 0) {
862       if (buf->nFlags & OMX_BUFFERFLAG_EOS) {
863          buf->nFilledLen = buf->nAllocLen;
864          enc_ClearBframes(port, inp);
865          enc_MoveTasks(&priv->stacked_tasks, &inp->tasks);
866          priv->codec->flush(priv->codec);
867       }
868       return base_port_SendBufferFunction(port, buf);
869    }
870 
871    if (buf->pOutputPortPrivate) {
872       struct pipe_video_buffer *vbuf = buf->pOutputPortPrivate;
873       buf->pOutputPortPrivate = task->buf;
874       task->buf = vbuf;
875    } else {
876       /* ------- load input image into video buffer ---- */
877       err = enc_LoadImage(port, buf, task->buf);
878       if (err != OMX_ErrorNone) {
879          FREE(task);
880          return err;
881       }
882    }
883 
884    /* -------------- determine picture type --------- */
885    if (!(priv->pic_order_cnt % OMX_VID_ENC_IDR_PERIOD_DEFAULT) ||
886        priv->force_pic_type.IntraRefreshVOP) {
887       enc_ClearBframes(port, inp);
888       picture_type = PIPE_H2645_ENC_PICTURE_TYPE_IDR;
889       priv->force_pic_type.IntraRefreshVOP = OMX_FALSE;
890       priv->frame_num = 0;
891       priv->pic_order_cnt = 0;
892    } else if (priv->codec->profile == PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE ||
893               !(priv->pic_order_cnt % OMX_VID_ENC_P_PERIOD_DEFAULT) ||
894               (buf->nFlags & OMX_BUFFERFLAG_EOS)) {
895       picture_type = PIPE_H2645_ENC_PICTURE_TYPE_P;
896    } else {
897       picture_type = PIPE_H2645_ENC_PICTURE_TYPE_B;
898    }
899 
900    task->pic_order_cnt = priv->pic_order_cnt++;
901 
902    if (picture_type == PIPE_H2645_ENC_PICTURE_TYPE_B) {
903       /* put frame at the tail of the queue */
904       list_addtail(&task->list, &priv->b_frames);
905    } else {
906       /* handle I or P frame */
907       priv->ref_idx_l0 = priv->ref_idx_l1;
908       enc_HandleTask(port, task, picture_type);
909       list_addtail(&task->list, &priv->stacked_tasks);
910       LIST_FOR_EACH_ENTRY(task, &priv->stacked_tasks, list) {
911          ++stacked_num;
912       }
913       if (stacked_num == priv->stacked_frames_num) {
914          struct encode_task *t;
915          t = list_entry(priv->stacked_tasks.next, struct encode_task, list);
916          list_del(&t->list);
917          list_addtail(&t->list, &inp->tasks);
918       }
919       priv->ref_idx_l1 = priv->frame_num++;
920 
921       /* handle B frames */
922       LIST_FOR_EACH_ENTRY(task, &priv->b_frames, list) {
923          enc_HandleTask(port, task, PIPE_H2645_ENC_PICTURE_TYPE_B);
924          if (!priv->restricted_b_frames)
925             priv->ref_idx_l0 = priv->frame_num;
926          priv->frame_num++;
927       }
928 
929       enc_MoveTasks(&priv->b_frames, &inp->tasks);
930    }
931 
932    if (list_is_empty(&inp->tasks))
933       return port->ReturnBufferFunction(port, buf);
934    else
935       return base_port_SendBufferFunction(port, buf);
936 }
937 
vid_enc_BufferEncoded(OMX_COMPONENTTYPE * comp,OMX_BUFFERHEADERTYPE * input,OMX_BUFFERHEADERTYPE * output)938 static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input, OMX_BUFFERHEADERTYPE* output)
939 {
940    vid_enc_PrivateType *priv = comp->pComponentPrivate;
941    vid_enc_BufferEncoded_common(priv, input, output);
942 }
943