content/media/omx/RtspOmxReader.cpp

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "RtspOmxReader.h"
michael@0 8
michael@0 9 #include "AbstractMediaDecoder.h"
michael@0 10 #include "MediaDecoderStateMachine.h"
michael@0 11 #include "MPAPI.h"
michael@0 12 #include "mozilla/dom/TimeRanges.h"
michael@0 13 #include "mozilla/Mutex.h"
michael@0 14 #include "mozilla/TimeStamp.h"
michael@0 15 #include "OmxDecoder.h"
michael@0 16 #include "RtspMediaResource.h"
michael@0 17 #include "RtspOmxDecoder.h"
michael@0 18 #include "VideoUtils.h"
michael@0 19
michael@0 20 #include <stagefright/MediaExtractor.h>
michael@0 21 #include <stagefright/MediaBufferGroup.h>
michael@0 22 #include <stagefright/MetaData.h>
michael@0 23
michael@0 24 #define FRAME_DEFAULT_SIZE 1024
michael@0 25
michael@0 26 using namespace android;
michael@0 27
michael@0 28 namespace mozilla {
michael@0 29
michael@0 30 /* class RtspMediaSource : implements MediaSource for OMX.
michael@0 31 * The decoder thread will trigger the MediaDecodeStateMachine to read a/v frame.
michael@0 32 * Then RtspOmxReader calls OMX decoder to decode a/v frame. Finally the code
michael@0 33 * path run into the read() here, it reads un-decoded frame data from mResource
michael@0 34 * and construct a MediaBuffer for output to OMX decoder.
michael@0 35 * */
michael@0 36 class RtspMediaSource : public android::MediaSource {
michael@0 37 public:
michael@0 38 RtspMediaSource(RtspMediaResource *aRtspMediaResource,
michael@0 39 ssize_t aTrackIdx,
michael@0 40 uint32_t aFrameMaxSize,
michael@0 41 const sp<MetaData>& aMeta)
michael@0 42 : mRtspResource(aRtspMediaResource)
michael@0 43 , mFormat(aMeta)
michael@0 44 , mTrackIdx(aTrackIdx)
michael@0 45 , mMonitor("RtspMediaSource.mMonitor")
michael@0 46 , mIsStarted(false)
michael@0 47 , mGroup(nullptr)
michael@0 48 , mBuffer(nullptr)
michael@0 49 , mFrameMaxSize(aFrameMaxSize) {
michael@0 50 MOZ_COUNT_CTOR(RtspMediaSource);
michael@0 51 };
michael@0 52 virtual ~RtspMediaSource() {
michael@0 53 MOZ_COUNT_DTOR(RtspMediaSource);
michael@0 54 }
michael@0 55 virtual status_t start(MetaData *params = nullptr) MOZ_FINAL MOZ_OVERRIDE;
michael@0 56 virtual status_t stop() MOZ_FINAL MOZ_OVERRIDE;
michael@0 57 virtual sp<MetaData> getFormat() MOZ_FINAL MOZ_OVERRIDE {
michael@0 58 ReentrantMonitorAutoEnter mon(mMonitor);
michael@0 59 return mFormat;
michael@0 60 };
michael@0 61 virtual status_t read(MediaBuffer **buffer,
michael@0 62 const ReadOptions *options = nullptr) MOZ_FINAL MOZ_OVERRIDE ;
michael@0 63 private:
michael@0 64 nsRefPtr<RtspMediaResource> mRtspResource;
michael@0 65 sp<MetaData> mFormat;
michael@0 66 uint32_t mTrackIdx;
michael@0 67 ReentrantMonitor mMonitor;
michael@0 68 bool mIsStarted;
michael@0 69
michael@0 70 // mGroup owns the mBuffer. mFrameMaxSize is the mBuffer size.
michael@0 71 // mBuffer is the input buffer for omx decoder.
michael@0 72 nsAutoPtr<MediaBufferGroup> mGroup;
michael@0 73 MediaBuffer* mBuffer;
michael@0 74 uint32_t mFrameMaxSize;
michael@0 75 };
michael@0 76
michael@0 77 status_t RtspMediaSource::start(MetaData *params)
michael@0 78 {
michael@0 79 ReentrantMonitorAutoEnter mon(mMonitor);
michael@0 80 if (!mIsStarted) {
michael@0 81 // RtspMediaSource relinquish the ownership of MediaBuffer |buf| to mGroup.
michael@0 82 mGroup = new MediaBufferGroup();
michael@0 83 MediaBuffer* buf = new MediaBuffer(mFrameMaxSize);
michael@0 84 mGroup->add_buffer(buf);
michael@0 85 mIsStarted = true;
michael@0 86 }
michael@0 87 return OK;
michael@0 88 }
michael@0 89
michael@0 90 status_t RtspMediaSource::stop()
michael@0 91 {
michael@0 92 ReentrantMonitorAutoEnter mon(mMonitor);
michael@0 93 if (mIsStarted) {
michael@0 94 if (mBuffer) {
michael@0 95 mBuffer->release();
michael@0 96 mBuffer = nullptr;
michael@0 97 }
michael@0 98 mGroup = nullptr;
michael@0 99 mIsStarted = false;
michael@0 100 }
michael@0 101 return OK;
michael@0 102 }
michael@0 103
michael@0 104 status_t RtspMediaSource::read(MediaBuffer **out, const ReadOptions *options)
michael@0 105 {
michael@0 106 ReentrantMonitorAutoEnter mon(mMonitor);
michael@0 107 NS_ENSURE_TRUE(mIsStarted, MEDIA_ERROR_BASE);
michael@0 108 NS_ENSURE_TRUE(out, MEDIA_ERROR_BASE);
michael@0 109 *out = nullptr;
michael@0 110
michael@0 111 // Video/audio track's initial frame size is FRAME_DEFAULT_SIZE.
michael@0 112 // We need to realloc the mBuffer if the mBuffer doesn't have enough space
michael@0 113 // for next ReadFrameFromTrack function. (actualFrameSize > mFrameMaxSize)
michael@0 114 status_t err;
michael@0 115 uint32_t readCount;
michael@0 116 uint32_t actualFrameSize;
michael@0 117 uint64_t time;
michael@0 118 nsresult rv;
michael@0 119
michael@0 120 while (1) {
michael@0 121 err = mGroup->acquire_buffer(&mBuffer);
michael@0 122 NS_ENSURE_TRUE(err == OK, err);
michael@0 123
michael@0 124 rv = mRtspResource->ReadFrameFromTrack((uint8_t *)mBuffer->data(),
michael@0 125 mFrameMaxSize, mTrackIdx, readCount,
michael@0 126 time, actualFrameSize);
michael@0 127 if (NS_FAILED(rv)) {
michael@0 128 // Release mGroup and mBuffer.
michael@0 129 stop();
michael@0 130 // Since RtspMediaSource is an implementation of Android media source,
michael@0 131 // it's held by OMXCodec and isn't released yet. So we have to re-construct
michael@0 132 // mGroup and mBuffer.
michael@0 133 start();
michael@0 134 NS_WARNING("ReadFrameFromTrack failed; releasing buffers and returning.");
michael@0 135 return ERROR_CONNECTION_LOST;
michael@0 136 }
michael@0 137 if (actualFrameSize > mFrameMaxSize) {
michael@0 138 // release mGroup and mBuffer
michael@0 139 stop();
michael@0 140 // re-construct mGroup and mBuffer
michael@0 141 mFrameMaxSize = actualFrameSize;
michael@0 142 err = start();
michael@0 143 NS_ENSURE_TRUE(err == OK, err);
michael@0 144 } else {
michael@0 145 // ReadFrameFromTrack success, break the while loop.
michael@0 146 break;
michael@0 147 }
michael@0 148 }
michael@0 149 mBuffer->set_range(0, readCount);
michael@0 150 if (NS_SUCCEEDED(rv)) {
michael@0 151 mBuffer->meta_data()->clear();
michael@0 152 // fill the meta data
michael@0 153 mBuffer->meta_data()->setInt64(kKeyTime, time);
michael@0 154 *out = mBuffer;
michael@0 155 mBuffer = nullptr;
michael@0 156 return OK;
michael@0 157 }
michael@0 158
michael@0 159 return ERROR_END_OF_STREAM;
michael@0 160 }
michael@0 161
michael@0 162
michael@0 163 // RtspExtractor is a custom extractor for Rtsp stream, whereas the other
michael@0 164 // XXXExtractors are made for container media content.
michael@0 165 // The extractor is used for |OmxDecoder::Init|, it provides the essential
michael@0 166 // information for creating OMXCodec instance.
michael@0 167 // For example, the |getTrackMetaData| returns metadata that includes the
michael@0 168 // codec type.
michael@0 169 class RtspExtractor: public MediaExtractor
michael@0 170 {
michael@0 171 public:
michael@0 172 virtual size_t countTracks() MOZ_FINAL MOZ_OVERRIDE;
michael@0 173 virtual sp<android::MediaSource> getTrack(size_t index)
michael@0 174 MOZ_FINAL MOZ_OVERRIDE;
michael@0 175 virtual sp<MetaData> getTrackMetaData(
michael@0 176 size_t index, uint32_t flag = 0) MOZ_FINAL MOZ_OVERRIDE;
michael@0 177 virtual uint32_t flags() const MOZ_FINAL MOZ_OVERRIDE;
michael@0 178
michael@0 179 RtspExtractor(RtspMediaResource *aResource)
michael@0 180 : mRtspResource(aResource) {
michael@0 181 MOZ_COUNT_CTOR(RtspExtractor);
michael@0 182 MOZ_ASSERT(aResource);
michael@0 183 mController = mRtspResource->GetMediaStreamController();
michael@0 184 MOZ_ASSERT(mController);
michael@0 185 }
michael@0 186 virtual ~RtspExtractor() MOZ_OVERRIDE {
michael@0 187 MOZ_COUNT_DTOR(RtspExtractor);
michael@0 188 }
michael@0 189 private:
michael@0 190 // mRtspResource is a pointer to RtspMediaResource. When |getTrack| is called
michael@0 191 // we use mRtspResource to construct a RtspMediaSource.
michael@0 192 RtspMediaResource* mRtspResource;
michael@0 193 // Through the mController in mRtspResource, we can get the essential
michael@0 194 // information for the extractor.
michael@0 195 nsRefPtr<nsIStreamingProtocolController> mController;
michael@0 196 };
michael@0 197
michael@0 198 size_t RtspExtractor::countTracks()
michael@0 199 {
michael@0 200 uint8_t tracks = 0;
michael@0 201 if (mController) {
michael@0 202 mController->GetTotalTracks(&tracks);
michael@0 203 }
michael@0 204 return size_t(tracks);
michael@0 205 }
michael@0 206
michael@0 207 sp<android::MediaSource> RtspExtractor::getTrack(size_t index)
michael@0 208 {
michael@0 209 NS_ENSURE_TRUE(index < countTracks(), nullptr);
michael@0 210
michael@0 211 sp<MetaData> meta = getTrackMetaData(index);
michael@0 212 sp<android::MediaSource> source = new RtspMediaSource(mRtspResource,
michael@0 213 index,
michael@0 214 FRAME_DEFAULT_SIZE,
michael@0 215 meta);
michael@0 216 return source;
michael@0 217 }
michael@0 218
michael@0 219 sp<MetaData> RtspExtractor::getTrackMetaData(size_t index, uint32_t flag)
michael@0 220 {
michael@0 221 NS_ENSURE_TRUE(index < countTracks(), nullptr);;
michael@0 222
michael@0 223 sp<MetaData> meta = new MetaData();
michael@0 224 nsCOMPtr<nsIStreamingProtocolMetaData> rtspMetadata;
michael@0 225 mController->GetTrackMetaData(index, getter_AddRefs(rtspMetadata));
michael@0 226
michael@0 227 if (rtspMetadata) {
michael@0 228 // Convert msMeta into meta.
michael@0 229 // The getter function of nsIStreamingProtocolMetaData will initialize the
michael@0 230 // metadata values to 0 before setting them.
michael@0 231 nsCString mime;
michael@0 232 rtspMetadata->GetMimeType(mime);
michael@0 233 meta->setCString(kKeyMIMEType, mime.get());
michael@0 234 uint32_t temp32;
michael@0 235 rtspMetadata->GetWidth(&temp32);
michael@0 236 meta->setInt32(kKeyWidth, temp32);
michael@0 237 rtspMetadata->GetHeight(&temp32);
michael@0 238 meta->setInt32(kKeyHeight, temp32);
michael@0 239 rtspMetadata->GetSampleRate(&temp32);
michael@0 240 meta->setInt32(kKeySampleRate, temp32);
michael@0 241 rtspMetadata->GetChannelCount(&temp32);
michael@0 242 meta->setInt32(kKeyChannelCount, temp32);
michael@0 243 uint64_t temp64;
michael@0 244 rtspMetadata->GetDuration(&temp64);
michael@0 245 meta->setInt64(kKeyDuration, temp64);
michael@0 246
michael@0 247 nsCString tempCString;
michael@0 248 rtspMetadata->GetEsdsData(tempCString);
michael@0 249 if (tempCString.Length()) {
michael@0 250 meta->setData(kKeyESDS, 0, tempCString.get(), tempCString.Length());
michael@0 251 }
michael@0 252 rtspMetadata->GetAvccData(tempCString);
michael@0 253 if (tempCString.Length()) {
michael@0 254 meta->setData(kKeyAVCC, 0, tempCString.get(), tempCString.Length());
michael@0 255 }
michael@0 256 }
michael@0 257 return meta;
michael@0 258 }
michael@0 259
michael@0 260 uint32_t RtspExtractor::flags() const
michael@0 261 {
michael@0 262 if (mRtspResource->IsRealTime()) {
michael@0 263 return 0;
michael@0 264 } else {
michael@0 265 return MediaExtractor::CAN_SEEK;
michael@0 266 }
michael@0 267 }
michael@0 268
michael@0 269 nsresult RtspOmxReader::InitOmxDecoder()
michael@0 270 {
michael@0 271 if (!mOmxDecoder.get()) {
michael@0 272 NS_ASSERTION(mDecoder, "RtspOmxReader mDecoder is null.");
michael@0 273 NS_ASSERTION(mDecoder->GetResource(),
michael@0 274 "RtspOmxReader mDecoder->GetResource() is null.");
michael@0 275 mExtractor = new RtspExtractor(mRtspResource);
michael@0 276 mOmxDecoder = new OmxDecoder(mDecoder->GetResource(), mDecoder);
michael@0 277 if (!mOmxDecoder->Init(mExtractor)) {
michael@0 278 return NS_ERROR_FAILURE;
michael@0 279 }
michael@0 280 }
michael@0 281 return NS_OK;
michael@0 282 }
michael@0 283
michael@0 284 nsresult RtspOmxReader::Seek(int64_t aTime, int64_t aStartTime,
michael@0 285 int64_t aEndTime, int64_t aCurrentTime)
michael@0 286 {
michael@0 287 // The seek function of Rtsp is time-based, we call the SeekTime function in
michael@0 288 // RtspMediaResource. The SeekTime function finally send a seek command to
michael@0 289 // Rtsp stream server through network and also clear the buffer data in
michael@0 290 // RtspMediaResource.
michael@0 291 if (mRtspResource) {
michael@0 292 mRtspResource->SeekTime(aTime);
michael@0 293 }
michael@0 294
michael@0 295 // Call |MediaOmxReader::Seek| to notify the OMX decoder we are performing a
michael@0 296 // seek operation. The function will clear the |mVideoQueue| and |mAudioQueue|
michael@0 297 // that store the decoded data and also call the |DecodeToTarget| to pass
michael@0 298 // the seek time to OMX a/v decoders.
michael@0 299 return MediaOmxReader::Seek(aTime, aStartTime, aEndTime, aCurrentTime);
michael@0 300 }
michael@0 301
michael@0 302 nsresult
michael@0 303 RtspOmxReader::ReadMetadata(MediaInfo* aInfo,
michael@0 304 MetadataTags** aTags)
michael@0 305 {
michael@0 306 SetActive();
michael@0 307
michael@0 308 nsresult rv = MediaOmxReader::ReadMetadata(aInfo, aTags);
michael@0 309 NS_ENSURE_SUCCESS(rv, rv);
michael@0 310
michael@0 311 return NS_OK;
michael@0 312 }
michael@0 313
michael@0 314 void RtspOmxReader::SetIdle() {
michael@0 315 // Call parent class to set OMXCodec idle.
michael@0 316 MediaOmxReader::SetIdle();
michael@0 317
michael@0 318 // Need to pause RTSP streaming OMXCodec decoding.
michael@0 319 if (mRtspResource) {
michael@0 320 nsIStreamingProtocolController* controller =
michael@0 321 mRtspResource->GetMediaStreamController();
michael@0 322 if (controller) {
michael@0 323 controller->Pause();
michael@0 324 }
michael@0 325 }
michael@0 326 }
michael@0 327
michael@0 328 void RtspOmxReader::SetActive() {
michael@0 329 // Need to start RTSP streaming OMXCodec decoding.
michael@0 330 if (mRtspResource) {
michael@0 331 nsIStreamingProtocolController* controller =
michael@0 332 mRtspResource->GetMediaStreamController();
michael@0 333 if (controller) {
michael@0 334 controller->Play();
michael@0 335 }
michael@0 336 }
michael@0 337
michael@0 338 // Call parent class to set OMXCodec active.
michael@0 339 MediaOmxReader::SetActive();
michael@0 340 }
michael@0 341
michael@0 342 } // namespace mozilla

mercurial