[encoder] Improved motion estimation.
[schroedinger/research-port.git] / gst / gstbasevideocoder.c
blob7dedc053c86c1354f6edccae57a0acd581247221
1 /* GStreamer
2 * Copyright (C) 2008 David Schleef <ds@schleef.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library 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 GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include "gstbasevideocoder.h"
26 static void gst_base_video_coder_finalize (GObject *object);
28 static gboolean gst_base_video_coder_sink_setcaps (GstPad *pad, GstCaps *caps);
29 static gboolean gst_base_video_coder_sink_event (GstPad *pad, GstEvent *event);
30 static GstFlowReturn gst_base_video_coder_chain (GstPad *pad, GstBuffer *buf);
31 //static GstFlowReturn gst_base_video_coder_process (GstBaseVideoCoder *base_video_coder);
32 static GstStateChangeReturn gst_base_video_coder_change_state (GstElement *element,
33 GstStateChange transition);
34 static const GstQueryType * gst_base_video_coder_get_query_types (GstPad *pad);
35 static gboolean gst_base_video_coder_src_query (GstPad *pad, GstQuery *query);
38 static GstElementClass *parent_class;
40 GST_BOILERPLATE (GstBaseVideoCoder, gst_base_video_coder, GstElement,
41 GST_TYPE_ELEMENT);
43 static void
44 gst_base_video_coder_base_init (gpointer g_class)
49 static void
50 gst_base_video_coder_class_init (GstBaseVideoCoderClass * klass)
52 GObjectClass *gobject_class;
53 GstElementClass *gstelement_class;
55 gobject_class = G_OBJECT_CLASS (klass);
56 gstelement_class = GST_ELEMENT_CLASS (klass);
58 gobject_class->finalize = gst_base_video_coder_finalize;
60 gstelement_class->change_state = gst_base_video_coder_change_state;
62 parent_class = g_type_class_peek_parent (klass);
65 static void
66 gst_base_video_coder_init (GstBaseVideoCoder *base_video_coder,
67 GstBaseVideoCoderClass *klass)
69 GstPadTemplate *pad_template;
71 GST_DEBUG ("gst_base_video_coder_init");
73 pad_template =
74 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "sink");
75 g_return_if_fail (pad_template != NULL);
76 base_video_coder->sinkpad = gst_pad_new_from_template (pad_template, "sink");
78 gst_pad_set_chain_function (base_video_coder->sinkpad, gst_base_video_coder_chain);
79 gst_pad_set_event_function (base_video_coder->sinkpad, gst_base_video_coder_sink_event);
80 gst_pad_set_setcaps_function (base_video_coder->sinkpad, gst_base_video_coder_sink_setcaps);
81 //gst_pad_set_query_function (base_video_coder->sinkpad, gst_base_video_coder_sink_query);
82 gst_element_add_pad (GST_ELEMENT(base_video_coder), base_video_coder->sinkpad);
84 pad_template =
85 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "src");
86 g_return_if_fail (pad_template != NULL);
87 base_video_coder->srcpad = gst_pad_new_from_template (pad_template, "src");
89 gst_pad_set_query_type_function (base_video_coder->srcpad, gst_base_video_coder_get_query_types);
90 gst_pad_set_query_function (base_video_coder->srcpad, gst_base_video_coder_src_query);
91 gst_element_add_pad (GST_ELEMENT(base_video_coder), base_video_coder->srcpad);
94 static gboolean
95 gst_base_video_coder_sink_setcaps (GstPad *pad, GstCaps *caps)
97 GstBaseVideoCoder *base_video_coder;
98 GstBaseVideoCoderClass *base_video_coder_class;
100 base_video_coder = GST_BASE_VIDEO_CODER (gst_pad_get_parent (pad));
101 base_video_coder_class = GST_BASE_VIDEO_CODER_GET_CLASS(base_video_coder);
103 GST_DEBUG("setcaps");
105 gst_video_format_parse_caps (caps, &base_video_coder->format,
106 &base_video_coder->width,
107 &base_video_coder->height);
108 gst_video_parse_caps_framerate (caps, &base_video_coder->fps_n,
109 &base_video_coder->fps_d);
111 base_video_coder->par_n = 1;
112 base_video_coder->par_d = 1;
113 gst_video_parse_caps_pixel_aspect_ratio (caps, &base_video_coder->par_n,
114 &base_video_coder->par_d);
116 base_video_coder_class->set_format (base_video_coder,
117 base_video_coder->format,
118 base_video_coder->width,
119 base_video_coder->height,
120 base_video_coder->fps_n,
121 base_video_coder->fps_d,
122 base_video_coder->par_n,
123 base_video_coder->par_d);
125 base_video_coder_class->start (base_video_coder);
127 g_object_unref (base_video_coder);
129 return TRUE;
132 static void
133 gst_base_video_coder_finalize (GObject *object)
135 GstBaseVideoCoder *base_video_coder;
136 GstBaseVideoCoderClass *base_video_coder_class;
138 g_return_if_fail (GST_IS_BASE_VIDEO_CODER (object));
139 base_video_coder = GST_BASE_VIDEO_CODER (object);
140 base_video_coder_class = GST_BASE_VIDEO_CODER_GET_CLASS (object);
142 GST_DEBUG("finalize");
144 G_OBJECT_CLASS (parent_class)->finalize (object);
147 static gboolean
148 gst_base_video_coder_sink_event (GstPad *pad, GstEvent *event)
150 GstBaseVideoCoder *base_video_coder;
151 GstBaseVideoCoderClass *base_video_coder_class;
152 gboolean ret = FALSE;
154 base_video_coder = GST_BASE_VIDEO_CODER (gst_pad_get_parent (pad));
155 base_video_coder_class = GST_BASE_VIDEO_CODER_GET_CLASS (base_video_coder);
157 switch (GST_EVENT_TYPE (event)) {
158 case GST_EVENT_EOS:
160 GstVideoFrame *frame;
162 frame = g_malloc0 (sizeof(GstVideoFrame));
163 frame->presentation_frame_number = base_video_coder->presentation_frame_number;
164 frame->presentation_duration = 0;
165 //frame->presentation_duration = 0;
166 base_video_coder->presentation_frame_number++;
168 base_video_coder->frames = g_list_append(base_video_coder->frames, frame);
169 base_video_coder_class->finish (base_video_coder, frame);
171 ret = gst_pad_push_event (base_video_coder->srcpad, event);
173 break;
174 case GST_EVENT_NEWSEGMENT:
176 gboolean update;
177 double rate;
178 double applied_rate;
179 GstFormat format;
180 gint64 start;
181 gint64 stop;
182 gint64 position;
184 gst_event_parse_new_segment_full (event, &update, &rate,
185 &applied_rate, &format, &start, &stop, &position);
187 if (format != GST_FORMAT_TIME)
188 goto newseg_wrong_format;
190 GST_DEBUG("new segment %lld %lld", start, position);
192 gst_segment_set_newsegment_full (&base_video_coder->segment, update,
193 rate, applied_rate, format, start, stop, position);
195 ret = gst_pad_push_event (base_video_coder->srcpad, event);
197 break;
198 default:
199 /* FIXME this changes the order of events */
200 ret = gst_pad_push_event (base_video_coder->srcpad, event);
201 break;
204 done:
205 gst_object_unref (base_video_coder);
206 return ret;
208 newseg_wrong_format:
210 GST_DEBUG_OBJECT (base_video_coder, "received non TIME newsegment");
211 gst_event_unref (event);
212 goto done;
216 #if 0
217 static gboolean
218 gst_base_video_coder_sink_convert (GstPad *pad,
219 GstFormat src_format, gint64 src_value,
220 GstFormat * dest_format, gint64 *dest_value)
222 gboolean res = TRUE;
223 GstBaseVideoCoder *enc;
225 if (src_format == *dest_format) {
226 *dest_value = src_value;
227 return TRUE;
230 enc = GST_BASE_VIDEO_CODER (gst_pad_get_parent (pad));
232 /* FIXME: check if we are in a decoding state */
234 switch (src_format) {
235 case GST_FORMAT_BYTES:
236 switch (*dest_format) {
237 #if 0
238 case GST_FORMAT_DEFAULT:
239 *dest_value = gst_util_uint64_scale_int (src_value, 1,
240 enc->bytes_per_picture);
241 break;
242 #endif
243 case GST_FORMAT_TIME:
244 /* seems like a rather silly conversion, implement me if you like */
245 default:
246 res = FALSE;
248 break;
249 case GST_FORMAT_DEFAULT:
250 switch (*dest_format) {
251 case GST_FORMAT_TIME:
252 *dest_value = gst_util_uint64_scale (src_value,
253 GST_SECOND * enc->fps_d, enc->fps_n);
254 break;
255 #if 0
256 case GST_FORMAT_BYTES:
257 *dest_value = gst_util_uint64_scale_int (src_value,
258 enc->bytes_per_picture, 1);
259 break;
260 #endif
261 default:
262 res = FALSE;
264 break;
265 default:
266 res = FALSE;
267 break;
270 #endif
272 static gboolean
273 gst_base_video_coder_src_convert (GstPad *pad,
274 GstFormat src_format, gint64 src_value,
275 GstFormat * dest_format, gint64 *dest_value)
277 gboolean res = TRUE;
278 GstBaseVideoCoder *enc;
280 if (src_format == *dest_format) {
281 *dest_value = src_value;
282 return TRUE;
285 enc = GST_BASE_VIDEO_CODER (gst_pad_get_parent (pad));
287 /* FIXME: check if we are in a encoding state */
289 GST_ERROR("src convert");
290 switch (src_format) {
291 #if 0
292 case GST_FORMAT_DEFAULT:
293 switch (*dest_format) {
294 case GST_FORMAT_TIME:
295 *dest_value = gst_util_uint64_scale (granulepos_to_frame (src_value),
296 enc->fps_d * GST_SECOND, enc->fps_n);
297 break;
298 default:
299 res = FALSE;
301 break;
302 case GST_FORMAT_TIME:
303 switch (*dest_format) {
304 case GST_FORMAT_DEFAULT:
306 *dest_value = gst_util_uint64_scale (src_value,
307 enc->fps_n, enc->fps_d * GST_SECOND);
308 break;
310 default:
311 res = FALSE;
312 break;
314 break;
315 #endif
316 default:
317 res = FALSE;
318 break;
321 gst_object_unref (enc);
323 return res;
326 static const GstQueryType *
327 gst_base_video_coder_get_query_types (GstPad *pad)
329 static const GstQueryType query_types[] = {
330 //GST_QUERY_POSITION,
331 //GST_QUERY_DURATION,
332 GST_QUERY_CONVERT,
336 return query_types;
339 static gboolean
340 gst_base_video_coder_src_query (GstPad *pad, GstQuery *query)
342 GstBaseVideoCoder *enc;
343 gboolean res;
345 enc = GST_BASE_VIDEO_CODER (gst_pad_get_parent (pad));
347 switch GST_QUERY_TYPE (query) {
348 case GST_QUERY_CONVERT:
350 GstFormat src_fmt, dest_fmt;
351 gint64 src_val, dest_val;
353 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
354 res = gst_base_video_coder_src_convert (pad, src_fmt, src_val, &dest_fmt,
355 &dest_val);
356 if (!res) goto error;
357 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
358 break;
360 default:
361 res = gst_pad_query_default (pad, query);
363 gst_object_unref (enc);
364 return res;
366 error:
367 GST_DEBUG_OBJECT (enc, "query failed");
368 gst_object_unref (enc);
369 return res;
372 static gboolean
373 gst_pad_is_negotiated (GstPad *pad)
375 GstCaps *caps;
377 g_return_val_if_fail (pad != NULL, FALSE);
379 caps = gst_pad_get_negotiated_caps (pad);
380 if (caps) {
381 gst_caps_unref (caps);
382 return TRUE;
385 return FALSE;
388 static GstFlowReturn
389 gst_base_video_coder_chain (GstPad *pad, GstBuffer *buf)
391 GstBaseVideoCoder *base_video_coder;
392 GstBaseVideoCoderClass *klass;
393 GstVideoFrame *frame;
395 if (!gst_pad_is_negotiated (pad)) {
396 return GST_FLOW_NOT_NEGOTIATED;
399 base_video_coder = GST_BASE_VIDEO_CODER (gst_pad_get_parent (pad));
400 klass = GST_BASE_VIDEO_CODER_GET_CLASS (base_video_coder);
402 if (base_video_coder->sink_clipping) {
403 gint64 start = GST_BUFFER_TIMESTAMP (buf);
404 gint64 stop = start + GST_BUFFER_DURATION (buf);
405 gint64 clip_start;
406 gint64 clip_stop;
408 if (!gst_segment_clip (&base_video_coder->segment,
409 GST_FORMAT_TIME, start, stop, &clip_start, &clip_stop)) {
410 GST_DEBUG("clipping to segment dropped frame");
411 goto done;
415 frame = g_malloc0 (sizeof(GstVideoFrame));
416 frame->sink_buffer = buf;
417 frame->presentation_timestamp = GST_BUFFER_TIMESTAMP(buf);
418 frame->presentation_duration = GST_BUFFER_DURATION(buf);
419 frame->presentation_frame_number = base_video_coder->presentation_frame_number;
420 base_video_coder->presentation_frame_number++;
422 base_video_coder->frames = g_list_append(base_video_coder->frames, frame);
424 klass->handle_frame (base_video_coder, frame);
426 done:
427 g_object_unref (base_video_coder);
429 return GST_FLOW_OK;
432 static GstStateChangeReturn
433 gst_base_video_coder_change_state (GstElement *element, GstStateChange transition)
435 GstBaseVideoCoder *base_video_coder;
436 GstBaseVideoCoderClass *base_video_coder_class;
437 GstStateChangeReturn ret;
439 base_video_coder = GST_BASE_VIDEO_CODER (element);
440 base_video_coder_class = GST_BASE_VIDEO_CODER_GET_CLASS (element);
442 switch (transition) {
443 default:
444 break;
447 ret = GST_ELEMENT_CLASS(parent_class)->change_state (element, transition);
449 switch (transition) {
450 case GST_STATE_CHANGE_PAUSED_TO_READY:
451 if (base_video_coder_class->stop) {
452 base_video_coder_class->stop (base_video_coder);
454 break;
455 default:
456 break;
459 return ret;
462 GstFlowReturn
463 gst_base_video_coder_finish_frame (GstBaseVideoCoder *base_video_coder,
464 GstVideoFrame *frame)
466 GstFlowReturn ret;
467 GstBaseVideoCoderClass *base_video_coder_class;
469 base_video_coder_class = GST_BASE_VIDEO_CODER_GET_CLASS (base_video_coder);
471 frame->system_frame_number = base_video_coder->system_frame_number;
472 base_video_coder->system_frame_number++;
474 if (frame->is_sync_point) {
475 base_video_coder->distance_from_sync = 0;
476 GST_BUFFER_FLAG_UNSET (frame->src_buffer, GST_BUFFER_FLAG_DELTA_UNIT);
477 } else {
478 GST_BUFFER_FLAG_SET (frame->src_buffer, GST_BUFFER_FLAG_DELTA_UNIT);
481 frame->distance_from_sync = base_video_coder->distance_from_sync;
482 base_video_coder->distance_from_sync++;
484 frame->decode_frame_number = frame->system_frame_number - 1;
485 if (frame->decode_frame_number < 0) {
486 frame->decode_timestamp = 0;
487 } else {
488 frame->decode_timestamp = gst_util_uint64_scale (frame->decode_frame_number,
489 GST_SECOND * base_video_coder->fps_d,
490 base_video_coder->fps_n);
493 GST_BUFFER_TIMESTAMP(frame->src_buffer) = frame->presentation_timestamp;
494 GST_BUFFER_DURATION(frame->src_buffer) = frame->presentation_duration;
495 GST_BUFFER_OFFSET(frame->src_buffer) = frame->decode_timestamp;
497 base_video_coder->frames = g_list_remove (base_video_coder->frames, frame);
499 if (!base_video_coder->set_output_caps) {
500 GstCaps *caps;
502 if (base_video_coder_class->get_caps) {
503 caps = base_video_coder_class->get_caps (base_video_coder);
504 } else {
505 caps = gst_caps_new_simple ("video/unknown", NULL);
507 base_video_coder->caps = gst_caps_ref (caps);
508 gst_pad_set_caps (base_video_coder->srcpad, caps);
509 base_video_coder->set_output_caps = TRUE;
512 if (base_video_coder_class->shape_output) {
513 ret = base_video_coder_class->shape_output (base_video_coder, frame);
514 } else {
515 ret = gst_pad_push (base_video_coder->srcpad, frame->src_buffer);
518 g_free (frame);
520 return ret;
524 gst_base_video_coder_get_height (GstBaseVideoCoder *base_video_coder)
526 return base_video_coder->height;
530 gst_base_video_coder_get_width (GstBaseVideoCoder *base_video_coder)
532 return base_video_coder->width;
535 GstFlowReturn
536 gst_base_video_coder_end_of_stream (GstBaseVideoCoder *base_video_coder,
537 GstBuffer *buffer)
540 if (base_video_coder->frames) {
541 GST_ERROR("EOS with frames left over");
544 return gst_pad_push (base_video_coder->srcpad, buffer);