• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2012> Collabora Ltd.
4  *   Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include <assert.h>
27 #include <string.h>
28 /* for stats file handling */
29 #include <stdio.h>
30 #include <glib/gstdio.h>
31 #include <errno.h>
32 
33 #include <libavcodec/avcodec.h>
34 #include <libavutil/opt.h>
35 
36 #include <gst/gst.h>
37 
38 #include "gstav.h"
39 #include "gstavcfg.h"
40 #include "gstavcodecmap.h"
41 #include "gstavutils.h"
42 #include "gstavaudenc.h"
43 
44 enum
45 {
46   PROP_0,
47   PROP_CFG_BASE,
48 };
49 
50 static void gst_ffmpegaudenc_class_init (GstFFMpegAudEncClass * klass);
51 static void gst_ffmpegaudenc_base_init (GstFFMpegAudEncClass * klass);
52 static void gst_ffmpegaudenc_init (GstFFMpegAudEnc * ffmpegaudenc);
53 static void gst_ffmpegaudenc_finalize (GObject * object);
54 
55 static gboolean gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder,
56     GstAudioInfo * info);
57 static GstFlowReturn gst_ffmpegaudenc_handle_frame (GstAudioEncoder * encoder,
58     GstBuffer * inbuf);
59 static gboolean gst_ffmpegaudenc_start (GstAudioEncoder * encoder);
60 static gboolean gst_ffmpegaudenc_stop (GstAudioEncoder * encoder);
61 static void gst_ffmpegaudenc_flush (GstAudioEncoder * encoder);
62 
63 static void gst_ffmpegaudenc_set_property (GObject * object,
64     guint prop_id, const GValue * value, GParamSpec * pspec);
65 static void gst_ffmpegaudenc_get_property (GObject * object,
66     guint prop_id, GValue * value, GParamSpec * pspec);
67 
68 #define GST_FFENC_PARAMS_QDATA g_quark_from_static_string("avenc-params")
69 
70 static GstElementClass *parent_class = NULL;
71 
72 static void
gst_ffmpegaudenc_base_init(GstFFMpegAudEncClass * klass)73 gst_ffmpegaudenc_base_init (GstFFMpegAudEncClass * klass)
74 {
75   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
76   AVCodec *in_plugin;
77   GstPadTemplate *srctempl = NULL, *sinktempl = NULL;
78   GstCaps *srccaps = NULL, *sinkcaps = NULL;
79   gchar *longname, *description;
80 
81   in_plugin =
82       (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
83       GST_FFENC_PARAMS_QDATA);
84   g_assert (in_plugin != NULL);
85 
86   /* construct the element details struct */
87   longname = g_strdup_printf ("libav %s encoder", in_plugin->long_name);
88   description = g_strdup_printf ("libav %s encoder", in_plugin->name);
89   gst_element_class_set_metadata (element_class, longname,
90       "Codec/Encoder/Audio", description,
91       "Wim Taymans <wim.taymans@gmail.com>, "
92       "Ronald Bultje <rbultje@ronald.bitfreak.net>");
93   g_free (longname);
94   g_free (description);
95 
96   if (!(srccaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, TRUE))) {
97     GST_DEBUG ("Couldn't get source caps for encoder '%s'", in_plugin->name);
98     srccaps = gst_caps_new_empty_simple ("unknown/unknown");
99   }
100 
101   sinkcaps = gst_ffmpeg_codectype_to_audio_caps (NULL,
102       in_plugin->id, TRUE, in_plugin);
103   if (!sinkcaps) {
104     GST_DEBUG ("Couldn't get sink caps for encoder '%s'", in_plugin->name);
105     sinkcaps = gst_caps_new_empty_simple ("unknown/unknown");
106   }
107 
108   /* pad templates */
109   sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
110       GST_PAD_ALWAYS, sinkcaps);
111   srctempl = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps);
112 
113   gst_element_class_add_pad_template (element_class, srctempl);
114   gst_element_class_add_pad_template (element_class, sinktempl);
115 
116   gst_caps_unref (sinkcaps);
117   gst_caps_unref (srccaps);
118 
119   klass->in_plugin = in_plugin;
120   klass->srctempl = srctempl;
121   klass->sinktempl = sinktempl;
122 
123   return;
124 }
125 
126 static void
gst_ffmpegaudenc_class_init(GstFFMpegAudEncClass * klass)127 gst_ffmpegaudenc_class_init (GstFFMpegAudEncClass * klass)
128 {
129   GObjectClass *gobject_class;
130   GstAudioEncoderClass *gstaudioencoder_class;
131 
132   gobject_class = (GObjectClass *) klass;
133   gstaudioencoder_class = (GstAudioEncoderClass *) klass;
134 
135   parent_class = g_type_class_peek_parent (klass);
136 
137   gobject_class->set_property = gst_ffmpegaudenc_set_property;
138   gobject_class->get_property = gst_ffmpegaudenc_get_property;
139 
140   gst_ffmpeg_cfg_install_properties (gobject_class, klass->in_plugin,
141       PROP_CFG_BASE, AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM);
142 
143   gobject_class->finalize = gst_ffmpegaudenc_finalize;
144 
145   gstaudioencoder_class->start = GST_DEBUG_FUNCPTR (gst_ffmpegaudenc_start);
146   gstaudioencoder_class->stop = GST_DEBUG_FUNCPTR (gst_ffmpegaudenc_stop);
147   gstaudioencoder_class->flush = GST_DEBUG_FUNCPTR (gst_ffmpegaudenc_flush);
148   gstaudioencoder_class->set_format =
149       GST_DEBUG_FUNCPTR (gst_ffmpegaudenc_set_format);
150   gstaudioencoder_class->handle_frame =
151       GST_DEBUG_FUNCPTR (gst_ffmpegaudenc_handle_frame);
152 }
153 
154 static void
gst_ffmpegaudenc_init(GstFFMpegAudEnc * ffmpegaudenc)155 gst_ffmpegaudenc_init (GstFFMpegAudEnc * ffmpegaudenc)
156 {
157   GstFFMpegAudEncClass *klass =
158       (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);
159 
160   GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (ffmpegaudenc));
161 
162   /* ffmpeg objects */
163   ffmpegaudenc->context = avcodec_alloc_context3 (klass->in_plugin);
164   ffmpegaudenc->refcontext = avcodec_alloc_context3 (klass->in_plugin);
165   ffmpegaudenc->opened = FALSE;
166   ffmpegaudenc->frame = av_frame_alloc ();
167 
168   gst_audio_encoder_set_drainable (GST_AUDIO_ENCODER (ffmpegaudenc), TRUE);
169 }
170 
171 static void
gst_ffmpegaudenc_finalize(GObject * object)172 gst_ffmpegaudenc_finalize (GObject * object)
173 {
174   GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) object;
175 
176   /* clean up remaining allocated data */
177   av_frame_free (&ffmpegaudenc->frame);
178   /* ohos.opt.memleak.0001
179    * avcodec_close is deprecated, it may cause memory leak */
180 #ifdef OHOS_OPT_MEMLEAK
181   avcodec_free_context (&ffmpegaudenc->context);
182   avcodec_free_context (&ffmpegaudenc->refcontext);
183 #else
184   gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
185   av_free (ffmpegaudenc->context);
186   av_free (ffmpegaudenc->refcontext);
187 #endif
188 
189   G_OBJECT_CLASS (parent_class)->finalize (object);
190 }
191 
192 static gboolean
gst_ffmpegaudenc_start(GstAudioEncoder * encoder)193 gst_ffmpegaudenc_start (GstAudioEncoder * encoder)
194 {
195   GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
196   GstFFMpegAudEncClass *oclass =
197       (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);
198 
199   gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
200   if (avcodec_get_context_defaults3 (ffmpegaudenc->context,
201           oclass->in_plugin) < 0) {
202     GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
203     return FALSE;
204   }
205 
206   return TRUE;
207 }
208 
209 static gboolean
gst_ffmpegaudenc_stop(GstAudioEncoder * encoder)210 gst_ffmpegaudenc_stop (GstAudioEncoder * encoder)
211 {
212   GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
213 
214   /* close old session */
215   gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
216   ffmpegaudenc->opened = FALSE;
217 
218   return TRUE;
219 }
220 
221 static void
gst_ffmpegaudenc_flush(GstAudioEncoder * encoder)222 gst_ffmpegaudenc_flush (GstAudioEncoder * encoder)
223 {
224   GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
225 
226   if (ffmpegaudenc->opened) {
227     avcodec_flush_buffers (ffmpegaudenc->context);
228   }
229 }
230 
231 static gboolean
gst_ffmpegaudenc_set_format(GstAudioEncoder * encoder,GstAudioInfo * info)232 gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info)
233 {
234   GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
235   GstCaps *other_caps;
236   GstCaps *allowed_caps;
237   GstCaps *icaps;
238   gsize frame_size;
239   GstFFMpegAudEncClass *oclass =
240       (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);
241 
242   /* close old session */
243   if (ffmpegaudenc->opened) {
244     gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
245     ffmpegaudenc->opened = FALSE;
246     if (avcodec_get_context_defaults3 (ffmpegaudenc->context,
247             oclass->in_plugin) < 0) {
248       GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
249       return FALSE;
250     }
251   }
252 
253   gst_ffmpeg_cfg_fill_context (G_OBJECT (ffmpegaudenc), ffmpegaudenc->context);
254 
255   /* fetch pix_fmt and so on */
256   gst_ffmpeg_audioinfo_to_context (info, ffmpegaudenc->context);
257   if (!ffmpegaudenc->context->time_base.den) {
258     ffmpegaudenc->context->time_base.den = GST_AUDIO_INFO_RATE (info);
259     ffmpegaudenc->context->time_base.num = 1;
260     ffmpegaudenc->context->ticks_per_frame = 1;
261   }
262 
263   if (ffmpegaudenc->context->channel_layout) {
264     gst_ffmpeg_channel_layout_to_gst (ffmpegaudenc->context->channel_layout,
265         ffmpegaudenc->context->channels, ffmpegaudenc->ffmpeg_layout);
266     ffmpegaudenc->needs_reorder =
267         (memcmp (ffmpegaudenc->ffmpeg_layout, info->position,
268             sizeof (GstAudioChannelPosition) *
269             ffmpegaudenc->context->channels) != 0);
270   }
271 
272   /* some codecs support more than one format, first auto-choose one */
273   GST_DEBUG_OBJECT (ffmpegaudenc, "picking an output format ...");
274   allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder));
275   if (!allowed_caps) {
276     GST_DEBUG_OBJECT (ffmpegaudenc, "... but no peer, using template caps");
277     /* we need to copy because get_allowed_caps returns a ref, and
278      * get_pad_template_caps doesn't */
279     allowed_caps =
280         gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder));
281   }
282   GST_DEBUG_OBJECT (ffmpegaudenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
283   gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
284       oclass->in_plugin->type, allowed_caps, ffmpegaudenc->context);
285 
286   /* open codec */
287   if (gst_ffmpeg_avcodec_open (ffmpegaudenc->context, oclass->in_plugin) < 0) {
288     gst_caps_unref (allowed_caps);
289     gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
290     GST_DEBUG_OBJECT (ffmpegaudenc, "avenc_%s: Failed to open FFMPEG codec",
291         oclass->in_plugin->name);
292     if (avcodec_get_context_defaults3 (ffmpegaudenc->context,
293             oclass->in_plugin) < 0)
294       GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
295 
296     if ((oclass->in_plugin->capabilities & AV_CODEC_CAP_EXPERIMENTAL) &&
297         ffmpegaudenc->context->strict_std_compliance !=
298         GST_FFMPEG_EXPERIMENTAL) {
299       GST_ELEMENT_ERROR (ffmpegaudenc, LIBRARY, SETTINGS,
300           ("Codec is experimental, but settings don't allow encoders to "
301               "produce output of experimental quality"),
302           ("This codec may not create output that is conformant to the specs "
303               "or of good quality. If you must use it anyway, set the "
304               "compliance property to experimental"));
305     }
306     return FALSE;
307   }
308 
309   /* try to set this caps on the other side */
310   other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id,
311       ffmpegaudenc->context, TRUE);
312 
313   if (!other_caps) {
314     gst_caps_unref (allowed_caps);
315     gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
316     GST_DEBUG ("Unsupported codec - no caps found");
317     if (avcodec_get_context_defaults3 (ffmpegaudenc->context,
318             oclass->in_plugin) < 0)
319       GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
320     return FALSE;
321   }
322 
323   icaps = gst_caps_intersect (allowed_caps, other_caps);
324   gst_caps_unref (allowed_caps);
325   gst_caps_unref (other_caps);
326   if (gst_caps_is_empty (icaps)) {
327     gst_caps_unref (icaps);
328     return FALSE;
329   }
330   icaps = gst_caps_fixate (icaps);
331 
332   if (!gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (ffmpegaudenc),
333           icaps)) {
334     gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
335     gst_caps_unref (icaps);
336     if (avcodec_get_context_defaults3 (ffmpegaudenc->context,
337             oclass->in_plugin) < 0)
338       GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
339     return FALSE;
340   }
341   gst_caps_unref (icaps);
342 
343   frame_size = ffmpegaudenc->context->frame_size;
344   if (frame_size > 1) {
345     gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc),
346         frame_size);
347     gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc),
348         frame_size);
349     gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 1);
350   } else {
351     gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc),
352         0);
353     gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc),
354         0);
355     gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 0);
356   }
357 
358   /* Store some tags */
359   {
360     GstTagList *tags = gst_tag_list_new_empty ();
361     const gchar *codec;
362 
363     gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
364         (guint) ffmpegaudenc->context->bit_rate, NULL);
365 
366     if ((codec =
367             gst_ffmpeg_get_codecid_longname (ffmpegaudenc->context->codec_id)))
368       gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, codec,
369           NULL);
370 
371     gst_audio_encoder_merge_tags (encoder, tags, GST_TAG_MERGE_REPLACE);
372     gst_tag_list_unref (tags);
373   }
374 
375   /* success! */
376   ffmpegaudenc->opened = TRUE;
377 
378   return TRUE;
379 }
380 
381 static void
gst_ffmpegaudenc_free_avpacket(gpointer pkt)382 gst_ffmpegaudenc_free_avpacket (gpointer pkt)
383 {
384   av_packet_unref ((AVPacket *) pkt);
385   g_slice_free (AVPacket, pkt);
386 }
387 
388 typedef struct
389 {
390   GstBuffer *buffer;
391   GstMapInfo map;
392 
393   guint8 **ext_data_array, *ext_data;
394 } BufferInfo;
395 
396 static void
buffer_info_free(void * opaque,guint8 * data)397 buffer_info_free (void *opaque, guint8 * data)
398 {
399   BufferInfo *info = opaque;
400 
401   if (info->buffer) {
402     gst_buffer_unmap (info->buffer, &info->map);
403     gst_buffer_unref (info->buffer);
404   } else {
405     av_free (info->ext_data);
406     av_free (info->ext_data_array);
407   }
408   g_slice_free (BufferInfo, info);
409 }
410 
411 static GstFlowReturn
gst_ffmpegaudenc_send_frame(GstFFMpegAudEnc * ffmpegaudenc,GstBuffer * buffer)412 gst_ffmpegaudenc_send_frame (GstFFMpegAudEnc * ffmpegaudenc, GstBuffer * buffer)
413 {
414   GstAudioEncoder *enc;
415   AVCodecContext *ctx;
416   GstFlowReturn ret;
417   gint res;
418   GstAudioInfo *info;
419   AVFrame *frame = ffmpegaudenc->frame;
420   gboolean planar;
421   gint nsamples = -1;
422 
423   enc = GST_AUDIO_ENCODER (ffmpegaudenc);
424 
425   ctx = ffmpegaudenc->context;
426 
427   if (buffer != NULL) {
428     BufferInfo *buffer_info = g_slice_new0 (BufferInfo);
429     guint8 *audio_in;
430     guint in_size;
431 
432     buffer_info->buffer = buffer;
433     gst_buffer_map (buffer, &buffer_info->map, GST_MAP_READ);
434     audio_in = buffer_info->map.data;
435     in_size = buffer_info->map.size;
436 
437     GST_LOG_OBJECT (ffmpegaudenc, "encoding buffer %p size:%u", audio_in,
438         in_size);
439 
440     info = gst_audio_encoder_get_audio_info (enc);
441     planar = av_sample_fmt_is_planar (ffmpegaudenc->context->sample_fmt);
442     frame->format = ffmpegaudenc->context->sample_fmt;
443     frame->sample_rate = ffmpegaudenc->context->sample_rate;
444     frame->channels = ffmpegaudenc->context->channels;
445     frame->channel_layout = ffmpegaudenc->context->channel_layout;
446 
447     if (planar && info->channels > 1) {
448       gint channels;
449       gint i, j;
450 
451       nsamples = frame->nb_samples = in_size / info->bpf;
452       channels = info->channels;
453 
454       frame->buf[0] =
455           av_buffer_create (NULL, 0, buffer_info_free, buffer_info, 0);
456 
457       if (info->channels > AV_NUM_DATA_POINTERS) {
458         buffer_info->ext_data_array = frame->extended_data =
459             av_malloc_array (info->channels, sizeof (uint8_t *));
460       } else {
461         frame->extended_data = frame->data;
462       }
463 
464       buffer_info->ext_data = frame->extended_data[0] = av_malloc (in_size);
465       frame->linesize[0] = in_size / channels;
466       for (i = 1; i < channels; i++)
467         frame->extended_data[i] =
468             frame->extended_data[i - 1] + frame->linesize[0];
469 
470       switch (info->finfo->width) {
471         case 8:{
472           const guint8 *idata = (const guint8 *) audio_in;
473 
474           for (i = 0; i < nsamples; i++) {
475             for (j = 0; j < channels; j++) {
476               ((guint8 *) frame->extended_data[j])[i] = idata[j];
477             }
478             idata += channels;
479           }
480           break;
481         }
482         case 16:{
483           const guint16 *idata = (const guint16 *) audio_in;
484 
485           for (i = 0; i < nsamples; i++) {
486             for (j = 0; j < channels; j++) {
487               ((guint16 *) frame->extended_data[j])[i] = idata[j];
488             }
489             idata += channels;
490           }
491           break;
492         }
493         case 32:{
494           const guint32 *idata = (const guint32 *) audio_in;
495 
496           for (i = 0; i < nsamples; i++) {
497             for (j = 0; j < channels; j++) {
498               ((guint32 *) frame->extended_data[j])[i] = idata[j];
499             }
500             idata += channels;
501           }
502 
503           break;
504         }
505         case 64:{
506           const guint64 *idata = (const guint64 *) audio_in;
507 
508           for (i = 0; i < nsamples; i++) {
509             for (j = 0; j < channels; j++) {
510               ((guint64 *) frame->extended_data[j])[i] = idata[j];
511             }
512             idata += channels;
513           }
514 
515           break;
516         }
517         default:
518           g_assert_not_reached ();
519           break;
520       }
521 
522       gst_buffer_unmap (buffer, &buffer_info->map);
523       gst_buffer_unref (buffer);
524       buffer_info->buffer = NULL;
525     } else {
526       frame->data[0] = audio_in;
527       frame->extended_data = frame->data;
528       frame->linesize[0] = in_size;
529       frame->nb_samples = nsamples = in_size / info->bpf;
530       frame->buf[0] =
531           av_buffer_create (NULL, 0, buffer_info_free, buffer_info, 0);
532     }
533 
534     /* we have a frame to feed the encoder */
535     res = avcodec_send_frame (ctx, frame);
536 
537     av_frame_unref (frame);
538   } else {
539     GST_LOG_OBJECT (ffmpegaudenc, "draining");
540     /* flushing the encoder */
541     res = avcodec_send_frame (ctx, NULL);
542   }
543 
544   if (res == 0) {
545     ret = GST_FLOW_OK;
546   } else if (res == AVERROR_EOF) {
547     ret = GST_FLOW_EOS;
548   } else {                      /* Any other return value is an error in our context */
549     ret = GST_FLOW_OK;
550     GST_WARNING_OBJECT (ffmpegaudenc, "Failed to encode buffer");
551   }
552 
553   return ret;
554 }
555 
556 static GstFlowReturn
gst_ffmpegaudenc_receive_packet(GstFFMpegAudEnc * ffmpegaudenc,gboolean * got_packet)557 gst_ffmpegaudenc_receive_packet (GstFFMpegAudEnc * ffmpegaudenc,
558     gboolean * got_packet)
559 {
560   GstAudioEncoder *enc;
561   AVCodecContext *ctx;
562   gint res;
563   GstFlowReturn ret;
564   AVPacket *pkt;
565 
566   enc = GST_AUDIO_ENCODER (ffmpegaudenc);
567 
568   ctx = ffmpegaudenc->context;
569 
570   pkt = g_slice_new0 (AVPacket);
571 
572   res = avcodec_receive_packet (ctx, pkt);
573 
574   if (res == 0) {
575     GstBuffer *outbuf;
576 
577     GST_LOG_OBJECT (ffmpegaudenc, "pushing size %d", pkt->size);
578 
579     outbuf =
580         gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, pkt->data,
581         pkt->size, 0, pkt->size, pkt, gst_ffmpegaudenc_free_avpacket);
582 
583     ret =
584         gst_audio_encoder_finish_frame (enc, outbuf,
585         pkt->duration > 0 ? pkt->duration : -1);
586     *got_packet = TRUE;
587   } else {
588     GST_LOG_OBJECT (ffmpegaudenc, "no output produced");
589     g_slice_free (AVPacket, pkt);
590     ret = GST_FLOW_OK;
591     *got_packet = FALSE;
592   }
593 
594   return ret;
595 }
596 
597 static GstFlowReturn
gst_ffmpegaudenc_drain(GstFFMpegAudEnc * ffmpegaudenc)598 gst_ffmpegaudenc_drain (GstFFMpegAudEnc * ffmpegaudenc)
599 {
600   GstFlowReturn ret = GST_FLOW_OK;
601   gboolean got_packet;
602 
603   ret = gst_ffmpegaudenc_send_frame (ffmpegaudenc, NULL);
604 
605   if (ret == GST_FLOW_OK) {
606     do {
607       ret = gst_ffmpegaudenc_receive_packet (ffmpegaudenc, &got_packet);
608       if (ret != GST_FLOW_OK)
609         break;
610     } while (got_packet);
611   }
612 
613   avcodec_flush_buffers (ffmpegaudenc->context);
614 
615   return ret;
616 }
617 
618 static GstFlowReturn
gst_ffmpegaudenc_handle_frame(GstAudioEncoder * encoder,GstBuffer * inbuf)619 gst_ffmpegaudenc_handle_frame (GstAudioEncoder * encoder, GstBuffer * inbuf)
620 {
621   GstFFMpegAudEnc *ffmpegaudenc;
622   GstFlowReturn ret;
623   gboolean got_packet;
624 
625   ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
626 
627   if (G_UNLIKELY (!ffmpegaudenc->opened))
628     goto not_negotiated;
629 
630   if (!inbuf)
631     return gst_ffmpegaudenc_drain (ffmpegaudenc);
632 
633   inbuf = gst_buffer_ref (inbuf);
634 
635   GST_DEBUG_OBJECT (ffmpegaudenc,
636       "Received time %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT
637       ", size %" G_GSIZE_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
638       GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)), gst_buffer_get_size (inbuf));
639 
640   /* Reorder channels to the GStreamer channel order */
641   if (ffmpegaudenc->needs_reorder) {
642     GstAudioInfo *info = gst_audio_encoder_get_audio_info (encoder);
643 
644     inbuf = gst_buffer_make_writable (inbuf);
645     gst_audio_buffer_reorder_channels (inbuf, info->finfo->format,
646         info->channels, info->position, ffmpegaudenc->ffmpeg_layout);
647   }
648 
649   ret = gst_ffmpegaudenc_send_frame (ffmpegaudenc, inbuf);
650 
651   if (ret != GST_FLOW_OK)
652     goto send_frame_failed;
653 
654   do {
655     ret = gst_ffmpegaudenc_receive_packet (ffmpegaudenc, &got_packet);
656   } while (got_packet);
657 
658   return GST_FLOW_OK;
659 
660   /* ERRORS */
661 not_negotiated:
662   {
663     GST_ELEMENT_ERROR (ffmpegaudenc, CORE, NEGOTIATION, (NULL),
664         ("not configured to input format before data start"));
665     gst_buffer_unref (inbuf);
666     return GST_FLOW_NOT_NEGOTIATED;
667   }
668 send_frame_failed:
669   {
670     GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to send frame %d (%s)", ret,
671         gst_flow_get_name (ret));
672     return ret;
673   }
674 }
675 
676 static void
gst_ffmpegaudenc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)677 gst_ffmpegaudenc_set_property (GObject * object,
678     guint prop_id, const GValue * value, GParamSpec * pspec)
679 {
680   GstFFMpegAudEnc *ffmpegaudenc;
681 
682   ffmpegaudenc = (GstFFMpegAudEnc *) (object);
683 
684   if (ffmpegaudenc->opened) {
685     GST_WARNING_OBJECT (ffmpegaudenc,
686         "Can't change properties once encoder is setup !");
687     return;
688   }
689 
690   switch (prop_id) {
691     default:
692       if (!gst_ffmpeg_cfg_set_property (ffmpegaudenc->refcontext, value, pspec))
693         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
694       break;
695   }
696 }
697 
698 static void
gst_ffmpegaudenc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)699 gst_ffmpegaudenc_get_property (GObject * object,
700     guint prop_id, GValue * value, GParamSpec * pspec)
701 {
702   GstFFMpegAudEnc *ffmpegaudenc;
703 
704   ffmpegaudenc = (GstFFMpegAudEnc *) (object);
705 
706   switch (prop_id) {
707     default:
708       if (!gst_ffmpeg_cfg_get_property (ffmpegaudenc->refcontext, value, pspec))
709         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
710       break;
711   }
712 }
713 
714 gboolean
gst_ffmpegaudenc_register(GstPlugin * plugin)715 gst_ffmpegaudenc_register (GstPlugin * plugin)
716 {
717   GTypeInfo typeinfo = {
718     sizeof (GstFFMpegAudEncClass),
719     (GBaseInitFunc) gst_ffmpegaudenc_base_init,
720     NULL,
721     (GClassInitFunc) gst_ffmpegaudenc_class_init,
722     NULL,
723     NULL,
724     sizeof (GstFFMpegAudEnc),
725     0,
726     (GInstanceInitFunc) gst_ffmpegaudenc_init,
727   };
728   GType type;
729   AVCodec *in_plugin;
730   void *i = 0;
731 
732 
733   GST_LOG ("Registering encoders");
734 
735   while ((in_plugin = (AVCodec *) av_codec_iterate (&i))) {
736     gchar *type_name;
737     guint rank;
738 
739     /* Skip non-AV codecs */
740     if (in_plugin->type != AVMEDIA_TYPE_AUDIO)
741       continue;
742 
743     /* no quasi codecs, please */
744     if (in_plugin->id == AV_CODEC_ID_PCM_S16LE_PLANAR ||
745         (in_plugin->id >= AV_CODEC_ID_PCM_S16LE &&
746             in_plugin->id <= AV_CODEC_ID_PCM_BLURAY) ||
747         (in_plugin->id >= AV_CODEC_ID_PCM_S8_PLANAR &&
748             in_plugin->id <= AV_CODEC_ID_PCM_F24LE)) {
749       continue;
750     }
751 
752     /* No encoders depending on external libraries (we don't build them, but
753      * people who build against an external ffmpeg might have them.
754      * We have native gstreamer plugins for all of those libraries anyway. */
755     if (!strncmp (in_plugin->name, "lib", 3)) {
756       GST_DEBUG
757           ("Not using external library encoder %s. Use the gstreamer-native ones instead.",
758           in_plugin->name);
759       continue;
760     }
761 
762     /* only encoders */
763     if (!av_codec_is_encoder (in_plugin)) {
764       continue;
765     }
766 
767     /* FIXME : We should have a method to know cheaply whether we have a mapping
768      * for the given plugin or not */
769 
770     GST_DEBUG ("Trying plugin %s [%s]", in_plugin->name, in_plugin->long_name);
771 
772     /* no codecs for which we're GUARANTEED to have better alternatives */
773     if (!strcmp (in_plugin->name, "vorbis")
774         || !strcmp (in_plugin->name, "flac")) {
775       GST_LOG ("Ignoring encoder %s", in_plugin->name);
776       continue;
777     }
778 
779     /* construct the type */
780     type_name = g_strdup_printf ("avenc_%s", in_plugin->name);
781 
782     type = g_type_from_name (type_name);
783 
784     if (!type) {
785 
786       /* create the glib type now */
787       type =
788           g_type_register_static (GST_TYPE_AUDIO_ENCODER, type_name, &typeinfo,
789           0);
790       g_type_set_qdata (type, GST_FFENC_PARAMS_QDATA, (gpointer) in_plugin);
791 
792       {
793         static const GInterfaceInfo preset_info = {
794           NULL,
795           NULL,
796           NULL
797         };
798         g_type_add_interface_static (type, GST_TYPE_PRESET, &preset_info);
799       }
800     }
801 
802     switch (in_plugin->id) {
803         /* avenc_aac: see https://bugzilla.gnome.org/show_bug.cgi?id=691617 */
804       case AV_CODEC_ID_AAC:
805         rank = GST_RANK_NONE;
806         break;
807       default:
808         rank = GST_RANK_SECONDARY;
809         break;
810     }
811 
812     if (!gst_element_register (plugin, type_name, rank, type)) {
813       g_free (type_name);
814       return FALSE;
815     }
816 
817     g_free (type_name);
818   }
819 
820   GST_LOG ("Finished registering encoders");
821 
822   return TRUE;
823 }
824