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