1/*
2 * Copyright 2013, 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//#define LOG_NDEBUG 0
18#define LOG_TAG "VideoFormats"
19#include <utils/Log.h>
20
21#include "VideoFormats.h"
22
23#include <media/stagefright/foundation/ADebug.h>
24
25namespace android {
26
27// static
28const VideoFormats::config_t VideoFormats::mResolutionTable[][32] = {
29    {
30        // CEA Resolutions
31        { 640, 480, 60, false, 0, 0},
32        { 720, 480, 60, false, 0, 0},
33        { 720, 480, 60, true, 0, 0},
34        { 720, 576, 50, false, 0, 0},
35        { 720, 576, 50, true, 0, 0},
36        { 1280, 720, 30, false, 0, 0},
37        { 1280, 720, 60, false, 0, 0},
38        { 1920, 1080, 30, false, 0, 0},
39        { 1920, 1080, 60, false, 0, 0},
40        { 1920, 1080, 60, true, 0, 0},
41        { 1280, 720, 25, false, 0, 0},
42        { 1280, 720, 50, false, 0, 0},
43        { 1920, 1080, 25, false, 0, 0},
44        { 1920, 1080, 50, false, 0, 0},
45        { 1920, 1080, 50, true, 0, 0},
46        { 1280, 720, 24, false, 0, 0},
47        { 1920, 1080, 24, false, 0, 0},
48        { 0, 0, 0, false, 0, 0},
49        { 0, 0, 0, false, 0, 0},
50        { 0, 0, 0, false, 0, 0},
51        { 0, 0, 0, false, 0, 0},
52        { 0, 0, 0, false, 0, 0},
53        { 0, 0, 0, false, 0, 0},
54        { 0, 0, 0, false, 0, 0},
55        { 0, 0, 0, false, 0, 0},
56        { 0, 0, 0, false, 0, 0},
57        { 0, 0, 0, false, 0, 0},
58        { 0, 0, 0, false, 0, 0},
59        { 0, 0, 0, false, 0, 0},
60        { 0, 0, 0, false, 0, 0},
61        { 0, 0, 0, false, 0, 0},
62        { 0, 0, 0, false, 0, 0},
63    },
64    {
65        // VESA Resolutions
66        { 800, 600, 30, false, 0, 0},
67        { 800, 600, 60, false, 0, 0},
68        { 1024, 768, 30, false, 0, 0},
69        { 1024, 768, 60, false, 0, 0},
70        { 1152, 864, 30, false, 0, 0},
71        { 1152, 864, 60, false, 0, 0},
72        { 1280, 768, 30, false, 0, 0},
73        { 1280, 768, 60, false, 0, 0},
74        { 1280, 800, 30, false, 0, 0},
75        { 1280, 800, 60, false, 0, 0},
76        { 1360, 768, 30, false, 0, 0},
77        { 1360, 768, 60, false, 0, 0},
78        { 1366, 768, 30, false, 0, 0},
79        { 1366, 768, 60, false, 0, 0},
80        { 1280, 1024, 30, false, 0, 0},
81        { 1280, 1024, 60, false, 0, 0},
82        { 1400, 1050, 30, false, 0, 0},
83        { 1400, 1050, 60, false, 0, 0},
84        { 1440, 900, 30, false, 0, 0},
85        { 1440, 900, 60, false, 0, 0},
86        { 1600, 900, 30, false, 0, 0},
87        { 1600, 900, 60, false, 0, 0},
88        { 1600, 1200, 30, false, 0, 0},
89        { 1600, 1200, 60, false, 0, 0},
90        { 1680, 1024, 30, false, 0, 0},
91        { 1680, 1024, 60, false, 0, 0},
92        { 1680, 1050, 30, false, 0, 0},
93        { 1680, 1050, 60, false, 0, 0},
94        { 1920, 1200, 30, false, 0, 0},
95        { 1920, 1200, 60, false, 0, 0},
96        { 0, 0, 0, false, 0, 0},
97        { 0, 0, 0, false, 0, 0},
98    },
99    {
100        // HH Resolutions
101        { 800, 480, 30, false, 0, 0},
102        { 800, 480, 60, false, 0, 0},
103        { 854, 480, 30, false, 0, 0},
104        { 854, 480, 60, false, 0, 0},
105        { 864, 480, 30, false, 0, 0},
106        { 864, 480, 60, false, 0, 0},
107        { 640, 360, 30, false, 0, 0},
108        { 640, 360, 60, false, 0, 0},
109        { 960, 540, 30, false, 0, 0},
110        { 960, 540, 60, false, 0, 0},
111        { 848, 480, 30, false, 0, 0},
112        { 848, 480, 60, false, 0, 0},
113        { 0, 0, 0, false, 0, 0},
114        { 0, 0, 0, false, 0, 0},
115        { 0, 0, 0, false, 0, 0},
116        { 0, 0, 0, false, 0, 0},
117        { 0, 0, 0, false, 0, 0},
118        { 0, 0, 0, false, 0, 0},
119        { 0, 0, 0, false, 0, 0},
120        { 0, 0, 0, false, 0, 0},
121        { 0, 0, 0, false, 0, 0},
122        { 0, 0, 0, false, 0, 0},
123        { 0, 0, 0, false, 0, 0},
124        { 0, 0, 0, false, 0, 0},
125        { 0, 0, 0, false, 0, 0},
126        { 0, 0, 0, false, 0, 0},
127        { 0, 0, 0, false, 0, 0},
128        { 0, 0, 0, false, 0, 0},
129        { 0, 0, 0, false, 0, 0},
130        { 0, 0, 0, false, 0, 0},
131        { 0, 0, 0, false, 0, 0},
132        { 0, 0, 0, false, 0, 0},
133    }
134};
135
136VideoFormats::VideoFormats() {
137    memcpy(mConfigs, mResolutionTable, sizeof(mConfigs));
138
139    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
140        mResolutionEnabled[i] = 0;
141    }
142
143    setNativeResolution(RESOLUTION_CEA, 0);  // default to 640x480 p60
144}
145
146void VideoFormats::setNativeResolution(ResolutionType type, size_t index) {
147    CHECK_LT(type, kNumResolutionTypes);
148    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));
149
150    mNativeType = type;
151    mNativeIndex = index;
152
153    setResolutionEnabled(type, index);
154}
155
156void VideoFormats::getNativeResolution(
157        ResolutionType *type, size_t *index) const {
158    *type = mNativeType;
159    *index = mNativeIndex;
160}
161
162void VideoFormats::disableAll() {
163    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
164        mResolutionEnabled[i] = 0;
165        for (size_t j = 0; j < 32; j++) {
166            mConfigs[i][j].profile = mConfigs[i][j].level = 0;
167        }
168    }
169}
170
171void VideoFormats::enableAll() {
172    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
173        mResolutionEnabled[i] = 0xffffffff;
174        for (size_t j = 0; j < 32; j++) {
175            mConfigs[i][j].profile = (1ul << PROFILE_CBP);
176            mConfigs[i][j].level = (1ul << LEVEL_31);
177        }
178    }
179}
180
181void VideoFormats::enableResolutionUpto(
182        ResolutionType type, size_t index,
183        ProfileType profile, LevelType level) {
184    size_t width, height, fps, score;
185    bool interlaced;
186    if (!GetConfiguration(type, index, &width, &height,
187            &fps, &interlaced)) {
188        ALOGE("Maximum resolution not found!");
189        return;
190    }
191    score = width * height * fps * (!interlaced + 1);
192    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
193        for (size_t j = 0; j < 32; j++) {
194            if (GetConfiguration((ResolutionType)i, j,
195                    &width, &height, &fps, &interlaced)
196                    && score >= width * height * fps * (!interlaced + 1)) {
197                setResolutionEnabled((ResolutionType)i, j);
198                setProfileLevel((ResolutionType)i, j, profile, level);
199            }
200        }
201    }
202}
203
204void VideoFormats::setResolutionEnabled(
205        ResolutionType type, size_t index, bool enabled) {
206    CHECK_LT(type, kNumResolutionTypes);
207    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));
208
209    if (enabled) {
210        mResolutionEnabled[type] |= (1ul << index);
211        mConfigs[type][index].profile = (1ul << PROFILE_CBP);
212        mConfigs[type][index].level = (1ul << LEVEL_31);
213    } else {
214        mResolutionEnabled[type] &= ~(1ul << index);
215        mConfigs[type][index].profile = 0;
216        mConfigs[type][index].level = 0;
217    }
218}
219
220void VideoFormats::setProfileLevel(
221        ResolutionType type, size_t index,
222        ProfileType profile, LevelType level) {
223    CHECK_LT(type, kNumResolutionTypes);
224    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));
225
226    mConfigs[type][index].profile = (1ul << profile);
227    mConfigs[type][index].level = (1ul << level);
228}
229
230void VideoFormats::getProfileLevel(
231        ResolutionType type, size_t index,
232        ProfileType *profile, LevelType *level) const{
233    CHECK_LT(type, kNumResolutionTypes);
234    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));
235
236    int i, bestProfile = -1, bestLevel = -1;
237
238    for (i = 0; i < kNumProfileTypes; ++i) {
239        if (mConfigs[type][index].profile & (1ul << i)) {
240            bestProfile = i;
241        }
242    }
243
244    for (i = 0; i < kNumLevelTypes; ++i) {
245        if (mConfigs[type][index].level & (1ul << i)) {
246            bestLevel = i;
247        }
248    }
249
250    if (bestProfile == -1 || bestLevel == -1) {
251        ALOGE("Profile or level not set for resolution type %d, index %zu",
252                type, index);
253        bestProfile = PROFILE_CBP;
254        bestLevel = LEVEL_31;
255    }
256
257    *profile = (ProfileType) bestProfile;
258    *level = (LevelType) bestLevel;
259}
260
261bool VideoFormats::isResolutionEnabled(
262        ResolutionType type, size_t index) const {
263    CHECK_LT(type, kNumResolutionTypes);
264    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));
265
266    return mResolutionEnabled[type] & (1ul << index);
267}
268
269// static
270bool VideoFormats::GetConfiguration(
271        ResolutionType type,
272        size_t index,
273        size_t *width, size_t *height, size_t *framesPerSecond,
274        bool *interlaced) {
275    CHECK_LT(type, kNumResolutionTypes);
276
277    if (index >= 32) {
278        return false;
279    }
280
281    const config_t *config = &mResolutionTable[type][index];
282
283    if (config->width == 0) {
284        return false;
285    }
286
287    if (width) {
288        *width = config->width;
289    }
290
291    if (height) {
292        *height = config->height;
293    }
294
295    if (framesPerSecond) {
296        *framesPerSecond = config->framesPerSecond;
297    }
298
299    if (interlaced) {
300        *interlaced = config->interlaced;
301    }
302
303    return true;
304}
305
306bool VideoFormats::parseH264Codec(const char *spec) {
307    unsigned profile, level, res[3];
308
309    if (sscanf(
310            spec,
311            "%02x %02x %08X %08X %08X",
312            &profile,
313            &level,
314            &res[0],
315            &res[1],
316            &res[2]) != 5) {
317        return false;
318    }
319
320    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
321        for (size_t j = 0; j < 32; ++j) {
322            if (res[i] & (1ul << j)){
323                mResolutionEnabled[i] |= (1ul << j);
324                if (profile > mConfigs[i][j].profile) {
325                    // prefer higher profile (even if level is lower)
326                    mConfigs[i][j].profile = profile;
327                    mConfigs[i][j].level = level;
328                } else if (profile == mConfigs[i][j].profile &&
329                           level > mConfigs[i][j].level) {
330                    mConfigs[i][j].level = level;
331                }
332            }
333        }
334    }
335
336    return true;
337}
338
339// static
340bool VideoFormats::GetProfileLevel(
341        ProfileType profile, LevelType level, unsigned *profileIdc,
342        unsigned *levelIdc, unsigned *constraintSet) {
343    CHECK_LT(profile, kNumProfileTypes);
344    CHECK_LT(level, kNumLevelTypes);
345
346    static const unsigned kProfileIDC[kNumProfileTypes] = {
347        66,     // PROFILE_CBP
348        100,    // PROFILE_CHP
349    };
350
351    static const unsigned kLevelIDC[kNumLevelTypes] = {
352        31,     // LEVEL_31
353        32,     // LEVEL_32
354        40,     // LEVEL_40
355        41,     // LEVEL_41
356        42,     // LEVEL_42
357    };
358
359    static const unsigned kConstraintSet[kNumProfileTypes] = {
360        0xc0,   // PROFILE_CBP
361        0x0c,   // PROFILE_CHP
362    };
363
364    if (profileIdc) {
365        *profileIdc = kProfileIDC[profile];
366    }
367
368    if (levelIdc) {
369        *levelIdc = kLevelIDC[level];
370    }
371
372    if (constraintSet) {
373        *constraintSet = kConstraintSet[profile];
374    }
375
376    return true;
377}
378
379bool VideoFormats::parseFormatSpec(const char *spec) {
380    CHECK_EQ(kNumResolutionTypes, 3);
381
382    disableAll();
383
384    unsigned native, dummy;
385    size_t size = strlen(spec);
386    size_t offset = 0;
387
388    if (sscanf(spec, "%02x %02x ", &native, &dummy) != 2) {
389        return false;
390    }
391
392    offset += 6; // skip native and preferred-display-mode-supported
393    CHECK_LE(offset + 58, size);
394    while (offset < size) {
395        parseH264Codec(spec + offset);
396        offset += 60; // skip H.264-codec + ", "
397    }
398
399    mNativeIndex = native >> 3;
400    mNativeType = (ResolutionType)(native & 7);
401
402    bool success;
403    if (mNativeType >= kNumResolutionTypes) {
404        success = false;
405    } else {
406        success = GetConfiguration(
407                mNativeType, mNativeIndex, NULL, NULL, NULL, NULL);
408    }
409
410    if (!success) {
411        ALOGW("sink advertised an illegal native resolution, fortunately "
412              "this value is ignored for the time being...");
413    }
414
415    return true;
416}
417
418AString VideoFormats::getFormatSpec(bool forM4Message) const {
419    CHECK_EQ(kNumResolutionTypes, 3);
420
421    // wfd_video_formats:
422    // 1 byte "native"
423    // 1 byte "preferred-display-mode-supported" 0 or 1
424    // one or more avc codec structures
425    //   1 byte profile
426    //   1 byte level
427    //   4 byte CEA mask
428    //   4 byte VESA mask
429    //   4 byte HH mask
430    //   1 byte latency
431    //   2 byte min-slice-slice
432    //   2 byte slice-enc-params
433    //   1 byte framerate-control-support
434    //   max-hres (none or 2 byte)
435    //   max-vres (none or 2 byte)
436
437    return AStringPrintf(
438            "%02x 00 %02x %02x %08x %08x %08x 00 0000 0000 00 none none",
439            forM4Message ? 0x00 : ((mNativeIndex << 3) | mNativeType),
440            mConfigs[mNativeType][mNativeIndex].profile,
441            mConfigs[mNativeType][mNativeIndex].level,
442            mResolutionEnabled[0],
443            mResolutionEnabled[1],
444            mResolutionEnabled[2]);
445}
446
447// static
448bool VideoFormats::PickBestFormat(
449        const VideoFormats &sinkSupported,
450        const VideoFormats &sourceSupported,
451        ResolutionType *chosenType,
452        size_t *chosenIndex,
453        ProfileType *chosenProfile,
454        LevelType *chosenLevel) {
455#if 0
456    // Support for the native format is a great idea, the spec includes
457    // these features, but nobody supports it and the tests don't validate it.
458
459    ResolutionType nativeType;
460    size_t nativeIndex;
461    sinkSupported.getNativeResolution(&nativeType, &nativeIndex);
462    if (sinkSupported.isResolutionEnabled(nativeType, nativeIndex)) {
463        if (sourceSupported.isResolutionEnabled(nativeType, nativeIndex)) {
464            ALOGI("Choosing sink's native resolution");
465            *chosenType = nativeType;
466            *chosenIndex = nativeIndex;
467            return true;
468        }
469    } else {
470        ALOGW("Sink advertised native resolution that it doesn't "
471              "actually support... ignoring");
472    }
473
474    sourceSupported.getNativeResolution(&nativeType, &nativeIndex);
475    if (sourceSupported.isResolutionEnabled(nativeType, nativeIndex)) {
476        if (sinkSupported.isResolutionEnabled(nativeType, nativeIndex)) {
477            ALOGI("Choosing source's native resolution");
478            *chosenType = nativeType;
479            *chosenIndex = nativeIndex;
480            return true;
481        }
482    } else {
483        ALOGW("Source advertised native resolution that it doesn't "
484              "actually support... ignoring");
485    }
486#endif
487
488    bool first = true;
489    uint32_t bestScore = 0;
490    size_t bestType = 0;
491    size_t bestIndex = 0;
492    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
493        for (size_t j = 0; j < 32; ++j) {
494            size_t width, height, framesPerSecond;
495            bool interlaced;
496            if (!GetConfiguration(
497                        (ResolutionType)i,
498                        j,
499                        &width, &height, &framesPerSecond, &interlaced)) {
500                break;
501            }
502
503            if (!sinkSupported.isResolutionEnabled((ResolutionType)i, j)
504                    || !sourceSupported.isResolutionEnabled(
505                        (ResolutionType)i, j)) {
506                continue;
507            }
508
509            ALOGV("type %zu, index %zu, %zu x %zu %c%zu supported",
510                  i, j, width, height, interlaced ? 'i' : 'p', framesPerSecond);
511
512            uint32_t score = width * height * framesPerSecond;
513            if (!interlaced) {
514                score *= 2;
515            }
516
517            if (first || score > bestScore) {
518                bestScore = score;
519                bestType = i;
520                bestIndex = j;
521
522                first = false;
523            }
524        }
525    }
526
527    if (first) {
528        return false;
529    }
530
531    *chosenType = (ResolutionType)bestType;
532    *chosenIndex = bestIndex;
533
534    // Pick the best profile/level supported by both sink and source.
535    ProfileType srcProfile, sinkProfile;
536    LevelType srcLevel, sinkLevel;
537    sourceSupported.getProfileLevel(
538                        (ResolutionType)bestType, bestIndex,
539                        &srcProfile, &srcLevel);
540    sinkSupported.getProfileLevel(
541                        (ResolutionType)bestType, bestIndex,
542                        &sinkProfile, &sinkLevel);
543    *chosenProfile = srcProfile < sinkProfile ? srcProfile : sinkProfile;
544    *chosenLevel = srcLevel < sinkLevel ? srcLevel : sinkLevel;
545
546    return true;
547}
548
549}  // namespace android
550
551