content/media/omx/RtspOmxReader.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/media/omx/RtspOmxReader.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,342 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "RtspOmxReader.h"
    1.11 +
    1.12 +#include "AbstractMediaDecoder.h"
    1.13 +#include "MediaDecoderStateMachine.h"
    1.14 +#include "MPAPI.h"
    1.15 +#include "mozilla/dom/TimeRanges.h"
    1.16 +#include "mozilla/Mutex.h"
    1.17 +#include "mozilla/TimeStamp.h"
    1.18 +#include "OmxDecoder.h"
    1.19 +#include "RtspMediaResource.h"
    1.20 +#include "RtspOmxDecoder.h"
    1.21 +#include "VideoUtils.h"
    1.22 +
    1.23 +#include <stagefright/MediaExtractor.h>
    1.24 +#include <stagefright/MediaBufferGroup.h>
    1.25 +#include <stagefright/MetaData.h>
    1.26 +
    1.27 +#define FRAME_DEFAULT_SIZE 1024
    1.28 +
    1.29 +using namespace android;
    1.30 +
    1.31 +namespace mozilla {
    1.32 +
    1.33 +/* class RtspMediaSource : implements MediaSource for OMX.
    1.34 + * The decoder thread will trigger the MediaDecodeStateMachine to read a/v frame.
    1.35 + * Then RtspOmxReader calls OMX decoder to decode a/v frame. Finally the code
    1.36 + * path run into the read() here, it reads un-decoded frame data from mResource
    1.37 + * and construct a MediaBuffer for output to OMX decoder.
    1.38 + * */
    1.39 +class RtspMediaSource : public android::MediaSource {
    1.40 +public:
    1.41 +  RtspMediaSource(RtspMediaResource *aRtspMediaResource,
    1.42 +                  ssize_t aTrackIdx,
    1.43 +                  uint32_t aFrameMaxSize,
    1.44 +                  const sp<MetaData>& aMeta)
    1.45 +  : mRtspResource(aRtspMediaResource)
    1.46 +  , mFormat(aMeta)
    1.47 +  , mTrackIdx(aTrackIdx)
    1.48 +  , mMonitor("RtspMediaSource.mMonitor")
    1.49 +  , mIsStarted(false)
    1.50 +  , mGroup(nullptr)
    1.51 +  , mBuffer(nullptr)
    1.52 +  , mFrameMaxSize(aFrameMaxSize) {
    1.53 +    MOZ_COUNT_CTOR(RtspMediaSource);
    1.54 +  };
    1.55 +  virtual ~RtspMediaSource() {
    1.56 +    MOZ_COUNT_DTOR(RtspMediaSource);
    1.57 +  }
    1.58 +  virtual status_t start(MetaData *params = nullptr) MOZ_FINAL MOZ_OVERRIDE;
    1.59 +  virtual status_t stop() MOZ_FINAL MOZ_OVERRIDE;
    1.60 +  virtual sp<MetaData> getFormat() MOZ_FINAL MOZ_OVERRIDE {
    1.61 +    ReentrantMonitorAutoEnter mon(mMonitor);
    1.62 +    return mFormat;
    1.63 +  };
    1.64 +  virtual status_t read(MediaBuffer **buffer,
    1.65 +                        const ReadOptions *options = nullptr) MOZ_FINAL MOZ_OVERRIDE ;
    1.66 +private:
    1.67 +  nsRefPtr<RtspMediaResource> mRtspResource;
    1.68 +  sp<MetaData> mFormat;
    1.69 +  uint32_t mTrackIdx;
    1.70 +  ReentrantMonitor mMonitor;
    1.71 +  bool mIsStarted;
    1.72 +
    1.73 +  // mGroup owns the mBuffer. mFrameMaxSize is the mBuffer size.
    1.74 +  // mBuffer is the input buffer for omx decoder.
    1.75 +  nsAutoPtr<MediaBufferGroup> mGroup;
    1.76 +  MediaBuffer* mBuffer;
    1.77 +  uint32_t mFrameMaxSize;
    1.78 +};
    1.79 +
    1.80 +status_t RtspMediaSource::start(MetaData *params)
    1.81 +{
    1.82 +  ReentrantMonitorAutoEnter mon(mMonitor);
    1.83 +  if (!mIsStarted) {
    1.84 +    // RtspMediaSource relinquish the ownership of MediaBuffer |buf| to mGroup.
    1.85 +    mGroup = new MediaBufferGroup();
    1.86 +    MediaBuffer* buf = new MediaBuffer(mFrameMaxSize);
    1.87 +    mGroup->add_buffer(buf);
    1.88 +    mIsStarted = true;
    1.89 +  }
    1.90 +  return OK;
    1.91 +}
    1.92 +
    1.93 +status_t RtspMediaSource::stop()
    1.94 +{
    1.95 +  ReentrantMonitorAutoEnter mon(mMonitor);
    1.96 +  if (mIsStarted) {
    1.97 +    if (mBuffer) {
    1.98 +      mBuffer->release();
    1.99 +      mBuffer = nullptr;
   1.100 +    }
   1.101 +    mGroup = nullptr;
   1.102 +    mIsStarted = false;
   1.103 +  }
   1.104 +  return OK;
   1.105 +}
   1.106 +
   1.107 +status_t RtspMediaSource::read(MediaBuffer **out, const ReadOptions *options)
   1.108 +{
   1.109 +  ReentrantMonitorAutoEnter mon(mMonitor);
   1.110 +  NS_ENSURE_TRUE(mIsStarted, MEDIA_ERROR_BASE);
   1.111 +  NS_ENSURE_TRUE(out, MEDIA_ERROR_BASE);
   1.112 +  *out = nullptr;
   1.113 +
   1.114 +  // Video/audio track's initial frame size is FRAME_DEFAULT_SIZE.
   1.115 +  // We need to realloc the mBuffer if the mBuffer doesn't have enough space
   1.116 +  // for next ReadFrameFromTrack function. (actualFrameSize > mFrameMaxSize)
   1.117 +  status_t err;
   1.118 +  uint32_t readCount;
   1.119 +  uint32_t actualFrameSize;
   1.120 +  uint64_t time;
   1.121 +  nsresult rv;
   1.122 +
   1.123 +  while (1) {
   1.124 +    err = mGroup->acquire_buffer(&mBuffer);
   1.125 +    NS_ENSURE_TRUE(err == OK, err);
   1.126 +
   1.127 +    rv = mRtspResource->ReadFrameFromTrack((uint8_t *)mBuffer->data(),
   1.128 +                                           mFrameMaxSize, mTrackIdx, readCount,
   1.129 +                                           time, actualFrameSize);
   1.130 +    if (NS_FAILED(rv)) {
   1.131 +      // Release mGroup and mBuffer.
   1.132 +      stop();
   1.133 +      // Since RtspMediaSource is an implementation of Android media source,
   1.134 +      // it's held by OMXCodec and isn't released yet. So we have to re-construct
   1.135 +      // mGroup and mBuffer.
   1.136 +      start();
   1.137 +      NS_WARNING("ReadFrameFromTrack failed; releasing buffers and returning.");
   1.138 +      return ERROR_CONNECTION_LOST;
   1.139 +    }
   1.140 +    if (actualFrameSize > mFrameMaxSize) {
   1.141 +      // release mGroup and mBuffer
   1.142 +      stop();
   1.143 +      // re-construct mGroup and mBuffer
   1.144 +      mFrameMaxSize = actualFrameSize;
   1.145 +      err = start();
   1.146 +      NS_ENSURE_TRUE(err == OK, err);
   1.147 +    } else {
   1.148 +      // ReadFrameFromTrack success, break the while loop.
   1.149 +      break;
   1.150 +    }
   1.151 +  }
   1.152 +  mBuffer->set_range(0, readCount);
   1.153 +  if (NS_SUCCEEDED(rv)) {
   1.154 +    mBuffer->meta_data()->clear();
   1.155 +    // fill the meta data
   1.156 +    mBuffer->meta_data()->setInt64(kKeyTime, time);
   1.157 +    *out = mBuffer;
   1.158 +    mBuffer = nullptr;
   1.159 +    return OK;
   1.160 +  }
   1.161 +
   1.162 +  return ERROR_END_OF_STREAM;
   1.163 +}
   1.164 +
   1.165 +
   1.166 +// RtspExtractor is a custom extractor for Rtsp stream, whereas the other
   1.167 +// XXXExtractors are made for container media content.
   1.168 +// The extractor is used for |OmxDecoder::Init|, it provides the essential
   1.169 +// information for creating OMXCodec instance.
   1.170 +// For example, the |getTrackMetaData| returns metadata that includes the
   1.171 +// codec type.
   1.172 +class RtspExtractor: public MediaExtractor
   1.173 +{
   1.174 +public:
   1.175 +  virtual size_t countTracks() MOZ_FINAL MOZ_OVERRIDE;
   1.176 +  virtual sp<android::MediaSource> getTrack(size_t index)
   1.177 +    MOZ_FINAL MOZ_OVERRIDE;
   1.178 +  virtual sp<MetaData> getTrackMetaData(
   1.179 +    size_t index, uint32_t flag = 0) MOZ_FINAL MOZ_OVERRIDE;
   1.180 +  virtual uint32_t flags() const MOZ_FINAL MOZ_OVERRIDE;
   1.181 +
   1.182 +  RtspExtractor(RtspMediaResource *aResource)
   1.183 +    : mRtspResource(aResource) {
   1.184 +    MOZ_COUNT_CTOR(RtspExtractor);
   1.185 +    MOZ_ASSERT(aResource);
   1.186 +    mController = mRtspResource->GetMediaStreamController();
   1.187 +    MOZ_ASSERT(mController);
   1.188 +  }
   1.189 +  virtual ~RtspExtractor() MOZ_OVERRIDE {
   1.190 +    MOZ_COUNT_DTOR(RtspExtractor);
   1.191 +  }
   1.192 +private:
   1.193 +  // mRtspResource is a pointer to RtspMediaResource. When |getTrack| is called
   1.194 +  // we use mRtspResource to construct a RtspMediaSource.
   1.195 +  RtspMediaResource* mRtspResource;
   1.196 +  // Through the mController in mRtspResource, we can get the essential
   1.197 +  // information for the extractor.
   1.198 +  nsRefPtr<nsIStreamingProtocolController> mController;
   1.199 +};
   1.200 +
   1.201 +size_t RtspExtractor::countTracks()
   1.202 +{
   1.203 +  uint8_t tracks = 0;
   1.204 +  if (mController) {
   1.205 +    mController->GetTotalTracks(&tracks);
   1.206 +  }
   1.207 +  return size_t(tracks);
   1.208 +}
   1.209 +
   1.210 +sp<android::MediaSource> RtspExtractor::getTrack(size_t index)
   1.211 +{
   1.212 +  NS_ENSURE_TRUE(index < countTracks(), nullptr);
   1.213 +
   1.214 +  sp<MetaData> meta = getTrackMetaData(index);
   1.215 +  sp<android::MediaSource> source = new RtspMediaSource(mRtspResource,
   1.216 +                                                        index,
   1.217 +                                                        FRAME_DEFAULT_SIZE,
   1.218 +                                                        meta);
   1.219 +  return source;
   1.220 +}
   1.221 +
   1.222 +sp<MetaData> RtspExtractor::getTrackMetaData(size_t index, uint32_t flag)
   1.223 +{
   1.224 +  NS_ENSURE_TRUE(index < countTracks(), nullptr);;
   1.225 +
   1.226 +  sp<MetaData> meta = new MetaData();
   1.227 +  nsCOMPtr<nsIStreamingProtocolMetaData> rtspMetadata;
   1.228 +  mController->GetTrackMetaData(index, getter_AddRefs(rtspMetadata));
   1.229 +
   1.230 +  if (rtspMetadata) {
   1.231 +    // Convert msMeta into meta.
   1.232 +    // The getter function of nsIStreamingProtocolMetaData will initialize the
   1.233 +    // metadata values to 0 before setting them.
   1.234 +    nsCString mime;
   1.235 +    rtspMetadata->GetMimeType(mime);
   1.236 +    meta->setCString(kKeyMIMEType, mime.get());
   1.237 +    uint32_t temp32;
   1.238 +    rtspMetadata->GetWidth(&temp32);
   1.239 +    meta->setInt32(kKeyWidth, temp32);
   1.240 +    rtspMetadata->GetHeight(&temp32);
   1.241 +    meta->setInt32(kKeyHeight, temp32);
   1.242 +    rtspMetadata->GetSampleRate(&temp32);
   1.243 +    meta->setInt32(kKeySampleRate, temp32);
   1.244 +    rtspMetadata->GetChannelCount(&temp32);
   1.245 +    meta->setInt32(kKeyChannelCount, temp32);
   1.246 +    uint64_t temp64;
   1.247 +    rtspMetadata->GetDuration(&temp64);
   1.248 +    meta->setInt64(kKeyDuration, temp64);
   1.249 +
   1.250 +    nsCString tempCString;
   1.251 +    rtspMetadata->GetEsdsData(tempCString);
   1.252 +    if (tempCString.Length()) {
   1.253 +      meta->setData(kKeyESDS, 0, tempCString.get(), tempCString.Length());
   1.254 +    }
   1.255 +    rtspMetadata->GetAvccData(tempCString);
   1.256 +    if (tempCString.Length()) {
   1.257 +      meta->setData(kKeyAVCC, 0, tempCString.get(), tempCString.Length());
   1.258 +    }
   1.259 +  }
   1.260 +  return meta;
   1.261 +}
   1.262 +
   1.263 +uint32_t RtspExtractor::flags() const
   1.264 +{
   1.265 +  if (mRtspResource->IsRealTime()) {
   1.266 +    return 0;
   1.267 +  } else {
   1.268 +    return MediaExtractor::CAN_SEEK;
   1.269 +  }
   1.270 +}
   1.271 +
   1.272 +nsresult RtspOmxReader::InitOmxDecoder()
   1.273 +{
   1.274 +  if (!mOmxDecoder.get()) {
   1.275 +    NS_ASSERTION(mDecoder, "RtspOmxReader mDecoder is null.");
   1.276 +    NS_ASSERTION(mDecoder->GetResource(),
   1.277 +                 "RtspOmxReader mDecoder->GetResource() is null.");
   1.278 +    mExtractor = new RtspExtractor(mRtspResource);
   1.279 +    mOmxDecoder = new OmxDecoder(mDecoder->GetResource(), mDecoder);
   1.280 +    if (!mOmxDecoder->Init(mExtractor)) {
   1.281 +      return NS_ERROR_FAILURE;
   1.282 +    }
   1.283 +  }
   1.284 +  return NS_OK;
   1.285 +}
   1.286 +
   1.287 +nsresult RtspOmxReader::Seek(int64_t aTime, int64_t aStartTime,
   1.288 +                             int64_t aEndTime, int64_t aCurrentTime)
   1.289 +{
   1.290 +  // The seek function of Rtsp is time-based, we call the SeekTime function in
   1.291 +  // RtspMediaResource. The SeekTime function finally send a seek command to
   1.292 +  // Rtsp stream server through network and also clear the buffer data in
   1.293 +  // RtspMediaResource.
   1.294 +  if (mRtspResource) {
   1.295 +    mRtspResource->SeekTime(aTime);
   1.296 +  }
   1.297 +
   1.298 +  // Call |MediaOmxReader::Seek| to notify the OMX decoder we are performing a
   1.299 +  // seek operation. The function will clear the |mVideoQueue| and |mAudioQueue|
   1.300 +  // that store the decoded data and also call the |DecodeToTarget| to pass
   1.301 +  // the seek time to OMX a/v decoders.
   1.302 +  return MediaOmxReader::Seek(aTime, aStartTime, aEndTime, aCurrentTime);
   1.303 +}
   1.304 +
   1.305 +nsresult
   1.306 +RtspOmxReader::ReadMetadata(MediaInfo* aInfo,
   1.307 +                            MetadataTags** aTags)
   1.308 +{
   1.309 +  SetActive();
   1.310 +
   1.311 +  nsresult rv = MediaOmxReader::ReadMetadata(aInfo, aTags);
   1.312 +  NS_ENSURE_SUCCESS(rv, rv);
   1.313 +
   1.314 +  return NS_OK;
   1.315 +}
   1.316 +
   1.317 +void RtspOmxReader::SetIdle() {
   1.318 +  // Call parent class to set OMXCodec idle.
   1.319 +  MediaOmxReader::SetIdle();
   1.320 +
   1.321 +  // Need to pause RTSP streaming OMXCodec decoding.
   1.322 +  if (mRtspResource) {
   1.323 +    nsIStreamingProtocolController* controller =
   1.324 +        mRtspResource->GetMediaStreamController();
   1.325 +    if (controller) {
   1.326 +      controller->Pause();
   1.327 +    }
   1.328 +  }
   1.329 +}
   1.330 +
   1.331 +void RtspOmxReader::SetActive() {
   1.332 +  // Need to start RTSP streaming OMXCodec decoding.
   1.333 +  if (mRtspResource) {
   1.334 +    nsIStreamingProtocolController* controller =
   1.335 +        mRtspResource->GetMediaStreamController();
   1.336 +    if (controller) {
   1.337 +      controller->Play();
   1.338 +    }
   1.339 +  }
   1.340 +
   1.341 +  // Call parent class to set OMXCodec active.
   1.342 +  MediaOmxReader::SetActive();
   1.343 +}
   1.344 +
   1.345 +} // namespace mozilla

mercurial