1 /*
2 * Copyright (C) 2000-2018 the xine project
3 *
4 * This file is part of xine, a free video player.
5 *
6 * xine is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * xine is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19 *
20 * YUV "Decoder" by Mike Melanson (melanson@pcisys.net)
21 * Actually, this decoder just reorganizes chunks of raw YUV data in such
22 * a way that xine can display them.
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34
35 #include <xine/xine_internal.h>
36 #include <xine/video_out.h>
37 #include <xine/buffer.h>
38 #include <xine/xineutils.h>
39 #include "bswap.h"
40 #include "group_raw.h"
41
42 #define VIDEOBUFSIZE 128*1024
43
44 typedef struct yuv_decoder_s {
45 video_decoder_t video_decoder; /* parent video decoder structure */
46
47 xine_stream_t *stream;
48
49 /* these are traditional variables in a video decoder object */
50 uint64_t video_step; /* frame duration in pts units */
51 int decoder_ok; /* current decoder status */
52 int skipframes;
53
54 unsigned char *buf; /* the accumulated buffer data */
55 int bufsize; /* the maximum size of buf */
56 int size; /* the current size of buf */
57
58 int width; /* the width of a video frame */
59 int height; /* the height of a video frame */
60 double ratio; /* the width to height ratio */
61
62 int progressive;
63 int top_field_first;
64 int color_matrix;
65
66 } yuv_decoder_t;
67
68 /**************************************************************************
69 * xine video plugin functions
70 *************************************************************************/
71
72 /*
73 * This function receives a buffer of data from the demuxer layer and
74 * figures out how to handle it based on its header flags.
75 */
yuv_decode_data(video_decoder_t * this_gen,buf_element_t * buf)76 static void yuv_decode_data (video_decoder_t *this_gen,
77 buf_element_t *buf) {
78
79 yuv_decoder_t *this = (yuv_decoder_t *) this_gen;
80 xine_bmiheader *bih;
81
82 vo_frame_t *img; /* video out frame */
83
84 /* a video decoder does not care about this flag (?) */
85 if (buf->decoder_flags & BUF_FLAG_PREVIEW)
86 return;
87
88 if (buf->decoder_flags & BUF_FLAG_FRAMERATE) {
89 this->video_step = buf->decoder_info[0];
90 _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->video_step);
91 }
92
93 if (buf->decoder_flags & BUF_FLAG_STDHEADER) { /* need to initialize */
94 (this->stream->video_out->open) (this->stream->video_out, this->stream);
95
96 bih = (xine_bmiheader *) buf->content;
97 this->width = bih->biWidth;
98 this->height = bih->biHeight;
99
100 if (buf->decoder_flags & BUF_FLAG_ASPECT)
101 this->ratio = (double)buf->decoder_info[1] / (double)buf->decoder_info[2];
102 else
103 this->ratio = (double)this->width / (double)this->height;
104
105 this->progressive = buf->decoder_info[3];
106 this->top_field_first = buf->decoder_info[4];
107
108 this->color_matrix = 4; /* undefined, mpeg range */
109
110 free (this->buf);
111 this->buf = NULL;
112
113 this->bufsize = 0;
114 this->size = 0;
115
116 this->decoder_ok = 1;
117
118 /* load the stream/meta info */
119 switch (buf->type) {
120
121 case BUF_VIDEO_YUY2:
122 this->width = (this->width + 1) & ~1;
123 this->bufsize = this->width * this->height * 2;
124 _x_meta_info_set_utf8(this->stream, XINE_META_INFO_VIDEOCODEC, "Raw YUY2");
125 break;
126
127 case BUF_VIDEO_YV12:
128 this->width = (this->width + 1) & ~1;
129 this->height = (this->height + 1) & ~1;
130 this->bufsize = this->width * this->height * 3 / 2;
131 _x_meta_info_set_utf8(this->stream, XINE_META_INFO_VIDEOCODEC, "Raw YV12");
132 break;
133
134 case BUF_VIDEO_YVU9:
135 this->width = (this->width + 3) & ~3;
136 this->height = (this->height + 3) & ~3;
137 this->bufsize = this->width * this->height * 9 / 8;
138 _x_meta_info_set_utf8(this->stream, XINE_META_INFO_VIDEOCODEC, "Raw YVU9");
139 break;
140
141 case BUF_VIDEO_GREY:
142 _x_meta_info_set_utf8(this->stream, XINE_META_INFO_VIDEOCODEC, "Greyscale YUV");
143 break;
144
145 case BUF_VIDEO_I420:
146 this->width = (this->width + 1) & ~1;
147 this->height = (this->height + 1) & ~1;
148 this->bufsize = this->width * this->height * 3 / 2;
149 _x_meta_info_set_utf8(this->stream, XINE_META_INFO_VIDEOCODEC, "Raw I420");
150 break;
151
152 }
153
154 this->buf = malloc(this->bufsize);
155
156 _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->width);
157 _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->height);
158 _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_RATIO, this->ratio*10000);
159
160 return;
161 } else if (this->decoder_ok && !(buf->decoder_flags & BUF_FLAG_SPECIAL)) {
162 uint8_t *src;
163
164 /* if buffer contains an entire frame then there's no need to copy it
165 * into our internal buffer */
166 if ((buf->decoder_flags & BUF_FLAG_FRAME_START) &&
167 (buf->decoder_flags & BUF_FLAG_FRAME_END))
168 src = buf->content;
169 else {
170 if (this->size + buf->size > this->bufsize) {
171 this->bufsize = this->size + 2 * buf->size;
172 this->buf = realloc (this->buf, this->bufsize);
173 }
174
175 xine_fast_memcpy (&this->buf[this->size], buf->content, buf->size);
176
177 this->size += buf->size;
178
179 src = this->buf;
180 }
181
182 if (buf->decoder_flags & BUF_FLAG_COLOR_MATRIX)
183 this->color_matrix = buf->decoder_info[4];
184
185 if (buf->decoder_flags & BUF_FLAG_FRAME_END) {
186 int format;
187 if (buf->type == BUF_VIDEO_YUY2) {
188 format = XINE_IMGFMT_YUY2;
189 } else {
190 format = XINE_IMGFMT_YV12;
191 }
192
193 img = this->stream->video_out->get_frame (this->stream->video_out,
194 this->width, this->height,
195 this->ratio, format,
196 VO_BOTH_FIELDS | VO_GET_FRAME_MAY_FAIL);
197 if (!img) {
198 xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
199 LOG_MODULE ": get_frame(%dx%d) failed\n", this->width, this->height);
200 this->size = 0;
201 return;
202 }
203
204
205 if (buf->type == BUF_VIDEO_YUY2) {
206
207 yuy2_to_yuy2(
208 /* src */
209 src, this->width*2,
210 /* dst */
211 img->base[0], img->pitches[0],
212 /* width x height */
213 this->width, this->height);
214
215 } else if (buf->type == BUF_VIDEO_YV12) {
216
217 yv12_to_yv12(
218 /* Y */
219 src, this->width,
220 img->base[0], img->pitches[0],
221 /* U */
222 src + (this->width * this->height * 5/4), this->width/2,
223 img->base[1], img->pitches[1],
224 /* V */
225 src + (this->width * this->height), this->width/2,
226 img->base[2], img->pitches[2],
227 /* width x height */
228 this->width, this->height);
229
230 } else if (buf->type == BUF_VIDEO_I420) {
231
232 yv12_to_yv12(
233 /* Y */
234 src, this->width,
235 img->base[0], img->pitches[0],
236 /* U */
237 src + (this->width * this->height), this->width/2,
238 img->base[1], img->pitches[1],
239 /* V */
240 src + (this->width * this->height * 5/4), this->width/2,
241 img->base[2], img->pitches[2],
242 /* width x height */
243 this->width, this->height);
244
245 } else if (buf->type == BUF_VIDEO_YVU9) {
246
247 yuv9_to_yv12(
248 /* Y */
249 src,
250 this->width,
251 img->base[0],
252 img->pitches[0],
253 /* U */
254 src + (this->width * this->height),
255 this->width / 4,
256 img->base[1],
257 img->pitches[1],
258 /* V */
259 src + (this->width * this->height) +
260 (this->width * this->height / 16),
261 this->width / 4,
262 img->base[2],
263 img->pitches[2],
264 /* width x height */
265 this->width,
266 this->height);
267
268 } else if (buf->type == BUF_VIDEO_GREY) {
269
270 xine_fast_memcpy(img->base[0], src, this->width * this->height);
271 memset( img->base[1], 0x80, this->width * this->height / 4 );
272 memset( img->base[2], 0x80, this->width * this->height / 4 );
273
274 } else {
275
276 xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
277 LOG_MODULE ": unsupported format 0x%x\n", buf->type);
278 }
279
280 VO_SET_FLAGS_CM (this->color_matrix, img->flags);
281
282 img->duration = this->video_step;
283 img->pts = buf->pts;
284 img->bad_frame = 0;
285
286 img->draw(img, this->stream);
287 img->free(img);
288
289 this->size = 0;
290 }
291 }
292 }
293
294 /*
295 * This function is called when xine needs to flush the system. Not
296 * sure when or if this is used or even if it needs to do anything.
297 */
yuv_flush(video_decoder_t * this_gen)298 static void yuv_flush (video_decoder_t *this_gen) {
299 (void)this_gen;
300 }
301
302 /*
303 * This function resets the video decoder.
304 */
yuv_reset(video_decoder_t * this_gen)305 static void yuv_reset (video_decoder_t *this_gen) {
306 yuv_decoder_t *this = (yuv_decoder_t *) this_gen;
307
308 this->size = 0;
309 }
310
yuv_discontinuity(video_decoder_t * this_gen)311 static void yuv_discontinuity (video_decoder_t *this_gen) {
312 (void)this_gen;
313 }
314
315 /*
316 * This function frees the video decoder instance allocated to the decoder.
317 */
yuv_dispose(video_decoder_t * this_gen)318 static void yuv_dispose (video_decoder_t *this_gen) {
319 yuv_decoder_t *this = (yuv_decoder_t *) this_gen;
320
321 free (this->buf);
322
323 if (this->decoder_ok) {
324 this->decoder_ok = 0;
325 this->stream->video_out->close(this->stream->video_out, this->stream);
326 }
327
328 free (this_gen);
329 }
330
open_plugin(video_decoder_class_t * class_gen,xine_stream_t * stream)331 static video_decoder_t *open_plugin (video_decoder_class_t *class_gen, xine_stream_t *stream) {
332
333 yuv_decoder_t *this ;
334
335 (void)class_gen;
336
337 this = (yuv_decoder_t *) calloc(1, sizeof(yuv_decoder_t));
338 if (!this)
339 return NULL;
340
341 this->video_decoder.decode_data = yuv_decode_data;
342 this->video_decoder.flush = yuv_flush;
343 this->video_decoder.reset = yuv_reset;
344 this->video_decoder.discontinuity = yuv_discontinuity;
345 this->video_decoder.dispose = yuv_dispose;
346 this->size = 0;
347
348 this->stream = stream;
349
350 this->decoder_ok = 0;
351 this->buf = NULL;
352
353 return &this->video_decoder;
354 }
355
decode_yuv_init_class(xine_t * xine,const void * data)356 void *decode_yuv_init_class (xine_t *xine, const void *data) {
357
358 (void)xine;
359 (void)data;
360
361 static const video_decoder_class_t decode_video_yuv_class = {
362 .open_plugin = open_plugin,
363 .identifier = "YUV",
364 .description = N_("Raw YUV video decoder plugin"),
365 .dispose = NULL,
366 };
367
368 return (void *)&decode_video_yuv_class;
369 }
370
371