• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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 "StagefrightMetadataRetriever"
19 
20 #include <inttypes.h>
21 
22 #include <utils/Log.h>
23 #include <cutils/properties.h>
24 
25 #include "include/FrameDecoder.h"
26 #include "include/StagefrightMetadataRetriever.h"
27 
28 #include <media/IMediaHTTPService.h>
29 #include <media/stagefright/foundation/ADebug.h>
30 #include <media/stagefright/foundation/AMessage.h>
31 #include <media/stagefright/DataSourceFactory.h>
32 #include <media/stagefright/FileSource.h>
33 #include <media/stagefright/MediaCodecList.h>
34 #include <media/stagefright/MediaDefs.h>
35 #include <media/stagefright/MediaErrors.h>
36 #include <media/stagefright/MediaExtractor.h>
37 #include <media/stagefright/MediaExtractorFactory.h>
38 #include <media/stagefright/MetaData.h>
39 #include <media/stagefright/Utils.h>
40 #include <media/CharacterEncodingDetector.h>
41 
42 namespace android {
43 
StagefrightMetadataRetriever()44 StagefrightMetadataRetriever::StagefrightMetadataRetriever()
45     : mParsedMetaData(false),
46       mAlbumArt(NULL),
47       mLastImageIndex(-1) {
48     ALOGV("StagefrightMetadataRetriever()");
49 }
50 
~StagefrightMetadataRetriever()51 StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
52     ALOGV("~StagefrightMetadataRetriever()");
53     clearMetadata();
54     if (mSource != NULL) {
55         mSource->close();
56     }
57 }
58 
setDataSource(const sp<IMediaHTTPService> & httpService,const char * uri,const KeyedVector<String8,String8> * headers)59 status_t StagefrightMetadataRetriever::setDataSource(
60         const sp<IMediaHTTPService> &httpService,
61         const char *uri,
62         const KeyedVector<String8, String8> *headers) {
63     ALOGV("setDataSource(%s)", uri);
64 
65     clearMetadata();
66     mSource = DataSourceFactory::CreateFromURI(httpService, uri, headers);
67 
68     if (mSource == NULL) {
69         ALOGE("Unable to create data source for '%s'.", uri);
70         return UNKNOWN_ERROR;
71     }
72 
73     mExtractor = MediaExtractorFactory::Create(mSource);
74 
75     if (mExtractor == NULL) {
76         ALOGE("Unable to instantiate an extractor for '%s'.", uri);
77 
78         mSource.clear();
79 
80         return UNKNOWN_ERROR;
81     }
82 
83     return OK;
84 }
85 
86 // Warning caller retains ownership of the filedescriptor! Dup it if necessary.
setDataSource(int fd,int64_t offset,int64_t length)87 status_t StagefrightMetadataRetriever::setDataSource(
88         int fd, int64_t offset, int64_t length) {
89     fd = dup(fd);
90 
91     ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
92 
93     clearMetadata();
94     mSource = new FileSource(fd, offset, length);
95 
96     status_t err;
97     if ((err = mSource->initCheck()) != OK) {
98         mSource.clear();
99 
100         return err;
101     }
102 
103     mExtractor = MediaExtractorFactory::Create(mSource);
104 
105     if (mExtractor == NULL) {
106         mSource.clear();
107 
108         return UNKNOWN_ERROR;
109     }
110 
111     return OK;
112 }
113 
setDataSource(const sp<DataSource> & source,const char * mime)114 status_t StagefrightMetadataRetriever::setDataSource(
115         const sp<DataSource>& source, const char *mime) {
116     ALOGV("setDataSource(DataSource)");
117 
118     clearMetadata();
119     mSource = source;
120     mExtractor = MediaExtractorFactory::Create(mSource, mime);
121 
122     if (mExtractor == NULL) {
123         ALOGE("Failed to instantiate a MediaExtractor.");
124         mSource.clear();
125         return UNKNOWN_ERROR;
126     }
127 
128     return OK;
129 }
130 
getImageAtIndex(int index,int colorFormat,bool metaOnly,bool thumbnail)131 sp<IMemory> StagefrightMetadataRetriever::getImageAtIndex(
132         int index, int colorFormat, bool metaOnly, bool thumbnail) {
133     ALOGV("getImageAtIndex: index(%d) colorFormat(%d) metaOnly(%d) thumbnail(%d)",
134             index, colorFormat, metaOnly, thumbnail);
135 
136     return getImageInternal(index, colorFormat, metaOnly, thumbnail, NULL);
137 }
138 
getImageRectAtIndex(int index,int colorFormat,int left,int top,int right,int bottom)139 sp<IMemory> StagefrightMetadataRetriever::getImageRectAtIndex(
140         int index, int colorFormat, int left, int top, int right, int bottom) {
141     ALOGV("getImageRectAtIndex: index(%d) colorFormat(%d) rect {%d, %d, %d, %d}",
142             index, colorFormat, left, top, right, bottom);
143 
144     FrameRect rect = {left, top, right, bottom};
145 
146     if (mImageDecoder != NULL && index == mLastImageIndex) {
147         return mImageDecoder->extractFrame(&rect);
148     }
149 
150     return getImageInternal(
151             index, colorFormat, false /*metaOnly*/, false /*thumbnail*/, &rect);
152 }
153 
getImageInternal(int index,int colorFormat,bool metaOnly,bool thumbnail,FrameRect * rect)154 sp<IMemory> StagefrightMetadataRetriever::getImageInternal(
155         int index, int colorFormat, bool metaOnly, bool thumbnail, FrameRect* rect) {
156 
157     if (mExtractor.get() == NULL) {
158         ALOGE("no extractor.");
159         return NULL;
160     }
161 
162     size_t n = mExtractor->countTracks();
163     size_t i;
164     int imageCount = 0;
165 
166     for (i = 0; i < n; ++i) {
167         sp<MetaData> meta = mExtractor->getTrackMetaData(i);
168         if (!meta) {
169             continue;
170         }
171         ALOGV("getting track %zu of %zu, meta=%s", i, n, meta->toString().c_str());
172 
173         const char *mime;
174         CHECK(meta->findCString(kKeyMIMEType, &mime));
175 
176         if (!strncasecmp(mime, "image/", 6)) {
177             int32_t isPrimary;
178             if ((index < 0 && meta->findInt32(
179                     kKeyTrackIsDefault, &isPrimary) && isPrimary)
180                     || (index == imageCount++)) {
181                 break;
182             }
183         }
184     }
185 
186     if (i == n) {
187         ALOGE("image track not found.");
188         return NULL;
189     }
190 
191     sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
192     if (!trackMeta) {
193         return NULL;
194     }
195 
196     if (metaOnly) {
197         return FrameDecoder::getMetadataOnly(trackMeta, colorFormat, thumbnail);
198     }
199 
200     sp<IMediaSource> source = mExtractor->getTrack(i);
201 
202     if (source.get() == NULL) {
203         ALOGE("unable to instantiate image track.");
204         return NULL;
205     }
206 
207     const char *mime;
208     CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
209     ALOGV("extracting from %s track", mime);
210     if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
211         mime = MEDIA_MIMETYPE_VIDEO_HEVC;
212         trackMeta = new MetaData(*trackMeta);
213         trackMeta->setCString(kKeyMIMEType, mime);
214     }
215 
216     bool preferhw = property_get_bool(
217             "media.stagefright.thumbnail.prefer_hw_codecs", false);
218     uint32_t flags = preferhw ? 0 : MediaCodecList::kPreferSoftwareCodecs;
219     Vector<AString> matchingCodecs;
220     MediaCodecList::findMatchingCodecs(
221             mime,
222             false, /* encoder */
223             flags,
224             &matchingCodecs);
225 
226     for (size_t i = 0; i < matchingCodecs.size(); ++i) {
227         const AString &componentName = matchingCodecs[i];
228         sp<ImageDecoder> decoder = new ImageDecoder(componentName, trackMeta, source);
229         int64_t frameTimeUs = thumbnail ? -1 : 0;
230         if (decoder->init(frameTimeUs, 1 /*numFrames*/, 0 /*option*/, colorFormat) == OK) {
231             sp<IMemory> frame = decoder->extractFrame(rect);
232 
233             if (frame != NULL) {
234                 if (rect != NULL) {
235                     // keep the decoder if slice decoding
236                     mImageDecoder = decoder;
237                     mLastImageIndex = index;
238                 }
239                 return frame;
240             }
241         }
242         ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName.c_str());
243     }
244 
245     return NULL;
246 }
247 
getFrameAtTime(int64_t timeUs,int option,int colorFormat,bool metaOnly)248 sp<IMemory> StagefrightMetadataRetriever::getFrameAtTime(
249         int64_t timeUs, int option, int colorFormat, bool metaOnly) {
250     ALOGV("getFrameAtTime: %" PRId64 " us option: %d colorFormat: %d, metaOnly: %d",
251             timeUs, option, colorFormat, metaOnly);
252 
253     sp<IMemory> frame;
254     status_t err = getFrameInternal(
255             timeUs, 1, option, colorFormat, metaOnly, &frame, NULL /*outFrames*/);
256     return (err == OK) ? frame : NULL;
257 }
258 
getFrameAtIndex(std::vector<sp<IMemory>> * frames,int frameIndex,int numFrames,int colorFormat,bool metaOnly)259 status_t StagefrightMetadataRetriever::getFrameAtIndex(
260         std::vector<sp<IMemory> >* frames,
261         int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
262     ALOGV("getFrameAtIndex: frameIndex %d, numFrames %d, colorFormat: %d, metaOnly: %d",
263             frameIndex, numFrames, colorFormat, metaOnly);
264 
265     return getFrameInternal(
266             frameIndex, numFrames, MediaSource::ReadOptions::SEEK_FRAME_INDEX,
267             colorFormat, metaOnly, NULL /*outFrame*/, frames);
268 }
269 
getFrameInternal(int64_t timeUs,int numFrames,int option,int colorFormat,bool metaOnly,sp<IMemory> * outFrame,std::vector<sp<IMemory>> * outFrames)270 status_t StagefrightMetadataRetriever::getFrameInternal(
271         int64_t timeUs, int numFrames, int option, int colorFormat, bool metaOnly,
272         sp<IMemory>* outFrame, std::vector<sp<IMemory> >* outFrames) {
273     if (mExtractor.get() == NULL) {
274         ALOGE("no extractor.");
275         return NO_INIT;
276     }
277 
278     sp<MetaData> fileMeta = mExtractor->getMetaData();
279 
280     if (fileMeta == NULL) {
281         ALOGE("extractor doesn't publish metadata, failed to initialize?");
282         return NO_INIT;
283     }
284 
285     size_t n = mExtractor->countTracks();
286     size_t i;
287     for (i = 0; i < n; ++i) {
288         sp<MetaData> meta = mExtractor->getTrackMetaData(i);
289         if (!meta) {
290             continue;
291         }
292 
293         const char *mime;
294         CHECK(meta->findCString(kKeyMIMEType, &mime));
295 
296         if (!strncasecmp(mime, "video/", 6)) {
297             break;
298         }
299     }
300 
301     if (i == n) {
302         ALOGE("no video track found.");
303         return INVALID_OPERATION;
304     }
305 
306     sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
307             i, MediaExtractor::kIncludeExtensiveMetaData);
308     if (!trackMeta) {
309         return UNKNOWN_ERROR;
310     }
311 
312     if (metaOnly) {
313         if (outFrame != NULL) {
314             *outFrame = FrameDecoder::getMetadataOnly(trackMeta, colorFormat);
315             if (*outFrame != NULL) {
316                 return OK;
317             }
318         }
319         return UNKNOWN_ERROR;
320     }
321 
322     sp<IMediaSource> source = mExtractor->getTrack(i);
323 
324     if (source.get() == NULL) {
325         ALOGV("unable to instantiate video track.");
326         return UNKNOWN_ERROR;
327     }
328 
329     const void *data;
330     uint32_t type;
331     size_t dataSize;
332     if (fileMeta->findData(kKeyAlbumArt, &type, &data, &dataSize)
333             && mAlbumArt == NULL) {
334         mAlbumArt = MediaAlbumArt::fromData(dataSize, data);
335     }
336 
337     const char *mime;
338     CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
339 
340     bool preferhw = property_get_bool(
341             "media.stagefright.thumbnail.prefer_hw_codecs", false);
342     uint32_t flags = preferhw ? 0 : MediaCodecList::kPreferSoftwareCodecs;
343     Vector<AString> matchingCodecs;
344     MediaCodecList::findMatchingCodecs(
345             mime,
346             false, /* encoder */
347             flags,
348             &matchingCodecs);
349 
350     for (size_t i = 0; i < matchingCodecs.size(); ++i) {
351         const AString &componentName = matchingCodecs[i];
352         sp<VideoFrameDecoder> decoder = new VideoFrameDecoder(componentName, trackMeta, source);
353         if (decoder->init(timeUs, numFrames, option, colorFormat) == OK) {
354             if (outFrame != NULL) {
355                 *outFrame = decoder->extractFrame();
356                 if (*outFrame != NULL) {
357                     return OK;
358                 }
359             } else if (outFrames != NULL) {
360                 status_t err = decoder->extractFrames(outFrames);
361                 if (err == OK) {
362                     return OK;
363                 }
364             }
365         }
366         ALOGV("%s failed to extract frame, trying next decoder.", componentName.c_str());
367     }
368 
369     ALOGE("all codecs failed to extract frame.");
370     return UNKNOWN_ERROR;
371 }
372 
extractAlbumArt()373 MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
374     ALOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
375 
376     if (mExtractor == NULL) {
377         return NULL;
378     }
379 
380     if (!mParsedMetaData) {
381         parseMetaData();
382 
383         mParsedMetaData = true;
384     }
385 
386     if (mAlbumArt) {
387         return mAlbumArt->clone();
388     }
389 
390     return NULL;
391 }
392 
extractMetadata(int keyCode)393 const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
394     if (mExtractor == NULL) {
395         return NULL;
396     }
397 
398     if (!mParsedMetaData) {
399         parseMetaData();
400 
401         mParsedMetaData = true;
402     }
403 
404     ssize_t index = mMetaData.indexOfKey(keyCode);
405 
406     if (index < 0) {
407         return NULL;
408     }
409 
410     return mMetaData.valueAt(index).string();
411 }
412 
parseColorAspects(const sp<MetaData> & meta)413 void StagefrightMetadataRetriever::parseColorAspects(const sp<MetaData>& meta) {
414     sp<AMessage> format = new AMessage();
415     if (convertMetaDataToMessage(meta, &format) != OK) {
416         return;
417     }
418 
419     int32_t standard, transfer, range;
420     if (format->findInt32("color-standard", &standard)
421             && format->findInt32("color-transfer", &transfer)
422             && format->findInt32("color-range", &range)) {
423         ALOGV("found color aspects : standard=%d, transfer=%d, range=%d",
424                 standard, transfer, range);
425 
426         mMetaData.add(METADATA_KEY_COLOR_STANDARD, String8::format("%d", standard));
427         mMetaData.add(METADATA_KEY_COLOR_TRANSFER, String8::format("%d", transfer));
428         mMetaData.add(METADATA_KEY_COLOR_RANGE, String8::format("%d", range));
429     }
430 }
431 
parseMetaData()432 void StagefrightMetadataRetriever::parseMetaData() {
433     sp<MetaData> meta = mExtractor->getMetaData();
434 
435     if (meta == NULL) {
436         ALOGV("extractor doesn't publish metadata, failed to initialize?");
437         return;
438     }
439 
440     struct Map {
441         int from;
442         int to;
443         const char *name;
444     };
445     static const Map kMap[] = {
446         { kKeyMIMEType, METADATA_KEY_MIMETYPE, NULL },
447         { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER, "tracknumber" },
448         { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER, "discnumber" },
449         { kKeyAlbum, METADATA_KEY_ALBUM, "album" },
450         { kKeyArtist, METADATA_KEY_ARTIST, "artist" },
451         { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST, "albumartist" },
452         { kKeyAuthor, METADATA_KEY_AUTHOR, NULL },
453         { kKeyComposer, METADATA_KEY_COMPOSER, "composer" },
454         { kKeyDate, METADATA_KEY_DATE, NULL },
455         { kKeyGenre, METADATA_KEY_GENRE, "genre" },
456         { kKeyTitle, METADATA_KEY_TITLE, "title" },
457         { kKeyYear, METADATA_KEY_YEAR, "year" },
458         { kKeyWriter, METADATA_KEY_WRITER, "writer" },
459         { kKeyCompilation, METADATA_KEY_COMPILATION, "compilation" },
460         { kKeyLocation, METADATA_KEY_LOCATION, NULL },
461     };
462 
463     static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
464 
465     CharacterEncodingDetector *detector = new CharacterEncodingDetector();
466 
467     for (size_t i = 0; i < kNumMapEntries; ++i) {
468         const char *value;
469         if (meta->findCString(kMap[i].from, &value)) {
470             if (kMap[i].name) {
471                 // add to charset detector
472                 detector->addTag(kMap[i].name, value);
473             } else {
474                 // directly add to output list
475                 mMetaData.add(kMap[i].to, String8(value));
476             }
477         }
478     }
479 
480     detector->detectAndConvert();
481     int size = detector->size();
482     if (size) {
483         for (int i = 0; i < size; i++) {
484             const char *name;
485             const char *value;
486             detector->getTag(i, &name, &value);
487             for (size_t j = 0; j < kNumMapEntries; ++j) {
488                 if (kMap[j].name && !strcmp(kMap[j].name, name)) {
489                     mMetaData.add(kMap[j].to, String8(value));
490                 }
491             }
492         }
493     }
494     delete detector;
495 
496     const void *data;
497     uint32_t type;
498     size_t dataSize;
499     if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize)
500             && mAlbumArt == NULL) {
501         mAlbumArt = MediaAlbumArt::fromData(dataSize, data);
502     }
503 
504     size_t numTracks = mExtractor->countTracks();
505 
506     char tmp[32];
507     sprintf(tmp, "%zu", numTracks);
508 
509     mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp));
510 
511     float captureFps;
512     if (meta->findFloat(kKeyCaptureFramerate, &captureFps)) {
513         sprintf(tmp, "%f", captureFps);
514         mMetaData.add(METADATA_KEY_CAPTURE_FRAMERATE, String8(tmp));
515     }
516 
517     int64_t exifOffset, exifSize;
518     if (meta->findInt64(kKeyExifOffset, &exifOffset)
519      && meta->findInt64(kKeyExifSize, &exifSize)) {
520         sprintf(tmp, "%lld", (long long)exifOffset);
521         mMetaData.add(METADATA_KEY_EXIF_OFFSET, String8(tmp));
522         sprintf(tmp, "%lld", (long long)exifSize);
523         mMetaData.add(METADATA_KEY_EXIF_LENGTH, String8(tmp));
524     }
525 
526     bool hasAudio = false;
527     bool hasVideo = false;
528     int32_t videoWidth = -1;
529     int32_t videoHeight = -1;
530     int32_t videoFrameCount = 0;
531     int32_t audioBitrate = -1;
532     int32_t rotationAngle = -1;
533     int32_t imageCount = 0;
534     int32_t imagePrimary = 0;
535     int32_t imageWidth = -1;
536     int32_t imageHeight = -1;
537     int32_t imageRotation = -1;
538 
539     // The overall duration is the duration of the longest track.
540     int64_t maxDurationUs = 0;
541     String8 timedTextLang;
542     for (size_t i = 0; i < numTracks; ++i) {
543         sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
544         if (!trackMeta) {
545             continue;
546         }
547 
548         int64_t durationUs;
549         if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
550             if (durationUs > maxDurationUs) {
551                 maxDurationUs = durationUs;
552             }
553         }
554 
555         const char *mime;
556         if (trackMeta->findCString(kKeyMIMEType, &mime)) {
557             if (!hasAudio && !strncasecmp("audio/", mime, 6)) {
558                 hasAudio = true;
559 
560                 if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) {
561                     audioBitrate = -1;
562                 }
563 
564                 int32_t bitsPerSample = -1;
565                 int32_t sampleRate = -1;
566                 trackMeta->findInt32(kKeyBitsPerSample, &bitsPerSample);
567                 trackMeta->findInt32(kKeySampleRate, &sampleRate);
568                 if (bitsPerSample >= 0) {
569                     sprintf(tmp, "%d", bitsPerSample);
570                     mMetaData.add(METADATA_KEY_BITS_PER_SAMPLE, String8(tmp));
571                 }
572                 if (sampleRate >= 0) {
573                     sprintf(tmp, "%d", sampleRate);
574                     mMetaData.add(METADATA_KEY_SAMPLERATE, String8(tmp));
575                 }
576             } else if (!hasVideo && !strncasecmp("video/", mime, 6)) {
577                 hasVideo = true;
578 
579                 CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
580                 CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
581                 if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
582                     rotationAngle = 0;
583                 }
584                 if (!trackMeta->findInt32(kKeyFrameCount, &videoFrameCount)) {
585                     videoFrameCount = 0;
586                 }
587 
588                 parseColorAspects(trackMeta);
589             } else if (!strncasecmp("image/", mime, 6)) {
590                 int32_t isPrimary;
591                 if (trackMeta->findInt32(
592                         kKeyTrackIsDefault, &isPrimary) && isPrimary) {
593                     imagePrimary = imageCount;
594                     CHECK(trackMeta->findInt32(kKeyWidth, &imageWidth));
595                     CHECK(trackMeta->findInt32(kKeyHeight, &imageHeight));
596                     if (!trackMeta->findInt32(kKeyRotation, &imageRotation)) {
597                         imageRotation = 0;
598                     }
599                 }
600                 imageCount++;
601             } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
602                 const char *lang;
603                 if (trackMeta->findCString(kKeyMediaLanguage, &lang)) {
604                     timedTextLang.append(String8(lang));
605                     timedTextLang.append(String8(":"));
606                 } else {
607                     ALOGE("No language found for timed text");
608                 }
609             }
610         }
611     }
612 
613     // To save the language codes for all timed text tracks
614     // If multiple text tracks present, the format will look
615     // like "eng:chi"
616     if (!timedTextLang.isEmpty()) {
617         mMetaData.add(METADATA_KEY_TIMED_TEXT_LANGUAGES, timedTextLang);
618     }
619 
620     // The duration value is a string representing the duration in ms.
621     sprintf(tmp, "%" PRId64, (maxDurationUs + 500) / 1000);
622     mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
623 
624     if (hasAudio) {
625         mMetaData.add(METADATA_KEY_HAS_AUDIO, String8("yes"));
626     }
627 
628     if (hasVideo) {
629         mMetaData.add(METADATA_KEY_HAS_VIDEO, String8("yes"));
630 
631         sprintf(tmp, "%d", videoWidth);
632         mMetaData.add(METADATA_KEY_VIDEO_WIDTH, String8(tmp));
633 
634         sprintf(tmp, "%d", videoHeight);
635         mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp));
636 
637         sprintf(tmp, "%d", rotationAngle);
638         mMetaData.add(METADATA_KEY_VIDEO_ROTATION, String8(tmp));
639 
640         if (videoFrameCount > 0) {
641             sprintf(tmp, "%d", videoFrameCount);
642             mMetaData.add(METADATA_KEY_VIDEO_FRAME_COUNT, String8(tmp));
643         }
644     }
645 
646     if (imageCount > 0) {
647         mMetaData.add(METADATA_KEY_HAS_IMAGE, String8("yes"));
648 
649         sprintf(tmp, "%d", imageCount);
650         mMetaData.add(METADATA_KEY_IMAGE_COUNT, String8(tmp));
651 
652         sprintf(tmp, "%d", imagePrimary);
653         mMetaData.add(METADATA_KEY_IMAGE_PRIMARY, String8(tmp));
654 
655         sprintf(tmp, "%d", imageWidth);
656         mMetaData.add(METADATA_KEY_IMAGE_WIDTH, String8(tmp));
657 
658         sprintf(tmp, "%d", imageHeight);
659         mMetaData.add(METADATA_KEY_IMAGE_HEIGHT, String8(tmp));
660 
661         sprintf(tmp, "%d", imageRotation);
662         mMetaData.add(METADATA_KEY_IMAGE_ROTATION, String8(tmp));
663     }
664 
665     if (numTracks == 1 && hasAudio && audioBitrate >= 0) {
666         sprintf(tmp, "%d", audioBitrate);
667         mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
668     } else {
669         off64_t sourceSize;
670         if (mSource != NULL && mSource->getSize(&sourceSize) == OK) {
671             int64_t avgBitRate = (int64_t)(sourceSize * 8E6 / maxDurationUs);
672 
673             sprintf(tmp, "%" PRId64, avgBitRate);
674             mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
675         }
676     }
677 
678     if (numTracks == 1) {
679         const char *fileMIME;
680 
681         if (meta->findCString(kKeyMIMEType, &fileMIME) &&
682                 !strcasecmp(fileMIME, "video/x-matroska")) {
683             sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0);
684             const char *trackMIME;
685             if (trackMeta != nullptr) {
686                 CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME));
687             }
688             if (!strncasecmp("audio/", trackMIME, 6)) {
689                 // The matroska file only contains a single audio track,
690                 // rewrite its mime type.
691                 mMetaData.add(
692                         METADATA_KEY_MIMETYPE, String8("audio/x-matroska"));
693             }
694         }
695     }
696 }
697 
clearMetadata()698 void StagefrightMetadataRetriever::clearMetadata() {
699     mParsedMetaData = false;
700     mMetaData.clear();
701     delete mAlbumArt;
702     mAlbumArt = NULL;
703 }
704 
705 }  // namespace android
706