diff --git a/autogen.sh b/autogen.sh index 820a017fbb..4a4a8f40c4 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,6 +1,12 @@ #!/bin/sh # Run this to generate all the initial makefiles, etc. +test -n "$srcdir" || srcdir=`dirname "$0"` +test -n "$srcdir" || srcdir=. + +olddir=`pwd` +cd "$srcdir" + DIE=0 package=gst-plugins-base srcfile=gst/audiotestsrc/gstaudiotestsrc.c @@ -106,13 +112,15 @@ test -n "$NOCONFIGURE" && { exit 0 } +cd "$olddir" + echo "+ running configure ... " -test ! -z "$CONFIGURE_DEF_OPT" && echo " ./configure default flags: $CONFIGURE_DEF_OPT" -test ! -z "$CONFIGURE_EXT_OPT" && echo " ./configure external flags: $CONFIGURE_EXT_OPT" -test ! -z "$CONFIGURE_FILE_OPT" && echo " ./configure enable/disable flags: $CONFIGURE_FILE_OPT" +test ! -z "$CONFIGURE_DEF_OPT" && echo " $srcdir/configure default flags: $CONFIGURE_DEF_OPT" +test ! -z "$CONFIGURE_EXT_OPT" && echo " $srcdir/configure external flags: $CONFIGURE_EXT_OPT" +test ! -z "$CONFIGURE_FILE_OPT" && echo " $srcdir/configure enable/disable flags: $CONFIGURE_FILE_OPT" echo -./configure $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT $CONFIGURE_FILE_OPT || { +"$srcdir/configure" $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT $CONFIGURE_FILE_OPT || { echo " configure failed" exit 1 } diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index d9ae6a180e..f31ecfa4d9 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -554,6 +554,9 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet, pad->current_granule); } else if (ogg->segment.rate > 0.0 && pad->current_granule != -1) { pad->current_granule += duration; + if (gst_ogg_stream_packet_is_key_frame (&pad->map, packet)) { + pad->keyframe_granule = pad->current_granule; + } GST_DEBUG_OBJECT (ogg, "interpolating granule %" G_GUINT64_FORMAT, pad->current_granule); } diff --git a/ext/ogg/gstoggstream.c b/ext/ogg/gstoggstream.c index 44af167fef..cab9233f0e 100644 --- a/ext/ogg/gstoggstream.c +++ b/ext/ogg/gstoggstream.c @@ -47,9 +47,13 @@ typedef gint64 (*GstOggMapToGranuleposFunc) (GstOggStream * pad, gint64 granule, gint64 keyframe_granule); /* returns TRUE if the granulepos denotes a key frame */ -typedef gboolean (*GstOggMapIsKeyFrameFunc) (GstOggStream * pad, +typedef gboolean (*GstOggMapIsGranuleposKeyFrameFunc) (GstOggStream * pad, gint64 granulepos); +/* returns TRUE if the packet is a key frame */ +typedef gboolean (*GstOggMapIsPacketKeyFrameFunc) (GstOggStream * pad, + ogg_packet * packet); + /* returns TRUE if the given packet is a stream header packet */ typedef gboolean (*GstOggMapIsHeaderPacketFunc) (GstOggStream * pad, ogg_packet * packet); @@ -74,7 +78,8 @@ struct _GstOggMap GstOggMapSetupFunc setup_func; GstOggMapToGranuleFunc granulepos_to_granule_func; GstOggMapToGranuleposFunc granule_to_granulepos_func; - GstOggMapIsKeyFrameFunc is_key_frame_func; + GstOggMapIsGranuleposKeyFrameFunc is_granulepos_key_frame_func; + GstOggMapIsPacketKeyFrameFunc is_packet_key_frame_func; GstOggMapIsHeaderPacketFunc is_header_func; GstOggMapPacketDurationFunc packet_duration_func; GstOggMapGranuleposToKeyGranuleFunc granulepos_to_key_granule_func; @@ -189,13 +194,25 @@ gst_ogg_stream_granulepos_is_key_frame (GstOggStream * pad, gint64 granulepos) return FALSE; } - if (mappers[pad->map].is_key_frame_func == NULL) { + if (mappers[pad->map].is_granulepos_key_frame_func == NULL) { GST_WARNING ("Failed to determine keyframeness for %s granulepos", gst_ogg_stream_get_media_type (pad)); return FALSE; } - return mappers[pad->map].is_key_frame_func (pad, granulepos); + return mappers[pad->map].is_granulepos_key_frame_func (pad, granulepos); +} + +gboolean +gst_ogg_stream_packet_is_key_frame (GstOggStream * pad, ogg_packet * packet) +{ + if (mappers[pad->map].is_packet_key_frame_func == NULL) { + GST_WARNING ("Failed to determine keyframeness of %s packet", + gst_ogg_stream_get_media_type (pad)); + return FALSE; + } + + return mappers[pad->map].is_packet_key_frame_func (pad, packet); } gboolean @@ -250,7 +267,13 @@ gst_ogg_stream_get_media_type (GstOggStream * pad) /* some generic functions */ static gboolean -is_keyframe_true (GstOggStream * pad, gint64 granulepos) +is_granulepos_keyframe_true (GstOggStream * pad, gint64 granulepos) +{ + return TRUE; +} + +static gboolean +is_packet_keyframe_true (GstOggStream * pad, ogg_packet * packet) { return TRUE; } @@ -383,6 +406,7 @@ setup_theora_mapper (GstOggStream * pad, ogg_packet * packet) /* 2 bits + 3 bits = 5 bits KFGSHIFT */ pad->granuleshift = ((GST_READ_UINT8 (data + 40) & 0x03) << 3) + (GST_READ_UINT8 (data + 41) >> 5); + GST_LOG ("granshift: %d", pad->granuleshift); pad->is_video = TRUE; pad->n_header_packets = 3; @@ -439,7 +463,7 @@ granulepos_to_granule_theora (GstOggStream * pad, gint64 granulepos) } static gboolean -is_keyframe_theora (GstOggStream * pad, gint64 granulepos) +is_granulepos_keyframe_theora (GstOggStream * pad, gint64 granulepos) { gint64 frame_mask; @@ -451,6 +475,14 @@ is_keyframe_theora (GstOggStream * pad, gint64 granulepos) return ((granulepos & frame_mask) == 0); } +static gboolean +is_packet_keyframe_theora (GstOggStream * pad, ogg_packet * packet) +{ + if (packet->bytes == 0) + return FALSE; + return (packet->packet[0] & 0xc0) == 0x00; +} + static gboolean is_header_theora (GstOggStream * pad, ogg_packet * packet) { @@ -1935,7 +1967,8 @@ const GstOggMap mappers[] = { setup_theora_mapper, granulepos_to_granule_theora, granule_to_granulepos_default, - is_keyframe_theora, + is_granulepos_keyframe_theora, + is_packet_keyframe_theora, is_header_theora, packet_duration_constant, NULL, @@ -1947,7 +1980,8 @@ const GstOggMap mappers[] = { setup_vorbis_mapper, granulepos_to_granule_default, granule_to_granulepos_default, - is_keyframe_true, + is_granulepos_keyframe_true, + is_packet_keyframe_true, is_header_vorbis, packet_duration_vorbis, NULL, @@ -1959,7 +1993,8 @@ const GstOggMap mappers[] = { setup_speex_mapper, granulepos_to_granule_default, granule_to_granulepos_default, - is_keyframe_true, + is_granulepos_keyframe_true, + is_packet_keyframe_true, is_header_count, packet_duration_constant, NULL, @@ -1972,6 +2007,7 @@ const GstOggMap mappers[] = { NULL, NULL, NULL, + NULL, is_header_count, NULL, NULL, @@ -1984,6 +2020,7 @@ const GstOggMap mappers[] = { NULL, NULL, NULL, + NULL, is_header_count, NULL, NULL, @@ -1996,6 +2033,7 @@ const GstOggMap mappers[] = { granulepos_to_granule_default, granule_to_granulepos_default, NULL, + NULL, is_header_count, NULL, NULL, @@ -2008,6 +2046,7 @@ const GstOggMap mappers[] = { NULL, NULL, NULL, + NULL, is_header_true, NULL, NULL, @@ -2019,7 +2058,8 @@ const GstOggMap mappers[] = { setup_fLaC_mapper, granulepos_to_granule_default, granule_to_granulepos_default, - is_keyframe_true, + is_granulepos_keyframe_true, + is_packet_keyframe_true, is_header_fLaC, packet_duration_flac, NULL, @@ -2031,7 +2071,8 @@ const GstOggMap mappers[] = { setup_flac_mapper, granulepos_to_granule_default, granule_to_granulepos_default, - is_keyframe_true, + is_granulepos_keyframe_true, + is_packet_keyframe_true, is_header_flac, packet_duration_flac, NULL, @@ -2046,6 +2087,7 @@ const GstOggMap mappers[] = { NULL, NULL, NULL, + NULL, NULL }, { @@ -2055,6 +2097,7 @@ const GstOggMap mappers[] = { granulepos_to_granule_default, granule_to_granulepos_default, NULL, + NULL, is_header_count, packet_duration_constant, NULL, @@ -2067,6 +2110,7 @@ const GstOggMap mappers[] = { granulepos_to_granule_default, granule_to_granulepos_default, NULL, + NULL, is_header_count, packet_duration_kate, NULL, @@ -2079,6 +2123,7 @@ const GstOggMap mappers[] = { granulepos_to_granule_dirac, granule_to_granulepos_dirac, is_keyframe_dirac, + NULL, is_header_count, packet_duration_constant, granulepos_to_key_granule_dirac, @@ -2091,6 +2136,7 @@ const GstOggMap mappers[] = { granulepos_to_granule_vp8, granule_to_granulepos_vp8, is_keyframe_vp8, + NULL, is_header_vp8, packet_duration_vp8, granulepos_to_key_granule_vp8, @@ -2103,6 +2149,7 @@ const GstOggMap mappers[] = { granulepos_to_granule_default, granule_to_granulepos_default, NULL, + NULL, is_header_opus, packet_duration_opus, NULL, @@ -2114,7 +2161,8 @@ const GstOggMap mappers[] = { setup_ogmaudio_mapper, granulepos_to_granule_default, granule_to_granulepos_default, - is_keyframe_true, + is_granulepos_keyframe_true, + is_packet_keyframe_true, is_header_ogm, packet_duration_ogm, NULL, @@ -2127,6 +2175,7 @@ const GstOggMap mappers[] = { granulepos_to_granule_default, granule_to_granulepos_default, NULL, + NULL, is_header_ogm, packet_duration_constant, NULL, @@ -2138,7 +2187,8 @@ const GstOggMap mappers[] = { setup_ogmtext_mapper, granulepos_to_granule_default, granule_to_granulepos_default, - is_keyframe_true, + is_granulepos_keyframe_true, + is_packet_keyframe_true, is_header_ogm, packet_duration_ogm, NULL, diff --git a/ext/ogg/gstoggstream.h b/ext/ogg/gstoggstream.h index a66a78c34d..c06bc51d6d 100644 --- a/ext/ogg/gstoggstream.h +++ b/ext/ogg/gstoggstream.h @@ -124,6 +124,7 @@ GstClockTime gst_ogg_stream_get_packet_start_time (GstOggStream *pad, gboolean gst_ogg_stream_granulepos_is_key_frame (GstOggStream *pad, gint64 granulepos); gboolean gst_ogg_stream_packet_is_header (GstOggStream *pad, ogg_packet *packet); +gboolean gst_ogg_stream_packet_is_key_frame (GstOggStream *pad, ogg_packet *packet); gint64 gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet *packet); void gst_ogg_stream_extract_tags (GstOggStream * pad, ogg_packet * packet); const char *gst_ogg_stream_get_media_type (GstOggStream * pad); diff --git a/ext/theora/gsttheoraenc.c b/ext/theora/gsttheoraenc.c index 0f287ba54b..dbca3ab314 100644 --- a/ext/theora/gsttheoraenc.c +++ b/ext/theora/gsttheoraenc.c @@ -1338,6 +1338,11 @@ theora_enc_encode_and_push (GstTheoraEnc * enc, ogg_packet op, goto multipass_read_failed; } } +#ifdef TH_ENCCTL_SET_DUPLICATE_FLAG + if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_GAP)) { + th_encode_ctl (enc->encoder, TH_ENCCTL_SET_DUPLICATE_FLAG, NULL, 0); + } +#endif res = th_encode_ycbcr_in (enc->encoder, ycbcr); /* none of the failure cases can happen here */ diff --git a/ext/vorbis/gstvorbisparse.c b/ext/vorbis/gstvorbisparse.c index 97f7eae636..174199bc19 100644 --- a/ext/vorbis/gstvorbisparse.c +++ b/ext/vorbis/gstvorbisparse.c @@ -400,7 +400,7 @@ vorbis_parse_parse_packet (GstVorbisParse * parse, GstBuffer * buf) have_header = FALSE; gst_buffer_map (buf, &map, GST_MAP_READ); if (map.size >= 1) { - if (map.data[0] >= 0x01 && map.data[0] <= 0x05) + if (map.data[0] & 1) have_header = TRUE; } gst_buffer_unmap (buf, &map); diff --git a/gst/typefind/gsttypefindfunctions.c b/gst/typefind/gsttypefindfunctions.c index 9c84fb59d5..0bffe5303e 100644 --- a/gst/typefind/gsttypefindfunctions.c +++ b/gst/typefind/gsttypefindfunctions.c @@ -2402,6 +2402,9 @@ h264_video_type_find (GstTypeFind * tf, gpointer unused) /* Stream consists of: a series of sync codes (00 00 00 01) followed * by NALs */ + gboolean seen_idr = FALSE; + gboolean seen_sps = FALSE; + gboolean seen_pps = FALSE; int nut, ref; int good = 0; int bad = 0; @@ -2426,6 +2429,13 @@ h264_video_type_find (GstTypeFind * tf, gpointer unused) ((nut == 6 || (nut >= 9 && nut <= 12)) && ref != 0)) { bad++; } else { + if (nut == 7) + seen_sps = TRUE; + else if (nut == 8) + seen_pps = TRUE; + else if (nut == 5) + seen_idr = TRUE; + good++; } } else if (nut >= 14 && nut <= 33) { @@ -2439,9 +2449,10 @@ h264_video_type_find (GstTypeFind * tf, gpointer unused) /* don't consider these bad */ } - GST_DEBUG ("good %d bad %d", good, bad); + GST_LOG ("good:%d, bad:%d, pps:%d, sps:%d, idr:%d", good, bad, seen_pps, + seen_sps, seen_idr); - if (good >= 10 && bad < 4) { + if (seen_sps && seen_pps && seen_idr && good >= 10 && bad < 4) { gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, H264_VIDEO_CAPS); return; } @@ -2451,9 +2462,11 @@ h264_video_type_find (GstTypeFind * tf, gpointer unused) data_scan_ctx_advance (tf, &c, 1); } - if (good >= 2 && bad < 1) { + GST_LOG ("good:%d, bad:%d, pps:%d, sps:%d, idr:%d", good, bad, seen_pps, + seen_sps, seen_idr); + + if (good >= 2 && bad == 0) { gst_type_find_suggest (tf, GST_TYPE_FIND_POSSIBLE, H264_VIDEO_CAPS); - return; } } diff --git a/gst/videoscale/gstvideoscale.c b/gst/videoscale/gstvideoscale.c index 0acc5542a8..86721b0459 100644 --- a/gst/videoscale/gstvideoscale.c +++ b/gst/videoscale/gstvideoscale.c @@ -1,6 +1,6 @@ /* GStreamer * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) 2005 David Schleef + * Copyright (C) 2005-2012 David Schleef * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -112,10 +112,10 @@ enum #undef GST_VIDEO_SIZE_RANGE #define GST_VIDEO_SIZE_RANGE "(int) [ 1, 32767]" -#define GST_VIDEO_FORMATS "{ \"I420\", \"YV12\", \"YUY2\", \"UYVY\", \"AYUV\", \"RGBx\", " \ - "\"BGRx\", \"xRGB\", \"xBGR\", \"RGBA\", \"BGRA\", \"ARGB\", \"ABGR\", \"RGB\", " \ - "\"BGR\", \"Y41B\", \"Y42B\", \"YVYU\", \"Y444\", \"GRAY8\", \"GRAY16_BE\", \"GRAY16_LE\", " \ - "\"v308\", \"Y800\", \"Y16\", \"RGB16\", \"RGB15\", \"ARGB64\", \"AYUV64\" } " +#define GST_VIDEO_FORMATS "{ I420, YV12, YUY2, UYVY, AYUV, RGBx, " \ + "BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, RGB, " \ + "BGR, Y41B, Y42B, YVYU, Y444, GRAY8, GRAY16_BE, GRAY16_LE, " \ + "v308, Y800, Y16, RGB16, RGB15, ARGB64, AYUV64, NV12 } " static GstStaticCaps gst_video_scale_format_caps[] = { @@ -1042,6 +1042,7 @@ _get_black_for_format (GstVideoFormat format) case GST_VIDEO_FORMAT_Y444: case GST_VIDEO_FORMAT_Y42B: case GST_VIDEO_FORMAT_Y41B: + case GST_VIDEO_FORMAT_NV12: return black[4]; /* Y, U, V, 0 */ case GST_VIDEO_FORMAT_RGB16: case GST_VIDEO_FORMAT_RGB15: @@ -1136,6 +1137,11 @@ gst_video_scale_transform_frame (GstVideoFilter * filter, case GST_VIDEO_SCALE_4TAP: vs_image_scale_4tap_AYUV64 (&dest[0], &src[0], videoscale->tmp_buf); break; + case GST_VIDEO_SCALE_LANCZOS: + vs_image_scale_lanczos_AYUV64 (&dest[0], &src[0], videoscale->tmp_buf, + videoscale->sharpness, videoscale->dither, videoscale->submethod, + videoscale->envelope, videoscale->sharpen); + break; default: goto unknown_mode; } @@ -1272,6 +1278,20 @@ gst_video_scale_transform_frame (GstVideoFilter * filter, goto unknown_mode; } break; + case GST_VIDEO_FORMAT_NV12: + switch (method) { + case GST_VIDEO_SCALE_NEAREST: + vs_image_scale_nearest_Y (&dest[0], &src[0], videoscale->tmp_buf); + vs_image_scale_nearest_NV12 (&dest[1], &src[1], videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_BILINEAR: + vs_image_scale_linear_Y (&dest[0], &src[0], videoscale->tmp_buf); + vs_image_scale_linear_NV12 (&dest[1], &src[1], videoscale->tmp_buf); + break; + default: + goto unknown_mode; + } + break; case GST_VIDEO_FORMAT_RGB16: if (add_borders) vs_fill_borders_RGB565 (&dest[0], black); diff --git a/gst/videoscale/vs_image.c b/gst/videoscale/vs_image.c index c28b0d8ff3..09ccf2580c 100644 --- a/gst/videoscale/vs_image.c +++ b/gst/videoscale/vs_image.c @@ -1,6 +1,6 @@ /* * Image Scaling Functions - * Copyright (c) 2005 David A. Schleef + * Copyright (c) 2005-2012 David A. Schleef * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -522,6 +522,136 @@ vs_image_scale_linear_UYVY (const VSImage * dest, const VSImage * src, } } +/* NV12 */ + +void +vs_image_scale_nearest_NV12 (const VSImage * dest, const VSImage * src, + uint8_t * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + int i; + int j; + int xacc; + + if (dest->height == 1) + y_increment = 0; + else + y_increment = ((src->height - 1) << 16) / (dest->height - 1); + + if (dest->width == 1) + x_increment = 0; + else + x_increment = ((src->width - 1) << 16) / (dest->width - 1); + + acc = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + + xacc = 0; + vs_scanline_resample_nearest_NV12 (dest->pixels + i * dest->stride, + src->pixels + j * src->stride, src->width, dest->width, &xacc, + x_increment); + + acc += y_increment; + } +} + +void +vs_image_scale_linear_NV12 (const VSImage * dest, const VSImage * src, + uint8_t * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + uint8_t *tmp1; + uint8_t *tmp2; + int y1; + int y2; + int i; + int j; + int x; + int dest_size; + int xacc; + + if (dest->height == 1) + y_increment = 0; + else + y_increment = ((src->height - 1) << 16) / (dest->height - 1) - 1; + + if (dest->width == 1) + x_increment = 0; + else + x_increment = ((src->width - 1) << 16) / (dest->width - 1) - 1; + + dest_size = ROUND_UP_4 (dest->width * 2); + + tmp1 = tmpbuf; + tmp2 = tmpbuf + dest_size; + + acc = 0; + xacc = 0; + y2 = -1; + vs_scanline_resample_linear_NV12 (tmp1, src->pixels, src->width, dest->width, + &xacc, x_increment); + y1 = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + x = acc & 0xffff; + + if (x == 0) { + if (j == y1) { + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } else if (j == y2) { + memcpy (dest->pixels + i * dest->stride, tmp2, dest_size); + } else { + xacc = 0; + vs_scanline_resample_linear_NV12 (tmp1, src->pixels + j * src->stride, + src->width, dest->width, &xacc, x_increment); + y1 = j; + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } + } else { + if (j == y1) { + if (j + 1 != y2) { + xacc = 0; + vs_scanline_resample_linear_NV12 (tmp2, + src->pixels + (j + 1) * src->stride, src->width, dest->width, + &xacc, x_increment); + y2 = j + 1; + } + vs_scanline_merge_linear_NV12 (dest->pixels + i * dest->stride, + tmp1, tmp2, dest->width, x); + } else if (j == y2) { + if (j + 1 != y1) { + xacc = 0; + vs_scanline_resample_linear_NV12 (tmp1, + src->pixels + (j + 1) * src->stride, src->width, dest->width, + &xacc, x_increment); + y1 = j + 1; + } + vs_scanline_merge_linear_NV12 (dest->pixels + i * dest->stride, + tmp2, tmp1, dest->width, x); + } else { + xacc = 0; + vs_scanline_resample_linear_NV12 (tmp1, src->pixels + j * src->stride, + src->width, dest->width, &xacc, x_increment); + y1 = j; + xacc = 0; + vs_scanline_resample_linear_NV12 (tmp2, + src->pixels + (j + 1) * src->stride, src->width, dest->width, + &xacc, x_increment); + y2 = (j + 1); + vs_scanline_merge_linear_NV12 (dest->pixels + i * dest->stride, + tmp1, tmp2, dest->width, x); + } + } + + acc += y_increment; + } +} + /* greyscale */ void diff --git a/gst/videoscale/vs_image.h b/gst/videoscale/vs_image.h index 2312acc7d5..d3cc31d7c3 100644 --- a/gst/videoscale/vs_image.h +++ b/gst/videoscale/vs_image.h @@ -52,6 +52,9 @@ void vs_image_scale_linear_RGBA (const VSImage *dest, const VSImage *src, void vs_image_scale_lanczos_AYUV (const VSImage * dest, const VSImage * src, uint8_t * tmpbuf, double sharpness, gboolean dither, int submethod, double a, double sharpen); +void vs_image_scale_lanczos_AYUV64 (const VSImage * dest, const VSImage * src, + uint8_t * tmpbuf, double sharpness, gboolean dither, int submethod, + double a, double sharpen); void vs_image_scale_nearest_RGB (const VSImage *dest, const VSImage *src, uint8_t *tmpbuf); @@ -68,6 +71,11 @@ void vs_image_scale_nearest_UYVY (const VSImage *dest, const VSImage *src, void vs_image_scale_linear_UYVY (const VSImage *dest, const VSImage *src, uint8_t *tmpbuf); +void vs_image_scale_nearest_NV12 (const VSImage *dest, const VSImage *src, + uint8_t *tmpbuf); +void vs_image_scale_linear_NV12 (const VSImage *dest, const VSImage *src, + uint8_t *tmpbuf); + void vs_image_scale_nearest_Y (const VSImage *dest, const VSImage *src, uint8_t *tmpbuf); void vs_image_scale_linear_Y (const VSImage *dest, const VSImage *src, diff --git a/gst/videoscale/vs_lanczos.c b/gst/videoscale/vs_lanczos.c index 1c87ba3dd3..d141a01c78 100644 --- a/gst/videoscale/vs_lanczos.c +++ b/gst/videoscale/vs_lanczos.c @@ -204,6 +204,9 @@ static void vs_image_scale_lanczos_AYUV_float (const VSImage * dest, static void vs_image_scale_lanczos_AYUV_double (const VSImage * dest, const VSImage * src, uint8_t * tmpbuf, double sharpness, gboolean dither, double a, double sharpen); +static void vs_image_scale_lanczos_AYUV64_double (const VSImage * dest, + const VSImage * src, uint8_t * tmpbuf, double sharpness, gboolean dither, + double a, double sharpen); static double sinc (double x) @@ -590,6 +593,15 @@ vs_image_scale_lanczos_AYUV (const VSImage * dest, const VSImage * src, } } +void +vs_image_scale_lanczos_AYUV64 (const VSImage * dest, const VSImage * src, + uint8_t * tmpbuf, double sharpness, gboolean dither, int submethod, + double a, double sharpen) +{ + vs_image_scale_lanczos_AYUV64_double (dest, src, tmpbuf, sharpness, dither, + a, sharpen); +} + #define RESAMPLE_HORIZ_FLOAT(function, dest_type, tap_type, src_type, _n_taps) \ @@ -813,9 +825,9 @@ RESAMPLE_VERT_DITHER (resample_vert_dither_int16_generic, gint16, gint16, n_taps, shift) /* *INDENT-ON* */ -#define RESAMPLE_VERT_FLOAT(function, tap_type, src_type, _n_taps, _shift) \ +#define RESAMPLE_VERT_FLOAT(function, dest_type, clamp, tap_type, src_type, _n_taps, _shift) \ static void \ -function (guint8 *dest, \ +function (dest_type *dest, \ const tap_type *taps, const src_type *src, int stride, int n_taps, \ int shift, int n) \ { \ @@ -828,13 +840,13 @@ function (guint8 *dest, \ const src_type *line = PTR_OFFSET(src, stride * l); \ sum_y += line[i] * taps[l]; \ } \ - dest[i] = CLAMP (floor(0.5 + sum_y), 0, 255); \ + dest[i] = CLAMP (floor(0.5 + sum_y), 0, clamp); \ } \ } -#define RESAMPLE_VERT_FLOAT_DITHER(function, tap_type, src_type, _n_taps, _shift) \ +#define RESAMPLE_VERT_FLOAT_DITHER(function, dest_type, clamp, tap_type, src_type, _n_taps, _shift) \ static void \ -function (guint8 *dest, \ +function (dest_type *dest, \ const tap_type *taps, const src_type *src, int stride, int n_taps, \ int shift, int n) \ { \ @@ -849,19 +861,24 @@ function (guint8 *dest, \ sum_y += line[i] * taps[l]; \ } \ err_y += sum_y; \ - dest[i] = CLAMP (floor (err_y), 0, 255); \ + dest[i] = CLAMP (floor (err_y), 0, clamp); \ err_y -= floor (err_y); \ } \ } /* *INDENT-OFF* */ -RESAMPLE_VERT_FLOAT (resample_vert_double_generic, double, double, n_taps, +RESAMPLE_VERT_FLOAT (resample_vert_double_generic, guint8, 255, double, double, n_taps, shift) -RESAMPLE_VERT_FLOAT_DITHER (resample_vert_dither_double_generic, double, double, +RESAMPLE_VERT_FLOAT_DITHER (resample_vert_dither_double_generic, guint8, 255, double, double, n_taps, shift) -RESAMPLE_VERT_FLOAT (resample_vert_float_generic, float, float, n_taps, shift) -RESAMPLE_VERT_FLOAT_DITHER (resample_vert_dither_float_generic, float, float, +RESAMPLE_VERT_FLOAT (resample_vert_double_generic_u16, guint16, 65535, double, double, n_taps, + shift) +RESAMPLE_VERT_FLOAT_DITHER (resample_vert_dither_double_generic_u16, guint16, 65535, double, double, + n_taps, shift) + +RESAMPLE_VERT_FLOAT (resample_vert_float_generic, guint8, 255, float, float, n_taps, shift) +RESAMPLE_VERT_FLOAT_DITHER (resample_vert_dither_float_generic, guint8, 255, float, float, n_taps, shift) /* *INDENT-ON* */ @@ -1556,3 +1573,77 @@ vs_image_scale_lanczos_AYUV_float (const VSImage * dest, const VSImage * src, scale1d_cleanup (&scale->y_scale1d); g_free (scale->tmpdata); } + +static void +vs_scale_lanczos_AYUV64_double (Scale * scale) +{ + int j; + int yi; + int tmp_yi; + + tmp_yi = 0; + + for (j = 0; j < scale->dest->height; j++) { + guint16 *destline; + double *taps; + + destline = (guint16 *) (scale->dest->pixels + scale->dest->stride * j); + + yi = scale->y_scale1d.offsets[j]; + + while (tmp_yi < yi + scale->y_scale1d.n_taps) { + scale->horiz_resample_func (TMP_LINE_DOUBLE_AYUV (tmp_yi), + scale->x_scale1d.offsets, scale->x_scale1d.taps, SRC_LINE (tmp_yi), + scale->x_scale1d.n_taps, 0, scale->dest->width); + tmp_yi++; + } + + taps = (double *) scale->y_scale1d.taps + j * scale->y_scale1d.n_taps; + if (scale->dither) { + resample_vert_dither_double_generic_u16 (destline, + taps, TMP_LINE_DOUBLE_AYUV (scale->y_scale1d.offsets[j]), + sizeof (double) * 4 * scale->dest->width, + scale->y_scale1d.n_taps, 0, scale->dest->width * 4); + } else { + resample_vert_double_generic_u16 (destline, + taps, TMP_LINE_DOUBLE_AYUV (scale->y_scale1d.offsets[j]), + sizeof (double) * 4 * scale->dest->width, + scale->y_scale1d.n_taps, 0, scale->dest->width * 4); + } + } +} + +void +vs_image_scale_lanczos_AYUV64_double (const VSImage * dest, const VSImage * src, + uint8_t * tmpbuf, double sharpness, gboolean dither, double a, + double sharpen) +{ + Scale s = { 0 }; + Scale *scale = &s; + int n_taps; + + scale->dest = dest; + scale->src = src; + + n_taps = scale1d_get_n_taps (src->width, dest->width, a, sharpness); + scale1d_calculate_taps (&scale->x_scale1d, + src->width, dest->width, n_taps, a, sharpness, sharpen); + + n_taps = scale1d_get_n_taps (src->height, dest->height, a, sharpness); + scale1d_calculate_taps (&scale->y_scale1d, + src->height, dest->height, n_taps, a, sharpness, sharpen); + + scale->dither = dither; + + scale->horiz_resample_func = + (HorizResampleFunc) resample_horiz_double_ayuv_generic; + + scale->tmpdata = + g_malloc (sizeof (double) * scale->dest->width * scale->src->height * 4); + + vs_scale_lanczos_AYUV64_double (scale); + + scale1d_cleanup (&scale->x_scale1d); + scale1d_cleanup (&scale->y_scale1d); + g_free (scale->tmpdata); +} diff --git a/gst/videoscale/vs_scanline.c b/gst/videoscale/vs_scanline.c index 822a6b6600..c9459c234c 100644 --- a/gst/videoscale/vs_scanline.c +++ b/gst/videoscale/vs_scanline.c @@ -519,6 +519,88 @@ vs_scanline_merge_linear_UYVY (uint8_t * dest, uint8_t * src1, } +/* NV12 */ + +/* n is the number of bi-pixels */ + +void +vs_scanline_downsample_NV12 (uint8_t * dest, uint8_t * src, int n) +{ + int i; + + for (i = 0; i < n; i++) { + dest[i * 2 + 0] = (src[i * 4 + 0] + src[i * 4 + 2]) / 2; + dest[i * 2 + 1] = (src[i * 4 + 1] + src[i * 4 + 3]) / 2; + } +} + +void +vs_scanline_resample_nearest_NV12 (uint8_t * dest, uint8_t * src, int src_width, + int n, int *accumulator, int increment) +{ + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + + dest[i * 2 + 0] = (x < 32768 + || j + 1 >= src_width) ? src[j * 2 + 0] : src[j * 2 + 2]; + dest[i * 2 + 1] = (x < 32768 + || j + 1 >= src_width) ? src[j * 2 + 1] : src[j * 2 + 3]; + + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_resample_linear_NV12 (uint8_t * dest, uint8_t * src, int src_width, + int n, int *accumulator, int increment) +{ + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + + if (j + 1 < src_width) { + dest[i * 2 + 0] = + (src[j * 2 + 0] * (65536 - x) + src[j * 2 + 2] * x) >> 16; + dest[i * 2 + 1] = + (src[j * 2 + 1] * (65536 - x) + src[j * 2 + 3] * x) >> 16; + } else { + dest[i * 4 + 0] = src[j * 2 + 0]; + dest[i * 4 + 1] = src[j * 2 + 1]; + } + + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_merge_linear_NV12 (uint8_t * dest, uint8_t * src1, + uint8_t * src2, int n, int x) +{ + uint32_t value = x >> 8; + + if (value == 0) { + memcpy (dest, src1, n * 2); + } else { + orc_merge_linear_u8 (dest, src1, src2, value, n * 2); + } +} + + /* RGB565 */ /* note that src and dest are uint16_t, and thus endian dependent */ diff --git a/gst/videoscale/vs_scanline.h b/gst/videoscale/vs_scanline.h index 387fc9511b..92d8f6f04d 100644 --- a/gst/videoscale/vs_scanline.h +++ b/gst/videoscale/vs_scanline.h @@ -55,6 +55,11 @@ void vs_scanline_resample_nearest_UYVY (uint8_t *dest, uint8_t *src, int src_wid void vs_scanline_resample_linear_UYVY (uint8_t *dest, uint8_t *src, int src_width, int n, int *accumulator, int increment); void vs_scanline_merge_linear_UYVY (uint8_t *dest, uint8_t *src1, uint8_t *src2, int n, int x); +void vs_scanline_downsample_NV12 (uint8_t *dest, uint8_t *src, int n); +void vs_scanline_resample_nearest_NV12 (uint8_t *dest, uint8_t *src, int src_width, int n, int *accumulator, int increment); +void vs_scanline_resample_linear_NV12 (uint8_t *dest, uint8_t *src, int src_width, int n, int *accumulator, int increment); +void vs_scanline_merge_linear_NV12 (uint8_t *dest, uint8_t *src1, uint8_t *src2, int n, int x); + void vs_scanline_downsample_RGB565 (uint8_t *dest, uint8_t *src, int n); void vs_scanline_resample_nearest_RGB565 (uint8_t *dest, uint8_t *src, int src_width, int n, int *accumulator, int increment); void vs_scanline_resample_linear_RGB565 (uint8_t *dest, uint8_t *src, int src_width, int n, int *accumulator, int increment); diff --git a/tests/check/libs/video.c b/tests/check/libs/video.c index 5678eb35b0..abc6f22c55 100644 --- a/tests/check/libs/video.c +++ b/tests/check/libs/video.c @@ -607,7 +607,13 @@ GST_START_TEST (test_parse_caps_rgb) GST_VIDEO_CAPS_MAKE ("RGBA"), GST_VIDEO_FORMAT_RGBA}, { GST_VIDEO_CAPS_MAKE ("ARGB"), GST_VIDEO_FORMAT_ARGB}, { GST_VIDEO_CAPS_MAKE ("BGRA"), GST_VIDEO_FORMAT_BGRA}, { - GST_VIDEO_CAPS_MAKE ("ABGR"), GST_VIDEO_FORMAT_ABGR} + GST_VIDEO_CAPS_MAKE ("ABGR"), GST_VIDEO_FORMAT_ABGR}, + /* 16 bit */ + { + GST_VIDEO_CAPS_MAKE ("RGB16"), GST_VIDEO_FORMAT_RGB16}, { + GST_VIDEO_CAPS_MAKE ("BGR16"), GST_VIDEO_FORMAT_BGR16}, { + GST_VIDEO_CAPS_MAKE ("RGB15"), GST_VIDEO_FORMAT_RGB15}, { + GST_VIDEO_CAPS_MAKE ("BGR15"), GST_VIDEO_FORMAT_BGR15} }; gint i;