Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 49 additions & 52 deletions src/torchcodec/decoders/_core/VideoDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ VideoDecoder::VideoDecoder(const std::string& videoFilePath, SeekMode seekMode)
av_log_set_level(AV_LOG_QUIET);

AVFormatContext* rawContext = nullptr;
int ffmpegStatus =
int status =
avformat_open_input(&rawContext, videoFilePath.c_str(), nullptr, nullptr);
TORCH_CHECK(
ffmpegStatus == 0,
status == 0,
"Could not open input file: " + videoFilePath + " " +
getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
getFFMPEGErrorStringFromErrorCode(status));
TORCH_CHECK(rawContext != nullptr);
formatContext_.reset(rawContext);

Expand All @@ -97,14 +97,13 @@ VideoDecoder::VideoDecoder(const void* data, size_t length, SeekMode seekMode)
TORCH_CHECK(rawContext != nullptr, "Unable to alloc avformat context");

rawContext->pb = ioBytesContext_->getAVIO();
int ffmpegStatus =
avformat_open_input(&rawContext, nullptr, nullptr, nullptr);
if (ffmpegStatus != 0) {
int status = avformat_open_input(&rawContext, nullptr, nullptr, nullptr);
if (status != 0) {
avformat_free_context(rawContext);
TORCH_CHECK(
false,
"Failed to open input buffer: " +
getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
getFFMPEGErrorStringFromErrorCode(status));
}

formatContext_.reset(rawContext);
Expand Down Expand Up @@ -132,11 +131,11 @@ void VideoDecoder::initializeDecoder() {
// store enough info in the header, so we call avformat_find_stream_info()
// which decodes a few frames to get missing info. For more, see:
// https://ffmpeg.org/doxygen/7.0/group__lavf__decoding.html
int ffmpegStatus = avformat_find_stream_info(formatContext_.get(), nullptr);
if (ffmpegStatus < 0) {
int status = avformat_find_stream_info(formatContext_.get(), nullptr);
if (status < 0) {
throw std::runtime_error(
"Failed to find stream info: " +
getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
getFFMPEGErrorStringFromErrorCode(status));
}

for (unsigned int i = 0; i < formatContext_->nb_streams; i++) {
Expand Down Expand Up @@ -231,16 +230,16 @@ void VideoDecoder::scanFileAndUpdateMetadataAndIndex() {
ReferenceAVPacket packet(autoAVPacket);

// av_read_frame is a misleading name: it gets the next **packet**.
int ffmpegStatus = av_read_frame(formatContext_.get(), packet.get());
int status = av_read_frame(formatContext_.get(), packet.get());

if (ffmpegStatus == AVERROR_EOF) {
if (status == AVERROR_EOF) {
break;
}

if (ffmpegStatus != AVSUCCESS) {
if (status != AVSUCCESS) {
throw std::runtime_error(
"Failed to read frame from input file: " +
getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
getFFMPEGErrorStringFromErrorCode(status));
}

if (packet->flags & AV_PKT_FLAG_DISCARD) {
Expand Down Expand Up @@ -923,23 +922,23 @@ VideoDecoder::AVFrameStream VideoDecoder::decodeAVFrame(
// Need to get the next frame or error from PopFrame.
UniqueAVFrame avFrame(av_frame_alloc());
AutoAVPacket autoAVPacket;
int ffmpegStatus = AVSUCCESS;
int status = AVSUCCESS;
bool reachedEOF = false;
while (true) {
ffmpegStatus =
status =
avcodec_receive_frame(streamInfo.codecContext.get(), avFrame.get());

if (ffmpegStatus != AVSUCCESS && ffmpegStatus != AVERROR(EAGAIN)) {
if (status != AVSUCCESS && status != AVERROR(EAGAIN)) {
// Non-retriable error
break;
}

decodeStats_.numFramesReceivedByDecoder++;
// Is this the kind of frame we're looking for?
if (ffmpegStatus == AVSUCCESS && filterFunction(avFrame.get())) {
if (status == AVSUCCESS && filterFunction(avFrame.get())) {
// Yes, this is the frame we'll return; break out of the decoding loop.
break;
} else if (ffmpegStatus == AVSUCCESS) {
} else if (status == AVSUCCESS) {
// No, but we received a valid frame - just not the kind we're looking
// for. The logic below will read packets and send them to the decoder.
// But since we did just receive a frame, we should skip reading more
Expand All @@ -958,29 +957,29 @@ VideoDecoder::AVFrameStream VideoDecoder::decodeAVFrame(
// packets and send them to the decoder.
ReferenceAVPacket packet(autoAVPacket);
do {
ffmpegStatus = av_read_frame(formatContext_.get(), packet.get());
status = av_read_frame(formatContext_.get(), packet.get());
decodeStats_.numPacketsRead++;

if (ffmpegStatus == AVERROR_EOF) {
if (status == AVERROR_EOF) {
// End of file reached. We must drain the codec by sending a nullptr
// packet.
ffmpegStatus = avcodec_send_packet(
status = avcodec_send_packet(
streamInfo.codecContext.get(),
/*avpkt=*/nullptr);
if (ffmpegStatus < AVSUCCESS) {
if (status < AVSUCCESS) {
throw std::runtime_error(
"Could not flush decoder: " +
getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
getFFMPEGErrorStringFromErrorCode(status));
}

reachedEOF = true;
break;
}

if (ffmpegStatus < AVSUCCESS) {
if (status < AVSUCCESS) {
throw std::runtime_error(
"Could not read frame from input file: " +
getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
getFFMPEGErrorStringFromErrorCode(status));
}
} while (packet->stream_index != activeStreamIndex_);

Expand All @@ -992,26 +991,25 @@ VideoDecoder::AVFrameStream VideoDecoder::decodeAVFrame(

// We got a valid packet. Send it to the decoder, and we'll receive it in
// the next iteration.
ffmpegStatus =
avcodec_send_packet(streamInfo.codecContext.get(), packet.get());
if (ffmpegStatus < AVSUCCESS) {
status = avcodec_send_packet(streamInfo.codecContext.get(), packet.get());
if (status < AVSUCCESS) {
throw std::runtime_error(
"Could not push packet to decoder: " +
getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
getFFMPEGErrorStringFromErrorCode(status));
}

decodeStats_.numPacketsSentToDecoder++;
}

if (ffmpegStatus < AVSUCCESS) {
if (reachedEOF || ffmpegStatus == AVERROR_EOF) {
if (status < AVSUCCESS) {
if (reachedEOF || status == AVERROR_EOF) {
throw VideoDecoder::EndOfFileException(
"Requested next frame while there are no more frames left to "
"decode.");
}
throw std::runtime_error(
"Could not receive frame from decoder: " +
getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
getFFMPEGErrorStringFromErrorCode(status));
}

// Note that we don't flush the decoder when we reach EOF (even though that's
Expand Down Expand Up @@ -1197,14 +1195,14 @@ torch::Tensor VideoDecoder::convertAVFrameToTensorUsingFilterGraph(
const AVFrame* avFrame) {
FilterGraphContext& filterGraphContext =
streamInfos_[activeStreamIndex_].filterGraphContext;
int ffmpegStatus =
int status =
av_buffersrc_write_frame(filterGraphContext.sourceContext, avFrame);
if (ffmpegStatus < AVSUCCESS) {
if (status < AVSUCCESS) {
throw std::runtime_error("Failed to add frame to buffer source context");
}

UniqueAVFrame filteredAVFrame(av_frame_alloc());
ffmpegStatus = av_buffersink_get_frame(
status = av_buffersink_get_frame(
filterGraphContext.sinkContext, filteredAVFrame.get());
TORCH_CHECK_EQ(filteredAVFrame->format, AV_PIX_FMT_RGB24);

Expand Down Expand Up @@ -1328,44 +1326,44 @@ void VideoDecoder::createFilterGraph(
filterArgs << ":pixel_aspect=" << codecContext->sample_aspect_ratio.num << "/"
<< codecContext->sample_aspect_ratio.den;

int ffmpegStatus = avfilter_graph_create_filter(
int status = avfilter_graph_create_filter(
&filterGraphContext.sourceContext,
buffersrc,
"in",
filterArgs.str().c_str(),
nullptr,
filterGraphContext.filterGraph.get());
if (ffmpegStatus < 0) {
if (status < 0) {
throw std::runtime_error(
std::string("Failed to create filter graph: ") + filterArgs.str() +
": " + getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
": " + getFFMPEGErrorStringFromErrorCode(status));
}

ffmpegStatus = avfilter_graph_create_filter(
status = avfilter_graph_create_filter(
&filterGraphContext.sinkContext,
buffersink,
"out",
nullptr,
nullptr,
filterGraphContext.filterGraph.get());
if (ffmpegStatus < 0) {
if (status < 0) {
throw std::runtime_error(
"Failed to create filter graph: " +
getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
getFFMPEGErrorStringFromErrorCode(status));
}

enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE};

ffmpegStatus = av_opt_set_int_list(
status = av_opt_set_int_list(
filterGraphContext.sinkContext,
"pix_fmts",
pix_fmts,
AV_PIX_FMT_NONE,
AV_OPT_SEARCH_CHILDREN);
if (ffmpegStatus < 0) {
if (status < 0) {
throw std::runtime_error(
"Failed to set output pixel formats: " +
getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
getFFMPEGErrorStringFromErrorCode(status));
}

UniqueAVFilterInOut outputs(avfilter_inout_alloc());
Expand All @@ -1386,26 +1384,25 @@ void VideoDecoder::createFilterGraph(

AVFilterInOut* outputsTmp = outputs.release();
AVFilterInOut* inputsTmp = inputs.release();
ffmpegStatus = avfilter_graph_parse_ptr(
status = avfilter_graph_parse_ptr(
filterGraphContext.filterGraph.get(),
description.str().c_str(),
&inputsTmp,
&outputsTmp,
nullptr);
outputs.reset(outputsTmp);
inputs.reset(inputsTmp);
if (ffmpegStatus < 0) {
if (status < 0) {
throw std::runtime_error(
"Failed to parse filter description: " +
getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
getFFMPEGErrorStringFromErrorCode(status));
}

ffmpegStatus =
avfilter_graph_config(filterGraphContext.filterGraph.get(), nullptr);
if (ffmpegStatus < 0) {
status = avfilter_graph_config(filterGraphContext.filterGraph.get(), nullptr);
if (status < 0) {
throw std::runtime_error(
"Failed to configure filter graph: " +
getFFMPEGErrorStringFromErrorCode(ffmpegStatus));
getFFMPEGErrorStringFromErrorCode(status));
}
}

Expand Down
Loading