diff options
author | Ole André Vadla Ravnås <oravnas@cisco.com> | 2009-10-26 16:09:00 +0100 |
---|---|---|
committer | Ole André Vadla Ravnås <oravnas@cisco.com> | 2010-10-28 17:08:41 +0200 |
commit | bb17394e76d1d44c5eb7e6340954e6d37ec7039f (patch) | |
tree | 61330f2fa354dba51c17483bcc0dc592ca23907d /sys | |
parent | d282a1d38066c1615ba6240bfd1e16b00d6b3489 (diff) | |
download | gstreamer-plugins-bad-bb17394e76d1d44c5eb7e6340954e6d37ec7039f.tar.gz |
winks: improve framerate fraction conversions
* For instance 7.5 fps should be represented as 15/2 instead of 7/1.
* Clamp AvgTimePerFrame and dwBitRate to account for rounding errors.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/winks/ksvideohelpers.c | 129 |
1 files changed, 81 insertions, 48 deletions
diff --git a/sys/winks/ksvideohelpers.c b/sys/winks/ksvideohelpers.c index 69b4311b2..9e502d021 100644 --- a/sys/winks/ksvideohelpers.c +++ b/sys/winks/ksvideohelpers.c @@ -21,6 +21,7 @@ #include "ksvideohelpers.h" +#include <math.h> #include <uuids.h> #include "kshelpers.h" @@ -269,10 +270,47 @@ guess_aspect (gint width, gint height, gint * par_width, gint * par_height) } } +/* NOTE: would probably be better to use a continued fractions approach here */ +static void +compress_fraction (gint64 in_num, gint64 in_den, gint64 * out_num, + gint64 * out_den) +{ + gdouble on, od, orig; + guint denominators[] = { 1, 2, 3, 5, 7 }, i; + const gdouble max_loss = 0.1; + + on = in_num; + od = in_den; + orig = on / od; + + for (i = 0; i < G_N_ELEMENTS (denominators); i++) { + gint64 cur_n, cur_d; + gdouble cur, loss; + + cur_n = floor ((on / (od / (gdouble) denominators[i])) + 0.5); + cur_d = denominators[i]; + cur = (gdouble) cur_n / (gdouble) cur_d; + loss = fabs (cur - orig); + + if (loss <= max_loss) { + *out_num = cur_n; + *out_den = cur_d; + + return; + } + } + + *out_num = in_num; + *out_den = in_den; +} + static gboolean ks_video_append_video_stream_cfg_fields (GstStructure * structure, const KS_VIDEO_STREAM_CONFIG_CAPS * vscc) { + GValue val = { 0, }; + gint64 max_n, max_d; + g_return_val_if_fail (structure, FALSE); g_return_val_if_fail (vscc, FALSE); @@ -297,17 +335,23 @@ ks_video_append_video_stream_cfg_fields (GstStructure * structure, } /* framerate */ + compress_fraction (NANOSECONDS, vscc->MaxFrameInterval, &max_n, &max_d); + if (vscc->MinFrameInterval == vscc->MaxFrameInterval) { - gst_structure_set (structure, - "framerate", GST_TYPE_FRACTION, - (gint) (10000000 / vscc->MaxFrameInterval), 1, NULL); + g_value_init (&val, GST_TYPE_FRACTION); + gst_value_set_fraction (&val, max_n, max_d); } else { - gst_structure_set (structure, - "framerate", GST_TYPE_FRACTION_RANGE, - (gint) (10000000 / vscc->MaxFrameInterval), 1, - (gint) (10000000 / vscc->MinFrameInterval), 1, NULL); + gint64 min_n, min_d; + + compress_fraction (NANOSECONDS, vscc->MinFrameInterval, &min_n, &min_d); + + g_value_init (&val, GST_TYPE_FRACTION_RANGE); + gst_value_set_fraction_range_full (&val, max_n, max_d, min_n, min_d); } + gst_structure_set_value (structure, "framerate", &val); + g_value_unset (&val); + { gint par_width, par_height; @@ -609,58 +653,47 @@ gboolean ks_video_fixate_media_type (const KSDATARANGE * range, guint8 * format, gint width, gint height, gint fps_n, gint fps_d) { - DWORD dwRate = (width * height * fps_n) / fps_d; + KS_DATARANGE_VIDEO *vr; + KS_VIDEOINFOHEADER *vih; + KS_BITMAPINFOHEADER *bih; + DWORD dwRate; g_return_val_if_fail (format != NULL, FALSE); if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo)) { - KS_VIDEOINFOHEADER *vih = (KS_VIDEOINFOHEADER *) format; - - /* FIXME: Need to figure out how to properly handle ranges */ - if (vih->bmiHeader.biWidth != width || vih->bmiHeader.biHeight != height) - return FALSE; - - vih->AvgTimePerFrame = gst_util_uint64_scale_int (10000000, fps_d, fps_n); - vih->dwBitRate = dwRate * vih->bmiHeader.biBitCount; + bih = &((KS_VIDEOINFOHEADER *) format)->bmiHeader; } else if (IsEqualGUID (&range->Specifier, &FORMAT_VideoInfo2)) { - KS_VIDEOINFOHEADER2 *vih = (KS_VIDEOINFOHEADER2 *) format; - - /* FIXME: see above */ - if (vih->bmiHeader.biWidth != width || vih->bmiHeader.biHeight != height) - return FALSE; - - vih->AvgTimePerFrame = gst_util_uint64_scale_int (10000000, fps_d, fps_n); - vih->dwBitRate = dwRate * vih->bmiHeader.biBitCount; + bih = &((KS_VIDEOINFOHEADER2 *) format)->bmiHeader; } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEGVideo)) { - KS_MPEG1VIDEOINFO *vih = (KS_MPEG1VIDEOINFO *) format; - - /* FIXME: see above */ - if (vih->hdr.bmiHeader.biWidth != width || - vih->hdr.bmiHeader.biHeight != height) - { - return FALSE; - } - - vih->hdr.AvgTimePerFrame = - gst_util_uint64_scale_int (10000000, fps_d, fps_n); - vih->hdr.dwBitRate = dwRate * vih->hdr.bmiHeader.biBitCount; + bih = &((KS_MPEG1VIDEOINFO *) format)->hdr.bmiHeader; } else if (IsEqualGUID (&range->Specifier, &FORMAT_MPEG2Video)) { - KS_MPEGVIDEOINFO2 *vih = (KS_MPEGVIDEOINFO2 *) format; - - /* FIXME: see above */ - if (vih->hdr.bmiHeader.biWidth != width || - vih->hdr.bmiHeader.biHeight != height) - { - return FALSE; - } - - vih->hdr.AvgTimePerFrame = - gst_util_uint64_scale_int (10000000, fps_d, fps_n); - vih->hdr.dwBitRate = dwRate * vih->hdr.bmiHeader.biBitCount; + bih = &((KS_MPEGVIDEOINFO2 *) format)->hdr.bmiHeader; } else { return FALSE; } + /* These formats' structures share the most basic stuff */ + vr = (KS_DATARANGE_VIDEO *) range; + vih = (KS_VIDEOINFOHEADER *) format; + + /* FIXME: Need to figure out how to properly handle ranges */ + if (bih->biWidth != width || bih->biHeight != height) + return FALSE; + + /* Framerate, clamped because of fraction conversion rounding errors */ + vih->AvgTimePerFrame = + gst_util_uint64_scale_int_round (NANOSECONDS, fps_d, fps_n); + vih->AvgTimePerFrame = + MAX (vih->AvgTimePerFrame, vr->ConfigCaps.MinFrameInterval); + vih->AvgTimePerFrame = + MIN (vih->AvgTimePerFrame, vr->ConfigCaps.MaxFrameInterval); + + /* Bitrate, clamped for the same reason as framerate */ + dwRate = (width * height * fps_n) / fps_d; + vih->dwBitRate = dwRate * bih->biBitCount; + vih->dwBitRate = MAX (vih->dwBitRate, vr->ConfigCaps.MinBitsPerSecond); + vih->dwBitRate = MIN (vih->dwBitRate, vr->ConfigCaps.MaxBitsPerSecond); + return TRUE; } |