MPEG2PSExtractor.cpp revision e314c678ea0b53dd9296ba6b5c3272c702433b47
1/* 2 * Copyright (C) 2011 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 "MPEG2PSExtractor" 19#include <utils/Log.h> 20 21#include "include/MPEG2PSExtractor.h" 22 23#include "AnotherPacketSource.h" 24#include "ESQueue.h" 25 26#include <media/stagefright/foundation/ABitReader.h> 27#include <media/stagefright/foundation/ABuffer.h> 28#include <media/stagefright/foundation/ADebug.h> 29#include <media/stagefright/foundation/AMessage.h> 30#include <media/stagefright/foundation/hexdump.h> 31#include <media/stagefright/DataSource.h> 32#include <media/stagefright/MediaDefs.h> 33#include <media/stagefright/MediaErrors.h> 34#include <media/stagefright/MediaSource.h> 35#include <media/stagefright/MetaData.h> 36#include <media/stagefright/Utils.h> 37#include <utils/String8.h> 38 39#include <inttypes.h> 40 41namespace android { 42 43struct MPEG2PSExtractor::Track : public MediaSource { 44 Track(MPEG2PSExtractor *extractor, 45 unsigned stream_id, unsigned stream_type); 46 47 virtual status_t start(MetaData *params); 48 virtual status_t stop(); 49 virtual sp<MetaData> getFormat(); 50 51 virtual status_t read( 52 MediaBuffer **buffer, const ReadOptions *options); 53 54protected: 55 virtual ~Track(); 56 57private: 58 friend struct MPEG2PSExtractor; 59 60 MPEG2PSExtractor *mExtractor; 61 62 unsigned mStreamID; 63 unsigned mStreamType; 64 ElementaryStreamQueue *mQueue; 65 sp<AnotherPacketSource> mSource; 66 67 status_t appendPESData( 68 unsigned PTS_DTS_flags, 69 uint64_t PTS, uint64_t DTS, 70 const uint8_t *data, size_t size); 71 72 DISALLOW_EVIL_CONSTRUCTORS(Track); 73}; 74 75struct MPEG2PSExtractor::WrappedTrack : public MediaSource { 76 WrappedTrack(const sp<MPEG2PSExtractor> &extractor, const sp<Track> &track); 77 78 virtual status_t start(MetaData *params); 79 virtual status_t stop(); 80 virtual sp<MetaData> getFormat(); 81 82 virtual status_t read( 83 MediaBuffer **buffer, const ReadOptions *options); 84 85protected: 86 virtual ~WrappedTrack(); 87 88private: 89 sp<MPEG2PSExtractor> mExtractor; 90 sp<MPEG2PSExtractor::Track> mTrack; 91 92 DISALLOW_EVIL_CONSTRUCTORS(WrappedTrack); 93}; 94 95//////////////////////////////////////////////////////////////////////////////// 96 97MPEG2PSExtractor::MPEG2PSExtractor(const sp<DataSource> &source) 98 : mDataSource(source), 99 mOffset(0), 100 mFinalResult(OK), 101 mBuffer(new ABuffer(0)), 102 mScanning(true), 103 mProgramStreamMapValid(false) { 104 for (size_t i = 0; i < 500; ++i) { 105 if (feedMore() != OK) { 106 break; 107 } 108 } 109 110 // Remove all tracks that were unable to determine their format. 111 for (size_t i = mTracks.size(); i-- > 0;) { 112 if (mTracks.valueAt(i)->getFormat() == NULL) { 113 mTracks.removeItemsAt(i); 114 } 115 } 116 117 mScanning = false; 118} 119 120MPEG2PSExtractor::~MPEG2PSExtractor() { 121} 122 123size_t MPEG2PSExtractor::countTracks() { 124 return mTracks.size(); 125} 126 127sp<MediaSource> MPEG2PSExtractor::getTrack(size_t index) { 128 if (index >= mTracks.size()) { 129 return NULL; 130 } 131 132 return new WrappedTrack(this, mTracks.valueAt(index)); 133} 134 135sp<MetaData> MPEG2PSExtractor::getTrackMetaData( 136 size_t index, uint32_t /* flags */) { 137 if (index >= mTracks.size()) { 138 return NULL; 139 } 140 141 return mTracks.valueAt(index)->getFormat(); 142} 143 144sp<MetaData> MPEG2PSExtractor::getMetaData() { 145 sp<MetaData> meta = new MetaData; 146 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2PS); 147 148 return meta; 149} 150 151uint32_t MPEG2PSExtractor::flags() const { 152 return CAN_PAUSE; 153} 154 155status_t MPEG2PSExtractor::feedMore() { 156 Mutex::Autolock autoLock(mLock); 157 158 // How much data we're reading at a time 159 static const size_t kChunkSize = 8192; 160 161 for (;;) { 162 status_t err = dequeueChunk(); 163 164 if (err == -EAGAIN && mFinalResult == OK) { 165 memmove(mBuffer->base(), mBuffer->data(), mBuffer->size()); 166 mBuffer->setRange(0, mBuffer->size()); 167 168 if (mBuffer->size() + kChunkSize > mBuffer->capacity()) { 169 size_t newCapacity = mBuffer->capacity() + kChunkSize; 170 sp<ABuffer> newBuffer = new ABuffer(newCapacity); 171 memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size()); 172 newBuffer->setRange(0, mBuffer->size()); 173 mBuffer = newBuffer; 174 } 175 176 ssize_t n = mDataSource->readAt( 177 mOffset, mBuffer->data() + mBuffer->size(), kChunkSize); 178 179 if (n < (ssize_t)kChunkSize) { 180 mFinalResult = (n < 0) ? (status_t)n : ERROR_END_OF_STREAM; 181 return mFinalResult; 182 } 183 184 mBuffer->setRange(mBuffer->offset(), mBuffer->size() + n); 185 mOffset += n; 186 } else if (err != OK) { 187 mFinalResult = err; 188 return err; 189 } else { 190 return OK; 191 } 192 } 193} 194 195status_t MPEG2PSExtractor::dequeueChunk() { 196 if (mBuffer->size() < 4) { 197 return -EAGAIN; 198 } 199 200 if (memcmp("\x00\x00\x01", mBuffer->data(), 3)) { 201 return ERROR_MALFORMED; 202 } 203 204 unsigned chunkType = mBuffer->data()[3]; 205 206 ssize_t res; 207 208 switch (chunkType) { 209 case 0xba: 210 { 211 res = dequeuePack(); 212 break; 213 } 214 215 case 0xbb: 216 { 217 res = dequeueSystemHeader(); 218 break; 219 } 220 221 default: 222 { 223 res = dequeuePES(); 224 break; 225 } 226 } 227 228 if (res > 0) { 229 if (mBuffer->size() < (size_t)res) { 230 return -EAGAIN; 231 } 232 233 mBuffer->setRange(mBuffer->offset() + res, mBuffer->size() - res); 234 res = OK; 235 } 236 237 return res; 238} 239 240ssize_t MPEG2PSExtractor::dequeuePack() { 241 // 32 + 2 + 3 + 1 + 15 + 1 + 15+ 1 + 9 + 1 + 22 + 1 + 1 | +5 242 243 if (mBuffer->size() < 14) { 244 return -EAGAIN; 245 } 246 247 unsigned pack_stuffing_length = mBuffer->data()[13] & 7; 248 249 return pack_stuffing_length + 14; 250} 251 252ssize_t MPEG2PSExtractor::dequeueSystemHeader() { 253 if (mBuffer->size() < 6) { 254 return -EAGAIN; 255 } 256 257 unsigned header_length = U16_AT(mBuffer->data() + 4); 258 259 return header_length + 6; 260} 261 262ssize_t MPEG2PSExtractor::dequeuePES() { 263 if (mBuffer->size() < 6) { 264 return -EAGAIN; 265 } 266 267 unsigned PES_packet_length = U16_AT(mBuffer->data() + 4); 268 if (PES_packet_length == 0u) { 269 ALOGE("PES_packet_length is 0"); 270 return -EAGAIN; 271 } 272 273 size_t n = PES_packet_length + 6; 274 275 if (mBuffer->size() < n) { 276 return -EAGAIN; 277 } 278 279 ABitReader br(mBuffer->data(), n); 280 281 unsigned packet_startcode_prefix = br.getBits(24); 282 283 ALOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix); 284 285 if (packet_startcode_prefix != 1) { 286 ALOGV("Supposedly payload_unit_start=1 unit does not start " 287 "with startcode."); 288 289 return ERROR_MALFORMED; 290 } 291 292 if (packet_startcode_prefix != 0x000001u) { 293 ALOGE("Wrong PES prefix"); 294 return ERROR_MALFORMED; 295 } 296 297 unsigned stream_id = br.getBits(8); 298 ALOGV("stream_id = 0x%02x", stream_id); 299 300 /* unsigned PES_packet_length = */br.getBits(16); 301 302 if (stream_id == 0xbc) { 303 // program_stream_map 304 305 if (!mScanning) { 306 return n; 307 } 308 309 mStreamTypeByESID.clear(); 310 311 /* unsigned current_next_indicator = */br.getBits(1); 312 /* unsigned reserved = */br.getBits(2); 313 /* unsigned program_stream_map_version = */br.getBits(5); 314 /* unsigned reserved = */br.getBits(7); 315 /* unsigned marker_bit = */br.getBits(1); 316 unsigned program_stream_info_length = br.getBits(16); 317 318 size_t offset = 0; 319 while (offset < program_stream_info_length) { 320 if (offset + 2 > program_stream_info_length) { 321 return ERROR_MALFORMED; 322 } 323 324 unsigned descriptor_tag = br.getBits(8); 325 unsigned descriptor_length = br.getBits(8); 326 327 ALOGI("found descriptor tag 0x%02x of length %u", 328 descriptor_tag, descriptor_length); 329 330 if (offset + 2 + descriptor_length > program_stream_info_length) { 331 return ERROR_MALFORMED; 332 } 333 334 br.skipBits(8 * descriptor_length); 335 336 offset += 2 + descriptor_length; 337 } 338 339 unsigned elementary_stream_map_length = br.getBits(16); 340 341 offset = 0; 342 while (offset < elementary_stream_map_length) { 343 if (offset + 4 > elementary_stream_map_length) { 344 return ERROR_MALFORMED; 345 } 346 347 unsigned stream_type = br.getBits(8); 348 unsigned elementary_stream_id = br.getBits(8); 349 350 ALOGI("elementary stream id 0x%02x has stream type 0x%02x", 351 elementary_stream_id, stream_type); 352 353 mStreamTypeByESID.add(elementary_stream_id, stream_type); 354 355 unsigned elementary_stream_info_length = br.getBits(16); 356 357 if (offset + 4 + elementary_stream_info_length 358 > elementary_stream_map_length) { 359 return ERROR_MALFORMED; 360 } 361 362 offset += 4 + elementary_stream_info_length; 363 } 364 365 /* unsigned CRC32 = */br.getBits(32); 366 367 mProgramStreamMapValid = true; 368 } else if (stream_id != 0xbe // padding_stream 369 && stream_id != 0xbf // private_stream_2 370 && stream_id != 0xf0 // ECM 371 && stream_id != 0xf1 // EMM 372 && stream_id != 0xff // program_stream_directory 373 && stream_id != 0xf2 // DSMCC 374 && stream_id != 0xf8) { // H.222.1 type E 375 /* unsigned PES_marker_bits = */br.getBits(2); // should be 0x2(hex) 376 /* unsigned PES_scrambling_control = */br.getBits(2); 377 /* unsigned PES_priority = */br.getBits(1); 378 /* unsigned data_alignment_indicator = */br.getBits(1); 379 /* unsigned copyright = */br.getBits(1); 380 /* unsigned original_or_copy = */br.getBits(1); 381 382 unsigned PTS_DTS_flags = br.getBits(2); 383 ALOGV("PTS_DTS_flags = %u", PTS_DTS_flags); 384 385 unsigned ESCR_flag = br.getBits(1); 386 ALOGV("ESCR_flag = %u", ESCR_flag); 387 388 unsigned ES_rate_flag = br.getBits(1); 389 ALOGV("ES_rate_flag = %u", ES_rate_flag); 390 391 unsigned DSM_trick_mode_flag = br.getBits(1); 392 ALOGV("DSM_trick_mode_flag = %u", DSM_trick_mode_flag); 393 394 unsigned additional_copy_info_flag = br.getBits(1); 395 ALOGV("additional_copy_info_flag = %u", additional_copy_info_flag); 396 397 /* unsigned PES_CRC_flag = */br.getBits(1); 398 /* PES_extension_flag = */br.getBits(1); 399 400 unsigned PES_header_data_length = br.getBits(8); 401 ALOGV("PES_header_data_length = %u", PES_header_data_length); 402 403 unsigned optional_bytes_remaining = PES_header_data_length; 404 405 uint64_t PTS = 0, DTS = 0; 406 407 if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) { 408 if (optional_bytes_remaining < 5u) { 409 return ERROR_MALFORMED; 410 } 411 412 if (br.getBits(4) != PTS_DTS_flags) { 413 return ERROR_MALFORMED; 414 } 415 416 PTS = ((uint64_t)br.getBits(3)) << 30; 417 if (br.getBits(1) != 1u) { 418 return ERROR_MALFORMED; 419 } 420 PTS |= ((uint64_t)br.getBits(15)) << 15; 421 if (br.getBits(1) != 1u) { 422 return ERROR_MALFORMED; 423 } 424 PTS |= br.getBits(15); 425 if (br.getBits(1) != 1u) { 426 return ERROR_MALFORMED; 427 } 428 429 ALOGV("PTS = %" PRIu64, PTS); 430 // ALOGI("PTS = %.2f secs", PTS / 90000.0f); 431 432 optional_bytes_remaining -= 5; 433 434 if (PTS_DTS_flags == 3) { 435 if (optional_bytes_remaining < 5u) { 436 return ERROR_MALFORMED; 437 } 438 439 if (br.getBits(4) != 1u) { 440 return ERROR_MALFORMED; 441 } 442 443 DTS = ((uint64_t)br.getBits(3)) << 30; 444 if (br.getBits(1) != 1u) { 445 return ERROR_MALFORMED; 446 } 447 DTS |= ((uint64_t)br.getBits(15)) << 15; 448 if (br.getBits(1) != 1u) { 449 return ERROR_MALFORMED; 450 } 451 DTS |= br.getBits(15); 452 if (br.getBits(1) != 1u) { 453 return ERROR_MALFORMED; 454 } 455 456 ALOGV("DTS = %" PRIu64, DTS); 457 458 optional_bytes_remaining -= 5; 459 } 460 } 461 462 if (ESCR_flag) { 463 if (optional_bytes_remaining < 6u) { 464 return ERROR_MALFORMED; 465 } 466 467 br.getBits(2); 468 469 uint64_t ESCR = ((uint64_t)br.getBits(3)) << 30; 470 if (br.getBits(1) != 1u) { 471 return ERROR_MALFORMED; 472 } 473 ESCR |= ((uint64_t)br.getBits(15)) << 15; 474 if (br.getBits(1) != 1u) { 475 return ERROR_MALFORMED; 476 } 477 ESCR |= br.getBits(15); 478 if (br.getBits(1) != 1u) { 479 return ERROR_MALFORMED; 480 } 481 482 ALOGV("ESCR = %" PRIu64, ESCR); 483 /* unsigned ESCR_extension = */br.getBits(9); 484 485 if (br.getBits(1) != 1u) { 486 return ERROR_MALFORMED; 487 } 488 489 optional_bytes_remaining -= 6; 490 } 491 492 if (ES_rate_flag) { 493 if (optional_bytes_remaining < 3u) { 494 return ERROR_MALFORMED; 495 } 496 497 if (br.getBits(1) != 1u) { 498 return ERROR_MALFORMED; 499 } 500 /* unsigned ES_rate = */br.getBits(22); 501 if (br.getBits(1) != 1u) { 502 return ERROR_MALFORMED; 503 } 504 505 optional_bytes_remaining -= 3; 506 } 507 508 br.skipBits(optional_bytes_remaining * 8); 509 510 // ES data follows. 511 512 if (PES_packet_length < PES_header_data_length + 3) { 513 return ERROR_MALFORMED; 514 } 515 516 unsigned dataLength = 517 PES_packet_length - 3 - PES_header_data_length; 518 519 if (br.numBitsLeft() < dataLength * 8) { 520 ALOGE("PES packet does not carry enough data to contain " 521 "payload. (numBitsLeft = %zu, required = %u)", 522 br.numBitsLeft(), dataLength * 8); 523 524 return ERROR_MALFORMED; 525 } 526 527 if (br.numBitsLeft() < dataLength * 8) { 528 return ERROR_MALFORMED; 529 } 530 531 ssize_t index = mTracks.indexOfKey(stream_id); 532 if (index < 0 && mScanning) { 533 unsigned streamType; 534 535 ssize_t streamTypeIndex; 536 if (mProgramStreamMapValid 537 && (streamTypeIndex = 538 mStreamTypeByESID.indexOfKey(stream_id)) >= 0) { 539 streamType = mStreamTypeByESID.valueAt(streamTypeIndex); 540 } else if ((stream_id & ~0x1f) == 0xc0) { 541 // ISO/IEC 13818-3 or ISO/IEC 11172-3 or ISO/IEC 13818-7 542 // or ISO/IEC 14496-3 audio 543 streamType = ATSParser::STREAMTYPE_MPEG2_AUDIO; 544 } else if ((stream_id & ~0x0f) == 0xe0) { 545 // ISO/IEC 13818-2 or ISO/IEC 11172-2 or ISO/IEC 14496-2 video 546 streamType = ATSParser::STREAMTYPE_MPEG2_VIDEO; 547 } else { 548 streamType = ATSParser::STREAMTYPE_RESERVED; 549 } 550 551 index = mTracks.add( 552 stream_id, new Track(this, stream_id, streamType)); 553 } 554 555 status_t err = OK; 556 557 if (index >= 0) { 558 err = 559 mTracks.editValueAt(index)->appendPESData( 560 PTS_DTS_flags, PTS, DTS, br.data(), dataLength); 561 } 562 563 br.skipBits(dataLength * 8); 564 565 if (err != OK) { 566 return err; 567 } 568 } else if (stream_id == 0xbe) { // padding_stream 569 if (PES_packet_length == 0u) { 570 return ERROR_MALFORMED; 571 } 572 br.skipBits(PES_packet_length * 8); 573 } else { 574 if (PES_packet_length == 0u) { 575 return ERROR_MALFORMED; 576 } 577 br.skipBits(PES_packet_length * 8); 578 } 579 580 return n; 581} 582 583//////////////////////////////////////////////////////////////////////////////// 584 585MPEG2PSExtractor::Track::Track( 586 MPEG2PSExtractor *extractor, unsigned stream_id, unsigned stream_type) 587 : mExtractor(extractor), 588 mStreamID(stream_id), 589 mStreamType(stream_type), 590 mQueue(NULL) { 591 bool supported = true; 592 ElementaryStreamQueue::Mode mode; 593 594 switch (mStreamType) { 595 case ATSParser::STREAMTYPE_H264: 596 mode = ElementaryStreamQueue::H264; 597 break; 598 case ATSParser::STREAMTYPE_MPEG2_AUDIO_ADTS: 599 mode = ElementaryStreamQueue::AAC; 600 break; 601 case ATSParser::STREAMTYPE_MPEG1_AUDIO: 602 case ATSParser::STREAMTYPE_MPEG2_AUDIO: 603 mode = ElementaryStreamQueue::MPEG_AUDIO; 604 break; 605 606 case ATSParser::STREAMTYPE_MPEG1_VIDEO: 607 case ATSParser::STREAMTYPE_MPEG2_VIDEO: 608 mode = ElementaryStreamQueue::MPEG_VIDEO; 609 break; 610 611 case ATSParser::STREAMTYPE_MPEG4_VIDEO: 612 mode = ElementaryStreamQueue::MPEG4_VIDEO; 613 break; 614 615 default: 616 supported = false; 617 break; 618 } 619 620 if (supported) { 621 mQueue = new ElementaryStreamQueue(mode); 622 } else { 623 ALOGI("unsupported stream ID 0x%02x", stream_id); 624 } 625} 626 627MPEG2PSExtractor::Track::~Track() { 628 delete mQueue; 629 mQueue = NULL; 630} 631 632status_t MPEG2PSExtractor::Track::start(MetaData *params) { 633 if (mSource == NULL) { 634 return NO_INIT; 635 } 636 637 return mSource->start(params); 638} 639 640status_t MPEG2PSExtractor::Track::stop() { 641 if (mSource == NULL) { 642 return NO_INIT; 643 } 644 645 return mSource->stop(); 646} 647 648sp<MetaData> MPEG2PSExtractor::Track::getFormat() { 649 if (mSource == NULL) { 650 return NULL; 651 } 652 653 return mSource->getFormat(); 654} 655 656status_t MPEG2PSExtractor::Track::read( 657 MediaBuffer **buffer, const ReadOptions *options) { 658 if (mSource == NULL) { 659 return NO_INIT; 660 } 661 662 status_t finalResult; 663 while (!mSource->hasBufferAvailable(&finalResult)) { 664 if (finalResult != OK) { 665 return ERROR_END_OF_STREAM; 666 } 667 668 status_t err = mExtractor->feedMore(); 669 670 if (err != OK) { 671 mSource->signalEOS(err); 672 } 673 } 674 675 return mSource->read(buffer, options); 676} 677 678status_t MPEG2PSExtractor::Track::appendPESData( 679 unsigned PTS_DTS_flags, 680 uint64_t PTS, uint64_t /* DTS */, 681 const uint8_t *data, size_t size) { 682 if (mQueue == NULL) { 683 return OK; 684 } 685 686 int64_t timeUs; 687 if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) { 688 timeUs = (PTS * 100) / 9; 689 } else { 690 timeUs = 0; 691 } 692 693 status_t err = mQueue->appendData(data, size, timeUs); 694 695 if (err != OK) { 696 return err; 697 } 698 699 sp<ABuffer> accessUnit; 700 while ((accessUnit = mQueue->dequeueAccessUnit()) != NULL) { 701 if (mSource == NULL) { 702 sp<MetaData> meta = mQueue->getFormat(); 703 704 if (meta != NULL) { 705 ALOGV("Stream ID 0x%02x now has data.", mStreamID); 706 707 mSource = new AnotherPacketSource(meta); 708 mSource->queueAccessUnit(accessUnit); 709 } 710 } else if (mQueue->getFormat() != NULL) { 711 mSource->queueAccessUnit(accessUnit); 712 } 713 } 714 715 return OK; 716} 717 718//////////////////////////////////////////////////////////////////////////////// 719 720MPEG2PSExtractor::WrappedTrack::WrappedTrack( 721 const sp<MPEG2PSExtractor> &extractor, const sp<Track> &track) 722 : mExtractor(extractor), 723 mTrack(track) { 724} 725 726MPEG2PSExtractor::WrappedTrack::~WrappedTrack() { 727} 728 729status_t MPEG2PSExtractor::WrappedTrack::start(MetaData *params) { 730 return mTrack->start(params); 731} 732 733status_t MPEG2PSExtractor::WrappedTrack::stop() { 734 return mTrack->stop(); 735} 736 737sp<MetaData> MPEG2PSExtractor::WrappedTrack::getFormat() { 738 return mTrack->getFormat(); 739} 740 741status_t MPEG2PSExtractor::WrappedTrack::read( 742 MediaBuffer **buffer, const ReadOptions *options) { 743 return mTrack->read(buffer, options); 744} 745 746//////////////////////////////////////////////////////////////////////////////// 747 748bool SniffMPEG2PS( 749 const sp<DataSource> &source, String8 *mimeType, float *confidence, 750 sp<AMessage> *) { 751 uint8_t header[5]; 752 if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) { 753 return false; 754 } 755 756 if (memcmp("\x00\x00\x01\xba", header, 4) || (header[4] >> 6) != 1) { 757 return false; 758 } 759 760 *confidence = 0.25f; // Slightly larger than .mp3 extractor's confidence 761 762 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2PS); 763 764 return true; 765} 766 767} // namespace android 768