示例#1
0
void setup(void) {
  /*Zero the struct and set the versions and keyframe_granule_shift.*/
  daala_info_init(&di);
  di.pic_width = 176;
  di.pic_height = 144;
  di.pixel_aspect_numerator = 128;
  di.pixel_aspect_denominator = 117;
  di.timebase_numerator = 30000;
  di.timebase_denominator = 1001;
  di.frame_duration = 30;
  di.nplanes = 2;
  dd = daala_encode_create(&di);
  ck_assert(dd != NULL);
  daala_comment_init(&dc);
  dc.comments = 2;
  dc.user_comments = (char **)malloc(sizeof(*dc.user_comments)*2);
  ck_assert(dc.user_comments != NULL);
  dc.comment_lengths = (int *)malloc(sizeof(*dc.comment_lengths)*2);
  ck_assert(dc.comment_lengths != NULL);
  dc.user_comments[0] = make_string("COMMENT=Comment 0");
  ck_assert(dc.user_comments[0] != NULL);
  dc.comment_lengths[0] = strlen(dc.user_comments[0]);
  dc.user_comments[1] = make_string("COMMENT=Comment 1 (this one longer)");
  ck_assert(dc.user_comments[1] != NULL);
  dc.comment_lengths[1] = strlen(dc.user_comments[1]);
}
示例#2
0
int player_example_daala_stream_init(player_example *player, int serial) {
  int ret;
  if (player == NULL) return -1;
  ret = ogg_stream_init(&player->os, serial);
  if (ret != 0) return -1;
  daala_info_init(&player->di);
  daala_comment_init(&player->dc);
  player->od_state = ODS_HEADER;
  return 0;
}
示例#3
0
文件: daala.c 项目: 9034725985/vlc
/*****************************************************************************
 * OpenDecoder: probe the decoder and return score
 *****************************************************************************/
static int OpenDecoder( vlc_object_t *p_this )
{
    decoder_t *p_dec = (decoder_t*)p_this;
    decoder_sys_t *p_sys;

    if( p_dec->fmt_in.i_codec != VLC_CODEC_DAALA )
    {
        return VLC_EGENERIC;
    }

    /* Allocate the memory needed to store the decoder's structure */
    p_sys = malloc(sizeof(*p_sys));
    if( p_sys == NULL )
        return VLC_ENOMEM;

    p_dec->p_sys = p_sys;
    p_dec->p_sys->b_packetizer = false;
    p_sys->b_has_headers = false;
    p_sys->i_pts = VLC_TS_INVALID;
    p_sys->b_decoded_first_keyframe = false;
    p_sys->dcx = NULL;

    /* Set output properties */
    p_dec->fmt_out.i_cat = VIDEO_ES;
    p_dec->fmt_out.i_codec = VLC_CODEC_I420;

    /* Set callbacks */
    p_dec->pf_decode_video = (picture_t *(*)(decoder_t *, block_t **))
        DecodeBlock;
    p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
        DecodeBlock;

    /* Init supporting Daala structures needed in header parsing */
    daala_comment_init( &p_sys->dc );
    daala_info_init( &p_sys->di );

    return VLC_SUCCESS;
}
示例#4
0
文件: daala.c 项目: 9034725985/vlc
static int OpenEncoder( vlc_object_t *p_this )
{
    encoder_t *p_enc = (encoder_t *)p_this;
    encoder_sys_t *p_sys;
    ogg_packet header;
    int status;

    if( p_enc->fmt_out.i_codec != VLC_CODEC_DAALA &&
        !p_enc->b_force )
    {
        return VLC_EGENERIC;
    }

    /* Allocate the memory needed to store the encoder's structure */
    p_sys = malloc( sizeof( encoder_sys_t ) );
    if( !p_sys )
        return VLC_ENOMEM;
    p_enc->p_sys = p_sys;

    p_enc->pf_encode_video = Encode;
    p_enc->fmt_in.i_codec = VLC_CODEC_I420;
    p_enc->fmt_out.i_codec = VLC_CODEC_DAALA;

    config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );

    char *psz_tmp = var_GetString( p_enc, ENC_CFG_PREFIX "chroma-fmt" );
    uint32_t i_codec;
    if( !psz_tmp ) {
        free(p_sys);
        return VLC_ENOMEM;
    } else {
        if( !strcmp( psz_tmp, "420" ) ) {
            i_codec = VLC_CODEC_I420;
        }
        else if( !strcmp( psz_tmp, "444" ) ) {
            i_codec = VLC_CODEC_I444;
        }
        else {
            msg_Err( p_enc, "Invalid chroma format: %s", psz_tmp );
            free( psz_tmp );
            free( p_sys );
            return VLC_EGENERIC;
        }
        free( psz_tmp );
        p_enc->fmt_in.i_codec = i_codec;
        /* update bits_per_pixel */
        video_format_Setup(&p_enc->fmt_in.video, i_codec,
                p_enc->fmt_in.video.i_width,
                p_enc->fmt_in.video.i_height,
                p_enc->fmt_in.video.i_visible_width,
                p_enc->fmt_in.video.i_visible_height,
                p_enc->fmt_in.video.i_sar_num,
                p_enc->fmt_in.video.i_sar_den);
    }

    daala_info_init( &p_sys->di );

    p_sys->di.pic_width = p_enc->fmt_in.video.i_visible_width;
    p_sys->di.pic_height = p_enc->fmt_in.video.i_visible_height;

    p_sys->di.nplanes = 3;
    for (int i = 0; i < p_sys->di.nplanes; i++)
    {
        p_sys->di.plane_info[i].xdec = i > 0 && i_codec != VLC_CODEC_I444;
        p_sys->di.plane_info[i].ydec = i_codec == VLC_CODEC_I420 ?
            p_sys->di.plane_info[i].xdec : 0;
    }
    p_sys->di.frame_duration = 1;

    if( !p_enc->fmt_in.video.i_frame_rate ||
        !p_enc->fmt_in.video.i_frame_rate_base )
    {
        p_sys->di.timebase_numerator = 25;
        p_sys->di.timebase_denominator = 1;
    }
    else
    {
        p_sys->di.timebase_numerator = p_enc->fmt_in.video.i_frame_rate;
        p_sys->di.timebase_denominator = p_enc->fmt_in.video.i_frame_rate_base;
    }

    if( p_enc->fmt_in.video.i_sar_num > 0 && p_enc->fmt_in.video.i_sar_den > 0 )
    {
        unsigned i_dst_num, i_dst_den;
        vlc_ureduce( &i_dst_num, &i_dst_den,
                     p_enc->fmt_in.video.i_sar_num,
                     p_enc->fmt_in.video.i_sar_den, 0 );
        p_sys->di.pixel_aspect_numerator = i_dst_num;
        p_sys->di.pixel_aspect_denominator = i_dst_den;
    }
    else
    {
        p_sys->di.pixel_aspect_numerator = 4;
        p_sys->di.pixel_aspect_denominator = 3;
    }

    p_sys->di.keyframe_rate = var_GetInteger( p_enc, ENC_CFG_PREFIX "keyint" );

    daala_enc_ctx *dcx;
    p_sys->dcx = dcx = daala_encode_create( &p_sys->di );
    if( !dcx )
    {
        free( p_sys );
        return VLC_ENOMEM;
    }

    daala_comment_init( &p_sys->dc );

    int i_quality = var_GetInteger( p_enc, ENC_CFG_PREFIX "quality" );
    daala_encode_ctl( dcx, OD_SET_QUANT, &i_quality, sizeof(i_quality) );

    /* Create and store headers */
    while( ( status = daala_encode_flush_header( dcx, &p_sys->dc, &header ) ) )
    {
        if ( status < 0 )
        {
            CloseEncoder( p_this );
            return VLC_EGENERIC;
        }
        if( xiph_AppendHeaders( &p_enc->fmt_out.i_extra,
                                &p_enc->fmt_out.p_extra, header.bytes,
                                header.packet ) )
        {
            p_enc->fmt_out.i_extra = 0;
            p_enc->fmt_out.p_extra = NULL;
        }
    }
    return VLC_SUCCESS;
}
示例#5
0
文件: upsample.c 项目: fidalco/daala
int main(int _argc, char **_argv) {
  const char *optstring = "";
  const struct option long_options[] = {
    { NULL, 0, NULL, 0 }
  };
  FILE *fin;
  FILE *fout;
  video_input vid;
  video_input_info info;
  int frameno;
  int pli;
  int xdec[3];
  int ydec[3];
  int w[3];
  int h[3];
  int long_option_index;
  int c;
  od_state state;
  daala_info dinfo;

  while ((c = getopt_long(_argc, _argv, optstring, long_options,
   &long_option_index)) != EOF) {
    switch (c) {
      default: {
        usage(_argv);
        exit(EXIT_FAILURE);
      }
    }
  }
  if (optind+2 != _argc) {
    usage(_argv);
    exit(EXIT_FAILURE);
  }
  fin = strcmp(_argv[optind], "-") == 0 ? stdin : fopen(_argv[optind], "rb");
  if (fin == NULL) {
    fprintf(stderr, "Unable to open '%s' for extraction.\n", _argv[optind]);
    exit(EXIT_FAILURE);
  }
  fprintf(stderr, "Opening %s as input...\n", _argv[optind]);
  if (video_input_open(&vid, fin) < 0) exit(EXIT_FAILURE);
  video_input_get_info(&vid, &info);

  daala_info_init(&dinfo);
  for (pli = 0; pli < 3; pli++) {
    xdec[pli] = pli && !(info.pixel_fmt&1);
    ydec[pli] = pli && !(info.pixel_fmt&2);
    h[pli] = info.pic_h >> ydec[pli];
    w[pli] = info.pic_w >> xdec[pli];

    dinfo.plane_info[pli].xdec = xdec[pli];
    dinfo.plane_info[pli].ydec = ydec[pli];
  }
  dinfo.nplanes = 3;
  dinfo.pic_height = h[0];
  dinfo.pic_width = w[0];

  od_state_init(&state, &dinfo);

  fout = strcmp(_argv[optind+1], "-") == 0 ? stdout : fopen(_argv[optind+1],
   "wb");
  if (fout == NULL) {
    fprintf(stderr, "Error opening output file \"%s\".\n", _argv[optind+1]);
    return 1;
  }
  fprintf(fout, "YUV4MPEG2 W%i H%i F%i:%i Ip A%i:%i%s\n",
   info.pic_w*2, info.pic_h*2, (unsigned)info.fps_n,
   (unsigned)info.fps_d, info.par_n, info.par_d,
   CHROMA_TAGS[ydec[1] ? xdec[1] ? 0 : 2 : 3]);
  for (frameno = 0;; frameno++) {
    video_input_ycbcr in;
    int ret = 0;
    char tag[5];
    od_img *simg = &state.io_imgs[OD_FRAME_REC];
    od_img *dimg = &state.ref_imgs[0];
    int x, y;
    ret = video_input_fetch_frame(&vid, in, tag);
    if (ret == 0) break;
    for (pli = 0; pli < 3; pli++) {
      od_img_plane *siplane = simg->planes + pli;
      unsigned char *src = siplane->data;
      int src_stride = siplane->ystride;
      int plane_width = simg->width >> xdec[pli];
      int plane_height = simg->height >> ydec[pli];
      for (y = 0; y < h[pli]; y++) {
        for (x = 0; x < w[pli]; x++) {
          int cy = y + (int)(info.pic_y >> ydec[pli]);
          int cx = x + (int)(info.pic_x >> xdec[pli]);
          src[y*src_stride + x] = in[pli].data[cy*in[pli].stride + cx];
        }
      }
      /*From od_img_plane_copy_pad8*/
      /*Right side.*/
      for (x = w[pli]; x < plane_width; x++) {
        src = siplane->data + x - 1;
        for (y = 0; y < h[pli]; y++) {
          src[1] = (2*src[0] + (src - (src_stride & -(y > 0)))[0]
           + (src + (src_stride & -(y + 1 < h[pli])))[0] + 2) >> 2;
          src += src_stride;
        }
      }
      /*Bottom.*/
      src = siplane->data + src_stride*h[pli];
      for (y = h[pli]; y < plane_height; y++) {
        for (x = 0; x < plane_width; x++) {
          src[x] = (2*(src - src_stride)[x] + (src - src_stride)[x - (x > 0)]
           + (src - src_stride)[x + (x + 1 < plane_width)] + 2) >> 2;
        }
        src += src_stride;
      }
    }
    od_state_upsample8(&state, dimg, simg);
    fprintf(fout, "FRAME\n");
    for (pli = 0; pli < 3; pli++) {
      od_img_plane *diplane = dimg->planes + pli;
      unsigned char *dst = diplane->data;
      for (y = 0; y < 2*h[pli]; y++) {
        if (fwrite(dst + diplane->ystride*y, 2*w[pli], 1, fout) < 1) {
          fprintf(stderr, "Error writing to output.\n");
          return EXIT_FAILURE;
        }
      }
    }
    fprintf(stderr, "Completed frame %d.\n", frameno);
  }
  video_input_close(&vid);
  if (fout != stdout) fclose(fout);
  return EXIT_SUCCESS;
}
示例#6
0
int main(int argc, char *argv[]) {
  daala_packet dp;
  ogg_packet op;

  int long_option_index;
  int c;
  ogg_sync_state oy;
  ogg_page og;
  ogg_stream_state to;
  daala_info di;
  daala_comment dc;
  daala_setup_info *ds;
  daala_dec_ctx *dd;
  daala_image img;
  const char *optstring = "o:r";
  struct option options [] = {
   { "output", required_argument, NULL, 'o' },
   { "raw", no_argument, NULL, 'r' }, /*Disable YUV4MPEG2 headers:*/
   { "version", no_argument, NULL, 0},
   { NULL, 0, NULL, 0 }
  };
  int frames = 0;
  int pix_fmt = 1;
  int daala_p = 0;
  int daala_processing_headers = 0;
  int stateflag = 0;
  /* single frame video buffering */
  int videobuf_ready = 0;
  int raw = 0;
  FILE *outfile = NULL;
  ogg_int32_t pic_width = 0;
  ogg_int32_t pic_height = 0;
  ogg_int32_t fps_num = 0;
  ogg_int32_t fps_denom = 0;
  FILE *infile = stdin;
  outfile = stdout;
  dd = NULL;
  ds = NULL;
  daala_log_init();
#ifdef _WIN32 /* We need to set stdin/stdout to binary mode on windows. */
  /* Beware the evil ifdef. We avoid these where we can, but this one we
     cannot. Don't add any more, you'll probably go to hell if you do. */
  _setmode(_fileno(stdin), _O_BINARY);
  _setmode(_fileno(stdout), _O_BINARY);
#endif
  /* Process option arguments. */
  while ((c = getopt_long(argc, argv, optstring, options, &long_option_index))
   != EOF) {
    switch (c) {
      case 'o': {
        if (strcmp(optarg, "-") != 0) {
          outfile = fopen(optarg, "wb");
          if (outfile == NULL) {
            fprintf(stderr, "Unable to open output file '%s'\n", optarg);
            exit(1);
          }
        }
        else {
          outfile = stdout;
        }
        break;
      }
      case 'r': {
        raw = 1;
        break;
      }
      case 0: {
        if (strcmp(options[long_option_index].name, "version") == 0) {
          version();
        }
        break;
      }
      default: usage(); break;
    }
  }
  if (optind < argc) {
    infile = fopen(argv[optind], "rb");
    if (infile == NULL) {
      fprintf(stderr, "Unable to open '%s' for extraction.\n", argv[optind]);
      exit(1);
    }
    if (++optind < argc) {
      usage();
      exit(1);
    }
  }
  /*Ok, Ogg parsing.
    The idea here is we have a bitstream that is made up of Ogg pages.
    The libogg sync layer will find them for us.
    There may be pages from several logical streams interleaved; we find the
     first daala stream and ignore any others.
    Then we pass the pages for our stream to the libogg stream layer which
     assembles our original set of packets out of them.
   start up Ogg stream synchronization layer */
  ogg_sync_init(&oy);

  /* init supporting Theora structures needed in header parsing */
  daala_comment_init(&dc);
  daala_info_init(&di);
  /*Ogg file open; parse the headers.
    Theora (like Vorbis) depends on some initial header packets for decoder
     setup and initialization.
    We retrieve these first before entering the main decode loop.*/
  /* Only interested in Daala streams */
  while (!stateflag) {
    int ret = buffer_data(infile, &oy);
    if (ret == 0) break;
    while (ogg_sync_pageout(&oy, &og) > 0) {
      int got_packet;
      ogg_stream_state test;
      /* is this a mandated initial header? If not, stop parsing */
      if (!ogg_page_bos(&og)) {
        /* don't leak the page; get it into the appropriate stream */
        queue_page(&og, &to, daala_p);
        stateflag = 1;
        break;
      }
      ogg_stream_init(&test, ogg_page_serialno(&og));
      ogg_stream_pagein(&test, &og);
      got_packet = ogg_stream_packetpeek(&test, &op);

      ogg_to_daala_packet(&dp, &op);
      /* identify the codec: try daala */
      if ((got_packet == 1) && !daala_p && (daala_processing_headers =
       daala_decode_header_in(&di, &dc, &ds, &dp)) >= 0) {
        /* it is daala -- save this stream state */
        memcpy(&to, &test, sizeof(test));
        daala_p = 1;
        /*Advance past the successfully processed header.*/
        if (daala_processing_headers) ogg_stream_packetout(&to, NULL);
      }
      else {
        /* whatever it is, we don't care about it */
        ogg_stream_clear(&test);
      }
    }
    /* fall through to non-bos page parsing */
  }
  /* we're expecting more header packets. */
  while (daala_p && daala_processing_headers) {
    int ret;
    /* look for further daala headers */
    while (daala_processing_headers &&
     (ret = ogg_stream_packetpeek(&to, &op))) {
      if (ret < 0) continue;
      ogg_to_daala_packet(&dp, &op);
      daala_processing_headers = daala_decode_header_in(&di, &dc, &ds, &dp);
      if (daala_processing_headers < 0) {
        fprintf(stderr, "Error parsing Daala stream headers; "
         "corrupt stream?\n");
        exit(1);
      }
      else if (daala_processing_headers >= 0) {
        /*Advance past the successfully processed header.*/
        ogg_stream_packetout(&to, NULL);
      }
      daala_p++;
    }
    /*Stop now so we don't fail if there aren't enough pages in a short
       stream.*/
    if (!(daala_p && daala_processing_headers)) break;
    /* The header pages/packets will arrive before anything else we
       care about, or the stream is not obeying spec */
    if (ogg_sync_pageout(&oy, &og) > 0) {
      queue_page(&og, &to, daala_p); /* demux into the appropriate stream */
    }
    else {
      if (buffer_data(infile, &oy) == 0) { /* someone needs more data */
        fprintf(stderr, "End of file while searching for codec headers.\n");
        exit(1);
      }
    }
  }
  /* and now we have it all.  initialize decoders */
  if (daala_p) {
    dump_comments(&dc);
    dd = daala_decode_create(&di, ds);
    fprintf(stderr, "Ogg logical stream %lx is Daala %dx%d %.02f fps video\n",
     to.serialno, di.pic_width, di.pic_height,
     di.timebase_numerator/(double)di.timebase_denominator*di.frame_duration);
  }
  else {
    /* tear down the partial daala setup */
    daala_info_clear(&di);
    daala_comment_clear(&dc);
  }
  /*Either way, we're done with the codec setup data.*/
  daala_setup_free(ds);
  if (!raw && outfile) {
    static const char *CHROMA_TYPES[5] = {
      "420jpeg", NULL, "422jpeg", "444", "mono"
    };
    pic_width = di.pic_width;
    pic_height = di.pic_height;
    fps_num = di.timebase_numerator;
    fps_denom = di.timebase_denominator*di.frame_duration;
    if (di.nplanes > 1) {
      /*calculate pixel_fmt based on the xdec & ydec values from one of the
        chroma planes.*/
      if (di.plane_info[1].xdec == 1 && di.plane_info[1].ydec == 1) {
        pix_fmt = 0;
      }
      else if (di.plane_info[1].xdec == 1 && di.plane_info[1].ydec == 0) {
        pix_fmt = 2;
      }
      else if (di.plane_info[1].xdec == 0 && di.plane_info[1].ydec == 0) {
        pix_fmt = 3;
      }
    }
    else {
      pix_fmt = 4;
    }
    if (pix_fmt >= 5 || pix_fmt == 1) {
      fprintf(stderr, "Unknown pixel format: %i\n", pix_fmt);
      exit(1);
    }
    /*Store header information*/
    fprintf(outfile, "YUV4MPEG2 W%d H%d F%d:%d Ip A%d:%d C%s\n",
     pic_width, pic_height, fps_num, fps_denom,
     di.pixel_aspect_numerator, di.pixel_aspect_denominator,
     CHROMA_TYPES[pix_fmt]);
  }
  /* install signal handler */
  signal(SIGINT, sigint_handler);

  /*Finally the main decode loop.

    It's one Daala packet per frame, so this is pretty straightforward if
     we're not trying to maintain sync with other multiplexed streams.

    The videobuf_ready flag is used to maintain the input buffer in the libogg
     stream state.
    If there's no output frame available at the end of the decode step, we must
     need more input data.
    We could simplify this by just using the return code on
     ogg_page_packetout(), but the flag system extends easily to the case where
     you care about more than one multiplexed stream (like with audio
     playback).
    In that case, just maintain a flag for each decoder you care about, and
     pull data when any one of them stalls.*/

  stateflag = 0; /* playback has not begun */
  /* queue any remaining pages from data we buffered but that did not
      contain headers */
  while (ogg_sync_pageout(&oy, &og) > 0) {
    queue_page(&og, &to, daala_p);
  }
  while (!got_sigint) {
    while (daala_p && !videobuf_ready) {
      if (ogg_stream_packetout(&to, &op) > 0) {
        ogg_to_daala_packet(&dp, &op);
        if (daala_decode_packet_in(dd, &dp) >= 0) {
          videobuf_ready = 1;
          frames++;
        }
      }
      else break;
    }
    if (!videobuf_ready && feof(infile)) break;
    if (!videobuf_ready) {
      /* no data yet for somebody.  Grab another page */
      buffer_data(infile, &oy);
      while (ogg_sync_pageout(&oy, &og) > 0) {
        queue_page(&og, &to, daala_p);
      }
    }
    /* dumpvideo frame, and get new one */
    else if (outfile && daala_decode_img_out(dd, &img)) {
      video_write(outfile, &img, raw);
    }
    videobuf_ready = 0;
  }
  /*Flush the output frame buffer of decoder.*/
  while (!got_sigint && daala_decode_img_out(dd, &img)) {
    video_write(outfile, &img, raw);
  }
  /* end of decoder loop -- close everything */
  if (daala_p) {
    ogg_stream_clear(&to);
    daala_decode_free(dd);
    daala_comment_clear(&dc);
    daala_info_clear(&di);
  }
  ogg_sync_clear(&oy);
  if (infile && infile != stdin) fclose(infile);
  if (outfile && outfile != stdout) fclose(outfile);
  fprintf(stderr, "\n\n%d frames\n", frames);
  fprintf(stderr, "\nDone.\n");

  return 0;
}
示例#7
0
文件: encode.c 项目: GGGO/baresip
static int open_encoder(struct videnc_state *ves, const struct vidsz *size)
{
	daala_info di;
	daala_comment dc;
	daala_packet dp;
	int err = 0;
	int complexity = 7;
	int video_q = 30;
	int bitrate = ves->bitrate;

	info("daala: open encoder (%d x %d, %d bps)\n",
	     size->w, size->h, bitrate);

	if (ves->enc) {
		debug("daala: re-opening encoder\n");
		daala_encode_free(ves->enc);
	}

	daala_info_init(&di);
	daala_comment_init(&dc);

	di.pic_width = size->w;
	di.pic_height = size->h;
	di.timebase_numerator = 1;
	di.timebase_denominator = ves->fps;
	di.frame_duration = 1;
	di.pixel_aspect_numerator = -1;
	di.pixel_aspect_denominator = -1;
	di.nplanes = 3;
	di.plane_info[0].xdec = 0;  /* YUV420P */
	di.plane_info[0].ydec = 0;
	di.plane_info[1].xdec = 1;
	di.plane_info[1].ydec = 1;
	di.plane_info[2].xdec = 1;
	di.plane_info[2].ydec = 1;

	di.keyframe_rate = 100;

	info("daala: open encoder with bitstream version %u.%u.%u\n",
	     di.version_major, di.version_minor, di.version_sub);

	ves->enc = daala_encode_create(&di);
	if (!ves->enc) {
		warning("daala: failed to open DAALA encoder\n");
		return ENOMEM;
	}

	daala_encode_ctl(ves->enc, OD_SET_QUANT,
			 &video_q, sizeof(video_q));

	daala_encode_ctl(ves->enc, OD_SET_COMPLEXITY,
			 &complexity, sizeof(complexity));

	daala_encode_ctl(ves->enc, OD_SET_BITRATE,
			 &bitrate, sizeof(bitrate));

	for (;;) {
		int r;

		r = daala_encode_flush_header(ves->enc, &dc, &dp);
		if (r < 0) {
			warning("daala: flush_header returned %d\n", r);
			break;
		}
		else if (r == 0)
			break;

		debug("daala: header: %lld bytes header=%d key=%d\n",
			  dp.bytes,
			  daala_packet_isheader(&dp),
			  daala_packet_iskeyframe(&dp));

#if 0
		re_printf("bos=%lld, eos=%lld, granule=%lld, packetno=%lld\n",
			  dp.b_o_s,
			  dp.e_o_s,
			  dp.granulepos,
			  dp.packetno);
#endif

		err = send_packet(ves, dp.b_o_s, dp.packet, dp.bytes);
		if (err)
			break;
	}

	daala_info_clear(&di);
	daala_comment_clear(&dc);

	return err;
}