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 | |
| parent | update for Zig 0.14.0 (diff) | |
| download | glsl-view-3df8ced3f0895289506565fbd42c530ba3871e82.tar.gz glsl-view-3df8ced3f0895289506565fbd42c530ba3871e82.zip | |
fix conditional compilation
| -rw-r--r-- | src/control.zig | 2 | ||||
| -rw-r--r-- | src/video.zig | 348 | ||||
| -rw-r--r-- | src/video/decoder.zig | 93 | ||||
| -rw-r--r-- | src/video/ffmpeg.zig | 126 | ||||
| -rw-r--r-- | src/video/hap.zig | 125 |
5 files changed, 357 insertions, 337 deletions
diff --git a/src/control.zig b/src/control.zig index dfdd55d..0ea6712 100644 --- a/src/control.zig +++ b/src/control.zig @@ -3,7 +3,6 @@ const gl = @import("gl.zig"); const video = @import("video.zig"); const std = @import("std"); const cfg = @import("config.zig"); -const build_config = @import("build_config"); fn verify_args(expected: u8, got: []const u8) !void { for (got) |typ| { @@ -96,7 +95,6 @@ fn set_texture( argv: [*c][*c]c.lo_arg, types: []const u8, ) !void { - if (!build_config.have_ffmpeg) return error.texturesDisabled; if (argc != 1 or types[0] != 's') return error.invalidType; if (dest.*) |old| { diff --git a/src/video.zig b/src/video.zig index 98772b6..9cf50eb 100644 --- a/src/video.zig +++ b/src/video.zig @@ -1,338 +1,16 @@ const std = @import("std"); const c = @import("c.zig"); const gl = @import("gl.zig"); +const build_config = @import("build_config"); +const dec = @import("video/decoder.zig"); +const ffmpeg = if (build_config.have_ffmpeg) @import("video/ffmpeg.zig") else unreachable; +const hap = if (build_config.have_hap) @import("video/hap.zig") else unreachable; -pub const Errors = error{ - AVGenericError, - AVAllocationError, - HAPBadArguments, - HAPBufferTooSmall, - HAPBadFrame, - HAPInternalError, - UnsupportedCodec, - OutOfMemory, - NoFrames, -}; - -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; -} - -fn hapCheck(err: c_uint) Errors!void { - return switch (err) { - c.HapResult_No_Error => return, - c.HapResult_Bad_Arguments => return error.HAPBadArguments, - c.HapResult_Buffer_Too_Small => return error.HAPBufferTooSmall, - c.HapResult_Bad_Frame => return error.HAPBadFrame, - c.HapResult_Internal_Error => return error.HAPInternalError, - else => unreachable, - }; -} - -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); - } -}; - -const AVDecoder = struct { - decoder: Decoder, - - sws_ctx: *c.SwsContext, - codec_par: c.AVCodecParameters, - codec_ctx: [*c]c.AVCodecContext, - - raw_frame: [*c]c.AVFrame, - rgba_frame: [*c]c.AVFrame, - - pub fn init(allocator: std.mem.Allocator, codec_par: c.AVCodecParameters) Errors!*Decoder { - const self = try allocator.create(AVDecoder); - errdefer allocator.destroy(self); - - const codec = c.avcodec_find_decoder(codec_par.codec_id) orelse return error.UnsupportedCodec; - - var codec_ctx = c.avcodec_alloc_context3(codec) orelse return error.AVAllocationError; - errdefer c.avcodec_free_context(&codec_ctx); - var raw_frame = c.av_frame_alloc() orelse return error.AVAllocationError; - errdefer c.av_frame_free(&raw_frame); - var rgba_frame = c.av_frame_alloc() orelse return error.AVAllocationError; - errdefer c.av_frame_free(&rgba_frame); - - try check(c.avcodec_parameters_to_context(codec_ctx, &codec_par)); - try check(c.avcodec_open2(codec_ctx, codec, null)); - errdefer check(c.avcodec_close(codec_ctx)) catch unreachable; - - const sws_ctx = c.sws_getContext( - codec_par.width, - codec_par.height, - codec_par.format, - codec_par.width, - codec_par.height, - c.AV_PIX_FMT_RGBA, - c.SWS_POINT, - null, - null, - 0, - ) orelse return error.AVGenericError; - errdefer c.sws_freeContext(sws_ctx); - - self.* = .{ - .decoder = .{ - .process_packet_fn = processPacket, - .init_texture_fn = initTexture, - .reset_fn = reset, - .deinit_fn = deinit, - .num_frames = 0, - }, - .sws_ctx = sws_ctx, - .codec_par = codec_par, - .codec_ctx = codec_ctx, - .raw_frame = raw_frame, - .rgba_frame = rgba_frame, - }; - return &self.decoder; - } - - pub fn deinit(decoder: *Decoder, allocator: std.mem.Allocator) void { - const self: *AVDecoder = @fieldParentPtr("decoder", decoder); - - const raw_ptr: [*c][*c]c.AVFrame = &self.raw_frame; - const rgba_ptr: [*c][*c]c.AVFrame = &self.rgba_frame; - c.av_frame_free(raw_ptr); - c.av_frame_free(rgba_ptr); - - c.sws_freeContext(self.sws_ctx); - check(c.avcodec_close(self.codec_ctx)) catch unreachable; - c.avcodec_free_context(&self.codec_ctx); - - allocator.destroy(self); - } - - pub fn reset(decoder: *Decoder) void { - const self: *AVDecoder = @fieldParentPtr("decoder", decoder); - c.avcodec_flush_buffers(self.codec_ctx); - } - - pub fn initTexture(decoder: *Decoder, texture: *const gl.Texture) void { - const self: *AVDecoder = @fieldParentPtr("decoder", decoder); - - texture.allocate( - self.codec_par.width, - self.codec_par.height, - self.decoder.num_frames, - c.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, - ); - } - - pub fn processPacket(decoder: *Decoder, packet: *c.AVPacket, texture: ?*const gl.Texture) Errors!bool { - const self: *AVDecoder = @fieldParentPtr("decoder", decoder); - - try check(c.avcodec_send_packet(self.codec_ctx, packet)); - while (true) { - const ires = c.avcodec_receive_frame(self.codec_ctx, self.raw_frame); - if (ires == c.AVERROR_EOF) return false; - if (ires == c.AVERROR(c.EAGAIN)) return true; - try check(ires); - try check(c.sws_scale_frame(self.sws_ctx, self.rgba_frame, self.raw_frame)); - - c.glPixelStorei(c.GL_UNPACK_ROW_LENGTH, @divFloor(self.rgba_frame.*.linesize[0], @sizeOf(u8) * 4)); - - if (texture) |tex| { - tex.setLayer( - self.rgba_frame.*.width, - self.rgba_frame.*.height, - self.decoder.num_frames, - c.GL_RGBA, - self.rgba_frame.*.data[0], - ); - - if (tex.type == .TEXTURE_2D) return false; - } - - self.decoder.num_frames += 1; - } - } -}; - -const HAPDecoder = struct { - decoder: Decoder, - - codec_par: c.AVCodecParameters, - format: ?c.HapTextureFormat, - gl_format: c.GLenum, - - pub fn init(allocator: std.mem.Allocator, codec_par: c.AVCodecParameters) Errors!*Decoder { - const self = try allocator.create(HAPDecoder); - - self.* = .{ - .decoder = .{ - .process_packet_fn = processPacket, - .init_texture_fn = initTexture, - .reset_fn = null, - .deinit_fn = deinit, - .num_frames = 0, - }, - .codec_par = codec_par, - .format = null, - .gl_format = undefined, - }; - return &self.decoder; - } - - pub fn deinit(decoder: *Decoder, allocator: std.mem.Allocator) void { - const self: *HAPDecoder = @fieldParentPtr("decoder", decoder); - allocator.destroy(self); - } - - pub fn initTexture(decoder: *Decoder, texture: *const gl.Texture) void { - const self: *HAPDecoder = @fieldParentPtr("decoder", decoder); - - texture.allocate( - self.codec_par.width, - self.codec_par.height, - self.decoder.num_frames, - self.gl_format, - ); - } - - fn launchThread(workfn: c.HapDecodeWorkFunction, p: ?*anyopaque, count: c_uint, info: ?*anyopaque) callconv(.C) void { - _ = info; - - var i: c_uint = 0; - while (i < count) : (i += 1) { - workfn.?(p, i); - } - } - - pub fn processPacket(decoder: *Decoder, packet: *c.AVPacket, texture: ?*const gl.Texture) Errors!bool { - const self: *HAPDecoder = @fieldParentPtr("decoder", decoder); - - var textureCount: u32 = undefined; - try hapCheck(c.HapGetFrameTextureCount(packet.data, @intCast(packet.size), &textureCount)); - if (textureCount != 1) { - return error.UnsupportedCodec; - } - - var format: c.HapTextureFormat = undefined; - - if (texture) |tex| { - var buffer: [16 * 1024 * 1024]u8 = undefined; - var length: c_ulong = undefined; - try hapCheck(c.HapDecode( - packet.data, - @intCast(packet.size), - 0, - launchThread, - self, - &buffer, - buffer.len, - &length, - &format, - )); - - tex.setLayerCompressed( - self.codec_par.width, - self.codec_par.height, - self.decoder.num_frames, - self.gl_format, - buffer[0..length], - ); - - if (tex.type == .TEXTURE_2D) return false; - } else { - try hapCheck(c.HapGetFrameTextureFormat(packet.data, @intCast(packet.size), 0, &format)); - if (self.format) |fmt| { - if (fmt != format) return error.UnsupportedCodec; - } else { - self.format = format; - self.gl_format = switch (format) { - c.HapTextureFormat_RGB_DXT1 => c.GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - c.HapTextureFormat_RGBA_DXT5 => c.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, - c.HapTextureFormat_YCoCg_DXT5, - c.HapTextureFormat_A_RGTC1, - c.HapTextureFormat_RGBA_BPTC_UNORM, - c.HapTextureFormat_RGB_BPTC_UNSIGNED_FLOAT, - c.HapTextureFormat_RGB_BPTC_SIGNED_FLOAT, - => return error.UnsupportedCodec, - else => unreachable, - }; - } - } - - self.decoder.num_frames += 1; - return true; - } -}; +const check = dec.check; pub fn loadVideo(progress_root: std.Progress.Node, filename: [*:0]const u8, texture_type: gl.Texture.Type) !gl.Texture { + if (!build_config.have_ffmpeg) return error.texturesDisabled; + const progress = progress_root.start("loading texture", 2); defer progress.end(); @@ -356,12 +34,12 @@ pub fn loadVideo(progress_root: std.Progress.Node, filename: [*:0]const u8, text const allocator = std.heap.c_allocator; - const decoder = switch (codec_par.codec_tag) { - c.MKTAG('H', 'a', 'p', '1'), - c.MKTAG('H', 'a', 'p', '5'), - => try HAPDecoder.init(allocator, codec_par), - else => try AVDecoder.init(allocator, codec_par), - }; + const is_hap = codec_par.codec_tag == c.MKTAG('H', 'a', 'p', '1') or codec_par.codec_tag == c.MKTAG('H', 'a', 'p', '5'); + const decoder = if (is_hap and build_config.have_hap) + try hap.HAPDecoder.init(allocator, codec_par) + else + try ffmpeg.AVDecoder.init(allocator, codec_par); + defer decoder.deinit(allocator); return try decoder.createTexture(progress, format, video_stream, texture_type); 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); + } +}; diff --git a/src/video/ffmpeg.zig b/src/video/ffmpeg.zig new file mode 100644 index 0000000..03456d5 --- /dev/null +++ b/src/video/ffmpeg.zig @@ -0,0 +1,126 @@ +const std = @import("std"); +const c = @import("../c.zig"); +const gl = @import("../gl.zig"); +const build_config = @import("build_config"); +const dec = @import("decoder.zig"); + +const check = dec.check; + +pub const AVDecoder = struct { + decoder: dec.Decoder, + + sws_ctx: *c.SwsContext, + codec_par: c.AVCodecParameters, + codec_ctx: [*c]c.AVCodecContext, + + raw_frame: [*c]c.AVFrame, + rgba_frame: [*c]c.AVFrame, + + pub fn init(allocator: std.mem.Allocator, codec_par: c.AVCodecParameters) dec.Errors!*dec.Decoder { + const self = try allocator.create(AVDecoder); + errdefer allocator.destroy(self); + + const codec = c.avcodec_find_decoder(codec_par.codec_id) orelse return error.UnsupportedCodec; + + var codec_ctx = c.avcodec_alloc_context3(codec) orelse return error.AVAllocationError; + errdefer c.avcodec_free_context(&codec_ctx); + var raw_frame = c.av_frame_alloc() orelse return error.AVAllocationError; + errdefer c.av_frame_free(&raw_frame); + var rgba_frame = c.av_frame_alloc() orelse return error.AVAllocationError; + errdefer c.av_frame_free(&rgba_frame); + + try check(c.avcodec_parameters_to_context(codec_ctx, &codec_par)); + try check(c.avcodec_open2(codec_ctx, codec, null)); + errdefer check(c.avcodec_close(codec_ctx)) catch unreachable; + + const sws_ctx = c.sws_getContext( + codec_par.width, + codec_par.height, + codec_par.format, + codec_par.width, + codec_par.height, + c.AV_PIX_FMT_RGBA, + c.SWS_POINT, + null, + null, + 0, + ) orelse return error.AVGenericError; + errdefer c.sws_freeContext(sws_ctx); + + self.* = .{ + .decoder = .{ + .process_packet_fn = processPacket, + .init_texture_fn = initTexture, + .reset_fn = reset, + .deinit_fn = deinit, + .num_frames = 0, + }, + .sws_ctx = sws_ctx, + .codec_par = codec_par, + .codec_ctx = codec_ctx, + .raw_frame = raw_frame, + .rgba_frame = rgba_frame, + }; + return &self.decoder; + } + + pub fn deinit(decoder: *dec.Decoder, allocator: std.mem.Allocator) void { + const self: *AVDecoder = @fieldParentPtr("decoder", decoder); + + const raw_ptr: [*c][*c]c.AVFrame = &self.raw_frame; + const rgba_ptr: [*c][*c]c.AVFrame = &self.rgba_frame; + c.av_frame_free(raw_ptr); + c.av_frame_free(rgba_ptr); + + c.sws_freeContext(self.sws_ctx); + check(c.avcodec_close(self.codec_ctx)) catch unreachable; + c.avcodec_free_context(&self.codec_ctx); + + allocator.destroy(self); + } + + pub fn reset(decoder: *dec.Decoder) void { + const self: *AVDecoder = @fieldParentPtr("decoder", decoder); + c.avcodec_flush_buffers(self.codec_ctx); + } + + pub fn initTexture(decoder: *dec.Decoder, texture: *const gl.Texture) void { + const self: *AVDecoder = @fieldParentPtr("decoder", decoder); + + texture.allocate( + self.codec_par.width, + self.codec_par.height, + self.decoder.num_frames, + c.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, + ); + } + + pub fn processPacket(decoder: *dec.Decoder, packet: *c.AVPacket, texture: ?*const gl.Texture) dec.Errors!bool { + const self: *AVDecoder = @fieldParentPtr("decoder", decoder); + + try check(c.avcodec_send_packet(self.codec_ctx, packet)); + while (true) { + const ires = c.avcodec_receive_frame(self.codec_ctx, self.raw_frame); + if (ires == c.AVERROR_EOF) return false; + if (ires == c.AVERROR(c.EAGAIN)) return true; + try check(ires); + try check(c.sws_scale_frame(self.sws_ctx, self.rgba_frame, self.raw_frame)); + + c.glPixelStorei(c.GL_UNPACK_ROW_LENGTH, @divFloor(self.rgba_frame.*.linesize[0], @sizeOf(u8) * 4)); + + if (texture) |tex| { + tex.setLayer( + self.rgba_frame.*.width, + self.rgba_frame.*.height, + self.decoder.num_frames, + c.GL_RGBA, + self.rgba_frame.*.data[0], + ); + + if (tex.type == .TEXTURE_2D) return false; + } + + self.decoder.num_frames += 1; + } + } +}; diff --git a/src/video/hap.zig b/src/video/hap.zig new file mode 100644 index 0000000..70b194a --- /dev/null +++ b/src/video/hap.zig @@ -0,0 +1,125 @@ +const std = @import("std"); +const c = @import("../c.zig"); +const gl = @import("../gl.zig"); +const dec = @import("decoder.zig"); + +fn check(err: c_uint) dec.Errors!void { + return switch (err) { + c.HapResult_No_Error => return, + c.HapResult_Bad_Arguments => return error.HAPBadArguments, + c.HapResult_Buffer_Too_Small => return error.HAPBufferTooSmall, + c.HapResult_Bad_Frame => return error.HAPBadFrame, + c.HapResult_Internal_Error => return error.HAPInternalError, + else => unreachable, + }; +} + +pub const HAPDecoder = struct { + decoder: dec.Decoder, + + codec_par: c.AVCodecParameters, + format: ?c.HapTextureFormat, + gl_format: c.GLenum, + + pub fn init(allocator: std.mem.Allocator, codec_par: c.AVCodecParameters) dec.Errors!*dec.Decoder { + const self = try allocator.create(HAPDecoder); + + self.* = .{ + .decoder = .{ + .process_packet_fn = processPacket, + .init_texture_fn = initTexture, + .reset_fn = null, + .deinit_fn = deinit, + .num_frames = 0, + }, + .codec_par = codec_par, + .format = null, + .gl_format = undefined, + }; + return &self.decoder; + } + + pub fn deinit(decoder: *dec.Decoder, allocator: std.mem.Allocator) void { + const self: *HAPDecoder = @fieldParentPtr("decoder", decoder); + allocator.destroy(self); + } + + pub fn initTexture(decoder: *dec.Decoder, texture: *const gl.Texture) void { + const self: *HAPDecoder = @fieldParentPtr("decoder", decoder); + + texture.allocate( + self.codec_par.width, + self.codec_par.height, + self.decoder.num_frames, + self.gl_format, + ); + } + + fn launchThread(workfn: c.HapDecodeWorkFunction, p: ?*anyopaque, count: c_uint, info: ?*anyopaque) callconv(.C) void { + _ = info; + + var i: c_uint = 0; + while (i < count) : (i += 1) { + workfn.?(p, i); + } + } + + pub fn processPacket(decoder: *dec.Decoder, packet: *c.AVPacket, texture: ?*const gl.Texture) dec.Errors!bool { + const self: *HAPDecoder = @fieldParentPtr("decoder", decoder); + + var textureCount: u32 = undefined; + try check(c.HapGetFrameTextureCount(packet.data, @intCast(packet.size), &textureCount)); + if (textureCount != 1) { + return error.UnsupportedCodec; + } + + var format: c.HapTextureFormat = undefined; + + if (texture) |tex| { + var buffer: [16 * 1024 * 1024]u8 = undefined; + var length: c_ulong = undefined; + try check(c.HapDecode( + packet.data, + @intCast(packet.size), + 0, + launchThread, + self, + &buffer, + buffer.len, + &length, + &format, + )); + + tex.setLayerCompressed( + self.codec_par.width, + self.codec_par.height, + self.decoder.num_frames, + self.gl_format, + buffer[0..length], + ); + + if (tex.type == .TEXTURE_2D) return false; + } else { + try check(c.HapGetFrameTextureFormat(packet.data, @intCast(packet.size), 0, &format)); + if (self.format) |fmt| { + if (fmt != format) return error.UnsupportedCodec; + } else { + self.format = format; + self.gl_format = switch (format) { + c.HapTextureFormat_RGB_DXT1 => c.GL_COMPRESSED_RGB_S3TC_DXT1_EXT, + c.HapTextureFormat_RGBA_DXT5 => c.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, + c.HapTextureFormat_YCoCg_DXT5, + c.HapTextureFormat_A_RGTC1, + c.HapTextureFormat_RGBA_BPTC_UNORM, + c.HapTextureFormat_RGB_BPTC_UNSIGNED_FLOAT, + c.HapTextureFormat_RGB_BPTC_SIGNED_FLOAT, + => return error.UnsupportedCodec, + else => unreachable, + }; + } + } + + self.decoder.num_frames += 1; + return true; + } +}; |
