[Libav-user] simple transcoding+filtering program segfaults

Haris Rotsos cr409 at cl.cam.ac.uk
Thu Oct 13 12:05:32 CEST 2011


Hi all,

I am trying to use ffmpeg in order to study the impact of network
conditions on various video and audio codecs, when streamed over the
network. In order to have an accurate matching of the frames between
the original video and the received one, I am interested to create a
simple program that will transcode videos and add a frame number in a
each frame.

As a first step in this program I created a c program that takes as
input a video, decodes it  applies a filter and then reencodes it and
saves it in a file. In order to do something like that I used the
encode-decode.c and filtering.c source code examples and tried to join
them in one program. The resulting code is the following.


#define _XOPEN_SOURCE 600 /* for usleep */

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfiltergraph.h>
//#include <libavfilter/vsink_buffer.h>
#include <libavfilter/vsrc_buffer.h>

const char *filter_descr = "scale=78:24";

static AVFormatContext *fmt_ctx;
static AVCodecContext *dec_ctx;
AVFilterContext *buffersink_ctx;
AVFilterContext *buffersrc_ctx;
AVFilterGraph *filter_graph;
static int video_stream_index = -1;
static int64_t last_pts = AV_NOPTS_VALUE;

static int open_input_file(const char *filename)
{
  int ret, i;
  AVCodec *dec;

  if ((ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL)) < 0) {
    av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
    return ret;
  }

  if ((ret = av_find_stream_info(fmt_ctx)) < 0) {
    av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
    return ret;
  }

  /* select the video stream */
  ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
  if (ret < 0) {
    av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the
input file\n");
    return ret;
  }
  video_stream_index = ret;
  dec_ctx = fmt_ctx->streams[video_stream_index]->codec;

  /* init the video decoder */
  if ((ret = avcodec_open(dec_ctx, dec)) < 0) {
    av_log(NULL, AV_LOG_ERROR, "Cannot open video decoder\n");
    return ret;
  }

  return 0;
}

static int init_filters(const char *filters_descr)
{
  char args[512];
  int ret;
  AVFilter *buffersrc  = avfilter_get_by_name("buffer");
  AVFilter *buffersink = avfilter_get_by_name("buffersink");
  AVFilterInOut *outputs = avfilter_inout_alloc();
  AVFilterInOut *inputs  = avfilter_inout_alloc();
  enum PixelFormat pix_fmts[] = { PIX_FMT_GRAY8, PIX_FMT_NONE };
  filter_graph = avfilter_graph_alloc();

  /* buffer video source: the decoded frames from the decoder will be
inserted here. */
  snprintf(args, sizeof(args), "%d:%d:%d:%d:%d:%d:%d",
      dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
      dec_ctx->time_base.num, dec_ctx->time_base.den,
      dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den);
  ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
      args, NULL, filter_graph);
  if (ret < 0) {
    av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
    return ret;
  }

  /* buffer video sink: to terminate the filter chain. */
  ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
      NULL, pix_fmts, filter_graph);
  if (ret < 0) {
    av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
    return ret;
  }

  /* Endpoints for the filter graph. */
  outputs->name       = av_strdup("in");
  outputs->filter_ctx = buffersrc_ctx;
  outputs->pad_idx    = 0;
  outputs->next       = NULL;

  inputs->name       = av_strdup("out");
  inputs->filter_ctx = buffersink_ctx;
  inputs->pad_idx    = 0;
  inputs->next       = NULL;

  if ((ret = avfilter_graph_parse(filter_graph, filter_descr,
          &inputs, &outputs, NULL)) < 0)
    return ret;

  if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
    return ret;
}

static void display_picref(AVFilterBufferRef *picref, AVRational time_base)
{
  int x, y;
  uint8_t *p0, *p;
  int64_t delay;

  if (picref->pts != AV_NOPTS_VALUE) {
    if (last_pts != AV_NOPTS_VALUE) {
      /* sleep roughly the right amount of time;
       * usleep is in microseconds, just like AV_TIME_BASE. */
      delay = av_rescale_q(picref->pts - last_pts,
          time_base, AV_TIME_BASE_Q);
      if (delay > 0 && delay < 1000000)
        usleep(delay);
    }
    last_pts = picref->pts;
  }

  /* Trivial ASCII grayscale display. */
  p0 = picref->data[0];
  puts("\033c");
  for (y = 0; y < picref->video->h; y++) {
    p = p0;
    for (x = 0; x < picref->video->w; x++)
      putchar(" .-+#"[*(p++) / 52]);
    putchar('\n');
    p0 += picref->linesize[0];
  }
  fflush(stdout);
}

int main(int argc, char **argv)
{
  int ret;
  AVPacket packet;
  AVFrame frame;
  int got_frame;

  if (argc != 2) {
    fprintf(stderr, "Usage: %s file\n", argv[0]);
    exit(1);
  }

  avcodec_register_all();
  av_register_all();
  avfilter_register_all();

  if ((ret = open_input_file(argv[1]) < 0))
    goto end;
  if ((ret = init_filters(filter_descr)) < 0)
    goto end;

  /* From the decoding_encoding exaple of the source code */
  AVCodec *codec;
  AVCodecContext *c= NULL;
  int i, out_size, size, x, y, outbuf_size;
  FILE *f;
  AVFrame *picture;
  uint8_t *outbuf;

  printf("Video encoding\n");

  /* find the mpeg1 video encoder */
  codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO);
  if (!codec) {
    fprintf(stderr, "codec not found\n");
    exit(1);
  }

  c = avcodec_alloc_context3(codec);
  picture= avcodec_alloc_frame();

  /* put sample parameters */
  c->bit_rate = dec_ctx->bit_rate; //400000;
  /* resolution must be a multiple of two */
  c->width = dec_ctx->width; // 352;
  c->height = dec_ctx->height; //288;
  /* frames per second */
  c->time_base.num =  dec_ctx->time_base.num; //(AVRational){1,25};
  c->time_base.den =  dec_ctx->time_base.den; //(AVRational){1,25};
  c->gop_size = dec_ctx->gop_size; //10; /* emit one intra frame every
ten frames */
  c->max_b_frames= dec_ctx->max_b_frames; //1;
  c->pix_fmt = dec_ctx->pix_fmt; //PIX_FMT_YUV420P;

    /* put sample parameters */
    c->bit_rate = 400000;
    /* resolution must be a multiple of two */
    c->width = 352;
    c->height = 288;
    /* frames per second */
    c->time_base= (AVRational){1,25};
    c->gop_size = 10; /* emit one intra frame every ten frames */
    c->max_b_frames=1;
    c->pix_fmt = PIX_FMT_YUV420P;



  /* open it */
  if (avcodec_open(c, codec) < 0) {
    fprintf(stderr, "could not open codec\n");
    exit(1);
  }

  f = fopen("haris.mpg", "wb");
  if (!f) {
    fprintf(stderr, "could not open haris.mpg\n");
    exit(1);
  }
  /* the image can be allocated by any means and av_image_alloc() is
   * just the most convenient way if av_malloc() is to be used */
  //    av_image_alloc(picture->data, picture->linesize,
  //                   c->width, c->height, c->pix_fmt, 1);
  /* alloc image and output buffer */
  outbuf_size = 1000000;
  outbuf = malloc(outbuf_size);

  /* read all packets */
  while (1) {

    //    AVFrame *picture;

    AVFilterBufferRef *picref;
    if ((ret = av_read_frame(fmt_ctx, &packet)) < 0)
      break;

    if (packet.stream_index == video_stream_index) {
      avcodec_get_frame_defaults(&frame);
      got_frame = 0;
      ret = avcodec_decode_video2(dec_ctx, &frame, &got_frame, &packet);
      av_free_packet(&packet);
      if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Error decoding video\n");
        break;
      }

      if (got_frame) {
        if (frame.pts == AV_NOPTS_VALUE)
          frame.pts = frame.pkt_dts == AV_NOPTS_VALUE ?
            frame.pkt_dts : frame.pkt_pts;
        /* push the decoded frame into the filtergraph */
        av_vsrc_buffer_add_frame(buffersrc_ctx, &frame);

        /* pull filtered pictures from the filtergraph */
        while (avfilter_poll_frame(buffersink_ctx->inputs[0])) {
          av_vsink_buffer_get_video_buffer_ref(buffersink_ctx, &picref, 0);
          if (picref) {
            ret = avfilter_fill_frame_from_video_buffer_ref (picture, picref);
            if(ret != 0) {
              fprintf(stderr,
"avfilter_fill_frame_from_video_buffer_ref failed with %d error\n",
ret);
              exit(2);
            }
            /* encode the image */
            printf("encoding frame %3d (size=%5d of %d)\n", i,
out_size, outbuf_size);
            out_size = avcodec_encode_video(c, outbuf, outbuf_size, picture);
            printf("encoding frame %3d (size=%5d)\n", i, out_size);
            fwrite(outbuf, 1, out_size, f);

            //        display_picref(picref,
buffersink_ctx->inputs[0]->time_base);
            avfilter_unref_buffer(picref);
          }
        }
      }
    }
  }
end:
  /* add sequence end code to have a real mpeg file */
  outbuf[0] = 0x00;
  outbuf[1] = 0x00;
  outbuf[2] = 0x01;
  outbuf[3] = 0xb7;
  fwrite(outbuf, 1, 4, f);
  fclose(f);
  free(outbuf);

  avcodec_close(c);
  av_free(c);
  av_free(picture->data[0]);
  av_free(picture);
  printf("\n");

  avfilter_graph_free(&filter_graph);
  if (dec_ctx)
    avcodec_close(dec_ctx);
  av_close_input_file(fmt_ctx);

  if (ret < 0 && ret != AVERROR_EOF) {
    char buf[1024];
    av_strerror(ret, buf, sizeof(buf));
    fprintf(stderr, "Error occurred: %s\n", buf);
    exit(1);
  }

  exit(0);
}

I compile the program with the following command, and complains with
only a few deprecation warnings:
gcc -g -o filtering -L/usr/local/lib/
-L/home/cr409/x264-snapshot-20111011-2245/build/lib/ -lavformat
-lavfilter -lx264 -lavcodec -lz -lavutil   filtering.c

Unfortunately, when I run the program I get a segfault in the
following function.

cr409 at elisavet-desktop:~/ffmpeg/doc/examples$ gdb filtering
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/cr409/ffmpeg/doc/examples/filtering...done.
(gdb) run ../../../chicane/test-boxes.mpg
Starting program: /home/cr409/ffmpeg/doc/examples/filtering
../../../chicane/test-boxes.mpg
[Thread debugging using libthread_db enabled]
[buffer @ 0x60c380] w:352 h:288 pixfmt:yuv420p tb:1/25 sar:1/1 sws_param:
[scale @ 0x60b060] w:352 h:288 fmt:yuv420p -> w:78 h:24 fmt:gray flags:0x2
Video encoding
encoding frame   0 (size=-1258291200 of 1000000)

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff6023a32 in memcpy () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) bt
#0  0x00007ffff6023a32 in memcpy () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x00007ffff6a7868e in MPV_encode_picture () from
/usr/local/lib/libavcodec.so.53
#2  0x00007ffff6b1cebf in avcodec_encode_video () from
/usr/local/lib/libavcodec.so.53
#3  0x0000000000402148 in main (argc=2, argv=0x7fffffffdff8) at filtering.c:283
(gdb)

you can find the reference video at
http://www.cl.cam.ac.uk/~cr409/misc/test-boxes.mpg

Any idea what I am doing wrong? I guess the problem is on the lines
that I convert the buffered frame into a AVFRAME, but looking in the
code of the library, I haven't found some code piece fundamentally
different from my version.

Any help is highly apprreciated.

Kind regards,


-- 
Charalampos Rotsos
PhD student
The University of Cambridge
Computer Laboratory
William Gates Building
JJ Thomson Avenue
Cambridge
CB3 0FD

Phone: +44-(0) 1223 767032
Email: cr409 at cl.cam.ac.uk


More information about the Libav-user mailing list