-
Notifications
You must be signed in to change notification settings - Fork 48
Add stream_index seek mode, read frame index and update metadata #764
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
88cacb9
4dfc581
ed3fdec
6030f9e
1361c0d
5bb23c2
6573943
3341dd8
e914160
394ac70
f13433c
8971bd6
5d66ef1
4907e6d
d9cec94
72ae22d
34eb7b4
9a343b3
7728895
dacd826
f90718d
a24c79c
ee6e867
011c8c5
c5c5cd2
4c6aadd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -198,6 +198,45 @@ int SingleStreamDecoder::getBestStreamIndex(AVMediaType mediaType) { | |||||||||||||||||||||||||||||
// VIDEO METADATA QUERY API | ||||||||||||||||||||||||||||||
// -------------------------------------------------------------------------- | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
void SingleStreamDecoder::sortAllFrames() { | ||||||||||||||||||||||||||||||
// Sort the allFrames and keyFrames vecs in each stream, and also sets | ||||||||||||||||||||||||||||||
// additional fields of the FrameInfo entries like nextPts and frameIndex | ||||||||||||||||||||||||||||||
// This is called at the end of a scan, or when setting a user-defined frame | ||||||||||||||||||||||||||||||
// mapping. | ||||||||||||||||||||||||||||||
for (auto& [streamIndex, streamInfo] : streamInfos_) { | ||||||||||||||||||||||||||||||
std::sort( | ||||||||||||||||||||||||||||||
streamInfo.keyFrames.begin(), | ||||||||||||||||||||||||||||||
streamInfo.keyFrames.end(), | ||||||||||||||||||||||||||||||
[](const FrameInfo& frameInfo1, const FrameInfo& frameInfo2) { | ||||||||||||||||||||||||||||||
return frameInfo1.pts < frameInfo2.pts; | ||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||
std::sort( | ||||||||||||||||||||||||||||||
streamInfo.allFrames.begin(), | ||||||||||||||||||||||||||||||
streamInfo.allFrames.end(), | ||||||||||||||||||||||||||||||
[](const FrameInfo& frameInfo1, const FrameInfo& frameInfo2) { | ||||||||||||||||||||||||||||||
return frameInfo1.pts < frameInfo2.pts; | ||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
size_t keyFrameIndex = 0; | ||||||||||||||||||||||||||||||
for (size_t i = 0; i < streamInfo.allFrames.size(); ++i) { | ||||||||||||||||||||||||||||||
streamInfo.allFrames[i].frameIndex = i; | ||||||||||||||||||||||||||||||
if (streamInfo.allFrames[i].isKeyFrame) { | ||||||||||||||||||||||||||||||
TORCH_CHECK( | ||||||||||||||||||||||||||||||
keyFrameIndex < streamInfo.keyFrames.size(), | ||||||||||||||||||||||||||||||
"The allFrames vec claims it has MORE keyFrames than the keyFrames vec. There's a bug in torchcodec."); | ||||||||||||||||||||||||||||||
streamInfo.keyFrames[keyFrameIndex].frameIndex = i; | ||||||||||||||||||||||||||||||
++keyFrameIndex; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
if (i + 1 < streamInfo.allFrames.size()) { | ||||||||||||||||||||||||||||||
streamInfo.allFrames[i].nextPts = streamInfo.allFrames[i + 1].pts; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
TORCH_CHECK( | ||||||||||||||||||||||||||||||
keyFrameIndex == streamInfo.keyFrames.size(), | ||||||||||||||||||||||||||||||
"The allFrames vec claims it has LESS keyFrames than the keyFrames vec. There's a bug in torchcodec."); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
void SingleStreamDecoder::scanFileAndUpdateMetadataAndIndex() { | ||||||||||||||||||||||||||||||
if (scannedAllStreams_) { | ||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||
|
@@ -283,40 +322,46 @@ void SingleStreamDecoder::scanFileAndUpdateMetadataAndIndex() { | |||||||||||||||||||||||||||||
getFFMPEGErrorStringFromErrorCode(status)); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// Sort all frames by their pts. | ||||||||||||||||||||||||||||||
for (auto& [streamIndex, streamInfo] : streamInfos_) { | ||||||||||||||||||||||||||||||
std::sort( | ||||||||||||||||||||||||||||||
streamInfo.keyFrames.begin(), | ||||||||||||||||||||||||||||||
streamInfo.keyFrames.end(), | ||||||||||||||||||||||||||||||
[](const FrameInfo& frameInfo1, const FrameInfo& frameInfo2) { | ||||||||||||||||||||||||||||||
return frameInfo1.pts < frameInfo2.pts; | ||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||
std::sort( | ||||||||||||||||||||||||||||||
streamInfo.allFrames.begin(), | ||||||||||||||||||||||||||||||
streamInfo.allFrames.end(), | ||||||||||||||||||||||||||||||
[](const FrameInfo& frameInfo1, const FrameInfo& frameInfo2) { | ||||||||||||||||||||||||||||||
return frameInfo1.pts < frameInfo2.pts; | ||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||
sortAllFrames(); | ||||||||||||||||||||||||||||||
scannedAllStreams_ = true; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
size_t keyFrameIndex = 0; | ||||||||||||||||||||||||||||||
for (size_t i = 0; i < streamInfo.allFrames.size(); ++i) { | ||||||||||||||||||||||||||||||
streamInfo.allFrames[i].frameIndex = i; | ||||||||||||||||||||||||||||||
if (streamInfo.allFrames[i].isKeyFrame) { | ||||||||||||||||||||||||||||||
TORCH_CHECK( | ||||||||||||||||||||||||||||||
keyFrameIndex < streamInfo.keyFrames.size(), | ||||||||||||||||||||||||||||||
"The allFrames vec claims it has MORE keyFrames than the keyFrames vec. There's a bug in torchcodec."); | ||||||||||||||||||||||||||||||
streamInfo.keyFrames[keyFrameIndex].frameIndex = i; | ||||||||||||||||||||||||||||||
++keyFrameIndex; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
if (i + 1 < streamInfo.allFrames.size()) { | ||||||||||||||||||||||||||||||
streamInfo.allFrames[i].nextPts = streamInfo.allFrames[i + 1].pts; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
void SingleStreamDecoder::readCustomFrameMappingsUpdateMetadataAndIndex( | ||||||||||||||||||||||||||||||
int streamIndex, | ||||||||||||||||||||||||||||||
FrameMappings customFrameMappings) { | ||||||||||||||||||||||||||||||
auto& all_frames = customFrameMappings.all_frames; | ||||||||||||||||||||||||||||||
auto& is_key_frame = customFrameMappings.is_key_frame; | ||||||||||||||||||||||||||||||
auto& duration = customFrameMappings.duration; | ||||||||||||||||||||||||||||||
TORCH_CHECK( | ||||||||||||||||||||||||||||||
all_frames.size(0) == is_key_frame.size(0) && | ||||||||||||||||||||||||||||||
is_key_frame.size(0) == duration.size(0), | ||||||||||||||||||||||||||||||
"all_frames, is_key_frame, and duration from custom_frame_mappings were not same size."); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
auto& streamMetadata = containerMetadata_.allStreamMetadata[streamIndex]; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
streamMetadata.beginStreamPtsFromContent = all_frames[0].item<int64_t>(); | ||||||||||||||||||||||||||||||
streamMetadata.endStreamPtsFromContent = | ||||||||||||||||||||||||||||||
all_frames[-1].item<int64_t>() + duration[-1].item<int64_t>(); | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TIL that tensors on the C++ side also support negative indices! I'm so used to that being not allowed in C++ arrays and standard containers that I initially thought this was undefined behavior! |
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
auto avStream = formatContext_->streams[streamIndex]; | ||||||||||||||||||||||||||||||
streamMetadata.beginStreamPtsSecondsFromContent = | ||||||||||||||||||||||||||||||
*streamMetadata.beginStreamPtsFromContent * av_q2d(avStream->time_base); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
streamMetadata.endStreamPtsSecondsFromContent = | ||||||||||||||||||||||||||||||
*streamMetadata.endStreamPtsFromContent * av_q2d(avStream->time_base); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably use the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just bumping this again as it may have been missed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will address #770 after completing this change, so we can update + test all locations in one PR. |
||||||||||||||||||||||||||||||
streamMetadata.numFramesFromContent = all_frames.size(0); | ||||||||||||||||||||||||||||||
for (int64_t i = 0; i < all_frames.size(0); ++i) { | ||||||||||||||||||||||||||||||
FrameInfo frameInfo; | ||||||||||||||||||||||||||||||
frameInfo.pts = all_frames[i].item<int64_t>(); | ||||||||||||||||||||||||||||||
frameInfo.isKeyFrame = is_key_frame[i].item<bool>(); | ||||||||||||||||||||||||||||||
streamInfos_[streamIndex].allFrames.push_back(frameInfo); | ||||||||||||||||||||||||||||||
NicolasHug marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
if (frameInfo.isKeyFrame) { | ||||||||||||||||||||||||||||||
streamInfos_[streamIndex].keyFrames.push_back(frameInfo); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
TORCH_CHECK( | ||||||||||||||||||||||||||||||
keyFrameIndex == streamInfo.keyFrames.size(), | ||||||||||||||||||||||||||||||
"The allFrames vec claims it has LESS keyFrames than the keyFrames vec. There's a bug in torchcodec."); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
scannedAllStreams_ = true; | ||||||||||||||||||||||||||||||
// Sort all frames by their pts | ||||||||||||||||||||||||||||||
sortAllFrames(); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I realize reading this that there is an additional design decision we'll have to make: whether we expect the index to be already sorted, or not. In the existing torchcodec/src/torchcodec/_core/SingleStreamDecoder.cpp Lines 285 to 298 in 86e952f
I suspect that frame mappings coming from
I think the simpler, safer choice is to sort in C++ and rely on the same sorting logic that we have in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed on sorting on the C++ side; we can do it quickly on the C++ side, and it's much nicer to users. We should extract the existing logic out to a utility function called only in this cpp file, and call it in both places. I think we sort in the scan function because I think it's possible for the actual packets to be not in PTS order. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the feedback! Sorting on the C++ side makes sense, I've updated the PR to reuse the sorting code from the scan function. |
||||||||||||||||||||||||||||||
ContainerMetadata SingleStreamDecoder::getContainerMetadata() const { | ||||||||||||||||||||||||||||||
|
@@ -431,7 +476,8 @@ void SingleStreamDecoder::addStream( | |||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
void SingleStreamDecoder::addVideoStream( | ||||||||||||||||||||||||||||||
int streamIndex, | ||||||||||||||||||||||||||||||
const VideoStreamOptions& videoStreamOptions) { | ||||||||||||||||||||||||||||||
const VideoStreamOptions& videoStreamOptions, | ||||||||||||||||||||||||||||||
std::optional<FrameMappings> customFrameMappings) { | ||||||||||||||||||||||||||||||
addStream( | ||||||||||||||||||||||||||||||
streamIndex, | ||||||||||||||||||||||||||||||
AVMEDIA_TYPE_VIDEO, | ||||||||||||||||||||||||||||||
|
@@ -456,6 +502,14 @@ void SingleStreamDecoder::addVideoStream( | |||||||||||||||||||||||||||||
streamMetadata.height = streamInfo.codecContext->height; | ||||||||||||||||||||||||||||||
streamMetadata.sampleAspectRatio = | ||||||||||||||||||||||||||||||
streamInfo.codecContext->sample_aspect_ratio; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
if (seekMode_ == SeekMode::custom_frame_mappings) { | ||||||||||||||||||||||||||||||
TORCH_CHECK( | ||||||||||||||||||||||||||||||
customFrameMappings.has_value(), | ||||||||||||||||||||||||||||||
"Please provide frame mappings when using custom_frame_mappings seek mode."); | ||||||||||||||||||||||||||||||
readCustomFrameMappingsUpdateMetadataAndIndex( | ||||||||||||||||||||||||||||||
streamIndex, customFrameMappings.value()); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
void SingleStreamDecoder::addAudioStream( | ||||||||||||||||||||||||||||||
|
@@ -1407,6 +1461,7 @@ int SingleStreamDecoder::getKeyFrameIndexForPtsUsingScannedIndex( | |||||||||||||||||||||||||||||
int64_t SingleStreamDecoder::secondsToIndexLowerBound(double seconds) { | ||||||||||||||||||||||||||||||
auto& streamInfo = streamInfos_[activeStreamIndex_]; | ||||||||||||||||||||||||||||||
switch (seekMode_) { | ||||||||||||||||||||||||||||||
case SeekMode::custom_frame_mappings: | ||||||||||||||||||||||||||||||
case SeekMode::exact: { | ||||||||||||||||||||||||||||||
auto frame = std::lower_bound( | ||||||||||||||||||||||||||||||
streamInfo.allFrames.begin(), | ||||||||||||||||||||||||||||||
|
@@ -1434,6 +1489,7 @@ int64_t SingleStreamDecoder::secondsToIndexLowerBound(double seconds) { | |||||||||||||||||||||||||||||
int64_t SingleStreamDecoder::secondsToIndexUpperBound(double seconds) { | ||||||||||||||||||||||||||||||
auto& streamInfo = streamInfos_[activeStreamIndex_]; | ||||||||||||||||||||||||||||||
switch (seekMode_) { | ||||||||||||||||||||||||||||||
case SeekMode::custom_frame_mappings: | ||||||||||||||||||||||||||||||
case SeekMode::exact: { | ||||||||||||||||||||||||||||||
auto frame = std::upper_bound( | ||||||||||||||||||||||||||||||
streamInfo.allFrames.begin(), | ||||||||||||||||||||||||||||||
|
@@ -1461,6 +1517,7 @@ int64_t SingleStreamDecoder::secondsToIndexUpperBound(double seconds) { | |||||||||||||||||||||||||||||
int64_t SingleStreamDecoder::getPts(int64_t frameIndex) { | ||||||||||||||||||||||||||||||
auto& streamInfo = streamInfos_[activeStreamIndex_]; | ||||||||||||||||||||||||||||||
switch (seekMode_) { | ||||||||||||||||||||||||||||||
case SeekMode::custom_frame_mappings: | ||||||||||||||||||||||||||||||
case SeekMode::exact: | ||||||||||||||||||||||||||||||
return streamInfo.allFrames[frameIndex].pts; | ||||||||||||||||||||||||||||||
case SeekMode::approximate: { | ||||||||||||||||||||||||||||||
|
@@ -1485,6 +1542,7 @@ int64_t SingleStreamDecoder::getPts(int64_t frameIndex) { | |||||||||||||||||||||||||||||
std::optional<int64_t> SingleStreamDecoder::getNumFrames( | ||||||||||||||||||||||||||||||
const StreamMetadata& streamMetadata) { | ||||||||||||||||||||||||||||||
switch (seekMode_) { | ||||||||||||||||||||||||||||||
case SeekMode::custom_frame_mappings: | ||||||||||||||||||||||||||||||
case SeekMode::exact: | ||||||||||||||||||||||||||||||
return streamMetadata.numFramesFromContent.value(); | ||||||||||||||||||||||||||||||
case SeekMode::approximate: { | ||||||||||||||||||||||||||||||
|
@@ -1498,6 +1556,7 @@ std::optional<int64_t> SingleStreamDecoder::getNumFrames( | |||||||||||||||||||||||||||||
double SingleStreamDecoder::getMinSeconds( | ||||||||||||||||||||||||||||||
const StreamMetadata& streamMetadata) { | ||||||||||||||||||||||||||||||
switch (seekMode_) { | ||||||||||||||||||||||||||||||
case SeekMode::custom_frame_mappings: | ||||||||||||||||||||||||||||||
case SeekMode::exact: | ||||||||||||||||||||||||||||||
return streamMetadata.beginStreamPtsSecondsFromContent.value(); | ||||||||||||||||||||||||||||||
case SeekMode::approximate: | ||||||||||||||||||||||||||||||
|
@@ -1510,6 +1569,7 @@ double SingleStreamDecoder::getMinSeconds( | |||||||||||||||||||||||||||||
std::optional<double> SingleStreamDecoder::getMaxSeconds( | ||||||||||||||||||||||||||||||
const StreamMetadata& streamMetadata) { | ||||||||||||||||||||||||||||||
switch (seekMode_) { | ||||||||||||||||||||||||||||||
case SeekMode::custom_frame_mappings: | ||||||||||||||||||||||||||||||
case SeekMode::exact: | ||||||||||||||||||||||||||||||
return streamMetadata.endStreamPtsSecondsFromContent.value(); | ||||||||||||||||||||||||||||||
case SeekMode::approximate: { | ||||||||||||||||||||||||||||||
|
@@ -1645,6 +1705,8 @@ SingleStreamDecoder::SeekMode seekModeFromString(std::string_view seekMode) { | |||||||||||||||||||||||||||||
return SingleStreamDecoder::SeekMode::exact; | ||||||||||||||||||||||||||||||
} else if (seekMode == "approximate") { | ||||||||||||||||||||||||||||||
return SingleStreamDecoder::SeekMode::approximate; | ||||||||||||||||||||||||||||||
} else if (seekMode == "custom_frame_mappings") { | ||||||||||||||||||||||||||||||
return SingleStreamDecoder::SeekMode::custom_frame_mappings; | ||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||
TORCH_CHECK(false, "Invalid seek mode: " + std::string(seekMode)); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -29,7 +29,7 @@ class SingleStreamDecoder { | |||||||
// CONSTRUCTION API | ||||||||
// -------------------------------------------------------------------------- | ||||||||
|
||||||||
enum class SeekMode { exact, approximate }; | ||||||||
enum class SeekMode { exact, approximate, custom_frame_mappings }; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know if we'll want to publicly expose a new There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. Right now, the torchcodec/src/torchcodec/_core/SingleStreamDecoder.cpp Lines 183 to 185 in d444567
Since the point of this feature is to avoid a file scan while still maintaining seek accuracy, I think it makes sense for it to be a new seek mode on the C++ side. We can figure out what to do with the public API later. |
||||||||
|
||||||||
// Creates a SingleStreamDecoder from the video at videoFilePath. | ||||||||
explicit SingleStreamDecoder( | ||||||||
|
@@ -53,20 +53,38 @@ class SingleStreamDecoder { | |||||||
// the allFrames and keyFrames vectors. | ||||||||
void scanFileAndUpdateMetadataAndIndex(); | ||||||||
|
||||||||
// Sorts the keyFrames and allFrames vectors in each StreamInfo by pts. | ||||||||
void sortAllFrames(); | ||||||||
|
||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just bumping #764 (comment) again, which may have been missed:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To elaborate on defining a new As a point of comparison, we do something similar with batched output. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the reference. I added |
||||||||
// Returns the metadata for the container. | ||||||||
ContainerMetadata getContainerMetadata() const; | ||||||||
|
||||||||
// Returns the key frame indices as a tensor. The tensor is 1D and contains | ||||||||
// int64 values, where each value is the frame index for a key frame. | ||||||||
torch::Tensor getKeyFrameIndices(); | ||||||||
|
||||||||
// FrameMappings is used for the custom_frame_mappings seek mode to store | ||||||||
// metadata of frames in a stream. The size of all tensors in this struct must | ||||||||
// match. | ||||||||
|
||||||||
// -------------------------------------------------------------------------- | ||||||||
// ADDING STREAMS API | ||||||||
// -------------------------------------------------------------------------- | ||||||||
struct FrameMappings { | ||||||||
// 1D tensor of int64, each value is the PTS of a frame in timebase units. | ||||||||
torch::Tensor all_frames; | ||||||||
// 1D tensor of bool, each value indicates if the corresponding frame in | ||||||||
// all_frames is a key frame. | ||||||||
torch::Tensor is_key_frame; | ||||||||
// 1D tensor of int64, each value is the duration of the corresponding frame | ||||||||
// in all_frames in timebase units. | ||||||||
torch::Tensor duration; | ||||||||
}; | ||||||||
|
||||||||
void addVideoStream( | ||||||||
int streamIndex, | ||||||||
const VideoStreamOptions& videoStreamOptions = VideoStreamOptions()); | ||||||||
const VideoStreamOptions& videoStreamOptions = VideoStreamOptions(), | ||||||||
std::optional<FrameMappings> customFrameMappings = std::nullopt); | ||||||||
void addAudioStream( | ||||||||
int streamIndex, | ||||||||
const AudioStreamOptions& audioStreamOptions = AudioStreamOptions()); | ||||||||
|
@@ -226,6 +244,13 @@ class SingleStreamDecoder { | |||||||
// -------------------------------------------------------------------------- | ||||||||
|
||||||||
void initializeDecoder(); | ||||||||
|
||||||||
// Reads the user provided frame index and updates each StreamInfo's index, | ||||||||
// i.e. the allFrames and keyFrames vectors, and | ||||||||
// endStreamPtsSecondsFromContent | ||||||||
void readCustomFrameMappingsUpdateMetadataAndIndex( | ||||||||
int streamIndex, | ||||||||
FrameMappings customFrameMappings); | ||||||||
// -------------------------------------------------------------------------- | ||||||||
// DECODING APIS AND RELATED UTILS | ||||||||
// -------------------------------------------------------------------------- | ||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add a small comment to explain what this does