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