Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 797 lines (660 sloc) 21.38 kB
892306e @honkasuo initial import
authored
1 /**
2 * gst-sh-mobile-enc
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
17 *
18 * Johannes Lahti <johannes.lahti@nomovok.com>
19 * Pablo Virolainen <pablo.virolainen@nomovok.com>
20 * Aki Honkasuo <aki.honkasuo@nomovok.com>
21 *
22 */
23
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <poll.h>
34 #include <sys/ioctl.h>
35 #include <sys/mman.h>
36 #include <string.h>
37 #include <pthread.h>
38
39 #include <gst/gst.h>
40
41 #include "gstshvideoenc.h"
42 #include "cntlfile/ControlFileUtil.h"
43
44 /**
45 * Define capatibilities for the sink factory
46 */
47
48 static GstStaticPadTemplate sink_factory =
49 GST_STATIC_PAD_TEMPLATE ("sink",
50 GST_PAD_SINK,
51 GST_PAD_ALWAYS,
52 GST_STATIC_CAPS ("video/x-raw-yuv, "
53 "format = (fourcc) NV12,"
54 "width = (int) [16, 720],"
55 "height = (int) [16, 720],"
56 "framerate = (fraction) [0, 30]")
57 );
58
59
60 /**
61 * Define capatibilities for the source factory
62 */
63
64 static GstStaticPadTemplate src_factory =
65 GST_STATIC_PAD_TEMPLATE ("src",
66 GST_PAD_SRC,
67 GST_PAD_ALWAYS,
68 GST_STATIC_CAPS ("video/mpeg,"
69 "width = (int) [16, 720],"
70 "height = (int) [16, 720],"
71 "framerate = (fraction) [0, 30],"
72 "mpegversion = (int) 4"
73 "; "
74 "video/x-h264,"
75 "width = (int) [16, 720],"
76 "height = (int) [16, 720],"
77 "framerate = (fraction) [0, 30]"
78 )
79 );
80
81 GST_DEBUG_CATEGORY_STATIC (gst_sh_mobile_debug);
82 #define GST_CAT_DEFAULT gst_sh_mobile_debug
83
84 static GstElementClass *parent_class = NULL;
85
86 /**
87 * Define encoder properties
88 */
89
90 enum
91 {
92 PROP_0,
93 PROP_CNTL_FILE,
94 PROP_LAST
95 };
96
97 static void
98 gst_shvideo_enc_init_class (gpointer g_class, gpointer data)
99 {
100 parent_class = g_type_class_peek_parent (g_class);
101 gst_shvideo_enc_class_init ((GstshvideoEncClass *) g_class);
102 }
103
104 GType gst_shvideo_enc_get_type (void)
105 {
106 static GType object_type = 0;
107
108 if (object_type == 0) {
109 static const GTypeInfo object_info = {
110 sizeof (GstshvideoEncClass),
111 gst_shvideo_enc_base_init,
112 NULL,
113 gst_shvideo_enc_init_class,
114 NULL,
115 NULL,
116 sizeof (GstshvideoEnc),
117 0,
118 (GInstanceInitFunc) gst_shvideo_enc_init
119 };
120
121 object_type =
122 g_type_register_static (GST_TYPE_ELEMENT, "gst-sh-mobile-enc",
123 &object_info, (GTypeFlags) 0);
124 }
125
126 return object_type;
127 }
128
129 static void
130 gst_shvideo_enc_base_init (gpointer klass)
131 {
132 static const GstElementDetails plugin_details =
133 GST_ELEMENT_DETAILS ("SH hardware video encoder",
134 "Codec/Encoder/Video",
135 "Encode mpeg-based video stream (mpeg4, h264)",
136 "Johannes Lahti <johannes.lahti@nomovok.com>");
137 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
138
139 gst_element_class_add_pad_template (element_class,
140 gst_static_pad_template_get (&src_factory));
141 gst_element_class_add_pad_template (element_class,
142 gst_static_pad_template_get (&sink_factory));
143 gst_element_class_set_details (element_class, &plugin_details);
144 }
145
146 static void
147 gst_shvideo_enc_dispose (GObject * object)
148 {
149 GstshvideoEnc *shvideoenc = GST_SHVIDEOENC (object);
150
151 if (shvideoenc->encoder!=NULL) {
152 shvideoenc->encoder= NULL;
153 }
154
155 pthread_mutex_destroy(&shvideoenc->mutex);
156 pthread_mutex_destroy(&shvideoenc->cond_mutex);
157 pthread_cond_destroy(&shvideoenc->thread_condition);
158
159 G_OBJECT_CLASS (parent_class)->dispose (object);
160 }
161
162 static void
163 gst_shvideo_enc_class_init (GstshvideoEncClass * klass)
164 {
165 GObjectClass *gobject_class;
166 GstElementClass *gstelement_class;
167
168 gobject_class = (GObjectClass *) klass;
169 gstelement_class = (GstElementClass *) klass;
170
171 gobject_class->dispose = gst_shvideo_enc_dispose;
172 gobject_class->set_property = gst_shvideo_enc_set_property;
173 gobject_class->get_property = gst_shvideo_enc_get_property;
174
175 GST_DEBUG_CATEGORY_INIT (gst_sh_mobile_debug, "gst-sh-mobile-enc",
176 0, "Encoder for H264/MPEG4 streams");
177
178 g_object_class_install_property (gobject_class, PROP_CNTL_FILE,
179 g_param_spec_string ("cntl-file", "Control file location",
180 "Location of the file including encoding parameters",
181 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
182 }
183
184 static void
185 gst_shvideo_enc_init (GstshvideoEnc * shvideoenc,
186 GstshvideoEncClass * gklass)
187 {
188 GstElementClass *klass = GST_ELEMENT_GET_CLASS (shvideoenc);
189
190 GST_LOG_OBJECT(shvideoenc,"%s called",__FUNCTION__);
191
192 shvideoenc->sinkpad =
193 gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
194 "sink"), "sink");
195
196 gst_element_add_pad (GST_ELEMENT (shvideoenc), shvideoenc->sinkpad);
197
198 gst_pad_set_setcaps_function (shvideoenc->sinkpad, gst_shvideoenc_setcaps);
199 gst_pad_set_activate_function (shvideoenc->sinkpad, gst_shvideo_enc_activate);
200 gst_pad_set_activatepull_function (shvideoenc->sinkpad,
201 gst_shvideo_enc_activate_pull);
202 gst_pad_set_event_function(shvideoenc->sinkpad, gst_shvideo_enc_sink_event);
203 gst_pad_set_chain_function(shvideoenc->sinkpad, gst_shvideo_enc_chain);
204 shvideoenc->srcpad =
205 gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
206 "src"), "src");
207 gst_pad_use_fixed_caps (shvideoenc->srcpad);
208
209 gst_pad_set_query_function (shvideoenc->srcpad,
210 GST_DEBUG_FUNCPTR (gst_shvideo_enc_src_query));
211
212 gst_element_add_pad (GST_ELEMENT (shvideoenc), shvideoenc->srcpad);
213
214 shvideoenc->encoder=NULL;
215 shvideoenc->caps_set=FALSE;
216 shvideoenc->enc_thread = 0;
217 shvideoenc->buffer_yuv = NULL;
218 shvideoenc->buffer_cbcr = NULL;
219
220 pthread_mutex_init(&shvideoenc->mutex,NULL);
221 pthread_mutex_init(&shvideoenc->cond_mutex,NULL);
222 pthread_cond_init(&shvideoenc->thread_condition,NULL);
223
224 shvideoenc->format = SHCodecs_Format_NONE;
225 shvideoenc->out_caps = NULL;
226 shvideoenc->width = 0;
227 shvideoenc->height = 0;
228 shvideoenc->fps_numerator = 0;
229 shvideoenc->fps_denominator = 0;
230 shvideoenc->frame_number = 0;
231 }
232
233 static void
234 gst_shvideo_enc_set_property (GObject * object, guint prop_id,
235 const GValue * value, GParamSpec * pspec)
236 {
237 GstshvideoEnc *shvideoenc = GST_SHVIDEOENC (object);
238
239 switch (prop_id)
240 {
241 case PROP_CNTL_FILE:
242 {
243 strcpy(shvideoenc->ainfo.ctrl_file_name_buf,g_value_get_string(value));
244 break;
245 }
246 default:
247 {
248 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
249 break;
250 }
251 }
252 }
253
254 static void
255 gst_shvideo_enc_get_property (GObject * object, guint prop_id,
256 GValue * value, GParamSpec * pspec)
257 {
258 GstshvideoEnc *shvideoenc = GST_SHVIDEOENC (object);
259
260 switch (prop_id)
261 {
262 case PROP_CNTL_FILE:
263 {
264 g_value_set_string(value,shvideoenc->ainfo.ctrl_file_name_buf);
265 break;
266 }
267 default:
268 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
269 }
270 }
271
272 static gboolean
273 gst_shvideo_enc_sink_event (GstPad * pad, GstEvent * event)
274 {
275 GstshvideoEnc *enc = (GstshvideoEnc *) (GST_OBJECT_PARENT (pad));
276
277 GST_LOG_OBJECT(enc,"%s called",__FUNCTION__);
278
279 return gst_pad_push_event(enc->srcpad,event);
280 }
281
282 static gboolean
283 gst_shvideoenc_setcaps (GstPad * pad, GstCaps * caps)
284 {
285 gboolean ret;
286 GstStructure *structure;
287 GstshvideoEnc *enc =
288 (GstshvideoEnc *) (GST_OBJECT_PARENT (pad));
289
290 enc->caps_set = FALSE;
291 ret = TRUE;
292
293 GST_LOG_OBJECT(enc,"%s called",__FUNCTION__);
294
295 // get input size
296 structure = gst_caps_get_structure (caps, 0);
297 ret = gst_structure_get_int (structure, "width", &enc->width);
298 ret &= gst_structure_get_int (structure, "height", &enc->height);
299 ret &= gst_structure_get_fraction (structure, "framerate",
300 &enc->fps_numerator,
301 &enc->fps_denominator);
302
303 if(!ret) {
304 return ret;
305 }
306
307 gst_shvideoenc_read_src_caps(enc);
308 gst_shvideo_enc_init_encoder(enc);
309
310 if(!gst_caps_is_any(enc->out_caps))
311 {
312 ret = gst_shvideoenc_set_src_caps(enc);
313 }
314
315 if(ret) {
316 enc->caps_set = TRUE;
317 }
318
319 return ret;
320 }
321
322 void
323 gst_shvideoenc_read_src_caps(GstshvideoEnc * shvideoenc)
324 {
325 GstStructure *structure;
326
327 GST_LOG_OBJECT(shvideoenc,"%s called",__FUNCTION__);
328
329 // get the caps of the next element in chain
330 shvideoenc->out_caps = gst_pad_peer_get_caps(shvideoenc->srcpad);
331
332 // Any format is ok too
333 if(!gst_caps_is_any(shvideoenc->out_caps))
334 {
335 structure = gst_caps_get_structure (shvideoenc->out_caps, 0);
336 if (!strcmp (gst_structure_get_name (structure), "video/mpeg")) {
337 shvideoenc->format = SHCodecs_Format_MPEG4;
338 }
339 else if (!strcmp (gst_structure_get_name (structure), "video/x-h264")) {
340 shvideoenc->format = SHCodecs_Format_H264;
341 }
342 }
343 }
344
345 gboolean
346 gst_shvideoenc_set_src_caps(GstshvideoEnc * shvideoenc)
347 {
348 GstCaps* caps = NULL;
349 gboolean ret = TRUE;
350
351 GST_LOG_OBJECT(shvideoenc,"%s called",__FUNCTION__);
352
353 if(shvideoenc->format == SHCodecs_Format_MPEG4)
354 {
355 caps = gst_caps_new_simple ("video/mpeg", "width", G_TYPE_INT,
356 shvideoenc->width, "height", G_TYPE_INT,
357 shvideoenc->height, "framerate",
358 GST_TYPE_FRACTION, shvideoenc->fps_numerator,
359 shvideoenc->fps_denominator, "mpegversion",
360 G_TYPE_INT, 4, NULL);
361 }
362 else if(shvideoenc->format == SHCodecs_Format_H264)
363 {
364 caps = gst_caps_new_simple ("video/x-h264", "width", G_TYPE_INT,
365 shvideoenc->width, "height", G_TYPE_INT,
366 shvideoenc->height, "framerate",
367 GST_TYPE_FRACTION, shvideoenc->fps_numerator,
368 shvideoenc->fps_denominator, NULL);
369 }
370 else
371 {
372 GST_ELEMENT_ERROR((GstElement*)shvideoenc,CORE,NEGOTIATION,
373 ("Format undefined."), (NULL));
374 }
375
376 if(!gst_pad_set_caps(shvideoenc->srcpad,caps))
377 {
378 GST_ELEMENT_ERROR((GstElement*)shvideoenc,CORE,NEGOTIATION,
379 ("Source pad not linked."), (NULL));
380 ret = FALSE;
381 }
382 if(!gst_pad_set_caps(gst_pad_get_peer(shvideoenc->srcpad),caps))
383 {
384 GST_ELEMENT_ERROR((GstElement*)shvideoenc,CORE,NEGOTIATION,
385 ("Source pad not linked."), (NULL));
386 ret = FALSE;
387 }
388 gst_caps_unref(caps);
389 return ret;
390 }
391
392 void
393 gst_shvideo_enc_init_encoder(GstshvideoEnc * shvideoenc)
394 {
395 gint ret = 0;
396 glong fmt = 0;
397
398 GST_LOG_OBJECT(shvideoenc,"%s called",__FUNCTION__);
399
400 ret = GetFromCtrlFTop((const char *)
401 shvideoenc->ainfo.ctrl_file_name_buf,
402 &shvideoenc->ainfo,
403 &fmt);
404 if (ret < 0) {
405 GST_ELEMENT_ERROR((GstElement*)shvideoenc,CORE,FAILED,
406 ("Error reading control file."), (NULL));
407 }
408
409 if(shvideoenc->format == SHCodecs_Format_NONE)
410 {
411 shvideoenc->format = fmt;
412 }
413
414 if(!shvideoenc->width)
415 {
416 shvideoenc->width = shvideoenc->ainfo.xpic;
417 }
418
419 if(!shvideoenc->height)
420 {
421 shvideoenc->height = shvideoenc->ainfo.ypic;
422 }
423
424 shvideoenc->encoder = shcodecs_encoder_init(shvideoenc->width,
425 shvideoenc->height,
426 shvideoenc->format);
427
428 shcodecs_encoder_set_input_callback(shvideoenc->encoder,
429 gst_shvideo_enc_get_input,
430 shvideoenc);
431 shcodecs_encoder_set_output_callback(shvideoenc->encoder,
432 gst_shvideo_enc_write_output,
433 shvideoenc);
434
435 ret =
436 GetFromCtrlFtoEncParam(shvideoenc->encoder, &shvideoenc->ainfo);
437
438 if (ret < 0) {
439 GST_ELEMENT_ERROR((GstElement*)shvideoenc,CORE,FAILED,
440 ("Error reading control file."), (NULL));
441 }
442
443 if(shvideoenc->fps_numerator && shvideoenc->fps_denominator)
444 {
445 shcodecs_encoder_set_frame_rate(shvideoenc->encoder,
446 (shvideoenc->fps_numerator/shvideoenc->fps_denominator*10));
447 }
448 shcodecs_encoder_set_xpic_size(shvideoenc->encoder,shvideoenc->width);
449 shcodecs_encoder_set_ypic_size(shvideoenc->encoder,shvideoenc->height);
450
451 shcodecs_encoder_set_frame_no_increment(shvideoenc->encoder,
452 shcodecs_encoder_get_frame_num_resolution(shvideoenc->encoder) /
453 (shcodecs_encoder_get_frame_rate(shvideoenc->encoder) / 10));
454
455 GST_DEBUG_OBJECT(shvideoenc,"Encoder init: %ldx%ld %ldfps format:%ld",
456 shcodecs_encoder_get_xpic_size(shvideoenc->encoder),
457 shcodecs_encoder_get_ypic_size(shvideoenc->encoder),
458 shcodecs_encoder_get_frame_rate(shvideoenc->encoder)/10,
459 shcodecs_encoder_get_stream_type(shvideoenc->encoder));
460 }
461
462 static gboolean
463 gst_shvideo_enc_activate (GstPad * pad)
464 {
465 gboolean ret;
466 GstshvideoEnc *enc =
467 (GstshvideoEnc *) (GST_OBJECT_PARENT (pad));
468
469 GST_LOG_OBJECT(enc,"%s called",__FUNCTION__);
470 if (gst_pad_check_pull_range (pad)) {
471 GST_LOG_OBJECT(enc,"PULL mode");
472 ret = gst_pad_activate_pull (pad, TRUE);
473 } else {
474 GST_LOG_OBJECT(enc,"PUSH mode");
475 ret = gst_pad_activate_push (pad, TRUE);
476 }
477 return ret;
478 }
479
480 static GstFlowReturn
481 gst_shvideo_enc_chain (GstPad * pad, GstBuffer * buffer)
482 {
483 gint yuv_size, cbcr_size, i, j;
484 guint8* cr_ptr;
485 guint8* cb_ptr;
486 GstshvideoEnc *enc = (GstshvideoEnc *) (GST_OBJECT_PARENT (pad));
487
488 GST_LOG_OBJECT(enc,"%s called",__FUNCTION__);
489
490 if(!enc->caps_set)
491 {
492 gst_shvideoenc_read_src_caps(enc);
493 gst_shvideo_enc_init_encoder(enc);
494 if(!gst_caps_is_any(enc->out_caps))
495 {
496 if(!gst_shvideoenc_set_src_caps(enc))
497 {
498 return GST_FLOW_UNEXPECTED;
499 }
500 }
501 enc->caps_set = TRUE;
502 }
503
504 /* If buffers are not empty we'll have to
505 wait until encoder has consumed data */
506 if(enc->buffer_yuv && enc->buffer_cbcr)
507 {
508 pthread_mutex_lock( &enc->cond_mutex );
509 pthread_cond_wait( &enc->thread_condition, &enc->cond_mutex );
510 pthread_mutex_unlock( &enc->cond_mutex );
511 }
512
513 // Lock mutex while handling the buffers
514 pthread_mutex_lock(&enc->mutex);
515 yuv_size = enc->width*enc->height;
516 cbcr_size = enc->width*enc->height/2;
517
518 // Check that we have got enough data
519 if(GST_BUFFER_SIZE(buffer) != yuv_size + cbcr_size)
520 {
521 GST_DEBUG_OBJECT (enc, "Not enough data");
522 // If we can't continue we can issue EOS
523 gst_pad_push_event(enc->srcpad,gst_event_new_eos ());
524 return GST_FLOW_OK;
525 }
526
527 enc->buffer_yuv = gst_buffer_new_and_alloc (yuv_size);
528 enc->buffer_cbcr = gst_buffer_new_and_alloc (cbcr_size);
529
530 memcpy(GST_BUFFER_DATA(enc->buffer_yuv),GST_BUFFER_DATA(buffer),yuv_size);
531
532 if(enc->ainfo.yuv_CbCr_format == 0)
533 {
534 cb_ptr = GST_BUFFER_DATA(buffer)+yuv_size;
535 cr_ptr = GST_BUFFER_DATA(buffer)+yuv_size+(cbcr_size/2);
536
537 for(i=0,j=0;i<cbcr_size;i+=2,j++)
538 {
539 GST_BUFFER_DATA(enc->buffer_cbcr)[i]=cb_ptr[j];
540 GST_BUFFER_DATA(enc->buffer_cbcr)[i+1]=cr_ptr[j];
541 }
542 }
543 else
544 {
545 memcpy(GST_BUFFER_DATA(enc->buffer_cbcr),GST_BUFFER_DATA(buffer)+yuv_size,
546 cbcr_size);
547 }
548
549 // Buffers are ready to be read
550 pthread_mutex_unlock(&enc->mutex);
551
552 gst_buffer_unref(buffer);
553
554 if(!enc->enc_thread)
555 {
556 /* We'll have to launch the encoder in
557 a separate thread to keep the pipeline running */
558 pthread_create( &enc->enc_thread, NULL, launch_encoder_thread, enc);
559 }
560
561 return GST_FLOW_OK;
562 }
563
564 static gboolean
565 gst_shvideo_enc_activate_pull (GstPad *pad,
566 gboolean active)
567 {
568 GstshvideoEnc *enc =
569 (GstshvideoEnc *) (GST_OBJECT_PARENT (pad));
570
571 GST_LOG_OBJECT(enc,"%s called",__FUNCTION__);
572
573 if (active) {
574 enc->offset = 0;
575 return gst_pad_start_task (pad,
576 (GstTaskFunction) gst_shvideo_enc_loop, enc);
577 } else {
578 return gst_pad_stop_task (pad);
579 }
580 }
581
582 static void
583 gst_shvideo_enc_loop (GstshvideoEnc *enc)
584 {
585 GstFlowReturn ret;
586 gint yuv_size, cbcr_size, i, j;
587 guint8* cb_ptr;
588 guint8* cr_ptr;
589 GstBuffer* tmp;
590
591 GST_LOG_OBJECT(enc,"%s called",__FUNCTION__);
592
593 if(!enc->caps_set)
594 {
595 gst_shvideoenc_read_src_caps(enc);
596 gst_shvideo_enc_init_encoder(enc);
597 if(!gst_caps_is_any(enc->out_caps))
598 {
599 if(!gst_shvideoenc_set_src_caps(enc))
600 {
601 gst_pad_pause_task (enc->sinkpad);
602 return;
603 }
604 }
605 enc->caps_set = TRUE;
606 }
607
608 /* If buffers are not empty we'll have to
609 wait until encoder has consumed data */
610 if(enc->buffer_yuv && enc->buffer_cbcr)
611 {
612 pthread_mutex_lock( &enc->cond_mutex );
613 pthread_cond_wait( &enc->thread_condition, &enc->cond_mutex );
614 pthread_mutex_unlock( &enc->cond_mutex );
615 }
616
617 // Lock mutex while handling the buffers
618 pthread_mutex_lock(&enc->mutex);
619 yuv_size = enc->width*enc->height;
620 cbcr_size = enc->width*enc->height/2;
621
622 ret = gst_pad_pull_range (enc->sinkpad, enc->offset,
623 yuv_size, &enc->buffer_yuv);
624
625 if (ret != GST_FLOW_OK) {
626 GST_DEBUG_OBJECT (enc, "pull_range failed: %s", gst_flow_get_name (ret));
627 gst_pad_pause_task (enc->sinkpad);
628 return;
629 }
630 else if(GST_BUFFER_SIZE(enc->buffer_yuv) != yuv_size)
631 {
632 GST_DEBUG_OBJECT (enc, "Not enough data");
633 gst_pad_pause_task (enc->sinkpad);
634 gst_pad_push_event(enc->srcpad,gst_event_new_eos ());
635 return;
636 }
637
638 enc->offset += yuv_size;
639
640 ret = gst_pad_pull_range (enc->sinkpad, enc->offset,
641 cbcr_size, &tmp);
642
643 if (ret != GST_FLOW_OK) {
644 GST_DEBUG_OBJECT (enc, "pull_range failed: %s", gst_flow_get_name (ret));
645 gst_pad_pause_task (enc->sinkpad);
646 return;
647 }
648 else if(GST_BUFFER_SIZE(tmp) != cbcr_size)
649 {
650 GST_DEBUG_OBJECT (enc, "Not enough data");
651 gst_pad_pause_task (enc->sinkpad);
652 gst_pad_push_event(enc->srcpad,gst_event_new_eos ());
653 return;
654 }
655
656 enc->offset += cbcr_size;
657
658 if(enc->ainfo.yuv_CbCr_format == 0)
659 {
660 cb_ptr = GST_BUFFER_DATA(tmp);
661 cr_ptr = GST_BUFFER_DATA(tmp)+(cbcr_size/2);
662 enc->buffer_cbcr = gst_buffer_new_and_alloc(cbcr_size);
663
664 for(i=0,j=0;i<cbcr_size;i+=2,j++)
665 {
666 GST_BUFFER_DATA(enc->buffer_cbcr)[i]=cb_ptr[j];
667 GST_BUFFER_DATA(enc->buffer_cbcr)[i+1]=cr_ptr[j];
668 }
669
670 gst_buffer_unref(tmp);
671 }
672 else
673 {
674 enc->buffer_cbcr = tmp;
675 }
676
677 pthread_mutex_unlock(&enc->mutex);
678
679 if(!enc->enc_thread)
680 {
681 /* We'll have to launch the encoder in
682 a separate thread to keep the pipeline running */
683 pthread_create( &enc->enc_thread, NULL, launch_encoder_thread, enc);
684 }
685 }
686
687 void *
688 launch_encoder_thread(void *data)
689 {
690 gint ret;
691 GstshvideoEnc *enc = (GstshvideoEnc *)data;
692
693 GST_LOG_OBJECT(enc,"%s called",__FUNCTION__);
694
695 ret = shcodecs_encoder_run(enc->encoder);
696
697 GST_DEBUG_OBJECT (enc,"shcodecs_encoder_run returned %d\n",ret);
698
699 // We can stop waiting if encoding has ended
700 pthread_mutex_lock( &enc->cond_mutex );
701 pthread_cond_signal( &enc->thread_condition);
702 pthread_mutex_unlock( &enc->cond_mutex );
703
704 // Calling stop task won't do any harm if we are in push mode
705 gst_pad_stop_task (enc->sinkpad);
706 gst_pad_push_event(enc->srcpad,gst_event_new_eos ());
707
708 return NULL;
709 }
710
711 static int
712 gst_shvideo_enc_get_input(SHCodecs_Encoder * encoder, void *user_data)
713 {
714 GstshvideoEnc *shvideoenc = (GstshvideoEnc *)user_data;
715 gint ret=0;
716
717 GST_LOG_OBJECT(shvideoenc,"%s called",__FUNCTION__);
718
719 // Lock mutex while reading the buffer
720 pthread_mutex_lock(&shvideoenc->mutex);
721 if(shvideoenc->buffer_yuv && shvideoenc->buffer_cbcr)
722 {
723 ret = shcodecs_encoder_input_provide(encoder,
724 GST_BUFFER_DATA(shvideoenc->buffer_yuv),
725 GST_BUFFER_DATA(shvideoenc->buffer_cbcr));
726
727 gst_buffer_unref(shvideoenc->buffer_yuv);
728 shvideoenc->buffer_yuv = NULL;
729 gst_buffer_unref(shvideoenc->buffer_cbcr);
730 shvideoenc->buffer_cbcr = NULL;
731
732 // Signal the main thread that buffers are read
733 pthread_mutex_lock( &shvideoenc->cond_mutex );
734 pthread_cond_signal( &shvideoenc->thread_condition);
735 pthread_mutex_unlock( &shvideoenc->cond_mutex );
736 }
737 pthread_mutex_unlock(&shvideoenc->mutex);
738
739 return 0;
740 }
741
742 static int
743 gst_shvideo_enc_write_output(SHCodecs_Encoder * encoder,
744 unsigned char *data, int length, void *user_data)
745 {
746 GstshvideoEnc *enc = (GstshvideoEnc *)user_data;
747 GstBuffer* buf=NULL;
748 gint ret=0;
749
750 GST_LOG_OBJECT(enc,"%s called. Got %d bytes data\n",__FUNCTION__, length);
751
752 if(length)
753 {
754 buf = gst_buffer_new();
755 gst_buffer_set_data(buf, data, length);
756
757 GST_BUFFER_DURATION(buf) = enc->fps_denominator*1000*GST_MSECOND/enc->fps_numerator;
758 GST_BUFFER_TIMESTAMP(buf) = enc->frame_number*GST_BUFFER_DURATION(buf);
759 enc->frame_number++;
760
761 ret = gst_pad_push (enc->srcpad, buf);
762
763 if (ret != GST_FLOW_OK) {
764 GST_DEBUG_OBJECT (enc, "pad_push failed: %s", gst_flow_get_name (ret));
765 return 1;
766 }
767 }
768 return 0;
769 }
770
771 static gboolean
772 gst_shvideo_enc_src_query (GstPad * pad, GstQuery * query)
773 {
774 GstshvideoEnc *enc =
775 (GstshvideoEnc *) (GST_OBJECT_PARENT (pad));
776 GST_LOG_OBJECT(enc,"%s called",__FUNCTION__);
777 return gst_pad_query_default (pad, query);
778 }
779
780 gboolean
781 gst_shvideo_enc_plugin_init (GstPlugin * plugin)
782 {
783 if (!gst_element_register (plugin, "gst-sh-mobile-enc", GST_RANK_PRIMARY,
784 GST_TYPE_SHVIDEOENC))
785 return FALSE;
786
787 return TRUE;
788 }
789
790 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
791 GST_VERSION_MINOR,
792 "gst-sh-mobile-enc",
793 "gst-sh-mobile",
794 gst_shvideo_enc_plugin_init,
795 VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
796
Something went wrong with that request. Please try again.