• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
25 namespace android {
26 
27 // static
28 const 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 
VideoFormats()136 VideoFormats::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 
setNativeResolution(ResolutionType type,size_t index)146 void 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 
getNativeResolution(ResolutionType * type,size_t * index) const156 void VideoFormats::getNativeResolution(
157         ResolutionType *type, size_t *index) const {
158     *type = mNativeType;
159     *index = mNativeIndex;
160 }
161 
disableAll()162 void 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 
enableAll()171 void 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 
enableResolutionUpto(ResolutionType type,size_t index,ProfileType profile,LevelType level)181 void 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 
setResolutionEnabled(ResolutionType type,size_t index,bool enabled)204 void 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 
setProfileLevel(ResolutionType type,size_t index,ProfileType profile,LevelType level)220 void 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 
getProfileLevel(ResolutionType type,size_t index,ProfileType * profile,LevelType * level) const230 void 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 
isResolutionEnabled(ResolutionType type,size_t index) const261 bool 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
GetConfiguration(ResolutionType type,size_t index,size_t * width,size_t * height,size_t * framesPerSecond,bool * interlaced)270 bool 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 
parseH264Codec(const char * spec)306 bool 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
GetProfileLevel(ProfileType profile,LevelType level,unsigned * profileIdc,unsigned * levelIdc,unsigned * constraintSet)340 bool 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 
parseFormatSpec(const char * spec)379 bool 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 
getFormatSpec(bool forM4Message) const418 AString 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
PickBestFormat(const VideoFormats & sinkSupported,const VideoFormats & sourceSupported,ResolutionType * chosenType,size_t * chosenIndex,ProfileType * chosenProfile,LevelType * chosenLevel)448 bool 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