rvdec: add RealVideo support
[gstreamer-omap:gst-ducati.git] / src / gstducatirvdec.c
1 /*
2  * GStreamer
3  * Copyright (c) 2010, Texas Instruments Incorporated
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation
8  * version 2.1 of the License.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 /**
21  * SECTION:element-ducatirvdec
22  *
23  * FIXME:Describe ducatirvdec here.
24  *
25  * <refsect2>
26  * <title>Example launch line</title>
27  * |[
28  * gst-launch -v -m fakesrc ! ducatirvdec ! fakesink silent=TRUE
29  * ]|
30  * </refsect2>
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #  include <config.h>
35 #endif
36
37 #include <gst/gst.h>
38 #include <gst/video/video.h>
39
40 #include "gstducatirvdec.h"
41
42
43 #define PADX  32
44 #define PADY  32
45
46
47 GST_BOILERPLATE (GstDucatiRVDec, gst_ducati_rvdec, GstDucatiVidDec,
48     GST_TYPE_DUCATIVIDDEC);
49
50 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
51     GST_PAD_SINK,
52     GST_PAD_ALWAYS,
53     GST_STATIC_CAPS ("video/x-pn-realvideo, "
54         "systemstream = (boolean)false, "
55         "rmversion = (int){ 3, 4 }, "
56         "width = (int)[ 16, 2048 ], "
57         "height = (int)[ 16, 2048 ], "
58         "framerate = (fraction)[ 0, max ];")
59     );
60
61 /* GstDucatiVidDec vmethod implementations */
62
63 static gboolean
64 gst_ducati_rvdec_parse_caps (GstDucatiVidDec * vdec, GstStructure * s)
65 {
66   GstDucatiRVDec *self = GST_DUCATIRVDEC (vdec);
67
68   if (parent_class->parse_caps (vdec, s)) {
69     gboolean ret = gst_structure_get_int (s, "rmversion", &self->rmversion);
70     if (ret) {
71       IrealVDEC_Params *params = (IrealVDEC_Params *) vdec->params;
72       GST_DEBUG_OBJECT (self, "rmversion: %d", self->rmversion);
73
74       if (self->rmversion == 3) {
75         params->stream_type = 1;
76         params->codec_version = 8;
77       } else if (self->rmversion == 4) {
78         params->stream_type = 1;
79         params->codec_version = 9;
80       } else {
81         ret = FALSE;
82       }
83     }
84
85     return ret;
86   }
87
88   return FALSE;
89 }
90
91 static void
92 gst_ducati_rvdec_update_buffer_size (GstDucatiVidDec * self)
93 {
94   /* calculate output buffer parameters: */
95   self->padded_width = ALIGN2 (self->width + (2 * PADX), 7);
96   self->padded_height = self->height + 2 * PADY;
97   self->min_buffers = 8;
98 }
99
100 static gboolean
101 gst_ducati_rvdec_allocate_params (GstDucatiVidDec * vdec, gint params_sz,
102     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
103 {
104   GstDucatiRVDec *self = GST_DUCATIRVDEC (vdec);
105   gboolean ret = parent_class->allocate_params (vdec,
106       sizeof (IrealVDEC_Params), sizeof (IrealVDEC_DynamicParams),
107       sizeof (IrealVDEC_Status), sizeof (IrealVDEC_InArgs),
108       sizeof (IrealVDEC_OutArgs));
109
110   if (ret) {
111     IrealVDEC_Params *params = (IrealVDEC_Params *) vdec->params;
112     vdec->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_1;
113     vdec->dynParams->newFrameFlag = FALSE;
114     vdec->dynParams->lateAcquireArg = -1;
115     vdec->params->numInputDataUnits = 1;
116     vdec->params->numOutputDataUnits = 1;
117   }
118
119   return ret;
120 }
121
122 static GstBuffer *
123 gst_ducati_rvdec_push_input (GstDucatiVidDec * vdec, GstBuffer * buf)
124 {
125   GstDucatiRVDec *self = GST_DUCATIRVDEC (vdec);
126   guint8 *data;
127   guint8 val[4];
128   gint i, sz, slice_count;
129
130   /* *** on first buffer, build up the stream header for the codec *** */
131   if (G_UNLIKELY (vdec->first_in_buffer) && vdec->codec_data) {
132
133     sz = GST_BUFFER_SIZE (vdec->codec_data);
134     data = GST_BUFFER_DATA (vdec->codec_data);
135
136     /* header size, 4 bytes, big-endian */
137     GST_WRITE_UINT32_BE (val, sz + 26);
138     push_input (vdec, val, 4);
139
140     /* stream type */
141     if (self->rmversion == 3) {
142       push_input (vdec, "VIDORV30", 8);
143     } else if (self->rmversion == 4) {
144       push_input (vdec, "VIDORV40", 8);
145     }
146
147     /* horiz x vert resolution */
148     GST_WRITE_UINT16_BE (val, vdec->width);
149     push_input (vdec, val, 2);
150     GST_WRITE_UINT16_BE (val, vdec->height);
151     push_input (vdec, val, 2);
152
153     /* unknown? */
154     GST_WRITE_UINT32_BE (val, 0x000c0000);
155     push_input (vdec, val, 4);
156
157     /* unknown? may be framerate.. */
158     GST_WRITE_UINT32_BE (val, 0x0000000f);
159     push_input (vdec, val, 4);
160
161     /* unknown? */
162     GST_WRITE_UINT16_BE (val, 0x0000);
163     push_input (vdec, val, 2);
164
165     /* and rest of stream header is the codec_data */
166     push_input (vdec, data, sz);
167   }
168
169   data = GST_BUFFER_DATA (buf);
170   sz = GST_BUFFER_SIZE (buf);
171   slice_count = (*data++) + 1;
172
173   /* payload size, excluding fixed header and slice header */
174   sz -= 1 + (8 * slice_count);
175
176   /* *** insert frame header *** */
177   /* payload size */
178   GST_WRITE_UINT32_BE (val, sz);
179   push_input (vdec, val, 4);
180
181   /* unknown? may be timestamp, hopefully decoder doesn't care */
182   GST_WRITE_UINT32_BE (val, 0x00000001);
183   push_input (vdec, val, 4);
184
185   /* unknown? may be sequence number, hopefully decoder doesn't care */
186   GST_WRITE_UINT16_BE (val, 0x0000);
187   push_input (vdec, val, 2);
188
189   /* unknown? may indicate I frame, hopefully decoder doesn't care */
190   if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
191     GST_WRITE_UINT16_BE (val, 0x0000);
192   } else {
193     GST_WRITE_UINT16_BE (val, 0x0002);
194   }
195   push_input (vdec, val, 2);
196
197   /* unknown? seems to be always zeros */
198   GST_WRITE_UINT32_BE (val, 0x00000000);
199   push_input (vdec, val, 4);
200
201   /* convert the slice_header to big endian, and note that the codec
202    * expects to get slice_count rather than slice_count-1
203    */
204   GST_WRITE_UINT32_BE (val, slice_count);
205   push_input (vdec, val, 4);
206
207   for (i = 0; i < slice_count; i++) {
208     GST_WRITE_UINT32_BE (val, 0x00000001);
209     push_input (vdec, val, 4);
210
211     data += 4;
212     GST_WRITE_UINT32_BE (val, GST_READ_UINT32_LE (data));
213     data += 4;
214     push_input (vdec, val, 4);
215   }
216
217   /* copy the payload (rest of buffer) */
218   push_input (vdec, data, sz);
219   gst_buffer_unref (buf);
220
221   return NULL;
222 }
223
224 /* GObject vmethod implementations */
225
226 static void
227 gst_ducati_rvdec_base_init (gpointer gclass)
228 {
229   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
230
231   gst_element_class_set_details_simple (element_class,
232       "DucatiRVDec",
233       "Codec/Decoder/Video",
234       "Decodes video in RealVideo (RV8/9/10) format with ducati",
235       "Rob Clark <rob@ti.com>");
236
237   gst_element_class_add_pad_template (element_class,
238       gst_static_pad_template_get (&sink_factory));
239 }
240
241 static void
242 gst_ducati_rvdec_class_init (GstDucatiRVDecClass * klass)
243 {
244   GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
245   bclass->codec_name = "ivahd_realvdec";
246   bclass->parse_caps =
247       GST_DEBUG_FUNCPTR (gst_ducati_rvdec_parse_caps);
248   bclass->update_buffer_size =
249       GST_DEBUG_FUNCPTR (gst_ducati_rvdec_update_buffer_size);
250   bclass->allocate_params =
251       GST_DEBUG_FUNCPTR (gst_ducati_rvdec_allocate_params);
252   bclass->push_input =
253       GST_DEBUG_FUNCPTR (gst_ducati_rvdec_push_input);
254 }
255
256 static void
257 gst_ducati_rvdec_init (GstDucatiRVDec * self,
258     GstDucatiRVDecClass * gclass)
259 {
260 }