Go to the documentation of this file.
35 #include "../internal.h"
41 #include <tensorflow/c/c_api.h>
83 #define OFFSET(x) offsetof(TFContext, x)
84 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM
121 for (uint32_t
i = 0;
i < nb_output; ++
i) {
140 if (!infer_request) {
147 return infer_request;
175 if (TF_GetCode(request->
status) != TF_OK) {
200 TF_DeleteStatus(request->
status);
227 TF_Buffer *graph_buf;
228 unsigned char *graph_data =
NULL;
230 long size, bytes_read;
243 bytes_read =
avio_read(model_file_context, graph_data,
size);
245 if (bytes_read !=
size){
250 graph_buf = TF_NewBuffer();
251 graph_buf->data = graph_data;
252 graph_buf->length =
size;
262 int64_t input_dims[] = {1,
input->height,
input->width,
input->channels};
266 size =
sizeof(float);
276 return TF_AllocateTensor(dt, input_dims, 4,
277 input_dims[1] * input_dims[2] * input_dims[3] *
size);
288 tf_output.oper = TF_GraphOperationByName(tf_model->
graph, input_name);
289 if (!tf_output.oper) {
295 input->dt = TF_OperationOutputType(tf_output);
299 TF_GraphGetTensorShape(tf_model->
graph, tf_output, dims, 4,
status);
300 if (TF_GetCode(
status) != TF_OK){
309 input->height = dims[1];
310 input->width = dims[2];
311 input->channels = dims[3];
317 const char *output_name,
int *output_width,
int *output_height)
326 .output_names = &output_name,
359 #define SPACE_CHARS " \t\r\n"
371 if (
c >=
'0' &&
c <=
'9')
373 else if (
c >=
'A' &&
c <=
'F')
392 TF_Buffer *graph_def;
393 TF_ImportGraphDefOptions *graph_opts;
394 TF_SessionOptions *sess_opts;
395 const TF_Operation *init_op;
396 uint8_t *sess_config =
NULL;
397 int sess_config_length = 0;
432 tf_model->
graph = TF_NewGraph();
433 tf_model->
status = TF_NewStatus();
434 graph_opts = TF_NewImportGraphDefOptions();
435 TF_GraphImportGraphDef(tf_model->
graph, graph_def, graph_opts, tf_model->
status);
436 TF_DeleteImportGraphDefOptions(graph_opts);
437 TF_DeleteBuffer(graph_def);
438 if (TF_GetCode(tf_model->
status) != TF_OK){
439 TF_DeleteGraph(tf_model->
graph);
440 TF_DeleteStatus(tf_model->
status);
446 init_op = TF_GraphOperationByName(tf_model->
graph,
"init");
447 sess_opts = TF_NewSessionOptions();
450 TF_SetConfig(sess_opts, sess_config, sess_config_length,tf_model->
status);
452 if (TF_GetCode(tf_model->
status) != TF_OK) {
453 TF_DeleteGraph(tf_model->
graph);
454 TF_DeleteStatus(tf_model->
status);
455 TF_DeleteSessionOptions(sess_opts);
463 TF_DeleteSessionOptions(sess_opts);
464 if (TF_GetCode(tf_model->
status) != TF_OK)
466 TF_DeleteGraph(tf_model->
graph);
467 TF_DeleteStatus(tf_model->
status);
478 if (TF_GetCode(tf_model->
status) != TF_OK)
481 TF_DeleteGraph(tf_model->
graph);
482 TF_DeleteStatus(tf_model->
status);
491 #define NAME_BUFFER_SIZE 256
498 TF_OperationDescription *op_desc;
500 int64_t strides[] = {1, 1, 1, 1};
501 TF_Tensor *kernel_tensor =
NULL, *biases_tensor =
NULL;
511 op_desc = TF_NewOperation(tf_model->
graph,
"Const", name_buffer);
512 TF_SetAttrType(op_desc,
"dtype", TF_FLOAT);
518 kernel_tensor = TF_AllocateTensor(TF_FLOAT, dims, dims_len,
size *
sizeof(
float));
519 memcpy(TF_TensorData(kernel_tensor), params->
kernel,
size *
sizeof(
float));
520 TF_SetAttrTensor(op_desc,
"value", kernel_tensor, tf_model->
status);
521 if (TF_GetCode(tf_model->
status) != TF_OK){
524 op = TF_FinishOperation(op_desc, tf_model->
status);
525 if (TF_GetCode(tf_model->
status) != TF_OK){
530 op_desc = TF_NewOperation(tf_model->
graph,
"Transpose", name_buffer);
532 TF_AddInput(op_desc,
input);
533 input.oper = transpose_op;
534 TF_AddInput(op_desc,
input);
535 TF_SetAttrType(op_desc,
"T", TF_FLOAT);
536 TF_SetAttrType(op_desc,
"Tperm", TF_INT32);
537 op = TF_FinishOperation(op_desc, tf_model->
status);
538 if (TF_GetCode(tf_model->
status) != TF_OK){
543 op_desc = TF_NewOperation(tf_model->
graph,
"Conv2D", name_buffer);
544 input.oper = *cur_op;
545 TF_AddInput(op_desc,
input);
547 TF_AddInput(op_desc,
input);
548 TF_SetAttrType(op_desc,
"T", TF_FLOAT);
549 TF_SetAttrIntList(op_desc,
"strides", strides, 4);
550 TF_SetAttrString(op_desc,
"padding",
"VALID", 5);
551 *cur_op = TF_FinishOperation(op_desc, tf_model->
status);
552 if (TF_GetCode(tf_model->
status) != TF_OK){
557 op_desc = TF_NewOperation(tf_model->
graph,
"Const", name_buffer);
558 TF_SetAttrType(op_desc,
"dtype", TF_FLOAT);
561 biases_tensor = TF_AllocateTensor(TF_FLOAT, dims, dims_len, params->
output_num *
sizeof(
float));
562 memcpy(TF_TensorData(biases_tensor), params->
biases, params->
output_num *
sizeof(
float));
563 TF_SetAttrTensor(op_desc,
"value", biases_tensor, tf_model->
status);
564 if (TF_GetCode(tf_model->
status) != TF_OK){
567 op = TF_FinishOperation(op_desc, tf_model->
status);
568 if (TF_GetCode(tf_model->
status) != TF_OK){
573 op_desc = TF_NewOperation(tf_model->
graph,
"BiasAdd", name_buffer);
574 input.oper = *cur_op;
575 TF_AddInput(op_desc,
input);
577 TF_AddInput(op_desc,
input);
578 TF_SetAttrType(op_desc,
"T", TF_FLOAT);
579 *cur_op = TF_FinishOperation(op_desc, tf_model->
status);
580 if (TF_GetCode(tf_model->
status) != TF_OK){
587 op_desc = TF_NewOperation(tf_model->
graph,
"Relu", name_buffer);
590 op_desc = TF_NewOperation(tf_model->
graph,
"Tanh", name_buffer);
593 op_desc = TF_NewOperation(tf_model->
graph,
"Sigmoid", name_buffer);
599 input.oper = *cur_op;
600 TF_AddInput(op_desc,
input);
601 TF_SetAttrType(op_desc,
"T", TF_FLOAT);
602 *cur_op = TF_FinishOperation(op_desc, tf_model->
status);
603 if (TF_GetCode(tf_model->
status) != TF_OK){
609 TF_DeleteTensor(kernel_tensor);
610 TF_DeleteTensor(biases_tensor);
619 TF_OperationDescription *op_desc;
624 op_desc = TF_NewOperation(tf_model->
graph,
"DepthToSpace", name_buffer);
625 input.oper = *cur_op;
627 TF_AddInput(op_desc,
input);
628 TF_SetAttrType(op_desc,
"T", TF_FLOAT);
629 TF_SetAttrInt(op_desc,
"block_size", params->
block_size);
630 *cur_op = TF_FinishOperation(op_desc, tf_model->
status);
631 if (TF_GetCode(tf_model->
status) != TF_OK){
645 TF_OperationDescription *op_desc;
648 int64_t pads_shape[] = {4, 2};
653 op_desc = TF_NewOperation(tf_model->
graph,
"Const", name_buffer);
654 TF_SetAttrType(op_desc,
"dtype", TF_INT32);
655 tensor = TF_AllocateTensor(TF_INT32, pads_shape, 2, 4 * 2 *
sizeof(
int32_t));
656 pads = (
int32_t *)TF_TensorData(tensor);
665 TF_SetAttrTensor(op_desc,
"value", tensor, tf_model->
status);
666 if (TF_GetCode(tf_model->
status) != TF_OK){
667 TF_DeleteTensor(tensor);
671 op = TF_FinishOperation(op_desc, tf_model->
status);
672 if (TF_GetCode(tf_model->
status) != TF_OK){
673 TF_DeleteTensor(tensor);
678 op_desc = TF_NewOperation(tf_model->
graph,
"MirrorPad",
"mirror_pad");
679 input.oper = *cur_op;
681 TF_AddInput(op_desc,
input);
683 TF_AddInput(op_desc,
input);
684 TF_SetAttrType(op_desc,
"T", TF_FLOAT);
685 TF_SetAttrType(op_desc,
"Tpaddings", TF_INT32);
686 TF_SetAttrString(op_desc,
"mode",
"SYMMETRIC", 9);
687 *cur_op = TF_FinishOperation(op_desc, tf_model->
status);
688 if (TF_GetCode(tf_model->
status) != TF_OK){
689 TF_DeleteTensor(tensor);
703 TF_OperationDescription *op_desc;
710 op_desc = TF_NewOperation(tf_model->
graph,
"Const", name_buffer);
711 TF_SetAttrType(op_desc,
"dtype", TF_FLOAT);
712 tensor = TF_AllocateTensor(TF_FLOAT,
NULL, 0, TF_DataTypeSize(TF_FLOAT));
713 y = (
float *)TF_TensorData(tensor);
715 TF_SetAttrTensor(op_desc,
"value", tensor, tf_model->
status);
716 if (TF_GetCode(tf_model->
status) != TF_OK){
717 TF_DeleteTensor(tensor);
721 op = TF_FinishOperation(op_desc, tf_model->
status);
722 if (TF_GetCode(tf_model->
status) != TF_OK){
723 TF_DeleteTensor(tensor);
729 op_desc = TF_NewOperation(tf_model->
graph,
"Maximum", name_buffer);
730 input.oper = *cur_op;
732 TF_AddInput(op_desc,
input);
734 TF_AddInput(op_desc,
input);
735 TF_SetAttrType(op_desc,
"T", TF_FLOAT);
736 *cur_op = TF_FinishOperation(op_desc, tf_model->
status);
737 if (TF_GetCode(tf_model->
status) != TF_OK){
738 TF_DeleteTensor(tensor);
750 TF_OperationDescription *op_desc;
752 TF_Operation *transpose_op;
753 TF_Tensor *tensor =
NULL;
756 int64_t transpose_perm_shape[] = {4};
757 int64_t input_shape[] = {1, -1, -1, -1};
768 native_model = model->
model;
769 tf_model->
graph = TF_NewGraph();
770 tf_model->
status = TF_NewStatus();
772 #define CLEANUP_ON_ERROR(tf_model) \
774 TF_DeleteTensor(tensor); \
775 TF_DeleteGraph(tf_model->graph); \
776 TF_DeleteStatus(tf_model->status); \
777 av_log(ctx, AV_LOG_ERROR, "Failed to set value or add operator to layer\n"); \
781 op_desc = TF_NewOperation(tf_model->
graph,
"Placeholder",
"x");
782 TF_SetAttrType(op_desc,
"dtype", TF_FLOAT);
783 TF_SetAttrShape(op_desc,
"shape", input_shape, 4);
784 op = TF_FinishOperation(op_desc, tf_model->
status);
785 if (TF_GetCode(tf_model->
status) != TF_OK){
789 op_desc = TF_NewOperation(tf_model->
graph,
"Const",
"transpose_perm");
790 TF_SetAttrType(op_desc,
"dtype", TF_INT32);
791 tensor = TF_AllocateTensor(TF_INT32, transpose_perm_shape, 1, 4 *
sizeof(
int32_t));
797 TF_SetAttrTensor(op_desc,
"value", tensor, tf_model->
status);
798 if (TF_GetCode(tf_model->
status) != TF_OK){
801 transpose_op = TF_FinishOperation(op_desc, tf_model->
status);
802 if (TF_GetCode(tf_model->
status) != TF_OK){
806 for (layer = 0; layer < native_model->
layers_num; ++layer){
836 op_desc = TF_NewOperation(tf_model->
graph,
"Identity",
"y");
839 TF_AddInput(op_desc,
input);
840 TF_FinishOperation(op_desc, tf_model->
status);
841 if (TF_GetCode(tf_model->
status) != TF_OK){
866 tf_model->
model = model;
868 ctx->class = &dnn_tensorflow_class;
883 if (
ctx->options.nireq <= 0) {
887 #if !HAVE_PTHREAD_CANCEL
888 if (
ctx->options.async) {
889 ctx->options.async = 0;
899 for (
int i = 0;
i <
ctx->options.nireq;
i++) {
911 item->
status = TF_NewStatus();
932 model->
model = tf_model;
972 if (!infer_request->
tf_input->oper){
1102 task = lltask->
task;
1103 tf_model = task->
model;
1212 tf_model = (*model)->
model;
1233 if (tf_model->
graph){
1234 TF_DeleteGraph(tf_model->
graph);
1241 TF_DeleteStatus(tf_model->
status);
AVFILTER_DEFINE_CLASS(dnn_tensorflow)
DNNAsyncStatusType ff_dnn_get_result_tf(const DNNModel *model, AVFrame **in, AVFrame **out)
#define AV_LOG_WARNING
Something somehow does not look correct.
Stores execution parameters for single call to the TensorFlow C API.
they must not be accessed directly The fifo field contains the frames that are queued in the input for processing by the filter The status_in and status_out fields contains the queued status(EOF or error) of the link
DNNReturnType ff_dnn_fill_task(TaskItem *task, DNNExecBaseParams *exec_params, void *backend_model, int async, int do_ioproc)
Fill the Task for Backend Execution.
static FilteringContext * filter_ctx
void av_opt_set_defaults(void *s)
Set the values of all AVOption fields to their default values.
void * ff_safe_queue_pop_front(SafeQueue *sq)
Remove and free first element from the queue in SafeQueue.
Common Async Execution Mechanism for the DNN Backends.
static DNNReturnType tf_start_inference(void *args)
Start synchronous inference for the TensorFlow model.
void * ff_queue_pop_front(Queue *q)
Remove and free first element from the Queue.
int ff_check_exec_params(void *ctx, DNNBackendType backend, DNNFunctionType func_type, DNNExecBaseParams *exec_params)
size_t ff_queue_size(Queue *q)
Return the length of the Queue.
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
DNNReturnType ff_dnn_start_inference_async(void *ctx, DNNAsyncExecModule *async_module)
Start asynchronous inference routine for the TensorFlow model on a detached thread.
This structure describes decoded (raw) audio or video data.
DNNModel * ff_dnn_load_model_native(const char *model_filename, DNNFunctionType func_type, const char *options, AVFilterContext *filter_ctx)
Double-ended queue with mutex locks ensuring data consistency while multithreading.
FramePrePostProc frame_pre_proc
static DNNReturnType fill_model_input_tf(TFModel *tf_model, TFRequestItem *request)
union DnnLayerMaximumParams::@200 val
SafeQueue * request_queue
void(* callback)(void *args)
Completion Callback for the backend.
static DNNReturnType add_pad_layer(TFModel *tf_model, TF_Operation **cur_op, LayerPadParams *params, const int layer)
static DNNReturnType get_output_tf(void *model, const char *input_name, int input_width, int input_height, const char *output_name, int *output_width, int *output_height)
int64_t avio_size(AVIOContext *s)
Get the filesize.
static void destroy_request_item(TFRequestItem **arg)
Free the TFRequestItem completely.
AVFilterContext * filter_ctx
Queue * ff_queue_create(void)
Create a Queue instance.
DNNReturnType ff_proc_from_dnn_to_frame(AVFrame *frame, DNNData *output, void *log_ctx)
DNNReturnType ff_proc_from_frame_to_dnn(AVFrame *frame, DNNData *input, void *log_ctx)
DNNReturnType(* get_output)(void *model, const char *input_name, int input_width, int input_height, const char *output_name, int *output_width, int *output_height)
static DNNReturnType get_input_tf(void *model, DNNData *input, const char *input_name)
Linear double-ended data structure.
int ff_queue_push_back(Queue *q, void *v)
Add data to the tail of the queue.
#define DNN_BACKEND_COMMON_OPTIONS
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
DNNAsyncExecModule exec_module
static TF_Buffer * read_graph(const char *model_filename)
static DNNReturnType add_maximum_layer(TFModel *tf_model, TF_Operation **cur_op, DnnLayerMaximumParams *params, const int layer)
static int op(uint8_t **dst, const uint8_t *dst_end, GetByteContext *gb, int pixel, int count, int *x, int width, int linesize)
Perform decode operation.
void ff_queue_destroy(Queue *q)
Destroy the Queue instance.
static DNNReturnType load_native_model(TFModel *tf_model, const char *model_filename)
#define av_assert0(cond)
assert() equivalent, that is always enabled.
static const AVFilterPad outputs[]
DNNActivationFunc activation
static const AVOption dnn_tensorflow_options[]
DNNReturnType(* get_input)(void *model, DNNData *input, const char *input_name)
static DNNReturnType extract_lltask_from_task(TaskItem *task, Queue *lltask_queue)
size_t ff_safe_queue_size(SafeQueue *sq)
Return the length of the SafeQueue.
void ff_dnn_free_model_native(DNNModel **model)
static DNNReturnType load_tf_model(TFModel *tf_model, const char *model_filename)
Describe the class of an AVClass context structure.
static DNNReturnType add_conv_layer(TFModel *tf_model, TF_Operation *transpose_op, TF_Operation **cur_op, ConvolutionalParams *params, const int layer)
SafeQueue * ff_safe_queue_create(void)
Create and initialize a SafeQueue instance.
FramePrePostProc frame_post_proc
int av_opt_set_from_string(void *ctx, const char *opts, const char *const *shorthand, const char *key_val_sep, const char *pairs_sep)
Parse the key-value pairs list in opts.
static TFInferRequest * tf_create_inference_request(void)
Create a TensorFlow inference request.
static void infer_completion_callback(void *args)
static void tf_free_request(TFInferRequest *request)
Free the contents of TensorFlow inference request.
static void transpose_perm(int16_t *out, int16_t *in, int num_vect, const uint8_t line_len[2], int length_div)
Interpret the input data as in the following table:
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
const OptionDef options[]
DNNReturnType ff_dnn_fill_gettingoutput_task(TaskItem *task, DNNExecBaseParams *exec_params, void *backend_model, int input_height, int input_width, void *ctx)
Allocate input and output frames and fill the Task with execution parameters.
DetectPostProc detect_post_proc
DNNReturnType ff_dnn_execute_model_tf(const DNNModel *model, DNNExecBaseParams *exec_params)
static DNNReturnType execute_model_tf(TFRequestItem *request, Queue *lltask_queue)
DNNFunctionType func_type
void avpriv_report_missing_feature(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
DNNReturnType(* start_inference)(void *request)
Synchronous inference function for the backend with corresponding request item as the argument.
void ff_safe_queue_destroy(SafeQueue *sq)
Destroy the SafeQueue instance.
DNNReturnType ff_dnn_flush_tf(const DNNModel *model)
static int hex_to_data(uint8_t *data, const char *p)
DNNReturnType ff_frame_to_dnn_detect(AVFrame *frame, DNNData *input, void *log_ctx)
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some input
DNNModel * ff_dnn_load_model_tf(const char *model_filename, DNNFunctionType func_type, const char *options, AVFilterContext *filter_ctx)
int ff_safe_queue_push_back(SafeQueue *sq, void *v)
Add data to the tail of queue in the SafeQueue after locking mutex.
int avio_closep(AVIOContext **s)
Close the resource accessed by the AVIOContext *s, free it and set the pointer pointing to it to NULL...
#define i(width, name, range_min, range_max)
TF_Tensor ** output_tensors
TFInferRequest * infer_request
#define av_malloc_array(a, b)
void * args
Argument for the execution functions.
static av_const int av_toupper(int c)
Locale-independent conversion of ASCII characters to uppercase.
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
const char ** output_names
void * av_calloc(size_t nmemb, size_t size)
#define AV_INPUT_BUFFER_PADDING_SIZE
static TF_Tensor * allocate_input_tensor(const DNNData *input)
static DNNReturnType add_depth_to_space_layer(TFModel *tf_model, TF_Operation **cur_op, DepthToSpaceParams *params, const int layer)
LastLevelTaskItem * lltask
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
DNNAsyncStatusType ff_dnn_get_result_common(Queue *task_queue, AVFrame **in, AVFrame **out)
Extract input and output frame from the Task Queue after asynchronous inference.
void * ff_queue_peek_front(Queue *q)
Return a pointer to the data at the head of the queue.
int avio_open(AVIOContext **s, const char *url, int flags)
Create and initialize a AVIOContext for accessing the resource indicated by url.
void ff_dnn_free_model_tf(DNNModel **model)
#define AVIO_FLAG_READ
read-only
static void free_buffer(void *data, size_t length)
DNNReturnType ff_dnn_async_module_cleanup(DNNAsyncExecModule *async_module)
Join the Async Execution thread and set module pointers to NULL.
#define CLEANUP_ON_ERROR(tf_model)