@@ -198,6 +198,34 @@ SeekMode seekModeFromString(std::string_view seekMode) {
198198 }
199199}
200200
201+ void writeFallbackBasedMetadata (
202+ std::map<std::string, std::string>& map,
203+ const StreamMetadata& streamMetadata,
204+ SeekMode seekMode) {
205+ auto durationSeconds = streamMetadata.getDurationSeconds (seekMode);
206+ if (durationSeconds.has_value ()) {
207+ map[" durationSeconds" ] = std::to_string (durationSeconds.value ());
208+ }
209+
210+ auto numFrames = streamMetadata.getNumFrames (seekMode);
211+ if (numFrames.has_value ()) {
212+ map[" numFrames" ] = std::to_string (numFrames.value ());
213+ }
214+
215+ double beginStreamSeconds = streamMetadata.getBeginStreamSeconds (seekMode);
216+ map[" beginStreamSeconds" ] = std::to_string (beginStreamSeconds);
217+
218+ auto endStreamSeconds = streamMetadata.getEndStreamSeconds (seekMode);
219+ if (endStreamSeconds.has_value ()) {
220+ map[" endStreamSeconds" ] = std::to_string (endStreamSeconds.value ());
221+ }
222+
223+ auto averageFps = streamMetadata.getAverageFps (seekMode);
224+ if (averageFps.has_value ()) {
225+ map[" averageFps" ] = std::to_string (averageFps.value ());
226+ }
227+ }
228+
201229int checkedToPositiveInt (const std::string& str) {
202230 int ret = 0 ;
203231 try {
@@ -917,30 +945,28 @@ std::string get_stream_json_metadata(
917945 // In approximate mode: content-based metadata does not exist for any stream.
918946 // In custom_frame_mappings: content-based metadata exists only for the active
919947 // stream.
948+ //
920949 // Our fallback logic assumes content-based metadata is available.
921950 // It is available for decoding on the active stream, but would break
922951 // when getting metadata from non-active streams.
923952 if ((seekMode != SeekMode::custom_frame_mappings) ||
924953 (seekMode == SeekMode::custom_frame_mappings &&
925954 stream_index == activeStreamIndex)) {
926- if (streamMetadata.getDurationSeconds (seekMode).has_value ()) {
927- map[" durationSeconds" ] =
928- std::to_string (streamMetadata.getDurationSeconds (seekMode).value ());
929- }
930- if (streamMetadata.getNumFrames (seekMode).has_value ()) {
931- map[" numFrames" ] =
932- std::to_string (streamMetadata.getNumFrames (seekMode).value ());
933- }
934- map[" beginStreamSeconds" ] =
935- std::to_string (streamMetadata.getBeginStreamSeconds (seekMode));
936- if (streamMetadata.getEndStreamSeconds (seekMode).has_value ()) {
937- map[" endStreamSeconds" ] =
938- std::to_string (streamMetadata.getEndStreamSeconds (seekMode).value ());
939- }
940- if (streamMetadata.getAverageFps (seekMode).has_value ()) {
941- map[" averageFps" ] =
942- std::to_string (streamMetadata.getAverageFps (seekMode).value ());
943- }
955+ writeFallbackBasedMetadata (map, streamMetadata, seekMode);
956+ } else if (seekMode == SeekMode::custom_frame_mappings) {
957+ // If this is not the active stream, then we don't have content-based
958+ // metadata for custom frame mappings. In that case, we want the same
959+ // behavior as we would get with approximate mode. Encoding this behavior in
960+ // the fallback logic itself is tricky and not worth it for this corner
961+ // case. So we hardcode in approximate mode.
962+ //
963+ // TODO: This hacky behavior is only necessary because the custom frame
964+ // mapping is supplied in SingleStreamDecoder::addVideoStream() rather
965+ // than in the constructor. And it's supplied to addVideoStream() and
966+ // not the constructor because we need to know the stream index. If we
967+ // can encode the relevant stream indices into custom frame mappings
968+ // itself, then we can put it in the constructor.
969+ writeFallbackBasedMetadata (map, streamMetadata, SeekMode::approximate);
944970 }
945971
946972 return mapToJson (map);
0 commit comments