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