4b097180c433c82b84d87dddd9e9e2f212f01cef
[platform/adaptation/emulator/gst-plugins-emulator.git] / src / gstmaruenc.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 "gstmarudevice.h"
32 #include "gstmaruutils.h"
33 #include "gstmaruinterface.h"
34 #include <gst/base/gstadapter.h>
35
36 #define GST_MARUENC_PARAMS_QDATA g_quark_from_static_string("maruenc-params")
37
38 typedef struct _GstMaruEnc
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 } GstMaruEnc;
64
65 typedef struct _GstMaruEncClass
66 {
67   GstElementClass parent_class;
68
69   CodecElement *codec;
70   GstPadTemplate *sinktempl;
71   GstPadTemplate *srctempl;
72   GstCaps *sinkcaps;
73 } GstMaruEncClass;
74
75 static GstElementClass *parent_class = NULL;
76
77 static void gst_maruenc_base_init (GstMaruEncClass *klass);
78 static void gst_maruenc_class_init (GstMaruEncClass *klass);
79 static void gst_maruenc_init (GstMaruEnc *maruenc);
80 static void gst_maruenc_finalize (GObject *object);
81
82 static gboolean gst_maruenc_setcaps (GstPad *pad, GstCaps *caps);
83 static GstCaps *gst_maruenc_getcaps (GstPad *pad);
84
85 static GstCaps *gst_maruenc_get_possible_sizes (GstMaruEnc *maruenc,
86   GstPad *pad, const GstCaps *caps);
87
88 static GstFlowReturn gst_maruenc_chain_video (GstPad *pad, GstBuffer *buffer);
89 static GstFlowReturn gst_maruenc_chain_audio (GstPad *pad, GstBuffer *buffer);
90
91 static gboolean gst_maruenc_event_video (GstPad *pad, GstEvent *event);
92 static gboolean gst_maruenc_event_src (GstPad *pad, GstEvent *event);
93
94 GstStateChangeReturn gst_maruenc_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_maruenc_base_init (GstMaruEncClass *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_MARUENC_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_maru_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_maru_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_maruenc_class_init (GstMaruEncClass *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_maruenc_set_property
181   gobject_class->get_property = gst_maruenc_get_property
182 #endif
183
184   gstelement_class->change_state = gst_maruenc_change_state;
185
186   gobject_class->finalize = gst_maruenc_finalize;
187 }
188
189 static void
190 gst_maruenc_init (GstMaruEnc *maruenc)
191 {
192   GstMaruEncClass *oclass;
193   oclass = (GstMaruEncClass*) (G_OBJECT_GET_CLASS(maruenc));
194
195   maruenc->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
196   gst_pad_set_setcaps_function (maruenc->sinkpad,
197     GST_DEBUG_FUNCPTR(gst_maruenc_setcaps));
198   gst_pad_set_getcaps_function (maruenc->sinkpad,
199     GST_DEBUG_FUNCPTR(gst_maruenc_getcaps));
200
201   maruenc->srcpad = gst_pad_new_from_template (oclass->srctempl, "src");
202   gst_pad_use_fixed_caps (maruenc->srcpad);
203
204   if (oclass->codec->media_type == AVMEDIA_TYPE_VIDEO) {
205     gst_pad_set_chain_function (maruenc->sinkpad, gst_maruenc_chain_video);
206     gst_pad_set_event_function (maruenc->sinkpad, gst_maruenc_event_video);
207     gst_pad_set_event_function (maruenc->srcpad, gst_maruenc_event_src);
208
209     maruenc->bitrate = DEFAULT_VIDEO_BITRATE;
210     maruenc->buffer_size = 512 * 1024;
211     maruenc->gop_size = DEFAULT_VIDEO_GOP_SIZE;
212 #if 0
213     maruenc->lmin = 2;
214     maruenc->lmax = 31;
215 #endif
216   } else if (oclass->codec->media_type == AVMEDIA_TYPE_AUDIO){
217     gst_pad_set_chain_function (maruenc->sinkpad, gst_maruenc_chain_audio);
218     maruenc->bitrate = DEFAULT_AUDIO_BITRATE;
219   }
220
221   gst_element_add_pad (GST_ELEMENT (maruenc), maruenc->sinkpad);
222   gst_element_add_pad (GST_ELEMENT (maruenc), maruenc->srcpad);
223
224   maruenc->context = g_malloc0 (sizeof(CodecContext));
225   maruenc->context->video.pix_fmt = PIX_FMT_NONE;
226   maruenc->context->audio.sample_fmt = SAMPLE_FMT_NONE;
227
228   maruenc->opened = FALSE;
229
230 #if 0
231   maruenc->file = NULL;
232 #endif
233   maruenc->delay = g_queue_new ();
234
235   maruenc->dev = g_malloc0 (sizeof(CodecDevice));
236   if (!maruenc->dev) {
237     printf("[gst-maru][%d] failed to allocate memory\n", __LINE__);
238   }
239
240   // need to know what adapter does.
241   maruenc->adapter = gst_adapter_new ();
242 }
243
244 static void
245 gst_maruenc_finalize (GObject *object)
246 {
247   // Deinit Decoder
248   GstMaruEnc *maruenc = (GstMaruEnc *) object;
249
250   if (maruenc->opened) {
251     gst_maru_avcodec_close (maruenc->context, maruenc->dev);
252     maruenc->opened = FALSE;
253   }
254
255   if (maruenc->context) {
256     g_free (maruenc->context);
257     maruenc->context = NULL;
258   }
259
260   g_queue_free (maruenc->delay);
261 #if 0
262   g_free (maruenc->filename);
263 #endif
264
265   g_object_unref (maruenc->adapter);
266
267   G_OBJECT_CLASS (parent_class)->finalize (object);
268 }
269
270 static GstCaps *
271 gst_maruenc_get_possible_sizes (GstMaruEnc *maruenc, 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 (maruenc->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 (maruenc->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_maruenc_getcaps (GstPad *pad)
338 {
339   GstMaruEnc *maruenc = (GstMaruEnc *) GST_PAD_PARENT (pad);
340   GstMaruEncClass *oclass =
341     (GstMaruEncClass *) G_OBJECT_GET_CLASS (maruenc);
342   CodecContext *ctx = NULL;
343   enum PixelFormat pixfmt;
344   GstCaps *caps = NULL;
345   GstCaps *finalcaps = NULL;
346   gint i;
347
348   GST_DEBUG_OBJECT (maruenc, "getting caps");
349
350   if (!oclass->codec) {
351     GST_ERROR_OBJECT (maruenc, "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 (maruenc, "audio caps, return template %" GST_PTR_FORMAT,
359       caps);
360     return caps;
361   }
362
363   // cached
364   if (oclass->sinkcaps) {
365     caps = gst_maruenc_get_possible_sizes (maruenc, pad, oclass->sinkcaps);
366     GST_DEBUG_OBJECT (maruenc, "return cached caps %" GST_PTR_FORMAT, caps);
367     return caps;
368   }
369
370   GST_DEBUG_OBJECT (maruenc, "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 (maruenc,
378           "At the end of official pixfmt for this codec, breaking out");
379       break;
380     }
381
382     GST_DEBUG_OBJECT (maruenc,
383         "Got an official pixfmt [%d], attempting to get caps", pixfmt);
384     tmpcaps = gst_maru_pixfmt_to_caps (pixfmt, NULL, oclass->codec->name);
385     if (tmpcaps) {
386       GST_DEBUG_OBJECT (maruenc, "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 (maruenc,
395         "Couldn't figure out caps without context, trying again with a context");
396
397     GST_DEBUG_OBJECT (maruenc, "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 (maruenc, "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_maru_avcodec_open (ctx, oclass->codec, maruenc->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_maru_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 (maruenc,
432             "Couldn't get caps for codec: %s", oclass->codec->name);
433       }
434       gst_maru_avcodec_close (ctx, maruenc->dev);
435     } else {
436       GST_DEBUG_OBJECT (maruenc, "Opening codec failed with pixfmt: %d", pixfmt);
437     }
438
439     gst_maru_avcodec_close (ctx, maruenc->dev);
440 #if 0
441     if (ctx->priv_data) {
442       gst_maru_avcodec_close (ctx, maruenc->dev);
443     }
444 #endif
445     g_free (ctx);
446   }
447
448   if (!caps) {
449     caps = gst_maruenc_get_possible_sizes (maruenc, pad,
450       gst_pad_get_pad_template_caps (pad));
451     GST_DEBUG_OBJECT (maruenc, "probing gave nothing, "
452       "return template %" GST_PTR_FORMAT, caps);
453     return caps;
454   }
455
456   GST_DEBUG_OBJECT (maruenc, "probed caps gave %" GST_PTR_FORMAT, caps);
457   oclass->sinkcaps = gst_caps_copy (caps);
458
459   finalcaps = gst_maruenc_get_possible_sizes (maruenc, pad, caps);
460   gst_caps_unref (caps);
461
462   return finalcaps;
463 }
464
465 static gboolean
466 gst_maruenc_setcaps (GstPad *pad, GstCaps *caps)
467 {
468   GstMaruEnc *maruenc;
469   GstMaruEncClass *oclass;
470   GstCaps *other_caps;
471   GstCaps *allowed_caps;
472   GstCaps *icaps;
473   enum PixelFormat pix_fmt;
474   int32_t buf_size;
475
476   maruenc = (GstMaruEnc *) (gst_pad_get_parent (pad));
477   oclass = (GstMaruEncClass *) (G_OBJECT_GET_CLASS (maruenc));
478
479   if (maruenc->opened) {
480     gst_maru_avcodec_close (maruenc->context, maruenc->dev);
481     maruenc->opened = FALSE;
482
483     gst_pad_set_caps (maruenc->srcpad, NULL);
484   }
485
486   maruenc->context->bit_rate = maruenc->bitrate;
487   GST_DEBUG_OBJECT (maruenc, "Setting context to bitrate %lu, gop_size %d",
488       maruenc->bitrate, maruenc->gop_size);
489
490 #if 0
491
492   // user defined properties
493   maruenc->context->gop_size = maruenc->gop_size;
494   maruenc->context->lmin = (maruenc->lmin * FF_QP2LAMBDA + 0.5);
495   maruenc->context->lmax = (maruenc->lmax * FF_QP2LAMBDA + 0.5);
496
497   // some other defaults
498   maruenc->context->b_frame_strategy = 0;
499   maruenc->context->coder_type = 0;
500   maruenc->context->context_model = 0;
501   maruenc->context->scenechange_threshold = 0;
502   maruenc->context->inter_threshold = 0;
503
504   if (maruenc->interlaced) {
505     maruenc->context->flags |=
506       CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME;
507     maruenc->picture->interlaced_frame = TRUE;
508
509     maruenc->picture->top_field_first = TRUE;
510   }
511 #endif
512
513   gst_maru_caps_with_codectype (oclass->codec->media_type, caps, maruenc->context);
514
515   if (!maruenc->context->video.fps_d) {
516     maruenc->context->video.fps_d = 25;
517     maruenc->context->video.fps_n = 1;
518   } else if (!strcmp(oclass->codec->name ,"mpeg4")
519       && (maruenc->context->video.fps_d > 65535)) {
520       maruenc->context->video.fps_n =
521         (gint) gst_util_uint64_scale_int (maruenc->context->video.fps_n,
522             65535, maruenc->context->video.fps_d);
523       maruenc->context->video.fps_d = 65535;
524       GST_LOG_OBJECT (maruenc, "MPEG4 : scaled down framerate to %d / %d",
525           maruenc->context->video.fps_d, maruenc->context->video.fps_n);
526   }
527
528   pix_fmt = maruenc->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 = maruenc->context->video.width;
537       height = maruenc->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   maruenc->dev->buf_size = gst_maru_align_size(buf_size);
551
552   // open codec
553   if (gst_maru_avcodec_open (maruenc->context,
554       oclass->codec, maruenc->dev) < 0) {
555     GST_DEBUG_OBJECT (maruenc, "maru_%senc: Failed to open codec",
556         oclass->codec->name);
557     return FALSE;
558   }
559
560   if (pix_fmt != maruenc->context->video.pix_fmt) {
561     gst_maru_avcodec_close (maruenc->context, maruenc->dev);
562     GST_DEBUG_OBJECT (maruenc,
563       "maru_%senc: AV wants different colorspace (%d given, %d wanted)",
564       oclass->codec->name, pix_fmt, maruenc->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 (maruenc, "maru_%senc: Failed to determine input format",
571       oclass->codec->name);
572     return FALSE;
573   }
574
575   GST_DEBUG_OBJECT (maruenc, "picking an output format.");
576   allowed_caps = gst_pad_get_allowed_caps (maruenc->srcpad);
577   if (!allowed_caps) {
578     GST_DEBUG_OBJECT (maruenc, "but no peer, using template caps");
579     allowed_caps =
580       gst_caps_copy (gst_pad_get_pad_template_caps (maruenc->srcpad));
581   }
582
583   GST_DEBUG_OBJECT (maruenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
584   gst_maru_caps_with_codecname (oclass->codec->name,
585     oclass->codec->media_type, allowed_caps, maruenc->context);
586
587   other_caps =
588   gst_maru_codecname_to_caps (oclass->codec->name, maruenc->context, TRUE);
589   if (!other_caps) {
590   GST_DEBUG("Unsupported codec - no caps found");
591     gst_maru_avcodec_close (maruenc->context, maruenc->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 (maruenc->srcpad, icaps)) {
614     gst_maru_avcodec_close (maruenc->context, maruenc->dev);
615     gst_caps_unref (icaps);
616     return FALSE;
617   }
618   gst_object_unref (maruenc);
619
620   maruenc->opened = TRUE;
621
622   return TRUE;
623 }
624
625 static void
626 gst_maruenc_setup_working_buf (GstMaruEnc *maruenc)
627 {
628   guint wanted_size =
629       maruenc->context->video.width * maruenc->context->video.height * 6 +
630       FF_MIN_BUFFER_SIZE;
631
632   if (maruenc->working_buf == NULL ||
633     maruenc->working_buf_size != wanted_size) {
634     if (maruenc->working_buf) {
635       g_free (maruenc->working_buf);
636     }
637     maruenc->working_buf_size = wanted_size;
638     maruenc->working_buf = g_malloc0 (maruenc->working_buf_size);
639   }
640   maruenc->buffer_size = wanted_size;
641 }
642
643 GstFlowReturn
644 gst_maruenc_chain_video (GstPad *pad, GstBuffer *buffer)
645 {
646   GstMaruEnc *maruenc = (GstMaruEnc *) (GST_PAD_PARENT (pad));
647   GstBuffer *outbuf = NULL;
648   gint ret_size = 0, frame_size = 0;
649   int ret = 0;
650   uint32_t mem_offset = 0;
651   uint8_t *working_buf = NULL;
652
653   GST_DEBUG_OBJECT (maruenc,
654       "Received buffer of time %" GST_TIME_FORMAT,
655       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
656
657 #if 0
658   GST_OBJECT_LOCK (maruenc);
659   force_keyframe = maruenc->force_keyframe;
660   maruenc->force_keyframe = FALSE;
661   GST_OBJECT_UNLOCK (maruenc);
662
663   if (force_keyframe) {
664     maruenc->picture->pict_type = FF_I_TYPE;
665   }
666 #endif
667
668   frame_size = gst_maru_avpicture_size (maruenc->context->video.pix_fmt,
669       maruenc->context->video.width, maruenc->context->video.height);
670   g_return_val_if_fail (frame_size == GST_BUFFER_SIZE (buffer),
671       GST_FLOW_ERROR);
672
673 #if 0
674   pts = gst_maru_time_gst_to_ff (GST_BUFFER_TIMESTAMP (buffer) /
675     maruenc->context.video.ticks_per_frame,
676     maruenc->context.video.fps_n, maruen->context.video.fps_d);
677 #endif
678
679   // TODO: check whether this func needs or not.
680   gst_maruenc_setup_working_buf (maruenc);
681
682   ret_size =
683     codec_encode_video (maruenc->context, maruenc->working_buf,
684                 maruenc->working_buf_size, GST_BUFFER_DATA (buffer),
685                 GST_BUFFER_SIZE (buffer), GST_BUFFER_TIMESTAMP (buffer),
686                 maruenc->dev);
687
688   if (ret_size < 0) {
689     GstMaruEncClass *oclass =
690       (GstMaruEncClass *) (G_OBJECT_GET_CLASS (maruenc));
691     GST_ERROR_OBJECT (maruenc,
692         "maru_%senc: failed to encode buffer", oclass->codec->name);
693     gst_buffer_unref (buffer);
694     return GST_FLOW_OK;
695   }
696
697   g_queue_push_tail (maruenc->delay, buffer);
698   if (ret_size) {
699     buffer = g_queue_pop_head (maruenc->delay);
700   } else {
701     return GST_FLOW_OK;
702   }
703
704 #if 0
705   if (maruenc->file && maruenc->context->stats_out) {
706     if (fprintf (maruenc->file, "%s", maruenc->context->stats_out) < 0) {
707       GST_ELEMENT_ERROR (maruenc, RESOURCE, WRITE,
708         (("Could not write to file \"%s\"."), maruenc->filename),
709         GST_ERROR_SYSTEM);
710     }
711   }
712 #endif
713
714   mem_offset = maruenc->dev->mem_info.offset;
715   working_buf = maruenc->dev->buf + mem_offset;
716
717   CODEC_LOG (DEBUG,
718     "encoded video. mem_offset = 0x%x\n",  mem_offset);
719
720   outbuf = gst_buffer_new_and_alloc (ret_size);
721 //  memcpy (GST_BUFFER_DATA (outbuf), maruenc->working_buf, ret_size);
722   memcpy (GST_BUFFER_DATA (outbuf), working_buf, ret_size);
723   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer);
724   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buffer);
725
726   ret = ioctl(maruenc->dev->fd, CODEC_CMD_RELEASE_BUFFER, &mem_offset);
727   if (ret < 0) {
728     CODEC_LOG (ERR, "failed to release used buffer\n");
729   }
730
731 #if 0
732   if (maruenc->context->coded_frame) {
733     if (!maruenc->context->coded_frame->key_frame) {
734       GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
735     }
736   } else {
737     GST_WARNING_OBJECT (maruenc, "codec did not provide keyframe info");
738   }
739 #endif
740   gst_buffer_set_caps (outbuf, GST_PAD_CAPS (maruenc->srcpad));
741
742   gst_buffer_unref (buffer);
743
744 #if 0
745
746   if (force_keyframe) {
747     gst_pad_push_event (maruenc->srcpad,
748       gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
749       gst_structure_new ("GstForceKeyUnit", "timestamp",
750                          G_TYPE_UINT64, GST_BUFFER_TIMESTAMP (outbuf), NULL)));
751   }
752 #endif
753
754   return gst_pad_push (maruenc->srcpad, outbuf);
755 }
756
757 GstFlowReturn
758 gst_maruenc_encode_audio (GstMaruEnc *maruenc, guint8 *audio_in,
759   guint in_size, guint max_size, GstClockTime timestamp,
760   GstClockTime duration, gboolean discont)
761 {
762   GstBuffer *outbuf;
763   guint8 *audio_out;
764   gint res;
765   GstFlowReturn ret;
766
767   outbuf = gst_buffer_new_and_alloc (max_size + FF_MIN_BUFFER_SIZE);
768   audio_out = GST_BUFFER_DATA (outbuf);
769
770   GST_LOG_OBJECT (maruenc, "encoding buffer of max size %d", max_size);
771   if (maruenc->buffer_size != max_size) {
772     maruenc->buffer_size = max_size;
773   }
774
775   res = codec_encode_audio (maruenc->context, audio_out, max_size,
776                                   audio_in, in_size, maruenc->dev);
777
778   if (res < 0) {
779     GST_ERROR_OBJECT (maruenc, "Failed to encode buffer: %d", res);
780     gst_buffer_unref (outbuf);
781     return GST_FLOW_OK;
782   }
783   GST_LOG_OBJECT (maruenc, "got output size %d", res);
784
785   GST_BUFFER_SIZE (outbuf) = res;
786   GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
787   GST_BUFFER_DURATION (outbuf) = duration;
788   if (discont) {
789     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
790   }
791   gst_buffer_set_caps (outbuf, GST_PAD_CAPS (maruenc->srcpad));
792
793   GST_LOG_OBJECT (maruenc, "pushing size %d, timestamp %",
794       GST_TIME_FORMAT, res, GST_TIME_ARGS (timestamp));
795
796   ret = gst_pad_push (maruenc->srcpad, outbuf);
797
798   return ret;
799 }
800
801 static GstFlowReturn
802 gst_maruenc_chain_audio (GstPad *pad, GstBuffer *buffer)
803 {
804   GstMaruEnc *maruenc;
805   GstMaruEncClass *oclass;
806   GstClockTime timestamp, duration;
807   guint in_size, frame_size;
808   gint osize;
809   GstFlowReturn ret;
810   gint out_size = 0;
811   gboolean discont;
812   guint8 *in_data;
813   CodecContext *ctx;
814
815   maruenc = (GstMaruEnc *) (GST_OBJECT_PARENT (pad));
816   oclass = (GstMaruEncClass *) G_OBJECT_GET_CLASS (maruenc);
817
818   ctx = maruenc->context;
819
820   in_size = GST_BUFFER_SIZE (buffer);
821   timestamp = GST_BUFFER_TIMESTAMP (buffer);
822   duration = GST_BUFFER_DURATION (buffer);
823   discont = GST_BUFFER_IS_DISCONT (buffer);
824
825   GST_DEBUG_OBJECT (maruenc,
826     "Received time %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT
827     ", size %d", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration), in_size);
828
829   frame_size = ctx->audio.frame_size;
830   osize = ctx->audio.bits_per_sample_fmt;
831
832   if (frame_size > 1) {
833     guint avail, frame_bytes;
834
835     if (discont) {
836       GST_LOG_OBJECT (maruenc, "DISCONT, clear adapter");
837       gst_adapter_clear (maruenc->adapter);
838       maruenc->discont = TRUE;
839     }
840
841     if (gst_adapter_available (maruenc->adapter) == 0) {
842       GST_LOG_OBJECT (maruenc, "taking buffer timestamp %" GST_TIME_FORMAT,
843         GST_TIME_ARGS (timestamp));
844       maruenc->adapter_ts = timestamp;
845       maruenc->adapter_consumed = 0;
846     } else {
847       GstClockTime upstream_time;
848       GstClockTime consumed_time;
849       guint64 bytes;
850
851       consumed_time =
852         gst_util_uint64_scale (maruenc->adapter_consumed, GST_SECOND,
853             ctx->audio.sample_rate);
854       timestamp = maruenc->adapter_ts + consumed_time;
855       GST_LOG_OBJECT (maruenc, "taking adapter timestamp %" GST_TIME_FORMAT
856         " and adding consumed time %" GST_TIME_FORMAT,
857         GST_TIME_ARGS (maruenc->adapter_ts), GST_TIME_ARGS (consumed_time));
858
859       upstream_time = gst_adapter_prev_timestamp (maruenc->adapter, &bytes);
860       if (GST_CLOCK_TIME_IS_VALID (upstream_time)) {
861         GstClockTimeDiff diff;
862
863         upstream_time +=
864           gst_util_uint64_scale (bytes, GST_SECOND,
865             ctx->audio.sample_rate * osize * ctx->audio.channels);
866         diff = upstream_time - timestamp;
867
868         if (diff > GST_SECOND / 10 || diff < -GST_SECOND / 10) {
869           GST_DEBUG_OBJECT (maruenc, "adapter timestamp drifting, "
870             "taking upstream timestamp %" GST_TIME_FORMAT,
871             GST_TIME_ARGS (upstream_time));
872           timestamp = upstream_time;
873
874           maruenc->adapter_consumed = bytes / (osize * ctx->audio.channels);
875           maruenc->adapter_ts =
876             upstream_time - gst_util_uint64_scale (maruenc->adapter_consumed,
877                 GST_SECOND, ctx->audio.sample_rate);
878           maruenc->discont = TRUE;
879         }
880       }
881     }
882
883     GST_LOG_OBJECT (maruenc, "pushing buffer in adapter");
884     gst_adapter_push (maruenc->adapter, buffer);
885
886     frame_bytes = frame_size * osize * ctx->audio.channels;
887     avail = gst_adapter_available (maruenc->adapter);
888
889     GST_LOG_OBJECT (maruenc, "frame_bytes %u, avail %u", frame_bytes, avail);
890
891     while (avail >= frame_bytes) {
892       GST_LOG_OBJECT (maruenc, "taking %u bytes from the adapter", frame_bytes);
893
894       in_data = (guint8 *) gst_adapter_peek (maruenc->adapter, frame_bytes);
895       maruenc->adapter_consumed += frame_size;
896
897       duration =
898         gst_util_uint64_scale (maruenc->adapter_consumed, GST_SECOND,
899           ctx->audio.sample_rate);
900       duration -= (timestamp - maruenc->adapter_ts);
901
902       out_size = frame_bytes * 4;
903
904       ret =
905         gst_maruenc_encode_audio (maruenc, in_data, frame_bytes, out_size,
906           timestamp, duration, maruenc->discont);
907
908       gst_adapter_flush (maruenc->adapter, frame_bytes);
909       if (ret != GST_FLOW_OK) {
910         GST_DEBUG_OBJECT (maruenc, "Failed to push buffer %d (%s)", ret,
911           gst_flow_get_name (ret));
912       }
913
914       timestamp += duration;
915
916       maruenc->discont = FALSE;
917       avail = gst_adapter_available (maruenc->adapter);
918     }
919     GST_LOG_OBJECT (maruenc, "%u bytes left in the adapter", avail);
920   } else {
921 #if 0
922     int coded_bps = av_get_bits_per_sample (oclass->codec->name);
923
924     GST_LOG_OBJECT (maruenc, "coded bps %d, osize %d", coded_bps, osize);
925
926     out_size = in_size / osize;
927     if (coded_bps) {
928       out_size = (out_size * coded_bps) / 8;
929     }
930 #endif
931     in_data = (guint8 *) GST_BUFFER_DATA (buffer);
932     ret = gst_maruenc_encode_audio (maruenc, in_data, in_size, out_size,
933       timestamp, duration, discont);
934     gst_buffer_unref (buffer);
935     if (ret != GST_FLOW_OK) {
936       GST_DEBUG_OBJECT (maruenc, "Failed to push buffer %d (%s)", ret,
937         gst_flow_get_name (ret));
938     }
939   }
940
941   return GST_FLOW_OK;
942 }
943
944 static void
945 gst_maruenc_flush_buffers (GstMaruEnc *maruenc, gboolean send)
946 {
947 #if 0
948   GstBuffer *outbuf, *inbuf;
949   gint ret_size = 0;
950 #endif
951
952   GST_DEBUG_OBJECT (maruenc, "flushing buffers with sending %d", send);
953
954   if (!maruenc->opened) {
955     while (!g_queue_is_empty (maruenc->delay)) {
956       gst_buffer_unref (g_queue_pop_head (maruenc->delay));
957     }
958   }
959
960 #if 0
961   while (!g_queue_is_empty (maruenc->delay)) {
962     maruenc_setup_working_buf (maruenc);
963
964     ret_size = codec_encode_video (maruenc->context,
965       maruenc->working_buf, maruenc->working_buf_size, NULL, NULL, 0,
966       maruenc->dev);
967
968     if (ret_size < 0) {
969       GstMaruEncClass *oclass =
970         (GstMaruEncClass *) (G_OBJECT_GET_CLASS (maruenc));
971       GST_WARNING_OBJECT (maruenc,
972         "maru_%senc: failed to flush buffer", oclass->codec->name);
973       break;
974     }
975
976     if (maruenc->file && maruenc->context->stats_out) {
977       if (fprintf (maruenc->file, "%s", maruenc->context->stats_out) < 0) {
978         GST_ELEMENT_ERROR (emeulenc, RESOURCE, WRITE,
979           (("Could not write to file \"%s\"."), maruenc->filename),
980           GST_ERROR_SYSTEM);
981       }
982     }
983
984     inbuf = g_queue_pop_head (maruenc->delay);
985
986     outbuf = gst_buffer_new_and_alloc (ret_size);
987     memcpy (GST_BUFFER_DATA (outbuf), maruenc->working_buf, ret_size);
988     GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf);
989     GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf);
990
991     if (!maruenc->context->coded_frame->key_frame) {
992       GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
993     }
994     gst_buffer_set_caps (outbuf, GST_PAD_CAPS (maruenc->srcpad));
995
996     gst_buffer_unref (inbuf);
997
998     if (send) {
999       gst_pad_push (maruenc->srcpad, outbuf);
1000     } else {
1001       gst_buffer_unref (outbuf);
1002     }
1003   }
1004
1005   while (!g_queue_is_empty (maruenc->delay)) {
1006     gst_buffer_unref (g_queue_pop_head (maruenc->delay));
1007   }
1008 #endif
1009 }
1010
1011 static gboolean
1012 gst_maruenc_event_video (GstPad *pad, GstEvent *event)
1013 {
1014   GstMaruEnc *maruenc;
1015   maruenc = (GstMaruEnc *) gst_pad_get_parent (pad);
1016
1017   switch (GST_EVENT_TYPE (event)) {
1018   case GST_EVENT_EOS:
1019     gst_maruenc_flush_buffers (maruenc, TRUE);
1020     break;
1021   case GST_EVENT_CUSTOM_DOWNSTREAM:
1022   {
1023     const GstStructure *s;
1024     s = gst_event_get_structure (event);
1025
1026     if (gst_structure_has_name (s, "GstForceKeyUnit")) {
1027 #if 0
1028       maruenc->picture->pict_type = FF_I_TYPE;
1029 #endif
1030     }
1031   }
1032     break;
1033   default:
1034     break;
1035   }
1036
1037   return gst_pad_push_event (maruenc->srcpad, event);
1038 }
1039
1040 static gboolean
1041 gst_maruenc_event_src (GstPad *pad, GstEvent *event)
1042 {
1043   GstMaruEnc *maruenc = (GstMaruEnc *) (GST_PAD_PARENT (pad));
1044   gboolean forward = TRUE;
1045
1046   switch (GST_EVENT_TYPE (event)) {
1047   case GST_EVENT_CUSTOM_UPSTREAM:
1048   {
1049     const GstStructure *s;
1050     s = gst_event_get_structure (event);
1051
1052     if (gst_structure_has_name (s, "GstForceKeyUnit")) {
1053 #if 0
1054       GST_OBJECT_LOCK (maruenc);
1055       maruenc->force_keyframe = TRUE;
1056       GST_OBJECT_UNLOCK (maruenc);
1057 #endif
1058       forward = FALSE;
1059       gst_event_unref (event);
1060     }
1061   }
1062     break;
1063   default:
1064     break;
1065   }
1066
1067   if (forward) {
1068     return gst_pad_push_event (maruenc->sinkpad, event);
1069   }
1070
1071   return TRUE;
1072 }
1073
1074 GstStateChangeReturn
1075 gst_maruenc_change_state (GstElement *element, GstStateChange transition)
1076 {
1077   GstMaruEnc *maruenc = (GstMaruEnc*)element;
1078   GstStateChangeReturn ret;
1079
1080   switch (transition) {
1081   default:
1082     break;
1083   }
1084
1085   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1086
1087   switch (transition) {
1088   case GST_STATE_CHANGE_PAUSED_TO_READY:
1089     gst_maruenc_flush_buffers (maruenc, FALSE);
1090     if (maruenc->opened) {
1091       gst_maru_avcodec_close (maruenc->context, maruenc->dev);
1092       maruenc->opened = FALSE;
1093     }
1094     gst_adapter_clear (maruenc->adapter);
1095
1096 #if 0
1097     if (maruenc->flie) {
1098       fclose (maruenc->file);
1099       maruenc->file = NULL;
1100     }
1101 #endif
1102
1103     if (maruenc->working_buf) {
1104       g_free (maruenc->working_buf);
1105       maruenc->working_buf = NULL;
1106     }
1107     break;
1108   default:
1109     break;
1110   }
1111
1112   return ret;
1113 }
1114
1115 gboolean
1116 gst_maruenc_register (GstPlugin *plugin, GList *element)
1117 {
1118   GTypeInfo typeinfo = {
1119       sizeof (GstMaruEncClass),
1120       (GBaseInitFunc) gst_maruenc_base_init,
1121       NULL,
1122       (GClassInitFunc) gst_maruenc_class_init,
1123       NULL,
1124       NULL,
1125       sizeof (GstMaruEnc),
1126       0,
1127       (GInstanceInitFunc) gst_maruenc_init,
1128   };
1129
1130   GType type;
1131   gchar *type_name;
1132   gint rank = GST_RANK_PRIMARY;
1133   GList *elem = element;
1134   CodecElement *codec = NULL;
1135
1136   if (!elem) {
1137     return FALSE;
1138   }
1139
1140   /* register element */
1141   do {
1142     codec = (CodecElement *)(elem->data);
1143     if (!codec) {
1144       return FALSE;
1145     }
1146
1147     if (codec->codec_type != CODEC_TYPE_ENCODE) {
1148       continue;
1149     }
1150
1151     type_name = g_strdup_printf ("maru_%senc", codec->name);
1152     type = g_type_from_name (type_name);
1153     if (!type) {
1154       type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
1155       g_type_set_qdata (type, GST_MARUENC_PARAMS_QDATA, (gpointer) codec);
1156     }
1157
1158     if (!gst_element_register (plugin, type_name, rank, type)) {
1159       g_free (type_name);
1160       return FALSE;
1161     }
1162     g_free (type_name);
1163   } while ((elem = elem->next));
1164
1165   return TRUE;
1166 }