modified the method of memory usage.
[platform/adaptation/emulator/gst-plugins-emulator.git] / src / gstemulenc.c
1 /*
2  * GStreamer codec plugin for Tizen Emulator.
3  *
4  * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  * KiTae Kim <kt920.kim@samsung.com>
8  * SeokYeon Hwang <syeon.hwang@samsung.com>
9  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
10  *
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.
15  *
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.
20  *
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.
25  *
26  * Contributors:
27  * - S-Core Co., Ltd
28  *
29  */
30
31 #include "gstemulutils.h"
32 #include "gstemulapi.h"
33 #include "gstemuldev.h"
34 #include <gst/base/gstadapter.h>
35
36 #define GST_EMULENC_PARAMS_QDATA g_quark_from_static_string("maruenc-params")
37
38 typedef struct _GstEmulEnc
39 {
40   GstElement element;
41
42   GstPad *srcpad;
43   GstPad *sinkpad;
44
45   CodecContext *context;
46   CodecDevice *dev;
47   gboolean opened;
48   GstClockTime adapter_ts;
49   guint64 adapter_consumed;
50   GstAdapter *adapter;
51   gboolean discont;
52
53   // cache
54   gulong bitrate;
55   gint gop_size;
56   gulong buffer_size;
57
58   guint8 *working_buf;
59   gulong working_buf_size;
60
61   GQueue *delay;
62
63 } GstEmulEnc;
64
65 typedef struct _GstEmulEncClass
66 {
67   GstElementClass parent_class;
68
69   CodecElement *codec;
70   GstPadTemplate *sinktempl;
71   GstPadTemplate *srctempl;
72   GstCaps *sinkcaps;
73 } GstEmulEncClass;
74
75 static GstElementClass *parent_class = NULL;
76
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);
81
82 static gboolean gst_emulenc_setcaps (GstPad *pad, GstCaps *caps);
83 static GstCaps *gst_emulenc_getcaps (GstPad *pad);
84
85 static GstCaps *gst_emulenc_get_possible_sizes (GstEmulEnc *emulenc,
86   GstPad *pad, const GstCaps *caps);
87
88 static GstFlowReturn gst_emulenc_chain_video (GstPad *pad, GstBuffer *buffer);
89 static GstFlowReturn gst_emulenc_chain_audio (GstPad *pad, GstBuffer *buffer);
90
91 static gboolean gst_emulenc_event_video (GstPad *pad, GstEvent *event);
92 static gboolean gst_emulenc_event_src (GstPad *pad, GstEvent *event);
93
94 GstStateChangeReturn gst_emulenc_change_state (GstElement *element, GstStateChange transition);
95
96 #define DEFAULT_VIDEO_BITRATE   300000
97 #define DEFAULT_VIDEO_GOP_SIZE  15
98 #define DEFAULT_AUDIO_BITRATE   128000
99
100 #define DEFAULT_WIDTH 352
101 #define DEFAULT_HEIGHT 288
102
103 /*
104  * Implementation
105  */
106 static void
107 gst_emulenc_base_init (GstEmulEncClass *klass)
108 {
109     GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
110     GstPadTemplate *sinktempl = NULL, *srctempl = NULL;
111     GstCaps *sinkcaps = NULL, *srccaps = NULL;
112     CodecElement *codec;
113     gchar *longname, *classification, *description;
114
115     codec =
116         (CodecElement *)g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
117          GST_EMULENC_PARAMS_QDATA);
118
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);
123
124     gst_element_class_set_details_simple (element_class,
125             longname,
126             classification,
127             description,
128 //            "accelerated codec for Tizen Emulator",
129             "Kitae Kim <kt920.kim@samsung.com>");
130
131     g_free (longname);
132     g_free (classification);
133
134
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);
138   }
139
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");
143     break;
144   case AVMEDIA_TYPE_AUDIO:
145     sinkcaps = gst_emul_codectype_to_audio_caps (NULL, codec->name, TRUE, codec);
146     break;
147   default:
148     GST_LOG("unknown media type.\n");
149     break;
150   }
151
152   if (!sinkcaps) {
153       GST_DEBUG ("Couldn't get sink caps for encoder '%s'", codec->name);
154       sinkcaps = gst_caps_new_simple ("unknown/unknown", NULL);
155   }
156
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);
161
162   gst_element_class_add_pad_template (element_class, srctempl);
163   gst_element_class_add_pad_template (element_class, sinktempl);
164
165   klass->codec = codec;
166   klass->sinktempl = sinktempl;
167   klass->srctempl = srctempl;
168   klass->sinkcaps = NULL;
169 }
170
171 static void
172 gst_emulenc_class_init (GstEmulEncClass *klass)
173 {
174   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
175   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
176
177   parent_class = g_type_class_peek_parent (klass);
178
179 #if 0
180   gobject_class->set_property = gst_emulenc_set_property
181   gobject_class->get_property = gst_emulenc_get_property
182 #endif
183
184   gstelement_class->change_state = gst_emulenc_change_state;
185
186   gobject_class->finalize = gst_emulenc_finalize;
187 }
188
189 static void
190 gst_emulenc_init (GstEmulEnc *emulenc)
191 {
192   GstEmulEncClass *oclass;
193   oclass = (GstEmulEncClass*) (G_OBJECT_GET_CLASS(emulenc));
194
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));
200
201   emulenc->srcpad = gst_pad_new_from_template (oclass->srctempl, "src");
202   gst_pad_use_fixed_caps (emulenc->srcpad);
203
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);
208
209     emulenc->bitrate = DEFAULT_VIDEO_BITRATE;
210     emulenc->buffer_size = 512 * 1024;
211     emulenc->gop_size = DEFAULT_VIDEO_GOP_SIZE;
212 #if 0
213     emulenc->lmin = 2;
214     emulenc->lmax = 31;
215 #endif
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;
219   }
220
221   gst_element_add_pad (GST_ELEMENT (emulenc), emulenc->sinkpad);
222   gst_element_add_pad (GST_ELEMENT (emulenc), emulenc->srcpad);
223
224   emulenc->context = g_malloc0 (sizeof(CodecContext));
225   emulenc->context->video.pix_fmt = PIX_FMT_NONE;
226   emulenc->context->audio.sample_fmt = SAMPLE_FMT_NONE;
227
228   emulenc->opened = FALSE;
229
230 #if 0
231   emulenc->file = NULL;
232 #endif
233   emulenc->delay = g_queue_new ();
234
235   emulenc->dev = g_malloc0 (sizeof(CodecDevice));
236   if (!emulenc->dev) {
237     printf("failed to allocate memory.\n");
238   }
239
240   // need to know what adapter does.
241   emulenc->adapter = gst_adapter_new ();
242 }
243
244 static void
245 gst_emulenc_finalize (GObject *object)
246 {
247   // Deinit Decoder
248   GstEmulEnc *emulenc = (GstEmulEnc *) object;
249
250   if (emulenc->opened) {
251     gst_emul_avcodec_close (emulenc->context, emulenc->dev);
252     emulenc->opened = FALSE;
253   }
254
255   if (emulenc->context) {
256     g_free (emulenc->context);
257     emulenc->context = NULL;
258   }
259
260   g_queue_free (emulenc->delay);
261 #if 0
262   g_free (emulenc->filename);
263 #endif
264
265   g_object_unref (emulenc->adapter);
266
267   G_OBJECT_CLASS (parent_class)->finalize (object);
268 }
269
270 static GstCaps *
271 gst_emulenc_get_possible_sizes (GstEmulEnc *emulenc, GstPad *pad,
272   const GstCaps *caps)
273 {
274   GstCaps *othercaps = NULL;
275   GstCaps *tmpcaps = NULL;
276   GstCaps *intersect = NULL;
277   guint i;
278
279   othercaps = gst_pad_peer_get_caps (emulenc->srcpad);
280
281   if (!othercaps) {
282     return gst_caps_copy (caps);
283   }
284
285   intersect = gst_caps_intersect (othercaps,
286     gst_pad_get_pad_template_caps (emulenc->srcpad));
287   gst_caps_unref (othercaps);
288
289   if (gst_caps_is_empty (intersect)) {
290     return intersect;
291   }
292
293   if (gst_caps_is_any (intersect)) {
294     return gst_caps_copy (caps);
295   }
296
297   tmpcaps = gst_caps_new_empty ();
298
299   for (i = 0; i <gst_caps_get_size (intersect); i++) {
300     GstStructure *s = gst_caps_get_structure (intersect, i);
301     const GValue *height = NULL;
302     const GValue *width = NULL;
303     const GValue *framerate = NULL;
304     GstStructure *tmps;
305
306     height = gst_structure_get_value (s, "height");
307     width = gst_structure_get_value (s, "width");
308     framerate = gst_structure_get_value (s, "framerate");
309
310     tmps = gst_structure_new ("video/x-rwa-rgb", NULL);
311     if (width) {
312       gst_structure_set_value (tmps, "width", width);
313     }
314     if (height) {
315       gst_structure_set_value (tmps, "height", height);
316     }
317     if (framerate) {
318       gst_structure_set_value (tmps, "framerate", framerate);
319     }
320     gst_caps_merge_structure (tmpcaps, gst_structure_copy (tmps));
321
322     gst_structure_set_name (tmps, "video/x-raw-yuv");
323     gst_caps_merge_structure (tmpcaps, gst_structure_copy (tmps));
324
325     gst_structure_set_name (tmps, "video/x-raw-gray");
326     gst_caps_merge_structure (tmpcaps, tmps);
327   }
328   gst_caps_unref (intersect);
329
330   intersect = gst_caps_intersect (caps, tmpcaps);
331   gst_caps_unref (tmpcaps);
332
333   return intersect;
334 }
335
336 static GstCaps *
337 gst_emulenc_getcaps (GstPad *pad)
338 {
339   GstEmulEnc *emulenc = (GstEmulEnc *) GST_PAD_PARENT (pad);
340   GstEmulEncClass *oclass =
341     (GstEmulEncClass *) G_OBJECT_GET_CLASS (emulenc);
342   CodecContext *ctx = NULL;
343   enum PixelFormat pixfmt;
344   GstCaps *caps = NULL;
345   GstCaps *finalcaps = NULL;
346   gint i;
347
348   GST_DEBUG_OBJECT (emulenc, "getting caps");
349
350   if (!oclass->codec) {
351     GST_ERROR_OBJECT (emulenc, "codec element is null.");
352     return NULL;
353   }
354
355   if (oclass->codec->media_type == AVMEDIA_TYPE_AUDIO) {
356     caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
357
358     GST_DEBUG_OBJECT (emulenc, "audio caps, return template %" GST_PTR_FORMAT,
359       caps);
360     return caps;
361   }
362
363   // cached
364   if (oclass->sinkcaps) {
365     caps = gst_emulenc_get_possible_sizes (emulenc, pad, oclass->sinkcaps);
366     GST_DEBUG_OBJECT (emulenc, "return cached caps %" GST_PTR_FORMAT, caps);
367     return caps;
368   }
369
370   GST_DEBUG_OBJECT (emulenc, "probing caps");
371   i = pixfmt = 0;
372
373   for (pixfmt = 0;; pixfmt++) {
374     GstCaps *tmpcaps;
375
376     if ((pixfmt = oclass->codec->pix_fmts[i++]) == PIX_FMT_NONE) {
377       GST_DEBUG_OBJECT (emulenc,
378           "At the end of official pixfmt for this codec, breaking out");
379       break;
380     }
381
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);
385     if (tmpcaps) {
386       GST_DEBUG_OBJECT (emulenc, "Got caps, breaking out");
387       if (!caps) {
388         caps = gst_caps_new_empty ();
389       }
390       gst_caps_append (caps, tmpcaps);
391       continue;
392     }
393
394     GST_DEBUG_OBJECT (emulenc,
395         "Couldn't figure out caps without context, trying again with a context");
396
397     GST_DEBUG_OBJECT (emulenc, "pixfmt: %d", pixfmt);
398     if (pixfmt >= PIX_FMT_NB) {
399       GST_WARNING ("Invalid pixfmt, breaking out");
400       break;
401     }
402
403     ctx = g_malloc0 (sizeof(CodecContext));
404     if (!ctx) {
405       GST_DEBUG_OBJECT (emulenc, "no context");
406       break;
407     }
408
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;
415
416 //  ctx->strict_std_compliance = -1;
417     ctx->video.pix_fmt = pixfmt;
418
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;
423       if (!caps) {
424         caps = gst_caps_new_empty ();
425       }
426       tmpcaps = gst_emul_codectype_to_caps (oclass->codec->media_type, ctx,
427           oclass->codec->name, TRUE);
428       if (tmpcaps) {
429         gst_caps_append (caps, tmpcaps);
430       } else {
431         GST_LOG_OBJECT (emulenc,
432             "Couldn't get caps for codec: %s", oclass->codec->name);
433       }
434       gst_emul_avcodec_close (ctx, emulenc->dev);
435     } else {
436       GST_DEBUG_OBJECT (emulenc, "Opening codec failed with pixfmt: %d", pixfmt);
437     }
438
439     gst_emul_avcodec_close (ctx, emulenc->dev);
440 #if 0
441     if (ctx->priv_data) {
442       gst_emul_avcodec_close (ctx, emulenc->dev);
443     }
444 #endif
445     g_free (ctx);
446   }
447
448   if (!caps) {
449     caps = gst_emulenc_get_possible_sizes (emulenc, pad,
450       gst_pad_get_pad_template_caps (pad));
451     GST_DEBUG_OBJECT (emulenc, "probing gave nothing, "
452       "return template %" GST_PTR_FORMAT, caps);
453     return caps;
454   }
455
456   GST_DEBUG_OBJECT (emulenc, "probed caps gave %" GST_PTR_FORMAT, caps);
457   oclass->sinkcaps = gst_caps_copy (caps);
458
459   finalcaps = gst_emulenc_get_possible_sizes (emulenc, pad, caps);
460   gst_caps_unref (caps);
461
462   return finalcaps;
463 }
464
465 static gboolean
466 gst_emulenc_setcaps (GstPad *pad, GstCaps *caps)
467 {
468   GstEmulEnc *emulenc;
469   GstEmulEncClass *oclass;
470   GstCaps *other_caps;
471   GstCaps *allowed_caps;
472   GstCaps *icaps;
473   enum PixelFormat pix_fmt;
474   int32_t buf_size;
475
476   emulenc = (GstEmulEnc *) (gst_pad_get_parent (pad));
477   oclass = (GstEmulEncClass *) (G_OBJECT_GET_CLASS (emulenc));
478
479   if (emulenc->opened) {
480     gst_emul_avcodec_close (emulenc->context, emulenc->dev);
481     emulenc->opened = FALSE;
482
483     gst_pad_set_caps (emulenc->srcpad, NULL);
484   }
485
486   emulenc->context->bit_rate = emulenc->bitrate;
487   GST_DEBUG_OBJECT (emulenc, "Setting context to bitrate %lu, gop_size %d",
488       emulenc->bitrate, emulenc->gop_size);
489
490 #if 0
491
492   // user defined properties
493   emulenc->context->gop_size = emulenc->gop_size;
494   emulenc->context->lmin = (emulenc->lmin * FF_QP2LAMBDA + 0.5);
495   emulenc->context->lmax = (emulenc->lmax * FF_QP2LAMBDA + 0.5);
496
497   // some other defaults
498   emulenc->context->b_frame_strategy = 0;
499   emulenc->context->coder_type = 0;
500   emulenc->context->context_model = 0;
501   emulenc->context->scenechange_threshold = 0;
502   emulenc->context->inter_threshold = 0;
503
504   if (emulenc->interlaced) {
505     emulenc->context->flags |=
506       CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME;
507     emulenc->picture->interlaced_frame = TRUE;
508
509     emulenc->picture->top_field_first = TRUE;
510   }
511 #endif
512
513   gst_emul_caps_with_codectype (oclass->codec->media_type, caps, emulenc->context);
514
515   if (!emulenc->context->video.fps_d) {
516     emulenc->context->video.fps_d = 25;
517     emulenc->context->video.fps_n = 1;
518   } else if (!strcmp(oclass->codec->name ,"mpeg4")
519       && (emulenc->context->video.fps_d > 65535)) {
520       emulenc->context->video.fps_n =
521         (gint) gst_util_uint64_scale_int (emulenc->context->video.fps_n,
522             65535, emulenc->context->video.fps_d);
523       emulenc->context->video.fps_d = 65535;
524       GST_LOG_OBJECT (emulenc, "MPEG4 : scaled down framerate to %d / %d",
525           emulenc->context->video.fps_d, emulenc->context->video.fps_n);
526   }
527
528   pix_fmt = emulenc->context->video.pix_fmt;
529
530   {
531     switch (oclass->codec->media_type) {
532     case AVMEDIA_TYPE_VIDEO:
533     {
534       int width, height;
535
536       width = emulenc->context->video.width;
537       height = emulenc->context->video.height;
538       buf_size = width * height * 6 + FF_MIN_BUFFER_SIZE + 100;
539       break;
540     }
541     case AVMEDIA_TYPE_AUDIO:
542         buf_size = FF_MAX_AUDIO_FRAME_SIZE + 100;
543         break;
544     default:
545         buf_size = -1;
546         break;
547     }
548   }
549
550   emulenc->dev->buf_size = gst_emul_align_size(buf_size);
551
552   // open codec
553   if (gst_emul_avcodec_open (emulenc->context,
554       oclass->codec, emulenc->dev) < 0) {
555     GST_DEBUG_OBJECT (emulenc, "maru_%senc: Failed to open codec",
556         oclass->codec->name);
557     return FALSE;
558   }
559
560   if (pix_fmt != emulenc->context->video.pix_fmt) {
561     gst_emul_avcodec_close (emulenc->context, emulenc->dev);
562     GST_DEBUG_OBJECT (emulenc,
563       "maru_%senc: AV wants different colorspace (%d given, %d wanted)",
564       oclass->codec->name, pix_fmt, emulenc->context->video.pix_fmt);
565     return FALSE;
566   }
567
568   if (oclass->codec->media_type == AVMEDIA_TYPE_VIDEO
569     && pix_fmt == PIX_FMT_NONE) {
570     GST_DEBUG_OBJECT (emulenc, "maru_%senc: Failed to determine input format",
571       oclass->codec->name);
572     return FALSE;
573   }
574
575   GST_DEBUG_OBJECT (emulenc, "picking an output format.");
576   allowed_caps = gst_pad_get_allowed_caps (emulenc->srcpad);
577   if (!allowed_caps) {
578     GST_DEBUG_OBJECT (emulenc, "but no peer, using template caps");
579     allowed_caps =
580       gst_caps_copy (gst_pad_get_pad_template_caps (emulenc->srcpad));
581   }
582
583   GST_DEBUG_OBJECT (emulenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
584   gst_emul_caps_with_codecname (oclass->codec->name,
585     oclass->codec->media_type, allowed_caps, emulenc->context);
586
587   other_caps =
588   gst_emul_codecname_to_caps (oclass->codec->name, emulenc->context, TRUE);
589   if (!other_caps) {
590   GST_DEBUG("Unsupported codec - no caps found");
591     gst_emul_avcodec_close (emulenc->context, emulenc->dev);
592     return FALSE;
593   }
594
595   icaps = gst_caps_intersect (allowed_caps, other_caps);
596   gst_caps_unref (allowed_caps);
597   gst_caps_unref (other_caps);
598   if (gst_caps_is_empty (icaps)) {
599     gst_caps_unref (icaps);
600     return FALSE;
601   }
602
603   if (gst_caps_get_size (icaps) > 1) {
604     GstCaps *newcaps;
605
606     newcaps =
607       gst_caps_new_full (gst_structure_copy (gst_caps_get_structure (icaps,
608               0)), NULL);
609     gst_caps_unref (icaps);
610     icaps = newcaps;
611   }
612
613   if (!gst_pad_set_caps (emulenc->srcpad, icaps)) {
614     gst_emul_avcodec_close (emulenc->context, emulenc->dev);
615     gst_caps_unref (icaps);
616     return FALSE;
617   }
618   gst_object_unref (emulenc);
619
620   emulenc->opened = TRUE;
621
622   return TRUE;
623 }
624
625 static void
626 gst_emulenc_setup_working_buf (GstEmulEnc *emulenc)
627 {
628   guint wanted_size =
629       emulenc->context->video.width * emulenc->context->video.height * 6 +
630       FF_MIN_BUFFER_SIZE;
631
632   if (emulenc->working_buf == NULL ||
633     emulenc->working_buf_size != wanted_size) {
634     if (emulenc->working_buf) {
635       g_free (emulenc->working_buf);
636     }
637     emulenc->working_buf_size = wanted_size;
638     emulenc->working_buf = g_malloc0 (emulenc->working_buf_size);
639   }
640   emulenc->buffer_size = wanted_size;
641 }
642
643 GstFlowReturn
644 gst_emulenc_chain_video (GstPad *pad, GstBuffer *buffer)
645 {
646   GstEmulEnc *emulenc = (GstEmulEnc *) (GST_PAD_PARENT (pad));
647   GstBuffer *outbuf;
648   gint ret_size = 0, frame_size;
649
650   GST_DEBUG_OBJECT (emulenc,
651       "Received buffer of time %" GST_TIME_FORMAT,
652       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
653
654 #if 0
655   GST_OBJECT_LOCK (emulenc);
656   force_keyframe = emulenc->force_keyframe;
657   emulenc->force_keyframe = FALSE;
658   GST_OBJECT_UNLOCK (emulenc);
659
660   if (force_keyframe) {
661     emulenc->picture->pict_type = FF_I_TYPE;
662   }
663 #endif
664
665   frame_size = gst_emul_avpicture_size (emulenc->context->video.pix_fmt,
666       emulenc->context->video.width, emulenc->context->video.height);
667   g_return_val_if_fail (frame_size == GST_BUFFER_SIZE (buffer),
668       GST_FLOW_ERROR);
669
670 #if 0
671   pts = gst_emul_time_gst_to_ff (GST_BUFFER_TIMESTAMP (buffer) /
672     emulenc->context.video.ticks_per_frame,
673     emulenc->context.video.fps_n, emulen->context.video.fps_d);
674 #endif
675
676   // TODO: check whether this func needs or not.
677   gst_emulenc_setup_working_buf (emulenc);
678
679   ret_size =
680     codec_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),
683                 emulenc->dev);
684
685   if (ret_size < 0) {
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);
691     return GST_FLOW_OK;
692   }
693
694   g_queue_push_tail (emulenc->delay, buffer);
695   if (ret_size) {
696     buffer = g_queue_pop_head (emulenc->delay);
697   } else {
698     return GST_FLOW_OK;
699   }
700
701 #if 0
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),
706         GST_ERROR_SYSTEM);
707     }
708   }
709 #endif
710 #if 1
711   {
712     int ret;
713     uint32_t mem_offset;
714     uint8_t *working_buf = NULL;
715
716     mem_offset = emulenc->dev->mem_info.offset;
717     working_buf = emulenc->dev->buf + mem_offset;
718     if (!working_buf) {
719     } else {
720       CODEC_LOG (INFO,
721           "encoded video. mem_offset = 0x%x\n",  mem_offset);
722
723       outbuf = gst_buffer_new_and_alloc (ret_size);
724 //    memcpy (GST_BUFFER_DATA (outbuf), emulenc->working_buf, ret_size);
725       memcpy (GST_BUFFER_DATA (outbuf), working_buf, ret_size);
726       GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer);
727       GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buffer);
728     }
729
730     ret = ioctl(emulenc->dev->fd, CODEC_CMD_RELEASE_MEMORY, &mem_offset);
731     if (ret < 0) {
732       CODEC_LOG (ERR, "failed to release used buffer\n");
733     }
734   }
735 #endif
736
737 #if 0
738   if (emulenc->context->coded_frame) {
739     if (!emulenc->context->coded_frame->key_frame) {
740       GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
741     }
742   } else {
743     GST_WARNING_OBJECT (emulenc, "codec did not provide keyframe info");
744   }
745 #endif
746   gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad));
747
748   gst_buffer_unref (buffer);
749
750 #if 0
751
752   if (force_keyframe) {
753     gst_pad_push_event (emulenc->srcpad,
754       gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
755       gst_structure_new ("GstForceKeyUnit", "timestamp",
756                          G_TYPE_UINT64, GST_BUFFER_TIMESTAMP (outbuf), NULL)));
757   }
758 #endif
759
760   return gst_pad_push (emulenc->srcpad, outbuf);
761 }
762
763 GstFlowReturn
764 gst_emulenc_encode_audio (GstEmulEnc *emulenc, guint8 *audio_in,
765   guint in_size, guint max_size, GstClockTime timestamp,
766   GstClockTime duration, gboolean discont)
767 {
768   GstBuffer *outbuf;
769   guint8 *audio_out;
770   gint res;
771   GstFlowReturn ret;
772
773   outbuf = gst_buffer_new_and_alloc (max_size + FF_MIN_BUFFER_SIZE);
774   audio_out = GST_BUFFER_DATA (outbuf);
775
776   GST_LOG_OBJECT (emulenc, "encoding buffer of max size %d", max_size);
777   if (emulenc->buffer_size != max_size) {
778     emulenc->buffer_size = max_size;
779   }
780
781   res = codec_encode_audio (emulenc->context, audio_out, max_size,
782                                   audio_in, in_size, emulenc->dev);
783
784   if (res < 0) {
785     GST_ERROR_OBJECT (emulenc, "Failed to encode buffer: %d", res);
786     gst_buffer_unref (outbuf);
787     return GST_FLOW_OK;
788   }
789   GST_LOG_OBJECT (emulenc, "got output size %d", res);
790
791   GST_BUFFER_SIZE (outbuf) = res;
792   GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
793   GST_BUFFER_DURATION (outbuf) = duration;
794   if (discont) {
795     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
796   }
797   gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad));
798
799   GST_LOG_OBJECT (emulenc, "pushing size %d, timestamp %",
800       GST_TIME_FORMAT, res, GST_TIME_ARGS (timestamp));
801
802   ret = gst_pad_push (emulenc->srcpad, outbuf);
803
804   return ret;
805 }
806
807 static GstFlowReturn
808 gst_emulenc_chain_audio (GstPad *pad, GstBuffer *buffer)
809 {
810   GstEmulEnc *emulenc;
811   GstEmulEncClass *oclass;
812   GstClockTime timestamp, duration;
813   guint in_size, frame_size;
814   gint osize;
815   GstFlowReturn ret;
816   gint out_size = 0;
817   gboolean discont;
818   guint8 *in_data;
819   CodecContext *ctx;
820
821   emulenc = (GstEmulEnc *) (GST_OBJECT_PARENT (pad));
822   oclass = (GstEmulEncClass *) G_OBJECT_GET_CLASS (emulenc);
823
824   ctx = emulenc->context;
825
826   in_size = GST_BUFFER_SIZE (buffer);
827   timestamp = GST_BUFFER_TIMESTAMP (buffer);
828   duration = GST_BUFFER_DURATION (buffer);
829   discont = GST_BUFFER_IS_DISCONT (buffer);
830
831   GST_DEBUG_OBJECT (emulenc,
832     "Received time %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT
833     ", size %d", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration), in_size);
834
835   frame_size = ctx->audio.frame_size;
836   osize = ctx->audio.bits_per_sample_fmt;
837
838   if (frame_size > 1) {
839     guint avail, frame_bytes;
840
841     if (discont) {
842       GST_LOG_OBJECT (emulenc, "DISCONT, clear adapter");
843       gst_adapter_clear (emulenc->adapter);
844       emulenc->discont = TRUE;
845     }
846
847     if (gst_adapter_available (emulenc->adapter) == 0) {
848       GST_LOG_OBJECT (emulenc, "taking buffer timestamp %" GST_TIME_FORMAT,
849         GST_TIME_ARGS (timestamp));
850       emulenc->adapter_ts = timestamp;
851       emulenc->adapter_consumed = 0;
852     } else {
853       GstClockTime upstream_time;
854       GstClockTime consumed_time;
855       guint64 bytes;
856
857       consumed_time =
858         gst_util_uint64_scale (emulenc->adapter_consumed, GST_SECOND,
859             ctx->audio.sample_rate);
860       timestamp = emulenc->adapter_ts + consumed_time;
861       GST_LOG_OBJECT (emulenc, "taking adapter timestamp %" GST_TIME_FORMAT
862         " and adding consumed time %" GST_TIME_FORMAT,
863         GST_TIME_ARGS (emulenc->adapter_ts), GST_TIME_ARGS (consumed_time));
864
865       upstream_time = gst_adapter_prev_timestamp (emulenc->adapter, &bytes);
866       if (GST_CLOCK_TIME_IS_VALID (upstream_time)) {
867         GstClockTimeDiff diff;
868
869         upstream_time +=
870           gst_util_uint64_scale (bytes, GST_SECOND,
871             ctx->audio.sample_rate * osize * ctx->audio.channels);
872         diff = upstream_time - timestamp;
873
874         if (diff > GST_SECOND / 10 || diff < -GST_SECOND / 10) {
875           GST_DEBUG_OBJECT (emulenc, "adapter timestamp drifting, "
876             "taking upstream timestamp %" GST_TIME_FORMAT,
877             GST_TIME_ARGS (upstream_time));
878           timestamp = upstream_time;
879
880           emulenc->adapter_consumed = bytes / (osize * ctx->audio.channels);
881           emulenc->adapter_ts =
882             upstream_time - gst_util_uint64_scale (emulenc->adapter_consumed,
883                 GST_SECOND, ctx->audio.sample_rate);
884           emulenc->discont = TRUE;
885         }
886       }
887     }
888
889     GST_LOG_OBJECT (emulenc, "pushing buffer in adapter");
890     gst_adapter_push (emulenc->adapter, buffer);
891
892     frame_bytes = frame_size * osize * ctx->audio.channels;
893     avail = gst_adapter_available (emulenc->adapter);
894
895     GST_LOG_OBJECT (emulenc, "frame_bytes %u, avail %u", frame_bytes, avail);
896
897     while (avail >= frame_bytes) {
898       GST_LOG_OBJECT (emulenc, "taking %u bytes from the adapter", frame_bytes);
899
900       in_data = (guint8 *) gst_adapter_peek (emulenc->adapter, frame_bytes);
901       emulenc->adapter_consumed += frame_size;
902
903       duration =
904         gst_util_uint64_scale (emulenc->adapter_consumed, GST_SECOND,
905           ctx->audio.sample_rate);
906       duration -= (timestamp - emulenc->adapter_ts);
907
908       out_size = frame_bytes * 4;
909
910       ret =
911         gst_emulenc_encode_audio (emulenc, in_data, frame_bytes, out_size,
912           timestamp, duration, emulenc->discont);
913
914       gst_adapter_flush (emulenc->adapter, frame_bytes);
915       if (ret != GST_FLOW_OK) {
916         GST_DEBUG_OBJECT (emulenc, "Failed to push buffer %d (%s)", ret,
917           gst_flow_get_name (ret));
918       }
919
920       timestamp += duration;
921
922       emulenc->discont = FALSE;
923       avail = gst_adapter_available (emulenc->adapter);
924     }
925     GST_LOG_OBJECT (emulenc, "%u bytes left in the adapter", avail);
926   } else {
927 #if 0
928     int coded_bps = av_get_bits_per_sample (oclass->codec->name);
929
930     GST_LOG_OBJECT (emulenc, "coded bps %d, osize %d", coded_bps, osize);
931
932     out_size = in_size / osize;
933     if (coded_bps) {
934       out_size = (out_size * coded_bps) / 8;
935     }
936 #endif
937     in_data = (guint8 *) GST_BUFFER_DATA (buffer);
938     ret = gst_emulenc_encode_audio (emulenc, in_data, in_size, out_size,
939       timestamp, duration, discont);
940     gst_buffer_unref (buffer);
941     if (ret != GST_FLOW_OK) {
942       GST_DEBUG_OBJECT (emulenc, "Failed to push buffer %d (%s)", ret,
943         gst_flow_get_name (ret));
944     }
945   }
946
947   return GST_FLOW_OK;
948 }
949
950 static void
951 gst_emulenc_flush_buffers (GstEmulEnc *emulenc, gboolean send)
952 {
953   GstBuffer *outbuf, *inbuf;
954   gint ret_size = 0;
955
956   GST_DEBUG_OBJECT (emulenc, "flushing buffers with sending %d", send);
957
958   if (!emulenc->opened) {
959     while (!g_queue_is_empty (emulenc->delay)) {
960       gst_buffer_unref (g_queue_pop_head (emulenc->delay));
961     }
962   }
963
964 #if 0
965   while (!g_queue_is_empty (emulenc->delay)) {
966     emulenc_setup_working_buf (emulenc);
967
968     ret_size = codec_encode_video (emulenc->context,
969       emulenc->working_buf, emulenc->working_buf_size, NULL, NULL, 0,
970       emulenc->dev);
971
972     if (ret_size < 0) {
973       GstEmulEncClass *oclass =
974         (GstEmulEncClass *) (G_OBJECT_GET_CLASS (emulenc));
975       GST_WARNING_OBJECT (emulenc,
976         "maru_%senc: failed to flush buffer", oclass->codec->name);
977       break;
978     }
979
980     if (emulenc->file && emulenc->context->stats_out) {
981       if (fprintf (emulenc->file, "%s", emulenc->context->stats_out) < 0) {
982         GST_ELEMENT_ERROR (emeulenc, RESOURCE, WRITE,
983           (("Could not write to file \"%s\"."), emulenc->filename),
984           GST_ERROR_SYSTEM);
985       }
986     }
987
988     inbuf = g_queue_pop_head (emulenc->delay);
989
990     outbuf = gst_buffer_new_and_alloc (ret_size);
991     memcpy (GST_BUFFER_DATA (outbuf), emulenc->working_buf, ret_size);
992     GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf);
993     GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf);
994
995     if (!emulenc->context->coded_frame->key_frame) {
996       GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
997     }
998     gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad));
999
1000     gst_buffer_unref (inbuf);
1001
1002     if (send) {
1003       gst_pad_push (emulenc->srcpad, outbuf);
1004     } else {
1005       gst_buffer_unref (outbuf);
1006     }
1007   }
1008
1009   while (!g_queue_is_empty (emulenc->delay)) {
1010     gst_buffer_unref (g_queue_pop_head (emulenc->delay));
1011   }
1012 #endif
1013 }
1014
1015 static gboolean
1016 gst_emulenc_event_video (GstPad *pad, GstEvent *event)
1017 {
1018   GstEmulEnc *emulenc;
1019   emulenc = (GstEmulEnc *) gst_pad_get_parent (pad);
1020
1021   switch (GST_EVENT_TYPE (event)) {
1022   case GST_EVENT_EOS:
1023     gst_emulenc_flush_buffers (emulenc, TRUE);
1024     break;
1025   case GST_EVENT_CUSTOM_DOWNSTREAM:
1026   {
1027     const GstStructure *s;
1028     s = gst_event_get_structure (event);
1029
1030     if (gst_structure_has_name (s, "GstForceKeyUnit")) {
1031 #if 0
1032       emulenc->picture->pict_type = FF_I_TYPE;
1033 #endif
1034     }
1035   }
1036     break;
1037   default:
1038     break;
1039   }
1040
1041   return gst_pad_push_event (emulenc->srcpad, event);
1042 }
1043
1044 static gboolean
1045 gst_emulenc_event_src (GstPad *pad, GstEvent *event)
1046 {
1047   GstEmulEnc *emulenc = (GstEmulEnc *) (GST_PAD_PARENT (pad));
1048   gboolean forward = TRUE;
1049
1050   switch (GST_EVENT_TYPE (event)) {
1051   case GST_EVENT_CUSTOM_UPSTREAM:
1052   {
1053     const GstStructure *s;
1054     s = gst_event_get_structure (event);
1055
1056     if (gst_structure_has_name (s, "GstForceKeyUnit")) {
1057 #if 0
1058       GST_OBJECT_LOCK (emulenc);
1059       emulenc->force_keyframe = TRUE;
1060       GST_OBJECT_UNLOCK (emulenc);
1061 #endif
1062       forward = FALSE;
1063       gst_event_unref (event);
1064     }
1065   }
1066     break;
1067   default:
1068     break;
1069   }
1070
1071   if (forward) {
1072     return gst_pad_push_event (emulenc->sinkpad, event);
1073   }
1074
1075   return TRUE;
1076 }
1077
1078 GstStateChangeReturn
1079 gst_emulenc_change_state (GstElement *element, GstStateChange transition)
1080 {
1081   GstEmulEnc *emulenc = (GstEmulEnc*)element;
1082   GstStateChangeReturn ret;
1083
1084   switch (transition) {
1085   default:
1086     break;
1087   }
1088
1089   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1090
1091   switch (transition) {
1092   case GST_STATE_CHANGE_PAUSED_TO_READY:
1093     gst_emulenc_flush_buffers (emulenc, FALSE);
1094     if (emulenc->opened) {
1095       gst_emul_avcodec_close (emulenc->context, emulenc->dev);
1096       emulenc->opened = FALSE;
1097     }
1098     gst_adapter_clear (emulenc->adapter);
1099
1100 #if 0
1101     if (emulenc->flie) {
1102       fclose (emulenc->file);
1103       emulenc->file = NULL;
1104     }
1105 #endif
1106
1107     if (emulenc->working_buf) {
1108       g_free (emulenc->working_buf);
1109       emulenc->working_buf = NULL;
1110     }
1111     break;
1112   default:
1113     break;
1114   }
1115
1116   return ret;
1117 }
1118
1119 gboolean
1120 gst_emulenc_register (GstPlugin *plugin, GList *element)
1121 {
1122   GTypeInfo typeinfo = {
1123       sizeof (GstEmulEncClass),
1124       (GBaseInitFunc) gst_emulenc_base_init,
1125       NULL,
1126       (GClassInitFunc) gst_emulenc_class_init,
1127       NULL,
1128       NULL,
1129       sizeof (GstEmulEnc),
1130       0,
1131       (GInstanceInitFunc) gst_emulenc_init,
1132   };
1133
1134   GType type;
1135   gchar *type_name;
1136   gint rank = GST_RANK_NONE;
1137   GList *elem = element;
1138   CodecElement *codec = NULL;
1139
1140   if (!elem) {
1141     return FALSE;
1142   }
1143
1144   /* register element */
1145   do {
1146     codec = (CodecElement *)(elem->data);
1147     if (!codec) {
1148       return FALSE;
1149     }
1150
1151     if (codec->codec_type != CODEC_TYPE_ENCODE) {
1152       continue;
1153     }
1154
1155     type_name = g_strdup_printf ("maru_%senc", codec->name);
1156     type = g_type_from_name (type_name);
1157     if (!type) {
1158       type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
1159       g_type_set_qdata (type, GST_EMULENC_PARAMS_QDATA, (gpointer) codec);
1160     }
1161
1162     if (!gst_element_register (plugin, type_name, rank, type)) {
1163       g_free (type_name);
1164       return FALSE;
1165     }
1166     g_free (type_name);
1167   } while ((elem = elem->next));
1168
1169   return TRUE;
1170 }