aboutsummaryrefslogtreecommitdiffstats
path: root/src/video/decoder.zig
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2025-03-10 14:52:42 +0000
committers-ol <s+removethis@s-ol.nu>2025-03-10 14:52:42 +0000
commit3df8ced3f0895289506565fbd42c530ba3871e82 (patch)
tree97cf711e3182a574fc5518a660e663055fbb94da /src/video/decoder.zig
parentupdate for Zig 0.14.0 (diff)
downloadglsl-view-3df8ced3f0895289506565fbd42c530ba3871e82.tar.gz
glsl-view-3df8ced3f0895289506565fbd42c530ba3871e82.zip
fix conditional compilation
Diffstat (limited to 'src/video/decoder.zig')
-rw-r--r--src/video/decoder.zig93
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);
+ }
+};