Class: TorchCodec::Decoders::VideoDecoder

Inherits:
Object
  • Object
show all
Defined in:
lib/torchcodec/decoders/video_decoder.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source, stream_index: nil, dimension_order: "NCHW", num_ffmpeg_threads: 1, device: nil, seek_mode: "exact", transforms: nil, custom_frame_mappings: nil) ⇒ VideoDecoder

Returns a new instance of VideoDecoder.



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/torchcodec/decoders/video_decoder.rb', line 6

def initialize(
  source,
  stream_index: nil,
  dimension_order: "NCHW",
  num_ffmpeg_threads: 1,
  device: nil,
  seek_mode: "exact",
  transforms: nil,
  custom_frame_mappings: nil
)
  allowed_seek_modes = ["exact", "approximate"]
  if !allowed_seek_modes.include?(seek_mode)
    raise ArgumentError, "Invalid seek mode (#{seek_mode})."
  end

  # Validate seek_mode and custom_frame_mappings are not mismatched
  if !custom_frame_mappings.nil? && seek_mode == "approximate"
    raise ArgumentError,
      "custom_frame_mappings is incompatible with seek_mode: 'approximate'. " +
      "Use seek_mode: 'custom_frame_mappings' or leave it unspecified to automatically use custom frame mappings."
  end

  # Auto-select custom_frame_mappings seek_mode and process data when mappings are provided
  custom_frame_mappings_data = nil
  if !custom_frame_mappings.nil?
    raise Todo
  end

  @decoder = Decoders.create_decoder(source, seek_mode)

  (
    @metadata,
    @stream_index,
    @begin_stream_seconds,
    @end_stream_seconds,
    @num_frames
  ) = (
    decoder: @decoder, stream_index: stream_index
  )

  allowed_dimension_orders = ["NCHW", "NHWC"]
  if !allowed_dimension_orders.include?(dimension_order)
    raise ArgumentError, "Invalid dimension order (#{dimension_order})."
  end

  if num_ffmpeg_threads.nil?
    raise ArgumentError, "#{num_ffmpeg_threads} should be an int."
  end

  if device.nil?
    device = "cpu" # TODO Torch.get_default_device.to_s
  elsif device.is_a?(Torch::Device)
    device = device.to_s
  end

  device_variant = Decoders._get_cuda_backend
  transform_specs = Transforms._make_transform_specs(
    transforms,
    [@metadata[:height], @metadata[:width]]
  )

  Core.add_video_stream(
    @decoder,
    num_ffmpeg_threads,
    dimension_order,
    @stream_index,
    device,
    device_variant,
    transform_specs,
    custom_frame_mappings_data
  )
end

Instance Attribute Details

#metadataObject (readonly)

Returns the value of attribute metadata.



4
5
6
# File 'lib/torchcodec/decoders/video_decoder.rb', line 4

def 
  @metadata
end

Instance Method Details

#get_frame_at(index) ⇒ Object



79
80
81
82
83
84
85
86
# File 'lib/torchcodec/decoders/video_decoder.rb', line 79

def get_frame_at(index)
  data, pts_seconds, duration_seconds = Core.get_frame_at_index(@decoder, index)
  {
    data: data,
    pts_seconds: pts_seconds.item,
    duration_seconds: duration_seconds.item
  }
end

#get_frame_played_at(seconds) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/torchcodec/decoders/video_decoder.rb', line 112

def get_frame_played_at(seconds)
  if !(@begin_stream_seconds <= seconds && seconds < @end_stream_seconds)
    raise IndexError, "Invalid pts in seconds: #{seconds}."
  end
  data, pts_seconds, duration_seconds = Core.get_frame_at_pts(
    @decoder, seconds
  )
  {
    data: data,
    pts_seconds: pts_seconds.item,
    duration_seconds: duration_seconds.item
  }
end

#get_frames_at(indices) ⇒ Object



88
89
90
91
92
93
94
95
96
# File 'lib/torchcodec/decoders/video_decoder.rb', line 88

def get_frames_at(indices)
  data, pts_seconds, duration_seconds = Core.get_frames_at_indices(@decoder, indices)

  {
    data: data,
    pts_seconds: pts_seconds,
    duration_seconds: duration_seconds
  }
end

#get_frames_in_range(start, stop, step: 1) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/torchcodec/decoders/video_decoder.rb', line 98

def get_frames_in_range(start, stop, step: 1)
  frames = Core.get_frames_in_range(
    @decoder,
    start,
    stop,
    step
  )
  {
    data: frames[0],
    pts_seconds: frames[1],
    duration_seconds: frames[2]
  }
end

#get_frames_played_at(seconds) ⇒ Object



126
127
128
129
130
131
132
133
134
135
# File 'lib/torchcodec/decoders/video_decoder.rb', line 126

def get_frames_played_at(seconds)
  data, pts_seconds, duration_seconds = Core.get_frames_by_pts(
    @decoder, seconds
  )
  {
    data: data,
    pts_seconds: pts_seconds,
    duration_seconds: duration_seconds
  }
end

#get_frames_played_in_range(start_seconds, stop_seconds) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/torchcodec/decoders/video_decoder.rb', line 137

def get_frames_played_in_range(start_seconds, stop_seconds)
  if !(start_seconds <= stop_seconds)
    raise ArgumentError, "Invalid start seconds: #{start_seconds}. It must be less than or equal to stop seconds (#{stop_seconds})."
  end
  if !(@begin_stream_seconds <= start_seconds && start_seconds < @end_stream_seconds)
    raise ArgumentError, "Invalid start seconds: #{start_seconds}."
  end
  if !(stop_seconds <= @end_stream_seconds)
    raise ArgumentError, "Invalid stop seconds: #{stop_seconds}."
  end
  frames = Core.get_frames_by_pts_in_range(
    @decoder,
    start_seconds,
    stop_seconds
  )

  {
    data: frames[0],
    pts_seconds: frames[1],
    duration_seconds: frames[2]
  }
end