Ejemplo n.º 1
0
static void
gst_ffmpegenc_base_init (GstFFMpegEncClass * klass)
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
  AVCodec *in_plugin;
  GstElementDetails details;
  GstPadTemplate *srctempl = NULL, *sinktempl = NULL;
  GstCaps *srccaps = NULL, *sinkcaps = NULL;

  in_plugin =
      (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
      GST_FFENC_PARAMS_QDATA);
  g_assert (in_plugin != NULL);

  /* construct the element details struct */
  details.longname = g_strdup_printf ("FFmpeg %s encoder",
      in_plugin->long_name);
  details.klass = g_strdup_printf ("Codec/Encoder/%s",
      (in_plugin->type == CODEC_TYPE_VIDEO) ? "Video" : "Audio");
  details.description = g_strdup_printf ("FFmpeg %s encoder", in_plugin->name);
  details.author = "Wim Taymans <*****@*****.**>, "
      "Ronald Bultje <*****@*****.**>";
  gst_element_class_set_details (element_class, &details);
  g_free (details.longname);
  g_free (details.klass);
  g_free (details.description);

  if (!(srccaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, TRUE))) {
    GST_DEBUG ("Couldn't get source caps for encoder '%s'", in_plugin->name);
    srccaps = gst_caps_new_simple ("unknown/unknown", NULL);
  }

  if (in_plugin->type == CODEC_TYPE_VIDEO) {
    sinkcaps = gst_caps_from_string
        ("video/x-raw-rgb; video/x-raw-yuv; video/x-raw-gray");
  } else {
    sinkcaps = gst_ffmpeg_codectype_to_audio_caps (NULL,
        in_plugin->id, TRUE, in_plugin);
  }
  if (!sinkcaps) {
    GST_DEBUG ("Couldn't get sink caps for encoder '%s'", in_plugin->name);
    sinkcaps = gst_caps_new_simple ("unknown/unknown", NULL);
  }

  /* pad templates */
  sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
      GST_PAD_ALWAYS, sinkcaps);
  srctempl = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps);

  gst_element_class_add_pad_template (element_class, srctempl);
  gst_element_class_add_pad_template (element_class, sinktempl);

  klass->in_plugin = in_plugin;
  klass->srctempl = srctempl;
  klass->sinktempl = sinktempl;
  klass->sinkcaps = NULL;

  return;
}
Ejemplo n.º 2
0
static void
gst_ffmpegauddec_base_init (GstFFMpegAudDecClass * klass)
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
  GstPadTemplate *sinktempl, *srctempl;
  GstCaps *sinkcaps, *srccaps;
  AVCodec *in_plugin;
  gchar *longname, *description;

  in_plugin =
      (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
      GST_FFDEC_PARAMS_QDATA);
  g_assert (in_plugin != NULL);

  /* construct the element details struct */
  longname = g_strdup_printf ("libav %s decoder", in_plugin->long_name);
  description = g_strdup_printf ("libav %s decoder", in_plugin->name);
  gst_element_class_set_metadata (element_class, longname,
      "Codec/Decoder/Audio", description,
      "Wim Taymans <*****@*****.**>, "
      "Ronald Bultje <*****@*****.**>, "
      "Edward Hervey <*****@*****.**>");
  g_free (longname);
  g_free (description);

  /* get the caps */
  sinkcaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, FALSE);
  if (!sinkcaps) {
    GST_DEBUG ("Couldn't get sink caps for decoder '%s'", in_plugin->name);
    sinkcaps = gst_caps_from_string ("unknown/unknown");
  }
  srccaps = gst_ffmpeg_codectype_to_audio_caps (NULL,
      in_plugin->id, FALSE, in_plugin);
  if (!srccaps) {
    GST_DEBUG ("Couldn't get source caps for decoder '%s'", in_plugin->name);
    srccaps = gst_caps_from_string ("audio/x-raw");
  }

  /* pad templates */
  sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
      GST_PAD_ALWAYS, sinkcaps);
  srctempl = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps);

  gst_element_class_add_pad_template (element_class, srctempl);
  gst_element_class_add_pad_template (element_class, sinktempl);

  gst_caps_unref (sinkcaps);
  gst_caps_unref (srccaps);

  klass->in_plugin = in_plugin;
  klass->srctempl = srctempl;
  klass->sinktempl = sinktempl;
}
Ejemplo n.º 3
0
static void
gst_ffmpegaudenc_base_init (GstFFMpegAudEncClass * klass)
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
  AVCodec *in_plugin;
  GstPadTemplate *srctempl = NULL, *sinktempl = NULL;
  GstCaps *srccaps = NULL, *sinkcaps = NULL;
  gchar *longname, *description;

  in_plugin =
      (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
      GST_FFENC_PARAMS_QDATA);
  g_assert (in_plugin != NULL);

  /* construct the element details struct */
  longname = g_strdup_printf ("libav %s encoder", in_plugin->long_name);
  description = g_strdup_printf ("libav %s encoder", in_plugin->name);
  gst_element_class_set_metadata (element_class, longname,
      "Codec/Encoder/Audio", description,
      "Wim Taymans <*****@*****.**>, "
      "Ronald Bultje <*****@*****.**>");
  g_free (longname);
  g_free (description);

  if (!(srccaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, TRUE))) {
    GST_DEBUG ("Couldn't get source caps for encoder '%s'", in_plugin->name);
    srccaps = gst_caps_new_empty_simple ("unknown/unknown");
  }

  sinkcaps = gst_ffmpeg_codectype_to_audio_caps (NULL,
      in_plugin->id, TRUE, in_plugin);
  if (!sinkcaps) {
    GST_DEBUG ("Couldn't get sink caps for encoder '%s'", in_plugin->name);
    sinkcaps = gst_caps_new_empty_simple ("unknown/unknown");
  }

  /* pad templates */
  sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
      GST_PAD_ALWAYS, sinkcaps);
  srctempl = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps);

  gst_element_class_add_pad_template (element_class, srctempl);
  gst_element_class_add_pad_template (element_class, sinktempl);

  klass->in_plugin = in_plugin;
  klass->srctempl = srctempl;
  klass->sinktempl = sinktempl;

  return;
}
Ejemplo n.º 4
0
static GstCaps *
gst_ffmpegmux_get_id_caps (enum CodecID *id_list)
{
  GstCaps *caps, *t;
  gint i;

  caps = gst_caps_new_empty ();
  for (i = 0; id_list[i] != CODEC_ID_NONE; i++) {
    if ((t = gst_ffmpeg_codecid_to_caps (id_list[i], NULL, TRUE)))
      gst_caps_append (caps, t);
  }
  if (gst_caps_is_empty (caps)) {
    gst_caps_unref (caps);
    return NULL;
  }

  return caps;
}
Ejemplo n.º 5
0
static gboolean
gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info)
{
  GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
  GstCaps *other_caps;
  GstCaps *allowed_caps;
  GstCaps *icaps;
  gsize frame_size;
  GstFFMpegAudEncClass *oclass =
      (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);

  /* close old session */
  if (ffmpegaudenc->opened) {
    gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
    ffmpegaudenc->opened = FALSE;
  }

  /* if we set it in _getcaps we should set it also in _link */
  ffmpegaudenc->context->strict_std_compliance = -1;

  /* user defined properties */
  if (ffmpegaudenc->bitrate > 0) {
    GST_INFO_OBJECT (ffmpegaudenc, "Setting avcontext to bitrate %d",
        ffmpegaudenc->bitrate);
    ffmpegaudenc->context->bit_rate = ffmpegaudenc->bitrate;
    ffmpegaudenc->context->bit_rate_tolerance = ffmpegaudenc->bitrate;
  } else {
    GST_INFO_OBJECT (ffmpegaudenc, "Using avcontext default bitrate %d",
        ffmpegaudenc->context->bit_rate);
  }

  /* RTP payload used for GOB production (for Asterisk) */
  if (ffmpegaudenc->rtp_payload_size) {
    ffmpegaudenc->context->rtp_payload_size = ffmpegaudenc->rtp_payload_size;
  }

  /* some other defaults */
  ffmpegaudenc->context->rc_strategy = 2;
  ffmpegaudenc->context->b_frame_strategy = 0;
  ffmpegaudenc->context->coder_type = 0;
  ffmpegaudenc->context->context_model = 0;
  ffmpegaudenc->context->scenechange_threshold = 0;
  ffmpegaudenc->context->inter_threshold = 0;

  /* fetch pix_fmt and so on */
  gst_ffmpeg_audioinfo_to_context (info, ffmpegaudenc->context);
  if (!ffmpegaudenc->context->time_base.den) {
    ffmpegaudenc->context->time_base.den = GST_AUDIO_INFO_RATE (info);
    ffmpegaudenc->context->time_base.num = 1;
    ffmpegaudenc->context->ticks_per_frame = 1;
  }

  if (ffmpegaudenc->context->channel_layout) {
    gst_ffmpeg_channel_layout_to_gst (ffmpegaudenc->context->channel_layout,
        ffmpegaudenc->context->channels, ffmpegaudenc->ffmpeg_layout);
    ffmpegaudenc->needs_reorder =
        (memcmp (ffmpegaudenc->ffmpeg_layout, info->position,
            sizeof (GstAudioChannelPosition) *
            ffmpegaudenc->context->channels) != 0);
  }

  /* open codec */
  if (gst_ffmpeg_avcodec_open (ffmpegaudenc->context, oclass->in_plugin) < 0) {
    if (ffmpegaudenc->context->priv_data)
      gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
    GST_DEBUG_OBJECT (ffmpegaudenc, "avenc_%s: Failed to open FFMPEG codec",
        oclass->in_plugin->name);
    return FALSE;
  }

  /* some codecs support more than one format, first auto-choose one */
  GST_DEBUG_OBJECT (ffmpegaudenc, "picking an output format ...");
  allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder));
  if (!allowed_caps) {
    GST_DEBUG_OBJECT (ffmpegaudenc, "... but no peer, using template caps");
    /* we need to copy because get_allowed_caps returns a ref, and
     * get_pad_template_caps doesn't */
    allowed_caps =
        gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder));
  }
  GST_DEBUG_OBJECT (ffmpegaudenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
  gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
      oclass->in_plugin->type, allowed_caps, ffmpegaudenc->context);

  /* try to set this caps on the other side */
  other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id,
      ffmpegaudenc->context, TRUE);

  if (!other_caps) {
    gst_caps_unref (allowed_caps);
    gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
    GST_DEBUG ("Unsupported codec - no caps found");
    return FALSE;
  }

  icaps = gst_caps_intersect (allowed_caps, other_caps);
  gst_caps_unref (allowed_caps);
  gst_caps_unref (other_caps);
  if (gst_caps_is_empty (icaps)) {
    gst_caps_unref (icaps);
    return FALSE;
  }
  icaps = gst_caps_truncate (icaps);

  if (!gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (ffmpegaudenc),
          icaps)) {
    gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
    gst_caps_unref (icaps);
    return FALSE;
  }
  gst_caps_unref (icaps);

  frame_size = ffmpegaudenc->context->frame_size;
  if (frame_size > 1) {
    gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc),
        frame_size);
    gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc),
        frame_size);
    gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 1);
  } else {
    gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc),
        0);
    gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc),
        0);
    gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 0);
  }

  /* success! */
  ffmpegaudenc->opened = TRUE;

  return TRUE;
}
Ejemplo n.º 6
0
static gboolean
gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info)
{
    GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
    GstCaps *other_caps;
    GstCaps *allowed_caps;
    GstCaps *icaps;
    gsize frame_size;
    GstFFMpegAudEncClass *oclass =
        (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);

    /* close old session */
    if (ffmpegaudenc->opened) {
        gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
        ffmpegaudenc->opened = FALSE;
        if (avcodec_get_context_defaults3 (ffmpegaudenc->context,
                                           oclass->in_plugin) < 0) {
            GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
            return FALSE;
        }
    }

    /* if we set it in _getcaps we should set it also in _link */
    ffmpegaudenc->context->strict_std_compliance = ffmpegaudenc->compliance;

    /* user defined properties */
    if (ffmpegaudenc->bitrate > 0) {
        GST_INFO_OBJECT (ffmpegaudenc, "Setting avcontext to bitrate %d",
                         ffmpegaudenc->bitrate);
        ffmpegaudenc->context->bit_rate = ffmpegaudenc->bitrate;
        ffmpegaudenc->context->bit_rate_tolerance = ffmpegaudenc->bitrate;
    } else {
        GST_INFO_OBJECT (ffmpegaudenc,
                         "Using avcontext default bitrate %" G_GINT64_FORMAT,
                         (gint64) ffmpegaudenc->context->bit_rate);
    }

    /* RTP payload used for GOB production (for Asterisk) */
    if (ffmpegaudenc->rtp_payload_size) {
        ffmpegaudenc->context->rtp_payload_size = ffmpegaudenc->rtp_payload_size;
    }

    /* some other defaults */
    ffmpegaudenc->context->rc_strategy = 2;
    ffmpegaudenc->context->b_frame_strategy = 0;
    ffmpegaudenc->context->coder_type = 0;
    ffmpegaudenc->context->context_model = 0;
    ffmpegaudenc->context->scenechange_threshold = 0;

    /* fetch pix_fmt and so on */
    gst_ffmpeg_audioinfo_to_context (info, ffmpegaudenc->context);
    if (!ffmpegaudenc->context->time_base.den) {
        ffmpegaudenc->context->time_base.den = GST_AUDIO_INFO_RATE (info);
        ffmpegaudenc->context->time_base.num = 1;
        ffmpegaudenc->context->ticks_per_frame = 1;
    }

    if (ffmpegaudenc->context->channel_layout) {
        gst_ffmpeg_channel_layout_to_gst (ffmpegaudenc->context->channel_layout,
                                          ffmpegaudenc->context->channels, ffmpegaudenc->ffmpeg_layout);
        ffmpegaudenc->needs_reorder =
            (memcmp (ffmpegaudenc->ffmpeg_layout, info->position,
                     sizeof (GstAudioChannelPosition) *
                     ffmpegaudenc->context->channels) != 0);
    }

    /* some codecs support more than one format, first auto-choose one */
    GST_DEBUG_OBJECT (ffmpegaudenc, "picking an output format ...");
    allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder));
    if (!allowed_caps) {
        GST_DEBUG_OBJECT (ffmpegaudenc, "... but no peer, using template caps");
        /* we need to copy because get_allowed_caps returns a ref, and
         * get_pad_template_caps doesn't */
        allowed_caps =
            gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder));
    }
    GST_DEBUG_OBJECT (ffmpegaudenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
    gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
                                  oclass->in_plugin->type, allowed_caps, ffmpegaudenc->context);

    /* open codec */
    if (gst_ffmpeg_avcodec_open (ffmpegaudenc->context, oclass->in_plugin) < 0) {
        gst_caps_unref (allowed_caps);
        gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
        GST_DEBUG_OBJECT (ffmpegaudenc, "avenc_%s: Failed to open FFMPEG codec",
                          oclass->in_plugin->name);
        if (avcodec_get_context_defaults3 (ffmpegaudenc->context,
                                           oclass->in_plugin) < 0)
            GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");

        if ((oclass->in_plugin->capabilities & CODEC_CAP_EXPERIMENTAL) &&
                ffmpegaudenc->compliance != GST_FFMPEG_EXPERIMENTAL) {
            GST_ELEMENT_ERROR (ffmpegaudenc, LIBRARY, SETTINGS,
                               ("Codec is experimental, but settings don't allow encoders to "
                                "produce output of experimental quality"),
                               ("This codec may not create output that is conformant to the specs "
                                "or of good quality. If you must use it anyway, set the "
                                "compliance property to experimental"));
        }
        return FALSE;
    }

    /* try to set this caps on the other side */
    other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id,
                 ffmpegaudenc->context, TRUE);

    if (!other_caps) {
        gst_caps_unref (allowed_caps);
        gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
        GST_DEBUG ("Unsupported codec - no caps found");
        if (avcodec_get_context_defaults3 (ffmpegaudenc->context,
                                           oclass->in_plugin) < 0)
            GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
        return FALSE;
    }

    icaps = gst_caps_intersect (allowed_caps, other_caps);
    gst_caps_unref (allowed_caps);
    gst_caps_unref (other_caps);
    if (gst_caps_is_empty (icaps)) {
        gst_caps_unref (icaps);
        return FALSE;
    }
    icaps = gst_caps_fixate (icaps);

    if (!gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (ffmpegaudenc),
            icaps)) {
        gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
        gst_caps_unref (icaps);
        if (avcodec_get_context_defaults3 (ffmpegaudenc->context,
                                           oclass->in_plugin) < 0)
            GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
        return FALSE;
    }
    gst_caps_unref (icaps);

    frame_size = ffmpegaudenc->context->frame_size;
    if (frame_size > 1) {
        gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc),
                frame_size);
        gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc),
                frame_size);
        gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 1);
    } else {
        gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc),
                0);
        gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc),
                0);
        gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 0);
    }

    /* Store some tags */
    {
        GstTagList *tags = gst_tag_list_new_empty ();
        const gchar *codec;

        gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
                          (guint) ffmpegaudenc->context->bit_rate, NULL);

        if ((codec =
                    gst_ffmpeg_get_codecid_longname (ffmpegaudenc->context->codec_id)))
            gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, codec,
                              NULL);

        gst_audio_encoder_merge_tags (encoder, tags, GST_TAG_MERGE_REPLACE);
        gst_tag_list_unref (tags);
    }

    /* success! */
    ffmpegaudenc->opened = TRUE;

    return TRUE;
}
Ejemplo n.º 7
0
static gboolean
gst_ffmpegenc_setcaps (GstPad * pad, GstCaps * caps)
{
  GstCaps *other_caps;
  GstCaps *allowed_caps;
  GstCaps *icaps;
  enum PixelFormat pix_fmt;
  GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) GST_PAD_PARENT (pad);
  GstFFMpegEncClass *oclass =
      (GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);

  /* close old session */
  if (ffmpegenc->opened) {
    gst_ffmpeg_avcodec_close (ffmpegenc->context);
    ffmpegenc->opened = FALSE;
  }

  /* set defaults */
  avcodec_get_context_defaults (ffmpegenc->context);

  /* if we set it in _getcaps we should set it also in _link */
  ffmpegenc->context->strict_std_compliance = -1;

  /* user defined properties */
  ffmpegenc->context->bit_rate = ffmpegenc->bitrate;
  ffmpegenc->context->bit_rate_tolerance = ffmpegenc->bitrate;
  ffmpegenc->context->gop_size = ffmpegenc->gop_size;
  ffmpegenc->context->me_method = ffmpegenc->me_method;
  GST_DEBUG_OBJECT (ffmpegenc, "Setting avcontext to bitrate %lu, gop_size %d",
      ffmpegenc->bitrate, ffmpegenc->gop_size);

  /* RTP payload used for GOB production (for Asterisk) */
  if (ffmpegenc->rtp_payload_size) {
    ffmpegenc->context->rtp_payload_size = ffmpegenc->rtp_payload_size;
  }

  /* additional avcodec settings */
  /* first fill in the majority by copying over */
  gst_ffmpeg_cfg_fill_context (ffmpegenc, ffmpegenc->context);

  /* then handle some special cases */
  ffmpegenc->context->lmin = (ffmpegenc->lmin * FF_QP2LAMBDA + 0.5);
  ffmpegenc->context->lmax = (ffmpegenc->lmax * FF_QP2LAMBDA + 0.5);

  if (ffmpegenc->interlaced) {
    ffmpegenc->context->flags |=
        CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME;
    ffmpegenc->picture->interlaced_frame = TRUE;
    /* if this is not the case, a filter element should be used to swap fields */
    ffmpegenc->picture->top_field_first = TRUE;
  }

  /* some other defaults */
  ffmpegenc->context->rc_strategy = 2;
  ffmpegenc->context->b_frame_strategy = 0;
  ffmpegenc->context->coder_type = 0;
  ffmpegenc->context->context_model = 0;
  ffmpegenc->context->scenechange_threshold = 0;
  ffmpegenc->context->inter_threshold = 0;

  /* and last but not least the pass; CBR, 2-pass, etc */
  ffmpegenc->context->flags |= ffmpegenc->pass;
  switch (ffmpegenc->pass) {
      /* some additional action depends on type of pass */
    case CODEC_FLAG_QSCALE:
      ffmpegenc->context->global_quality
          = ffmpegenc->picture->quality = FF_QP2LAMBDA * ffmpegenc->quantizer;
      break;
    case CODEC_FLAG_PASS1:     /* need to prepare a stats file */
      /* we don't close when changing caps, fingers crossed */
      if (!ffmpegenc->file)
        ffmpegenc->file = g_fopen (ffmpegenc->filename, "w");
      if (!ffmpegenc->file) {
        GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, OPEN_WRITE,
            (("Could not open file \"%s\" for writing."), ffmpegenc->filename),
            GST_ERROR_SYSTEM);
        return FALSE;
      }
      break;
    case CODEC_FLAG_PASS2:
    {                           /* need to read the whole stats file ! */
      gsize size;

      if (!g_file_get_contents (ffmpegenc->filename,
              &ffmpegenc->context->stats_in, &size, NULL)) {
        GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, READ,
            (("Could not get contents of file \"%s\"."), ffmpegenc->filename),
            GST_ERROR_SYSTEM);
        return FALSE;
      }

      break;
    }
    default:
      break;
  }

  /* fetch pix_fmt and so on */
  gst_ffmpeg_caps_with_codectype (oclass->in_plugin->type,
      caps, ffmpegenc->context);
  if (!ffmpegenc->context->time_base.den) {
    ffmpegenc->context->time_base.den = 25;
    ffmpegenc->context->time_base.num = 1;
    ffmpegenc->context->ticks_per_frame = 1;
  } else if ((oclass->in_plugin->id == CODEC_ID_MPEG4)
      && (ffmpegenc->context->time_base.den > 65535)) {
    /* MPEG4 Standards do not support time_base denominator greater than
     * (1<<16) - 1 . We therefore scale them down.
     * Agreed, it will not be the exact framerate... but the difference
     * shouldn't be that noticeable */
    ffmpegenc->context->time_base.num =
        (gint) gst_util_uint64_scale_int (ffmpegenc->context->time_base.num,
        65535, ffmpegenc->context->time_base.den);
    ffmpegenc->context->time_base.den = 65535;
    GST_LOG_OBJECT (ffmpegenc, "MPEG4 : scaled down framerate to %d / %d",
        ffmpegenc->context->time_base.den, ffmpegenc->context->time_base.num);
  }

  pix_fmt = ffmpegenc->context->pix_fmt;

  /* max-key-interval may need the framerate set above */
  if (ffmpegenc->max_key_interval) {
    AVCodecContext *ctx;

    /* override gop-size */
    ctx = ffmpegenc->context;
    ctx->gop_size = (ffmpegenc->max_key_interval < 0) ?
        (-ffmpegenc->max_key_interval
        * (ctx->time_base.den * ctx->ticks_per_frame / ctx->time_base.num))
        : ffmpegenc->max_key_interval;
  }

  /* open codec */
  if (gst_ffmpeg_avcodec_open (ffmpegenc->context, oclass->in_plugin) < 0) {
    if (ffmpegenc->context->priv_data)
      gst_ffmpeg_avcodec_close (ffmpegenc->context);
    if (ffmpegenc->context->stats_in)
      g_free (ffmpegenc->context->stats_in);
    GST_DEBUG_OBJECT (ffmpegenc, "ffenc_%s: Failed to open FFMPEG codec",
        oclass->in_plugin->name);
    return FALSE;
  }

  /* second pass stats buffer no longer needed */
  if (ffmpegenc->context->stats_in)
    g_free (ffmpegenc->context->stats_in);

  /* is the colourspace correct? */
  if (pix_fmt != ffmpegenc->context->pix_fmt) {
    gst_ffmpeg_avcodec_close (ffmpegenc->context);
    GST_DEBUG_OBJECT (ffmpegenc,
        "ffenc_%s: AV wants different colourspace (%d given, %d wanted)",
        oclass->in_plugin->name, pix_fmt, ffmpegenc->context->pix_fmt);
    return FALSE;
  }
  /* we may have failed mapping caps to a pixfmt,
   * and quite some codecs do not make up their own mind about that
   * in any case, _NONE can never work out later on */
  if (oclass->in_plugin->type == CODEC_TYPE_VIDEO && pix_fmt == PIX_FMT_NONE) {
    GST_DEBUG_OBJECT (ffmpegenc, "ffenc_%s: Failed to determine input format",
        oclass->in_plugin->name);
    return FALSE;
  }

  /* some codecs support more than one format, first auto-choose one */
  GST_DEBUG_OBJECT (ffmpegenc, "picking an output format ...");
  allowed_caps = gst_pad_get_allowed_caps (ffmpegenc->srcpad);
  if (!allowed_caps) {
    GST_DEBUG_OBJECT (ffmpegenc, "... but no peer, using template caps");
    /* we need to copy because get_allowed_caps returns a ref, and
     * get_pad_template_caps doesn't */
    allowed_caps =
        gst_caps_copy (gst_pad_get_pad_template_caps (ffmpegenc->srcpad));
  }
  GST_DEBUG_OBJECT (ffmpegenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
  gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
      oclass->in_plugin->type, allowed_caps, ffmpegenc->context);

  /* try to set this caps on the other side */
  other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id,
      ffmpegenc->context, TRUE);

  if (!other_caps) {
    gst_ffmpeg_avcodec_close (ffmpegenc->context);
    GST_DEBUG ("Unsupported codec - no caps found");
    return FALSE;
  }

  icaps = gst_caps_intersect (allowed_caps, other_caps);
  gst_caps_unref (allowed_caps);
  gst_caps_unref (other_caps);
  if (gst_caps_is_empty (icaps)) {
    gst_caps_unref (icaps);
    return FALSE;
  }

  if (gst_caps_get_size (icaps) > 1) {
    GstCaps *newcaps;

    newcaps =
        gst_caps_new_full (gst_structure_copy (gst_caps_get_structure (icaps,
                0)), NULL);
    gst_caps_unref (icaps);
    icaps = newcaps;
  }

  if (!gst_pad_set_caps (ffmpegenc->srcpad, icaps)) {
    gst_ffmpeg_avcodec_close (ffmpegenc->context);
    gst_caps_unref (icaps);
    return FALSE;
  }
  gst_caps_unref (icaps);

  /* success! */
  ffmpegenc->opened = TRUE;

  return TRUE;
}
Ejemplo n.º 8
0
static gboolean
gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder,
                             GstVideoCodecState * state)
{
    GstCaps *other_caps;
    GstCaps *allowed_caps;
    GstCaps *icaps;
    GstVideoCodecState *output_format;
    enum AVPixelFormat pix_fmt;
    GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
    GstFFMpegVidEncClass *oclass =
        (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);

    /* close old session */
    if (ffmpegenc->opened) {
        gst_ffmpeg_avcodec_close (ffmpegenc->context);
        ffmpegenc->opened = FALSE;
        if (avcodec_get_context_defaults3 (ffmpegenc->context,
                                           oclass->in_plugin) < 0) {
            GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults");
            return FALSE;
        }
    }

    /* if we set it in _getcaps we should set it also in _link */
    ffmpegenc->context->strict_std_compliance = ffmpegenc->compliance;

    /* user defined properties */
    ffmpegenc->context->bit_rate = ffmpegenc->bitrate;
    ffmpegenc->context->bit_rate_tolerance = ffmpegenc->bitrate;
    ffmpegenc->context->gop_size = ffmpegenc->gop_size;
    ffmpegenc->context->me_method = ffmpegenc->me_method;
    GST_DEBUG_OBJECT (ffmpegenc, "Setting avcontext to bitrate %d, gop_size %d",
                      ffmpegenc->bitrate, ffmpegenc->gop_size);

    if (ffmpegenc->max_threads == 0) {
        if (!(oclass->in_plugin->capabilities & CODEC_CAP_AUTO_THREADS))
            ffmpegenc->context->thread_count = gst_ffmpeg_auto_max_threads ();
        else
            ffmpegenc->context->thread_count = 0;
    } else
        ffmpegenc->context->thread_count = ffmpegenc->max_threads;

    /* RTP payload used for GOB production (for Asterisk) */
    if (ffmpegenc->rtp_payload_size) {
        ffmpegenc->context->rtp_payload_size = ffmpegenc->rtp_payload_size;
    }

    /* additional avcodec settings */
    /* first fill in the majority by copying over */
    gst_ffmpeg_cfg_fill_context (ffmpegenc, ffmpegenc->context);

    /* then handle some special cases */
    ffmpegenc->context->lmin = (ffmpegenc->lmin * FF_QP2LAMBDA + 0.5);
    ffmpegenc->context->lmax = (ffmpegenc->lmax * FF_QP2LAMBDA + 0.5);

    if (ffmpegenc->interlaced) {
        ffmpegenc->context->flags |=
            CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME;
    }

    /* some other defaults */
    ffmpegenc->context->rc_strategy = 2;
    ffmpegenc->context->b_frame_strategy = 0;
    ffmpegenc->context->coder_type = 0;
    ffmpegenc->context->context_model = 0;
    ffmpegenc->context->scenechange_threshold = 0;

    /* and last but not least the pass; CBR, 2-pass, etc */
    ffmpegenc->context->flags |= ffmpegenc->pass;
    switch (ffmpegenc->pass) {
    /* some additional action depends on type of pass */
    case CODEC_FLAG_QSCALE:
        ffmpegenc->context->global_quality
            = ffmpegenc->picture->quality = FF_QP2LAMBDA * ffmpegenc->quantizer;
        break;
    case CODEC_FLAG_PASS1:     /* need to prepare a stats file */
        /* we don't close when changing caps, fingers crossed */
        if (!ffmpegenc->file)
            ffmpegenc->file = g_fopen (ffmpegenc->filename, "w");
        if (!ffmpegenc->file)
            goto open_file_err;
        break;
    case CODEC_FLAG_PASS2:
    {   /* need to read the whole stats file ! */
        gsize size;

        if (!g_file_get_contents (ffmpegenc->filename,
                                  &ffmpegenc->context->stats_in, &size, NULL))
            goto file_read_err;

        break;
    }
    default:
        break;
    }

    GST_DEBUG_OBJECT (ffmpegenc, "Extracting common video information");
    /* fetch pix_fmt, fps, par, width, height... */
    gst_ffmpeg_videoinfo_to_context (&state->info, ffmpegenc->context);

    /* sanitize time base */
    if (ffmpegenc->context->time_base.num <= 0
            || ffmpegenc->context->time_base.den <= 0)
        goto insane_timebase;

    if ((oclass->in_plugin->id == AV_CODEC_ID_MPEG4)
            && (ffmpegenc->context->time_base.den > 65535)) {
        /* MPEG4 Standards do not support time_base denominator greater than
         * (1<<16) - 1 . We therefore scale them down.
         * Agreed, it will not be the exact framerate... but the difference
         * shouldn't be that noticeable */
        ffmpegenc->context->time_base.num =
            (gint) gst_util_uint64_scale_int (ffmpegenc->context->time_base.num,
                                              65535, ffmpegenc->context->time_base.den);
        ffmpegenc->context->time_base.den = 65535;
        GST_LOG_OBJECT (ffmpegenc, "MPEG4 : scaled down framerate to %d / %d",
                        ffmpegenc->context->time_base.den, ffmpegenc->context->time_base.num);
    }

    pix_fmt = ffmpegenc->context->pix_fmt;

    /* max-key-interval may need the framerate set above */
    if (ffmpegenc->max_key_interval) {
        AVCodecContext *ctx;

        /* override gop-size */
        ctx = ffmpegenc->context;
        ctx->gop_size = (ffmpegenc->max_key_interval < 0) ?
                        (-ffmpegenc->max_key_interval
                         * (ctx->time_base.den * ctx->ticks_per_frame / ctx->time_base.num))
                        : ffmpegenc->max_key_interval;
    }

    /* some codecs support more than one format, first auto-choose one */
    GST_DEBUG_OBJECT (ffmpegenc, "picking an output format ...");
    allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
    if (!allowed_caps) {
        GST_DEBUG_OBJECT (ffmpegenc, "... but no peer, using template caps");
        /* we need to copy because get_allowed_caps returns a ref, and
         * get_pad_template_caps doesn't */
        allowed_caps =
            gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
    }
    GST_DEBUG_OBJECT (ffmpegenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
    gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
                                  oclass->in_plugin->type, allowed_caps, ffmpegenc->context);

    /* open codec */
    if (gst_ffmpeg_avcodec_open (ffmpegenc->context, oclass->in_plugin) < 0) {
        gst_caps_unref (allowed_caps);
        goto open_codec_fail;
    }

    /* is the colourspace correct? */
    if (pix_fmt != ffmpegenc->context->pix_fmt) {
        gst_caps_unref (allowed_caps);
        goto pix_fmt_err;
    }

    /* we may have failed mapping caps to a pixfmt,
     * and quite some codecs do not make up their own mind about that
     * in any case, _NONE can never work out later on */
    if (pix_fmt == AV_PIX_FMT_NONE) {
        gst_caps_unref (allowed_caps);
        goto bad_input_fmt;
    }

    /* second pass stats buffer no longer needed */
    g_free (ffmpegenc->context->stats_in);

    /* try to set this caps on the other side */
    other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id,
                 ffmpegenc->context, TRUE);

    if (!other_caps) {
        gst_caps_unref (allowed_caps);
        goto unsupported_codec;
    }

    icaps = gst_caps_intersect (allowed_caps, other_caps);
    gst_caps_unref (allowed_caps);
    gst_caps_unref (other_caps);
    if (gst_caps_is_empty (icaps)) {
        gst_caps_unref (icaps);
        goto unsupported_codec;
    }
    icaps = gst_caps_fixate (icaps);

    GST_DEBUG_OBJECT (ffmpegenc, "codec flags 0x%08x", ffmpegenc->context->flags);

    /* Store input state and set output state */
    if (ffmpegenc->input_state)
        gst_video_codec_state_unref (ffmpegenc->input_state);
    ffmpegenc->input_state = gst_video_codec_state_ref (state);

    output_format = gst_video_encoder_set_output_state (encoder, icaps, state);
    gst_video_codec_state_unref (output_format);

    /* Store some tags */
    {
        GstTagList *tags = gst_tag_list_new_empty ();
        const gchar *codec;

        gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
                          (guint) ffmpegenc->context->bit_rate, NULL);

        if ((codec =
                    gst_ffmpeg_get_codecid_longname (ffmpegenc->context->codec_id)))
            gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_VIDEO_CODEC, codec,
                              NULL);

        gst_video_encoder_merge_tags (encoder, tags, GST_TAG_MERGE_REPLACE);
        gst_tag_list_unref (tags);
    }

    /* success! */
    ffmpegenc->opened = TRUE;

    return TRUE;

    /* ERRORS */
open_file_err:
    {
        GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, OPEN_WRITE,
                           (("Could not open file \"%s\" for writing."), ffmpegenc->filename),
                           GST_ERROR_SYSTEM);
        return FALSE;
    }
file_read_err:
    {
        GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, READ,
                           (("Could not get contents of file \"%s\"."), ffmpegenc->filename),
                           GST_ERROR_SYSTEM);
        return FALSE;
    }

insane_timebase:
    {
        GST_ERROR_OBJECT (ffmpegenc, "Rejecting time base %d/%d",
                          ffmpegenc->context->time_base.den, ffmpegenc->context->time_base.num);
        goto cleanup_stats_in;
    }
unsupported_codec:
    {
        GST_DEBUG ("Unsupported codec - no caps found");
        goto cleanup_stats_in;
    }
open_codec_fail:
    {
        GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to open libav codec",
                          oclass->in_plugin->name);
        goto close_codec;
    }

pix_fmt_err:
    {
        GST_DEBUG_OBJECT (ffmpegenc,
                          "avenc_%s: AV wants different colourspace (%d given, %d wanted)",
                          oclass->in_plugin->name, pix_fmt, ffmpegenc->context->pix_fmt);
        goto close_codec;
    }

bad_input_fmt:
    {
        GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to determine input format",
                          oclass->in_plugin->name);
        goto close_codec;
    }
close_codec:
    {
        gst_ffmpeg_avcodec_close (ffmpegenc->context);
        if (avcodec_get_context_defaults3 (ffmpegenc->context,
                                           oclass->in_plugin) < 0)
            GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults");
        goto cleanup_stats_in;
    }
cleanup_stats_in:
    {
        g_free (ffmpegenc->context->stats_in);
        return FALSE;
    }
}