1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** USBX Component                                                        */
16 /**                                                                       */
17 /**   Video Class                                                         */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 
23 /* Include necessary system files.  */
24 
25 #define UX_SOURCE_CODE
26 
27 #include "ux_api.h"
28 #include "ux_host_class_video.h"
29 #include "ux_host_stack.h"
30 
31 /*
32     VS_FRAME_UNCOMPRESSED  : wWidth @ 5, wHeight @ 7, dwDefaultFrameInterval @ 21, bFrameIntervalType @ 25, intervals @ 26
33     VS_FRAME_MJPEG         : wWidth @ 5, wHeight @ 7, dwDefaultFrameInterval @ 21, bFrameIntervalType @ 25, intervals @ 26
34     VS_FRAME_FRAME_BASED   : wWidth @ 5, wHeight @ 7, dwDefaultFrameInterval @ 17, bFrameIntervalType @ 21, intervals @ 26
35     VS_FRAME_H264          : wWidth @ 4, wHeight @ 6, dwDefaultFrameInterval @ 39, bNumFrameIntervals @ 43, intervals @ 44
36     VS_FRAME_VP8           : wWidth @ 4, wHeight @ 6, dwDefaultFrameInterval @ 26, bNumFrameIntervals @ 30, intervals @ 31
37 */
38 static const UCHAR _ux_host_class_video_frame_descriptor_offsets[][5] =
39 {
40     { 5, 7, 21, 25, 26 },
41     { 5, 7, 17, 21, 26 },
42     { 4, 6, 39, 43, 44 },
43     { 4, 6, 26, 30, 31 },
44 };
45 #define _OFFSETS_UNCOMPRESSED_MJPEG             0
46 #define _OFFSETS_FRAME_BASED                    1
47 #define _OFFSETS_H264                           2
48 #define _OFFSETS_VP8                            3
49 
50 
51 /**************************************************************************/
52 /*                                                                        */
53 /*  FUNCTION                                               RELEASE        */
54 /*                                                                        */
55 /*    _ux_host_class_video_frame_data_get                 PORTABLE C      */
56 /*                                                           6.3.0        */
57 /*  AUTHOR                                                                */
58 /*                                                                        */
59 /*    Chaoqiong Xiao, Microsoft Corporation                               */
60 /*                                                                        */
61 /*  DESCRIPTION                                                           */
62 /*                                                                        */
63 /*    This function finds the frame data within the input terminal.       */
64 /*                                                                        */
65 /*  INPUT                                                                 */
66 /*                                                                        */
67 /*    video                                 Pointer to video class        */
68 /*    frame_data                            Frame request structure       */
69 /*                                                                        */
70 /*  OUTPUT                                                                */
71 /*                                                                        */
72 /*    Completion Status                                                   */
73 /*                                                                        */
74 /*  CALLS                                                                 */
75 /*                                                                        */
76 /*    _ux_system_error_handler              Log system error              */
77 /*    _ux_utility_descriptor_parse          Parse descriptor              */
78 /*                                                                        */
79 /*  CALLED BY                                                             */
80 /*                                                                        */
81 /*    Video Class                                                         */
82 /*                                                                        */
83 /*  RELEASE HISTORY                                                       */
84 /*                                                                        */
85 /*    DATE              NAME                      DESCRIPTION             */
86 /*                                                                        */
87 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
88 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
89 /*                                            resulting in version 6.1    */
90 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
91 /*                                            improved extracted data,    */
92 /*                                            resulting in version 6.3.0  */
93 /*                                                                        */
94 /**************************************************************************/
_ux_host_class_video_frame_data_get(UX_HOST_CLASS_VIDEO * video,UX_HOST_CLASS_VIDEO_PARAMETER_FRAME_DATA * frame_parameter)95 UINT  _ux_host_class_video_frame_data_get(UX_HOST_CLASS_VIDEO *video, UX_HOST_CLASS_VIDEO_PARAMETER_FRAME_DATA *frame_parameter)
96 {
97 
98 UCHAR                                           *descriptor;
99 ULONG                                           total_descriptor_length;
100 ULONG                                           descriptor_length;
101 ULONG                                           descriptor_type;
102 ULONG                                           descriptor_subtype;
103 UCHAR                                           *field_offsets;
104 
105 
106     /* Get the descriptor to the selected format.  */
107     descriptor =  video -> ux_host_class_video_current_format_address;
108     total_descriptor_length =  video -> ux_host_class_video_length_formats;
109 
110     /* Descriptors are arranged in order. First FORMAT then FRAME.  */
111     while (total_descriptor_length)
112     {
113 
114         /* Gather the length, type and subtype of the descriptor.  */
115         descriptor_length =   *descriptor;
116         descriptor_type =     *(descriptor + 1);
117         descriptor_subtype =  *(descriptor + 2);
118 
119         /* Make sure this descriptor has at least the minimum length.  */
120         if (descriptor_length < 3)
121         {
122 
123             /* Error trap. */
124             _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
125 
126             /* If trace is enabled, insert this event into the trace buffer.  */
127             UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
128 
129             return(UX_DESCRIPTOR_CORRUPTED);
130         }
131 
132         /* Must be CS_INTERFACE.  */
133         if (descriptor_type == UX_HOST_CLASS_VIDEO_CS_INTERFACE)
134         {
135 
136             /* Process relative to descriptor type.  */
137             switch (descriptor_subtype)
138             {
139 
140             case UX_HOST_CLASS_VIDEO_VS_FRAME_UNCOMPRESSED  : /* wWidth @ 5, wHeight @ 7, dwDefaultFrameInterval @ 21, bFrameIntervalType @ 25, intervals @ 26  */
141             case UX_HOST_CLASS_VIDEO_VS_FRAME_MJPEG         : /* wWidth @ 5, wHeight @ 7, dwDefaultFrameInterval @ 21, bFrameIntervalType @ 25, intervals @ 26  */
142             case UX_HOST_CLASS_VIDEO_VS_FRAME_FRAME_BASED   : /* wWidth @ 5, wHeight @ 7, dwDefaultFrameInterval @ 17, bFrameIntervalType @ 21, intervals @ 26  */
143             case UX_HOST_CLASS_VIDEO_VS_FRAME_H264          : /* wWidth @ 4, wHeight @ 6, dwDefaultFrameInterval @ 39, bNumFrameIntervals @ 43, intervals @ 44  */
144             case UX_HOST_CLASS_VIDEO_VS_FRAME_VP8           : /* wWidth @ 4, wHeight @ 6, dwDefaultFrameInterval @ 26, bNumFrameIntervals @ 30, intervals @ 31  */
145 
146                 /* We found a Frame descriptor.  Is it the right one ? */
147                 if (frame_parameter -> ux_host_class_video_parameter_frame_requested == *(descriptor + 3))
148                 {
149 
150                     /* Get key offsets.  */
151                     if (descriptor_subtype == UX_HOST_CLASS_VIDEO_VS_FRAME_FRAME_BASED)
152                         field_offsets = (UCHAR*)_ux_host_class_video_frame_descriptor_offsets[_OFFSETS_FRAME_BASED];
153                     else if (descriptor_subtype == UX_HOST_CLASS_VIDEO_VS_FRAME_H264)
154                         field_offsets = (UCHAR*)_ux_host_class_video_frame_descriptor_offsets[_OFFSETS_H264];
155                     else if (descriptor_subtype == UX_HOST_CLASS_VIDEO_VS_FRAME_VP8)
156                         field_offsets = (UCHAR*)_ux_host_class_video_frame_descriptor_offsets[_OFFSETS_VP8];
157                     else
158                         field_offsets = (UCHAR*)_ux_host_class_video_frame_descriptor_offsets[_OFFSETS_UNCOMPRESSED_MJPEG];
159 
160                     /* Save the frame subtype.  */
161                     frame_parameter -> ux_host_class_video_parameter_frame_subtype =  descriptor_type;
162 
163                     /* Save useful frame parameters. */
164                     frame_parameter -> ux_host_class_video_parameter_frame_width = _ux_utility_short_get(descriptor + field_offsets[0]);
165                     frame_parameter -> ux_host_class_video_parameter_frame_height = _ux_utility_short_get(descriptor + field_offsets[1]);
166                     frame_parameter -> ux_host_class_video_parameter_default_frame_interval = _ux_utility_long_get(descriptor + field_offsets[2]);
167                     frame_parameter -> ux_host_class_video_parameter_frame_interval_type = *(descriptor + field_offsets[3]);
168                     frame_parameter -> ux_host_class_video_parameter_frame_intervals = (descriptor + field_offsets[4]);
169 
170                     video -> ux_host_class_video_current_frame_address = descriptor;
171                     video -> ux_host_class_video_current_frame_interval = frame_parameter -> ux_host_class_video_parameter_default_frame_interval;
172 
173                     /* We are done here. */
174                     return(UX_SUCCESS);
175                 }
176                 break;
177             }
178         }
179 
180         /* Verify if the descriptor is still valid.  */
181         if (descriptor_length > total_descriptor_length)
182         {
183 
184             /* Error trap. */
185             _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
186 
187             /* If trace is enabled, insert this event into the trace buffer.  */
188             UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
189 
190             return(UX_DESCRIPTOR_CORRUPTED);
191         }
192 
193         /* Jump to the next descriptor if we have not reached the end.  */
194         descriptor +=  descriptor_length;
195 
196         /* And adjust the length left to parse in the descriptor.  */
197         total_descriptor_length -=  descriptor_length;
198     }
199 
200     /* Error trap. */
201     _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_VIDEO_WRONG_TYPE);
202 
203     /* We get here when either the report descriptor has a problem or we could
204        not find the right video device.  */
205     return(UX_HOST_CLASS_VIDEO_WRONG_TYPE);
206 }
207