1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18#include <stdio.h>
19#include <string.h>
20#include <unistd.h>
21#include <sys/time.h>
22#include <fcntl.h>
23
24#include <OMXAL/OpenMAXAL.h>
25#include <OMXAL/OpenMAXAL_Android.h> // for VP8 definitions
26
27#define NUM_ENGINE_INTERFACES 1
28
29char unknown[50];
30
31//-----------------------------------------------------------------
32/* Exits the application if an error is encountered */
33#define ExitOnError(x) ExitOnErrorFunc(x,__LINE__)
34
35void ExitOnErrorFunc( XAresult result , int line)
36{
37    if (XA_RESULT_SUCCESS != result) {
38        fprintf(stderr, "Error %u encountered at line %d, exiting\n", result, line);
39        exit(EXIT_FAILURE);
40    }
41}
42
43const char* videoCodecIdToString(XAuint32 decoderId) {
44    switch(decoderId) {
45    case XA_VIDEOCODEC_MPEG2: return "XA_VIDEOCODEC_MPEG2"; break;
46    case XA_VIDEOCODEC_H263: return "XA_VIDEOCODEC_H263"; break;
47    case XA_VIDEOCODEC_MPEG4: return "XA_VIDEOCODEC_MPEG4"; break;
48    case XA_VIDEOCODEC_AVC: return "XA_VIDEOCODEC_AVC"; break;
49    case XA_VIDEOCODEC_VC1: return "XA_VIDEOCODEC_VC1"; break;
50    case XA_ANDROID_VIDEOCODEC_VP8: return "XA_ANDROID_VIDEOCODEC_VP8"; break;
51    default:
52        sprintf(unknown, "Video codec %d unknown to OpenMAX AL", decoderId);
53        return unknown;
54    }
55}
56
57// Use a table of [integer, string] entries to map an integer to a string
58
59typedef struct {
60    XAuint32 id;
61    const char *string;
62} id_to_string_t;
63
64const char *id_to_string(XAuint32 id, const id_to_string_t *table, size_t numEntries)
65{
66    size_t i;
67    for (i = 0; i < numEntries; ++i) {
68        if (id == table[i].id) {
69            return table[i].string;
70        }
71    }
72    return "Unknown";
73}
74
75// Use a table of [integer, table] entries to map a pair of integers to a string
76
77typedef struct {
78    XAuint32 id1;
79    const id_to_string_t *id2_table;
80    size_t id2_numEntries;
81} id_pair_to_string_t;
82
83const char *id_pair_to_string(XAuint32 id1, XAuint32 id2, const id_pair_to_string_t *table,
84        size_t numEntries)
85{
86    size_t i;
87    for (i = 0; i < numEntries; ++i) {
88        if (id1 == table[i].id1) {
89            return id_to_string(id2, table[i].id2_table, table[i].id2_numEntries);
90        }
91    }
92    return "Unknown";
93}
94
95// Map a video codec and profile to string
96
97const char *videoProfileToString(XAuint32 codec, XAuint32 profile) {
98    // http://en.wikipedia.org/wiki/H.262/MPEG-2_Part_2
99    static const id_to_string_t MPEG2[] = {
100        {XA_VIDEOPROFILE_MPEG2_SIMPLE,  "Simple"},
101        {XA_VIDEOPROFILE_MPEG2_MAIN,    "Main"},
102        {XA_VIDEOPROFILE_MPEG2_422,     "4:2:2"},
103        {XA_VIDEOPROFILE_MPEG2_SNR,     "SNR Scalable"},
104        {XA_VIDEOPROFILE_MPEG2_SPATIAL, "Spatially Scalable"},
105        {XA_VIDEOPROFILE_MPEG2_HIGH,    "High"},
106    }, H263[] = {
107        {XA_VIDEOPROFILE_H263_BASELINE,           "baseline"},
108        {XA_VIDEOPROFILE_H263_H320CODING,         "H320 coding"},
109        {XA_VIDEOPROFILE_H263_BACKWARDCOMPATIBLE, "backwards compatible"},
110        {XA_VIDEOPROFILE_H263_ISWV2,              "isw v2"},
111        {XA_VIDEOPROFILE_H263_ISWV3,              "isw v3"},
112        {XA_VIDEOPROFILE_H263_HIGHCOMPRESSION,    "high compression"},
113        {XA_VIDEOPROFILE_H263_INTERNET,           "internet"},
114        {XA_VIDEOPROFILE_H263_INTERLACE,          "interlace"},
115        {XA_VIDEOPROFILE_H263_HIGHLATENCY,        "high latency"},
116    }, MPEG4[] = {
117        {XA_VIDEOPROFILE_MPEG4_SIMPLE,           "simple"},
118        {XA_VIDEOPROFILE_MPEG4_SIMPLESCALABLE,   "simple scalable"},
119        {XA_VIDEOPROFILE_MPEG4_CORE,             "core"},
120        {XA_VIDEOPROFILE_MPEG4_MAIN,             "main"},
121        {XA_VIDEOPROFILE_MPEG4_NBIT,             "nbit"},
122        {XA_VIDEOPROFILE_MPEG4_SCALABLETEXTURE,  "scalable texture"},
123        {XA_VIDEOPROFILE_MPEG4_SIMPLEFACE,       "simple face"},
124        {XA_VIDEOPROFILE_MPEG4_SIMPLEFBA,        "simple fba"},
125        {XA_VIDEOPROFILE_MPEG4_BASICANIMATED,    "basic animated"},
126        {XA_VIDEOPROFILE_MPEG4_HYBRID,           "hybrid"},
127        {XA_VIDEOPROFILE_MPEG4_ADVANCEDREALTIME, "advanced realtime"},
128        {XA_VIDEOPROFILE_MPEG4_CORESCALABLE,     "core scalable"},
129        {XA_VIDEOPROFILE_MPEG4_ADVANCEDCODING,   "advanced coding"},
130        {XA_VIDEOPROFILE_MPEG4_ADVANCEDCORE,     "advanced core"},
131        {XA_VIDEOPROFILE_MPEG4_ADVANCEDSCALABLE, "advanced scalable"},
132        // FIXME OpenMAX AL is out-of-date with respect to OpenMAX IL
133        {16,                                     "advanced simple"},
134    }, AVC[] = {
135        {XA_VIDEOPROFILE_AVC_BASELINE, "Baseline"},
136        {XA_VIDEOPROFILE_AVC_MAIN,     "Main"},
137        {XA_VIDEOPROFILE_AVC_EXTENDED, "Extended"},
138        {XA_VIDEOPROFILE_AVC_HIGH,     "High"},
139        {XA_VIDEOPROFILE_AVC_HIGH10,   "High 10"},
140        {XA_VIDEOPROFILE_AVC_HIGH422,  "High 4:2:2"},
141        {XA_VIDEOPROFILE_AVC_HIGH444,  "High 4:4:4"},
142    }, VC1[] = {
143        // FIXME sic should be XA_VIDEOPROFILE_*
144        {XA_VIDEOLEVEL_VC1_SIMPLE,   "simple"},
145        {XA_VIDEOLEVEL_VC1_MAIN,     "main"},
146        {XA_VIDEOLEVEL_VC1_ADVANCED, "advanced"},
147    };
148    static const id_pair_to_string_t table[] = {
149        {XA_VIDEOCODEC_MPEG2, MPEG2, sizeof(MPEG2) / sizeof(MPEG2[0])},
150        {XA_VIDEOCODEC_H263,  H263,  sizeof(H263)  / sizeof(H263[0])},
151        {XA_VIDEOCODEC_MPEG4, MPEG4, sizeof(MPEG4) / sizeof(MPEG4[0])},
152        {XA_VIDEOCODEC_AVC,   AVC,   sizeof(AVC)   / sizeof(AVC[0])},
153        {XA_VIDEOCODEC_VC1,   VC1,   sizeof(VC1)   / sizeof(VC1[0])},
154    };
155    return id_pair_to_string(codec, profile, table, sizeof(table) / sizeof(table[0]));
156}
157
158// Map a video codec and level to string
159
160const char* videoLevelToString(XAuint32 codec, XAuint32 level) {
161    static const id_to_string_t MPEG2[] = {
162        {XA_VIDEOLEVEL_MPEG2_LL,  "Low"},
163        {XA_VIDEOLEVEL_MPEG2_ML,  "Main"},
164        {XA_VIDEOLEVEL_MPEG2_H14, "H-14"},
165        {XA_VIDEOLEVEL_MPEG2_HL,  "High"},
166    }, H263[]= {
167        {XA_VIDEOLEVEL_H263_10, "10"},
168        {XA_VIDEOLEVEL_H263_20, "20"},
169        {XA_VIDEOLEVEL_H263_30, "30"},
170        {XA_VIDEOLEVEL_H263_40, "40"},
171        {XA_VIDEOLEVEL_H263_45, "45"},
172        {XA_VIDEOLEVEL_H263_50, "50"},
173        {XA_VIDEOLEVEL_H263_60, "60"},
174        {XA_VIDEOLEVEL_H263_70, "70"},
175    }, MPEG4[] = {
176        {XA_VIDEOLEVEL_MPEG4_0,  "0"},
177        {XA_VIDEOLEVEL_MPEG4_0b, "0b"},
178        {XA_VIDEOLEVEL_MPEG4_1,  "1"},
179        {XA_VIDEOLEVEL_MPEG4_2,  "2"},
180        {XA_VIDEOLEVEL_MPEG4_3,  "3"},
181        {XA_VIDEOLEVEL_MPEG4_4,  "4"},
182        {XA_VIDEOLEVEL_MPEG4_4a, "4a"},
183        // FIXME OpenMAX AL is out-of-date with respect to OpenMAX IL
184        {8,                      "5"},
185    }, AVC[] = {
186        {XA_VIDEOLEVEL_AVC_1,  "1"},
187        {XA_VIDEOLEVEL_AVC_1B, "1B"},
188        {XA_VIDEOLEVEL_AVC_11, "1.1"},
189        {XA_VIDEOLEVEL_AVC_12, "1.2"},
190        {XA_VIDEOLEVEL_AVC_13, "1.3"},
191        {XA_VIDEOLEVEL_AVC_2,  "2"},
192        {XA_VIDEOLEVEL_AVC_21, "2.1"},
193        {XA_VIDEOLEVEL_AVC_22, "2.2"},
194        {XA_VIDEOLEVEL_AVC_3,  "3"},
195        {XA_VIDEOLEVEL_AVC_31, "3.1"},
196        {XA_VIDEOLEVEL_AVC_32, "3.2"},
197        {XA_VIDEOLEVEL_AVC_4,  "4"},
198        {XA_VIDEOLEVEL_AVC_41, "4.1"},
199        {XA_VIDEOLEVEL_AVC_42, "4.2"},
200        {XA_VIDEOLEVEL_AVC_5,  "5"},
201        {XA_VIDEOLEVEL_AVC_51, "5.1"},
202    }, VC1[] = {
203        {XA_VIDEOLEVEL_VC1_LOW,    "Low"},
204        {XA_VIDEOLEVEL_VC1_MEDIUM, "Medium"},
205        {XA_VIDEOLEVEL_VC1_HIGH,   "High"},
206        {XA_VIDEOLEVEL_VC1_L0,     "L0"},
207        {XA_VIDEOLEVEL_VC1_L1,     "L1"},
208        {XA_VIDEOLEVEL_VC1_L2,     "L2"},
209        {XA_VIDEOLEVEL_VC1_L3,     "L3"},
210        {XA_VIDEOLEVEL_VC1_L4,     "L4"},
211    };
212    static const id_pair_to_string_t table[] = {
213        {XA_VIDEOCODEC_MPEG2, MPEG2, sizeof(MPEG2) / sizeof(MPEG2[0])},
214        {XA_VIDEOCODEC_H263,  H263,  sizeof(H263)  / sizeof(H263[0])},
215        {XA_VIDEOCODEC_MPEG4, MPEG4, sizeof(MPEG4) / sizeof(MPEG4[0])},
216        {XA_VIDEOCODEC_AVC,   AVC,   sizeof(AVC)   / sizeof(AVC[0])},
217        {XA_VIDEOCODEC_VC1,   VC1,   sizeof(VC1)   / sizeof(VC1[0])},
218    };
219    return id_pair_to_string(codec, level, table, sizeof(table) / sizeof(table[0]));
220}
221
222//-----------------------------------------------------------------
223void TestVideoDecoderCapabilities() {
224
225    XAObjectItf xa;
226    XAresult res;
227
228    /* parameters for the OpenMAX AL engine creation */
229    XAEngineOption EngineOption[] = {
230            {(XAuint32) XA_ENGINEOPTION_THREADSAFE, (XAuint32) XA_BOOLEAN_TRUE}
231    };
232    XAInterfaceID itfIidArray[NUM_ENGINE_INTERFACES] = { XA_IID_VIDEODECODERCAPABILITIES };
233    XAboolean     itfRequired[NUM_ENGINE_INTERFACES] = { XA_BOOLEAN_TRUE };
234
235    /* create OpenMAX AL engine */
236    res = xaCreateEngine( &xa, 1, EngineOption, NUM_ENGINE_INTERFACES, itfIidArray, itfRequired);
237    ExitOnError(res);
238
239    /* realize the engine in synchronous mode. */
240    res = (*xa)->Realize(xa, XA_BOOLEAN_FALSE); ExitOnError(res);
241
242    /* Get the video decoder capabilities interface which was explicitly requested */
243    XAVideoDecoderCapabilitiesItf decItf;
244    res = (*xa)->GetInterface(xa, XA_IID_VIDEODECODERCAPABILITIES, (void*)&decItf);
245    ExitOnError(res);
246
247    /* Query the platform capabilities */
248    XAuint32 numDecoders = 0;
249    XAuint32 *decoderIds = NULL;
250
251    /* -> Number of decoders */
252    res = (*decItf)->GetVideoDecoders(decItf, &numDecoders, NULL); ExitOnError(res);
253    fprintf(stdout, "Found %d video decoders\n", numDecoders);
254    if (0 == numDecoders) {
255        fprintf(stderr, "0 video decoders is not an acceptable number, exiting\n");
256        goto destroyRes;
257    }
258
259    /* -> Decoder list */
260    decoderIds = (XAuint32 *) malloc(numDecoders * sizeof(XAuint32));
261    res = (*decItf)->GetVideoDecoders(decItf, &numDecoders, decoderIds); ExitOnError(res);
262    fprintf(stdout, "Decoders:\n");
263    for(XAuint32 i = 0 ; i < numDecoders ; i++) {
264        fprintf(stdout, "decoder %d is %s\n", i, videoCodecIdToString(decoderIds[i]));
265    }
266
267    /* -> Decoder capabilities */
268    /*       for each decoder  */
269    for(XAuint32 i = 0 ; i < numDecoders ; i++) {
270        XAuint32 nbCombinations = 0;
271        /* get the number of profile / level combinations */
272        res = (*decItf)->GetVideoDecoderCapabilities(decItf, decoderIds[i], &nbCombinations, NULL);
273        ExitOnError(res);
274        fprintf(stdout, "decoder %s has %d profile/level combinations:\n\t",
275                videoCodecIdToString(decoderIds[i]), nbCombinations);
276        /* display the profile / level combinations */
277        for(XAuint32 pl = 0 ; pl < nbCombinations ; pl++) {
278            XAVideoCodecDescriptor decDescriptor;
279            XAuint32 decoder = decoderIds[i];
280            res = (*decItf)->GetVideoDecoderCapabilities(decItf, decoder, &pl, &decDescriptor);
281            ExitOnError(res);
282            XAuint32 profile = decDescriptor.profileSetting;
283            XAuint32 level = decDescriptor.levelSetting;
284            fprintf(stdout, "%u/%u ", profile, level);
285            ExitOnError(res);
286            printf("(%s/%s) ", videoProfileToString(decoder, profile),
287                    videoLevelToString(decoder, level));
288        }
289        fprintf(stdout, "\n");
290    }
291
292destroyRes:
293    free(decoderIds);
294
295    /* shutdown OpenMAX AL */
296    (*xa)->Destroy(xa);
297}
298
299
300//-----------------------------------------------------------------
301int main(int argc, char* const argv[])
302{
303    XAresult    result;
304    XAObjectItf sl;
305
306    fprintf(stdout, "OpenMAX AL test %s: exercises SLAudioDecoderCapabiltiesItf ", argv[0]);
307    fprintf(stdout, "and displays the list of supported video decoders, and for each, lists the ");
308    fprintf(stdout, "profile / levels combinations, that map to the constants defined in ");
309    fprintf(stdout, "\"XA_VIDEOPROFILE and XA_VIDEOLEVEL\" section of the specification\n\n");
310
311    TestVideoDecoderCapabilities();
312
313    return EXIT_SUCCESS;
314}
315