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.
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
,
44 gst_base_video_coder_base_init (gpointer g_class
)
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
);
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");
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
);
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
);
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
);
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
);
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
)) {
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
);
174 case GST_EVENT_NEWSEGMENT
:
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
);
199 /* FIXME this changes the order of events */
200 ret
= gst_pad_push_event (base_video_coder
->srcpad
, event
);
205 gst_object_unref (base_video_coder
);
210 GST_DEBUG_OBJECT (base_video_coder
, "received non TIME newsegment");
211 gst_event_unref (event
);
218 gst_base_video_coder_sink_convert (GstPad
*pad
,
219 GstFormat src_format
, gint64 src_value
,
220 GstFormat
* dest_format
, gint64
*dest_value
)
223 GstBaseVideoCoder
*enc
;
225 if (src_format
== *dest_format
) {
226 *dest_value
= src_value
;
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
) {
238 case GST_FORMAT_DEFAULT
:
239 *dest_value
= gst_util_uint64_scale_int (src_value
, 1,
240 enc
->bytes_per_picture
);
243 case GST_FORMAT_TIME
:
244 /* seems like a rather silly conversion, implement me if you like */
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
);
256 case GST_FORMAT_BYTES
:
257 *dest_value
= gst_util_uint64_scale_int (src_value
,
258 enc
->bytes_per_picture
, 1);
273 gst_base_video_coder_src_convert (GstPad
*pad
,
274 GstFormat src_format
, gint64 src_value
,
275 GstFormat
* dest_format
, gint64
*dest_value
)
278 GstBaseVideoCoder
*enc
;
280 if (src_format
== *dest_format
) {
281 *dest_value
= src_value
;
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
) {
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
);
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
);
321 gst_object_unref (enc
);
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,
340 gst_base_video_coder_src_query (GstPad
*pad
, GstQuery
*query
)
342 GstBaseVideoCoder
*enc
;
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
,
356 if (!res
) goto error
;
357 gst_query_set_convert (query
, src_fmt
, src_val
, dest_fmt
, dest_val
);
361 res
= gst_pad_query_default (pad
, query
);
363 gst_object_unref (enc
);
367 GST_DEBUG_OBJECT (enc
, "query failed");
368 gst_object_unref (enc
);
373 gst_pad_is_negotiated (GstPad
*pad
)
377 g_return_val_if_fail (pad
!= NULL
, FALSE
);
379 caps
= gst_pad_get_negotiated_caps (pad
);
381 gst_caps_unref (caps
);
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
);
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");
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
);
427 g_object_unref (base_video_coder
);
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
) {
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
);
463 gst_base_video_coder_finish_frame (GstBaseVideoCoder
*base_video_coder
,
464 GstVideoFrame
*frame
)
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
);
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;
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
) {
502 if (base_video_coder_class
->get_caps
) {
503 caps
= base_video_coder_class
->get_caps (base_video_coder
);
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
);
515 ret
= gst_pad_push (base_video_coder
->srcpad
, frame
->src_buffer
);
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
;
536 gst_base_video_coder_end_of_stream (GstBaseVideoCoder
*base_video_coder
,
540 if (base_video_coder
->frames
) {
541 GST_ERROR("EOS with frames left over");
544 return gst_pad_push (base_video_coder
->srcpad
, buffer
);