text: /*
   * Copyright (C) 2011 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  //#define LOG_NDEBUG 0
  #define LOG_TAG "MPEG2PSExtractor"
  #include <utils/Log.h>
  
  #include "MPEG2PSExtractor.h"
  
  #include <AnotherPacketSource.h>
  #include <ESQueue.h>
  
  #include <media/stagefright/foundation/ABitReader.h>
  #include <media/stagefright/foundation/ABuffer.h>
  #include <media/stagefright/foundation/ADebug.h>
  #include <media/stagefright/foundation/AMessage.h>
  #include <media/stagefright/foundation/ByteUtils.h>
  #include <media/stagefright/foundation/hexdump.h>
  #include <media/stagefright/MediaDefs.h>
  #include <media/stagefright/MediaErrors.h>
  #include <media/stagefright/MetaData.h>
  #include <media/stagefright/Utils.h>
  #include <utils/String8.h>
  
  #include <inttypes.h>
  
  namespace android {
  
  struct MPEG2PSExtractor::Track : public MediaTrackHelper {
      Track(MPEG2PSExtractor *extractor,
            unsigned stream_id, unsigned stream_type);
  
      virtual media_status_t start();
      virtual media_status_t stop();
      virtual media_status_t getFormat(AMediaFormat *);
  
      virtual media_status_t read(
              MediaBufferHelper **buffer, const ReadOptions *options);
  
  protected:
      virtual ~Track();
  
  private:
      friend struct MPEG2PSExtractor;
  
      MPEG2PSExtractor *mExtractor;
  
      unsigned mStreamID;
      unsigned mStreamType;
      ElementaryStreamQueue *mQueue;
      sp<AnotherPacketSource> mSource;
  
      status_t appendPESData(
              unsigned PTS_DTS_flags,
              uint64_t PTS, uint64_t DTS,
              const uint8_t *data, size_t size);
  
      DISALLOW_EVIL_CONSTRUCTORS(Track);
  };
  
  struct MPEG2PSExtractor::WrappedTrack : public MediaTrackHelper {
      WrappedTrack(MPEG2PSExtractor *extractor, Track *track);
  
      virtual media_status_t start();
      virtual media_status_t stop();
      virtual media_status_t getFormat(AMediaFormat *);
  
      virtual media_status_t read(
              MediaBufferHelper **buffer, const ReadOptions *options);
  
  protected:
      virtual ~WrappedTrack();
  
  private:
      MPEG2PSExtractor *mExtractor;
      MPEG2PSExtractor::Track *mTrack;
  
      DISALLOW_EVIL_CONSTRUCTORS(WrappedTrack);
  };
  
  ////////////////////////////////////////////////////////////////////////////////
  
  MPEG2PSExtractor::MPEG2PSExtractor(DataSourceHelper *source)
      : mDataSource(source),
        mOffset(0),
        mFinalResult(OK),
        mBuffer(new ABuffer(0)),
        mScanning(true),
        mProgramStreamMapValid(false) {
      for (size_t i = 0; i < 500; ++i) {
          if (feedMore() != OK) {
              break;
          }
      }
  
      // Remove all tracks that were unable to determine their format.
      AMediaFormat *meta = AMediaFormat_new();
      for (size_t i = mTracks.size(); i > 0;) {
          i--;
          Track *track = mTracks.valueAt(i);
          if (track->getFormat(meta) != AMEDIA_OK) {
              mTracks.removeItemsAt(i);
              delete track;
          }
      }
      AMediaFormat_delete(meta);
  
      mScanning = false;
  }
  
  MPEG2PSExtractor::~MPEG2PSExtractor() {
      delete mDataSource;
      for (size_t i = mTracks.size(); i > 0;) {
          i--;
          delete mTracks.valueAt(i);
      }
  }
  
  size_t MPEG2PSExtractor::countTracks() {
      return mTracks.size();
  }
  
  MediaTrackHelper *MPEG2PSExtractor::getTrack(size_t index) {
      if (index >= mTracks.size()) {
          return NULL;
      }
  
      return new WrappedTrack(this, mTracks.valueAt(index));
  }
  
  media_status_t MPEG2PSExtractor::getTrackMetaData(
          AMediaFormat *meta,
          size_t index, uint32_t /* flags */) {
      if (index >= mTracks.size()) {
          return AMEDIA_ERROR_UNKNOWN;
      }
  
      return mTracks.valueAt(index)->getFormat(meta);
  }
  
  media_status_t MPEG2PSExtractor::getMetaData(AMediaFormat *meta) {
      AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_CONTAINER_MPEG2PS);
  
      return AMEDIA_OK;
  }
  
  uint32_t MPEG2PSExtractor::flags() const {
      return CAN_PAUSE;
  }
  
  status_t MPEG2PSExtractor::feedMore() {
      Mutex::Autolock autoLock(mLock);
  
      // How much data we're reading at a time
      static const size_t kChunkSize = 8192;
  
      for (;;) {
          status_t err = dequeueChunk();
  
          if (err == -EAGAIN && mFinalResult == OK) {
              memmove(mBuffer->base(), mBuffer->data(), mBuffer->size());
              mBuffer->setRange(0, mBuffer->size());
  
              if (mBuffer->size() + kChunkSize > mBuffer->capacity()) {
                  size_t newCapacity = mBuffer->capacity() + kChunkSize;
                  sp<ABuffer> newBuffer = new ABuffer(newCapacity);
                  memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size());
                  newBuffer->setRange(0, mBuffer->size());
                  mBuffer = newBuffer;
              }
  
              ssize_t n = mDataSource->readAt(
                      mOffset, mBuffer->data() + mBuffer->size(), kChunkSize);
  
              if (n < (ssize_t)kChunkSize) {
                  mFinalResult = (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
                  return mFinalResult;
              }
  
              mBuffer->setRange(mBuffer->offset(), mBuffer->size() + n);
              mOffset += n;
          } else if (err != OK) {
              mFinalResult = err;
              return err;
          } else {
              return OK;
          }
      }
  }
  
  status_t MPEG2PSExtractor::dequeueChunk() {
      if (mBuffer->size() < 4) {
          return -EAGAIN;
      }
  
      if (memcmp("\x00\x00\x01", mBuffer->data(), 3)) {
          return ERROR_MALFORMED;
      }
  
      unsigned chunkType = mBuffer->data()[3];
  
      ssize_t res;
  
      switch (chunkType) {
          case 0xba:
          {
              res = dequeuePack();
              break;
          }
  
          case 0xbb:
          {
              res = dequeueSystemHeader();
              break;
          }
  
          default:
          {
              res = dequeuePES();
              break;
          }
      }
  
      if (res > 0) {
          if (mBuffer->size() < (size_t)res) {
              return -EAGAIN;
          }
  
          mBuffer->setRange(mBuffer->offset() + res, mBuffer->size() - res);
          res = OK;
      }
  
      return res;
  }
  
  ssize_t MPEG2PSExtractor::dequeuePack() {
      // 32 + 2 + 3 + 1 + 15 + 1 + 15+ 1 + 9 + 1 + 22 + 1 + 1 | +5
  
      if (mBuffer->size() < 14) {
          return -EAGAIN;
      }
  
      unsigned pack_stuffing_length = mBuffer->data()[13] & 7;
  
      return pack_stuffing_length + 14;
  }
  
  ssize_t MPEG2PSExtractor::dequeueSystemHeader() {
      if (mBuffer->size() < 6) {
          return -EAGAIN;
      }
  
      unsigned header_length = U16_AT(mBuffer->data() + 4);
  
      return header_length + 6;
  }
  
  ssize_t MPEG2PSExtractor::dequeuePES() {
      if (mBuffer->size() < 6) {
          return -EAGAIN;
      }
  
      unsigned PES_packet_length = U16_AT(mBuffer->data() + 4);
      if (PES_packet_length == 0u) {
          ALOGE("PES_packet_length is 0");
          return -EAGAIN;
      }
  
      size_t n = PES_packet_length + 6;
  
      if (mBuffer->size() < n) {
          return -EAGAIN;
      }
  
      ABitReader br(mBuffer->data(), n);
  
      unsigned packet_startcode_prefix = br.getBits(24);
  
      ALOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix);
  
      if (packet_startcode_prefix != 1) {
          ALOGV("Supposedly payload_unit_start=1 unit does not start "
               "with startcode.");
  
          return ERROR_MALFORMED;
      }
  
      if (packet_startcode_prefix != 0x000001u) {
          ALOGE("Wrong PES prefix");
          return ERROR_MALFORMED;
      }
  
      unsigned stream_id = br.getBits(8);
      ALOGV("stream_id = 0x%02x", stream_id);
  
      /* unsigned PES_packet_length = */br.getBits(16);
  
      if (stream_id == 0xbc) {
          // program_stream_map
  
          if (!mScanning) {
              return n;
          }
  
          mStreamTypeByESID.clear();
  
          /* unsigned current_next_indicator = */br.getBits(1);
          /* unsigned reserved = */br.getBits(2);
          /* unsigned program_stream_map_version = */br.getBits(5);
          /* unsigned reserved = */br.getBits(7);
          /* unsigned marker_bit = */br.getBits(1);
          unsigned program_stream_info_length = br.getBits(16);
  
          size_t offset = 0;
          while (offset < program_stream_info_length) {
              if (offset + 2 > program_stream_info_length) {
                  return ERROR_MALFORMED;
              }
  
              unsigned descriptor_tag = br.getBits(8);
              unsigned descriptor_length = br.getBits(8);
  
              ALOGI("found descriptor tag 0x%02x of length %u",
                   descriptor_tag, descriptor_length);
  
              if (offset + 2 + descriptor_length > program_stream_info_length) {
                  return ERROR_MALFORMED;
              }
  
              br.skipBits(8 * descriptor_length);
  
              offset += 2 + descriptor_length;
          }
  
          unsigned elementary_stream_map_length = br.getBits(16);
  
          offset = 0;
          while (offset < elementary_stream_map_length) {
              if (offset + 4 > elementary_stream_map_length) {
                  return ERROR_MALFORMED;
              }
  
              unsigned stream_type = br.getBits(8);
              unsigned elementary_stream_id = br.getBits(8);
  
              ALOGI("elementary stream id 0x%02x has stream type 0x%02x",
                   elementary_stream_id, stream_type);
  
              mStreamTypeByESID.add(elementary_stream_id, stream_type);
  
              unsigned elementary_stream_info_length = br.getBits(16);
  
              if (offset + 4 + elementary_stream_info_length
                      > elementary_stream_map_length) {
                  return ERROR_MALFORMED;
              }
  
              offset += 4 + elementary_stream_info_length;
          }
  
          /* unsigned CRC32 = */br.getBits(32);
  
          mProgramStreamMapValid = true;
      } else if (stream_id != 0xbe  // padding_stream
              && stream_id != 0xbf  // private_stream_2
              && stream_id != 0xf0  // ECM
              && stream_id != 0xf1  // EMM
              && stream_id != 0xff  // program_stream_directory
              && stream_id != 0xf2  // DSMCC
              && stream_id != 0xf8) {  // H.222.1 type E
          /* unsigned PES_marker_bits = */br.getBits(2);  // should be 0x2(hex)
          /* unsigned PES_scrambling_control = */br.getBits(2);
          /* unsigned PES_priority = */br.getBits(1);
          /* unsigned data_alignment_indicator = */br.getBits(1);
          /* unsigned copyright = */br.getBits(1);
          /* unsigned original_or_copy = */br.getBits(1);
  
          unsigned PTS_DTS_flags = br.getBits(2);
          ALOGV("PTS_DTS_flags = %u", PTS_DTS_flags);
  
          unsigned ESCR_flag = br.getBits(1);
          ALOGV("ESCR_flag = %u", ESCR_flag);
  
          unsigned ES_rate_flag = br.getBits(1);
          ALOGV("ES_rate_flag = %u", ES_rate_flag);
  
          unsigned DSM_trick_mode_flag = br.getBits(1);
          ALOGV("DSM_trick_mode_flag = %u", DSM_trick_mode_flag);
  
          unsigned additional_copy_info_flag = br.getBits(1);
          ALOGV("additional_copy_info_flag = %u", additional_copy_info_flag);
  
          /* unsigned PES_CRC_flag = */br.getBits(1);
          /* PES_extension_flag = */br.getBits(1);
  
          unsigned PES_header_data_length = br.getBits(8);
          ALOGV("PES_header_data_length = %u", PES_header_data_length);
  
          unsigned optional_bytes_remaining = PES_header_data_length;
  
          uint64_t PTS = 0, DTS = 0;
  
          if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) {
              if (optional_bytes_remaining < 5u) {
                  return ERROR_MALFORMED;
              }
  
              if (br.getBits(4) != PTS_DTS_flags) {
                  return ERROR_MALFORMED;
              }
  
              PTS = ((uint64_t)br.getBits(3)) << 30;
              if (br.getBits(1) != 1u) {
                  return ERROR_MALFORMED;
              }
              PTS |= ((uint64_t)br.getBits(15)) << 15;
              if (br.getBits(1) != 1u) {
                  return ERROR_MALFORMED;
              }
              PTS |= br.getBits(15);
              if (br.getBits(1) != 1u) {
                  return ERROR_MALFORMED;
              }
  
              ALOGV("PTS = %" PRIu64, PTS);
              // ALOGI("PTS = %.2f secs", PTS / 90000.0f);
  
              optional_bytes_remaining -= 5;
  
              if (PTS_DTS_flags == 3) {
                  if (optional_bytes_remaining < 5u) {
                      return ERROR_MALFORMED;
                  }
  
                  if (br.getBits(4) != 1u) {
                      return ERROR_MALFORMED;
                  }
  
                  DTS = ((uint64_t)br.getBits(3)) << 30;
                  if (br.getBits(1) != 1u) {
                      return ERROR_MALFORMED;
                  }
                  DTS |= ((uint64_t)br.getBits(15)) << 15;
                  if (br.getBits(1) != 1u) {
                      return ERROR_MALFORMED;
                  }
                  DTS |= br.getBits(15);
                  if (br.getBits(1) != 1u) {
                      return ERROR_MALFORMED;
                  }
  
                  ALOGV("DTS = %" PRIu64, DTS);
  
                  optional_bytes_remaining -= 5;
              }
          }
  
          if (ESCR_flag) {
              if (optional_bytes_remaining < 6u) {
                  return ERROR_MALFORMED;
              }
  
              br.getBits(2);
  
              uint64_t ESCR = ((uint64_t)br.getBits(3)) << 30;
              if (br.getBits(1) != 1u) {
                  return ERROR_MALFORMED;
              }
              ESCR |= ((uint64_t)br.getBits(15)) << 15;
              if (br.getBits(1) != 1u) {
                  return ERROR_MALFORMED;
              }
              ESCR |= br.getBits(15);
              if (br.getBits(1) != 1u) {
                  return ERROR_MALFORMED;
              }
  
              ALOGV("ESCR = %" PRIu64, ESCR);
              /* unsigned ESCR_extension = */br.getBits(9);
  
              if (br.getBits(1) != 1u) {
                  return ERROR_MALFORMED;
              }
  
              optional_bytes_remaining -= 6;
          }
  
          if (ES_rate_flag) {
              if (optional_bytes_remaining < 3u) {
                  return ERROR_MALFORMED;
              }
  
              if (br.getBits(1) != 1u) {
                  return ERROR_MALFORMED;
              }
              /* unsigned ES_rate = */br.getBits(22);
              if (br.getBits(1) != 1u) {
                  return ERROR_MALFORMED;
              }
  
              optional_bytes_remaining -= 3;
          }
  
          if (br.numBitsLeft() < optional_bytes_remaining * 8) {
              return ERROR_MALFORMED;
          }
  
          br.skipBits(optional_bytes_remaining * 8);
  
          // ES data follows.
  
          if (PES_packet_length < PES_header_data_length + 3) {
              return ERROR_MALFORMED;
          }
  
          unsigned dataLength =
              PES_packet_length - 3 - PES_header_data_length;
  
          if (br.numBitsLeft() < dataLength * 8) {
              ALOGE("PES packet does not carry enough data to contain "
                   "payload. (numBitsLeft = %zu, required = %u)",
                   br.numBitsLeft(), dataLength * 8);
  
              return ERROR_MALFORMED;
          }
  
          if (br.numBitsLeft() < dataLength * 8) {
              return ERROR_MALFORMED;
          }
  
          ssize_t index = mTracks.indexOfKey(stream_id);
          if (index < 0 && mScanning) {
              unsigned streamType;
  
              ssize_t streamTypeIndex;
              if (mProgramStreamMapValid
                      && (streamTypeIndex =
                              mStreamTypeByESID.indexOfKey(stream_id)) >= 0) {
                  streamType = mStreamTypeByESID.valueAt(streamTypeIndex);
              } else if ((stream_id & ~0x1f) == 0xc0) {
                  // ISO/IEC 13818-3 or ISO/IEC 11172-3 or ISO/IEC 13818-7
                  // or ISO/IEC 14496-3 audio
                  streamType = ATSParser::STREAMTYPE_MPEG2_AUDIO;
              } else if ((stream_id & ~0x0f) == 0xe0) {
                  // ISO/IEC 13818-2 or ISO/IEC 11172-2 or ISO/IEC 14496-2 video
                  streamType = ATSParser::STREAMTYPE_MPEG2_VIDEO;
              } else {
                  streamType = ATSParser::STREAMTYPE_RESERVED;
              }
  
              index = mTracks.add(
                      stream_id, new Track(this, stream_id, streamType));
          }
  
          status_t err = OK;
  
          if (index >= 0) {
              err =
                  mTracks.editValueAt(index)->appendPESData(
                      PTS_DTS_flags, PTS, DTS, br.data(), dataLength);
          }
  
          br.skipBits(dataLength * 8);
  
          if (err != OK) {
              return err;
          }
      } else if (stream_id == 0xbe) {  // padding_stream
          if (PES_packet_length == 0u) {
              return ERROR_MALFORMED;
          }
          br.skipBits(PES_packet_length * 8);
      } else {
          if (PES_packet_length == 0u) {
              return ERROR_MALFORMED;
          }
          br.skipBits(PES_packet_length * 8);
      }
  
      return n;
  }
  
  ////////////////////////////////////////////////////////////////////////////////
  
  MPEG2PSExtractor::Track::Track(
          MPEG2PSExtractor *extractor, unsigned stream_id, unsigned stream_type)
      : mExtractor(extractor),
        mStreamID(stream_id),
        mStreamType(stream_type),
        mQueue(NULL) {
      bool supported = true;
      ElementaryStreamQueue::Mode mode;
  
      switch (mStreamType) {
          case ATSParser::STREAMTYPE_H264:
              mode = ElementaryStreamQueue::H264;
              break;
          case ATSParser::STREAMTYPE_MPEG2_AUDIO_ADTS:
              mode = ElementaryStreamQueue::AAC;
              break;
          case ATSParser::STREAMTYPE_MPEG1_AUDIO:
          case ATSParser::STREAMTYPE_MPEG2_AUDIO:
              mode = ElementaryStreamQueue::MPEG_AUDIO;
              break;
  
          case ATSParser::STREAMTYPE_MPEG1_VIDEO:
          case ATSParser::STREAMTYPE_MPEG2_VIDEO:
              mode = ElementaryStreamQueue::MPEG_VIDEO;
              break;
  
          case ATSParser::STREAMTYPE_MPEG4_VIDEO:
              mode = ElementaryStreamQueue::MPEG4_VIDEO;
              break;
  
          default:
              supported = false;
              break;
      }
  
      if (supported) {
          mQueue = new ElementaryStreamQueue(mode);
      } else {
          ALOGI("unsupported stream ID 0x%02x", stream_id);
      }
  }
  
  MPEG2PSExtractor::Track::~Track() {
      delete mQueue;
      mQueue = NULL;
  }
  
  media_status_t MPEG2PSExtractor::Track::start() {
      if (mSource == NULL) {
          return AMEDIA_ERROR_UNKNOWN;
      }
  
      // initialize with one small buffer, but allow growth
      mBufferGroup->init(1 /* one buffer */, 256 /* buffer size */, 64 /* max number of buffers */);
  
      if (mSource->start(NULL) == OK) { // AnotherPacketSource::start doesn't use its argument
          return AMEDIA_OK;
      }
      return AMEDIA_ERROR_UNKNOWN;
  }
  
  media_status_t MPEG2PSExtractor::Track::stop() {
      if (mSource == NULL) {
          return AMEDIA_ERROR_UNKNOWN;
      }
  
      if (mSource->stop() == OK) {
          return AMEDIA_OK;
      }
      return AMEDIA_ERROR_UNKNOWN;
  }
  
  void copyAMessageToAMediaFormat(AMediaFormat *format, sp<AMessage> msg);
  
  media_status_t MPEG2PSExtractor::Track::getFormat(AMediaFormat *meta) {
      if (mSource == NULL) {
          return AMEDIA_ERROR_UNKNOWN;
      }
  
      sp<MetaData> sourceMeta = mSource->getFormat();
      sp<AMessage> msg;
      convertMetaDataToMessage(sourceMeta, &msg);
      copyAMessageToAMediaFormat(meta, msg);
      return AMEDIA_OK;
  }
  
  media_status_t MPEG2PSExtractor::Track::read(
          MediaBufferHelper **buffer, const ReadOptions *options) {
      if (mSource == NULL) {
          return AMEDIA_ERROR_UNKNOWN;
      }
  
      status_t finalResult;
      while (!mSource->hasBufferAvailable(&finalResult)) {
          if (finalResult != OK) {
              return AMEDIA_ERROR_END_OF_STREAM;
          }
  
          status_t err = mExtractor->feedMore();
  
          if (err != OK) {
              mSource->signalEOS(err);
          }
      }
  
      MediaBufferBase *mbuf;
      mSource->read(&mbuf, (MediaTrack::ReadOptions*) options);
      size_t length = mbuf->range_length();
      MediaBufferHelper *outbuf;
      mBufferGroup->acquire_buffer(&outbuf, false, length);
      memcpy(outbuf->data(), mbuf->data(), length);
      outbuf->set_range(0, length);
      *buffer = outbuf;
      MetaDataBase &inMeta = mbuf->meta_data();
      AMediaFormat *outMeta = outbuf->meta_data();
      int64_t val64;
      if (inMeta.findInt64(kKeyTime, &val64)) {
          AMediaFormat_setInt64(outMeta, AMEDIAFORMAT_KEY_TIME_US, val64);
      }
      int32_t val32;
      if (inMeta.findInt32(kKeyIsSyncFrame, &val32)) {
          AMediaFormat_setInt32(outMeta, AMEDIAFORMAT_KEY_IS_SYNC_FRAME, val32);
      }
      if (inMeta.findInt32(kKeyCryptoMode, &val32)) {
          AMediaFormat_setInt32(outMeta, AMEDIAFORMAT_KEY_CRYPTO_MODE, val32);
      }
      uint32_t bufType;
      const void *bufData;
      size_t bufSize;
      if (inMeta.findData(kKeyCryptoIV, &bufType, &bufData, &bufSize)) {
          AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_CRYPTO_IV, bufData, bufSize);
      }
      if (inMeta.findData(kKeyCryptoKey, &bufType, &bufData, &bufSize)) {
          AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_CRYPTO_KEY, bufData, bufSize);
      }
      if (inMeta.findData(kKeyPlainSizes, &bufType, &bufData, &bufSize)) {
          AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_CRYPTO_PLAIN_SIZES, bufData, bufSize);
      }
      if (inMeta.findData(kKeyEncryptedSizes, &bufType, &bufData, &bufSize)) {
          AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_CRYPTO_ENCRYPTED_SIZES, bufData, bufSize);
      }
      if (inMeta.findData(kKeySEI, &bufType, &bufData, &bufSize)) {
          AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_SEI, bufData, bufSize);
      }
      if (inMeta.findData(kKeyAudioPresentationInfo, &bufType, &bufData, &bufSize)) {
          AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_AUDIO_PRESENTATION_INFO, bufData, bufSize);
      }
      mbuf->release();
      return AMEDIA_OK;
  }
  
  status_t MPEG2PSExtractor::Track::appendPESData(
          unsigned PTS_DTS_flags,
          uint64_t PTS, uint64_t /* DTS */,
          const uint8_t *data, size_t size) {
      if (mQueue == NULL) {
          return OK;
      }
  
      int64_t timeUs;
      if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) {
          timeUs = (PTS * 100) / 9;
      } else {
          timeUs = 0;
      }
  
      status_t err = mQueue->appendData(data, size, timeUs);
  
      if (err != OK) {
          return err;
      }
  
      sp<ABuffer> accessUnit;
      while ((accessUnit = mQueue->dequeueAccessUnit()) != NULL) {
          if (mSource == NULL) {
              sp<MetaData> meta = mQueue->getFormat();
  
              if (meta != NULL) {
                  ALOGV("Stream ID 0x%02x now has data.", mStreamID);
  
                  mSource = new AnotherPacketSource(meta);
                  mSource->queueAccessUnit(accessUnit);
              }
          } else if (mQueue->getFormat() != NULL) {
              mSource->queueAccessUnit(accessUnit);
          }
      }
  
      return OK;
  }
  
  ////////////////////////////////////////////////////////////////////////////////
  
  MPEG2PSExtractor::WrappedTrack::WrappedTrack(
          MPEG2PSExtractor *extractor, Track *track)
      : mExtractor(extractor),
        mTrack(track) {
  }
  
  MPEG2PSExtractor::WrappedTrack::~WrappedTrack() {
  }
  
  media_status_t MPEG2PSExtractor::WrappedTrack::start() {
      delete mTrack->mBufferGroup;
      mTrack->mBufferGroup = mBufferGroup;
      mBufferGroup = nullptr;
      return mTrack->start();
  }
  
  media_status_t MPEG2PSExtractor::WrappedTrack::stop() {
      return mTrack->stop();
  }
  
  media_status_t MPEG2PSExtractor::WrappedTrack::getFormat(AMediaFormat *meta) {
      return mTrack->getFormat(meta);
  }
  
  media_status_t MPEG2PSExtractor::WrappedTrack::read(
          MediaBufferHelper **buffer, const ReadOptions *options) {
      return mTrack->read(buffer, options);
  }
  
  ////////////////////////////////////////////////////////////////////////////////
  
  bool SniffMPEG2PS(
          DataSourceHelper *source, float *confidence) {
      uint8_t header[5];
      if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
          return false;
      }
  
      if (memcmp("\x00\x00\x01\xba", header, 4) || (header[4] >> 6) != 1) {
          return false;
      }
  
      *confidence = 0.25f;  // Slightly larger than .mp3 extractor's confidence
  
      return true;
  }
  
  }  // namespace android
  