2 * GStreamer codec plugin for Tizen Emulator.
4 * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved.
7 * KiTae Kim <kt920.kim@samsung.com>
8 * SeokYeon Hwang <syeon.hwang@samsung.com>
9 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public
22 * License along with this library; if not, write to the
23 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 * Boston, MA 02111-1307, USA.
31 #include "gstemulutils.h"
32 #include "gstemulapi.h"
33 #include "gstemuldev.h"
34 #include <gst/base/gstadapter.h>
36 #define GST_EMULENC_PARAMS_QDATA g_quark_from_static_string("maruenc-params")
38 typedef struct _GstEmulEnc
45 CodecContext *context;
48 GstClockTime adapter_ts;
49 guint64 adapter_consumed;
59 gulong working_buf_size;
65 typedef struct _GstEmulEncClass
67 GstElementClass parent_class;
70 GstPadTemplate *sinktempl;
71 GstPadTemplate *srctempl;
75 static GstElementClass *parent_class = NULL;
77 static void gst_emulenc_base_init (GstEmulEncClass *klass);
78 static void gst_emulenc_class_init (GstEmulEncClass *klass);
79 static void gst_emulenc_init (GstEmulEnc *emulenc);
80 static void gst_emulenc_finalize (GObject *object);
82 static gboolean gst_emulenc_setcaps (GstPad *pad, GstCaps *caps);
83 static GstCaps *gst_emulenc_getcaps (GstPad *pad);
85 static GstCaps *gst_emulenc_get_possible_sizes (GstEmulEnc *emulenc,
86 GstPad *pad, const GstCaps *caps);
88 static GstFlowReturn gst_emulenc_chain_video (GstPad *pad, GstBuffer *buffer);
89 static GstFlowReturn gst_emulenc_chain_audio (GstPad *pad, GstBuffer *buffer);
91 static gboolean gst_emulenc_event_video (GstPad *pad, GstEvent *event);
92 static gboolean gst_emulenc_event_src (GstPad *pad, GstEvent *event);
94 GstStateChangeReturn gst_emulenc_change_state (GstElement *element, GstStateChange transition);
96 #define DEFAULT_VIDEO_BITRATE 300000
97 #define DEFAULT_VIDEO_GOP_SIZE 15
98 #define DEFAULT_AUDIO_BITRATE 128000
100 #define DEFAULT_WIDTH 352
101 #define DEFAULT_HEIGHT 288
107 gst_emulenc_base_init (GstEmulEncClass *klass)
109 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
110 GstPadTemplate *sinktempl = NULL, *srctempl = NULL;
111 GstCaps *sinkcaps = NULL, *srccaps = NULL;
113 gchar *longname, *classification, *description;
116 (CodecElement *)g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
117 GST_EMULENC_PARAMS_QDATA);
119 longname = g_strdup_printf ("%s Encoder", codec->longname);
120 classification = g_strdup_printf ("Codec/Encoder/%s",
121 (codec->media_type == AVMEDIA_TYPE_VIDEO) ? "Video" : "Audio");
122 description = g_strdup_printf ("%s Encoder", codec->name);
124 gst_element_class_set_details_simple (element_class,
128 // "accelerated codec for Tizen Emulator",
129 "Kitae Kim <kt920.kim@samsung.com>");
132 g_free (classification);
135 if (!(srccaps = gst_emul_codecname_to_caps (codec->name, NULL, TRUE))) {
136 GST_DEBUG ("Couldn't get source caps for encoder '%s'", codec->name);
137 srccaps = gst_caps_new_simple ("unknown/unknown", NULL);
140 switch (codec->media_type) {
141 case AVMEDIA_TYPE_VIDEO:
142 sinkcaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv; video/x-raw-gray");
144 case AVMEDIA_TYPE_AUDIO:
145 sinkcaps = gst_emul_codectype_to_audio_caps (NULL, codec->name, TRUE, codec);
148 GST_LOG("unknown media type.\n");
153 GST_DEBUG ("Couldn't get sink caps for encoder '%s'", codec->name);
154 sinkcaps = gst_caps_new_simple ("unknown/unknown", NULL);
157 sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
158 GST_PAD_ALWAYS, sinkcaps);
159 srctempl = gst_pad_template_new ("src", GST_PAD_SRC,
160 GST_PAD_ALWAYS, srccaps);
162 gst_element_class_add_pad_template (element_class, srctempl);
163 gst_element_class_add_pad_template (element_class, sinktempl);
165 klass->codec = codec;
166 klass->sinktempl = sinktempl;
167 klass->srctempl = srctempl;
168 klass->sinkcaps = NULL;
172 gst_emulenc_class_init (GstEmulEncClass *klass)
174 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
175 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
177 parent_class = g_type_class_peek_parent (klass);
180 gobject_class->set_property = gst_emulenc_set_property
181 gobject_class->get_property = gst_emulenc_get_property
184 gstelement_class->change_state = gst_emulenc_change_state;
186 gobject_class->finalize = gst_emulenc_finalize;
190 gst_emulenc_init (GstEmulEnc *emulenc)
192 GstEmulEncClass *oclass;
193 oclass = (GstEmulEncClass*) (G_OBJECT_GET_CLASS(emulenc));
195 emulenc->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
196 gst_pad_set_setcaps_function (emulenc->sinkpad,
197 GST_DEBUG_FUNCPTR(gst_emulenc_setcaps));
198 gst_pad_set_getcaps_function (emulenc->sinkpad,
199 GST_DEBUG_FUNCPTR(gst_emulenc_getcaps));
201 emulenc->srcpad = gst_pad_new_from_template (oclass->srctempl, "src");
202 gst_pad_use_fixed_caps (emulenc->srcpad);
204 if (oclass->codec->media_type == AVMEDIA_TYPE_VIDEO) {
205 gst_pad_set_chain_function (emulenc->sinkpad, gst_emulenc_chain_video);
206 gst_pad_set_event_function (emulenc->sinkpad, gst_emulenc_event_video);
207 gst_pad_set_event_function (emulenc->srcpad, gst_emulenc_event_src);
209 emulenc->bitrate = DEFAULT_VIDEO_BITRATE;
210 emulenc->buffer_size = 512 * 1024;
211 emulenc->gop_size = DEFAULT_VIDEO_GOP_SIZE;
216 } else if (oclass->codec->media_type == AVMEDIA_TYPE_AUDIO){
217 gst_pad_set_chain_function (emulenc->sinkpad, gst_emulenc_chain_audio);
218 emulenc->bitrate = DEFAULT_AUDIO_BITRATE;
221 gst_element_add_pad (GST_ELEMENT (emulenc), emulenc->sinkpad);
222 gst_element_add_pad (GST_ELEMENT (emulenc), emulenc->srcpad);
225 emulenc->context = g_malloc0 (sizeof(CodecContext));
226 if (!emulenc->context) {
227 printf("failed to allocate memory.\n");
229 emulenc->context->video.pix_fmt = PIX_FMT_NONE;
230 emulenc->context->audio.sample_fmt = SAMPLE_FMT_NONE;
232 emulenc->opened = FALSE;
235 emulenc->file = NULL;
237 emulenc->delay = g_queue_new ();
239 emulenc->dev = g_malloc0 (sizeof(CodecDevice));
241 printf("failed to allocate memory.\n");
244 // need to know what adapter does.
245 emulenc->adapter = gst_adapter_new ();
249 gst_emulenc_finalize (GObject *object)
252 GstEmulEnc *emulenc = (GstEmulEnc *) object;
254 if (emulenc->opened) {
255 gst_emul_avcodec_close (emulenc->context, emulenc->dev);
256 emulenc->opened = FALSE;
259 if (emulenc->context) {
260 g_free (emulenc->context);
261 emulenc->context = NULL;
264 g_queue_free (emulenc->delay);
266 g_free (emulenc->filename);
269 g_object_unref (emulenc->adapter);
271 G_OBJECT_CLASS (parent_class)->finalize (object);
275 gst_emulenc_get_possible_sizes (GstEmulEnc *emulenc, GstPad *pad,
278 GstCaps *othercaps = NULL;
279 GstCaps *tmpcaps = NULL;
280 GstCaps *intersect = NULL;
283 othercaps = gst_pad_peer_get_caps (emulenc->srcpad);
286 return gst_caps_copy (caps);
289 intersect = gst_caps_intersect (othercaps,
290 gst_pad_get_pad_template_caps (emulenc->srcpad));
291 gst_caps_unref (othercaps);
293 if (gst_caps_is_empty (intersect)) {
297 if (gst_caps_is_any (intersect)) {
298 return gst_caps_copy (caps);
301 tmpcaps = gst_caps_new_empty ();
303 for (i = 0; i <gst_caps_get_size (intersect); i++) {
304 GstStructure *s = gst_caps_get_structure (intersect, i);
305 const GValue *height = NULL;
306 const GValue *width = NULL;
307 const GValue *framerate = NULL;
310 height = gst_structure_get_value (s, "height");
311 width = gst_structure_get_value (s, "width");
312 framerate = gst_structure_get_value (s, "framerate");
314 tmps = gst_structure_new ("video/x-rwa-rgb", NULL);
316 gst_structure_set_value (tmps, "width", width);
319 gst_structure_set_value (tmps, "height", height);
322 gst_structure_set_value (tmps, "framerate", framerate);
324 gst_caps_merge_structure (tmpcaps, gst_structure_copy (tmps));
326 gst_structure_set_name (tmps, "video/x-raw-yuv");
327 gst_caps_merge_structure (tmpcaps, gst_structure_copy (tmps));
329 gst_structure_set_name (tmps, "video/x-raw-gray");
330 gst_caps_merge_structure (tmpcaps, tmps);
332 gst_caps_unref (intersect);
334 intersect = gst_caps_intersect (caps, tmpcaps);
335 gst_caps_unref (tmpcaps);
341 gst_emulenc_getcaps (GstPad *pad)
343 GstEmulEnc *emulenc = (GstEmulEnc *) GST_PAD_PARENT (pad);
344 GstEmulEncClass *oclass =
345 (GstEmulEncClass *) G_OBJECT_GET_CLASS (emulenc);
346 CodecContext *ctx = NULL;
347 enum PixelFormat pixfmt;
348 GstCaps *caps = NULL;
349 GstCaps *finalcaps = NULL;
352 GST_DEBUG_OBJECT (emulenc, "getting caps");
354 if (oclass->codec && oclass->codec->media_type == AVMEDIA_TYPE_AUDIO) {
355 caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
357 GST_DEBUG_OBJECT (emulenc, "audio caps, return template %" GST_PTR_FORMAT,
363 if (oclass->sinkcaps) {
364 caps = gst_emulenc_get_possible_sizes (emulenc, pad, oclass->sinkcaps);
365 GST_DEBUG_OBJECT (emulenc, "return cached caps %" GST_PTR_FORMAT, caps);
369 GST_DEBUG_OBJECT (emulenc, "probing caps");
373 for (pixfmt = 0;; pixfmt++) {
376 // if (oclass->codec->pix_fmts) {
377 if ((pixfmt = oclass->codec->pix_fmts[i++]) == PIX_FMT_NONE) {
378 GST_DEBUG_OBJECT (emulenc,
379 "At the end of official pixfmt for this codec, breaking out");
382 GST_DEBUG_OBJECT (emulenc,
383 "Got an official pixfmt [%d], attempting to get caps", pixfmt);
384 tmpcaps = gst_emul_pixfmt_to_caps (pixfmt, NULL, oclass->codec->name);
386 GST_DEBUG_OBJECT (emulenc, "Got caps, breaking out");
388 caps = gst_caps_new_empty ();
390 gst_caps_append (caps, tmpcaps);
393 GST_DEBUG_OBJECT (emulenc,
394 "Couldn't figure out caps without context, trying again with a context");
397 GST_DEBUG_OBJECT (emulenc, "pixfmt: %d", pixfmt);
398 if (pixfmt >= PIX_FMT_NB) {
399 GST_WARNING ("Invalid pixfmt, breaking out");
403 ctx = g_malloc0 (sizeof(CodecContext));
405 GST_DEBUG_OBJECT (emulenc, "no context");
409 ctx->video.width = DEFAULT_WIDTH;
410 ctx->video.height = DEFAULT_HEIGHT;
411 ctx->video.fps_n = 1;
412 ctx->video.fps_d = 25;
413 ctx->video.ticks_per_frame = 1;
414 ctx->bit_rate = DEFAULT_VIDEO_BITRATE;
416 // ctx->strict_std_compliance = -1;
417 ctx->video.pix_fmt = pixfmt;
419 GST_DEBUG ("Attempting to open codec");
420 if (gst_emul_avcodec_open (ctx, oclass->codec, emulenc->dev) >= 0
421 && ctx->video.pix_fmt == pixfmt) {
422 ctx->video.width = -1;
424 caps = gst_caps_new_empty ();
426 tmpcaps = gst_emul_codectype_to_caps (oclass->codec->media_type, ctx,
427 oclass->codec->name, TRUE);
429 gst_caps_append (caps, tmpcaps);
431 GST_LOG_OBJECT (emulenc,
432 "Couldn't get caps for codec: %s", oclass->codec->name);
434 gst_emul_avcodec_close (ctx, emulenc->dev);
436 GST_DEBUG_OBJECT (emulenc, "Opening codec failed with pixfmt: %d", pixfmt);
439 gst_emul_avcodec_close (ctx, emulenc->dev);
441 if (ctx->priv_data) {
442 gst_emul_avcodec_close (ctx, emulenc->dev);
450 caps = gst_emulenc_get_possible_sizes (emulenc, pad,
451 gst_pad_get_pad_template_caps (pad));
452 GST_DEBUG_OBJECT (emulenc, "probing gave nothing, "
453 "return template %" GST_PTR_FORMAT, caps);
457 GST_DEBUG_OBJECT (emulenc, "probed caps gave %" GST_PTR_FORMAT, caps);
458 oclass->sinkcaps = gst_caps_copy (caps);
460 finalcaps = gst_emulenc_get_possible_sizes (emulenc, pad, caps);
461 gst_caps_unref (caps);
467 gst_emulenc_setcaps (GstPad *pad, GstCaps *caps)
470 GstEmulEncClass *oclass;
472 GstCaps *allowed_caps;
474 enum PixelFormat pix_fmt;
477 emulenc = (GstEmulEnc *) (gst_pad_get_parent (pad));
478 oclass = (GstEmulEncClass *) (G_OBJECT_GET_CLASS (emulenc));
480 if (emulenc->opened) {
481 gst_emul_avcodec_close (emulenc->context, emulenc->dev);
482 emulenc->opened = FALSE;
484 gst_pad_set_caps (emulenc->srcpad, NULL);
487 emulenc->context->bit_rate = emulenc->bitrate;
488 GST_DEBUG_OBJECT (emulenc, "Setting context to bitrate %lu, gop_size %d",
489 emulenc->bitrate, emulenc->gop_size);
493 // user defined properties
494 emulenc->context->gop_size = emulenc->gop_size;
495 emulenc->context->lmin = (emulenc->lmin * FF_QP2LAMBDA + 0.5);
496 emulenc->context->lmax = (emulenc->lmax * FF_QP2LAMBDA + 0.5);
498 // some other defaults
499 emulenc->context->b_frame_strategy = 0;
500 emulenc->context->coder_type = 0;
501 emulenc->context->context_model = 0;
502 emulenc->context->scenechange_threshold = 0;
503 emulenc->context->inter_threshold = 0;
505 if (emulenc->interlaced) {
506 emulenc->context->flags |=
507 CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME;
508 emulenc->picture->interlaced_frame = TRUE;
510 emulenc->picture->top_field_first = TRUE;
514 gst_emul_caps_with_codectype (oclass->codec->media_type, caps, emulenc->context);
516 if (!emulenc->context->video.fps_d) {
517 emulenc->context->video.fps_d = 25;
518 emulenc->context->video.fps_n = 1;
519 } else if (!strcmp(oclass->codec->name ,"mpeg4")
520 && (emulenc->context->video.fps_d > 65535)) {
521 emulenc->context->video.fps_n =
522 (gint) gst_util_uint64_scale_int (emulenc->context->video.fps_n,
523 65535, emulenc->context->video.fps_d);
524 emulenc->context->video.fps_d = 65535;
525 GST_LOG_OBJECT (emulenc, "MPEG4 : scaled down framerate to %d / %d",
526 emulenc->context->video.fps_d, emulenc->context->video.fps_n);
529 pix_fmt = emulenc->context->video.pix_fmt;
532 switch (oclass->codec->media_type) {
533 case AVMEDIA_TYPE_VIDEO:
537 width = emulenc->context->video.width;
538 height = emulenc->context->video.height;
539 buf_size = width * height * 6 + FF_MIN_BUFFER_SIZE + 100;
542 case AVMEDIA_TYPE_AUDIO:
543 buf_size = FF_MAX_AUDIO_FRAME_SIZE + 100;
551 emulenc->dev->buf_size = gst_emul_align_size(buf_size);
554 if (gst_emul_avcodec_open (emulenc->context,
555 oclass->codec, emulenc->dev) < 0) {
556 GST_DEBUG_OBJECT (emulenc, "maru_%senc: Failed to open codec",
557 oclass->codec->name);
561 if (pix_fmt != emulenc->context->video.pix_fmt) {
562 gst_emul_avcodec_close (emulenc->context, emulenc->dev);
563 GST_DEBUG_OBJECT (emulenc,
564 "maru_%senc: AV wants different colorspace (%d given, %d wanted)",
565 oclass->codec->name, pix_fmt, emulenc->context->video.pix_fmt);
569 if (oclass->codec->media_type == AVMEDIA_TYPE_VIDEO
570 && pix_fmt == PIX_FMT_NONE) {
571 GST_DEBUG_OBJECT (emulenc, "maru_%senc: Failed to determine input format",
572 oclass->codec->name);
576 GST_DEBUG_OBJECT (emulenc, "picking an output format.");
577 allowed_caps = gst_pad_get_allowed_caps (emulenc->srcpad);
579 GST_DEBUG_OBJECT (emulenc, "but no peer, using template caps");
581 gst_caps_copy (gst_pad_get_pad_template_caps (emulenc->srcpad));
584 GST_DEBUG_OBJECT (emulenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
585 gst_emul_caps_with_codecname (oclass->codec->name,
586 oclass->codec->media_type, allowed_caps, emulenc->context);
589 gst_emul_codecname_to_caps (oclass->codec->name, emulenc->context, TRUE);
591 GST_DEBUG("Unsupported codec - no caps found");
592 gst_emul_avcodec_close (emulenc->context, emulenc->dev);
596 icaps = gst_caps_intersect (allowed_caps, other_caps);
597 gst_caps_unref (allowed_caps);
598 gst_caps_unref (other_caps);
599 if (gst_caps_is_empty (icaps)) {
600 gst_caps_unref (icaps);
604 if (gst_caps_get_size (icaps) > 1) {
608 gst_caps_new_full (gst_structure_copy (gst_caps_get_structure (icaps,
610 gst_caps_unref (icaps);
614 if (!gst_pad_set_caps (emulenc->srcpad, icaps)) {
615 gst_emul_avcodec_close (emulenc->context, emulenc->dev);
616 gst_caps_unref (icaps);
619 gst_object_unref (emulenc);
621 emulenc->opened = TRUE;
627 gst_emulenc_setup_working_buf (GstEmulEnc *emulenc)
630 emulenc->context->video.width * emulenc->context->video.height * 6 +
633 if (emulenc->working_buf == NULL ||
634 emulenc->working_buf_size != wanted_size) {
635 if (emulenc->working_buf) {
636 g_free (emulenc->working_buf);
638 emulenc->working_buf_size = wanted_size;
639 emulenc->working_buf = g_malloc0 (emulenc->working_buf_size);
641 emulenc->buffer_size = wanted_size;
645 gst_emulenc_chain_video (GstPad *pad, GstBuffer *buffer)
647 GstEmulEnc *emulenc = (GstEmulEnc *) (GST_PAD_PARENT (pad));
649 gint ret_size = 0, frame_size;
651 GST_DEBUG_OBJECT (emulenc,
652 "Received buffer of time %" GST_TIME_FORMAT,
653 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
656 GST_OBJECT_LOCK (emulenc);
657 force_keyframe = emulenc->force_keyframe;
658 emulenc->force_keyframe = FALSE;
659 GST_OBJECT_UNLOCK (emulenc);
661 if (force_keyframe) {
662 emulenc->picture->pict_type = FF_I_TYPE;
666 frame_size = gst_emul_avpicture_size (emulenc->context->video.pix_fmt,
667 emulenc->context->video.width, emulenc->context->video.height);
668 g_return_val_if_fail (frame_size == GST_BUFFER_SIZE (buffer),
672 pts = gst_emul_time_gst_to_ff (GST_BUFFER_TIMESTAMP (buffer) /
673 emulenc->context.video.ticks_per_frame,
674 emulenc->context.video.fps_n, emulen->context.video.fps_d);
677 gst_emulenc_setup_working_buf (emulenc);
680 emul_avcodec_encode_video (emulenc->context, emulenc->working_buf,
681 emulenc->working_buf_size, GST_BUFFER_DATA (buffer),
682 GST_BUFFER_SIZE (buffer), GST_BUFFER_TIMESTAMP (buffer),
686 GstEmulEncClass *oclass =
687 (GstEmulEncClass *) (G_OBJECT_GET_CLASS (emulenc));
688 GST_ERROR_OBJECT (emulenc,
689 "maru_%senc: failed to encode buffer", oclass->codec->name);
690 gst_buffer_unref (buffer);
694 g_queue_push_tail (emulenc->delay, buffer);
696 buffer = g_queue_pop_head (emulenc->delay);
702 if (emulenc->file && emulenc->context->stats_out) {
703 if (fprintf (emulenc->file, "%s", emulenc->context->stats_out) < 0) {
704 GST_ELEMENT_ERROR (emulenc, RESOURCE, WRITE,
705 (("Could not write to file \"%s\"."), emulenc->filename),
711 outbuf = gst_buffer_new_and_alloc (ret_size);
712 memcpy (GST_BUFFER_DATA (outbuf), emulenc->working_buf, ret_size);
713 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer);
714 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buffer);
716 if (emulenc->context->coded_frame) {
717 if (!emulenc->context->coded_frame->key_frame) {
718 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
721 GST_WARNING_OBJECT (emulenc, "codec did not provide keyframe info");
724 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad));
726 gst_buffer_unref (buffer);
730 if (force_keyframe) {
731 gst_pad_push_event (emulenc->srcpad,
732 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
733 gst_structure_new ("GstForceKeyUnit", "timestamp",
734 G_TYPE_UINT64, GST_BUFFER_TIMESTAMP (outbuf), NULL)));
738 return gst_pad_push (emulenc->srcpad, outbuf);
742 gst_emulenc_encode_audio (GstEmulEnc *emulenc, guint8 *audio_in,
743 guint in_size, guint max_size, GstClockTime timestamp,
744 GstClockTime duration, gboolean discont)
751 outbuf = gst_buffer_new_and_alloc (max_size + FF_MIN_BUFFER_SIZE);
752 audio_out = GST_BUFFER_DATA (outbuf);
754 GST_LOG_OBJECT (emulenc, "encoding buffer of max size %d", max_size);
755 if (emulenc->buffer_size != max_size) {
756 emulenc->buffer_size = max_size;
759 res = emul_avcodec_encode_audio (emulenc->context, audio_out, max_size,
760 audio_in, in_size, emulenc->dev);
763 GST_ERROR_OBJECT (emulenc, "Failed to encode buffer: %d", res);
764 gst_buffer_unref (outbuf);
767 GST_LOG_OBJECT (emulenc, "got output size %d", res);
769 GST_BUFFER_SIZE (outbuf) = res;
770 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
771 GST_BUFFER_DURATION (outbuf) = duration;
773 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
775 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad));
777 GST_LOG_OBJECT (emulenc, "pushing size %d, timestamp %",
778 GST_TIME_FORMAT, res, GST_TIME_ARGS (timestamp));
780 ret = gst_pad_push (emulenc->srcpad, outbuf);
786 gst_emulenc_chain_audio (GstPad *pad, GstBuffer *buffer)
789 GstEmulEncClass *oclass;
790 GstClockTime timestamp, duration;
791 guint in_size, frame_size;
799 emulenc = (GstEmulEnc *) (GST_OBJECT_PARENT (pad));
800 oclass = (GstEmulEncClass *) G_OBJECT_GET_CLASS (emulenc);
802 ctx = emulenc->context;
804 in_size = GST_BUFFER_SIZE (buffer);
805 timestamp = GST_BUFFER_TIMESTAMP (buffer);
806 duration = GST_BUFFER_DURATION (buffer);
807 discont = GST_BUFFER_IS_DISCONT (buffer);
809 GST_DEBUG_OBJECT (emulenc,
810 "Received time %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT
811 ", size %d", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration), in_size);
813 frame_size = ctx->audio.frame_size;
814 osize = ctx->audio.bits_per_smp_fmt;
816 if (frame_size > 1) {
817 guint avail, frame_bytes;
820 GST_LOG_OBJECT (emulenc, "DISCONT, clear adapter");
821 gst_adapter_clear (emulenc->adapter);
822 emulenc->discont = TRUE;
825 if (gst_adapter_available (emulenc->adapter) == 0) {
826 GST_LOG_OBJECT (emulenc, "taking buffer timestamp %" GST_TIME_FORMAT,
827 GST_TIME_ARGS (timestamp));
828 emulenc->adapter_ts = timestamp;
829 emulenc->adapter_consumed = 0;
831 GstClockTime upstream_time;
832 GstClockTime consumed_time;
836 gst_util_uint64_scale (emulenc->adapter_consumed, GST_SECOND,
837 ctx->audio.sample_rate);
838 timestamp = emulenc->adapter_ts + consumed_time;
839 GST_LOG_OBJECT (emulenc, "taking adapter timestamp %" GST_TIME_FORMAT
840 " and adding consumed time %" GST_TIME_FORMAT,
841 GST_TIME_ARGS (emulenc->adapter_ts), GST_TIME_ARGS (consumed_time));
843 upstream_time = gst_adapter_prev_timestamp (emulenc->adapter, &bytes);
844 if (GST_CLOCK_TIME_IS_VALID (upstream_time)) {
845 GstClockTimeDiff diff;
848 gst_util_uint64_scale (bytes, GST_SECOND,
849 ctx->audio.sample_rate * osize * ctx->audio.channels);
850 diff = upstream_time - timestamp;
852 if (diff > GST_SECOND / 10 || diff < -GST_SECOND / 10) {
853 GST_DEBUG_OBJECT (emulenc, "adapter timestamp drifting, "
854 "taking upstream timestamp %" GST_TIME_FORMAT,
855 GST_TIME_ARGS (upstream_time));
856 timestamp = upstream_time;
858 emulenc->adapter_consumed = bytes / (osize * ctx->audio.channels);
859 emulenc->adapter_ts =
860 upstream_time - gst_util_uint64_scale (emulenc->adapter_consumed,
861 GST_SECOND, ctx->audio.sample_rate);
862 emulenc->discont = TRUE;
867 GST_LOG_OBJECT (emulenc, "pushing buffer in adapter");
868 gst_adapter_push (emulenc->adapter, buffer);
870 frame_bytes = frame_size * osize * ctx->audio.channels;
871 avail = gst_adapter_available (emulenc->adapter);
873 GST_LOG_OBJECT (emulenc, "frame_bytes %u, avail %u", frame_bytes, avail);
875 while (avail >= frame_bytes) {
876 GST_LOG_OBJECT (emulenc, "taking %u bytes from the adapter", frame_bytes);
878 in_data = (guint8 *) gst_adapter_peek (emulenc->adapter, frame_bytes);
879 emulenc->adapter_consumed += frame_size;
882 gst_util_uint64_scale (emulenc->adapter_consumed, GST_SECOND,
883 ctx->audio.sample_rate);
884 duration -= (timestamp - emulenc->adapter_ts);
886 out_size = frame_bytes * 4;
889 gst_emulenc_encode_audio (emulenc, in_data, frame_bytes, out_size,
890 timestamp, duration, emulenc->discont);
892 gst_adapter_flush (emulenc->adapter, frame_bytes);
893 if (ret != GST_FLOW_OK) {
894 GST_DEBUG_OBJECT (emulenc, "Failed to push buffer %d (%s)", ret,
895 gst_flow_get_name (ret));
898 timestamp += duration;
900 emulenc->discont = FALSE;
901 avail = gst_adapter_available (emulenc->adapter);
903 GST_LOG_OBJECT (emulenc, "%u bytes left in the adapter", avail);
906 int coded_bps = av_get_bits_per_sample (oclass->codec->name);
908 GST_LOG_OBJECT (emulenc, "coded bps %d, osize %d", coded_bps, osize);
910 out_size = in_size / osize;
912 out_size = (out_size * coded_bps) / 8;
915 in_data = (guint8 *) GST_BUFFER_DATA (buffer);
916 ret = gst_emulenc_encode_audio (emulenc, in_data, in_size, out_size,
917 timestamp, duration, discont);
918 gst_buffer_unref (buffer);
919 if (ret != GST_FLOW_OK) {
920 GST_DEBUG_OBJECT (emulenc, "Failed to push buffer %d (%s)", ret,
921 gst_flow_get_name (ret));
929 gst_emulenc_flush_buffers (GstEmulEnc *emulenc, gboolean send)
931 GstBuffer *outbuf, *inbuf;
934 GST_DEBUG_OBJECT (emulenc, "flushing buffers with sending %d", send);
937 if (!emulenc->opened) {
938 while (!g_queue_is_empty (emulenc->delay)) {
939 gst_buffer_unref (g_queue_pop_head (emulenc->delay));
945 while (!g_queue_is_empty (emulenc->delay)) {
946 emulenc_setup_working_buf (emulenc);
948 ret_size = emul_avcodec_encode_video (emulenc->context,
949 emulenc->working_buf, emulenc->working_buf_size, NULL, NULL, 0,
953 GstEmulEncClass *oclass =
954 (GstEmulEncClass *) (G_OBJECT_GET_CLASS (emulenc));
955 GST_WARNING_OBJECT (emulenc,
956 "maru_%senc: failed to flush buffer", oclass->codec->name);
960 if (emulenc->file && emulenc->context->stats_out) {
961 if (fprintf (emulenc->file, "%s", emulenc->context->stats_out) < 0) {
962 GST_ELEMENT_ERROR (emeulenc, RESOURCE, WRITE,
963 (("Could not write to file \"%s\"."), emulenc->filename),
968 inbuf = g_queue_pop_head (emulenc->delay);
970 outbuf = gst_buffer_new_and_alloc (ret_size);
971 memcpy (GST_BUFFER_DATA (outbuf), emulenc->working_buf, ret_size);
972 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf);
973 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf);
975 if (!emulenc->context->coded_frame->key_frame) {
976 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
978 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad));
980 gst_buffer_unref (inbuf);
983 gst_pad_push (emulenc->srcpad, outbuf);
985 gst_buffer_unref (outbuf);
989 while (!g_queue_is_empty (emulenc->delay)) {
990 gst_buffer_unref (g_queue_pop_head (emulenc->delay));
996 gst_emulenc_event_video (GstPad *pad, GstEvent *event)
999 emulenc = (GstEmulEnc *) gst_pad_get_parent (pad);
1001 switch (GST_EVENT_TYPE (event)) {
1003 gst_emulenc_flush_buffers (emulenc, TRUE);
1005 case GST_EVENT_CUSTOM_DOWNSTREAM:
1007 const GstStructure *s;
1008 s = gst_event_get_structure (event);
1010 if (gst_structure_has_name (s, "GstForceKeyUnit")) {
1012 emulenc->picture->pict_type = FF_I_TYPE;
1021 return gst_pad_push_event (emulenc->srcpad, event);
1025 gst_emulenc_event_src (GstPad *pad, GstEvent *event)
1027 GstEmulEnc *emulenc = (GstEmulEnc *) (GST_PAD_PARENT (pad));
1028 gboolean forward = TRUE;
1030 switch (GST_EVENT_TYPE (event)) {
1031 case GST_EVENT_CUSTOM_UPSTREAM:
1033 const GstStructure *s;
1034 s = gst_event_get_structure (event);
1036 if (gst_structure_has_name (s, "GstForceKeyUnit")) {
1038 GST_OBJECT_LOCK (emulenc);
1039 emulenc->force_keyframe = TRUE;
1040 GST_OBJECT_UNLOCK (emulenc);
1043 gst_event_unref (event);
1052 return gst_pad_push_event (emulenc->sinkpad, event);
1058 GstStateChangeReturn
1059 gst_emulenc_change_state (GstElement *element, GstStateChange transition)
1061 GstEmulEnc *emulenc = (GstEmulEnc*)element;
1062 GstStateChangeReturn ret;
1064 switch (transition) {
1069 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1071 switch (transition) {
1072 case GST_STATE_CHANGE_PAUSED_TO_READY:
1073 gst_emulenc_flush_buffers (emulenc, FALSE);
1074 if (emulenc->opened) {
1075 gst_emul_avcodec_close (emulenc->context, emulenc->dev);
1076 emulenc->opened = FALSE;
1078 gst_adapter_clear (emulenc->adapter);
1081 if (emulenc->flie) {
1082 fclose (emulenc->file);
1083 emulenc->file = NULL;
1087 if (emulenc->working_buf) {
1088 g_free (emulenc->working_buf);
1089 emulenc->working_buf = NULL;
1100 gst_emulenc_register (GstPlugin *plugin, GList *element)
1102 GTypeInfo typeinfo = {
1103 sizeof (GstEmulEncClass),
1104 (GBaseInitFunc) gst_emulenc_base_init,
1106 (GClassInitFunc) gst_emulenc_class_init,
1109 sizeof (GstEmulEnc),
1111 (GInstanceInitFunc) gst_emulenc_init,
1116 gint rank = GST_RANK_NONE;
1117 GList *elem = element;
1118 CodecElement *codec = NULL;
1124 /* register element */
1126 codec = (CodecElement *)(elem->data);
1132 if (codec->codec_type != CODEC_TYPE_ENCODE) {
1136 type_name = g_strdup_printf ("maru_%senc", codec->name);
1137 type = g_type_from_name (type_name);
1139 type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
1140 g_type_set_qdata (type, GST_EMULENC_PARAMS_QDATA, (gpointer) codec);
1143 if (!gst_element_register (plugin, type_name, rank, type)) {
1148 } while ((elem = g_list_next (elem)));