• 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 "state_tracker/drm_driver.h"
52 #include "util/u_memory.h"
53 #include "vl/vl_video_buffer.h"
54 
55 #include "entrypoint.h"
56 #include "vid_enc.h"
57 
58 struct encode_task {
59    struct list_head list;
60 
61    struct pipe_video_buffer *buf;
62    unsigned pic_order_cnt;
63    struct pipe_resource *bitstream;
64    void *feedback;
65 };
66 
67 struct input_buf_private {
68    struct list_head tasks;
69 
70    struct pipe_resource *resource;
71    struct pipe_transfer *transfer;
72 };
73 
74 struct output_buf_private {
75    struct pipe_resource *bitstream;
76    struct pipe_transfer *transfer;
77 };
78 
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);
96 
97 static void enc_ReleaseTasks(struct list_head *head);
98 
vid_enc_LoaderComponent(stLoaderComponentType * comp)99 OMX_ERRORTYPE vid_enc_LoaderComponent(stLoaderComponentType *comp)
100 {
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;
107 
108    comp->name = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);
109    if (!comp->name)
110       return OMX_ErrorInsufficientResources;
111 
112    comp->name_specific = CALLOC(1, sizeof(char *));
113    if (!comp->name_specific)
114       goto error_arrays;
115 
116    comp->role_specific = CALLOC(1, sizeof(char *));
117    if (!comp->role_specific)
118       goto error_arrays;
119 
120    comp->name_specific[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);
121    if (comp->name_specific[0] == NULL)
122       goto error_specific;
123 
124    comp->role_specific[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);
125    if (comp->role_specific[0] == NULL)
126       goto error_specific;
127 
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);
131 
132    return OMX_ErrorNone;
133 
134 error_specific:
135    FREE(comp->role_specific[0]);
136    FREE(comp->name_specific[0]);
137 
138 error_arrays:
139    FREE(comp->role_specific);
140    FREE(comp->name_specific);
141 
142    FREE(comp->name);
143 
144    return OMX_ErrorInsufficientResources;
145 }
146 
vid_enc_Constructor(OMX_COMPONENTTYPE * comp,OMX_STRING name)147 static OMX_ERRORTYPE vid_enc_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING name)
148 {
149    vid_enc_PrivateType *priv;
150    omx_base_video_PortType *port;
151    struct pipe_screen *screen;
152    OMX_ERRORTYPE r;
153    int i;
154 
155    assert(!comp->pComponentPrivate);
156 
157    priv = comp->pComponentPrivate = CALLOC(1, sizeof(vid_enc_PrivateType));
158    if (!priv)
159       return OMX_ErrorInsufficientResources;
160 
161    r = omx_base_filter_Constructor(comp, name);
162    if (r)
163 	return r;
164 
165    priv->BufferMgmtCallback = vid_enc_BufferEncoded;
166    priv->messageHandler = vid_enc_MessageHandler;
167    priv->destructor = vid_enc_Destructor;
168 
169    comp->SetParameter = vid_enc_SetParameter;
170    comp->GetParameter = vid_enc_GetParameter;
171    comp->GetConfig = vid_enc_GetConfig;
172    comp->SetConfig = vid_enc_SetConfig;
173 
174    priv->screen = omx_get_screen();
175    if (!priv->screen)
176       return OMX_ErrorInsufficientResources;
177 
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;
182 
183    priv->s_pipe = screen->context_create(screen, priv->screen, 0);
184    if (!priv->s_pipe)
185       return OMX_ErrorInsufficientResources;
186 
187    if (!vl_compositor_init(&priv->compositor, priv->s_pipe)) {
188       priv->s_pipe->destroy(priv->s_pipe);
189       priv->s_pipe = NULL;
190       return OMX_ErrorInsufficientResources;
191    }
192 
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);
196       priv->s_pipe = NULL;
197       return OMX_ErrorInsufficientResources;
198    }
199 
200    priv->t_pipe = screen->context_create(screen, priv->screen, 0);
201    if (!priv->t_pipe)
202       return OMX_ErrorInsufficientResources;
203 
204    priv->sPortTypesParam[OMX_PortDomainVideo].nStartPortNumber = 0;
205    priv->sPortTypesParam[OMX_PortDomainVideo].nPorts = 2;
206    priv->ports = CALLOC(2, sizeof(omx_base_PortType *));
207    if (!priv->ports)
208       return OMX_ErrorInsufficientResources;
209 
210    for (i = 0; i < 2; ++i) {
211       priv->ports[i] = CALLOC(1, sizeof(omx_base_video_PortType));
212       if (!priv->ports[i])
213          return OMX_ErrorInsufficientResources;
214 
215       base_video_port_Constructor(comp, &priv->ports[i], i, i == 0);
216    }
217 
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;
225 
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;
230 
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;
237 
238    port->Port_AllocateBuffer = vid_enc_AllocateOutBuffer;
239    port->Port_FreeBuffer = vid_enc_FreeOutBuffer;
240 
241    priv->bitrate.eControlRate = OMX_Video_ControlRateDisable;
242    priv->bitrate.nTargetBitrate = 0;
243 
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;
247 
248    priv->profile_level.eProfile = OMX_VIDEO_AVCProfileBaseline;
249    priv->profile_level.eLevel = OMX_VIDEO_AVCLevel51;
250 
251    priv->force_pic_type.IntraRefreshVOP = OMX_FALSE;
252    priv->frame_num = 0;
253    priv->pic_order_cnt = 0;
254    priv->restricted_b_frames = debug_get_bool_option("OMX_USE_RESTRICTED_B_FRAMES", FALSE);
255 
256    priv->scale.xWidth = OMX_VID_ENC_SCALING_WIDTH_DEFAULT;
257    priv->scale.xHeight = OMX_VID_ENC_SCALING_WIDTH_DEFAULT;
258 
259    LIST_INITHEAD(&priv->free_tasks);
260    LIST_INITHEAD(&priv->used_tasks);
261    LIST_INITHEAD(&priv->b_frames);
262    LIST_INITHEAD(&priv->stacked_tasks);
263 
264    return OMX_ErrorNone;
265 }
266 
vid_enc_Destructor(OMX_COMPONENTTYPE * comp)267 static OMX_ERRORTYPE vid_enc_Destructor(OMX_COMPONENTTYPE *comp)
268 {
269    vid_enc_PrivateType* priv = comp->pComponentPrivate;
270    int i;
271 
272    enc_ReleaseTasks(&priv->free_tasks);
273    enc_ReleaseTasks(&priv->used_tasks);
274    enc_ReleaseTasks(&priv->b_frames);
275    enc_ReleaseTasks(&priv->stacked_tasks);
276 
277    if (priv->ports) {
278       for (i = 0; i < priv->sPortTypesParam[OMX_PortDomainVideo].nPorts; ++i) {
279          if(priv->ports[i])
280             priv->ports[i]->PortDestructor(priv->ports[i]);
281       }
282       FREE(priv->ports);
283       priv->ports=NULL;
284    }
285 
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]);
289 
290    if (priv->s_pipe) {
291       vl_compositor_cleanup_state(&priv->cstate);
292       vl_compositor_cleanup(&priv->compositor);
293       priv->s_pipe->destroy(priv->s_pipe);
294    }
295 
296    if (priv->t_pipe)
297       priv->t_pipe->destroy(priv->t_pipe);
298 
299    if (priv->screen)
300       omx_put_screen();
301 
302    return omx_workaround_Destructor(comp);
303 }
304 
enc_AllocateBackTexture(omx_base_PortType * port,struct pipe_resource ** resource,struct pipe_transfer ** transfer,OMX_U8 ** map)305 static OMX_ERRORTYPE enc_AllocateBackTexture(omx_base_PortType *port,
306                                              struct pipe_resource **resource,
307                                              struct pipe_transfer **transfer,
308                                              OMX_U8 **map)
309 {
310    OMX_COMPONENTTYPE* comp = port->standCompContainer;
311    vid_enc_PrivateType *priv = comp->pComponentPrivate;
312    struct pipe_resource buf_templ;
313    struct pipe_box box = {};
314    OMX_U8 *ptr;
315 
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;
321    buf_templ.flags = 0;
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;
326 
327    *resource = priv->s_pipe->screen->resource_create(priv->s_pipe->screen, &buf_templ);
328    if (!*resource)
329       return OMX_ErrorInsufficientResources;
330 
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);
335    if (map)
336       *map = ptr;
337 
338    return OMX_ErrorNone;
339 }
340 
vid_enc_SetParameter(OMX_HANDLETYPE handle,OMX_INDEXTYPE idx,OMX_PTR param)341 static OMX_ERRORTYPE vid_enc_SetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param)
342 {
343    OMX_COMPONENTTYPE *comp = handle;
344    vid_enc_PrivateType *priv = comp->pComponentPrivate;
345    OMX_ERRORTYPE r;
346 
347    if (!param)
348       return OMX_ErrorBadParameter;
349 
350    switch(idx) {
351    case OMX_IndexParamPortDefinition: {
352       OMX_PARAM_PORTDEFINITIONTYPE *def = param;
353 
354       r = omx_base_component_SetParameter(handle, idx, param);
355       if (r)
356          return r;
357 
358       if (def->nPortIndex == OMX_BASE_FILTER_INPUTPORT_INDEX) {
359          omx_base_video_PortType *port;
360          unsigned framesize;
361          struct pipe_resource *resource;
362          struct pipe_transfer *transfer;
363 
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);
370 
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;
375 
376          port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX];
377          port->sPortParam.nBufferSize = framesize * 512 / (16*16);
378 
379          priv->frame_rate = def->format.video.xFramerate;
380 
381          priv->callbacks->EventHandler(comp, priv->callbackData, OMX_EventPortSettingsChanged,
382                                        OMX_BASE_FILTER_OUTPUTPORT_INDEX, 0, NULL);
383       }
384       break;
385    }
386    case OMX_IndexParamStandardComponentRole: {
387       OMX_PARAM_COMPONENTROLETYPE *role = param;
388 
389       r = checkHeader(param, sizeof(OMX_PARAM_COMPONENTROLETYPE));
390       if (r)
391          return r;
392 
393       if (strcmp((char *)role->cRole, OMX_VID_ENC_AVC_ROLE)) {
394          return OMX_ErrorBadParameter;
395       }
396 
397       break;
398    }
399    case OMX_IndexParamVideoBitrate: {
400       OMX_VIDEO_PARAM_BITRATETYPE *bitrate = param;
401 
402       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_BITRATETYPE));
403       if (r)
404          return r;
405 
406       priv->bitrate = *bitrate;
407 
408       break;
409    }
410    case OMX_IndexParamVideoQuantization: {
411       OMX_VIDEO_PARAM_QUANTIZATIONTYPE *quant = param;
412 
413       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE));
414       if (r)
415          return r;
416 
417       priv->quant = *quant;
418 
419       break;
420    }
421    case OMX_IndexParamVideoProfileLevelCurrent: {
422       OMX_VIDEO_PARAM_PROFILELEVELTYPE *profile_level = param;
423 
424       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE));
425       if (r)
426          return r;
427 
428       priv->profile_level = *profile_level;
429 
430       break;
431    }
432    default:
433       return omx_base_component_SetParameter(handle, idx, param);
434    }
435    return OMX_ErrorNone;
436 }
437 
vid_enc_GetParameter(OMX_HANDLETYPE handle,OMX_INDEXTYPE idx,OMX_PTR param)438 static OMX_ERRORTYPE vid_enc_GetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param)
439 {
440    OMX_COMPONENTTYPE *comp = handle;
441    vid_enc_PrivateType *priv = comp->pComponentPrivate;
442    OMX_ERRORTYPE r;
443 
444    if (!param)
445       return OMX_ErrorBadParameter;
446 
447    switch(idx) {
448    case OMX_IndexParamStandardComponentRole: {
449       OMX_PARAM_COMPONENTROLETYPE *role = param;
450 
451       r = checkHeader(param, sizeof(OMX_PARAM_COMPONENTROLETYPE));
452       if (r)
453          return r;
454 
455       strcpy((char *)role->cRole, OMX_VID_ENC_AVC_ROLE);
456       break;
457    }
458    case OMX_IndexParamVideoInit:
459       r = checkHeader(param, sizeof(OMX_PORT_PARAM_TYPE));
460       if (r)
461          return r;
462 
463       memcpy(param, &priv->sPortTypesParam[OMX_PortDomainVideo], sizeof(OMX_PORT_PARAM_TYPE));
464       break;
465 
466    case OMX_IndexParamVideoPortFormat: {
467       OMX_VIDEO_PARAM_PORTFORMATTYPE *format = param;
468       omx_base_video_PortType *port;
469 
470       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
471       if (r)
472          return r;
473 
474       if (format->nPortIndex > 1)
475          return OMX_ErrorBadPortIndex;
476 
477       port = (omx_base_video_PortType *)priv->ports[format->nPortIndex];
478       memcpy(format, &port->sVideoParam, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
479       break;
480    }
481    case OMX_IndexParamVideoBitrate: {
482       OMX_VIDEO_PARAM_BITRATETYPE *bitrate = param;
483 
484       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_BITRATETYPE));
485       if (r)
486          return r;
487 
488       bitrate->eControlRate = priv->bitrate.eControlRate;
489       bitrate->nTargetBitrate = priv->bitrate.nTargetBitrate;
490 
491       break;
492    }
493    case OMX_IndexParamVideoQuantization: {
494       OMX_VIDEO_PARAM_QUANTIZATIONTYPE *quant = param;
495 
496       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE));
497       if (r)
498          return r;
499 
500       quant->nQpI = priv->quant.nQpI;
501       quant->nQpP = priv->quant.nQpP;
502       quant->nQpB = priv->quant.nQpB;
503 
504       break;
505    }
506    case OMX_IndexParamVideoProfileLevelCurrent: {
507       OMX_VIDEO_PARAM_PROFILELEVELTYPE *profile_level = param;
508 
509       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE));
510       if (r)
511          return r;
512 
513       profile_level->eProfile = priv->profile_level.eProfile;
514       profile_level->eLevel = priv->profile_level.eLevel;
515 
516       break;
517    }
518    default:
519       return omx_base_component_GetParameter(handle, idx, param);
520    }
521    return OMX_ErrorNone;
522 }
523 
vid_enc_SetConfig(OMX_HANDLETYPE handle,OMX_INDEXTYPE idx,OMX_PTR config)524 static OMX_ERRORTYPE vid_enc_SetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config)
525 {
526    OMX_COMPONENTTYPE *comp = handle;
527    vid_enc_PrivateType *priv = comp->pComponentPrivate;
528    OMX_ERRORTYPE r;
529    int i;
530 
531    if (!config)
532       return OMX_ErrorBadParameter;
533 
534    switch(idx) {
535    case OMX_IndexConfigVideoIntraVOPRefresh: {
536       OMX_CONFIG_INTRAREFRESHVOPTYPE *type = config;
537 
538       r = checkHeader(config, sizeof(OMX_CONFIG_INTRAREFRESHVOPTYPE));
539       if (r)
540          return r;
541 
542       priv->force_pic_type = *type;
543 
544       break;
545    }
546    case OMX_IndexConfigCommonScale: {
547       OMX_CONFIG_SCALEFACTORTYPE *scale = config;
548 
549       r = checkHeader(config, sizeof(OMX_CONFIG_SCALEFACTORTYPE));
550       if (r)
551          return r;
552 
553       if (scale->xWidth < 176 || scale->xHeight < 144)
554          return OMX_ErrorBadParameter;
555 
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;
560          }
561       }
562 
563       priv->scale = *scale;
564       if (priv->scale.xWidth != 0xffffffff && priv->scale.xHeight != 0xffffffff) {
565          struct pipe_video_buffer templat = {};
566 
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;
576          }
577       }
578 
579       break;
580    }
581    default:
582       return omx_base_component_SetConfig(handle, idx, config);
583    }
584 
585    return OMX_ErrorNone;
586 }
587 
vid_enc_GetConfig(OMX_HANDLETYPE handle,OMX_INDEXTYPE idx,OMX_PTR config)588 static OMX_ERRORTYPE vid_enc_GetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config)
589 {
590    OMX_COMPONENTTYPE *comp = handle;
591    vid_enc_PrivateType *priv = comp->pComponentPrivate;
592    OMX_ERRORTYPE r;
593 
594    if (!config)
595       return OMX_ErrorBadParameter;
596 
597    switch(idx) {
598    case OMX_IndexConfigCommonScale: {
599       OMX_CONFIG_SCALEFACTORTYPE *scale = config;
600 
601       r = checkHeader(config, sizeof(OMX_CONFIG_SCALEFACTORTYPE));
602       if (r)
603          return r;
604 
605       scale->xWidth = priv->scale.xWidth;
606       scale->xHeight = priv->scale.xHeight;
607 
608       break;
609    }
610    default:
611       return omx_base_component_GetConfig(handle, idx, config);
612    }
613 
614    return OMX_ErrorNone;
615 }
616 
enc_TranslateOMXProfileToPipe(unsigned omx_profile)617 static enum pipe_video_profile enc_TranslateOMXProfileToPipe(unsigned omx_profile)
618 {
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;
634    default:
635       return PIPE_VIDEO_PROFILE_UNKNOWN;
636    }
637 }
638 
enc_TranslateOMXLevelToPipe(unsigned omx_level)639 static unsigned enc_TranslateOMXLevelToPipe(unsigned omx_level)
640 {
641    switch (omx_level) {
642    case OMX_VIDEO_AVCLevel1:
643    case OMX_VIDEO_AVCLevel1b:
644       return 10;
645    case OMX_VIDEO_AVCLevel11:
646       return 11;
647    case OMX_VIDEO_AVCLevel12:
648       return 12;
649    case OMX_VIDEO_AVCLevel13:
650       return 13;
651    case OMX_VIDEO_AVCLevel2:
652       return 20;
653    case OMX_VIDEO_AVCLevel21:
654       return 21;
655    case OMX_VIDEO_AVCLevel22:
656       return 22;
657    case OMX_VIDEO_AVCLevel3:
658       return 30;
659    case OMX_VIDEO_AVCLevel31:
660       return 31;
661    case OMX_VIDEO_AVCLevel32:
662       return 32;
663    case OMX_VIDEO_AVCLevel4:
664       return 40;
665    case OMX_VIDEO_AVCLevel41:
666       return 41;
667    default:
668    case OMX_VIDEO_AVCLevel42:
669       return 42;
670    case OMX_VIDEO_AVCLevel5:
671       return 50;
672    case OMX_VIDEO_AVCLevel51:
673       return 51;
674    }
675 }
676 
vid_enc_MessageHandler(OMX_COMPONENTTYPE * comp,internalRequestMessageType * msg)677 static OMX_ERRORTYPE vid_enc_MessageHandler(OMX_COMPONENTTYPE* comp, internalRequestMessageType *msg)
678 {
679    vid_enc_PrivateType* priv = comp->pComponentPrivate;
680 
681    if (msg->messageType == OMX_CommandStateSet) {
682       if ((msg->messageParam == OMX_StateIdle ) && (priv->state == OMX_StateLoaded)) {
683 
684          struct pipe_video_codec templat = {};
685          omx_base_video_PortType *port;
686 
687          port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];
688 
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;
697 
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);
706          } else {
707             templat.max_references = OMX_VID_ENC_P_PERIOD_DEFAULT;
708             priv->stacked_frames_num = 1;
709          }
710          priv->codec = priv->s_pipe->create_video_codec(priv->s_pipe, &templat);
711 
712       } else if ((msg->messageParam == OMX_StateLoaded) && (priv->state == OMX_StateIdle)) {
713          if (priv->codec) {
714             priv->codec->destroy(priv->codec);
715             priv->codec = NULL;
716          }
717       }
718    }
719 
720    return omx_base_component_MessageHandler(comp, msg);
721 }
722 
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)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)
725 {
726    struct input_buf_private *inp;
727    OMX_ERRORTYPE r;
728 
729    r = base_port_AllocateBuffer(port, buf, idx, private, size);
730    if (r)
731       return r;
732 
733    inp = (*buf)->pInputPortPrivate = CALLOC_STRUCT(input_buf_private);
734    if (!inp) {
735       base_port_FreeBuffer(port, idx, *buf);
736       return OMX_ErrorInsufficientResources;
737    }
738 
739    LIST_INITHEAD(&inp->tasks);
740 
741    FREE((*buf)->pBuffer);
742    r = enc_AllocateBackTexture(port, &inp->resource, &inp->transfer, &(*buf)->pBuffer);
743    if (r) {
744       FREE(inp);
745       base_port_FreeBuffer(port, idx, *buf);
746       return r;
747    }
748 
749    return OMX_ErrorNone;
750 }
751 
vid_enc_UseInBuffer(omx_base_PortType * port,OMX_BUFFERHEADERTYPE ** buf,OMX_U32 idx,OMX_PTR private,OMX_U32 size,OMX_U8 * mem)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)
754 {
755    struct input_buf_private *inp;
756    OMX_ERRORTYPE r;
757 
758    r = base_port_UseBuffer(port, buf, idx, private, size, mem);
759    if (r)
760       return r;
761 
762    inp = (*buf)->pInputPortPrivate = CALLOC_STRUCT(input_buf_private);
763    if (!inp) {
764       base_port_FreeBuffer(port, idx, *buf);
765       return OMX_ErrorInsufficientResources;
766    }
767 
768    LIST_INITHEAD(&inp->tasks);
769 
770    return OMX_ErrorNone;
771 }
772 
vid_enc_FreeInBuffer(omx_base_PortType * port,OMX_U32 idx,OMX_BUFFERHEADERTYPE * buf)773 static OMX_ERRORTYPE vid_enc_FreeInBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf)
774 {
775    OMX_COMPONENTTYPE* comp = port->standCompContainer;
776    vid_enc_PrivateType *priv = comp->pComponentPrivate;
777    struct input_buf_private *inp = buf->pInputPortPrivate;
778 
779    if (inp) {
780       enc_ReleaseTasks(&inp->tasks);
781       if (inp->transfer)
782          pipe_transfer_unmap(priv->s_pipe, inp->transfer);
783       pipe_resource_reference(&inp->resource, NULL);
784       FREE(inp);
785    }
786    buf->pBuffer = NULL;
787 
788    return base_port_FreeBuffer(port, idx, buf);
789 }
790 
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)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)
793 {
794    OMX_ERRORTYPE r;
795 
796    r = base_port_AllocateBuffer(port, buf, idx, private, size);
797    if (r)
798       return r;
799 
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;
806    }
807 
808    return OMX_ErrorNone;
809 }
810 
vid_enc_FreeOutBuffer(omx_base_PortType * port,OMX_U32 idx,OMX_BUFFERHEADERTYPE * buf)811 static OMX_ERRORTYPE vid_enc_FreeOutBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf)
812 {
813    OMX_COMPONENTTYPE* comp = port->standCompContainer;
814    vid_enc_PrivateType *priv = comp->pComponentPrivate;
815 
816    if (buf->pOutputPortPrivate) {
817       struct output_buf_private *outp = buf->pOutputPortPrivate;
818       if (outp->transfer)
819          pipe_transfer_unmap(priv->t_pipe, outp->transfer);
820       pipe_resource_reference(&outp->bitstream, NULL);
821       FREE(outp);
822       buf->pOutputPortPrivate = NULL;
823    }
824    buf->pBuffer = NULL;
825 
826    return base_port_FreeBuffer(port, idx, buf);
827 }
828 
enc_NeedTask(omx_base_PortType * port)829 static struct encode_task *enc_NeedTask(omx_base_PortType *port)
830 {
831    OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video;
832    OMX_COMPONENTTYPE* comp = port->standCompContainer;
833    vid_enc_PrivateType *priv = comp->pComponentPrivate;
834 
835    struct pipe_video_buffer templat = {};
836    struct encode_task *task;
837 
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);
841       return task;
842    }
843 
844    /* allocate a new one */
845    task = CALLOC_STRUCT(encode_task);
846    if (!task)
847       return NULL;
848 
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;
854 
855    task->buf = priv->s_pipe->create_video_buffer(priv->s_pipe, &templat);
856    if (!task->buf) {
857       FREE(task);
858       return NULL;
859    }
860 
861    return task;
862 }
863 
enc_MoveTasks(struct list_head * from,struct list_head * to)864 static void enc_MoveTasks(struct list_head *from, struct list_head *to)
865 {
866    to->prev->next = from->next;
867    from->next->prev = to->prev;
868    from->prev->next = to;
869    to->prev = from->prev;
870    LIST_INITHEAD(from);
871 }
872 
enc_ReleaseTasks(struct list_head * head)873 static void enc_ReleaseTasks(struct list_head *head)
874 {
875    struct encode_task *i, *next;
876 
877    if (!head || !head->next)
878       return;
879 
880    LIST_FOR_EACH_ENTRY_SAFE(i, next, head, list) {
881       pipe_resource_reference(&i->bitstream, NULL);
882       i->buf->destroy(i->buf);
883       FREE(i);
884    }
885 }
886 
enc_LoadImage(omx_base_PortType * port,OMX_BUFFERHEADERTYPE * buf,struct pipe_video_buffer * vbuf)887 static OMX_ERRORTYPE enc_LoadImage(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf,
888                                    struct pipe_video_buffer *vbuf)
889 {
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;
895 
896    if (!inp->resource) {
897       struct pipe_sampler_view **views;
898       void *ptr;
899 
900       views = vbuf->get_sampler_view_planes(vbuf);
901       if (!views)
902          return OMX_ErrorInsufficientResources;
903 
904       ptr = buf->pBuffer;
905       box.width = def->nFrameWidth;
906       box.height = def->nFrameHeight;
907       box.depth = 1;
908       priv->s_pipe->texture_subdata(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;
914       box.depth = 1;
915       priv->s_pipe->texture_subdata(priv->s_pipe, views[1]->texture, 0,
916                                     PIPE_TRANSFER_WRITE, &box,
917                                     ptr, def->nStride, 0);
918    } else {
919       struct pipe_blit_info blit;
920       struct vl_video_buffer *dst_buf = (struct vl_video_buffer *)vbuf;
921 
922       pipe_transfer_unmap(priv->s_pipe, inp->transfer);
923 
924       box.width = def->nFrameWidth;
925       box.height = def->nFrameHeight;
926       box.depth = 1;
927 
928       priv->s_pipe->resource_copy_region(priv->s_pipe,
929                                          dst_buf->resources[0],
930                                          0, 0, 0, 0, inp->resource, 0, &box);
931 
932       memset(&blit, 0, sizeof(blit));
933       blit.src.resource = inp->resource;
934       blit.src.format = inp->resource->format;
935 
936       blit.src.box.x = 0;
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;
941 
942       blit.dst.resource = dst_buf->resources[1];
943       blit.dst.format = blit.dst.resource->format;
944 
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;
949 
950       blit.mask = PIPE_MASK_G;
951       priv->s_pipe->blit(priv->s_pipe, &blit);
952 
953       blit.src.box.x = 1;
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);
957 
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,
963                                                 &inp->transfer);
964    }
965 
966    return OMX_ErrorNone;
967 }
968 
enc_ScaleInput(omx_base_PortType * port,struct pipe_video_buffer ** vbuf,unsigned * size)969 static void enc_ScaleInput(omx_base_PortType *port, struct pipe_video_buffer **vbuf, unsigned *size)
970 {
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;
979    unsigned i;
980 
981    if (!priv->scale_buffer[priv->current_scale_buffer])
982       return;
983 
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);
988 
989    for (i = 0; i < VL_MAX_SURFACES; ++i) {
990       struct u_rect src_rect;
991       if (!views[i] || !dst_surface[i])
992          continue;
993       src_rect.x0 = 0;
994       src_rect.y0 = 0;
995       src_rect.x1 = def->nFrameWidth;
996       src_rect.y1 = def->nFrameHeight;
997       if (i > 0) {
998          src_rect.x1 /= 2;
999          src_rect.y1 /= 2;
1000       }
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);
1003    }
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;
1007 }
1008 
enc_GetPictureParamPreset(struct pipe_h264_enc_picture_desc * picture)1009 static void enc_GetPictureParamPreset(struct pipe_h264_enc_picture_desc *picture)
1010 {
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;
1015 }
1016 
enc_ControlPicture(omx_base_PortType * port,struct pipe_h264_enc_picture_desc * picture)1017 static void enc_ControlPicture(omx_base_PortType *port, struct pipe_h264_enc_picture_desc *picture)
1018 {
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;
1022 
1023    switch (priv->bitrate.eControlRate) {
1024    case OMX_Video_ControlRateVariable:
1025       rate_ctrl->rate_ctrl_method = PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE;
1026       break;
1027    case OMX_Video_ControlRateConstant:
1028       rate_ctrl->rate_ctrl_method = PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT;
1029       break;
1030    case OMX_Video_ControlRateVariableSkipFrames:
1031       rate_ctrl->rate_ctrl_method = PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP;
1032       break;
1033    case OMX_Video_ControlRateConstantSkipFrames:
1034       rate_ctrl->rate_ctrl_method = PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP;
1035       break;
1036    default:
1037       rate_ctrl->rate_ctrl_method = PIPE_H264_ENC_RATE_CONTROL_METHOD_DISABLE;
1038       break;
1039    }
1040 
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;
1043 
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;
1049       else
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);
1054       else
1055          rate_ctrl->vbv_buffer_size = rate_ctrl->target_bitrate;
1056 
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;
1061       } else {
1062          rate_ctrl->target_bits_picture = rate_ctrl->target_bitrate;
1063       }
1064       rate_ctrl->peak_bits_picture_integer = rate_ctrl->target_bits_picture;
1065       rate_ctrl->peak_bits_picture_fraction = 0;
1066    }
1067 
1068    picture->quant_i_frames = priv->quant.nQpI;
1069    picture->quant_p_frames = priv->quant.nQpP;
1070    picture->quant_b_frames = priv->quant.nQpB;
1071 
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);
1077 }
1078 
enc_HandleTask(omx_base_PortType * port,struct encode_task * task,enum pipe_h264_enc_picture_type picture_type)1079 static void enc_HandleTask(omx_base_PortType *port, struct encode_task *task,
1080                            enum pipe_h264_enc_picture_type picture_type)
1081 {
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 = {};
1087 
1088    /* -------------- scale input image --------- */
1089    enc_ScaleInput(port, &vbuf, &size);
1090    priv->s_pipe->flush(priv->s_pipe, NULL, 0);
1091 
1092    /* -------------- allocate output buffer --------- */
1093    task->bitstream = pipe_buffer_create(priv->s_pipe->screen, PIPE_BIND_VERTEX_BUFFER,
1094                                         PIPE_USAGE_STREAM, size);
1095 
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);
1101 
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);
1106 }
1107 
enc_ClearBframes(omx_base_PortType * port,struct input_buf_private * inp)1108 static void enc_ClearBframes(omx_base_PortType *port, struct input_buf_private *inp)
1109 {
1110    OMX_COMPONENTTYPE* comp = port->standCompContainer;
1111    vid_enc_PrivateType *priv = comp->pComponentPrivate;
1112    struct encode_task *task;
1113 
1114    if (LIST_IS_EMPTY(&priv->b_frames))
1115       return;
1116 
1117    task = LIST_ENTRY(struct encode_task, priv->b_frames.prev, list);
1118    LIST_DEL(&task->list);
1119 
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++;
1125 
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;
1131       priv->frame_num++;
1132    }
1133 
1134    enc_MoveTasks(&priv->b_frames, &inp->tasks);
1135 }
1136 
vid_enc_EncodeFrame(omx_base_PortType * port,OMX_BUFFERHEADERTYPE * buf)1137 static OMX_ERRORTYPE vid_enc_EncodeFrame(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf)
1138 {
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;
1145    OMX_ERRORTYPE err;
1146 
1147    enc_MoveTasks(&inp->tasks, &priv->free_tasks);
1148    task = enc_NeedTask(port);
1149    if (!task)
1150       return OMX_ErrorInsufficientResources;
1151 
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);
1158       }
1159       return base_port_SendBufferFunction(port, buf);
1160    }
1161 
1162    if (buf->pOutputPortPrivate) {
1163       struct pipe_video_buffer *vbuf = buf->pOutputPortPrivate;
1164       buf->pOutputPortPrivate = task->buf;
1165       task->buf = vbuf;
1166    } else {
1167       /* ------- load input image into video buffer ---- */
1168       err = enc_LoadImage(port, buf, task->buf);
1169       if (err != OMX_ErrorNone) {
1170          FREE(task);
1171          return err;
1172       }
1173    }
1174 
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;
1186    } else {
1187       picture_type = PIPE_H264_ENC_PICTURE_TYPE_B;
1188    }
1189 
1190    task->pic_order_cnt = priv->pic_order_cnt++;
1191 
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);
1195    } else {
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) {
1201          ++stacked_num;
1202       }
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);
1206          LIST_DEL(&t->list);
1207          LIST_ADDTAIL(&t->list, &inp->tasks);
1208       }
1209       priv->ref_idx_l1 = priv->frame_num++;
1210 
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;
1216          priv->frame_num++;
1217       }
1218 
1219       enc_MoveTasks(&priv->b_frames, &inp->tasks);
1220    }
1221 
1222    if (LIST_IS_EMPTY(&inp->tasks))
1223       return port->ReturnBufferFunction(port, buf);
1224    else
1225       return base_port_SendBufferFunction(port, buf);
1226 }
1227 
vid_enc_BufferEncoded(OMX_COMPONENTTYPE * comp,OMX_BUFFERHEADERTYPE * input,OMX_BUFFERHEADERTYPE * output)1228 static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input, OMX_BUFFERHEADERTYPE* output)
1229 {
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 = {};
1235    unsigned size;
1236 
1237    if (!inp || LIST_IS_EMPTY(&inp->tasks)) {
1238       input->nFilledLen = 0; /* mark buffer as empty */
1239       enc_MoveTasks(&priv->used_tasks, &inp->tasks);
1240       return;
1241    }
1242 
1243    task = LIST_ENTRY(struct encode_task, inp->tasks.next, list);
1244    LIST_DEL(&task->list);
1245    LIST_ADDTAIL(&task->list, &priv->used_tasks);
1246 
1247    if (!task->bitstream)
1248       return;
1249 
1250    /* ------------- map result buffer ----------------- */
1251 
1252    if (outp->transfer)
1253       pipe_transfer_unmap(priv->t_pipe, outp->transfer);
1254 
1255    pipe_resource_reference(&outp->bitstream, task->bitstream);
1256    pipe_resource_reference(&task->bitstream, NULL);
1257 
1258    box.width = outp->bitstream->width0;
1259    box.height = outp->bitstream->height0;
1260    box.depth = outp->bitstream->depth0;
1261 
1262    output->pBuffer = priv->t_pipe->transfer_map(priv->t_pipe, outp->bitstream, 0,
1263                                                 PIPE_TRANSFER_READ_WRITE,
1264                                                 &box, &outp->transfer);
1265 
1266    /* ------------- get size of result ----------------- */
1267 
1268    priv->codec->get_feedback(priv->codec, task->feedback, &size);
1269 
1270    output->nOffset = 0;
1271    output->nFilledLen = size; /* mark buffer as full */
1272 }
1273