VideoFormats.cpp revision aef5c98cd3f67e0209e1fa28489078e9f40d6f46
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
27VideoFormats::config_t VideoFormats::mConfigs[][32] = {
28    {
29        // CEA Resolutions
30        { 640, 480, 60, false, 0, 0},
31        { 720, 480, 60, false, 0, 0},
32        { 720, 480, 60, true, 0, 0},
33        { 720, 576, 50, false, 0, 0},
34        { 720, 576, 50, true, 0, 0},
35        { 1280, 720, 30, false, 0, 0},
36        { 1280, 720, 60, false, 0, 0},
37        { 1920, 1080, 30, false, 0, 0},
38        { 1920, 1080, 60, false, 0, 0},
39        { 1920, 1080, 60, true, 0, 0},
40        { 1280, 720, 25, false, 0, 0},
41        { 1280, 720, 50, false, 0, 0},
42        { 1920, 1080, 25, false, 0, 0},
43        { 1920, 1080, 50, false, 0, 0},
44        { 1920, 1080, 50, true, 0, 0},
45        { 1280, 720, 24, false, 0, 0},
46        { 1920, 1080, 24, false, 0, 0},
47        { 0, 0, 0, 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    },
63    {
64        // VESA Resolutions
65        { 800, 600, 30, false, 0, 0},
66        { 800, 600, 60, false, 0, 0},
67        { 1024, 768, 30, false, 0, 0},
68        { 1024, 768, 60, false, 0, 0},
69        { 1152, 864, 30, false, 0, 0},
70        { 1152, 864, 60, false, 0, 0},
71        { 1280, 768, 30, false, 0, 0},
72        { 1280, 768, 60, false, 0, 0},
73        { 1280, 800, 30, false, 0, 0},
74        { 1280, 800, 60, false, 0, 0},
75        { 1360, 768, 30, false, 0, 0},
76        { 1360, 768, 60, false, 0, 0},
77        { 1366, 768, 30, false, 0, 0},
78        { 1366, 768, 60, false, 0, 0},
79        { 1280, 1024, 30, false, 0, 0},
80        { 1280, 1024, 60, false, 0, 0},
81        { 1400, 1050, 30, false, 0, 0},
82        { 1400, 1050, 60, false, 0, 0},
83        { 1440, 900, 30, false, 0, 0},
84        { 1440, 900, 60, false, 0, 0},
85        { 1600, 900, 30, false, 0, 0},
86        { 1600, 900, 60, false, 0, 0},
87        { 1600, 1200, 30, false, 0, 0},
88        { 1600, 1200, 60, false, 0, 0},
89        { 1680, 1024, 30, false, 0, 0},
90        { 1680, 1024, 60, false, 0, 0},
91        { 1680, 1050, 30, false, 0, 0},
92        { 1680, 1050, 60, false, 0, 0},
93        { 1920, 1200, 30, false, 0, 0},
94        { 1920, 1200, 60, false, 0, 0},
95        { 0, 0, 0, false, 0, 0},
96        { 0, 0, 0, false, 0, 0},
97    },
98    {
99        // HH Resolutions
100        { 800, 480, 30, false, 0, 0},
101        { 800, 480, 60, false, 0, 0},
102        { 854, 480, 30, false, 0, 0},
103        { 854, 480, 60, false, 0, 0},
104        { 864, 480, 30, false, 0, 0},
105        { 864, 480, 60, false, 0, 0},
106        { 640, 360, 30, false, 0, 0},
107        { 640, 360, 60, false, 0, 0},
108        { 960, 540, 30, false, 0, 0},
109        { 960, 540, 60, false, 0, 0},
110        { 848, 480, 30, false, 0, 0},
111        { 848, 480, 60, false, 0, 0},
112        { 0, 0, 0, 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    }
133};
134
135VideoFormats::VideoFormats() {
136    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
137        mResolutionEnabled[i] = 0;
138    }
139
140    setNativeResolution(RESOLUTION_CEA, 0);  // default to 640x480 p60
141}
142
143void VideoFormats::setNativeResolution(ResolutionType type, size_t index) {
144    CHECK_LT(type, kNumResolutionTypes);
145    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));
146
147    mNativeType = type;
148    mNativeIndex = index;
149
150    setResolutionEnabled(type, index);
151}
152
153void VideoFormats::getNativeResolution(
154        ResolutionType *type, size_t *index) const {
155    *type = mNativeType;
156    *index = mNativeIndex;
157}
158
159void VideoFormats::disableAll() {
160    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
161        mResolutionEnabled[i] = 0;
162        for (size_t j = 0; j < 32; j++) {
163            mConfigs[i][j].profile = mConfigs[i][j].level = 0;
164        }
165    }
166}
167
168void VideoFormats::enableAll() {
169    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
170        mResolutionEnabled[i] = 0xffffffff;
171        for (size_t j = 0; j < 32; j++) {
172            mConfigs[i][j].profile = (1ul << PROFILE_CBP);
173            mConfigs[i][j].level = (1ul << LEVEL_31);
174        }
175    }
176}
177
178void VideoFormats::setResolutionEnabled(
179        ResolutionType type, size_t index, bool enabled) {
180    CHECK_LT(type, kNumResolutionTypes);
181    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));
182
183    if (enabled) {
184        mResolutionEnabled[type] |= (1ul << index);
185    } else {
186        mResolutionEnabled[type] &= ~(1ul << index);
187    }
188}
189
190bool VideoFormats::isResolutionEnabled(
191        ResolutionType type, size_t index) const {
192    CHECK_LT(type, kNumResolutionTypes);
193    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));
194
195    return mResolutionEnabled[type] & (1ul << index);
196}
197
198// static
199bool VideoFormats::GetConfiguration(
200        ResolutionType type,
201        size_t index,
202        size_t *width, size_t *height, size_t *framesPerSecond,
203        bool *interlaced) {
204    CHECK_LT(type, kNumResolutionTypes);
205
206    if (index >= 32) {
207        return false;
208    }
209
210    const config_t *config = &mConfigs[type][index];
211
212    if (config->width == 0) {
213        return false;
214    }
215
216    if (width) {
217        *width = config->width;
218    }
219
220    if (height) {
221        *height = config->height;
222    }
223
224    if (framesPerSecond) {
225        *framesPerSecond = config->framesPerSecond;
226    }
227
228    if (interlaced) {
229        *interlaced = config->interlaced;
230    }
231
232    return true;
233}
234
235bool VideoFormats::parseH264Codec(const char *spec) {
236    unsigned profile, level, res[3];
237
238    if (sscanf(
239            spec,
240            "%02x %02x %08X %08X %08X",
241            &profile,
242            &level,
243            &res[0],
244            &res[1],
245            &res[2]) != 5) {
246        return false;
247    }
248
249    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
250        for (size_t j = 0; j < 32; ++j) {
251            if (res[i] & (1ul << j)){
252                mResolutionEnabled[i] |= (1ul << j);
253                if (profile > mConfigs[i][j].profile) {
254                    mConfigs[i][j].profile = profile;
255                    if (level > mConfigs[i][j].level)
256                        mConfigs[i][j].level = level;
257                }
258            }
259        }
260    }
261
262    return true;
263}
264
265bool VideoFormats::parseFormatSpec(const char *spec) {
266    CHECK_EQ(kNumResolutionTypes, 3);
267
268    unsigned native, dummy;
269    unsigned res[3];
270    size_t size = strlen(spec);
271    size_t offset = 0;
272
273    if (sscanf(spec, "%02x %02x ", &native, &dummy) != 2) {
274        return false;
275    }
276
277    offset += 6; // skip native and preferred-display-mode-supported
278    CHECK_LE(offset + 58, size);
279    while (offset < size) {
280        parseH264Codec(spec + offset);
281        offset += 60; // skip H.264-codec + ", "
282    }
283
284    mNativeIndex = native >> 3;
285    mNativeType = (ResolutionType)(native & 7);
286
287    bool success;
288    if (mNativeType >= kNumResolutionTypes) {
289        success = false;
290    } else {
291        success = GetConfiguration(
292                mNativeType, mNativeIndex, NULL, NULL, NULL, NULL);
293    }
294
295    if (!success) {
296        ALOGW("sink advertised an illegal native resolution, fortunately "
297              "this value is ignored for the time being...");
298    }
299
300    return true;
301}
302
303AString VideoFormats::getFormatSpec(bool forM4Message) const {
304    CHECK_EQ(kNumResolutionTypes, 3);
305
306    // wfd_video_formats:
307    // 1 byte "native"
308    // 1 byte "preferred-display-mode-supported" 0 or 1
309    // one or more avc codec structures
310    //   1 byte profile
311    //   1 byte level
312    //   4 byte CEA mask
313    //   4 byte VESA mask
314    //   4 byte HH mask
315    //   1 byte latency
316    //   2 byte min-slice-slice
317    //   2 byte slice-enc-params
318    //   1 byte framerate-control-support
319    //   max-hres (none or 2 byte)
320    //   max-vres (none or 2 byte)
321
322    return StringPrintf(
323            "%02x 00 02 02 %08x %08x %08x 00 0000 0000 00 none none",
324            forM4Message ? 0x00 : ((mNativeIndex << 3) | mNativeType),
325            mResolutionEnabled[0],
326            mResolutionEnabled[1],
327            mResolutionEnabled[2]);
328}
329
330// static
331bool VideoFormats::PickBestFormat(
332        const VideoFormats &sinkSupported,
333        const VideoFormats &sourceSupported,
334        ResolutionType *chosenType,
335        size_t *chosenIndex) {
336#if 0
337    // Support for the native format is a great idea, the spec includes
338    // these features, but nobody supports it and the tests don't validate it.
339
340    ResolutionType nativeType;
341    size_t nativeIndex;
342    sinkSupported.getNativeResolution(&nativeType, &nativeIndex);
343    if (sinkSupported.isResolutionEnabled(nativeType, nativeIndex)) {
344        if (sourceSupported.isResolutionEnabled(nativeType, nativeIndex)) {
345            ALOGI("Choosing sink's native resolution");
346            *chosenType = nativeType;
347            *chosenIndex = nativeIndex;
348            return true;
349        }
350    } else {
351        ALOGW("Sink advertised native resolution that it doesn't "
352              "actually support... ignoring");
353    }
354
355    sourceSupported.getNativeResolution(&nativeType, &nativeIndex);
356    if (sourceSupported.isResolutionEnabled(nativeType, nativeIndex)) {
357        if (sinkSupported.isResolutionEnabled(nativeType, nativeIndex)) {
358            ALOGI("Choosing source's native resolution");
359            *chosenType = nativeType;
360            *chosenIndex = nativeIndex;
361            return true;
362        }
363    } else {
364        ALOGW("Source advertised native resolution that it doesn't "
365              "actually support... ignoring");
366    }
367#endif
368
369    bool first = true;
370    uint32_t bestScore = 0;
371    size_t bestType = 0;
372    size_t bestIndex = 0;
373    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
374        for (size_t j = 0; j < 32; ++j) {
375            size_t width, height, framesPerSecond;
376            bool interlaced;
377            if (!GetConfiguration(
378                        (ResolutionType)i,
379                        j,
380                        &width, &height, &framesPerSecond, &interlaced)) {
381                break;
382            }
383
384            if (!sinkSupported.isResolutionEnabled((ResolutionType)i, j)
385                    || !sourceSupported.isResolutionEnabled(
386                        (ResolutionType)i, j)) {
387                continue;
388            }
389
390            ALOGV("type %u, index %u, %u x %u %c%u supported",
391                  i, j, width, height, interlaced ? 'i' : 'p', framesPerSecond);
392
393            uint32_t score = width * height * framesPerSecond;
394            if (!interlaced) {
395                score *= 2;
396            }
397
398            if (first || score > bestScore) {
399                bestScore = score;
400                bestType = i;
401                bestIndex = j;
402
403                first = false;
404            }
405        }
406    }
407
408    if (first) {
409        return false;
410    }
411
412    *chosenType = (ResolutionType)bestType;
413    *chosenIndex = bestIndex;
414
415    return true;
416}
417
418}  // namespace android
419
420