Skip to content

Commit 678d4eb

Browse files
author
pytorchbot
committed
2025-02-08 nightly release (a85907b)
1 parent 5be07b0 commit 678d4eb

File tree

1 file changed

+48
-25
lines changed

1 file changed

+48
-25
lines changed

src/torchcodec/decoders/_core/VideoDecoder.cpp

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ extern "C" {
2020
#include <libavfilter/buffersrc.h>
2121
#include <libavformat/avformat.h>
2222
#include <libavutil/imgutils.h>
23+
#include <libavutil/log.h>
2324
#include <libavutil/pixdesc.h>
2425
#include <libswscale/swscale.h>
2526
}
@@ -69,6 +70,8 @@ std::vector<std::string> splitStringWithDelimiters(
6970

7071
VideoDecoder::VideoDecoder(const std::string& videoFilePath, SeekMode seekMode)
7172
: seekMode_(seekMode) {
73+
av_log_set_level(AV_LOG_QUIET);
74+
7275
AVFormatContext* formatContext = nullptr;
7376
int open_ret = avformat_open_input(
7477
&formatContext, videoFilePath.c_str(), nullptr, nullptr);
@@ -89,6 +92,8 @@ VideoDecoder::VideoDecoder(const void* buffer, size_t length, SeekMode seekMode)
8992
: seekMode_(seekMode) {
9093
TORCH_CHECK(buffer != nullptr, "Video buffer cannot be nullptr!");
9194

95+
av_log_set_level(AV_LOG_QUIET);
96+
9297
AVInput input;
9398
input.formatContext.reset(avformat_alloc_context());
9499
TORCH_CHECK(
@@ -222,6 +227,13 @@ void VideoDecoder::scanFileAndUpdateMetadataAndIndex() {
222227
return;
223228
}
224229

230+
for (unsigned int i = 0; i < formatContext_->nb_streams; ++i) {
231+
// We want to scan and update the metadata of all streams.
232+
TORCH_CHECK(
233+
formatContext_->streams[i]->discard != AVDISCARD_ALL,
234+
"Did you add a stream before you called for a scan?");
235+
}
236+
225237
AutoAVPacket autoAVPacket;
226238
while (true) {
227239
ReferenceAVPacket packet(autoAVPacket);
@@ -481,6 +493,16 @@ void VideoDecoder::addVideoStreamDecoder(
481493
updateMetadataWithCodecContext(streamInfo.streamIndex, codecContext);
482494
streamInfo.videoStreamOptions = videoStreamOptions;
483495

496+
// We will only need packets from the active stream, so we tell FFmpeg to
497+
// discard packets from the other streams. Note that av_read_frame() may still
498+
// return some of those un-desired packet under some conditions, so it's still
499+
// important to discard/demux correctly in the inner decoding loop.
500+
for (unsigned int i = 0; i < formatContext_->nb_streams; ++i) {
501+
if (i != static_cast<unsigned int>(activeStreamIndex_)) {
502+
formatContext_->streams[i]->discard = AVDISCARD_ALL;
503+
}
504+
}
505+
484506
// By default, we want to use swscale for color conversion because it is
485507
// faster. However, it has width requirements, so we may need to fall back
486508
// to filtergraph. We also need to respect what was requested from the
@@ -971,43 +993,44 @@ VideoDecoder::AVFrameStream VideoDecoder::decodeAVFrame(
971993
}
972994

973995
if (reachedEOF) {
974-
// We don't have any more packets to send to the decoder. So keep on
975-
// pulling frames from its internal buffers.
996+
// We don't have any more packets to receive. So keep on pulling frames
997+
// from its internal buffers.
976998
continue;
977999
}
9781000

9791001
// We still haven't found the frame we're looking for. So let's read more
9801002
// packets and send them to the decoder.
9811003
ReferenceAVPacket packet(autoAVPacket);
982-
ffmpegStatus = av_read_frame(formatContext_.get(), packet.get());
983-
decodeStats_.numPacketsRead++;
1004+
do {
1005+
ffmpegStatus = av_read_frame(formatContext_.get(), packet.get());
1006+
decodeStats_.numPacketsRead++;
1007+
1008+
if (ffmpegStatus == AVERROR_EOF) {
1009+
// End of file reached. We must drain the codec by sending a nullptr
1010+
// packet.
1011+
ffmpegStatus = avcodec_send_packet(
1012+
streamInfo.codecContext.get(),
1013+
/*avpkt=*/nullptr);
1014+
if (ffmpegStatus < AVSUCCESS) {
1015+
throw std::runtime_error(
1016+
"Could not flush decoder: " +
1017+
getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
1018+
}
1019+
1020+
reachedEOF = true;
1021+
break;
1022+
}
9841023

985-
if (ffmpegStatus == AVERROR_EOF) {
986-
// End of file reached. We must drain the codec by sending a nullptr
987-
// packet.
988-
ffmpegStatus = avcodec_send_packet(
989-
streamInfo.codecContext.get(),
990-
/*avpkt=*/nullptr);
9911024
if (ffmpegStatus < AVSUCCESS) {
9921025
throw std::runtime_error(
993-
"Could not flush decoder: " +
1026+
"Could not read frame from input file: " +
9941027
getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
9951028
}
1029+
} while (packet->stream_index != activeStreamIndex_);
9961030

997-
// We've reached the end of file so we can't read any more packets from
998-
// it, but the decoder may still have frames to read in its buffer.
999-
// Continue iterating to try reading frames.
1000-
reachedEOF = true;
1001-
continue;
1002-
}
1003-
1004-
if (ffmpegStatus < AVSUCCESS) {
1005-
throw std::runtime_error(
1006-
"Could not read frame from input file: " +
1007-
getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
1008-
}
1009-
1010-
if (packet->stream_index != activeStreamIndex_) {
1031+
if (reachedEOF) {
1032+
// We don't have any more packets to send to the decoder. So keep on
1033+
// pulling frames from its internal buffers.
10111034
continue;
10121035
}
10131036

0 commit comments

Comments
 (0)