basevideo: cater for format conversion
authorMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Mon, 28 Mar 2011 09:15:49 +0000 (11:15 +0200)
committerMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Mon, 16 May 2011 18:32:22 +0000 (20:32 +0200)
gst-libs/gst/video/gstbasevideocodec.h
gst-libs/gst/video/gstbasevideodecoder.c
gst-libs/gst/video/gstbasevideoencoder.c
gst-libs/gst/video/gstbasevideoutils.c

index e8f9f45..9bada93 100644 (file)
@@ -148,6 +148,9 @@ struct _GstBaseVideoCodec
   GstClockTime earliest_time;
   gboolean discont;
 
+  gint64 bytes;
+  gint64 time;
+
   /* FIXME before moving to base */
   void *padding[GST_PADDING_LARGE];
 };
@@ -169,9 +172,9 @@ void gst_base_video_codec_free_frame (GstVideoFrame *frame);
 gboolean gst_base_video_rawvideo_convert (GstVideoState *state,
     GstFormat src_format, gint64 src_value,
     GstFormat * dest_format, gint64 *dest_value);
-gboolean gst_base_video_encoded_video_convert (GstVideoState *state,
-    GstFormat src_format, gint64 src_value,
-    GstFormat * dest_format, gint64 *dest_value);
+gboolean gst_base_video_encoded_video_convert (GstVideoState * state,
+    gint64 bytes, gint64 time, GstFormat src_format,
+    gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
 
 GstClockTime gst_video_state_get_timestamp (const GstVideoState *state,
     GstSegment *segment, int frame_number);
index ac146b5..ff77098 100644 (file)
@@ -46,9 +46,6 @@ static const GstQueryType *gst_base_video_decoder_get_query_types (GstPad *
     pad);
 static gboolean gst_base_video_decoder_src_query (GstPad * pad,
     GstQuery * query);
-static gboolean gst_base_video_decoder_src_convert (GstPad * pad,
-    GstFormat src_format, gint64 src_value, GstFormat * dest_format,
-    gint64 * dest_value);
 static void gst_base_video_decoder_reset (GstBaseVideoDecoder *
     base_video_decoder);
 
@@ -324,14 +321,12 @@ gst_base_video_decoder_src_event (GstPad * pad, GstEvent * event)
       gst_event_unref (event);
 
       tformat = GST_FORMAT_TIME;
-      res =
-          gst_base_video_decoder_src_convert (pad, format, cur, &tformat,
-          &tcur);
+      res = gst_pad_query_convert (GST_BASE_VIDEO_CODEC_SINK_PAD
+          (base_video_decoder), format, cur, &tformat, &tcur);
       if (!res)
         goto convert_error;
-      res =
-          gst_base_video_decoder_src_convert (pad, format, stop, &tformat,
-          &tstop);
+      res = gst_pad_query_convert (GST_BASE_VIDEO_CODEC_SINK_PAD
+          (base_video_decoder), format, stop, &tformat, &tstop);
       if (!res)
         goto convert_error;
 
@@ -400,60 +395,6 @@ convert_error:
   goto done;
 }
 
-static gboolean
-gst_base_video_decoder_src_convert (GstPad * pad,
-    GstFormat src_format, gint64 src_value,
-    GstFormat * dest_format, gint64 * dest_value)
-{
-  gboolean res = TRUE;
-  GstBaseVideoDecoder *dec;
-
-  if (src_format == *dest_format) {
-    *dest_value = src_value;
-    return TRUE;
-  }
-
-  dec = GST_BASE_VIDEO_DECODER (gst_pad_get_parent (pad));
-
-  /* FIXME: check if we are in a encoding state */
-
-  GST_DEBUG_OBJECT (dec, "src convert");
-  switch (src_format) {
-#if 0
-    case GST_FORMAT_DEFAULT:
-      switch (*dest_format) {
-        case GST_FORMAT_TIME:
-          *dest_value = gst_util_uint64_scale (granulepos_to_frame (src_value),
-              enc->fps_d * GST_SECOND, enc->fps_n);
-          break;
-        default:
-          res = FALSE;
-      }
-      break;
-    case GST_FORMAT_TIME:
-      switch (*dest_format) {
-        case GST_FORMAT_DEFAULT:
-        {
-          *dest_value = gst_util_uint64_scale (src_value,
-              enc->fps_n, enc->fps_d * GST_SECOND);
-          break;
-        }
-        default:
-          res = FALSE;
-          break;
-      }
-      break;
-#endif
-    default:
-      res = FALSE;
-      break;
-  }
-
-  gst_object_unref (dec);
-
-  return res;
-}
-
 static const GstQueryType *
 gst_base_video_decoder_get_query_types (GstPad * pad)
 {
@@ -513,9 +454,8 @@ gst_base_video_decoder_src_query (GstPad * pad, GstQuery * query)
       GST_DEBUG_OBJECT (dec, "convert query");
 
       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
-      res =
-          gst_base_video_decoder_src_convert (pad, src_fmt, src_val, &dest_fmt,
-          &dest_val);
+      res = gst_base_video_rawvideo_convert (&GST_BASE_VIDEO_CODEC (dec)->state,
+          src_fmt, src_val, &dest_fmt, &dest_val);
       if (!res)
         goto error;
       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
@@ -548,13 +488,13 @@ gst_base_video_decoder_sink_query (GstPad * pad, GstQuery * query)
   switch (GST_QUERY_TYPE (query)) {
     case GST_QUERY_CONVERT:
     {
+      GstBaseVideoCodec *codec = GST_BASE_VIDEO_CODEC (base_video_decoder);
       GstFormat src_fmt, dest_fmt;
       gint64 src_val, dest_val;
 
       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
-      res =
-          gst_base_video_rawvideo_convert (&GST_BASE_VIDEO_CODEC
-          (base_video_decoder)->state, src_fmt, src_val, &dest_fmt, &dest_val);
+      res = gst_base_video_encoded_video_convert (&codec->state, codec->bytes,
+          codec->time, src_fmt, src_val, &dest_fmt, &dest_val);
       if (!res)
         goto error;
       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
@@ -1010,6 +950,17 @@ gst_base_video_decoder_finish_frame (GstBaseVideoDecoder * base_video_decoder,
   GST_BUFFER_OFFSET (src_buffer) = GST_BUFFER_OFFSET_NONE;
   GST_BUFFER_OFFSET_END (src_buffer) = GST_BUFFER_OFFSET_NONE;
 
+  /* update rate estimate */
+  GST_BASE_VIDEO_CODEC (base_video_decoder)->bytes +=
+      GST_BUFFER_SIZE (src_buffer);
+  if (GST_CLOCK_TIME_IS_VALID (frame->presentation_duration)) {
+    GST_BASE_VIDEO_CODEC (base_video_decoder)->time +=
+        frame->presentation_duration;
+  } else {
+    /* better none than nothing valid */
+    GST_BASE_VIDEO_CODEC (base_video_decoder)->time = GST_CLOCK_TIME_NONE;
+  }
+
   GST_DEBUG_OBJECT (base_video_decoder, "pushing frame %" GST_TIME_FORMAT,
       GST_TIME_ARGS (frame->presentation_timestamp));
 
@@ -1294,6 +1245,9 @@ gst_base_video_decoder_set_src_caps (GstBaseVideoDecoder * base_video_decoder)
   caps = gst_video_format_new_caps (state->format,
       state->width, state->height,
       state->fps_n, state->fps_d, state->par_n, state->par_d);
+  /* arrange for derived info */
+  state->bytes_per_picture =
+      gst_video_format_get_size (state->format, state->width, state->height);
   gst_caps_set_simple (caps, "interlaced",
       G_TYPE_BOOLEAN, state->interlaced, NULL);
 
index 3514ccd..5c9950c 100644 (file)
@@ -324,6 +324,8 @@ gst_base_video_encoder_sink_setcaps (GstPad * pad, GstCaps * caps)
     state->interlaced = v;
   }
 
+  state->bytes_per_picture =
+      gst_video_format_get_size (state->format, state->width, state->height);
   state->clean_width = state->width;
   state->clean_height = state->height;
   state->clean_offset_left = 0;
@@ -534,13 +536,13 @@ gst_base_video_encoder_src_query (GstPad * pad, GstQuery * query)
   switch (GST_QUERY_TYPE (query)) {
     case GST_QUERY_CONVERT:
     {
+      GstBaseVideoCodec *codec = GST_BASE_VIDEO_CODEC (enc);
       GstFormat src_fmt, dest_fmt;
       gint64 src_val, dest_val;
 
       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
-      res =
-          gst_base_video_encoded_video_convert (&GST_BASE_VIDEO_CODEC
-          (enc)->state, src_fmt, src_val, &dest_fmt, &dest_val);
+      res = gst_base_video_encoded_video_convert (&codec->state,
+          codec->bytes, codec->time, src_fmt, src_val, &dest_fmt, &dest_val);
       if (!res)
         goto error;
       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
@@ -748,6 +750,17 @@ gst_base_video_encoder_finish_frame (GstBaseVideoEncoder * base_video_encoder,
   GST_BUFFER_DURATION (frame->src_buffer) = frame->presentation_duration;
   GST_BUFFER_OFFSET (frame->src_buffer) = frame->decode_timestamp;
 
+  /* update rate estimate */
+  GST_BASE_VIDEO_CODEC (base_video_encoder)->bytes +=
+      GST_BUFFER_SIZE (frame->src_buffer);
+  if (GST_CLOCK_TIME_IS_VALID (frame->presentation_duration)) {
+    GST_BASE_VIDEO_CODEC (base_video_encoder)->time +=
+        frame->presentation_duration;
+  } else {
+    /* better none than nothing valid */
+    GST_BASE_VIDEO_CODEC (base_video_encoder)->time = GST_CLOCK_TIME_NONE;
+  }
+
   if (G_UNLIKELY (GST_BASE_VIDEO_CODEC (base_video_encoder)->discont)) {
     GST_LOG_OBJECT (base_video_encoder, "marking discont");
     GST_BUFFER_FLAG_SET (frame->src_buffer, GST_BUFFER_FLAG_DISCONT);
index 3b8b5d1..2d83213 100644 (file)
@@ -36,7 +36,10 @@ gst_base_video_rawvideo_convert (GstVideoState * state,
 {
   gboolean res = FALSE;
 
-  if (src_format == *dest_format) {
+  g_return_val_if_fail (dest_format != NULL, FALSE);
+  g_return_val_if_fail (dest_value != NULL, FALSE);
+
+  if (src_format == *dest_format || src_value == 0 || src_value == -1) {
     *dest_value = src_value;
     return TRUE;
   }
@@ -66,43 +69,77 @@ gst_base_video_rawvideo_convert (GstVideoState * state,
     *dest_value = gst_util_uint64_scale (src_value, state->fps_n,
         GST_SECOND * state->fps_d);
     res = TRUE;
+  } else if (src_format == GST_FORMAT_TIME &&
+      *dest_format == GST_FORMAT_BYTES && state->fps_d != 0 &&
+      state->bytes_per_picture != 0) {
+    /* convert time to frames */
+    /* FIXME subtract segment time? */
+    *dest_value = gst_util_uint64_scale (src_value,
+        state->fps_n * state->bytes_per_picture, GST_SECOND * state->fps_d);
+    res = TRUE;
+  } else if (src_format == GST_FORMAT_BYTES &&
+      *dest_format == GST_FORMAT_TIME && state->fps_n != 0 &&
+      state->bytes_per_picture != 0) {
+    /* convert frames to time */
+    /* FIXME add segment time? */
+    *dest_value = gst_util_uint64_scale (src_value,
+        GST_SECOND * state->fps_d, state->fps_n * state->bytes_per_picture);
+    res = TRUE;
   }
 
-  /* FIXME add bytes <--> time */
-
   return res;
 }
 
 gboolean
 gst_base_video_encoded_video_convert (GstVideoState * state,
-    GstFormat src_format, gint64 src_value,
-    GstFormat * dest_format, gint64 * dest_value)
+    gint64 bytes, gint64 time, GstFormat src_format,
+    gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
 {
   gboolean res = FALSE;
 
-  if (src_format == *dest_format) {
-    *dest_value = src_value;
+  g_return_val_if_fail (dest_format != NULL, FALSE);
+  g_return_val_if_fail (dest_value != NULL, FALSE);
+
+  if (G_UNLIKELY (src_format == *dest_format || src_value == 0 ||
+          src_value == -1)) {
+    if (dest_value)
+      *dest_value = src_value;
     return TRUE;
   }
 
-  GST_DEBUG ("src convert");
+  if (bytes <= 0 || time <= 0) {
+    GST_DEBUG ("not enough metadata yet to convert");
+    goto exit;
+  }
 
-#if 0
-  if (src_format == GST_FORMAT_DEFAULT && *dest_format == GST_FORMAT_TIME) {
-    if (dec->fps_d != 0) {
-      *dest_value = gst_util_uint64_scale (granulepos_to_frame (src_value),
-          dec->fps_d * GST_SECOND, dec->fps_n);
-      res = TRUE;
-    } else {
+  switch (src_format) {
+    case GST_FORMAT_BYTES:
+      switch (*dest_format) {
+        case GST_FORMAT_TIME:
+          *dest_value = gst_util_uint64_scale (src_value, time, bytes);
+          res = TRUE;
+          break;
+        default:
+          res = FALSE;
+      }
+      break;
+    case GST_FORMAT_TIME:
+      switch (*dest_format) {
+        case GST_FORMAT_BYTES:
+          *dest_value = gst_util_uint64_scale (src_value, bytes, time);
+          res = TRUE;
+          break;
+        default:
+          res = FALSE;
+      }
+      break;
+    default:
+      GST_DEBUG ("unhandled conversion from %d to %d", src_format,
+          *dest_format);
       res = FALSE;
-    }
-  } else {
-    GST_WARNING ("unhandled conversion from %d to %d", src_format,
-        *dest_format);
-    res = FALSE;
   }
-#endif
 
+exit:
   return res;
 }