aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2025-10-23 12:28:43 +0000
committers-ol <s+removethis@s-ol.nu>2025-10-24 11:01:17 +0000
commitd2b98c9ac2ffe045daac4b73da9e08edd7068b77 (patch)
treec028c3b0f6f08e633ef5f4e37349a9836f2c1201
parentStream*Source: rewind on EOF (diff)
downloadglsl-view-d2b98c9ac2ffe045daac4b73da9e08edd7068b77.tar.gz
glsl-view-d2b98c9ac2ffe045daac4b73da9e08edd7068b77.zip
ffmpeg: refactor/turn inside avcodec loops inside-out
-rw-r--r--src/control.zig4
-rw-r--r--src/ffmpeg.zig398
-rw-r--r--src/hap.zig128
3 files changed, 231 insertions, 299 deletions
diff --git a/src/control.zig b/src/control.zig
index 4a29309..053f985 100644
--- a/src/control.zig
+++ b/src/control.zig
@@ -407,7 +407,7 @@ pub const ControlServer = struct {
if (!std.mem.eql(u8, std.mem.span(texture_typeZ), "TEXTURE_2D")) return error.textureTypeInvalid;
const ffmpeg = @import("ffmpeg.zig");
- const source = try ffmpeg.StreamSource.init(self.cache.allocator, self.constants, filenameZ, formatZ, args);
+ const source = try ffmpeg.StreamSource.init(self.cache.allocator, self.constants, .TEXTURE_2D, 1, filenameZ, formatZ, args);
try self.add_source(name, source);
return true;
@@ -430,7 +430,7 @@ pub const ControlServer = struct {
const args = if (argv.len > 4) argv[4..] else &.{};
const ffmpeg = @import("ffmpeg.zig");
- const source = try ffmpeg.BufferedStreamSource.init(self.cache.allocator, self.constants, texture_type, depth, filenameZ, formatZ, args);
+ const source = try ffmpeg.StreamSource.init(self.cache.allocator, self.constants, texture_type, depth, filenameZ, formatZ, args);
try self.add_source(name, source);
return true;
diff --git a/src/ffmpeg.zig b/src/ffmpeg.zig
index 71c214b..f5f0ee4 100644
--- a/src/ffmpeg.zig
+++ b/src/ffmpeg.zig
@@ -15,6 +15,9 @@ pub const Errors = error{
UnsupportedCodec,
OutOfMemory,
NoFrames,
+
+ EOF,
+ TryLater,
};
pub fn check(err: c_int) Errors!void {
@@ -59,59 +62,107 @@ fn get_format_context(
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,
+ format: *c.AVFormatContext,
+ stream: *c.AVStream,
+ packet: [*c]c.AVPacket,
+
+ vtable: VTable,
+
+ pub const VTable = struct {
+ process_next_frame_fn: *const fn (self: *Decoder, texture: ?*const gl.Texture, z: i32) Errors!void,
+ 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,
+ };
+
+ pub const StreamState = enum {
+ done,
+ more_now,
+ more_later,
+ };
+
+ pub fn init(format: *c.AVFormatContext, stream: *c.AVStream, vtable: VTable) Decoder {
+ return .{
+ .num_frames = 0,
+
+ .format = format,
+ .stream = stream,
+ .packet = c.av_packet_alloc(),
+
+ .vtable = vtable,
+ };
+ }
+
+ pub fn getNextPacket(self: *Decoder) Errors!void {
+ while (true) {
+ return switch (c.av_read_frame(self.format, self.packet)) {
+ c.AVERROR_EOF => error.EOF,
+ c.AVERROR(c.EAGAIN) => error.TryLater,
+ else => |res| {
+ try check(res);
+
+ if (self.packet.*.stream_index == self.stream.index) {
+ return;
+ } else {
+ c.av_packet_unref(self.packet);
+ continue;
+ }
+ },
+ };
+ }
+ }
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);
+ var just_one = false;
+ if (texture) |tex| {
+ if (tex.type == .TEXTURE_2D) {
+ just_one = true;
+ }
+ }
+ try self.rewind();
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;
- if (texture) |tex| {
- if (tex.type == .TEXTURE_2D) break;
- }
- }
- c.av_packet_unref(packet);
- } else {
- if (res != c.AVERROR_EOF) try check(res);
+ while (true) {
+ const res = self.vtable.process_next_frame_fn(self, texture, self.num_frames);
+ if (res != error.EOF) try res;
+
+ self.num_frames += 1;
+ progress.setCompletedItems(@intCast(self.num_frames));
+
+ if (just_one or res == error.EOF) break;
+ }
+ }
+
+ pub fn processFrame(
+ self: *Decoder,
+ texture: ?*const gl.Texture,
+ z: i32,
+ ) Errors!void {
+ if (!self.opened) {
+ try self.getNextPacket();
+ self.opened = true;
}
+ try self.vtable.process_next_frame_fn(self, texture, z);
}
- pub fn rewind(self: *Decoder, format: *c.AVFormatContext, stream_index: i32) !void {
- try check(c.avformat_seek_file(format, stream_index, 0, 0, 0, 0));
- if (self.reset_fn) |reset_fn| reset_fn(self);
+ pub fn rewind(self: *Decoder) !void {
+ try check(c.avformat_seek_file(self.format, self.stream.index, 0, 0, 0, 0));
+ if (self.vtable.reset_fn) |reset_fn| reset_fn(self);
}
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,
+ outer_progress.start("scanning video frames", @intCast(self.stream.nb_frames)),
null,
);
if (self.num_frames <= 0) return error.NoFrames;
@@ -119,18 +170,17 @@ pub const Decoder = struct {
const texture = gl.Texture.create(texture_type);
errdefer texture.destroy();
- self.init_texture_fn(self, &texture);
+ self.vtable.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);
+ c.av_packet_free(&self.packet);
+ self.vtable.deinit_fn(self, allocator);
}
};
@@ -144,10 +194,11 @@ pub const AVDecoder = struct {
raw_frame: [*c]c.AVFrame,
rgba_frame: [*c]c.AVFrame,
- pub fn init(allocator: std.mem.Allocator, codec_par: c.AVCodecParameters) Errors!*Decoder {
+ pub fn init(allocator: std.mem.Allocator, format: *c.AVFormatContext, stream: *c.AVStream) Errors!*Decoder {
const self = try allocator.create(AVDecoder);
errdefer allocator.destroy(self);
+ const codec_par = stream.codecpar.*;
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;
@@ -175,13 +226,16 @@ pub const AVDecoder = struct {
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,
- },
+ .decoder = Decoder.init(
+ format,
+ stream,
+ .{
+ .process_next_frame_fn = processNextFrame,
+ .init_texture_fn = initTexture,
+ .reset_fn = reset,
+ .deinit_fn = deinit,
+ },
+ ),
.sws_ctx = sws_ctx,
.codec_par = codec_par,
.codec_ctx = codec_ctx,
@@ -221,39 +275,46 @@ pub const AVDecoder = struct {
);
}
- fn processPacket(decoder: *Decoder, packet: *c.AVPacket, texture: ?*const gl.Texture) Errors!bool {
+ fn getNextFrame(self: *AVDecoder) Errors!void {
+ while (true) {
+ switch (c.avcodec_receive_frame(self.codec_ctx, self.raw_frame)) {
+ c.AVERROR_EOF => return error.EOF,
+ c.AVERROR(c.EAGAIN) => {
+ try self.decoder.getNextPacket();
+ defer c.av_packet_unref(self.decoder.packet);
+
+ try check(c.avcodec_send_packet(self.codec_ctx, self.decoder.packet));
+ continue;
+ },
+ else => |res| {
+ try check(res);
+ return;
+ },
+ }
+ }
+ }
+
+ fn processNextFrame(decoder: *Decoder, texture: ?*const gl.Texture, z: i32) Errors!void {
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 self.getNextFrame();
+ if (texture) |tex| {
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 true;
- }
-
- self.decoder.num_frames += 1;
+ tex.setLayer(
+ self.rgba_frame.*.width,
+ self.rgba_frame.*.height,
+ z,
+ c.GL_RGBA,
+ self.rgba_frame.*.data[0],
+ );
}
}
};
pub const VideoSource = struct {
source: src.Source,
- decoder: *Decoder,
pub fn init(
allocator: std.mem.Allocator,
@@ -280,33 +341,27 @@ pub const VideoSource = struct {
} else unreachable;
const codec_par = video_stream.codecpar.*;
-
- var packet = c.av_packet_alloc();
- defer c.av_packet_free(&packet);
-
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 @import("hap.zig").HAPDecoder.init(allocator, format, video_stream)
+ else
+ try AVDecoder.init(allocator, format, video_stream);
+ errdefer decoder.deinit(allocator);
+
self.* = .{
.source = .{
- .texture = undefined,
+ .texture = try decoder.createTexture(progress, texture_type),
.deinit_fn = deinit,
},
- .decoder = if (is_hap and build_config.have_hap)
- try @import("hap.zig").HAPDecoder.init(allocator, codec_par)
- else
- try AVDecoder.init(allocator, codec_par),
};
- errdefer self.decoder.deinit(allocator);
- self.source.texture = try self.decoder.createTexture(progress, format, video_stream, texture_type);
return &self.source;
}
fn deinit(source: *const src.Source, allocator: std.mem.Allocator) void {
const self: *const VideoSource = @fieldParentPtr("source", source);
-
- self.decoder.deinit(allocator);
allocator.destroy(self);
}
};
@@ -317,129 +372,8 @@ pub const StreamSource = struct {
decoder: *Decoder,
format: *c.AVFormatContext,
- stream: i32,
- packet: *c.AVPacket,
-
- thread: *gl.Thread,
-
- pub fn init(
- allocator: std.mem.Allocator,
- constants: *const gl.Constants,
- filename: [*:0]const u8,
- format_name: ?[*:0]const u8,
- format_options: []const [*c]c.lo_arg,
- ) !*src.Source {
- const self = try allocator.create(StreamSource);
- errdefer allocator.destroy(self);
-
- var format = try get_format_context(filename, format_name, format_options);
- errdefer c.avformat_close_input(@ptrCast(&format));
- format.flags |= c.AVFMT_FLAG_NONBLOCK;
-
- try check(c.avformat_find_stream_info(format, null));
-
- const video_stream = for (format.streams, 0..format.nb_streams) |c_stream, _| {
- const stream = @as(*c.AVStream, c_stream orelse unreachable);
- if (stream.codecpar.*.codec_type == c.AVMEDIA_TYPE_VIDEO) break stream;
- } else unreachable;
-
- const codec_par = video_stream.codecpar.*;
-
- var packet = c.av_packet_alloc();
- errdefer c.av_packet_free(&packet);
-
- const texture = gl.Texture.create(.TEXTURE_2D);
- texture.allocate(
- codec_par.width,
- codec_par.height,
- 1,
- c.GL_RGBA8,
- );
-
- const decoder = try AVDecoder.init(allocator, codec_par);
- errdefer decoder.deinit(allocator);
-
- self.* = .{
- .source = .{
- .texture = texture,
- .deinit_fn = deinit,
- .register_fn = register_methods,
- .unregister_fn = unregister_methods,
- },
- .flags = .{},
-
- .decoder = decoder,
- .format = format,
- .stream = video_stream.index,
- .packet = packet,
-
- .thread = undefined,
- };
-
- _ = try self.update();
- self.thread = try gl.Thread.init(allocator, constants, update_loop, .{self});
-
- return &self.source;
- }
-
- fn register_methods(source: *src.Source, name: []const u8, control: *ctrl.ControlServer) void {
- const self: *StreamSource = @fieldParentPtr("source", source);
- self.flags.register(name, control);
- }
- fn unregister_methods(source: *src.Source, name: []const u8, control: *ctrl.ControlServer) void {
- const self: *StreamSource = @fieldParentPtr("source", source);
- self.flags.unregister(name, control);
- }
-
- fn update_loop(self: *StreamSource) !void {
- while (!self.thread.quit) {
- const more = try self.update();
- if (!more) {
- try self.decoder.rewind(self.format, self.stream);
- _ = try self.update();
- }
-
- c.glFlush();
- try std.Thread.yield();
- }
- }
-
- fn update(self: *StreamSource) !bool {
- const res = c.av_read_frame(self.format, self.packet);
- if (res == c.AVERROR_EOF) return false;
- try check(res);
- defer c.av_packet_unref(self.packet);
-
- if (self.packet.*.stream_index != self.stream) return true;
-
- self.decoder.num_frames = 0;
- return try self.decoder.process_packet_fn(
- self.decoder,
- self.packet,
- if (self.flags.shouldStep()) &self.source.texture else null,
- );
- }
-
- fn deinit(source: *src.Source, allocator: std.mem.Allocator) void {
- const self: *StreamSource = @fieldParentPtr("source", source);
-
- self.thread.deinit(allocator);
- self.decoder.deinit(allocator);
- c.av_packet_free(@ptrCast(&self.packet));
- c.avformat_close_input(@ptrCast(&self.format));
- allocator.destroy(self);
- }
-};
-
-pub const BufferedStreamSource = struct {
- source: src.Source,
- flags: src.StreamFlags,
-
- decoder: *Decoder,
- format: *c.AVFormatContext,
- stream: i32,
depth: i32,
- packet: *c.AVPacket,
+ frame: i32,
thread: *gl.Thread,
@@ -452,7 +386,7 @@ pub const BufferedStreamSource = struct {
format_name: ?[*:0]const u8,
format_options: []const [*c]c.lo_arg,
) !*src.Source {
- const self = try allocator.create(BufferedStreamSource);
+ const self = try allocator.create(StreamSource);
errdefer allocator.destroy(self);
var format = try get_format_context(filename, format_name, format_options);
@@ -468,11 +402,14 @@ pub const BufferedStreamSource = struct {
const codec_par = video_stream.codecpar.*;
- var packet = c.av_packet_alloc();
- errdefer c.av_packet_free(&packet);
-
+ switch (texture_type) {
+ .TEXTURE_2D, .TEXTURE_RECTANGLE => {
+ std.debug.assert(depth == 1);
+ },
+ else => {},
+ }
const texture = switch (texture_type) {
- .TEXTURE_3D, .TEXTURE_2D_ARRAY => |t| gl.Texture.create(t),
+ .TEXTURE_3D, .TEXTURE_2D_ARRAY, .TEXTURE_2D, .TEXTURE_RECTANGLE => |t| gl.Texture.create(t),
else => return error.textureTypeInvalid,
};
texture.allocate(
@@ -482,7 +419,7 @@ pub const BufferedStreamSource = struct {
c.GL_RGBA8,
);
- const decoder = try AVDecoder.init(allocator, codec_par);
+ const decoder = try AVDecoder.init(allocator, format, video_stream);
errdefer decoder.deinit(allocator);
self.* = .{
@@ -497,9 +434,8 @@ pub const BufferedStreamSource = struct {
.decoder = decoder,
.format = format,
- .stream = video_stream.index,
.depth = depth,
- .packet = packet,
+ .frame = 0,
.thread = undefined,
};
@@ -511,19 +447,19 @@ pub const BufferedStreamSource = struct {
}
fn register_methods(source: *src.Source, name: []const u8, control: *ctrl.ControlServer) void {
- const self: *BufferedStreamSource = @fieldParentPtr("source", source);
+ const self: *StreamSource = @fieldParentPtr("source", source);
self.flags.register(name, control);
}
fn unregister_methods(source: *src.Source, name: []const u8, control: *ctrl.ControlServer) void {
- const self: *BufferedStreamSource = @fieldParentPtr("source", source);
+ const self: *StreamSource = @fieldParentPtr("source", source);
self.flags.unregister(name, control);
}
fn update_uniform(source: *src.Source, param: []const u8, value: gl.UniformPointer) !void {
- const self: *BufferedStreamSource = @fieldParentPtr("source", source);
+ const self: *StreamSource = @fieldParentPtr("source", source);
if (!std.mem.eql(u8, param, "offset")) return error.unknownSourceParam;
- const frame = @rem(self.decoder.num_frames + self.depth - 1, self.depth);
+ const frame = @rem(self.frame + self.depth - 1, self.depth);
try switch (value) {
.FLOAT => |val| val.* = @as(f32, @floatFromInt(frame)) / @as(f32, @floatFromInt(self.depth)),
.DOUBLE => |val| val.* = @as(f64, @floatFromInt(frame)) / @as(f64, @floatFromInt(self.depth)),
@@ -533,12 +469,18 @@ pub const BufferedStreamSource = struct {
};
}
- fn update_loop(self: *BufferedStreamSource) !void {
+ fn update_loop(self: *StreamSource) !void {
while (!self.thread.quit) {
- const more = try self.update();
- if (!more) {
- try self.decoder.rewind(self.format, self.stream);
- _ = try self.update();
+ while (true) {
+ if (self.update()) {
+ break;
+ } else |err| {
+ switch (err) {
+ error.TryLater => break,
+ error.EOF => try self.decoder.rewind(),
+ else => return err,
+ }
+ }
}
c.glFlush();
@@ -546,29 +488,19 @@ pub const BufferedStreamSource = struct {
}
}
- fn update(self: *BufferedStreamSource) !bool {
- const res = c.av_read_frame(self.format, self.packet);
- if (res == c.AVERROR_EOF) return false;
- try check(res);
- defer c.av_packet_unref(self.packet);
-
- if (self.packet.*.stream_index != self.stream) return true;
-
- const more = try self.decoder.process_packet_fn(
- self.decoder,
- self.packet,
+ fn update(self: *StreamSource) Errors!void {
+ try self.decoder.processFrame(
if (self.flags.shouldStep()) &self.source.texture else null,
+ self.frame,
);
- self.decoder.num_frames = @rem(self.decoder.num_frames, self.depth);
- return more;
+ self.frame = @rem(self.frame + 1, self.depth);
}
fn deinit(source: *src.Source, allocator: std.mem.Allocator) void {
- const self: *BufferedStreamSource = @fieldParentPtr("source", source);
+ const self: *StreamSource = @fieldParentPtr("source", source);
self.thread.deinit(allocator);
self.decoder.deinit(allocator);
- c.av_packet_free(@ptrCast(&self.packet));
c.avformat_close_input(@ptrCast(&self.format));
allocator.destroy(self);
}
diff --git a/src/hap.zig b/src/hap.zig
index 7a2dd50..073cb8b 100644
--- a/src/hap.zig
+++ b/src/hap.zig
@@ -23,19 +23,23 @@ pub const HAPDecoder = struct {
pub fn init(
allocator: std.mem.Allocator,
- codec_par: c.AVCodecParameters,
+ format: *c.AVFormatContext,
+ stream: *c.AVStream,
) ffmpeg.Errors!*ffmpeg.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,
+ .decoder = ffmpeg.Decoder.init(
+ format,
+ stream,
+ .{
+ .process_next_frame_fn = processNextFrame,
+ .init_texture_fn = initTexture,
+ .reset_fn = null,
+ .deinit_fn = deinit,
+ },
+ ),
+ .codec_par = stream.codecpar.*,
.format = null,
.gl_format = undefined,
};
@@ -72,66 +76,62 @@ pub const HAPDecoder = struct {
}
}
- fn processPacket(
- decoder: *ffmpeg.Decoder,
- packet: *c.AVPacket,
- texture: ?*const gl.Texture,
- ) ffmpeg.Errors!bool {
+ fn processNextFrame(decoder: *ffmpeg.Decoder, texture: ?*const gl.Texture, z: i32) ffmpeg.Errors!void {
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;
- }
+ try self.decoder.getNextPacket();
+ defer c.av_packet_unref(self.decoder.packet);
+
+ if (self.decoder.packet) |packet| {
+ 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 true;
- } else {
- try check(c.HapGetFrameTextureFormat(packet.data, @intCast(packet.size), 0, &format));
- if (self.format) |fmt| {
- if (fmt != format) 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,
+ z,
+ self.gl_format,
+ buffer[0..length],
+ );
} 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,
- };
+ 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;
}
};