7956165da2961535a22f10c495cba50d56bb733c
[platform/upstream/gst-plugins-good.git] / gst / videoflip / videoflip.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 #define DEBUG_ENABLED
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <gst/gst.h>
26 #include <stdlib.h>
27 #include <math.h>
28 #include <videoflip.h>
29 #include <string.h>
30
31 #include "gstvideoflip.h"
32
33 static void gst_videoflip_planar411 (GstVideoflip *scale, unsigned char *dest, unsigned char *src);
34
35 static void gst_videoflip_flip(GstVideoflip *videoflip, unsigned char *dest,
36     unsigned char *src, int sw, int sh, int dw, int dh);
37
38 struct videoflip_format_struct videoflip_formats[] = {
39         /* planar */
40         { "YV12", 12, gst_videoflip_planar411, },
41         { "I420", 12, gst_videoflip_planar411, },
42 };
43
44 int videoflip_n_formats = sizeof(videoflip_formats)/sizeof(videoflip_formats[0]);
45
46 GstStructure *
47 videoflip_get_cap(struct videoflip_format_struct *format)
48 {
49   unsigned int fourcc;
50   GstStructure *structure;
51
52   if(format->scale==NULL)
53     return NULL;
54
55   fourcc = GST_MAKE_FOURCC(format->fourcc[0],format->fourcc[1],format->fourcc[2],format->fourcc[3]);
56
57   if(format->bpp){
58     structure = gst_structure_new("video/x-raw-rgb",
59         "depth", G_TYPE_INT, format->bpp,
60         "bpp", G_TYPE_INT, format->depth,
61         "endianness", G_TYPE_INT, format->endianness,
62         "red_mask", G_TYPE_INT, format->red_mask,
63         "green_mask", G_TYPE_INT, format->green_mask,
64         "blue_mask", G_TYPE_INT, format->blue_mask, NULL);
65   }else{
66     structure = gst_structure_new("video/x-raw-yuv",
67         "format", GST_TYPE_FOURCC, fourcc, NULL);
68   }
69
70   return structure;
71 }
72
73 struct videoflip_format_struct *
74 videoflip_find_by_caps(const GstCaps *caps)
75 {
76   int i;
77
78   GST_DEBUG ("finding %p", caps);
79
80   g_return_val_if_fail(caps != NULL, NULL);
81
82   for (i = 0; i < videoflip_n_formats; i++){
83     GstCaps *c;
84
85     c = gst_caps_new_full (videoflip_get_cap (videoflip_formats + i), NULL);
86     if(c){
87       if(gst_caps_is_always_compatible(caps, c)){
88         gst_caps_free(c);
89         return videoflip_formats + i;
90       }
91       gst_caps_free(c);
92     }
93   }
94
95   return NULL;
96 }
97
98 void
99 gst_videoflip_setup (GstVideoflip *videoflip)
100 {
101   if(videoflip->from_width==0 || videoflip->from_height==0){
102     return;
103   }
104
105   switch(videoflip->method){
106     case GST_VIDEOFLIP_METHOD_90R:
107     case GST_VIDEOFLIP_METHOD_90L:
108     case GST_VIDEOFLIP_METHOD_TRANS:
109     case GST_VIDEOFLIP_METHOD_OTHER:
110       videoflip->to_height = videoflip->from_width;
111       videoflip->to_width = videoflip->from_height;
112       break;
113     case GST_VIDEOFLIP_METHOD_IDENTITY:
114     case GST_VIDEOFLIP_METHOD_180:
115     case GST_VIDEOFLIP_METHOD_HORIZ:
116     case GST_VIDEOFLIP_METHOD_VERT:
117       videoflip->to_height = videoflip->from_height;
118       videoflip->to_width = videoflip->from_width;
119       break;
120     default:
121       /* FIXME */
122       break;
123   }
124
125   GST_DEBUG ("format=%p \"%s\" from %dx%d to %dx%d",
126                 videoflip->format, videoflip->format->fourcc,
127                 videoflip->from_width, videoflip->from_height,
128                 videoflip->to_width, videoflip->to_height);
129
130   if(videoflip->method == GST_VIDEOFLIP_METHOD_IDENTITY){
131     GST_DEBUG ("videoflip: using passthru");
132     videoflip->passthru = TRUE;
133     videoflip->inited = TRUE;
134     return;
135   }
136
137   videoflip->from_buf_size = (videoflip->from_width * videoflip->from_height
138                   * videoflip->format->depth) / 8;
139   videoflip->to_buf_size = (videoflip->to_width * videoflip->to_height
140                   * videoflip->format->depth) / 8;
141
142   videoflip->inited = TRUE;
143 }
144
145 static void
146 gst_videoflip_planar411 (GstVideoflip *scale, unsigned char *dest, unsigned char *src)
147 {
148   int sw = scale->from_width;
149   int sh = scale->from_height;
150   int dw = scale->to_width;
151   int dh = scale->to_height;
152
153   GST_DEBUG ("videoflip: scaling planar 4:1:1 %dx%d to %dx%d", sw, sh, dw, dh);
154
155   gst_videoflip_flip(scale, dest, src, sw, sh, dw, dh);
156
157   src += sw*sh;
158   dest += dw*dh;
159
160   dh = dh>>1;
161   dw = dw>>1;
162   sh = sh>>1;
163   sw = sw>>1;
164
165   gst_videoflip_flip(scale, dest, src, sw, sh, dw, dh);
166
167   src += sw*sh;
168   dest += dw*dh;
169
170   gst_videoflip_flip(scale, dest, src, sw, sh, dw, dh);
171 }
172
173 static void
174 gst_videoflip_flip(GstVideoflip *videoflip, unsigned char *dest,
175     unsigned char *src, int sw, int sh, int dw, int dh)
176 {
177   int x,y;
178
179   switch(videoflip->method){
180     case GST_VIDEOFLIP_METHOD_90R:
181       for(y=0;y<dh;y++){
182         for(x=0;x<dw;x++){
183           dest[y*dw + x] = src[(sh - 1 - x)*sw + y];
184         }
185       }
186       break;
187     case GST_VIDEOFLIP_METHOD_90L:
188       for(y=0;y<dh;y++){
189         for(x=0;x<dw;x++){
190           dest[y*dw + x] = src[x*sw + (sw - 1 - y)];
191         }
192       }
193       break;
194     case GST_VIDEOFLIP_METHOD_180:
195       for(y=0;y<dh;y++){
196         for(x=0;x<dw;x++){
197           dest[y*dw + x] = src[(sh - 1 - y)*sw + (sw - 1 - x)];
198         }
199       }
200       break;
201     case GST_VIDEOFLIP_METHOD_HORIZ:
202       for(y=0;y<dh;y++){
203         for(x=0;x<dw;x++){
204           dest[y*dw + x] = src[y*sw + (sw - 1 - x)];
205         }
206       }
207       break;
208     case GST_VIDEOFLIP_METHOD_VERT:
209       for(y=0;y<dh;y++){
210         for(x=0;x<dw;x++){
211           dest[y*dw + x] = src[(sh - 1 - y)*sw + x];
212         }
213       }
214       break;
215     case GST_VIDEOFLIP_METHOD_TRANS:
216       for(y=0;y<dh;y++){
217         for(x=0;x<dw;x++){
218           dest[y*dw + x] = src[x*sw + y];
219         }
220       }
221       break;
222     case GST_VIDEOFLIP_METHOD_OTHER:
223       for(y=0;y<dh;y++){
224         for(x=0;x<dw;x++){
225           dest[y*dw + x] = src[(sh - 1 - x)*sw + (sw - 1 - y)];
226         }
227       }
228       break;
229     default:
230       /* FIXME */
231       break;
232   }
233 }
234