The EIL can be configured to accept externally allocated input frames. To do this, the integration should set external_input in EILInitSettings to true. When configured in this mode, the EIL will not allocate any pictures itself, and so EIL_GetPicture will always fail.
In external input mode, the integration must create the EILPicture object itself. The object can be default initialised using EIL_InitPictureDefault. The integration then must set the plane pointers to memory it has allocated and stride to the number of bytes per line. The other fields are then used in the same manner as when external input is disabled.
The planes must be valid from the point that the picture is passed to EIL_Encode, until the associated output is produced.
The EIL can also accept Android hardware buffers in this mode when the EIL is configured for GPU mode. To do this the picture's memory_type is set to EIL_MT_AHardwareBuffer and the plane pointers are set to AHardwareBuffer.
bool InitialiseExteranlInput(EILContext context)
{
EILInitSettings settings;
EILReturnCode rc = EIL_InitSettingsDefault(&settings);
settings.width = 1920;
settings.height = 1080;
settings.fps_num = 25;
settings.fps_denom = 1;
settings.bitrate = 3000; // NB: This is in kbps
settings.external_input = 1;
// The properties are usually generated from user input
settings.properties_json = "{ \"encoding_transform_type\": \"dds\" }";
if ((rc = EIL_Initialise(context, &settings)) != EIL_RC_Success)
{
fprintf(stderr, "Unable to intiailise the EIL: %s\n",
EIL_GetErrorString(rc));
return false;
}
return true;
}
bool EncodeExternalInput(EILContext context, int64_t pts)
{
EILPicture* picture = (EILPicture*)malloc(sizeof(EILPicture));
if (EIL_InitPictureDefault(picture) != EIL_RC_Success)
{
fprintf(stderr, "Unable to initialise picture object\n");
return false;
}
// For the example the planes are allocated inline. These could just as
// easily be set to pointers that already contain the frame data to
// avoid copying the data.
// Assuming 1080p YUV420p
picture->pts = pts;
picture->num_planes = 3;
picture->plane[0] = malloc(1920 * 1080);
picture->stride[0] = 1080;
picture->plane[1] = malloc(960 * 540);
picture->stride[1] = 540;
picture->plane[2] = malloc(960 * 540);
picture->stride[2] = 540;
picture->user_data = picture;
// populate the allocated planes with frame data
EILReturnCode rc = EIL_Encode(context, picture);
if (rc != EIL_RC_Success)
{
for (int i = 0; i < picture->num_planes; ++i)
free(picture->plane[i]);
fprintf(stderr, "Unable to encode frame: %s\n", EIL_GetErrorString(rc));
return false;
}
return true;
}
bool HandleOutput(EILContext context)
{
EILOutput* output = NULL;
EILReturnCode rc = EIL_GetOutput(context, &output);
if (rc != EIL_RC_Success)
{
if (rc != EIL_RC_Finished)
{
fprintf(stderr, "Unable to get output from the EIL: %s\n",
EIL_GetErrorString(rc));
return false;
}
return true;
}
// pass the bitstream to a muxer
mux(output->pts, output->dts, output->data, output->data_length);
EILPicture* picture = (EILPicture*)output->user_data;
for (int i = 0; i < picture->num_planes; ++i)
free(picture->plane[i]);
if ((rc = EIL_ReleaseOutput(context, output)) != EIL_RC_Success)
{
fprintf(stderr, "Unable to release output back to the EIL: %s\n",
EIL_GetErrorString(rc));
return false;
}
return true;
}
Dynamic Reconfiguration
The EIL is able to reconfigure the target bitrate and framerate, if the base encoder also supports dynamic reconfiguration. This is done by passing EILReconfigureSettings, with the new values, to the EIL_Reconfigure function.