/*
 * Copyright (c) 2023-2025 Huawei Device Co., Ltd.
 * 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.
 */

#ifndef AVCODEC_DEMUXER_PLUGIN_H
#define AVCODEC_DEMUXER_PLUGIN_H

#include <memory>
#include <vector>
#include <functional>
#include "meta/meta.h"
#include "plugin/plugin_base.h"
#include "plugin/plugin_caps.h"
#include "plugin/plugin_definition.h"
#include "plugin/plugin_info.h"
#include "common/media_core.h"

namespace OHOS {
namespace Media {
namespace Plugins {
/**
 * @brief Demuxer Plugin Interface.
 *
 * Used for audio and video media file parse.
 *
 * @since 1.0
 * @version 1.0
 */
struct DemuxerPlugin : public PluginBase {
    // Cache pressure callback type, executed in the read thread; must dispatch work asynchronously.
    using CachePressureCallback = std::function<void(uint32_t /*trackId*/, uint32_t /*cachedBytes*/)>;

    /// constructor
    explicit DemuxerPlugin(std::string name): PluginBase(std::move(name)) {}
    /**
     * @brief Set the data source to demuxer component.
     *
     * The function is valid only in the CREATED state.
     *
     * @param source Data source where data read from.
     * @param configs Configuration information, optional parameter, refer to Plugin::DemuxerMode.
     * @return  Execution Status return
     *  @retval OK: Plugin SetDataSource succeeded.
     */
    virtual Status SetDataSource(const std::shared_ptr<DataSource>& source,
        const std::shared_ptr<Media::Meta>& configs = nullptr) = 0;

    /**
     * @brief Get the attributes of a media file.
     *
     * The attributes contain file and stream attributes.
     * The function is valid only after INITIALIZED state.
     *
     * @param mediaInfo Indicates the pointer to the source attributes
     * @return  Execution status return
     *  @retval OK: Plugin GetMediaInfo succeeded.
     */
    virtual Status GetMediaInfo(MediaInfo& mediaInfo) = 0;

    /**
     * @brief Get the user meta of a media file.
     *
     * The attributes contain file and stream attributes.
     * The function is valid only after INITIALIZED state.
     *
     * @param mediaInfo Indicates the pointer to the user meta attributes
     * @return  Execution status return
     *  @retval OK: Plugin GetUserMeta succeeded.
     */
    virtual Status GetUserMeta(std::shared_ptr<Meta> meta) = 0;

    /**
     * @brief Select a specified media track.
     *
     * The function is valid only after RUNNING state.
     *
     * @param trackId Identifies the media track. If an invalid value is passed, the default media track specified.
     * @return  Execution Status return
     *  @retval OK: Plugin SelectTrack succeeded.
     */
    virtual Status SelectTrack(uint32_t trackId) = 0;

    /**
     * @brief Unselect a specified media track from which the demuxer reads data frames.
     *
     * The function is valid only after RUNNING state.
     *
     * @param trackId Identifies the media track. ignore the invalid value is passed.
     * @return  Execution Status return
     *  @retval OK: Plugin UnselectTrack succeeded.
     */
    virtual Status UnselectTrack(uint32_t trackId) = 0;

    /**
     * @brief Reads data frames (synchronous version).
     *
     * This function uses a synchronous implementation mechanism. It is valid only after the RUNNING state.
     *
     * @note This synchronous interface must be used together with the synchronous version of GetNextSampleSize.
     *       Synchronous and asynchronous interfaces (with and without timeout) cannot be mixed in the same instance.
     *
     * @note Memory management: The data will be copied into the memory provided by @param sample->memory_.
     *       The caller must pre-allocate sufficient memory in sample->memory_ before calling this function.
     *
     * @param trackId Identifies the media track. ignore the invalid value is passed.
     * @param sample Buffer where store data frames. The sample->memory_ must be pre-allocated with sufficient capacity.
     * @return  Execution Status return
     *  @retval OK: Plugin ReadFrame succeeded.
     *  @retval ERROR_TIMED_OUT: Operation timeout.
     */
    virtual Status ReadSample(uint32_t trackId, std::shared_ptr<AVBuffer> sample) = 0;

    /**
     * @brief Reads data frames within @param timeout milliseconds (asynchronous version).
     *
     * This function uses an asynchronous implementation mechanism.
     * It is valid only after the RUNNING state.
     *
     * @note This asynchronous interface must be used together with the asynchronous version
     *       of GetNextSampleSize. Synchronous and asynchronous interfaces
     *       (with and without timeout) cannot be mixed in the same instance.
     *
     * @note Memory management: The data will be copied into the memory provided by
     *       @param sample->memory_. The caller must pre-allocate sufficient memory in
     *       sample->memory_ before calling this function.
     *
     * @note If the buffer capacity is insufficient, the sample data will be split across
     *       multiple calls (the buffer flag indicates partial data). The caller should call
     *       this function again to copy the remaining data until all data is copied.
     *
     * @param trackId Identifies the media track. ignore the invalid value is passed.
     * @param timeout If no result is available after @param timeout milliseconds, the function returns.
     * @return  Execution Status return
     *  @retval OK: Plugin ReadFrame succeeded.
     *  @retval ERROR_WAIT_TIMEOUT: Operation timeout.
     *  @retval END_OF_STREAM: Read end (EOS).
     *  @retval ERROR_UNKNOWN: Call av_read_frame failed.
     *  @retval ERROR_NULL_POINTER: Call av_packet_alloc failed or sample->memory_ is nullptr.
     */
    virtual Status ReadSample(uint32_t trackId, std::shared_ptr<AVBuffer> sample, uint32_t timeout) = 0;

    /**
    * @brief Reads data frames within @param timeout milliseconds
    *        (asynchronous version, zero-copy mode).
    *
    * This function uses an asynchronous implementation mechanism with zero-copy optimization.
    * It is valid only after the RUNNING state.
    *
    * @note This asynchronous interface must be used together with the asynchronous version
    *       of GetNextSampleSize. Synchronous and asynchronous interfaces
    *       (with and without timeout) cannot be mixed in the same instance.
    *
    * @note Memory management: The function will create new memory internally and replace
    *       sample->memory_ with it. The caller does not need to pre-allocate memory in
    *       sample->memory_. The original memory will be replaced. The memory is managed
    *       internally through AVPacketMemory, achieving zero-copy mechanism.
    *
    * @param trackId Identifies the media track. ignore the invalid value is passed.
    * @param sample Buffer where store data frames. The sample->memory_ will be replaced with
    *               the new memory created internally.
    * @param timeout If no result is available after @param timeout milliseconds, the function returns.
    * @return  Execution Status return
    *  @retval OK: Plugin ReadFrame succeeded.
    *  @retval ERROR_WAIT_TIMEOUT: Operation timeout.
    *  @retval END_OF_STREAM: Read end (EOS).
    *  @retval ERROR_UNKNOWN: Call av_read_frame failed.
    *  @retval ERROR_NULL_POINTER: Call av_packet_alloc failed.
    */
    virtual Status ReadSampleZeroCopy(uint32_t trackId, std::shared_ptr<AVBuffer> sample, uint32_t timeout) = 0;

    /**
     * @brief Get next sample size (synchronous version).
     *
     * This function uses a synchronous implementation mechanism. It is valid only after the RUNNING state.
     *
     * @note This synchronous interface must be used together with the synchronous version of ReadSample.
     *       Synchronous and asynchronous interfaces (with and without timeout) cannot be mixed in the same instance.
     *
     * @param trackId Identifies the media track. ignore the invalid value is passed.
     * @param size Output parameter for the next sample size.
     * @return Execution Status
     */
    virtual Status GetNextSampleSize(uint32_t trackId, int32_t& size) = 0;

    /**
     * @brief Get next sample size within @param timeout milliseconds (asynchronous version).
     *
     * This function uses an asynchronous implementation mechanism. It is valid only after the RUNNING state.
     *
     * @note This asynchronous interface must be used together with the asynchronous version of ReadSample.
     *       Synchronous and asynchronous interfaces (with and without timeout) cannot be mixed in the same instance.
     *
     * @param trackId Identifies the media track. ignore the invalid value is passed.
     * @param size Output parameter for the next sample size.
     * @param timeout If no result is available after @param timeout milliseconds, the function returns.
     * @return Execution Status
     */
    virtual Status GetNextSampleSize(uint32_t trackId, int32_t& size, uint32_t timeout) = 0;

    /**
     * @brief Pause reading data from ffmpeg in another thread.
     *
     * @return Execution Status
     */
    virtual Status Pause() = 0;

    /**
     * @brief Get the latest PTS by trackId.
     *
     * @param trackId Identifies the media track. ignore the invalid value is passed.
     * @param lastPTS the latest PTS.
     * @return Execution Status
     */
    virtual Status GetLastPTSByTrackId(uint32_t trackId, int64_t &lastPTS) = 0;

    /**
     * @brief Seeks for a specified position for the demuxer.
     *
     * After being started, the demuxer seeks for a specified position to read data frames.
     *
     * The function is valid only after RUNNING state.
     *
     * @param trackId Identifies the stream in the media file.
     * @param seekTime Indicates the target position, based on {@link HST_TIME_BASE} .
     * @param mode Indicates the seek mode.
     * @param realSeekTime Indicates the accurate target position, based on {@link HST_TIME_BASE} .
     * @return  Execution Status return
     *  @retval OK: Plugin SeekTo succeeded.
     *  @retval ERROR_INVALID_DATA: The input data is invalid.
     */
    virtual Status SeekTo(int32_t trackId, int64_t seekTime, SeekMode mode, int64_t& realSeekTime) = 0;

    virtual Status Reset() = 0;

    virtual Status Start() = 0;

    virtual Status Stop() = 0;

    virtual Status Flush() = 0;

    virtual void ResetEosStatus() = 0;

    virtual bool IsRefParserSupported() { return false; };
    virtual Status ParserRefUpdatePos(int64_t timeStampMs, bool isForward = true) = 0;
    virtual Status ParserRefInfo() = 0;
    virtual Status GetFrameLayerInfo(std::shared_ptr<AVBuffer> videoSample, FrameLayerInfo &frameLayerInfo) = 0;
    virtual Status GetFrameLayerInfo(uint32_t frameId, FrameLayerInfo &frameLayerInfo) = 0;
    virtual Status GetGopLayerInfo(uint32_t gopId, GopLayerInfo &gopLayerInfo) = 0;
    virtual Status GetIFramePos(std::vector<uint32_t> &IFramePos) = 0;
    virtual Status Dts2FrameId(int64_t dts, uint32_t &frameId) = 0;
    virtual Status SeekMs2FrameId(int64_t seekMs, uint32_t &frameId) = 0;
    virtual Status FrameId2SeekMs(uint32_t frameId, int64_t &seekMs) = 0;

    virtual Status GetDrmInfo(std::multimap<std::string, std::vector<uint8_t>>& drmInfo)
    {
        (void)drmInfo;
        return Status::OK;
    }

    virtual void SetInterruptState(bool isInterruptNeeded) {}

    virtual Status GetIndexByRelativePresentationTimeUs(const uint32_t trackIndex,
        const uint64_t relativePresentationTimeUs, uint32_t &index) = 0;

    virtual Status GetRelativePresentationTimeUsByIndex(const uint32_t trackIndex,
        const uint32_t index, uint64_t &relativePresentationTimeUs) = 0;

    virtual void SetCacheLimit(uint32_t limitSize) = 0;
    virtual Status GetCurrentCacheSize(uint32_t trackId, uint32_t& size)
    {
        size = 0;
        return Status::OK;
    };
    virtual Status GetCurrentCacheFrameCount(uint32_t trackId, uint32_t& frameCount)
    {
        frameCount = 0;
        return Status::OK;
    };

    /**
     * @brief Register cache pressure callback function.
     *
     * @param cb Callback function, called by the read thread when track cache exceeds limit.
     *           Warning: The callback executes in the read thread. It must not directly call
     *           plugin interfaces such as ReadSample or GetNextSampleSize that may acquire
     *           internal locks. The actual work should be asynchronously dispatched to other
     *           threads to avoid deadlocks with operations such as SeekTo and Flush.
     *
     * @return Execution Status
     */
    virtual Status SetCachePressureCallback(CachePressureCallback cb) = 0;

    /**
     * @brief Set per-track cache size limit and notification throttle window.
     *
     * @param trackId    Track ID.
     * @param limitBytes Cache size limit in bytes for the given track.
     * @param windowMs   Minimum interval (in milliseconds) between two notifications of the same track.
     * @return Execution Status
     */
    virtual Status SetTrackCacheLimit(uint32_t trackId, uint32_t limitBytes, uint32_t windowMs = 500) = 0;

    /**
     * @brief Set read timeout for init/seek operations.
     *
     * If dataSource keeps returning ERROR_AGAIN beyond the timeout during init or seek,
     * the operation will report an error and exit.
     *
     * @param timeoutMs Timeout value in milliseconds. 0 means no timeout. Must be non-negative.
     * @return Execution Status
     */
    virtual Status SetReadTimeoutForInitSeek(int64_t timeoutMs) = 0;

    virtual bool GetProbeSize(int32_t &offset, int32_t &size) { return false; };
    virtual Status SetDataSourceWithProbSize(const std::shared_ptr<DataSource>& source,
        const int32_t probSize) = 0;

    /**
     * @brief Boosts the asynchronous read thread priority.
     *
     * Elevates thread priority if called with proper permissions and when thread is not RUNNING.
     * By default, the thread operates at normal priority.
     *
     * @return Execution status
     */
    virtual Status BoostReadThreadPriority() = 0;
    virtual Status SetAVReadPacketStopState(bool state) = 0;
    /**
     * @brief Seek to the first frame of the media file.
     *
     * @return Execution status
    */
    virtual Status SeekToStart() = 0;
    /**
     * @brief Seek to the first key frame at or after the specified time on the default track.
     *
     * @param trackId       [Ignored] Present for consistency with the @c SeekTo() interface.
     *                      Internally, the video track is always used; if no video track exists,
     *                      track 0 is used instead.
     * @param seekTime      Indicates the target position, based on {@link HST_TIME_BASE} .
     * @param mode          Only @c SeekMode::SEEK_NEXT_SYNC is supported.
     * @param[out] realSeekTime  On success, contains the converted timestamp of the found keyframe.
     *                           On failure, contains the offset-adjusted version of @p seekTime.
     * @param timeoutMs     Timeout in milliseconds. A value of 0 means no timeout (blocking wait).
     *
     * @return Execution status
    */
    virtual Status SeekToKeyFrame(int32_t trackId, int64_t seekTime,
        SeekMode mode, int64_t& realSeekTime, uint32_t timeoutMs) { return Status::ERROR_UNKNOWN; };
    /**
     * @brief Seeks to a specified frame by DTS.
     *
     * @param trackId Identifies the stream in the media file.
     * @param seekTime Indicates the target DTS.
     * @param mode Indicates the seek mode.
     * @param realSeekTime Indicates the accurate target DTS.
     * @param timeoutMs If no result is available after @param timeoutMs milliseconds, the function returns.
     * @return Execution Status
     */
    virtual Status SeekToFrameByDts(int32_t trackId, int64_t seekTime,
        SeekMode mode, int64_t& realSeekTime, uint32_t timeoutMs) = 0;
};

/// Demuxer plugin api major number.
#define DEMUXER_API_VERSION_MAJOR (1)

/// Demuxer plugin api minor number
#define DEMUXER_API_VERSION_MINOR (0)

/// Demuxer plugin version
#define DEMUXER_API_VERSION MAKE_VERSION(DEMUXER_API_VERSION_MAJOR, DEMUXER_API_VERSION_MINOR)

/**
 * @brief Describes the demuxer plugin information.
 *
 * @since 1.0
 * @version 1.0
 */
struct DemuxerPluginDef : public PluginDefBase {
    DemuxerPluginDef()
        : PluginDefBase()
    {
        apiVersion = DEMUXER_API_VERSION; ///< Demuxer plugin version.
        pluginType = PluginType::DEMUXER; ///< Plugin type, MUST be DEMUXER.
    }
};
} // namespace Plugins
} // namespace Media
} // namespace OHOS
#endif // AVCODEC_DEMUXER_PLUGIN_H