Skip to content

Commit

Permalink
Improved the transcoder to support seamless transitions in multi-audi…
Browse files Browse the repository at this point in the history
…o tracks.
  • Loading branch information
Keukhan committed Feb 11, 2025
1 parent f7ee5b7 commit 695705f
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 44 deletions.
37 changes: 13 additions & 24 deletions src/projects/transcoder/transcoder_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ bool TranscoderStream::PrepareInternal()
logti("No decoder generated");
}

StoreInputTrackSnapshot(_input_stream);
StoreTracks(_input_stream);

return true;
}
Expand All @@ -244,9 +244,9 @@ bool TranscoderStream::UpdateInternal(const std::shared_ptr<info::Stream> &strea
// - The input track should not change.
_is_updating = true;

if (IsAvailableSmoothTransition(stream) == true)
if (CanSeamlessTransition(stream) == true)
{
logtd("%s This stream will be a smooth transition", _log_prefix.CStr());
logtd("%s This stream support seamless transitions", _log_prefix.CStr());
FlushBuffers();

RemoveDecoders();
Expand All @@ -256,7 +256,7 @@ bool TranscoderStream::UpdateInternal(const std::shared_ptr<info::Stream> &strea
}
else
{
logtw("%s This stream does not support smooth transitions. renew the all components", _log_prefix.CStr());
logtw("%s This stream does not support seamless transitions. Renewing all", _log_prefix.CStr());

FlushBuffers();

Expand All @@ -269,7 +269,7 @@ bool TranscoderStream::UpdateInternal(const std::shared_ptr<info::Stream> &strea
UpdateMsidOfOutputStreams(stream->GetMsid());
NotifyUpdateStreams();

StoreInputTrackSnapshot(stream);
StoreTracks(stream);
}

_is_updating = false;
Expand Down Expand Up @@ -389,24 +389,12 @@ std::shared_ptr<info::Stream> TranscoderStream::GetOutputStreamByTrackId(MediaTr
return nullptr;
}

bool TranscoderStream::IsAvailableSmoothTransition(const std::shared_ptr<info::Stream> &input_stream)
bool TranscoderStream::CanSeamlessTransition(const std::shared_ptr<info::Stream> &input_stream)
{
// #1. The number of tracks per media type should not exceed one.
int32_t track_count_per_mediatype[(uint32_t)cmn::MediaType::Nb] = {0};
for (const auto &[track_id, track] : input_stream->GetTracks())
{
UNUSED_VARIABLE(track_id)

if ((++track_count_per_mediatype[(uint32_t)track->GetMediaType()]) > 1)
{
// Could not support smooth transition. because, number of tracks per media type exceed one.
logtw("%s Smooth transitions are not possible because the number of tracks per media type exceeds one.", _log_prefix.CStr());
return false;
}
}
auto new_tracks = input_stream->GetTracks();

// #2. Check if the number and type of original tracks are different.
if(IsEqualCountAndMediaTypeOfMediaTracks(input_stream->GetTracks(), GetInputTrackSnapshot()) == false)
// Check if the number and type of original tracks are different.
if(CompareTracksForSeamlessTransition(new_tracks, GetStoredTracks()) == false)
{
logtw("%s The input track has changed. It does not support smooth transitions.", _log_prefix.CStr());
return false;
Expand Down Expand Up @@ -1509,8 +1497,8 @@ void TranscoderStream::OnDecodedFrame(TranscodeResult result, MediaTrackId decod
// Record the timestamp of the last decoded frame. managed by microseconds.
_last_decoded_frame_pts[decoder_id] = last_frame->GetPts() * filter_expr * 1000000.0;

logtd("%s Create filler frame because there is no decoding frame. Type(%s), Decoder(%u), FillerFrames(%d)"
, _log_prefix.CStr(), cmn::GetMediaTypeString(input_track->GetMediaType()).CStr(), decoder_id, 1);
// logtd("%s Create filler frame because there is no decoding frame. Type(%s), Decoder(%u), FillerFrames(%d)"
// , _log_prefix.CStr(), cmn::GetMediaTypeString(input_track->GetMediaType()).CStr(), decoder_id, 1);

// Send Temporary Frame to Filter
SpreadToFilters(decoder_id, last_frame);
Expand Down Expand Up @@ -1600,7 +1588,7 @@ void TranscoderStream::OnDecodedFrame(TranscodeResult result, MediaTrackId decod
}

SpreadToFilters(decoder_id, clone_frame);
// logte("%s Create filler frame. Type(%s), %s", _log_prefix.CStr(), cmn::GetMediaTypeString(input_track->GetMediaType()).CStr(), clone_frame->GetInfoString().CStr());
// logtd("%s Create filler frame. Type(%s), %s", _log_prefix.CStr(), cmn::GetMediaTypeString(input_track->GetMediaType()).CStr(), clone_frame->GetInfoString().CStr());
}
}
}
Expand All @@ -1610,6 +1598,7 @@ void TranscoderStream::OnDecodedFrame(TranscodeResult result, MediaTrackId decod
}

case TranscodeResult::DataReady: {


// The last decoded frame is kept and used as a filling frame in the blank section.
SetLastDecodedFrame(decoder_id, decoded_frame);
Expand Down
2 changes: 1 addition & 1 deletion src/projects/transcoder/transcoder_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ class TranscoderStream : public ov::EnableSharedFromThis<TranscoderStream>, publ
void UpdateInputTrack(std::shared_ptr<MediaFrame> buffer);
void UpdateOutputTrack(std::shared_ptr<MediaFrame> buffer);
void UpdateMsidOfOutputStreams(uint32_t msid);
bool IsAvailableSmoothTransition(const std::shared_ptr<info::Stream> &stream);
bool CanSeamlessTransition(const std::shared_ptr<info::Stream> &stream);
void FlushBuffers();

// Step 2: Filter (resample/rescale the decoded frame)
Expand Down
24 changes: 12 additions & 12 deletions src/projects/transcoder/transcoder_stream_internal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -756,41 +756,41 @@ void TranscoderStreamInternal::UpdateOutputTrackTranscode(const std::shared_ptr<
}
}

bool TranscoderStreamInternal::StoreInputTrackSnapshot(std::shared_ptr<info::Stream> stream)
bool TranscoderStreamInternal::StoreTracks(std::shared_ptr<info::Stream> stream)
{
_input_track_snapshot.clear();
_store_tracks.clear();

for (auto &[track_id, track] : stream->GetTracks())
{
auto clone = track->Clone();
_input_track_snapshot[track_id] = clone;
_store_tracks[track_id] = clone;
}

return true;
}

std::map<int32_t, std::shared_ptr<MediaTrack>>& TranscoderStreamInternal::GetInputTrackSnapshot()
std::map<int32_t, std::shared_ptr<MediaTrack>>& TranscoderStreamInternal::GetStoredTracks()
{
return _input_track_snapshot;
return _store_tracks;
}

bool TranscoderStreamInternal::IsEqualCountAndMediaTypeOfMediaTracks(std::map<int32_t, std::shared_ptr<MediaTrack>> a, std::map<int32_t, std::shared_ptr<MediaTrack>> b)
bool TranscoderStreamInternal::CompareTracksForSeamlessTransition(std::map<int32_t, std::shared_ptr<MediaTrack>> prev_tracks, std::map<int32_t, std::shared_ptr<MediaTrack>> new_tracks)
{
if (a.size() != b.size())
// #1 Check the number of tracks
if (prev_tracks.size() != new_tracks.size())
{
return false;
}

for (auto &[track_id, track] : a)
// #2 Check type of tracks
for (auto &[track_id, prev_track] : prev_tracks)
{
if (b.find(track_id) == b.end())
if (new_tracks.find(track_id) == new_tracks.end())
{
return false;
}

auto track_b = b[track_id];

if(track->GetMediaType() != track_b->GetMediaType())
if(prev_track->GetMediaType() != new_tracks[track_id]->GetMediaType())
{
return false;
}
Expand Down
12 changes: 5 additions & 7 deletions src/projects/transcoder/transcoder_stream_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,11 @@ class TranscoderStreamInternal
uint32_t &audio, uint32_t &audio_bypass,
uint32_t &image, uint32_t &data);


public:
// For the purpose of checking if the input track has changed during the update.
bool StoreInputTrackSnapshot(std::shared_ptr<info::Stream> stream);
std::map<int32_t, std::shared_ptr<MediaTrack>>& GetInputTrackSnapshot();
bool IsEqualCountAndMediaTypeOfMediaTracks(std::map<int32_t, std::shared_ptr<MediaTrack>> a, std::map<int32_t, std::shared_ptr<MediaTrack>> b);
// This is used to check if the input track has changed during the update.
bool StoreTracks(std::shared_ptr<info::Stream> stream);
std::map<int32_t, std::shared_ptr<MediaTrack>> &GetStoredTracks();
bool CompareTracksForSeamlessTransition(std::map<int32_t, std::shared_ptr<MediaTrack>> prev_tracks, std::map<int32_t, std::shared_ptr<MediaTrack>> new_tracks);

private:
std::map<int32_t, std::shared_ptr<MediaTrack>> _input_track_snapshot;
std::map<int32_t, std::shared_ptr<MediaTrack>> _store_tracks;
};

0 comments on commit 695705f

Please sign in to comment.