diff options
| author | s-ol <s+removethis@s-ol.nu> | 2025-03-10 14:52:42 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2025-03-10 14:52:42 +0000 |
| commit | 3df8ced3f0895289506565fbd42c530ba3871e82 (patch) | |
| tree | 97cf711e3182a574fc5518a660e663055fbb94da /src/video/decoder.zig | |
| parent | update for Zig 0.14.0 (diff) | |
| download | glsl-view-3df8ced3f0895289506565fbd42c530ba3871e82.tar.gz glsl-view-3df8ced3f0895289506565fbd42c530ba3871e82.zip | |
fix conditional compilation
Diffstat (limited to 'src/video/decoder.zig')
| -rw-r--r-- | src/video/decoder.zig | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/src/video/decoder.zig b/src/video/decoder.zig new file mode 100644 index 0000000..4c78374 --- /dev/null +++ b/src/video/decoder.zig @@ -0,0 +1,93 @@ +const std = @import("std"); +const c = @import("../c.zig"); +const gl = @import("../gl.zig"); + +pub const Errors = error{ + AVGenericError, + AVAllocationError, + HAPBadArguments, + HAPBufferTooSmall, + HAPBadFrame, + HAPInternalError, + UnsupportedCodec, + OutOfMemory, + NoFrames, +}; + +pub fn check(err: c_int) Errors!void { + if (err >= 0) return; + var buf: [c.AV_ERROR_MAX_STRING_SIZE]u8 = undefined; + _ = c.av_make_error_string(&buf, buf.len, err); + std.debug.print("libav error: {s}\n", .{buf}); + return error.AVGenericError; +} + +pub const Decoder = struct { + num_frames: i32, + + process_packet_fn: *const fn (self: *Decoder, packet: *c.AVPacket, texture: ?*const gl.Texture) Errors!bool, + init_texture_fn: *const fn (self: *Decoder, texture: *const gl.Texture) void, + reset_fn: ?*const fn (self: *Decoder) void, + deinit_fn: *const fn (self: *Decoder, allocator: std.mem.Allocator) void, + + fn processStream( + self: *Decoder, + progress: std.Progress.Node, + format: *c.AVFormatContext, + stream: *c.AVStream, + texture: ?*const gl.Texture, + ) Errors!void { + defer progress.end(); + + try check(c.avformat_seek_file(format, stream.index, 0, 0, 0, 0)); + if (self.reset_fn) |reset_fn| reset_fn(self); + + var packet = c.av_packet_alloc(); + defer c.av_packet_free(&packet); + + self.num_frames = 0; + var res = c.av_read_frame(format, packet); + while (res >= 0) : (res = c.av_read_frame(format, packet)) { + if (packet.*.stream_index == stream.index) { + const more = try self.process_packet_fn(self, packet, texture); + progress.setCompletedItems(@intCast(self.num_frames)); + if (!more) break; + } + c.av_packet_unref(packet); + } else { + if (res != c.AVERROR_EOF) try check(res); + } + } + + pub fn createTexture( + self: *Decoder, + outer_progress: std.Progress.Node, + format: *c.AVFormatContext, + stream: *c.AVStream, + texture_type: gl.Texture.Type, + ) Errors!gl.Texture { + try self.processStream( + outer_progress.start("scanning video frames", @intCast(stream.nb_frames)), + format, + stream, + null, + ); + if (self.num_frames <= 0) return error.NoFrames; + + const texture = gl.Texture.create(texture_type); + errdefer texture.destroy(); + + self.init_texture_fn(self, &texture); + try self.processStream( + outer_progress.start("loading video frames", @intCast(self.num_frames)), + format, + stream, + &texture, + ); + return texture; + } + + pub fn deinit(self: *Decoder, allocator: std.mem.Allocator) void { + self.deinit_fn(self, allocator); + } +}; |
