~ubuntu-branches/ubuntu/intrepid/gstreamer0.10-ffmpeg/intrepid

« back to all changes in this revision

Viewing changes to ext/ffmpeg/gstffmpegenc.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Dröge
  • Date: 2006-12-13 23:10:28 UTC
  • mto: This revision was merged to the branch mainline in revision 10.
  • Revision ID: james.westby@ubuntu.com-20061213231028-9vl0epppqnwbq78i
Tags: upstream-0.10.2
Import upstream version 0.10.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
 
24
24
#include <assert.h>
25
25
#include <string.h>
 
26
/* for stats file handling */
 
27
#include <stdio.h>
 
28
#include <glib/gstdio.h>
 
29
#include <errno.h>
26
30
 
27
31
#ifdef HAVE_FFMPEG_UNINSTALLED
28
32
#include <avcodec.h>
34
38
 
35
39
#include "gstffmpeg.h"
36
40
#include "gstffmpegcodecmap.h"
 
41
#include "gstffmpegenc.h"
 
42
#include "gstffmpegcfg.h"
37
43
 
38
 
#define DEFAULT_VIDEO_BITRATE 300000 /* in bps */
 
44
#define DEFAULT_VIDEO_BITRATE 300000    /* in bps */
39
45
#define DEFAULT_VIDEO_GOP_SIZE 15
40
46
#define DEFAULT_AUDIO_BITRATE 128000
41
47
 
42
48
#define DEFAULT_WIDTH 352
43
49
#define DEFAULT_HEIGHT 288
44
50
 
45
 
typedef struct _GstFFMpegEnc GstFFMpegEnc;
46
 
 
47
 
struct _GstFFMpegEnc
48
 
{
49
 
  GstElement element;
50
 
 
51
 
  /* We need to keep track of our pads, so we do so here. */
52
 
  GstPad *srcpad;
53
 
  GstPad *sinkpad;
54
 
 
55
 
  AVCodecContext *context;
56
 
  AVFrame *picture;
57
 
  gboolean opened;
58
 
  GstBuffer *cache;
59
 
 
60
 
  /* cache */
61
 
  gulong bitrate;
62
 
  gint me_method;
63
 
  gint gop_size;
64
 
  gulong buffer_size;
65
 
  gulong rtp_payload_size;
66
 
};
67
 
 
68
 
typedef struct _GstFFMpegEncClass GstFFMpegEncClass;
69
 
 
70
 
struct _GstFFMpegEncClass
71
 
{
72
 
  GstElementClass parent_class;
73
 
 
74
 
  AVCodec *in_plugin;
75
 
  GstPadTemplate *srctempl, *sinktempl;
76
 
  GstCaps *sinkcaps;
77
 
};
78
 
 
79
 
typedef struct
80
 
{
81
 
  AVCodec *in_plugin;
82
 
  GstCaps *srccaps, *sinkcaps;
83
 
} GstFFMpegEncClassParams;
84
 
 
85
 
#define GST_TYPE_FFMPEGENC \
86
 
  (gst_ffmpegenc_get_type())
87
 
#define GST_FFMPEGENC(obj) \
88
 
  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGENC,GstFFMpegEnc))
89
 
#define GST_FFMPEGENC_CLASS(klass) \
90
 
  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGENC,GstFFMpegEncClass))
91
 
#define GST_IS_FFMPEGENC(obj) \
92
 
  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGENC))
93
 
#define GST_IS_FFMPEGENC_CLASS(obj) \
94
 
  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGENC))
95
51
 
96
52
#define VIDEO_BUFFER_SIZE (1024*1024)
97
53
 
108
64
  ARG_GOP_SIZE,
109
65
  ARG_ME_METHOD,
110
66
  ARG_BUFSIZE,
111
 
  ARG_RTP_PAYLOAD_SIZE
112
 
  /* FILL ME */
 
67
  ARG_RTP_PAYLOAD_SIZE,
 
68
  ARG_CFG_BASE
113
69
};
114
70
 
115
71
#define GST_TYPE_ME_METHOD (gst_ffmpegenc_me_method_get_type())
142
98
static void gst_ffmpegenc_dispose (GObject * object);
143
99
 
144
100
static gboolean gst_ffmpegenc_setcaps (GstPad * pad, GstCaps * caps);
145
 
static GstCaps * gst_ffmpegenc_getcaps (GstPad * pad);
146
 
static GstFlowReturn gst_ffmpegenc_chain_video (GstPad * pad, GstBuffer *buffer);
147
 
static GstFlowReturn gst_ffmpegenc_chain_audio (GstPad * pad, GstBuffer *buffer);
 
101
static GstCaps *gst_ffmpegenc_getcaps (GstPad * pad);
 
102
static GstFlowReturn gst_ffmpegenc_chain_video (GstPad * pad,
 
103
    GstBuffer * buffer);
 
104
static GstFlowReturn gst_ffmpegenc_chain_audio (GstPad * pad,
 
105
    GstBuffer * buffer);
 
106
static gboolean gst_ffmpegenc_event_video (GstPad * pad, GstEvent * event);
148
107
 
149
108
static void gst_ffmpegenc_set_property (GObject * object,
150
109
    guint prop_id, const GValue * value, GParamSpec * pspec);
213
172
  gobject_class = (GObjectClass *) klass;
214
173
  gstelement_class = (GstElementClass *) klass;
215
174
 
216
 
  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
 
175
  parent_class = g_type_class_peek_parent (klass);
217
176
 
218
177
  gobject_class->set_property = gst_ffmpegenc_set_property;
219
178
  gobject_class->get_property = gst_ffmpegenc_get_property;
221
180
  if (klass->in_plugin->type == CODEC_TYPE_VIDEO) {
222
181
    g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BIT_RATE,
223
182
        g_param_spec_ulong ("bitrate", "Bit Rate",
224
 
            "Target Video Bitrate", 0, G_MAXULONG, DEFAULT_VIDEO_BITRATE, G_PARAM_READWRITE));
 
183
            "Target Video Bitrate", 0, G_MAXULONG, DEFAULT_VIDEO_BITRATE,
 
184
            G_PARAM_READWRITE));
225
185
    g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_GOP_SIZE,
226
186
        g_param_spec_int ("gop_size", "GOP Size",
227
 
            "Number of frames within one GOP",
228
 
            0, G_MAXINT, DEFAULT_VIDEO_GOP_SIZE, G_PARAM_READWRITE));
 
187
            "Number of frames within one GOP", 0, G_MAXINT,
 
188
            DEFAULT_VIDEO_GOP_SIZE, G_PARAM_READWRITE));
229
189
    g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ME_METHOD,
230
 
        g_param_spec_enum ("me_method", "ME Method",
231
 
            "Motion Estimation Method",
232
 
            GST_TYPE_ME_METHOD, ME_LOG, G_PARAM_READWRITE));
 
190
        g_param_spec_enum ("me_method", "ME Method", "Motion Estimation Method",
 
191
            GST_TYPE_ME_METHOD, ME_EPZS, G_PARAM_READWRITE));
233
192
    g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFSIZE,
234
193
        g_param_spec_ulong ("buffer_size", "Buffer Size",
235
194
            "Size of the video buffers", 0, G_MAXULONG, 0, G_PARAM_READWRITE));
236
195
    g_object_class_install_property (G_OBJECT_CLASS (klass),
237
 
        ARG_RTP_PAYLOAD_SIZE,
238
 
        g_param_spec_ulong ("rtp_payload_size", "RTP Payload Size",
239
 
            "Target GOB length", 0, G_MAXULONG, 0, G_PARAM_READWRITE));
 
196
        ARG_RTP_PAYLOAD_SIZE, g_param_spec_ulong ("rtp_payload_size",
 
197
            "RTP Payload Size", "Target GOB length", 0, G_MAXULONG, 0,
 
198
            G_PARAM_READWRITE));
 
199
 
 
200
    /* register additional properties, possibly dependent on the exact CODEC */
 
201
    gst_ffmpeg_cfg_install_property (klass, ARG_CFG_BASE);
240
202
  } else if (klass->in_plugin->type == CODEC_TYPE_AUDIO) {
241
203
    g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BIT_RATE,
242
204
        g_param_spec_ulong ("bitrate", "Bit Rate",
243
 
            "Target Audio Bitrate", 0, G_MAXULONG, DEFAULT_AUDIO_BITRATE, G_PARAM_READWRITE));
 
205
            "Target Audio Bitrate", 0, G_MAXULONG, DEFAULT_AUDIO_BITRATE,
 
206
            G_PARAM_READWRITE));
244
207
  }
245
208
 
246
209
  gstelement_class->change_state = gst_ffmpegenc_change_state;
266
229
  ffmpegenc->picture = avcodec_alloc_frame ();
267
230
  ffmpegenc->opened = FALSE;
268
231
 
 
232
  ffmpegenc->file = NULL;
 
233
  ffmpegenc->delay = g_queue_new ();
 
234
 
269
235
  if (oclass->in_plugin->type == CODEC_TYPE_VIDEO) {
270
236
    gst_pad_set_chain_function (ffmpegenc->sinkpad, gst_ffmpegenc_chain_video);
 
237
    /* so we know when to flush the buffers on EOS */
 
238
    gst_pad_set_event_function (ffmpegenc->sinkpad, gst_ffmpegenc_event_video);
271
239
 
272
240
    ffmpegenc->bitrate = DEFAULT_VIDEO_BITRATE;
 
241
    ffmpegenc->me_method = ME_EPZS;
273
242
    ffmpegenc->buffer_size = 512 * 1024;
274
243
    ffmpegenc->gop_size = DEFAULT_VIDEO_GOP_SIZE;
275
244
    ffmpegenc->rtp_payload_size = 0;
 
245
 
 
246
    ffmpegenc->lmin = 2;
 
247
    ffmpegenc->lmax = 31;
 
248
    ffmpegenc->max_key_interval = 0;
 
249
 
 
250
    gst_ffmpeg_cfg_set_defaults (ffmpegenc);
276
251
  } else if (oclass->in_plugin->type == CODEC_TYPE_AUDIO) {
277
252
    gst_pad_set_chain_function (ffmpegenc->sinkpad, gst_ffmpegenc_chain_audio);
278
253
 
298
273
  av_free (ffmpegenc->context);
299
274
  av_free (ffmpegenc->picture);
300
275
 
 
276
  g_queue_free (ffmpegenc->delay);
 
277
  g_free (ffmpegenc->filename);
 
278
 
301
279
  G_OBJECT_CLASS (parent_class)->dispose (object);
302
280
}
303
281
 
336
314
  /* makes it silent */
337
315
  ctx->strict_std_compliance = -1;
338
316
 
339
 
   /* shut up the logging while we autoprobe; we don't want warnings and
340
 
    * errors about unsupported formats */
341
 
   /* FIXME: if someone cares about this disabling the logging for other
342
 
    * instances/threads/..., one could investigate if there is a way to
343
 
    * set this as a struct member on the av context, and check it from the
344
 
    * log handler */
 
317
  /* shut up the logging while we autoprobe; we don't want warnings and
 
318
   * errors about unsupported formats */
 
319
  /* FIXME: if someone cares about this disabling the logging for other
 
320
   * instances/threads/..., one could investigate if there is a way to
 
321
   * set this as a struct member on the av context, and check it from the
 
322
   * log handler */
345
323
#ifndef GST_DISABLE_GST_DEBUG
346
324
  _shut_up_I_am_probing = TRUE;
347
325
#endif
348
326
  for (pixfmt = 0; pixfmt < PIX_FMT_NB; pixfmt++) {
 
327
    GstCaps *tmpcaps;
 
328
 
349
329
    ctx->pix_fmt = pixfmt;
350
330
    if (gst_ffmpeg_avcodec_open (ctx, oclass->in_plugin) >= 0 &&
351
331
        ctx->pix_fmt == pixfmt) {
352
332
      ctx->width = -1;
353
333
      if (!caps)
354
334
        caps = gst_caps_new_empty ();
355
 
      gst_caps_append (caps,
356
 
          gst_ffmpeg_codectype_to_caps (oclass->in_plugin->type, ctx));
 
335
      tmpcaps = gst_ffmpeg_codectype_to_caps (oclass->in_plugin->type, ctx);
 
336
      if (tmpcaps)
 
337
        gst_caps_append (caps, tmpcaps);
 
338
      else
 
339
        GST_LOG_OBJECT (ffmpegenc,
 
340
            "Couldn't get caps for oclass->in_plugin->name:%s",
 
341
            oclass->in_plugin->name);
357
342
      gst_ffmpeg_avcodec_close (ctx);
358
343
    }
359
344
    if (ctx->priv_data)
402
387
  ffmpegenc->context->bit_rate_tolerance = ffmpegenc->bitrate;
403
388
  ffmpegenc->context->gop_size = ffmpegenc->gop_size;
404
389
  ffmpegenc->context->me_method = ffmpegenc->me_method;
405
 
  GST_DEBUG_OBJECT (ffmpegenc, "Setting avcontext with bitrate %d, gop_size %d",
 
390
  GST_DEBUG_OBJECT (ffmpegenc, "Setting avcontext to bitrate %lu, gop_size %d",
406
391
      ffmpegenc->bitrate, ffmpegenc->gop_size);
407
392
 
408
393
  /* RTP payload used for GOB production (for Asterisk) */
409
394
  if (ffmpegenc->rtp_payload_size) {
410
395
    ffmpegenc->context->rtp_mode = 1;
411
396
    ffmpegenc->context->rtp_payload_size = ffmpegenc->rtp_payload_size;
412
 
  } else {
413
 
    ffmpegenc->context->rtp_mode = 0;
414
 
    ffmpegenc->context->rtp_payload_size = 512;
415
 
  }
416
 
 
417
 
  /* general properties */
418
 
  ffmpegenc->context->qmin = 1;
419
 
  ffmpegenc->context->qmax = 31;
420
 
  ffmpegenc->context->max_qdiff = 15;
 
397
  }
 
398
 
 
399
  /* additional avcodec settings */
 
400
  /* first fill in the majority by copying over */
 
401
  gst_ffmpeg_cfg_fill_context (ffmpegenc, ffmpegenc->context);
 
402
 
 
403
  /* then handle some special cases */
 
404
  ffmpegenc->context->lmin = (ffmpegenc->lmin * FF_QP2LAMBDA + 0.5);
 
405
  ffmpegenc->context->lmax = (ffmpegenc->lmax * FF_QP2LAMBDA + 0.5);
 
406
 
 
407
  if (ffmpegenc->interlaced) {
 
408
    ffmpegenc->context->flags |=
 
409
        CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME;
 
410
    ffmpegenc->picture->interlaced_frame = TRUE;
 
411
    /* if this is not the case, a filter element should be used to swap fields */
 
412
    ffmpegenc->picture->top_field_first = TRUE;
 
413
  }
 
414
 
 
415
  /* some other defaults */
 
416
  ffmpegenc->context->rc_strategy = 2;
 
417
  ffmpegenc->context->b_frame_strategy = 0;
 
418
  ffmpegenc->context->coder_type = 0;
 
419
  ffmpegenc->context->context_model = 0;
 
420
  ffmpegenc->context->scenechange_threshold = 0;
 
421
  ffmpegenc->context->inter_threshold = 0;
 
422
 
 
423
  /* and last but not least the pass; CBR, 2-pass, etc */
 
424
  ffmpegenc->context->flags |= ffmpegenc->pass;
 
425
  switch (ffmpegenc->pass) {
 
426
      /* some additional action depends on type of pass */
 
427
    case CODEC_FLAG_QSCALE:
 
428
      ffmpegenc->context->global_quality
 
429
          = ffmpegenc->picture->quality = FF_QP2LAMBDA * ffmpegenc->quantizer;
 
430
      break;
 
431
    case CODEC_FLAG_PASS1:     /* need to prepare a stats file */
 
432
      /* we don't close when changing caps, fingers crossed */
 
433
      if (!ffmpegenc->file)
 
434
        ffmpegenc->file = g_fopen (ffmpegenc->filename, "w");
 
435
      if (!ffmpegenc->file) {
 
436
        GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, OPEN_WRITE,
 
437
            (("Could not open file \"%s\" for writing."), ffmpegenc->filename),
 
438
            GST_ERROR_SYSTEM);
 
439
        return FALSE;
 
440
      }
 
441
      break;
 
442
    case CODEC_FLAG_PASS2:
 
443
    {                           /* need to read the whole stats file ! */
 
444
      gsize size;
 
445
 
 
446
      if (!g_file_get_contents (ffmpegenc->filename,
 
447
              &ffmpegenc->context->stats_in, &size, NULL)) {
 
448
        GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, READ,
 
449
            (("Could not get contents of file \"%s\"."), ffmpegenc->filename),
 
450
            GST_ERROR_SYSTEM);
 
451
        return FALSE;
 
452
      }
 
453
 
 
454
      break;
 
455
    }
 
456
    default:
 
457
      break;
 
458
  }
421
459
 
422
460
  /* fetch pix_fmt and so on */
423
461
  gst_ffmpeg_caps_with_codectype (oclass->in_plugin->type,
425
463
  if (!ffmpegenc->context->time_base.den) {
426
464
    ffmpegenc->context->time_base.den = 25;
427
465
    ffmpegenc->context->time_base.num = 1;
 
466
  } else if ((oclass->in_plugin->id == CODEC_ID_MPEG4)
 
467
      && (ffmpegenc->context->time_base.den > 65535)) {
 
468
    /* MPEG4 Standards do not support time_base denominator greater than
 
469
     * (1<<16) - 1 . We therefore scale them down.
 
470
     * Agreed, it will not be the exact framerate... but the difference
 
471
     * shouldn't be that noticeable */
 
472
    ffmpegenc->context->time_base.num =
 
473
        (gint) gst_util_uint64_scale_int (ffmpegenc->context->time_base.num,
 
474
        65535, ffmpegenc->context->time_base.den);
 
475
    ffmpegenc->context->time_base.den = 65535;
 
476
    GST_LOG_OBJECT (ffmpegenc, "MPEG4 : scaled down framerate to %d / %d",
 
477
        ffmpegenc->context->time_base.den, ffmpegenc->context->time_base.num);
428
478
  }
429
479
 
430
480
  pix_fmt = ffmpegenc->context->pix_fmt;
431
481
 
 
482
  /* max-key-interval may need the framerate set above */
 
483
  if (ffmpegenc->max_key_interval) {
 
484
    AVCodecContext *ctx;
 
485
 
 
486
    /* override gop-size */
 
487
    ctx = ffmpegenc->context;
 
488
    ctx->gop_size = (ffmpegenc->max_key_interval < 0) ?
 
489
        (-ffmpegenc->max_key_interval
 
490
        * (ctx->time_base.den / ctx->time_base.num))
 
491
        : ffmpegenc->max_key_interval;
 
492
  }
 
493
 
432
494
  /* open codec */
433
495
  if (gst_ffmpeg_avcodec_open (ffmpegenc->context, oclass->in_plugin) < 0) {
434
496
    if (ffmpegenc->context->priv_data)
435
497
      gst_ffmpeg_avcodec_close (ffmpegenc->context);
 
498
    if (ffmpegenc->context->stats_in)
 
499
      g_free (ffmpegenc->context->stats_in);
436
500
    GST_DEBUG_OBJECT (ffmpegenc, "ffenc_%s: Failed to open FFMPEG codec",
437
501
        oclass->in_plugin->name);
438
502
    return FALSE;
439
503
  }
440
504
 
 
505
  /* second pass stats buffer no longer needed */
 
506
  if (ffmpegenc->context->stats_in)
 
507
    g_free (ffmpegenc->context->stats_in);
 
508
 
441
509
  /* is the colourspace correct? */
442
510
  if (pix_fmt != ffmpegenc->context->pix_fmt) {
443
511
    gst_ffmpeg_avcodec_close (ffmpegenc->context);
444
 
    GST_DEBUG_OBJECT (ffmpegenc, "ffenc_%s: AV wants different colourspace (%d given, %d wanted)",
 
512
    GST_DEBUG_OBJECT (ffmpegenc,
 
513
        "ffenc_%s: AV wants different colourspace (%d given, %d wanted)",
445
514
        oclass->in_plugin->name, pix_fmt, ffmpegenc->context->pix_fmt);
446
515
    return FALSE;
447
516
  }
453
522
    GST_DEBUG_OBJECT (ffmpegenc, "... but no peer, using template caps");
454
523
    /* we need to copy because get_allowed_caps returns a ref, and
455
524
     * get_pad_template_caps doesn't */
456
 
    allowed_caps = gst_caps_copy (
457
 
        gst_pad_get_pad_template_caps (ffmpegenc->srcpad));
 
525
    allowed_caps =
 
526
        gst_caps_copy (gst_pad_get_pad_template_caps (ffmpegenc->srcpad));
458
527
  }
459
528
  GST_DEBUG_OBJECT (ffmpegenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
460
529
  gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
483
552
 
484
553
    newcaps =
485
554
        gst_caps_new_full (gst_structure_copy (gst_caps_get_structure (icaps,
486
 
            0)), NULL);
 
555
                0)), NULL);
487
556
    gst_caps_unref (icaps);
488
557
    icaps = newcaps;
489
558
  }
506
575
{
507
576
  GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (GST_PAD_PARENT (pad));
508
577
  GstBuffer *outbuf;
509
 
  GstFFMpegEncClass *oclass =
510
 
      (GstFFMpegEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc));
511
578
  gint ret_size = 0, frame_size;
512
579
 
513
580
  GST_DEBUG_OBJECT (ffmpegenc,
522
589
 
523
590
  ffmpegenc->picture->pts =
524
591
      gst_ffmpeg_time_gst_to_ff (GST_BUFFER_TIMESTAMP (inbuf),
525
 
          ffmpegenc->context->time_base);
 
592
      ffmpegenc->context->time_base);
526
593
 
527
594
  outbuf = gst_buffer_new_and_alloc (ffmpegenc->buffer_size);
528
595
  ret_size = avcodec_encode_video (ffmpegenc->context,
529
 
      GST_BUFFER_DATA (outbuf),
530
 
      GST_BUFFER_SIZE (outbuf), ffmpegenc->picture);
 
596
      GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf), ffmpegenc->picture);
531
597
 
532
598
  if (ret_size < 0) {
 
599
#ifndef GST_DISABLE_GST_DEBUG
 
600
    GstFFMpegEncClass *oclass =
 
601
        (GstFFMpegEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc));
533
602
    GST_ERROR_OBJECT (ffmpegenc,
534
603
        "ffenc_%s: failed to encode buffer", oclass->in_plugin->name);
 
604
#endif /* GST_DISABLE_GST_DEBUG */
535
605
    gst_buffer_unref (inbuf);
536
606
    gst_buffer_unref (outbuf);
537
607
    return GST_FLOW_OK;
538
608
  }
539
609
 
 
610
  /* handle b-frame delay when no output, so we don't output empty frames;
 
611
   * timestamps and so can permute a bit between coding and display order
 
612
   * but keyframes should still end up with the proper metadata */
 
613
  g_queue_push_tail (ffmpegenc->delay, inbuf);
 
614
  if (ret_size)
 
615
    inbuf = g_queue_pop_head (ffmpegenc->delay);
 
616
  else
 
617
    return GST_FLOW_OK;
 
618
 
 
619
  /* save stats info if there is some as well as a stats file */
 
620
  if (ffmpegenc->file && ffmpegenc->context->stats_out)
 
621
    if (fprintf (ffmpegenc->file, "%s", ffmpegenc->context->stats_out) < 0)
 
622
      GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, WRITE,
 
623
          (("Could not write to file \"%s\"."), ffmpegenc->filename),
 
624
          GST_ERROR_SYSTEM);
 
625
 
540
626
  GST_BUFFER_SIZE (outbuf) = ret_size;
541
627
  GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf);
542
628
  GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf);
617
703
 
618
704
    outbuf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (subbuf));
619
705
    ret_size = avcodec_encode_audio (ffmpegenc->context,
620
 
        GST_BUFFER_DATA (outbuf),
621
 
        GST_BUFFER_SIZE (outbuf), (const short int *)
 
706
        GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf), (const short int *)
622
707
        GST_BUFFER_DATA (subbuf));
623
708
 
624
709
    if (ret_size < 0) {
644
729
}
645
730
 
646
731
static void
 
732
gst_ffmpegenc_flush_buffers (GstFFMpegEnc * ffmpegenc, gboolean send)
 
733
{
 
734
  GstBuffer *outbuf, *inbuf;
 
735
  gint ret_size;
 
736
 
 
737
  GST_DEBUG_OBJECT (ffmpegenc, "flushing buffers with sending %d", send);
 
738
 
 
739
  /* no need to empty codec if there is none */
 
740
  if (!ffmpegenc->opened)
 
741
    goto flush;
 
742
 
 
743
  while (!g_queue_is_empty (ffmpegenc->delay)) {
 
744
 
 
745
    outbuf = gst_buffer_new_and_alloc (ffmpegenc->buffer_size);
 
746
    ret_size = avcodec_encode_video (ffmpegenc->context,
 
747
        GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf), NULL);
 
748
 
 
749
    if (ret_size < 0) {         /* there should be something, notify and give up */
 
750
#ifndef GST_DISABLE_GST_DEBUG
 
751
      GstFFMpegEncClass *oclass =
 
752
          (GstFFMpegEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc));
 
753
      GST_WARNING_OBJECT (ffmpegenc,
 
754
          "ffenc_%s: failed to flush buffer", oclass->in_plugin->name);
 
755
#endif /* GST_DISABLE_GST_DEBUG */
 
756
      break;
 
757
    }
 
758
 
 
759
    /* save stats info if there is some as well as a stats file */
 
760
    if (ffmpegenc->file && ffmpegenc->context->stats_out)
 
761
      if (fprintf (ffmpegenc->file, "%s", ffmpegenc->context->stats_out) < 0)
 
762
        GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, WRITE,
 
763
            (("Could not write to file \"%s\"."), ffmpegenc->filename),
 
764
            GST_ERROR_SYSTEM);
 
765
 
 
766
    /* handle b-frame delay when no output, so we don't output empty frames */
 
767
    inbuf = g_queue_pop_head (ffmpegenc->delay);
 
768
 
 
769
    GST_BUFFER_SIZE (outbuf) = ret_size;
 
770
    GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf);
 
771
    GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf);
 
772
    if (!ffmpegenc->context->coded_frame->key_frame)
 
773
      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
 
774
    gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegenc->srcpad));
 
775
 
 
776
    gst_buffer_unref (inbuf);
 
777
 
 
778
    if (send)
 
779
      gst_pad_push (ffmpegenc->srcpad, outbuf);
 
780
    else
 
781
      gst_buffer_unref (outbuf);
 
782
  }
 
783
 
 
784
flush:
 
785
  {
 
786
    /* make sure that we empty the queue, is still needed if we had to break */
 
787
    while (!g_queue_is_empty (ffmpegenc->delay))
 
788
      gst_buffer_unref (g_queue_pop_head (ffmpegenc->delay));
 
789
  }
 
790
}
 
791
 
 
792
static gboolean
 
793
gst_ffmpegenc_event_video (GstPad * pad, GstEvent * event)
 
794
{
 
795
  GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (GST_PAD_PARENT (pad));
 
796
 
 
797
  switch (GST_EVENT_TYPE (event)) {
 
798
    case GST_EVENT_EOS:
 
799
      gst_ffmpegenc_flush_buffers (ffmpegenc, TRUE);
 
800
      break;
 
801
      /* no flushing if flush received,
 
802
       * buffers in encoder are considered (in the) past */
 
803
    default:
 
804
      break;
 
805
  }
 
806
 
 
807
  return gst_pad_push_event (ffmpegenc->srcpad, event);
 
808
}
 
809
 
 
810
static void
647
811
gst_ffmpegenc_set_property (GObject * object,
648
812
    guint prop_id, const GValue * value, GParamSpec * pspec)
649
813
{
670
834
      ffmpegenc->rtp_payload_size = g_value_get_ulong (value);
671
835
      break;
672
836
    default:
673
 
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
837
      if (!gst_ffmpeg_cfg_set_property (object, value, pspec))
 
838
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
674
839
      break;
675
840
  }
676
841
}
702
867
      g_value_set_ulong (value, ffmpegenc->rtp_payload_size);
703
868
      break;
704
869
    default:
705
 
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
870
      if (!gst_ffmpeg_cfg_get_property (object, value, pspec))
 
871
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
706
872
      break;
707
873
  }
708
874
}
722
888
 
723
889
  switch (transition) {
724
890
    case GST_STATE_CHANGE_PAUSED_TO_READY:
 
891
      gst_ffmpegenc_flush_buffers (ffmpegenc, FALSE);
725
892
      if (ffmpegenc->opened) {
726
893
        gst_ffmpeg_avcodec_close (ffmpegenc->context);
727
894
        ffmpegenc->opened = FALSE;
730
897
        gst_buffer_unref (ffmpegenc->cache);
731
898
        ffmpegenc->cache = NULL;
732
899
      }
 
900
      if (ffmpegenc->file) {
 
901
        fclose (ffmpegenc->file);
 
902
        ffmpegenc->file = NULL;
 
903
      }
733
904
      break;
734
905
    default:
735
906
      break;
758
929
 
759
930
  enc_global_plugins = g_hash_table_new (NULL, NULL);
760
931
 
 
932
  /* build global ffmpeg param/property info */
 
933
  gst_ffmpeg_cfg_init ();
 
934
 
761
935
  while (in_plugin) {
762
936
    gchar *type_name;
763
 
    GstCaps *srccaps, *sinkcaps;
 
937
    GstCaps *srccaps = NULL, *sinkcaps = NULL;
764
938
    GstFFMpegEncClassParams *params;
765
939
 
766
940
    /* no quasi codecs, please */
778
952
 
779
953
    /* name */
780
954
    if (!gst_ffmpeg_get_codecid_longname (in_plugin->id)) {
781
 
      g_warning ("Add encoder %s (%d) please",
782
 
          in_plugin->name, in_plugin->id);
 
955
      GST_INFO ("Add encoder %s (%d) please", in_plugin->name, in_plugin->id);
783
956
      goto next;
784
957
    }
785
958
 
786
959
    /* first make sure we've got a supported type */
787
960
    srccaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, TRUE);
788
961
    if (in_plugin->type == CODEC_TYPE_VIDEO) {
789
 
      sinkcaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv");
 
962
      sinkcaps =
 
963
          gst_caps_from_string
 
964
          ("video/x-raw-rgb; video/x-raw-yuv; video/x-raw-gray");
790
965
    } else {
791
966
      sinkcaps = gst_ffmpeg_codectype_to_caps (in_plugin->type, NULL);
792
967
    }
804
979
 
805
980
    params = g_new0 (GstFFMpegEncClassParams, 1);
806
981
    params->in_plugin = in_plugin;
807
 
    params->srccaps = srccaps;
808
 
    params->sinkcaps = sinkcaps;
 
982
    params->srccaps = gst_caps_ref (srccaps);
 
983
    params->sinkcaps = gst_caps_ref (sinkcaps);
809
984
 
810
985
    g_hash_table_insert (enc_global_plugins,
811
986
        GINT_TO_POINTER (0), (gpointer) params);
823
998
        GINT_TO_POINTER (type), (gpointer) params);
824
999
 
825
1000
  next:
 
1001
    if (sinkcaps)
 
1002
      gst_caps_unref (sinkcaps);
 
1003
    if (srccaps)
 
1004
      gst_caps_unref (srccaps);
826
1005
    in_plugin = in_plugin->next;
827
1006
  }
828
1007
  g_hash_table_remove (enc_global_plugins, GINT_TO_POINTER (0));