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