Skip to content
Open
Show file tree
Hide file tree
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
33 changes: 22 additions & 11 deletions src/torchcodec/_core/BetaCudaDeviceInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -686,14 +686,14 @@ int BetaCudaDeviceInterface::stream_property_change(

// Moral equivalent of avcodec_send_packet(). Here, we pass the AVPacket down to
// the NVCUVID parser.
int BetaCudaDeviceInterface::send_packet(ReferenceAVPacket& packet) {
int BetaCudaDeviceInterface::send_packet(const AVPacket& packet) {
CudaContextGuard context_guard(device_.index());
if (decoding_on_cpu_) {
return cpu_interface_->send_packet(packet);
}

STD_TORCH_CHECK(
packet.get() && packet->data && packet->size > 0,
packet.data && packet.size > 0,
"sendPacket received an empty packet, this is unexpected, please report.");

// Apply BSF if needed. We want applyBSF to return a *new* filtered packet, or
Expand All @@ -703,15 +703,15 @@ int BetaCudaDeviceInterface::send_packet(ReferenceAVPacket& packet) {
// reference.
AutoAVPacket filtered_auto_packet;
ReferenceAVPacket filtered_packet(filtered_auto_packet);
ReferenceAVPacket& packet_to_send = apply_bsf(packet, filtered_packet);
const AVPacket& packet_to_send = apply_bsf(packet, filtered_packet);

CUVIDSOURCEDATAPACKET cuvid_packet = {};
cuvid_packet.payload = packet_to_send->data;
cuvid_packet.payload_size = packet_to_send->size;
cuvid_packet.payload = packet_to_send.data;
cuvid_packet.payload_size = packet_to_send.size;
cuvid_packet.flags = CUVID_PKT_TIMESTAMP;
cuvid_packet.timestamp = packet_to_send->pts;
cuvid_packet.timestamp = packet_to_send.pts;

if (packet_to_send->flags & AV_PKT_FLAG_DISCARD) {
if (packet_to_send.flags & AV_PKT_FLAG_DISCARD) {
discarded_timestamps_.insert(cuvid_packet.timestamp);
}

Expand All @@ -737,14 +737,25 @@ int BetaCudaDeviceInterface::send_cuvid_packet(
return result == CUDA_SUCCESS ? AVSUCCESS : AVERROR_EXTERNAL;
}

ReferenceAVPacket& BetaCudaDeviceInterface::apply_bsf(
ReferenceAVPacket& packet,
const AVPacket& BetaCudaDeviceInterface::apply_bsf(
const AVPacket& packet,
ReferenceAVPacket& filtered_packet) {
if (!bitstream_filter_) {
return packet;
}

int ret_val = av_bsf_send_packet(bitstream_filter_.get(), packet.get());
// av_bsf_send_packet() takes ownership of what it is given: it moves the
// reference out of the packet, leaving it empty. Our caller only lends us
// theirs, so send a reference of our own instead.
AutoAVPacket auto_input_packet;
ReferenceAVPacket input_packet(auto_input_packet);
int ret_val = av_packet_ref(input_packet.get(), &packet);
STD_TORCH_CHECK(
ret_val >= AVSUCCESS,
"Failed to reference packet for the bitstream filter: ",
get_ffmpeg_error_string_from_error_code(ret_val));

ret_val = av_bsf_send_packet(bitstream_filter_.get(), input_packet.get());
STD_TORCH_CHECK(
ret_val >= AVSUCCESS,
"Failed to send packet to bitstream filter: ",
Expand All @@ -761,7 +772,7 @@ ReferenceAVPacket& BetaCudaDeviceInterface::apply_bsf(
"Failed to receive packet from bitstream filter: ",
get_ffmpeg_error_string_from_error_code(ret_val));

return filtered_packet;
return *filtered_packet;
}

// Parser triggers this callback within cuvidParseVideoData when a frame is
Expand Down
6 changes: 3 additions & 3 deletions src/torchcodec/_core/BetaCudaDeviceInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class BetaCudaDeviceInterface : public DeviceInterface {
std::optional<torch::stable::Tensor> pre_allocated_output_tensor)
override;

int send_packet(ReferenceAVPacket& packet) override;
int send_packet(const AVPacket& packet) override;
int send_eof_packet() override;
int receive_frame(UniqueAVFrame& av_frame) override;
void flush() override;
Expand All @@ -99,8 +99,8 @@ class BetaCudaDeviceInterface : public DeviceInterface {
const UniqueDecodingAVFormatContext& av_format_ctx);
// Apply bitstream filter, returns filtered packet or original if no filter
// needed.
ReferenceAVPacket& apply_bsf(
ReferenceAVPacket& packet,
const AVPacket& apply_bsf(
const AVPacket& packet,
ReferenceAVPacket& filtered_packet);

CUdeviceptr previously_mapped_frame_ = 0;
Expand Down
6 changes: 4 additions & 2 deletions src/torchcodec/_core/DeviceInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,13 @@ class DeviceInterface {
// Returns AVSUCCESS on success, AVERROR(EAGAIN) if decoder queue full, or
// other AVERROR on failure
// Default implementation uses FFmpeg directly
virtual int send_packet(ReferenceAVPacket& av_packet) {
// The packet is borrowed: an implementation that hands it to something which
// takes ownership (a bitstream filter, say) must reference it first.
virtual int send_packet(const AVPacket& av_packet) {
STD_TORCH_CHECK(
codec_context_ != nullptr,
"Codec context not available for default packet sending");
return avcodec_send_packet(codec_context_.get(), av_packet.get());
return avcodec_send_packet(codec_context_.get(), &av_packet);
}

// Send an EOF packet to flush the decoder
Expand Down
13 changes: 2 additions & 11 deletions src/torchcodec/_core/PacketDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,8 @@ PacketDecoder::PacketDecoder(
stream, demuxer.format_context(), options);
}

int PacketDecoder::send_packet(AVPacket* packet) {
// The decode seam expects a ReferenceAVPacket. Copy a reference of the
// caller- owned packet into a temporary one (cheap, refcount bump); the
// temporary is unref'd on scope exit while the caller retains ownership of
// `packet`.
AutoAVPacket auto_packet;
ReferenceAVPacket ref(auto_packet);
int status = av_packet_ref(ref.get(), packet);
STD_TORCH_CHECK(status >= AVSUCCESS, "av_packet_ref failed");

status = device_interface_->send_packet(ref);
int PacketDecoder::send_packet(const AVPacket& packet) {
int status = device_interface_->send_packet(packet);

if (status == AVERROR_INVALIDDATA && packet_data_may_be_misaligned_) {
// Seeking in an MPEG program stream lands on a container-level byte offset,
Expand Down
2 changes: 1 addition & 1 deletion src/torchcodec/_core/PacketDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class FORCE_PUBLIC_VISIBILITY PacketDecoder {
std::optional<int> ffmpeg_thread_count = std::nullopt);

// Feed one packet to the decoder. Borrows `packet` (does not take ownership).
int send_packet(AVPacket* packet);
int send_packet(const AVPacket& packet);
// Signal end-of-stream so the decoder flushes its remaining frames.
int send_eof();
// Pull one frame. Returns AVSUCCESS with `av_frame` filled, AVERROR(EAGAIN)
Expand Down
2 changes: 1 addition & 1 deletion src/torchcodec/_core/SingleStreamDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1473,7 +1473,7 @@ UniqueAVFrame SingleStreamDecoder::decode_av_frame(

// We got a valid packet. Send it to the decoder, and we'll receive it in
// the next iteration.
status = device_interface_->send_packet(packet);
status = device_interface_->send_packet(*packet);

if (status == AVERROR_INVALIDDATA && packet_data_may_be_misaligned) {
// The MPEG-PS demuxer doesn't return proper packets just after a seek, so
Expand Down
5 changes: 2 additions & 3 deletions src/torchcodec/_core/custom_ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -963,9 +963,8 @@ int64_t _blocks_packet_decoder_send_packet(
torch::stable::Tensor& decoder,
torch::stable::Tensor& packet) {
PacketDecoder* decoder_ptr = unwrap_tensor_to_pointer<PacketDecoder>(decoder);
// TODO_API_BREAKDOWN CC P1: Do we really need this to be a raw AVPacket*?
AVPacket* raw_packet = unwrap_tensor_to_pointer<AVPacket>(packet);
return static_cast<int64_t>(decoder_ptr->send_packet(raw_packet));
return static_cast<int64_t>(
decoder_ptr->send_packet(*unwrap_tensor_to_pointer<AVPacket>(packet)));
}

int64_t _blocks_packet_decoder_send_eof(torch::stable::Tensor& decoder) {
Expand Down
Loading