/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#if !defined(HLSDemuxer_h_)
#  define HLSDemuxer_h_

#  include "MediaCodec.h"
#  include "MediaDataDemuxer.h"
#  include "MediaDecoder.h"
#  include "mozilla/Atomics.h"
#  include "mozilla/java/GeckoHLSDemuxerWrapperWrappers.h"
#  include "mozilla/java/GeckoHLSSampleWrappers.h"
#  include "mozilla/Maybe.h"
#  include "mozilla/Mutex.h"
#  include "mozilla/TaskQueue.h"

#  include "VideoUtils.h"

namespace mozilla {

class AbstractThread;
class MediaResult;
class HLSTrackDemuxer;

DDLoggedTypeDeclNameAndBase(HLSDemuxer, MediaDataDemuxer);
DDLoggedTypeNameAndBase(HLSTrackDemuxer, MediaTrackDemuxer);

class HLSDemuxer final : public MediaDataDemuxer,
                         public DecoderDoctorLifeLogger<HLSDemuxer> {
  class HLSDemuxerCallbacksSupport;

 public:
  explicit HLSDemuxer(int aPlayerId);

  RefPtr<InitPromise> Init() override;

  uint32_t GetNumberTracks(TrackInfo::TrackType aType) const override;

  already_AddRefed<MediaTrackDemuxer> GetTrackDemuxer(
      TrackInfo::TrackType aType, uint32_t aTrackNumber) override;

  bool IsSeekable() const override;

  UniquePtr<EncryptionInfo> GetCrypto() override;

  bool ShouldComputeStartTime() const override { return true; }

  void NotifyDataArrived() override;

  TaskQueue* GetTaskQueue() const { return mTaskQueue; }
  void OnInitialized(bool aHasAudio, bool aHasVideo);
  void OnError(int aErrorCode);

 private:
  media::TimeUnit GetNextKeyFrameTime();

  bool OnTaskQueue() const;
  ~HLSDemuxer();
  friend class HLSTrackDemuxer;

  const RefPtr<TaskQueue> mTaskQueue;
  RefPtr<HLSTrackDemuxer> mAudioDemuxer;
  RefPtr<HLSTrackDemuxer> mVideoDemuxer;

  MozPromiseHolder<InitPromise> mInitPromise;
  RefPtr<HLSDemuxerCallbacksSupport> mCallbackSupport;

  java::GeckoHLSDemuxerWrapper::Callbacks::GlobalRef mJavaCallbacks;
  java::GeckoHLSDemuxerWrapper::GlobalRef mHLSDemuxerWrapper;
};

class HLSTrackDemuxer : public MediaTrackDemuxer,
                        public DecoderDoctorLifeLogger<HLSTrackDemuxer> {
 public:
  HLSTrackDemuxer(HLSDemuxer* aParent, TrackInfo::TrackType aType,
                  UniquePtr<TrackInfo> aTrackInfo);
  ~HLSTrackDemuxer();
  UniquePtr<TrackInfo> GetInfo() const override;

  RefPtr<SeekPromise> Seek(const media::TimeUnit& aTime) override;

  RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples = 1) override;

  void UpdateMediaInfo(int index);

  void Reset() override;

  nsresult GetNextRandomAccessPoint(media::TimeUnit* aTime) override;

  RefPtr<SkipAccessPointPromise> SkipToNextRandomAccessPoint(
      const media::TimeUnit& aTimeThreshold) override;

  media::TimeIntervals GetBuffered() override;

  void BreakCycles() override;

  bool GetSamplesMayBlock() const override { return false; }

  bool IsTrackValid() const {
    MutexAutoLock lock(mMutex);
    return mTrackInfo->IsValid();
  }

 private:
  // Update the timestamp of the next keyframe if there's one.
  void UpdateNextKeyFrameTime();

  // Runs on HLSDemuxer's task queue.
  RefPtr<SeekPromise> DoSeek(const media::TimeUnit& aTime);
  RefPtr<SamplesPromise> DoGetSamples(int32_t aNumSamples);
  RefPtr<SkipAccessPointPromise> DoSkipToNextRandomAccessPoint(
      const media::TimeUnit& aTimeThreshold);

  CryptoSample ExtractCryptoSample(
      size_t aSampleSize,
      java::sdk::MediaCodec::CryptoInfo::LocalRef aCryptoInfo);
  RefPtr<MediaRawData> ConvertToMediaRawData(
      java::GeckoHLSSample::LocalRef aSample);

  RefPtr<HLSDemuxer> mParent;
  TrackInfo::TrackType mType;
  Maybe<media::TimeUnit> mNextKeyframeTime;
  int32_t mLastFormatIndex = -1;
  // Queued samples extracted by the demuxer, but not yet returned.
  RefPtr<MediaRawData> mQueuedSample;

  // Mutex to protect members below across multiple threads.
  mutable Mutex mMutex MOZ_UNANNOTATED;
  UniquePtr<TrackInfo> mTrackInfo;
};

}  // namespace mozilla

#endif
