• 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   avcodec_free_context (&ffmpegaudenc->context);
179   avcodec_free_context (&ffmpegaudenc->refcontext);
180 
181   G_OBJECT_CLASS (parent_class)->finalize (object);
182 }
183 
184 static gboolean
gst_ffmpegaudenc_start(GstAudioEncoder * encoder)185 gst_ffmpegaudenc_start (GstAudioEncoder * encoder)
186 {
187   GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
188   GstFFMpegAudEncClass *oclass =
189       (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);
190 
191   ffmpegaudenc->opened = FALSE;
192   ffmpegaudenc->need_reopen = FALSE;
193 
194   avcodec_free_context (&ffmpegaudenc->context);
195   ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
196   if (ffmpegaudenc->context == NULL) {
197     GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
198     return FALSE;
199   }
200 
201   return TRUE;
202 }
203 
204 static gboolean
gst_ffmpegaudenc_stop(GstAudioEncoder * encoder)205 gst_ffmpegaudenc_stop (GstAudioEncoder * encoder)
206 {
207   GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
208 
209   /* close old session */
210   gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
211   ffmpegaudenc->opened = FALSE;
212   ffmpegaudenc->need_reopen = FALSE;
213 
214   return TRUE;
215 }
216 
217 static void
gst_ffmpegaudenc_flush(GstAudioEncoder * encoder)218 gst_ffmpegaudenc_flush (GstAudioEncoder * encoder)
219 {
220   GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
221 
222   if (ffmpegaudenc->opened) {
223     avcodec_flush_buffers (ffmpegaudenc->context);
224   }
225 }
226 
227 static gboolean
gst_ffmpegaudenc_set_format(GstAudioEncoder * encoder,GstAudioInfo * info)228 gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info)
229 {
230   GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
231   GstCaps *other_caps;
232   GstCaps *allowed_caps;
233   GstCaps *icaps;
234   gsize frame_size;
235   GstFFMpegAudEncClass *oclass =
236       (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);
237 
238   ffmpegaudenc->need_reopen = FALSE;
239 
240   /* close old session */
241   if (ffmpegaudenc->opened) {
242     avcodec_free_context (&ffmpegaudenc->context);
243     ffmpegaudenc->opened = FALSE;
244     ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
245     if (ffmpegaudenc->context == NULL) {
246       GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
247       return FALSE;
248     }
249   }
250 
251   gst_ffmpeg_cfg_fill_context (G_OBJECT (ffmpegaudenc), ffmpegaudenc->context);
252 
253   /* fetch pix_fmt and so on */
254   gst_ffmpeg_audioinfo_to_context (info, ffmpegaudenc->context);
255   if (!ffmpegaudenc->context->time_base.den) {
256     ffmpegaudenc->context->time_base.den = GST_AUDIO_INFO_RATE (info);
257     ffmpegaudenc->context->time_base.num = 1;
258     ffmpegaudenc->context->ticks_per_frame = 1;
259   }
260 
261   if (ffmpegaudenc->context->channel_layout) {
262     gst_ffmpeg_channel_layout_to_gst (ffmpegaudenc->context->channel_layout,
263         ffmpegaudenc->context->channels, ffmpegaudenc->ffmpeg_layout);
264     ffmpegaudenc->needs_reorder =
265         (memcmp (ffmpegaudenc->ffmpeg_layout, info->position,
266             sizeof (GstAudioChannelPosition) *
267             ffmpegaudenc->context->channels) != 0);
268   }
269 
270   /* some codecs support more than one format, first auto-choose one */
271   GST_DEBUG_OBJECT (ffmpegaudenc, "picking an output format ...");
272   allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder));
273   if (!allowed_caps) {
274     GST_DEBUG_OBJECT (ffmpegaudenc, "... but no peer, using template caps");
275     /* we need to copy because get_allowed_caps returns a ref, and
276      * get_pad_template_caps doesn't */
277     allowed_caps =
278         gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder));
279   }
280   GST_DEBUG_OBJECT (ffmpegaudenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
281   gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
282       oclass->in_plugin->type, allowed_caps, ffmpegaudenc->context);
283 
284   /* open codec */
285   if (gst_ffmpeg_avcodec_open (ffmpegaudenc->context, oclass->in_plugin) < 0) {
286     gst_caps_unref (allowed_caps);
287     avcodec_free_context (&ffmpegaudenc->context);
288     GST_DEBUG_OBJECT (ffmpegaudenc, "avenc_%s: Failed to open FFMPEG codec",
289         oclass->in_plugin->name);
290     ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
291     if (ffmpegaudenc->context == NULL)
292       GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
293 
294     if ((oclass->in_plugin->capabilities & AV_CODEC_CAP_EXPERIMENTAL) &&
295         ffmpegaudenc->context->strict_std_compliance !=
296         FF_COMPLIANCE_EXPERIMENTAL) {
297       GST_ELEMENT_ERROR (ffmpegaudenc, LIBRARY, SETTINGS,
298           ("Codec is experimental, but settings don't allow encoders to "
299               "produce output of experimental quality"),
300           ("This codec may not create output that is conformant to the specs "
301               "or of good quality. If you must use it anyway, set the "
302               "compliance property to experimental"));
303     }
304     return FALSE;
305   }
306 
307   /* try to set this caps on the other side */
308   other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id,
309       ffmpegaudenc->context, TRUE);
310 
311   if (!other_caps) {
312     gst_caps_unref (allowed_caps);
313     avcodec_free_context (&ffmpegaudenc->context);
314     GST_DEBUG ("Unsupported codec - no caps found");
315     ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
316     if (ffmpegaudenc->context == NULL)
317       GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
318     return FALSE;
319   }
320 
321   icaps = gst_caps_intersect (allowed_caps, other_caps);
322   gst_caps_unref (allowed_caps);
323   gst_caps_unref (other_caps);
324   if (gst_caps_is_empty (icaps)) {
325     gst_caps_unref (icaps);
326     return FALSE;
327   }
328   icaps = gst_caps_fixate (icaps);
329 
330   if (!gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (ffmpegaudenc),
331           icaps)) {
332     avcodec_free_context (&ffmpegaudenc->context);
333     gst_caps_unref (icaps);
334     ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
335     if (ffmpegaudenc->context == NULL)
336       GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
337     return FALSE;
338   }
339   gst_caps_unref (icaps);
340 
341   frame_size = ffmpegaudenc->context->frame_size;
342   if (frame_size > 1) {
343     gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc),
344         frame_size);
345     gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc),
346         frame_size);
347     gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 1);
348   } else {
349     gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc),
350         0);
351     gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc),
352         0);
353     gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 0);
354   }
355 
356   /* Store some tags */
357   {
358     GstTagList *tags = gst_tag_list_new_empty ();
359     const gchar *codec;
360 
361     gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
362         (guint) ffmpegaudenc->context->bit_rate, NULL);
363 
364     if ((codec =
365             gst_ffmpeg_get_codecid_longname (ffmpegaudenc->context->codec_id)))
366       gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, codec,
367           NULL);
368 
369     gst_audio_encoder_merge_tags (encoder, tags, GST_TAG_MERGE_REPLACE);
370     gst_tag_list_unref (tags);
371   }
372 
373   /* success! */
374   ffmpegaudenc->opened = TRUE;
375   ffmpegaudenc->need_reopen = FALSE;
376 
377   return TRUE;
378 }
379 
380 static void
gst_ffmpegaudenc_free_avpacket(gpointer pkt)381 gst_ffmpegaudenc_free_avpacket (gpointer pkt)
382 {
383   av_packet_unref ((AVPacket *) pkt);
384   g_slice_free (AVPacket, pkt);
385 }
386 
387 typedef struct
388 {
389   GstBuffer *buffer;
390   GstMapInfo map;
391 
392   guint8 **ext_data_array, *ext_data;
393 } BufferInfo;
394 
395 static void
buffer_info_free(void * opaque,guint8 * data)396 buffer_info_free (void *opaque, guint8 * data)
397 {
398   BufferInfo *info = opaque;
399 
400   if (info->buffer) {
401     gst_buffer_unmap (info->buffer, &info->map);
402     gst_buffer_unref (info->buffer);
403   } else {
404     av_freep (&info->ext_data);
405     av_freep (&info->ext_data_array);
406   }
407   g_slice_free (BufferInfo, info);
408 }
409 
410 static GstFlowReturn
gst_ffmpegaudenc_send_frame(GstFFMpegAudEnc * ffmpegaudenc,GstBuffer * buffer)411 gst_ffmpegaudenc_send_frame (GstFFMpegAudEnc * ffmpegaudenc, GstBuffer * buffer)
412 {
413   GstAudioEncoder *enc;
414   AVCodecContext *ctx;
415   GstFlowReturn ret;
416   gint res;
417   GstAudioInfo *info;
418   AVFrame *frame = ffmpegaudenc->frame;
419   gboolean planar;
420   gint nsamples = -1;
421 
422   enc = GST_AUDIO_ENCODER (ffmpegaudenc);
423 
424   ctx = ffmpegaudenc->context;
425 
426   if (buffer != NULL) {
427     BufferInfo *buffer_info = g_slice_new0 (BufferInfo);
428     guint8 *audio_in;
429     guint in_size;
430 
431     buffer_info->buffer = buffer;
432     gst_buffer_map (buffer, &buffer_info->map, GST_MAP_READ);
433     audio_in = buffer_info->map.data;
434     in_size = buffer_info->map.size;
435 
436     GST_LOG_OBJECT (ffmpegaudenc, "encoding buffer %p size:%u", audio_in,
437         in_size);
438 
439     info = gst_audio_encoder_get_audio_info (enc);
440     planar = av_sample_fmt_is_planar (ffmpegaudenc->context->sample_fmt);
441     frame->format = ffmpegaudenc->context->sample_fmt;
442     frame->sample_rate = ffmpegaudenc->context->sample_rate;
443     frame->channels = ffmpegaudenc->context->channels;
444     frame->channel_layout = ffmpegaudenc->context->channel_layout;
445 
446     if (planar && info->channels > 1) {
447       gint channels;
448       gint i, j;
449 
450       nsamples = frame->nb_samples = in_size / info->bpf;
451       channels = info->channels;
452 
453       frame->buf[0] =
454           av_buffer_create (NULL, 0, buffer_info_free, buffer_info, 0);
455 
456       if (info->channels > AV_NUM_DATA_POINTERS) {
457         buffer_info->ext_data_array = frame->extended_data =
458             av_malloc_array (info->channels, sizeof (uint8_t *));
459       } else {
460         frame->extended_data = frame->data;
461       }
462 
463       buffer_info->ext_data = frame->extended_data[0] = av_malloc (in_size);
464       frame->linesize[0] = in_size / channels;
465       for (i = 1; i < channels; i++)
466         frame->extended_data[i] =
467             frame->extended_data[i - 1] + frame->linesize[0];
468 
469       switch (info->finfo->width) {
470         case 8:{
471           const guint8 *idata = (const guint8 *) audio_in;
472 
473           for (i = 0; i < nsamples; i++) {
474             for (j = 0; j < channels; j++) {
475               ((guint8 *) frame->extended_data[j])[i] = idata[j];
476             }
477             idata += channels;
478           }
479           break;
480         }
481         case 16:{
482           const guint16 *idata = (const guint16 *) audio_in;
483 
484           for (i = 0; i < nsamples; i++) {
485             for (j = 0; j < channels; j++) {
486               ((guint16 *) frame->extended_data[j])[i] = idata[j];
487             }
488             idata += channels;
489           }
490           break;
491         }
492         case 32:{
493           const guint32 *idata = (const guint32 *) audio_in;
494 
495           for (i = 0; i < nsamples; i++) {
496             for (j = 0; j < channels; j++) {
497               ((guint32 *) frame->extended_data[j])[i] = idata[j];
498             }
499             idata += channels;
500           }
501 
502           break;
503         }
504         case 64:{
505           const guint64 *idata = (const guint64 *) audio_in;
506 
507           for (i = 0; i < nsamples; i++) {
508             for (j = 0; j < channels; j++) {
509               ((guint64 *) frame->extended_data[j])[i] = idata[j];
510             }
511             idata += channels;
512           }
513 
514           break;
515         }
516         default:
517           g_assert_not_reached ();
518           break;
519       }
520 
521       gst_buffer_unmap (buffer, &buffer_info->map);
522       gst_buffer_unref (buffer);
523       buffer_info->buffer = NULL;
524     } else {
525       frame->data[0] = audio_in;
526       frame->extended_data = frame->data;
527       frame->linesize[0] = in_size;
528       frame->nb_samples = nsamples = in_size / info->bpf;
529       frame->buf[0] =
530           av_buffer_create (NULL, 0, buffer_info_free, buffer_info, 0);
531     }
532 
533     /* we have a frame to feed the encoder */
534     res = avcodec_send_frame (ctx, frame);
535 
536     av_frame_unref (frame);
537   } else {
538     GstFFMpegAudEncClass *oclass =
539         (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);
540 
541     GST_LOG_OBJECT (ffmpegaudenc, "draining");
542     /* flushing the encoder */
543     res = avcodec_send_frame (ctx, NULL);
544 
545     /* If AV_CODEC_CAP_ENCODER_FLUSH wasn't set, we need to re-open
546      * encoder */
547     if (!(oclass->in_plugin->capabilities & AV_CODEC_CAP_ENCODER_FLUSH)) {
548       GST_DEBUG_OBJECT (ffmpegaudenc, "Encoder needs reopen later");
549 
550       /* we will reopen later handle_frame() */
551       ffmpegaudenc->need_reopen = TRUE;
552     }
553   }
554 
555   if (res == 0) {
556     ret = GST_FLOW_OK;
557   } else if (res == AVERROR_EOF) {
558     ret = GST_FLOW_EOS;
559   } else {                      /* Any other return value is an error in our context */
560     ret = GST_FLOW_OK;
561     GST_WARNING_OBJECT (ffmpegaudenc, "Failed to encode buffer");
562   }
563 
564   return ret;
565 }
566 
567 static GstFlowReturn
gst_ffmpegaudenc_receive_packet(GstFFMpegAudEnc * ffmpegaudenc,gboolean * got_packet)568 gst_ffmpegaudenc_receive_packet (GstFFMpegAudEnc * ffmpegaudenc,
569     gboolean * got_packet)
570 {
571   GstAudioEncoder *enc;
572   AVCodecContext *ctx;
573   gint res;
574   GstFlowReturn ret;
575   AVPacket *pkt;
576 
577   enc = GST_AUDIO_ENCODER (ffmpegaudenc);
578 
579   ctx = ffmpegaudenc->context;
580 
581   pkt = g_slice_new0 (AVPacket);
582 
583   res = avcodec_receive_packet (ctx, pkt);
584 
585   if (res == 0) {
586     GstBuffer *outbuf;
587 
588     GST_LOG_OBJECT (ffmpegaudenc, "pushing size %d", pkt->size);
589 
590     outbuf =
591         gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, pkt->data,
592         pkt->size, 0, pkt->size, pkt, gst_ffmpegaudenc_free_avpacket);
593 
594     ret =
595         gst_audio_encoder_finish_frame (enc, outbuf,
596         pkt->duration > 0 ? pkt->duration : -1);
597     *got_packet = TRUE;
598   } else {
599     GST_LOG_OBJECT (ffmpegaudenc, "no output produced");
600     g_slice_free (AVPacket, pkt);
601     ret = GST_FLOW_OK;
602     *got_packet = FALSE;
603   }
604 
605   return ret;
606 }
607 
608 static GstFlowReturn
gst_ffmpegaudenc_drain(GstFFMpegAudEnc * ffmpegaudenc)609 gst_ffmpegaudenc_drain (GstFFMpegAudEnc * ffmpegaudenc)
610 {
611   GstFlowReturn ret = GST_FLOW_OK;
612   gboolean got_packet;
613 
614   ret = gst_ffmpegaudenc_send_frame (ffmpegaudenc, NULL);
615 
616   if (ret == GST_FLOW_OK) {
617     do {
618       ret = gst_ffmpegaudenc_receive_packet (ffmpegaudenc, &got_packet);
619       if (ret != GST_FLOW_OK)
620         break;
621     } while (got_packet);
622   }
623 
624   /* NOTE: this may or may not work depending on capability */
625   avcodec_flush_buffers (ffmpegaudenc->context);
626 
627   /* FFMpeg will return AVERROR_EOF if it's internal was fully drained
628    * then we are translating it to GST_FLOW_EOS. However, because this behavior
629    * is fully internal stuff of this implementation and gstaudioencoder
630    * baseclass doesn't convert this GST_FLOW_EOS to GST_FLOW_OK,
631    * convert this flow returned here */
632   if (ret == GST_FLOW_EOS)
633     ret = GST_FLOW_OK;
634 
635   return ret;
636 }
637 
638 static GstFlowReturn
gst_ffmpegaudenc_handle_frame(GstAudioEncoder * encoder,GstBuffer * inbuf)639 gst_ffmpegaudenc_handle_frame (GstAudioEncoder * encoder, GstBuffer * inbuf)
640 {
641   GstFFMpegAudEnc *ffmpegaudenc;
642   GstFlowReturn ret;
643   gboolean got_packet;
644 
645   ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
646 
647   if (G_UNLIKELY (!ffmpegaudenc->opened))
648     goto not_negotiated;
649 
650   if (!inbuf)
651     return gst_ffmpegaudenc_drain (ffmpegaudenc);
652 
653   /* endoder was drained or flushed, and ffmpeg encoder doesn't support
654    * flushing. We need to re-open encoder then */
655   if (ffmpegaudenc->need_reopen) {
656     GST_DEBUG_OBJECT (ffmpegaudenc, "Open encoder again");
657 
658     if (!gst_ffmpegaudenc_set_format (encoder,
659             gst_audio_encoder_get_audio_info (encoder))) {
660       GST_ERROR_OBJECT (ffmpegaudenc, "Couldn't re-open encoder");
661       return GST_FLOW_NOT_NEGOTIATED;
662     }
663   }
664 
665   inbuf = gst_buffer_ref (inbuf);
666 
667   GST_DEBUG_OBJECT (ffmpegaudenc,
668       "Received time %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT
669       ", size %" G_GSIZE_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
670       GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)), gst_buffer_get_size (inbuf));
671 
672   /* Reorder channels to the GStreamer channel order */
673   if (ffmpegaudenc->needs_reorder) {
674     GstAudioInfo *info = gst_audio_encoder_get_audio_info (encoder);
675 
676     inbuf = gst_buffer_make_writable (inbuf);
677     gst_audio_buffer_reorder_channels (inbuf, info->finfo->format,
678         info->channels, info->position, ffmpegaudenc->ffmpeg_layout);
679   }
680 
681   ret = gst_ffmpegaudenc_send_frame (ffmpegaudenc, inbuf);
682 
683   if (ret != GST_FLOW_OK)
684     goto send_frame_failed;
685 
686   do {
687     ret = gst_ffmpegaudenc_receive_packet (ffmpegaudenc, &got_packet);
688   } while (got_packet);
689 
690   return GST_FLOW_OK;
691 
692   /* ERRORS */
693 not_negotiated:
694   {
695     GST_ELEMENT_ERROR (ffmpegaudenc, CORE, NEGOTIATION, (NULL),
696         ("not configured to input format before data start"));
697     gst_buffer_unref (inbuf);
698     return GST_FLOW_NOT_NEGOTIATED;
699   }
700 send_frame_failed:
701   {
702     GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to send frame %d (%s)", ret,
703         gst_flow_get_name (ret));
704     return ret;
705   }
706 }
707 
708 static void
gst_ffmpegaudenc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)709 gst_ffmpegaudenc_set_property (GObject * object,
710     guint prop_id, const GValue * value, GParamSpec * pspec)
711 {
712   GstFFMpegAudEnc *ffmpegaudenc;
713 
714   ffmpegaudenc = (GstFFMpegAudEnc *) (object);
715 
716   if (ffmpegaudenc->opened) {
717     GST_WARNING_OBJECT (ffmpegaudenc,
718         "Can't change properties once encoder is setup !");
719     return;
720   }
721 
722   switch (prop_id) {
723     default:
724       if (!gst_ffmpeg_cfg_set_property (ffmpegaudenc->refcontext, value, pspec))
725         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
726       break;
727   }
728 }
729 
730 static void
gst_ffmpegaudenc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)731 gst_ffmpegaudenc_get_property (GObject * object,
732     guint prop_id, GValue * value, GParamSpec * pspec)
733 {
734   GstFFMpegAudEnc *ffmpegaudenc;
735 
736   ffmpegaudenc = (GstFFMpegAudEnc *) (object);
737 
738   switch (prop_id) {
739     default:
740       if (!gst_ffmpeg_cfg_get_property (ffmpegaudenc->refcontext, value, pspec))
741         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
742       break;
743   }
744 }
745 
746 gboolean
gst_ffmpegaudenc_register(GstPlugin * plugin)747 gst_ffmpegaudenc_register (GstPlugin * plugin)
748 {
749   GTypeInfo typeinfo = {
750     sizeof (GstFFMpegAudEncClass),
751     (GBaseInitFunc) gst_ffmpegaudenc_base_init,
752     NULL,
753     (GClassInitFunc) gst_ffmpegaudenc_class_init,
754     NULL,
755     NULL,
756     sizeof (GstFFMpegAudEnc),
757     0,
758     (GInstanceInitFunc) gst_ffmpegaudenc_init,
759   };
760   GType type;
761   AVCodec *in_plugin;
762   void *i = 0;
763 
764 
765   GST_LOG ("Registering encoders");
766 
767   while ((in_plugin = (AVCodec *) av_codec_iterate (&i))) {
768     gchar *type_name;
769     guint rank;
770 
771     /* Skip non-AV codecs */
772     if (in_plugin->type != AVMEDIA_TYPE_AUDIO)
773       continue;
774 
775     /* no quasi codecs, please */
776     if (in_plugin->id == AV_CODEC_ID_PCM_S16LE_PLANAR ||
777         (in_plugin->id >= AV_CODEC_ID_PCM_S16LE &&
778             in_plugin->id <= AV_CODEC_ID_PCM_BLURAY) ||
779         (in_plugin->id >= AV_CODEC_ID_PCM_S8_PLANAR &&
780             in_plugin->id <= AV_CODEC_ID_PCM_F24LE)) {
781       continue;
782     }
783 
784     /* No encoders depending on external libraries (we don't build them, but
785      * people who build against an external ffmpeg might have them.
786      * We have native gstreamer plugins for all of those libraries anyway. */
787     if (!strncmp (in_plugin->name, "lib", 3)) {
788       GST_DEBUG
789           ("Not using external library encoder %s. Use the gstreamer-native ones instead.",
790           in_plugin->name);
791       continue;
792     }
793 
794     /* only encoders */
795     if (!av_codec_is_encoder (in_plugin)) {
796       continue;
797     }
798 
799     /* FIXME : We should have a method to know cheaply whether we have a mapping
800      * for the given plugin or not */
801 
802     GST_DEBUG ("Trying plugin %s [%s]", in_plugin->name, in_plugin->long_name);
803 
804     /* no codecs for which we're GUARANTEED to have better alternatives */
805     if (!strcmp (in_plugin->name, "vorbis")
806         || !strcmp (in_plugin->name, "flac")) {
807       GST_LOG ("Ignoring encoder %s", in_plugin->name);
808       continue;
809     }
810 
811     /* construct the type */
812     type_name = g_strdup_printf ("avenc_%s", in_plugin->name);
813 
814     type = g_type_from_name (type_name);
815 
816     if (!type) {
817 
818       /* create the glib type now */
819       type =
820           g_type_register_static (GST_TYPE_AUDIO_ENCODER, type_name, &typeinfo,
821           0);
822 /**
823  * ohos.opt.compat.0031
824  * Fix Flush at eos and flush opearte.
825  * Enable flush audenc cap to flush.
826  */
827 #ifdef OHOS_OPT_COMPAT
828       in_plugin->capabilities |= AV_CODEC_CAP_ENCODER_FLUSH;
829 #endif
830       g_type_set_qdata (type, GST_FFENC_PARAMS_QDATA, (gpointer) in_plugin);
831 
832       {
833         static const GInterfaceInfo preset_info = {
834           NULL,
835           NULL,
836           NULL
837         };
838         g_type_add_interface_static (type, GST_TYPE_PRESET, &preset_info);
839       }
840     }
841 
842     switch (in_plugin->id) {
843         /* avenc_aac: see https://bugzilla.gnome.org/show_bug.cgi?id=691617 */
844       case AV_CODEC_ID_AAC:
845         rank = GST_RANK_NONE;
846         break;
847       default:
848         rank = GST_RANK_SECONDARY;
849         break;
850     }
851 
852     if (!gst_element_register (plugin, type_name, rank, type)) {
853       g_free (type_name);
854       return FALSE;
855     }
856 
857     g_free (type_name);
858   }
859 
860   GST_LOG ("Finished registering encoders");
861 
862   return TRUE;
863 }
864