Advertisement
Guest User

Untitled

a guest
May 2nd, 2018
147
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.00 KB | None | 0 0
  1. #include <libavfilter/avfilter.h>
  2. #include <libavfilter/buffersink.h>
  3. #include <libavfilter/buffersrc.h>
  4. #include <libavutil/channel_layout.h>
  5. #include <libavutil/frame.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8.  
  9. typedef struct FilteringContext {
  10.     const char *desc;
  11.     AVFilterGraph *graph;
  12.     int nb_inputs;
  13.     AVFilterContext **inputs;
  14.     int nb_outputs;
  15.     AVFilterContext **outputs;
  16. } FilteringContext;
  17.  
  18. static AVFrame *get_dummy_frame(int width, int height, int frame_index)
  19. {
  20.     int ret = 0;
  21.     AVFrame *frame = av_frame_alloc();
  22.     if (!frame)
  23.         return NULL;
  24.  
  25.     frame->format = AV_PIX_FMT_YUV420P;
  26.     frame->width = width;
  27.     frame->height = height;
  28.  
  29.     if ((ret = av_frame_get_buffer(frame, 0)) < 0) {
  30.         printf("Failed to allocate frame buffer: %s\n", av_err2str(ret));
  31.         av_frame_free(&frame);
  32.         return NULL;
  33.     }
  34.  
  35.     for (int y = 0; y < height; y++)
  36.         for (int x = 0; x < width; x++)
  37.             frame->data[0][y * frame->linesize[0] + x] = x + y + frame_index * 3;
  38.  
  39.     for (int y = 0; y < height / 2; y++) {
  40.         for (int x = 0; x < width / 2; x++) {
  41.             frame->data[1][y * frame->linesize[1] + x] = 128 + y + frame_index * 2;
  42.             frame->data[2][y * frame->linesize[2] + x] = 64 + x + frame_index * 5;
  43.         }
  44.     }
  45.  
  46.     return frame;
  47. }
  48.  
  49. static int init_input_filter(FilteringContext *fc, AVFilterInOut *in)
  50. {
  51.     int ret = 0;
  52.     char args[512];
  53.     const AVFilter *buffersrc;
  54.     AVFilterContext *buffersrc_ctx = NULL;
  55.     enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx);
  56.  
  57.     if (type == AVMEDIA_TYPE_VIDEO) {
  58.         buffersrc = avfilter_get_by_name("buffer");
  59.         snprintf(args, sizeof(args),
  60.                  "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
  61.                  320, 240, AV_PIX_FMT_YUV420P, 1, 1, 1, 1);
  62.     } else if (type == AVMEDIA_TYPE_AUDIO) {
  63.         buffersrc = avfilter_get_by_name("abuffer");
  64.         const int64_t channel_layout = AV_CH_LAYOUT_STEREO;
  65.         snprintf(args, sizeof(args),
  66.                  "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64,
  67.                  1, 1, 44100, av_get_sample_fmt_name(AV_SAMPLE_FMT_S16), channel_layout);
  68.     } else {
  69.         printf("Only video and audio filters are supported\n");
  70.         return AVERROR(EINVAL);
  71.     }
  72.  
  73.     if ((ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
  74.             args, NULL, fc->graph)) < 0) {
  75.         printf("Failed to create buffer source filter: %s\n", av_err2str(ret));
  76.         return ret;
  77.     }
  78.  
  79.     fc->nb_inputs++;
  80.     fc->inputs = av_realloc_array(fc->inputs, fc->nb_inputs, sizeof(AVFilterContext*));
  81.     fc->inputs[fc->nb_inputs - 1] = buffersrc_ctx;
  82.  
  83.     if ((ret = avfilter_link(buffersrc_ctx, 0, in->filter_ctx, in->pad_idx)) < 0) {
  84.         printf("Could not link buffer source to graph: %s\n", av_err2str(ret));
  85.         return ret;
  86.     }
  87.  
  88.     return ret;
  89. }
  90.  
  91. static int init_output_filter(FilteringContext *fc, AVFilterInOut *out)
  92. {
  93.     int ret = 0;
  94.     const AVFilter *buffersink;
  95.     AVFilterContext *buffersink_ctx = NULL;
  96.     enum AVMediaType type = avfilter_pad_get_type(out->filter_ctx->input_pads, out->pad_idx);
  97.  
  98.     if (type == AVMEDIA_TYPE_VIDEO) {
  99.         buffersink = avfilter_get_by_name("buffersink");
  100.     } else if (type == AVMEDIA_TYPE_AUDIO) {
  101.         buffersink = avfilter_get_by_name("abuffersink");
  102.     } else {
  103.         printf("Only video and audio filters are supported\n");
  104.         return AVERROR(EINVAL);
  105.     }
  106.  
  107.     if ((ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
  108.             NULL, NULL, fc->graph)) < 0) {
  109.         printf("Failed to create buffer sink filter: %s\n", av_err2str(ret));
  110.         return ret;
  111.     }
  112.  
  113.     fc->nb_outputs++;
  114.     fc->outputs = av_realloc_array(fc->outputs, fc->nb_outputs, sizeof(AVFilterContext*));
  115.     fc->outputs[fc->nb_outputs - 1] = buffersink_ctx;
  116.  
  117.     if ((ret = avfilter_link(out->filter_ctx, out->pad_idx, buffersink_ctx, 0)) < 0) {
  118.         printf("Could not link buffer source to graph: %s\n", av_err2str(ret));
  119.         return ret;
  120.     }
  121.  
  122.     return ret;
  123. }
  124.  
  125. static int init_filters(FilteringContext *fc)
  126. {
  127.     int ret = 0;
  128.     AVFilterInOut *inputs = NULL;
  129.     AVFilterInOut *outputs = NULL;
  130.  
  131.     fc->graph = avfilter_graph_alloc();
  132.     if (!fc->graph)
  133.         return -1;
  134.  
  135.     printf("Parsing: %s\n", fc->desc);
  136.     if ((ret = avfilter_graph_parse2(fc->graph, fc->desc, &inputs, &outputs)) < 0) {
  137.         printf("Failed to parse filter graph: %s\n", av_err2str(ret));
  138.         goto end;
  139.     }
  140.  
  141.     for (AVFilterInOut *current = inputs; current; current = current->next) {
  142.         if ((ret = init_input_filter(fc, current)) < 0) {
  143.             printf("Failed to create input for graph\n");
  144.             goto end;
  145.         }
  146.     }
  147.     for (AVFilterInOut *current = outputs; current; current = current->next) {
  148.         if ((ret = init_output_filter(fc, current)) < 0) {
  149.             printf("Failed to create output for graph\n");
  150.             goto end;
  151.         }
  152.     }
  153.  
  154.     if ((ret = avfilter_graph_config(fc->graph, NULL)) < 0) {
  155.         printf("Failed to configure graph: %s\n", av_err2str(ret));
  156.         goto end;
  157.     }
  158.  
  159. end:
  160.     avfilter_inout_free(&inputs);
  161.     avfilter_inout_free(&outputs);
  162.  
  163.     return ret;
  164. }
  165.  
  166. static int pull_frame(AVFilterContext *sink_ctx, AVFrame **frame)
  167. {
  168.     int ret = 0;
  169.     while (ret >= 0) {
  170.         if (!*frame)
  171.             *frame = av_frame_alloc();
  172.         if (!*frame)
  173.             return AVERROR(ENOMEM);
  174.  
  175.         ret = av_buffersink_get_frame_flags(sink_ctx, *frame, AV_BUFFERSINK_FLAG_NO_REQUEST);
  176.         if (ret < 0) {
  177.             if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
  178.                 printf("Failed to pull from filter chain: %s (%d)\n", av_err2str(ret), ret);
  179.             }
  180.             break;
  181.         }
  182.     }
  183.  
  184.     return ret;
  185. }
  186.  
  187. static int push_frame(AVFilterContext *src_ctx, AVFrame *frame)
  188. {
  189.     int ret = av_buffersrc_add_frame_flags(src_ctx, frame, AV_BUFFERSRC_FLAG_PUSH);
  190.     if (ret < 0) {
  191.         if (ret != AVERROR_EOF)
  192.             printf("Failed to feed filter chain: %s (%d)\n", av_err2str(ret), ret);
  193.         return ret;
  194.     }
  195.  
  196.     return 0;
  197. }
  198.  
  199. int main(int argc, char *argv[])
  200. {
  201.     int ret = 0;
  202.     FilteringContext *fc = NULL;
  203.     const char *filterspec = "[in1] scale=iw/4:ih/4 [mid1]; [in2] [mid1] overlay=main_w-overlay_w-10:main_h-overlay_h-10:shortest=1 [out1]";
  204.  
  205.     if (argc > 1 && argv[1]) {
  206.         int level = atoi(argv[1]);
  207.         av_log_set_level(level);
  208.     }
  209.  
  210.     fc = av_mallocz(sizeof(*fc));
  211.     if (!fc)
  212.         goto end;
  213.     fc->desc = av_strdup(filterspec);
  214.  
  215.     if ((ret = init_filters(fc)) < 0)
  216.         goto end;
  217.  
  218.     //printf("Graph:\n%s\n", avfilter_graph_dump(fc->graph, NULL));
  219.  
  220.     for (int frame_index = 0; frame_index < 25; ++frame_index) {
  221.         for (int i = 0; i < fc->nb_inputs; ++i) {
  222.             AVFrame *input = get_dummy_frame(320, 240, frame_index);
  223.             input->pts = frame_index;
  224.             if ((ret = push_frame(fc->inputs[i], input)) < 0) {
  225.                 printf("Error pushing frame: %s\n", av_err2str(ret));
  226.                 av_frame_free(&input);
  227.                 break;
  228.             }
  229.             av_frame_free(&input);
  230.         }
  231.  
  232.         for (int i = 0; i < fc->nb_outputs; ++i) {
  233.             AVFrame *output;
  234.             if ((ret = pull_frame(fc->outputs[i], &output)) < 0) {
  235.                 printf("Error pulling frame: %s\n", av_err2str(ret));
  236.                 av_frame_free(&output);
  237.                 break;
  238.             }
  239.         }
  240.     }
  241.  
  242.     for (int i = 0; i < fc->nb_inputs; ++i) {
  243.         if ((ret = push_frame(fc->inputs[i], NULL)) < 0) {
  244.             printf("Error flushing filters: %s\n", av_err2str(ret));
  245.         }
  246.     }
  247.  
  248. end:
  249.     if (fc) {
  250.         avfilter_graph_free(&fc->graph);
  251.         av_free(fc->inputs);
  252.         av_free(fc->outputs);
  253.         av_freep(&fc->desc);
  254.     }
  255.     av_free(fc);
  256.  
  257.     return (ret < 0 ? 1 : 0);
  258. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement