1 /*****************************************************************************
2  * es_format.c : es_format_t helpers.
3  *****************************************************************************
4  * Copyright (C) 2008 VLC authors and VideoLAN
5  * $Id: 1c9a78e1a4f254eaf1f078d0d8feec7025ae4433 $
6  *
7  * Author: Laurent Aimar <fenrir@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23 
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31 
32 #include <assert.h>
33 
34 #include <vlc_common.h>
35 #include <vlc_es.h>
36 
37 
38 /*****************************************************************************
39  * BinaryLog: computes the base 2 log of a binary value
40  *****************************************************************************
41  * This functions is used by MaskToShift, to get a bit index from a binary
42  * value.
43  *****************************************************************************/
BinaryLog(uint32_t i)44 static int BinaryLog( uint32_t i )
45 {
46     int i_log = 0;
47 
48     if( i == 0 ) return -31337;
49 
50     if( i & 0xffff0000 ) i_log += 16;
51     if( i & 0xff00ff00 ) i_log += 8;
52     if( i & 0xf0f0f0f0 ) i_log += 4;
53     if( i & 0xcccccccc ) i_log += 2;
54     if( i & 0xaaaaaaaa ) i_log += 1;
55 
56     return i_log;
57 }
58 
59 /**
60  * It transforms a color mask into right and left shifts
61  * FIXME copied from video_output.c
62  */
MaskToShift(int * pi_left,int * pi_right,uint32_t i_mask)63 static void MaskToShift( int *pi_left, int *pi_right, uint32_t i_mask )
64 {
65     uint32_t i_low, i_high;            /* lower and higher bits of the mask */
66 
67     if( !i_mask )
68     {
69         *pi_left = *pi_right = 0;
70         return;
71     }
72 
73     /* Get bits */
74     i_low = i_high = i_mask;
75 
76     i_low &= - (int32_t)i_low;          /* lower bit of the mask */
77     i_high += i_low;                    /* higher bit of the mask */
78 
79     /* Transform bits into an index. Also deal with i_high overflow, which
80      * is faster than changing the BinaryLog code to handle 64 bit integers. */
81     i_low =  BinaryLog (i_low);
82     i_high = i_high ? BinaryLog (i_high) : 32;
83 
84     /* Update pointers and return */
85     *pi_left =   i_low;
86     *pi_right = (8 - i_high + i_low);
87 }
88 
89 /* */
video_format_FixRgb(video_format_t * p_fmt)90 void video_format_FixRgb( video_format_t *p_fmt )
91 {
92     /* FIXME find right default mask */
93     if( !p_fmt->i_rmask || !p_fmt->i_gmask || !p_fmt->i_bmask )
94     {
95         switch( p_fmt->i_chroma )
96         {
97         case VLC_CODEC_RGB15:
98             p_fmt->i_rmask = 0x7c00;
99             p_fmt->i_gmask = 0x03e0;
100             p_fmt->i_bmask = 0x001f;
101             break;
102 
103         case VLC_CODEC_RGB16:
104             p_fmt->i_rmask = 0xf800;
105             p_fmt->i_gmask = 0x07e0;
106             p_fmt->i_bmask = 0x001f;
107             break;
108 
109         case VLC_CODEC_RGB24:
110             p_fmt->i_rmask = 0xff0000;
111             p_fmt->i_gmask = 0x00ff00;
112             p_fmt->i_bmask = 0x0000ff;
113             break;
114         case VLC_CODEC_RGB32:
115             p_fmt->i_rmask = 0x00ff0000;
116             p_fmt->i_gmask = 0x0000ff00;
117             p_fmt->i_bmask = 0x000000ff;
118             break;
119 
120         default:
121             return;
122         }
123     }
124 
125     MaskToShift( &p_fmt->i_lrshift, &p_fmt->i_rrshift,
126                  p_fmt->i_rmask );
127     MaskToShift( &p_fmt->i_lgshift, &p_fmt->i_rgshift,
128                  p_fmt->i_gmask );
129     MaskToShift( &p_fmt->i_lbshift, &p_fmt->i_rbshift,
130                  p_fmt->i_bmask );
131 }
132 
video_format_Setup(video_format_t * p_fmt,vlc_fourcc_t i_chroma,int i_width,int i_height,int i_visible_width,int i_visible_height,int i_sar_num,int i_sar_den)133 void video_format_Setup( video_format_t *p_fmt, vlc_fourcc_t i_chroma,
134                          int i_width, int i_height,
135                          int i_visible_width, int i_visible_height,
136                          int i_sar_num, int i_sar_den )
137 {
138     p_fmt->i_chroma         = vlc_fourcc_GetCodec( VIDEO_ES, i_chroma );
139     p_fmt->i_width          = i_width;
140     p_fmt->i_visible_width  = i_visible_width;
141     p_fmt->i_height         = i_height;
142     p_fmt->i_visible_height = i_visible_height;
143     p_fmt->i_x_offset       =
144     p_fmt->i_y_offset       = 0;
145     vlc_ureduce( &p_fmt->i_sar_num, &p_fmt->i_sar_den,
146                  i_sar_num, i_sar_den, 0 );
147 
148     switch( p_fmt->i_chroma )
149     {
150     case VLC_CODEC_YUVA:
151         p_fmt->i_bits_per_pixel = 32;
152         break;
153     case VLC_CODEC_YUV420A:
154         p_fmt->i_bits_per_pixel = 20;
155         break;
156     case VLC_CODEC_YUV422A:
157         p_fmt->i_bits_per_pixel = 24;
158         break;
159     case VLC_CODEC_I444:
160     case VLC_CODEC_J444:
161         p_fmt->i_bits_per_pixel = 24;
162         break;
163     case VLC_CODEC_I422:
164     case VLC_CODEC_YUYV:
165     case VLC_CODEC_YVYU:
166     case VLC_CODEC_UYVY:
167     case VLC_CODEC_VYUY:
168     case VLC_CODEC_J422:
169         p_fmt->i_bits_per_pixel = 16;
170         break;
171     case VLC_CODEC_I440:
172     case VLC_CODEC_J440:
173         p_fmt->i_bits_per_pixel = 16;
174         break;
175     case VLC_CODEC_P010:
176         p_fmt->i_bits_per_pixel = 15;
177         break;
178     case VLC_CODEC_I411:
179     case VLC_CODEC_YV12:
180     case VLC_CODEC_I420:
181     case VLC_CODEC_J420:
182     case VLC_CODEC_NV12:
183         p_fmt->i_bits_per_pixel = 12;
184         break;
185     case VLC_CODEC_YV9:
186     case VLC_CODEC_I410:
187         p_fmt->i_bits_per_pixel = 9;
188         break;
189     case VLC_CODEC_Y211:
190         p_fmt->i_bits_per_pixel = 8;
191         break;
192     case VLC_CODEC_YUVP:
193         p_fmt->i_bits_per_pixel = 8;
194         break;
195 
196     case VLC_CODEC_RGB32:
197     case VLC_CODEC_RGBA:
198     case VLC_CODEC_ARGB:
199     case VLC_CODEC_BGRA:
200         p_fmt->i_bits_per_pixel = 32;
201         break;
202     case VLC_CODEC_RGB24:
203         p_fmt->i_bits_per_pixel = 24;
204         break;
205     case VLC_CODEC_RGB15:
206     case VLC_CODEC_RGB16:
207         p_fmt->i_bits_per_pixel = 16;
208         break;
209     case VLC_CODEC_RGB8:
210         p_fmt->i_bits_per_pixel = 8;
211         break;
212 
213     case VLC_CODEC_GREY:
214     case VLC_CODEC_RGBP:
215         p_fmt->i_bits_per_pixel = 8;
216         break;
217 
218     case VLC_CODEC_XYZ12:
219         p_fmt->i_bits_per_pixel = 48;
220         break;
221 
222     default:
223         p_fmt->i_bits_per_pixel = 0;
224         break;
225     }
226 }
227 
video_format_CopyCrop(video_format_t * p_dst,const video_format_t * p_src)228 void video_format_CopyCrop( video_format_t *p_dst, const video_format_t *p_src )
229 {
230     p_dst->i_x_offset       = p_src->i_x_offset;
231     p_dst->i_y_offset       = p_src->i_y_offset;
232     p_dst->i_visible_width  = p_src->i_visible_width;
233     p_dst->i_visible_height = p_src->i_visible_height;
234 }
235 
video_format_ScaleCropAr(video_format_t * p_dst,const video_format_t * p_src)236 void video_format_ScaleCropAr( video_format_t *p_dst, const video_format_t *p_src )
237 {
238     p_dst->i_x_offset       = (uint64_t)p_src->i_x_offset       * p_dst->i_width  / p_src->i_width;
239     p_dst->i_y_offset       = (uint64_t)p_src->i_y_offset       * p_dst->i_height / p_src->i_height;
240     p_dst->i_visible_width  = (uint64_t)p_src->i_visible_width  * p_dst->i_width  / p_src->i_width;
241     p_dst->i_visible_height = (uint64_t)p_src->i_visible_height * p_dst->i_height / p_src->i_height;
242 
243     p_dst->i_sar_num *= p_src->i_width;
244     p_dst->i_sar_den *= p_dst->i_width;
245     vlc_ureduce(&p_dst->i_sar_num, &p_dst->i_sar_den,
246                 p_dst->i_sar_num, p_dst->i_sar_den, 65536);
247 
248     p_dst->i_sar_num *= p_dst->i_height;
249     p_dst->i_sar_den *= p_src->i_height;
250     vlc_ureduce(&p_dst->i_sar_num, &p_dst->i_sar_den,
251                 p_dst->i_sar_num, p_dst->i_sar_den, 65536);
252 }
253 
254 //Simplify transforms to have something more manageable. Order: angle, hflip.
transform_GetBasicOps(video_transform_t transform,unsigned * restrict angle,bool * restrict hflip)255 static void transform_GetBasicOps( video_transform_t transform,
256                                    unsigned *restrict angle,
257                                    bool *restrict hflip )
258 {
259     *hflip = ORIENT_IS_MIRROR(transform);
260 
261     switch ( transform )
262     {
263         case TRANSFORM_R90:
264         case TRANSFORM_TRANSPOSE:
265             *angle = 90;
266             break;
267         case TRANSFORM_R180:
268         case TRANSFORM_VFLIP:
269             *angle = 180;
270             break;
271         case TRANSFORM_R270:
272         case TRANSFORM_ANTI_TRANSPOSE:
273             *angle = 270;
274             break;
275         case TRANSFORM_HFLIP:
276         case TRANSFORM_IDENTITY:
277             *angle = 0;
278             break;
279         default:
280             vlc_assert_unreachable ();
281     }
282 }
283 
transform_FromBasicOps(unsigned angle,bool hflip)284 static video_transform_t transform_FromBasicOps( unsigned angle, bool hflip )
285 {
286     switch ( angle )
287     {
288         case 90:
289             return hflip ? TRANSFORM_TRANSPOSE : TRANSFORM_R90;
290         case 180:
291             return hflip ? TRANSFORM_VFLIP : TRANSFORM_R180;
292         case 270:
293             return hflip ? TRANSFORM_ANTI_TRANSPOSE : TRANSFORM_R270;
294         default:
295             return hflip ? TRANSFORM_HFLIP : TRANSFORM_IDENTITY;
296     }
297 }
298 
video_format_GetTransform(video_orientation_t src,video_orientation_t dst)299 video_transform_t video_format_GetTransform( video_orientation_t src,
300                                              video_orientation_t dst )
301 {
302     unsigned angle1, angle2;
303     bool hflip1, hflip2;
304 
305     transform_GetBasicOps(  (video_transform_t)src, &angle1, &hflip1 );
306     transform_GetBasicOps( transform_Inverse( (video_transform_t)dst ),
307                            &angle2, &hflip2 );
308 
309     int angle = (angle1 + angle2) % 360;
310     bool hflip = hflip1 ^ hflip2;
311 
312     return transform_FromBasicOps(angle, hflip);
313 }
314 
video_format_TransformBy(video_format_t * fmt,video_transform_t transform)315 void video_format_TransformBy( video_format_t *fmt, video_transform_t transform )
316 {
317     /* Get destination orientation */
318     unsigned angle1, angle2;
319     bool hflip1, hflip2;
320 
321     transform_GetBasicOps( transform, &angle1, &hflip1 );
322     transform_GetBasicOps( (video_transform_t)fmt->orientation, &angle2, &hflip2 );
323 
324     unsigned angle = (angle2 - angle1 + 360) % 360;
325     bool hflip = hflip2 ^ hflip1;
326 
327     video_orientation_t dst_orient = ORIENT_NORMAL;
328 
329     if( hflip ) {
330 
331         if( angle == 0 )
332             dst_orient = ORIENT_HFLIPPED;
333         else if( angle == 90 )
334             dst_orient = ORIENT_ANTI_TRANSPOSED;
335         else if( angle == 180 )
336             dst_orient = ORIENT_VFLIPPED;
337         else if( angle == 270 )
338             dst_orient = ORIENT_TRANSPOSED;
339     }
340     else {
341 
342         if( angle == 90 )
343             dst_orient = ORIENT_ROTATED_90;
344         else if( angle == 180 )
345             dst_orient = ORIENT_ROTATED_180;
346         else if( angle == 270 )
347             dst_orient = ORIENT_ROTATED_270;
348     }
349 
350     /* Apply transform */
351     if( ORIENT_IS_SWAP( fmt->orientation ) != ORIENT_IS_SWAP( dst_orient ) )
352     {
353         video_format_t scratch = *fmt;
354 
355         fmt->i_width = scratch.i_height;
356         fmt->i_visible_width = scratch.i_visible_height;
357         fmt->i_height = scratch.i_width;
358         fmt->i_visible_height = scratch.i_visible_width;
359         fmt->i_x_offset = scratch.i_y_offset;
360         fmt->i_y_offset = scratch.i_x_offset;
361         fmt->i_sar_num = scratch.i_sar_den;
362         fmt->i_sar_den = scratch.i_sar_num;
363     }
364 
365     fmt->orientation = dst_orient;
366 }
367 
video_format_TransformTo(video_format_t * restrict fmt,video_orientation_t dst_orientation)368 void video_format_TransformTo( video_format_t *restrict fmt,
369                                video_orientation_t dst_orientation )
370 {
371     video_transform_t transform = video_format_GetTransform(fmt->orientation,
372                                                             dst_orientation);
373     video_format_TransformBy(fmt, transform);
374 }
375 
video_format_ApplyRotation(video_format_t * restrict out,const video_format_t * restrict in)376 void video_format_ApplyRotation( video_format_t *restrict out,
377                                  const video_format_t *restrict in )
378 {
379     *out = *in;
380 
381     video_format_TransformTo(out, ORIENT_NORMAL);
382 }
383 
video_format_IsSimilar(const video_format_t * f1,const video_format_t * f2)384 bool video_format_IsSimilar( const video_format_t *f1,
385                              const video_format_t *f2 )
386 {
387     if( f1->i_chroma != f2->i_chroma )
388         return false;
389 
390     if( f1->i_width != f2->i_width || f1->i_height != f2->i_height ||
391         f1->i_visible_width != f2->i_visible_width ||
392         f1->i_visible_height != f2->i_visible_height ||
393         f1->i_x_offset != f2->i_x_offset || f1->i_y_offset != f2->i_y_offset )
394         return false;
395     if( (int64_t)f1->i_sar_num * f2->i_sar_den !=
396         (int64_t)f2->i_sar_num * f1->i_sar_den )
397         return false;
398 
399     if( f1->orientation != f2->orientation)
400         return false;
401 
402     if( f1->multiview_mode!= f2->multiview_mode )
403        return false;
404 
405     if( f1->i_chroma == VLC_CODEC_RGB15 ||
406         f1->i_chroma == VLC_CODEC_RGB16 ||
407         f1->i_chroma == VLC_CODEC_RGB24 ||
408         f1->i_chroma == VLC_CODEC_RGB32 )
409     {
410         video_format_t v1 = *f1;
411         video_format_t v2 = *f2;
412 
413         video_format_FixRgb( &v1 );
414         video_format_FixRgb( &v2 );
415 
416         if( v1.i_rmask != v2.i_rmask ||
417             v1.i_gmask != v2.i_gmask ||
418             v1.i_bmask != v2.i_bmask )
419             return false;
420     }
421     return true;
422 }
video_format_Print(vlc_object_t * p_this,const char * psz_text,const video_format_t * fmt)423 void video_format_Print( vlc_object_t *p_this,
424                          const char *psz_text, const video_format_t *fmt )
425 {
426     msg_Dbg( p_this,
427              "%s sz %ix%i, of (%i,%i), vsz %ix%i, 4cc %4.4s, sar %i:%i, msk r0x%x g0x%x b0x%x",
428              psz_text,
429              fmt->i_width, fmt->i_height, fmt->i_x_offset, fmt->i_y_offset,
430              fmt->i_visible_width, fmt->i_visible_height,
431              (char*)&fmt->i_chroma,
432              fmt->i_sar_num, fmt->i_sar_den,
433              fmt->i_rmask, fmt->i_gmask, fmt->i_bmask );
434 }
435 
es_format_Init(es_format_t * fmt,int i_cat,vlc_fourcc_t i_codec)436 void es_format_Init( es_format_t *fmt,
437                      int i_cat, vlc_fourcc_t i_codec )
438 {
439     memset(fmt, 0, sizeof (*fmt));
440     fmt->i_cat                  = i_cat;
441     fmt->i_codec                = i_codec;
442     fmt->i_profile              = -1;
443     fmt->i_level                = -1;
444     fmt->i_id                   = -1;
445     fmt->i_priority             = ES_PRIORITY_SELECTABLE_MIN;
446     fmt->psz_language           = NULL;
447     fmt->psz_description        = NULL;
448     fmt->p_extra_languages      = NULL;
449 
450     if (fmt->i_cat == VIDEO_ES)
451         video_format_Init(&fmt->video, 0);
452 
453     fmt->b_packetized           = true;
454     fmt->p_extra                = NULL;
455 }
456 
es_format_InitFromVideo(es_format_t * p_es,const video_format_t * p_fmt)457 void es_format_InitFromVideo( es_format_t *p_es, const video_format_t *p_fmt )
458 {
459     es_format_Init( p_es, VIDEO_ES, p_fmt->i_chroma );
460     video_format_Copy( &p_es->video, p_fmt );
461 }
462 
es_format_Copy(es_format_t * restrict dst,const es_format_t * src)463 int es_format_Copy(es_format_t *restrict dst, const es_format_t *src)
464 {
465     int ret = VLC_SUCCESS;
466 
467     *dst = *src;
468 
469     if (src->psz_language != NULL)
470     {
471         dst->psz_language = strdup(src->psz_language);
472         if (unlikely(dst->psz_language == NULL))
473             ret = VLC_ENOMEM;
474     }
475     if (src->psz_description != NULL)
476     {
477         dst->psz_description = strdup(src->psz_description);
478         if (unlikely(dst->psz_description == NULL))
479             ret = VLC_ENOMEM;
480     }
481 
482     if (src->i_extra > 0)
483     {
484         assert(src->p_extra != NULL);
485         dst->p_extra = malloc( src->i_extra );
486 
487         if( likely(dst->p_extra != NULL) )
488             memcpy(dst->p_extra, src->p_extra, src->i_extra);
489         else
490         {
491             dst->i_extra = 0;
492             ret = VLC_ENOMEM;
493         }
494     }
495     else
496         dst->p_extra = NULL;
497 
498     if (src->i_cat == VIDEO_ES)
499         ret = video_format_Copy( &dst->video, &src->video );
500 
501     if (src->i_cat == SPU_ES)
502     {
503         if (src->subs.psz_encoding != NULL)
504         {
505             dst->subs.psz_encoding = strdup(src->subs.psz_encoding);
506             if (unlikely(dst->subs.psz_encoding == NULL))
507                 ret = VLC_ENOMEM;
508         }
509         if (src->subs.p_style != NULL)
510         {
511             dst->subs.p_style = text_style_Duplicate(src->subs.p_style);
512             if (unlikely(dst->subs.p_style == NULL))
513                 ret = VLC_ENOMEM;
514         }
515     }
516 
517     if (src->i_extra_languages > 0)
518     {
519         assert(src->p_extra_languages != NULL);
520         dst->p_extra_languages = calloc(dst->i_extra_languages,
521                                         sizeof (*dst->p_extra_languages));
522         if (likely(dst->p_extra_languages != NULL))
523         {
524             for (unsigned i = 0; i < dst->i_extra_languages; i++)
525             {
526                 if (src->p_extra_languages[i].psz_language != NULL)
527                     dst->p_extra_languages[i].psz_language = strdup(src->p_extra_languages[i].psz_language);
528                 if (src->p_extra_languages[i].psz_description != NULL)
529                     dst->p_extra_languages[i].psz_description = strdup(src->p_extra_languages[i].psz_description);
530             }
531             dst->i_extra_languages = src->i_extra_languages;
532         }
533         else
534         {
535             dst->i_extra_languages = 0;
536             ret = VLC_ENOMEM;
537         }
538     }
539     return ret;
540 }
541 
es_format_Clean(es_format_t * fmt)542 void es_format_Clean(es_format_t *fmt)
543 {
544     free(fmt->psz_language);
545     free(fmt->psz_description);
546     assert(fmt->i_extra == 0 || fmt->p_extra != NULL);
547     free(fmt->p_extra);
548 
549     if (fmt->i_cat == VIDEO_ES)
550         video_format_Clean( &fmt->video );
551     if (fmt->i_cat == SPU_ES)
552     {
553         free(fmt->subs.psz_encoding);
554 
555         if (fmt->subs.p_style != NULL)
556             text_style_Delete(fmt->subs.p_style);
557     }
558 
559     for (unsigned i = 0; i < fmt->i_extra_languages; i++)
560     {
561         free(fmt->p_extra_languages[i].psz_language);
562         free(fmt->p_extra_languages[i].psz_description);
563     }
564     free(fmt->p_extra_languages);
565 
566     /* es_format_Clean can be called multiple times */
567     es_format_Init(fmt, UNKNOWN_ES, 0);
568 }
569 
es_format_IsSimilar(const es_format_t * p_fmt1,const es_format_t * p_fmt2)570 bool es_format_IsSimilar( const es_format_t *p_fmt1, const es_format_t *p_fmt2 )
571 {
572     if( p_fmt1->i_cat != p_fmt2->i_cat ||
573         vlc_fourcc_GetCodec( p_fmt1->i_cat, p_fmt1->i_codec ) !=
574         vlc_fourcc_GetCodec( p_fmt2->i_cat, p_fmt2->i_codec ) )
575         return false;
576 
577     switch( p_fmt1->i_cat )
578     {
579     case AUDIO_ES:
580     {
581         audio_format_t a1 = p_fmt1->audio;
582         audio_format_t a2 = p_fmt2->audio;
583 
584         if( a1.i_format && a2.i_format && a1.i_format != a2.i_format )
585             return false;
586         if( a1.channel_type != a2.channel_type ||
587             a1.i_rate != a2.i_rate ||
588             a1.i_channels != a2.i_channels ||
589             a1.i_physical_channels != a2.i_physical_channels ||
590             a1.i_chan_mode != a2.i_chan_mode )
591             return false;
592         if( p_fmt1->i_profile != p_fmt2->i_profile )
593             return false;
594         return true;
595     }
596 
597     case VIDEO_ES:
598     {
599         video_format_t v1 = p_fmt1->video;
600         video_format_t v2 = p_fmt2->video;
601         if( !v1.i_chroma )
602             v1.i_chroma = vlc_fourcc_GetCodec( p_fmt1->i_cat, p_fmt1->i_codec );
603         if( !v2.i_chroma )
604             v2.i_chroma = vlc_fourcc_GetCodec( p_fmt2->i_cat, p_fmt2->i_codec );
605         return video_format_IsSimilar( &p_fmt1->video, &p_fmt2->video );
606     }
607 
608     case SPU_ES:
609     default:
610         return true;
611     }
612 }
613 
614