* 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 HISTREAMER_SUBTITLE_SINK_H
#define HISTREAMER_SUBTITLE_SINK_H
#include <mutex>
#include <deque>
#include "common/status.h"
#include "meta/meta.h"
#include "sink/media_synchronous_sink.h"
#include "media_sync_manager.h"
#include "buffer/avbuffer_queue.h"
#include "buffer/avbuffer_queue_define.h"
#include "filter/filter.h"
#include <unordered_set>
#include <stack>
namespace OHOS {
namespace Media {
using namespace OHOS::Media::Plugins;
class SubtitleSink : public std::enable_shared_from_this<SubtitleSink>, public Pipeline::MediaSynchronousSink {
public:
SubtitleSink();
~SubtitleSink();
Status Init(std::shared_ptr<Meta>& meta, const std::shared_ptr<Pipeline::EventReceiver>& receiver);
sptr<AVBufferQueueProducer> GetBufferQueueProducer();
sptr<AVBufferQueueConsumer> GetBufferQueueConsumer();
Status SetParameter(const std::shared_ptr<Meta>& meta);
Status GetParameter(std::shared_ptr<Meta>& meta);
Status Prepare();
Status Start();
Status Stop();
Status Pause();
Status Resume();
Status Flush(bool isSeekFlush);
Status Release();
void DrainOutputBuffer(bool flushed);
void SetEventReceiver(const std::shared_ptr<Pipeline::EventReceiver>& receiver);
Status GetLatency(uint64_t& nanoSec);
void SetSyncCenter(std::shared_ptr<Pipeline::MediaSyncManager> syncCenter);
int64_t DoSyncWrite(const std::shared_ptr<OHOS::Media::AVBuffer>& buffer, int64_t& actionClock) override;
void ResetSyncInfo() override;
Status SetIsTransitent(bool isTransitent);
void NotifySeek();
virtual void OnInterrupted(bool isInterruptNeeded) override;
Status SetSpeed(float speed);
protected:
std::atomic<OHOS::Media::Pipeline::FilterState> state_;
private:
struct SubtitleInfo {
std::string text_;
int64_t pts_;
int64_t duration_;
std::shared_ptr<AVBuffer> buffer_ {nullptr};
SubtitleInfo(std::string text, int64_t pts, int64_t duration) : text_(text), pts_(pts), duration_(duration) {}
SubtitleInfo(std::string text, int64_t pts, int64_t duration, std::shared_ptr<AVBuffer> buffer)
: text_(text), pts_(pts), duration_(duration), buffer_(buffer) {}
SubtitleInfo(const SubtitleInfo& other)
: text_(other.text_), pts_(other.pts_), duration_(other.duration_), buffer_(other.buffer_) {}
SubtitleInfo& operator=(const SubtitleInfo& other)
{
if (this != &other) {
text_ = other.text_;
pts_ = other.pts_;
duration_ = other.duration_;
buffer_ = other.buffer_;
}
return *this;
}
};
void NotifyRender(SubtitleInfo &subtitleInfo);
void RenderLoop();
uint64_t CalcWaitTime(SubtitleInfo &subtitleInfo);
uint32_t ActionToDo(SubtitleInfo &subtitleInfo);
void GetTargetSubtitleIndex(int64_t currentTime);
Status PrepareInputBufferQueue();
int64_t getDurationUsPlayedAtSampleRate(uint32_t numFrames);
int64_t GetMediaTime();
std::string RemoveTextTags(const std::string& text);
std::pair<std::string, bool> ParseTag(const std::string& tagContent);
bool FindAndRemoveMatchingTag(std::stack<std::pair<std::string, size_t>>& openTags, const std::string& tag);
void RestoreUnsupportedTags(std::string& result, std::stack<std::pair<std::string, size_t>>& openTags);
std::shared_ptr<Pipeline::EventReceiver> playerEventReceiver_;
int32_t appUid_{0};
int32_t appPid_{0};
int64_t numFramesWritten_ {0};
int64_t lastReportedClockTime_ {HST_TIME_NONE};
int64_t latestBufferPts_ {HST_TIME_NONE};
int64_t latestBufferDuration_ {0};
const std::string INPUT_BUFFER_QUEUE_NAME = "SubtitleSinkInputBufferQueue";
std::shared_ptr<AVBufferQueue> inputBufferQueue_;
sptr<AVBufferQueueProducer> inputBufferQueueProducer_;
sptr<AVBufferQueueConsumer> inputBufferQueueConsumer_;
bool isTransitent_ {false};
std::atomic<bool> isEos_{false};
std::unique_ptr<std::thread> readThread_ = nullptr;
std::mutex mutex_;
std::condition_variable updateCond_;
std::shared_ptr<AVBuffer> filledOutputBuffer_;
std::atomic<bool> isPaused_{false};
std::atomic<bool> isThreadExit_{false};
std::atomic<bool> shouldUpdate_{false};
float speed_ = 1.0;
enum SubtitleBufferState : uint32_t {
WAIT,
SHOW,
DROP,
};
std::deque<SubtitleInfo> subtitleInfoVec_;
uint32_t currentInfoIndex_ = 0;
std::atomic<bool> isFlush_ = false;
std::vector<std::shared_ptr<AVBuffer>> inputBufferVector_;
};
}
}
#endif