DVBCore  20.3.0
DVBCore Documentation
vtc.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright © 2014 The DTVKit Open Software Foundation Ltd (www.dtvkit.org)
3  * Copyright © 2004 Ocean Blue Software Ltd
4  *
5  * This file is part of a DTVKit Software Component
6  * You are permitted to copy, modify or distribute this file subject to the terms
7  * of the DTVKit 1.0 Licence which can be found in licence.txt or at www.dtvkit.org
8  *
9  * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
10  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
11  * OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * If you or your organisation is not a member of DTVKit then you have access
14  * to this source code outside of the terms of the licence agreement
15  * and you are expected to delete this and any associated files immediately.
16  * Further information on DTVKit, membership and terms can be found at www.dtvkit.org
17  *******************************************************************************/
25 /*******************
26  * INCLUDE FILES *
27  ********************/
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stddef.h>
31 #include <assert.h>
32 
33 #include "techtype.h"
34 #include "dbgfuncs.h"
35 #include "osdtype.h"
36 #include "vtc.h"
37 
38 /*******************
39  * LOCAL MACROS *
40  ********************/
41 
42 /* #define PRINT_STATE */
43 
44 #ifdef PRINT_STATE
45 #define DBG(x) do { STB_SPDebugNoCnWrite x; } while (0)
46 #else
47 #define DBG(x)
48 #endif
49 
50 
51 /*******************
52  * EXPORTED DATA *
53  ********************/
54 
55 /*******************
56  * LOCAL TYPEDEFS *
57  ********************/
58 
59 typedef enum
60 {
61  AFD_PREFERENCE_AUTO,
62  AFD_PREFERENCE_16_9_LB,
63  AFD_PREFERENCE_14_9_LB,
64  AFD_PREFERENCE_CCO
65 } E_AFD_PREFERENCE;
66 
67 typedef enum
68 {
69  MHEG_SCALING_NONE,
70  MHEG_SCALING_QUARTER,
71  MHEG_SCALING_OFFSET,
72  MHEG_SCALING_OTHER,
73 } E_MHEG_SCALING;
74 
75 typedef struct
76 {
77  U8BIT afd;
78  E_ASPECT_RATIO video_aspect_ratio;
79  E_ASPECT_RATIO display_aspect_ratio;
80  E_AFD_PREFERENCE afd_preference;
81  E_FORMAT_CONVERSION transformation;
82 } S_AFD_TRANS;
83 
84 typedef struct s_fraction
85 {
86  S32BIT numerator;
87  S32BIT denominator;
89 
90 
91 /* (a 0 b)
92  (0 c d)
93  (0 0 1)*/
94 typedef struct s_matrix
95 {
96  S_VT_FRACTION a;
97  S_VT_FRACTION b;
98  S_VT_FRACTION c;
99  S_VT_FRACTION d;
100 } S_VT_MATRIX;
101 
102 
103 /* (width ) (left)
104  (height) (top )
105  ( 0 ) ( 1 )*/
106 typedef struct s_fract_rect
107 {
108  S_VT_FRACTION left;
109  S_VT_FRACTION top;
110  S_VT_FRACTION width;
111  S_VT_FRACTION height;
113 
114 typedef struct s_conversion_state
115 {
116  E_AFD_PREFERENCE afd_preference;
117  E_VIDEO_ASPECT_MODE alignment;
118  E_ASPECT_RATIO mheg_aspect_ratio;
119  E_VIDEO_ASPECT_MODE mheg_wam;
120  S_RECTANGLE mheg_scaling_rect;
121  S_RECTANGLE app_scaling_window;
122  S_RECTANGLE hbb_window_rect;
123  BOOLEAN afd_enabled;
124  BOOLEAN hbb_enabled;
125  BOOLEAN mheg_enabled;
126  BOOLEAN mheg_scaling_given;
127  BOOLEAN app_scaling_enabled;
128  BOOLEAN user_pref_changed;
129  BOOLEAN settings_changed;
130  BOOLEAN updating;
131  U16BIT mheg_resolution_width;
132  U16BIT mheg_resolution_height;
133  U16BIT resolution_width;
134  U16BIT resolution_height;
135  U16BIT video_width;
136  U16BIT video_height;
137  U16BIT screen_width;
138  U16BIT screen_height;
139  E_ASPECT_RATIO video_aspect_ratio;
140  E_ASPECT_RATIO display_aspect_ratio;
141  E_STB_AV_DECODER_STATUS decoder_status;
142  U8BIT afd;
143  U8BIT wss;
144  F_VT_NOTIFICATION_CALLBACK video_callback;
145  void *video_callback_userdata;
146  F_VT_NOTIFICATION_CALLBACK userpref_callback;
147  void *userpref_callback_userdata;
148  S_RECTANGLE input_rectangle, output_rectangle;
149  F_VT_CUSTOM_MODE_CALLBACK custom_mode_callback;
151 
152 
153 /*******************
154  * STATIC DATA *
155  ********************/
156 static const S_AFD_TRANS afd_table[] = {
157  { 0, ASPECT_RATIO_4_3, ASPECT_RATIO_16_9, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_PILLAR_BOX },
158  { 0, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_16_9_LB, FORMAT_CONVERSION_LETTERBOX },
159  { 0, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_14_9_LB, FORMAT_CONVERSION_LETTERBOX_14_9 },
160  { 0, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_CCO, FORMAT_CONVERSION_PANSCAN },
161  { 0, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_LETTERBOX },
162 
163  { 1, ASPECT_RATIO_4_3, ASPECT_RATIO_16_9, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_PILLAR_BOX },
164  { 1, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_PANSCAN },
165 
166  { 2, ASPECT_RATIO_4_3, ASPECT_RATIO_16_9, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_ZOOM_4_3 },
167  { 2, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_LETTERBOX },
168 
169  { 3, ASPECT_RATIO_4_3, ASPECT_RATIO_16_9, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_ZOOM_14_9 },
170  { 3, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_16_9_LB, FORMAT_CONVERSION_LETTERBOX_14_9 },
171  { 3, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_CCO, FORMAT_CONVERSION_PANSCAN },
172  { 3, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_LETTERBOX_14_9 },
173 
174  { 5, ASPECT_RATIO_4_3, ASPECT_RATIO_16_9, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_ZOOM_14_9 },
175  { 5, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_PANSCAN },
176  { 5, ASPECT_RATIO_16_9, ASPECT_RATIO_16_9, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_PANSCAN_14_9 },
177 
178  { 6, ASPECT_RATIO_4_3, ASPECT_RATIO_16_9, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_ZOOM_4_3 },
179  { 6, ASPECT_RATIO_4_3, ASPECT_RATIO_4_3, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_CENTRE_14_9 },
180  { 6, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_16_9_LB, FORMAT_CONVERSION_LETTERBOX },
181  { 6, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_14_9_LB, FORMAT_CONVERSION_LETTERBOX_14_9 },
182  { 6, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_CCO, FORMAT_CONVERSION_PANSCAN },
183  { 6, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_LETTERBOX_14_9 },
184 
185  { 7, ASPECT_RATIO_4_3, ASPECT_RATIO_16_9, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_ZOOM_4_3 },
186  { 7, ASPECT_RATIO_4_3, ASPECT_RATIO_4_3, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_CENTRE_4_3 },
187  { 7, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_16_9_LB, FORMAT_CONVERSION_LETTERBOX },
188  { 7, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_14_9_LB, FORMAT_CONVERSION_LETTERBOX_14_9 },
189  { 7, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_CCO, FORMAT_CONVERSION_PANSCAN },
190  { 7, ASPECT_RATIO_16_9, ASPECT_RATIO_4_3, AFD_PREFERENCE_AUTO, FORMAT_CONVERSION_PANSCAN }
191 };
192 
193 /**********************
194  * FUNCTION PROTOTYPES *
195  ***********************/
196 static void Recalculate(S_VT_CONVERSION_STATE *state);
197 static E_MHEG_SCALING MhegScalingType(S_VT_CONVERSION_STATE *state);
198 static BOOLEAN UpdateOnAfdChange(S_VT_CONVERSION_STATE *state);
199 static BOOLEAN RectanglesDiffer(S_RECTANGLE *a, S_RECTANGLE *b);
200 static void CalculateMhegScaling(S_VT_CONVERSION_STATE *state);
201 static void InitRect(S_RECTANGLE *rect, S32BIT left, S32BIT top,
202  S32BIT width, S32BIT height);
203 static U8BIT GetWss(S_VT_CONVERSION_STATE *state);
204 static E_FORMAT_CONVERSION GetVideoTransformation(S_VT_CONVERSION_STATE *state,
205  S_VT_MATRIX *transform,
206  S_VT_MATRIX *clip_transform);
207 static E_FORMAT_CONVERSION GetIframeTransformation(S_VT_CONVERSION_STATE *state,
208  S_VT_MATRIX *transform,
209  S_VT_MATRIX *clip_transform);
210 #ifdef PRINT_STATE
211 static void PrintState(S_VT_CONVERSION_STATE *state);
212 #endif
213 
214 static void ClipRectangle(S_VT_FRACT_RECT *clip_rect, S_VT_FRACT_RECT *rect);
215 static void MultiplyMatrices(S_VT_MATRIX *matrix_a, S_VT_MATRIX *matrix_b, S_VT_MATRIX *output_matrix);
216 static void InvertMatrix(S_VT_MATRIX *matrix, S_VT_MATRIX *inverse);
217 static BOOLEAN ReduceFraction(S_VT_FRACTION *input, S_VT_FRACTION *output);
218 
219 static void AddFractions(S_VT_FRACTION *in_a, S_VT_FRACTION *in_b, S_VT_FRACTION *out);
220 static void SubtractFraction(S_VT_FRACTION *in_a, S_VT_FRACTION *in_b, S_VT_FRACTION *out);
221 static int CompareFractions(S_VT_FRACTION *in_a, S_VT_FRACTION *in_b);
222 
223 static E_FORMAT_CONVERSION FindAfdTransformation(S_VT_CONVERSION_STATE *state);
224 
225 static void ApplyTransformation(S_VT_MATRIX *matrix, S_VT_FRACT_RECT *input,
226  S_VT_FRACT_RECT *output);
227 
228 static void VTC_IdentityMatrix(S_VT_MATRIX *matrix);
229 
230 static void VTC_VideoCsScaling(S_VT_CONVERSION_STATE *state,
231  S_VT_MATRIX *current);
232 
233 static E_FORMAT_CONVERSION VTC_UserPreferenceScaling(S_VT_CONVERSION_STATE *state,
234  S_VT_MATRIX *current);
235 
236 static E_FORMAT_CONVERSION VTC_AfdScaling(S_VT_CONVERSION_STATE *state,
237  S_VT_MATRIX *current);
238 
239 static void VTC_MhegScaling(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *current);
240 
241 static void VTC_HbbScaleToScreen(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *current);
242 
243 static void VTC_AppScaling(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *current);
244 
245 static E_FORMAT_CONVERSION VTC_QuarterScreenScaling(S_VT_CONVERSION_STATE *state,
246  S_VT_MATRIX *current);
247 
248 static void VTC_SceneArScaling(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *current);
249 
250 static void VTC_ToScreen(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *current);
251 
252 #if 0
253 static E_FORMAT_CONVERSION VTC_AppScalingTransform(S_VT_CONVERSION_STATE *state,
254  S_VT_MATRIX *current);
255 #endif
256 
257 static void VTC_ApplyWSS(S_VT_CONVERSION_STATE *state, S_VT_FRACT_RECT *output);
258 
259 static void VTC_TransformRectangles(S_VT_CONVERSION_STATE *state,
260  S_VT_MATRIX *transform,
261  S_VT_MATRIX *clip_transform,
262  S_VT_FRACT_RECT *input_rect,
263  S_VT_FRACT_RECT *output_rect);
264 
265 static void VTC_FractRectangleToRectangle(S_VT_FRACT_RECT *fract_rect,
266  S_RECTANGLE *rectangle);
267 
268 static void VTC_RectangleToFractRectangle(S_RECTANGLE *rectangle,
269  S_VT_FRACT_RECT *fract_rect);
270 
271 static void PrintMatrix(S_VT_MATRIX *matrix);
272 
273 static void PrintFractRect(S_VT_FRACT_RECT *fract_rect);
274 
275 /*Scaling functions*/
276 /*video resolution -> MHEG coordinate space*/
277 static void Scale_352_288_Video(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform);
278 
279 static void Scale_352_576_Video(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform);
280 
281 static void Scale_480_576_Video(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform);
282 
283 static void Scale_544_576_Video(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform);
284 
285 static void Scale_Video(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform);
286 
287 /* presentation coordinate space -> screen resolution*/
288 static void Scale_ToScreen(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform);
289 
290 /* hbbtv coordinate space -> screen resolution*/
291 static void Scale_HbbToScreen(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform);
292 
293 /*AFDs*/
294 static void Scale_Pillarbox(S_VT_CONVERSION_STATE *state, S32BIT width,
295  S32BIT height, S_VT_MATRIX *transform);
296 
297 static void Scale_4_3_Zoom(S_VT_CONVERSION_STATE *state, S32BIT width,
298  S32BIT height, S_VT_MATRIX *transform);
299 
300 static void Scale_14_9_Zoom(S_VT_CONVERSION_STATE *state, S32BIT width,
301  S32BIT height, S_VT_MATRIX *transform);
302 
303 static void Scale_14_9_Centre(S_VT_CONVERSION_STATE *state, S32BIT width,
304  S32BIT height, S_VT_MATRIX *transform);
305 
306 static void Scale_4_3_Centre(S_VT_CONVERSION_STATE *state, S32BIT width,
307  S32BIT height, S_VT_MATRIX *transform);
308 
309 static void Scale_16_9_Letterbox(S_VT_CONVERSION_STATE *state, S32BIT width,
310  S32BIT height, S_VT_MATRIX *transform);
311 
312 static void Scale_14_9_Letterbox(S_VT_CONVERSION_STATE *state, S32BIT width,
313  S32BIT height, S_VT_MATRIX *transform);
314 
315 static void Scale_CentreCutOut(S_VT_CONVERSION_STATE *state, S32BIT width,
316  S32BIT height, S_VT_MATRIX *transform);
317 
318 static void Scale_16_9_Zoom(S_VT_CONVERSION_STATE *state, S32BIT width,
319  S32BIT height, S_VT_MATRIX *transform);
320 
321 static void UpdateResolution(S_VT_CONVERSION_STATE *state);
322 
323 /* MHEG scaling and positioning */
324 static void MhegScaling(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform);
325 
326 static void HbbScaling(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform);
327 
328 /* Application scaling and positioning */
329 static void AppScaling(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform);
330 
331 /*1:1 scaling, for use in some default cases*/
332 static void NoScaling(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform);
333 
334 /* Create a new fraction */
335 static S_VT_FRACTION MakeFraction(S32BIT numerator, S32BIT denominator);
336 
337 static S_VT_FRACT_RECT MakeRectangle(S32BIT left, S32BIT top, S32BIT width, S32BIT height);
338 
339 /***********************
340  * FUNCTION DEFINITIONS *
341  ************************/
342 
343 /*!**************************************************************************
344  * @brief Open video transformation manager
345  * @param options - transformation manager options
346  * @return Pointer to manager context, NULL if cannot be created
347  ****************************************************************************/
348 void* VT_Open(S_VT_OPTIONS *options)
349 {
350  S_VT_CONVERSION_STATE *new_state;
351 
352  new_state = malloc(sizeof *new_state);
353  if (new_state != NULL)
354  {
355  new_state->mheg_enabled = options->mheg_required;
356  new_state->afd_enabled = options->afd_required;
357  new_state->hbb_enabled = options->hbbtv_required;
358 
359  new_state->afd_preference = AFD_PREFERENCE_AUTO;
360  new_state->alignment = ASPECT_MODE_AUTO;
361  new_state->afd = 0;
362  new_state->mheg_aspect_ratio = ASPECT_UNDEFINED;
363  new_state->mheg_wam = ASPECT_MODE_4_3;
364 
365  InitRect(&new_state->mheg_scaling_rect, 0, 0, SD_WIDTH, SD_HEIGHT);
366  new_state->mheg_resolution_width = SD_WIDTH;
367  new_state->mheg_resolution_height = SD_HEIGHT;
368  new_state->mheg_scaling_given = FALSE;
369 
370  InitRect(&new_state->app_scaling_window, 0, 0, SD_WIDTH, SD_HEIGHT);
371  new_state->app_scaling_enabled = FALSE;
372 
373  InitRect(&new_state->hbb_window_rect, 0, 0, HD_WIDTH, HD_HEIGHT);
374 
375  new_state->resolution_width = SD_WIDTH;
376  new_state->resolution_height = SD_HEIGHT;
377 
378  new_state->video_width = SD_WIDTH;
379  new_state->video_height = SD_HEIGHT;
380 
381  new_state->screen_width = SD_WIDTH;
382  new_state->screen_height = SD_HEIGHT;
383 
384  new_state->video_aspect_ratio = ASPECT_RATIO_4_3;
385  new_state->display_aspect_ratio = ASPECT_RATIO_16_9;
386 
387  new_state->wss = 0;
388 
389  new_state->decoder_status = DECODER_STATUS_NONE;
390 
391  new_state->video_callback = NULL;
392  new_state->video_callback_userdata = NULL;
393  new_state->userpref_callback = NULL;
394  new_state->userpref_callback_userdata = NULL;
395  new_state->user_pref_changed = FALSE;
396  new_state->custom_mode_callback = NULL;
397 
398  new_state->settings_changed = FALSE;
399  new_state->updating = FALSE;
400 
401  InitRect(&new_state->input_rectangle, 0, 0, SD_WIDTH, SD_HEIGHT);
402  InitRect(&new_state->output_rectangle, 0, 0, SD_WIDTH, SD_HEIGHT);
403  }
404 
405  return new_state;
406 }
407 
408 /*!**************************************************************************
409  * @brief Close video transformation manager
410  * @param context - transformation calculator context
411  ****************************************************************************/
412 void VT_Close(void *context)
413 {
414  ASSERT(context != NULL);
415 
416  free(context);
417 }
418 
419 /*!**************************************************************************
420  * @brief Enable or disable transformation calculations
421  * @param context - transformation calculator context
422  * @param enable - TRUE if calculations are enabled, FALSE otherwise
423  ****************************************************************************/
424 void VT_Enable(void *context, BOOLEAN enable)
425 {
426  S_VT_CONVERSION_STATE *state;
427 
428  ASSERT(context != NULL);
429 
430  state = context;
431  if (state->updating != enable)
432  {
433  state->updating = enable;
434  if ((enable) && (state->settings_changed))
435  {
436  Recalculate(state);
437  }
438  }
439 }
440 
441 /*!**************************************************************************
442  * @brief Set current AFD (active format descriptor value)
443  * @param context - transformation calculator context
444  * @param afd_value - AFD value
445  ****************************************************************************/
446 void VT_SetAfd(void *context, U8BIT afd_value)
447 {
448  S_VT_CONVERSION_STATE *state;
449 
450  ASSERT(context != NULL);
451 
452  state = context;
453  if (state->afd != afd_value)
454  {
455  state->afd = afd_value;
456  state->settings_changed = TRUE;
457  if ((state->updating) && (UpdateOnAfdChange(state)))
458  {
459  Recalculate(state);
460  }
461  }
462 }
463 
464 /*!**************************************************************************
465  * @brief Set video aspect ratio
466  * @param context - transformation calculator context
467  * @param aspect_ratio - video aspect ratio
468  ****************************************************************************/
469 void VT_SetVideoAspectRatio(void *context, E_ASPECT_RATIO aspect_ratio)
470 {
471  S_VT_CONVERSION_STATE *state;
472 
473  ASSERT(context != NULL);
474 
475  state = context;
476  if (state->video_aspect_ratio != aspect_ratio)
477  {
478  state->video_aspect_ratio = aspect_ratio;
479  state->settings_changed = TRUE;
480  if (state->updating)
481  {
482  Recalculate(state);
483  }
484  }
485 }
486 
487 /*!**************************************************************************
488  * @brief Get video aspect ratio
489  * @param context - transformation calculator context
490  * @return aspect_ratio - video aspect ratio
491  ****************************************************************************/
492 E_ASPECT_RATIO VT_GetVideoAspectRatio(void *context)
493 {
494  S_VT_CONVERSION_STATE *state;
495  E_ASPECT_RATIO aspect_ratio;
496 
497  ASSERT(context != NULL);
498 
499  state = context;
500  aspect_ratio = state->video_aspect_ratio;
501 
502  return aspect_ratio;
503 }
504 
505 /*!**************************************************************************
506  * @brief Set MHEG-5 aspect ratio
507  * @param context - transformation calculator context
508  * @param aspect_ratio - MHEG5 scene aspect ratio
509  ****************************************************************************/
510 void VT_SetMhegAspectRatio(void *context, E_ASPECT_RATIO aspect_ratio)
511 {
512  S_VT_CONVERSION_STATE *state;
513 
514  ASSERT(context != NULL);
515 
516  state = context;
517  if (state->mheg_aspect_ratio != aspect_ratio)
518  {
519  state->mheg_aspect_ratio = aspect_ratio;
520  state->settings_changed = TRUE;
521  if ((state->updating) && (state->mheg_enabled))
522  {
523  Recalculate(state);
524  }
525  }
526 }
527 
528 /*!**************************************************************************
529  * @brief Get display aspect ratio
530  * @param context - transformation calculator context
531  * @return E_ASPECT_RATIO of display
532  ****************************************************************************/
533 E_ASPECT_RATIO VT_GetDisplayAspectRatio(void *context)
534 {
535  S_VT_CONVERSION_STATE *state;
536 
537  ASSERT(context != NULL);
538 
539  state = context;
540  return state->display_aspect_ratio;
541 }
542 
543 /*!**************************************************************************
544  * @brief Set display aspect ratio
545  * @param context - transformation calculator context
546  * @param aspect_ratio - video aspect ratio
547  ****************************************************************************/
548 void VT_SetDisplayAspectRatio(void *context, E_ASPECT_RATIO aspect_ratio)
549 {
550  S_VT_CONVERSION_STATE *state;
551 
552  ASSERT(context != NULL);
553 
554  state = context;
555  if (state->display_aspect_ratio != aspect_ratio)
556  {
557  state->display_aspect_ratio = aspect_ratio;
558  state->settings_changed = TRUE;
559  if (state->updating)
560  {
561  Recalculate(state);
562  }
563  }
564 }
565 
566 /*!**************************************************************************
567  * @brief Set user preference for video aspect ratio alignment
568  *
569  * @param context - transformation calculator context
570  * @param alignment - New video alignment preference:
571  ****************************************************************************/
572 void VT_SetVideoAlignmentPref(void *context, E_VIDEO_ASPECT_MODE alignment)
573 {
574  S_VT_CONVERSION_STATE *state;
575 
576  ASSERT(context != NULL);
577  state = context;
578  if (state->alignment != alignment)
579  {
580  if (state->display_aspect_ratio == ASPECT_RATIO_4_3)
581  {
582  switch (alignment)
583  {
584  default:
585  case ASPECT_MODE_16_9:
586  state->afd_preference = AFD_PREFERENCE_16_9_LB;
587  break;
588 
589  case ASPECT_MODE_ZOOM:
590  case ASPECT_MODE_4_3:
591  state->afd_preference = AFD_PREFERENCE_CCO;
592  break;
593 
594  case ASPECT_MODE_14_9:
595  state->afd_preference = AFD_PREFERENCE_14_9_LB;
596  break;
597  }
598  }
599  else
600  {
601  state->afd_preference = AFD_PREFERENCE_AUTO;
602  }
603  state->alignment = alignment;
604  state->user_pref_changed = TRUE;
605  state->settings_changed = TRUE;
606  if (state->updating)
607  {
608  Recalculate(state);
609  }
610  }
611 }
612 
614 {
615  S_VT_CONVERSION_STATE *state;
616 
617  ASSERT(context != NULL);
618 
619  state = context;
620  state->custom_mode_callback = callback;
621  if (state->updating)
622  {
623  Recalculate(state);
624  }
625 }
626 
627 /*!**************************************************************************
628  * @brief Set MHEG5 scaling resolution
629  * @param context - transformation calculator context
630  * @param width
631  * @param height
632  ****************************************************************************/
633 void VT_SetMhegScalingResolution(void *context, U16BIT width, U16BIT height)
634 {
635  S_VT_CONVERSION_STATE *state;
636 
637  ASSERT(context != NULL);
638 
639  state = context;
640 
641  state->mheg_resolution_width = width;
642  state->mheg_resolution_height = height;
643  if (state->mheg_enabled)
644  {
645  state->resolution_width = width;
646  state->resolution_height = height;
647  }
648 }
649 
650 /*!**************************************************************************
651  * @brief Set MHEG-5 scaling information
652  * @param context - transformation calculator context
653  * @param scaling - scaling and positioning transformation
654  * @note When scaling is NULL, scaling is ignored and the behaviour will
655  * be as if full screen video is mapped to the full screen.
656  ****************************************************************************/
657 void VT_SetMhegScaling(void *context, S_RECTANGLE *scaling)
658 {
659  S_VT_CONVERSION_STATE *state;
660 
661  ASSERT(context != NULL);
662 
663  state = context;
664  if (scaling == NULL)
665  {
666  state->mheg_scaling_given = FALSE;
667  }
668  else
669  {
670  state->mheg_scaling_given = TRUE;
671  state->mheg_scaling_rect = *scaling;
672  }
673  state->settings_changed = TRUE;
674  if ((state->updating) && (state->mheg_enabled))
675  {
676  Recalculate(state);
677  }
678 }
679 
680 /*!**************************************************************************
681  * @brief Set application scaling information
682  * @param context - transformation calculator context
683  * @param window - output window (screen CS)
684  * @note When window is NULL, application scaling is turned off
685  ****************************************************************************/
686 void VT_SetAppScaling(void *context, S_RECTANGLE *window)
687 {
688  S_VT_CONVERSION_STATE *state;
689 
690  ASSERT(context != NULL);
691 
692  state = context;
693 
694  if (window == NULL)
695  {
696  state->app_scaling_enabled = FALSE;
697  }
698  else
699  {
700  state->app_scaling_enabled = TRUE;
701  state->app_scaling_window = *window;
702  }
703  UpdateResolution(state);
704  state->settings_changed = TRUE;
705  if (state->updating)
706  {
707  Recalculate(state);
708  }
709 }
710 
711 /*!**************************************************************************
712  * @brief Set video resolution
713  * @param context - transformation calculator context
714  * @param width - video width (in pixels)
715  * @param height - video height (in pixels)
716  ****************************************************************************/
717 void VT_SetVideoResolution(void *context, U16BIT width, U16BIT height)
718 {
719  S_VT_CONVERSION_STATE *state;
720 
721  ASSERT(context != NULL);
722 
723  state = context;
724  if ((state->video_width != width) ||
725  (state->video_height != height))
726  {
727  state->video_width = width;
728  state->video_height = height;
729  state->settings_changed = TRUE;
730 
731  if (state->updating)
732  {
733  Recalculate(state);
734  }
735  }
736 }
737 
738 /*!**************************************************************************
739  * @brief Set screen resolution
740  * @param context - transformation calculator context
741  * @param width - screen width (in pixels)
742  * @param height - screen height (in pixels)
743  ****************************************************************************/
744 void VT_SetScreenResolution(void *context, U16BIT width, U16BIT height)
745 {
746  S_VT_CONVERSION_STATE *state;
747 
748  ASSERT(context != NULL);
749 
750  state = context;
751  if ((state->screen_width != width) ||
752  (state->screen_height != height))
753  {
754  state->screen_width = width;
755  state->screen_height = height;
756  state->settings_changed = TRUE;
757 
758  if (state->updating)
759  {
760  Recalculate(state);
761  }
762  }
763 }
764 
765 /*!**************************************************************************
766  * @brief Set widescreeen alignment mode for MHEG-5
767  * @param context - transformation calculator context
768  * @param wam - widescreen alignment mode
769  ****************************************************************************/
770 void VT_SetMhegVideoAlignment(void *context, E_VIDEO_ASPECT_MODE mode)
771 {
772  S_VT_CONVERSION_STATE *state;
773 
774  ASSERT(context != NULL);
775 
776  state = context;
777  state->mheg_wam = mode;
778  state->settings_changed = TRUE;
779  if (state->updating && state->mheg_enabled)
780  {
781  Recalculate(state);
782  }
783 }
784 
785 /*!**************************************************************************
786  * @brief Set profile to apply MHEG5 option
787  * @param context - transformation calculator context
788  * @param enable - TRUE turns MHEG5 option on
789  ****************************************************************************/
790 void VT_SetProfileMheg5(void *context, BOOLEAN enable)
791 {
792  S_VT_CONVERSION_STATE *state;
793 
794  ASSERT(context != NULL);
795 
796  state = context;
797  state->mheg_enabled = enable;
798  state->settings_changed = TRUE;
799  UpdateResolution(state);
800  if (state->updating)
801  {
802  Recalculate(state);
803  }
804 }
805 
806 /*!**************************************************************************
807  * @brief Set profile to apply HBBTV option
808  * @param context - transformation calculator context
809  * @param enable - TRUE turns HBBTV option on
810  ****************************************************************************/
811 void VT_SetProfileHbbtv(void *context, BOOLEAN enable)
812 {
813  S_VT_CONVERSION_STATE *state;
814 
815  ASSERT(context != NULL);
816 
817  state = context;
818  state->hbb_enabled = enable;
819  state->settings_changed = TRUE;
820  UpdateResolution(state);
821  if (state->updating)
822  {
823  Recalculate(state);
824  }
825 }
826 
827 /*!**************************************************************************
828  * @brief Set HBBTV output window
829  * @param context - transformation calculator context
830  * @param output - window
831  ****************************************************************************/
832 void VT_SetHbbtvWindow(void *context, S_RECTANGLE *output)
833 {
834  S_VT_CONVERSION_STATE *state;
835 
836  ASSERT(context != NULL);
837 
838  state = context;
839  if (output == NULL)
840  {
841  state->hbb_window_rect.top = 0;
842  state->hbb_window_rect.left = 0;
843  state->hbb_window_rect.width = HD_WIDTH;
844  state->hbb_window_rect.height = HD_HEIGHT;
845  }
846  else
847  {
848  state->hbb_window_rect = *output;
849  }
850  state->settings_changed = TRUE;
851  if ((state->updating) && (state->hbb_enabled))
852  {
853  Recalculate(state);
854  }
855 }
856 
857 /*!**************************************************************************
858  * @brief Get the current video transfromation rectangles
859  * @param context - transformation calculator context
860  * @param input_rect - input rectangle for transformation
861  * @param output_rect - output rectangle for transformation
862  ****************************************************************************/
863 void VT_GetVideoTransformation(void *context, S_RECTANGLE *input_rect,
864  S_RECTANGLE *output_rect)
865 {
866  S_VT_CONVERSION_STATE *state;
867 
868  ASSERT(context != NULL);
869  state = context;
870  *input_rect = state->input_rectangle;
871  *output_rect = state->output_rectangle;
872 }
873 
874 /*!**************************************************************************
875  * @brief Return WSS (wide-screen signalling) value
876  * @param context - transformation calculator context
877  * @param wss - WSS value
878  ****************************************************************************/
879 void VT_GetWss(void *context, U8BIT *wss)
880 {
881  S_VT_CONVERSION_STATE *state;
882 
883  ASSERT(context != NULL);
884  state = context;
885  *wss = state->wss;
886 }
887 
888 /*!**************************************************************************
889  * @brief Set video change callback
890  *
891  * The callback is called whenever the video transformation is changed
892  * for any reason.
893  *
894  * @param context - transformation calculator context
895  * @param callback - the callback to call
896  * @param user_data - user data to pass to the callback
897  ****************************************************************************/
898 void VT_SetVideoChangedCallback(void *context,
899  F_VT_NOTIFICATION_CALLBACK callback,
900  void *user_data)
901 {
902  S_VT_CONVERSION_STATE *state;
903 
904  ASSERT(context != NULL);
905 
906  state = context;
907  state->video_callback = callback;
908  state->video_callback_userdata = user_data;
909 }
910 
911 /*!**************************************************************************
912  * @brief Set user preference change callback
913  *
914  * The callback is called whenever the video transformation changes as
915  * a result of a change in user preferences.
916  *
917  * @param context - transformation calculator context
918  * @param callback - the callback to call
919  * @param user_data - user data to pass to the callback
920  ****************************************************************************/
922  F_VT_NOTIFICATION_CALLBACK callback,
923  void *user_data)
924 {
925  S_VT_CONVERSION_STATE *state;
926 
927  ASSERT(context != NULL);
928 
929  state = context;
930  state->userpref_callback = callback;
931  state->userpref_callback_userdata = user_data;
932 }
933 
934 /*!**************************************************************************
935  * @brief Return the current decoder format conversion
936  * @param context - transformation calculator context
937  * @return Decoder format conversion
938  ****************************************************************************/
939 E_FORMAT_CONVERSION VT_GetDecoderFormatConversion(void *context)
940 {
941  E_FORMAT_CONVERSION format_conversion;
942  S_VT_MATRIX transform, clip_transform;
943 
944  ASSERT(context != NULL);
945 
946  VTC_IdentityMatrix(&transform);
947  VTC_IdentityMatrix(&clip_transform);
948  format_conversion = GetVideoTransformation(context, &transform,
949  &clip_transform);
950 
951  return format_conversion;
952 }
953 
954 /*!**************************************************************************
955  * @brief Return the current screen resolution
956  * @param context - transformation calculator context
957  * @param width - screen width
958  * @param height - screen height
959  ****************************************************************************/
960 void VT_GetScreenResolution(void *context, U16BIT *width, U16BIT *height)
961 {
962  S_VT_CONVERSION_STATE *state;
963 
964  ASSERT(context != NULL);
965  state = context;
966 
967  *width = state->screen_width;
968  *height = state->screen_height;
969 }
970 
971 /*!**************************************************************************
972  * @brief Return the current video resolution
973  * @param context - transformation calculator context
974  * @param width - video width
975  * @param height - video height
976  ****************************************************************************/
977 void VT_GetVideoResolution(void *context, U16BIT *width, U16BIT *height)
978 {
979  S_VT_CONVERSION_STATE *state;
980 
981  ASSERT(context != NULL);
982  state = context;
983 
984  if ((state->video_width <= SD_WIDTH) || (state->video_height <= SD_HEIGHT))
985  {
986  *width = SD_WIDTH;
987  *height = SD_HEIGHT;
988  }
989  else if (state->video_height < FULL_HD_HEIGHT)
990  {
991  *width = state->video_width;
992  *height = HD_HEIGHT;
993  }
994  else
995  {
996  *width = state->video_width;
997  *height = FULL_HD_HEIGHT;
998  }
999 }
1000 
1001 /*!**************************************************************************
1002  * @brief Check if osd must be scaled due to MHEG scene aspect ratio
1003  *
1004  * @param context - transformation calculator context
1005  * @return TRUE if osd scaling is required, FALSE otherwise
1006  ****************************************************************************/
1007 BOOLEAN VT_IsOsdScaled(void *context)
1008 {
1009  S_VT_CONVERSION_STATE *state;
1010 
1011  ASSERT(context != NULL);
1012  state = context;
1013  if (state->display_aspect_ratio == ASPECT_RATIO_16_9 &&
1014  state->mheg_aspect_ratio == ASPECT_RATIO_4_3)
1015  {
1016  return TRUE;
1017  }
1018  else
1019  {
1020  return FALSE;
1021  }
1022 }
1023 
1024 /*!**************************************************************************
1025  * @brief Set the decoder status
1026  * @param context - transformation calculator context
1027  * @param status - New decoder status
1028  ****************************************************************************/
1029 void VT_SetDecoderStatus(void *context, E_STB_AV_DECODER_STATUS status)
1030 {
1031  S_VT_CONVERSION_STATE *state;
1032 
1033  ASSERT(context != NULL);
1034  state = context;
1035  state->decoder_status = status;
1036  state->settings_changed = TRUE;
1037 
1038  if (state->updating)
1039  {
1040  Recalculate(state);
1041  }
1042 }
1043 
1044 /*!**************************************************************************
1045  * @brief Get the decoder status
1046  * @param context - transformation calculator context
1047  * @return The decoder status
1048  ****************************************************************************/
1049 E_STB_AV_DECODER_STATUS VT_GetDecoderStatus(void *context)
1050 {
1051  S_VT_CONVERSION_STATE *state;
1052 
1053  ASSERT(context != NULL);
1054  state = context;
1055 
1056  return state->decoder_status;
1057 }
1058 
1059 /*!**************************************************************************
1060  * @brief Find the type of scaling specified by the MHEG application, if any
1061  *
1062  * @param state - transformation calculator state
1063  * @return MHEG_SCALING_QUARTER if video should be quarter-screen,
1064  * MHEG_SCALING_NONE if video is not scaled
1065  * MHEG_SCALING_OTHER for any other scaling
1066  ****************************************************************************/
1067 static E_MHEG_SCALING MhegScalingType(S_VT_CONVERSION_STATE *state)
1068 {
1069  S_RECTANGLE *scaling = &state->mheg_scaling_rect;
1070 
1071  if ((scaling->width == state->mheg_resolution_width / 2) && (scaling->height == state->mheg_resolution_height / 2))
1072  {
1073  return MHEG_SCALING_QUARTER;
1074  }
1075  else if ((scaling->width == state->mheg_resolution_width) && (scaling->height == state->mheg_resolution_height))
1076  {
1077  if ((scaling->top == 0) && (scaling->left == 0))
1078  {
1079  return MHEG_SCALING_NONE;
1080  }
1081  else
1082  {
1083  return MHEG_SCALING_OFFSET;
1084  }
1085  }
1086  else
1087  {
1088  return MHEG_SCALING_OTHER;
1089  }
1090 }
1091 
1092 /*!**************************************************************************
1093  * @brief Check if there will be an update when the AFD changes
1094  *
1095  * AFD changes do not affect the transformation if:
1096  * 1. AFD support is enabled
1097  * 2. The MHEG-5 scene aspect ratio is unspecified
1098  * 3. The video is not transformed in any way
1099  * 4. User preferences are on AUTO
1100  *
1101  * If MHEG-5 is not active, conditions #2 and #3 are always true.
1102  *
1103  * @param state - transformation calculator state
1104  * @return TRUE if AFD changes affect updates, FALSE otherwise
1105  ****************************************************************************/
1106 static BOOLEAN UpdateOnAfdChange(S_VT_CONVERSION_STATE *state)
1107 {
1108  if (!state->afd_enabled)
1109  {
1110  return FALSE;
1111  }
1112 
1113  if (state->mheg_enabled)
1114  {
1115  /* Check that SceneAR=None, not scaling/positioning and pref=Auto */
1116  if (state->mheg_aspect_ratio == ASPECT_UNDEFINED &&
1117  MhegScalingType(state) == MHEG_SCALING_NONE &&
1118  state->alignment == ASPECT_MODE_AUTO)
1119  {
1120  return TRUE;
1121  }
1122  }
1123  else
1124  {
1125  if (state->alignment == ASPECT_MODE_AUTO)
1126  {
1127  return TRUE;
1128  }
1129  }
1130 
1131  return FALSE;
1132 }
1133 
1134 /*!**************************************************************************
1135  * @fn
1136  * @brief
1137  *
1138  * @param
1139  *
1140  *
1141  *
1142  * @return
1143  *
1144  *
1145  * @warning
1146  * @bug
1147  ****************************************************************************/
1148 static E_FORMAT_CONVERSION AfdOrUserPreferenceTransform(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *current)
1149 {
1150  E_FORMAT_CONVERSION transform;
1151 
1152  if (state->alignment == ASPECT_MODE_AUTO)
1153  {
1154  transform = VTC_AfdScaling(state, current);
1155  }
1156  else
1157  {
1158  transform = VTC_UserPreferenceScaling(state, current);
1159  }
1160 
1161  return transform;
1162 }
1163 
1164 /*!**************************************************************************
1165  * @brief Recalculate video transformation
1166  * @param state - current state of the system
1167  ****************************************************************************/
1168 static void Recalculate(S_VT_CONVERSION_STATE *state)
1169 {
1170  S_VT_MATRIX transform, clip_transform;
1171  U8BIT temp_wss;
1172  S_RECTANGLE input_rectangle, output_rectangle;
1173  S_VT_FRACT_RECT input, output;
1174  BOOLEAN changed;
1175 
1176  CalculateMhegScaling(state);
1177 
1178  #ifdef PRINT_STATE
1179  PrintState(state);
1180  #endif
1181 
1182  input_rectangle.top = 0;
1183  input_rectangle.left = 0;
1184  input_rectangle.width = state->video_width;
1185  input_rectangle.height = state->video_height;
1186 
1187  temp_wss = GetWss(state);
1188 
1189  VTC_IdentityMatrix(&transform);
1190  VTC_IdentityMatrix(&clip_transform);
1191 
1192  if (state->decoder_status == DECODER_STATUS_VIDEO)
1193  {
1194  GetVideoTransformation(state, &transform, &clip_transform);
1195  }
1196  else if (state->decoder_status == DECODER_STATUS_IFRAME)
1197  {
1198  GetIframeTransformation(state, &transform, &clip_transform);
1199  }
1200 
1201  VTC_RectangleToFractRectangle(&input_rectangle, &input);
1202 
1203  /* Apply the transformation on input/output rectangles */
1204  DBG(("Clip transform:\n"));
1205  PrintMatrix(&clip_transform);
1206 
1207  VTC_TransformRectangles(state, &transform, &clip_transform, &input, &output);
1208 
1209  /* Apply "WSS" transformation, if required */
1210  VTC_ApplyWSS(state, &output);
1211 
1212  VTC_FractRectangleToRectangle(&input, &input_rectangle);
1213  VTC_FractRectangleToRectangle(&output, &output_rectangle);
1214 
1215  /* Check if the transformation has changed */
1216  changed = FALSE;
1217  if ((RectanglesDiffer(&input_rectangle, &state->input_rectangle)) ||
1218  (RectanglesDiffer(&output_rectangle, &state->output_rectangle)))
1219  {
1220  changed = TRUE;
1221  }
1222 
1223  state->input_rectangle = input_rectangle;
1224  state->output_rectangle = output_rectangle;
1225  state->wss = temp_wss;
1226 
1227  if (state->video_callback != NULL)
1228  {
1229  state->video_callback(state->video_callback_userdata);
1230  }
1231 
1232  DBG(("user_pref_changed = %d, changed = %d\n",
1233  state->user_pref_changed, changed));
1234  if (state->user_pref_changed && state->userpref_callback != NULL && changed)
1235  {
1236  DBG(("Calling userpref changed callback\n"));
1237  state->userpref_callback(state->userpref_callback_userdata);
1238  }
1239 
1240  state->user_pref_changed = FALSE;
1241  state->settings_changed = FALSE;
1242 }
1243 
1244 /*!**************************************************************************
1245  * @brief Calculate the transformation for the video using the data set in
1246  * the state
1247  *
1248  * @param state - current state of the system
1249  * @param transform - The tranformation matrix
1250  * @param clip_transform - Transformation matrix for clipping region
1251  * @return The transformation type that was chosen
1252  ****************************************************************************/
1253 static E_FORMAT_CONVERSION GetVideoTransformation(S_VT_CONVERSION_STATE *state,
1254  S_VT_MATRIX *transform,
1255  S_VT_MATRIX *clip_transform)
1256 {
1257  E_FORMAT_CONVERSION transform_type;
1258 
1259  transform_type = FORMAT_CONVERSION_IGNORE;
1260 
1261  DBG(("Initial transformation:\n"));
1262  PrintMatrix(transform);
1263 
1264  VTC_VideoCsScaling(state, transform);
1265  DBG(("VTC_VideoCsScaling:\n"));
1266  PrintMatrix(transform);
1267 
1268  if (state->app_scaling_enabled)
1269  {
1270  /* Apply application scaling transformation */
1271  transform_type = AfdOrUserPreferenceTransform(state, transform);
1272  DBG(("AppScalingTransform:\n"));
1273  PrintMatrix(transform);
1274 
1275  VTC_AppScaling(state, transform);
1276  VTC_AppScaling(state, clip_transform);
1277  DBG(("VTC_AppScaling:\n"));
1278  PrintMatrix(transform);
1279  }
1280  else if (state->hbb_enabled)
1281  {
1282  VTC_HbbScaleToScreen(state, transform);
1283  VTC_HbbScaleToScreen(state, clip_transform);
1284  DBG(("VTC_HbbScaleToScreen:\n"));
1285  PrintMatrix(transform);
1286  }
1287  else
1288  {
1289  if (state->mheg_enabled)
1290  {
1291  if (MhegScalingType(state) == MHEG_SCALING_QUARTER)
1292  {
1293  transform_type = VTC_QuarterScreenScaling(state, transform);
1294  }
1295  else if (state->mheg_aspect_ratio == ASPECT_UNDEFINED)
1296  {
1297  if ((MhegScalingType(state) == MHEG_SCALING_NONE) ||
1298  (MhegScalingType(state) == MHEG_SCALING_OFFSET))
1299  {
1300  transform_type = AfdOrUserPreferenceTransform(state, transform);
1301  DBG(("AfdOrUserPreferenceTransform:\n"));
1302  PrintMatrix(transform);
1303  }
1304  }
1305  else
1306  {
1307  VTC_SceneArScaling(state, transform);
1308  DBG(("VTC_SceneArScaling:\n"));
1309  PrintMatrix(transform);
1310  }
1311 
1312  VTC_MhegScaling(state, transform);
1313  VTC_MhegScaling(state, clip_transform);
1314  DBG(("VTC_MhegScaling:\n"));
1315  PrintMatrix(transform);
1316  }
1317  else
1318  {
1319  transform_type = AfdOrUserPreferenceTransform(state, transform);
1320  DBG(("AfdOrUserPreferenceTransform:\n"));
1321  PrintMatrix(transform);
1322  }
1323 
1324  /* Transform from presentation coordinates back to screen coordinates */
1325  VTC_ToScreen(state, transform);
1326  VTC_ToScreen(state, clip_transform);
1327  DBG(("VTC_ToScreen:\n"));
1328  PrintMatrix(transform);
1329  }
1330 
1331  return transform_type;
1332 }
1333 
1334 /*!**************************************************************************
1335  * @brief Calculate the transformation for the I-Frame using the data set
1336  * in the state
1337  *
1338  * @param state - current state of the system
1339  * @param transform - The tranformation matrix
1340  * @param clip_transform - Transformation matrix for clipping region
1341  * @return The transformation type that was chosen
1342  ****************************************************************************/
1343 static E_FORMAT_CONVERSION GetIframeTransformation(S_VT_CONVERSION_STATE *state,
1344  S_VT_MATRIX *transform,
1345  S_VT_MATRIX *clip_transform)
1346 {
1347  E_FORMAT_CONVERSION transform_type;
1348 
1349  transform_type = FORMAT_CONVERSION_IGNORE;
1350 
1351  DBG(("Initial transformation:\n"));
1352  PrintMatrix(transform);
1353 
1354  VTC_VideoCsScaling(state, transform);
1355  DBG(("VTC_VideoCsScaling:\n"));
1356  PrintMatrix(transform);
1357 
1358  if (state->mheg_enabled)
1359  {
1360  VTC_MhegScaling(state, transform);
1361  DBG(("VTC_MhegScaling:\n"));
1362  PrintMatrix(transform);
1363  }
1364 
1365  /* Compose a transformation from the presentation coordinates to screen coordinates with the
1366  current transformation */
1367  VTC_ToScreen(state, transform);
1368  VTC_ToScreen(state, clip_transform);
1369  DBG(("VTC_ToScreen:\n"));
1370  PrintMatrix(transform);
1371 
1372  return transform_type;
1373 }
1374 
1375 /*!**************************************************************************
1376  * @brief Calculate MHEG-5 scaling transformation given input and output
1377  * @param state - conversion state
1378  ****************************************************************************/
1379 static void CalculateMhegScaling(S_VT_CONVERSION_STATE *state)
1380 {
1381  if (!state->mheg_scaling_given)
1382  {
1383  InitRect(&state->mheg_scaling_rect, 0, 0, state->mheg_resolution_width, state->mheg_resolution_height);
1384  }
1385 }
1386 
1387 /*!**************************************************************************
1388  * @brief Check if two rectangles are different
1389  *
1390  * @param a - first rectange
1391  * @param b - second rectangle
1392  * @return TRUE if rectangles are different, FALSE if they are the same
1393  ****************************************************************************/
1394 static BOOLEAN RectanglesDiffer(S_RECTANGLE *a, S_RECTANGLE *b)
1395 {
1396  if (a->left != b->left)
1397  {
1398  return TRUE;
1399  }
1400  if (a->top != b->top)
1401  {
1402  return TRUE;
1403  }
1404  if (a->width != b->width)
1405  {
1406  return TRUE;
1407  }
1408  if (a->height != b->height)
1409  {
1410  return TRUE;
1411  }
1412  return FALSE;
1413 }
1414 
1415 /*!**************************************************************************
1416  * @brief Initialise rectangle
1417  * @param rect - rectangle to initialise
1418  * @param left - left position
1419  * @param top - top position
1420  * @param width - rectangle width
1421  * @param height - rectangle height
1422  ****************************************************************************/
1423 static void InitRect(S_RECTANGLE *rect, S32BIT left, S32BIT top,
1424  S32BIT width, S32BIT height)
1425 {
1426  rect->left = left;
1427  rect->top = top;
1428  rect->width = width;
1429  rect->height = height;
1430 }
1431 
1432 /*!**************************************************************************
1433  * @brief Return WSS
1434  * @param state - conversion state
1435  * @return The calculated WSS value
1436  ****************************************************************************/
1437 static U8BIT GetWss(S_VT_CONVERSION_STATE *state)
1438 {
1439  if (state->video_aspect_ratio == ASPECT_RATIO_4_3)
1440  {
1441  switch (state->afd)
1442  {
1443  case 0:
1444  case 1:
1445  case 3:
1446  return 0x1;
1447  break;
1448  case 2:
1449  return 0xd;
1450  break;
1451  case 5:
1452  return 0x7;
1453  break;
1454  case 6:
1455  return 0xd;
1456  break;
1457  case 7:
1458 
1459  break;
1460  }
1461  }
1462  else
1463  {
1464  if (state->display_aspect_ratio == ASPECT_RATIO_4_3)
1465  {
1466  switch (state->afd)
1467  {
1468  case 0:
1469  switch (state->afd_preference)
1470  {
1471  case AFD_PREFERENCE_AUTO:
1472  case AFD_PREFERENCE_16_9_LB:
1473  return 0xd;
1474  break;
1475  case AFD_PREFERENCE_14_9_LB:
1476  return 0x8;
1477  break;
1478  case AFD_PREFERENCE_CCO:
1479  return 0x1;
1480  break;
1481  }
1482 
1483  break;
1484  case 1:
1485  return 0x1;
1486 
1487  break;
1488  case 2:
1489 
1490  return 0xd;
1491 
1492  break;
1493  case 3:
1494 
1495  if (state->afd_preference == AFD_PREFERENCE_CCO)
1496  {
1497  return 0x1;
1498  }
1499  else
1500  {
1501  return 0x8;
1502  }
1503 
1504  break;
1505  case 5:
1506  return 0x7;
1507  break;
1508  case 6:
1509  case 7:
1510  if (state->afd_preference == AFD_PREFERENCE_CCO)
1511  {
1512  return 0x1;
1513  }
1514  else if (state->afd_preference == AFD_PREFERENCE_14_9_LB)
1515  {
1516  return 0x8;
1517  }
1518  else
1519  {
1520  return 0xd;
1521  }
1522 
1523  break;
1524  }
1525  }
1526  else
1527  {
1528  return 0xe;
1529  }
1530  }
1531  return 1;
1532 }
1533 
1534 #ifdef PRINT_STATE
1535 /*!**************************************************************************
1536  * @brief Print the state
1537  * @param state - conversion state
1538  ****************************************************************************/
1539 static void PrintState(S_VT_CONVERSION_STATE *state)
1540 {
1541  DBG(("Conversion state:\n"));
1542  DBG((" mheg_enabled : %s\n",
1543  state->mheg_enabled ? "TRUE" : "FALSE"));
1544  DBG((" afd_enabled : %s\n",
1545  state->afd_enabled ? "TRUE" : "FALSE"));
1546  DBG((" hbb_enabled : %s\n",
1547  state->hbb_enabled ? "TRUE" : "FALSE"));
1548  DBG((" afd_preference : %s\n",
1549  state->afd_preference == AFD_PREFERENCE_AUTO ? "AFD_PREFERENCE_AUTO" :
1550  state->afd_preference == AFD_PREFERENCE_16_9_LB ? "AFD_PREFERENCE_16_9_LB" :
1551  state->afd_preference == AFD_PREFERENCE_14_9_LB ? "AFD_PREFERENCE_14_9_LB" :
1552  state->afd_preference == AFD_PREFERENCE_CCO ? "AFD_PREFERENCE_CCO" :
1553  "UNKNOWN"));
1554  DBG((" alignment : %s\n",
1555  state->alignment == ASPECT_MODE_4_3 ? "ASPECT_MODE_4_3" :
1556  state->alignment == ASPECT_MODE_14_9 ? "ASPECT_MODE_14_9" :
1557  state->alignment == ASPECT_MODE_16_9 ? "ASPECT_MODE_16_9" :
1558  state->alignment == ASPECT_MODE_AUTO ? "ASPECT_MODE_AUTO" :
1559  state->alignment == ASPECT_MODE_CUSTOM ? "ASPECT_MODE_CUSTOM" :
1560  "UNKNOWN"));
1561  DBG((" afd : %d\n", state->afd));
1562  DBG((" mheg_aspect_ratio : %s\n",
1563  state->mheg_aspect_ratio == ASPECT_RATIO_4_3 ? "ASPECT_RATIO_4_3" :
1564  state->mheg_aspect_ratio == ASPECT_RATIO_16_9 ? "ASPECT_RATIO_16_9" :
1565  state->mheg_aspect_ratio == ASPECT_UNDEFINED ? "ASPECT_UNSPECIFIED" :
1566  "UNKNOWN"));
1567  DBG((" wam : %s\n",
1568  state->mheg_wam == ASPECT_MODE_AUTO ? "ALIGNMENT_MODE_NONE" :
1569  state->mheg_wam == ASPECT_MODE_4_3 ? "ALIGNMENT_MODE_CCO" :
1570  state->mheg_wam == ASPECT_MODE_16_9 ? "ALIGNMENT_MODE_LB" :
1571  "UNKNOWN"));
1572  DBG((" mheg_scaling_rect : { l=%ld, t=%ld, w=%ld, h=%ld }\n",
1573  state->mheg_scaling_rect.left,
1574  state->mheg_scaling_rect.top,
1575  state->mheg_scaling_rect.width,
1576  state->mheg_scaling_rect.height));
1577  DBG((" hbb_window_rect : { l=%ld, t=%ld, w=%ld, h=%ld }\n",
1578  state->hbb_window_rect.left,
1579  state->hbb_window_rect.top,
1580  state->hbb_window_rect.width,
1581  state->hbb_window_rect.height));
1582  DBG((" mheg_scaling_given : %s\n",
1583  state->mheg_scaling_given ? "TRUE" : "FALSE"));
1584  DBG((" mheg_resolution : { w=%d, h=%d}\n",
1585  state->mheg_resolution_width, state->mheg_resolution_height));
1586  DBG((" resolution : { w=%d, h=%d}\n",
1587  state->resolution_width, state->resolution_height));
1588  DBG((" video_width : %d\n",
1589  state->video_width));
1590  DBG((" video_height : %d\n",
1591  state->video_height));
1592  DBG((" screen_width : %d\n",
1593  state->screen_width));
1594  DBG((" screen_height : %d\n",
1595  state->screen_height));
1596  DBG((" video_aspect_ratio : %s\n",
1597  state->video_aspect_ratio == ASPECT_RATIO_4_3 ? "ASPECT_RATIO_4_3" :
1598  state->video_aspect_ratio == ASPECT_RATIO_16_9 ? "ASPECT_RATIO_16_9" :
1599  state->video_aspect_ratio == ASPECT_UNDEFINED ? "ASPECT_UNDEFINED" :
1600  "UNKNOWN"));
1601  DBG((" display_aspect_ratio : %s\n",
1602  state->display_aspect_ratio == ASPECT_RATIO_4_3 ? "ASPECT_RATIO_4_3" :
1603  state->display_aspect_ratio == ASPECT_RATIO_16_9 ? "ASPECT_RATIO_16_9" :
1604  state->display_aspect_ratio == ASPECT_UNDEFINED ? "ASPECT_UNDEFINED" :
1605  "UNKNOWN"));
1606 }
1607 
1608 #endif
1609 
1610 static void PrintMatrix(S_VT_MATRIX *matrix)
1611 {
1612  if (matrix)
1613  {
1614  DBG(("matrix: A:%ld/%ld B:%ld/%ld C:%ld/%ld D:%ld/%ld\n",
1615  matrix->a.numerator,
1616  matrix->a.denominator,
1617  matrix->b.numerator,
1618  matrix->b.denominator,
1619  matrix->c.numerator,
1620  matrix->c.denominator,
1621  matrix->d.numerator,
1622  matrix->d.denominator));
1623  }
1624 }
1625 
1626 static void PrintFractRect(S_VT_FRACT_RECT *fract_rect)
1627 {
1628  if (fract_rect)
1629  {
1630  DBG(("fract_rect: Width:%ld/%ld Height:%ld/%ld Left:%ld/%ld Top:%ld/%ld\n",
1631  fract_rect->width.numerator,
1632  fract_rect->width.denominator,
1633  fract_rect->height.numerator,
1634  fract_rect->height.denominator,
1635  fract_rect->left.numerator,
1636  fract_rect->left.denominator,
1637  fract_rect->top.numerator,
1638  fract_rect->top.denominator));
1639  }
1640 }
1641 
1642 /*!**************************************************************************
1643  * @brief Create an identity matrix
1644  * @param matrix - the matrix
1645  ****************************************************************************/
1646 static void VTC_IdentityMatrix(S_VT_MATRIX *matrix)
1647 {
1648  matrix->a = MakeFraction(1, 1);
1649  matrix->b = MakeFraction(0, 1);
1650  matrix->c = MakeFraction(1, 1);
1651  matrix->d = MakeFraction(0, 1);
1652 }
1653 
1654 /*!**************************************************************************
1655  * @brief Apply video CS transformation
1656  * @param current - the current transformation matrix
1657  * @param state - conversion state
1658  ****************************************************************************/
1659 static void VTC_VideoCsScaling(S_VT_CONVERSION_STATE *state,
1660  S_VT_MATRIX *current)
1661 {
1662  S_VT_MATRIX transform;
1663 
1664  if (state->video_width == 352 && state->video_height == 288)
1665  {
1666  Scale_352_288_Video(state, &transform);
1667  }
1668  else if (state->video_width == 352 && state->video_height == 576)
1669  {
1670  Scale_352_576_Video(state, &transform);
1671  }
1672  else if (state->video_width == 480 && state->video_height == 576)
1673  {
1674  Scale_480_576_Video(state, &transform);
1675  }
1676  else if (state->video_width == 544 && state->video_height == 576)
1677  {
1678  Scale_544_576_Video(state, &transform);
1679  }
1680  else
1681  {
1682  Scale_Video(state, &transform);
1683  }
1684 
1685  MultiplyMatrices(&transform, current, current);
1686 }
1687 
1688 /*!**************************************************************************
1689  * @brief Apply AFD-override scaling transformation
1690  * @param state - conversion state
1691  * @param current - the current transformation matrix
1692  * @return Format conversion applied
1693  ****************************************************************************/
1694 static E_FORMAT_CONVERSION VTC_UserPreferenceScaling(S_VT_CONVERSION_STATE *state,
1695  S_VT_MATRIX *current)
1696 {
1697  E_FORMAT_CONVERSION transformation;
1698  S_VT_MATRIX transform;
1699 
1700  VTC_IdentityMatrix(&transform);
1701  transformation = FORMAT_CONVERSION_IGNORE;
1702 
1703  if (state->alignment == ASPECT_MODE_CUSTOM)
1704  {
1705  if (state->custom_mode_callback != NULL)
1706  {
1707  transformation = state->custom_mode_callback(state->video_aspect_ratio,
1708  state->display_aspect_ratio);
1709  switch (transformation)
1710  {
1711  case FORMAT_CONVERSION_PANSCAN:
1712  {
1713  Scale_CentreCutOut(state, state->resolution_width, state->resolution_height,
1714  &transform);
1715  break;
1716  }
1717  case FORMAT_CONVERSION_LETTERBOX:
1718  {
1719  Scale_16_9_Letterbox(state, state->resolution_width, state->resolution_height,
1720  &transform);
1721  break;
1722  }
1723  case FORMAT_CONVERSION_LETTERBOX_14_9:
1724  {
1725  Scale_14_9_Letterbox(state, state->resolution_width, state->resolution_height,
1726  &transform);
1727  break;
1728  }
1729  case FORMAT_CONVERSION_PILLAR_BOX:
1730  {
1731  Scale_Pillarbox(state, state->resolution_width, state->resolution_height,
1732  &transform);
1733  break;
1734  }
1735  case FORMAT_CONVERSION_ZOOM_4_3:
1736  {
1737  Scale_4_3_Zoom(state, state->resolution_width, state->resolution_height, &transform);
1738  break;
1739  }
1740  case FORMAT_CONVERSION_ZOOM_14_9:
1741  {
1742  Scale_14_9_Zoom(state, state->resolution_width, state->resolution_height,
1743  &transform);
1744  break;
1745  }
1746  case FORMAT_CONVERSION_PANSCAN_14_9:
1747  {
1748  Scale_16_9_Zoom(state, state->resolution_width, state->resolution_height,
1749  &transform);
1750  break;
1751  }
1752  case FORMAT_CONVERSION_CENTRE_14_9:
1753  {
1754  Scale_14_9_Centre(state, state->resolution_width, state->resolution_height,
1755  &transform);
1756  break;
1757  }
1758  case FORMAT_CONVERSION_CENTRE_4_3:
1759  {
1760  Scale_4_3_Centre(state, state->resolution_width, state->resolution_height,
1761  &transform);
1762  break;
1763  }
1764  default:
1765  {
1766  break;
1767  }
1768  }
1769  }
1770  }
1771  else
1772  {
1773  /* 4:3 display */
1774  if (state->display_aspect_ratio == ASPECT_RATIO_4_3)
1775  {
1776  /* 4:3 video */
1777  if (state->video_aspect_ratio == ASPECT_RATIO_4_3)
1778  {
1779  switch (state->alignment)
1780  {
1781  case ASPECT_MODE_16_9:
1782  Scale_4_3_Centre(state, state->resolution_width, state->resolution_height, &transform);
1783  transformation = FORMAT_CONVERSION_CENTRE_4_3;
1784  break;
1785  case ASPECT_MODE_14_9:
1786  Scale_14_9_Centre(state, state->resolution_width, state->resolution_height, &transform);
1787  transformation = FORMAT_CONVERSION_CENTRE_14_9;
1788  break;
1789  default:
1790  ;
1791  }
1792  }
1793  /* 16:9 video */
1794  else if (state->video_aspect_ratio == ASPECT_RATIO_16_9)
1795  {
1796  switch (state->alignment)
1797  {
1798  case ASPECT_MODE_16_9:
1799  default:
1800  Scale_16_9_Letterbox(state, state->resolution_width, state->resolution_height, &transform);
1801  transformation = FORMAT_CONVERSION_LETTERBOX;
1802  break;
1803  case ASPECT_MODE_14_9:
1804  Scale_14_9_Letterbox(state, state->resolution_width, state->resolution_height, &transform);
1805  transformation = FORMAT_CONVERSION_LETTERBOX_14_9;
1806  break;
1807  case ASPECT_MODE_4_3:
1808  case ASPECT_MODE_ZOOM:
1809  Scale_CentreCutOut(state, state->resolution_width, state->resolution_height, &transform);
1810  transformation = FORMAT_CONVERSION_PANSCAN;
1811  break;
1812  }
1813  }
1814  }
1815  else if (state->display_aspect_ratio == ASPECT_RATIO_16_9)
1816  {
1817  /* 16:9 display */
1818  if (state->video_aspect_ratio == ASPECT_RATIO_4_3)
1819  {
1820  /* 4:3 video */
1821  switch (state->alignment)
1822  {
1823  case ASPECT_MODE_16_9:
1824  case ASPECT_MODE_ZOOM:
1825  Scale_4_3_Zoom(state, state->resolution_width, state->resolution_height, &transform);
1826  transformation = FORMAT_CONVERSION_ZOOM_4_3;
1827  break;
1828  case ASPECT_MODE_14_9:
1829  Scale_14_9_Zoom(state, state->resolution_width, state->resolution_height, &transform);
1830  transformation = FORMAT_CONVERSION_ZOOM_14_9;
1831  break;
1832  case ASPECT_MODE_4_3:
1833  default:
1834  Scale_Pillarbox(state, state->resolution_width, state->resolution_height, &transform);
1835  transformation = FORMAT_CONVERSION_PILLAR_BOX;
1836  break;
1837  }
1838  }
1839  else if (state->video_aspect_ratio == ASPECT_RATIO_16_9)
1840  {
1841  /* 16:9 video */
1842  switch (state->alignment)
1843  {
1844  case ASPECT_MODE_4_3:
1845  Scale_Pillarbox(state, state->resolution_width, state->resolution_height, &transform);
1846  transformation = FORMAT_CONVERSION_PILLAR_BOX;
1847  break;
1848  case ASPECT_MODE_14_9:
1849  Scale_16_9_Zoom(state, state->resolution_width, state->resolution_height, &transform);
1850  transformation = FORMAT_CONVERSION_PANSCAN_14_9;
1851  break;
1852  default:
1853  ;
1854  }
1855  }
1856  }
1857  }
1858 
1859  MultiplyMatrices(&transform, current, current);
1860 
1861  return transformation;
1862 }
1863 
1864 /*!**************************************************************************
1865  * @brief Apply AFD video scaling transformation
1866  * @param state - conversion state
1867  * @param current - the current transformation matrix
1868  * @return Format conversion applied
1869  ****************************************************************************/
1870 static E_FORMAT_CONVERSION VTC_AfdScaling(S_VT_CONVERSION_STATE *state,
1871  S_VT_MATRIX *current)
1872 {
1873  BOOLEAN apply;
1874  E_FORMAT_CONVERSION transformation;
1875  S_VT_MATRIX transform;
1876 
1877  apply = TRUE;
1878  transformation = FindAfdTransformation(state);
1879  switch (transformation)
1880  {
1881  case FORMAT_CONVERSION_PILLAR_BOX:
1882  Scale_Pillarbox(state, state->resolution_width, state->resolution_height, &transform);
1883  break;
1884 
1885  case FORMAT_CONVERSION_ZOOM_4_3:
1886  Scale_4_3_Zoom(state, state->resolution_width, state->resolution_height, &transform);
1887  break;
1888 
1889  case FORMAT_CONVERSION_ZOOM_14_9:
1890  Scale_14_9_Zoom(state, state->resolution_width, state->resolution_height, &transform);
1891  break;
1892 
1893  case FORMAT_CONVERSION_LETTERBOX:
1894  Scale_16_9_Letterbox(state, state->resolution_width, state->resolution_height, &transform);
1895  break;
1896 
1897  case FORMAT_CONVERSION_LETTERBOX_14_9:
1898  Scale_14_9_Letterbox(state, state->resolution_width, state->resolution_height, &transform);
1899  break;
1900 
1901  case FORMAT_CONVERSION_PANSCAN:
1902  Scale_CentreCutOut(state, state->resolution_width, state->resolution_height, &transform);
1903  break;
1904 
1905  case FORMAT_CONVERSION_PANSCAN_14_9:
1906  Scale_16_9_Zoom(state, state->resolution_width, state->resolution_height, &transform);
1907  break;
1908 
1909  case FORMAT_CONVERSION_CENTRE_14_9:
1910  Scale_14_9_Centre(state, state->resolution_width, state->resolution_height, &transform);
1911  break;
1912 
1913  case FORMAT_CONVERSION_CENTRE_4_3:
1914  Scale_4_3_Centre(state, state->resolution_width, state->resolution_height, &transform);
1915  break;
1916 
1917  default:
1918  /* Couldn't find - don't transform */
1919  apply = FALSE;
1920  }
1921 
1922  if (apply)
1923  {
1924  MultiplyMatrices(&transform, current, current);
1925  }
1926 
1927  return transformation;
1928 }
1929 
1930 /*!**************************************************************************
1931  * @brief Apply MHEG-5 video scaling transformation
1932  * @param state - conversion state
1933  * @param current - the current transformation matrix
1934  ****************************************************************************/
1935 static void VTC_MhegScaling(S_VT_CONVERSION_STATE *state,
1936  S_VT_MATRIX *current)
1937 {
1938  S_VT_MATRIX transform;
1939 
1940  MhegScaling(state, &transform);
1941  MultiplyMatrices(&transform, current, current);
1942 }
1943 
1944 /*!**************************************************************************
1945  * @brief Apply HBBTV video transformation
1946  * @param state - conversion state
1947  * @param current - the current transformation matrix
1948  ****************************************************************************/
1949 static void VTC_HbbScaleToScreen(S_VT_CONVERSION_STATE *state,
1950  S_VT_MATRIX *current)
1951 {
1952  S_VT_MATRIX transform;
1953 
1954  HbbScaling(state, &transform);
1955  DBG(("HbbScaling:\n"));
1956  PrintMatrix(&transform);
1957 
1958  MultiplyMatrices(&transform, current, current);
1959 
1960  Scale_HbbToScreen(state, &transform);
1961  DBG(("Scale_HbbToScreen:\n"));
1962  PrintMatrix(&transform);
1963  MultiplyMatrices(&transform, current, current);
1964 }
1965 
1966 /*!**************************************************************************
1967  * @brief Apply application scaling transformation
1968  * @param state - conversion state
1969  * @param current - the current transformation matrix
1970  ****************************************************************************/
1971 static void VTC_AppScaling(S_VT_CONVERSION_STATE *state,
1972  S_VT_MATRIX *current)
1973 {
1974  S_VT_MATRIX transform;
1975 
1976  AppScaling(state, &transform);
1977  MultiplyMatrices(&transform, current, current);
1978 }
1979 
1980 /*!**************************************************************************
1981  * @brief Apply MHEG-5 quarter screen video scaling transformation
1982  * @param state - conversion state
1983  * @param current - the current transformation matrix
1984  * @return Format conversion applied
1985  ****************************************************************************/
1986 static E_FORMAT_CONVERSION VTC_QuarterScreenScaling(S_VT_CONVERSION_STATE *state,
1987  S_VT_MATRIX *current)
1988 {
1989  E_FORMAT_CONVERSION transformation;
1990  S_VT_MATRIX transform;
1991 
1992  transformation = FORMAT_CONVERSION_IGNORE;
1993 
1994  NoScaling(state, &transform);
1995  if (state->mheg_aspect_ratio == ASPECT_UNDEFINED)
1996  {
1997  if ((state->video_aspect_ratio == ASPECT_RATIO_4_3) &&
1998  (state->display_aspect_ratio == ASPECT_RATIO_16_9))
1999  {
2000  /* 4:3 video on 16:9 display = pillar-box */
2001  transformation = FORMAT_CONVERSION_PILLAR_BOX;
2002  Scale_Pillarbox(state, state->resolution_width, state->resolution_height, &transform);
2003  }
2004  else if ((state->video_aspect_ratio == ASPECT_RATIO_16_9) &&
2005  (state->display_aspect_ratio == ASPECT_RATIO_4_3))
2006  {
2007  /* 16:9 video on 4:3 display = pan-scan (centre cut-out) */
2008  transformation = FORMAT_CONVERSION_PANSCAN;
2009  Scale_CentreCutOut(state, state->resolution_width, state->resolution_height, &transform);
2010  }
2011  }
2012  else if ((state->mheg_aspect_ratio == ASPECT_RATIO_4_3) &&
2013  (state->video_aspect_ratio == ASPECT_RATIO_16_9))
2014  {
2015  /* SAR=4:3, 16:9 video = pan-scan (centre cut-out) */
2016  transformation = FORMAT_CONVERSION_PANSCAN;
2017  Scale_CentreCutOut(state, state->resolution_width, state->resolution_height, &transform);
2018  }
2019  else if ((state->mheg_aspect_ratio == ASPECT_RATIO_16_9) &&
2020  (state->video_aspect_ratio == ASPECT_RATIO_4_3) &&
2021  (state->display_aspect_ratio == ASPECT_RATIO_16_9))
2022  {
2023  /* SAR=16:9, 4:3 video = pillar-box (only on 16:9 display) */
2024  transformation = FORMAT_CONVERSION_PILLAR_BOX;
2025  Scale_Pillarbox(state, state->resolution_width, state->resolution_height, &transform);
2026  }
2027  else if ((state->mheg_aspect_ratio == ASPECT_RATIO_16_9) &&
2028  (state->video_aspect_ratio == ASPECT_RATIO_16_9) &&
2029  (state->display_aspect_ratio == ASPECT_RATIO_4_3))
2030  {
2031  /* SAR=16:9, 16:9 video = pan-scan (when using 4:3 display) */
2032  transformation = FORMAT_CONVERSION_PANSCAN;
2033  Scale_CentreCutOut(state, state->resolution_width, state->resolution_height, &transform);
2034  }
2035  MultiplyMatrices(&transform, current, current);
2036 
2037  return transformation;
2038 }
2039 
2040 /*!**************************************************************************
2041  * @brief Apply scene aspect ratio transformation (if required)
2042  * @param state - conversion state
2043  * @param current - the current transformation matrix
2044  ****************************************************************************/
2045 static void VTC_SceneArScaling(S_VT_CONVERSION_STATE *state,
2046  S_VT_MATRIX *current)
2047 {
2048  BOOLEAN apply;
2049  S_VT_MATRIX transform;
2050 
2051  apply = FALSE;
2052 
2053  if ((state->mheg_aspect_ratio == ASPECT_RATIO_4_3) &&
2054  (state->video_aspect_ratio == ASPECT_RATIO_16_9) &&
2055  (state->decoder_status == DECODER_STATUS_VIDEO))
2056  {
2057  /* 16:9 video on 4:3 Scene: follow Widescreen Alignment Mode */
2058  switch (state->mheg_wam)
2059  {
2060  default:
2061  /* Anamorphic output - do nothing */
2062  break;
2063  case ASPECT_MODE_4_3:
2064  Scale_CentreCutOut(state, state->resolution_width, state->resolution_height, &transform);
2065  apply = TRUE;
2066  break;
2067  case ASPECT_MODE_16_9:
2068  Scale_16_9_Letterbox(state, state->resolution_width, state->resolution_height, &transform);
2069  apply = TRUE;
2070  break;
2071  }
2072  }
2073 
2074  if (apply)
2075  {
2076  MultiplyMatrices(&transform, current, current);
2077  }
2078 }
2079 
2080 /*!**************************************************************************
2081  * @brief Compose a transformation from the presentation coordinates to
2082  * screen coordinateswith the given transformation.
2083  * @param state - conversion state
2084  * @param current - the current transformation matrix
2085  ****************************************************************************/
2086 static void VTC_ToScreen(S_VT_CONVERSION_STATE *state,
2087  S_VT_MATRIX *current)
2088 {
2089  S_VT_MATRIX transform;
2090 
2091  Scale_ToScreen(state, &transform);
2092  MultiplyMatrices(&transform, current, current);
2093 }
2094 
2095 #if 0
2096 /*!**************************************************************************
2097  * @brief Compose an application scaling transformation with the given
2098  * transformation
2099  * @param state - conversion state
2100  * @param current - the current transformation matrix
2101  * @return Format conversion applied
2102  ****************************************************************************/
2103 static E_FORMAT_CONVERSION VTC_AppScalingTransform(S_VT_CONVERSION_STATE *state,
2104  S_VT_MATRIX *current)
2105 {
2106  E_FORMAT_CONVERSION transformation;
2107  S_VT_MATRIX transform;
2108 
2109  transformation = FORMAT_CONVERSION_IGNORE;
2110 
2111  /* Take care of video aspact ratio */
2112  NoScaling(state, &transform);
2113  if ((state->video_aspect_ratio == ASPECT_RATIO_4_3) &&
2114  (state->display_aspect_ratio == ASPECT_RATIO_16_9))
2115  {
2116  /* 4:3 video on 16:9 display = pillar-box */
2117  transformation = FORMAT_CONVERSION_PILLAR_BOX;
2118  Scale_Pillarbox(state, state->resolution_width, state->resolution_height, &transform);
2119  }
2120  else if ((state->video_aspect_ratio == ASPECT_RATIO_16_9) &&
2121  (state->display_aspect_ratio == ASPECT_RATIO_4_3))
2122  {
2123  /* 16:9 video on 4:3 display = pan-scan (centre cut-out) */
2124  transformation = FORMAT_CONVERSION_PANSCAN;
2125  Scale_CentreCutOut(state, state->resolution_width, state->resolution_height, &transform);
2126  }
2127  MultiplyMatrices(&transform, current, current);
2128 
2129  return transformation;
2130 }
2131 #endif
2132 
2133 /*!**************************************************************************
2134  * @brief Apply a WSS transformation on the output
2135  * @param state - conversion state
2136  * @param output - output double vector
2137  ****************************************************************************/
2138 static void VTC_ApplyWSS(S_VT_CONVERSION_STATE *state,
2139  S_VT_FRACT_RECT *output)
2140 {
2141  S_VT_MATRIX transform;
2142 
2143  DBG(("VTC_ApplyWSS: before:\n"));
2144  PrintFractRect(output);
2145 
2146  if ((state->mheg_enabled) &&
2147  (state->mheg_aspect_ratio == ASPECT_RATIO_4_3) &&
2148  (state->display_aspect_ratio == ASPECT_RATIO_16_9))
2149  {
2150  /* "Pillar-box" the output (input is unchanged) */
2151  VTC_IdentityMatrix(&transform);
2152  Scale_Pillarbox(state, state->screen_width, state->screen_height,
2153  &transform);
2154  PrintMatrix(&transform);
2155  ApplyTransformation(&transform, output, output);
2156  DBG(("VTC_ApplyWSS: after:\n"));
2157  PrintFractRect(output);
2158  }
2159 }
2160 
2161 /*!**************************************************************************
2162  * @brief Convert an S_RECTANGLE to a S_VT_FRACT_RECT
2163  * @param rectangle - rectangle to be converted
2164  * @param vector - resulting vector
2165  ****************************************************************************/
2166 static void VTC_RectangleToFractRectangle(S_RECTANGLE *rectangle,
2167  S_VT_FRACT_RECT *fract_rect)
2168 {
2169  fract_rect->left = MakeFraction(rectangle->left, 1);
2170  fract_rect->top = MakeFraction(rectangle->top, 1);
2171  fract_rect->width = MakeFraction(rectangle->width, 1);
2172  fract_rect->height = MakeFraction(rectangle->height, 1);
2173 }
2174 
2175 /*!**************************************************************************
2176  * @brief Convert an S_VT_FRACT_RECT to a S_RECTANGLE (with rounded-down
2177  * values)
2178  * @param vector - vector to be converted
2179  * @param rectangle - resulting rectangle
2180  ****************************************************************************/
2181 static void VTC_FractRectangleToRectangle(S_VT_FRACT_RECT *fract_rect,
2182  S_RECTANGLE *rectangle)
2183 {
2184  rectangle->left = ((fract_rect->left.numerator + fract_rect->left.denominator / 2) /
2185  fract_rect->left.denominator);
2186  rectangle->top = ((fract_rect->top.numerator + fract_rect->top.denominator / 2) /
2187  fract_rect->top.denominator);
2188  rectangle->width = ((fract_rect->width.numerator + fract_rect->width.denominator / 2) /
2189  fract_rect->width.denominator);
2190  rectangle->height = ((fract_rect->height.numerator + fract_rect->height.denominator / 2) /
2191  fract_rect->height.denominator);
2192 }
2193 
2194 /*!**************************************************************************
2195  * @brief Apply the given transformation on a rectangle
2196  * @param state - conversion state
2197  * @param transform - the transformation matrix
2198  * @param clip_transform - clipping transformation matrix
2199  * @param input_rect - input rectangle
2200  * @param output_rect - output rectangle
2201  ****************************************************************************/
2202 static void VTC_TransformRectangles(S_VT_CONVERSION_STATE *state,
2203  S_VT_MATRIX *transform,
2204  S_VT_MATRIX *clip_transform,
2205  S_VT_FRACT_RECT *input_rect,
2206  S_VT_FRACT_RECT *output_rect)
2207 {
2208  S_VT_FRACT_RECT screen_clip;
2209  S_VT_FRACT_RECT scale_clip;
2210  S_VT_FRACT_RECT trans_clip;
2211  S_VT_MATRIX inverse;
2212 
2213  screen_clip = MakeRectangle(0, 0, state->screen_width, state->screen_height);
2214 
2215  scale_clip = MakeRectangle(0, 0, state->resolution_width, state->resolution_height);
2216 
2217  /* Multiply the vectors by the input matrix */
2218  ApplyTransformation(transform, input_rect, output_rect);
2219 
2220  /* Create a clipping region for mheg scaling */
2221  ApplyTransformation(clip_transform, &scale_clip, &trans_clip);
2222 
2223  /* Clip output */
2224  ClipRectangle(&screen_clip, output_rect);
2225  ClipRectangle(&trans_clip, output_rect);
2226 
2227  /*check that app has specified non-zero size output*/
2228  if (transform->a.numerator != 0 && transform->c.numerator != 0)
2229  {
2230  /* Find input rectangle for clipped result */
2231  InvertMatrix(transform, &inverse);
2232  ApplyTransformation(&inverse, output_rect, input_rect);
2233  }
2234 }
2235 
2236 /******************************************/
2237 
2238 /*!**************************************************************************
2239  * @brief Clip rectangle to given region
2240  * @param clip_rect - clipping region (rectangle)
2241  * @param rect - the rectangle to clip
2242  ****************************************************************************/
2243 static void ClipRectangle(S_VT_FRACT_RECT *clip_rect, S_VT_FRACT_RECT *rect)
2244 {
2245  S_VT_FRACTION right, bottom;
2246  S_VT_FRACTION clip_right, clip_bottom;
2247 
2248  AddFractions(&rect->left, &rect->width, &right);
2249  AddFractions(&rect->top, &rect->height, &bottom);
2250 
2251  AddFractions(&clip_rect->left, &clip_rect->width, &clip_right);
2252  AddFractions(&clip_rect->top, &clip_rect->height, &clip_bottom);
2253 
2254  if ((CompareFractions(&rect->left, &clip_right) >= 0) ||
2255  (CompareFractions(&rect->top, &clip_bottom) >= 0) ||
2256  (CompareFractions(&right, &clip_rect->left) <= 0) ||
2257  (CompareFractions(&bottom, &clip_rect->top) <= 0))
2258  {
2259  /* Invalid transformation */
2260  rect->left = MakeFraction(0, 1);
2261  rect->top = MakeFraction(0, 1);
2262  rect->width = MakeFraction(0, 1);
2263  rect->height = MakeFraction(0, 1);
2264  }
2265  else
2266  {
2267  if (CompareFractions(&rect->left, &clip_rect->left) < 0)
2268  {
2269  SubtractFraction(&right, &clip_rect->left, &rect->width);
2270  rect->left = clip_rect->left;
2271  }
2272 
2273  if (CompareFractions(&rect->top, &clip_rect->top) < 0)
2274  {
2275  SubtractFraction(&bottom, &clip_rect->top, &rect->height);
2276  rect->top = clip_rect->top;
2277  }
2278 
2279  AddFractions(&rect->left, &rect->width, &right);
2280  AddFractions(&rect->top, &rect->height, &bottom);
2281 
2282  if (CompareFractions(&right, &clip_right) > 0)
2283  {
2284  SubtractFraction(&clip_right, &rect->left, &rect->width);
2285  }
2286 
2287  if (CompareFractions(&bottom, &clip_bottom) > 0)
2288  {
2289  SubtractFraction(&clip_bottom, &rect->top, &rect->height);
2290  }
2291  }
2292 }
2293 
2294 static S32BIT Gcd(S32BIT a, S32BIT b)
2295 {
2296  S32BIT r;
2297 
2298  while (b != 0)
2299  {
2300  r = b;
2301  b = a % b;
2302  a = r;
2303  }
2304 
2305  return a;
2306 }
2307 
2308 static BOOLEAN ReduceFraction(S_VT_FRACTION *input, S_VT_FRACTION *output)
2309 {
2310  S32BIT num, den, gcd;
2311 
2312  num = input->numerator >= 0 ? input->numerator : -input->numerator;
2313  den = input->denominator >= 0 ? input->denominator : -input->denominator;
2314 
2315  gcd = Gcd(num, den);
2316 
2317  ASSERT(gcd != 0);
2318 
2319  output->numerator = input->numerator / gcd;
2320  output->denominator = input->denominator / gcd;
2321 
2322  return TRUE;
2323 }
2324 
2325 static void AddFractions(S_VT_FRACTION *in_a, S_VT_FRACTION *in_b, S_VT_FRACTION *out)
2326 {
2327  S32BIT gcd;
2328 
2329  /* Check if one of the inputs is 0, in which case the more
2330  * complicated addition function doesn't need to be performed
2331  */
2332  ASSERT(in_a->denominator != 0);
2333  ASSERT(in_b->denominator != 0);
2334 
2335  if (in_a->numerator == 0)
2336  {
2337  ReduceFraction(in_b, out);
2338  ASSERT(out->denominator != 0);
2339  }
2340  else if (in_b->numerator == 0)
2341  {
2342  ReduceFraction(in_a, out);
2343  ASSERT(out->denominator != 0);
2344  }
2345  else
2346  {
2347  /* Add the two fractions */
2348  gcd = Gcd(in_a->denominator, in_b->denominator);
2349  out->numerator = ((in_a->numerator * in_b->denominator / gcd) +
2350  (in_b->numerator * in_a->denominator / gcd));
2351  out->denominator = in_a->denominator * in_b->denominator / gcd;
2352  ASSERT(out->denominator != 0);
2353  ReduceFraction(out, out);
2354  }
2355 }
2356 
2357 static void SubtractFraction(S_VT_FRACTION *in_a, S_VT_FRACTION *in_b,
2358  S_VT_FRACTION *out)
2359 {
2360  S_VT_FRACTION temp;
2361 
2362  temp = *in_b;
2363  temp.numerator = 0 - temp.numerator;
2364  AddFractions(in_a, &temp, out);
2365 }
2366 
2367 static int CompareFractions(S_VT_FRACTION *in_a, S_VT_FRACTION *in_b)
2368 {
2369  return(in_a->numerator * in_b->denominator -
2370  in_b->numerator * in_a->denominator);
2371 }
2372 
2373 static void MultiplyMatrices(S_VT_MATRIX *matrix_a, S_VT_MATRIX *matrix_b,
2374  S_VT_MATRIX *output_matrix)
2375 {
2376  S_VT_FRACTION buffer;
2377  S_VT_MATRIX tmp;
2378 
2379  /* Multiplying:
2380  *
2381  * (a 0 b) (a 0 b)
2382  * (0 c d) x (0 c d)
2383  * (0 0 1) (0 0 1)
2384  *
2385  * The order used allows the output matrix to be the same as one of
2386  * the input matrices.
2387  */
2388 
2389  ASSERT(matrix_a->a.denominator != 0);
2390  ASSERT(matrix_a->b.denominator != 0);
2391  ASSERT(matrix_a->c.denominator != 0);
2392  ASSERT(matrix_a->d.denominator != 0);
2393  ASSERT(matrix_b->a.denominator != 0);
2394  ASSERT(matrix_b->b.denominator != 0);
2395  ASSERT(matrix_b->c.denominator != 0);
2396  ASSERT(matrix_b->d.denominator != 0);
2397 
2398  buffer.numerator = matrix_a->a.numerator * matrix_b->b.numerator;
2399  buffer.denominator = matrix_a->a.denominator * matrix_b->b.denominator;
2400  AddFractions(&buffer, &matrix_a->b, &tmp.b);
2401 
2402  tmp.a.denominator = matrix_a->a.denominator * matrix_b->a.denominator;
2403  tmp.a.numerator = matrix_a->a.numerator * matrix_b->a.numerator;
2404  ReduceFraction(&tmp.a, &tmp.a);
2405 
2406  buffer.numerator = matrix_a->c.numerator * matrix_b->d.numerator;
2407  buffer.denominator = matrix_a->c.denominator * matrix_b->d.denominator;
2408  ASSERT(buffer.denominator != 0);
2409  ASSERT(matrix_a->d.denominator != 0);
2410  AddFractions(&buffer, &matrix_a->d, &tmp.d);
2411 
2412  tmp.c.denominator = matrix_a->c.denominator * matrix_b->c.denominator;
2413  tmp.c.numerator = matrix_a->c.numerator * matrix_b->c.numerator;
2414  ReduceFraction(&tmp.c, &tmp.c);
2415 
2416  ASSERT(tmp.a.denominator != 0);
2417  ASSERT(tmp.b.denominator != 0);
2418  ASSERT(tmp.c.denominator != 0);
2419  ASSERT(tmp.d.denominator != 0);
2420 
2421  *output_matrix = tmp;
2422 }
2423 
2424 static void InvertMatrix(S_VT_MATRIX *matrix, S_VT_MATRIX *inverse)
2425 {
2426  S32BIT temp;
2427 
2428  /* Inverse:
2429  *
2430  * (a 0 b) (1/a 0 -b/a)
2431  * (0 c d) -> ( 0 1/c -d/c)
2432  * (0 0 1) ( 0 0 1 )
2433  *
2434  * The order used allows the output matrix to be the same as one of
2435  * the input matrices.
2436  */
2437 
2438  ASSERT(matrix->a.numerator != 0);
2439  ASSERT(matrix->c.numerator != 0);
2440 
2441  inverse->b.numerator = -matrix->b.numerator * matrix->a.denominator;
2442  inverse->b.denominator = matrix->b.denominator * matrix->a.numerator;
2443  if (inverse->b.denominator < 0)
2444  {
2445  inverse->b.numerator *= -1;
2446  inverse->b.denominator *= -1;
2447  }
2448  ReduceFraction(&inverse->b, &inverse->b);
2449 
2450  inverse->d.numerator = -matrix->d.numerator * matrix->c.denominator;
2451  inverse->d.denominator = matrix->d.denominator * matrix->c.numerator;
2452  if (inverse->d.denominator < 0)
2453  {
2454  inverse->d.numerator *= -1;
2455  inverse->d.denominator *= -1;
2456  }
2457  ReduceFraction(&inverse->d, &inverse->d);
2458 
2459  temp = matrix->a.numerator;
2460  inverse->a.numerator = matrix->a.denominator;
2461  inverse->a.denominator = temp;
2462  if (inverse->a.denominator < 0)
2463  {
2464  inverse->a.numerator *= -1;
2465  inverse->a.denominator *= -1;
2466  }
2467 
2468  temp = matrix->c.numerator;
2469  inverse->c.numerator = matrix->c.denominator;
2470  inverse->c.denominator = temp;
2471  if (inverse->c.denominator < 0)
2472  {
2473  inverse->c.numerator *= -1;
2474  inverse->c.denominator *= -1;
2475  }
2476 
2477  ASSERT(inverse->a.denominator != 0);
2478  ASSERT(inverse->b.denominator != 0);
2479  ASSERT(inverse->c.denominator != 0);
2480  ASSERT(inverse->d.denominator != 0);
2481 }
2482 
2483 /*!**************************************************************************
2484  * @brief Apply a transformation to a vector
2485  * @param matrix - the transformation matrix
2486  * @param input - the vector to transform
2487  * @param output - the transformed vector
2488  ****************************************************************************/
2489 static void ApplyTransformation(S_VT_MATRIX *matrix, S_VT_FRACT_RECT *input,
2490  S_VT_FRACT_RECT *output)
2491 {
2492  S_VT_FRACT_RECT tmp;
2493 
2494  tmp.width.numerator = input->width.numerator * matrix->a.numerator;
2495  tmp.width.denominator = input->width.denominator * matrix->a.denominator;
2496  tmp.height.numerator = input->height.numerator * matrix->c.numerator;
2497  tmp.height.denominator = input->height.denominator * matrix->c.denominator;
2498  ReduceFraction(&tmp.width, &tmp.width);
2499  ReduceFraction(&tmp.height, &tmp.height);
2500 
2501  tmp.left.numerator = input->left.numerator * matrix->a.numerator;
2502  tmp.left.denominator = input->left.denominator * matrix->a.denominator;
2503  tmp.top.numerator = input->top.numerator * matrix->c.numerator;
2504  tmp.top.denominator = input->top.denominator * matrix->c.denominator;
2505 
2506  AddFractions(&tmp.left, &matrix->b, &tmp.left);
2507  AddFractions(&tmp.top, &matrix->d, &tmp.top);
2508 
2509  *output = tmp;
2510 }
2511 
2512 /*!**************************************************************************
2513  * @brief Find the AFD transformation
2514  * @param state - conversion state
2515  * @return The AFD transformation, or NONE if not found
2516  ****************************************************************************/
2517 static E_FORMAT_CONVERSION FindAfdTransformation(S_VT_CONVERSION_STATE *state)
2518 {
2519  E_FORMAT_CONVERSION trans;
2520  size_t i;
2521 
2522  DBG(("Looking for AFD transformation (%d, %s, %s, %s)\n",
2523  state->afd,
2524  state->video_aspect_ratio == ASPECT_RATIO_4_3 ? "ASPECT_RATIO_4_3" :
2525  state->video_aspect_ratio == ASPECT_RATIO_16_9 ? "ASPECT_RATIO_16_9" :
2526  "UNKNOWN",
2527  state->display_aspect_ratio == ASPECT_RATIO_4_3 ? "ASPECT_RATIO_4_3" :
2528  state->display_aspect_ratio == ASPECT_RATIO_16_9 ? "ASPECT_RATIO_16_9" :
2529  "UNKNOWN",
2530  state->afd_preference == AFD_PREFERENCE_CCO ? "AFD_PREFERENCE_CCO" :
2531  state->afd_preference == AFD_PREFERENCE_14_9_LB ? "AFD_PREFERENCE_14_9_LB" :
2532  state->afd_preference == AFD_PREFERENCE_16_9_LB ? "AFD_PREFERENCE_16_9_LB" :
2533  state->afd_preference == AFD_PREFERENCE_AUTO ? "AFD_PREFERENCE_AUTO" :
2534  "UNKNOWN"));
2535 
2536  for (i = 0; i < sizeof(afd_table) / sizeof(*afd_table); i++)
2537  {
2538  /* Use AFD_PREFERENCE_AUTO as a fall-back */
2539  if ((afd_table[i].afd == state->afd) &&
2540  (afd_table[i].video_aspect_ratio == state->video_aspect_ratio) &&
2541  (afd_table[i].display_aspect_ratio == state->display_aspect_ratio) &&
2542  ((afd_table[i].afd_preference == state->afd_preference) ||
2543  (afd_table[i].afd_preference == AFD_PREFERENCE_AUTO)))
2544  {
2545  trans = afd_table[i].transformation;
2546  DBG(("Found transformation %s\n",
2547  trans == FORMAT_CONVERSION_PILLAR_BOX ? "FORMAT_CONVERSION_PILLAR_BOX" :
2548  trans == FORMAT_CONVERSION_ZOOM_4_3 ? "FORMAT_CONVERSION_ZOOM_4_3" :
2549  trans == FORMAT_CONVERSION_ZOOM_14_9 ? "FORMAT_CONVERSION_ZOOM_14_9" :
2550  trans == FORMAT_CONVERSION_LETTERBOX ? "FORMAT_CONVERSION_LETTERBOX" :
2551  trans == FORMAT_CONVERSION_LETTERBOX_14_9 ? "FORMAT_CONVERSION_LETTERBOX_14_9" :
2552  trans == FORMAT_CONVERSION_PANSCAN ? "FORMAT_CONVERSION_PANSCAN" :
2553  trans == FORMAT_CONVERSION_PANSCAN_14_9 ? "FORMAT_CONVERSION_PANSCAN_14_9" :
2554  "NONE"));
2555 
2556  return trans;
2557  }
2558  }
2559 
2560  return FORMAT_CONVERSION_IGNORE;
2561 }
2562 
2563 static void Scale_352_288_Video(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform)
2564 {
2565  ASSERT(state);
2566 
2567  transform->a = MakeFraction(state->resolution_width, 360);
2568  transform->b = MakeFraction(state->resolution_width, 90);
2569  transform->c = MakeFraction(state->resolution_height, 288);
2570  transform->d = MakeFraction(0, 1);
2571 }
2572 
2573 static void Scale_352_576_Video(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform)
2574 {
2575  ASSERT(state);
2576 
2577  transform->a = MakeFraction(state->resolution_width, 360);
2578  transform->b = MakeFraction(state->resolution_width, 90);
2579  transform->c = MakeFraction(state->resolution_height, 576);
2580  transform->d = MakeFraction(0, 1);
2581 }
2582 
2583 static void Scale_480_576_Video(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform)
2584 {
2585  ASSERT(state);
2586 
2587  transform->a = MakeFraction(state->resolution_width, 480);
2588  transform->b = MakeFraction(0, 1);
2589  transform->c = MakeFraction(state->resolution_height, 576);
2590  transform->d = MakeFraction(0, 1);
2591 }
2592 
2593 static void Scale_544_576_Video(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform)
2594 {
2595  ASSERT(state);
2596 
2597  transform->a = MakeFraction(state->resolution_width, 540);
2598  transform->b = MakeFraction(0 - state->resolution_width, 270);
2599  transform->c = MakeFraction(state->resolution_height, 576);
2600  transform->d = MakeFraction(0, 1);
2601 }
2602 
2603 static void Scale_Video(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform)
2604 {
2605  ASSERT(state);
2606 
2607  transform->a = MakeFraction(state->resolution_width, state->video_width);
2608  transform->b = MakeFraction(0, 1);
2609  transform->c = MakeFraction(state->resolution_height, state->video_height);
2610  transform->d = MakeFraction(0, 1);
2611 }
2612 
2613 static void Scale_ToScreen(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform)
2614 {
2615  ASSERT(state);
2616 
2617  transform->a = MakeFraction(state->screen_width, state->resolution_width);
2618  transform->b = MakeFraction(0, 1);
2619  transform->c = MakeFraction(state->screen_height, state->resolution_height);
2620  transform->d = MakeFraction(0, 1);
2621 }
2622 
2623 static void Scale_HbbToScreen(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform)
2624 {
2625  ASSERT(state);
2626 
2627  transform->a = MakeFraction(state->screen_width, HD_WIDTH);
2628  transform->b = MakeFraction(0, 1);
2629  transform->c = MakeFraction(state->screen_height, HD_HEIGHT);
2630  transform->d = MakeFraction(0, 1);
2631 }
2632 
2633 static void Scale_Pillarbox(S_VT_CONVERSION_STATE *state, S32BIT width,
2634  S32BIT height, S_VT_MATRIX *transform)
2635 {
2636  USE_UNWANTED_PARAM(state);
2637  USE_UNWANTED_PARAM(height);
2638 
2639  transform->a = MakeFraction(3, 4);
2640  transform->b = MakeFraction(width, 8);
2641  transform->c = MakeFraction(1, 1);
2642  transform->d = MakeFraction(0, 1);
2643 }
2644 
2645 static void Scale_4_3_Zoom(S_VT_CONVERSION_STATE *state, S32BIT width,
2646  S32BIT height, S_VT_MATRIX *transform)
2647 {
2648  USE_UNWANTED_PARAM(state);
2649  USE_UNWANTED_PARAM(width);
2650 
2651  transform->a = MakeFraction(1, 1);
2652  transform->b = MakeFraction(0, 1);
2653  transform->c = MakeFraction(4, 3);
2654  transform->d = MakeFraction(-height, 6);
2655 }
2656 
2657 static void Scale_14_9_Zoom(S_VT_CONVERSION_STATE *state, S32BIT width,
2658  S32BIT height, S_VT_MATRIX *transform)
2659 {
2660  USE_UNWANTED_PARAM(state);
2661 
2662  transform->a = MakeFraction(7, 8);
2663  transform->b = MakeFraction(width, 16);
2664  transform->c = MakeFraction(7, 6);
2665  transform->d = MakeFraction(-height, 12);
2666 }
2667 
2668 static void Scale_14_9_Centre(S_VT_CONVERSION_STATE *state, S32BIT width,
2669  S32BIT height, S_VT_MATRIX *transform)
2670 {
2671  USE_UNWANTED_PARAM(state);
2672 
2673  transform->a = MakeFraction(8, 7);
2674  transform->b = MakeFraction(-width, 14);
2675  transform->c = MakeFraction(8, 7);
2676  transform->d = MakeFraction(-height, 14);
2677 }
2678 
2679 static void Scale_4_3_Centre(S_VT_CONVERSION_STATE *state, S32BIT width,
2680  S32BIT height, S_VT_MATRIX *transform)
2681 {
2682  USE_UNWANTED_PARAM(state);
2683 
2684  transform->a = MakeFraction(4, 3);
2685  transform->b = MakeFraction(-width, 6);
2686  transform->c = MakeFraction(4, 3);
2687  transform->d = MakeFraction(-height, 6);
2688 }
2689 
2690 static void Scale_16_9_Letterbox(S_VT_CONVERSION_STATE *state, S32BIT width,
2691  S32BIT height, S_VT_MATRIX *transform)
2692 {
2693  USE_UNWANTED_PARAM(state);
2694  USE_UNWANTED_PARAM(width);
2695 
2696  transform->a = MakeFraction(1, 1);
2697  transform->b = MakeFraction(0, 1);
2698  transform->c = MakeFraction(3, 4);
2699  transform->d = MakeFraction(height, 8);
2700 }
2701 
2702 static void Scale_14_9_Letterbox(S_VT_CONVERSION_STATE *state, S32BIT width,
2703  S32BIT height, S_VT_MATRIX *transform)
2704 {
2705  USE_UNWANTED_PARAM(state);
2706 
2707  transform->a = MakeFraction(8, 7);
2708  transform->b = MakeFraction(-width, 14);
2709  transform->c = MakeFraction(6, 7);
2710  transform->d = MakeFraction(height, 14);
2711 }
2712 
2713 static void Scale_CentreCutOut(S_VT_CONVERSION_STATE *state, S32BIT width,
2714  S32BIT height, S_VT_MATRIX *transform)
2715 {
2716  USE_UNWANTED_PARAM(state);
2717  USE_UNWANTED_PARAM(height);
2718 
2719  transform->a = MakeFraction(4, 3);
2720  transform->b = MakeFraction(-width, 6);
2721  transform->c = MakeFraction(1, 1);
2722  transform->d = MakeFraction(0, 1);
2723 }
2724 
2725 static void Scale_16_9_Zoom(S_VT_CONVERSION_STATE *state, S32BIT width,
2726  S32BIT height, S_VT_MATRIX *transform)
2727 {
2728  USE_UNWANTED_PARAM(state);
2729 
2730  transform->a = MakeFraction(7, 6);
2731  transform->b = MakeFraction(-width, 12);
2732  transform->c = MakeFraction(7, 6);
2733  transform->d = MakeFraction(-height, 12);
2734 }
2735 
2736 static void UpdateResolution(S_VT_CONVERSION_STATE *state)
2737 {
2738  if (state->app_scaling_enabled)
2739  {
2740  state->resolution_width = state->screen_width;
2741  state->resolution_height = state->screen_height;
2742  }
2743  else if (state->mheg_enabled)
2744  {
2745  state->resolution_width = state->mheg_resolution_width;
2746  state->resolution_height = state->mheg_resolution_height;
2747  }
2748  else if (state->hbb_enabled)
2749  {
2750  state->resolution_width = HD_WIDTH;
2751  state->resolution_height = HD_HEIGHT;
2752  }
2753  else
2754  {
2755  state->resolution_width = SD_WIDTH;
2756  state->resolution_height = SD_HEIGHT;
2757  }
2758 }
2759 
2760 static void MhegScaling(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform)
2761 {
2762  S32BIT x = state->mheg_scaling_rect.left;
2763  S32BIT y = state->mheg_scaling_rect.top;
2764  S32BIT width = state->mheg_scaling_rect.width;
2765  S32BIT height = state->mheg_scaling_rect.height;
2766  S32BIT res_width = state->mheg_resolution_width;
2767  S32BIT res_height = state->mheg_resolution_height;
2768 
2769  transform->a = MakeFraction(width, res_width);
2770  transform->b = MakeFraction(x, 1);
2771  transform->c = MakeFraction(height, res_height);
2772  transform->d = MakeFraction(y, 1);
2773 }
2774 
2775 static void HbbScaling(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform)
2776 {
2777  S32BIT x = state->hbb_window_rect.left;
2778  S32BIT y = state->hbb_window_rect.top;
2779  S32BIT width = state->hbb_window_rect.width;
2780  S32BIT height = state->hbb_window_rect.height;
2781  S32BIT adjust;
2782  if (state->video_aspect_ratio == ASPECT_RATIO_4_3)
2783  {
2784  adjust = (height * 4) / 3;
2785  if (width > adjust)
2786  {
2787  x += (width - adjust) / 2;
2788  width = adjust;
2789  }
2790  else
2791  {
2792  adjust = (width * 3) / 4;
2793  if (height > adjust)
2794  {
2795  y += (height - adjust) / 2;
2796  height = adjust;
2797  }
2798  }
2799  }
2800  else /*ASPECT_RATIO_16_9*/
2801  {
2802  adjust = (height * 16) / 9;
2803  if (width > adjust)
2804  {
2805  x += (width - adjust) / 2;
2806  width = adjust;
2807  }
2808  else
2809  {
2810  adjust = (width * 9) / 16;
2811  if (height > adjust)
2812  {
2813  y += (height - adjust) / 2;
2814  height = adjust;
2815  }
2816  }
2817  }
2818  transform->a = MakeFraction(width, HD_WIDTH);
2819  transform->b = MakeFraction(x, 1);
2820  transform->c = MakeFraction(height, HD_HEIGHT);
2821  transform->d = MakeFraction(y, 1);
2822 }
2823 
2824 static void AppScaling(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform)
2825 {
2826  S32BIT x = state->app_scaling_window.left;
2827  S32BIT y = state->app_scaling_window.top;
2828  S32BIT width = state->app_scaling_window.width;
2829  S32BIT height = state->app_scaling_window.height;
2830 
2831  ASSERT(state);
2832 
2833  transform->a = MakeFraction(width, state->resolution_width);
2834  transform->b = MakeFraction(x, 1);
2835  transform->c = MakeFraction(height, state->resolution_height);
2836  transform->d = MakeFraction(y, 1);
2837 }
2838 
2839 static void NoScaling(S_VT_CONVERSION_STATE *state, S_VT_MATRIX *transform)
2840 {
2841  USE_UNWANTED_PARAM(state);
2842 
2843  transform->a = MakeFraction(1, 1);
2844  transform->b = MakeFraction(0, 1);
2845  transform->c = MakeFraction(1, 1);
2846  transform->d = MakeFraction(0, 1);
2847 }
2848 
2849 static S_VT_FRACTION MakeFraction(S32BIT numerator, S32BIT denominator)
2850 {
2851  S_VT_FRACTION fraction;
2852  fraction.numerator = numerator;
2853  fraction.denominator = denominator;
2854  return fraction;
2855 }
2856 
2857 static S_VT_FRACT_RECT MakeRectangle(S32BIT left, S32BIT top, S32BIT width, S32BIT height)
2858 {
2859  S_VT_FRACT_RECT rect;
2860  rect.left.numerator = left;
2861  rect.top.numerator = top;
2862  rect.width.numerator = width;
2863  rect.height.numerator = height;
2864 
2865  rect.left.denominator = 1;
2866  rect.top.denominator = 1;
2867  rect.width.denominator = 1;
2868  rect.height.denominator = 1;
2869  return rect;
2870 }
2871 
Header file - Function prototypes for A/V control.
void VT_SetHbbtvWindow(void *context, S_RECTANGLE *output)
Set HBBTV output window.
Definition: vtc.c:832
void VT_SetProfileHbbtv(void *context, BOOLEAN enable)
Set profile to apply HBBTV option.
Definition: vtc.c:811
void VT_SetMhegScalingResolution(void *context, U16BIT width, U16BIT height)
Set MHEG5 scaling resolution.
Definition: vtc.c:633
void VT_GetVideoResolution(void *context, U16BIT *width, U16BIT *height)
Return the current video resolution.
Definition: vtc.c:977
void VT_SetUserPreferenceChangedCallback(void *context, F_VT_NOTIFICATION_CALLBACK callback, void *user_data)
Set user preference change callback.
Definition: vtc.c:921
void VT_GetScreenResolution(void *context, U16BIT *width, U16BIT *height)
Return the current screen resolution.
Definition: vtc.c:960
void VT_SetAppScaling(void *context, S_RECTANGLE *window)
Set application scaling information.
Definition: vtc.c:686
void VT_SetVideoChangedCallback(void *context, F_VT_NOTIFICATION_CALLBACK callback, void *user_data)
Set video change callback.
Definition: vtc.c:898
void VT_SetCustomModeCallback(void *context, F_VT_CUSTOM_MODE_CALLBACK callback)
Set customer mode callback.
Definition: vtc.c:613
E_FORMAT_CONVERSION(* F_VT_CUSTOM_MODE_CALLBACK)(E_ASPECT_RATIO video_aspect_ratio, E_ASPECT_RATIO display_aspect_ratio)
Callback used by the VTC module to determine what format conversion needs to be applied when the aspe...
Definition: vtctype.h:69
void VT_SetAfd(void *context, U8BIT afd_value)
Set current AFD (active format descriptor value)
Definition: vtc.c:446
BOOLEAN VT_IsOsdScaled(void *context)
Check if osd must be scaled due to MHEG scene aspect ratio.
Definition: vtc.c:1007
void VT_SetDisplayAspectRatio(void *context, E_ASPECT_RATIO aspect_ratio)
Set display aspect ratio.
Definition: vtc.c:548
E_STB_AV_DECODER_STATUS VT_GetDecoderStatus(void *context)
Get the decoder status.
Definition: vtc.c:1049
void VT_SetMhegScaling(void *context, S_RECTANGLE *scaling)
Set MHEG-5 scaling information.
Definition: vtc.c:657
E_FORMAT_CONVERSION VT_GetDecoderFormatConversion(void *context)
Return the current decoder format conversion.
Definition: vtc.c:939
E_ASPECT_RATIO VT_GetVideoAspectRatio(void *context)
Get video aspect ratio.
Definition: vtc.c:492
void VT_Close(void *context)
Close video transformation manager.
Definition: vtc.c:412
void VT_SetMhegAspectRatio(void *context, E_ASPECT_RATIO aspect_ratio)
Set MHEG-5 aspect ratio.
Definition: vtc.c:510
void VT_SetVideoAlignmentPref(void *context, E_VIDEO_ASPECT_MODE alignment)
Set user preference for video aspect ratio alignment.
Definition: vtc.c:572
void VT_SetVideoAspectRatio(void *context, E_ASPECT_RATIO aspect_ratio)
Set video aspect ratio.
Definition: vtc.c:469
void VT_GetWss(void *context, U8BIT *wss)
Return WSS (wide-screen signalling) value.
Definition: vtc.c:879
void VT_Enable(void *context, BOOLEAN enable)
Enable or disable transformation calculations.
Definition: vtc.c:424
Debug functions header file.
void VT_SetProfileMheg5(void *context, BOOLEAN enable)
Set profile to apply MHEG5 option.
Definition: vtc.c:790
Definition: vtc.c:94
void VT_SetScreenResolution(void *context, U16BIT width, U16BIT height)
Set screen resolution.
Definition: vtc.c:744
E_ASPECT_RATIO VT_GetDisplayAspectRatio(void *context)
Get display aspect ratio.
Definition: vtc.c:533
System Wide Global Technical Data Type Definitions.
void VT_SetVideoResolution(void *context, U16BIT width, U16BIT height)
Set video resolution.
Definition: vtc.c:717
void * VT_Open(S_VT_OPTIONS *options)
Open video transformation manager.
Definition: vtc.c:348
Blank description.
void VT_SetDecoderStatus(void *context, E_STB_AV_DECODER_STATUS status)
Set the decoder status.
Definition: vtc.c:1029
Definition: vtc.c:84
void VT_SetMhegVideoAlignment(void *context, E_VIDEO_ASPECT_MODE mode)
Set widescreeen alignment mode for MHEG-5.
Definition: vtc.c:770
void VT_GetVideoTransformation(void *context, S_RECTANGLE *input_rect, S_RECTANGLE *output_rect)
Get the current video transfromation rectangles.
Definition: vtc.c:863