saving b/c im scared
This commit is contained in:
parent
cc960812ec
commit
b733d7a329
|
|
@ -9,14 +9,14 @@ pub const Console = struct {
|
||||||
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This());
|
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This());
|
||||||
|
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
stringArena: std.heap.ArenaAllocator,
|
arena: std.heap.ArenaAllocator,
|
||||||
|
|
||||||
commandMap: std.StringHashMapUnmanaged(ConsoleCommand) = .{},
|
commandMap: std.StringHashMapUnmanaged(ConsoleCommand) = .{},
|
||||||
|
|
||||||
pub fn create(allocator: std.mem.Allocator) !*@This() {
|
pub fn create(allocator: std.mem.Allocator) !*@This() {
|
||||||
const self = try allocator.create(@This());
|
const self = try allocator.create(@This());
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.stringArena = std.heap.ArenaAllocator.init(allocator),
|
.arena = std.heap.ArenaAllocator.init(allocator),
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -27,7 +27,7 @@ pub const Console = struct {
|
||||||
|
|
||||||
pub fn addConsoleCommand(self: *@This(), funcName: []const u8, func: ConsoleFunc) !void {
|
pub fn addConsoleCommand(self: *@This(), funcName: []const u8, func: ConsoleFunc) !void {
|
||||||
try self.commandMap.put(self.allocator, funcName, .{
|
try self.commandMap.put(self.allocator, funcName, .{
|
||||||
.command = try self.stringArena.allocator().dupe(u8, funcName),
|
.command = try self.arena.allocator().dupe(u8, funcName),
|
||||||
.func = func,
|
.func = func,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -55,7 +55,7 @@ pub const Console = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(self: *@This()) void {
|
pub fn destroy(self: *@This()) void {
|
||||||
self.stringArena.deinit();
|
self.arena.deinit();
|
||||||
self.commandMap.deinit(self.allocator);
|
self.commandMap.deinit(self.allocator);
|
||||||
self.allocator.destroy(self);
|
self.allocator.destroy(self);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,21 @@ fn test_consoleCommands() !void {
|
||||||
try core.console.addCommand("echo", ConsoleCommands.echo);
|
try core.console.addCommand("echo", ConsoleCommands.echo);
|
||||||
try core.console.addCommand("foo", ConsoleCommands.foo);
|
try core.console.addCommand("foo", ConsoleCommands.foo);
|
||||||
|
|
||||||
|
const T = struct {
|
||||||
|
var ScreenResolution: u32 = undefined;
|
||||||
|
|
||||||
|
pub fn F(args: []const u8) void {
|
||||||
|
core.engine_log("Setting screen resolution to = {s}", .{args});
|
||||||
|
ScreenResolution = std.fmt.parseInt(u32, args, 10) catch return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
T.ScreenResolution = core.configVar(u32, "Some.bullshit.ScreenResolution", 420);
|
||||||
|
try core.assert(T.ScreenResolution == 420);
|
||||||
|
try core.console.addCommand("ScreenResolution", T.F);
|
||||||
|
core.console.evaluate("ScreenResolution 1");
|
||||||
|
try core.assert(T.ScreenResolution == 1);
|
||||||
|
|
||||||
core.console.evaluate("echo lmfao");
|
core.console.evaluate("echo lmfao");
|
||||||
core.console.evaluate("foo lmfao");
|
core.console.evaluate("foo lmfao");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ pub const Impl = struct {
|
||||||
drawData: [*c]ig.DrawData = undefined,
|
drawData: [*c]ig.DrawData = undefined,
|
||||||
rendererDebug: bool = true,
|
rendererDebug: bool = true,
|
||||||
|
|
||||||
|
dtAverage: f64 = 0.0,
|
||||||
|
|
||||||
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This());
|
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This());
|
||||||
|
|
||||||
pub const Settings = struct {
|
pub const Settings = struct {
|
||||||
|
|
@ -55,7 +57,7 @@ pub const Impl = struct {
|
||||||
//const renderpass = cmd.beginGPURenderPass(color_target_infos: [*c]const GPUColorTargetInfo, num_color_targets: u32, depth_stencil_target_info: [*c]const GPUDepthStencilTargetInfo);
|
//const renderpass = cmd.beginGPURenderPass(color_target_infos: [*c]const GPUColorTargetInfo, num_color_targets: u32, depth_stencil_target_info: [*c]const GPUDepthStencilTargetInfo);
|
||||||
|
|
||||||
var targetInfo: gpu.GPUColorTargetInfo = std.mem.zeroes(gpu.GPUColorTargetInfo);
|
var targetInfo: gpu.GPUColorTargetInfo = std.mem.zeroes(gpu.GPUColorTargetInfo);
|
||||||
targetInfo.texture = rend.context().swapchainTexture.?;
|
targetInfo.texture = rend.context().state.swapchainTexture.?;
|
||||||
targetInfo.clear_color = .{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 0.0 };
|
targetInfo.clear_color = .{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 0.0 };
|
||||||
targetInfo.load_op = .loadopLoad;
|
targetInfo.load_op = .loadopLoad;
|
||||||
targetInfo.store_op = .storeopStore;
|
targetInfo.store_op = .storeopStore;
|
||||||
|
|
@ -71,14 +73,19 @@ pub const Impl = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn preTick(self: *@This(), _: f64) core.EngineDataEventError!void {
|
pub fn preTick(self: *@This(), dt: f64) core.EngineDataEventError!void {
|
||||||
c.Imgui_SDL3_NewFrame();
|
c.Imgui_SDL3_NewFrame();
|
||||||
c.igNewFrame();
|
c.igNewFrame();
|
||||||
|
|
||||||
|
core.rollingAverage(&self.dtAverage, dt, 50);
|
||||||
|
|
||||||
if (ig.begin("renderer debug", &self.rendererDebug, .{})) {
|
if (ig.begin("renderer debug", &self.rendererDebug, .{})) {
|
||||||
_ = ig.sliderFloat("directional light yaw", &rend.context().directionalLightYaw, 0, 360, null, .{});
|
_ = ig.sliderFloat("directional light yaw", &rend.context().directionalLightYaw, 0, 360, null, .{});
|
||||||
_ = ig.sliderFloat("ortho near", &rend.context().shadowOrthoNear, 0, 200, null, .{});
|
_ = ig.sliderFloat("ortho near", &rend.context().shadowOrthoNear, 0, 200, null, .{});
|
||||||
_ = ig.sliderFloat("ortho far", &rend.context().shadowOrthoFar, 0, 6000, null, .{});
|
_ = ig.sliderFloat("ortho far", &rend.context().shadowOrthoFar, 0, 6000, null, .{});
|
||||||
|
if (self.dtAverage > 0.000001) {
|
||||||
|
ig.textFmt("frameTime: {d:.2}ms ({d:.2}fps)", .{ self.dtAverage * 1000, @as(u32, @intFromFloat(1 / self.dtAverage)) }) catch return error.UnknownStatePanic;
|
||||||
|
}
|
||||||
ig.end();
|
ig.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,14 @@
|
||||||
Texture2D<float4> Texture : register(t0, space2);
|
Texture2D<float4> Texture0 : register(t0, space2);
|
||||||
SamplerState Sampler : register(s0, space2);
|
SamplerState Sampler0 : register(s0, space2);
|
||||||
|
|
||||||
Texture2D<float> DirectionalShadowDepthMap : register(t1, space2);
|
Texture2D<float4> Texture1 : register(t1, space2);
|
||||||
SamplerState DirectionalShadowSampler : register(s1, space2);
|
SamplerState Sampler1 : register(s1, space2);
|
||||||
|
|
||||||
|
Texture2D<float4> Texture2 : register(t2, space2);
|
||||||
|
SamplerState Sampler2 : register(s2, space2);
|
||||||
|
|
||||||
|
Texture2D<float> DirectionalShadowDepthMap : register(t3, space2);
|
||||||
|
SamplerState DirectionalShadowSampler : register(s3, space2);
|
||||||
|
|
||||||
cbuffer Uniforms : register(b0, space3)
|
cbuffer Uniforms : register(b0, space3)
|
||||||
{
|
{
|
||||||
|
|
@ -15,6 +20,16 @@ cbuffer Uniforms : register(b0, space3)
|
||||||
float time;
|
float time;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Scene
|
||||||
|
{
|
||||||
|
float4x4 Model;
|
||||||
|
|
||||||
|
uint textureMode; // 0 = regular triple,
|
||||||
|
// 0x10 = video yuv,
|
||||||
|
};
|
||||||
|
|
||||||
|
StructuredBuffer<Scene> scene: register(t0, space0);
|
||||||
|
|
||||||
// from learnopengl.com
|
// from learnopengl.com
|
||||||
float3 BlinnPhong(float3 normal, float3 fragPos, float3 lightPos, float3 lightColor)
|
float3 BlinnPhong(float3 normal, float3 fragPos, float3 lightPos, float3 lightColor)
|
||||||
{
|
{
|
||||||
|
|
@ -157,18 +172,68 @@ float3 DirectionalLight(float3 normal, float3 fragPos, float4 DirectionalShadow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
float4 main(
|
float4 main(
|
||||||
float4 ScreenPosition: SV_POSITION,
|
float4 ScreenPosition: SV_POSITION,
|
||||||
|
|
||||||
float2 UV : TEXCOORD0,
|
float2 UV : TEXCOORD0,
|
||||||
float3 WorldPos: TEXCOORD1,
|
float3 WorldPos: TEXCOORD1,
|
||||||
float3 Normal: TEXCOORD2,
|
float3 Normal: TEXCOORD2,
|
||||||
float4 DirectionalShadowFragPos: TEXCOORD3
|
float4 DirectionalShadowFragPos: TEXCOORD3,
|
||||||
|
uint Instance: TEXCOORD4
|
||||||
) : SV_Target0
|
) : SV_Target0
|
||||||
{
|
{
|
||||||
float4 s = Texture.Sample(Sampler, UV);
|
|
||||||
|
|
||||||
|
float4 s;
|
||||||
float alpha = s.w;
|
float alpha = s.w;
|
||||||
|
|
||||||
|
int texMode = scene[Instance].textureMode;
|
||||||
|
if (texMode == 0x10) // YUV
|
||||||
|
{
|
||||||
|
float3 offset = float3(-0.0625, -0.5, -0.5);
|
||||||
|
float3 Rcoeff = float3(1.164, 0.000, 1.793);
|
||||||
|
float3 Gcoeff = float3(1.164, -0.213, -0.533);
|
||||||
|
float3 Bcoeff = float3(1.164, 2.112, 0.000);
|
||||||
|
|
||||||
|
float3 yuv, rgb;
|
||||||
|
|
||||||
|
yuv.x =Texture0.Sample(Sampler0, UV).r;
|
||||||
|
yuv.y =Texture1.Sample(Sampler1, UV).r;
|
||||||
|
yuv.z =Texture2.Sample(Sampler2, UV).r;
|
||||||
|
|
||||||
|
yuv += offset;
|
||||||
|
rgb.r = dot(yuv, Rcoeff);
|
||||||
|
rgb.g = dot(yuv, Gcoeff);
|
||||||
|
rgb.b = dot(yuv, Bcoeff);
|
||||||
|
|
||||||
|
// " gl_FragColor = vec4(rgb, 1.0);\n"
|
||||||
|
// "uniform sampler2D samp0;\n"
|
||||||
|
// "uniform sampler2D samp1;\n"
|
||||||
|
// "uniform sampler2D samp2;\n"
|
||||||
|
// "const vec3 offset = vec3(-0.0625, -0.5, -0.5);\n"
|
||||||
|
// "const vec3 Rcoeff = vec3(1.164, 0.000, 1.793);\n"
|
||||||
|
// "const vec3 Gcoeff = vec3(1.164, -0.213, -0.533);\n"
|
||||||
|
// "const vec3 Bcoeff = vec3(1.164, 2.112, 0.000);\n"
|
||||||
|
// "void main() {\n"
|
||||||
|
// " vec2 tcoord;\n"
|
||||||
|
// " vec3 yuv, rgb;\n"
|
||||||
|
// " tcoord = gl_TexCoord[0].xy;\n"
|
||||||
|
// " yuv.x = texture2D(samp0, tcoord).r;\n"
|
||||||
|
// " yuv.y = texture2D(samp1, tcoord).r;\n"
|
||||||
|
// " yuv.z = texture2D(samp2, tcoord).r;\n"
|
||||||
|
// " yuv += offset;\n"
|
||||||
|
// " rgb.r = dot(yuv, Rcoeff);\n"
|
||||||
|
// " rgb.g = dot(yuv, Gcoeff);\n"
|
||||||
|
// " rgb.b = dot(yuv, Bcoeff);\n"
|
||||||
|
// " gl_FragColor = vec4(rgb, 1.0);\n"
|
||||||
|
// "}\n";
|
||||||
|
}
|
||||||
|
else if(texMode == 0)
|
||||||
|
{
|
||||||
|
s = Texture0.Sample(Sampler0, UV);
|
||||||
|
}
|
||||||
|
|
||||||
if(alpha < 0.01)
|
if(alpha < 0.01)
|
||||||
{
|
{
|
||||||
discard;
|
discard;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"types" : {
|
"types" : {
|
||||||
"_14" : {
|
"_15" : {
|
||||||
"name" : "type.Uniforms",
|
"name" : "type.Uniforms",
|
||||||
"members" : [
|
"members" : [
|
||||||
{
|
{
|
||||||
|
|
@ -40,6 +40,40 @@
|
||||||
"offset" : 72
|
"offset" : 72
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"_18" : {
|
||||||
|
"name" : "Scene",
|
||||||
|
"members" : [
|
||||||
|
{
|
||||||
|
"name" : "Model",
|
||||||
|
"type" : "mat4",
|
||||||
|
"offset" : 0,
|
||||||
|
"matrix_stride" : 16,
|
||||||
|
"row_major" : true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "textureMode",
|
||||||
|
"type" : "uint",
|
||||||
|
"offset" : 64
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"_17" : {
|
||||||
|
"name" : "type.StructuredBuffer.Scene",
|
||||||
|
"members" : [
|
||||||
|
{
|
||||||
|
"name" : "_m0",
|
||||||
|
"type" : "_18",
|
||||||
|
"array" : [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"array_size_is_literal" : [
|
||||||
|
true
|
||||||
|
],
|
||||||
|
"offset" : 0,
|
||||||
|
"array_stride" : 80
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"inputs" : [
|
"inputs" : [
|
||||||
|
|
@ -62,6 +96,11 @@
|
||||||
"type" : "vec4",
|
"type" : "vec4",
|
||||||
"name" : "in.var.TEXCOORD3",
|
"name" : "in.var.TEXCOORD3",
|
||||||
"location" : 3
|
"location" : 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type" : "uint",
|
||||||
|
"name" : "in.var.TEXCOORD4",
|
||||||
|
"location" : 4
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"outputs" : [
|
"outputs" : [
|
||||||
|
|
@ -74,7 +113,7 @@
|
||||||
"separate_images" : [
|
"separate_images" : [
|
||||||
{
|
{
|
||||||
"type" : "texture2D",
|
"type" : "texture2D",
|
||||||
"name" : "Texture",
|
"name" : "Texture0",
|
||||||
"set" : 2,
|
"set" : 2,
|
||||||
"binding" : 0
|
"binding" : 0
|
||||||
},
|
},
|
||||||
|
|
@ -82,13 +121,13 @@
|
||||||
"type" : "texture2D",
|
"type" : "texture2D",
|
||||||
"name" : "DirectionalShadowDepthMap",
|
"name" : "DirectionalShadowDepthMap",
|
||||||
"set" : 2,
|
"set" : 2,
|
||||||
"binding" : 1
|
"binding" : 3
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"separate_samplers" : [
|
"separate_samplers" : [
|
||||||
{
|
{
|
||||||
"type" : "sampler",
|
"type" : "sampler",
|
||||||
"name" : "Sampler",
|
"name" : "Sampler0",
|
||||||
"set" : 2,
|
"set" : 2,
|
||||||
"binding" : 0
|
"binding" : 0
|
||||||
},
|
},
|
||||||
|
|
@ -96,12 +135,22 @@
|
||||||
"type" : "sampler",
|
"type" : "sampler",
|
||||||
"name" : "DirectionalShadowSampler",
|
"name" : "DirectionalShadowSampler",
|
||||||
"set" : 2,
|
"set" : 2,
|
||||||
"binding" : 1
|
"binding" : 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ssbos" : [
|
||||||
|
{
|
||||||
|
"type" : "_17",
|
||||||
|
"name" : "scene",
|
||||||
|
"readonly" : true,
|
||||||
|
"block_size" : 0,
|
||||||
|
"set" : 0,
|
||||||
|
"binding" : 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ubos" : [
|
"ubos" : [
|
||||||
{
|
{
|
||||||
"type" : "_14",
|
"type" : "_15",
|
||||||
"name" : "type.Uniforms",
|
"name" : "type.Uniforms",
|
||||||
"block_size" : 76,
|
"block_size" : 76,
|
||||||
"set" : 3,
|
"set" : 3,
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ struct Output
|
||||||
float3 WorldPos : TEXCOORD1;
|
float3 WorldPos : TEXCOORD1;
|
||||||
float3 Normal: TEXCOORD2;
|
float3 Normal: TEXCOORD2;
|
||||||
float4 DirectionalShadowFragPos: TEXCOORD3;
|
float4 DirectionalShadowFragPos: TEXCOORD3;
|
||||||
|
uint Instance: TEXCOORD4;
|
||||||
|
|
||||||
float4 Position : SV_Position;
|
float4 Position : SV_Position;
|
||||||
};
|
};
|
||||||
|
|
@ -25,6 +26,9 @@ struct Output
|
||||||
struct Scene
|
struct Scene
|
||||||
{
|
{
|
||||||
float4x4 Model;
|
float4x4 Model;
|
||||||
|
|
||||||
|
uint textureMode; // 0 = regular triple,
|
||||||
|
// 0x10 = video yuv,
|
||||||
};
|
};
|
||||||
|
|
||||||
StructuredBuffer<Scene> scene: register(t0, space0);
|
StructuredBuffer<Scene> scene: register(t0, space0);
|
||||||
|
|
@ -51,6 +55,7 @@ Output main(Input input)
|
||||||
output.WorldPos = WorldPos.xyz;
|
output.WorldPos = WorldPos.xyz;
|
||||||
output.Normal = input.Normal;
|
output.Normal = input.Normal;
|
||||||
output.DirectionalShadowFragPos = mul(ShadowMapProjection, WorldPos);
|
output.DirectionalShadowFragPos = mul(ShadowMapProjection, WorldPos);
|
||||||
|
output.Instance = input.Instance;
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"types" : {
|
"types" : {
|
||||||
"_12" : {
|
"_13" : {
|
||||||
"name" : "Scene",
|
"name" : "Scene",
|
||||||
"members" : [
|
"members" : [
|
||||||
{
|
{
|
||||||
|
|
@ -15,15 +15,20 @@
|
||||||
"offset" : 0,
|
"offset" : 0,
|
||||||
"matrix_stride" : 16,
|
"matrix_stride" : 16,
|
||||||
"row_major" : true
|
"row_major" : true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "textureMode",
|
||||||
|
"type" : "uint",
|
||||||
|
"offset" : 64
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"_11" : {
|
"_12" : {
|
||||||
"name" : "type.StructuredBuffer.Scene",
|
"name" : "type.StructuredBuffer.Scene",
|
||||||
"members" : [
|
"members" : [
|
||||||
{
|
{
|
||||||
"name" : "_m0",
|
"name" : "_m0",
|
||||||
"type" : "_12",
|
"type" : "_13",
|
||||||
"array" : [
|
"array" : [
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
|
|
@ -31,11 +36,11 @@
|
||||||
true
|
true
|
||||||
],
|
],
|
||||||
"offset" : 0,
|
"offset" : 0,
|
||||||
"array_stride" : 64
|
"array_stride" : 80
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"_14" : {
|
"_15" : {
|
||||||
"name" : "type.Uniforms",
|
"name" : "type.Uniforms",
|
||||||
"members" : [
|
"members" : [
|
||||||
{
|
{
|
||||||
|
|
@ -97,11 +102,16 @@
|
||||||
"type" : "vec4",
|
"type" : "vec4",
|
||||||
"name" : "out.var.TEXCOORD3",
|
"name" : "out.var.TEXCOORD3",
|
||||||
"location" : 3
|
"location" : 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type" : "uint",
|
||||||
|
"name" : "out.var.TEXCOORD4",
|
||||||
|
"location" : 4
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ssbos" : [
|
"ssbos" : [
|
||||||
{
|
{
|
||||||
"type" : "_11",
|
"type" : "_12",
|
||||||
"name" : "scene",
|
"name" : "scene",
|
||||||
"readonly" : true,
|
"readonly" : true,
|
||||||
"block_size" : 0,
|
"block_size" : 0,
|
||||||
|
|
@ -111,7 +121,7 @@
|
||||||
],
|
],
|
||||||
"ubos" : [
|
"ubos" : [
|
||||||
{
|
{
|
||||||
"type" : "_14",
|
"type" : "_15",
|
||||||
"name" : "type.Uniforms",
|
"name" : "type.Uniforms",
|
||||||
"block_size" : 132,
|
"block_size" : 132,
|
||||||
"set" : 1,
|
"set" : 1,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,13 @@ texture: ?*Texture = null,
|
||||||
|
|
||||||
entity: core.Entity = undefined,
|
entity: core.Entity = undefined,
|
||||||
|
|
||||||
|
textureMode: u32 = 0,
|
||||||
|
// DEBUG for-fun function, completely override what happens when the renderer tries to render this mesh.
|
||||||
|
cmrf: ?*rend.renderer.CustomMeshRenderFunc = null,
|
||||||
|
|
||||||
|
pub const textureMode_default = 0;
|
||||||
|
pub const textureMode_videoYUV = 0x10;
|
||||||
|
|
||||||
pub var BaseContainer: *MeshSet = undefined;
|
pub var BaseContainer: *MeshSet = undefined;
|
||||||
pub const ComponentName = "Mesh";
|
pub const ComponentName = "Mesh";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ pub fn destroy(self: *@This()) void {
|
||||||
|
|
||||||
pub fn render(self: *@This(), cmd: *gpu.GPUCommandBuffer) void {
|
pub fn render(self: *@This(), cmd: *gpu.GPUCommandBuffer) void {
|
||||||
const targetInfo: gpu.GPUColorTargetInfo = std.mem.zeroInit(gpu.GPUColorTargetInfo, .{
|
const targetInfo: gpu.GPUColorTargetInfo = std.mem.zeroInit(gpu.GPUColorTargetInfo, .{
|
||||||
.texture = rend.context().swapchainTexture.?,
|
.texture = rend.context().state.swapchainTexture.?,
|
||||||
.clear_color = self.skyboxColor,
|
.clear_color = self.skyboxColor,
|
||||||
.load_op = .loadopClear,
|
.load_op = .loadopClear,
|
||||||
.store_op = .storeopStore,
|
.store_op = .storeopStore,
|
||||||
|
|
@ -101,10 +101,10 @@ pub fn render(self: *@This(), cmd: *gpu.GPUCommandBuffer) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const renderpass = cmd.beginGPURenderPass(&targetInfo, 1, null);
|
||||||
if (self.skyboxTexture) |skyboxTexture| {
|
if (self.skyboxTexture) |skyboxTexture| {
|
||||||
if (self.skyboxMesh) |skyboxMesh| {
|
if (self.skyboxMesh) |skyboxMesh| {
|
||||||
const ctx = rend.context();
|
const ctx = rend.context();
|
||||||
const renderpass = cmd.beginGPURenderPass(&targetInfo, 1, null);
|
|
||||||
|
|
||||||
self.uploadSkyboxUniforms(cmd);
|
self.uploadSkyboxUniforms(cmd);
|
||||||
|
|
||||||
|
|
@ -115,9 +115,9 @@ pub fn render(self: *@This(), cmd: *gpu.GPUCommandBuffer) void {
|
||||||
renderpass.bindGPUGraphicsPipeline(self.skyboxPipeline);
|
renderpass.bindGPUGraphicsPipeline(self.skyboxPipeline);
|
||||||
renderpass.bindGPUFragmentSamplers(0, &.{ .texture = skyboxTexture.texture, .sampler = self.sampler }, 1);
|
renderpass.bindGPUFragmentSamplers(0, &.{ .texture = skyboxTexture.texture, .sampler = self.sampler }, 1);
|
||||||
renderpass.drawGPUIndexedPrimitives(skyboxMesh.index.size, 1, skyboxMesh.index.start, @intCast(skyboxMesh.vertex.start), 0);
|
renderpass.drawGPUIndexedPrimitives(skyboxMesh.index.size, 1, skyboxMesh.index.start, @intCast(skyboxMesh.vertex.start), 0);
|
||||||
renderpass.endGPURenderPass();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
renderpass.endGPURenderPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uploadSkyboxUniforms(self: *@This(), cmd: *gpu.GPUCommandBuffer) void {
|
pub fn uploadSkyboxUniforms(self: *@This(), cmd: *gpu.GPUCommandBuffer) void {
|
||||||
|
|
|
||||||
|
|
@ -69,14 +69,14 @@ pub const MeshPool = struct {
|
||||||
switch (u) {
|
switch (u) {
|
||||||
.new => |new| {
|
.new => |new| {
|
||||||
var name = new.name;
|
var name = new.name;
|
||||||
core.engine_log("uploading mesh => {s}", .{name.utf8()});
|
// core.engine_log("uploading mesh => {s}", .{name.utf8()});
|
||||||
|
|
||||||
const indexSpan = try self.addTransfer(copyPass, self.indexBuffer, u32, &self.indexSpans, new.indices);
|
const indexSpan = try self.addTransfer(copyPass, self.indexBuffer, u32, &self.indexSpans, new.indices);
|
||||||
const vertexSpan = try self.addTransfer(copyPass, self.vertexBuffer, meshes.MeshVertex, &self.vertexSpans, new.vertices);
|
const vertexSpan = try self.addTransfer(copyPass, self.vertexBuffer, meshes.MeshVertex, &self.vertexSpans, new.vertices);
|
||||||
|
|
||||||
core.graphics_log("uploading {d} vertices and {d} indices", .{ vertexSpan.size, indexSpan.size });
|
// core.graphics_log("uploading {d} vertices and {d} indices", .{ vertexSpan.size, indexSpan.size });
|
||||||
|
|
||||||
core.engine_log("install mesh by name {d}", .{name.handle()});
|
// core.engine_log("install mesh by name {d}", .{name.handle()});
|
||||||
try self.installedMeshes.put(self.allocator, name.handle(), .{
|
try self.installedMeshes.put(self.allocator, name.handle(), .{
|
||||||
.vertex = vertexSpan,
|
.vertex = vertexSpan,
|
||||||
.index = indexSpan,
|
.index = indexSpan,
|
||||||
|
|
@ -131,7 +131,7 @@ pub const MeshPool = struct {
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
core.engine_log("uploading {s} buffer span {d}[{d}] ({d} bytes)", .{ @typeName(T), newSpan.start, newSpan.size, newSpan.size * @sizeOf(T) });
|
// core.engine_log("uploading {s} buffer span {d}[{d}] ({d} bytes)", .{ @typeName(T), newSpan.start, newSpan.size, newSpan.size * @sizeOf(T) });
|
||||||
|
|
||||||
return newSpan;
|
return newSpan;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,10 +63,14 @@ pub const Renderer = struct {
|
||||||
shadowDepthDebugOutput: *gpu.GPUTexture = undefined,
|
shadowDepthDebugOutput: *gpu.GPUTexture = undefined,
|
||||||
shadowCastingPipeline: *gpu.GPUGraphicsPipeline = undefined,
|
shadowCastingPipeline: *gpu.GPUGraphicsPipeline = undefined,
|
||||||
|
|
||||||
|
shadowDepthTextureSlot: u32 = 3,
|
||||||
|
|
||||||
skyboxSystem: *SkyboxSystem = undefined,
|
skyboxSystem: *SkyboxSystem = undefined,
|
||||||
|
|
||||||
// transients DO NOT TOUCH
|
// transients DO NOT TOUCH NORMALLY, just a way to let me make the renderer more modular and flexible for exploring
|
||||||
swapchainTexture: ?*gpu.GPUTexture = undefined,
|
// only valid when rendering
|
||||||
|
state: RendererState = .{},
|
||||||
|
// swapchainTexture: ?*gpu.GPUTexture = undefined,
|
||||||
|
|
||||||
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This());
|
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This());
|
||||||
|
|
||||||
|
|
@ -112,6 +116,7 @@ pub const Renderer = struct {
|
||||||
|
|
||||||
try self.createSamplers();
|
try self.createSamplers();
|
||||||
|
|
||||||
|
// todo... make these embedded
|
||||||
try assets.load(
|
try assets.load(
|
||||||
assets.MakeImportRefOptions(
|
assets.MakeImportRefOptions(
|
||||||
"Texture",
|
"Texture",
|
||||||
|
|
@ -133,6 +138,16 @@ pub const Renderer = struct {
|
||||||
|
|
||||||
try self.createDirectionalShadowsPipeline();
|
try self.createDirectionalShadowsPipeline();
|
||||||
self.skyboxSystem = try self.createRendererEngineObject(SkyboxSystem);
|
self.skyboxSystem = try self.createRendererEngineObject(SkyboxSystem);
|
||||||
|
|
||||||
|
_ = try core.fs().installFileBytesMount("embedded:plane.obj", @constCast(&plane_obj), true);
|
||||||
|
|
||||||
|
try assets.load(
|
||||||
|
assets.MakeImportRefOptions(
|
||||||
|
"Mesh",
|
||||||
|
"m_plane",
|
||||||
|
.{ .path = "embedded:plane.obj" },
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createDirectionalShadowsPipeline(self: *@This()) !void {
|
pub fn createDirectionalShadowsPipeline(self: *@This()) !void {
|
||||||
|
|
@ -366,7 +381,7 @@ pub const Renderer = struct {
|
||||||
|
|
||||||
// iterate over MeshComponents
|
// iterate over MeshComponents
|
||||||
for (0..uploadCount) |i| {
|
for (0..uploadCount) |i| {
|
||||||
// const object = &container.dense.items[i].value;
|
const object = &container.dense.items[i].value;
|
||||||
const objectId = container.dense.items[i].sparseIndex;
|
const objectId = container.dense.items[i].sparseIndex;
|
||||||
var transform = core.zm.identity();
|
var transform = core.zm.identity();
|
||||||
|
|
||||||
|
|
@ -374,6 +389,7 @@ pub const Renderer = struct {
|
||||||
transform = repr.transform;
|
transform = repr.transform;
|
||||||
}
|
}
|
||||||
uploadMapped[i].Model = @bitCast(transform);
|
uploadMapped[i].Model = @bitCast(transform);
|
||||||
|
uploadMapped[i].textureMode = object.textureMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -506,7 +522,7 @@ pub const Renderer = struct {
|
||||||
pub fn tick(self: *@This(), dt: f64) void {
|
pub fn tick(self: *@This(), dt: f64) void {
|
||||||
self.totalTime += dt;
|
self.totalTime += dt;
|
||||||
|
|
||||||
const cmd = self.device.acquireGPUCommandBuffer();
|
self.state.cmd = self.device.acquireGPUCommandBuffer();
|
||||||
self.frameUploads();
|
self.frameUploads();
|
||||||
|
|
||||||
// mesh pre-iteration
|
// mesh pre-iteration
|
||||||
|
|
@ -526,10 +542,10 @@ pub const Renderer = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (self.preDraws.items) |interface| {
|
for (self.preDraws.items) |interface| {
|
||||||
interface.func(interface.ptr, cmd);
|
interface.func(interface.ptr, self.state.cmd.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.draw(cmd);
|
self.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
// orthographic view projection from the sun towards the center of the thing
|
// orthographic view projection from the sun towards the center of the thing
|
||||||
|
|
@ -584,9 +600,11 @@ pub const Renderer = struct {
|
||||||
renderpass.endGPURenderPass();
|
renderpass.endGPURenderPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(self: *@This(), cmd: *gpu.GPUCommandBuffer) void {
|
pub fn draw(self: *@This()) void {
|
||||||
if (cmd.waitAndAcquireGPUSwapchainTexture(self.window, @ptrCast(&self.swapchainTexture), null, null)) {
|
const cmd = self.state.cmd.?;
|
||||||
if (self.swapchainTexture == null) {
|
|
||||||
|
if (cmd.waitAndAcquireGPUSwapchainTexture(self.window, @ptrCast(&self.state.swapchainTexture), null, null)) {
|
||||||
|
if (self.state.swapchainTexture == null) {
|
||||||
_ = cmd.submitGPUCommandBuffer();
|
_ = cmd.submitGPUCommandBuffer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -602,7 +620,7 @@ pub const Renderer = struct {
|
||||||
|
|
||||||
// can cache this
|
// can cache this
|
||||||
const targetInfo: gpu.GPUColorTargetInfo = std.mem.zeroInit(gpu.GPUColorTargetInfo, .{
|
const targetInfo: gpu.GPUColorTargetInfo = std.mem.zeroInit(gpu.GPUColorTargetInfo, .{
|
||||||
.texture = self.swapchainTexture.?,
|
.texture = self.state.swapchainTexture.?,
|
||||||
.load_op = .loadopLoad,
|
.load_op = .loadopLoad,
|
||||||
.store_op = .storeopStore,
|
.store_op = .storeopStore,
|
||||||
});
|
});
|
||||||
|
|
@ -617,7 +635,8 @@ pub const Renderer = struct {
|
||||||
.clear_stencil = 0,
|
.clear_stencil = 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
const renderpass = cmd.beginGPURenderPass(&targetInfo, 1, &depthTarget);
|
self.state.pass = cmd.beginGPURenderPass(&targetInfo, 1, &depthTarget);
|
||||||
|
const renderpass = self.state.pass.?;
|
||||||
//renderpass.bindGPUGraphicsPipeline(self.testPipeline);
|
//renderpass.bindGPUGraphicsPipeline(self.testPipeline);
|
||||||
|
|
||||||
renderpass.bindGPUVertexStorageBuffers(0, &self.ssboScene, 1);
|
renderpass.bindGPUVertexStorageBuffers(0, &self.ssboScene, 1);
|
||||||
|
|
@ -626,7 +645,7 @@ pub const Renderer = struct {
|
||||||
|
|
||||||
// render the meshes
|
// render the meshes
|
||||||
renderpass.bindGPUGraphicsPipeline(self.meshPipe);
|
renderpass.bindGPUGraphicsPipeline(self.meshPipe);
|
||||||
renderpass.bindGPUFragmentSamplers(1, &.{ .texture = self.shadowDepthTexture, .sampler = self.blockySampler }, 1);
|
renderpass.bindGPUFragmentSamplers(self.shadowDepthTextureSlot, &.{ .texture = self.shadowDepthTexture, .sampler = self.blockySampler }, 1);
|
||||||
// todo move into materials system
|
// todo move into materials system
|
||||||
|
|
||||||
renderpass.setGPUScissor(&self.scissor);
|
renderpass.setGPUScissor(&self.scissor);
|
||||||
|
|
@ -696,7 +715,7 @@ const assets = @import("assets");
|
||||||
const core = @import("core");
|
const core = @import("core");
|
||||||
const platform = @import("platform");
|
const platform = @import("platform");
|
||||||
const sdl3 = @import("sdl3");
|
const sdl3 = @import("sdl3");
|
||||||
const gpu = sdl3.gpu;
|
pub const gpu = sdl3.gpu;
|
||||||
|
|
||||||
const meshes_vert = @import("meshes.vert");
|
const meshes_vert = @import("meshes.vert");
|
||||||
const lit_mesh_frag = @import("lit_mesh.frag");
|
const lit_mesh_frag = @import("lit_mesh.frag");
|
||||||
|
|
@ -766,4 +785,14 @@ pub fn getTexture(name: *core.Name) ?*rend.Texture {
|
||||||
return gRenderer.textureList.map.get(name.handle());
|
return gRenderer.textureList.map.get(name.handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const RendererState = struct {
|
||||||
|
copyPass: ?*gpu.GPURenderPass = null,
|
||||||
|
pass: ?*gpu.GPURenderPass = null,
|
||||||
|
cmd: ?*gpu.GPUCommandBuffer = null,
|
||||||
|
swapchainTexture: ?*gpu.GPUTexture = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const CustomMeshRenderFunc = *const fn (mesh: *rend.MeshComponent, renderState: *RendererState) void;
|
||||||
pub const GPUTextureType = gpu.GPUTexture;
|
pub const GPUTextureType = gpu.GPUTexture;
|
||||||
|
|
||||||
|
const skybox_mesh_obj align(8) = @embedFile("embedded/plane.obj").*;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const mod = b.addModule("videoplayer", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = b.path("src/videoplayer.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
const dep = b.dependency("Backlog", .{ .target = target, .optimize = optimize });
|
||||||
|
mod.addImport("Backlog", dep.module("Backlog"));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const dep = b.dependency("theorafile", .{ .target = target, .optimize = optimize });
|
||||||
|
mod.addImport("theorafile", dep.module("theorafile"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
.{
|
||||||
|
.name = .gameExtras,
|
||||||
|
.version = "0.0.0",
|
||||||
|
.dependencies = .{
|
||||||
|
.Backlog = .{ .path = "../../" },
|
||||||
|
.theorafile = .{ .path = "../../lib/theoratest" },
|
||||||
|
},
|
||||||
|
.paths = .{
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
.fingerprint = 0x993cf5f438b86d4a,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
# extras
|
||||||
|
|
||||||
|
These are sample implementations of various common functionality that's meant to be in your game not really part of the engine.
|
||||||
|
|
||||||
|
To get access to these extras
|
||||||
|
|
@ -0,0 +1,247 @@
|
||||||
|
// video player implemented for sgpu,
|
||||||
|
// uses theora/ogg playback from file.
|
||||||
|
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
|
||||||
|
videoFile: OggTheora_File = undefined,
|
||||||
|
width: c_int = undefined,
|
||||||
|
height: c_int = undefined,
|
||||||
|
uvWidth: c_int = undefined,
|
||||||
|
uvHeight: c_int = undefined,
|
||||||
|
fps: f64 = undefined,
|
||||||
|
fmt: c.th_pixel_fmt = undefined,
|
||||||
|
|
||||||
|
playbackStarted: bool = false,
|
||||||
|
|
||||||
|
currentFrame: c_int = 0,
|
||||||
|
currentTime: f64 = 0.0,
|
||||||
|
|
||||||
|
showDebug: bool = true,
|
||||||
|
|
||||||
|
device: *gpu.GPUDevice = undefined,
|
||||||
|
// TH_PF_420,
|
||||||
|
// /**Currently reserved.*/
|
||||||
|
// TH_PF_RSVD,
|
||||||
|
// /**Chroma decimation by 2 in the X direction (4:2:2).
|
||||||
|
// The Cb and Cr chroma planes are half the width of the luma plane, but full
|
||||||
|
// height.*/
|
||||||
|
// TH_PF_422,
|
||||||
|
// /**No chroma decimation (4:4:4).
|
||||||
|
// The Cb and Cr chroma planes are full width and full height.*/
|
||||||
|
// TH_PF_444,
|
||||||
|
// /**The total number of currently defined pixel formats.*/
|
||||||
|
// TH_PF_NFORMATS
|
||||||
|
|
||||||
|
yTexture: *gpu.GPUTexture = undefined,
|
||||||
|
uTexture: *gpu.GPUTexture = undefined,
|
||||||
|
vTexture: *gpu.GPUTexture = undefined,
|
||||||
|
|
||||||
|
gpuTransferBuffer: *gpu.GPUTransferBuffer = undefined,
|
||||||
|
|
||||||
|
fn log(comptime fmt: []const u8, args: anytype) void {
|
||||||
|
core.engine_log("[Videoplayer] " ++ fmt, args);
|
||||||
|
}
|
||||||
|
pub fn create(allocator: std.mem.Allocator) !*@This() {
|
||||||
|
const self = try allocator.create(@This());
|
||||||
|
self.* = .{
|
||||||
|
.allocator = allocator,
|
||||||
|
};
|
||||||
|
|
||||||
|
log("initialized", .{});
|
||||||
|
|
||||||
|
self.device = rend.context().device;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn startPlayback(self: *@This(), filePath: [*c]const u8) !void {
|
||||||
|
if (c.tf_fopen(filePath, &self.videoFile) < 0) {
|
||||||
|
return error.UnableToOpenTestFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
c.tf_videoinfo(&self.videoFile, &self.width, &self.height, &self.fps, &self.fmt);
|
||||||
|
log("playing video {s}", .{filePath});
|
||||||
|
log("dimensions : {d}x{d} px {d}fps format={d}", .{ self.width, self.height, self.fps, self.fmt });
|
||||||
|
|
||||||
|
if (self.fmt == c.TH_PF_420) {
|
||||||
|
log("PF = 420", .{});
|
||||||
|
// /* Subsampled in both dimensions */
|
||||||
|
self.uvWidth = @divTrunc(self.width, 2);
|
||||||
|
self.uvHeight = @divTrunc(self.height, 2);
|
||||||
|
} else if (self.fmt == c.TH_PF_422) {
|
||||||
|
log("PF = 422", .{});
|
||||||
|
// /* Subsampled only horizontally */
|
||||||
|
self.uvWidth = @divTrunc(self.width, 2);
|
||||||
|
self.uvHeight = self.height;
|
||||||
|
} else {
|
||||||
|
// /* No subsampling at all... */
|
||||||
|
log("PF = ANY", .{});
|
||||||
|
self.uvWidth = self.width;
|
||||||
|
self.uvHeight = self.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
try self.createTextures();
|
||||||
|
|
||||||
|
// self.frame = try self.allocator.alloc(u8, @intCast(self.width * self.height * 2));
|
||||||
|
self.playbackStarted = true;
|
||||||
|
|
||||||
|
const frame = self.acquireVideoFrameBuffer();
|
||||||
|
|
||||||
|
while (c.tf_readvideo(&self.videoFile, frame.ptr, 1) == 0) {}
|
||||||
|
|
||||||
|
const cmd = rend.context().device.acquireGPUCommandBuffer();
|
||||||
|
self.device.unmapGPUTransferBuffer(self.gpuTransferBuffer);
|
||||||
|
self.releaseAndUploadFrameBuffer(cmd);
|
||||||
|
_ = cmd.submitGPUCommandBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getFrameLength(self: @This()) c_int {
|
||||||
|
return self.width * self.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn acquireVideoFrameBuffer(self: *@This()) []u8 {
|
||||||
|
var slice: []u8 = undefined;
|
||||||
|
slice.ptr = rend.context().device.mapGPUTransferBuffer(self.gpuTransferBuffer, false);
|
||||||
|
slice.len = @intCast(self.width * self.width * 2);
|
||||||
|
return slice;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn releaseAndUploadFrameBuffer(self: *@This(), cmd: *gpu.GPUCommandBuffer) void {
|
||||||
|
const copyPass = cmd.beginGPUCopyPass();
|
||||||
|
// copy Y buffer
|
||||||
|
copyPass.uploadToGPUTexture(
|
||||||
|
&.{
|
||||||
|
.transfer_buffer = self.gpuTransferBuffer,
|
||||||
|
.offset = 0,
|
||||||
|
.pixels_per_row = @intCast(self.width),
|
||||||
|
.rows_per_layer = @intCast(self.height),
|
||||||
|
},
|
||||||
|
&std.mem.zeroInit(gpu.GPUTextureRegion, .{
|
||||||
|
.texture = self.yTexture,
|
||||||
|
.w = @as(u32, @intCast(self.width)),
|
||||||
|
.h = @as(u32, @intCast(self.height)),
|
||||||
|
.d = 1,
|
||||||
|
}),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
// copy u buffer
|
||||||
|
copyPass.uploadToGPUTexture(
|
||||||
|
&.{
|
||||||
|
.transfer_buffer = self.gpuTransferBuffer,
|
||||||
|
.offset = @intCast(self.getFrameLength()),
|
||||||
|
.pixels_per_row = @intCast(self.uvWidth),
|
||||||
|
.rows_per_layer = @intCast(self.uvHeight),
|
||||||
|
},
|
||||||
|
&std.mem.zeroInit(gpu.GPUTextureRegion, .{
|
||||||
|
.texture = self.yTexture,
|
||||||
|
.w = @as(u32, @intCast(self.uvWidth)),
|
||||||
|
.h = @as(u32, @intCast(self.uvHeight)),
|
||||||
|
.d = 1,
|
||||||
|
}),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
// copy v buffer
|
||||||
|
copyPass.uploadToGPUTexture(
|
||||||
|
&.{
|
||||||
|
.transfer_buffer = self.gpuTransferBuffer,
|
||||||
|
.offset = @intCast(self.getFrameLength() + self.uvWidth * self.uvHeight),
|
||||||
|
.pixels_per_row = @intCast(self.uvWidth),
|
||||||
|
.rows_per_layer = @intCast(self.uvHeight),
|
||||||
|
},
|
||||||
|
&std.mem.zeroInit(gpu.GPUTextureRegion, .{
|
||||||
|
.texture = self.yTexture,
|
||||||
|
.w = @as(u32, @intCast(self.uvWidth)),
|
||||||
|
.h = @as(u32, @intCast(self.uvHeight)),
|
||||||
|
.d = 1,
|
||||||
|
}),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
copyPass.endGPUCopyPass();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn createTextureInner(width: c_int, height: c_int) !*gpu.GPUTexture {
|
||||||
|
const ctx = rend.context();
|
||||||
|
|
||||||
|
const gpuTexture = ctx.device.createGPUTexture(&std.mem.zeroInit(gpu.GPUTextureCreateInfo, .{
|
||||||
|
.type = .texturetype2d,
|
||||||
|
.format = .textureformatR8Unorm,
|
||||||
|
.usage = .{ .textureusageSampler = true },
|
||||||
|
.width = @as(u32, @intCast(width)),
|
||||||
|
.height = @as(u32, @intCast(height)),
|
||||||
|
.layer_count_or_depth = 1,
|
||||||
|
.num_levels = 1,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return gpuTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn createTextures(self: *@This()) !void {
|
||||||
|
self.yTexture = try createTextureInner(self.width, self.height);
|
||||||
|
self.uTexture = try createTextureInner(self.uvWidth, self.uvHeight);
|
||||||
|
self.vTexture = try createTextureInner(self.uvWidth, self.uvHeight);
|
||||||
|
|
||||||
|
// create transfer Buffer
|
||||||
|
self.gpuTransferBuffer = self.device.createGPUTransferBuffer(&.{
|
||||||
|
.usage = .transferbufferusageUpload,
|
||||||
|
.size = @as(u32, @intCast(self.width * self.height * 2)),
|
||||||
|
.props = 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick(self: *@This(), dt: f64) void {
|
||||||
|
if (!self.playbackStarted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (c.tf_eos(&self.videoFile) != 0) {
|
||||||
|
c.tf_reset(&self.videoFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.currentTime += dt;
|
||||||
|
const thisFrame: c_int = @intFromFloat(self.currentTime * self.fps);
|
||||||
|
|
||||||
|
// read the file's new frame
|
||||||
|
if (thisFrame > self.currentFrame) {
|
||||||
|
const frame = self.acquireVideoFrameBuffer();
|
||||||
|
const newFrame = c.tf_readvideo(&self.videoFile, frame.ptr, thisFrame - self.currentFrame);
|
||||||
|
|
||||||
|
if (newFrame != 0) {
|
||||||
|
const cmd = rend.context().device.acquireGPUCommandBuffer();
|
||||||
|
self.releaseAndUploadFrameBuffer(cmd);
|
||||||
|
_ = cmd.submitGPUCommandBuffer();
|
||||||
|
// kick off texture upload here
|
||||||
|
}
|
||||||
|
|
||||||
|
self.device.unmapGPUTransferBuffer(self.gpuTransferBuffer);
|
||||||
|
|
||||||
|
self.currentFrame = thisFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ig.begin("videoPlayer", &self.showDebug, .{})) {
|
||||||
|
ig.textFmt("video frame: {d}", .{self.currentFrame}) catch unreachable;
|
||||||
|
ig.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a video player entity
|
||||||
|
pub fn createVideoPlayerEntity() !core.Entity {}
|
||||||
|
|
||||||
|
pub fn destroy(self: *@This()) void {
|
||||||
|
core.engine_logs("[Videoplayer] destroying player");
|
||||||
|
|
||||||
|
if (self.playbackStarted) {}
|
||||||
|
self.allocator.destroy(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const backlog = @import("Backlog");
|
||||||
|
const core = backlog.core;
|
||||||
|
const rend = backlog.rend;
|
||||||
|
const c = @import("theorafile").c;
|
||||||
|
const gpu = rend.renderer.gpu;
|
||||||
|
|
||||||
|
const OggTheora_File = c.OggTheora_File;
|
||||||
|
|
||||||
|
const ig = backlog.imgui.api;
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
.DS_Store
|
||||||
|
xcuserdata/
|
||||||
|
*.xcworkspace/
|
||||||
|
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
# Makefile for Theorafile
|
||||||
|
# Written by Ethan "flibitijibibo" Lee
|
||||||
|
|
||||||
|
# Detect cross targets
|
||||||
|
TRIPLET=$(shell $(CC) -dumpmachine)
|
||||||
|
WINDOWS_TARGET=0
|
||||||
|
APPLE_TARGET=0
|
||||||
|
ifeq ($(OS), Windows_NT) # cygwin/msys2
|
||||||
|
WINDOWS_TARGET=1
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring w64-mingw32,$(TRIPLET)))
|
||||||
|
WINDOWS_TARGET=1
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring w64-windows,$(TRIPLET)))
|
||||||
|
WINDOWS_TARGET=1
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring apple-darwin,$(TRIPLET)))
|
||||||
|
APPLE_TARGET=1
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring x86_64,$(TRIPLET)))
|
||||||
|
DEFINES += -DOC_X86_ASM -DOC_X86_64_ASM
|
||||||
|
TFSRC_ARCH_OPT = $(TFSRC_ARCH_X86)
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring i686,$(TRIPLET)))
|
||||||
|
DEFINES += -DOC_X86_ASM
|
||||||
|
TFSRC_ARCH_OPT = $(TFSRC_ARCH_X86)
|
||||||
|
endif
|
||||||
|
# this requires the compiler to support the ARM Neon, Media, and EDSP extensions
|
||||||
|
ifneq (,$(findstring armv7,$(TRIPLET)))
|
||||||
|
DEFINES += -DOC_ARM_ASM -DOC_ARM_ASM_EDSP -DOC_ARM_ASM_MEDIA -DOC_ARM_ASM_NEON
|
||||||
|
TFSRC_ARCH_OPT = $(TFSRC_ARCH_ARM)
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring aarch64,$(TRIPLET)))
|
||||||
|
DEFINES += -DOC_ARM_ASM -DOC_ARM_ASM_EDSP -DOC_ARM_ASM_MEDIA -DOC_ARM_ASM_NEON
|
||||||
|
TFSRC_ARCH_OPT = $(TFSRC_ARCH_ARM)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Compiler
|
||||||
|
ifeq ($(WINDOWS_TARGET),1)
|
||||||
|
TARGET = dll
|
||||||
|
LDFLAGS += -static-libgcc
|
||||||
|
else ifeq ($(APPLE_TARGET),1)
|
||||||
|
CC += -mmacosx-version-min=10.9
|
||||||
|
TARGET = dylib
|
||||||
|
CFLAGS += -fpic -fPIC
|
||||||
|
LDFLAGS += -install_name @rpath/libtheorafile.dylib
|
||||||
|
else
|
||||||
|
TARGET = so
|
||||||
|
CFLAGS += -fpic -fPIC
|
||||||
|
endif
|
||||||
|
|
||||||
|
LIB = libtheorafile.$(TARGET)
|
||||||
|
|
||||||
|
CFLAGS += -O3
|
||||||
|
|
||||||
|
SRCDIR = $(dir $(MAKEFILE_LIST))
|
||||||
|
|
||||||
|
vpath %.c $(SRCDIR)
|
||||||
|
|
||||||
|
# Includes
|
||||||
|
INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/lib -I$(SRCDIR)/lib/ogg -I$(SRCDIR)/lib/vorbis -I$(SRCDIR)/lib/theora
|
||||||
|
|
||||||
|
# Source
|
||||||
|
TFSRC = $(TFSRC_ARCH_GENERIC) $(TFSRC_ARCH_OPT)
|
||||||
|
TFSRC_ARCH_GENERIC = \
|
||||||
|
theorafile.c \
|
||||||
|
lib/ogg/bitwise.c \
|
||||||
|
lib/ogg/framing.c \
|
||||||
|
lib/vorbis/analysis.c \
|
||||||
|
lib/vorbis/bitrate.c \
|
||||||
|
lib/vorbis/block.c \
|
||||||
|
lib/vorbis/codebook.c \
|
||||||
|
lib/vorbis/envelope.c \
|
||||||
|
lib/vorbis/floor0.c \
|
||||||
|
lib/vorbis/floor1.c \
|
||||||
|
lib/vorbis/vinfo.c \
|
||||||
|
lib/vorbis/lookup.c \
|
||||||
|
lib/vorbis/lpc.c \
|
||||||
|
lib/vorbis/lsp.c \
|
||||||
|
lib/vorbis/mapping0.c \
|
||||||
|
lib/vorbis/mdct.c \
|
||||||
|
lib/vorbis/psy.c \
|
||||||
|
lib/vorbis/registry.c \
|
||||||
|
lib/vorbis/res0.c \
|
||||||
|
lib/vorbis/sharedbook.c \
|
||||||
|
lib/vorbis/smallft.c \
|
||||||
|
lib/vorbis/synthesis.c \
|
||||||
|
lib/vorbis/window.c \
|
||||||
|
lib/theora/apiwrapper.c \
|
||||||
|
lib/theora/bitpack.c \
|
||||||
|
lib/theora/decapiwrapper.c \
|
||||||
|
lib/theora/decinfo.c \
|
||||||
|
lib/theora/decode.c \
|
||||||
|
lib/theora/dequant.c \
|
||||||
|
lib/theora/fragment.c \
|
||||||
|
lib/theora/huffdec.c \
|
||||||
|
lib/theora/idct.c \
|
||||||
|
lib/theora/tinfo.c \
|
||||||
|
lib/theora/internal.c \
|
||||||
|
lib/theora/quant.c \
|
||||||
|
lib/theora/state.c
|
||||||
|
TFSRC_ARCH_X86 = \
|
||||||
|
lib/theora/x86/mmxfrag.c \
|
||||||
|
lib/theora/x86/mmxidct.c \
|
||||||
|
lib/theora/x86/mmxstate.c \
|
||||||
|
lib/theora/x86/sse2idct.c \
|
||||||
|
lib/theora/x86/x86cpu.c \
|
||||||
|
lib/theora/x86/x86state.c
|
||||||
|
TFSRC_ARCH_ARM = \
|
||||||
|
lib/theora/arm-intrinsics/armcpu.c \
|
||||||
|
lib/theora/arm-intrinsics/armfrag.c \
|
||||||
|
lib/theora/arm-intrinsics/armidct.c \
|
||||||
|
lib/theora/arm-intrinsics/armloop.c \
|
||||||
|
lib/theora/arm-intrinsics/armstate.c
|
||||||
|
|
||||||
|
# Targets
|
||||||
|
.PHONY: lib all clean test
|
||||||
|
lib: $(LIB)
|
||||||
|
all: $(LIB) theorafile-test
|
||||||
|
clean:
|
||||||
|
rm -f $(LIB) theorafile-test
|
||||||
|
test: theorafile-test
|
||||||
|
$(LIB): $(TFSRC)
|
||||||
|
$(CC) $(CFLAGS) -shared -o $@ $^ $(INCLUDES) $(DEFINES) -lm $(LDFLAGS)
|
||||||
|
theorafile-test: $(TFSRC)
|
||||||
|
$(CC) $(CFLAGS) -g -o $@ sdl3test/sdl3test.c $(TFSRC) $(INCLUDES) $(DEFINES) -lSDL3 -lm
|
||||||
|
lib/theora/arm/armfrag.o: lib/theora/arm/armopts-gnu.S
|
||||||
|
.INTERMEDIATE: lib/theora/arm/armopts-gnu.S
|
||||||
|
.SUFFIXES:
|
||||||
|
%-gnu.S: %.s
|
||||||
|
lib/theora/arm/arm2gnu.pl < $< > $@
|
||||||
|
%.o: %-gnu.S
|
||||||
|
$(CC) -c -o $@ -Ilib/theora/arm $<
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
This is Theorafile, a library for quickly and easily decoding Ogg Theora videos.
|
||||||
|
|
||||||
|
Project Website: https://github.com/FNA-XNA/Theorafile
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
Theorafile is released under the zlib license.
|
||||||
|
|
||||||
|
libogg/libvorbis/libtheora are released under the BSD license.
|
||||||
|
|
||||||
|
See the licenses/ folder for details.
|
||||||
|
|
||||||
|
About Theorafile
|
||||||
|
----------------
|
||||||
|
Theorafile was written to be used for FNA's VideoPlayer. We access this library
|
||||||
|
via Theorafile#, which you can find in the 'csharp/' directory.
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
------------
|
||||||
|
Theorafile depends solely on the C runtime. libogg, libvorbis, and libtheoradec
|
||||||
|
are statically linked into Theorafile.
|
||||||
|
|
||||||
|
Theorafile's "sdl3test" test program requires SDL3.
|
||||||
|
|
||||||
|
Building Theorafile
|
||||||
|
-------------------
|
||||||
|
For *nix platforms, just type `make` in the root directory!
|
||||||
|
|
||||||
|
For Windows, see the 'visualc/' directory.
|
||||||
|
|
||||||
|
For Xbox GDK, see the 'visualc-gdk/' directory.
|
||||||
|
|
||||||
|
For iOS/tvOS and macOS universal binaries, see the 'Xcode/' directory.
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const theorafile = b.addModule(
|
||||||
|
"theorafile",
|
||||||
|
.{
|
||||||
|
.optimize = optimize,
|
||||||
|
.target = target,
|
||||||
|
.root_source_file = b.path("theorafile.zig"),
|
||||||
|
.link_libc = true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const sdl_dep = b.dependency("sdl", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
const sdl_lib = sdl_dep.artifact("SDL3");
|
||||||
|
theorafile.linkLibrary(sdl_lib);
|
||||||
|
theorafile.addIncludePath(b.path("../sdl3/SDL/include"));
|
||||||
|
theorafile.addIncludePath(b.path("lib/ogg"));
|
||||||
|
theorafile.addIncludePath(b.path("lib/theora"));
|
||||||
|
theorafile.addIncludePath(b.path("lib/vorbis"));
|
||||||
|
theorafile.addIncludePath(b.path("lib"));
|
||||||
|
theorafile.addIncludePath(b.path("."));
|
||||||
|
|
||||||
|
theorafile.addCSourceFiles(.{
|
||||||
|
.files = &.{
|
||||||
|
"theorafile.c",
|
||||||
|
"lib/ogg/bitwise.c",
|
||||||
|
"lib/ogg/framing.c",
|
||||||
|
"lib/vorbis/analysis.c",
|
||||||
|
"lib/vorbis/bitrate.c",
|
||||||
|
"lib/vorbis/block.c",
|
||||||
|
"lib/vorbis/codebook.c",
|
||||||
|
"lib/vorbis/envelope.c",
|
||||||
|
"lib/vorbis/floor0.c",
|
||||||
|
"lib/vorbis/floor1.c",
|
||||||
|
"lib/vorbis/vinfo.c",
|
||||||
|
"lib/vorbis/lookup.c",
|
||||||
|
"lib/vorbis/lpc.c",
|
||||||
|
"lib/vorbis/lsp.c",
|
||||||
|
"lib/vorbis/mapping0.c",
|
||||||
|
"lib/vorbis/mdct.c",
|
||||||
|
"lib/vorbis/psy.c",
|
||||||
|
"lib/vorbis/registry.c",
|
||||||
|
"lib/vorbis/res0.c",
|
||||||
|
"lib/vorbis/sharedbook.c",
|
||||||
|
"lib/vorbis/smallft.c",
|
||||||
|
"lib/vorbis/synthesis.c",
|
||||||
|
"lib/vorbis/window.c",
|
||||||
|
"lib/theora/apiwrapper.c",
|
||||||
|
"lib/theora/bitpack.c",
|
||||||
|
"lib/theora/decapiwrapper.c",
|
||||||
|
"lib/theora/decinfo.c",
|
||||||
|
"lib/theora/decode.c",
|
||||||
|
"lib/theora/dequant.c",
|
||||||
|
"lib/theora/fragment.c",
|
||||||
|
"lib/theora/huffdec.c",
|
||||||
|
"lib/theora/idct.c",
|
||||||
|
"lib/theora/tinfo.c",
|
||||||
|
"lib/theora/internal.c",
|
||||||
|
"lib/theora/quant.c",
|
||||||
|
"lib/theora/state.c",
|
||||||
|
},
|
||||||
|
.flags = &.{
|
||||||
|
"-fno-sanitize=undefined",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
theorafile.addCSourceFiles(.{
|
||||||
|
.files = &.{
|
||||||
|
"lib/theora/x86/mmxfrag.c",
|
||||||
|
"lib/theora/x86/mmxidct.c",
|
||||||
|
"lib/theora/x86/mmxstate.c",
|
||||||
|
"lib/theora/x86/sse2idct.c",
|
||||||
|
"lib/theora/x86/x86cpu.c",
|
||||||
|
"lib/theora/x86/x86state.c",
|
||||||
|
},
|
||||||
|
.flags = &.{
|
||||||
|
"-fno-sanitize=undefined",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// TFSRC_ARCH_X86 ="
|
||||||
|
// lib/theora/x86/mmxfrag.c \
|
||||||
|
// lib/theora/x86/mmxidct.c \
|
||||||
|
// lib/theora/x86/mmxstate.c \
|
||||||
|
// lib/theora/x86/sse2idct.c \
|
||||||
|
// lib/theora/x86/x86cpu.c \
|
||||||
|
// lib/theora/x86/x86state.c
|
||||||
|
// link theorafile
|
||||||
|
|
||||||
|
const test_step = b.step("test", "run unit tests for sdl3");
|
||||||
|
const tests = b.addExecutable(.{
|
||||||
|
.name = "test",
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.link_libc = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
tests.addCSourceFile(.{
|
||||||
|
.file = b.path("sdl3test/sdl3test.c"),
|
||||||
|
.flags = &.{
|
||||||
|
"-fno-sanitize=undefined",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
tests.root_module.addImport("theorafile", theorafile);
|
||||||
|
|
||||||
|
tests.root_module.addIncludePath(b.path("../sdl3/SDL/include"));
|
||||||
|
tests.root_module.addIncludePath(b.path("lib/ogg"));
|
||||||
|
tests.root_module.addIncludePath(b.path("lib/theora"));
|
||||||
|
tests.root_module.addIncludePath(b.path("lib/vorbis"));
|
||||||
|
tests.root_module.addIncludePath(b.path("lib"));
|
||||||
|
|
||||||
|
tests.root_module.addIncludePath(b.path("."));
|
||||||
|
tests.root_module.addIncludePath(b.path("sdl3test"));
|
||||||
|
|
||||||
|
const runArtifact = b.addRunArtifact(tests);
|
||||||
|
test_step.dependOn(&runArtifact.step);
|
||||||
|
b.installArtifact(tests);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
.{
|
||||||
|
.name = .theorafile,
|
||||||
|
.version = "0.0.0",
|
||||||
|
.dependencies = .{
|
||||||
|
.sdl = .{ .path = "../sdl3/SDL" },
|
||||||
|
},
|
||||||
|
.paths = .{
|
||||||
|
""
|
||||||
|
},
|
||||||
|
.fingerprint = 0x5105e7c085faf2fb,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub const c = @cImport(
|
||||||
|
@cInclude("theorafile.h"),
|
||||||
|
);
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
This is a local copy of the Xiph libs used by Theorafile, with all the unused
|
||||||
|
files stripped out. Below are the notes for each library.
|
||||||
|
|
||||||
|
libogg: Version 1.3.3
|
||||||
|
- os_types.h falls back to stdint for unrecognized platforms
|
||||||
|
libvorbis: Version 1.3.6
|
||||||
|
- info.c has been renamed to vinfo.c
|
||||||
|
libtheora: git commit 7180717276af1ebc7da15c83162d6c5d6203aabf
|
||||||
|
- info.c has been renamed to tinfo.c
|
||||||
|
- AArch64 NEON support from https://github.com/linnaea/theora
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,210 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: toplevel libogg include
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
#ifndef _OGG_H
|
||||||
|
#define _OGG_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <ogg/os_types.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *iov_base;
|
||||||
|
size_t iov_len;
|
||||||
|
} ogg_iovec_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
long endbyte;
|
||||||
|
int endbit;
|
||||||
|
|
||||||
|
unsigned char *buffer;
|
||||||
|
unsigned char *ptr;
|
||||||
|
long storage;
|
||||||
|
} oggpack_buffer;
|
||||||
|
|
||||||
|
/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char *header;
|
||||||
|
long header_len;
|
||||||
|
unsigned char *body;
|
||||||
|
long body_len;
|
||||||
|
} ogg_page;
|
||||||
|
|
||||||
|
/* ogg_stream_state contains the current encode/decode state of a logical
|
||||||
|
Ogg bitstream **********************************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char *body_data; /* bytes from packet bodies */
|
||||||
|
long body_storage; /* storage elements allocated */
|
||||||
|
long body_fill; /* elements stored; fill mark */
|
||||||
|
long body_returned; /* elements of fill returned */
|
||||||
|
|
||||||
|
|
||||||
|
int *lacing_vals; /* The values that will go to the segment table */
|
||||||
|
ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
|
||||||
|
this way, but it is simple coupled to the
|
||||||
|
lacing fifo */
|
||||||
|
long lacing_storage;
|
||||||
|
long lacing_fill;
|
||||||
|
long lacing_packet;
|
||||||
|
long lacing_returned;
|
||||||
|
|
||||||
|
unsigned char header[282]; /* working space for header encode */
|
||||||
|
int header_fill;
|
||||||
|
|
||||||
|
int e_o_s; /* set when we have buffered the last packet in the
|
||||||
|
logical bitstream */
|
||||||
|
int b_o_s; /* set after we've written the initial page
|
||||||
|
of a logical bitstream */
|
||||||
|
long serialno;
|
||||||
|
long pageno;
|
||||||
|
ogg_int64_t packetno; /* sequence number for decode; the framing
|
||||||
|
knows where there's a hole in the data,
|
||||||
|
but we need coupling so that the codec
|
||||||
|
(which is in a separate abstraction
|
||||||
|
layer) also knows about the gap */
|
||||||
|
ogg_int64_t granulepos;
|
||||||
|
|
||||||
|
} ogg_stream_state;
|
||||||
|
|
||||||
|
/* ogg_packet is used to encapsulate the data and metadata belonging
|
||||||
|
to a single raw Ogg/Vorbis packet *************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char *packet;
|
||||||
|
long bytes;
|
||||||
|
long b_o_s;
|
||||||
|
long e_o_s;
|
||||||
|
|
||||||
|
ogg_int64_t granulepos;
|
||||||
|
|
||||||
|
ogg_int64_t packetno; /* sequence number for decode; the framing
|
||||||
|
knows where there's a hole in the data,
|
||||||
|
but we need coupling so that the codec
|
||||||
|
(which is in a separate abstraction
|
||||||
|
layer) also knows about the gap */
|
||||||
|
} ogg_packet;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char *data;
|
||||||
|
int storage;
|
||||||
|
int fill;
|
||||||
|
int returned;
|
||||||
|
|
||||||
|
int unsynced;
|
||||||
|
int headerbytes;
|
||||||
|
int bodybytes;
|
||||||
|
} ogg_sync_state;
|
||||||
|
|
||||||
|
/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/
|
||||||
|
|
||||||
|
extern void oggpack_writeinit(oggpack_buffer *b);
|
||||||
|
extern int oggpack_writecheck(oggpack_buffer *b);
|
||||||
|
extern void oggpack_writetrunc(oggpack_buffer *b,long bits);
|
||||||
|
extern void oggpack_writealign(oggpack_buffer *b);
|
||||||
|
extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits);
|
||||||
|
extern void oggpack_reset(oggpack_buffer *b);
|
||||||
|
extern void oggpack_writeclear(oggpack_buffer *b);
|
||||||
|
extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
|
||||||
|
extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits);
|
||||||
|
extern long oggpack_look(oggpack_buffer *b,int bits);
|
||||||
|
extern long oggpack_look1(oggpack_buffer *b);
|
||||||
|
extern void oggpack_adv(oggpack_buffer *b,int bits);
|
||||||
|
extern void oggpack_adv1(oggpack_buffer *b);
|
||||||
|
extern long oggpack_read(oggpack_buffer *b,int bits);
|
||||||
|
extern long oggpack_read1(oggpack_buffer *b);
|
||||||
|
extern long oggpack_bytes(oggpack_buffer *b);
|
||||||
|
extern long oggpack_bits(oggpack_buffer *b);
|
||||||
|
extern unsigned char *oggpack_get_buffer(oggpack_buffer *b);
|
||||||
|
|
||||||
|
extern void oggpackB_writeinit(oggpack_buffer *b);
|
||||||
|
extern int oggpackB_writecheck(oggpack_buffer *b);
|
||||||
|
extern void oggpackB_writetrunc(oggpack_buffer *b,long bits);
|
||||||
|
extern void oggpackB_writealign(oggpack_buffer *b);
|
||||||
|
extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits);
|
||||||
|
extern void oggpackB_reset(oggpack_buffer *b);
|
||||||
|
extern void oggpackB_writeclear(oggpack_buffer *b);
|
||||||
|
extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
|
||||||
|
extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits);
|
||||||
|
extern long oggpackB_look(oggpack_buffer *b,int bits);
|
||||||
|
extern long oggpackB_look1(oggpack_buffer *b);
|
||||||
|
extern void oggpackB_adv(oggpack_buffer *b,int bits);
|
||||||
|
extern void oggpackB_adv1(oggpack_buffer *b);
|
||||||
|
extern long oggpackB_read(oggpack_buffer *b,int bits);
|
||||||
|
extern long oggpackB_read1(oggpack_buffer *b);
|
||||||
|
extern long oggpackB_bytes(oggpack_buffer *b);
|
||||||
|
extern long oggpackB_bits(oggpack_buffer *b);
|
||||||
|
extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b);
|
||||||
|
|
||||||
|
/* Ogg BITSTREAM PRIMITIVES: encoding **************************/
|
||||||
|
|
||||||
|
extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op);
|
||||||
|
extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov,
|
||||||
|
int count, long e_o_s, ogg_int64_t granulepos);
|
||||||
|
extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og);
|
||||||
|
extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill);
|
||||||
|
extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og);
|
||||||
|
extern int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill);
|
||||||
|
|
||||||
|
/* Ogg BITSTREAM PRIMITIVES: decoding **************************/
|
||||||
|
|
||||||
|
extern int ogg_sync_init(ogg_sync_state *oy);
|
||||||
|
extern int ogg_sync_clear(ogg_sync_state *oy);
|
||||||
|
extern int ogg_sync_reset(ogg_sync_state *oy);
|
||||||
|
extern int ogg_sync_destroy(ogg_sync_state *oy);
|
||||||
|
extern int ogg_sync_check(ogg_sync_state *oy);
|
||||||
|
|
||||||
|
extern char *ogg_sync_buffer(ogg_sync_state *oy, long size);
|
||||||
|
extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes);
|
||||||
|
extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
|
||||||
|
extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
|
||||||
|
extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
|
||||||
|
extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
|
||||||
|
extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);
|
||||||
|
|
||||||
|
/* Ogg BITSTREAM PRIMITIVES: general ***************************/
|
||||||
|
|
||||||
|
extern int ogg_stream_init(ogg_stream_state *os,int serialno);
|
||||||
|
extern int ogg_stream_clear(ogg_stream_state *os);
|
||||||
|
extern int ogg_stream_reset(ogg_stream_state *os);
|
||||||
|
extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno);
|
||||||
|
extern int ogg_stream_destroy(ogg_stream_state *os);
|
||||||
|
extern int ogg_stream_check(ogg_stream_state *os);
|
||||||
|
extern int ogg_stream_eos(ogg_stream_state *os);
|
||||||
|
|
||||||
|
extern void ogg_page_checksum_set(ogg_page *og);
|
||||||
|
|
||||||
|
extern int ogg_page_version(const ogg_page *og);
|
||||||
|
extern int ogg_page_continued(const ogg_page *og);
|
||||||
|
extern int ogg_page_bos(const ogg_page *og);
|
||||||
|
extern int ogg_page_eos(const ogg_page *og);
|
||||||
|
extern ogg_int64_t ogg_page_granulepos(const ogg_page *og);
|
||||||
|
extern int ogg_page_serialno(const ogg_page *og);
|
||||||
|
extern long ogg_page_pageno(const ogg_page *og);
|
||||||
|
extern int ogg_page_packets(const ogg_page *og);
|
||||||
|
|
||||||
|
extern void ogg_packet_clear(ogg_packet *op);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _OGG_H */
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: #ifdef jail to whip a few platforms into the UNIX ideal.
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
#ifndef _OS_TYPES_H
|
||||||
|
#define _OS_TYPES_H
|
||||||
|
|
||||||
|
/* make it easy on the folks that want to compile the libs with a
|
||||||
|
different malloc than stdlib */
|
||||||
|
#define _ogg_malloc malloc
|
||||||
|
#define _ogg_calloc calloc
|
||||||
|
#define _ogg_realloc realloc
|
||||||
|
#define _ogg_free free
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
# if defined(__CYGWIN__)
|
||||||
|
# include <stdint.h>
|
||||||
|
typedef int16_t ogg_int16_t;
|
||||||
|
typedef uint16_t ogg_uint16_t;
|
||||||
|
typedef int32_t ogg_int32_t;
|
||||||
|
typedef uint32_t ogg_uint32_t;
|
||||||
|
typedef int64_t ogg_int64_t;
|
||||||
|
typedef uint64_t ogg_uint64_t;
|
||||||
|
# elif defined(__MINGW32__)
|
||||||
|
# include <sys/types.h>
|
||||||
|
typedef short ogg_int16_t;
|
||||||
|
typedef unsigned short ogg_uint16_t;
|
||||||
|
typedef int ogg_int32_t;
|
||||||
|
typedef unsigned int ogg_uint32_t;
|
||||||
|
typedef long long ogg_int64_t;
|
||||||
|
typedef unsigned long long ogg_uint64_t;
|
||||||
|
# elif defined(__MWERKS__)
|
||||||
|
typedef long long ogg_int64_t;
|
||||||
|
typedef int ogg_int32_t;
|
||||||
|
typedef unsigned int ogg_uint32_t;
|
||||||
|
typedef short ogg_int16_t;
|
||||||
|
typedef unsigned short ogg_uint16_t;
|
||||||
|
# else
|
||||||
|
# if defined(_MSC_VER) && (_MSC_VER >= 1800) /* MSVC 2013 and newer */
|
||||||
|
# include <stdint.h>
|
||||||
|
typedef int16_t ogg_int16_t;
|
||||||
|
typedef uint16_t ogg_uint16_t;
|
||||||
|
typedef int32_t ogg_int32_t;
|
||||||
|
typedef uint32_t ogg_uint32_t;
|
||||||
|
typedef int64_t ogg_int64_t;
|
||||||
|
typedef uint64_t ogg_uint64_t;
|
||||||
|
# else
|
||||||
|
/* MSVC/Borland */
|
||||||
|
typedef __int64 ogg_int64_t;
|
||||||
|
typedef __int32 ogg_int32_t;
|
||||||
|
typedef unsigned __int32 ogg_uint32_t;
|
||||||
|
typedef __int16 ogg_int16_t;
|
||||||
|
typedef unsigned __int16 ogg_uint16_t;
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
|
||||||
|
|
||||||
|
# include <inttypes.h>
|
||||||
|
typedef int16_t ogg_int16_t;
|
||||||
|
typedef uint16_t ogg_uint16_t;
|
||||||
|
typedef int32_t ogg_int32_t;
|
||||||
|
typedef uint32_t ogg_uint32_t;
|
||||||
|
typedef int64_t ogg_int64_t;
|
||||||
|
|
||||||
|
#elif defined(__HAIKU__)
|
||||||
|
|
||||||
|
/* Haiku */
|
||||||
|
# include <sys/types.h>
|
||||||
|
typedef short ogg_int16_t;
|
||||||
|
typedef unsigned short ogg_uint16_t;
|
||||||
|
typedef int ogg_int32_t;
|
||||||
|
typedef unsigned int ogg_uint32_t;
|
||||||
|
typedef long long ogg_int64_t;
|
||||||
|
|
||||||
|
#elif defined(__BEOS__)
|
||||||
|
|
||||||
|
/* Be */
|
||||||
|
# include <inttypes.h>
|
||||||
|
typedef int16_t ogg_int16_t;
|
||||||
|
typedef uint16_t ogg_uint16_t;
|
||||||
|
typedef int32_t ogg_int32_t;
|
||||||
|
typedef uint32_t ogg_uint32_t;
|
||||||
|
typedef int64_t ogg_int64_t;
|
||||||
|
|
||||||
|
#elif defined (__EMX__)
|
||||||
|
|
||||||
|
/* OS/2 GCC */
|
||||||
|
typedef short ogg_int16_t;
|
||||||
|
typedef unsigned short ogg_uint16_t;
|
||||||
|
typedef int ogg_int32_t;
|
||||||
|
typedef unsigned int ogg_uint32_t;
|
||||||
|
typedef long long ogg_int64_t;
|
||||||
|
|
||||||
|
#elif defined (DJGPP)
|
||||||
|
|
||||||
|
/* DJGPP */
|
||||||
|
typedef short ogg_int16_t;
|
||||||
|
typedef int ogg_int32_t;
|
||||||
|
typedef unsigned int ogg_uint32_t;
|
||||||
|
typedef long long ogg_int64_t;
|
||||||
|
|
||||||
|
#elif defined(R5900)
|
||||||
|
|
||||||
|
/* PS2 EE */
|
||||||
|
typedef long ogg_int64_t;
|
||||||
|
typedef int ogg_int32_t;
|
||||||
|
typedef unsigned ogg_uint32_t;
|
||||||
|
typedef short ogg_int16_t;
|
||||||
|
|
||||||
|
#elif defined(__SYMBIAN32__)
|
||||||
|
|
||||||
|
/* Symbian GCC */
|
||||||
|
typedef signed short ogg_int16_t;
|
||||||
|
typedef unsigned short ogg_uint16_t;
|
||||||
|
typedef signed int ogg_int32_t;
|
||||||
|
typedef unsigned int ogg_uint32_t;
|
||||||
|
typedef long long int ogg_int64_t;
|
||||||
|
|
||||||
|
#elif defined(__TMS320C6X__)
|
||||||
|
|
||||||
|
/* TI C64x compiler */
|
||||||
|
typedef signed short ogg_int16_t;
|
||||||
|
typedef unsigned short ogg_uint16_t;
|
||||||
|
typedef signed int ogg_int32_t;
|
||||||
|
typedef unsigned int ogg_uint32_t;
|
||||||
|
typedef long long int ogg_int64_t;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Theorafile change! We assume you have stdint... */
|
||||||
|
# include <stdint.h>
|
||||||
|
typedef int16_t ogg_int16_t;
|
||||||
|
typedef uint16_t ogg_uint16_t;
|
||||||
|
typedef int32_t ogg_int32_t;
|
||||||
|
typedef uint32_t ogg_uint32_t;
|
||||||
|
typedef int64_t ogg_int64_t;
|
||||||
|
typedef uint64_t ogg_uint64_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _OS_TYPES_H */
|
||||||
|
|
@ -0,0 +1,166 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include "apiwrapper.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const char *theora_version_string(void){
|
||||||
|
return th_version_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
ogg_uint32_t theora_version_number(void){
|
||||||
|
return th_version_number();
|
||||||
|
}
|
||||||
|
|
||||||
|
void theora_info_init(theora_info *_ci){
|
||||||
|
memset(_ci,0,sizeof(*_ci));
|
||||||
|
}
|
||||||
|
|
||||||
|
void theora_info_clear(theora_info *_ci){
|
||||||
|
th_api_wrapper *api;
|
||||||
|
api=(th_api_wrapper *)_ci->codec_setup;
|
||||||
|
memset(_ci,0,sizeof(*_ci));
|
||||||
|
if(api!=NULL){
|
||||||
|
if(api->clear!=NULL)(*api->clear)(api);
|
||||||
|
_ogg_free(api);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void theora_clear(theora_state *_th){
|
||||||
|
/*Provide compatibility with mixed encoder and decoder shared lib versions.*/
|
||||||
|
if(_th->internal_decode!=NULL){
|
||||||
|
(*((oc_state_dispatch_vtable *)_th->internal_decode)->clear)(_th);
|
||||||
|
}
|
||||||
|
if(_th->internal_encode!=NULL){
|
||||||
|
(*((oc_state_dispatch_vtable *)_th->internal_encode)->clear)(_th);
|
||||||
|
}
|
||||||
|
if(_th->i!=NULL)theora_info_clear(_th->i);
|
||||||
|
memset(_th,0,sizeof(*_th));
|
||||||
|
}
|
||||||
|
|
||||||
|
int theora_control(theora_state *_th,int _req,void *_buf,size_t _buf_sz){
|
||||||
|
/*Provide compatibility with mixed encoder and decoder shared lib versions.*/
|
||||||
|
if(_th->internal_decode!=NULL){
|
||||||
|
return (*((oc_state_dispatch_vtable *)_th->internal_decode)->control)(_th,
|
||||||
|
_req,_buf,_buf_sz);
|
||||||
|
}
|
||||||
|
else if(_th->internal_encode!=NULL){
|
||||||
|
return (*((oc_state_dispatch_vtable *)_th->internal_encode)->control)(_th,
|
||||||
|
_req,_buf,_buf_sz);
|
||||||
|
}
|
||||||
|
else return TH_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ogg_int64_t theora_granule_frame(theora_state *_th,ogg_int64_t _gp){
|
||||||
|
/*Provide compatibility with mixed encoder and decoder shared lib versions.*/
|
||||||
|
if(_th->internal_decode!=NULL){
|
||||||
|
return (*((oc_state_dispatch_vtable *)_th->internal_decode)->granule_frame)(
|
||||||
|
_th,_gp);
|
||||||
|
}
|
||||||
|
else if(_th->internal_encode!=NULL){
|
||||||
|
return (*((oc_state_dispatch_vtable *)_th->internal_encode)->granule_frame)(
|
||||||
|
_th,_gp);
|
||||||
|
}
|
||||||
|
else return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
double theora_granule_time(theora_state *_th, ogg_int64_t _gp){
|
||||||
|
/*Provide compatibility with mixed encoder and decoder shared lib versions.*/
|
||||||
|
if(_th->internal_decode!=NULL){
|
||||||
|
return (*((oc_state_dispatch_vtable *)_th->internal_decode)->granule_time)(
|
||||||
|
_th,_gp);
|
||||||
|
}
|
||||||
|
else if(_th->internal_encode!=NULL){
|
||||||
|
return (*((oc_state_dispatch_vtable *)_th->internal_encode)->granule_time)(
|
||||||
|
_th,_gp);
|
||||||
|
}
|
||||||
|
else return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_theora_info2th_info(th_info *_info,const theora_info *_ci){
|
||||||
|
_info->version_major=_ci->version_major;
|
||||||
|
_info->version_minor=_ci->version_minor;
|
||||||
|
_info->version_subminor=_ci->version_subminor;
|
||||||
|
_info->frame_width=_ci->width;
|
||||||
|
_info->frame_height=_ci->height;
|
||||||
|
_info->pic_width=_ci->frame_width;
|
||||||
|
_info->pic_height=_ci->frame_height;
|
||||||
|
_info->pic_x=_ci->offset_x;
|
||||||
|
_info->pic_y=_ci->offset_y;
|
||||||
|
_info->fps_numerator=_ci->fps_numerator;
|
||||||
|
_info->fps_denominator=_ci->fps_denominator;
|
||||||
|
_info->aspect_numerator=_ci->aspect_numerator;
|
||||||
|
_info->aspect_denominator=_ci->aspect_denominator;
|
||||||
|
switch(_ci->colorspace){
|
||||||
|
case OC_CS_ITU_REC_470M:_info->colorspace=TH_CS_ITU_REC_470M;break;
|
||||||
|
case OC_CS_ITU_REC_470BG:_info->colorspace=TH_CS_ITU_REC_470BG;break;
|
||||||
|
default:_info->colorspace=TH_CS_UNSPECIFIED;break;
|
||||||
|
}
|
||||||
|
switch(_ci->pixelformat){
|
||||||
|
case OC_PF_420:_info->pixel_fmt=TH_PF_420;break;
|
||||||
|
case OC_PF_422:_info->pixel_fmt=TH_PF_422;break;
|
||||||
|
case OC_PF_444:_info->pixel_fmt=TH_PF_444;break;
|
||||||
|
default:_info->pixel_fmt=TH_PF_RSVD;
|
||||||
|
}
|
||||||
|
_info->target_bitrate=_ci->target_bitrate;
|
||||||
|
_info->quality=_ci->quality;
|
||||||
|
_info->keyframe_granule_shift=_ci->keyframe_frequency_force>0?
|
||||||
|
OC_MINI(31,oc_ilog(_ci->keyframe_frequency_force-1)):0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int theora_packet_isheader(ogg_packet *_op){
|
||||||
|
return th_packet_isheader(_op);
|
||||||
|
}
|
||||||
|
|
||||||
|
int theora_packet_iskeyframe(ogg_packet *_op){
|
||||||
|
return th_packet_iskeyframe(_op);
|
||||||
|
}
|
||||||
|
|
||||||
|
int theora_granule_shift(theora_info *_ci){
|
||||||
|
/*This breaks when keyframe_frequency_force is not positive or is larger than
|
||||||
|
2**31 (if your int is more than 32 bits), but that's what the original
|
||||||
|
function does.*/
|
||||||
|
return oc_ilog(_ci->keyframe_frequency_force-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void theora_comment_init(theora_comment *_tc){
|
||||||
|
th_comment_init((th_comment *)_tc);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *theora_comment_query(theora_comment *_tc,char *_tag,int _count){
|
||||||
|
return th_comment_query((th_comment *)_tc,_tag,_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
int theora_comment_query_count(theora_comment *_tc,char *_tag){
|
||||||
|
return th_comment_query_count((th_comment *)_tc,_tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void theora_comment_clear(theora_comment *_tc){
|
||||||
|
th_comment_clear((th_comment *)_tc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void theora_comment_add(theora_comment *_tc,char *_comment){
|
||||||
|
th_comment_add((th_comment *)_tc,_comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
void theora_comment_add_tag(theora_comment *_tc, char *_tag, char *_value){
|
||||||
|
th_comment_add_tag((th_comment *)_tc,_tag,_value);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id: apiwrapper.h 13596 2007-08-23 20:05:38Z tterribe $
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#if !defined(_apiwrapper_H)
|
||||||
|
# define _apiwrapper_H (1)
|
||||||
|
# include <ogg/ogg.h>
|
||||||
|
# include <theora/theora.h>
|
||||||
|
# include "theora/theoradec.h"
|
||||||
|
# include "theora/theoraenc.h"
|
||||||
|
# include "state.h"
|
||||||
|
|
||||||
|
typedef struct th_api_wrapper th_api_wrapper;
|
||||||
|
typedef struct th_api_info th_api_info;
|
||||||
|
|
||||||
|
/*Provide an entry point for the codec setup to clear itself in case we ever
|
||||||
|
want to break pieces off into a common base library shared by encoder and
|
||||||
|
decoder.
|
||||||
|
In addition, this makes several other pieces of the API wrapper cleaner.*/
|
||||||
|
typedef void (*oc_setup_clear_func)(void *_ts);
|
||||||
|
|
||||||
|
/*Generally only one of these pointers will be non-NULL in any given instance.
|
||||||
|
Technically we do not even really need this struct, since we should be able
|
||||||
|
to figure out which one from "context", but doing it this way makes sure we
|
||||||
|
don't flub it up.*/
|
||||||
|
struct th_api_wrapper{
|
||||||
|
oc_setup_clear_func clear;
|
||||||
|
th_setup_info *setup;
|
||||||
|
th_dec_ctx *decode;
|
||||||
|
th_enc_ctx *encode;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct th_api_info{
|
||||||
|
th_api_wrapper api;
|
||||||
|
theora_info info;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void oc_theora_info2th_info(th_info *_info,const theora_info *_ci);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2010 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
CPU capability detection for ARM processors.
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id: cpu.c 17344 2010-07-21 01:42:18Z tterribe $
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include "armcpu.h"
|
||||||
|
|
||||||
|
#if !defined(OC_ARM_ASM) || !defined(OC_ARM_ASM_NEON)
|
||||||
|
ogg_uint32_t oc_cpu_flags_get(void){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__aarch64__) || defined(_M_ARM64)
|
||||||
|
ogg_uint32_t oc_cpu_flags_get(void) {
|
||||||
|
return OC_CPU_ARM_NEON;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
/*For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION.*/
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# define WIN32_EXTRA_LEAN
|
||||||
|
# include <windows.h>
|
||||||
|
|
||||||
|
ogg_uint32_t oc_cpu_flags_get(void){
|
||||||
|
ogg_uint32_t flags;
|
||||||
|
flags=0;
|
||||||
|
/*MSVC has no inline __asm support for ARM, but it does let you __emit
|
||||||
|
instructions via their assembled hex code.
|
||||||
|
All of these instructions should be essentially nops.*/
|
||||||
|
# if defined(OC_ARM_ASM_NEON)
|
||||||
|
__try{
|
||||||
|
# if defined(__aarch64__) || defined(_M_ARM64)
|
||||||
|
/*MOV v0.16B,v0.16B*/
|
||||||
|
__emit(0x4EA01C00);
|
||||||
|
# else
|
||||||
|
/*VORR q0,q0,q0*/
|
||||||
|
__emit(0xF2200150);
|
||||||
|
# endif
|
||||||
|
flags|=OC_CPU_ARM_NEON;
|
||||||
|
}
|
||||||
|
__except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
|
||||||
|
/*Ignore exception.*/
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__linux__)
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <string.h>
|
||||||
|
|
||||||
|
ogg_uint32_t oc_cpu_flags_get(void){
|
||||||
|
ogg_uint32_t flags;
|
||||||
|
FILE *fin;
|
||||||
|
flags=0;
|
||||||
|
/*Reading /proc/self/auxv would be easier, but that doesn't work reliably on
|
||||||
|
Android.
|
||||||
|
This also means that detection will fail in Scratchbox.*/
|
||||||
|
fin=fopen("/proc/cpuinfo","r");
|
||||||
|
if(fin!=NULL){
|
||||||
|
/*512 should be enough for anybody (it's even enough for all the flags that
|
||||||
|
x86 has accumulated... so far).*/
|
||||||
|
char buf[512];
|
||||||
|
while(fgets(buf,511,fin)!=NULL){
|
||||||
|
if(memcmp(buf,"Features",8)==0){
|
||||||
|
char *p;
|
||||||
|
p=strstr(buf," neon");
|
||||||
|
if(p!=NULL&&(p[5]==' '||p[5]=='\n'))flags|=OC_CPU_ARM_NEON;
|
||||||
|
p=strstr(buf," asimd");
|
||||||
|
if(p!=NULL&&(p[6]==' '||p[6]=='\n'))flags|=OC_CPU_ARM_NEON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fin);
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__riscos__)
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <swis.h>
|
||||||
|
|
||||||
|
ogg_uint32_t oc_cpu_flags_get(void) {
|
||||||
|
ogg_uint32_t flags = 0;
|
||||||
|
|
||||||
|
#if defined(OC_ARM_ASM_NEON)
|
||||||
|
ogg_uint32_t mvfr1;
|
||||||
|
test = _swix(VFPSupport_Features, _IN(0)|_OUT(2), 0, &mvfr1);
|
||||||
|
if (test==NULL && (mvfr1 & 0xFFF00)==0x11100)flags|=OC_CPU_ARM_NEON;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
/*The feature registers which can tell us what the processor supports are
|
||||||
|
accessible in priveleged modes only, so we can't have a general user-space
|
||||||
|
detection method like on x86.*/
|
||||||
|
# error "Configured to use ARM asm but no CPU detection method available for " \
|
||||||
|
"your platform. Reconfigure with --disable-asm (or send patches)."
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2010 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
function:
|
||||||
|
last mod: $Id: cpu.h 17344 2010-07-21 01:42:18Z tterribe $
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#if !defined(_arm_armcpu_H)
|
||||||
|
# define _arm_armcpu_H (1)
|
||||||
|
#include "../internal.h"
|
||||||
|
|
||||||
|
#define OC_CPU_ARM_NEON (1<<12)
|
||||||
|
|
||||||
|
ogg_uint32_t oc_cpu_flags_get(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
#include "armfrag.h"
|
||||||
|
|
||||||
|
#if defined(OC_ARM_ASM_NEON)
|
||||||
|
#include <arm_neon.h>
|
||||||
|
#include "../state.h"
|
||||||
|
|
||||||
|
void oc_frag_copy_neon(unsigned char *_dst,const unsigned char *_src,int _ystride) {
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
vst1_u8(&_dst[i * _ystride], vld1_u8(&_src[i * _ystride]));
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_frag_copy_list_neon(unsigned char *_dst_frame, const unsigned char *_src_frame,int _ystride,
|
||||||
|
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs) {
|
||||||
|
ptrdiff_t fragii;
|
||||||
|
for (fragii = 0; fragii < _nfragis; fragii++) {
|
||||||
|
ptrdiff_t frag_buf_off;
|
||||||
|
frag_buf_off = _frag_buf_offs[_fragis[fragii]];
|
||||||
|
oc_frag_copy_neon(_dst_frame + frag_buf_off,
|
||||||
|
_src_frame + frag_buf_off, _ystride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_frag_recon_intra_neon(unsigned char *_dst,
|
||||||
|
int _ystride, const int16_t _residue[64]) {
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
vst1_u8(&_dst[i * _ystride],
|
||||||
|
vqmovun_s16(vaddq_s16(vld1q_s16(&_residue[i * 8]),
|
||||||
|
vdupq_n_s16(128))));
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_frag_recon_inter_neon(unsigned char *_dst, const unsigned char *_src,
|
||||||
|
int _ystride,const int16_t _residue[64]) {
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
vst1_u8(&_dst[i * _ystride],
|
||||||
|
vqmovun_s16(vaddq_s16(vld1q_s16(&_residue[i * 8]),
|
||||||
|
vreinterpretq_s16_u16(vmovl_u8(vld1_u8(&_src[i * _ystride]))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_frag_recon_inter2_neon(unsigned char *_dst,const unsigned char *_src1, const unsigned char *_src2,
|
||||||
|
int _ystride,const int16_t _residue[64]) {
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
vst1_u8(&_dst[i * _ystride],
|
||||||
|
vqmovun_s16(vaddq_s16(vld1q_s16(&_residue[i * 8]),
|
||||||
|
vreinterpretq_s16_u16(vmovl_u8(vhadd_u8(vld1_u8(&_src1[i * _ystride]),
|
||||||
|
vld1_u8(&_src2[i * _ystride])))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_state_frag_recon_neon(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||||
|
int _pli,int16_t _dct_coeffs[128],int _last_zzi,uint16_t _dc_quant){
|
||||||
|
unsigned char *dst;
|
||||||
|
ptrdiff_t frag_buf_off;
|
||||||
|
int ystride;
|
||||||
|
int refi;
|
||||||
|
/*Apply the inverse transform.*/
|
||||||
|
/*Special case only having a DC component.*/
|
||||||
|
if(_last_zzi<2){
|
||||||
|
ogg_int16_t p;
|
||||||
|
int ci;
|
||||||
|
/*We round this dequant product (and not any of the others) because there's
|
||||||
|
no iDCT rounding.*/
|
||||||
|
p=(ogg_int16_t)(_dct_coeffs[0]*(ogg_int32_t)_dc_quant+15>>5);
|
||||||
|
/*LOOP VECTORIZES.*/
|
||||||
|
/*Apparently GCC doesn't want to vectorize it. This is the only line changed.*/
|
||||||
|
// for(ci=0;ci<64;ci++)_dct_coeffs[64+ci]=p;
|
||||||
|
for(ci=8;ci<16;ci++) vst1q_s16(&_dct_coeffs[ci*8], vdupq_n_s16(p));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
/*First, dequantize the DC coefficient.*/
|
||||||
|
_dct_coeffs[0]=(ogg_int16_t)(_dct_coeffs[0]*(int)_dc_quant);
|
||||||
|
oc_idct8x8_neon(_dct_coeffs+64,_dct_coeffs,_last_zzi);
|
||||||
|
}
|
||||||
|
/*Fill in the target buffer.*/
|
||||||
|
frag_buf_off=_state->frag_buf_offs[_fragi];
|
||||||
|
refi=_state->frags[_fragi].refi;
|
||||||
|
ystride=_state->ref_ystride[_pli];
|
||||||
|
dst=_state->ref_frame_data[OC_FRAME_SELF]+frag_buf_off;
|
||||||
|
if(refi==OC_FRAME_SELF)oc_frag_recon_intra_neon(dst,ystride,_dct_coeffs+64);
|
||||||
|
else{
|
||||||
|
const unsigned char *ref;
|
||||||
|
int mvoffsets[2];
|
||||||
|
ref=_state->ref_frame_data[refi]+frag_buf_off;
|
||||||
|
if(oc_state_get_mv_offsets(_state,mvoffsets,_pli,
|
||||||
|
_state->frag_mvs[_fragi])>1){
|
||||||
|
oc_frag_recon_inter2_neon(
|
||||||
|
dst,ref+mvoffsets[0],ref+mvoffsets[1],ystride,_dct_coeffs+64);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
oc_frag_recon_inter_neon(dst,ref+mvoffsets[0],ystride,_dct_coeffs+64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef _arm_intrinsics_armfrag_H
|
||||||
|
#define _arm_intrinsics_armfrag_H 1
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OC_ARM_ASM_NEON
|
||||||
|
typedef struct oc_theora_state oc_theora_state;
|
||||||
|
void oc_idct8x8_neon(int16_t _y[64],int16_t _x[64],int _last_zzi);
|
||||||
|
void oc_loop_filter_init_neon(signed char _bv[256],int _flimit);
|
||||||
|
void oc_state_loop_filter_frag_rows_neon(const oc_theora_state *_state,
|
||||||
|
signed char *_bv,int _refi,int _pli,int _fragy0,int _fragy_end);
|
||||||
|
void oc_frag_copy_neon(unsigned char *_dst,const unsigned char *_src,int _ystride);
|
||||||
|
void oc_frag_copy_list_neon(unsigned char *_dst_frame, const unsigned char *_src_frame,int _ystride,
|
||||||
|
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs);
|
||||||
|
void oc_frag_recon_intra_neon(unsigned char *_dst,
|
||||||
|
int _ystride, const int16_t _residue[64]);
|
||||||
|
void oc_frag_recon_inter_neon(unsigned char *_dst, const unsigned char *_src,
|
||||||
|
int _ystride,const int16_t _residue[64]);
|
||||||
|
void oc_frag_recon_inter2_neon(unsigned char *_dst,const unsigned char *_src1, const unsigned char *_src2,
|
||||||
|
int _ystride,const int16_t _residue[64]);
|
||||||
|
void oc_state_frag_recon_neon(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||||
|
int _pli,int16_t _dct_coeffs[128],int _last_zzi,uint16_t _dc_quant);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //_arm_intrinsics_armfrag_H
|
||||||
|
|
@ -0,0 +1,235 @@
|
||||||
|
#include "armfrag.h"
|
||||||
|
|
||||||
|
#if defined(OC_ARM_ASM_NEON)
|
||||||
|
typedef int32_t ogg_int32_t;
|
||||||
|
#include "../dct.h"
|
||||||
|
#include "neon_a64_compat.h"
|
||||||
|
#include "neon_transpose.h"
|
||||||
|
|
||||||
|
static inline int16x8_t scale_nu_s16(int16x8_t a, uint16_t b) {
|
||||||
|
if (!(b & 1))
|
||||||
|
return vqdmulhq_n_s16(a, b >> 1);
|
||||||
|
if (b < 32768)
|
||||||
|
return vshrq_n_s16(vqdmulhq_n_s16(a, b), 1);
|
||||||
|
|
||||||
|
int32x4_t al = vmovl_s16(vget_low_s16(a));
|
||||||
|
int32x4_t ah = vmovl_high_s16(a);
|
||||||
|
al = vmulq_n_s32(al, b);
|
||||||
|
ah = vmulq_n_s32(ah, b);
|
||||||
|
return vuzp2q_s16(vreinterpretq_s16_s32(al), vreinterpretq_s16_s32(ah));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void v_transpose4x8(const int16x4_t a[8], int16x8_t b[4]) {
|
||||||
|
int16x8x2_t s0 = vtrnq_s16(vcombine_s16(a[0], a[4]), vcombine_s16(a[1], a[5]));
|
||||||
|
int16x8x2_t s1 = vtrnq_s16(vcombine_s16(a[2], a[6]), vcombine_s16(a[3], a[7]));
|
||||||
|
/* 1 5 3 7 17 21 19 23 s0[0] = VTRN1.1N p0 p1 */
|
||||||
|
/* 2 6 4 8 18 22 20 24 s0[1] = VTRN2.1N p0 p1 */
|
||||||
|
/* 9 13 11 15 25 29 27 31 s1[0] = VTRN1.1N p2 p3 */
|
||||||
|
/* 10 14 12 16 26 30 28 32 s1[1] = VTRN2.1N p2 p3 */
|
||||||
|
|
||||||
|
int32x4x2_t t0 = vtrnq_s32(vreinterpretq_s32_s16(s0.val[0]), vreinterpretq_s32_s16(s1.val[0]));
|
||||||
|
int32x4x2_t t1 = vtrnq_s32(vreinterpretq_s32_s16(s0.val[1]), vreinterpretq_s32_s16(s1.val[1]));
|
||||||
|
/* 1 5 9 13 17 21 25 29 t0[0] = VTRN1.2N s0[0] s1[0] */
|
||||||
|
/* 2 6 10 14 18 22 26 30 t1[0] = VTRN1.2N s0[1] s1[1] */
|
||||||
|
/* 3 7 11 15 19 23 27 31 t0[1] = VTRN2.2N s0[0] s1[0] */
|
||||||
|
/* 4 8 12 16 20 24 28 32 t1[1] = VTRN2.2N s0[1] s1[1] */
|
||||||
|
|
||||||
|
b[0] = vreinterpretq_s16_s32(t0.val[0]);
|
||||||
|
b[1] = vreinterpretq_s16_s32(t1.val[0]);
|
||||||
|
b[2] = vreinterpretq_s16_s32(t0.val[1]);
|
||||||
|
b[3] = vreinterpretq_s16_s32(t1.val[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void idct8x8(const int16x8_t x[8], int16x8_t y[8]) {
|
||||||
|
int16x8_t t[8], r;
|
||||||
|
|
||||||
|
/*Stage 1:*/
|
||||||
|
/*0-1 butterfly.*/
|
||||||
|
t[0] = scale_nu_s16(vaddq_s16(x[0], x[4]), OC_C4S4);
|
||||||
|
t[1] = scale_nu_s16(vsubq_s16(x[0], x[4]), OC_C4S4);
|
||||||
|
/*2-3 rotation by 6pi/16.*/
|
||||||
|
t[2] = vsubq_s16(scale_nu_s16(x[2], OC_C6S2), scale_nu_s16(x[6], OC_C2S6));
|
||||||
|
t[3] = vaddq_s16(scale_nu_s16(x[2], OC_C2S6), scale_nu_s16(x[6], OC_C6S2));
|
||||||
|
/*4-7 rotation by 7pi/16.*/
|
||||||
|
t[4] = vsubq_s16(scale_nu_s16(x[1], OC_C7S1), scale_nu_s16(x[7], OC_C1S7));
|
||||||
|
t[7] = vaddq_s16(scale_nu_s16(x[1], OC_C1S7), scale_nu_s16(x[7], OC_C7S1));
|
||||||
|
/*5-6 rotation by 3pi/16.*/
|
||||||
|
t[5] = vsubq_s16(scale_nu_s16(x[5], OC_C3S5), scale_nu_s16(x[3], OC_C5S3));
|
||||||
|
t[6] = vaddq_s16(scale_nu_s16(x[5], OC_C5S3), scale_nu_s16(x[3], OC_C3S5));
|
||||||
|
|
||||||
|
/*Stage 2:*/
|
||||||
|
/*4-5 butterfly.*/
|
||||||
|
r = vaddq_s16(t[4], t[5]);
|
||||||
|
t[5] = scale_nu_s16(vsubq_s16(t[4], t[5]), OC_C4S4);
|
||||||
|
t[4] = r;
|
||||||
|
/*7-6 butterfly.*/
|
||||||
|
r = vaddq_s16(t[7], t[6]);
|
||||||
|
t[6] = scale_nu_s16(vsubq_s16(t[7], t[6]), OC_C4S4);
|
||||||
|
t[7] = r;
|
||||||
|
|
||||||
|
/*Stage 3:*/
|
||||||
|
/*0-3 butterfly.*/
|
||||||
|
r = vaddq_s16(t[0], t[3]);
|
||||||
|
t[3] = vsubq_s16(t[0], t[3]);
|
||||||
|
t[0] = r;
|
||||||
|
/*1-2 butterfly.*/
|
||||||
|
r = vaddq_s16(t[1], t[2]);
|
||||||
|
t[2] = vsubq_s16(t[1], t[2]);
|
||||||
|
t[1] = r;
|
||||||
|
/*6-5 butterfly.*/
|
||||||
|
r = vaddq_s16(t[6], t[5]);
|
||||||
|
t[5] = vsubq_s16(t[6], t[5]);
|
||||||
|
t[6] = r;
|
||||||
|
|
||||||
|
/*Stage 4:*/
|
||||||
|
/*0-7 butterfly.*/
|
||||||
|
y[0] = vaddq_s16(t[0], t[7]);
|
||||||
|
y[7] = vsubq_s16(t[0], t[7]);
|
||||||
|
/*1-6 butterfly.*/
|
||||||
|
y[1] = vaddq_s16(t[1], t[6]);
|
||||||
|
y[6] = vsubq_s16(t[1], t[6]);
|
||||||
|
/*2-5 butterfly.*/
|
||||||
|
y[2] = vaddq_s16(t[2], t[5]);
|
||||||
|
y[5] = vsubq_s16(t[2], t[5]);
|
||||||
|
/*3-4 butterfly.*/
|
||||||
|
y[3] = vaddq_s16(t[3], t[4]);
|
||||||
|
y[4] = vsubq_s16(t[3], t[4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// cos(n*pi/16) (resp. sin(m*pi/16)) scaled by 2147483648
|
||||||
|
// GCC doesn't have vld1_s32_x4
|
||||||
|
//static const int32_t I32_COSINE[8] = {
|
||||||
|
// 2106220352, 418953276, // C1 C7
|
||||||
|
// 1984016189, 821806413, // C2 C6
|
||||||
|
// 1785567396, 1193077991, // C3 C5
|
||||||
|
// 1518500250, 1518500250, // C4 C4
|
||||||
|
//};
|
||||||
|
static const int32_t I32_COSINE[8] = {
|
||||||
|
OC_C1S7 << 15, OC_C2S6 << 15, OC_C3S5 << 15, OC_C4S4 << 15,
|
||||||
|
OC_C7S1 << 15, OC_C6S2 << 15, OC_C5S3 << 15, OC_C4S4 << 15,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void idct4x4_4x8(const int16x4_t x[4], int16x4_t y[8]) {
|
||||||
|
int32x4_t s[4];
|
||||||
|
int16x4_t t[8], r;
|
||||||
|
int32x2x4_t c = vld4_s32(I32_COSINE);
|
||||||
|
|
||||||
|
/*Stage 1:*/
|
||||||
|
t[0] = vmovn_s32(vqdmulhq_lane_s32(vmovl_s16(x[0]), c.val[3], 0)); // C4S4
|
||||||
|
t[1] = vmovn_s32(vqdmulhq_lane_s32(vmovl_s16(x[0]), c.val[3], 0)); // C4S4
|
||||||
|
t[2] = vmovn_s32(vqdmulhq_lane_s32(vmovl_s16(x[2]), c.val[1], 1)); // C6S2
|
||||||
|
t[3] = vmovn_s32(vqdmulhq_lane_s32(vmovl_s16(x[2]), c.val[1], 0)); // C2S6
|
||||||
|
s[0] = vqdmulhq_lane_s32(vmovl_s16(x[1]), c.val[0], 1); // C7S1
|
||||||
|
s[3] = vqdmulhq_lane_s32(vmovl_s16(x[1]), c.val[0], 0); // C1S7
|
||||||
|
s[1] = vqdmulhq_lane_s32(vmovl_s16(x[3]), c.val[2], 1); // C5S3
|
||||||
|
s[2] = vqdmulhq_lane_s32(vmovl_s16(x[3]), c.val[2], 0); // C3S5
|
||||||
|
s[1] = vnegq_s32(s[1]);
|
||||||
|
|
||||||
|
/*Stage 2:*/
|
||||||
|
t[5] = vmovn_s32(vqdmulhq_lane_s32(vsubq_s32(s[0], s[1]), c.val[3], 0)); // C4S4
|
||||||
|
t[4] = vmovn_s32(vaddq_s32(s[0], s[1]));
|
||||||
|
t[6] = vmovn_s32(vqdmulhq_lane_s32(vsubq_s32(s[3], s[2]), c.val[3], 0)); // C4S4
|
||||||
|
t[7] = vmovn_s32(vaddq_s32(s[3], s[2]));
|
||||||
|
|
||||||
|
/*Stage 3:*/
|
||||||
|
r = vadd_s16(t[0], t[3]);
|
||||||
|
t[3] = vsub_s16(t[0], t[3]);
|
||||||
|
t[0] = r;
|
||||||
|
r = vadd_s16(t[1], t[2]);
|
||||||
|
t[2] = vsub_s16(t[1], t[2]);
|
||||||
|
t[1] = r;
|
||||||
|
r = vadd_s16(t[6], t[5]);
|
||||||
|
t[5] = vsub_s16(t[6], t[5]);
|
||||||
|
t[6] = r;
|
||||||
|
|
||||||
|
/*Stage 4:*/
|
||||||
|
y[0] = vadd_s16(t[0], t[7]);
|
||||||
|
y[7] = vsub_s16(t[0], t[7]);
|
||||||
|
y[1] = vadd_s16(t[1], t[6]);
|
||||||
|
y[6] = vsub_s16(t[1], t[6]);
|
||||||
|
y[2] = vadd_s16(t[2], t[5]);
|
||||||
|
y[5] = vsub_s16(t[2], t[5]);
|
||||||
|
y[3] = vadd_s16(t[3], t[4]);
|
||||||
|
y[4] = vsub_s16(t[3], t[4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void idct8x4_8x8(const int16x8_t x[4], int16x8_t y[8]) {
|
||||||
|
int16x8_t t[8], r;
|
||||||
|
|
||||||
|
/*Stage 1:*/
|
||||||
|
t[0] = scale_nu_s16(x[0], OC_C4S4);
|
||||||
|
t[1] = scale_nu_s16(x[0], OC_C4S4);
|
||||||
|
t[2] = scale_nu_s16(x[2], OC_C6S2);
|
||||||
|
t[3] = scale_nu_s16(x[2], OC_C2S6);
|
||||||
|
t[4] = scale_nu_s16(x[1], OC_C7S1);
|
||||||
|
t[7] = scale_nu_s16(x[1], OC_C1S7);
|
||||||
|
t[5] = vnegq_s16(scale_nu_s16(x[3], OC_C5S3));
|
||||||
|
t[6] = scale_nu_s16(x[3], OC_C3S5);
|
||||||
|
|
||||||
|
/*Stage 2:*/
|
||||||
|
r = vaddq_s16(t[4], t[5]);
|
||||||
|
t[5] = scale_nu_s16(vsubq_s16(t[4], t[5]), OC_C4S4);
|
||||||
|
t[4] = r;
|
||||||
|
r = vaddq_s16(t[7], t[6]);
|
||||||
|
t[6] = scale_nu_s16(vsubq_s16(t[7], t[6]), OC_C4S4);
|
||||||
|
t[7] = r;
|
||||||
|
|
||||||
|
/*Stage 3:*/
|
||||||
|
r = vaddq_s16(t[0], t[3]);
|
||||||
|
t[3] = vsubq_s16(t[0], t[3]);
|
||||||
|
t[0] = r;
|
||||||
|
r = vaddq_s16(t[1], t[2]);
|
||||||
|
t[2] = vsubq_s16(t[1], t[2]);
|
||||||
|
t[1] = r;
|
||||||
|
r = vaddq_s16(t[6], t[5]);
|
||||||
|
t[5] = vsubq_s16(t[6], t[5]);
|
||||||
|
t[6] = r;
|
||||||
|
|
||||||
|
/*Stage 4:*/
|
||||||
|
y[0] = vaddq_s16(t[0], t[7]);
|
||||||
|
y[7] = vsubq_s16(t[0], t[7]);
|
||||||
|
y[1] = vaddq_s16(t[1], t[6]);
|
||||||
|
y[6] = vsubq_s16(t[1], t[6]);
|
||||||
|
y[2] = vaddq_s16(t[2], t[5]);
|
||||||
|
y[5] = vsubq_s16(t[2], t[5]);
|
||||||
|
y[3] = vaddq_s16(t[3], t[4]);
|
||||||
|
y[4] = vsubq_s16(t[3], t[4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scale_final(const int16x8_t y[8], int16_t _y[64]) {
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
vst1q_s16(&_y[i * 8], vrshrq_n_s16(y[i], 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void oc_idct8x8_4(int16_t _y[64], int16_t _x[64]) {
|
||||||
|
int16x4_t x0[4], y0[8];
|
||||||
|
int16x8_t x1[4], y1[8];
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
x0[i] = vld1_s16(&_x[i * 8]);
|
||||||
|
idct4x4_4x8(x0, y0);
|
||||||
|
v_transpose4x8(y0, x1);
|
||||||
|
idct8x4_8x8(x1, y1);
|
||||||
|
scale_final(y1, _y);
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
vst1_s16(&_x[i * 8], vcreate_s16(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void oc_idct8x8_8(int16_t _y[64], int16_t _x[64]) {
|
||||||
|
int16x8_t x[8], y[8];
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
x[i] = vld1q_s16(&_x[i * 8]);
|
||||||
|
idct8x8(x, y);
|
||||||
|
v_transpose8x8(y, x);
|
||||||
|
idct8x8(x, y);
|
||||||
|
scale_final(y, _y);
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
vst1q_s16(&_x[i * 8], veorq_s16(x[0], x[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_idct8x8_neon(int16_t _y[64],int16_t _x[64],int _last_zzi) {
|
||||||
|
if (_last_zzi <= 10)
|
||||||
|
oc_idct8x8_4(_y, _x);
|
||||||
|
else
|
||||||
|
oc_idct8x8_8(_y, _x);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2010 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id: x86int.h 17344 2010-07-21 01:42:18Z tterribe $
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
#if !defined(_arm_armint_H)
|
||||||
|
# define _arm_armint_H (1)
|
||||||
|
# include "../internal.h"
|
||||||
|
|
||||||
|
# if defined(OC_ARM_ASM)
|
||||||
|
# define oc_state_accel_init oc_state_accel_init_arm
|
||||||
|
# if defined(__aarch64__) || defined(_M_ARM64)
|
||||||
|
# define oc_loop_filter_init(_state,...) oc_loop_filter_init_neon(__VA_ARGS__)
|
||||||
|
# define oc_state_loop_filter_frag_rows(...) oc_state_loop_filter_frag_rows_neon(__VA_ARGS__)
|
||||||
|
# define oc_frag_copy(_state,...) oc_frag_copy_neon(__VA_ARGS__)
|
||||||
|
# define oc_frag_copy_list(_state,...) oc_frag_copy_list_neon(__VA_ARGS__)
|
||||||
|
|
||||||
|
# define oc_state_frag_recon oc_state_frag_recon_neon
|
||||||
|
# define oc_idct8x8(_state,...) oc_idct8x8_neon(__VA_ARGS__)
|
||||||
|
# define oc_frag_recon_intra(_state,...) oc_frag_recon_intra_neon(__VA_ARGS__)
|
||||||
|
# define oc_frag_recon_inter(_state,...) oc_frag_recon_inter_neon(__VA_ARGS__)
|
||||||
|
# define oc_frag_recon_inter2(_state,...) oc_frag_recon_inter2_neon(__VA_ARGS__)
|
||||||
|
# else
|
||||||
|
# define OC_STATE_USE_VTABLE (1)
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# include "../state.h"
|
||||||
|
# include "armcpu.h"
|
||||||
|
|
||||||
|
# if defined(OC_ARM_ASM)
|
||||||
|
# include "armfrag.h"
|
||||||
|
void oc_state_accel_init_arm(oc_theora_state *_state);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
#include "armint.h"
|
||||||
|
|
||||||
|
#if defined(OC_ARM_ASM_NEON)
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <arm_neon.h>
|
||||||
|
|
||||||
|
static inline uint8x8x2_t loop_filter_neon(uint8x8x4_t pix, uint16_t lim2u) {
|
||||||
|
uint16x8_t lim2 = vdupq_n_u16(lim2u);
|
||||||
|
|
||||||
|
int16x8_t r2 = vreinterpretq_s16_u16(vsubl_u8(pix.val[2], pix.val[1]));
|
||||||
|
int16x8_t r = vreinterpretq_s16_u16(vsubl_u8(pix.val[0], pix.val[3]));
|
||||||
|
r = vaddq_s16(r, r2);
|
||||||
|
r = vaddq_s16(r, vshlq_n_s16(r2, 1));
|
||||||
|
r = vrshrq_n_s16(r, 3);
|
||||||
|
|
||||||
|
uint16x8_t absR = vreinterpretq_u16_s16(vabsq_s16(r));
|
||||||
|
int16x8_t sgnR = vshrq_n_s16(r, 15);
|
||||||
|
|
||||||
|
uint16x8_t absF = vminq_u16(absR, vqsubq_u16(lim2, absR)); // |f| = MIN(|R|,MAX(2L-|R|, 0));
|
||||||
|
int16x8_t f = veorq_s16(vaddq_s16(sgnR, vreinterpretq_s16_u16(absF)), sgnR);
|
||||||
|
|
||||||
|
uint16x8_t p1 = vaddw_u8(vreinterpretq_u16_s16(f), pix.val[1]);
|
||||||
|
int16x8_t p2 = vsubq_s16(vreinterpretq_s16_u16(vmovl_u8(pix.val[2])), f);
|
||||||
|
|
||||||
|
uint8x8x2_t fr = {{vqmovun_s16(vreinterpretq_s16_u16(p1)), vqmovun_s16(p2)}};
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loop_filter_neon_h(unsigned char *_pix,int _ystride,uint16_t lim2) {
|
||||||
|
_pix -= 2;
|
||||||
|
uint8x8x4_t cols = {};
|
||||||
|
cols = vld4_lane_u8(&_pix[_ystride * 0], cols, 0);
|
||||||
|
cols = vld4_lane_u8(&_pix[_ystride * 1], cols, 1);
|
||||||
|
cols = vld4_lane_u8(&_pix[_ystride * 2], cols, 2);
|
||||||
|
cols = vld4_lane_u8(&_pix[_ystride * 3], cols, 3);
|
||||||
|
cols = vld4_lane_u8(&_pix[_ystride * 4], cols, 4);
|
||||||
|
cols = vld4_lane_u8(&_pix[_ystride * 5], cols, 5);
|
||||||
|
cols = vld4_lane_u8(&_pix[_ystride * 6], cols, 6);
|
||||||
|
cols = vld4_lane_u8(&_pix[_ystride * 7], cols, 7);
|
||||||
|
|
||||||
|
uint8x8x2_t fp = loop_filter_neon(cols, lim2);
|
||||||
|
|
||||||
|
_pix += 1;
|
||||||
|
vst2_lane_u8(&_pix[_ystride * 0], fp, 0);
|
||||||
|
vst2_lane_u8(&_pix[_ystride * 1], fp, 1);
|
||||||
|
vst2_lane_u8(&_pix[_ystride * 2], fp, 2);
|
||||||
|
vst2_lane_u8(&_pix[_ystride * 3], fp, 3);
|
||||||
|
vst2_lane_u8(&_pix[_ystride * 4], fp, 4);
|
||||||
|
vst2_lane_u8(&_pix[_ystride * 5], fp, 5);
|
||||||
|
vst2_lane_u8(&_pix[_ystride * 6], fp, 6);
|
||||||
|
vst2_lane_u8(&_pix[_ystride * 7], fp, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loop_filter_neon_v(unsigned char *_pix,int _ystride,uint16_t lim2) {
|
||||||
|
_pix -= _ystride * 2;
|
||||||
|
uint8x8x4_t rows = {{
|
||||||
|
vld1_u8(&_pix[_ystride * 0]),
|
||||||
|
vld1_u8(&_pix[_ystride * 1]),
|
||||||
|
vld1_u8(&_pix[_ystride * 2]),
|
||||||
|
vld1_u8(&_pix[_ystride * 3])
|
||||||
|
}};
|
||||||
|
|
||||||
|
uint8x8x2_t fp = loop_filter_neon(rows, lim2);
|
||||||
|
|
||||||
|
vst1_u8(&_pix[_ystride * 1], fp.val[0]);
|
||||||
|
vst1_u8(&_pix[_ystride * 2], fp.val[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Direct copy of the generic functions,
|
||||||
|
other than _bv being used to store 2*flimit */
|
||||||
|
|
||||||
|
void oc_loop_filter_init_neon(signed char _bv[256],int _flimit) {
|
||||||
|
uint16_t lim2u = _flimit * 2;
|
||||||
|
memcpy(_bv, &lim2u, sizeof(uint16_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_state_loop_filter_frag_rows_neon(const oc_theora_state *_state,
|
||||||
|
signed char *_bv,int _refi,int _pli,int _fragy0,int _fragy_end) {
|
||||||
|
const oc_fragment_plane *fplane;
|
||||||
|
const oc_fragment *frags;
|
||||||
|
const ptrdiff_t *frag_buf_offs;
|
||||||
|
unsigned char *ref_frame_data;
|
||||||
|
ptrdiff_t fragi_top;
|
||||||
|
ptrdiff_t fragi_bot;
|
||||||
|
ptrdiff_t fragi0;
|
||||||
|
ptrdiff_t fragi0_end;
|
||||||
|
int ystride;
|
||||||
|
int nhfrags;
|
||||||
|
uint16_t lim2;
|
||||||
|
fplane = _state->fplanes + _pli;
|
||||||
|
nhfrags = fplane->nhfrags;
|
||||||
|
fragi_top = fplane->froffset;
|
||||||
|
fragi_bot = fragi_top + fplane->nfrags;
|
||||||
|
fragi0 = fragi_top + _fragy0 * (ptrdiff_t) nhfrags;
|
||||||
|
fragi0_end = fragi_top + _fragy_end * (ptrdiff_t) nhfrags;
|
||||||
|
ystride = _state->ref_ystride[_pli];
|
||||||
|
frags = _state->frags;
|
||||||
|
frag_buf_offs = _state->frag_buf_offs;
|
||||||
|
ref_frame_data = _state->ref_frame_data[_refi];
|
||||||
|
memcpy(&lim2, _bv, sizeof(uint16_t));
|
||||||
|
/*The following loops are constructed somewhat non-intuitively on purpose.
|
||||||
|
The main idea is: if a block boundary has at least one coded fragment on
|
||||||
|
it, the filter is applied to it.
|
||||||
|
However, the order that the filters are applied in matters, and VP3 chose
|
||||||
|
the somewhat strange ordering used below.*/
|
||||||
|
while (fragi0 < fragi0_end) {
|
||||||
|
ptrdiff_t fragi;
|
||||||
|
ptrdiff_t fragi_end;
|
||||||
|
fragi = fragi0;
|
||||||
|
fragi_end = fragi + nhfrags;
|
||||||
|
while (fragi < fragi_end) {
|
||||||
|
if (frags[fragi].coded) {
|
||||||
|
unsigned char *ref;
|
||||||
|
ref = ref_frame_data + frag_buf_offs[fragi];
|
||||||
|
if (fragi > fragi0)loop_filter_neon_h(ref, ystride, lim2);
|
||||||
|
if (fragi0 > fragi_top)loop_filter_neon_v(ref, ystride, lim2);
|
||||||
|
if (fragi + 1 < fragi_end && !frags[fragi + 1].coded) {
|
||||||
|
loop_filter_neon_h(ref + 8, ystride, lim2);
|
||||||
|
}
|
||||||
|
if (fragi + nhfrags < fragi_bot && !frags[fragi + nhfrags].coded) {
|
||||||
|
loop_filter_neon_v(ref + (ystride << 3), ystride, lim2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragi++;
|
||||||
|
}
|
||||||
|
fragi0 += nhfrags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
#include "armint.h"
|
||||||
|
|
||||||
|
static const unsigned char OC_FZIG_ZAG_NEON[128]={
|
||||||
|
0, 8, 1, 2, 9,16,24,17,
|
||||||
|
10, 3, 4,11,18,25,32,40,
|
||||||
|
33,26,19,12, 5, 6,13,20,
|
||||||
|
27,34,41,48,56,49,42,35,
|
||||||
|
28,21,14, 7,15,22,29,36,
|
||||||
|
43,50,57,58,51,44,37,30,
|
||||||
|
23,31,38,45,52,59,60,53,
|
||||||
|
46,39,47,54,61,62,55,63,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64
|
||||||
|
};
|
||||||
|
|
||||||
|
void oc_state_accel_init_arm(oc_theora_state *_state){
|
||||||
|
oc_state_accel_init_c(_state);
|
||||||
|
_state->cpu_flags=oc_cpu_flags_get();
|
||||||
|
#if defined(OC_ARM_ASM_NEON)
|
||||||
|
if(_state->cpu_flags & OC_CPU_ARM_NEON){
|
||||||
|
# if defined(OC_STATE_USE_VTABLE)
|
||||||
|
_state->opt_vtable.loop_filter_init=oc_loop_filter_init_neon;
|
||||||
|
_state->opt_vtable.state_loop_filter_frag_rows=oc_state_loop_filter_frag_rows_neon;
|
||||||
|
_state->opt_vtable.frag_copy=oc_frag_copy_neon;
|
||||||
|
_state->opt_vtable.frag_copy_list=oc_frag_copy_list_neon;
|
||||||
|
|
||||||
|
_state->opt_vtable.state_frag_recon=oc_state_frag_recon_neon;
|
||||||
|
_state->opt_vtable.idct8x8=oc_idct8x8_neon;
|
||||||
|
_state->opt_vtable.frag_recon_intra=oc_frag_recon_intra_neon;
|
||||||
|
_state->opt_vtable.frag_recon_inter=oc_frag_recon_inter_neon;
|
||||||
|
_state->opt_vtable.frag_recon_inter2=oc_frag_recon_inter2_neon;
|
||||||
|
# endif
|
||||||
|
_state->opt_data.dct_fzig_zag=OC_FZIG_ZAG_NEON;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef _neon_a64_compat_H
|
||||||
|
#define _neon_a64_compat_H
|
||||||
|
#include <arm_neon.h>
|
||||||
|
|
||||||
|
#if !defined(__aarch64__) && !defined(_M_ARM64)
|
||||||
|
# define vuzp1q_s64(a, b) vcombine_s64(vget_low_s64(a), vget_low_s64(b))
|
||||||
|
# define vuzp2q_s64(a, b) vcombine_s64(vget_high_s64(a), vget_high_s64(b))
|
||||||
|
# define vmovl_high_s16(a) vmovl_s16(vget_high_s16(a))
|
||||||
|
# define vuzp2q_s16(a, b) vuzpq_s16(a, b).val[1]
|
||||||
|
|
||||||
|
#define vaddv_s32(p) vget_lane_s32(vpadd_s32(p, p), 0)
|
||||||
|
|
||||||
|
static inline int32_t vaddvq_s32(int32x4_t p) {
|
||||||
|
int32x2_t r = vadd_s32(vget_high_s32(p), vget_low_s32(p));
|
||||||
|
return vaddv_s32(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int32_t vaddlvq_s16(int16x8_t p) {
|
||||||
|
return vaddvq_s32(vpaddlq_s16(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define vaddv_u32(p) vget_lane_u32(vpadd_u32(p, p), 0)
|
||||||
|
|
||||||
|
static inline uint32_t vaddvq_u32(uint32x4_t p) {
|
||||||
|
uint32x2_t r = vadd_u32(vget_high_u32(p), vget_low_u32(p));
|
||||||
|
return vaddv_u32(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t vaddlvq_u16(uint16x8_t p) {
|
||||||
|
return vaddvq_u32(vpaddlq_u16(p));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //_neon_a64_compat_H
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
#ifndef _arm_neon_transpose_H
|
||||||
|
#define _arm_neon_transpose_H
|
||||||
|
#include "neon_a64_compat.h"
|
||||||
|
|
||||||
|
static void v_transpose8x8(const int16x8_t a[8], int16x8_t b[8]) {
|
||||||
|
int16x8x2_t s0 = vtrnq_s16(a[0], a[1]);
|
||||||
|
int16x8x2_t s1 = vtrnq_s16(a[2], a[3]);
|
||||||
|
int16x8x2_t s2 = vtrnq_s16(a[4], a[5]);
|
||||||
|
int16x8x2_t s3 = vtrnq_s16(a[6], a[7]);
|
||||||
|
/* 1 9 3 11 5 13 7 15 s0[0] = VTRN1.1N p0 p1 */
|
||||||
|
/* 2 10 4 12 6 14 8 16 s0[1] = VTRN2.1N p0 p1 */
|
||||||
|
/* 17 25 19 27 21 29 23 31 s1[0] = VTRN1.1N p2 p3 */
|
||||||
|
/* 18 26 20 28 22 30 24 32 s1[1] = VTRN2.1N p2 p3 */
|
||||||
|
/* 33 41 35 43 37 45 39 47 s2[0] = VTRN1.1N p4 p5 */
|
||||||
|
/* 34 42 36 44 38 46 40 48 s2[1] = VTRN2.1N p4 p5 */
|
||||||
|
/* 49 57 51 59 53 61 55 63 s3[0] = VTRN1.1N p6 p7 */
|
||||||
|
/* 50 58 52 60 54 62 56 64 s3[1] = VTRN2.1N p6 p7 */
|
||||||
|
|
||||||
|
int32x4x2_t t0 = vtrnq_s32(vreinterpretq_s32_s16(s0.val[0]), vreinterpretq_s32_s16(s1.val[0]));
|
||||||
|
int32x4x2_t t1 = vtrnq_s32(vreinterpretq_s32_s16(s0.val[1]), vreinterpretq_s32_s16(s1.val[1]));
|
||||||
|
int32x4x2_t t2 = vtrnq_s32(vreinterpretq_s32_s16(s2.val[0]), vreinterpretq_s32_s16(s3.val[0]));
|
||||||
|
int32x4x2_t t3 = vtrnq_s32(vreinterpretq_s32_s16(s2.val[1]), vreinterpretq_s32_s16(s3.val[1]));
|
||||||
|
/* 1 9 17 25 5 13 21 29 t0[0] = VTRN1.2N s0[0] s1[0] */
|
||||||
|
/* 2 10 18 26 6 14 22 30 t1[0] = VTRN1.2N s0[1] s1[1] */
|
||||||
|
/* 3 11 19 27 7 15 23 31 t0[1] = VTRN2.2N s0[0] s1[0] */
|
||||||
|
/* 4 12 20 28 8 16 24 32 t1[1] = VTRN2.2N s0[1] s1[1] */
|
||||||
|
/* 33 41 49 57 37 45 53 61 t2[0] = VTRN1.2N s2[0] s3[0] */
|
||||||
|
/* 34 42 50 58 38 46 54 62 t3[0] = VTRN1.2N s2[1] s3[1] */
|
||||||
|
/* 35 43 51 59 39 47 55 63 t2[1] = VTRN2.2N s2[0] s3[0] */
|
||||||
|
/* 36 44 52 60 40 48 56 64 t3[1] = VTRN2.2N s2[1] s3[1] */
|
||||||
|
|
||||||
|
int64x2_t u0 = vuzp1q_s64(vreinterpretq_s64_s32(t0.val[0]), vreinterpretq_s64_s32(t2.val[0]));
|
||||||
|
int64x2_t u1 = vuzp1q_s64(vreinterpretq_s64_s32(t1.val[0]), vreinterpretq_s64_s32(t3.val[0]));
|
||||||
|
int64x2_t u2 = vuzp1q_s64(vreinterpretq_s64_s32(t0.val[1]), vreinterpretq_s64_s32(t2.val[1]));
|
||||||
|
int64x2_t u3 = vuzp1q_s64(vreinterpretq_s64_s32(t1.val[1]), vreinterpretq_s64_s32(t3.val[1]));
|
||||||
|
int64x2_t u4 = vuzp2q_s64(vreinterpretq_s64_s32(t0.val[0]), vreinterpretq_s64_s32(t2.val[0]));
|
||||||
|
int64x2_t u5 = vuzp2q_s64(vreinterpretq_s64_s32(t1.val[0]), vreinterpretq_s64_s32(t3.val[0]));
|
||||||
|
int64x2_t u6 = vuzp2q_s64(vreinterpretq_s64_s32(t0.val[1]), vreinterpretq_s64_s32(t2.val[1]));
|
||||||
|
int64x2_t u7 = vuzp2q_s64(vreinterpretq_s64_s32(t1.val[1]), vreinterpretq_s64_s32(t3.val[1]));
|
||||||
|
/* 1 9 17 25 33 41 49 57 u0 = VUZP1 t0[0] t2[0] */
|
||||||
|
/* 2 10 18 26 34 42 50 58 u1 = VUZP1 t1[0] t3[0] */
|
||||||
|
/* 3 11 19 27 35 43 51 59 u2 = VUZP1 t0[1] t2[1] */
|
||||||
|
/* 4 12 20 28 36 44 52 60 u3 = VUZP1 t1[1] t3[1] */
|
||||||
|
/* 5 13 21 29 37 45 53 61 u4 = VUZP2 t0[0] t2[0] */
|
||||||
|
/* 6 14 22 30 38 46 54 62 u5 = VUZP2 t1[0] t3[0] */
|
||||||
|
/* 7 15 23 31 39 47 55 63 u6 = VUZP2 t0[1] t2[1] */
|
||||||
|
/* 8 16 24 32 40 48 56 64 u7 = VUZP2 t1[1] t3[1] */
|
||||||
|
|
||||||
|
b[0] = vreinterpretq_s16_s64(u0);
|
||||||
|
b[1] = vreinterpretq_s16_s64(u1);
|
||||||
|
b[2] = vreinterpretq_s16_s64(u2);
|
||||||
|
b[3] = vreinterpretq_s16_s64(u3);
|
||||||
|
b[4] = vreinterpretq_s16_s64(u4);
|
||||||
|
b[5] = vreinterpretq_s16_s64(u5);
|
||||||
|
b[6] = vreinterpretq_s16_s64(u6);
|
||||||
|
b[7] = vreinterpretq_s16_s64(u7);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggTheora SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: packing variable sized words into an octet stream
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "bitpack.h"
|
||||||
|
|
||||||
|
/*We're 'MSb' endian; if we write a word but read individual bits,
|
||||||
|
then we'll read the MSb first.*/
|
||||||
|
|
||||||
|
void oc_pack_readinit(oc_pack_buf *_b,unsigned char *_buf,long _bytes){
|
||||||
|
memset(_b,0,sizeof(*_b));
|
||||||
|
_b->ptr=_buf;
|
||||||
|
_b->stop=_buf+_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static oc_pb_window oc_pack_refill(oc_pack_buf *_b,int _bits){
|
||||||
|
const unsigned char *ptr;
|
||||||
|
const unsigned char *stop;
|
||||||
|
oc_pb_window window;
|
||||||
|
int available;
|
||||||
|
unsigned shift;
|
||||||
|
stop=_b->stop;
|
||||||
|
ptr=_b->ptr;
|
||||||
|
window=_b->window;
|
||||||
|
available=_b->bits;
|
||||||
|
shift=OC_PB_WINDOW_SIZE-available;
|
||||||
|
while(7<shift&&ptr<stop){
|
||||||
|
shift-=8;
|
||||||
|
window|=(oc_pb_window)*ptr++<<shift;
|
||||||
|
}
|
||||||
|
_b->ptr=ptr;
|
||||||
|
available=OC_PB_WINDOW_SIZE-shift;
|
||||||
|
if(_bits>available){
|
||||||
|
if(ptr>=stop){
|
||||||
|
_b->eof=1;
|
||||||
|
available=OC_LOTS_OF_BITS;
|
||||||
|
}
|
||||||
|
else window|=*ptr>>(available&7);
|
||||||
|
}
|
||||||
|
_b->bits=available;
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
int oc_pack_look1(oc_pack_buf *_b){
|
||||||
|
oc_pb_window window;
|
||||||
|
int available;
|
||||||
|
window=_b->window;
|
||||||
|
available=_b->bits;
|
||||||
|
if(available<1)_b->window=window=oc_pack_refill(_b,1);
|
||||||
|
return window>>OC_PB_WINDOW_SIZE-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_pack_adv1(oc_pack_buf *_b){
|
||||||
|
_b->window<<=1;
|
||||||
|
_b->bits--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Here we assume that 0<=_bits&&_bits<=32.*/
|
||||||
|
long oc_pack_read_c(oc_pack_buf *_b,int _bits){
|
||||||
|
oc_pb_window window;
|
||||||
|
int available;
|
||||||
|
long result;
|
||||||
|
window=_b->window;
|
||||||
|
available=_b->bits;
|
||||||
|
if(_bits==0)return 0;
|
||||||
|
if(available<_bits){
|
||||||
|
window=oc_pack_refill(_b,_bits);
|
||||||
|
available=_b->bits;
|
||||||
|
}
|
||||||
|
result=window>>OC_PB_WINDOW_SIZE-_bits;
|
||||||
|
available-=_bits;
|
||||||
|
window<<=1;
|
||||||
|
window<<=_bits-1;
|
||||||
|
_b->window=window;
|
||||||
|
_b->bits=available;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int oc_pack_read1_c(oc_pack_buf *_b){
|
||||||
|
oc_pb_window window;
|
||||||
|
int available;
|
||||||
|
int result;
|
||||||
|
window=_b->window;
|
||||||
|
available=_b->bits;
|
||||||
|
if(available<1){
|
||||||
|
window=oc_pack_refill(_b,1);
|
||||||
|
available=_b->bits;
|
||||||
|
}
|
||||||
|
result=window>>OC_PB_WINDOW_SIZE-1;
|
||||||
|
available--;
|
||||||
|
window<<=1;
|
||||||
|
_b->window=window;
|
||||||
|
_b->bits=available;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
long oc_pack_bytes_left(oc_pack_buf *_b){
|
||||||
|
if(_b->eof)return -1;
|
||||||
|
return _b->stop-_b->ptr+(_b->bits>>3);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggTheora SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: packing variable sized words into an octet stream
|
||||||
|
last mod: $Id: bitwise.c 7675 2004-09-01 00:34:39Z xiphmont $
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
#if !defined(_bitpack_H)
|
||||||
|
# define _bitpack_H (1)
|
||||||
|
# include <stddef.h>
|
||||||
|
# include <limits.h>
|
||||||
|
# include "internal.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef size_t oc_pb_window;
|
||||||
|
typedef struct oc_pack_buf oc_pack_buf;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# if !defined(oc_pack_read)
|
||||||
|
# define oc_pack_read oc_pack_read_c
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_pack_read1)
|
||||||
|
# define oc_pack_read1 oc_pack_read1_c
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_huff_token_decode)
|
||||||
|
# define oc_huff_token_decode oc_huff_token_decode_c
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# define OC_PB_WINDOW_SIZE ((int)sizeof(oc_pb_window)*CHAR_BIT)
|
||||||
|
/*This is meant to be a large, positive constant that can still be efficiently
|
||||||
|
loaded as an immediate (on platforms like ARM, for example).
|
||||||
|
Even relatively modest values like 100 would work fine.*/
|
||||||
|
# define OC_LOTS_OF_BITS (0x40000000)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct oc_pack_buf{
|
||||||
|
const unsigned char *stop;
|
||||||
|
const unsigned char *ptr;
|
||||||
|
oc_pb_window window;
|
||||||
|
int bits;
|
||||||
|
int eof;
|
||||||
|
};
|
||||||
|
|
||||||
|
void oc_pack_readinit(oc_pack_buf *_b,unsigned char *_buf,long _bytes);
|
||||||
|
int oc_pack_look1(oc_pack_buf *_b);
|
||||||
|
void oc_pack_adv1(oc_pack_buf *_b);
|
||||||
|
/*Here we assume 0<=_bits&&_bits<=32.*/
|
||||||
|
long oc_pack_read_c(oc_pack_buf *_b,int _bits);
|
||||||
|
int oc_pack_read1_c(oc_pack_buf *_b);
|
||||||
|
/* returns -1 for read beyond EOF, or the number of whole bytes available */
|
||||||
|
long oc_pack_bytes_left(oc_pack_buf *_b);
|
||||||
|
|
||||||
|
/*These two functions are implemented locally in huffdec.c*/
|
||||||
|
/*Read in bits without advancing the bitptr.
|
||||||
|
Here we assume 0<=_bits&&_bits<=32.*/
|
||||||
|
/*static int oc_pack_look(oc_pack_buf *_b,int _bits);*/
|
||||||
|
/*static void oc_pack_adv(oc_pack_buf *_b,int _bits);*/
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,606 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id: theora.h,v 1.8 2004/03/15 22:17:32 derf Exp $
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
/**\mainpage
|
||||||
|
*
|
||||||
|
* \section intro Introduction
|
||||||
|
*
|
||||||
|
* This is the documentation for the <tt>libtheora</tt> C API.
|
||||||
|
*
|
||||||
|
* The \c libtheora package is the current reference
|
||||||
|
* implementation for <a href="http://www.theora.org/">Theora</a>, a free,
|
||||||
|
* patent-unencumbered video codec.
|
||||||
|
* Theora is derived from On2's VP3 codec with additional features and
|
||||||
|
* integration with Ogg multimedia formats by
|
||||||
|
* <a href="http://www.xiph.org/">the Xiph.Org Foundation</a>.
|
||||||
|
* Complete documentation of the format itself is available in
|
||||||
|
* <a href="http://www.theora.org/doc/Theora.pdf">the Theora
|
||||||
|
* specification</a>.
|
||||||
|
*
|
||||||
|
* \section Organization
|
||||||
|
*
|
||||||
|
* The functions documented here are divided between two
|
||||||
|
* separate libraries:
|
||||||
|
* - \c libtheoraenc contains the encoder interface,
|
||||||
|
* described in \ref encfuncs.
|
||||||
|
* - \c libtheoradec contains the decoder interface,
|
||||||
|
* described in \ref decfuncs, \n
|
||||||
|
* and additional \ref basefuncs.
|
||||||
|
*
|
||||||
|
* New code should link to \c libtheoradec. If using encoder
|
||||||
|
* features, it must also link to \c libtheoraenc.
|
||||||
|
*
|
||||||
|
* During initial development, prior to the 1.0 release,
|
||||||
|
* \c libtheora exported a different \ref oldfuncs which
|
||||||
|
* combined both encode and decode functions.
|
||||||
|
* In general, legacy API symbols can be indentified
|
||||||
|
* by their \c theora_ or \c OC_ namespace prefixes.
|
||||||
|
* The current API uses \c th_ or \c TH_ instead.
|
||||||
|
*
|
||||||
|
* While deprecated, \c libtheoraenc and \c libtheoradec
|
||||||
|
* together export the legacy api as well at the one documented above.
|
||||||
|
* Likewise, the legacy \c libtheora included with this package
|
||||||
|
* exports the new 1.x API. Older code and build scripts can therefore
|
||||||
|
* but updated independently to the current scheme.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**\file
|
||||||
|
* The shared <tt>libtheoradec</tt> and <tt>libtheoraenc</tt> C API.
|
||||||
|
* You don't need to include this directly.*/
|
||||||
|
|
||||||
|
#if !defined(_O_THEORA_CODEC_H_)
|
||||||
|
# define _O_THEORA_CODEC_H_ (1)
|
||||||
|
# include <ogg/ogg.h>
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**\name Return codes*/
|
||||||
|
/*@{*/
|
||||||
|
/**An invalid pointer was provided.*/
|
||||||
|
#define TH_EFAULT (-1)
|
||||||
|
/**An invalid argument was provided.*/
|
||||||
|
#define TH_EINVAL (-10)
|
||||||
|
/**The contents of the header were incomplete, invalid, or unexpected.*/
|
||||||
|
#define TH_EBADHEADER (-20)
|
||||||
|
/**The header does not belong to a Theora stream.*/
|
||||||
|
#define TH_ENOTFORMAT (-21)
|
||||||
|
/**The bitstream version is too high.*/
|
||||||
|
#define TH_EVERSION (-22)
|
||||||
|
/**The specified function is not implemented.*/
|
||||||
|
#define TH_EIMPL (-23)
|
||||||
|
/**There were errors in the video data packet.*/
|
||||||
|
#define TH_EBADPACKET (-24)
|
||||||
|
/**The decoded packet represented a dropped frame.
|
||||||
|
The player can continue to display the current frame, as the contents of the
|
||||||
|
decoded frame buffer have not changed.*/
|
||||||
|
#define TH_DUPFRAME (1)
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
/**The currently defined color space tags.
|
||||||
|
* See <a href="http://www.theora.org/doc/Theora.pdf">the Theora
|
||||||
|
* specification</a>, Chapter 4, for exact details on the meaning
|
||||||
|
* of each of these color spaces.*/
|
||||||
|
typedef enum{
|
||||||
|
/**The color space was not specified at the encoder.
|
||||||
|
It may be conveyed by an external means.*/
|
||||||
|
TH_CS_UNSPECIFIED,
|
||||||
|
/**A color space designed for NTSC content.*/
|
||||||
|
TH_CS_ITU_REC_470M,
|
||||||
|
/**A color space designed for PAL/SECAM content.*/
|
||||||
|
TH_CS_ITU_REC_470BG,
|
||||||
|
/**The total number of currently defined color spaces.*/
|
||||||
|
TH_CS_NSPACES
|
||||||
|
}th_colorspace;
|
||||||
|
|
||||||
|
/**The currently defined pixel format tags.
|
||||||
|
* See <a href="http://www.theora.org/doc/Theora.pdf">the Theora
|
||||||
|
* specification</a>, Section 4.4, for details on the precise sample
|
||||||
|
* locations.*/
|
||||||
|
typedef enum{
|
||||||
|
/**Chroma decimation by 2 in both the X and Y directions (4:2:0).
|
||||||
|
The Cb and Cr chroma planes are half the width and half the
|
||||||
|
height of the luma plane.*/
|
||||||
|
TH_PF_420,
|
||||||
|
/**Currently reserved.*/
|
||||||
|
TH_PF_RSVD,
|
||||||
|
/**Chroma decimation by 2 in the X direction (4:2:2).
|
||||||
|
The Cb and Cr chroma planes are half the width of the luma plane, but full
|
||||||
|
height.*/
|
||||||
|
TH_PF_422,
|
||||||
|
/**No chroma decimation (4:4:4).
|
||||||
|
The Cb and Cr chroma planes are full width and full height.*/
|
||||||
|
TH_PF_444,
|
||||||
|
/**The total number of currently defined pixel formats.*/
|
||||||
|
TH_PF_NFORMATS
|
||||||
|
}th_pixel_fmt;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**A buffer for a single color plane in an uncompressed image.
|
||||||
|
* This contains the image data in a left-to-right, top-down format.
|
||||||
|
* Each row of pixels is stored contiguously in memory, but successive
|
||||||
|
* rows need not be.
|
||||||
|
* Use \a stride to compute the offset of the next row.
|
||||||
|
* The encoder accepts both positive \a stride values (top-down in memory)
|
||||||
|
* and negative (bottom-up in memory).
|
||||||
|
* The decoder currently always generates images with positive strides.*/
|
||||||
|
typedef struct{
|
||||||
|
/**The width of this plane.*/
|
||||||
|
int width;
|
||||||
|
/**The height of this plane.*/
|
||||||
|
int height;
|
||||||
|
/**The offset in bytes between successive rows.*/
|
||||||
|
int stride;
|
||||||
|
/**A pointer to the beginning of the first row.*/
|
||||||
|
unsigned char *data;
|
||||||
|
}th_img_plane;
|
||||||
|
|
||||||
|
/**A complete image buffer for an uncompressed frame.
|
||||||
|
* The chroma planes may be decimated by a factor of two in either
|
||||||
|
* direction, as indicated by th_info#pixel_fmt.
|
||||||
|
* The width and height of the Y' plane must be multiples of 16.
|
||||||
|
* They may need to be cropped for display, using the rectangle
|
||||||
|
* specified by th_info#pic_x, th_info#pic_y, th_info#pic_width,
|
||||||
|
* and th_info#pic_height.
|
||||||
|
* All samples are 8 bits.
|
||||||
|
* \note The term YUV often used to describe a colorspace is ambiguous.
|
||||||
|
* The exact parameters of the RGB to YUV conversion process aside, in
|
||||||
|
* many contexts the U and V channels actually have opposite meanings.
|
||||||
|
* To avoid this confusion, we are explicit: the name of the color
|
||||||
|
* channels are Y'CbCr, and they appear in that order, always.
|
||||||
|
* The prime symbol denotes that the Y channel is non-linear.
|
||||||
|
* Cb and Cr stand for "Chroma blue" and "Chroma red", respectively.*/
|
||||||
|
typedef th_img_plane th_ycbcr_buffer[3];
|
||||||
|
|
||||||
|
/**Theora bitstream information.
|
||||||
|
* This contains the basic playback parameters for a stream, and corresponds to
|
||||||
|
* the initial 'info' header packet.
|
||||||
|
* To initialize an encoder, the application fills in this structure and
|
||||||
|
* passes it to th_encode_alloc().
|
||||||
|
* A default encoding mode is chosen based on the values of the #quality and
|
||||||
|
* #target_bitrate fields.
|
||||||
|
* On decode, it is filled in by th_decode_headerin(), and then passed to
|
||||||
|
* th_decode_alloc().
|
||||||
|
*
|
||||||
|
* Encoded Theora frames must be a multiple of 16 in size;
|
||||||
|
* this is what the #frame_width and #frame_height members represent.
|
||||||
|
* To handle arbitrary picture sizes, a crop rectangle is specified in the
|
||||||
|
* #pic_x, #pic_y, #pic_width and #pic_height members.
|
||||||
|
*
|
||||||
|
* All frame buffers contain pointers to the full, padded frame.
|
||||||
|
* However, the current encoder <em>will not</em> reference pixels outside of
|
||||||
|
* the cropped picture region, and the application does not need to fill them
|
||||||
|
* in.
|
||||||
|
* The decoder <em>will</em> allocate storage for a full frame, but the
|
||||||
|
* application <em>should not</em> rely on the padding containing sensible
|
||||||
|
* data.
|
||||||
|
*
|
||||||
|
* It is also generally recommended that the offsets and sizes should still be
|
||||||
|
* multiples of 2 to avoid chroma sampling shifts when chroma is sub-sampled.
|
||||||
|
* See <a href="http://www.theora.org/doc/Theora.pdf">the Theora
|
||||||
|
* specification</a>, Section 4.4, for more details.
|
||||||
|
*
|
||||||
|
* Frame rate, in frames per second, is stored as a rational fraction, as is
|
||||||
|
* the pixel aspect ratio.
|
||||||
|
* Note that this refers to the aspect ratio of the individual pixels, not of
|
||||||
|
* the overall frame itself.
|
||||||
|
* The frame aspect ratio can be computed from pixel aspect ratio using the
|
||||||
|
* image dimensions.*/
|
||||||
|
typedef struct{
|
||||||
|
/**\name Theora version
|
||||||
|
* Bitstream version information.*/
|
||||||
|
/*@{*/
|
||||||
|
unsigned char version_major;
|
||||||
|
unsigned char version_minor;
|
||||||
|
unsigned char version_subminor;
|
||||||
|
/*@}*/
|
||||||
|
/**The encoded frame width.
|
||||||
|
* This must be a multiple of 16, and less than 1048576.*/
|
||||||
|
ogg_uint32_t frame_width;
|
||||||
|
/**The encoded frame height.
|
||||||
|
* This must be a multiple of 16, and less than 1048576.*/
|
||||||
|
ogg_uint32_t frame_height;
|
||||||
|
/**The displayed picture width.
|
||||||
|
* This must be no larger than width.*/
|
||||||
|
ogg_uint32_t pic_width;
|
||||||
|
/**The displayed picture height.
|
||||||
|
* This must be no larger than height.*/
|
||||||
|
ogg_uint32_t pic_height;
|
||||||
|
/**The X offset of the displayed picture.
|
||||||
|
* This must be no larger than #frame_width-#pic_width or 255, whichever is
|
||||||
|
* smaller.*/
|
||||||
|
ogg_uint32_t pic_x;
|
||||||
|
/**The Y offset of the displayed picture.
|
||||||
|
* This must be no larger than #frame_height-#pic_height, and
|
||||||
|
* #frame_height-#pic_height-#pic_y must be no larger than 255.
|
||||||
|
* This slightly funny restriction is due to the fact that the offset is
|
||||||
|
* specified from the top of the image for consistency with the standard
|
||||||
|
* graphics left-handed coordinate system used throughout this API, while
|
||||||
|
* it is stored in the encoded stream as an offset from the bottom.*/
|
||||||
|
ogg_uint32_t pic_y;
|
||||||
|
/**\name Frame rate
|
||||||
|
* The frame rate, as a fraction.
|
||||||
|
* If either is 0, the frame rate is undefined.*/
|
||||||
|
/*@{*/
|
||||||
|
ogg_uint32_t fps_numerator;
|
||||||
|
ogg_uint32_t fps_denominator;
|
||||||
|
/*@}*/
|
||||||
|
/**\name Aspect ratio
|
||||||
|
* The aspect ratio of the pixels.
|
||||||
|
* If either value is zero, the aspect ratio is undefined.
|
||||||
|
* If not specified by any external means, 1:1 should be assumed.
|
||||||
|
* The aspect ratio of the full picture can be computed as
|
||||||
|
* \code
|
||||||
|
* aspect_numerator*pic_width/(aspect_denominator*pic_height).
|
||||||
|
* \endcode */
|
||||||
|
/*@{*/
|
||||||
|
ogg_uint32_t aspect_numerator;
|
||||||
|
ogg_uint32_t aspect_denominator;
|
||||||
|
/*@}*/
|
||||||
|
/**The color space.*/
|
||||||
|
th_colorspace colorspace;
|
||||||
|
/**The pixel format.*/
|
||||||
|
th_pixel_fmt pixel_fmt;
|
||||||
|
/**The target bit-rate in bits per second.
|
||||||
|
If initializing an encoder with this struct, set this field to a non-zero
|
||||||
|
value to activate CBR encoding by default.*/
|
||||||
|
int target_bitrate;
|
||||||
|
/**The target quality level.
|
||||||
|
Valid values range from 0 to 63, inclusive, with higher values giving
|
||||||
|
higher quality.
|
||||||
|
If initializing an encoder with this struct, and #target_bitrate is set
|
||||||
|
to zero, VBR encoding at this quality will be activated by default.*/
|
||||||
|
/*Currently this is set so that a qi of 0 corresponds to distortions of 24
|
||||||
|
times the JND, and each increase by 16 halves that value.
|
||||||
|
This gives us fine discrimination at low qualities, yet effective rate
|
||||||
|
control at high qualities.
|
||||||
|
The qi value 63 is special, however.
|
||||||
|
For this, the highest quality, we use one half of a JND for our threshold.
|
||||||
|
Due to the lower bounds placed on allowable quantizers in Theora, we will
|
||||||
|
not actually be able to achieve quality this good, but this should
|
||||||
|
provide as close to visually lossless quality as Theora is capable of.
|
||||||
|
We could lift the quantizer restrictions without breaking VP3.1
|
||||||
|
compatibility, but this would result in quantized coefficients that are
|
||||||
|
too large for the current bitstream to be able to store.
|
||||||
|
We'd have to redesign the token syntax to store these large coefficients,
|
||||||
|
which would make transcoding complex.*/
|
||||||
|
int quality;
|
||||||
|
/**The amount to shift to extract the last keyframe number from the granule
|
||||||
|
* position.
|
||||||
|
* This can be at most 31.
|
||||||
|
* th_info_init() will set this to a default value (currently <tt>6</tt>,
|
||||||
|
* which is good for streaming applications), but you can set it to 0 to
|
||||||
|
* make every frame a keyframe.
|
||||||
|
* The maximum distance between key frames is
|
||||||
|
* <tt>1<<#keyframe_granule_shift</tt>.
|
||||||
|
* The keyframe frequency can be more finely controlled with
|
||||||
|
* #TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE, which can also be adjusted
|
||||||
|
* during encoding (for example, to force the next frame to be a keyframe),
|
||||||
|
* but it cannot be set larger than the amount permitted by this field after
|
||||||
|
* the headers have been output.*/
|
||||||
|
int keyframe_granule_shift;
|
||||||
|
}th_info;
|
||||||
|
|
||||||
|
/**The comment information.
|
||||||
|
*
|
||||||
|
* This structure holds the in-stream metadata corresponding to
|
||||||
|
* the 'comment' header packet.
|
||||||
|
* The comment header is meant to be used much like someone jotting a quick
|
||||||
|
* note on the label of a video.
|
||||||
|
* It should be a short, to the point text note that can be more than a couple
|
||||||
|
* words, but not more than a short paragraph.
|
||||||
|
*
|
||||||
|
* The metadata is stored as a series of (tag, value) pairs, in
|
||||||
|
* length-encoded string vectors.
|
||||||
|
* The first occurrence of the '=' character delimits the tag and value.
|
||||||
|
* A particular tag may occur more than once, and order is significant.
|
||||||
|
* The character set encoding for the strings is always UTF-8, but the tag
|
||||||
|
* names are limited to ASCII, and treated as case-insensitive.
|
||||||
|
* See <a href="http://www.theora.org/doc/Theora.pdf">the Theora
|
||||||
|
* specification</a>, Section 6.3.3 for details.
|
||||||
|
*
|
||||||
|
* In filling in this structure, th_decode_headerin() will null-terminate
|
||||||
|
* the user_comment strings for safety.
|
||||||
|
* However, the bitstream format itself treats them as 8-bit clean vectors,
|
||||||
|
* possibly containing null characters, so the length array should be
|
||||||
|
* treated as their authoritative length.
|
||||||
|
*/
|
||||||
|
typedef struct th_comment{
|
||||||
|
/**The array of comment string vectors.*/
|
||||||
|
char **user_comments;
|
||||||
|
/**An array of the corresponding length of each vector, in bytes.*/
|
||||||
|
int *comment_lengths;
|
||||||
|
/**The total number of comment strings.*/
|
||||||
|
int comments;
|
||||||
|
/**The null-terminated vendor string.
|
||||||
|
This identifies the software used to encode the stream.*/
|
||||||
|
char *vendor;
|
||||||
|
}th_comment;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**A single base matrix.*/
|
||||||
|
typedef unsigned char th_quant_base[64];
|
||||||
|
|
||||||
|
/**A set of \a qi ranges.*/
|
||||||
|
typedef struct{
|
||||||
|
/**The number of ranges in the set.*/
|
||||||
|
int nranges;
|
||||||
|
/**The size of each of the #nranges ranges.
|
||||||
|
These must sum to 63.*/
|
||||||
|
const int *sizes;
|
||||||
|
/**#nranges <tt>+1</tt> base matrices.
|
||||||
|
Matrices \a i and <tt>i+1</tt> form the endpoints of range \a i.*/
|
||||||
|
const th_quant_base *base_matrices;
|
||||||
|
}th_quant_ranges;
|
||||||
|
|
||||||
|
/**A complete set of quantization parameters.
|
||||||
|
The quantizer for each coefficient is calculated as:
|
||||||
|
\code
|
||||||
|
Q=MAX(MIN(qmin[qti][ci!=0],scale[ci!=0][qi]*base[qti][pli][qi][ci]/100),
|
||||||
|
1024).
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\a qti is the quantization type index: 0 for intra, 1 for inter.
|
||||||
|
<tt>ci!=0</tt> is 0 for the DC coefficient and 1 for AC coefficients.
|
||||||
|
\a qi is the quality index, ranging between 0 (low quality) and 63 (high
|
||||||
|
quality).
|
||||||
|
\a pli is the color plane index: 0 for Y', 1 for Cb, 2 for Cr.
|
||||||
|
\a ci is the DCT coefficient index.
|
||||||
|
Coefficient indices correspond to the normal 2D DCT block
|
||||||
|
ordering--row-major with low frequencies first--\em not zig-zag order.
|
||||||
|
|
||||||
|
Minimum quantizers are constant, and are given by:
|
||||||
|
\code
|
||||||
|
qmin[2][2]={{4,2},{8,4}}.
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
Parameters that can be stored in the bitstream are as follows:
|
||||||
|
- The two scale matrices ac_scale and dc_scale.
|
||||||
|
\code
|
||||||
|
scale[2][64]={dc_scale,ac_scale}.
|
||||||
|
\endcode
|
||||||
|
- The base matrices for each \a qi, \a qti and \a pli (up to 384 in all).
|
||||||
|
In order to avoid storing a full 384 base matrices, only a sparse set of
|
||||||
|
matrices are stored, and the rest are linearly interpolated.
|
||||||
|
This is done as follows.
|
||||||
|
For each \a qti and \a pli, a series of \a n \a qi ranges is defined.
|
||||||
|
The size of each \a qi range can vary arbitrarily, but they must sum to
|
||||||
|
63.
|
||||||
|
Then, <tt>n+1</tt> matrices are specified, one for each endpoint of the
|
||||||
|
ranges.
|
||||||
|
For interpolation purposes, each range's endpoints are the first \a qi
|
||||||
|
value it contains and one past the last \a qi value it contains.
|
||||||
|
Fractional values are rounded to the nearest integer, with ties rounded
|
||||||
|
away from zero.
|
||||||
|
|
||||||
|
Base matrices are stored by reference, so if the same matrices are used
|
||||||
|
multiple times, they will only appear once in the bitstream.
|
||||||
|
The bitstream is also capable of omitting an entire set of ranges and
|
||||||
|
its associated matrices if they are the same as either the previous
|
||||||
|
set (indexed in row-major order) or if the inter set is the same as the
|
||||||
|
intra set.
|
||||||
|
|
||||||
|
- Loop filter limit values.
|
||||||
|
The same limits are used for the loop filter in all color planes, despite
|
||||||
|
potentially differing levels of quantization in each.
|
||||||
|
|
||||||
|
For the current encoder, <tt>scale[ci!=0][qi]</tt> must be no greater
|
||||||
|
than <tt>scale[ci!=0][qi-1]</tt> and <tt>base[qti][pli][qi][ci]</tt> must
|
||||||
|
be no greater than <tt>base[qti][pli][qi-1][ci]</tt>.
|
||||||
|
These two conditions ensure that the actual quantizer for a given \a qti,
|
||||||
|
\a pli, and \a ci does not increase as \a qi increases.
|
||||||
|
This is not required by the decoder.*/
|
||||||
|
typedef struct{
|
||||||
|
/**The DC scaling factors.*/
|
||||||
|
ogg_uint16_t dc_scale[64];
|
||||||
|
/**The AC scaling factors.*/
|
||||||
|
ogg_uint16_t ac_scale[64];
|
||||||
|
/**The loop filter limit values.*/
|
||||||
|
unsigned char loop_filter_limits[64];
|
||||||
|
/**The \a qi ranges for each \a ci and \a pli.*/
|
||||||
|
th_quant_ranges qi_ranges[2][3];
|
||||||
|
}th_quant_info;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**The number of Huffman tables used by Theora.*/
|
||||||
|
#define TH_NHUFFMAN_TABLES (80)
|
||||||
|
/**The number of DCT token values in each table.*/
|
||||||
|
#define TH_NDCT_TOKENS (32)
|
||||||
|
|
||||||
|
/**A Huffman code for a Theora DCT token.
|
||||||
|
* Each set of Huffman codes in a given table must form a complete, prefix-free
|
||||||
|
* code.
|
||||||
|
* There is no requirement that all the tokens in a table have a valid code,
|
||||||
|
* but the current encoder is not optimized to take advantage of this.
|
||||||
|
* If each of the five grouops of 16 tables does not contain at least one table
|
||||||
|
* with a code for every token, then the encoder may fail to encode certain
|
||||||
|
* frames.
|
||||||
|
* The complete table in the first group of 16 does not have to be in the same
|
||||||
|
* place as the complete table in the other groups, but the complete tables in
|
||||||
|
* the remaining four groups must all be in the same place.*/
|
||||||
|
typedef struct{
|
||||||
|
/**The bit pattern for the code, with the LSbit of the pattern aligned in
|
||||||
|
* the LSbit of the word.*/
|
||||||
|
ogg_uint32_t pattern;
|
||||||
|
/**The number of bits in the code.
|
||||||
|
* This must be between 0 and 32, inclusive.*/
|
||||||
|
int nbits;
|
||||||
|
}th_huff_code;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**\defgroup basefuncs Functions Shared by Encode and Decode*/
|
||||||
|
/*@{*/
|
||||||
|
/**\name Basic shared functions
|
||||||
|
* These functions return information about the library itself,
|
||||||
|
* or provide high-level information about codec state
|
||||||
|
* and packet type.
|
||||||
|
*
|
||||||
|
* You must link to \c libtheoradec if you use any of the
|
||||||
|
* functions in this section.*/
|
||||||
|
/*@{*/
|
||||||
|
/**Retrieves a human-readable string to identify the library vendor and
|
||||||
|
* version.
|
||||||
|
* \return the version string.*/
|
||||||
|
extern const char *th_version_string(void);
|
||||||
|
/**Retrieves the library version number.
|
||||||
|
* This is the highest bitstream version that the encoder library will produce,
|
||||||
|
* or that the decoder library can decode.
|
||||||
|
* This number is composed of a 16-bit major version, 8-bit minor version
|
||||||
|
* and 8 bit sub-version, composed as follows:
|
||||||
|
* \code
|
||||||
|
* (VERSION_MAJOR<<16)+(VERSION_MINOR<<8)+(VERSION_SUBMINOR)
|
||||||
|
* \endcode
|
||||||
|
* \return the version number.*/
|
||||||
|
extern ogg_uint32_t th_version_number(void);
|
||||||
|
/**Converts a granule position to an absolute frame index, starting at
|
||||||
|
* <tt>0</tt>.
|
||||||
|
* The granule position is interpreted in the context of a given
|
||||||
|
* #th_enc_ctx or #th_dec_ctx handle (either will suffice).
|
||||||
|
* \param _encdec A previously allocated #th_enc_ctx or #th_dec_ctx
|
||||||
|
* handle.
|
||||||
|
* \param _granpos The granule position to convert.
|
||||||
|
* \returns The absolute frame index corresponding to \a _granpos.
|
||||||
|
* \retval -1 The given granule position was invalid (i.e. negative).*/
|
||||||
|
extern ogg_int64_t th_granule_frame(void *_encdec,ogg_int64_t _granpos);
|
||||||
|
/**Converts a granule position to an absolute time in seconds.
|
||||||
|
* The granule position is interpreted in the context of a given
|
||||||
|
* #th_enc_ctx or #th_dec_ctx handle (either will suffice).
|
||||||
|
* \param _encdec A previously allocated #th_enc_ctx or #th_dec_ctx
|
||||||
|
* handle.
|
||||||
|
* \param _granpos The granule position to convert.
|
||||||
|
* \return The absolute time in seconds corresponding to \a _granpos.
|
||||||
|
* This is the "end time" for the frame, or the latest time it should
|
||||||
|
* be displayed.
|
||||||
|
* It is not the presentation time.
|
||||||
|
* \retval -1 The given granule position was invalid (i.e. negative).*/
|
||||||
|
extern double th_granule_time(void *_encdec,ogg_int64_t _granpos);
|
||||||
|
/**Determines whether a Theora packet is a header or not.
|
||||||
|
* This function does no verification beyond checking the packet type bit, so
|
||||||
|
* it should not be used for bitstream identification; use
|
||||||
|
* th_decode_headerin() for that.
|
||||||
|
* As per the Theora specification, an empty (0-byte) packet is treated as a
|
||||||
|
* data packet (a delta frame with no coded blocks).
|
||||||
|
* \param _op An <tt>ogg_packet</tt> containing encoded Theora data.
|
||||||
|
* \retval 1 The packet is a header packet
|
||||||
|
* \retval 0 The packet is a video data packet.*/
|
||||||
|
extern int th_packet_isheader(ogg_packet *_op);
|
||||||
|
/**Determines whether a theora packet is a key frame or not.
|
||||||
|
* This function does no verification beyond checking the packet type and
|
||||||
|
* key frame bits, so it should not be used for bitstream identification; use
|
||||||
|
* th_decode_headerin() for that.
|
||||||
|
* As per the Theora specification, an empty (0-byte) packet is treated as a
|
||||||
|
* delta frame (with no coded blocks).
|
||||||
|
* \param _op An <tt>ogg_packet</tt> containing encoded Theora data.
|
||||||
|
* \retval 1 The packet contains a key frame.
|
||||||
|
* \retval 0 The packet contains a delta frame.
|
||||||
|
* \retval -1 The packet is not a video data packet.*/
|
||||||
|
extern int th_packet_iskeyframe(ogg_packet *_op);
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
/**\name Functions for manipulating header data
|
||||||
|
* These functions manipulate the #th_info and #th_comment structures
|
||||||
|
* which describe video parameters and key-value metadata, respectively.
|
||||||
|
*
|
||||||
|
* You must link to \c libtheoradec if you use any of the
|
||||||
|
* functions in this section.*/
|
||||||
|
/*@{*/
|
||||||
|
/**Initializes a th_info structure.
|
||||||
|
* This should be called on a freshly allocated #th_info structure before
|
||||||
|
* attempting to use it.
|
||||||
|
* \param _info The #th_info struct to initialize.*/
|
||||||
|
extern void th_info_init(th_info *_info);
|
||||||
|
/**Clears a #th_info structure.
|
||||||
|
* This should be called on a #th_info structure after it is no longer
|
||||||
|
* needed.
|
||||||
|
* \param _info The #th_info struct to clear.*/
|
||||||
|
extern void th_info_clear(th_info *_info);
|
||||||
|
|
||||||
|
/**Initialize a #th_comment structure.
|
||||||
|
* This should be called on a freshly allocated #th_comment structure
|
||||||
|
* before attempting to use it.
|
||||||
|
* \param _tc The #th_comment struct to initialize.*/
|
||||||
|
extern void th_comment_init(th_comment *_tc);
|
||||||
|
/**Add a comment to an initialized #th_comment structure.
|
||||||
|
* \note Neither th_comment_add() nor th_comment_add_tag() support
|
||||||
|
* comments containing null values, although the bitstream format does
|
||||||
|
* support them.
|
||||||
|
* To add such comments you will need to manipulate the #th_comment
|
||||||
|
* structure directly.
|
||||||
|
* \param _tc The #th_comment struct to add the comment to.
|
||||||
|
* \param _comment Must be a null-terminated UTF-8 string containing the
|
||||||
|
* comment in "TAG=the value" form.*/
|
||||||
|
extern void th_comment_add(th_comment *_tc,const char *_comment);
|
||||||
|
/**Add a comment to an initialized #th_comment structure.
|
||||||
|
* \note Neither th_comment_add() nor th_comment_add_tag() support
|
||||||
|
* comments containing null values, although the bitstream format does
|
||||||
|
* support them.
|
||||||
|
* To add such comments you will need to manipulate the #th_comment
|
||||||
|
* structure directly.
|
||||||
|
* \param _tc The #th_comment struct to add the comment to.
|
||||||
|
* \param _tag A null-terminated string containing the tag associated with
|
||||||
|
* the comment.
|
||||||
|
* \param _val The corresponding value as a null-terminated string.*/
|
||||||
|
extern void th_comment_add_tag(th_comment *_tc,const char *_tag,
|
||||||
|
const char *_val);
|
||||||
|
/**Look up a comment value by its tag.
|
||||||
|
* \param _tc An initialized #th_comment structure.
|
||||||
|
* \param _tag The tag to look up.
|
||||||
|
* \param _count The instance of the tag.
|
||||||
|
* The same tag can appear multiple times, each with a distinct
|
||||||
|
* value, so an index is required to retrieve them all.
|
||||||
|
* The order in which these values appear is significant and
|
||||||
|
* should be preserved.
|
||||||
|
* Use th_comment_query_count() to get the legal range for
|
||||||
|
* the \a _count parameter.
|
||||||
|
* \return A pointer to the queried tag's value.
|
||||||
|
* This points directly to data in the #th_comment structure.
|
||||||
|
* It should not be modified or freed by the application, and
|
||||||
|
* modifications to the structure may invalidate the pointer.
|
||||||
|
* \retval NULL If no matching tag is found.*/
|
||||||
|
extern char *th_comment_query(th_comment *_tc,const char *_tag,int _count);
|
||||||
|
/**Look up the number of instances of a tag.
|
||||||
|
* Call this first when querying for a specific tag and then iterate over the
|
||||||
|
* number of instances with separate calls to th_comment_query() to
|
||||||
|
* retrieve all the values for that tag in order.
|
||||||
|
* \param _tc An initialized #th_comment structure.
|
||||||
|
* \param _tag The tag to look up.
|
||||||
|
* \return The number of instances of this particular tag.*/
|
||||||
|
extern int th_comment_query_count(th_comment *_tc,const char *_tag);
|
||||||
|
/**Clears a #th_comment structure.
|
||||||
|
* This should be called on a #th_comment structure after it is no longer
|
||||||
|
* needed.
|
||||||
|
* It will free all memory used by the structure members.
|
||||||
|
* \param _tc The #th_comment struct to clear.*/
|
||||||
|
extern void th_comment_clear(th_comment *_tc);
|
||||||
|
/*@}*/
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
/*Definitions shared by the forward and inverse DCT transforms.*/
|
||||||
|
#if !defined(_dct_H)
|
||||||
|
# define _dct_H (1)
|
||||||
|
|
||||||
|
/*cos(n*pi/16) (resp. sin(m*pi/16)) scaled by 65536.*/
|
||||||
|
#define OC_C1S7 ((ogg_int32_t)64277)
|
||||||
|
#define OC_C2S6 ((ogg_int32_t)60547)
|
||||||
|
#define OC_C3S5 ((ogg_int32_t)54491)
|
||||||
|
#define OC_C4S4 ((ogg_int32_t)46341)
|
||||||
|
#define OC_C5S3 ((ogg_int32_t)36410)
|
||||||
|
#define OC_C6S2 ((ogg_int32_t)25080)
|
||||||
|
#define OC_C7S1 ((ogg_int32_t)12785)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,193 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id: decapiwrapper.c 13596 2007-08-23 20:05:38Z tterribe $
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include "apiwrapper.h"
|
||||||
|
#include "decint.h"
|
||||||
|
#include "theora/theoradec.h"
|
||||||
|
|
||||||
|
static void th_dec_api_clear(th_api_wrapper *_api){
|
||||||
|
if(_api->setup)th_setup_free(_api->setup);
|
||||||
|
if(_api->decode)th_decode_free(_api->decode);
|
||||||
|
memset(_api,0,sizeof(*_api));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void theora_decode_clear(theora_state *_td){
|
||||||
|
if(_td->i!=NULL)theora_info_clear(_td->i);
|
||||||
|
memset(_td,0,sizeof(*_td));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int theora_decode_control(theora_state *_td,int _req,
|
||||||
|
void *_buf,size_t _buf_sz){
|
||||||
|
return th_decode_ctl(((th_api_wrapper *)_td->i->codec_setup)->decode,
|
||||||
|
_req,_buf,_buf_sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ogg_int64_t theora_decode_granule_frame(theora_state *_td,
|
||||||
|
ogg_int64_t _gp){
|
||||||
|
return th_granule_frame(((th_api_wrapper *)_td->i->codec_setup)->decode,_gp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static double theora_decode_granule_time(theora_state *_td,ogg_int64_t _gp){
|
||||||
|
return th_granule_time(((th_api_wrapper *)_td->i->codec_setup)->decode,_gp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const oc_state_dispatch_vtable OC_DEC_DISPATCH_VTBL={
|
||||||
|
(oc_state_clear_func)theora_decode_clear,
|
||||||
|
(oc_state_control_func)theora_decode_control,
|
||||||
|
(oc_state_granule_frame_func)theora_decode_granule_frame,
|
||||||
|
(oc_state_granule_time_func)theora_decode_granule_time,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void th_info2theora_info(theora_info *_ci,const th_info *_info){
|
||||||
|
_ci->version_major=_info->version_major;
|
||||||
|
_ci->version_minor=_info->version_minor;
|
||||||
|
_ci->version_subminor=_info->version_subminor;
|
||||||
|
_ci->width=_info->frame_width;
|
||||||
|
_ci->height=_info->frame_height;
|
||||||
|
_ci->frame_width=_info->pic_width;
|
||||||
|
_ci->frame_height=_info->pic_height;
|
||||||
|
_ci->offset_x=_info->pic_x;
|
||||||
|
_ci->offset_y=_info->pic_y;
|
||||||
|
_ci->fps_numerator=_info->fps_numerator;
|
||||||
|
_ci->fps_denominator=_info->fps_denominator;
|
||||||
|
_ci->aspect_numerator=_info->aspect_numerator;
|
||||||
|
_ci->aspect_denominator=_info->aspect_denominator;
|
||||||
|
switch(_info->colorspace){
|
||||||
|
case TH_CS_ITU_REC_470M:_ci->colorspace=OC_CS_ITU_REC_470M;break;
|
||||||
|
case TH_CS_ITU_REC_470BG:_ci->colorspace=OC_CS_ITU_REC_470BG;break;
|
||||||
|
default:_ci->colorspace=OC_CS_UNSPECIFIED;break;
|
||||||
|
}
|
||||||
|
switch(_info->pixel_fmt){
|
||||||
|
case TH_PF_420:_ci->pixelformat=OC_PF_420;break;
|
||||||
|
case TH_PF_422:_ci->pixelformat=OC_PF_422;break;
|
||||||
|
case TH_PF_444:_ci->pixelformat=OC_PF_444;break;
|
||||||
|
default:_ci->pixelformat=OC_PF_RSVD;
|
||||||
|
}
|
||||||
|
_ci->target_bitrate=_info->target_bitrate;
|
||||||
|
_ci->quality=_info->quality;
|
||||||
|
_ci->keyframe_frequency_force=1<<_info->keyframe_granule_shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
int theora_decode_init(theora_state *_td,theora_info *_ci){
|
||||||
|
th_api_info *apiinfo;
|
||||||
|
th_api_wrapper *api;
|
||||||
|
th_info info;
|
||||||
|
api=(th_api_wrapper *)_ci->codec_setup;
|
||||||
|
/*Allocate our own combined API wrapper/theora_info struct.
|
||||||
|
We put them both in one malloc'd block so that when the API wrapper is
|
||||||
|
freed, the info struct goes with it.
|
||||||
|
This avoids having to figure out whether or not we need to free the info
|
||||||
|
struct in either theora_info_clear() or theora_clear().*/
|
||||||
|
apiinfo=(th_api_info *)_ogg_calloc(1,sizeof(*apiinfo));
|
||||||
|
if(apiinfo==NULL)return OC_FAULT;
|
||||||
|
/*Make our own copy of the info struct, since its lifetime should be
|
||||||
|
independent of the one we were passed in.*/
|
||||||
|
*&apiinfo->info=*_ci;
|
||||||
|
/*Convert the info struct now instead of saving the the one we decoded with
|
||||||
|
theora_decode_header(), since the user might have modified values (i.e.,
|
||||||
|
color space, aspect ratio, etc. can be specified from a higher level).
|
||||||
|
The user also might be doing something "clever" with the header packets if
|
||||||
|
they are not using an Ogg encapsulation.*/
|
||||||
|
oc_theora_info2th_info(&info,_ci);
|
||||||
|
/*Don't bother to copy the setup info; th_decode_alloc() makes its own copy
|
||||||
|
of the stuff it needs.*/
|
||||||
|
apiinfo->api.decode=th_decode_alloc(&info,api->setup);
|
||||||
|
if(apiinfo->api.decode==NULL){
|
||||||
|
_ogg_free(apiinfo);
|
||||||
|
return OC_EINVAL;
|
||||||
|
}
|
||||||
|
apiinfo->api.clear=(oc_setup_clear_func)th_dec_api_clear;
|
||||||
|
_td->internal_encode=NULL;
|
||||||
|
/*Provide entry points for ABI compatibility with old decoder shared libs.*/
|
||||||
|
_td->internal_decode=(void *)&OC_DEC_DISPATCH_VTBL;
|
||||||
|
_td->granulepos=0;
|
||||||
|
_td->i=&apiinfo->info;
|
||||||
|
_td->i->codec_setup=&apiinfo->api;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int theora_decode_header(theora_info *_ci,theora_comment *_cc,ogg_packet *_op){
|
||||||
|
th_api_wrapper *api;
|
||||||
|
th_info info;
|
||||||
|
int ret;
|
||||||
|
api=(th_api_wrapper *)_ci->codec_setup;
|
||||||
|
/*Allocate an API wrapper struct on demand, since it will not also include a
|
||||||
|
theora_info struct like the ones that are used in a theora_state struct.*/
|
||||||
|
if(api==NULL){
|
||||||
|
_ci->codec_setup=_ogg_calloc(1,sizeof(*api));
|
||||||
|
if(_ci->codec_setup==NULL)return OC_FAULT;
|
||||||
|
api=(th_api_wrapper *)_ci->codec_setup;
|
||||||
|
api->clear=(oc_setup_clear_func)th_dec_api_clear;
|
||||||
|
}
|
||||||
|
/*Convert from the theora_info struct instead of saving our own th_info
|
||||||
|
struct between calls.
|
||||||
|
The user might be doing something "clever" with the header packets if they
|
||||||
|
are not using an Ogg encapsulation, and we don't want to break this.*/
|
||||||
|
oc_theora_info2th_info(&info,_ci);
|
||||||
|
/*We rely on the fact that theora_comment and th_comment structures are
|
||||||
|
actually identical.
|
||||||
|
Take care not to change this fact unless you change the code here as
|
||||||
|
well!*/
|
||||||
|
ret=th_decode_headerin(&info,(th_comment *)_cc,&api->setup,_op);
|
||||||
|
/*We also rely on the fact that the error return code values are the same,
|
||||||
|
and that the implementations of these two functions return the same set of
|
||||||
|
them.
|
||||||
|
Note that theora_decode_header() really can return OC_NOTFORMAT, even
|
||||||
|
though it is not currently documented to do so.*/
|
||||||
|
if(ret<0)return ret;
|
||||||
|
th_info2theora_info(_ci,&info);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int theora_decode_packetin(theora_state *_td,ogg_packet *_op){
|
||||||
|
th_api_wrapper *api;
|
||||||
|
ogg_int64_t gp;
|
||||||
|
int ret;
|
||||||
|
if(!_td||!_td->i||!_td->i->codec_setup)return OC_FAULT;
|
||||||
|
api=(th_api_wrapper *)_td->i->codec_setup;
|
||||||
|
ret=th_decode_packetin(api->decode,_op,&gp);
|
||||||
|
if(ret<0)return OC_BADPACKET;
|
||||||
|
_td->granulepos=gp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int theora_decode_YUVout(theora_state *_td,yuv_buffer *_yuv){
|
||||||
|
th_api_wrapper *api;
|
||||||
|
th_dec_ctx *decode;
|
||||||
|
th_ycbcr_buffer buf;
|
||||||
|
int ret;
|
||||||
|
if(!_td||!_td->i||!_td->i->codec_setup)return OC_FAULT;
|
||||||
|
api=(th_api_wrapper *)_td->i->codec_setup;
|
||||||
|
decode=(th_dec_ctx *)api->decode;
|
||||||
|
if(!decode)return OC_FAULT;
|
||||||
|
ret=th_decode_ycbcr_out(decode,buf);
|
||||||
|
if(ret>=0){
|
||||||
|
_yuv->y_width=buf[0].width;
|
||||||
|
_yuv->y_height=buf[0].height;
|
||||||
|
_yuv->y_stride=buf[0].stride;
|
||||||
|
_yuv->uv_width=buf[1].width;
|
||||||
|
_yuv->uv_height=buf[1].height;
|
||||||
|
_yuv->uv_stride=buf[1].stride;
|
||||||
|
_yuv->y=buf[0].data;
|
||||||
|
_yuv->u=buf[1].data;
|
||||||
|
_yuv->v=buf[2].data;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,274 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include "decint.h"
|
||||||
|
|
||||||
|
/*Only used for fuzzing.*/
|
||||||
|
#if defined(HAVE_MEMORY_CONSTRAINT)
|
||||||
|
static const int MAX_FUZZING_WIDTH = 16384;
|
||||||
|
static const int MAX_FUZZING_HEIGHT = 16384;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*Unpacks a series of octets from a given byte array into the pack buffer.
|
||||||
|
No checking is done to ensure the buffer contains enough data.
|
||||||
|
_opb: The pack buffer to read the octets from.
|
||||||
|
_buf: The byte array to store the unpacked bytes in.
|
||||||
|
_len: The number of octets to unpack.*/
|
||||||
|
static void oc_unpack_octets(oc_pack_buf *_opb,char *_buf,size_t _len){
|
||||||
|
while(_len-->0){
|
||||||
|
long val;
|
||||||
|
val=oc_pack_read(_opb,8);
|
||||||
|
*_buf++=(char)val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Unpacks a 32-bit integer encoded by octets in little-endian form.*/
|
||||||
|
static long oc_unpack_length(oc_pack_buf *_opb){
|
||||||
|
long ret[4];
|
||||||
|
int i;
|
||||||
|
for(i=0;i<4;i++)ret[i]=oc_pack_read(_opb,8);
|
||||||
|
return ret[0]|ret[1]<<8|ret[2]<<16|ret[3]<<24;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int oc_info_unpack(oc_pack_buf *_opb,th_info *_info){
|
||||||
|
long val;
|
||||||
|
/*Check the codec bitstream version.*/
|
||||||
|
val=oc_pack_read(_opb,8);
|
||||||
|
_info->version_major=(unsigned char)val;
|
||||||
|
val=oc_pack_read(_opb,8);
|
||||||
|
_info->version_minor=(unsigned char)val;
|
||||||
|
val=oc_pack_read(_opb,8);
|
||||||
|
_info->version_subminor=(unsigned char)val;
|
||||||
|
/*verify we can parse this bitstream version.
|
||||||
|
We accept earlier minors and all subminors, by spec*/
|
||||||
|
if(_info->version_major>TH_VERSION_MAJOR||
|
||||||
|
(_info->version_major==TH_VERSION_MAJOR&&
|
||||||
|
_info->version_minor>TH_VERSION_MINOR)){
|
||||||
|
return TH_EVERSION;
|
||||||
|
}
|
||||||
|
/*Read the encoded frame description.*/
|
||||||
|
val=oc_pack_read(_opb,16);
|
||||||
|
_info->frame_width=(ogg_uint32_t)val<<4;
|
||||||
|
val=oc_pack_read(_opb,16);
|
||||||
|
_info->frame_height=(ogg_uint32_t)val<<4;
|
||||||
|
val=oc_pack_read(_opb,24);
|
||||||
|
_info->pic_width=(ogg_uint32_t)val;
|
||||||
|
val=oc_pack_read(_opb,24);
|
||||||
|
_info->pic_height=(ogg_uint32_t)val;
|
||||||
|
val=oc_pack_read(_opb,8);
|
||||||
|
_info->pic_x=(ogg_uint32_t)val;
|
||||||
|
val=oc_pack_read(_opb,8);
|
||||||
|
_info->pic_y=(ogg_uint32_t)val;
|
||||||
|
val=oc_pack_read(_opb,32);
|
||||||
|
_info->fps_numerator=(ogg_uint32_t)val;
|
||||||
|
val=oc_pack_read(_opb,32);
|
||||||
|
_info->fps_denominator=(ogg_uint32_t)val;
|
||||||
|
if(_info->frame_width==0||_info->frame_height==0||
|
||||||
|
_info->pic_width+_info->pic_x>_info->frame_width||
|
||||||
|
_info->pic_height+_info->pic_y>_info->frame_height||
|
||||||
|
_info->fps_numerator==0||_info->fps_denominator==0){
|
||||||
|
return TH_EBADHEADER;
|
||||||
|
}
|
||||||
|
#if defined(HAVE_MEMORY_CONSTRAINT)
|
||||||
|
if(_info->frame_width>=MAX_FUZZING_WIDTH&&_info->frame_height>=MAX_FUZZING_HEIGHT){
|
||||||
|
return TH_EBADHEADER;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/*Note: The sense of pic_y is inverted in what we pass back to the
|
||||||
|
application compared to how it is stored in the bitstream.
|
||||||
|
This is because the bitstream uses a right-handed coordinate system, while
|
||||||
|
applications expect a left-handed one.*/
|
||||||
|
_info->pic_y=_info->frame_height-_info->pic_height-_info->pic_y;
|
||||||
|
val=oc_pack_read(_opb,24);
|
||||||
|
_info->aspect_numerator=(ogg_uint32_t)val;
|
||||||
|
val=oc_pack_read(_opb,24);
|
||||||
|
_info->aspect_denominator=(ogg_uint32_t)val;
|
||||||
|
val=oc_pack_read(_opb,8);
|
||||||
|
_info->colorspace=(th_colorspace)val;
|
||||||
|
val=oc_pack_read(_opb,24);
|
||||||
|
_info->target_bitrate=(int)val;
|
||||||
|
val=oc_pack_read(_opb,6);
|
||||||
|
_info->quality=(int)val;
|
||||||
|
val=oc_pack_read(_opb,5);
|
||||||
|
_info->keyframe_granule_shift=(int)val;
|
||||||
|
val=oc_pack_read(_opb,2);
|
||||||
|
_info->pixel_fmt=(th_pixel_fmt)val;
|
||||||
|
if(_info->pixel_fmt==TH_PF_RSVD)return TH_EBADHEADER;
|
||||||
|
val=oc_pack_read(_opb,3);
|
||||||
|
if(val!=0||oc_pack_bytes_left(_opb)<0)return TH_EBADHEADER;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int oc_comment_unpack(oc_pack_buf *_opb,th_comment *_tc){
|
||||||
|
long len;
|
||||||
|
int i;
|
||||||
|
/*Read the vendor string.*/
|
||||||
|
len=oc_unpack_length(_opb);
|
||||||
|
if(len<0||len>oc_pack_bytes_left(_opb))return TH_EBADHEADER;
|
||||||
|
_tc->vendor=_ogg_malloc((size_t)len+1);
|
||||||
|
if(_tc->vendor==NULL)return TH_EFAULT;
|
||||||
|
oc_unpack_octets(_opb,_tc->vendor,len);
|
||||||
|
_tc->vendor[len]='\0';
|
||||||
|
/*Read the user comments.*/
|
||||||
|
_tc->comments=(int)oc_unpack_length(_opb);
|
||||||
|
len=_tc->comments;
|
||||||
|
if(len<0||len>(LONG_MAX>>2)||len<<2>oc_pack_bytes_left(_opb)){
|
||||||
|
_tc->comments=0;
|
||||||
|
return TH_EBADHEADER;
|
||||||
|
}
|
||||||
|
_tc->comment_lengths=(int *)_ogg_malloc(
|
||||||
|
_tc->comments*sizeof(_tc->comment_lengths[0]));
|
||||||
|
_tc->user_comments=(char **)_ogg_malloc(
|
||||||
|
_tc->comments*sizeof(_tc->user_comments[0]));
|
||||||
|
if(_tc->comment_lengths==NULL||_tc->user_comments==NULL){
|
||||||
|
_tc->comments=0;
|
||||||
|
return TH_EFAULT;
|
||||||
|
}
|
||||||
|
for(i=0;i<_tc->comments;i++){
|
||||||
|
len=oc_unpack_length(_opb);
|
||||||
|
if(len<0||len>oc_pack_bytes_left(_opb)){
|
||||||
|
_tc->comments=i;
|
||||||
|
return TH_EBADHEADER;
|
||||||
|
}
|
||||||
|
_tc->comment_lengths[i]=len;
|
||||||
|
_tc->user_comments[i]=_ogg_malloc((size_t)len+1);
|
||||||
|
if(_tc->user_comments[i]==NULL){
|
||||||
|
_tc->comments=i;
|
||||||
|
return TH_EFAULT;
|
||||||
|
}
|
||||||
|
oc_unpack_octets(_opb,_tc->user_comments[i],len);
|
||||||
|
_tc->user_comments[i][len]='\0';
|
||||||
|
}
|
||||||
|
return oc_pack_bytes_left(_opb)<0?TH_EBADHEADER:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int oc_setup_unpack(oc_pack_buf *_opb,th_setup_info *_setup){
|
||||||
|
int ret;
|
||||||
|
/*Read the quantizer tables.*/
|
||||||
|
ret=oc_quant_params_unpack(_opb,&_setup->qinfo);
|
||||||
|
if(ret<0)return ret;
|
||||||
|
/*Read the Huffman trees.*/
|
||||||
|
return oc_huff_trees_unpack(_opb,_setup->huff_tables);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void oc_setup_clear(th_setup_info *_setup){
|
||||||
|
oc_quant_params_clear(&_setup->qinfo);
|
||||||
|
oc_huff_trees_clear(_setup->huff_tables);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int oc_dec_headerin(oc_pack_buf *_opb,th_info *_info,
|
||||||
|
th_comment *_tc,th_setup_info **_setup,ogg_packet *_op){
|
||||||
|
char buffer[6];
|
||||||
|
long val;
|
||||||
|
int packtype;
|
||||||
|
int ret;
|
||||||
|
val=oc_pack_read(_opb,8);
|
||||||
|
packtype=(int)val;
|
||||||
|
/*If we're at a data packet...*/
|
||||||
|
if(!(packtype&0x80)){
|
||||||
|
/*Check to make sure we received all three headers...
|
||||||
|
If we haven't seen any valid headers, assume this is not actually
|
||||||
|
Theora.*/
|
||||||
|
if(_info->frame_width<=0)return TH_ENOTFORMAT;
|
||||||
|
/*Follow our documentation, which says we'll return TH_EFAULT if this
|
||||||
|
are NULL (_info was checked by our caller).*/
|
||||||
|
if(_tc==NULL)return TH_EFAULT;
|
||||||
|
/*And if any other headers were missing, declare this packet "out of
|
||||||
|
sequence" instead.*/
|
||||||
|
if(_tc->vendor==NULL)return TH_EBADHEADER;
|
||||||
|
/*Don't check this until it's needed, since we allow passing NULL for the
|
||||||
|
arguments that we're not expecting the next header to fill in yet.*/
|
||||||
|
if(_setup==NULL)return TH_EFAULT;
|
||||||
|
if(*_setup==NULL)return TH_EBADHEADER;
|
||||||
|
/*If we got everything, we're done.*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*Check the codec string.*/
|
||||||
|
oc_unpack_octets(_opb,buffer,6);
|
||||||
|
if(memcmp(buffer,"theora",6)!=0)return TH_ENOTFORMAT;
|
||||||
|
switch(packtype){
|
||||||
|
/*Codec info header.*/
|
||||||
|
case 0x80:{
|
||||||
|
/*This should be the first packet, and we should not already be
|
||||||
|
initialized.*/
|
||||||
|
if(!_op->b_o_s||_info->frame_width>0)return TH_EBADHEADER;
|
||||||
|
ret=oc_info_unpack(_opb,_info);
|
||||||
|
if(ret<0)th_info_clear(_info);
|
||||||
|
else ret=3;
|
||||||
|
}break;
|
||||||
|
/*Comment header.*/
|
||||||
|
case 0x81:{
|
||||||
|
if(_tc==NULL)return TH_EFAULT;
|
||||||
|
/*We shoud have already decoded the info header, and should not yet have
|
||||||
|
decoded the comment header.*/
|
||||||
|
if(_info->frame_width==0||_tc->vendor!=NULL)return TH_EBADHEADER;
|
||||||
|
ret=oc_comment_unpack(_opb,_tc);
|
||||||
|
if(ret<0)th_comment_clear(_tc);
|
||||||
|
else ret=2;
|
||||||
|
}break;
|
||||||
|
/*Codec setup header.*/
|
||||||
|
case 0x82:{
|
||||||
|
oc_setup_info *setup;
|
||||||
|
if(_tc==NULL||_setup==NULL)return TH_EFAULT;
|
||||||
|
/*We should have already decoded the info header and the comment header,
|
||||||
|
and should not yet have decoded the setup header.*/
|
||||||
|
if(_info->frame_width==0||_tc->vendor==NULL||*_setup!=NULL){
|
||||||
|
return TH_EBADHEADER;
|
||||||
|
}
|
||||||
|
setup=(oc_setup_info *)_ogg_calloc(1,sizeof(*setup));
|
||||||
|
if(setup==NULL)return TH_EFAULT;
|
||||||
|
ret=oc_setup_unpack(_opb,setup);
|
||||||
|
if(ret<0){
|
||||||
|
oc_setup_clear(setup);
|
||||||
|
_ogg_free(setup);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
*_setup=setup;
|
||||||
|
ret=1;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
default:{
|
||||||
|
/*We don't know what this header is.*/
|
||||||
|
return TH_EBADHEADER;
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*Decodes one header packet.
|
||||||
|
This should be called repeatedly with the packets at the beginning of the
|
||||||
|
stream until it returns 0.*/
|
||||||
|
int th_decode_headerin(th_info *_info,th_comment *_tc,
|
||||||
|
th_setup_info **_setup,ogg_packet *_op){
|
||||||
|
oc_pack_buf opb;
|
||||||
|
if(_op==NULL)return TH_EBADHEADER;
|
||||||
|
if(_info==NULL)return TH_EFAULT;
|
||||||
|
oc_pack_readinit(&opb,_op->packet,_op->bytes);
|
||||||
|
return oc_dec_headerin(&opb,_info,_tc,_setup,_op);
|
||||||
|
}
|
||||||
|
|
||||||
|
void th_setup_free(th_setup_info *_setup){
|
||||||
|
if(_setup!=NULL){
|
||||||
|
oc_setup_clear(_setup);
|
||||||
|
_ogg_free(_setup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,185 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#if !defined(_decint_H)
|
||||||
|
# define _decint_H (1)
|
||||||
|
# include "theora/theoradec.h"
|
||||||
|
# include "state.h"
|
||||||
|
# include "bitpack.h"
|
||||||
|
# include "huffdec.h"
|
||||||
|
# include "dequant.h"
|
||||||
|
|
||||||
|
typedef struct th_setup_info oc_setup_info;
|
||||||
|
typedef struct oc_dec_opt_vtable oc_dec_opt_vtable;
|
||||||
|
typedef struct oc_dec_pipeline_state oc_dec_pipeline_state;
|
||||||
|
typedef struct th_dec_ctx oc_dec_ctx;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*Decoder-specific accelerated functions.*/
|
||||||
|
# if defined(OC_C64X_ASM)
|
||||||
|
# include "c64x/c64xdec.h"
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if !defined(oc_dec_accel_init)
|
||||||
|
# define oc_dec_accel_init oc_dec_accel_init_c
|
||||||
|
# endif
|
||||||
|
# if defined(OC_DEC_USE_VTABLE)
|
||||||
|
# if !defined(oc_dec_dc_unpredict_mcu_plane)
|
||||||
|
# define oc_dec_dc_unpredict_mcu_plane(_dec,_pipe,_pli) \
|
||||||
|
((*(_dec)->opt_vtable.dc_unpredict_mcu_plane)(_dec,_pipe,_pli))
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# if !defined(oc_dec_dc_unpredict_mcu_plane)
|
||||||
|
# define oc_dec_dc_unpredict_mcu_plane oc_dec_dc_unpredict_mcu_plane_c
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*Constants for the packet-in state machine specific to the decoder.*/
|
||||||
|
|
||||||
|
/*Next packet to read: Data packet.*/
|
||||||
|
#define OC_PACKET_DATA (0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct th_setup_info{
|
||||||
|
/*The Huffman codes.*/
|
||||||
|
ogg_int16_t *huff_tables[TH_NHUFFMAN_TABLES];
|
||||||
|
/*The quantization parameters.*/
|
||||||
|
th_quant_info qinfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*Decoder specific functions with accelerated variants.*/
|
||||||
|
struct oc_dec_opt_vtable{
|
||||||
|
void (*dc_unpredict_mcu_plane)(oc_dec_ctx *_dec,
|
||||||
|
oc_dec_pipeline_state *_pipe,int _pli);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct oc_dec_pipeline_state{
|
||||||
|
/*Decoded DCT coefficients.
|
||||||
|
These are placed here instead of on the stack so that they can persist
|
||||||
|
between blocks, which makes clearing them back to zero much faster when
|
||||||
|
only a few non-zero coefficients were decoded.
|
||||||
|
It requires at least 65 elements because the zig-zag index array uses the
|
||||||
|
65th element as a dumping ground for out-of-range indices to protect us
|
||||||
|
from buffer overflow.
|
||||||
|
We make it fully twice as large so that the second half can serve as the
|
||||||
|
reconstruction buffer, which saves passing another parameter to all the
|
||||||
|
acceleration functios.
|
||||||
|
It also solves problems with 16-byte alignment for NEON on ARM.
|
||||||
|
gcc (as of 4.2.1) only seems to be able to give stack variables 8-byte
|
||||||
|
alignment, and silently produces incorrect results if you ask for 16.
|
||||||
|
Finally, keeping it off the stack means there's less likely to be a data
|
||||||
|
hazard beween the NEON co-processor and the regular ARM core, which avoids
|
||||||
|
unnecessary stalls.*/
|
||||||
|
OC_ALIGN16(ogg_int16_t dct_coeffs[128]);
|
||||||
|
OC_ALIGN16(signed char bounding_values[256]);
|
||||||
|
ptrdiff_t ti[3][64];
|
||||||
|
ptrdiff_t ebi[3][64];
|
||||||
|
ptrdiff_t eob_runs[3][64];
|
||||||
|
const ptrdiff_t *coded_fragis[3];
|
||||||
|
const ptrdiff_t *uncoded_fragis[3];
|
||||||
|
ptrdiff_t ncoded_fragis[3];
|
||||||
|
ptrdiff_t nuncoded_fragis[3];
|
||||||
|
const ogg_uint16_t *dequant[3][3][2];
|
||||||
|
int fragy0[3];
|
||||||
|
int fragy_end[3];
|
||||||
|
int pred_last[3][4];
|
||||||
|
int mcu_nvfrags;
|
||||||
|
int loop_filter;
|
||||||
|
int pp_level;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct th_dec_ctx{
|
||||||
|
/*Shared encoder/decoder state.*/
|
||||||
|
oc_theora_state state;
|
||||||
|
/*Whether or not packets are ready to be emitted.
|
||||||
|
This takes on negative values while there are remaining header packets to
|
||||||
|
be emitted, reaches 0 when the codec is ready for input, and goes to 1
|
||||||
|
when a frame has been processed and a data packet is ready.*/
|
||||||
|
int packet_state;
|
||||||
|
/*Buffer in which to assemble packets.*/
|
||||||
|
oc_pack_buf opb;
|
||||||
|
/*Huffman decode trees.*/
|
||||||
|
ogg_int16_t *huff_tables[TH_NHUFFMAN_TABLES];
|
||||||
|
/*The index of the first token in each plane for each coefficient.*/
|
||||||
|
ptrdiff_t ti0[3][64];
|
||||||
|
/*The number of outstanding EOB runs at the start of each coefficient in each
|
||||||
|
plane.*/
|
||||||
|
ptrdiff_t eob_runs[3][64];
|
||||||
|
/*The DCT token lists.*/
|
||||||
|
unsigned char *dct_tokens;
|
||||||
|
/*The extra bits associated with DCT tokens.*/
|
||||||
|
unsigned char *extra_bits;
|
||||||
|
/*The number of dct tokens unpacked so far.*/
|
||||||
|
int dct_tokens_count;
|
||||||
|
/*The out-of-loop post-processing level.*/
|
||||||
|
int pp_level;
|
||||||
|
/*The DC scale used for out-of-loop deblocking.*/
|
||||||
|
int pp_dc_scale[64];
|
||||||
|
/*The sharpen modifier used for out-of-loop deringing.*/
|
||||||
|
int pp_sharp_mod[64];
|
||||||
|
/*The DC quantization index of each block.*/
|
||||||
|
unsigned char *dc_qis;
|
||||||
|
/*The variance of each block.*/
|
||||||
|
int *variances;
|
||||||
|
/*The storage for the post-processed frame buffer.*/
|
||||||
|
unsigned char *pp_frame_data;
|
||||||
|
/*Whether or not the post-processsed frame buffer has space for chroma.*/
|
||||||
|
int pp_frame_state;
|
||||||
|
/*The buffer used for the post-processed frame.
|
||||||
|
Note that this is _not_ guaranteed to have the same strides and offsets as
|
||||||
|
the reference frame buffers.*/
|
||||||
|
th_ycbcr_buffer pp_frame_buf;
|
||||||
|
/*The striped decode callback function.*/
|
||||||
|
th_stripe_callback stripe_cb;
|
||||||
|
oc_dec_pipeline_state pipe;
|
||||||
|
# if defined(OC_DEC_USE_VTABLE)
|
||||||
|
/*Table for decoder acceleration functions.*/
|
||||||
|
oc_dec_opt_vtable opt_vtable;
|
||||||
|
# endif
|
||||||
|
# if defined(HAVE_CAIRO)
|
||||||
|
/*Output metrics for debugging.*/
|
||||||
|
int telemetry_mbmode;
|
||||||
|
int telemetry_mv;
|
||||||
|
int telemetry_qi;
|
||||||
|
int telemetry_bits;
|
||||||
|
int telemetry_frame_bytes;
|
||||||
|
int telemetry_coding_bytes;
|
||||||
|
int telemetry_mode_bytes;
|
||||||
|
int telemetry_mv_bytes;
|
||||||
|
int telemetry_qi_bytes;
|
||||||
|
int telemetry_dc_bytes;
|
||||||
|
unsigned char *telemetry_frame_data;
|
||||||
|
# endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/*Default pure-C implementations of decoder-specific accelerated functions.*/
|
||||||
|
void oc_dec_accel_init_c(oc_dec_ctx *_dec);
|
||||||
|
|
||||||
|
void oc_dec_dc_unpredict_mcu_plane_c(oc_dec_ctx *_dec,
|
||||||
|
oc_dec_pipeline_state *_pipe,int _pli);
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,182 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
#include "dequant.h"
|
||||||
|
#include "decint.h"
|
||||||
|
|
||||||
|
int oc_quant_params_unpack(oc_pack_buf *_opb,th_quant_info *_qinfo){
|
||||||
|
th_quant_base *base_mats;
|
||||||
|
long val;
|
||||||
|
int nbase_mats;
|
||||||
|
int sizes[64];
|
||||||
|
int indices[64];
|
||||||
|
int nbits;
|
||||||
|
int bmi;
|
||||||
|
int ci;
|
||||||
|
int qti;
|
||||||
|
int pli;
|
||||||
|
int qri;
|
||||||
|
int qi;
|
||||||
|
int i;
|
||||||
|
val=oc_pack_read(_opb,3);
|
||||||
|
nbits=(int)val;
|
||||||
|
for(qi=0;qi<64;qi++){
|
||||||
|
val=oc_pack_read(_opb,nbits);
|
||||||
|
_qinfo->loop_filter_limits[qi]=(unsigned char)val;
|
||||||
|
}
|
||||||
|
val=oc_pack_read(_opb,4);
|
||||||
|
nbits=(int)val+1;
|
||||||
|
for(qi=0;qi<64;qi++){
|
||||||
|
val=oc_pack_read(_opb,nbits);
|
||||||
|
_qinfo->ac_scale[qi]=(ogg_uint16_t)val;
|
||||||
|
}
|
||||||
|
val=oc_pack_read(_opb,4);
|
||||||
|
nbits=(int)val+1;
|
||||||
|
for(qi=0;qi<64;qi++){
|
||||||
|
val=oc_pack_read(_opb,nbits);
|
||||||
|
_qinfo->dc_scale[qi]=(ogg_uint16_t)val;
|
||||||
|
}
|
||||||
|
val=oc_pack_read(_opb,9);
|
||||||
|
nbase_mats=(int)val+1;
|
||||||
|
base_mats=_ogg_malloc(nbase_mats*sizeof(base_mats[0]));
|
||||||
|
if(base_mats==NULL)return TH_EFAULT;
|
||||||
|
for(bmi=0;bmi<nbase_mats;bmi++){
|
||||||
|
for(ci=0;ci<64;ci++){
|
||||||
|
val=oc_pack_read(_opb,8);
|
||||||
|
base_mats[bmi][ci]=(unsigned char)val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nbits=oc_ilog(nbase_mats-1);
|
||||||
|
for(i=0;i<6;i++){
|
||||||
|
th_quant_ranges *qranges;
|
||||||
|
th_quant_base *qrbms;
|
||||||
|
int *qrsizes;
|
||||||
|
qti=i/3;
|
||||||
|
pli=i%3;
|
||||||
|
qranges=_qinfo->qi_ranges[qti]+pli;
|
||||||
|
if(i>0){
|
||||||
|
val=oc_pack_read1(_opb);
|
||||||
|
if(!val){
|
||||||
|
int qtj;
|
||||||
|
int plj;
|
||||||
|
if(qti>0){
|
||||||
|
val=oc_pack_read1(_opb);
|
||||||
|
if(val){
|
||||||
|
qtj=qti-1;
|
||||||
|
plj=pli;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
qtj=(i-1)/3;
|
||||||
|
plj=(i-1)%3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
qtj=(i-1)/3;
|
||||||
|
plj=(i-1)%3;
|
||||||
|
}
|
||||||
|
*qranges=*(_qinfo->qi_ranges[qtj]+plj);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val=oc_pack_read(_opb,nbits);
|
||||||
|
indices[0]=(int)val;
|
||||||
|
for(qi=qri=0;qi<63;){
|
||||||
|
val=oc_pack_read(_opb,oc_ilog(62-qi));
|
||||||
|
sizes[qri]=(int)val+1;
|
||||||
|
qi+=(int)val+1;
|
||||||
|
val=oc_pack_read(_opb,nbits);
|
||||||
|
indices[++qri]=(int)val;
|
||||||
|
}
|
||||||
|
/*Note: The caller is responsible for cleaning up any partially
|
||||||
|
constructed qinfo.*/
|
||||||
|
if(qi>63){
|
||||||
|
_ogg_free(base_mats);
|
||||||
|
return TH_EBADHEADER;
|
||||||
|
}
|
||||||
|
qranges->nranges=qri;
|
||||||
|
qranges->sizes=qrsizes=(int *)_ogg_malloc(qri*sizeof(qrsizes[0]));
|
||||||
|
if(qranges->sizes==NULL){
|
||||||
|
/*Note: The caller is responsible for cleaning up any partially
|
||||||
|
constructed qinfo.*/
|
||||||
|
_ogg_free(base_mats);
|
||||||
|
return TH_EFAULT;
|
||||||
|
}
|
||||||
|
memcpy(qrsizes,sizes,qri*sizeof(qrsizes[0]));
|
||||||
|
qrbms=(th_quant_base *)_ogg_malloc((qri+1)*sizeof(qrbms[0]));
|
||||||
|
if(qrbms==NULL){
|
||||||
|
/*Note: The caller is responsible for cleaning up any partially
|
||||||
|
constructed qinfo.*/
|
||||||
|
_ogg_free(base_mats);
|
||||||
|
return TH_EFAULT;
|
||||||
|
}
|
||||||
|
qranges->base_matrices=(const th_quant_base *)qrbms;
|
||||||
|
do{
|
||||||
|
bmi=indices[qri];
|
||||||
|
/*Note: The caller is responsible for cleaning up any partially
|
||||||
|
constructed qinfo.*/
|
||||||
|
if(bmi>=nbase_mats){
|
||||||
|
_ogg_free(base_mats);
|
||||||
|
return TH_EBADHEADER;
|
||||||
|
}
|
||||||
|
memcpy(qrbms[qri],base_mats[bmi],sizeof(qrbms[qri]));
|
||||||
|
}
|
||||||
|
while(qri-->0);
|
||||||
|
}
|
||||||
|
_ogg_free(base_mats);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_quant_params_clear(th_quant_info *_qinfo){
|
||||||
|
int i;
|
||||||
|
for(i=6;i-->0;){
|
||||||
|
int qti;
|
||||||
|
int pli;
|
||||||
|
qti=i/3;
|
||||||
|
pli=i%3;
|
||||||
|
/*Clear any duplicate pointer references.*/
|
||||||
|
if(i>0){
|
||||||
|
int qtj;
|
||||||
|
int plj;
|
||||||
|
qtj=(i-1)/3;
|
||||||
|
plj=(i-1)%3;
|
||||||
|
if(_qinfo->qi_ranges[qti][pli].sizes==
|
||||||
|
_qinfo->qi_ranges[qtj][plj].sizes){
|
||||||
|
_qinfo->qi_ranges[qti][pli].sizes=NULL;
|
||||||
|
}
|
||||||
|
if(_qinfo->qi_ranges[qti][pli].base_matrices==
|
||||||
|
_qinfo->qi_ranges[qtj][plj].base_matrices){
|
||||||
|
_qinfo->qi_ranges[qti][pli].base_matrices=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(qti>0){
|
||||||
|
if(_qinfo->qi_ranges[1][pli].sizes==
|
||||||
|
_qinfo->qi_ranges[0][pli].sizes){
|
||||||
|
_qinfo->qi_ranges[1][pli].sizes=NULL;
|
||||||
|
}
|
||||||
|
if(_qinfo->qi_ranges[1][pli].base_matrices==
|
||||||
|
_qinfo->qi_ranges[0][pli].base_matrices){
|
||||||
|
_qinfo->qi_ranges[1][pli].base_matrices=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*Now free all the non-duplicate storage.*/
|
||||||
|
_ogg_free((void *)_qinfo->qi_ranges[qti][pli].sizes);
|
||||||
|
_ogg_free((void *)_qinfo->qi_ranges[qti][pli].base_matrices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#if !defined(_dequant_H)
|
||||||
|
# define _dequant_H (1)
|
||||||
|
# include "quant.h"
|
||||||
|
# include "bitpack.h"
|
||||||
|
|
||||||
|
int oc_quant_params_unpack(oc_pack_buf *_opb,
|
||||||
|
th_quant_info *_qinfo);
|
||||||
|
void oc_quant_params_clear(th_quant_info *_qinfo);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
#include <string.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
void oc_frag_copy_c(unsigned char *_dst,const unsigned char *_src,int _ystride){
|
||||||
|
int i;
|
||||||
|
for(i=8;i-->0;){
|
||||||
|
memcpy(_dst,_src,8*sizeof(*_dst));
|
||||||
|
_dst+=_ystride;
|
||||||
|
_src+=_ystride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Copies the fragments specified by the lists of fragment indices from one
|
||||||
|
frame to another.
|
||||||
|
_dst_frame: The reference frame to copy to.
|
||||||
|
_src_frame: The reference frame to copy from.
|
||||||
|
_ystride: The row stride of the reference frames.
|
||||||
|
_fragis: A pointer to a list of fragment indices.
|
||||||
|
_nfragis: The number of fragment indices to copy.
|
||||||
|
_frag_buf_offs: The offsets of fragments in the reference frames.*/
|
||||||
|
void oc_frag_copy_list_c(unsigned char *_dst_frame,
|
||||||
|
const unsigned char *_src_frame,int _ystride,
|
||||||
|
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs){
|
||||||
|
ptrdiff_t fragii;
|
||||||
|
for(fragii=0;fragii<_nfragis;fragii++){
|
||||||
|
ptrdiff_t frag_buf_off;
|
||||||
|
frag_buf_off=_frag_buf_offs[_fragis[fragii]];
|
||||||
|
oc_frag_copy_c(_dst_frame+frag_buf_off,
|
||||||
|
_src_frame+frag_buf_off,_ystride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_frag_recon_intra_c(unsigned char *_dst,int _ystride,
|
||||||
|
const ogg_int16_t _residue[64]){
|
||||||
|
int i;
|
||||||
|
for(i=0;i<8;i++){
|
||||||
|
int j;
|
||||||
|
for(j=0;j<8;j++)_dst[j]=OC_CLAMP255(_residue[i*8+j]+128);
|
||||||
|
_dst+=_ystride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_frag_recon_inter_c(unsigned char *_dst,
|
||||||
|
const unsigned char *_src,int _ystride,const ogg_int16_t _residue[64]){
|
||||||
|
int i;
|
||||||
|
for(i=0;i<8;i++){
|
||||||
|
int j;
|
||||||
|
for(j=0;j<8;j++)_dst[j]=OC_CLAMP255(_residue[i*8+j]+_src[j]);
|
||||||
|
_dst+=_ystride;
|
||||||
|
_src+=_ystride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_frag_recon_inter2_c(unsigned char *_dst,const unsigned char *_src1,
|
||||||
|
const unsigned char *_src2,int _ystride,const ogg_int16_t _residue[64]){
|
||||||
|
int i;
|
||||||
|
for(i=0;i<8;i++){
|
||||||
|
int j;
|
||||||
|
for(j=0;j<8;j++)_dst[j]=OC_CLAMP255(_residue[i*8+j]+(_src1[j]+_src2[j]>>1));
|
||||||
|
_dst+=_ystride;
|
||||||
|
_src1+=_ystride;
|
||||||
|
_src2+=_ystride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_restore_fpu_c(void){}
|
||||||
|
|
@ -0,0 +1,512 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
#include "huffdec.h"
|
||||||
|
#include "decint.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*Instead of storing every branching in the tree, subtrees can be collapsed
|
||||||
|
into one node, with a table of size 1<<nbits pointing directly to its
|
||||||
|
descedents nbits levels down.
|
||||||
|
This allows more than one bit to be read at a time, and avoids following all
|
||||||
|
the intermediate branches with next to no increased code complexity once
|
||||||
|
the collapsed tree has been built.
|
||||||
|
We do _not_ require that a subtree be complete to be collapsed, but instead
|
||||||
|
store duplicate pointers in the table, and record the actual depth of the
|
||||||
|
node below its parent.
|
||||||
|
This tells us the number of bits to advance the stream after reaching it.
|
||||||
|
|
||||||
|
This turns out to be equivalent to the method described in \cite{Hash95},
|
||||||
|
without the requirement that codewords be sorted by length.
|
||||||
|
If the codewords were sorted by length (so-called ``canonical-codes''), they
|
||||||
|
could be decoded much faster via either Lindell and Moffat's approach or
|
||||||
|
Hashemian's Condensed Huffman Code approach, the latter of which has an
|
||||||
|
extremely small memory footprint.
|
||||||
|
We can't use Choueka et al.'s finite state machine approach, which is
|
||||||
|
extremely fast, because we can't allow multiple symbols to be output at a
|
||||||
|
time; the codebook can and does change between symbols.
|
||||||
|
It also has very large memory requirements, which impairs cache coherency.
|
||||||
|
|
||||||
|
We store the tree packed in an array of 16-bit integers (words).
|
||||||
|
Each node consists of a single word, followed consecutively by two or more
|
||||||
|
indices of its children.
|
||||||
|
Let n be the value of this first word.
|
||||||
|
This is the number of bits that need to be read to traverse the node, and
|
||||||
|
must be positive.
|
||||||
|
1<<n entries follow in the array, each an index to a child node.
|
||||||
|
If the child is positive, then it is the index of another internal node in
|
||||||
|
the table.
|
||||||
|
If the child is negative or zero, then it is a leaf node.
|
||||||
|
These are stored directly in the child pointer to save space, since they only
|
||||||
|
require a single word.
|
||||||
|
If a leaf node would have been encountered before reading n bits, then it is
|
||||||
|
duplicated the necessary number of times in this table.
|
||||||
|
Leaf nodes pack both a token value and their actual depth in the tree.
|
||||||
|
The token in the leaf node is (-leaf&255).
|
||||||
|
The number of bits that need to be consumed to reach the leaf, starting from
|
||||||
|
the current node, is (-leaf>>8).
|
||||||
|
|
||||||
|
@ARTICLE{Hash95,
|
||||||
|
author="Reza Hashemian",
|
||||||
|
title="Memory Efficient and High-Speed Search {Huffman} Coding",
|
||||||
|
journal="{IEEE} Transactions on Communications",
|
||||||
|
volume=43,
|
||||||
|
number=10,
|
||||||
|
pages="2576--2581",
|
||||||
|
month=Oct,
|
||||||
|
year=1995
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*The map from external spec-defined tokens to internal tokens.
|
||||||
|
This is constructed so that any extra bits read with the original token value
|
||||||
|
can be masked off the least significant bits of its internal token index.
|
||||||
|
In addition, all of the tokens which require additional extra bits are placed
|
||||||
|
at the start of the list, and grouped by type.
|
||||||
|
OC_DCT_REPEAT_RUN3_TOKEN is placed first, as it is an extra-special case, so
|
||||||
|
giving it index 0 may simplify comparisons on some architectures.
|
||||||
|
These requirements require some substantial reordering.*/
|
||||||
|
static const unsigned char OC_DCT_TOKEN_MAP[TH_NDCT_TOKENS]={
|
||||||
|
/*OC_DCT_EOB1_TOKEN (0 extra bits)*/
|
||||||
|
15,
|
||||||
|
/*OC_DCT_EOB2_TOKEN (0 extra bits)*/
|
||||||
|
16,
|
||||||
|
/*OC_DCT_EOB3_TOKEN (0 extra bits)*/
|
||||||
|
17,
|
||||||
|
/*OC_DCT_REPEAT_RUN0_TOKEN (2 extra bits)*/
|
||||||
|
88,
|
||||||
|
/*OC_DCT_REPEAT_RUN1_TOKEN (3 extra bits)*/
|
||||||
|
80,
|
||||||
|
/*OC_DCT_REPEAT_RUN2_TOKEN (4 extra bits)*/
|
||||||
|
1,
|
||||||
|
/*OC_DCT_REPEAT_RUN3_TOKEN (12 extra bits)*/
|
||||||
|
0,
|
||||||
|
/*OC_DCT_SHORT_ZRL_TOKEN (3 extra bits)*/
|
||||||
|
48,
|
||||||
|
/*OC_DCT_ZRL_TOKEN (6 extra bits)*/
|
||||||
|
14,
|
||||||
|
/*OC_ONE_TOKEN (0 extra bits)*/
|
||||||
|
56,
|
||||||
|
/*OC_MINUS_ONE_TOKEN (0 extra bits)*/
|
||||||
|
57,
|
||||||
|
/*OC_TWO_TOKEN (0 extra bits)*/
|
||||||
|
58,
|
||||||
|
/*OC_MINUS_TWO_TOKEN (0 extra bits)*/
|
||||||
|
59,
|
||||||
|
/*OC_DCT_VAL_CAT2 (1 extra bit)*/
|
||||||
|
60,
|
||||||
|
62,
|
||||||
|
64,
|
||||||
|
66,
|
||||||
|
/*OC_DCT_VAL_CAT3 (2 extra bits)*/
|
||||||
|
68,
|
||||||
|
/*OC_DCT_VAL_CAT4 (3 extra bits)*/
|
||||||
|
72,
|
||||||
|
/*OC_DCT_VAL_CAT5 (4 extra bits)*/
|
||||||
|
2,
|
||||||
|
/*OC_DCT_VAL_CAT6 (5 extra bits)*/
|
||||||
|
4,
|
||||||
|
/*OC_DCT_VAL_CAT7 (6 extra bits)*/
|
||||||
|
6,
|
||||||
|
/*OC_DCT_VAL_CAT8 (10 extra bits)*/
|
||||||
|
8,
|
||||||
|
/*OC_DCT_RUN_CAT1A (1 extra bit)*/
|
||||||
|
18,
|
||||||
|
20,
|
||||||
|
22,
|
||||||
|
24,
|
||||||
|
26,
|
||||||
|
/*OC_DCT_RUN_CAT1B (3 extra bits)*/
|
||||||
|
32,
|
||||||
|
/*OC_DCT_RUN_CAT1C (4 extra bits)*/
|
||||||
|
12,
|
||||||
|
/*OC_DCT_RUN_CAT2A (2 extra bits)*/
|
||||||
|
28,
|
||||||
|
/*OC_DCT_RUN_CAT2B (3 extra bits)*/
|
||||||
|
40
|
||||||
|
};
|
||||||
|
|
||||||
|
/*The log base 2 of number of internal tokens associated with each of the spec
|
||||||
|
tokens (i.e., how many of the extra bits are folded into the token value).
|
||||||
|
Increasing the maximum value beyond 3 will enlarge the amount of stack
|
||||||
|
required for tree construction.*/
|
||||||
|
static const unsigned char OC_DCT_TOKEN_MAP_LOG_NENTRIES[TH_NDCT_TOKENS]={
|
||||||
|
0,0,0,2,3,0,0,3,0,0,0,0,0,1,1,1,1,2,3,1,1,1,2,1,1,1,1,1,3,1,2,3
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*The size a lookup table is allowed to grow to relative to the number of
|
||||||
|
unique nodes it contains.
|
||||||
|
E.g., if OC_HUFF_SLUSH is 4, then at most 75% of the space in the tree is
|
||||||
|
wasted (1/4 of the space must be used).
|
||||||
|
Larger numbers can decode tokens with fewer read operations, while smaller
|
||||||
|
numbers may save more space.
|
||||||
|
With a sample file:
|
||||||
|
32233473 read calls are required when no tree collapsing is done (100.0%).
|
||||||
|
19269269 read calls are required when OC_HUFF_SLUSH is 1 (59.8%).
|
||||||
|
11144969 read calls are required when OC_HUFF_SLUSH is 2 (34.6%).
|
||||||
|
10538563 read calls are required when OC_HUFF_SLUSH is 4 (32.7%).
|
||||||
|
10192578 read calls are required when OC_HUFF_SLUSH is 8 (31.6%).
|
||||||
|
Since a value of 2 gets us the vast majority of the speed-up with only a
|
||||||
|
small amount of wasted memory, this is what we use.
|
||||||
|
This value must be less than 128, or you could create a tree with more than
|
||||||
|
32767 entries, which would overflow the 16-bit words used to index it.*/
|
||||||
|
#define OC_HUFF_SLUSH (2)
|
||||||
|
/*The root of the tree is on the fast path, and a larger value here is more
|
||||||
|
beneficial than elsewhere in the tree.
|
||||||
|
7 appears to give the best performance, trading off between increased use of
|
||||||
|
the single-read fast path and cache footprint for the tables, though
|
||||||
|
obviously this will depend on your cache size.
|
||||||
|
Using 7 here, the VP3 tables are about twice as large compared to using 2.*/
|
||||||
|
#define OC_ROOT_HUFF_SLUSH (7)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*Unpacks a Huffman codebook.
|
||||||
|
_opb: The buffer to unpack from.
|
||||||
|
_tokens: Stores a list of internal tokens, in the order they were found in
|
||||||
|
the codebook, and the lengths of their corresponding codewords.
|
||||||
|
This is enough to completely define the codebook, while minimizing
|
||||||
|
stack usage and avoiding temporary allocations (for platforms
|
||||||
|
where free() is a no-op).
|
||||||
|
Return: The number of internal tokens in the codebook, or a negative value
|
||||||
|
on error.*/
|
||||||
|
int oc_huff_tree_unpack(oc_pack_buf *_opb,unsigned char _tokens[256][2]){
|
||||||
|
ogg_uint32_t code;
|
||||||
|
int len;
|
||||||
|
int ntokens;
|
||||||
|
int nleaves;
|
||||||
|
code=0;
|
||||||
|
len=ntokens=nleaves=0;
|
||||||
|
for(;;){
|
||||||
|
long bits;
|
||||||
|
bits=oc_pack_read1(_opb);
|
||||||
|
/*Only process nodes so long as there's more bits in the buffer.*/
|
||||||
|
if(oc_pack_bytes_left(_opb)<0)return TH_EBADHEADER;
|
||||||
|
/*Read an internal node:*/
|
||||||
|
if(!bits){
|
||||||
|
len++;
|
||||||
|
/*Don't allow codewords longer than 32 bits.*/
|
||||||
|
if(len>32)return TH_EBADHEADER;
|
||||||
|
}
|
||||||
|
/*Read a leaf node:*/
|
||||||
|
else{
|
||||||
|
ogg_uint32_t code_bit;
|
||||||
|
int neb;
|
||||||
|
int nentries;
|
||||||
|
int token;
|
||||||
|
/*Don't allow more than 32 spec-tokens per codebook.*/
|
||||||
|
if(++nleaves>32)return TH_EBADHEADER;
|
||||||
|
bits=oc_pack_read(_opb,OC_NDCT_TOKEN_BITS);
|
||||||
|
neb=OC_DCT_TOKEN_MAP_LOG_NENTRIES[bits];
|
||||||
|
token=OC_DCT_TOKEN_MAP[bits];
|
||||||
|
nentries=1<<neb;
|
||||||
|
while(nentries-->0){
|
||||||
|
_tokens[ntokens][0]=(unsigned char)token++;
|
||||||
|
_tokens[ntokens][1]=(unsigned char)(len+neb);
|
||||||
|
ntokens++;
|
||||||
|
}
|
||||||
|
code_bit=0x80000000U>>len-1;
|
||||||
|
while(len>0&&(code&code_bit)){
|
||||||
|
code^=code_bit;
|
||||||
|
code_bit<<=1;
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
if(len<=0)break;
|
||||||
|
code|=code_bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ntokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Count how many tokens would be required to fill a subtree at depth _depth.
|
||||||
|
_tokens: A list of internal tokens, in the order they are found in the
|
||||||
|
codebook, and the lengths of their corresponding codewords.
|
||||||
|
_depth: The depth of the desired node in the corresponding tree structure.
|
||||||
|
Return: The number of tokens that belong to that subtree.*/
|
||||||
|
static int oc_huff_subtree_tokens(unsigned char _tokens[][2],int _depth){
|
||||||
|
ogg_uint32_t code;
|
||||||
|
int ti;
|
||||||
|
code=0;
|
||||||
|
ti=0;
|
||||||
|
do{
|
||||||
|
if(_tokens[ti][1]-_depth<32)code+=0x80000000U>>_tokens[ti++][1]-_depth;
|
||||||
|
else{
|
||||||
|
/*Because of the expanded internal tokens, we can have codewords as long
|
||||||
|
as 35 bits.
|
||||||
|
A single recursion here is enough to advance past them.*/
|
||||||
|
code++;
|
||||||
|
ti+=oc_huff_subtree_tokens(_tokens+ti,_depth+31);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(code<0x80000000U);
|
||||||
|
return ti;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Compute the number of bits to use for a collapsed tree node at the given
|
||||||
|
depth.
|
||||||
|
_tokens: A list of internal tokens, in the order they are found in the
|
||||||
|
codebook, and the lengths of their corresponding codewords.
|
||||||
|
_ntokens: The number of tokens corresponding to this tree node.
|
||||||
|
_depth: The depth of this tree node.
|
||||||
|
Return: The number of bits to use for a collapsed tree node rooted here.
|
||||||
|
This is always at least one, even if this was a leaf node.*/
|
||||||
|
static int oc_huff_tree_collapse_depth(unsigned char _tokens[][2],
|
||||||
|
int _ntokens,int _depth){
|
||||||
|
int got_leaves;
|
||||||
|
int loccupancy;
|
||||||
|
int occupancy;
|
||||||
|
int slush;
|
||||||
|
int nbits;
|
||||||
|
int best_nbits;
|
||||||
|
slush=_depth>0?OC_HUFF_SLUSH:OC_ROOT_HUFF_SLUSH;
|
||||||
|
/*It's legal to have a tree with just a single node, which requires no bits
|
||||||
|
to decode and always returns the same token.
|
||||||
|
However, no encoder actually does this (yet).
|
||||||
|
To avoid a special case in oc_huff_token_decode(), we force the number of
|
||||||
|
lookahead bits to be at least one.
|
||||||
|
This will produce a tree that looks ahead one bit and then advances the
|
||||||
|
stream zero bits.*/
|
||||||
|
nbits=1;
|
||||||
|
occupancy=2;
|
||||||
|
got_leaves=1;
|
||||||
|
do{
|
||||||
|
int ti;
|
||||||
|
if(got_leaves)best_nbits=nbits;
|
||||||
|
nbits++;
|
||||||
|
got_leaves=0;
|
||||||
|
loccupancy=occupancy;
|
||||||
|
for(occupancy=ti=0;ti<_ntokens;occupancy++){
|
||||||
|
if(_tokens[ti][1]<_depth+nbits)ti++;
|
||||||
|
else if(_tokens[ti][1]==_depth+nbits){
|
||||||
|
got_leaves=1;
|
||||||
|
ti++;
|
||||||
|
}
|
||||||
|
else ti+=oc_huff_subtree_tokens(_tokens+ti,_depth+nbits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(occupancy>loccupancy&&occupancy*slush>=1<<nbits);
|
||||||
|
return best_nbits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Determines the size in words of a Huffman tree node that represents a
|
||||||
|
subtree of depth _nbits.
|
||||||
|
_nbits: The depth of the subtree.
|
||||||
|
This must be greater than zero.
|
||||||
|
Return: The number of words required to store the node.*/
|
||||||
|
static size_t oc_huff_node_size(int _nbits){
|
||||||
|
return 1+(1<<_nbits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Produces a collapsed-tree representation of the given token list.
|
||||||
|
_tree: The storage for the collapsed Huffman tree.
|
||||||
|
This may be NULL to compute the required storage size instead of
|
||||||
|
constructing the tree.
|
||||||
|
_tokens: A list of internal tokens, in the order they are found in the
|
||||||
|
codebook, and the lengths of their corresponding codewords.
|
||||||
|
_ntokens: The number of tokens corresponding to this tree node.
|
||||||
|
Return: The number of words required to store the tree.*/
|
||||||
|
static size_t oc_huff_tree_collapse(ogg_int16_t *_tree,
|
||||||
|
unsigned char _tokens[][2],int _ntokens){
|
||||||
|
ogg_int16_t node[34];
|
||||||
|
unsigned char depth[34];
|
||||||
|
unsigned char last[34];
|
||||||
|
size_t ntree;
|
||||||
|
int ti;
|
||||||
|
int l;
|
||||||
|
depth[0]=0;
|
||||||
|
last[0]=(unsigned char)(_ntokens-1);
|
||||||
|
ntree=0;
|
||||||
|
ti=0;
|
||||||
|
l=0;
|
||||||
|
do{
|
||||||
|
int nbits;
|
||||||
|
nbits=oc_huff_tree_collapse_depth(_tokens+ti,last[l]+1-ti,depth[l]);
|
||||||
|
node[l]=(ogg_int16_t)ntree;
|
||||||
|
ntree+=oc_huff_node_size(nbits);
|
||||||
|
if(_tree!=NULL)_tree[node[l]++]=(ogg_int16_t)nbits;
|
||||||
|
do{
|
||||||
|
while(ti<=last[l]&&_tokens[ti][1]<=depth[l]+nbits){
|
||||||
|
if(_tree!=NULL){
|
||||||
|
ogg_int16_t leaf;
|
||||||
|
int nentries;
|
||||||
|
nentries=1<<depth[l]+nbits-_tokens[ti][1];
|
||||||
|
leaf=(ogg_int16_t)-(_tokens[ti][1]-depth[l]<<8|_tokens[ti][0]);
|
||||||
|
while(nentries-->0)_tree[node[l]++]=leaf;
|
||||||
|
}
|
||||||
|
ti++;
|
||||||
|
}
|
||||||
|
if(ti<=last[l]){
|
||||||
|
/*We need to recurse*/
|
||||||
|
depth[l+1]=(unsigned char)(depth[l]+nbits);
|
||||||
|
if(_tree!=NULL)_tree[node[l]++]=(ogg_int16_t)ntree;
|
||||||
|
l++;
|
||||||
|
last[l]=
|
||||||
|
(unsigned char)(ti+oc_huff_subtree_tokens(_tokens+ti,depth[l])-1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*Pop back up a level of recursion.*/
|
||||||
|
else if(l-->0)nbits=depth[l+1]-depth[l];
|
||||||
|
}
|
||||||
|
while(l>=0);
|
||||||
|
}
|
||||||
|
while(l>=0);
|
||||||
|
return ntree;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Unpacks a set of Huffman trees, and reduces them to a collapsed
|
||||||
|
representation.
|
||||||
|
_opb: The buffer to unpack the trees from.
|
||||||
|
_nodes: The table to fill with the Huffman trees.
|
||||||
|
Return: 0 on success, or a negative value on error.
|
||||||
|
The caller is responsible for cleaning up any partially initialized
|
||||||
|
_nodes on failure.*/
|
||||||
|
int oc_huff_trees_unpack(oc_pack_buf *_opb,
|
||||||
|
ogg_int16_t *_nodes[TH_NHUFFMAN_TABLES]){
|
||||||
|
int i;
|
||||||
|
for(i=0;i<TH_NHUFFMAN_TABLES;i++){
|
||||||
|
unsigned char tokens[256][2];
|
||||||
|
int ntokens;
|
||||||
|
ogg_int16_t *tree;
|
||||||
|
size_t size;
|
||||||
|
/*Unpack the full tree into a temporary buffer.*/
|
||||||
|
ntokens=oc_huff_tree_unpack(_opb,tokens);
|
||||||
|
if(ntokens<0)return ntokens;
|
||||||
|
/*Figure out how big the collapsed tree will be and allocate space for it.*/
|
||||||
|
size=oc_huff_tree_collapse(NULL,tokens,ntokens);
|
||||||
|
/*This should never happen; if it does it means you set OC_HUFF_SLUSH or
|
||||||
|
OC_ROOT_HUFF_SLUSH too large.*/
|
||||||
|
if(size>32767)return TH_EIMPL;
|
||||||
|
tree=(ogg_int16_t *)_ogg_malloc(size*sizeof(*tree));
|
||||||
|
if(tree==NULL)return TH_EFAULT;
|
||||||
|
/*Construct the collapsed the tree.*/
|
||||||
|
oc_huff_tree_collapse(tree,tokens,ntokens);
|
||||||
|
_nodes[i]=tree;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Determines the size in words of a Huffman subtree.
|
||||||
|
_tree: The complete Huffman tree.
|
||||||
|
_node: The index of the root of the desired subtree.
|
||||||
|
Return: The number of words required to store the tree.*/
|
||||||
|
static size_t oc_huff_tree_size(const ogg_int16_t *_tree,int _node){
|
||||||
|
size_t size;
|
||||||
|
int nchildren;
|
||||||
|
int n;
|
||||||
|
int i;
|
||||||
|
n=_tree[_node];
|
||||||
|
size=oc_huff_node_size(n);
|
||||||
|
nchildren=1<<n;
|
||||||
|
i=0;
|
||||||
|
do{
|
||||||
|
int child;
|
||||||
|
child=_tree[_node+i+1];
|
||||||
|
if(child<=0)i+=1<<n-(-child>>8);
|
||||||
|
else{
|
||||||
|
size+=oc_huff_tree_size(_tree,child);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(i<nchildren);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Makes a copy of the given set of Huffman trees.
|
||||||
|
_dst: The array to store the copy in.
|
||||||
|
_src: The array of trees to copy.*/
|
||||||
|
int oc_huff_trees_copy(ogg_int16_t *_dst[TH_NHUFFMAN_TABLES],
|
||||||
|
const ogg_int16_t *const _src[TH_NHUFFMAN_TABLES]){
|
||||||
|
int i;
|
||||||
|
for(i=0;i<TH_NHUFFMAN_TABLES;i++){
|
||||||
|
size_t size;
|
||||||
|
size=oc_huff_tree_size(_src[i],0);
|
||||||
|
_dst[i]=(ogg_int16_t *)_ogg_malloc(size*sizeof(*_dst[i]));
|
||||||
|
if(_dst[i]==NULL){
|
||||||
|
while(i-->0)_ogg_free(_dst[i]);
|
||||||
|
return TH_EFAULT;
|
||||||
|
}
|
||||||
|
memcpy(_dst[i],_src[i],size*sizeof(*_dst[i]));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Frees the memory used by a set of Huffman trees.
|
||||||
|
_nodes: The array of trees to free.*/
|
||||||
|
void oc_huff_trees_clear(ogg_int16_t *_nodes[TH_NHUFFMAN_TABLES]){
|
||||||
|
int i;
|
||||||
|
for(i=0;i<TH_NHUFFMAN_TABLES;i++)_ogg_free(_nodes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*Unpacks a single token using the given Huffman tree.
|
||||||
|
_opb: The buffer to unpack the token from.
|
||||||
|
_node: The tree to unpack the token with.
|
||||||
|
Return: The token value.*/
|
||||||
|
int oc_huff_token_decode_c(oc_pack_buf *_opb,const ogg_int16_t *_tree){
|
||||||
|
const unsigned char *ptr;
|
||||||
|
const unsigned char *stop;
|
||||||
|
oc_pb_window window;
|
||||||
|
int available;
|
||||||
|
long bits;
|
||||||
|
int node;
|
||||||
|
int n;
|
||||||
|
ptr=_opb->ptr;
|
||||||
|
window=_opb->window;
|
||||||
|
stop=_opb->stop;
|
||||||
|
available=_opb->bits;
|
||||||
|
node=0;
|
||||||
|
for(;;){
|
||||||
|
n=_tree[node];
|
||||||
|
if(n>available){
|
||||||
|
unsigned shift;
|
||||||
|
shift=OC_PB_WINDOW_SIZE-available;
|
||||||
|
do{
|
||||||
|
/*We don't bother setting eof because we won't check for it after we've
|
||||||
|
started decoding DCT tokens.*/
|
||||||
|
if(ptr>=stop){
|
||||||
|
shift=(unsigned)-OC_LOTS_OF_BITS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
shift-=8;
|
||||||
|
window|=(oc_pb_window)*ptr++<<shift;
|
||||||
|
}
|
||||||
|
while(shift>=8);
|
||||||
|
/*Note: We never request more than 24 bits, so there's no need to fill in
|
||||||
|
the last partial byte here.*/
|
||||||
|
available=OC_PB_WINDOW_SIZE-shift;
|
||||||
|
}
|
||||||
|
bits=window>>OC_PB_WINDOW_SIZE-n;
|
||||||
|
node=_tree[node+1+bits];
|
||||||
|
if(node<=0)break;
|
||||||
|
window<<=n;
|
||||||
|
available-=n;
|
||||||
|
}
|
||||||
|
node=-node;
|
||||||
|
n=node>>8;
|
||||||
|
window<<=n;
|
||||||
|
available-=n;
|
||||||
|
_opb->ptr=ptr;
|
||||||
|
_opb->window=window;
|
||||||
|
_opb->bits=available;
|
||||||
|
return node&255;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#if !defined(_huffdec_H)
|
||||||
|
# define _huffdec_H (1)
|
||||||
|
# include "huffman.h"
|
||||||
|
# include "bitpack.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int oc_huff_trees_unpack(oc_pack_buf *_opb,
|
||||||
|
ogg_int16_t *_nodes[TH_NHUFFMAN_TABLES]);
|
||||||
|
int oc_huff_trees_copy(ogg_int16_t *_dst[TH_NHUFFMAN_TABLES],
|
||||||
|
const ogg_int16_t *const _src[TH_NHUFFMAN_TABLES]);
|
||||||
|
void oc_huff_trees_clear(ogg_int16_t *_nodes[TH_NHUFFMAN_TABLES]);
|
||||||
|
int oc_huff_token_decode_c(oc_pack_buf *_opb,const ogg_int16_t *_node);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#if !defined(_huffman_H)
|
||||||
|
# define _huffman_H (1)
|
||||||
|
# include "theora/codec.h"
|
||||||
|
# include "ocintrin.h"
|
||||||
|
|
||||||
|
/*The range of valid quantized DCT coefficient values.
|
||||||
|
VP3 used 511 in the encoder, but the bitstream is capable of 580.*/
|
||||||
|
#define OC_DCT_VAL_RANGE (580)
|
||||||
|
|
||||||
|
#define OC_NDCT_TOKEN_BITS (5)
|
||||||
|
|
||||||
|
#define OC_DCT_EOB1_TOKEN (0)
|
||||||
|
#define OC_DCT_EOB2_TOKEN (1)
|
||||||
|
#define OC_DCT_EOB3_TOKEN (2)
|
||||||
|
#define OC_DCT_REPEAT_RUN0_TOKEN (3)
|
||||||
|
#define OC_DCT_REPEAT_RUN1_TOKEN (4)
|
||||||
|
#define OC_DCT_REPEAT_RUN2_TOKEN (5)
|
||||||
|
#define OC_DCT_REPEAT_RUN3_TOKEN (6)
|
||||||
|
|
||||||
|
#define OC_DCT_SHORT_ZRL_TOKEN (7)
|
||||||
|
#define OC_DCT_ZRL_TOKEN (8)
|
||||||
|
|
||||||
|
#define OC_ONE_TOKEN (9)
|
||||||
|
#define OC_MINUS_ONE_TOKEN (10)
|
||||||
|
#define OC_TWO_TOKEN (11)
|
||||||
|
#define OC_MINUS_TWO_TOKEN (12)
|
||||||
|
|
||||||
|
#define OC_DCT_VAL_CAT2 (13)
|
||||||
|
#define OC_DCT_VAL_CAT3 (17)
|
||||||
|
#define OC_DCT_VAL_CAT4 (18)
|
||||||
|
#define OC_DCT_VAL_CAT5 (19)
|
||||||
|
#define OC_DCT_VAL_CAT6 (20)
|
||||||
|
#define OC_DCT_VAL_CAT7 (21)
|
||||||
|
#define OC_DCT_VAL_CAT8 (22)
|
||||||
|
|
||||||
|
#define OC_DCT_RUN_CAT1A (23)
|
||||||
|
#define OC_DCT_RUN_CAT1B (28)
|
||||||
|
#define OC_DCT_RUN_CAT1C (29)
|
||||||
|
#define OC_DCT_RUN_CAT2A (30)
|
||||||
|
#define OC_DCT_RUN_CAT2B (31)
|
||||||
|
|
||||||
|
#define OC_NDCT_EOB_TOKEN_MAX (7)
|
||||||
|
#define OC_NDCT_ZRL_TOKEN_MAX (9)
|
||||||
|
#define OC_NDCT_VAL_MAX (23)
|
||||||
|
#define OC_NDCT_VAL_CAT1_MAX (13)
|
||||||
|
#define OC_NDCT_VAL_CAT2_MAX (17)
|
||||||
|
#define OC_NDCT_VAL_CAT2_SIZE (OC_NDCT_VAL_CAT2_MAX-OC_DCT_VAL_CAT2)
|
||||||
|
#define OC_NDCT_RUN_MAX (32)
|
||||||
|
#define OC_NDCT_RUN_CAT1A_MAX (28)
|
||||||
|
|
||||||
|
extern const unsigned char OC_DCT_TOKEN_EXTRA_BITS[TH_NDCT_TOKENS];
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,330 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "internal.h"
|
||||||
|
#include "dct.h"
|
||||||
|
|
||||||
|
/*Performs an inverse 8 point Type-II DCT transform.
|
||||||
|
The output is scaled by a factor of 2 relative to the orthonormal version of
|
||||||
|
the transform.
|
||||||
|
_y: The buffer to store the result in.
|
||||||
|
Data will be placed in every 8th entry (e.g., in a column of an 8x8
|
||||||
|
block).
|
||||||
|
_x: The input coefficients.
|
||||||
|
The first 8 entries are used (e.g., from a row of an 8x8 block).*/
|
||||||
|
static void idct8(ogg_int16_t *_y,const ogg_int16_t _x[8]){
|
||||||
|
ogg_int32_t t[8];
|
||||||
|
ogg_int32_t r;
|
||||||
|
/*Stage 1:*/
|
||||||
|
/*0-1 butterfly.*/
|
||||||
|
t[0]=OC_C4S4*(ogg_int16_t)(_x[0]+_x[4])>>16;
|
||||||
|
t[1]=OC_C4S4*(ogg_int16_t)(_x[0]-_x[4])>>16;
|
||||||
|
/*2-3 rotation by 6pi/16.*/
|
||||||
|
t[2]=(OC_C6S2*_x[2]>>16)-(OC_C2S6*_x[6]>>16);
|
||||||
|
t[3]=(OC_C2S6*_x[2]>>16)+(OC_C6S2*_x[6]>>16);
|
||||||
|
/*4-7 rotation by 7pi/16.*/
|
||||||
|
t[4]=(OC_C7S1*_x[1]>>16)-(OC_C1S7*_x[7]>>16);
|
||||||
|
/*5-6 rotation by 3pi/16.*/
|
||||||
|
t[5]=(OC_C3S5*_x[5]>>16)-(OC_C5S3*_x[3]>>16);
|
||||||
|
t[6]=(OC_C5S3*_x[5]>>16)+(OC_C3S5*_x[3]>>16);
|
||||||
|
t[7]=(OC_C1S7*_x[1]>>16)+(OC_C7S1*_x[7]>>16);
|
||||||
|
/*Stage 2:*/
|
||||||
|
/*4-5 butterfly.*/
|
||||||
|
r=t[4]+t[5];
|
||||||
|
t[5]=OC_C4S4*(ogg_int16_t)(t[4]-t[5])>>16;
|
||||||
|
t[4]=r;
|
||||||
|
/*7-6 butterfly.*/
|
||||||
|
r=t[7]+t[6];
|
||||||
|
t[6]=OC_C4S4*(ogg_int16_t)(t[7]-t[6])>>16;
|
||||||
|
t[7]=r;
|
||||||
|
/*Stage 3:*/
|
||||||
|
/*0-3 butterfly.*/
|
||||||
|
r=t[0]+t[3];
|
||||||
|
t[3]=t[0]-t[3];
|
||||||
|
t[0]=r;
|
||||||
|
/*1-2 butterfly.*/
|
||||||
|
r=t[1]+t[2];
|
||||||
|
t[2]=t[1]-t[2];
|
||||||
|
t[1]=r;
|
||||||
|
/*6-5 butterfly.*/
|
||||||
|
r=t[6]+t[5];
|
||||||
|
t[5]=t[6]-t[5];
|
||||||
|
t[6]=r;
|
||||||
|
/*Stage 4:*/
|
||||||
|
/*0-7 butterfly.*/
|
||||||
|
_y[0<<3]=(ogg_int16_t)(t[0]+t[7]);
|
||||||
|
/*1-6 butterfly.*/
|
||||||
|
_y[1<<3]=(ogg_int16_t)(t[1]+t[6]);
|
||||||
|
/*2-5 butterfly.*/
|
||||||
|
_y[2<<3]=(ogg_int16_t)(t[2]+t[5]);
|
||||||
|
/*3-4 butterfly.*/
|
||||||
|
_y[3<<3]=(ogg_int16_t)(t[3]+t[4]);
|
||||||
|
_y[4<<3]=(ogg_int16_t)(t[3]-t[4]);
|
||||||
|
_y[5<<3]=(ogg_int16_t)(t[2]-t[5]);
|
||||||
|
_y[6<<3]=(ogg_int16_t)(t[1]-t[6]);
|
||||||
|
_y[7<<3]=(ogg_int16_t)(t[0]-t[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Performs an inverse 8 point Type-II DCT transform.
|
||||||
|
The output is scaled by a factor of 2 relative to the orthonormal version of
|
||||||
|
the transform.
|
||||||
|
_y: The buffer to store the result in.
|
||||||
|
Data will be placed in every 8th entry (e.g., in a column of an 8x8
|
||||||
|
block).
|
||||||
|
_x: The input coefficients.
|
||||||
|
Only the first 4 entries are used.
|
||||||
|
The other 4 are assumed to be 0.*/
|
||||||
|
static void idct8_4(ogg_int16_t *_y,const ogg_int16_t _x[8]){
|
||||||
|
ogg_int32_t t[8];
|
||||||
|
ogg_int32_t r;
|
||||||
|
/*Stage 1:*/
|
||||||
|
t[0]=OC_C4S4*_x[0]>>16;
|
||||||
|
t[2]=OC_C6S2*_x[2]>>16;
|
||||||
|
t[3]=OC_C2S6*_x[2]>>16;
|
||||||
|
t[4]=OC_C7S1*_x[1]>>16;
|
||||||
|
t[5]=-(OC_C5S3*_x[3]>>16);
|
||||||
|
t[6]=OC_C3S5*_x[3]>>16;
|
||||||
|
t[7]=OC_C1S7*_x[1]>>16;
|
||||||
|
/*Stage 2:*/
|
||||||
|
r=t[4]+t[5];
|
||||||
|
t[5]=OC_C4S4*(ogg_int16_t)(t[4]-t[5])>>16;
|
||||||
|
t[4]=r;
|
||||||
|
r=t[7]+t[6];
|
||||||
|
t[6]=OC_C4S4*(ogg_int16_t)(t[7]-t[6])>>16;
|
||||||
|
t[7]=r;
|
||||||
|
/*Stage 3:*/
|
||||||
|
t[1]=t[0]+t[2];
|
||||||
|
t[2]=t[0]-t[2];
|
||||||
|
r=t[0]+t[3];
|
||||||
|
t[3]=t[0]-t[3];
|
||||||
|
t[0]=r;
|
||||||
|
r=t[6]+t[5];
|
||||||
|
t[5]=t[6]-t[5];
|
||||||
|
t[6]=r;
|
||||||
|
/*Stage 4:*/
|
||||||
|
_y[0<<3]=(ogg_int16_t)(t[0]+t[7]);
|
||||||
|
_y[1<<3]=(ogg_int16_t)(t[1]+t[6]);
|
||||||
|
_y[2<<3]=(ogg_int16_t)(t[2]+t[5]);
|
||||||
|
_y[3<<3]=(ogg_int16_t)(t[3]+t[4]);
|
||||||
|
_y[4<<3]=(ogg_int16_t)(t[3]-t[4]);
|
||||||
|
_y[5<<3]=(ogg_int16_t)(t[2]-t[5]);
|
||||||
|
_y[6<<3]=(ogg_int16_t)(t[1]-t[6]);
|
||||||
|
_y[7<<3]=(ogg_int16_t)(t[0]-t[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Performs an inverse 8 point Type-II DCT transform.
|
||||||
|
The output is scaled by a factor of 2 relative to the orthonormal version of
|
||||||
|
the transform.
|
||||||
|
_y: The buffer to store the result in.
|
||||||
|
Data will be placed in every 8th entry (e.g., in a column of an 8x8
|
||||||
|
block).
|
||||||
|
_x: The input coefficients.
|
||||||
|
Only the first 3 entries are used.
|
||||||
|
The other 5 are assumed to be 0.*/
|
||||||
|
static void idct8_3(ogg_int16_t *_y,const ogg_int16_t _x[8]){
|
||||||
|
ogg_int32_t t[8];
|
||||||
|
ogg_int32_t r;
|
||||||
|
/*Stage 1:*/
|
||||||
|
t[0]=OC_C4S4*_x[0]>>16;
|
||||||
|
t[2]=OC_C6S2*_x[2]>>16;
|
||||||
|
t[3]=OC_C2S6*_x[2]>>16;
|
||||||
|
t[4]=OC_C7S1*_x[1]>>16;
|
||||||
|
t[7]=OC_C1S7*_x[1]>>16;
|
||||||
|
/*Stage 2:*/
|
||||||
|
t[5]=OC_C4S4*t[4]>>16;
|
||||||
|
t[6]=OC_C4S4*t[7]>>16;
|
||||||
|
/*Stage 3:*/
|
||||||
|
t[1]=t[0]+t[2];
|
||||||
|
t[2]=t[0]-t[2];
|
||||||
|
r=t[0]+t[3];
|
||||||
|
t[3]=t[0]-t[3];
|
||||||
|
t[0]=r;
|
||||||
|
r=t[6]+t[5];
|
||||||
|
t[5]=t[6]-t[5];
|
||||||
|
t[6]=r;
|
||||||
|
/*Stage 4:*/
|
||||||
|
_y[0<<3]=(ogg_int16_t)(t[0]+t[7]);
|
||||||
|
_y[1<<3]=(ogg_int16_t)(t[1]+t[6]);
|
||||||
|
_y[2<<3]=(ogg_int16_t)(t[2]+t[5]);
|
||||||
|
_y[3<<3]=(ogg_int16_t)(t[3]+t[4]);
|
||||||
|
_y[4<<3]=(ogg_int16_t)(t[3]-t[4]);
|
||||||
|
_y[5<<3]=(ogg_int16_t)(t[2]-t[5]);
|
||||||
|
_y[6<<3]=(ogg_int16_t)(t[1]-t[6]);
|
||||||
|
_y[7<<3]=(ogg_int16_t)(t[0]-t[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Performs an inverse 8 point Type-II DCT transform.
|
||||||
|
The output is scaled by a factor of 2 relative to the orthonormal version of
|
||||||
|
the transform.
|
||||||
|
_y: The buffer to store the result in.
|
||||||
|
Data will be placed in every 8th entry (e.g., in a column of an 8x8
|
||||||
|
block).
|
||||||
|
_x: The input coefficients.
|
||||||
|
Only the first 2 entries are used.
|
||||||
|
The other 6 are assumed to be 0.*/
|
||||||
|
static void idct8_2(ogg_int16_t *_y,const ogg_int16_t _x[8]){
|
||||||
|
ogg_int32_t t[8];
|
||||||
|
ogg_int32_t r;
|
||||||
|
/*Stage 1:*/
|
||||||
|
t[0]=OC_C4S4*_x[0]>>16;
|
||||||
|
t[4]=OC_C7S1*_x[1]>>16;
|
||||||
|
t[7]=OC_C1S7*_x[1]>>16;
|
||||||
|
/*Stage 2:*/
|
||||||
|
t[5]=OC_C4S4*t[4]>>16;
|
||||||
|
t[6]=OC_C4S4*t[7]>>16;
|
||||||
|
/*Stage 3:*/
|
||||||
|
r=t[6]+t[5];
|
||||||
|
t[5]=t[6]-t[5];
|
||||||
|
t[6]=r;
|
||||||
|
/*Stage 4:*/
|
||||||
|
_y[0<<3]=(ogg_int16_t)(t[0]+t[7]);
|
||||||
|
_y[1<<3]=(ogg_int16_t)(t[0]+t[6]);
|
||||||
|
_y[2<<3]=(ogg_int16_t)(t[0]+t[5]);
|
||||||
|
_y[3<<3]=(ogg_int16_t)(t[0]+t[4]);
|
||||||
|
_y[4<<3]=(ogg_int16_t)(t[0]-t[4]);
|
||||||
|
_y[5<<3]=(ogg_int16_t)(t[0]-t[5]);
|
||||||
|
_y[6<<3]=(ogg_int16_t)(t[0]-t[6]);
|
||||||
|
_y[7<<3]=(ogg_int16_t)(t[0]-t[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Performs an inverse 8 point Type-II DCT transform.
|
||||||
|
The output is scaled by a factor of 2 relative to the orthonormal version of
|
||||||
|
the transform.
|
||||||
|
_y: The buffer to store the result in.
|
||||||
|
Data will be placed in every 8th entry (e.g., in a column of an 8x8
|
||||||
|
block).
|
||||||
|
_x: The input coefficients.
|
||||||
|
Only the first entry is used.
|
||||||
|
The other 7 are assumed to be 0.*/
|
||||||
|
static void idct8_1(ogg_int16_t *_y,const ogg_int16_t _x[1]){
|
||||||
|
_y[0<<3]=_y[1<<3]=_y[2<<3]=_y[3<<3]=
|
||||||
|
_y[4<<3]=_y[5<<3]=_y[6<<3]=_y[7<<3]=(ogg_int16_t)(OC_C4S4*_x[0]>>16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Performs an inverse 8x8 Type-II DCT transform.
|
||||||
|
The input is assumed to be scaled by a factor of 4 relative to orthonormal
|
||||||
|
version of the transform.
|
||||||
|
All coefficients but the first 3 in zig-zag scan order are assumed to be 0:
|
||||||
|
x x 0 0 0 0 0 0
|
||||||
|
x 0 0 0 0 0 0 0
|
||||||
|
0 0 0 0 0 0 0 0
|
||||||
|
0 0 0 0 0 0 0 0
|
||||||
|
0 0 0 0 0 0 0 0
|
||||||
|
0 0 0 0 0 0 0 0
|
||||||
|
0 0 0 0 0 0 0 0
|
||||||
|
0 0 0 0 0 0 0 0
|
||||||
|
_y: The buffer to store the result in.
|
||||||
|
This may be the same as _x.
|
||||||
|
_x: The input coefficients.*/
|
||||||
|
static void oc_idct8x8_3(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||||
|
ogg_int16_t w[64];
|
||||||
|
int i;
|
||||||
|
/*Transform rows of x into columns of w.*/
|
||||||
|
idct8_2(w,_x);
|
||||||
|
idct8_1(w+1,_x+8);
|
||||||
|
/*Transform rows of w into columns of y.*/
|
||||||
|
for(i=0;i<8;i++)idct8_2(_y+i,w+i*8);
|
||||||
|
/*Adjust for the scale factor.*/
|
||||||
|
for(i=0;i<64;i++)_y[i]=(ogg_int16_t)(_y[i]+8>>4);
|
||||||
|
/*Clear input data for next block.*/
|
||||||
|
_x[0]=_x[1]=_x[8]=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Performs an inverse 8x8 Type-II DCT transform.
|
||||||
|
The input is assumed to be scaled by a factor of 4 relative to orthonormal
|
||||||
|
version of the transform.
|
||||||
|
All coefficients but the first 10 in zig-zag scan order are assumed to be 0:
|
||||||
|
x x x x 0 0 0 0
|
||||||
|
x x x 0 0 0 0 0
|
||||||
|
x x 0 0 0 0 0 0
|
||||||
|
x 0 0 0 0 0 0 0
|
||||||
|
0 0 0 0 0 0 0 0
|
||||||
|
0 0 0 0 0 0 0 0
|
||||||
|
0 0 0 0 0 0 0 0
|
||||||
|
0 0 0 0 0 0 0 0
|
||||||
|
_y: The buffer to store the result in.
|
||||||
|
This may be the same as _x.
|
||||||
|
_x: The input coefficients.*/
|
||||||
|
static void oc_idct8x8_10(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||||
|
ogg_int16_t w[64];
|
||||||
|
int i;
|
||||||
|
/*Transform rows of x into columns of w.*/
|
||||||
|
idct8_4(w,_x);
|
||||||
|
idct8_3(w+1,_x+8);
|
||||||
|
idct8_2(w+2,_x+16);
|
||||||
|
idct8_1(w+3,_x+24);
|
||||||
|
/*Transform rows of w into columns of y.*/
|
||||||
|
for(i=0;i<8;i++)idct8_4(_y+i,w+i*8);
|
||||||
|
/*Adjust for the scale factor.*/
|
||||||
|
for(i=0;i<64;i++)_y[i]=(ogg_int16_t)(_y[i]+8>>4);
|
||||||
|
/*Clear input data for next block.*/
|
||||||
|
_x[0]=_x[1]=_x[2]=_x[3]=_x[8]=_x[9]=_x[10]=_x[16]=_x[17]=_x[24]=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Performs an inverse 8x8 Type-II DCT transform.
|
||||||
|
The input is assumed to be scaled by a factor of 4 relative to orthonormal
|
||||||
|
version of the transform.
|
||||||
|
_y: The buffer to store the result in.
|
||||||
|
This may be the same as _x.
|
||||||
|
_x: The input coefficients.*/
|
||||||
|
static void oc_idct8x8_slow(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||||
|
ogg_int16_t w[64];
|
||||||
|
int i;
|
||||||
|
/*Transform rows of x into columns of w.*/
|
||||||
|
for(i=0;i<8;i++)idct8(w+i,_x+i*8);
|
||||||
|
/*Transform rows of w into columns of y.*/
|
||||||
|
for(i=0;i<8;i++)idct8(_y+i,w+i*8);
|
||||||
|
/*Adjust for the scale factor.*/
|
||||||
|
for(i=0;i<64;i++)_y[i]=(ogg_int16_t)(_y[i]+8>>4);
|
||||||
|
/*Clear input data for next block.*/
|
||||||
|
for(i=0;i<64;i++)_x[i]=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Performs an inverse 8x8 Type-II DCT transform.
|
||||||
|
The input is assumed to be scaled by a factor of 4 relative to orthonormal
|
||||||
|
version of the transform.*/
|
||||||
|
void oc_idct8x8_c(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi){
|
||||||
|
/*_last_zzi is subtly different from an actual count of the number of
|
||||||
|
coefficients we decoded for this block.
|
||||||
|
It contains the value of zzi BEFORE the final token in the block was
|
||||||
|
decoded.
|
||||||
|
In most cases this is an EOB token (the continuation of an EOB run from a
|
||||||
|
previous block counts), and so this is the same as the coefficient count.
|
||||||
|
However, in the case that the last token was NOT an EOB token, but filled
|
||||||
|
the block up with exactly 64 coefficients, _last_zzi will be less than 64.
|
||||||
|
Provided the last token was not a pure zero run, the minimum value it can
|
||||||
|
be is 46, and so that doesn't affect any of the cases in this routine.
|
||||||
|
However, if the last token WAS a pure zero run of length 63, then _last_zzi
|
||||||
|
will be 1 while the number of coefficients decoded is 64.
|
||||||
|
Thus, we will trigger the following special case, where the real
|
||||||
|
coefficient count would not.
|
||||||
|
Note also that a zero run of length 64 will give _last_zzi a value of 0,
|
||||||
|
but we still process the DC coefficient, which might have a non-zero value
|
||||||
|
due to DC prediction.
|
||||||
|
Although convoluted, this is arguably the correct behavior: it allows us to
|
||||||
|
use a smaller transform when the block ends with a long zero run instead
|
||||||
|
of a normal EOB token.
|
||||||
|
It could be smarter... multiple separate zero runs at the end of a block
|
||||||
|
will fool it, but an encoder that generates these really deserves what it
|
||||||
|
gets.
|
||||||
|
Needless to say we inherited this approach from VP3.*/
|
||||||
|
/*Then perform the iDCT.*/
|
||||||
|
if(_last_zzi<=3)oc_idct8x8_3(_y,_x);
|
||||||
|
else if(_last_zzi<=10)oc_idct8x8_10(_y,_x);
|
||||||
|
else oc_idct8x8_slow(_y,_x);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,210 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*A map from the index in the zig zag scan to the coefficient number in a
|
||||||
|
block.
|
||||||
|
All zig zag indices beyond 63 are sent to coefficient 64, so that zero runs
|
||||||
|
past the end of a block in bogus streams get mapped to a known location.*/
|
||||||
|
const unsigned char OC_FZIG_ZAG[128]={
|
||||||
|
0, 1, 8,16, 9, 2, 3,10,
|
||||||
|
17,24,32,25,18,11, 4, 5,
|
||||||
|
12,19,26,33,40,48,41,34,
|
||||||
|
27,20,13, 6, 7,14,21,28,
|
||||||
|
35,42,49,56,57,50,43,36,
|
||||||
|
29,22,15,23,30,37,44,51,
|
||||||
|
58,59,52,45,38,31,39,46,
|
||||||
|
53,60,61,54,47,55,62,63,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64
|
||||||
|
};
|
||||||
|
|
||||||
|
/*A map from the coefficient number in a block to its index in the zig zag
|
||||||
|
scan.*/
|
||||||
|
const unsigned char OC_IZIG_ZAG[64]={
|
||||||
|
0, 1, 5, 6,14,15,27,28,
|
||||||
|
2, 4, 7,13,16,26,29,42,
|
||||||
|
3, 8,12,17,25,30,41,43,
|
||||||
|
9,11,18,24,31,40,44,53,
|
||||||
|
10,19,23,32,39,45,52,54,
|
||||||
|
20,22,33,38,46,51,55,60,
|
||||||
|
21,34,37,47,50,56,59,61,
|
||||||
|
35,36,48,49,57,58,62,63
|
||||||
|
};
|
||||||
|
|
||||||
|
/*A map from physical macro block ordering to bitstream macro block
|
||||||
|
ordering within a super block.*/
|
||||||
|
const unsigned char OC_MB_MAP[2][2]={{0,3},{1,2}};
|
||||||
|
|
||||||
|
/*A list of the indices in the oc_mb.map array that can be valid for each of
|
||||||
|
the various chroma decimation types.*/
|
||||||
|
const unsigned char OC_MB_MAP_IDXS[TH_PF_NFORMATS][12]={
|
||||||
|
{0,1,2,3,4,8},
|
||||||
|
{0,1,2,3,4,5,8,9},
|
||||||
|
{0,1,2,3,4,6,8,10},
|
||||||
|
{0,1,2,3,4,5,6,7,8,9,10,11}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*The number of indices in the oc_mb.map array that can be valid for each of
|
||||||
|
the various chroma decimation types.*/
|
||||||
|
const unsigned char OC_MB_MAP_NIDXS[TH_PF_NFORMATS]={6,8,8,12};
|
||||||
|
|
||||||
|
/*The number of extra bits that are coded with each of the DCT tokens.
|
||||||
|
Each DCT token has some fixed number of additional bits (possibly 0) stored
|
||||||
|
after the token itself, containing, for example, coefficient magnitude,
|
||||||
|
sign bits, etc.*/
|
||||||
|
const unsigned char OC_DCT_TOKEN_EXTRA_BITS[TH_NDCT_TOKENS]={
|
||||||
|
0,0,0,2,3,4,12,3,6,
|
||||||
|
0,0,0,0,
|
||||||
|
1,1,1,1,2,3,4,5,6,10,
|
||||||
|
1,1,1,1,1,3,4,
|
||||||
|
2,3
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int oc_ilog(unsigned _v){
|
||||||
|
int ret;
|
||||||
|
for(ret=0;_v;ret++)_v>>=1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void *oc_aligned_malloc(size_t _sz,size_t _align){
|
||||||
|
unsigned char *p;
|
||||||
|
if(_align-1>UCHAR_MAX||(_align&_align-1)||_sz>~(size_t)0-_align)return NULL;
|
||||||
|
p=(unsigned char *)_ogg_malloc(_sz+_align);
|
||||||
|
if(p!=NULL){
|
||||||
|
int offs;
|
||||||
|
offs=((p-(unsigned char *)0)-1&_align-1);
|
||||||
|
p[offs]=offs;
|
||||||
|
p+=offs+1;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_aligned_free(void *_ptr){
|
||||||
|
unsigned char *p;
|
||||||
|
p=(unsigned char *)_ptr;
|
||||||
|
if(p!=NULL){
|
||||||
|
int offs;
|
||||||
|
offs=*--p;
|
||||||
|
_ogg_free(p-offs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void **oc_malloc_2d(size_t _height,size_t _width,size_t _sz){
|
||||||
|
size_t rowsz;
|
||||||
|
size_t colsz;
|
||||||
|
size_t datsz;
|
||||||
|
char *ret;
|
||||||
|
colsz=_height*sizeof(void *);
|
||||||
|
rowsz=_sz*_width;
|
||||||
|
datsz=rowsz*_height;
|
||||||
|
/*Alloc array and row pointers.*/
|
||||||
|
ret=(char *)_ogg_malloc(datsz+colsz);
|
||||||
|
/*Initialize the array.*/
|
||||||
|
if(ret!=NULL){
|
||||||
|
size_t i;
|
||||||
|
void **p;
|
||||||
|
char *datptr;
|
||||||
|
p=(void **)ret;
|
||||||
|
i=_height;
|
||||||
|
for(datptr=ret+colsz;i-->0;p++,datptr+=rowsz)*p=(void *)datptr;
|
||||||
|
}
|
||||||
|
return (void **)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void **oc_calloc_2d(size_t _height,size_t _width,size_t _sz){
|
||||||
|
size_t colsz;
|
||||||
|
size_t rowsz;
|
||||||
|
size_t datsz;
|
||||||
|
char *ret;
|
||||||
|
colsz=_height*sizeof(void *);
|
||||||
|
rowsz=_sz*_width;
|
||||||
|
datsz=rowsz*_height;
|
||||||
|
/*Alloc array and row pointers.*/
|
||||||
|
ret=(char *)_ogg_calloc(datsz+colsz,1);
|
||||||
|
/*Initialize the array.*/
|
||||||
|
if(ret!=NULL){
|
||||||
|
size_t i;
|
||||||
|
void **p;
|
||||||
|
char *datptr;
|
||||||
|
p=(void **)ret;
|
||||||
|
i=_height;
|
||||||
|
for(datptr=ret+colsz;i-->0;p++,datptr+=rowsz)*p=(void *)datptr;
|
||||||
|
}
|
||||||
|
return (void **)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_free_2d(void *_ptr){
|
||||||
|
_ogg_free(_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Fills in a Y'CbCr buffer with a pointer to the image data in the first
|
||||||
|
buffer, but with the opposite vertical orientation.
|
||||||
|
_dst: The destination buffer.
|
||||||
|
This can be the same as _src.
|
||||||
|
_src: The source buffer.*/
|
||||||
|
void oc_ycbcr_buffer_flip(th_ycbcr_buffer _dst,
|
||||||
|
const th_ycbcr_buffer _src){
|
||||||
|
int pli;
|
||||||
|
for(pli=0;pli<3;pli++){
|
||||||
|
_dst[pli].width=_src[pli].width;
|
||||||
|
_dst[pli].height=_src[pli].height;
|
||||||
|
_dst[pli].stride=-_src[pli].stride;
|
||||||
|
_dst[pli].data=_src[pli].data
|
||||||
|
+(1-_dst[pli].height)*(ptrdiff_t)_dst[pli].stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *th_version_string(void){
|
||||||
|
return OC_VENDOR_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
ogg_uint32_t th_version_number(void){
|
||||||
|
return (TH_VERSION_MAJOR<<16)+(TH_VERSION_MINOR<<8)+TH_VERSION_SUB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Determines the packet type.
|
||||||
|
Note that this correctly interprets a 0-byte packet as a video data packet.
|
||||||
|
Return: 1 for a header packet, 0 for a data packet.*/
|
||||||
|
int th_packet_isheader(ogg_packet *_op){
|
||||||
|
return _op->bytes>0?_op->packet[0]>>7:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Determines the frame type of a video data packet.
|
||||||
|
Note that this correctly interprets a 0-byte packet as a delta frame.
|
||||||
|
Return: 1 for a key frame, 0 for a delta frame, and -1 for a header
|
||||||
|
packet.*/
|
||||||
|
int th_packet_iskeyframe(ogg_packet *_op){
|
||||||
|
return _op->bytes<=0?0:_op->packet[0]&0x80?-1:!(_op->packet[0]&0x40);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
#if !defined(_internal_H)
|
||||||
|
# define _internal_H (1)
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <limits.h>
|
||||||
|
# if defined(HAVE_CONFIG_H)
|
||||||
|
# include "config.h"
|
||||||
|
# endif
|
||||||
|
# include "theora/codec.h"
|
||||||
|
# include "theora/theora.h"
|
||||||
|
# include "ocintrin.h"
|
||||||
|
|
||||||
|
# if !defined(__GNUC_PREREQ)
|
||||||
|
# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
|
||||||
|
# define __GNUC_PREREQ(_maj,_min) \
|
||||||
|
((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
|
||||||
|
# else
|
||||||
|
# define __GNUC_PREREQ(_maj,_min) 0
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(_MSC_VER)
|
||||||
|
/*Disable missing EMMS warnings.*/
|
||||||
|
# pragma warning(disable:4799)
|
||||||
|
/*Thank you Microsoft, I know the order of operations.*/
|
||||||
|
# pragma warning(disable:4554)
|
||||||
|
# endif
|
||||||
|
/*You, too, gcc.*/
|
||||||
|
# if __GNUC_PREREQ(4,2)
|
||||||
|
# pragma GCC diagnostic ignored "-Wparentheses"
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/*Some assembly constructs require aligned operands.
|
||||||
|
The following macros are _only_ intended for structure member declarations.
|
||||||
|
Although they will sometimes work on stack variables, gcc will often silently
|
||||||
|
ignore them.
|
||||||
|
A separate set of macros could be made for manual stack alignment, but we
|
||||||
|
don't actually require it anywhere.*/
|
||||||
|
# if defined(OC_X86_ASM)||defined(OC_ARM_ASM)
|
||||||
|
# if defined(__GNUC__)
|
||||||
|
# define OC_ALIGN8(expr) expr __attribute__((aligned(8)))
|
||||||
|
# define OC_ALIGN16(expr) expr __attribute__((aligned(16)))
|
||||||
|
# elif defined(_MSC_VER)
|
||||||
|
# define OC_ALIGN8(expr) __declspec (align(8)) expr
|
||||||
|
# define OC_ALIGN16(expr) __declspec (align(16)) expr
|
||||||
|
# else
|
||||||
|
# error "Alignment macros required for this platform."
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# if !defined(OC_ALIGN8)
|
||||||
|
# define OC_ALIGN8(expr) expr
|
||||||
|
# endif
|
||||||
|
# if !defined(OC_ALIGN16)
|
||||||
|
# define OC_ALIGN16(expr) expr
|
||||||
|
# endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*This library's version.*/
|
||||||
|
# define OC_VENDOR_STRING "Xiph.Org libtheora 1.2.0alpha 20100924 (Ptalarbvorm)"
|
||||||
|
|
||||||
|
/*Theora bitstream version.*/
|
||||||
|
# define TH_VERSION_MAJOR (3)
|
||||||
|
# define TH_VERSION_MINOR (2)
|
||||||
|
# define TH_VERSION_SUB (1)
|
||||||
|
# define TH_VERSION_CHECK(_info,_maj,_min,_sub) \
|
||||||
|
((_info)->version_major>(_maj)||(_info)->version_major==(_maj)&& \
|
||||||
|
((_info)->version_minor>(_min)||(_info)->version_minor==(_min)&& \
|
||||||
|
(_info)->version_subminor>=(_sub)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*A map from the index in the zig zag scan to the coefficient number in a
|
||||||
|
block.*/
|
||||||
|
extern const unsigned char OC_FZIG_ZAG[128];
|
||||||
|
/*A map from the coefficient number in a block to its index in the zig zag
|
||||||
|
scan.*/
|
||||||
|
extern const unsigned char OC_IZIG_ZAG[64];
|
||||||
|
/*A map from physical macro block ordering to bitstream macro block
|
||||||
|
ordering within a super block.*/
|
||||||
|
extern const unsigned char OC_MB_MAP[2][2];
|
||||||
|
/*A list of the indices in the oc_mb_map array that can be valid for each of
|
||||||
|
the various chroma decimation types.*/
|
||||||
|
extern const unsigned char OC_MB_MAP_IDXS[TH_PF_NFORMATS][12];
|
||||||
|
/*The number of indices in the oc_mb_map array that can be valid for each of
|
||||||
|
the various chroma decimation types.*/
|
||||||
|
extern const unsigned char OC_MB_MAP_NIDXS[TH_PF_NFORMATS];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int oc_ilog(unsigned _v);
|
||||||
|
void *oc_aligned_malloc(size_t _sz,size_t _align);
|
||||||
|
void oc_aligned_free(void *_ptr);
|
||||||
|
void **oc_malloc_2d(size_t _height,size_t _width,size_t _sz);
|
||||||
|
void **oc_calloc_2d(size_t _height,size_t _width,size_t _sz);
|
||||||
|
void oc_free_2d(void *_ptr);
|
||||||
|
|
||||||
|
void oc_ycbcr_buffer_flip(th_ycbcr_buffer _dst,
|
||||||
|
const th_ycbcr_buffer _src);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
/*Some common macros for potential platform-specific optimization.*/
|
||||||
|
#include <math.h>
|
||||||
|
#if !defined(_ocintrin_H)
|
||||||
|
# define _ocintrin_H (1)
|
||||||
|
|
||||||
|
/*Some specific platforms may have optimized intrinsic or inline assembly
|
||||||
|
versions of these functions which can substantially improve performance.
|
||||||
|
We define macros for them to allow easy incorporation of these non-ANSI
|
||||||
|
features.*/
|
||||||
|
|
||||||
|
/*Note that we do not provide a macro for abs(), because it is provided as a
|
||||||
|
library function, which we assume is translated into an intrinsic to avoid
|
||||||
|
the function call overhead and then implemented in the smartest way for the
|
||||||
|
target platform.
|
||||||
|
With modern gcc (4.x), this is true: it uses cmov instructions if the
|
||||||
|
architecture supports it and branchless bit-twiddling if it does not (the
|
||||||
|
speed difference between the two approaches is not measurable).
|
||||||
|
Interestingly, the bit-twiddling method was patented in 2000 (US 6,073,150)
|
||||||
|
by Sun Microsystems, despite prior art dating back to at least 1996:
|
||||||
|
http://web.archive.org/web/19961201174141/www.x86.org/ftp/articles/pentopt/PENTOPT.TXT
|
||||||
|
On gcc 3.x, however, our assumption is not true, as abs() is translated to a
|
||||||
|
conditional jump, which is horrible on deeply piplined architectures (e.g.,
|
||||||
|
all consumer architectures for the past decade or more).
|
||||||
|
Also be warned that -C*abs(x) where C is a constant is mis-optimized as
|
||||||
|
abs(C*x) on every gcc release before 4.2.3.
|
||||||
|
See bug http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34130 */
|
||||||
|
|
||||||
|
/*Modern gcc (4.x) can compile the naive versions of min and max with cmov if
|
||||||
|
given an appropriate architecture, but the branchless bit-twiddling versions
|
||||||
|
are just as fast, and do not require any special target architecture.
|
||||||
|
Earlier gcc versions (3.x) compiled both code to the same assembly
|
||||||
|
instructions, because of the way they represented ((_b)>(_a)) internally.*/
|
||||||
|
#define OC_MAXI(_a,_b) ((_a)-((_a)-(_b)&-((_b)>(_a))))
|
||||||
|
#define OC_MINI(_a,_b) ((_a)+((_b)-(_a)&-((_b)<(_a))))
|
||||||
|
/*Clamps an integer into the given range.
|
||||||
|
If _a>_c, then the lower bound _a is respected over the upper bound _c (this
|
||||||
|
behavior is required to meet our documented API behavior).
|
||||||
|
_a: The lower bound.
|
||||||
|
_b: The value to clamp.
|
||||||
|
_c: The upper boud.*/
|
||||||
|
#define OC_CLAMPI(_a,_b,_c) (OC_MAXI(_a,OC_MINI(_b,_c)))
|
||||||
|
#define OC_CLAMP255(_x) ((unsigned char)((((_x)<0)-1)&((_x)|-((_x)>255))))
|
||||||
|
/*This has a chance of compiling branchless, and is just as fast as the
|
||||||
|
bit-twiddling method, which is slightly less portable, since it relies on a
|
||||||
|
sign-extended rightshift, which is not guaranteed by ANSI (but present on
|
||||||
|
every relevant platform).*/
|
||||||
|
#define OC_SIGNI(_a) (((_a)>0)-((_a)<0))
|
||||||
|
/*Slightly more portable than relying on a sign-extended right-shift (which is
|
||||||
|
not guaranteed by ANSI), and just as fast, since gcc (3.x and 4.x both)
|
||||||
|
compile it into the right-shift anyway.*/
|
||||||
|
#define OC_SIGNMASK(_a) (-((_a)<0))
|
||||||
|
/*Divides an integer by a power of two, truncating towards 0.
|
||||||
|
_dividend: The integer to divide.
|
||||||
|
_shift: The non-negative power of two to divide by.
|
||||||
|
_rmask: (1<<_shift)-1*/
|
||||||
|
#define OC_DIV_POW2(_dividend,_shift,_rmask)\
|
||||||
|
((_dividend)+(OC_SIGNMASK(_dividend)&(_rmask))>>(_shift))
|
||||||
|
/*Divides _x by 65536, truncating towards 0.*/
|
||||||
|
#define OC_DIV2_16(_x) OC_DIV_POW2(_x,16,0xFFFF)
|
||||||
|
/*Divides _x by 2, truncating towards 0.*/
|
||||||
|
#define OC_DIV2(_x) OC_DIV_POW2(_x,1,0x1)
|
||||||
|
/*Divides _x by 8, truncating towards 0.*/
|
||||||
|
#define OC_DIV8(_x) OC_DIV_POW2(_x,3,0x7)
|
||||||
|
/*Divides _x by 16, truncating towards 0.*/
|
||||||
|
#define OC_DIV16(_x) OC_DIV_POW2(_x,4,0xF)
|
||||||
|
/*Right shifts _dividend by _shift, adding _rval, and subtracting one for
|
||||||
|
negative dividends first.
|
||||||
|
When _rval is (1<<_shift-1), this is equivalent to division with rounding
|
||||||
|
ties away from zero.*/
|
||||||
|
#define OC_DIV_ROUND_POW2(_dividend,_shift,_rval)\
|
||||||
|
((_dividend)+OC_SIGNMASK(_dividend)+(_rval)>>(_shift))
|
||||||
|
/*Divides a _x by 2, rounding towards even numbers.*/
|
||||||
|
#define OC_DIV2_RE(_x) ((_x)+((_x)>>1&1)>>1)
|
||||||
|
/*Divides a _x by (1<<(_shift)), rounding towards even numbers.*/
|
||||||
|
#define OC_DIV_POW2_RE(_x,_shift) \
|
||||||
|
((_x)+((_x)>>(_shift)&1)+((1<<(_shift))-1>>1)>>(_shift))
|
||||||
|
/*Swaps two integers _a and _b if _a>_b.*/
|
||||||
|
#define OC_SORT2I(_a,_b) \
|
||||||
|
do{ \
|
||||||
|
int t__; \
|
||||||
|
t__=((_a)^(_b))&-((_b)<(_a)); \
|
||||||
|
(_a)^=t__; \
|
||||||
|
(_b)^=t__; \
|
||||||
|
} \
|
||||||
|
while(0)
|
||||||
|
|
||||||
|
/*Accesses one of four (signed) bytes given an index.
|
||||||
|
This can be used to avoid small lookup tables.*/
|
||||||
|
#define OC_BYTE_TABLE32(_a,_b,_c,_d,_i) \
|
||||||
|
((signed char) \
|
||||||
|
(((_a)&0xFF|((_b)&0xFF)<<8|((_c)&0xFF)<<16|((_d)&0xFF)<<24)>>(_i)*8))
|
||||||
|
/*Accesses one of eight (unsigned) nibbles given an index.
|
||||||
|
This can be used to avoid small lookup tables.*/
|
||||||
|
#define OC_UNIBBLE_TABLE32(_a,_b,_c,_d,_e,_f,_g,_h,_i) \
|
||||||
|
((((_a)&0xF|((_b)&0xF)<<4|((_c)&0xF)<<8|((_d)&0xF)<<12| \
|
||||||
|
((_e)&0xF)<<16|((_f)&0xF)<<20|((_g)&0xF)<<24|((_h)&0xF)<<28)>>(_i)*4)&0xF)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*All of these macros should expect floats as arguments.*/
|
||||||
|
#define OC_MAXF(_a,_b) ((_a)<(_b)?(_b):(_a))
|
||||||
|
#define OC_MINF(_a,_b) ((_a)>(_b)?(_b):(_a))
|
||||||
|
#define OC_CLAMPF(_a,_b,_c) (OC_MINF(_a,OC_MAXF(_b,_c)))
|
||||||
|
#define OC_FABSF(_f) ((float)fabs(_f))
|
||||||
|
#define OC_SQRTF(_f) ((float)sqrt(_f))
|
||||||
|
#define OC_POWF(_b,_e) ((float)pow(_b,_e))
|
||||||
|
#define OC_LOGF(_f) ((float)log(_f))
|
||||||
|
#define OC_IFLOORF(_f) ((int)floor(_f))
|
||||||
|
#define OC_ICEILF(_f) ((int)ceil(_f))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
#include "quant.h"
|
||||||
|
#include "decint.h"
|
||||||
|
|
||||||
|
/*The maximum output of the DCT with +/- 255 inputs is +/- 8157.
|
||||||
|
These minimum quantizers ensure the result after quantization (and after
|
||||||
|
prediction for DC) will be no more than +/- 510.
|
||||||
|
The tokenization system can handle values up to +/- 580, so there is no need
|
||||||
|
to do any coefficient clamping.
|
||||||
|
I would rather have allowed smaller quantizers and had to clamp, but these
|
||||||
|
minimums were required when constructing the original VP3 matrices and have
|
||||||
|
been formalized in the spec.*/
|
||||||
|
static const unsigned OC_DC_QUANT_MIN[2]={4<<2,8<<2};
|
||||||
|
static const unsigned OC_AC_QUANT_MIN[2]={2<<2,4<<2};
|
||||||
|
|
||||||
|
/*Initializes the dequantization tables from a set of quantizer info.
|
||||||
|
Currently the dequantizer (and elsewhere enquantizer) tables are expected to
|
||||||
|
be initialized as pointing to the storage reserved for them in the
|
||||||
|
oc_theora_state (resp. oc_enc_ctx) structure.
|
||||||
|
If some tables are duplicates of others, the pointers will be adjusted to
|
||||||
|
point to a single copy of the tables, but the storage for them will not be
|
||||||
|
freed.
|
||||||
|
If you're concerned about the memory footprint, the obvious thing to do is
|
||||||
|
to move the storage out of its fixed place in the structures and allocate
|
||||||
|
it on demand.
|
||||||
|
However, a much, much better option is to only store the quantization
|
||||||
|
matrices being used for the current frame, and to recalculate these as the
|
||||||
|
qi values change between frames (this is what VP3 did).*/
|
||||||
|
void oc_dequant_tables_init(ogg_uint16_t *_dequant[64][3][2],
|
||||||
|
int _pp_dc_scale[64],const th_quant_info *_qinfo){
|
||||||
|
/*Coding mode: intra or inter.*/
|
||||||
|
int qti;
|
||||||
|
/*Y', C_b, C_r*/
|
||||||
|
int pli;
|
||||||
|
for(qti=0;qti<2;qti++)for(pli=0;pli<3;pli++){
|
||||||
|
/*Quality index.*/
|
||||||
|
int qi;
|
||||||
|
/*Range iterator.*/
|
||||||
|
int qri;
|
||||||
|
for(qi=0,qri=0;qri<=_qinfo->qi_ranges[qti][pli].nranges;qri++){
|
||||||
|
th_quant_base base;
|
||||||
|
ogg_uint32_t q;
|
||||||
|
int qi_start;
|
||||||
|
int qi_end;
|
||||||
|
memcpy(base,_qinfo->qi_ranges[qti][pli].base_matrices[qri],
|
||||||
|
sizeof(base));
|
||||||
|
qi_start=qi;
|
||||||
|
if(qri==_qinfo->qi_ranges[qti][pli].nranges)qi_end=qi+1;
|
||||||
|
else qi_end=qi+_qinfo->qi_ranges[qti][pli].sizes[qri];
|
||||||
|
/*Iterate over quality indicies in this range.*/
|
||||||
|
for(;;){
|
||||||
|
ogg_uint32_t qfac;
|
||||||
|
int zzi;
|
||||||
|
int ci;
|
||||||
|
/*In the original VP3.2 code, the rounding offset and the size of the
|
||||||
|
dead zone around 0 were controlled by a "sharpness" parameter.
|
||||||
|
The size of our dead zone is now controlled by the per-coefficient
|
||||||
|
quality thresholds returned by our HVS module.
|
||||||
|
We round down from a more accurate value when the quality of the
|
||||||
|
reconstruction does not fall below our threshold and it saves bits.
|
||||||
|
Hence, all of that VP3.2 code is gone from here, and the remaining
|
||||||
|
floating point code has been implemented as equivalent integer code
|
||||||
|
with exact precision.*/
|
||||||
|
qfac=(ogg_uint32_t)_qinfo->dc_scale[qi]*base[0];
|
||||||
|
/*For postprocessing, not dequantization.*/
|
||||||
|
if(_pp_dc_scale!=NULL)_pp_dc_scale[qi]=(int)(qfac/160);
|
||||||
|
/*Scale DC the coefficient from the proper table.*/
|
||||||
|
q=(qfac/100)<<2;
|
||||||
|
q=OC_CLAMPI(OC_DC_QUANT_MIN[qti],q,OC_QUANT_MAX);
|
||||||
|
_dequant[qi][pli][qti][0]=(ogg_uint16_t)q;
|
||||||
|
/*Now scale AC coefficients from the proper table.*/
|
||||||
|
for(zzi=1;zzi<64;zzi++){
|
||||||
|
q=((ogg_uint32_t)_qinfo->ac_scale[qi]*base[OC_FZIG_ZAG[zzi]]/100)<<2;
|
||||||
|
q=OC_CLAMPI(OC_AC_QUANT_MIN[qti],q,OC_QUANT_MAX);
|
||||||
|
_dequant[qi][pli][qti][zzi]=(ogg_uint16_t)q;
|
||||||
|
}
|
||||||
|
/*If this is a duplicate of a previous matrix, use that instead.
|
||||||
|
This simple check helps us improve cache coherency later.*/
|
||||||
|
{
|
||||||
|
int dupe;
|
||||||
|
int qtj;
|
||||||
|
int plj;
|
||||||
|
dupe=0;
|
||||||
|
for(qtj=0;qtj<=qti;qtj++){
|
||||||
|
for(plj=0;plj<(qtj<qti?3:pli);plj++){
|
||||||
|
if(!memcmp(_dequant[qi][pli][qti],_dequant[qi][plj][qtj],
|
||||||
|
sizeof(oc_quant_table))){
|
||||||
|
dupe=1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(dupe)break;
|
||||||
|
}
|
||||||
|
if(dupe)_dequant[qi][pli][qti]=_dequant[qi][plj][qtj];
|
||||||
|
}
|
||||||
|
if(++qi>=qi_end)break;
|
||||||
|
/*Interpolate the next base matrix.*/
|
||||||
|
for(ci=0;ci<64;ci++){
|
||||||
|
base[ci]=(unsigned char)(
|
||||||
|
(2*((qi_end-qi)*_qinfo->qi_ranges[qti][pli].base_matrices[qri][ci]+
|
||||||
|
(qi-qi_start)*_qinfo->qi_ranges[qti][pli].base_matrices[qri+1][ci])
|
||||||
|
+_qinfo->qi_ranges[qti][pli].sizes[qri])/
|
||||||
|
(2*_qinfo->qi_ranges[qti][pli].sizes[qri]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#if !defined(_quant_H)
|
||||||
|
# define _quant_H (1)
|
||||||
|
# include "theora/codec.h"
|
||||||
|
# include "ocintrin.h"
|
||||||
|
|
||||||
|
typedef ogg_uint16_t oc_quant_table[64];
|
||||||
|
|
||||||
|
|
||||||
|
/*Maximum scaled quantizer value.*/
|
||||||
|
#define OC_QUANT_MAX (1024<<2)
|
||||||
|
|
||||||
|
|
||||||
|
void oc_dequant_tables_init(ogg_uint16_t *_dequant[64][3][2],
|
||||||
|
int _pp_dc_scale[64],const th_quant_info *_qinfo);
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,555 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id: internal.h 17337 2010-07-19 16:08:54Z tterribe $
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
#if !defined(_state_H)
|
||||||
|
# define _state_H (1)
|
||||||
|
# include "internal.h"
|
||||||
|
# include "huffman.h"
|
||||||
|
# include "quant.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*A single quadrant of the map from a super block to fragment numbers.*/
|
||||||
|
typedef ptrdiff_t oc_sb_map_quad[4];
|
||||||
|
/*A map from a super block to fragment numbers.*/
|
||||||
|
typedef oc_sb_map_quad oc_sb_map[4];
|
||||||
|
/*A single plane of the map from a macro block to fragment numbers.*/
|
||||||
|
typedef ptrdiff_t oc_mb_map_plane[4];
|
||||||
|
/*A map from a macro block to fragment numbers.*/
|
||||||
|
typedef oc_mb_map_plane oc_mb_map[3];
|
||||||
|
/*A motion vector.*/
|
||||||
|
typedef ogg_int16_t oc_mv;
|
||||||
|
|
||||||
|
typedef struct oc_sb_flags oc_sb_flags;
|
||||||
|
typedef struct oc_border_info oc_border_info;
|
||||||
|
typedef struct oc_fragment oc_fragment;
|
||||||
|
typedef struct oc_fragment_plane oc_fragment_plane;
|
||||||
|
typedef struct oc_base_opt_vtable oc_base_opt_vtable;
|
||||||
|
typedef struct oc_base_opt_data oc_base_opt_data;
|
||||||
|
typedef struct oc_state_dispatch_vtable oc_state_dispatch_vtable;
|
||||||
|
typedef struct oc_theora_state oc_theora_state;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*Shared accelerated functions.*/
|
||||||
|
# if defined(OC_X86_ASM)
|
||||||
|
# if defined(_MSC_VER)
|
||||||
|
# include "x86_vc/x86int.h"
|
||||||
|
# else
|
||||||
|
# include "x86/x86int.h"
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# if defined(OC_ARM_ASM)
|
||||||
|
# include "arm-intrinsics/armint.h"
|
||||||
|
# endif
|
||||||
|
# if defined(OC_C64X_ASM)
|
||||||
|
# include "c64x/c64xint.h"
|
||||||
|
# endif
|
||||||
|
# if defined(OC_WASM_SIMD128)
|
||||||
|
# include "wasm-simd/wav128int.h"
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if !defined(oc_state_accel_init)
|
||||||
|
# define oc_state_accel_init oc_state_accel_init_c
|
||||||
|
# endif
|
||||||
|
# if defined(OC_STATE_USE_VTABLE)
|
||||||
|
# if !defined(oc_frag_copy)
|
||||||
|
# define oc_frag_copy(_state,_dst,_src,_ystride) \
|
||||||
|
((*(_state)->opt_vtable.frag_copy)(_dst,_src,_ystride))
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_frag_copy_list)
|
||||||
|
# define oc_frag_copy_list(_state,_dst_frame,_src_frame,_ystride, \
|
||||||
|
_fragis,_nfragis,_frag_buf_offs) \
|
||||||
|
((*(_state)->opt_vtable.frag_copy_list)(_dst_frame,_src_frame,_ystride, \
|
||||||
|
_fragis,_nfragis,_frag_buf_offs))
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_frag_recon_intra)
|
||||||
|
# define oc_frag_recon_intra(_state,_dst,_dst_ystride,_residue) \
|
||||||
|
((*(_state)->opt_vtable.frag_recon_intra)(_dst,_dst_ystride,_residue))
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_frag_recon_inter)
|
||||||
|
# define oc_frag_recon_inter(_state,_dst,_src,_ystride,_residue) \
|
||||||
|
((*(_state)->opt_vtable.frag_recon_inter)(_dst,_src,_ystride,_residue))
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_frag_recon_inter2)
|
||||||
|
# define oc_frag_recon_inter2(_state,_dst,_src1,_src2,_ystride,_residue) \
|
||||||
|
((*(_state)->opt_vtable.frag_recon_inter2)(_dst, \
|
||||||
|
_src1,_src2,_ystride,_residue))
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_idct8x8)
|
||||||
|
# define oc_idct8x8(_state,_y,_x,_last_zzi) \
|
||||||
|
((*(_state)->opt_vtable.idct8x8)(_y,_x,_last_zzi))
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_state_frag_recon)
|
||||||
|
# define oc_state_frag_recon(_state,_fragi, \
|
||||||
|
_pli,_dct_coeffs,_last_zzi,_dc_quant) \
|
||||||
|
((*(_state)->opt_vtable.state_frag_recon)(_state,_fragi, \
|
||||||
|
_pli,_dct_coeffs,_last_zzi,_dc_quant))
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_loop_filter_init)
|
||||||
|
# define oc_loop_filter_init(_state,_bv,_flimit) \
|
||||||
|
((*(_state)->opt_vtable.loop_filter_init)(_bv,_flimit))
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_state_loop_filter_frag_rows)
|
||||||
|
# define oc_state_loop_filter_frag_rows(_state, \
|
||||||
|
_bv,_refi,_pli,_fragy0,_fragy_end) \
|
||||||
|
((*(_state)->opt_vtable.state_loop_filter_frag_rows)(_state, \
|
||||||
|
_bv,_refi,_pli,_fragy0,_fragy_end))
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_restore_fpu)
|
||||||
|
# define oc_restore_fpu(_state) \
|
||||||
|
((*(_state)->opt_vtable.restore_fpu)())
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# if !defined(oc_frag_copy)
|
||||||
|
# define oc_frag_copy(_state,_dst,_src,_ystride) \
|
||||||
|
oc_frag_copy_c(_dst,_src,_ystride)
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_frag_copy_list)
|
||||||
|
# define oc_frag_copy_list(_state,_dst_frame,_src_frame,_ystride, \
|
||||||
|
_fragis,_nfragis,_frag_buf_offs) \
|
||||||
|
oc_frag_copy_list_c(_dst_frame,_src_frame,_ystride, \
|
||||||
|
_fragis,_nfragis,_frag_buf_offs)
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_frag_recon_intra)
|
||||||
|
# define oc_frag_recon_intra(_state,_dst,_dst_ystride,_residue) \
|
||||||
|
oc_frag_recon_intra_c(_dst,_dst_ystride,_residue)
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_frag_recon_inter)
|
||||||
|
# define oc_frag_recon_inter(_state,_dst,_src,_ystride,_residue) \
|
||||||
|
oc_frag_recon_inter_c(_dst,_src,_ystride,_residue)
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_frag_recon_inter2)
|
||||||
|
# define oc_frag_recon_inter2(_state,_dst,_src1,_src2,_ystride,_residue) \
|
||||||
|
oc_frag_recon_inter2_c(_dst,_src1,_src2,_ystride,_residue)
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_idct8x8)
|
||||||
|
# define oc_idct8x8(_state,_y,_x,_last_zzi) oc_idct8x8_c(_y,_x,_last_zzi)
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_state_frag_recon)
|
||||||
|
# define oc_state_frag_recon oc_state_frag_recon_c
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_loop_filter_init)
|
||||||
|
# define oc_loop_filter_init(_state,_bv,_flimit) \
|
||||||
|
oc_loop_filter_init_c(_bv,_flimit)
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_state_loop_filter_frag_rows)
|
||||||
|
# define oc_state_loop_filter_frag_rows oc_state_loop_filter_frag_rows_c
|
||||||
|
# endif
|
||||||
|
# if !defined(oc_restore_fpu)
|
||||||
|
# define oc_restore_fpu(_state) do{}while(0)
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*A keyframe.*/
|
||||||
|
# define OC_INTRA_FRAME (0)
|
||||||
|
/*A predicted frame.*/
|
||||||
|
# define OC_INTER_FRAME (1)
|
||||||
|
/*A frame of unknown type (frame type decision has not yet been made).*/
|
||||||
|
# define OC_UNKWN_FRAME (-1)
|
||||||
|
|
||||||
|
/*The amount of padding to add to the reconstructed frame buffers on all
|
||||||
|
sides.
|
||||||
|
This is used to allow unrestricted motion vectors without special casing.
|
||||||
|
This must be a multiple of 2.*/
|
||||||
|
# define OC_UMV_PADDING (16)
|
||||||
|
|
||||||
|
/*Frame classification indices.*/
|
||||||
|
/*The previous golden frame.*/
|
||||||
|
# define OC_FRAME_GOLD (0)
|
||||||
|
/*The previous frame.*/
|
||||||
|
# define OC_FRAME_PREV (1)
|
||||||
|
/*The current frame.*/
|
||||||
|
# define OC_FRAME_SELF (2)
|
||||||
|
/*Used to mark uncoded fragments (for DC prediction).*/
|
||||||
|
# define OC_FRAME_NONE (3)
|
||||||
|
|
||||||
|
/*The input or output buffer.*/
|
||||||
|
# define OC_FRAME_IO (3)
|
||||||
|
/*Uncompressed prev golden frame.*/
|
||||||
|
# define OC_FRAME_GOLD_ORIG (4)
|
||||||
|
/*Uncompressed previous frame. */
|
||||||
|
# define OC_FRAME_PREV_ORIG (5)
|
||||||
|
|
||||||
|
/*Macroblock modes.*/
|
||||||
|
/*Macro block is invalid: It is never coded.*/
|
||||||
|
# define OC_MODE_INVALID (-1)
|
||||||
|
/*Encoded difference from the same macro block in the previous frame.*/
|
||||||
|
# define OC_MODE_INTER_NOMV (0)
|
||||||
|
/*Encoded with no motion compensated prediction.*/
|
||||||
|
# define OC_MODE_INTRA (1)
|
||||||
|
/*Encoded difference from the previous frame offset by the given motion
|
||||||
|
vector.*/
|
||||||
|
# define OC_MODE_INTER_MV (2)
|
||||||
|
/*Encoded difference from the previous frame offset by the last coded motion
|
||||||
|
vector.*/
|
||||||
|
# define OC_MODE_INTER_MV_LAST (3)
|
||||||
|
/*Encoded difference from the previous frame offset by the second to last
|
||||||
|
coded motion vector.*/
|
||||||
|
# define OC_MODE_INTER_MV_LAST2 (4)
|
||||||
|
/*Encoded difference from the same macro block in the previous golden
|
||||||
|
frame.*/
|
||||||
|
# define OC_MODE_GOLDEN_NOMV (5)
|
||||||
|
/*Encoded difference from the previous golden frame offset by the given motion
|
||||||
|
vector.*/
|
||||||
|
# define OC_MODE_GOLDEN_MV (6)
|
||||||
|
/*Encoded difference from the previous frame offset by the individual motion
|
||||||
|
vectors given for each block.*/
|
||||||
|
# define OC_MODE_INTER_MV_FOUR (7)
|
||||||
|
/*The number of (coded) modes.*/
|
||||||
|
# define OC_NMODES (8)
|
||||||
|
|
||||||
|
/*Determines the reference frame used for a given MB mode.*/
|
||||||
|
# define OC_FRAME_FOR_MODE(_x) \
|
||||||
|
OC_UNIBBLE_TABLE32(OC_FRAME_PREV,OC_FRAME_SELF,OC_FRAME_PREV,OC_FRAME_PREV, \
|
||||||
|
OC_FRAME_PREV,OC_FRAME_GOLD,OC_FRAME_GOLD,OC_FRAME_PREV,(_x))
|
||||||
|
|
||||||
|
/*Constants for the packet state machine common between encoder and decoder.*/
|
||||||
|
|
||||||
|
/*Next packet to emit/read: Codec info header.*/
|
||||||
|
# define OC_PACKET_INFO_HDR (-3)
|
||||||
|
/*Next packet to emit/read: Comment header.*/
|
||||||
|
# define OC_PACKET_COMMENT_HDR (-2)
|
||||||
|
/*Next packet to emit/read: Codec setup header.*/
|
||||||
|
# define OC_PACKET_SETUP_HDR (-1)
|
||||||
|
/*No more packets to emit/read.*/
|
||||||
|
# define OC_PACKET_DONE (INT_MAX)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define OC_MV(_x,_y) ((oc_mv)((_x)&0xFF|(_y)<<8))
|
||||||
|
#define OC_MV_X(_mv) ((signed char)(_mv))
|
||||||
|
#define OC_MV_Y(_mv) ((_mv)>>8)
|
||||||
|
#define OC_MV_ADD(_mv1,_mv2) \
|
||||||
|
OC_MV(OC_MV_X(_mv1)+OC_MV_X(_mv2), \
|
||||||
|
OC_MV_Y(_mv1)+OC_MV_Y(_mv2))
|
||||||
|
#define OC_MV_SUB(_mv1,_mv2) \
|
||||||
|
OC_MV(OC_MV_X(_mv1)-OC_MV_X(_mv2), \
|
||||||
|
OC_MV_Y(_mv1)-OC_MV_Y(_mv2))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*Super blocks are 32x32 segments of pixels in a single color plane indexed
|
||||||
|
in image order.
|
||||||
|
Internally, super blocks are broken up into four quadrants, each of which
|
||||||
|
contains a 2x2 pattern of blocks, each of which is an 8x8 block of pixels.
|
||||||
|
Quadrants, and the blocks within them, are indexed in a special order called
|
||||||
|
a "Hilbert curve" within the super block.
|
||||||
|
|
||||||
|
In order to differentiate between the Hilbert-curve indexing strategy and
|
||||||
|
the regular image order indexing strategy, blocks indexed in image order
|
||||||
|
are called "fragments".
|
||||||
|
Fragments are indexed in image order, left to right, then bottom to top,
|
||||||
|
from Y' plane to Cb plane to Cr plane.
|
||||||
|
|
||||||
|
The co-located fragments in all image planes corresponding to the location
|
||||||
|
of a single quadrant of a luma plane super block form a macro block.
|
||||||
|
Thus there is only a single set of macro blocks for all planes, each of which
|
||||||
|
contains between 6 and 12 fragments, depending on the pixel format.
|
||||||
|
Therefore macro block information is kept in a separate set of arrays from
|
||||||
|
super blocks to avoid unused space in the other planes.
|
||||||
|
The lists are indexed in super block order.
|
||||||
|
That is, the macro block corresponding to the macro block mbi in (luma plane)
|
||||||
|
super block sbi is at index (sbi<<2|mbi).
|
||||||
|
Thus the number of macro blocks in each dimension is always twice the number
|
||||||
|
of super blocks, even when only an odd number fall inside the coded frame.
|
||||||
|
These "extra" macro blocks are just an artifact of our internal data layout,
|
||||||
|
and not part of the coded stream; they are flagged with a negative MB mode.*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*Super block information.*/
|
||||||
|
struct oc_sb_flags{
|
||||||
|
unsigned char coded_fully:1;
|
||||||
|
unsigned char coded_partially:1;
|
||||||
|
unsigned char quad_valid:4;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*Information about a fragment which intersects the border of the displayable
|
||||||
|
region.
|
||||||
|
This marks which pixels belong to the displayable region.*/
|
||||||
|
struct oc_border_info{
|
||||||
|
/*A bit mask marking which pixels are in the displayable region.
|
||||||
|
Pixel (x,y) corresponds to bit (y<<3|x).*/
|
||||||
|
ogg_int64_t mask;
|
||||||
|
/*The number of pixels in the displayable region.
|
||||||
|
This is always positive, and always less than 64.*/
|
||||||
|
int npixels;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*Fragment information.*/
|
||||||
|
struct oc_fragment{
|
||||||
|
/*A flag indicating whether or not this fragment is coded.*/
|
||||||
|
unsigned coded:1;
|
||||||
|
/*A flag indicating that this entire fragment lies outside the displayable
|
||||||
|
region of the frame.
|
||||||
|
Note the contrast with an invalid macro block, which is outside the coded
|
||||||
|
frame, not just the displayable one.
|
||||||
|
There are no fragments outside the coded frame by construction.*/
|
||||||
|
unsigned invalid:1;
|
||||||
|
/*The index of the quality index used for this fragment's AC coefficients.*/
|
||||||
|
unsigned qii:4;
|
||||||
|
/*The index of the reference frame this fragment is predicted from.*/
|
||||||
|
unsigned refi:2;
|
||||||
|
/*The mode of the macroblock this fragment belongs to.*/
|
||||||
|
unsigned mb_mode:3;
|
||||||
|
/*The index of the associated border information for fragments which lie
|
||||||
|
partially outside the displayable region.
|
||||||
|
For fragments completely inside or outside this region, this is -1.
|
||||||
|
Note that the C standard requires an explicit signed keyword for bitfield
|
||||||
|
types, since some compilers may treat them as unsigned without it.*/
|
||||||
|
signed int borderi:5;
|
||||||
|
/*The prediction-corrected DC component.
|
||||||
|
Note that the C standard requires an explicit signed keyword for bitfield
|
||||||
|
types, since some compilers may treat them as unsigned without it.*/
|
||||||
|
signed int dc:16;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*A description of each fragment plane.*/
|
||||||
|
struct oc_fragment_plane{
|
||||||
|
/*The number of fragments in the horizontal direction.*/
|
||||||
|
int nhfrags;
|
||||||
|
/*The number of fragments in the vertical direction.*/
|
||||||
|
int nvfrags;
|
||||||
|
/*The offset of the first fragment in the plane.*/
|
||||||
|
ptrdiff_t froffset;
|
||||||
|
/*The total number of fragments in the plane.*/
|
||||||
|
ptrdiff_t nfrags;
|
||||||
|
/*The number of super blocks in the horizontal direction.*/
|
||||||
|
unsigned nhsbs;
|
||||||
|
/*The number of super blocks in the vertical direction.*/
|
||||||
|
unsigned nvsbs;
|
||||||
|
/*The offset of the first super block in the plane.*/
|
||||||
|
unsigned sboffset;
|
||||||
|
/*The total number of super blocks in the plane.*/
|
||||||
|
unsigned nsbs;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*oc_state_loop_filter_frag_rows_func)(
|
||||||
|
const oc_theora_state *_state,signed char _bv[256],int _refi,int _pli,
|
||||||
|
int _fragy0,int _fragy_end);
|
||||||
|
|
||||||
|
/*The shared (encoder and decoder) functions that have accelerated variants.*/
|
||||||
|
struct oc_base_opt_vtable{
|
||||||
|
void (*frag_copy)(unsigned char *_dst,
|
||||||
|
const unsigned char *_src,int _ystride);
|
||||||
|
void (*frag_copy_list)(unsigned char *_dst_frame,
|
||||||
|
const unsigned char *_src_frame,int _ystride,
|
||||||
|
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs);
|
||||||
|
void (*frag_recon_intra)(unsigned char *_dst,int _ystride,
|
||||||
|
const ogg_int16_t _residue[64]);
|
||||||
|
void (*frag_recon_inter)(unsigned char *_dst,
|
||||||
|
const unsigned char *_src,int _ystride,const ogg_int16_t _residue[64]);
|
||||||
|
void (*frag_recon_inter2)(unsigned char *_dst,const unsigned char *_src1,
|
||||||
|
const unsigned char *_src2,int _ystride,const ogg_int16_t _residue[64]);
|
||||||
|
void (*idct8x8)(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi);
|
||||||
|
void (*state_frag_recon)(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||||
|
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant);
|
||||||
|
void (*loop_filter_init)(signed char _bv[256],int _flimit);
|
||||||
|
oc_state_loop_filter_frag_rows_func state_loop_filter_frag_rows;
|
||||||
|
void (*restore_fpu)(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*The shared (encoder and decoder) tables that vary according to which variants
|
||||||
|
of the above functions are used.*/
|
||||||
|
struct oc_base_opt_data{
|
||||||
|
const unsigned char *dct_fzig_zag;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*State information common to both the encoder and decoder.*/
|
||||||
|
struct oc_theora_state{
|
||||||
|
/*The stream information.*/
|
||||||
|
th_info info;
|
||||||
|
# if defined(OC_STATE_USE_VTABLE)
|
||||||
|
/*Table for shared accelerated functions.*/
|
||||||
|
oc_base_opt_vtable opt_vtable;
|
||||||
|
# endif
|
||||||
|
/*Table for shared data used by accelerated functions.*/
|
||||||
|
oc_base_opt_data opt_data;
|
||||||
|
/*CPU flags to detect the presence of extended instruction sets.*/
|
||||||
|
ogg_uint32_t cpu_flags;
|
||||||
|
/*The fragment plane descriptions.*/
|
||||||
|
oc_fragment_plane fplanes[3];
|
||||||
|
/*The list of fragments, indexed in image order.*/
|
||||||
|
oc_fragment *frags;
|
||||||
|
/*The the offset into the reference frame buffer to the upper-left pixel of
|
||||||
|
each fragment.*/
|
||||||
|
ptrdiff_t *frag_buf_offs;
|
||||||
|
/*The motion vector for each fragment.*/
|
||||||
|
oc_mv *frag_mvs;
|
||||||
|
/*The total number of fragments in a single frame.*/
|
||||||
|
ptrdiff_t nfrags;
|
||||||
|
/*The list of super block maps, indexed in image order.*/
|
||||||
|
oc_sb_map *sb_maps;
|
||||||
|
/*The list of super block flags, indexed in image order.*/
|
||||||
|
oc_sb_flags *sb_flags;
|
||||||
|
/*The total number of super blocks in a single frame.*/
|
||||||
|
unsigned nsbs;
|
||||||
|
/*The fragments from each color plane that belong to each macro block.
|
||||||
|
Fragments are stored in image order (left to right then top to bottom).
|
||||||
|
When chroma components are decimated, the extra fragments have an index of
|
||||||
|
-1.*/
|
||||||
|
oc_mb_map *mb_maps;
|
||||||
|
/*The list of macro block modes.
|
||||||
|
A negative number indicates the macro block lies entirely outside the
|
||||||
|
coded frame.*/
|
||||||
|
signed char *mb_modes;
|
||||||
|
/*The number of macro blocks in the X direction.*/
|
||||||
|
unsigned nhmbs;
|
||||||
|
/*The number of macro blocks in the Y direction.*/
|
||||||
|
unsigned nvmbs;
|
||||||
|
/*The total number of macro blocks.*/
|
||||||
|
size_t nmbs;
|
||||||
|
/*The list of coded fragments, in coded order.
|
||||||
|
Uncoded fragments are stored in reverse order from the end of the list.*/
|
||||||
|
ptrdiff_t *coded_fragis;
|
||||||
|
/*The number of coded fragments in each plane.*/
|
||||||
|
ptrdiff_t ncoded_fragis[3];
|
||||||
|
/*The total number of coded fragments.*/
|
||||||
|
ptrdiff_t ntotal_coded_fragis;
|
||||||
|
/*The actual buffers used for the reference frames.*/
|
||||||
|
th_ycbcr_buffer ref_frame_bufs[6];
|
||||||
|
/*The index of the buffers being used for each OC_FRAME_* reference frame.*/
|
||||||
|
int ref_frame_idx[6];
|
||||||
|
/*The storage for the reference frame buffers.
|
||||||
|
This is just ref_frame_bufs[ref_frame_idx[i]][0].data, but is cached here
|
||||||
|
for faster look-up.*/
|
||||||
|
unsigned char *ref_frame_data[6];
|
||||||
|
/*The handle used to allocate the reference frame buffers.*/
|
||||||
|
unsigned char *ref_frame_handle;
|
||||||
|
/*The strides for each plane in the reference frames.*/
|
||||||
|
int ref_ystride[3];
|
||||||
|
/*The number of unique border patterns.*/
|
||||||
|
int nborders;
|
||||||
|
/*The unique border patterns for all border fragments.
|
||||||
|
The borderi field of fragments which straddle the border indexes this
|
||||||
|
list.*/
|
||||||
|
oc_border_info borders[16];
|
||||||
|
/*The frame number of the last keyframe.*/
|
||||||
|
ogg_int64_t keyframe_num;
|
||||||
|
/*The frame number of the current frame.*/
|
||||||
|
ogg_int64_t curframe_num;
|
||||||
|
/*The granpos of the current frame.*/
|
||||||
|
ogg_int64_t granpos;
|
||||||
|
/*The type of the current frame.*/
|
||||||
|
signed char frame_type;
|
||||||
|
/*The bias to add to the frame count when computing granule positions.*/
|
||||||
|
unsigned char granpos_bias;
|
||||||
|
/*The number of quality indices used in the current frame.*/
|
||||||
|
unsigned char nqis;
|
||||||
|
/*The quality indices of the current frame.*/
|
||||||
|
unsigned char qis[3];
|
||||||
|
/*The dequantization tables, stored in zig-zag order, and indexed by
|
||||||
|
qi, pli, qti, and zzi.*/
|
||||||
|
ogg_uint16_t *dequant_tables[64][3][2];
|
||||||
|
OC_ALIGN16(oc_quant_table dequant_table_data[64][3][2]);
|
||||||
|
/*Loop filter strength parameters.*/
|
||||||
|
unsigned char loop_filter_limits[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*The function type used to fill in the chroma plane motion vectors for a
|
||||||
|
macro block when 4 different motion vectors are specified in the luma
|
||||||
|
plane.
|
||||||
|
_cbmvs: The chroma block-level motion vectors to fill in.
|
||||||
|
_lmbmv: The luma macro-block level motion vector to fill in for use in
|
||||||
|
prediction.
|
||||||
|
_lbmvs: The luma block-level motion vectors.*/
|
||||||
|
typedef void (*oc_set_chroma_mvs_func)(oc_mv _cbmvs[4],const oc_mv _lbmvs[4]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*A table of functions used to fill in the Cb,Cr plane motion vectors for a
|
||||||
|
macro block when 4 different motion vectors are specified in the luma
|
||||||
|
plane.*/
|
||||||
|
extern const oc_set_chroma_mvs_func OC_SET_CHROMA_MVS_TABLE[TH_PF_NFORMATS];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int oc_state_init(oc_theora_state *_state,const th_info *_info,int _nrefs);
|
||||||
|
void oc_state_clear(oc_theora_state *_state);
|
||||||
|
void oc_state_accel_init_c(oc_theora_state *_state);
|
||||||
|
void oc_state_borders_fill_rows(oc_theora_state *_state,int _refi,int _pli,
|
||||||
|
int _y0,int _yend);
|
||||||
|
void oc_state_borders_fill_caps(oc_theora_state *_state,int _refi,int _pli);
|
||||||
|
void oc_state_borders_fill(oc_theora_state *_state,int _refi);
|
||||||
|
void oc_state_fill_buffer_ptrs(oc_theora_state *_state,int _buf_idx,
|
||||||
|
th_ycbcr_buffer _img);
|
||||||
|
int oc_state_mbi_for_pos(oc_theora_state *_state,int _mbx,int _mby);
|
||||||
|
int oc_state_get_mv_offsets(const oc_theora_state *_state,int _offsets[2],
|
||||||
|
int _pli,oc_mv _mv);
|
||||||
|
|
||||||
|
void oc_loop_filter_init_c(signed char _bv[256],int _flimit);
|
||||||
|
void oc_state_loop_filter(oc_theora_state *_state,int _frame);
|
||||||
|
# if defined(OC_DUMP_IMAGES)
|
||||||
|
int oc_state_dump_frame(const oc_theora_state *_state,int _frame,
|
||||||
|
const char *_suf);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/*Default pure-C implementations of shared accelerated functions.*/
|
||||||
|
void oc_frag_copy_c(unsigned char *_dst,
|
||||||
|
const unsigned char *_src,int _src_ystride);
|
||||||
|
void oc_frag_copy_list_c(unsigned char *_dst_frame,
|
||||||
|
const unsigned char *_src_frame,int _ystride,
|
||||||
|
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs);
|
||||||
|
void oc_frag_recon_intra_c(unsigned char *_dst,int _dst_ystride,
|
||||||
|
const ogg_int16_t _residue[64]);
|
||||||
|
void oc_frag_recon_inter_c(unsigned char *_dst,
|
||||||
|
const unsigned char *_src,int _ystride,const ogg_int16_t _residue[64]);
|
||||||
|
void oc_frag_recon_inter2_c(unsigned char *_dst,const unsigned char *_src1,
|
||||||
|
const unsigned char *_src2,int _ystride,const ogg_int16_t _residue[64]);
|
||||||
|
void oc_idct8x8_c(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi);
|
||||||
|
void oc_state_frag_recon_c(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||||
|
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant);
|
||||||
|
void oc_state_loop_filter_frag_rows_c(const oc_theora_state *_state,
|
||||||
|
signed char _bv[256],int _refi,int _pli,int _fragy0,int _fragy_end);
|
||||||
|
void oc_restore_fpu_c(void);
|
||||||
|
|
||||||
|
/*We need a way to call a few encoder functions without introducing a link-time
|
||||||
|
dependency into the decoder, while still allowing the old alpha API which
|
||||||
|
does not distinguish between encoder and decoder objects to be used.
|
||||||
|
We do this by placing a function table at the start of the encoder object
|
||||||
|
which can dispatch into the encoder library.
|
||||||
|
We do a similar thing for the decoder in case we ever decide to split off a
|
||||||
|
common base library.*/
|
||||||
|
typedef void (*oc_state_clear_func)(theora_state *_th);
|
||||||
|
typedef int (*oc_state_control_func)(theora_state *th,int _req,
|
||||||
|
void *_buf,size_t _buf_sz);
|
||||||
|
typedef ogg_int64_t (*oc_state_granule_frame_func)(theora_state *_th,
|
||||||
|
ogg_int64_t _granulepos);
|
||||||
|
typedef double (*oc_state_granule_time_func)(theora_state *_th,
|
||||||
|
ogg_int64_t _granulepos);
|
||||||
|
|
||||||
|
|
||||||
|
struct oc_state_dispatch_vtable{
|
||||||
|
oc_state_clear_func clear;
|
||||||
|
oc_state_control_func control;
|
||||||
|
oc_state_granule_frame_func granule_frame;
|
||||||
|
oc_state_granule_time_func granule_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,786 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id: theora.h,v 1.17 2003/12/06 18:06:19 arc Exp $
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _O_THEORA_H_
|
||||||
|
#define _O_THEORA_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#include <stddef.h> /* for size_t */
|
||||||
|
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* The libtheora pre-1.0 legacy C API.
|
||||||
|
*
|
||||||
|
* \ingroup oldfuncs
|
||||||
|
*
|
||||||
|
* \section intro Introduction
|
||||||
|
*
|
||||||
|
* This is the documentation for the libtheora legacy C API, declared in
|
||||||
|
* the theora.h header, which describes the old interface used before
|
||||||
|
* the 1.0 release. This API was widely deployed for several years and
|
||||||
|
* remains supported, but for new code we recommend the cleaner API
|
||||||
|
* declared in theoradec.h and theoraenc.h.
|
||||||
|
*
|
||||||
|
* libtheora is the reference implementation for
|
||||||
|
* <a href="http://www.theora.org/">Theora</a>, a free video codec.
|
||||||
|
* Theora is derived from On2's VP3 codec with improved integration with
|
||||||
|
* Ogg multimedia formats by <a href="http://www.xiph.org/">Xiph.Org</a>.
|
||||||
|
*
|
||||||
|
* \section overview Overview
|
||||||
|
*
|
||||||
|
* This library will both decode and encode theora packets to/from raw YUV
|
||||||
|
* frames. In either case, the packets will most likely either come from or
|
||||||
|
* need to be embedded in an Ogg stream. Use
|
||||||
|
* <a href="http://xiph.org/ogg/">libogg</a> or
|
||||||
|
* <a href="http://www.annodex.net/software/liboggz/index.html">liboggz</a>
|
||||||
|
* to extract/package these packets.
|
||||||
|
*
|
||||||
|
* \section decoding Decoding Process
|
||||||
|
*
|
||||||
|
* Decoding can be separated into the following steps:
|
||||||
|
* -# initialise theora_info and theora_comment structures using
|
||||||
|
* theora_info_init() and theora_comment_init():
|
||||||
|
\verbatim
|
||||||
|
theora_info info;
|
||||||
|
theora_comment comment;
|
||||||
|
|
||||||
|
theora_info_init(&info);
|
||||||
|
theora_comment_init(&comment);
|
||||||
|
\endverbatim
|
||||||
|
* -# retrieve header packets from Ogg stream (there should be 3) and decode
|
||||||
|
* into theora_info and theora_comment structures using
|
||||||
|
* theora_decode_header(). See \ref identification for more information on
|
||||||
|
* identifying which packets are theora packets.
|
||||||
|
\verbatim
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
(get a theora packet "op" from the Ogg stream)
|
||||||
|
theora_decode_header(&info, &comment, op);
|
||||||
|
}
|
||||||
|
\endverbatim
|
||||||
|
* -# initialise the decoder based on the information retrieved into the
|
||||||
|
* theora_info struct by theora_decode_header(). You will need a
|
||||||
|
* theora_state struct.
|
||||||
|
\verbatim
|
||||||
|
theora_state state;
|
||||||
|
|
||||||
|
theora_decode_init(&state, &info);
|
||||||
|
\endverbatim
|
||||||
|
* -# pass in packets and retrieve decoded frames! See the yuv_buffer
|
||||||
|
* documentation for information on how to retrieve raw YUV data.
|
||||||
|
\verbatim
|
||||||
|
yuf_buffer buffer;
|
||||||
|
while (last packet was not e_o_s) {
|
||||||
|
(get a theora packet "op" from the Ogg stream)
|
||||||
|
theora_decode_packetin(&state, op);
|
||||||
|
theora_decode_YUVout(&state, &buffer);
|
||||||
|
}
|
||||||
|
\endverbatim
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* \subsection identification Identifying Theora Packets
|
||||||
|
*
|
||||||
|
* All streams inside an Ogg file have a unique serial_no attached to the
|
||||||
|
* stream. Typically, you will want to
|
||||||
|
* - retrieve the serial_no for each b_o_s (beginning of stream) page
|
||||||
|
* encountered within the Ogg file;
|
||||||
|
* - test the first (only) packet on that page to determine if it is a theora
|
||||||
|
* packet;
|
||||||
|
* - once you have found a theora b_o_s page then use the retrieved serial_no
|
||||||
|
* to identify future packets belonging to the same theora stream.
|
||||||
|
*
|
||||||
|
* Note that you \e cannot use theora_packet_isheader() to determine if a
|
||||||
|
* packet is a theora packet or not, as this function does not perform any
|
||||||
|
* checking beyond whether a header bit is present. Instead, use the
|
||||||
|
* theora_decode_header() function and check the return value; or examine the
|
||||||
|
* header bytes at the beginning of the Ogg page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/** \defgroup oldfuncs Legacy pre-1.0 C API */
|
||||||
|
/* @{ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A YUV buffer for passing uncompressed frames to and from the codec.
|
||||||
|
* This holds a Y'CbCr frame in planar format. The CbCr planes can be
|
||||||
|
* subsampled and have their own separate dimensions and row stride
|
||||||
|
* offsets. Note that the strides may be negative in some
|
||||||
|
* configurations. For theora the width and height of the largest plane
|
||||||
|
* must be a multiple of 16. The actual meaningful picture size and
|
||||||
|
* offset are stored in the theora_info structure; frames returned by
|
||||||
|
* the decoder may need to be cropped for display.
|
||||||
|
*
|
||||||
|
* All samples are 8 bits. Within each plane samples are ordered by
|
||||||
|
* row from the top of the frame to the bottom. Within each row samples
|
||||||
|
* are ordered from left to right.
|
||||||
|
*
|
||||||
|
* During decode, the yuv_buffer struct is allocated by the user, but all
|
||||||
|
* fields (including luma and chroma pointers) are filled by the library.
|
||||||
|
* These pointers address library-internal memory and their contents should
|
||||||
|
* not be modified.
|
||||||
|
*
|
||||||
|
* Conversely, during encode the user allocates the struct and fills out all
|
||||||
|
* fields. The user also manages the data addressed by the luma and chroma
|
||||||
|
* pointers. See the encoder_example.c and dump_video.c example files in
|
||||||
|
* theora/examples/ for more information.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
int y_width; /**< Width of the Y' luminance plane */
|
||||||
|
int y_height; /**< Height of the luminance plane */
|
||||||
|
int y_stride; /**< Offset in bytes between successive rows */
|
||||||
|
|
||||||
|
int uv_width; /**< Width of the Cb and Cr chroma planes */
|
||||||
|
int uv_height; /**< Height of the chroma planes */
|
||||||
|
int uv_stride; /**< Offset between successive chroma rows */
|
||||||
|
unsigned char *y; /**< Pointer to start of luminance data */
|
||||||
|
unsigned char *u; /**< Pointer to start of Cb data */
|
||||||
|
unsigned char *v; /**< Pointer to start of Cr data */
|
||||||
|
|
||||||
|
} yuv_buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Colorspace.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
OC_CS_UNSPECIFIED, /**< The colorspace is unknown or unspecified */
|
||||||
|
OC_CS_ITU_REC_470M, /**< This is the best option for 'NTSC' content */
|
||||||
|
OC_CS_ITU_REC_470BG, /**< This is the best option for 'PAL' content */
|
||||||
|
OC_CS_NSPACES /**< This marks the end of the defined colorspaces */
|
||||||
|
} theora_colorspace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Chroma subsampling
|
||||||
|
*
|
||||||
|
* These enumerate the available chroma subsampling options supported
|
||||||
|
* by the theora format. See Section 4.4 of the specification for
|
||||||
|
* exact definitions.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
OC_PF_420, /**< Chroma subsampling by 2 in each direction (4:2:0) */
|
||||||
|
OC_PF_RSVD, /**< Reserved value */
|
||||||
|
OC_PF_422, /**< Horizonatal chroma subsampling by 2 (4:2:2) */
|
||||||
|
OC_PF_444 /**< No chroma subsampling at all (4:4:4) */
|
||||||
|
} theora_pixelformat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Theora bitstream info.
|
||||||
|
* Contains the basic playback parameters for a stream,
|
||||||
|
* corresponding to the initial 'info' header packet.
|
||||||
|
*
|
||||||
|
* Encoded theora frames must be a multiple of 16 in width and height.
|
||||||
|
* To handle other frame sizes, a crop rectangle is specified in
|
||||||
|
* frame_height and frame_width, offset_x and * offset_y. The offset
|
||||||
|
* and size should still be a multiple of 2 to avoid chroma sampling
|
||||||
|
* shifts. Offset values in this structure are measured from the
|
||||||
|
* upper left of the image.
|
||||||
|
*
|
||||||
|
* Frame rate, in frames per second, is stored as a rational
|
||||||
|
* fraction. Aspect ratio is also stored as a rational fraction, and
|
||||||
|
* refers to the aspect ratio of the frame pixels, not of the
|
||||||
|
* overall frame itself.
|
||||||
|
*
|
||||||
|
* See <a href="http://svn.xiph.org/trunk/theora/examples/encoder_example.c">
|
||||||
|
* examples/encoder_example.c</a> for usage examples of the
|
||||||
|
* other parameters and good default settings for the encoder parameters.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
ogg_uint32_t width; /**< encoded frame width */
|
||||||
|
ogg_uint32_t height; /**< encoded frame height */
|
||||||
|
ogg_uint32_t frame_width; /**< display frame width */
|
||||||
|
ogg_uint32_t frame_height; /**< display frame height */
|
||||||
|
ogg_uint32_t offset_x; /**< horizontal offset of the displayed frame */
|
||||||
|
ogg_uint32_t offset_y; /**< vertical offset of the displayed frame */
|
||||||
|
ogg_uint32_t fps_numerator; /**< frame rate numerator **/
|
||||||
|
ogg_uint32_t fps_denominator; /**< frame rate denominator **/
|
||||||
|
ogg_uint32_t aspect_numerator; /**< pixel aspect ratio numerator */
|
||||||
|
ogg_uint32_t aspect_denominator; /**< pixel aspect ratio denominator */
|
||||||
|
theora_colorspace colorspace; /**< colorspace */
|
||||||
|
int target_bitrate; /**< nominal bitrate in bits per second */
|
||||||
|
int quality; /**< Nominal quality setting, 0-63 */
|
||||||
|
int quick_p; /**< Quick encode/decode */
|
||||||
|
|
||||||
|
/* decode only */
|
||||||
|
unsigned char version_major;
|
||||||
|
unsigned char version_minor;
|
||||||
|
unsigned char version_subminor;
|
||||||
|
|
||||||
|
void *codec_setup;
|
||||||
|
|
||||||
|
/* encode only */
|
||||||
|
int dropframes_p;
|
||||||
|
int keyframe_auto_p;
|
||||||
|
ogg_uint32_t keyframe_frequency;
|
||||||
|
ogg_uint32_t keyframe_frequency_force; /* also used for decode init to
|
||||||
|
get granpos shift correct */
|
||||||
|
ogg_uint32_t keyframe_data_target_bitrate;
|
||||||
|
ogg_int32_t keyframe_auto_threshold;
|
||||||
|
ogg_uint32_t keyframe_mindistance;
|
||||||
|
ogg_int32_t noise_sensitivity;
|
||||||
|
ogg_int32_t sharpness;
|
||||||
|
|
||||||
|
theora_pixelformat pixelformat; /**< chroma subsampling mode to expect */
|
||||||
|
|
||||||
|
} theora_info;
|
||||||
|
|
||||||
|
/** Codec internal state and context.
|
||||||
|
*/
|
||||||
|
typedef struct{
|
||||||
|
theora_info *i;
|
||||||
|
ogg_int64_t granulepos;
|
||||||
|
|
||||||
|
void *internal_encode;
|
||||||
|
void *internal_decode;
|
||||||
|
|
||||||
|
} theora_state;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comment header metadata.
|
||||||
|
*
|
||||||
|
* This structure holds the in-stream metadata corresponding to
|
||||||
|
* the 'comment' header packet.
|
||||||
|
*
|
||||||
|
* Meta data is stored as a series of (tag, value) pairs, in
|
||||||
|
* length-encoded string vectors. The first occurence of the
|
||||||
|
* '=' character delimits the tag and value. A particular tag
|
||||||
|
* may occur more than once. The character set encoding for
|
||||||
|
* the strings is always UTF-8, but the tag names are limited
|
||||||
|
* to case-insensitive ASCII. See the spec for details.
|
||||||
|
*
|
||||||
|
* In filling in this structure, theora_decode_header() will
|
||||||
|
* null-terminate the user_comment strings for safety. However,
|
||||||
|
* the bitstream format itself treats them as 8-bit clean,
|
||||||
|
* and so the length array should be treated as authoritative
|
||||||
|
* for their length.
|
||||||
|
*/
|
||||||
|
typedef struct theora_comment{
|
||||||
|
char **user_comments; /**< An array of comment string vectors */
|
||||||
|
int *comment_lengths; /**< An array of corresponding string vector lengths in bytes */
|
||||||
|
int comments; /**< The total number of comment string vectors */
|
||||||
|
char *vendor; /**< The vendor string identifying the encoder, null terminated */
|
||||||
|
|
||||||
|
} theora_comment;
|
||||||
|
|
||||||
|
|
||||||
|
/**\name theora_control() codes */
|
||||||
|
/* \anchor decctlcodes_old
|
||||||
|
* These are the available request codes for theora_control()
|
||||||
|
* when called with a decoder instance.
|
||||||
|
* By convention decoder control codes are odd, to distinguish
|
||||||
|
* them from \ref encctlcodes_old "encoder control codes" which
|
||||||
|
* are even.
|
||||||
|
*
|
||||||
|
* Note that since the 1.0 release, both the legacy and the final
|
||||||
|
* implementation accept all the same control codes, but only the
|
||||||
|
* final API declares the newer codes.
|
||||||
|
*
|
||||||
|
* Keep any experimental or vendor-specific values above \c 0x8000.*/
|
||||||
|
|
||||||
|
/*@{*/
|
||||||
|
|
||||||
|
/**Get the maximum post-processing level.
|
||||||
|
* The decoder supports a post-processing filter that can improve
|
||||||
|
* the appearance of the decoded images. This returns the highest
|
||||||
|
* level setting for this post-processor, corresponding to maximum
|
||||||
|
* improvement and computational expense.
|
||||||
|
*/
|
||||||
|
#define TH_DECCTL_GET_PPLEVEL_MAX (1)
|
||||||
|
|
||||||
|
/**Set the post-processing level.
|
||||||
|
* Sets the level of post-processing to use when decoding the
|
||||||
|
* compressed stream. This must be a value between zero (off)
|
||||||
|
* and the maximum returned by TH_DECCTL_GET_PPLEVEL_MAX.
|
||||||
|
*/
|
||||||
|
#define TH_DECCTL_SET_PPLEVEL (3)
|
||||||
|
|
||||||
|
/**Sets the maximum distance between key frames.
|
||||||
|
* This can be changed during an encode, but will be bounded by
|
||||||
|
* <tt>1<<th_info#keyframe_granule_shift</tt>.
|
||||||
|
* If it is set before encoding begins, th_info#keyframe_granule_shift will
|
||||||
|
* be enlarged appropriately.
|
||||||
|
*
|
||||||
|
* \param[in] buf <tt>ogg_uint32_t</tt>: The maximum distance between key
|
||||||
|
* frames.
|
||||||
|
* \param[out] buf <tt>ogg_uint32_t</tt>: The actual maximum distance set.
|
||||||
|
* \retval OC_FAULT \a theora_state or \a buf is <tt>NULL</tt>.
|
||||||
|
* \retval OC_EINVAL \a buf_sz is not <tt>sizeof(ogg_uint32_t)</tt>.
|
||||||
|
* \retval OC_IMPL Not supported by this implementation.*/
|
||||||
|
#define TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE (4)
|
||||||
|
|
||||||
|
/**Set the granule position.
|
||||||
|
* Call this after a seek, to update the internal granulepos
|
||||||
|
* in the decoder, to insure that subsequent frames are marked
|
||||||
|
* properly. If you track timestamps yourself and do not use
|
||||||
|
* the granule postion returned by the decoder, then you do
|
||||||
|
* not need to use this control.
|
||||||
|
*/
|
||||||
|
#define TH_DECCTL_SET_GRANPOS (5)
|
||||||
|
|
||||||
|
/**\anchor encctlcodes_old */
|
||||||
|
|
||||||
|
/**Sets the quantization parameters to use.
|
||||||
|
* The parameters are copied, not stored by reference, so they can be freed
|
||||||
|
* after this call.
|
||||||
|
* <tt>NULL</tt> may be specified to revert to the default parameters.
|
||||||
|
*
|
||||||
|
* \param[in] buf #th_quant_info
|
||||||
|
* \retval OC_FAULT \a theora_state is <tt>NULL</tt>.
|
||||||
|
* \retval OC_EINVAL Encoding has already begun, the quantization parameters
|
||||||
|
* are not acceptable to this version of the encoder,
|
||||||
|
* \a buf is <tt>NULL</tt> and \a buf_sz is not zero,
|
||||||
|
* or \a buf is non-<tt>NULL</tt> and \a buf_sz is
|
||||||
|
* not <tt>sizeof(#th_quant_info)</tt>.
|
||||||
|
* \retval OC_IMPL Not supported by this implementation.*/
|
||||||
|
#define TH_ENCCTL_SET_QUANT_PARAMS (2)
|
||||||
|
|
||||||
|
/**Disables any encoder features that would prevent lossless transcoding back
|
||||||
|
* to VP3.
|
||||||
|
* This primarily means disabling block-level QI values and not using 4MV mode
|
||||||
|
* when any of the luma blocks in a macro block are not coded.
|
||||||
|
* It also includes using the VP3 quantization tables and Huffman codes; if you
|
||||||
|
* set them explicitly after calling this function, the resulting stream will
|
||||||
|
* not be VP3-compatible.
|
||||||
|
* If you enable VP3-compatibility when encoding 4:2:2 or 4:4:4 source
|
||||||
|
* material, or when using a picture region smaller than the full frame (e.g.
|
||||||
|
* a non-multiple-of-16 width or height), then non-VP3 bitstream features will
|
||||||
|
* still be disabled, but the stream will still not be VP3-compatible, as VP3
|
||||||
|
* was not capable of encoding such formats.
|
||||||
|
* If you call this after encoding has already begun, then the quantization
|
||||||
|
* tables and codebooks cannot be changed, but the frame-level features will
|
||||||
|
* be enabled or disabled as requested.
|
||||||
|
*
|
||||||
|
* \param[in] buf <tt>int</tt>: a non-zero value to enable VP3 compatibility,
|
||||||
|
* or 0 to disable it (the default).
|
||||||
|
* \param[out] buf <tt>int</tt>: 1 if all bitstream features required for
|
||||||
|
* VP3-compatibility could be set, and 0 otherwise.
|
||||||
|
* The latter will be returned if the pixel format is not
|
||||||
|
* 4:2:0, the picture region is smaller than the full frame,
|
||||||
|
* or if encoding has begun, preventing the quantization
|
||||||
|
* tables and codebooks from being set.
|
||||||
|
* \retval OC_FAULT \a theora_state or \a buf is <tt>NULL</tt>.
|
||||||
|
* \retval OC_EINVAL \a buf_sz is not <tt>sizeof(int)</tt>.
|
||||||
|
* \retval OC_IMPL Not supported by this implementation.*/
|
||||||
|
#define TH_ENCCTL_SET_VP3_COMPATIBLE (10)
|
||||||
|
|
||||||
|
/**Gets the maximum speed level.
|
||||||
|
* Higher speed levels favor quicker encoding over better quality per bit.
|
||||||
|
* Depending on the encoding mode, and the internal algorithms used, quality
|
||||||
|
* may actually improve, but in this case bitrate will also likely increase.
|
||||||
|
* In any case, overall rate/distortion performance will probably decrease.
|
||||||
|
* The maximum value, and the meaning of each value, may change depending on
|
||||||
|
* the current encoding mode (VBR vs. CQI, etc.).
|
||||||
|
*
|
||||||
|
* \param[out] buf int: The maximum encoding speed level.
|
||||||
|
* \retval OC_FAULT \a theora_state or \a buf is <tt>NULL</tt>.
|
||||||
|
* \retval OC_EINVAL \a buf_sz is not <tt>sizeof(int)</tt>.
|
||||||
|
* \retval OC_IMPL Not supported by this implementation in the current
|
||||||
|
* encoding mode.*/
|
||||||
|
#define TH_ENCCTL_GET_SPLEVEL_MAX (12)
|
||||||
|
|
||||||
|
/**Sets the speed level.
|
||||||
|
* By default a speed value of 1 is used.
|
||||||
|
*
|
||||||
|
* \param[in] buf int: The new encoding speed level.
|
||||||
|
* 0 is slowest, larger values use less CPU.
|
||||||
|
* \retval OC_FAULT \a theora_state or \a buf is <tt>NULL</tt>.
|
||||||
|
* \retval OC_EINVAL \a buf_sz is not <tt>sizeof(int)</tt>, or the
|
||||||
|
* encoding speed level is out of bounds.
|
||||||
|
* The maximum encoding speed level may be
|
||||||
|
* implementation- and encoding mode-specific, and can be
|
||||||
|
* obtained via #TH_ENCCTL_GET_SPLEVEL_MAX.
|
||||||
|
* \retval OC_IMPL Not supported by this implementation in the current
|
||||||
|
* encoding mode.*/
|
||||||
|
#define TH_ENCCTL_SET_SPLEVEL (14)
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
#define OC_FAULT -1 /**< General failure */
|
||||||
|
#define OC_EINVAL -10 /**< Library encountered invalid internal data */
|
||||||
|
#define OC_DISABLED -11 /**< Requested action is disabled */
|
||||||
|
#define OC_BADHEADER -20 /**< Header packet was corrupt/invalid */
|
||||||
|
#define OC_NOTFORMAT -21 /**< Packet is not a theora packet */
|
||||||
|
#define OC_VERSION -22 /**< Bitstream version is not handled */
|
||||||
|
#define OC_IMPL -23 /**< Feature or action not implemented */
|
||||||
|
#define OC_BADPACKET -24 /**< Packet is corrupt */
|
||||||
|
#define OC_NEWPACKET -25 /**< Packet is an (ignorable) unhandled extension */
|
||||||
|
#define OC_DUPFRAME 1 /**< Packet is a dropped frame */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a human-readable string to identify the encoder vendor and version.
|
||||||
|
* \returns A version string.
|
||||||
|
*/
|
||||||
|
extern const char *theora_version_string(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a 32-bit version number.
|
||||||
|
* This number is composed of a 16-bit major version, 8-bit minor version
|
||||||
|
* and 8 bit sub-version, composed as follows:
|
||||||
|
<pre>
|
||||||
|
(VERSION_MAJOR<<16) + (VERSION_MINOR<<8) + (VERSION_SUB)
|
||||||
|
</pre>
|
||||||
|
* \returns The version number.
|
||||||
|
*/
|
||||||
|
extern ogg_uint32_t theora_version_number(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the theora encoder.
|
||||||
|
* \param th The theora_state handle to initialize for encoding.
|
||||||
|
* \param ti A theora_info struct filled with the desired encoding parameters.
|
||||||
|
* \retval 0 Success
|
||||||
|
*/
|
||||||
|
extern int theora_encode_init(theora_state *th, theora_info *ti);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a YUV buffer to the theora encoder.
|
||||||
|
* \param t A theora_state handle previously initialized for encoding.
|
||||||
|
* \param yuv A buffer of YUV data to encode. Note that both the yuv_buffer
|
||||||
|
* struct and the luma/chroma buffers within should be allocated by
|
||||||
|
* the user.
|
||||||
|
* \retval OC_EINVAL Encoder is not ready, or is finished.
|
||||||
|
* \retval -1 The size of the given frame differs from those previously input
|
||||||
|
* \retval 0 Success
|
||||||
|
*/
|
||||||
|
extern int theora_encode_YUVin(theora_state *t, yuv_buffer *yuv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request the next packet of encoded video.
|
||||||
|
* The encoded data is placed in a user-provided ogg_packet structure.
|
||||||
|
* \param t A theora_state handle previously initialized for encoding.
|
||||||
|
* \param last_p whether this is the last packet the encoder should produce.
|
||||||
|
* \param op An ogg_packet structure to fill. libtheora will set all
|
||||||
|
* elements of this structure, including a pointer to encoded
|
||||||
|
* data. The memory for the encoded data is owned by libtheora.
|
||||||
|
* \retval 0 No internal storage exists OR no packet is ready
|
||||||
|
* \retval -1 The encoding process has completed
|
||||||
|
* \retval 1 Success
|
||||||
|
*/
|
||||||
|
extern int theora_encode_packetout( theora_state *t, int last_p,
|
||||||
|
ogg_packet *op);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request a packet containing the initial header.
|
||||||
|
* A pointer to the header data is placed in a user-provided ogg_packet
|
||||||
|
* structure.
|
||||||
|
* \param t A theora_state handle previously initialized for encoding.
|
||||||
|
* \param op An ogg_packet structure to fill. libtheora will set all
|
||||||
|
* elements of this structure, including a pointer to the header
|
||||||
|
* data. The memory for the header data is owned by libtheora.
|
||||||
|
* \retval 0 Success
|
||||||
|
*/
|
||||||
|
extern int theora_encode_header(theora_state *t, ogg_packet *op);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request a comment header packet from provided metadata.
|
||||||
|
* A pointer to the comment data is placed in a user-provided ogg_packet
|
||||||
|
* structure.
|
||||||
|
* \param tc A theora_comment structure filled with the desired metadata
|
||||||
|
* \param op An ogg_packet structure to fill. libtheora will set all
|
||||||
|
* elements of this structure, including a pointer to the encoded
|
||||||
|
* comment data. The memory for the comment data is owned by
|
||||||
|
* the application, and must be freed by it using _ogg_free().
|
||||||
|
* On some systems (such as Windows when using dynamic linking), this
|
||||||
|
* may mean the free is executed in a different module from the
|
||||||
|
* malloc, which will crash; there is no way to free this memory on
|
||||||
|
* such systems.
|
||||||
|
* \retval 0 Success
|
||||||
|
*/
|
||||||
|
extern int theora_encode_comment(theora_comment *tc, ogg_packet *op);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request a packet containing the codebook tables for the stream.
|
||||||
|
* A pointer to the codebook data is placed in a user-provided ogg_packet
|
||||||
|
* structure.
|
||||||
|
* \param t A theora_state handle previously initialized for encoding.
|
||||||
|
* \param op An ogg_packet structure to fill. libtheora will set all
|
||||||
|
* elements of this structure, including a pointer to the codebook
|
||||||
|
* data. The memory for the header data is owned by libtheora.
|
||||||
|
* \retval 0 Success
|
||||||
|
*/
|
||||||
|
extern int theora_encode_tables(theora_state *t, ogg_packet *op);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode an Ogg packet, with the expectation that the packet contains
|
||||||
|
* an initial header, comment data or codebook tables.
|
||||||
|
*
|
||||||
|
* \param ci A theora_info structure to fill. This must have been previously
|
||||||
|
* initialized with theora_info_init(). If \a op contains an initial
|
||||||
|
* header, theora_decode_header() will fill \a ci with the
|
||||||
|
* parsed header values. If \a op contains codebook tables,
|
||||||
|
* theora_decode_header() will parse these and attach an internal
|
||||||
|
* representation to \a ci->codec_setup.
|
||||||
|
* \param cc A theora_comment structure to fill. If \a op contains comment
|
||||||
|
* data, theora_decode_header() will fill \a cc with the parsed
|
||||||
|
* comments.
|
||||||
|
* \param op An ogg_packet structure which you expect contains an initial
|
||||||
|
* header, comment data or codebook tables.
|
||||||
|
*
|
||||||
|
* \retval OC_BADHEADER \a op is NULL; OR the first byte of \a op->packet
|
||||||
|
* has the signature of an initial packet, but op is
|
||||||
|
* not a b_o_s packet; OR this packet has the signature
|
||||||
|
* of an initial header packet, but an initial header
|
||||||
|
* packet has already been seen; OR this packet has the
|
||||||
|
* signature of a comment packet, but the initial header
|
||||||
|
* has not yet been seen; OR this packet has the signature
|
||||||
|
* of a comment packet, but contains invalid data; OR
|
||||||
|
* this packet has the signature of codebook tables,
|
||||||
|
* but the initial header or comments have not yet
|
||||||
|
* been seen; OR this packet has the signature of codebook
|
||||||
|
* tables, but contains invalid data;
|
||||||
|
* OR the stream being decoded has a compatible version
|
||||||
|
* but this packet does not have the signature of a
|
||||||
|
* theora initial header, comments, or codebook packet
|
||||||
|
* \retval OC_VERSION The packet data of \a op is an initial header with
|
||||||
|
* a version which is incompatible with this version of
|
||||||
|
* libtheora.
|
||||||
|
* \retval OC_NEWPACKET the stream being decoded has an incompatible (future)
|
||||||
|
* version and contains an unknown signature.
|
||||||
|
* \retval 0 Success
|
||||||
|
*
|
||||||
|
* \note The normal usage is that theora_decode_header() be called on the
|
||||||
|
* first three packets of a theora logical bitstream in succession.
|
||||||
|
*/
|
||||||
|
extern int theora_decode_header(theora_info *ci, theora_comment *cc,
|
||||||
|
ogg_packet *op);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a theora_state handle for decoding.
|
||||||
|
* \param th The theora_state handle to initialize.
|
||||||
|
* \param c A theora_info struct filled with the desired decoding parameters.
|
||||||
|
* This is of course usually obtained from a previous call to
|
||||||
|
* theora_decode_header().
|
||||||
|
* \retval 0 Success
|
||||||
|
*/
|
||||||
|
extern int theora_decode_init(theora_state *th, theora_info *c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input a packet containing encoded data into the theora decoder.
|
||||||
|
* \param th A theora_state handle previously initialized for decoding.
|
||||||
|
* \param op An ogg_packet containing encoded theora data.
|
||||||
|
* \retval 0 Success
|
||||||
|
* \retval OC_BADPACKET \a op does not contain encoded video data
|
||||||
|
*/
|
||||||
|
extern int theora_decode_packetin(theora_state *th,ogg_packet *op);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output the next available frame of decoded YUV data.
|
||||||
|
* \param th A theora_state handle previously initialized for decoding.
|
||||||
|
* \param yuv A yuv_buffer in which libtheora should place the decoded data.
|
||||||
|
* Note that the buffer struct itself is allocated by the user, but
|
||||||
|
* that the luma and chroma pointers will be filled in by the
|
||||||
|
* library. Also note that these luma and chroma regions should be
|
||||||
|
* considered read-only by the user.
|
||||||
|
* \retval 0 Success
|
||||||
|
*/
|
||||||
|
extern int theora_decode_YUVout(theora_state *th,yuv_buffer *yuv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report whether a theora packet is a header or not
|
||||||
|
* This function does no verification beyond checking the header
|
||||||
|
* flag bit so it should not be used for bitstream identification;
|
||||||
|
* use theora_decode_header() for that.
|
||||||
|
*
|
||||||
|
* \param op An ogg_packet containing encoded theora data.
|
||||||
|
* \retval 1 The packet is a header packet
|
||||||
|
* \retval 0 The packet is not a header packet (and so contains frame data)
|
||||||
|
*
|
||||||
|
* Thus function was added in the 1.0alpha4 release.
|
||||||
|
*/
|
||||||
|
extern int theora_packet_isheader(ogg_packet *op);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report whether a theora packet is a keyframe or not
|
||||||
|
*
|
||||||
|
* \param op An ogg_packet containing encoded theora data.
|
||||||
|
* \retval 1 The packet contains a keyframe image
|
||||||
|
* \retval 0 The packet is contains an interframe delta
|
||||||
|
* \retval -1 The packet is not an image data packet at all
|
||||||
|
*
|
||||||
|
* Thus function was added in the 1.0alpha4 release.
|
||||||
|
*/
|
||||||
|
extern int theora_packet_iskeyframe(ogg_packet *op);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report the granulepos shift radix
|
||||||
|
*
|
||||||
|
* When embedded in Ogg, Theora uses a two-part granulepos,
|
||||||
|
* splitting the 64-bit field into two pieces. The more-significant
|
||||||
|
* section represents the frame count at the last keyframe,
|
||||||
|
* and the less-significant section represents the count of
|
||||||
|
* frames since the last keyframe. In this way the overall
|
||||||
|
* field is still non-decreasing with time, but usefully encodes
|
||||||
|
* a pointer to the last keyframe, which is necessary for
|
||||||
|
* correctly restarting decode after a seek.
|
||||||
|
*
|
||||||
|
* This function reports the number of bits used to represent
|
||||||
|
* the distance to the last keyframe, and thus how the granulepos
|
||||||
|
* field must be shifted or masked to obtain the two parts.
|
||||||
|
*
|
||||||
|
* Since libtheora returns compressed data in an ogg_packet
|
||||||
|
* structure, this may be generally useful even if the Theora
|
||||||
|
* packets are not being used in an Ogg container.
|
||||||
|
*
|
||||||
|
* \param ti A previously initialized theora_info struct
|
||||||
|
* \returns The bit shift dividing the two granulepos fields
|
||||||
|
*
|
||||||
|
* This function was added in the 1.0alpha5 release.
|
||||||
|
*/
|
||||||
|
int theora_granule_shift(theora_info *ti);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a granulepos to an absolute frame index, starting at 0.
|
||||||
|
* The granulepos is interpreted in the context of a given theora_state handle.
|
||||||
|
*
|
||||||
|
* Note that while the granulepos encodes the frame count (i.e. starting
|
||||||
|
* from 1) this call returns the frame index, starting from zero. Thus
|
||||||
|
* One can calculate the presentation time by multiplying the index by
|
||||||
|
* the rate.
|
||||||
|
*
|
||||||
|
* \param th A previously initialized theora_state handle (encode or decode)
|
||||||
|
* \param granulepos The granulepos to convert.
|
||||||
|
* \returns The frame index corresponding to \a granulepos.
|
||||||
|
* \retval -1 The given granulepos is undefined (i.e. negative)
|
||||||
|
*
|
||||||
|
* Thus function was added in the 1.0alpha4 release.
|
||||||
|
*/
|
||||||
|
extern ogg_int64_t theora_granule_frame(theora_state *th,ogg_int64_t granulepos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a granulepos to absolute time in seconds. The granulepos is
|
||||||
|
* interpreted in the context of a given theora_state handle, and gives
|
||||||
|
* the end time of a frame's presentation as used in Ogg mux ordering.
|
||||||
|
*
|
||||||
|
* \param th A previously initialized theora_state handle (encode or decode)
|
||||||
|
* \param granulepos The granulepos to convert.
|
||||||
|
* \returns The absolute time in seconds corresponding to \a granulepos.
|
||||||
|
* This is the "end time" for the frame, or the latest time it should
|
||||||
|
* be displayed.
|
||||||
|
* It is not the presentation time.
|
||||||
|
* \retval -1. The given granulepos is undefined (i.e. negative).
|
||||||
|
*/
|
||||||
|
extern double theora_granule_time(theora_state *th,ogg_int64_t granulepos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a theora_info structure. All values within the given theora_info
|
||||||
|
* structure are initialized, and space is allocated within libtheora for
|
||||||
|
* internal codec setup data.
|
||||||
|
* \param c A theora_info struct to initialize.
|
||||||
|
*/
|
||||||
|
extern void theora_info_init(theora_info *c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear a theora_info structure. All values within the given theora_info
|
||||||
|
* structure are cleared, and associated internal codec setup data is freed.
|
||||||
|
* \param c A theora_info struct to initialize.
|
||||||
|
*/
|
||||||
|
extern void theora_info_clear(theora_info *c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free all internal data associated with a theora_state handle.
|
||||||
|
* \param t A theora_state handle.
|
||||||
|
*/
|
||||||
|
extern void theora_clear(theora_state *t);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize an allocated theora_comment structure
|
||||||
|
* \param tc An allocated theora_comment structure
|
||||||
|
**/
|
||||||
|
extern void theora_comment_init(theora_comment *tc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a comment to an initialized theora_comment structure
|
||||||
|
* \param tc A previously initialized theora comment structure
|
||||||
|
* \param comment A null-terminated string encoding the comment in the form
|
||||||
|
* "TAG=the value"
|
||||||
|
*
|
||||||
|
* Neither theora_comment_add() nor theora_comment_add_tag() support
|
||||||
|
* comments containing null values, although the bitstream format
|
||||||
|
* supports this. To add such comments you will need to manipulate
|
||||||
|
* the theora_comment structure directly.
|
||||||
|
**/
|
||||||
|
|
||||||
|
extern void theora_comment_add(theora_comment *tc, char *comment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a comment to an initialized theora_comment structure.
|
||||||
|
* \param tc A previously initialized theora comment structure
|
||||||
|
* \param tag A null-terminated string containing the tag
|
||||||
|
* associated with the comment.
|
||||||
|
* \param value The corresponding value as a null-terminated string
|
||||||
|
*
|
||||||
|
* Neither theora_comment_add() nor theora_comment_add_tag() support
|
||||||
|
* comments containing null values, although the bitstream format
|
||||||
|
* supports this. To add such comments you will need to manipulate
|
||||||
|
* the theora_comment structure directly.
|
||||||
|
**/
|
||||||
|
extern void theora_comment_add_tag(theora_comment *tc,
|
||||||
|
char *tag, char *value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up a comment value by tag.
|
||||||
|
* \param tc Tn initialized theora_comment structure
|
||||||
|
* \param tag The tag to look up
|
||||||
|
* \param count The instance of the tag. The same tag can appear multiple
|
||||||
|
* times, each with a distinct and ordered value, so an index
|
||||||
|
* is required to retrieve them all.
|
||||||
|
* \returns A pointer to the queried tag's value
|
||||||
|
* \retval NULL No matching tag is found
|
||||||
|
*
|
||||||
|
* \note Use theora_comment_query_count() to get the legal range for the
|
||||||
|
* count parameter.
|
||||||
|
**/
|
||||||
|
|
||||||
|
extern char *theora_comment_query(theora_comment *tc, char *tag, int count);
|
||||||
|
|
||||||
|
/** Look up the number of instances of a tag.
|
||||||
|
* \param tc An initialized theora_comment structure
|
||||||
|
* \param tag The tag to look up
|
||||||
|
* \returns The number on instances of a particular tag.
|
||||||
|
*
|
||||||
|
* Call this first when querying for a specific tag and then interate
|
||||||
|
* over the number of instances with separate calls to
|
||||||
|
* theora_comment_query() to retrieve all instances in order.
|
||||||
|
**/
|
||||||
|
extern int theora_comment_query_count(theora_comment *tc, char *tag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear an allocated theora_comment struct so that it can be freed.
|
||||||
|
* \param tc An allocated theora_comment structure.
|
||||||
|
**/
|
||||||
|
extern void theora_comment_clear(theora_comment *tc);
|
||||||
|
|
||||||
|
/**Encoder control function.
|
||||||
|
* This is used to provide advanced control the encoding process.
|
||||||
|
* \param th A #theora_state handle.
|
||||||
|
* \param req The control code to process.
|
||||||
|
* See \ref encctlcodes_old "the list of available
|
||||||
|
* control codes" for details.
|
||||||
|
* \param buf The parameters for this control code.
|
||||||
|
* \param buf_sz The size of the parameter buffer.*/
|
||||||
|
extern int theora_control(theora_state *th,int req,void *buf,size_t buf_sz);
|
||||||
|
|
||||||
|
/* @} */ /* end oldfuncs doxygen group */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif /* _O_THEORA_H_ */
|
||||||
|
|
@ -0,0 +1,333 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id: theora.h,v 1.8 2004/03/15 22:17:32 derf Exp $
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
/**\file
|
||||||
|
* The <tt>libtheoradec</tt> C decoding API.*/
|
||||||
|
|
||||||
|
#if !defined(_O_THEORA_THEORADEC_H_)
|
||||||
|
# define _O_THEORA_THEORADEC_H_ (1)
|
||||||
|
# include <stddef.h>
|
||||||
|
# include <ogg/ogg.h>
|
||||||
|
# include "codec.h"
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**\name th_decode_ctl() codes
|
||||||
|
* \anchor decctlcodes
|
||||||
|
* These are the available request codes for th_decode_ctl().
|
||||||
|
* By convention, these are odd, to distinguish them from the
|
||||||
|
* \ref encctlcodes "encoder control codes".
|
||||||
|
* Keep any experimental or vendor-specific values above \c 0x8000.*/
|
||||||
|
/*@{*/
|
||||||
|
/**Gets the maximum post-processing level.
|
||||||
|
* The decoder supports a post-processing filter that can improve
|
||||||
|
* the appearance of the decoded images. This returns the highest
|
||||||
|
* level setting for this post-processor, corresponding to maximum
|
||||||
|
* improvement and computational expense.
|
||||||
|
*
|
||||||
|
* \param[out] _buf int: The maximum post-processing level.
|
||||||
|
* \retval TH_EFAULT \a _dec_ctx or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(int)</tt>.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation.*/
|
||||||
|
#define TH_DECCTL_GET_PPLEVEL_MAX (1)
|
||||||
|
/**Sets the post-processing level.
|
||||||
|
* By default, post-processing is disabled.
|
||||||
|
*
|
||||||
|
* Sets the level of post-processing to use when decoding the
|
||||||
|
* compressed stream. This must be a value between zero (off)
|
||||||
|
* and the maximum returned by TH_DECCTL_GET_PPLEVEL_MAX.
|
||||||
|
*
|
||||||
|
* \param[in] _buf int: The new post-processing level.
|
||||||
|
* 0 to disable; larger values use more CPU.
|
||||||
|
* \retval TH_EFAULT \a _dec_ctx or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(int)</tt>, or the
|
||||||
|
* post-processing level is out of bounds.
|
||||||
|
* The maximum post-processing level may be
|
||||||
|
* implementation-specific, and can be obtained via
|
||||||
|
* #TH_DECCTL_GET_PPLEVEL_MAX.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation.*/
|
||||||
|
#define TH_DECCTL_SET_PPLEVEL (3)
|
||||||
|
/**Sets the granule position.
|
||||||
|
* Call this after a seek, before decoding the first frame, to ensure that the
|
||||||
|
* proper granule position is returned for all subsequent frames.
|
||||||
|
* If you track timestamps yourself and do not use the granule position
|
||||||
|
* returned by the decoder, then you need not call this function.
|
||||||
|
*
|
||||||
|
* \param[in] _buf <tt>ogg_int64_t</tt>: The granule position of the next
|
||||||
|
* frame.
|
||||||
|
* \retval TH_EFAULT \a _dec_ctx or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(ogg_int64_t)</tt>, or the
|
||||||
|
* granule position is negative.*/
|
||||||
|
#define TH_DECCTL_SET_GRANPOS (5)
|
||||||
|
/**Sets the striped decode callback function.
|
||||||
|
* If set, this function will be called as each piece of a frame is fully
|
||||||
|
* decoded in th_decode_packetin().
|
||||||
|
* You can pass in a #th_stripe_callback with
|
||||||
|
* th_stripe_callback#stripe_decoded set to <tt>NULL</tt> to disable the
|
||||||
|
* callbacks at any point.
|
||||||
|
* Enabling striped decode does not prevent you from calling
|
||||||
|
* th_decode_ycbcr_out() after the frame is fully decoded.
|
||||||
|
*
|
||||||
|
* \param[in] _buf #th_stripe_callback: The callback parameters.
|
||||||
|
* \retval TH_EFAULT \a _dec_ctx or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL \a _buf_sz is not
|
||||||
|
* <tt>sizeof(th_stripe_callback)</tt>.*/
|
||||||
|
#define TH_DECCTL_SET_STRIPE_CB (7)
|
||||||
|
|
||||||
|
/**Sets the macroblock display mode. Set to 0 to disable displaying
|
||||||
|
* macroblocks.*/
|
||||||
|
#define TH_DECCTL_SET_TELEMETRY_MBMODE (9)
|
||||||
|
/**Sets the motion vector display mode. Set to 0 to disable displaying motion
|
||||||
|
* vectors.*/
|
||||||
|
#define TH_DECCTL_SET_TELEMETRY_MV (11)
|
||||||
|
/**Sets the adaptive quantization display mode. Set to 0 to disable displaying
|
||||||
|
* adaptive quantization. */
|
||||||
|
#define TH_DECCTL_SET_TELEMETRY_QI (13)
|
||||||
|
/**Sets the bitstream breakdown visualization mode. Set to 0 to disable
|
||||||
|
* displaying bitstream breakdown.*/
|
||||||
|
#define TH_DECCTL_SET_TELEMETRY_BITS (15)
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**A callback function for striped decode.
|
||||||
|
* This is a function pointer to an application-provided function that will be
|
||||||
|
* called each time a section of the image is fully decoded in
|
||||||
|
* th_decode_packetin().
|
||||||
|
* This allows the application to process the section immediately, while it is
|
||||||
|
* still in cache.
|
||||||
|
* Note that the frame is decoded bottom to top, so \a _yfrag0 will steadily
|
||||||
|
* decrease with each call until it reaches 0, at which point the full frame
|
||||||
|
* is decoded.
|
||||||
|
* The number of fragment rows made available in each call depends on the pixel
|
||||||
|
* format and the number of post-processing filters enabled, and may not even
|
||||||
|
* be constant for the entire frame.
|
||||||
|
* If a non-<tt>NULL</tt> \a _granpos pointer is passed to
|
||||||
|
* th_decode_packetin(), the granule position for the frame will be stored
|
||||||
|
* in it before the first callback is made.
|
||||||
|
* If an entire frame is dropped (a 0-byte packet), then no callbacks will be
|
||||||
|
* made at all for that frame.
|
||||||
|
* \param _ctx An application-provided context pointer.
|
||||||
|
* \param _buf The image buffer for the decoded frame.
|
||||||
|
* \param _yfrag0 The Y coordinate of the first row of 8x8 fragments
|
||||||
|
* decoded.
|
||||||
|
* Multiply this by 8 to obtain the pixel row number in the
|
||||||
|
* luma plane.
|
||||||
|
* If the chroma planes are subsampled in the Y direction,
|
||||||
|
* this will always be divisible by two.
|
||||||
|
* \param _yfrag_end The Y coordinate of the first row of 8x8 fragments past
|
||||||
|
* the newly decoded section.
|
||||||
|
* If the chroma planes are subsampled in the Y direction,
|
||||||
|
* this will always be divisible by two.
|
||||||
|
* I.e., this section contains fragment rows
|
||||||
|
* <tt>\a _yfrag0 ...\a _yfrag_end -1</tt>.*/
|
||||||
|
typedef void (*th_stripe_decoded_func)(void *_ctx,th_ycbcr_buffer _buf,
|
||||||
|
int _yfrag0,int _yfrag_end);
|
||||||
|
|
||||||
|
/**The striped decode callback data to pass to #TH_DECCTL_SET_STRIPE_CB.*/
|
||||||
|
typedef struct{
|
||||||
|
/**An application-provided context pointer.
|
||||||
|
* This will be passed back verbatim to the application.*/
|
||||||
|
void *ctx;
|
||||||
|
/**The callback function pointer.*/
|
||||||
|
th_stripe_decoded_func stripe_decoded;
|
||||||
|
}th_stripe_callback;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**\name Decoder state
|
||||||
|
The following data structures are opaque, and their contents are not
|
||||||
|
publicly defined by this API.
|
||||||
|
Referring to their internals directly is unsupported, and may break without
|
||||||
|
warning.*/
|
||||||
|
/*@{*/
|
||||||
|
/**The decoder context.*/
|
||||||
|
typedef struct th_dec_ctx th_dec_ctx;
|
||||||
|
/**Setup information.
|
||||||
|
This contains auxiliary information (Huffman tables and quantization
|
||||||
|
parameters) decoded from the setup header by th_decode_headerin() to be
|
||||||
|
passed to th_decode_alloc().
|
||||||
|
It can be re-used to initialize any number of decoders, and can be freed
|
||||||
|
via th_setup_free() at any time.*/
|
||||||
|
typedef struct th_setup_info th_setup_info;
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**\defgroup decfuncs Functions for Decoding*/
|
||||||
|
/*@{*/
|
||||||
|
/**\name Functions for decoding
|
||||||
|
* You must link to <tt>libtheoradec</tt> if you use any of the
|
||||||
|
* functions in this section.
|
||||||
|
*
|
||||||
|
* The functions are listed in the order they are used in a typical decode.
|
||||||
|
* The basic steps are:
|
||||||
|
* - Parse the header packets by repeatedly calling th_decode_headerin().
|
||||||
|
* - Allocate a #th_dec_ctx handle with th_decode_alloc().
|
||||||
|
* - Call th_setup_free() to free any memory used for codec setup
|
||||||
|
* information.
|
||||||
|
* - Perform any additional decoder configuration with th_decode_ctl().
|
||||||
|
* - For each video data packet:
|
||||||
|
* - Submit the packet to the decoder via th_decode_packetin().
|
||||||
|
* - Retrieve the uncompressed video data via th_decode_ycbcr_out().
|
||||||
|
* - Call th_decode_free() to release all decoder memory.*/
|
||||||
|
/*@{*/
|
||||||
|
/**Decodes the header packets of a Theora stream.
|
||||||
|
* This should be called on the initial packets of the stream, in succession,
|
||||||
|
* until it returns <tt>0</tt>, indicating that all headers have been
|
||||||
|
* processed, or an error is encountered.
|
||||||
|
* At least three header packets are required, and additional optional header
|
||||||
|
* packets may follow.
|
||||||
|
* This can be used on the first packet of any logical stream to determine if
|
||||||
|
* that stream is a Theora stream.
|
||||||
|
* \param _info A #th_info structure to fill in.
|
||||||
|
* This must have been previously initialized with
|
||||||
|
* th_info_init().
|
||||||
|
* The application may immediately begin using the contents of
|
||||||
|
* this structure after the first header is decoded, though it
|
||||||
|
* must continue to be passed in on all subsequent calls.
|
||||||
|
* \param _tc A #th_comment structure to fill in.
|
||||||
|
* The application may immediately begin using the contents of
|
||||||
|
* this structure after the second header is decoded, though it
|
||||||
|
* must continue to be passed in on all subsequent calls.
|
||||||
|
* \param _setup Returns a pointer to additional, private setup information
|
||||||
|
* needed by the decoder.
|
||||||
|
* The contents of this pointer must be initialized to
|
||||||
|
* <tt>NULL</tt> on the first call, and the returned value must
|
||||||
|
* continue to be passed in on all subsequent calls.
|
||||||
|
* \param _op An <tt>ogg_packet</tt> structure which contains one of the
|
||||||
|
* initial packets of an Ogg logical stream.
|
||||||
|
* \return A positive value indicates that a Theora header was successfully
|
||||||
|
* processed.
|
||||||
|
* \retval 0 The first video data packet was encountered after all
|
||||||
|
* required header packets were parsed.
|
||||||
|
* The packet just passed in on this call should be saved
|
||||||
|
* and fed to th_decode_packetin() to begin decoding
|
||||||
|
* video data.
|
||||||
|
* \retval TH_EFAULT One of \a _info, \a _tc, or \a _setup was
|
||||||
|
* <tt>NULL</tt>.
|
||||||
|
* \retval TH_EBADHEADER \a _op was <tt>NULL</tt>, the packet was not the next
|
||||||
|
* header packet in the expected sequence, or the format
|
||||||
|
* of the header data was invalid.
|
||||||
|
* \retval TH_EVERSION The packet data was a Theora info header, but for a
|
||||||
|
* bitstream version not decodable with this version of
|
||||||
|
* <tt>libtheoradec</tt>.
|
||||||
|
* \retval TH_ENOTFORMAT The packet was not a Theora header.
|
||||||
|
*/
|
||||||
|
extern int th_decode_headerin(th_info *_info,th_comment *_tc,
|
||||||
|
th_setup_info **_setup,ogg_packet *_op);
|
||||||
|
/**Allocates a decoder instance.
|
||||||
|
*
|
||||||
|
* <b>Security Warning:</b> The Theora format supports very large frame sizes,
|
||||||
|
* potentially even larger than the address space of a 32-bit machine, and
|
||||||
|
* creating a decoder context allocates the space for several frames of data.
|
||||||
|
* If the allocation fails here, your program will crash, possibly at some
|
||||||
|
* future point because the OS kernel returned a valid memory range and will
|
||||||
|
* only fail when it tries to map the pages in it the first time they are
|
||||||
|
* used.
|
||||||
|
* Even if it succeeds, you may experience a denial of service if the frame
|
||||||
|
* size is large enough to cause excessive paging.
|
||||||
|
* If you are integrating libtheora in a larger application where such things
|
||||||
|
* are undesirable, it is highly recommended that you check the frame size in
|
||||||
|
* \a _info before calling this function and refuse to decode streams where it
|
||||||
|
* is larger than some reasonable maximum.
|
||||||
|
* libtheora will not check this for you, because there may be machines that
|
||||||
|
* can handle such streams and applications that wish to.
|
||||||
|
* \param _info A #th_info struct filled via th_decode_headerin().
|
||||||
|
* \param _setup A #th_setup_info handle returned via
|
||||||
|
* th_decode_headerin().
|
||||||
|
* \return The initialized #th_dec_ctx handle.
|
||||||
|
* \retval NULL If the decoding parameters were invalid.*/
|
||||||
|
extern th_dec_ctx *th_decode_alloc(const th_info *_info,
|
||||||
|
const th_setup_info *_setup);
|
||||||
|
/**Releases all storage used for the decoder setup information.
|
||||||
|
* This should be called after you no longer want to create any decoders for
|
||||||
|
* a stream whose headers you have parsed with th_decode_headerin().
|
||||||
|
* \param _setup The setup information to free.
|
||||||
|
* This can safely be <tt>NULL</tt>.*/
|
||||||
|
extern void th_setup_free(th_setup_info *_setup);
|
||||||
|
/**Decoder control function.
|
||||||
|
* This is used to provide advanced control of the decoding process.
|
||||||
|
* \param _dec A #th_dec_ctx handle.
|
||||||
|
* \param _req The control code to process.
|
||||||
|
* See \ref decctlcodes "the list of available control codes"
|
||||||
|
* for details.
|
||||||
|
* \param _buf The parameters for this control code.
|
||||||
|
* \param _buf_sz The size of the parameter buffer.
|
||||||
|
* \return Possible return values depend on the control code used.
|
||||||
|
* See \ref decctlcodes "the list of control codes" for
|
||||||
|
* specific values. Generally 0 indicates success.*/
|
||||||
|
extern int th_decode_ctl(th_dec_ctx *_dec,int _req,void *_buf,
|
||||||
|
size_t _buf_sz);
|
||||||
|
/**Submits a packet containing encoded video data to the decoder.
|
||||||
|
* \param _dec A #th_dec_ctx handle.
|
||||||
|
* \param _op An <tt>ogg_packet</tt> containing encoded video data.
|
||||||
|
* \param _granpos Returns the granule position of the decoded packet.
|
||||||
|
* If non-<tt>NULL</tt>, the granule position for this specific
|
||||||
|
* packet is stored in this location.
|
||||||
|
* This is computed incrementally from previously decoded
|
||||||
|
* packets.
|
||||||
|
* After a seek, the correct granule position must be set via
|
||||||
|
* #TH_DECCTL_SET_GRANPOS for this to work properly.
|
||||||
|
* \retval 0 Success.
|
||||||
|
* A new decoded frame can be retrieved by calling
|
||||||
|
* th_decode_ycbcr_out().
|
||||||
|
* \retval TH_DUPFRAME The packet represented a dropped frame (either a
|
||||||
|
* 0-byte frame or an INTER frame with no coded blocks).
|
||||||
|
* The player can skip the call to th_decode_ycbcr_out(),
|
||||||
|
* as the contents of the decoded frame buffer have not
|
||||||
|
* changed.
|
||||||
|
* \retval TH_EFAULT \a _dec or \a _op was <tt>NULL</tt>.
|
||||||
|
* \retval TH_EBADPACKET \a _op does not contain encoded video data.
|
||||||
|
* \retval TH_EIMPL The video data uses bitstream features which this
|
||||||
|
* library does not support.*/
|
||||||
|
extern int th_decode_packetin(th_dec_ctx *_dec,const ogg_packet *_op,
|
||||||
|
ogg_int64_t *_granpos);
|
||||||
|
/**Outputs the next available frame of decoded Y'CbCr data.
|
||||||
|
* If a striped decode callback has been set with #TH_DECCTL_SET_STRIPE_CB,
|
||||||
|
* then the application does not need to call this function.
|
||||||
|
* \param _dec A #th_dec_ctx handle.
|
||||||
|
* \param _ycbcr A video buffer structure to fill in.
|
||||||
|
* <tt>libtheoradec</tt> will fill in all the members of this
|
||||||
|
* structure, including the pointers to the uncompressed video
|
||||||
|
* data.
|
||||||
|
* The memory for this video data is owned by
|
||||||
|
* <tt>libtheoradec</tt>.
|
||||||
|
* It may be freed or overwritten without notification when
|
||||||
|
* subsequent frames are decoded.
|
||||||
|
* \retval 0 Success
|
||||||
|
* \retval TH_EFAULT \a _dec or \a _ycbcr was <tt>NULL</tt>.
|
||||||
|
*/
|
||||||
|
extern int th_decode_ycbcr_out(th_dec_ctx *_dec,
|
||||||
|
th_ycbcr_buffer _ycbcr);
|
||||||
|
/**Frees an allocated decoder instance.
|
||||||
|
* \param _dec A #th_dec_ctx handle.*/
|
||||||
|
extern void th_decode_free(th_dec_ctx *_dec);
|
||||||
|
/*@}*/
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,548 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id: theora.h,v 1.8 2004/03/15 22:17:32 derf Exp $
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
/**\file
|
||||||
|
* The <tt>libtheoraenc</tt> C encoding API.*/
|
||||||
|
|
||||||
|
#if !defined(_O_THEORA_THEORAENC_H_)
|
||||||
|
# define _O_THEORA_THEORAENC_H_ (1)
|
||||||
|
# include <stddef.h>
|
||||||
|
# include <ogg/ogg.h>
|
||||||
|
# include "codec.h"
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**\name th_encode_ctl() codes
|
||||||
|
* \anchor encctlcodes
|
||||||
|
* These are the available request codes for th_encode_ctl().
|
||||||
|
* By convention, these are even, to distinguish them from the
|
||||||
|
* \ref decctlcodes "decoder control codes".
|
||||||
|
* Keep any experimental or vendor-specific values above \c 0x8000.*/
|
||||||
|
/*@{*/
|
||||||
|
/**Sets the Huffman tables to use.
|
||||||
|
* The tables are copied, not stored by reference, so they can be freed after
|
||||||
|
* this call.
|
||||||
|
* <tt>NULL</tt> may be specified to revert to the default tables.
|
||||||
|
*
|
||||||
|
* \param[in] _buf <tt>#th_huff_code[#TH_NHUFFMAN_TABLES][#TH_NDCT_TOKENS]</tt>
|
||||||
|
* \retval TH_EFAULT \a _enc is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL Encoding has already begun or one or more of the given
|
||||||
|
* tables is not full or prefix-free, \a _buf is
|
||||||
|
* <tt>NULL</tt> and \a _buf_sz is not zero, or \a _buf is
|
||||||
|
* non-<tt>NULL</tt> and \a _buf_sz is not
|
||||||
|
* <tt>sizeof(#th_huff_code)*#TH_NHUFFMAN_TABLES*#TH_NDCT_TOKENS</tt>.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation.*/
|
||||||
|
#define TH_ENCCTL_SET_HUFFMAN_CODES (0)
|
||||||
|
/**Sets the quantization parameters to use.
|
||||||
|
* The parameters are copied, not stored by reference, so they can be freed
|
||||||
|
* after this call.
|
||||||
|
* <tt>NULL</tt> may be specified to revert to the default parameters.
|
||||||
|
*
|
||||||
|
* \param[in] _buf #th_quant_info
|
||||||
|
* \retval TH_EFAULT \a _enc is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL Encoding has already begun, \a _buf is
|
||||||
|
* <tt>NULL</tt> and \a _buf_sz is not zero,
|
||||||
|
* or \a _buf is non-<tt>NULL</tt> and
|
||||||
|
* \a _buf_sz is not <tt>sizeof(#th_quant_info)</tt>.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation.*/
|
||||||
|
#define TH_ENCCTL_SET_QUANT_PARAMS (2)
|
||||||
|
/**Sets the maximum distance between key frames.
|
||||||
|
* This can be changed during an encode, but will be bounded by
|
||||||
|
* <tt>1<<th_info#keyframe_granule_shift</tt>.
|
||||||
|
* If it is set before encoding begins, th_info#keyframe_granule_shift will
|
||||||
|
* be enlarged appropriately.
|
||||||
|
*
|
||||||
|
* \param[in] _buf <tt>ogg_uint32_t</tt>: The maximum distance between key
|
||||||
|
* frames.
|
||||||
|
* \param[out] _buf <tt>ogg_uint32_t</tt>: The actual maximum distance set.
|
||||||
|
* \retval TH_EFAULT \a _enc or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(ogg_uint32_t)</tt>.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation.*/
|
||||||
|
#define TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE (4)
|
||||||
|
/**Disables any encoder features that would prevent lossless transcoding back
|
||||||
|
* to VP3.
|
||||||
|
* This primarily means disabling block-adaptive quantization and always coding
|
||||||
|
* all four luma blocks in a macro block when 4MV is used.
|
||||||
|
* It also includes using the VP3 quantization tables and Huffman codes; if you
|
||||||
|
* set them explicitly after calling this function, the resulting stream will
|
||||||
|
* not be VP3-compatible.
|
||||||
|
* If you enable VP3-compatibility when encoding 4:2:2 or 4:4:4 source
|
||||||
|
* material, or when using a picture region smaller than the full frame (e.g.
|
||||||
|
* a non-multiple-of-16 width or height), then non-VP3 bitstream features will
|
||||||
|
* still be disabled, but the stream will still not be VP3-compatible, as VP3
|
||||||
|
* was not capable of encoding such formats.
|
||||||
|
* If you call this after encoding has already begun, then the quantization
|
||||||
|
* tables and codebooks cannot be changed, but the frame-level features will
|
||||||
|
* be enabled or disabled as requested.
|
||||||
|
*
|
||||||
|
* \param[in] _buf <tt>int</tt>: a non-zero value to enable VP3 compatibility,
|
||||||
|
* or 0 to disable it (the default).
|
||||||
|
* \param[out] _buf <tt>int</tt>: 1 if all bitstream features required for
|
||||||
|
* VP3-compatibility could be set, and 0 otherwise.
|
||||||
|
* The latter will be returned if the pixel format is not
|
||||||
|
* 4:2:0, the picture region is smaller than the full frame,
|
||||||
|
* or if encoding has begun, preventing the quantization
|
||||||
|
* tables and codebooks from being set.
|
||||||
|
* \retval TH_EFAULT \a _enc or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(int)</tt>.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation.*/
|
||||||
|
#define TH_ENCCTL_SET_VP3_COMPATIBLE (10)
|
||||||
|
/**Gets the maximum speed level.
|
||||||
|
* Higher speed levels favor quicker encoding over better quality per bit.
|
||||||
|
* Depending on the encoding mode, and the internal algorithms used, quality
|
||||||
|
* may actually improve, but in this case bitrate will also likely increase.
|
||||||
|
* In any case, overall rate/distortion performance will probably decrease.
|
||||||
|
* The maximum value, and the meaning of each value, may change depending on
|
||||||
|
* the current encoding mode (VBR vs. constant quality, etc.).
|
||||||
|
*
|
||||||
|
* \param[out] _buf <tt>int</tt>: The maximum encoding speed level.
|
||||||
|
* \retval TH_EFAULT \a _enc or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(int)</tt>.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation in the current
|
||||||
|
* encoding mode.*/
|
||||||
|
#define TH_ENCCTL_GET_SPLEVEL_MAX (12)
|
||||||
|
/**Sets the speed level.
|
||||||
|
* The current speed level may be retrieved using #TH_ENCCTL_GET_SPLEVEL.
|
||||||
|
*
|
||||||
|
* \param[in] _buf <tt>int</tt>: The new encoding speed level.
|
||||||
|
* 0 is slowest, larger values use less CPU.
|
||||||
|
* \retval TH_EFAULT \a _enc or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(int)</tt>, or the
|
||||||
|
* encoding speed level is out of bounds.
|
||||||
|
* The maximum encoding speed level may be
|
||||||
|
* implementation- and encoding mode-specific, and can be
|
||||||
|
* obtained via #TH_ENCCTL_GET_SPLEVEL_MAX.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation in the current
|
||||||
|
* encoding mode.*/
|
||||||
|
#define TH_ENCCTL_SET_SPLEVEL (14)
|
||||||
|
/**Gets the current speed level.
|
||||||
|
* The default speed level may vary according to encoder implementation, but if
|
||||||
|
* this control code is not supported (it returns #TH_EIMPL), the default may
|
||||||
|
* be assumed to be the slowest available speed (0).
|
||||||
|
* The maximum encoding speed level may be implementation- and encoding
|
||||||
|
* mode-specific, and can be obtained via #TH_ENCCTL_GET_SPLEVEL_MAX.
|
||||||
|
*
|
||||||
|
* \param[out] _buf <tt>int</tt>: The current encoding speed level.
|
||||||
|
* 0 is slowest, larger values use less CPU.
|
||||||
|
* \retval TH_EFAULT \a _enc or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(int)</tt>.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation in the current
|
||||||
|
* encoding mode.*/
|
||||||
|
#define TH_ENCCTL_GET_SPLEVEL (16)
|
||||||
|
/**Sets the number of duplicates of the next frame to produce.
|
||||||
|
* Although libtheora can encode duplicate frames very cheaply, it costs some
|
||||||
|
* amount of CPU to detect them, and a run of duplicates cannot span a
|
||||||
|
* keyframe boundary.
|
||||||
|
* This control code tells the encoder to produce the specified number of extra
|
||||||
|
* duplicates of the next frame.
|
||||||
|
* This allows the encoder to make smarter keyframe placement decisions and
|
||||||
|
* rate control decisions, and reduces CPU usage as well, when compared to
|
||||||
|
* just submitting the same frame for encoding multiple times.
|
||||||
|
* This setting only applies to the next frame submitted for encoding.
|
||||||
|
* You MUST call th_encode_packetout() repeatedly until it returns 0, or the
|
||||||
|
* extra duplicate frames will be lost.
|
||||||
|
*
|
||||||
|
* \param[in] _buf <tt>int</tt>: The number of duplicates to produce.
|
||||||
|
* If this is negative or zero, no duplicates will be produced.
|
||||||
|
* \retval TH_EFAULT \a _enc or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(int)</tt>, or the
|
||||||
|
* number of duplicates is greater than or equal to the
|
||||||
|
* maximum keyframe interval.
|
||||||
|
* In the latter case, NO duplicate frames will be produced.
|
||||||
|
* You must ensure that the maximum keyframe interval is set
|
||||||
|
* larger than the maximum number of duplicates you will
|
||||||
|
* ever wish to insert prior to encoding.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation in the current
|
||||||
|
* encoding mode.*/
|
||||||
|
#define TH_ENCCTL_SET_DUP_COUNT (18)
|
||||||
|
/**Modifies the default bitrate management behavior.
|
||||||
|
* Use to allow or disallow frame dropping, and to enable or disable capping
|
||||||
|
* bit reservoir overflows and underflows.
|
||||||
|
* See \ref encctlcodes "the list of available flags".
|
||||||
|
* The flags are set by default to
|
||||||
|
* <tt>#TH_RATECTL_DROP_FRAMES|#TH_RATECTL_CAP_OVERFLOW</tt>.
|
||||||
|
*
|
||||||
|
* \param[in] _buf <tt>int</tt>: Any combination of
|
||||||
|
* \ref ratectlflags "the available flags":
|
||||||
|
* - #TH_RATECTL_DROP_FRAMES: Enable frame dropping.
|
||||||
|
* - #TH_RATECTL_CAP_OVERFLOW: Don't bank excess bits for later
|
||||||
|
* use.
|
||||||
|
* - #TH_RATECTL_CAP_UNDERFLOW: Don't try to make up shortfalls
|
||||||
|
* later.
|
||||||
|
* \retval TH_EFAULT \a _enc or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(int)</tt> or rate control
|
||||||
|
* is not enabled.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation in the current
|
||||||
|
* encoding mode.*/
|
||||||
|
#define TH_ENCCTL_SET_RATE_FLAGS (20)
|
||||||
|
/**Sets the size of the bitrate management bit reservoir as a function
|
||||||
|
* of number of frames.
|
||||||
|
* The reservoir size affects how quickly bitrate management reacts to
|
||||||
|
* instantaneous changes in the video complexity.
|
||||||
|
* Larger reservoirs react more slowly, and provide better overall quality, but
|
||||||
|
* require more buffering by a client, adding more latency to live streams.
|
||||||
|
* By default, libtheora sets the reservoir to the maximum distance between
|
||||||
|
* keyframes, subject to a minimum and maximum limit.
|
||||||
|
* This call may be used to increase or decrease the reservoir, increasing or
|
||||||
|
* decreasing the allowed temporary variance in bitrate.
|
||||||
|
* An implementation may impose some limits on the size of a reservoir it can
|
||||||
|
* handle, in which case the actual reservoir size may not be exactly what was
|
||||||
|
* requested.
|
||||||
|
* The actual value set will be returned.
|
||||||
|
*
|
||||||
|
* \param[in] _buf <tt>int</tt>: Requested size of the reservoir measured in
|
||||||
|
* frames.
|
||||||
|
* \param[out] _buf <tt>int</tt>: The actual size of the reservoir set.
|
||||||
|
* \retval TH_EFAULT \a _enc or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(int)</tt>, or rate control
|
||||||
|
* is not enabled. The buffer has an implementation
|
||||||
|
* defined minimum and maximum size and the value in _buf
|
||||||
|
* will be adjusted to match the actual value set.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation in the current
|
||||||
|
* encoding mode.*/
|
||||||
|
#define TH_ENCCTL_SET_RATE_BUFFER (22)
|
||||||
|
/**Enable pass 1 of two-pass encoding mode and retrieve the first pass metrics.
|
||||||
|
* Pass 1 mode must be enabled before the first frame is encoded, and a target
|
||||||
|
* bitrate must have already been specified to the encoder.
|
||||||
|
* Although this does not have to be the exact rate that will be used in the
|
||||||
|
* second pass, closer values may produce better results.
|
||||||
|
* The first call returns the size of the two-pass header data, along with some
|
||||||
|
* placeholder content, and sets the encoder into pass 1 mode implicitly.
|
||||||
|
* This call sets the encoder to pass 1 mode implicitly.
|
||||||
|
* Then, a subsequent call must be made after each call to
|
||||||
|
* th_encode_ycbcr_in() to retrieve the metrics for that frame.
|
||||||
|
* An additional, final call must be made to retrieve the summary data,
|
||||||
|
* containing such information as the total number of frames, etc.
|
||||||
|
* This must be stored in place of the placeholder data that was returned
|
||||||
|
* in the first call, before the frame metrics data.
|
||||||
|
* All of this data must be presented back to the encoder during pass 2 using
|
||||||
|
* #TH_ENCCTL_2PASS_IN.
|
||||||
|
*
|
||||||
|
* \param[out] <tt>char *</tt>_buf: Returns a pointer to internal storage
|
||||||
|
* containing the two pass metrics data.
|
||||||
|
* This storage is only valid until the next call, or until the
|
||||||
|
* encoder context is freed, and must be copied by the
|
||||||
|
* application.
|
||||||
|
* \retval >=0 The number of bytes of metric data available in the
|
||||||
|
* returned buffer.
|
||||||
|
* \retval TH_EFAULT \a _enc or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL \a _buf_sz is not <tt>sizeof(char *)</tt>, no target
|
||||||
|
* bitrate has been set, or the first call was made after
|
||||||
|
* the first frame was submitted for encoding.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation.*/
|
||||||
|
#define TH_ENCCTL_2PASS_OUT (24)
|
||||||
|
/**Submits two-pass encoding metric data collected the first encoding pass to
|
||||||
|
* the second pass.
|
||||||
|
* The first call must be made before the first frame is encoded, and a target
|
||||||
|
* bitrate must have already been specified to the encoder.
|
||||||
|
* It sets the encoder to pass 2 mode implicitly; this cannot be disabled.
|
||||||
|
* The encoder may require reading data from some or all of the frames in
|
||||||
|
* advance, depending on, e.g., the reservoir size used in the second pass.
|
||||||
|
* You must call this function repeatedly before each frame to provide data
|
||||||
|
* until either a) it fails to consume all of the data presented or b) all of
|
||||||
|
* the pass 1 data has been consumed.
|
||||||
|
* In the first case, you must save the remaining data to be presented after
|
||||||
|
* the next frame.
|
||||||
|
* You can call this function with a NULL argument to get an upper bound on
|
||||||
|
* the number of bytes that will be required before the next frame.
|
||||||
|
*
|
||||||
|
* When pass 2 is first enabled, the default bit reservoir is set to the entire
|
||||||
|
* file; this gives maximum flexibility but can lead to very high peak rates.
|
||||||
|
* You can subsequently set it to another value with #TH_ENCCTL_SET_RATE_BUFFER
|
||||||
|
* (e.g., to set it to the keyframe interval for non-live streaming), however,
|
||||||
|
* you may then need to provide more data before the next frame.
|
||||||
|
*
|
||||||
|
* \param[in] _buf <tt>char[]</tt>: A buffer containing the data returned by
|
||||||
|
* #TH_ENCCTL_2PASS_OUT in pass 1.
|
||||||
|
* You may pass <tt>NULL</tt> for \a _buf to return an upper
|
||||||
|
* bound on the number of additional bytes needed before the
|
||||||
|
* next frame.
|
||||||
|
* The summary data returned at the end of pass 1 must be at
|
||||||
|
* the head of the buffer on the first call with a
|
||||||
|
* non-<tt>NULL</tt> \a _buf, and the placeholder data
|
||||||
|
* returned at the start of pass 1 should be omitted.
|
||||||
|
* After each call you should advance this buffer by the number
|
||||||
|
* of bytes consumed.
|
||||||
|
* \retval >0 The number of bytes of metric data required/consumed.
|
||||||
|
* \retval 0 No more data is required before the next frame.
|
||||||
|
* \retval TH_EFAULT \a _enc is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL No target bitrate has been set, or the first call was
|
||||||
|
* made after the first frame was submitted for
|
||||||
|
* encoding.
|
||||||
|
* \retval TH_ENOTFORMAT The data did not appear to be pass 1 from a compatible
|
||||||
|
* implementation of this library.
|
||||||
|
* \retval TH_EBADHEADER The data was invalid; this may be returned when
|
||||||
|
* attempting to read an aborted pass 1 file that still
|
||||||
|
* has the placeholder data in place of the summary
|
||||||
|
* data.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation.*/
|
||||||
|
#define TH_ENCCTL_2PASS_IN (26)
|
||||||
|
/**Sets the current encoding quality.
|
||||||
|
* This is only valid so long as no bitrate has been specified, either through
|
||||||
|
* the #th_info struct used to initialize the encoder or through
|
||||||
|
* #TH_ENCCTL_SET_BITRATE (this restriction may be relaxed in a future
|
||||||
|
* version).
|
||||||
|
* If it is set before the headers are emitted, the target quality encoded in
|
||||||
|
* them will be updated.
|
||||||
|
*
|
||||||
|
* \param[in] _buf <tt>int</tt>: The new target quality, in the range 0...63,
|
||||||
|
* inclusive.
|
||||||
|
* \retval 0 Success.
|
||||||
|
* \retval TH_EFAULT \a _enc or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL A target bitrate has already been specified, or the
|
||||||
|
* quality index was not in the range 0...63.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation.*/
|
||||||
|
#define TH_ENCCTL_SET_QUALITY (28)
|
||||||
|
/**Sets the current encoding bitrate.
|
||||||
|
* Once a bitrate is set, the encoder must use a rate-controlled mode for all
|
||||||
|
* future frames (this restriction may be relaxed in a future version).
|
||||||
|
* If it is set before the headers are emitted, the target bitrate encoded in
|
||||||
|
* them will be updated.
|
||||||
|
* Due to the buffer delay, the exact bitrate of each section of the encode is
|
||||||
|
* not guaranteed.
|
||||||
|
* The encoder may have already used more bits than allowed for the frames it
|
||||||
|
* has encoded, expecting to make them up in future frames, or it may have
|
||||||
|
* used fewer, holding the excess in reserve.
|
||||||
|
* The exact transition between the two bitrates is not well-defined by this
|
||||||
|
* API, but may be affected by flags set with #TH_ENCCTL_SET_RATE_FLAGS.
|
||||||
|
* After a number of frames equal to the buffer delay, one may expect further
|
||||||
|
* output to average at the target bitrate.
|
||||||
|
*
|
||||||
|
* \param[in] _buf <tt>long</tt>: The new target bitrate, in bits per second.
|
||||||
|
* \retval 0 Success.
|
||||||
|
* \retval TH_EFAULT \a _enc or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL The target bitrate was not positive.
|
||||||
|
* A future version of this library may allow passing 0
|
||||||
|
* to disabled rate-controlled mode and return to a
|
||||||
|
* quality-based mode, in which case this function will
|
||||||
|
* not return an error for that value.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation.*/
|
||||||
|
#define TH_ENCCTL_SET_BITRATE (30)
|
||||||
|
/**Sets the configuration to be compatible with that from the given setup
|
||||||
|
* header.
|
||||||
|
* This sets the Huffman codebooks and quantization parameters to match those
|
||||||
|
* found in the given setup header.
|
||||||
|
* This guarantees that packets encoded by this encoder will be decodable using
|
||||||
|
* a decoder configured with the passed-in setup header.
|
||||||
|
* It does <em>not</em> guarantee that th_encode_flushheader() will produce a
|
||||||
|
* bit-identical setup header, only that they will be compatible.
|
||||||
|
* If you need a bit-identical setup header, then use the one you passed into
|
||||||
|
* this command, and not the one returned by th_encode_flushheader().
|
||||||
|
*
|
||||||
|
* This also does <em>not</em> enable or disable VP3 compatibility; that is not
|
||||||
|
* signaled in the setup header (or anywhere else in the encoded stream), and
|
||||||
|
* is controlled independently by the #TH_ENCCTL_SET_VP3_COMPATIBLE function.
|
||||||
|
* If you wish to enable VP3 compatibility mode <em>and</em> want the codebooks
|
||||||
|
* and quantization parameters to match the given setup header, you should
|
||||||
|
* enable VP3 compatibility before invoking this command, otherwise the
|
||||||
|
* codebooks and quantization parameters will be reset to the VP3 defaults.
|
||||||
|
*
|
||||||
|
* The current encoder does not support Huffman codebooks which do not contain
|
||||||
|
* codewords for all 32 tokens.
|
||||||
|
* Such codebooks are legal, according to the specification, but cannot be
|
||||||
|
* configured with this function.
|
||||||
|
*
|
||||||
|
* \param[in] _buf <tt>unsigned char[]</tt>: The encoded setup header to copy
|
||||||
|
* the configuration from.
|
||||||
|
* This should be the original,
|
||||||
|
* undecoded setup header packet,
|
||||||
|
* and <em>not</em> a #th_setup_info
|
||||||
|
* structure filled in by
|
||||||
|
* th_decode_headerin().
|
||||||
|
* \retval TH_EFAULT \a _enc or \a _buf is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL Encoding has already begun, so the codebooks and
|
||||||
|
* quantization parameters cannot be changed, or the
|
||||||
|
* data in the setup header was not supported by this
|
||||||
|
* encoder.
|
||||||
|
* \retval TH_EBADHEADER \a _buf did not contain a valid setup header packet.
|
||||||
|
* \retval TH_ENOTFORMAT \a _buf did not contain a Theora header at all.
|
||||||
|
* \retval TH_EIMPL Not supported by this implementation.*/
|
||||||
|
#define TH_ENCCTL_SET_COMPAT_CONFIG (32)
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
/**\name TH_ENCCTL_SET_RATE_FLAGS flags
|
||||||
|
* \anchor ratectlflags
|
||||||
|
* These are the flags available for use with #TH_ENCCTL_SET_RATE_FLAGS.*/
|
||||||
|
/*@{*/
|
||||||
|
/**Drop frames to keep within bitrate buffer constraints.
|
||||||
|
* This can have a severe impact on quality, but is the only way to ensure that
|
||||||
|
* bitrate targets are met at low rates during sudden bursts of activity.
|
||||||
|
* It is enabled by default.*/
|
||||||
|
#define TH_RATECTL_DROP_FRAMES (0x1)
|
||||||
|
/**Ignore bitrate buffer overflows.
|
||||||
|
* If the encoder uses so few bits that the reservoir of available bits
|
||||||
|
* overflows, ignore the excess.
|
||||||
|
* The encoder will not try to use these extra bits in future frames.
|
||||||
|
* At high rates this may cause the result to be undersized, but allows a
|
||||||
|
* client to play the stream using a finite buffer; it should normally be
|
||||||
|
* enabled, which is the default.*/
|
||||||
|
#define TH_RATECTL_CAP_OVERFLOW (0x2)
|
||||||
|
/**Ignore bitrate buffer underflows.
|
||||||
|
* If the encoder uses so many bits that the reservoir of available bits
|
||||||
|
* underflows, ignore the deficit.
|
||||||
|
* The encoder will not try to make up these extra bits in future frames.
|
||||||
|
* At low rates this may cause the result to be oversized; it should normally
|
||||||
|
* be disabled, which is the default.*/
|
||||||
|
#define TH_RATECTL_CAP_UNDERFLOW (0x4)
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**The quantization parameters used by VP3.*/
|
||||||
|
extern const th_quant_info TH_VP31_QUANT_INFO;
|
||||||
|
|
||||||
|
/**The Huffman tables used by VP3.*/
|
||||||
|
extern const th_huff_code
|
||||||
|
TH_VP31_HUFF_CODES[TH_NHUFFMAN_TABLES][TH_NDCT_TOKENS];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**\name Encoder state
|
||||||
|
The following data structure is opaque, and its contents are not publicly
|
||||||
|
defined by this API.
|
||||||
|
Referring to its internals directly is unsupported, and may break without
|
||||||
|
warning.*/
|
||||||
|
/*@{*/
|
||||||
|
/**The encoder context.*/
|
||||||
|
typedef struct th_enc_ctx th_enc_ctx;
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**\defgroup encfuncs Functions for Encoding*/
|
||||||
|
/*@{*/
|
||||||
|
/**\name Functions for encoding
|
||||||
|
* You must link to <tt>libtheoraenc</tt> and <tt>libtheoradec</tt>
|
||||||
|
* if you use any of the functions in this section.
|
||||||
|
*
|
||||||
|
* The functions are listed in the order they are used in a typical encode.
|
||||||
|
* The basic steps are:
|
||||||
|
* - Fill in a #th_info structure with details on the format of the video you
|
||||||
|
* wish to encode.
|
||||||
|
* - Allocate a #th_enc_ctx handle with th_encode_alloc().
|
||||||
|
* - Perform any additional encoder configuration required with
|
||||||
|
* th_encode_ctl().
|
||||||
|
* - Repeatedly call th_encode_flushheader() to retrieve all the header
|
||||||
|
* packets.
|
||||||
|
* - For each uncompressed frame:
|
||||||
|
* - Submit the uncompressed frame via th_encode_ycbcr_in()
|
||||||
|
* - Repeatedly call th_encode_packetout() to retrieve any video
|
||||||
|
* data packets that are ready.
|
||||||
|
* - Call th_encode_free() to release all encoder memory.*/
|
||||||
|
/*@{*/
|
||||||
|
/**Allocates an encoder instance.
|
||||||
|
* \param _info A #th_info struct filled with the desired encoding parameters.
|
||||||
|
* \return The initialized #th_enc_ctx handle.
|
||||||
|
* \retval NULL If the encoding parameters were invalid.*/
|
||||||
|
extern th_enc_ctx *th_encode_alloc(const th_info *_info);
|
||||||
|
/**Encoder control function.
|
||||||
|
* This is used to provide advanced control the encoding process.
|
||||||
|
* \param _enc A #th_enc_ctx handle.
|
||||||
|
* \param _req The control code to process.
|
||||||
|
* See \ref encctlcodes "the list of available control codes"
|
||||||
|
* for details.
|
||||||
|
* \param _buf The parameters for this control code.
|
||||||
|
* \param _buf_sz The size of the parameter buffer.
|
||||||
|
* \return Possible return values depend on the control code used.
|
||||||
|
* See \ref encctlcodes "the list of control codes" for
|
||||||
|
* specific values. Generally 0 indicates success.*/
|
||||||
|
extern int th_encode_ctl(th_enc_ctx *_enc,int _req,void *_buf,size_t _buf_sz);
|
||||||
|
/**Outputs the next header packet.
|
||||||
|
* This should be called repeatedly after encoder initialization until it
|
||||||
|
* returns 0 in order to get all of the header packets, in order, before
|
||||||
|
* encoding actual video data.
|
||||||
|
* \param _enc A #th_enc_ctx handle.
|
||||||
|
* \param _comments The metadata to place in the comment header, when it is
|
||||||
|
* encoded.
|
||||||
|
* \param _op An <tt>ogg_packet</tt> structure to fill.
|
||||||
|
* All of the elements of this structure will be set,
|
||||||
|
* including a pointer to the header data.
|
||||||
|
* The memory for the header data is owned by
|
||||||
|
* <tt>libtheoraenc</tt>, and may be invalidated when the
|
||||||
|
* next encoder function is called.
|
||||||
|
* \return A positive value indicates that a header packet was successfully
|
||||||
|
* produced.
|
||||||
|
* \retval 0 No packet was produced, and no more header packets remain.
|
||||||
|
* \retval TH_EFAULT \a _enc, \a _comments, or \a _op was <tt>NULL</tt>.*/
|
||||||
|
extern int th_encode_flushheader(th_enc_ctx *_enc,
|
||||||
|
th_comment *_comments,ogg_packet *_op);
|
||||||
|
/**Submits an uncompressed frame to the encoder.
|
||||||
|
* \param _enc A #th_enc_ctx handle.
|
||||||
|
* \param _ycbcr A buffer of Y'CbCr data to encode.
|
||||||
|
* If the width and height of the buffer matches the frame size
|
||||||
|
* the encoder was initialized with, the encoder will only
|
||||||
|
* reference the portion inside the picture region.
|
||||||
|
* Any data outside this region will be ignored, and need not map
|
||||||
|
* to a valid address.
|
||||||
|
* Alternatively, you can pass a buffer equal to the size of the
|
||||||
|
* picture region, if this is less than the full frame size.
|
||||||
|
* When using subsampled chroma planes, odd picture sizes or odd
|
||||||
|
* picture offsets may require an unexpected chroma plane size,
|
||||||
|
* and their use is generally discouraged, as they will not be
|
||||||
|
* well-supported by players and other media frameworks.
|
||||||
|
* See Section 4.4 of
|
||||||
|
* <a href="http://www.theora.org/doc/Theora.pdf">the Theora
|
||||||
|
* specification</a> for details if you wish to use them anyway.
|
||||||
|
* \retval 0 Success.
|
||||||
|
* \retval TH_EFAULT \a _enc or \a _ycbcr is <tt>NULL</tt>.
|
||||||
|
* \retval TH_EINVAL The buffer size matches neither the frame size nor the
|
||||||
|
* picture size the encoder was initialized with, or
|
||||||
|
* encoding has already completed.*/
|
||||||
|
extern int th_encode_ycbcr_in(th_enc_ctx *_enc,th_ycbcr_buffer _ycbcr);
|
||||||
|
/**Retrieves encoded video data packets.
|
||||||
|
* This should be called repeatedly after each frame is submitted to flush any
|
||||||
|
* encoded packets, until it returns 0.
|
||||||
|
* The encoder will not buffer these packets as subsequent frames are
|
||||||
|
* compressed, so a failure to do so will result in lost video data.
|
||||||
|
* \note Currently the encoder operates in a one-frame-in, one-packet-out
|
||||||
|
* manner.
|
||||||
|
* However, this may be changed in the future.
|
||||||
|
* \param _enc A #th_enc_ctx handle.
|
||||||
|
* \param _last Set this flag to a non-zero value if no more uncompressed
|
||||||
|
* frames will be submitted.
|
||||||
|
* This ensures that a proper EOS flag is set on the last packet.
|
||||||
|
* \param _op An <tt>ogg_packet</tt> structure to fill.
|
||||||
|
* All of the elements of this structure will be set, including a
|
||||||
|
* pointer to the video data.
|
||||||
|
* The memory for the video data is owned by
|
||||||
|
* <tt>libtheoraenc</tt>, and may be invalidated when the next
|
||||||
|
* encoder function is called.
|
||||||
|
* \return A positive value indicates that a video data packet was successfully
|
||||||
|
* produced.
|
||||||
|
* \retval 0 No packet was produced, and no more encoded video data
|
||||||
|
* remains.
|
||||||
|
* \retval TH_EFAULT \a _enc or \a _op was <tt>NULL</tt>.*/
|
||||||
|
extern int th_encode_packetout(th_enc_ctx *_enc,int _last,ogg_packet *_op);
|
||||||
|
/**Frees an allocated encoder instance.
|
||||||
|
* \param _enc A #th_enc_ctx handle.*/
|
||||||
|
extern void th_encode_free(th_enc_ctx *_enc);
|
||||||
|
/*@}*/
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*This is more or less the same as strncasecmp, but that doesn't exist
|
||||||
|
everywhere, and this is a fairly trivial function, so we include it.
|
||||||
|
Note: We take advantage of the fact that we know _n is less than or equal to
|
||||||
|
the length of at least one of the strings.*/
|
||||||
|
static int oc_tagcompare(const char *_s1,const char *_s2,int _n){
|
||||||
|
int c;
|
||||||
|
for(c=0;c<_n;c++){
|
||||||
|
if(toupper(_s1[c])!=toupper(_s2[c]))return !0;
|
||||||
|
}
|
||||||
|
return _s1[c]!='=';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void th_info_init(th_info *_info){
|
||||||
|
memset(_info,0,sizeof(*_info));
|
||||||
|
_info->version_major=TH_VERSION_MAJOR;
|
||||||
|
_info->version_minor=TH_VERSION_MINOR;
|
||||||
|
_info->version_subminor=TH_VERSION_SUB;
|
||||||
|
_info->keyframe_granule_shift=6;
|
||||||
|
}
|
||||||
|
|
||||||
|
void th_info_clear(th_info *_info){
|
||||||
|
memset(_info,0,sizeof(*_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void th_comment_init(th_comment *_tc){
|
||||||
|
memset(_tc,0,sizeof(*_tc));
|
||||||
|
}
|
||||||
|
|
||||||
|
void th_comment_add(th_comment *_tc,const char *_comment){
|
||||||
|
char **user_comments;
|
||||||
|
int *comment_lengths;
|
||||||
|
int comment_len;
|
||||||
|
user_comments=_ogg_realloc(_tc->user_comments,
|
||||||
|
(_tc->comments+2)*sizeof(*_tc->user_comments));
|
||||||
|
if(user_comments==NULL)return;
|
||||||
|
_tc->user_comments=user_comments;
|
||||||
|
comment_lengths=_ogg_realloc(_tc->comment_lengths,
|
||||||
|
(_tc->comments+2)*sizeof(*_tc->comment_lengths));
|
||||||
|
if(comment_lengths==NULL)return;
|
||||||
|
_tc->comment_lengths=comment_lengths;
|
||||||
|
comment_len=strlen(_comment);
|
||||||
|
comment_lengths[_tc->comments]=comment_len;
|
||||||
|
user_comments[_tc->comments]=_ogg_malloc(comment_len+1);
|
||||||
|
if(user_comments[_tc->comments]==NULL)return;
|
||||||
|
memcpy(_tc->user_comments[_tc->comments],_comment,comment_len+1);
|
||||||
|
_tc->comments++;
|
||||||
|
_tc->user_comments[_tc->comments]=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void th_comment_add_tag(th_comment *_tc,const char *_tag,const char *_val){
|
||||||
|
char *comment;
|
||||||
|
int tag_len;
|
||||||
|
int val_len;
|
||||||
|
tag_len=strlen(_tag);
|
||||||
|
val_len=strlen(_val);
|
||||||
|
/*+2 for '=' and '\0'.*/
|
||||||
|
comment=_ogg_malloc(tag_len+val_len+2);
|
||||||
|
if(comment==NULL)return;
|
||||||
|
memcpy(comment,_tag,tag_len);
|
||||||
|
comment[tag_len]='=';
|
||||||
|
memcpy(comment+tag_len+1,_val,val_len+1);
|
||||||
|
th_comment_add(_tc,comment);
|
||||||
|
_ogg_free(comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *th_comment_query(th_comment *_tc,const char *_tag,int _count){
|
||||||
|
long i;
|
||||||
|
int found;
|
||||||
|
int tag_len;
|
||||||
|
tag_len=strlen(_tag);
|
||||||
|
found=0;
|
||||||
|
for(i=0;i<_tc->comments;i++){
|
||||||
|
if(!oc_tagcompare(_tc->user_comments[i],_tag,tag_len)){
|
||||||
|
/*We return a pointer to the data, not a copy.*/
|
||||||
|
if(_count==found++)return _tc->user_comments[i]+tag_len+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*Didn't find anything.*/
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int th_comment_query_count(th_comment *_tc,const char *_tag){
|
||||||
|
long i;
|
||||||
|
int tag_len;
|
||||||
|
int count;
|
||||||
|
tag_len=strlen(_tag);
|
||||||
|
count=0;
|
||||||
|
for(i=0;i<_tc->comments;i++){
|
||||||
|
if(!oc_tagcompare(_tc->user_comments[i],_tag,tag_len))count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void th_comment_clear(th_comment *_tc){
|
||||||
|
if(_tc!=NULL){
|
||||||
|
long i;
|
||||||
|
for(i=0;i<_tc->comments;i++)_ogg_free(_tc->user_comments[i]);
|
||||||
|
_ogg_free(_tc->user_comments);
|
||||||
|
_ogg_free(_tc->comment_lengths);
|
||||||
|
_ogg_free(_tc->vendor);
|
||||||
|
memset(_tc,0,sizeof(*_tc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,368 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
/*MMX acceleration of fragment reconstruction for motion compensation.
|
||||||
|
Originally written by Rudolf Marek.
|
||||||
|
Additional optimization by Nils Pipenbrinck.
|
||||||
|
Note: Loops are unrolled for best performance.
|
||||||
|
The iteration each instruction belongs to is marked in the comments as #i.*/
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "x86int.h"
|
||||||
|
|
||||||
|
#if defined(OC_X86_ASM)
|
||||||
|
|
||||||
|
/*Copies an 8x8 block of pixels from _src to _dst, assuming _ystride bytes
|
||||||
|
between rows.*/
|
||||||
|
# define OC_FRAG_COPY_MMX(_dst,_src,_ystride) \
|
||||||
|
do{ \
|
||||||
|
const unsigned char *src; \
|
||||||
|
unsigned char *dst; \
|
||||||
|
ptrdiff_t ystride3; \
|
||||||
|
src=(_src); \
|
||||||
|
dst=(_dst); \
|
||||||
|
__asm__ __volatile__( \
|
||||||
|
/*src+0*ystride*/ \
|
||||||
|
"movq (%[src]),%%mm0\n\t" \
|
||||||
|
/*src+1*ystride*/ \
|
||||||
|
"movq (%[src],%[ystride]),%%mm1\n\t" \
|
||||||
|
/*ystride3=ystride*3*/ \
|
||||||
|
"lea (%[ystride],%[ystride],2),%[ystride3]\n\t" \
|
||||||
|
/*src+2*ystride*/ \
|
||||||
|
"movq (%[src],%[ystride],2),%%mm2\n\t" \
|
||||||
|
/*src+3*ystride*/ \
|
||||||
|
"movq (%[src],%[ystride3]),%%mm3\n\t" \
|
||||||
|
/*dst+0*ystride*/ \
|
||||||
|
"movq %%mm0,(%[dst])\n\t" \
|
||||||
|
/*dst+1*ystride*/ \
|
||||||
|
"movq %%mm1,(%[dst],%[ystride])\n\t" \
|
||||||
|
/*Pointer to next 4.*/ \
|
||||||
|
"lea (%[src],%[ystride],4),%[src]\n\t" \
|
||||||
|
/*dst+2*ystride*/ \
|
||||||
|
"movq %%mm2,(%[dst],%[ystride],2)\n\t" \
|
||||||
|
/*dst+3*ystride*/ \
|
||||||
|
"movq %%mm3,(%[dst],%[ystride3])\n\t" \
|
||||||
|
/*Pointer to next 4.*/ \
|
||||||
|
"lea (%[dst],%[ystride],4),%[dst]\n\t" \
|
||||||
|
/*src+0*ystride*/ \
|
||||||
|
"movq (%[src]),%%mm0\n\t" \
|
||||||
|
/*src+1*ystride*/ \
|
||||||
|
"movq (%[src],%[ystride]),%%mm1\n\t" \
|
||||||
|
/*src+2*ystride*/ \
|
||||||
|
"movq (%[src],%[ystride],2),%%mm2\n\t" \
|
||||||
|
/*src+3*ystride*/ \
|
||||||
|
"movq (%[src],%[ystride3]),%%mm3\n\t" \
|
||||||
|
/*dst+0*ystride*/ \
|
||||||
|
"movq %%mm0,(%[dst])\n\t" \
|
||||||
|
/*dst+1*ystride*/ \
|
||||||
|
"movq %%mm1,(%[dst],%[ystride])\n\t" \
|
||||||
|
/*dst+2*ystride*/ \
|
||||||
|
"movq %%mm2,(%[dst],%[ystride],2)\n\t" \
|
||||||
|
/*dst+3*ystride*/ \
|
||||||
|
"movq %%mm3,(%[dst],%[ystride3])\n\t" \
|
||||||
|
:[dst]"+r"(dst),[src]"+r"(src),[ystride3]"=&r"(ystride3) \
|
||||||
|
:[ystride]"r"((ptrdiff_t)(_ystride)) \
|
||||||
|
:"memory" \
|
||||||
|
); \
|
||||||
|
} \
|
||||||
|
while(0)
|
||||||
|
|
||||||
|
/*Copies an 8x8 block of pixels from _src to _dst, assuming _ystride bytes
|
||||||
|
between rows.*/
|
||||||
|
void oc_frag_copy_mmx(unsigned char *_dst,
|
||||||
|
const unsigned char *_src,int _ystride){
|
||||||
|
OC_FRAG_COPY_MMX(_dst,_src,_ystride);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Copies the fragments specified by the lists of fragment indices from one
|
||||||
|
frame to another.
|
||||||
|
_dst_frame: The reference frame to copy to.
|
||||||
|
_src_frame: The reference frame to copy from.
|
||||||
|
_ystride: The row stride of the reference frames.
|
||||||
|
_fragis: A pointer to a list of fragment indices.
|
||||||
|
_nfragis: The number of fragment indices to copy.
|
||||||
|
_frag_buf_offs: The offsets of fragments in the reference frames.*/
|
||||||
|
void oc_frag_copy_list_mmx(unsigned char *_dst_frame,
|
||||||
|
const unsigned char *_src_frame,int _ystride,
|
||||||
|
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs){
|
||||||
|
ptrdiff_t fragii;
|
||||||
|
for(fragii=0;fragii<_nfragis;fragii++){
|
||||||
|
ptrdiff_t frag_buf_off;
|
||||||
|
frag_buf_off=_frag_buf_offs[_fragis[fragii]];
|
||||||
|
OC_FRAG_COPY_MMX(_dst_frame+frag_buf_off,
|
||||||
|
_src_frame+frag_buf_off,_ystride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void oc_frag_recon_intra_mmx(unsigned char *_dst,int _ystride,
|
||||||
|
const ogg_int16_t *_residue){
|
||||||
|
__asm__ __volatile__(
|
||||||
|
/*Set mm0 to 0xFFFFFFFFFFFFFFFF.*/
|
||||||
|
"pcmpeqw %%mm0,%%mm0\n\t"
|
||||||
|
/*#0 Load low residue.*/
|
||||||
|
"movq 0*8(%[residue]),%%mm1\n\t"
|
||||||
|
/*#0 Load high residue.*/
|
||||||
|
"movq 1*8(%[residue]),%%mm2\n\t"
|
||||||
|
/*Set mm0 to 0x8000800080008000.*/
|
||||||
|
"psllw $15,%%mm0\n\t"
|
||||||
|
/*#1 Load low residue.*/
|
||||||
|
"movq 2*8(%[residue]),%%mm3\n\t"
|
||||||
|
/*#1 Load high residue.*/
|
||||||
|
"movq 3*8(%[residue]),%%mm4\n\t"
|
||||||
|
/*Set mm0 to 0x0080008000800080.*/
|
||||||
|
"psrlw $8,%%mm0\n\t"
|
||||||
|
/*#2 Load low residue.*/
|
||||||
|
"movq 4*8(%[residue]),%%mm5\n\t"
|
||||||
|
/*#2 Load high residue.*/
|
||||||
|
"movq 5*8(%[residue]),%%mm6\n\t"
|
||||||
|
/*#0 Bias low residue.*/
|
||||||
|
"paddsw %%mm0,%%mm1\n\t"
|
||||||
|
/*#0 Bias high residue.*/
|
||||||
|
"paddsw %%mm0,%%mm2\n\t"
|
||||||
|
/*#0 Pack to byte.*/
|
||||||
|
"packuswb %%mm2,%%mm1\n\t"
|
||||||
|
/*#1 Bias low residue.*/
|
||||||
|
"paddsw %%mm0,%%mm3\n\t"
|
||||||
|
/*#1 Bias high residue.*/
|
||||||
|
"paddsw %%mm0,%%mm4\n\t"
|
||||||
|
/*#1 Pack to byte.*/
|
||||||
|
"packuswb %%mm4,%%mm3\n\t"
|
||||||
|
/*#2 Bias low residue.*/
|
||||||
|
"paddsw %%mm0,%%mm5\n\t"
|
||||||
|
/*#2 Bias high residue.*/
|
||||||
|
"paddsw %%mm0,%%mm6\n\t"
|
||||||
|
/*#2 Pack to byte.*/
|
||||||
|
"packuswb %%mm6,%%mm5\n\t"
|
||||||
|
/*#0 Write row.*/
|
||||||
|
"movq %%mm1,(%[dst])\n\t"
|
||||||
|
/*#1 Write row.*/
|
||||||
|
"movq %%mm3,(%[dst],%[ystride])\n\t"
|
||||||
|
/*#2 Write row.*/
|
||||||
|
"movq %%mm5,(%[dst],%[ystride],2)\n\t"
|
||||||
|
/*#3 Load low residue.*/
|
||||||
|
"movq 6*8(%[residue]),%%mm1\n\t"
|
||||||
|
/*#3 Load high residue.*/
|
||||||
|
"movq 7*8(%[residue]),%%mm2\n\t"
|
||||||
|
/*#4 Load high residue.*/
|
||||||
|
"movq 8*8(%[residue]),%%mm3\n\t"
|
||||||
|
/*#4 Load high residue.*/
|
||||||
|
"movq 9*8(%[residue]),%%mm4\n\t"
|
||||||
|
/*#5 Load high residue.*/
|
||||||
|
"movq 10*8(%[residue]),%%mm5\n\t"
|
||||||
|
/*#5 Load high residue.*/
|
||||||
|
"movq 11*8(%[residue]),%%mm6\n\t"
|
||||||
|
/*#3 Bias low residue.*/
|
||||||
|
"paddsw %%mm0,%%mm1\n\t"
|
||||||
|
/*#3 Bias high residue.*/
|
||||||
|
"paddsw %%mm0,%%mm2\n\t"
|
||||||
|
/*#3 Pack to byte.*/
|
||||||
|
"packuswb %%mm2,%%mm1\n\t"
|
||||||
|
/*#4 Bias low residue.*/
|
||||||
|
"paddsw %%mm0,%%mm3\n\t"
|
||||||
|
/*#4 Bias high residue.*/
|
||||||
|
"paddsw %%mm0,%%mm4\n\t"
|
||||||
|
/*#4 Pack to byte.*/
|
||||||
|
"packuswb %%mm4,%%mm3\n\t"
|
||||||
|
/*#5 Bias low residue.*/
|
||||||
|
"paddsw %%mm0,%%mm5\n\t"
|
||||||
|
/*#5 Bias high residue.*/
|
||||||
|
"paddsw %%mm0,%%mm6\n\t"
|
||||||
|
/*#5 Pack to byte.*/
|
||||||
|
"packuswb %%mm6,%%mm5\n\t"
|
||||||
|
/*#3 Write row.*/
|
||||||
|
"movq %%mm1,(%[dst],%[ystride3])\n\t"
|
||||||
|
/*#4 Write row.*/
|
||||||
|
"movq %%mm3,(%[dst4])\n\t"
|
||||||
|
/*#5 Write row.*/
|
||||||
|
"movq %%mm5,(%[dst4],%[ystride])\n\t"
|
||||||
|
/*#6 Load low residue.*/
|
||||||
|
"movq 12*8(%[residue]),%%mm1\n\t"
|
||||||
|
/*#6 Load high residue.*/
|
||||||
|
"movq 13*8(%[residue]),%%mm2\n\t"
|
||||||
|
/*#7 Load low residue.*/
|
||||||
|
"movq 14*8(%[residue]),%%mm3\n\t"
|
||||||
|
/*#7 Load high residue.*/
|
||||||
|
"movq 15*8(%[residue]),%%mm4\n\t"
|
||||||
|
/*#6 Bias low residue.*/
|
||||||
|
"paddsw %%mm0,%%mm1\n\t"
|
||||||
|
/*#6 Bias high residue.*/
|
||||||
|
"paddsw %%mm0,%%mm2\n\t"
|
||||||
|
/*#6 Pack to byte.*/
|
||||||
|
"packuswb %%mm2,%%mm1\n\t"
|
||||||
|
/*#7 Bias low residue.*/
|
||||||
|
"paddsw %%mm0,%%mm3\n\t"
|
||||||
|
/*#7 Bias high residue.*/
|
||||||
|
"paddsw %%mm0,%%mm4\n\t"
|
||||||
|
/*#7 Pack to byte.*/
|
||||||
|
"packuswb %%mm4,%%mm3\n\t"
|
||||||
|
/*#6 Write row.*/
|
||||||
|
"movq %%mm1,(%[dst4],%[ystride],2)\n\t"
|
||||||
|
/*#7 Write row.*/
|
||||||
|
"movq %%mm3,(%[dst4],%[ystride3])\n\t"
|
||||||
|
:
|
||||||
|
:[residue]"r"(_residue),
|
||||||
|
[dst]"r"(_dst),
|
||||||
|
[dst4]"r"(_dst+(_ystride<<2)),
|
||||||
|
[ystride]"r"((ptrdiff_t)_ystride),
|
||||||
|
[ystride3]"r"((ptrdiff_t)_ystride*3)
|
||||||
|
:"memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_frag_recon_inter_mmx(unsigned char *_dst,const unsigned char *_src,
|
||||||
|
int _ystride,const ogg_int16_t *_residue){
|
||||||
|
int i;
|
||||||
|
/*Zero mm0.*/
|
||||||
|
__asm__ __volatile__("pxor %%mm0,%%mm0\n\t"::);
|
||||||
|
for(i=4;i-->0;){
|
||||||
|
__asm__ __volatile__(
|
||||||
|
/*#0 Load source.*/
|
||||||
|
"movq (%[src]),%%mm3\n\t"
|
||||||
|
/*#1 Load source.*/
|
||||||
|
"movq (%[src],%[ystride]),%%mm7\n\t"
|
||||||
|
/*#0 Get copy of src.*/
|
||||||
|
"movq %%mm3,%%mm4\n\t"
|
||||||
|
/*#0 Expand high source.*/
|
||||||
|
"punpckhbw %%mm0,%%mm4\n\t"
|
||||||
|
/*#0 Expand low source.*/
|
||||||
|
"punpcklbw %%mm0,%%mm3\n\t"
|
||||||
|
/*#0 Add residue high.*/
|
||||||
|
"paddsw 8(%[residue]),%%mm4\n\t"
|
||||||
|
/*#1 Get copy of src.*/
|
||||||
|
"movq %%mm7,%%mm2\n\t"
|
||||||
|
/*#0 Add residue low.*/
|
||||||
|
"paddsw (%[residue]), %%mm3\n\t"
|
||||||
|
/*#1 Expand high source.*/
|
||||||
|
"punpckhbw %%mm0,%%mm2\n\t"
|
||||||
|
/*#0 Pack final row pixels.*/
|
||||||
|
"packuswb %%mm4,%%mm3\n\t"
|
||||||
|
/*#1 Expand low source.*/
|
||||||
|
"punpcklbw %%mm0,%%mm7\n\t"
|
||||||
|
/*#1 Add residue low.*/
|
||||||
|
"paddsw 16(%[residue]),%%mm7\n\t"
|
||||||
|
/*#1 Add residue high.*/
|
||||||
|
"paddsw 24(%[residue]),%%mm2\n\t"
|
||||||
|
/*Advance residue.*/
|
||||||
|
"lea 32(%[residue]),%[residue]\n\t"
|
||||||
|
/*#1 Pack final row pixels.*/
|
||||||
|
"packuswb %%mm2,%%mm7\n\t"
|
||||||
|
/*Advance src.*/
|
||||||
|
"lea (%[src],%[ystride],2),%[src]\n\t"
|
||||||
|
/*#0 Write row.*/
|
||||||
|
"movq %%mm3,(%[dst])\n\t"
|
||||||
|
/*#1 Write row.*/
|
||||||
|
"movq %%mm7,(%[dst],%[ystride])\n\t"
|
||||||
|
/*Advance dst.*/
|
||||||
|
"lea (%[dst],%[ystride],2),%[dst]\n\t"
|
||||||
|
:[residue]"+r"(_residue),[dst]"+r"(_dst),[src]"+r"(_src)
|
||||||
|
:[ystride]"r"((ptrdiff_t)_ystride)
|
||||||
|
:"memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_frag_recon_inter2_mmx(unsigned char *_dst,const unsigned char *_src1,
|
||||||
|
const unsigned char *_src2,int _ystride,const ogg_int16_t *_residue){
|
||||||
|
int i;
|
||||||
|
/*Zero mm7.*/
|
||||||
|
__asm__ __volatile__("pxor %%mm7,%%mm7\n\t"::);
|
||||||
|
for(i=4;i-->0;){
|
||||||
|
__asm__ __volatile__(
|
||||||
|
/*#0 Load src1.*/
|
||||||
|
"movq (%[src1]),%%mm0\n\t"
|
||||||
|
/*#0 Load src2.*/
|
||||||
|
"movq (%[src2]),%%mm2\n\t"
|
||||||
|
/*#0 Copy src1.*/
|
||||||
|
"movq %%mm0,%%mm1\n\t"
|
||||||
|
/*#0 Copy src2.*/
|
||||||
|
"movq %%mm2,%%mm3\n\t"
|
||||||
|
/*#1 Load src1.*/
|
||||||
|
"movq (%[src1],%[ystride]),%%mm4\n\t"
|
||||||
|
/*#0 Unpack lower src1.*/
|
||||||
|
"punpcklbw %%mm7,%%mm0\n\t"
|
||||||
|
/*#1 Load src2.*/
|
||||||
|
"movq (%[src2],%[ystride]),%%mm5\n\t"
|
||||||
|
/*#0 Unpack higher src1.*/
|
||||||
|
"punpckhbw %%mm7,%%mm1\n\t"
|
||||||
|
/*#0 Unpack lower src2.*/
|
||||||
|
"punpcklbw %%mm7,%%mm2\n\t"
|
||||||
|
/*#0 Unpack higher src2.*/
|
||||||
|
"punpckhbw %%mm7,%%mm3\n\t"
|
||||||
|
/*Advance src1 ptr.*/
|
||||||
|
"lea (%[src1],%[ystride],2),%[src1]\n\t"
|
||||||
|
/*Advance src2 ptr.*/
|
||||||
|
"lea (%[src2],%[ystride],2),%[src2]\n\t"
|
||||||
|
/*#0 Lower src1+src2.*/
|
||||||
|
"paddsw %%mm2,%%mm0\n\t"
|
||||||
|
/*#0 Higher src1+src2.*/
|
||||||
|
"paddsw %%mm3,%%mm1\n\t"
|
||||||
|
/*#1 Copy src1.*/
|
||||||
|
"movq %%mm4,%%mm2\n\t"
|
||||||
|
/*#0 Build lo average.*/
|
||||||
|
"psraw $1,%%mm0\n\t"
|
||||||
|
/*#1 Copy src2.*/
|
||||||
|
"movq %%mm5,%%mm3\n\t"
|
||||||
|
/*#1 Unpack lower src1.*/
|
||||||
|
"punpcklbw %%mm7,%%mm4\n\t"
|
||||||
|
/*#0 Build hi average.*/
|
||||||
|
"psraw $1,%%mm1\n\t"
|
||||||
|
/*#1 Unpack higher src1.*/
|
||||||
|
"punpckhbw %%mm7,%%mm2\n\t"
|
||||||
|
/*#0 low+=residue.*/
|
||||||
|
"paddsw (%[residue]),%%mm0\n\t"
|
||||||
|
/*#1 Unpack lower src2.*/
|
||||||
|
"punpcklbw %%mm7,%%mm5\n\t"
|
||||||
|
/*#0 high+=residue.*/
|
||||||
|
"paddsw 8(%[residue]),%%mm1\n\t"
|
||||||
|
/*#1 Unpack higher src2.*/
|
||||||
|
"punpckhbw %%mm7,%%mm3\n\t"
|
||||||
|
/*#1 Lower src1+src2.*/
|
||||||
|
"paddsw %%mm4,%%mm5\n\t"
|
||||||
|
/*#0 Pack and saturate.*/
|
||||||
|
"packuswb %%mm1,%%mm0\n\t"
|
||||||
|
/*#1 Higher src1+src2.*/
|
||||||
|
"paddsw %%mm2,%%mm3\n\t"
|
||||||
|
/*#0 Write row.*/
|
||||||
|
"movq %%mm0,(%[dst])\n\t"
|
||||||
|
/*#1 Build lo average.*/
|
||||||
|
"psraw $1,%%mm5\n\t"
|
||||||
|
/*#1 Build hi average.*/
|
||||||
|
"psraw $1,%%mm3\n\t"
|
||||||
|
/*#1 low+=residue.*/
|
||||||
|
"paddsw 16(%[residue]),%%mm5\n\t"
|
||||||
|
/*#1 high+=residue.*/
|
||||||
|
"paddsw 24(%[residue]),%%mm3\n\t"
|
||||||
|
/*#1 Pack and saturate.*/
|
||||||
|
"packuswb %%mm3,%%mm5\n\t"
|
||||||
|
/*#1 Write row ptr.*/
|
||||||
|
"movq %%mm5,(%[dst],%[ystride])\n\t"
|
||||||
|
/*Advance residue ptr.*/
|
||||||
|
"add $32,%[residue]\n\t"
|
||||||
|
/*Advance dest ptr.*/
|
||||||
|
"lea (%[dst],%[ystride],2),%[dst]\n\t"
|
||||||
|
:[dst]"+r"(_dst),[residue]"+r"(_residue),
|
||||||
|
[src1]"+r"(_src1),[src2]"+r"(_src2)
|
||||||
|
:[ystride]"r"((ptrdiff_t)_ystride)
|
||||||
|
:"memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_restore_fpu_mmx(void){
|
||||||
|
__asm__ __volatile__("emms\n\t");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,558 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
/*MMX acceleration of Theora's iDCT.
|
||||||
|
Originally written by Rudolf Marek, based on code from On2's VP3.*/
|
||||||
|
#include "x86int.h"
|
||||||
|
#include "../dct.h"
|
||||||
|
|
||||||
|
#if defined(OC_X86_ASM)
|
||||||
|
|
||||||
|
/*These are offsets into the table of constants below.*/
|
||||||
|
/*7 rows of cosines, in order: pi/16 * (1 ... 7).*/
|
||||||
|
#define OC_COSINE_OFFSET (0)
|
||||||
|
/*A row of 8's.*/
|
||||||
|
#define OC_EIGHT_OFFSET (56)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*38 cycles*/
|
||||||
|
#define OC_IDCT_BEGIN(_y,_x) \
|
||||||
|
"#OC_IDCT_BEGIN\n\t" \
|
||||||
|
"movq "OC_I(3,_x)",%%mm2\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x30,c)",%%mm6\n\t" \
|
||||||
|
"movq %%mm2,%%mm4\n\t" \
|
||||||
|
"movq "OC_J(5,_x)",%%mm7\n\t" \
|
||||||
|
"pmulhw %%mm6,%%mm4\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x50,c)",%%mm1\n\t" \
|
||||||
|
"pmulhw %%mm7,%%mm6\n\t" \
|
||||||
|
"movq %%mm1,%%mm5\n\t" \
|
||||||
|
"pmulhw %%mm2,%%mm1\n\t" \
|
||||||
|
"movq "OC_I(1,_x)",%%mm3\n\t" \
|
||||||
|
"pmulhw %%mm7,%%mm5\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x10,c)",%%mm0\n\t" \
|
||||||
|
"paddw %%mm2,%%mm4\n\t" \
|
||||||
|
"paddw %%mm7,%%mm6\n\t" \
|
||||||
|
"paddw %%mm1,%%mm2\n\t" \
|
||||||
|
"movq "OC_J(7,_x)",%%mm1\n\t" \
|
||||||
|
"paddw %%mm5,%%mm7\n\t" \
|
||||||
|
"movq %%mm0,%%mm5\n\t" \
|
||||||
|
"pmulhw %%mm3,%%mm0\n\t" \
|
||||||
|
"paddw %%mm7,%%mm4\n\t" \
|
||||||
|
"pmulhw %%mm1,%%mm5\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x70,c)",%%mm7\n\t" \
|
||||||
|
"psubw %%mm2,%%mm6\n\t" \
|
||||||
|
"paddw %%mm3,%%mm0\n\t" \
|
||||||
|
"pmulhw %%mm7,%%mm3\n\t" \
|
||||||
|
"movq "OC_I(2,_x)",%%mm2\n\t" \
|
||||||
|
"pmulhw %%mm1,%%mm7\n\t" \
|
||||||
|
"paddw %%mm1,%%mm5\n\t" \
|
||||||
|
"movq %%mm2,%%mm1\n\t" \
|
||||||
|
"pmulhw "OC_MEM_OFFS(0x20,c)",%%mm2\n\t" \
|
||||||
|
"psubw %%mm5,%%mm3\n\t" \
|
||||||
|
"movq "OC_J(6,_x)",%%mm5\n\t" \
|
||||||
|
"paddw %%mm7,%%mm0\n\t" \
|
||||||
|
"movq %%mm5,%%mm7\n\t" \
|
||||||
|
"psubw %%mm4,%%mm0\n\t" \
|
||||||
|
"pmulhw "OC_MEM_OFFS(0x20,c)",%%mm5\n\t" \
|
||||||
|
"paddw %%mm1,%%mm2\n\t" \
|
||||||
|
"pmulhw "OC_MEM_OFFS(0x60,c)",%%mm1\n\t" \
|
||||||
|
"paddw %%mm4,%%mm4\n\t" \
|
||||||
|
"paddw %%mm0,%%mm4\n\t" \
|
||||||
|
"psubw %%mm6,%%mm3\n\t" \
|
||||||
|
"paddw %%mm7,%%mm5\n\t" \
|
||||||
|
"paddw %%mm6,%%mm6\n\t" \
|
||||||
|
"pmulhw "OC_MEM_OFFS(0x60,c)",%%mm7\n\t" \
|
||||||
|
"paddw %%mm3,%%mm6\n\t" \
|
||||||
|
"movq %%mm4,"OC_I(1,_y)"\n\t" \
|
||||||
|
"psubw %%mm5,%%mm1\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x40,c)",%%mm4\n\t" \
|
||||||
|
"movq %%mm3,%%mm5\n\t" \
|
||||||
|
"pmulhw %%mm4,%%mm3\n\t" \
|
||||||
|
"paddw %%mm2,%%mm7\n\t" \
|
||||||
|
"movq %%mm6,"OC_I(2,_y)"\n\t" \
|
||||||
|
"movq %%mm0,%%mm2\n\t" \
|
||||||
|
"movq "OC_I(0,_x)",%%mm6\n\t" \
|
||||||
|
"pmulhw %%mm4,%%mm0\n\t" \
|
||||||
|
"paddw %%mm3,%%mm5\n\t" \
|
||||||
|
"movq "OC_J(4,_x)",%%mm3\n\t" \
|
||||||
|
"psubw %%mm1,%%mm5\n\t" \
|
||||||
|
"paddw %%mm0,%%mm2\n\t" \
|
||||||
|
"psubw %%mm3,%%mm6\n\t" \
|
||||||
|
"movq %%mm6,%%mm0\n\t" \
|
||||||
|
"pmulhw %%mm4,%%mm6\n\t" \
|
||||||
|
"paddw %%mm3,%%mm3\n\t" \
|
||||||
|
"paddw %%mm1,%%mm1\n\t" \
|
||||||
|
"paddw %%mm0,%%mm3\n\t" \
|
||||||
|
"paddw %%mm5,%%mm1\n\t" \
|
||||||
|
"pmulhw %%mm3,%%mm4\n\t" \
|
||||||
|
"paddw %%mm0,%%mm6\n\t" \
|
||||||
|
"psubw %%mm2,%%mm6\n\t" \
|
||||||
|
"paddw %%mm2,%%mm2\n\t" \
|
||||||
|
"movq "OC_I(1,_y)",%%mm0\n\t" \
|
||||||
|
"paddw %%mm6,%%mm2\n\t" \
|
||||||
|
"paddw %%mm3,%%mm4\n\t" \
|
||||||
|
"psubw %%mm1,%%mm2\n\t" \
|
||||||
|
"#end OC_IDCT_BEGIN\n\t" \
|
||||||
|
|
||||||
|
/*38+8=46 cycles.*/
|
||||||
|
#define OC_ROW_IDCT(_y,_x) \
|
||||||
|
"#OC_ROW_IDCT\n" \
|
||||||
|
OC_IDCT_BEGIN(_y,_x) \
|
||||||
|
/*r3=D'*/ \
|
||||||
|
"movq "OC_I(2,_y)",%%mm3\n\t" \
|
||||||
|
/*r4=E'=E-G*/ \
|
||||||
|
"psubw %%mm7,%%mm4\n\t" \
|
||||||
|
/*r1=H'+H'*/ \
|
||||||
|
"paddw %%mm1,%%mm1\n\t" \
|
||||||
|
/*r7=G+G*/ \
|
||||||
|
"paddw %%mm7,%%mm7\n\t" \
|
||||||
|
/*r1=R1=A''+H'*/ \
|
||||||
|
"paddw %%mm2,%%mm1\n\t" \
|
||||||
|
/*r7=G'=E+G*/ \
|
||||||
|
"paddw %%mm4,%%mm7\n\t" \
|
||||||
|
/*r4=R4=E'-D'*/ \
|
||||||
|
"psubw %%mm3,%%mm4\n\t" \
|
||||||
|
"paddw %%mm3,%%mm3\n\t" \
|
||||||
|
/*r6=R6=F'-B''*/ \
|
||||||
|
"psubw %%mm5,%%mm6\n\t" \
|
||||||
|
"paddw %%mm5,%%mm5\n\t" \
|
||||||
|
/*r3=R3=E'+D'*/ \
|
||||||
|
"paddw %%mm4,%%mm3\n\t" \
|
||||||
|
/*r5=R5=F'+B''*/ \
|
||||||
|
"paddw %%mm6,%%mm5\n\t" \
|
||||||
|
/*r7=R7=G'-C'*/ \
|
||||||
|
"psubw %%mm0,%%mm7\n\t" \
|
||||||
|
"paddw %%mm0,%%mm0\n\t" \
|
||||||
|
/*Save R1.*/ \
|
||||||
|
"movq %%mm1,"OC_I(1,_y)"\n\t" \
|
||||||
|
/*r0=R0=G.+C.*/ \
|
||||||
|
"paddw %%mm7,%%mm0\n\t" \
|
||||||
|
"#end OC_ROW_IDCT\n\t" \
|
||||||
|
|
||||||
|
/*The following macro does two 4x4 transposes in place.
|
||||||
|
At entry, we assume:
|
||||||
|
r0 = a3 a2 a1 a0
|
||||||
|
I(1) = b3 b2 b1 b0
|
||||||
|
r2 = c3 c2 c1 c0
|
||||||
|
r3 = d3 d2 d1 d0
|
||||||
|
|
||||||
|
r4 = e3 e2 e1 e0
|
||||||
|
r5 = f3 f2 f1 f0
|
||||||
|
r6 = g3 g2 g1 g0
|
||||||
|
r7 = h3 h2 h1 h0
|
||||||
|
|
||||||
|
At exit, we have:
|
||||||
|
I(0) = d0 c0 b0 a0
|
||||||
|
I(1) = d1 c1 b1 a1
|
||||||
|
I(2) = d2 c2 b2 a2
|
||||||
|
I(3) = d3 c3 b3 a3
|
||||||
|
|
||||||
|
J(4) = h0 g0 f0 e0
|
||||||
|
J(5) = h1 g1 f1 e1
|
||||||
|
J(6) = h2 g2 f2 e2
|
||||||
|
J(7) = h3 g3 f3 e3
|
||||||
|
|
||||||
|
I(0) I(1) I(2) I(3) is the transpose of r0 I(1) r2 r3.
|
||||||
|
J(4) J(5) J(6) J(7) is the transpose of r4 r5 r6 r7.
|
||||||
|
|
||||||
|
Since r1 is free at entry, we calculate the Js first.*/
|
||||||
|
/*19 cycles.*/
|
||||||
|
#define OC_TRANSPOSE(_y) \
|
||||||
|
"#OC_TRANSPOSE\n\t" \
|
||||||
|
"movq %%mm4,%%mm1\n\t" \
|
||||||
|
"punpcklwd %%mm5,%%mm4\n\t" \
|
||||||
|
"movq %%mm0,"OC_I(0,_y)"\n\t" \
|
||||||
|
"punpckhwd %%mm5,%%mm1\n\t" \
|
||||||
|
"movq %%mm6,%%mm0\n\t" \
|
||||||
|
"punpcklwd %%mm7,%%mm6\n\t" \
|
||||||
|
"movq %%mm4,%%mm5\n\t" \
|
||||||
|
"punpckldq %%mm6,%%mm4\n\t" \
|
||||||
|
"punpckhdq %%mm6,%%mm5\n\t" \
|
||||||
|
"movq %%mm1,%%mm6\n\t" \
|
||||||
|
"movq %%mm4,"OC_J(4,_y)"\n\t" \
|
||||||
|
"punpckhwd %%mm7,%%mm0\n\t" \
|
||||||
|
"movq %%mm5,"OC_J(5,_y)"\n\t" \
|
||||||
|
"punpckhdq %%mm0,%%mm6\n\t" \
|
||||||
|
"movq "OC_I(0,_y)",%%mm4\n\t" \
|
||||||
|
"punpckldq %%mm0,%%mm1\n\t" \
|
||||||
|
"movq "OC_I(1,_y)",%%mm5\n\t" \
|
||||||
|
"movq %%mm4,%%mm0\n\t" \
|
||||||
|
"movq %%mm6,"OC_J(7,_y)"\n\t" \
|
||||||
|
"punpcklwd %%mm5,%%mm0\n\t" \
|
||||||
|
"movq %%mm1,"OC_J(6,_y)"\n\t" \
|
||||||
|
"punpckhwd %%mm5,%%mm4\n\t" \
|
||||||
|
"movq %%mm2,%%mm5\n\t" \
|
||||||
|
"punpcklwd %%mm3,%%mm2\n\t" \
|
||||||
|
"movq %%mm0,%%mm1\n\t" \
|
||||||
|
"punpckldq %%mm2,%%mm0\n\t" \
|
||||||
|
"punpckhdq %%mm2,%%mm1\n\t" \
|
||||||
|
"movq %%mm4,%%mm2\n\t" \
|
||||||
|
"movq %%mm0,"OC_I(0,_y)"\n\t" \
|
||||||
|
"punpckhwd %%mm3,%%mm5\n\t" \
|
||||||
|
"movq %%mm1,"OC_I(1,_y)"\n\t" \
|
||||||
|
"punpckhdq %%mm5,%%mm4\n\t" \
|
||||||
|
"punpckldq %%mm5,%%mm2\n\t" \
|
||||||
|
"movq %%mm4,"OC_I(3,_y)"\n\t" \
|
||||||
|
"movq %%mm2,"OC_I(2,_y)"\n\t" \
|
||||||
|
"#end OC_TRANSPOSE\n\t" \
|
||||||
|
|
||||||
|
/*38+19=57 cycles.*/
|
||||||
|
#define OC_COLUMN_IDCT(_y) \
|
||||||
|
"#OC_COLUMN_IDCT\n" \
|
||||||
|
OC_IDCT_BEGIN(_y,_y) \
|
||||||
|
"paddw "OC_MEM_OFFS(0x00,c)",%%mm2\n\t" \
|
||||||
|
/*r1=H'+H'*/ \
|
||||||
|
"paddw %%mm1,%%mm1\n\t" \
|
||||||
|
/*r1=R1=A''+H'*/ \
|
||||||
|
"paddw %%mm2,%%mm1\n\t" \
|
||||||
|
/*r2=NR2*/ \
|
||||||
|
"psraw $4,%%mm2\n\t" \
|
||||||
|
/*r4=E'=E-G*/ \
|
||||||
|
"psubw %%mm7,%%mm4\n\t" \
|
||||||
|
/*r1=NR1*/ \
|
||||||
|
"psraw $4,%%mm1\n\t" \
|
||||||
|
/*r3=D'*/ \
|
||||||
|
"movq "OC_I(2,_y)",%%mm3\n\t" \
|
||||||
|
/*r7=G+G*/ \
|
||||||
|
"paddw %%mm7,%%mm7\n\t" \
|
||||||
|
/*Store NR2 at I(2).*/ \
|
||||||
|
"movq %%mm2,"OC_I(2,_y)"\n\t" \
|
||||||
|
/*r7=G'=E+G*/ \
|
||||||
|
"paddw %%mm4,%%mm7\n\t" \
|
||||||
|
/*Store NR1 at I(1).*/ \
|
||||||
|
"movq %%mm1,"OC_I(1,_y)"\n\t" \
|
||||||
|
/*r4=R4=E'-D'*/ \
|
||||||
|
"psubw %%mm3,%%mm4\n\t" \
|
||||||
|
"paddw "OC_MEM_OFFS(0x00,c)",%%mm4\n\t" \
|
||||||
|
/*r3=D'+D'*/ \
|
||||||
|
"paddw %%mm3,%%mm3\n\t" \
|
||||||
|
/*r3=R3=E'+D'*/ \
|
||||||
|
"paddw %%mm4,%%mm3\n\t" \
|
||||||
|
/*r4=NR4*/ \
|
||||||
|
"psraw $4,%%mm4\n\t" \
|
||||||
|
/*r6=R6=F'-B''*/ \
|
||||||
|
"psubw %%mm5,%%mm6\n\t" \
|
||||||
|
/*r3=NR3*/ \
|
||||||
|
"psraw $4,%%mm3\n\t" \
|
||||||
|
"paddw "OC_MEM_OFFS(0x00,c)",%%mm6\n\t" \
|
||||||
|
/*r5=B''+B''*/ \
|
||||||
|
"paddw %%mm5,%%mm5\n\t" \
|
||||||
|
/*r5=R5=F'+B''*/ \
|
||||||
|
"paddw %%mm6,%%mm5\n\t" \
|
||||||
|
/*r6=NR6*/ \
|
||||||
|
"psraw $4,%%mm6\n\t" \
|
||||||
|
/*Store NR4 at J(4).*/ \
|
||||||
|
"movq %%mm4,"OC_J(4,_y)"\n\t" \
|
||||||
|
/*r5=NR5*/ \
|
||||||
|
"psraw $4,%%mm5\n\t" \
|
||||||
|
/*Store NR3 at I(3).*/ \
|
||||||
|
"movq %%mm3,"OC_I(3,_y)"\n\t" \
|
||||||
|
/*r7=R7=G'-C'*/ \
|
||||||
|
"psubw %%mm0,%%mm7\n\t" \
|
||||||
|
"paddw "OC_MEM_OFFS(0x00,c)",%%mm7\n\t" \
|
||||||
|
/*r0=C'+C'*/ \
|
||||||
|
"paddw %%mm0,%%mm0\n\t" \
|
||||||
|
/*r0=R0=G'+C'*/ \
|
||||||
|
"paddw %%mm7,%%mm0\n\t" \
|
||||||
|
/*r7=NR7*/ \
|
||||||
|
"psraw $4,%%mm7\n\t" \
|
||||||
|
/*Store NR6 at J(6).*/ \
|
||||||
|
"movq %%mm6,"OC_J(6,_y)"\n\t" \
|
||||||
|
/*r0=NR0*/ \
|
||||||
|
"psraw $4,%%mm0\n\t" \
|
||||||
|
/*Store NR5 at J(5).*/ \
|
||||||
|
"movq %%mm5,"OC_J(5,_y)"\n\t" \
|
||||||
|
/*Store NR7 at J(7).*/ \
|
||||||
|
"movq %%mm7,"OC_J(7,_y)"\n\t" \
|
||||||
|
/*Store NR0 at I(0).*/ \
|
||||||
|
"movq %%mm0,"OC_I(0,_y)"\n\t" \
|
||||||
|
"#end OC_COLUMN_IDCT\n\t" \
|
||||||
|
|
||||||
|
static void oc_idct8x8_slow_mmx(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||||
|
int i;
|
||||||
|
/*This routine accepts an 8x8 matrix, but in partially transposed form.
|
||||||
|
Every 4x4 block is transposed.*/
|
||||||
|
__asm__ __volatile__(
|
||||||
|
#define OC_I(_k,_y) OC_MEM_OFFS((_k)*16,_y)
|
||||||
|
#define OC_J(_k,_y) OC_MEM_OFFS(((_k)-4)*16+8,_y)
|
||||||
|
OC_ROW_IDCT(y,x)
|
||||||
|
OC_TRANSPOSE(y)
|
||||||
|
#undef OC_I
|
||||||
|
#undef OC_J
|
||||||
|
#define OC_I(_k,_y) OC_MEM_OFFS((_k)*16+64,_y)
|
||||||
|
#define OC_J(_k,_y) OC_MEM_OFFS(((_k)-4)*16+72,_y)
|
||||||
|
OC_ROW_IDCT(y,x)
|
||||||
|
OC_TRANSPOSE(y)
|
||||||
|
#undef OC_I
|
||||||
|
#undef OC_J
|
||||||
|
#define OC_I(_k,_y) OC_MEM_OFFS((_k)*16,_y)
|
||||||
|
#define OC_J(_k,_y) OC_I(_k,_y)
|
||||||
|
OC_COLUMN_IDCT(y)
|
||||||
|
#undef OC_I
|
||||||
|
#undef OC_J
|
||||||
|
#define OC_I(_k,_y) OC_MEM_OFFS((_k)*16+8,_y)
|
||||||
|
#define OC_J(_k,_y) OC_I(_k,_y)
|
||||||
|
OC_COLUMN_IDCT(y)
|
||||||
|
#undef OC_I
|
||||||
|
#undef OC_J
|
||||||
|
:[y]"=m"OC_ARRAY_OPERAND(ogg_int16_t,_y,64)
|
||||||
|
:[x]"m"OC_CONST_ARRAY_OPERAND(ogg_int16_t,_x,64),
|
||||||
|
[c]"m"OC_CONST_ARRAY_OPERAND(ogg_int16_t,OC_IDCT_CONSTS,128)
|
||||||
|
);
|
||||||
|
__asm__ __volatile__("pxor %%mm0,%%mm0\n\t"::);
|
||||||
|
for(i=0;i<4;i++){
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x00,x)"\n\t"
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x08,x)"\n\t"
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x10,x)"\n\t"
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x18,x)"\n\t"
|
||||||
|
:[x]"=m"OC_ARRAY_OPERAND(ogg_int16_t,_x+16*i,16)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*25 cycles.*/
|
||||||
|
#define OC_IDCT_BEGIN_10(_y,_x) \
|
||||||
|
"#OC_IDCT_BEGIN_10\n\t" \
|
||||||
|
"movq "OC_I(3,_x)",%%mm2\n\t" \
|
||||||
|
"nop\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x30,c)",%%mm6\n\t" \
|
||||||
|
"movq %%mm2,%%mm4\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x50,c)",%%mm1\n\t" \
|
||||||
|
"pmulhw %%mm6,%%mm4\n\t" \
|
||||||
|
"movq "OC_I(1,_x)",%%mm3\n\t" \
|
||||||
|
"pmulhw %%mm2,%%mm1\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x10,c)",%%mm0\n\t" \
|
||||||
|
"paddw %%mm2,%%mm4\n\t" \
|
||||||
|
"pxor %%mm6,%%mm6\n\t" \
|
||||||
|
"paddw %%mm1,%%mm2\n\t" \
|
||||||
|
"movq "OC_I(2,_x)",%%mm5\n\t" \
|
||||||
|
"pmulhw %%mm3,%%mm0\n\t" \
|
||||||
|
"movq %%mm5,%%mm1\n\t" \
|
||||||
|
"paddw %%mm3,%%mm0\n\t" \
|
||||||
|
"pmulhw "OC_MEM_OFFS(0x70,c)",%%mm3\n\t" \
|
||||||
|
"psubw %%mm2,%%mm6\n\t" \
|
||||||
|
"pmulhw "OC_MEM_OFFS(0x20,c)",%%mm5\n\t" \
|
||||||
|
"psubw %%mm4,%%mm0\n\t" \
|
||||||
|
"movq "OC_I(2,_x)",%%mm7\n\t" \
|
||||||
|
"paddw %%mm4,%%mm4\n\t" \
|
||||||
|
"paddw %%mm5,%%mm7\n\t" \
|
||||||
|
"paddw %%mm0,%%mm4\n\t" \
|
||||||
|
"pmulhw "OC_MEM_OFFS(0x60,c)",%%mm1\n\t" \
|
||||||
|
"psubw %%mm6,%%mm3\n\t" \
|
||||||
|
"movq %%mm4,"OC_I(1,_y)"\n\t" \
|
||||||
|
"paddw %%mm6,%%mm6\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x40,c)",%%mm4\n\t" \
|
||||||
|
"paddw %%mm3,%%mm6\n\t" \
|
||||||
|
"movq %%mm3,%%mm5\n\t" \
|
||||||
|
"pmulhw %%mm4,%%mm3\n\t" \
|
||||||
|
"movq %%mm6,"OC_I(2,_y)"\n\t" \
|
||||||
|
"movq %%mm0,%%mm2\n\t" \
|
||||||
|
"movq "OC_I(0,_x)",%%mm6\n\t" \
|
||||||
|
"pmulhw %%mm4,%%mm0\n\t" \
|
||||||
|
"paddw %%mm3,%%mm5\n\t" \
|
||||||
|
"paddw %%mm0,%%mm2\n\t" \
|
||||||
|
"psubw %%mm1,%%mm5\n\t" \
|
||||||
|
"pmulhw %%mm4,%%mm6\n\t" \
|
||||||
|
"paddw "OC_I(0,_x)",%%mm6\n\t" \
|
||||||
|
"paddw %%mm1,%%mm1\n\t" \
|
||||||
|
"movq %%mm6,%%mm4\n\t" \
|
||||||
|
"paddw %%mm5,%%mm1\n\t" \
|
||||||
|
"psubw %%mm2,%%mm6\n\t" \
|
||||||
|
"paddw %%mm2,%%mm2\n\t" \
|
||||||
|
"movq "OC_I(1,_y)",%%mm0\n\t" \
|
||||||
|
"paddw %%mm6,%%mm2\n\t" \
|
||||||
|
"psubw %%mm1,%%mm2\n\t" \
|
||||||
|
"nop\n\t" \
|
||||||
|
"#end OC_IDCT_BEGIN_10\n\t" \
|
||||||
|
|
||||||
|
/*25+8=33 cycles.*/
|
||||||
|
#define OC_ROW_IDCT_10(_y,_x) \
|
||||||
|
"#OC_ROW_IDCT_10\n\t" \
|
||||||
|
OC_IDCT_BEGIN_10(_y,_x) \
|
||||||
|
/*r3=D'*/ \
|
||||||
|
"movq "OC_I(2,_y)",%%mm3\n\t" \
|
||||||
|
/*r4=E'=E-G*/ \
|
||||||
|
"psubw %%mm7,%%mm4\n\t" \
|
||||||
|
/*r1=H'+H'*/ \
|
||||||
|
"paddw %%mm1,%%mm1\n\t" \
|
||||||
|
/*r7=G+G*/ \
|
||||||
|
"paddw %%mm7,%%mm7\n\t" \
|
||||||
|
/*r1=R1=A''+H'*/ \
|
||||||
|
"paddw %%mm2,%%mm1\n\t" \
|
||||||
|
/*r7=G'=E+G*/ \
|
||||||
|
"paddw %%mm4,%%mm7\n\t" \
|
||||||
|
/*r4=R4=E'-D'*/ \
|
||||||
|
"psubw %%mm3,%%mm4\n\t" \
|
||||||
|
"paddw %%mm3,%%mm3\n\t" \
|
||||||
|
/*r6=R6=F'-B''*/ \
|
||||||
|
"psubw %%mm5,%%mm6\n\t" \
|
||||||
|
"paddw %%mm5,%%mm5\n\t" \
|
||||||
|
/*r3=R3=E'+D'*/ \
|
||||||
|
"paddw %%mm4,%%mm3\n\t" \
|
||||||
|
/*r5=R5=F'+B''*/ \
|
||||||
|
"paddw %%mm6,%%mm5\n\t" \
|
||||||
|
/*r7=R7=G'-C'*/ \
|
||||||
|
"psubw %%mm0,%%mm7\n\t" \
|
||||||
|
"paddw %%mm0,%%mm0\n\t" \
|
||||||
|
/*Save R1.*/ \
|
||||||
|
"movq %%mm1,"OC_I(1,_y)"\n\t" \
|
||||||
|
/*r0=R0=G'+C'*/ \
|
||||||
|
"paddw %%mm7,%%mm0\n\t" \
|
||||||
|
"#end OC_ROW_IDCT_10\n\t" \
|
||||||
|
|
||||||
|
/*25+19=44 cycles'*/
|
||||||
|
#define OC_COLUMN_IDCT_10(_y) \
|
||||||
|
"#OC_COLUMN_IDCT_10\n\t" \
|
||||||
|
OC_IDCT_BEGIN_10(_y,_y) \
|
||||||
|
"paddw "OC_MEM_OFFS(0x00,c)",%%mm2\n\t" \
|
||||||
|
/*r1=H'+H'*/ \
|
||||||
|
"paddw %%mm1,%%mm1\n\t" \
|
||||||
|
/*r1=R1=A''+H'*/ \
|
||||||
|
"paddw %%mm2,%%mm1\n\t" \
|
||||||
|
/*r2=NR2*/ \
|
||||||
|
"psraw $4,%%mm2\n\t" \
|
||||||
|
/*r4=E'=E-G*/ \
|
||||||
|
"psubw %%mm7,%%mm4\n\t" \
|
||||||
|
/*r1=NR1*/ \
|
||||||
|
"psraw $4,%%mm1\n\t" \
|
||||||
|
/*r3=D'*/ \
|
||||||
|
"movq "OC_I(2,_y)",%%mm3\n\t" \
|
||||||
|
/*r7=G+G*/ \
|
||||||
|
"paddw %%mm7,%%mm7\n\t" \
|
||||||
|
/*Store NR2 at I(2).*/ \
|
||||||
|
"movq %%mm2,"OC_I(2,_y)"\n\t" \
|
||||||
|
/*r7=G'=E+G*/ \
|
||||||
|
"paddw %%mm4,%%mm7\n\t" \
|
||||||
|
/*Store NR1 at I(1).*/ \
|
||||||
|
"movq %%mm1,"OC_I(1,_y)"\n\t" \
|
||||||
|
/*r4=R4=E'-D'*/ \
|
||||||
|
"psubw %%mm3,%%mm4\n\t" \
|
||||||
|
"paddw "OC_MEM_OFFS(0x00,c)",%%mm4\n\t" \
|
||||||
|
/*r3=D'+D'*/ \
|
||||||
|
"paddw %%mm3,%%mm3\n\t" \
|
||||||
|
/*r3=R3=E'+D'*/ \
|
||||||
|
"paddw %%mm4,%%mm3\n\t" \
|
||||||
|
/*r4=NR4*/ \
|
||||||
|
"psraw $4,%%mm4\n\t" \
|
||||||
|
/*r6=R6=F'-B''*/ \
|
||||||
|
"psubw %%mm5,%%mm6\n\t" \
|
||||||
|
/*r3=NR3*/ \
|
||||||
|
"psraw $4,%%mm3\n\t" \
|
||||||
|
"paddw "OC_MEM_OFFS(0x00,c)",%%mm6\n\t" \
|
||||||
|
/*r5=B''+B''*/ \
|
||||||
|
"paddw %%mm5,%%mm5\n\t" \
|
||||||
|
/*r5=R5=F'+B''*/ \
|
||||||
|
"paddw %%mm6,%%mm5\n\t" \
|
||||||
|
/*r6=NR6*/ \
|
||||||
|
"psraw $4,%%mm6\n\t" \
|
||||||
|
/*Store NR4 at J(4).*/ \
|
||||||
|
"movq %%mm4,"OC_J(4,_y)"\n\t" \
|
||||||
|
/*r5=NR5*/ \
|
||||||
|
"psraw $4,%%mm5\n\t" \
|
||||||
|
/*Store NR3 at I(3).*/ \
|
||||||
|
"movq %%mm3,"OC_I(3,_y)"\n\t" \
|
||||||
|
/*r7=R7=G'-C'*/ \
|
||||||
|
"psubw %%mm0,%%mm7\n\t" \
|
||||||
|
"paddw "OC_MEM_OFFS(0x00,c)",%%mm7\n\t" \
|
||||||
|
/*r0=C'+C'*/ \
|
||||||
|
"paddw %%mm0,%%mm0\n\t" \
|
||||||
|
/*r0=R0=G'+C'*/ \
|
||||||
|
"paddw %%mm7,%%mm0\n\t" \
|
||||||
|
/*r7=NR7*/ \
|
||||||
|
"psraw $4,%%mm7\n\t" \
|
||||||
|
/*Store NR6 at J(6).*/ \
|
||||||
|
"movq %%mm6,"OC_J(6,_y)"\n\t" \
|
||||||
|
/*r0=NR0*/ \
|
||||||
|
"psraw $4,%%mm0\n\t" \
|
||||||
|
/*Store NR5 at J(5).*/ \
|
||||||
|
"movq %%mm5,"OC_J(5,_y)"\n\t" \
|
||||||
|
/*Store NR7 at J(7).*/ \
|
||||||
|
"movq %%mm7,"OC_J(7,_y)"\n\t" \
|
||||||
|
/*Store NR0 at I(0).*/ \
|
||||||
|
"movq %%mm0,"OC_I(0,_y)"\n\t" \
|
||||||
|
"#end OC_COLUMN_IDCT_10\n\t" \
|
||||||
|
|
||||||
|
static void oc_idct8x8_10_mmx(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||||
|
__asm__ __volatile__(
|
||||||
|
#define OC_I(_k,_y) OC_MEM_OFFS((_k)*16,_y)
|
||||||
|
#define OC_J(_k,_y) OC_MEM_OFFS(((_k)-4)*16+8,_y)
|
||||||
|
/*Done with dequant, descramble, and partial transpose.
|
||||||
|
Now do the iDCT itself.*/
|
||||||
|
OC_ROW_IDCT_10(y,x)
|
||||||
|
OC_TRANSPOSE(y)
|
||||||
|
#undef OC_I
|
||||||
|
#undef OC_J
|
||||||
|
#define OC_I(_k,_y) OC_MEM_OFFS((_k)*16,_y)
|
||||||
|
#define OC_J(_k,_y) OC_I(_k,_y)
|
||||||
|
OC_COLUMN_IDCT_10(y)
|
||||||
|
#undef OC_I
|
||||||
|
#undef OC_J
|
||||||
|
#define OC_I(_k,_y) OC_MEM_OFFS((_k)*16+8,_y)
|
||||||
|
#define OC_J(_k,_y) OC_I(_k,_y)
|
||||||
|
OC_COLUMN_IDCT_10(y)
|
||||||
|
#undef OC_I
|
||||||
|
#undef OC_J
|
||||||
|
:[y]"=m"OC_ARRAY_OPERAND(ogg_int16_t,_y,64)
|
||||||
|
:[x]"m"OC_CONST_ARRAY_OPERAND(ogg_int16_t,_x,64),
|
||||||
|
[c]"m"OC_CONST_ARRAY_OPERAND(ogg_int16_t,OC_IDCT_CONSTS,128)
|
||||||
|
);
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"pxor %%mm0,%%mm0\n\t"
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x00,x)"\n\t"
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x10,x)"\n\t"
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x20,x)"\n\t"
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x30,x)"\n\t"
|
||||||
|
:[x]"+m"OC_ARRAY_OPERAND(ogg_int16_t,_x,28)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Performs an inverse 8x8 Type-II DCT transform.
|
||||||
|
The input is assumed to be scaled by a factor of 4 relative to orthonormal
|
||||||
|
version of the transform.*/
|
||||||
|
void oc_idct8x8_mmx(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi){
|
||||||
|
/*_last_zzi is subtly different from an actual count of the number of
|
||||||
|
coefficients we decoded for this block.
|
||||||
|
It contains the value of zzi BEFORE the final token in the block was
|
||||||
|
decoded.
|
||||||
|
In most cases this is an EOB token (the continuation of an EOB run from a
|
||||||
|
previous block counts), and so this is the same as the coefficient count.
|
||||||
|
However, in the case that the last token was NOT an EOB token, but filled
|
||||||
|
the block up with exactly 64 coefficients, _last_zzi will be less than 64.
|
||||||
|
Provided the last token was not a pure zero run, the minimum value it can
|
||||||
|
be is 46, and so that doesn't affect any of the cases in this routine.
|
||||||
|
However, if the last token WAS a pure zero run of length 63, then _last_zzi
|
||||||
|
will be 1 while the number of coefficients decoded is 64.
|
||||||
|
Thus, we will trigger the following special case, where the real
|
||||||
|
coefficient count would not.
|
||||||
|
Note also that a zero run of length 64 will give _last_zzi a value of 0,
|
||||||
|
but we still process the DC coefficient, which might have a non-zero value
|
||||||
|
due to DC prediction.
|
||||||
|
Although convoluted, this is arguably the correct behavior: it allows us to
|
||||||
|
use a smaller transform when the block ends with a long zero run instead
|
||||||
|
of a normal EOB token.
|
||||||
|
It could be smarter... multiple separate zero runs at the end of a block
|
||||||
|
will fool it, but an encoder that generates these really deserves what it
|
||||||
|
gets.
|
||||||
|
Needless to say we inherited this approach from VP3.*/
|
||||||
|
/*Then perform the iDCT.*/
|
||||||
|
if(_last_zzi<=10)oc_idct8x8_10_mmx(_y,_x);
|
||||||
|
else oc_idct8x8_slow_mmx(_y,_x);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,318 @@
|
||||||
|
#if !defined(_x86_mmxloop_H)
|
||||||
|
# define _x86_mmxloop_H (1)
|
||||||
|
# include <stddef.h>
|
||||||
|
# include "x86int.h"
|
||||||
|
|
||||||
|
#if defined(OC_X86_ASM)
|
||||||
|
|
||||||
|
/*On entry, mm0={a0,...,a7}, mm1={b0,...,b7}, mm2={c0,...,c7}, mm3={d0,...d7}.
|
||||||
|
On exit, mm1={b0+lflim(R_0,L),...,b7+lflim(R_7,L)} and
|
||||||
|
mm2={c0-lflim(R_0,L),...,c7-lflim(R_7,L)}; mm0 and mm3 are clobbered.*/
|
||||||
|
#define OC_LOOP_FILTER8_MMX \
|
||||||
|
"#OC_LOOP_FILTER8_MMX\n\t" \
|
||||||
|
/*mm7=0*/ \
|
||||||
|
"pxor %%mm7,%%mm7\n\t" \
|
||||||
|
/*mm6:mm0={a0,...,a7}*/ \
|
||||||
|
"movq %%mm0,%%mm6\n\t" \
|
||||||
|
"punpcklbw %%mm7,%%mm0\n\t" \
|
||||||
|
"punpckhbw %%mm7,%%mm6\n\t" \
|
||||||
|
/*mm3:mm5={d0,...,d7}*/ \
|
||||||
|
"movq %%mm3,%%mm5\n\t" \
|
||||||
|
"punpcklbw %%mm7,%%mm3\n\t" \
|
||||||
|
"punpckhbw %%mm7,%%mm5\n\t" \
|
||||||
|
/*mm6:mm0={a0-d0,...,a7-d7}*/ \
|
||||||
|
"psubw %%mm3,%%mm0\n\t" \
|
||||||
|
"psubw %%mm5,%%mm6\n\t" \
|
||||||
|
/*mm3:mm1={b0,...,b7}*/ \
|
||||||
|
"movq %%mm1,%%mm3\n\t" \
|
||||||
|
"punpcklbw %%mm7,%%mm1\n\t" \
|
||||||
|
"movq %%mm2,%%mm4\n\t" \
|
||||||
|
"punpckhbw %%mm7,%%mm3\n\t" \
|
||||||
|
/*mm5:mm4={c0,...,c7}*/ \
|
||||||
|
"movq %%mm2,%%mm5\n\t" \
|
||||||
|
"punpcklbw %%mm7,%%mm4\n\t" \
|
||||||
|
"punpckhbw %%mm7,%%mm5\n\t" \
|
||||||
|
/*mm7={3}x4 \
|
||||||
|
mm5:mm4={c0-b0,...,c7-b7}*/ \
|
||||||
|
"pcmpeqw %%mm7,%%mm7\n\t" \
|
||||||
|
"psubw %%mm1,%%mm4\n\t" \
|
||||||
|
"psrlw $14,%%mm7\n\t" \
|
||||||
|
"psubw %%mm3,%%mm5\n\t" \
|
||||||
|
/*Scale by 3.*/ \
|
||||||
|
"pmullw %%mm7,%%mm4\n\t" \
|
||||||
|
"pmullw %%mm7,%%mm5\n\t" \
|
||||||
|
/*mm7={4}x4 \
|
||||||
|
mm5:mm4=f={a0-d0+3*(c0-b0),...,a7-d7+3*(c7-b7)}*/ \
|
||||||
|
"psrlw $1,%%mm7\n\t" \
|
||||||
|
"paddw %%mm0,%%mm4\n\t" \
|
||||||
|
"psllw $2,%%mm7\n\t" \
|
||||||
|
"movq (%[ll]),%%mm0\n\t" \
|
||||||
|
"paddw %%mm6,%%mm5\n\t" \
|
||||||
|
/*R_i has the range [-127,128], so we compute -R_i instead. \
|
||||||
|
mm4=-R_i=-(f+4>>3)=0xFF^(f-4>>3)*/ \
|
||||||
|
"psubw %%mm7,%%mm4\n\t" \
|
||||||
|
"psubw %%mm7,%%mm5\n\t" \
|
||||||
|
"psraw $3,%%mm4\n\t" \
|
||||||
|
"psraw $3,%%mm5\n\t" \
|
||||||
|
"pcmpeqb %%mm7,%%mm7\n\t" \
|
||||||
|
"packsswb %%mm5,%%mm4\n\t" \
|
||||||
|
"pxor %%mm6,%%mm6\n\t" \
|
||||||
|
"pxor %%mm7,%%mm4\n\t" \
|
||||||
|
"packuswb %%mm3,%%mm1\n\t" \
|
||||||
|
/*Now compute lflim of -mm4 cf. Section 7.10 of the sepc.*/ \
|
||||||
|
/*There's no unsigned byte+signed byte with unsigned saturation op code, so \
|
||||||
|
we have to split things by sign (the other option is to work in 16 bits, \
|
||||||
|
but working in 8 bits gives much better parallelism). \
|
||||||
|
We compute abs(R_i), but save a mask of which terms were negative in mm6. \
|
||||||
|
Then we compute mm4=abs(lflim(R_i,L))=min(abs(R_i),max(2*L-abs(R_i),0)). \
|
||||||
|
Finally, we split mm4 into positive and negative pieces using the mask in \
|
||||||
|
mm6, and add and subtract them as appropriate.*/ \
|
||||||
|
/*mm4=abs(-R_i)*/ \
|
||||||
|
/*mm7=255-2*L*/ \
|
||||||
|
"pcmpgtb %%mm4,%%mm6\n\t" \
|
||||||
|
"psubb %%mm0,%%mm7\n\t" \
|
||||||
|
"pxor %%mm6,%%mm4\n\t" \
|
||||||
|
"psubb %%mm0,%%mm7\n\t" \
|
||||||
|
"psubb %%mm6,%%mm4\n\t" \
|
||||||
|
/*mm7=255-max(2*L-abs(R_i),0)*/ \
|
||||||
|
"paddusb %%mm4,%%mm7\n\t" \
|
||||||
|
/*mm4=min(abs(R_i),max(2*L-abs(R_i),0))*/ \
|
||||||
|
"paddusb %%mm7,%%mm4\n\t" \
|
||||||
|
"psubusb %%mm7,%%mm4\n\t" \
|
||||||
|
/*Now split mm4 by the original sign of -R_i.*/ \
|
||||||
|
"movq %%mm4,%%mm5\n\t" \
|
||||||
|
"pand %%mm6,%%mm4\n\t" \
|
||||||
|
"pandn %%mm5,%%mm6\n\t" \
|
||||||
|
/*mm1={b0+lflim(R_0,L),...,b7+lflim(R_7,L)}*/ \
|
||||||
|
/*mm2={c0-lflim(R_0,L),...,c7-lflim(R_7,L)}*/ \
|
||||||
|
"paddusb %%mm4,%%mm1\n\t" \
|
||||||
|
"psubusb %%mm4,%%mm2\n\t" \
|
||||||
|
"psubusb %%mm6,%%mm1\n\t" \
|
||||||
|
"paddusb %%mm6,%%mm2\n\t" \
|
||||||
|
|
||||||
|
/*On entry, mm0={a0,...,a7}, mm1={b0,...,b7}, mm2={c0,...,c7}, mm3={d0,...d7}.
|
||||||
|
On exit, mm1={b0+lflim(R_0,L),...,b7+lflim(R_7,L)} and
|
||||||
|
mm2={c0-lflim(R_0,L),...,c7-lflim(R_7,L)}.
|
||||||
|
All other MMX registers are clobbered.*/
|
||||||
|
#define OC_LOOP_FILTER8_MMXEXT \
|
||||||
|
"#OC_LOOP_FILTER8_MMXEXT\n\t" \
|
||||||
|
/*R_i=(a_i-3*b_i+3*c_i-d_i+4>>3) has the range [-127,128], so we compute \
|
||||||
|
-R_i=(-a_i+3*b_i-3*c_i+d_i+3>>3) instead.*/ \
|
||||||
|
/*This first part is based on the transformation \
|
||||||
|
f = -(3*(c-b)+a-d+4>>3) \
|
||||||
|
= -(3*(c+255-b)+(a+255-d)+4-1020>>3) \
|
||||||
|
= -(3*(c+~b)+(a+~d)-1016>>3) \
|
||||||
|
= 127-(3*(c+~b)+(a+~d)>>3) \
|
||||||
|
= 128+~(3*(c+~b)+(a+~d)>>3) (mod 256). \
|
||||||
|
Although pavgb(a,b) = (a+b+1>>1) (biased up), we rely heavily on the \
|
||||||
|
fact that ~pavgb(~a,~b) = (a+b>>1) (biased down). \
|
||||||
|
Using this, the last expression above can be computed in 8 bits of working \
|
||||||
|
precision via: \
|
||||||
|
u = ~pavgb(~b,c); \
|
||||||
|
v = pavgb(b,~c); \
|
||||||
|
This mask is 0 or 0xFF, and controls whether t is biased up or down: \
|
||||||
|
m = u-v; \
|
||||||
|
t = m^pavgb(m^~a,m^d); \
|
||||||
|
f = 128+pavgb(pavgb(t,u),v); \
|
||||||
|
This required some careful analysis to ensure that carries are propagated \
|
||||||
|
correctly in all cases, but has been checked exhaustively.*/ \
|
||||||
|
/*input (a, b, c, d, ., ., ., .)*/ \
|
||||||
|
/*ff=0xFF; \
|
||||||
|
u=b; \
|
||||||
|
v=c; \
|
||||||
|
ll=255-2*L;*/ \
|
||||||
|
"pcmpeqb %%mm7,%%mm7\n\t" \
|
||||||
|
"movq %%mm1,%%mm4\n\t" \
|
||||||
|
"movq %%mm2,%%mm5\n\t" \
|
||||||
|
"movq (%[ll]),%%mm6\n\t" \
|
||||||
|
/*allocated u, v, ll, ff: (a, b, c, d, u, v, ll, ff)*/ \
|
||||||
|
/*u^=ff; \
|
||||||
|
v^=ff;*/ \
|
||||||
|
"pxor %%mm7,%%mm4\n\t" \
|
||||||
|
"pxor %%mm7,%%mm5\n\t" \
|
||||||
|
/*allocated ll: (a, b, c, d, u, v, ll, ff)*/ \
|
||||||
|
/*u=pavgb(u,c); \
|
||||||
|
v=pavgb(v,b);*/ \
|
||||||
|
"pavgb %%mm2,%%mm4\n\t" \
|
||||||
|
"pavgb %%mm1,%%mm5\n\t" \
|
||||||
|
/*u^=ff; \
|
||||||
|
a^=ff;*/ \
|
||||||
|
"pxor %%mm7,%%mm4\n\t" \
|
||||||
|
"pxor %%mm7,%%mm0\n\t" \
|
||||||
|
/*m=u-v;*/ \
|
||||||
|
"psubb %%mm5,%%mm4\n\t" \
|
||||||
|
/*freed u, allocated m: (a, b, c, d, m, v, ll, ff)*/ \
|
||||||
|
/*a^=m; \
|
||||||
|
d^=m;*/ \
|
||||||
|
"pxor %%mm4,%%mm0\n\t" \
|
||||||
|
"pxor %%mm4,%%mm3\n\t" \
|
||||||
|
/*t=pavgb(a,d);*/ \
|
||||||
|
"pavgb %%mm3,%%mm0\n\t" \
|
||||||
|
"psllw $7,%%mm7\n\t" \
|
||||||
|
/*freed a, d, ff, allocated t, of: (t, b, c, ., m, v, ll, of)*/ \
|
||||||
|
/*t^=m; \
|
||||||
|
u=m+v;*/ \
|
||||||
|
"pxor %%mm4,%%mm0\n\t" \
|
||||||
|
"paddb %%mm5,%%mm4\n\t" \
|
||||||
|
/*freed t, m, allocated f, u: (f, b, c, ., u, v, ll, of)*/ \
|
||||||
|
/*f=pavgb(f,u); \
|
||||||
|
of=128;*/ \
|
||||||
|
"pavgb %%mm4,%%mm0\n\t" \
|
||||||
|
"packsswb %%mm7,%%mm7\n\t" \
|
||||||
|
/*freed u, ff, allocated ll: (f, b, c, ., ll, v, ll, of)*/ \
|
||||||
|
/*f=pavgb(f,v);*/ \
|
||||||
|
"pavgb %%mm5,%%mm0\n\t" \
|
||||||
|
"movq %%mm7,%%mm3\n\t" \
|
||||||
|
"movq %%mm6,%%mm4\n\t" \
|
||||||
|
/*freed v, allocated of: (f, b, c, of, ll, ., ll, of)*/ \
|
||||||
|
/*Now compute lflim of R_i=-(128+mm0) cf. Section 7.10 of the sepc.*/ \
|
||||||
|
/*There's no unsigned byte+signed byte with unsigned saturation op code, so \
|
||||||
|
we have to split things by sign (the other option is to work in 16 bits, \
|
||||||
|
but staying in 8 bits gives much better parallelism).*/ \
|
||||||
|
/*Instead of adding the offset of 128 in mm3, we use it to split mm0. \
|
||||||
|
This is the same number of instructions as computing a mask and splitting \
|
||||||
|
after the lflim computation, but has shorter dependency chains.*/ \
|
||||||
|
/*mm0=R_i<0?-R_i:0 (denoted abs(R_i<0))\
|
||||||
|
mm3=R_i>0?R_i:0* (denoted abs(R_i>0))*/ \
|
||||||
|
"psubusb %%mm0,%%mm3\n\t" \
|
||||||
|
"psubusb %%mm7,%%mm0\n\t" \
|
||||||
|
/*mm6=255-max(2*L-abs(R_i<0),0) \
|
||||||
|
mm4=255-max(2*L-abs(R_i>0),0)*/ \
|
||||||
|
"paddusb %%mm3,%%mm4\n\t" \
|
||||||
|
"paddusb %%mm0,%%mm6\n\t" \
|
||||||
|
/*mm0=min(abs(R_i<0),max(2*L-abs(R_i<0),0)) \
|
||||||
|
mm3=min(abs(R_i>0),max(2*L-abs(R_i>0),0))*/ \
|
||||||
|
"paddusb %%mm4,%%mm3\n\t" \
|
||||||
|
"paddusb %%mm6,%%mm0\n\t" \
|
||||||
|
"psubusb %%mm4,%%mm3\n\t" \
|
||||||
|
"psubusb %%mm6,%%mm0\n\t" \
|
||||||
|
/*mm1={b0+lflim(R_0,L),...,b7+lflim(R_7,L)}*/ \
|
||||||
|
/*mm2={c0-lflim(R_0,L),...,c7-lflim(R_7,L)}*/ \
|
||||||
|
"paddusb %%mm3,%%mm1\n\t" \
|
||||||
|
"psubusb %%mm3,%%mm2\n\t" \
|
||||||
|
"psubusb %%mm0,%%mm1\n\t" \
|
||||||
|
"paddusb %%mm0,%%mm2\n\t" \
|
||||||
|
|
||||||
|
#define OC_LOOP_FILTER_V(_filter,_pix,_ystride,_ll) \
|
||||||
|
do{ \
|
||||||
|
ptrdiff_t ystride3__; \
|
||||||
|
__asm__ __volatile__( \
|
||||||
|
/*mm0={a0,...,a7}*/ \
|
||||||
|
"movq (%[pix]),%%mm0\n\t" \
|
||||||
|
/*ystride3=_ystride*3*/ \
|
||||||
|
"lea (%[ystride],%[ystride],2),%[ystride3]\n\t" \
|
||||||
|
/*mm3={d0,...,d7}*/ \
|
||||||
|
"movq (%[pix],%[ystride3]),%%mm3\n\t" \
|
||||||
|
/*mm1={b0,...,b7}*/ \
|
||||||
|
"movq (%[pix],%[ystride]),%%mm1\n\t" \
|
||||||
|
/*mm2={c0,...,c7}*/ \
|
||||||
|
"movq (%[pix],%[ystride],2),%%mm2\n\t" \
|
||||||
|
_filter \
|
||||||
|
/*Write it back out.*/ \
|
||||||
|
"movq %%mm1,(%[pix],%[ystride])\n\t" \
|
||||||
|
"movq %%mm2,(%[pix],%[ystride],2)\n\t" \
|
||||||
|
:[ystride3]"=&r"(ystride3__) \
|
||||||
|
:[pix]"r"(_pix-_ystride*2),[ystride]"r"((ptrdiff_t)(_ystride)), \
|
||||||
|
[ll]"r"(_ll) \
|
||||||
|
:"memory" \
|
||||||
|
); \
|
||||||
|
} \
|
||||||
|
while(0)
|
||||||
|
|
||||||
|
#define OC_LOOP_FILTER_H(_filter,_pix,_ystride,_ll) \
|
||||||
|
do{ \
|
||||||
|
unsigned char *pix__; \
|
||||||
|
ptrdiff_t ystride3__; \
|
||||||
|
ptrdiff_t d__; \
|
||||||
|
pix__=(_pix)-2; \
|
||||||
|
__asm__ __volatile__( \
|
||||||
|
/*x x x x d0 c0 b0 a0*/ \
|
||||||
|
"movd (%[pix]),%%mm0\n\t" \
|
||||||
|
/*x x x x d1 c1 b1 a1*/ \
|
||||||
|
"movd (%[pix],%[ystride]),%%mm1\n\t" \
|
||||||
|
/*ystride3=_ystride*3*/ \
|
||||||
|
"lea (%[ystride],%[ystride],2),%[ystride3]\n\t" \
|
||||||
|
/*x x x x d2 c2 b2 a2*/ \
|
||||||
|
"movd (%[pix],%[ystride],2),%%mm2\n\t" \
|
||||||
|
/*x x x x d3 c3 b3 a3*/ \
|
||||||
|
"lea (%[pix],%[ystride],4),%[d]\n\t" \
|
||||||
|
"movd (%[pix],%[ystride3]),%%mm3\n\t" \
|
||||||
|
/*x x x x d4 c4 b4 a4*/ \
|
||||||
|
"movd (%[d]),%%mm4\n\t" \
|
||||||
|
/*x x x x d5 c5 b5 a5*/ \
|
||||||
|
"movd (%[d],%[ystride]),%%mm5\n\t" \
|
||||||
|
/*x x x x d6 c6 b6 a6*/ \
|
||||||
|
"movd (%[d],%[ystride],2),%%mm6\n\t" \
|
||||||
|
/*x x x x d7 c7 b7 a7*/ \
|
||||||
|
"movd (%[d],%[ystride3]),%%mm7\n\t" \
|
||||||
|
/*mm0=d1 d0 c1 c0 b1 b0 a1 a0*/ \
|
||||||
|
"punpcklbw %%mm1,%%mm0\n\t" \
|
||||||
|
/*mm2=d3 d2 c3 c2 b3 b2 a3 a2*/ \
|
||||||
|
"punpcklbw %%mm3,%%mm2\n\t" \
|
||||||
|
/*mm3=d1 d0 c1 c0 b1 b0 a1 a0*/ \
|
||||||
|
"movq %%mm0,%%mm3\n\t" \
|
||||||
|
/*mm0=b3 b2 b1 b0 a3 a2 a1 a0*/ \
|
||||||
|
"punpcklwd %%mm2,%%mm0\n\t" \
|
||||||
|
/*mm3=d3 d2 d1 d0 c3 c2 c1 c0*/ \
|
||||||
|
"punpckhwd %%mm2,%%mm3\n\t" \
|
||||||
|
/*mm1=b3 b2 b1 b0 a3 a2 a1 a0*/ \
|
||||||
|
"movq %%mm0,%%mm1\n\t" \
|
||||||
|
/*mm4=d5 d4 c5 c4 b5 b4 a5 a4*/ \
|
||||||
|
"punpcklbw %%mm5,%%mm4\n\t" \
|
||||||
|
/*mm6=d7 d6 c7 c6 b7 b6 a7 a6*/ \
|
||||||
|
"punpcklbw %%mm7,%%mm6\n\t" \
|
||||||
|
/*mm5=d5 d4 c5 c4 b5 b4 a5 a4*/ \
|
||||||
|
"movq %%mm4,%%mm5\n\t" \
|
||||||
|
/*mm4=b7 b6 b5 b4 a7 a6 a5 a4*/ \
|
||||||
|
"punpcklwd %%mm6,%%mm4\n\t" \
|
||||||
|
/*mm5=d7 d6 d5 d4 c7 c6 c5 c4*/ \
|
||||||
|
"punpckhwd %%mm6,%%mm5\n\t" \
|
||||||
|
/*mm2=d3 d2 d1 d0 c3 c2 c1 c0*/ \
|
||||||
|
"movq %%mm3,%%mm2\n\t" \
|
||||||
|
/*mm0=a7 a6 a5 a4 a3 a2 a1 a0*/ \
|
||||||
|
"punpckldq %%mm4,%%mm0\n\t" \
|
||||||
|
/*mm1=b7 b6 b5 b4 b3 b2 b1 b0*/ \
|
||||||
|
"punpckhdq %%mm4,%%mm1\n\t" \
|
||||||
|
/*mm2=c7 c6 c5 c4 c3 c2 c1 c0*/ \
|
||||||
|
"punpckldq %%mm5,%%mm2\n\t" \
|
||||||
|
/*mm3=d7 d6 d5 d4 d3 d2 d1 d0*/ \
|
||||||
|
"punpckhdq %%mm5,%%mm3\n\t" \
|
||||||
|
_filter \
|
||||||
|
/*mm2={b0+R_0'',...,b7+R_7''}*/ \
|
||||||
|
"movq %%mm1,%%mm0\n\t" \
|
||||||
|
/*mm1={b0+R_0'',c0-R_0'',...,b3+R_3'',c3-R_3''}*/ \
|
||||||
|
"punpcklbw %%mm2,%%mm1\n\t" \
|
||||||
|
/*mm2={b4+R_4'',c4-R_4'',...,b7+R_7'',c7-R_7''}*/ \
|
||||||
|
"punpckhbw %%mm2,%%mm0\n\t" \
|
||||||
|
/*[d]=c1 b1 c0 b0*/ \
|
||||||
|
"movd %%mm1,%[d]\n\t" \
|
||||||
|
"movw %w[d],1(%[pix])\n\t" \
|
||||||
|
"psrlq $32,%%mm1\n\t" \
|
||||||
|
"shr $16,%[d]\n\t" \
|
||||||
|
"movw %w[d],1(%[pix],%[ystride])\n\t" \
|
||||||
|
/*[d]=c3 b3 c2 b2*/ \
|
||||||
|
"movd %%mm1,%[d]\n\t" \
|
||||||
|
"movw %w[d],1(%[pix],%[ystride],2)\n\t" \
|
||||||
|
"shr $16,%[d]\n\t" \
|
||||||
|
"movw %w[d],1(%[pix],%[ystride3])\n\t" \
|
||||||
|
"lea (%[pix],%[ystride],4),%[pix]\n\t" \
|
||||||
|
/*[d]=c5 b5 c4 b4*/ \
|
||||||
|
"movd %%mm0,%[d]\n\t" \
|
||||||
|
"movw %w[d],1(%[pix])\n\t" \
|
||||||
|
"psrlq $32,%%mm0\n\t" \
|
||||||
|
"shr $16,%[d]\n\t" \
|
||||||
|
"movw %w[d],1(%[pix],%[ystride])\n\t" \
|
||||||
|
/*[d]=c7 b7 c6 b6*/ \
|
||||||
|
"movd %%mm0,%[d]\n\t" \
|
||||||
|
"movw %w[d],1(%[pix],%[ystride],2)\n\t" \
|
||||||
|
"shr $16,%[d]\n\t" \
|
||||||
|
"movw %w[d],1(%[pix],%[ystride3])\n\t" \
|
||||||
|
:[pix]"+r"(pix__),[ystride3]"=&r"(ystride3__),[d]"=&r"(d__) \
|
||||||
|
:[ystride]"r"((ptrdiff_t)(_ystride)),[ll]"r"(_ll) \
|
||||||
|
:"memory" \
|
||||||
|
); \
|
||||||
|
} \
|
||||||
|
while(0)
|
||||||
|
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,226 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
/*MMX acceleration of complete fragment reconstruction algorithm.
|
||||||
|
Originally written by Rudolf Marek.*/
|
||||||
|
#include <string.h>
|
||||||
|
#include "x86int.h"
|
||||||
|
#include "mmxloop.h"
|
||||||
|
|
||||||
|
#if defined(OC_X86_ASM)
|
||||||
|
|
||||||
|
void oc_state_frag_recon_mmx(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||||
|
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant){
|
||||||
|
unsigned char *dst;
|
||||||
|
ptrdiff_t frag_buf_off;
|
||||||
|
int ystride;
|
||||||
|
int refi;
|
||||||
|
/*Apply the inverse transform.*/
|
||||||
|
/*Special case only having a DC component.*/
|
||||||
|
if(_last_zzi<2){
|
||||||
|
/*Note that this value must be unsigned, to keep the __asm__ block from
|
||||||
|
sign-extending it when it puts it in a register.*/
|
||||||
|
ogg_uint16_t p;
|
||||||
|
int i;
|
||||||
|
/*We round this dequant product (and not any of the others) because there's
|
||||||
|
no iDCT rounding.*/
|
||||||
|
p=(ogg_int16_t)(_dct_coeffs[0]*(ogg_int32_t)_dc_quant+15>>5);
|
||||||
|
/*Fill _dct_coeffs with p.*/
|
||||||
|
__asm__ __volatile__(
|
||||||
|
/*mm0=0000 0000 0000 AAAA*/
|
||||||
|
"movd %[p],%%mm0\n\t"
|
||||||
|
/*mm0=0000 0000 AAAA AAAA*/
|
||||||
|
"punpcklwd %%mm0,%%mm0\n\t"
|
||||||
|
/*mm0=AAAA AAAA AAAA AAAA*/
|
||||||
|
"punpckldq %%mm0,%%mm0\n\t"
|
||||||
|
:
|
||||||
|
:[p]"r"((unsigned)p)
|
||||||
|
);
|
||||||
|
for(i=0;i<4;i++){
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x00,y)"\n\t"
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x08,y)"\n\t"
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x10,y)"\n\t"
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x18,y)"\n\t"
|
||||||
|
:[y]"=m"OC_ARRAY_OPERAND(ogg_int16_t,_dct_coeffs+64+16*i,16)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
/*Dequantize the DC coefficient.*/
|
||||||
|
_dct_coeffs[0]=(ogg_int16_t)(_dct_coeffs[0]*(int)_dc_quant);
|
||||||
|
oc_idct8x8(_state,_dct_coeffs+64,_dct_coeffs,_last_zzi);
|
||||||
|
}
|
||||||
|
/*Fill in the target buffer.*/
|
||||||
|
frag_buf_off=_state->frag_buf_offs[_fragi];
|
||||||
|
refi=_state->frags[_fragi].refi;
|
||||||
|
ystride=_state->ref_ystride[_pli];
|
||||||
|
dst=_state->ref_frame_data[OC_FRAME_SELF]+frag_buf_off;
|
||||||
|
if(refi==OC_FRAME_SELF)oc_frag_recon_intra_mmx(dst,ystride,_dct_coeffs+64);
|
||||||
|
else{
|
||||||
|
const unsigned char *ref;
|
||||||
|
int mvoffsets[2];
|
||||||
|
ref=_state->ref_frame_data[refi]+frag_buf_off;
|
||||||
|
if(oc_state_get_mv_offsets(_state,mvoffsets,_pli,
|
||||||
|
_state->frag_mvs[_fragi])>1){
|
||||||
|
oc_frag_recon_inter2_mmx(dst,ref+mvoffsets[0],ref+mvoffsets[1],ystride,
|
||||||
|
_dct_coeffs+64);
|
||||||
|
}
|
||||||
|
else oc_frag_recon_inter_mmx(dst,ref+mvoffsets[0],ystride,_dct_coeffs+64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*We copy these entire function to inline the actual MMX routines so that we
|
||||||
|
use only a single indirect call.*/
|
||||||
|
|
||||||
|
void oc_loop_filter_init_mmx(signed char _bv[256],int _flimit){
|
||||||
|
memset(_bv,_flimit,8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Apply the loop filter to a given set of fragment rows in the given plane.
|
||||||
|
The filter may be run on the bottom edge, affecting pixels in the next row of
|
||||||
|
fragments, so this row also needs to be available.
|
||||||
|
_bv: The bounding values array.
|
||||||
|
_refi: The index of the frame buffer to filter.
|
||||||
|
_pli: The color plane to filter.
|
||||||
|
_fragy0: The Y coordinate of the first fragment row to filter.
|
||||||
|
_fragy_end: The Y coordinate of the fragment row to stop filtering at.*/
|
||||||
|
void oc_state_loop_filter_frag_rows_mmx(const oc_theora_state *_state,
|
||||||
|
signed char _bv[256],int _refi,int _pli,int _fragy0,int _fragy_end){
|
||||||
|
OC_ALIGN8(unsigned char ll[8]);
|
||||||
|
const oc_fragment_plane *fplane;
|
||||||
|
const oc_fragment *frags;
|
||||||
|
const ptrdiff_t *frag_buf_offs;
|
||||||
|
unsigned char *ref_frame_data;
|
||||||
|
ptrdiff_t fragi_top;
|
||||||
|
ptrdiff_t fragi_bot;
|
||||||
|
ptrdiff_t fragi0;
|
||||||
|
ptrdiff_t fragi0_end;
|
||||||
|
int ystride;
|
||||||
|
int nhfrags;
|
||||||
|
memset(ll,_state->loop_filter_limits[_state->qis[0]],sizeof(ll));
|
||||||
|
fplane=_state->fplanes+_pli;
|
||||||
|
nhfrags=fplane->nhfrags;
|
||||||
|
fragi_top=fplane->froffset;
|
||||||
|
fragi_bot=fragi_top+fplane->nfrags;
|
||||||
|
fragi0=fragi_top+_fragy0*(ptrdiff_t)nhfrags;
|
||||||
|
fragi0_end=fragi0+(_fragy_end-_fragy0)*(ptrdiff_t)nhfrags;
|
||||||
|
ystride=_state->ref_ystride[_pli];
|
||||||
|
frags=_state->frags;
|
||||||
|
frag_buf_offs=_state->frag_buf_offs;
|
||||||
|
ref_frame_data=_state->ref_frame_data[_refi];
|
||||||
|
/*The following loops are constructed somewhat non-intuitively on purpose.
|
||||||
|
The main idea is: if a block boundary has at least one coded fragment on
|
||||||
|
it, the filter is applied to it.
|
||||||
|
However, the order that the filters are applied in matters, and VP3 chose
|
||||||
|
the somewhat strange ordering used below.*/
|
||||||
|
while(fragi0<fragi0_end){
|
||||||
|
ptrdiff_t fragi;
|
||||||
|
ptrdiff_t fragi_end;
|
||||||
|
fragi=fragi0;
|
||||||
|
fragi_end=fragi+nhfrags;
|
||||||
|
while(fragi<fragi_end){
|
||||||
|
if(frags[fragi].coded){
|
||||||
|
unsigned char *ref;
|
||||||
|
ref=ref_frame_data+frag_buf_offs[fragi];
|
||||||
|
if(fragi>fragi0){
|
||||||
|
OC_LOOP_FILTER_H(OC_LOOP_FILTER8_MMX,ref,ystride,ll);
|
||||||
|
}
|
||||||
|
if(fragi0>fragi_top){
|
||||||
|
OC_LOOP_FILTER_V(OC_LOOP_FILTER8_MMX,ref,ystride,ll);
|
||||||
|
}
|
||||||
|
if(fragi+1<fragi_end&&!frags[fragi+1].coded){
|
||||||
|
OC_LOOP_FILTER_H(OC_LOOP_FILTER8_MMX,ref+8,ystride,ll);
|
||||||
|
}
|
||||||
|
if(fragi+nhfrags<fragi_bot&&!frags[fragi+nhfrags].coded){
|
||||||
|
OC_LOOP_FILTER_V(OC_LOOP_FILTER8_MMX,ref+(ystride<<3),ystride,ll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragi++;
|
||||||
|
}
|
||||||
|
fragi0+=nhfrags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_loop_filter_init_mmxext(signed char _bv[256],int _flimit){
|
||||||
|
memset(_bv,~(_flimit<<1),8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Apply the loop filter to a given set of fragment rows in the given plane.
|
||||||
|
The filter may be run on the bottom edge, affecting pixels in the next row of
|
||||||
|
fragments, so this row also needs to be available.
|
||||||
|
_bv: The bounding values array.
|
||||||
|
_refi: The index of the frame buffer to filter.
|
||||||
|
_pli: The color plane to filter.
|
||||||
|
_fragy0: The Y coordinate of the first fragment row to filter.
|
||||||
|
_fragy_end: The Y coordinate of the fragment row to stop filtering at.*/
|
||||||
|
void oc_state_loop_filter_frag_rows_mmxext(const oc_theora_state *_state,
|
||||||
|
signed char _bv[256],int _refi,int _pli,int _fragy0,int _fragy_end){
|
||||||
|
const oc_fragment_plane *fplane;
|
||||||
|
const oc_fragment *frags;
|
||||||
|
const ptrdiff_t *frag_buf_offs;
|
||||||
|
unsigned char *ref_frame_data;
|
||||||
|
ptrdiff_t fragi_top;
|
||||||
|
ptrdiff_t fragi_bot;
|
||||||
|
ptrdiff_t fragi0;
|
||||||
|
ptrdiff_t fragi0_end;
|
||||||
|
int ystride;
|
||||||
|
int nhfrags;
|
||||||
|
fplane=_state->fplanes+_pli;
|
||||||
|
nhfrags=fplane->nhfrags;
|
||||||
|
fragi_top=fplane->froffset;
|
||||||
|
fragi_bot=fragi_top+fplane->nfrags;
|
||||||
|
fragi0=fragi_top+_fragy0*(ptrdiff_t)nhfrags;
|
||||||
|
fragi0_end=fragi_top+_fragy_end*(ptrdiff_t)nhfrags;
|
||||||
|
ystride=_state->ref_ystride[_pli];
|
||||||
|
frags=_state->frags;
|
||||||
|
frag_buf_offs=_state->frag_buf_offs;
|
||||||
|
ref_frame_data=_state->ref_frame_data[_refi];
|
||||||
|
/*The following loops are constructed somewhat non-intuitively on purpose.
|
||||||
|
The main idea is: if a block boundary has at least one coded fragment on
|
||||||
|
it, the filter is applied to it.
|
||||||
|
However, the order that the filters are applied in matters, and VP3 chose
|
||||||
|
the somewhat strange ordering used below.*/
|
||||||
|
while(fragi0<fragi0_end){
|
||||||
|
ptrdiff_t fragi;
|
||||||
|
ptrdiff_t fragi_end;
|
||||||
|
fragi=fragi0;
|
||||||
|
fragi_end=fragi+nhfrags;
|
||||||
|
while(fragi<fragi_end){
|
||||||
|
if(frags[fragi].coded){
|
||||||
|
unsigned char *ref;
|
||||||
|
ref=ref_frame_data+frag_buf_offs[fragi];
|
||||||
|
if(fragi>fragi0){
|
||||||
|
OC_LOOP_FILTER_H(OC_LOOP_FILTER8_MMXEXT,ref,ystride,_bv);
|
||||||
|
}
|
||||||
|
if(fragi0>fragi_top){
|
||||||
|
OC_LOOP_FILTER_V(OC_LOOP_FILTER8_MMXEXT,ref,ystride,_bv);
|
||||||
|
}
|
||||||
|
if(fragi+1<fragi_end&&!frags[fragi+1].coded){
|
||||||
|
OC_LOOP_FILTER_H(OC_LOOP_FILTER8_MMXEXT,ref+8,ystride,_bv);
|
||||||
|
}
|
||||||
|
if(fragi+nhfrags<fragi_bot&&!frags[fragi+nhfrags].coded){
|
||||||
|
OC_LOOP_FILTER_V(OC_LOOP_FILTER8_MMXEXT,ref+(ystride<<3),ystride,_bv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragi++;
|
||||||
|
}
|
||||||
|
fragi0+=nhfrags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,456 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id: mmxidct.c 16503 2009-08-22 18:14:02Z giles $
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
/*SSE2 acceleration of Theora's iDCT.*/
|
||||||
|
#include "x86int.h"
|
||||||
|
#include "sse2trans.h"
|
||||||
|
#include "../dct.h"
|
||||||
|
|
||||||
|
#if defined(OC_X86_ASM)
|
||||||
|
|
||||||
|
/*A table of constants used by the MMX routines.*/
|
||||||
|
const unsigned short __attribute__((aligned(16),used)) OC_IDCT_CONSTS[64]={
|
||||||
|
8, 8, 8, 8, 8, 8, 8, 8,
|
||||||
|
OC_C1S7,OC_C1S7,OC_C1S7,OC_C1S7,OC_C1S7,OC_C1S7,OC_C1S7,OC_C1S7,
|
||||||
|
OC_C2S6,OC_C2S6,OC_C2S6,OC_C2S6,OC_C2S6,OC_C2S6,OC_C2S6,OC_C2S6,
|
||||||
|
OC_C3S5,OC_C3S5,OC_C3S5,OC_C3S5,OC_C3S5,OC_C3S5,OC_C3S5,OC_C3S5,
|
||||||
|
OC_C4S4,OC_C4S4,OC_C4S4,OC_C4S4,OC_C4S4,OC_C4S4,OC_C4S4,OC_C4S4,
|
||||||
|
OC_C5S3,OC_C5S3,OC_C5S3,OC_C5S3,OC_C5S3,OC_C5S3,OC_C5S3,OC_C5S3,
|
||||||
|
OC_C6S2,OC_C6S2,OC_C6S2,OC_C6S2,OC_C6S2,OC_C6S2,OC_C6S2,OC_C6S2,
|
||||||
|
OC_C7S1,OC_C7S1,OC_C7S1,OC_C7S1,OC_C7S1,OC_C7S1,OC_C7S1,OC_C7S1
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*Performs the first three stages of the iDCT.
|
||||||
|
xmm2, xmm6, xmm3, and xmm5 must contain the corresponding rows of the input
|
||||||
|
(accessed in that order).
|
||||||
|
The remaining rows must be in _x at their corresponding locations.
|
||||||
|
On output, xmm7 down to xmm4 contain rows 0 through 3, and xmm0 up to xmm3
|
||||||
|
contain rows 4 through 7.*/
|
||||||
|
#define OC_IDCT_8x8_ABC(_x) \
|
||||||
|
"#OC_IDCT_8x8_ABC\n\t" \
|
||||||
|
/*Stage 1:*/ \
|
||||||
|
/*2-3 rotation by 6pi/16. \
|
||||||
|
xmm4=xmm7=C6, xmm0=xmm1=C2, xmm2=X2, xmm6=X6.*/ \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x20,c)",%%xmm1\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x60,c)",%%xmm4\n\t" \
|
||||||
|
"movdqa %%xmm1,%%xmm0\n\t" \
|
||||||
|
"pmulhw %%xmm2,%%xmm1\n\t" \
|
||||||
|
"movdqa %%xmm4,%%xmm7\n\t" \
|
||||||
|
"pmulhw %%xmm6,%%xmm0\n\t" \
|
||||||
|
"pmulhw %%xmm2,%%xmm7\n\t" \
|
||||||
|
"pmulhw %%xmm6,%%xmm4\n\t" \
|
||||||
|
"paddw %%xmm6,%%xmm0\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x30,c)",%%xmm6\n\t" \
|
||||||
|
"paddw %%xmm1,%%xmm2\n\t" \
|
||||||
|
"psubw %%xmm0,%%xmm7\n\t" \
|
||||||
|
"movdqa %%xmm7,"OC_MEM_OFFS(0x00,buf)"\n\t" \
|
||||||
|
"paddw %%xmm4,%%xmm2\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x50,c)",%%xmm4\n\t" \
|
||||||
|
"movdqa %%xmm2,"OC_MEM_OFFS(0x10,buf)"\n\t" \
|
||||||
|
/*5-6 rotation by 3pi/16. \
|
||||||
|
xmm4=xmm2=C5, xmm1=xmm6=C3, xmm3=X3, xmm5=X5.*/ \
|
||||||
|
"movdqa %%xmm4,%%xmm2\n\t" \
|
||||||
|
"movdqa %%xmm6,%%xmm1\n\t" \
|
||||||
|
"pmulhw %%xmm3,%%xmm4\n\t" \
|
||||||
|
"pmulhw %%xmm5,%%xmm1\n\t" \
|
||||||
|
"pmulhw %%xmm3,%%xmm6\n\t" \
|
||||||
|
"pmulhw %%xmm5,%%xmm2\n\t" \
|
||||||
|
"paddw %%xmm3,%%xmm4\n\t" \
|
||||||
|
"paddw %%xmm5,%%xmm3\n\t" \
|
||||||
|
"paddw %%xmm6,%%xmm3\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x70,_x)",%%xmm6\n\t" \
|
||||||
|
"paddw %%xmm5,%%xmm1\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x10,_x)",%%xmm5\n\t" \
|
||||||
|
"paddw %%xmm3,%%xmm2\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x70,c)",%%xmm3\n\t" \
|
||||||
|
"psubw %%xmm4,%%xmm1\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x10,c)",%%xmm4\n\t" \
|
||||||
|
/*4-7 rotation by 7pi/16. \
|
||||||
|
xmm4=xmm7=C1, xmm3=xmm0=C7, xmm5=X1, xmm6=X7.*/ \
|
||||||
|
"movdqa %%xmm3,%%xmm0\n\t" \
|
||||||
|
"movdqa %%xmm4,%%xmm7\n\t" \
|
||||||
|
"pmulhw %%xmm5,%%xmm3\n\t" \
|
||||||
|
"pmulhw %%xmm5,%%xmm7\n\t" \
|
||||||
|
"pmulhw %%xmm6,%%xmm4\n\t" \
|
||||||
|
"pmulhw %%xmm6,%%xmm0\n\t" \
|
||||||
|
"paddw %%xmm6,%%xmm4\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x40,_x)",%%xmm6\n\t" \
|
||||||
|
"paddw %%xmm5,%%xmm7\n\t" \
|
||||||
|
"psubw %%xmm4,%%xmm3\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x40,c)",%%xmm4\n\t" \
|
||||||
|
"paddw %%xmm7,%%xmm0\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x00,_x)",%%xmm7\n\t" \
|
||||||
|
/*0-1 butterfly. \
|
||||||
|
xmm4=xmm5=C4, xmm7=X0, xmm6=X4.*/ \
|
||||||
|
"paddw %%xmm7,%%xmm6\n\t" \
|
||||||
|
"movdqa %%xmm4,%%xmm5\n\t" \
|
||||||
|
"pmulhw %%xmm6,%%xmm4\n\t" \
|
||||||
|
"paddw %%xmm7,%%xmm7\n\t" \
|
||||||
|
"psubw %%xmm6,%%xmm7\n\t" \
|
||||||
|
"paddw %%xmm6,%%xmm4\n\t" \
|
||||||
|
/*Stage 2:*/ \
|
||||||
|
/*4-5 butterfly: xmm3=t[4], xmm1=t[5] \
|
||||||
|
7-6 butterfly: xmm2=t[6], xmm0=t[7]*/ \
|
||||||
|
"movdqa %%xmm3,%%xmm6\n\t" \
|
||||||
|
"paddw %%xmm1,%%xmm3\n\t" \
|
||||||
|
"psubw %%xmm1,%%xmm6\n\t" \
|
||||||
|
"movdqa %%xmm5,%%xmm1\n\t" \
|
||||||
|
"pmulhw %%xmm7,%%xmm5\n\t" \
|
||||||
|
"paddw %%xmm7,%%xmm5\n\t" \
|
||||||
|
"movdqa %%xmm0,%%xmm7\n\t" \
|
||||||
|
"paddw %%xmm2,%%xmm0\n\t" \
|
||||||
|
"psubw %%xmm2,%%xmm7\n\t" \
|
||||||
|
"movdqa %%xmm1,%%xmm2\n\t" \
|
||||||
|
"pmulhw %%xmm6,%%xmm1\n\t" \
|
||||||
|
"pmulhw %%xmm7,%%xmm2\n\t" \
|
||||||
|
"paddw %%xmm6,%%xmm1\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x00,buf)",%%xmm6\n\t" \
|
||||||
|
"paddw %%xmm7,%%xmm2\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x10,buf)",%%xmm7\n\t" \
|
||||||
|
/*Stage 3: \
|
||||||
|
6-5 butterfly: xmm1=t[5], xmm2=t[6] -> xmm1=t[6]+t[5], xmm2=t[6]-t[5] \
|
||||||
|
0-3 butterfly: xmm4=t[0], xmm7=t[3] -> xmm7=t[0]+t[3], xmm4=t[0]-t[3] \
|
||||||
|
1-2 butterfly: xmm5=t[1], xmm6=t[2] -> xmm6=t[1]+t[2], xmm5=t[1]-t[2]*/ \
|
||||||
|
"paddw %%xmm2,%%xmm1\n\t" \
|
||||||
|
"paddw %%xmm5,%%xmm6\n\t" \
|
||||||
|
"paddw %%xmm4,%%xmm7\n\t" \
|
||||||
|
"paddw %%xmm2,%%xmm2\n\t" \
|
||||||
|
"paddw %%xmm4,%%xmm4\n\t" \
|
||||||
|
"paddw %%xmm5,%%xmm5\n\t" \
|
||||||
|
"psubw %%xmm1,%%xmm2\n\t" \
|
||||||
|
"psubw %%xmm7,%%xmm4\n\t" \
|
||||||
|
"psubw %%xmm6,%%xmm5\n\t" \
|
||||||
|
|
||||||
|
/*Performs the last stage of the iDCT.
|
||||||
|
On input, xmm7 down to xmm4 contain rows 0 through 3, and xmm0 up to xmm3
|
||||||
|
contain rows 4 through 7.
|
||||||
|
On output, xmm0 through xmm7 contain the corresponding rows.*/
|
||||||
|
#define OC_IDCT_8x8_D \
|
||||||
|
"#OC_IDCT_8x8_D\n\t" \
|
||||||
|
/*Stage 4: \
|
||||||
|
0-7 butterfly: xmm7=t[0], xmm0=t[7] -> xmm0=t[0]+t[7], xmm7=t[0]-t[7] \
|
||||||
|
1-6 butterfly: xmm6=t[1], xmm1=t[6] -> xmm1=t[1]+t[6], xmm6=t[1]-t[6] \
|
||||||
|
2-5 butterfly: xmm5=t[2], xmm2=t[5] -> xmm2=t[2]+t[5], xmm5=t[2]-t[5] \
|
||||||
|
3-4 butterfly: xmm4=t[3], xmm3=t[4] -> xmm3=t[3]+t[4], xmm4=t[3]-t[4]*/ \
|
||||||
|
"psubw %%xmm0,%%xmm7\n\t" \
|
||||||
|
"psubw %%xmm1,%%xmm6\n\t" \
|
||||||
|
"psubw %%xmm2,%%xmm5\n\t" \
|
||||||
|
"psubw %%xmm3,%%xmm4\n\t" \
|
||||||
|
"paddw %%xmm0,%%xmm0\n\t" \
|
||||||
|
"paddw %%xmm1,%%xmm1\n\t" \
|
||||||
|
"paddw %%xmm2,%%xmm2\n\t" \
|
||||||
|
"paddw %%xmm3,%%xmm3\n\t" \
|
||||||
|
"paddw %%xmm7,%%xmm0\n\t" \
|
||||||
|
"paddw %%xmm6,%%xmm1\n\t" \
|
||||||
|
"paddw %%xmm5,%%xmm2\n\t" \
|
||||||
|
"paddw %%xmm4,%%xmm3\n\t" \
|
||||||
|
|
||||||
|
/*Performs the last stage of the iDCT.
|
||||||
|
On input, xmm7 down to xmm4 contain rows 0 through 3, and xmm0 up to xmm3
|
||||||
|
contain rows 4 through 7.
|
||||||
|
On output, xmm0 through xmm7 contain the corresponding rows.*/
|
||||||
|
#define OC_IDCT_8x8_D_STORE \
|
||||||
|
"#OC_IDCT_8x8_D_STORE\n\t" \
|
||||||
|
/*Stage 4: \
|
||||||
|
0-7 butterfly: xmm7=t[0], xmm0=t[7] -> xmm0=t[0]+t[7], xmm7=t[0]-t[7] \
|
||||||
|
1-6 butterfly: xmm6=t[1], xmm1=t[6] -> xmm1=t[1]+t[6], xmm6=t[1]-t[6] \
|
||||||
|
2-5 butterfly: xmm5=t[2], xmm2=t[5] -> xmm2=t[2]+t[5], xmm5=t[2]-t[5] \
|
||||||
|
3-4 butterfly: xmm4=t[3], xmm3=t[4] -> xmm3=t[3]+t[4], xmm4=t[3]-t[4]*/ \
|
||||||
|
"psubw %%xmm3,%%xmm4\n\t" \
|
||||||
|
"movdqa %%xmm4,"OC_MEM_OFFS(0x40,y)"\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x00,c)",%%xmm4\n\t" \
|
||||||
|
"psubw %%xmm0,%%xmm7\n\t" \
|
||||||
|
"psubw %%xmm1,%%xmm6\n\t" \
|
||||||
|
"psubw %%xmm2,%%xmm5\n\t" \
|
||||||
|
"paddw %%xmm4,%%xmm7\n\t" \
|
||||||
|
"paddw %%xmm4,%%xmm6\n\t" \
|
||||||
|
"paddw %%xmm4,%%xmm5\n\t" \
|
||||||
|
"paddw "OC_MEM_OFFS(0x40,y)",%%xmm4\n\t" \
|
||||||
|
"paddw %%xmm0,%%xmm0\n\t" \
|
||||||
|
"paddw %%xmm1,%%xmm1\n\t" \
|
||||||
|
"paddw %%xmm2,%%xmm2\n\t" \
|
||||||
|
"paddw %%xmm3,%%xmm3\n\t" \
|
||||||
|
"paddw %%xmm7,%%xmm0\n\t" \
|
||||||
|
"paddw %%xmm6,%%xmm1\n\t" \
|
||||||
|
"psraw $4,%%xmm0\n\t" \
|
||||||
|
"paddw %%xmm5,%%xmm2\n\t" \
|
||||||
|
"movdqa %%xmm0,"OC_MEM_OFFS(0x00,y)"\n\t" \
|
||||||
|
"psraw $4,%%xmm1\n\t" \
|
||||||
|
"paddw %%xmm4,%%xmm3\n\t" \
|
||||||
|
"movdqa %%xmm1,"OC_MEM_OFFS(0x10,y)"\n\t" \
|
||||||
|
"psraw $4,%%xmm2\n\t" \
|
||||||
|
"movdqa %%xmm2,"OC_MEM_OFFS(0x20,y)"\n\t" \
|
||||||
|
"psraw $4,%%xmm3\n\t" \
|
||||||
|
"movdqa %%xmm3,"OC_MEM_OFFS(0x30,y)"\n\t" \
|
||||||
|
"psraw $4,%%xmm4\n\t" \
|
||||||
|
"movdqa %%xmm4,"OC_MEM_OFFS(0x40,y)"\n\t" \
|
||||||
|
"psraw $4,%%xmm5\n\t" \
|
||||||
|
"movdqa %%xmm5,"OC_MEM_OFFS(0x50,y)"\n\t" \
|
||||||
|
"psraw $4,%%xmm6\n\t" \
|
||||||
|
"movdqa %%xmm6,"OC_MEM_OFFS(0x60,y)"\n\t" \
|
||||||
|
"psraw $4,%%xmm7\n\t" \
|
||||||
|
"movdqa %%xmm7,"OC_MEM_OFFS(0x70,y)"\n\t" \
|
||||||
|
|
||||||
|
static void oc_idct8x8_slow_sse2(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||||
|
OC_ALIGN16(ogg_int16_t buf[16]);
|
||||||
|
int i;
|
||||||
|
/*This routine accepts an 8x8 matrix pre-transposed.*/
|
||||||
|
__asm__ __volatile__(
|
||||||
|
/*Load rows 2, 3, 5, and 6 for the first stage of the iDCT.*/
|
||||||
|
"movdqa "OC_MEM_OFFS(0x20,x)",%%xmm2\n\t"
|
||||||
|
"movdqa "OC_MEM_OFFS(0x60,x)",%%xmm6\n\t"
|
||||||
|
"movdqa "OC_MEM_OFFS(0x30,x)",%%xmm3\n\t"
|
||||||
|
"movdqa "OC_MEM_OFFS(0x50,x)",%%xmm5\n\t"
|
||||||
|
OC_IDCT_8x8_ABC(x)
|
||||||
|
OC_IDCT_8x8_D
|
||||||
|
OC_TRANSPOSE_8x8
|
||||||
|
/*Clear out rows 0, 1, 4, and 7 for the first stage of the iDCT.*/
|
||||||
|
"movdqa %%xmm7,"OC_MEM_OFFS(0x70,y)"\n\t"
|
||||||
|
"movdqa %%xmm4,"OC_MEM_OFFS(0x40,y)"\n\t"
|
||||||
|
"movdqa %%xmm1,"OC_MEM_OFFS(0x10,y)"\n\t"
|
||||||
|
"movdqa %%xmm0,"OC_MEM_OFFS(0x00,y)"\n\t"
|
||||||
|
OC_IDCT_8x8_ABC(y)
|
||||||
|
OC_IDCT_8x8_D_STORE
|
||||||
|
:[buf]"=m"(OC_ARRAY_OPERAND(ogg_int16_t,buf,16)),
|
||||||
|
[y]"=m"(OC_ARRAY_OPERAND(ogg_int16_t,_y,64))
|
||||||
|
:[x]"m"(OC_CONST_ARRAY_OPERAND(ogg_int16_t,_x,64)),
|
||||||
|
[c]"m"(OC_CONST_ARRAY_OPERAND(ogg_int16_t,OC_IDCT_CONSTS,128))
|
||||||
|
);
|
||||||
|
__asm__ __volatile__("pxor %%xmm0,%%xmm0\n\t"::);
|
||||||
|
/*Clear input data for next block (decoder only).*/
|
||||||
|
for(i=0;i<2;i++){
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"movdqa %%xmm0,"OC_MEM_OFFS(0x00,x)"\n\t"
|
||||||
|
"movdqa %%xmm0,"OC_MEM_OFFS(0x10,x)"\n\t"
|
||||||
|
"movdqa %%xmm0,"OC_MEM_OFFS(0x20,x)"\n\t"
|
||||||
|
"movdqa %%xmm0,"OC_MEM_OFFS(0x30,x)"\n\t"
|
||||||
|
:[x]"=m"(OC_ARRAY_OPERAND(ogg_int16_t,_x+i*32,32))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*For the first step of the 10-coefficient version of the 8x8 iDCT, we only
|
||||||
|
need to work with four columns at a time.
|
||||||
|
Doing this in MMX is faster on processors with a 64-bit data path.*/
|
||||||
|
#define OC_IDCT_8x8_10_MMX \
|
||||||
|
"#OC_IDCT_8x8_10_MMX\n\t" \
|
||||||
|
/*Stage 1:*/ \
|
||||||
|
/*2-3 rotation by 6pi/16. \
|
||||||
|
mm7=C6, mm6=C2, mm2=X2, X6=0.*/ \
|
||||||
|
"movq "OC_MEM_OFFS(0x60,c)",%%mm7\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x20,c)",%%mm6\n\t" \
|
||||||
|
"pmulhw %%mm2,%%mm6\n\t" \
|
||||||
|
"pmulhw %%mm2,%%mm7\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x50,c)",%%mm5\n\t" \
|
||||||
|
"paddw %%mm6,%%mm2\n\t" \
|
||||||
|
"movq %%mm2,"OC_MEM_OFFS(0x10,buf)"\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x30,c)",%%mm2\n\t" \
|
||||||
|
"movq %%mm7,"OC_MEM_OFFS(0x00,buf)"\n\t" \
|
||||||
|
/*5-6 rotation by 3pi/16. \
|
||||||
|
mm5=C5, mm2=C3, mm3=X3, X5=0.*/ \
|
||||||
|
"pmulhw %%mm3,%%mm5\n\t" \
|
||||||
|
"pmulhw %%mm3,%%mm2\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x10,c)",%%mm7\n\t" \
|
||||||
|
"paddw %%mm3,%%mm5\n\t" \
|
||||||
|
"paddw %%mm3,%%mm2\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x70,c)",%%mm3\n\t" \
|
||||||
|
/*4-7 rotation by 7pi/16. \
|
||||||
|
mm7=C1, mm3=C7, mm1=X1, X7=0.*/ \
|
||||||
|
"pmulhw %%mm1,%%mm3\n\t" \
|
||||||
|
"pmulhw %%mm1,%%mm7\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x40,c)",%%mm4\n\t" \
|
||||||
|
"movq %%mm3,%%mm6\n\t" \
|
||||||
|
"paddw %%mm1,%%mm7\n\t" \
|
||||||
|
/*0-1 butterfly. \
|
||||||
|
mm4=C4, mm0=X0, X4=0.*/ \
|
||||||
|
/*Stage 2:*/ \
|
||||||
|
/*4-5 butterfly: mm3=t[4], mm5=t[5] \
|
||||||
|
7-6 butterfly: mm2=t[6], mm7=t[7]*/ \
|
||||||
|
"psubw %%mm5,%%mm3\n\t" \
|
||||||
|
"paddw %%mm5,%%mm6\n\t" \
|
||||||
|
"movq %%mm4,%%mm1\n\t" \
|
||||||
|
"pmulhw %%mm0,%%mm4\n\t" \
|
||||||
|
"paddw %%mm0,%%mm4\n\t" \
|
||||||
|
"movq %%mm7,%%mm0\n\t" \
|
||||||
|
"movq %%mm4,%%mm5\n\t" \
|
||||||
|
"paddw %%mm2,%%mm0\n\t" \
|
||||||
|
"psubw %%mm2,%%mm7\n\t" \
|
||||||
|
"movq %%mm1,%%mm2\n\t" \
|
||||||
|
"pmulhw %%mm6,%%mm1\n\t" \
|
||||||
|
"pmulhw %%mm7,%%mm2\n\t" \
|
||||||
|
"paddw %%mm6,%%mm1\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x00,buf)",%%mm6\n\t" \
|
||||||
|
"paddw %%mm7,%%mm2\n\t" \
|
||||||
|
"movq "OC_MEM_OFFS(0x10,buf)",%%mm7\n\t" \
|
||||||
|
/*Stage 3: \
|
||||||
|
6-5 butterfly: mm1=t[5], mm2=t[6] -> mm1=t[6]+t[5], mm2=t[6]-t[5] \
|
||||||
|
0-3 butterfly: mm4=t[0], mm7=t[3] -> mm7=t[0]+t[3], mm4=t[0]-t[3] \
|
||||||
|
1-2 butterfly: mm5=t[1], mm6=t[2] -> mm6=t[1]+t[2], mm5=t[1]-t[2]*/ \
|
||||||
|
"paddw %%mm2,%%mm1\n\t" \
|
||||||
|
"paddw %%mm5,%%mm6\n\t" \
|
||||||
|
"paddw %%mm4,%%mm7\n\t" \
|
||||||
|
"paddw %%mm2,%%mm2\n\t" \
|
||||||
|
"paddw %%mm4,%%mm4\n\t" \
|
||||||
|
"paddw %%mm5,%%mm5\n\t" \
|
||||||
|
"psubw %%mm1,%%mm2\n\t" \
|
||||||
|
"psubw %%mm7,%%mm4\n\t" \
|
||||||
|
"psubw %%mm6,%%mm5\n\t" \
|
||||||
|
/*Stage 4: \
|
||||||
|
0-7 butterfly: mm7=t[0], mm0=t[7] -> mm0=t[0]+t[7], mm7=t[0]-t[7] \
|
||||||
|
1-6 butterfly: mm6=t[1], mm1=t[6] -> mm1=t[1]+t[6], mm6=t[1]-t[6] \
|
||||||
|
2-5 butterfly: mm5=t[2], mm2=t[5] -> mm2=t[2]+t[5], mm5=t[2]-t[5] \
|
||||||
|
3-4 butterfly: mm4=t[3], mm3=t[4] -> mm3=t[3]+t[4], mm4=t[3]-t[4]*/ \
|
||||||
|
"psubw %%mm0,%%mm7\n\t" \
|
||||||
|
"psubw %%mm1,%%mm6\n\t" \
|
||||||
|
"psubw %%mm2,%%mm5\n\t" \
|
||||||
|
"psubw %%mm3,%%mm4\n\t" \
|
||||||
|
"paddw %%mm0,%%mm0\n\t" \
|
||||||
|
"paddw %%mm1,%%mm1\n\t" \
|
||||||
|
"paddw %%mm2,%%mm2\n\t" \
|
||||||
|
"paddw %%mm3,%%mm3\n\t" \
|
||||||
|
"paddw %%mm7,%%mm0\n\t" \
|
||||||
|
"paddw %%mm6,%%mm1\n\t" \
|
||||||
|
"paddw %%mm5,%%mm2\n\t" \
|
||||||
|
"paddw %%mm4,%%mm3\n\t" \
|
||||||
|
|
||||||
|
#define OC_IDCT_8x8_10_ABC \
|
||||||
|
"#OC_IDCT_8x8_10_ABC\n\t" \
|
||||||
|
/*Stage 1:*/ \
|
||||||
|
/*2-3 rotation by 6pi/16. \
|
||||||
|
xmm7=C6, xmm6=C2, xmm2=X2, X6=0.*/ \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x60,c)",%%xmm7\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x20,c)",%%xmm6\n\t" \
|
||||||
|
"pmulhw %%xmm2,%%xmm6\n\t" \
|
||||||
|
"pmulhw %%xmm2,%%xmm7\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x50,c)",%%xmm5\n\t" \
|
||||||
|
"paddw %%xmm6,%%xmm2\n\t" \
|
||||||
|
"movdqa %%xmm2,"OC_MEM_OFFS(0x10,buf)"\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x30,c)",%%xmm2\n\t" \
|
||||||
|
"movdqa %%xmm7,"OC_MEM_OFFS(0x00,buf)"\n\t" \
|
||||||
|
/*5-6 rotation by 3pi/16. \
|
||||||
|
xmm5=C5, xmm2=C3, xmm3=X3, X5=0.*/ \
|
||||||
|
"pmulhw %%xmm3,%%xmm5\n\t" \
|
||||||
|
"pmulhw %%xmm3,%%xmm2\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x10,c)",%%xmm7\n\t" \
|
||||||
|
"paddw %%xmm3,%%xmm5\n\t" \
|
||||||
|
"paddw %%xmm3,%%xmm2\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x70,c)",%%xmm3\n\t" \
|
||||||
|
/*4-7 rotation by 7pi/16. \
|
||||||
|
xmm7=C1, xmm3=C7, xmm1=X1, X7=0.*/ \
|
||||||
|
"pmulhw %%xmm1,%%xmm3\n\t" \
|
||||||
|
"pmulhw %%xmm1,%%xmm7\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x40,c)",%%xmm4\n\t" \
|
||||||
|
"movdqa %%xmm3,%%xmm6\n\t" \
|
||||||
|
"paddw %%xmm1,%%xmm7\n\t" \
|
||||||
|
/*0-1 butterfly. \
|
||||||
|
xmm4=C4, xmm0=X0, X4=0.*/ \
|
||||||
|
/*Stage 2:*/ \
|
||||||
|
/*4-5 butterfly: xmm3=t[4], xmm5=t[5] \
|
||||||
|
7-6 butterfly: xmm2=t[6], xmm7=t[7]*/ \
|
||||||
|
"psubw %%xmm5,%%xmm3\n\t" \
|
||||||
|
"paddw %%xmm5,%%xmm6\n\t" \
|
||||||
|
"movdqa %%xmm4,%%xmm1\n\t" \
|
||||||
|
"pmulhw %%xmm0,%%xmm4\n\t" \
|
||||||
|
"paddw %%xmm0,%%xmm4\n\t" \
|
||||||
|
"movdqa %%xmm7,%%xmm0\n\t" \
|
||||||
|
"movdqa %%xmm4,%%xmm5\n\t" \
|
||||||
|
"paddw %%xmm2,%%xmm0\n\t" \
|
||||||
|
"psubw %%xmm2,%%xmm7\n\t" \
|
||||||
|
"movdqa %%xmm1,%%xmm2\n\t" \
|
||||||
|
"pmulhw %%xmm6,%%xmm1\n\t" \
|
||||||
|
"pmulhw %%xmm7,%%xmm2\n\t" \
|
||||||
|
"paddw %%xmm6,%%xmm1\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x00,buf)",%%xmm6\n\t" \
|
||||||
|
"paddw %%xmm7,%%xmm2\n\t" \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x10,buf)",%%xmm7\n\t" \
|
||||||
|
/*Stage 3: \
|
||||||
|
6-5 butterfly: xmm1=t[5], xmm2=t[6] -> xmm1=t[6]+t[5], xmm2=t[6]-t[5] \
|
||||||
|
0-3 butterfly: xmm4=t[0], xmm7=t[3] -> xmm7=t[0]+t[3], xmm4=t[0]-t[3] \
|
||||||
|
1-2 butterfly: xmm5=t[1], xmm6=t[2] -> xmm6=t[1]+t[2], xmm5=t[1]-t[2]*/ \
|
||||||
|
"paddw %%xmm2,%%xmm1\n\t" \
|
||||||
|
"paddw %%xmm5,%%xmm6\n\t" \
|
||||||
|
"paddw %%xmm4,%%xmm7\n\t" \
|
||||||
|
"paddw %%xmm2,%%xmm2\n\t" \
|
||||||
|
"paddw %%xmm4,%%xmm4\n\t" \
|
||||||
|
"paddw %%xmm5,%%xmm5\n\t" \
|
||||||
|
"psubw %%xmm1,%%xmm2\n\t" \
|
||||||
|
"psubw %%xmm7,%%xmm4\n\t" \
|
||||||
|
"psubw %%xmm6,%%xmm5\n\t" \
|
||||||
|
|
||||||
|
static void oc_idct8x8_10_sse2(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||||
|
OC_ALIGN16(ogg_int16_t buf[16]);
|
||||||
|
/*This routine accepts an 8x8 matrix pre-transposed.*/
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"movq "OC_MEM_OFFS(0x20,x)",%%mm2\n\t"
|
||||||
|
"movq "OC_MEM_OFFS(0x30,x)",%%mm3\n\t"
|
||||||
|
"movq "OC_MEM_OFFS(0x10,x)",%%mm1\n\t"
|
||||||
|
"movq "OC_MEM_OFFS(0x00,x)",%%mm0\n\t"
|
||||||
|
OC_IDCT_8x8_10_MMX
|
||||||
|
OC_TRANSPOSE_8x4_MMX2SSE
|
||||||
|
OC_IDCT_8x8_10_ABC
|
||||||
|
OC_IDCT_8x8_D_STORE
|
||||||
|
:[buf]"=m"(OC_ARRAY_OPERAND(short,buf,16)),
|
||||||
|
[y]"=m"(OC_ARRAY_OPERAND(ogg_int16_t,_y,64))
|
||||||
|
:[x]"m"OC_CONST_ARRAY_OPERAND(ogg_int16_t,_x,64),
|
||||||
|
[c]"m"(OC_CONST_ARRAY_OPERAND(ogg_int16_t,OC_IDCT_CONSTS,128))
|
||||||
|
);
|
||||||
|
/*Clear input data for next block (decoder only).*/
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"pxor %%mm0,%%mm0\n\t"
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x00,x)"\n\t"
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x10,x)"\n\t"
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x20,x)"\n\t"
|
||||||
|
"movq %%mm0,"OC_MEM_OFFS(0x30,x)"\n\t"
|
||||||
|
:[x]"+m"(OC_ARRAY_OPERAND(ogg_int16_t,_x,28))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Performs an inverse 8x8 Type-II DCT transform.
|
||||||
|
The input is assumed to be scaled by a factor of 4 relative to orthonormal
|
||||||
|
version of the transform.*/
|
||||||
|
void oc_idct8x8_sse2(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi){
|
||||||
|
/*_last_zzi is subtly different from an actual count of the number of
|
||||||
|
coefficients we decoded for this block.
|
||||||
|
It contains the value of zzi BEFORE the final token in the block was
|
||||||
|
decoded.
|
||||||
|
In most cases this is an EOB token (the continuation of an EOB run from a
|
||||||
|
previous block counts), and so this is the same as the coefficient count.
|
||||||
|
However, in the case that the last token was NOT an EOB token, but filled
|
||||||
|
the block up with exactly 64 coefficients, _last_zzi will be less than 64.
|
||||||
|
Provided the last token was not a pure zero run, the minimum value it can
|
||||||
|
be is 46, and so that doesn't affect any of the cases in this routine.
|
||||||
|
However, if the last token WAS a pure zero run of length 63, then _last_zzi
|
||||||
|
will be 1 while the number of coefficients decoded is 64.
|
||||||
|
Thus, we will trigger the following special case, where the real
|
||||||
|
coefficient count would not.
|
||||||
|
Note also that a zero run of length 64 will give _last_zzi a value of 0,
|
||||||
|
but we still process the DC coefficient, which might have a non-zero value
|
||||||
|
due to DC prediction.
|
||||||
|
Although convoluted, this is arguably the correct behavior: it allows us to
|
||||||
|
use a smaller transform when the block ends with a long zero run instead
|
||||||
|
of a normal EOB token.
|
||||||
|
It could be smarter... multiple separate zero runs at the end of a block
|
||||||
|
will fool it, but an encoder that generates these really deserves what it
|
||||||
|
gets.
|
||||||
|
Needless to say we inherited this approach from VP3.*/
|
||||||
|
/*Then perform the iDCT.*/
|
||||||
|
if(_last_zzi<=10)oc_idct8x8_10_sse2(_y,_x);
|
||||||
|
else oc_idct8x8_slow_sse2(_y,_x);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,242 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id: sse2trans.h 15675 2009-02-06 09:43:27Z tterribe $
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#if !defined(_x86_sse2trans_H)
|
||||||
|
# define _x86_sse2trans_H (1)
|
||||||
|
# include "x86int.h"
|
||||||
|
|
||||||
|
# if defined(OC_X86_64_ASM)
|
||||||
|
/*On x86-64 we can transpose in-place without spilling registers.
|
||||||
|
By clever choices of the order to apply the butterflies and the order of
|
||||||
|
their outputs, we can take the rows in order and output the columns in order
|
||||||
|
without any extra operations and using just one temporary register.*/
|
||||||
|
# define OC_TRANSPOSE_8x8 \
|
||||||
|
"#OC_TRANSPOSE_8x8\n\t" \
|
||||||
|
"movdqa %%xmm4,%%xmm8\n\t" \
|
||||||
|
/*xmm4 = f3 e3 f2 e2 f1 e1 f0 e0*/ \
|
||||||
|
"punpcklwd %%xmm5,%%xmm4\n\t" \
|
||||||
|
/*xmm8 = f7 e7 f6 e6 f5 e5 f4 e4*/ \
|
||||||
|
"punpckhwd %%xmm5,%%xmm8\n\t" \
|
||||||
|
/*xmm5 is free.*/ \
|
||||||
|
"movdqa %%xmm0,%%xmm5\n\t" \
|
||||||
|
/*xmm0 = b3 a3 b2 a2 b1 a1 b0 a0*/ \
|
||||||
|
"punpcklwd %%xmm1,%%xmm0\n\t" \
|
||||||
|
/*xmm5 = b7 a7 b6 a6 b5 a5 b4 a4*/ \
|
||||||
|
"punpckhwd %%xmm1,%%xmm5\n\t" \
|
||||||
|
/*xmm1 is free.*/ \
|
||||||
|
"movdqa %%xmm6,%%xmm1\n\t" \
|
||||||
|
/*xmm6 = h3 g3 h2 g2 h1 g1 h0 g0*/ \
|
||||||
|
"punpcklwd %%xmm7,%%xmm6\n\t" \
|
||||||
|
/*xmm1 = h7 g7 h6 g6 h5 g5 h4 g4*/ \
|
||||||
|
"punpckhwd %%xmm7,%%xmm1\n\t" \
|
||||||
|
/*xmm7 is free.*/ \
|
||||||
|
"movdqa %%xmm2,%%xmm7\n\t" \
|
||||||
|
/*xmm2 = d7 c7 d6 c6 d5 c5 d4 c4*/ \
|
||||||
|
"punpckhwd %%xmm3,%%xmm2\n\t" \
|
||||||
|
/*xmm7 = d3 c3 d2 c2 d1 c1 d0 c0*/ \
|
||||||
|
"punpcklwd %%xmm3,%%xmm7\n\t" \
|
||||||
|
/*xmm3 is free.*/ \
|
||||||
|
"movdqa %%xmm0,%%xmm3\n\t" \
|
||||||
|
/*xmm0 = d1 c1 b1 a1 d0 c0 b0 a0*/ \
|
||||||
|
"punpckldq %%xmm7,%%xmm0\n\t" \
|
||||||
|
/*xmm3 = d3 c3 b3 a3 d2 c2 b2 a2*/ \
|
||||||
|
"punpckhdq %%xmm7,%%xmm3\n\t" \
|
||||||
|
/*xmm7 is free.*/ \
|
||||||
|
"movdqa %%xmm5,%%xmm7\n\t" \
|
||||||
|
/*xmm5 = d5 c5 b5 a5 d4 c4 b4 a4*/ \
|
||||||
|
"punpckldq %%xmm2,%%xmm5\n\t" \
|
||||||
|
/*xmm7 = d7 c7 b7 a7 d6 c6 b6 a6*/ \
|
||||||
|
"punpckhdq %%xmm2,%%xmm7\n\t" \
|
||||||
|
/*xmm2 is free.*/ \
|
||||||
|
"movdqa %%xmm4,%%xmm2\n\t" \
|
||||||
|
/*xmm4 = h3 g3 f3 e3 h2 g2 f2 e2*/ \
|
||||||
|
"punpckhdq %%xmm6,%%xmm4\n\t" \
|
||||||
|
/*xmm2 = h1 g1 f1 e1 h0 g0 f0 e0*/ \
|
||||||
|
"punpckldq %%xmm6,%%xmm2\n\t" \
|
||||||
|
/*xmm6 is free.*/ \
|
||||||
|
"movdqa %%xmm8,%%xmm6\n\t" \
|
||||||
|
/*xmm6 = h5 g5 f5 e5 h4 g4 f4 e4*/ \
|
||||||
|
"punpckldq %%xmm1,%%xmm6\n\t" \
|
||||||
|
/*xmm8 = h7 g7 f7 e7 h6 g6 f6 e6*/ \
|
||||||
|
"punpckhdq %%xmm1,%%xmm8\n\t" \
|
||||||
|
/*xmm1 is free.*/ \
|
||||||
|
"movdqa %%xmm0,%%xmm1\n\t" \
|
||||||
|
/*xmm0 = h0 g0 f0 e0 d0 c0 b0 a0*/ \
|
||||||
|
"punpcklqdq %%xmm2,%%xmm0\n\t" \
|
||||||
|
/*xmm1 = h1 g1 f1 e1 d1 c1 b1 a1*/ \
|
||||||
|
"punpckhqdq %%xmm2,%%xmm1\n\t" \
|
||||||
|
/*xmm2 is free.*/ \
|
||||||
|
"movdqa %%xmm3,%%xmm2\n\t" \
|
||||||
|
/*xmm3 = h3 g3 f3 e3 d3 c3 b3 a3*/ \
|
||||||
|
"punpckhqdq %%xmm4,%%xmm3\n\t" \
|
||||||
|
/*xmm2 = h2 g2 f2 e2 d2 c2 b2 a2*/ \
|
||||||
|
"punpcklqdq %%xmm4,%%xmm2\n\t" \
|
||||||
|
/*xmm4 is free.*/ \
|
||||||
|
"movdqa %%xmm5,%%xmm4\n\t" \
|
||||||
|
/*xmm5 = h5 g5 f5 e5 d5 c5 b5 a5*/ \
|
||||||
|
"punpckhqdq %%xmm6,%%xmm5\n\t" \
|
||||||
|
/*xmm4 = h4 g4 f4 e4 d4 c4 b4 a4*/ \
|
||||||
|
"punpcklqdq %%xmm6,%%xmm4\n\t" \
|
||||||
|
/*xmm6 is free.*/ \
|
||||||
|
"movdqa %%xmm7,%%xmm6\n\t" \
|
||||||
|
/*xmm7 = h7 g7 f7 e7 d7 c7 b7 a7*/ \
|
||||||
|
"punpckhqdq %%xmm8,%%xmm7\n\t" \
|
||||||
|
/*xmm6 = h6 g6 f6 e6 d6 c6 b6 a6*/ \
|
||||||
|
"punpcklqdq %%xmm8,%%xmm6\n\t" \
|
||||||
|
/*xmm8 is free.*/ \
|
||||||
|
|
||||||
|
# else
|
||||||
|
/*Otherwise, we need to spill some values to %[buf] temporarily.
|
||||||
|
Again, the butterflies are carefully arranged to get the columns to come out
|
||||||
|
in order, minimizing register spills and maximizing the delay between a load
|
||||||
|
and when the value loaded is actually used.*/
|
||||||
|
# define OC_TRANSPOSE_8x8 \
|
||||||
|
"#OC_TRANSPOSE_8x8\n\t" \
|
||||||
|
/*buf[0] = a7 a6 a5 a4 a3 a2 a1 a0*/ \
|
||||||
|
"movdqa %%xmm0,"OC_MEM_OFFS(0x00,buf)"\n\t" \
|
||||||
|
/*xmm0 is free.*/ \
|
||||||
|
"movdqa %%xmm2,%%xmm0\n\t" \
|
||||||
|
/*xmm2 = d7 c7 d6 c6 d5 c5 d4 c4*/ \
|
||||||
|
"punpckhwd %%xmm3,%%xmm2\n\t" \
|
||||||
|
/*xmm0 = d3 c3 d2 c2 d1 c1 d0 c0*/ \
|
||||||
|
"punpcklwd %%xmm3,%%xmm0\n\t" \
|
||||||
|
/*xmm3 = a7 a6 a5 a4 a3 a2 a1 a0*/ \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x00,buf)",%%xmm3\n\t" \
|
||||||
|
/*buf[1] = d7 c7 d6 c6 d5 c5 d4 c4*/ \
|
||||||
|
"movdqa %%xmm2,"OC_MEM_OFFS(0x10,buf)"\n\t" \
|
||||||
|
/*xmm2 is free.*/ \
|
||||||
|
"movdqa %%xmm6,%%xmm2\n\t" \
|
||||||
|
/*xmm6 = h3 g3 h2 g2 h1 g1 h0 g0*/ \
|
||||||
|
"punpcklwd %%xmm7,%%xmm6\n\t" \
|
||||||
|
/*xmm2 = h7 g7 h6 g6 h5 g5 h4 g4*/ \
|
||||||
|
"punpckhwd %%xmm7,%%xmm2\n\t" \
|
||||||
|
/*xmm7 is free.*/ \
|
||||||
|
"movdqa %%xmm4,%%xmm7\n\t" \
|
||||||
|
/*xmm4 = f3 e3 f2 e2 f1 e1 f0 e0*/ \
|
||||||
|
"punpcklwd %%xmm5,%%xmm4\n\t" \
|
||||||
|
/*xmm7 = f7 e7 f6 e6 f5 e5 f4 e4*/ \
|
||||||
|
"punpckhwd %%xmm5,%%xmm7\n\t" \
|
||||||
|
/*xmm5 is free.*/ \
|
||||||
|
"movdqa %%xmm3,%%xmm5\n\t" \
|
||||||
|
/*xmm3 = b3 a3 b2 a2 b1 a1 b0 a0*/ \
|
||||||
|
"punpcklwd %%xmm1,%%xmm3\n\t" \
|
||||||
|
/*xmm5 = b7 a7 b6 a6 b5 a5 b4 a4*/ \
|
||||||
|
"punpckhwd %%xmm1,%%xmm5\n\t" \
|
||||||
|
/*xmm1 is free.*/ \
|
||||||
|
"movdqa %%xmm7,%%xmm1\n\t" \
|
||||||
|
/*xmm7 = h5 g5 f5 e5 h4 g4 f4 e4*/ \
|
||||||
|
"punpckldq %%xmm2,%%xmm7\n\t" \
|
||||||
|
/*xmm1 = h7 g7 f7 e7 h6 g6 f6 e6*/ \
|
||||||
|
"punpckhdq %%xmm2,%%xmm1\n\t" \
|
||||||
|
/*xmm2 = d7 c7 d6 c6 d5 c5 d4 c4*/ \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x10,buf)",%%xmm2\n\t" \
|
||||||
|
/*buf[0] = h7 g7 f7 e7 h6 g6 f6 e6*/ \
|
||||||
|
"movdqa %%xmm1,"OC_MEM_OFFS(0x00,buf)"\n\t" \
|
||||||
|
/*xmm1 is free.*/ \
|
||||||
|
"movdqa %%xmm3,%%xmm1\n\t" \
|
||||||
|
/*xmm3 = d3 c3 b3 a3 d2 c2 b2 a2*/ \
|
||||||
|
"punpckhdq %%xmm0,%%xmm3\n\t" \
|
||||||
|
/*xmm1 = d1 c1 b1 a1 d0 c0 b0 a0*/ \
|
||||||
|
"punpckldq %%xmm0,%%xmm1\n\t" \
|
||||||
|
/*xmm0 is free.*/ \
|
||||||
|
"movdqa %%xmm4,%%xmm0\n\t" \
|
||||||
|
/*xmm4 = h3 g3 f3 e3 h2 g2 f2 e2*/ \
|
||||||
|
"punpckhdq %%xmm6,%%xmm4\n\t" \
|
||||||
|
/*xmm0 = h1 g1 f1 e1 h0 g0 f0 e0*/ \
|
||||||
|
"punpckldq %%xmm6,%%xmm0\n\t" \
|
||||||
|
/*xmm6 is free.*/ \
|
||||||
|
"movdqa %%xmm5,%%xmm6\n\t" \
|
||||||
|
/*xmm5 = d5 c5 b5 a5 d4 c4 b4 a4*/ \
|
||||||
|
"punpckldq %%xmm2,%%xmm5\n\t" \
|
||||||
|
/*xmm6 = d7 c7 b7 a7 d6 c6 b6 a6*/ \
|
||||||
|
"punpckhdq %%xmm2,%%xmm6\n\t" \
|
||||||
|
/*xmm2 is free.*/ \
|
||||||
|
"movdqa %%xmm1,%%xmm2\n\t" \
|
||||||
|
/*xmm1 = h1 g1 f1 e1 d1 c1 b1 a1*/ \
|
||||||
|
"punpckhqdq %%xmm0,%%xmm1\n\t" \
|
||||||
|
/*xmm2 = h0 g0 f0 e0 d0 c0 b0 a0*/ \
|
||||||
|
"punpcklqdq %%xmm0,%%xmm2\n\t" \
|
||||||
|
/*xmm0 = h7 g7 f7 e7 h6 g6 f6 e6*/ \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x00,buf)",%%xmm0\n\t" \
|
||||||
|
/*buf[1] = h0 g0 f0 e0 d0 c0 b0 a0*/ \
|
||||||
|
"movdqa %%xmm2,"OC_MEM_OFFS(0x10,buf)"\n\t" \
|
||||||
|
/*xmm2 is free.*/ \
|
||||||
|
"movdqa %%xmm3,%%xmm2\n\t" \
|
||||||
|
/*xmm3 = h3 g3 f3 e3 d3 c3 b3 a3*/ \
|
||||||
|
"punpckhqdq %%xmm4,%%xmm3\n\t" \
|
||||||
|
/*xmm2 = h2 g2 f2 e2 d2 c2 b2 a2*/ \
|
||||||
|
"punpcklqdq %%xmm4,%%xmm2\n\t" \
|
||||||
|
/*xmm4 is free.*/ \
|
||||||
|
"movdqa %%xmm5,%%xmm4\n\t" \
|
||||||
|
/*xmm5 = h5 g5 f5 e5 d5 c5 b5 a5*/ \
|
||||||
|
"punpckhqdq %%xmm7,%%xmm5\n\t" \
|
||||||
|
/*xmm4 = h4 g4 f4 e4 d4 c4 b4 a4*/ \
|
||||||
|
"punpcklqdq %%xmm7,%%xmm4\n\t" \
|
||||||
|
/*xmm7 is free.*/ \
|
||||||
|
"movdqa %%xmm6,%%xmm7\n\t" \
|
||||||
|
/*xmm6 = h6 g6 f6 e6 d6 c6 b6 a6*/ \
|
||||||
|
"punpcklqdq %%xmm0,%%xmm6\n\t" \
|
||||||
|
/*xmm7 = h7 g7 f7 e7 d7 c7 b7 a7*/ \
|
||||||
|
"punpckhqdq %%xmm0,%%xmm7\n\t" \
|
||||||
|
/*xmm0 = h0 g0 f0 e0 d0 c0 b0 a0*/ \
|
||||||
|
"movdqa "OC_MEM_OFFS(0x10,buf)",%%xmm0\n\t" \
|
||||||
|
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/*Transpose 4 values in each of 8 MMX registers into 8 values in the first
|
||||||
|
four SSE registers.
|
||||||
|
No need to be clever here; we have plenty of room.*/
|
||||||
|
# define OC_TRANSPOSE_8x4_MMX2SSE \
|
||||||
|
"#OC_TRANSPOSE_8x4_MMX2SSE\n\t" \
|
||||||
|
"movq2dq %%mm0,%%xmm0\n\t" \
|
||||||
|
"movq2dq %%mm1,%%xmm1\n\t" \
|
||||||
|
/*xmmA = b3 a3 b2 a2 b1 a1 b0 a0*/ \
|
||||||
|
"punpcklwd %%xmm1,%%xmm0\n\t" \
|
||||||
|
"movq2dq %%mm2,%%xmm3\n\t" \
|
||||||
|
"movq2dq %%mm3,%%xmm2\n\t" \
|
||||||
|
/*xmmC = d3 c3 d2 c2 d1 c1 d0 c0*/ \
|
||||||
|
"punpcklwd %%xmm2,%%xmm3\n\t" \
|
||||||
|
"movq2dq %%mm4,%%xmm4\n\t" \
|
||||||
|
"movq2dq %%mm5,%%xmm5\n\t" \
|
||||||
|
/*xmmE = f3 e3 f2 e2 f1 e1 f0 e0*/ \
|
||||||
|
"punpcklwd %%xmm5,%%xmm4\n\t" \
|
||||||
|
"movq2dq %%mm6,%%xmm7\n\t" \
|
||||||
|
"movq2dq %%mm7,%%xmm6\n\t" \
|
||||||
|
/*xmmG = h3 g3 h2 g2 h1 g1 h0 g0*/ \
|
||||||
|
"punpcklwd %%xmm6,%%xmm7\n\t" \
|
||||||
|
"movdqa %%xmm0,%%xmm2\n\t" \
|
||||||
|
/*xmm0 = d1 c1 b1 a1 d0 c0 b0 a0*/ \
|
||||||
|
"punpckldq %%xmm3,%%xmm0\n\t" \
|
||||||
|
/*xmm2 = d3 c3 b3 a3 d2 c2 b2 a2*/ \
|
||||||
|
"punpckhdq %%xmm3,%%xmm2\n\t" \
|
||||||
|
"movdqa %%xmm4,%%xmm5\n\t" \
|
||||||
|
/*xmm4 = h1 g1 f1 e1 h0 g0 f0 e0*/ \
|
||||||
|
"punpckldq %%xmm7,%%xmm4\n\t" \
|
||||||
|
/*xmm3 = h3 g3 f3 e3 h2 g2 f2 e2*/ \
|
||||||
|
"punpckhdq %%xmm7,%%xmm5\n\t" \
|
||||||
|
"movdqa %%xmm0,%%xmm1\n\t" \
|
||||||
|
/*xmm0 = h0 g0 f0 e0 d0 c0 b0 a0*/ \
|
||||||
|
"punpcklqdq %%xmm4,%%xmm0\n\t" \
|
||||||
|
/*xmm1 = h1 g1 f1 e1 d1 c1 b1 a1*/ \
|
||||||
|
"punpckhqdq %%xmm4,%%xmm1\n\t" \
|
||||||
|
"movdqa %%xmm2,%%xmm3\n\t" \
|
||||||
|
/*xmm2 = h2 g2 f2 e2 d2 c2 b2 a2*/ \
|
||||||
|
"punpcklqdq %%xmm5,%%xmm2\n\t" \
|
||||||
|
/*xmm3 = h3 g3 f3 e3 d3 c3 b3 a3*/ \
|
||||||
|
"punpckhqdq %%xmm5,%%xmm3\n\t" \
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
CPU capability detection for x86 processors.
|
||||||
|
Originally written by Rudolf Marek.
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include "x86cpu.h"
|
||||||
|
|
||||||
|
#if !defined(OC_X86_ASM)
|
||||||
|
ogg_uint32_t oc_cpu_flags_get(void){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# if defined(__amd64__)||defined(__x86_64__)
|
||||||
|
/*On x86-64, gcc seems to be able to figure out how to save %rbx for us when
|
||||||
|
compiling with -fPIC.*/
|
||||||
|
# define cpuid(_op,_eax,_ebx,_ecx,_edx) \
|
||||||
|
__asm__ __volatile__( \
|
||||||
|
"cpuid\n\t" \
|
||||||
|
:[eax]"=a"(_eax),[ebx]"=b"(_ebx),[ecx]"=c"(_ecx),[edx]"=d"(_edx) \
|
||||||
|
:"a"(_op) \
|
||||||
|
:"cc" \
|
||||||
|
)
|
||||||
|
# else
|
||||||
|
/*On x86-32, not so much.*/
|
||||||
|
# define cpuid(_op,_eax,_ebx,_ecx,_edx) \
|
||||||
|
__asm__ __volatile__( \
|
||||||
|
"xchgl %%ebx,%[ebx]\n\t" \
|
||||||
|
"cpuid\n\t" \
|
||||||
|
"xchgl %%ebx,%[ebx]\n\t" \
|
||||||
|
:[eax]"=a"(_eax),[ebx]"=r"(_ebx),[ecx]"=c"(_ecx),[edx]"=d"(_edx) \
|
||||||
|
:"a"(_op) \
|
||||||
|
:"cc" \
|
||||||
|
)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
static ogg_uint32_t oc_parse_intel_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){
|
||||||
|
ogg_uint32_t flags;
|
||||||
|
/*If there isn't even MMX, give up.*/
|
||||||
|
if(!(_edx&0x00800000))return 0;
|
||||||
|
flags=OC_CPU_X86_MMX;
|
||||||
|
if(_edx&0x02000000)flags|=OC_CPU_X86_MMXEXT|OC_CPU_X86_SSE;
|
||||||
|
if(_edx&0x04000000)flags|=OC_CPU_X86_SSE2;
|
||||||
|
if(_ecx&0x00000001)flags|=OC_CPU_X86_PNI;
|
||||||
|
if(_ecx&0x00000100)flags|=OC_CPU_X86_SSSE3;
|
||||||
|
if(_ecx&0x00080000)flags|=OC_CPU_X86_SSE4_1;
|
||||||
|
if(_ecx&0x00100000)flags|=OC_CPU_X86_SSE4_2;
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ogg_uint32_t oc_parse_amd_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){
|
||||||
|
ogg_uint32_t flags;
|
||||||
|
/*If there isn't even MMX, give up.*/
|
||||||
|
if(!(_edx&0x00800000))return 0;
|
||||||
|
flags=OC_CPU_X86_MMX;
|
||||||
|
if(_edx&0x00400000)flags|=OC_CPU_X86_MMXEXT;
|
||||||
|
if(_edx&0x80000000)flags|=OC_CPU_X86_3DNOW;
|
||||||
|
if(_edx&0x40000000)flags|=OC_CPU_X86_3DNOWEXT;
|
||||||
|
if(_ecx&0x00000040)flags|=OC_CPU_X86_SSE4A;
|
||||||
|
if(_ecx&0x00000800)flags|=OC_CPU_X86_SSE5;
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
ogg_uint32_t oc_cpu_flags_get(void){
|
||||||
|
ogg_uint32_t flags;
|
||||||
|
ogg_uint32_t eax;
|
||||||
|
ogg_uint32_t ebx;
|
||||||
|
ogg_uint32_t ecx;
|
||||||
|
ogg_uint32_t edx;
|
||||||
|
# if !defined(__amd64__)&&!defined(__x86_64__)
|
||||||
|
/*Not all x86-32 chips support cpuid, so we have to check.*/
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"pushfl\n\t"
|
||||||
|
"pushfl\n\t"
|
||||||
|
"popl %[a]\n\t"
|
||||||
|
"movl %[a],%[b]\n\t"
|
||||||
|
"xorl $0x200000,%[a]\n\t"
|
||||||
|
"pushl %[a]\n\t"
|
||||||
|
"popfl\n\t"
|
||||||
|
"pushfl\n\t"
|
||||||
|
"popl %[a]\n\t"
|
||||||
|
"popfl\n\t"
|
||||||
|
:[a]"=r"(eax),[b]"=r"(ebx)
|
||||||
|
:
|
||||||
|
:"cc"
|
||||||
|
);
|
||||||
|
/*No cpuid.*/
|
||||||
|
if(eax==ebx)return 0;
|
||||||
|
# endif
|
||||||
|
cpuid(0,eax,ebx,ecx,edx);
|
||||||
|
/* l e t n I e n i u n e G*/
|
||||||
|
if(ecx==0x6C65746E&&edx==0x49656E69&&ebx==0x756E6547||
|
||||||
|
/* 6 8 x M T e n i u n e G*/
|
||||||
|
ecx==0x3638784D&&edx==0x54656E69&&ebx==0x756E6547){
|
||||||
|
int family;
|
||||||
|
int model;
|
||||||
|
/*Intel, Transmeta (tested with Crusoe TM5800):*/
|
||||||
|
cpuid(1,eax,ebx,ecx,edx);
|
||||||
|
flags=oc_parse_intel_flags(edx,ecx);
|
||||||
|
family=(eax>>8)&0xF;
|
||||||
|
model=(eax>>4)&0xF;
|
||||||
|
/*The SSE unit on the Pentium M and Core Duo is much slower than the MMX
|
||||||
|
unit, so don't use it.*/
|
||||||
|
if(family==6&&(model==9||model==13||model==14)){
|
||||||
|
flags&=~(OC_CPU_X86_SSE2|OC_CPU_X86_PNI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* D M A c i t n e h t u A*/
|
||||||
|
else if(ecx==0x444D4163&&edx==0x69746E65&&ebx==0x68747541||
|
||||||
|
/* C S N y b e d o e G*/
|
||||||
|
ecx==0x43534e20&&edx==0x79622065&&ebx==0x646f6547){
|
||||||
|
/*AMD, Geode:*/
|
||||||
|
cpuid(0x80000000,eax,ebx,ecx,edx);
|
||||||
|
if(eax<0x80000001)flags=0;
|
||||||
|
else{
|
||||||
|
cpuid(0x80000001,eax,ebx,ecx,edx);
|
||||||
|
flags=oc_parse_amd_flags(edx,ecx);
|
||||||
|
}
|
||||||
|
/*Also check for SSE.*/
|
||||||
|
cpuid(1,eax,ebx,ecx,edx);
|
||||||
|
flags|=oc_parse_intel_flags(edx,ecx);
|
||||||
|
}
|
||||||
|
/*Technically some VIA chips can be configured in the BIOS to return any
|
||||||
|
string here the user wants.
|
||||||
|
There is a special detection method that can be used to identify such
|
||||||
|
processors, but in my opinion, if the user really wants to change it, they
|
||||||
|
deserve what they get.*/
|
||||||
|
/* s l u a H r u a t n e C*/
|
||||||
|
else if(ecx==0x736C7561&&edx==0x48727561&&ebx==0x746E6543){
|
||||||
|
/*VIA:*/
|
||||||
|
/*I only have documentation for the C7 (Esther) and Isaiah (forthcoming)
|
||||||
|
chips (thanks to the engineers from Centaur Technology who provided it).
|
||||||
|
These chips support Intel-like cpuid info.
|
||||||
|
The C3-2 (Nehemiah) cores appear to, as well.*/
|
||||||
|
cpuid(1,eax,ebx,ecx,edx);
|
||||||
|
flags=oc_parse_intel_flags(edx,ecx);
|
||||||
|
if(eax>=0x80000001){
|
||||||
|
/*The (non-Nehemiah) C3 processors support AMD-like cpuid info.
|
||||||
|
We need to check this even if the Intel test succeeds to pick up 3DNow!
|
||||||
|
support on these processors.
|
||||||
|
Unlike actual AMD processors, we cannot _rely_ on this info, since
|
||||||
|
some cores (e.g., the 693 stepping of the Nehemiah) claim to support
|
||||||
|
this function, yet return edx=0, despite the Intel test indicating
|
||||||
|
MMX support.
|
||||||
|
Therefore the features detected here are strictly added to those
|
||||||
|
detected by the Intel test.*/
|
||||||
|
/*TODO: How about earlier chips?*/
|
||||||
|
cpuid(0x80000001,eax,ebx,ecx,edx);
|
||||||
|
/*Note: As of the C7, this function returns Intel-style extended feature
|
||||||
|
flags, not AMD-style.
|
||||||
|
Currently, this only defines bits 11, 20, and 29 (0x20100800), which
|
||||||
|
do not conflict with any of the AMD flags we inspect.
|
||||||
|
For the remaining bits, Intel tells us, "Do not count on their value",
|
||||||
|
but VIA assures us that they will all be zero (at least on the C7 and
|
||||||
|
Isaiah chips).
|
||||||
|
In the (unlikely) event a future processor uses bits 18, 19, 30, or 31
|
||||||
|
(0xC0C00000) for something else, we will have to add code to detect
|
||||||
|
the model to decide when it is appropriate to inspect them.*/
|
||||||
|
flags|=oc_parse_amd_flags(edx,ecx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
/*Implement me.*/
|
||||||
|
flags=0;
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#if !defined(_x86_x86cpu_H)
|
||||||
|
# define _x86_x86cpu_H (1)
|
||||||
|
#include "../internal.h"
|
||||||
|
|
||||||
|
#define OC_CPU_X86_MMX (1<<0)
|
||||||
|
#define OC_CPU_X86_3DNOW (1<<1)
|
||||||
|
#define OC_CPU_X86_3DNOWEXT (1<<2)
|
||||||
|
#define OC_CPU_X86_MMXEXT (1<<3)
|
||||||
|
#define OC_CPU_X86_SSE (1<<4)
|
||||||
|
#define OC_CPU_X86_SSE2 (1<<5)
|
||||||
|
#define OC_CPU_X86_PNI (1<<6)
|
||||||
|
#define OC_CPU_X86_SSSE3 (1<<7)
|
||||||
|
#define OC_CPU_X86_SSE4_1 (1<<8)
|
||||||
|
#define OC_CPU_X86_SSE4_2 (1<<9)
|
||||||
|
#define OC_CPU_X86_SSE4A (1<<10)
|
||||||
|
#define OC_CPU_X86_SSE5 (1<<11)
|
||||||
|
|
||||||
|
ogg_uint32_t oc_cpu_flags_get(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#if !defined(_x86_x86int_H)
|
||||||
|
# define _x86_x86int_H (1)
|
||||||
|
# include "../internal.h"
|
||||||
|
|
||||||
|
# if defined(OC_X86_ASM)
|
||||||
|
# define oc_state_accel_init oc_state_accel_init_x86
|
||||||
|
# if defined(OC_X86_64_ASM)
|
||||||
|
/*x86-64 guarantees SIMD support up through at least SSE2.
|
||||||
|
If the best routine we have available only needs SSE2 (which at the moment
|
||||||
|
covers all of them), then we can avoid runtime detection and the indirect
|
||||||
|
call.*/
|
||||||
|
# define oc_frag_copy(_state,_dst,_src,_ystride) \
|
||||||
|
oc_frag_copy_mmx(_dst,_src,_ystride)
|
||||||
|
# define oc_frag_copy_list(_state,_dst_frame,_src_frame,_ystride, \
|
||||||
|
_fragis,_nfragis,_frag_buf_offs) \
|
||||||
|
oc_frag_copy_list_mmx(_dst_frame,_src_frame,_ystride, \
|
||||||
|
_fragis,_nfragis,_frag_buf_offs)
|
||||||
|
# define oc_frag_recon_intra(_state,_dst,_ystride,_residue) \
|
||||||
|
oc_frag_recon_intra_mmx(_dst,_ystride,_residue)
|
||||||
|
# define oc_frag_recon_inter(_state,_dst,_src,_ystride,_residue) \
|
||||||
|
oc_frag_recon_inter_mmx(_dst,_src,_ystride,_residue)
|
||||||
|
# define oc_frag_recon_inter2(_state,_dst,_src1,_src2,_ystride,_residue) \
|
||||||
|
oc_frag_recon_inter2_mmx(_dst,_src1,_src2,_ystride,_residue)
|
||||||
|
# define oc_idct8x8(_state,_y,_x,_last_zzi) \
|
||||||
|
oc_idct8x8_sse2(_y,_x,_last_zzi)
|
||||||
|
# define oc_state_frag_recon oc_state_frag_recon_mmx
|
||||||
|
# define oc_loop_filter_init(_state,_bv,_flimit) \
|
||||||
|
oc_loop_filter_init_mmxext(_bv,_flimit)
|
||||||
|
# define oc_state_loop_filter_frag_rows oc_state_loop_filter_frag_rows_mmxext
|
||||||
|
# define oc_restore_fpu(_state) \
|
||||||
|
oc_restore_fpu_mmx()
|
||||||
|
# else
|
||||||
|
# define OC_STATE_USE_VTABLE (1)
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# include "../state.h"
|
||||||
|
# include "x86cpu.h"
|
||||||
|
|
||||||
|
/*Converts the expression in the argument to a string.*/
|
||||||
|
#define OC_M2STR(_s) #_s
|
||||||
|
|
||||||
|
/*Memory operands do not always include an offset.
|
||||||
|
To avoid warnings, we force an offset with %H (which adds 8).*/
|
||||||
|
# if __GNUC_PREREQ(4,0)
|
||||||
|
# define OC_MEM_OFFS(_offs,_name) \
|
||||||
|
OC_M2STR(_offs-8+%H[_name])
|
||||||
|
# endif
|
||||||
|
/*If your gcc version does't support %H, then you get to suffer the warnings.
|
||||||
|
Note that Apple's gas breaks on things like _offs+(%esp): it throws away the
|
||||||
|
whole offset, instead of substituting in 0 for the missing operand to +.*/
|
||||||
|
# if !defined(OC_MEM_OFFS)
|
||||||
|
# define OC_MEM_OFFS(_offs,_name) \
|
||||||
|
OC_M2STR(_offs+%[_name])
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/*Declare an array operand with an exact size.
|
||||||
|
This tells gcc we're going to clobber this memory region, without having to
|
||||||
|
clobber all of "memory" and lets us access local buffers directly using the
|
||||||
|
stack pointer, without allocating a separate register to point to them.*/
|
||||||
|
#define OC_ARRAY_OPERAND(_type,_ptr,_size) \
|
||||||
|
(*({ \
|
||||||
|
struct{_type array_value__[(_size)];} *array_addr__=(void *)(_ptr); \
|
||||||
|
array_addr__; \
|
||||||
|
}))
|
||||||
|
|
||||||
|
/*Declare an array operand with an exact size.
|
||||||
|
This tells gcc we're going to clobber this memory region, without having to
|
||||||
|
clobber all of "memory" and lets us access local buffers directly using the
|
||||||
|
stack pointer, without allocating a separate register to point to them.*/
|
||||||
|
#define OC_CONST_ARRAY_OPERAND(_type,_ptr,_size) \
|
||||||
|
(*({ \
|
||||||
|
const struct{_type array_value__[(_size)];} *array_addr__= \
|
||||||
|
(const void *)(_ptr); \
|
||||||
|
array_addr__; \
|
||||||
|
}))
|
||||||
|
|
||||||
|
extern const unsigned short __attribute__((aligned(16))) OC_IDCT_CONSTS[64];
|
||||||
|
|
||||||
|
void oc_state_accel_init_x86(oc_theora_state *_state);
|
||||||
|
|
||||||
|
void oc_frag_copy_mmx(unsigned char *_dst,
|
||||||
|
const unsigned char *_src,int _ystride);
|
||||||
|
void oc_frag_copy_list_mmx(unsigned char *_dst_frame,
|
||||||
|
const unsigned char *_src_frame,int _ystride,
|
||||||
|
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs);
|
||||||
|
void oc_frag_recon_intra_mmx(unsigned char *_dst,int _ystride,
|
||||||
|
const ogg_int16_t *_residue);
|
||||||
|
void oc_frag_recon_inter_mmx(unsigned char *_dst,
|
||||||
|
const unsigned char *_src,int _ystride,const ogg_int16_t *_residue);
|
||||||
|
void oc_frag_recon_inter2_mmx(unsigned char *_dst,const unsigned char *_src1,
|
||||||
|
const unsigned char *_src2,int _ystride,const ogg_int16_t *_residue);
|
||||||
|
void oc_idct8x8_mmx(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi);
|
||||||
|
void oc_idct8x8_sse2(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi);
|
||||||
|
void oc_state_frag_recon_mmx(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||||
|
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant);
|
||||||
|
void oc_loop_filter_init_mmx(signed char _bv[256],int _flimit);
|
||||||
|
void oc_loop_filter_init_mmxext(signed char _bv[256],int _flimit);
|
||||||
|
void oc_state_loop_filter_frag_rows_mmx(const oc_theora_state *_state,
|
||||||
|
signed char _bv[256],int _refi,int _pli,int _fragy0,int _fragy_end);
|
||||||
|
void oc_state_loop_filter_frag_rows_mmxext(const oc_theora_state *_state,
|
||||||
|
signed char _bv[256],int _refi,int _pli,int _fragy0,int _fragy_end);
|
||||||
|
void oc_restore_fpu_mmx(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include "x86int.h"
|
||||||
|
|
||||||
|
#if defined(OC_X86_ASM)
|
||||||
|
|
||||||
|
#if defined(OC_STATE_USE_VTABLE)
|
||||||
|
/*This table has been modified from OC_FZIG_ZAG by baking a 4x4 transpose into
|
||||||
|
each quadrant of the destination.*/
|
||||||
|
static const unsigned char OC_FZIG_ZAG_MMX[128]={
|
||||||
|
0, 8, 1, 2, 9,16,24,17,
|
||||||
|
10, 3,32,11,18,25, 4,12,
|
||||||
|
5,26,19,40,33,34,41,48,
|
||||||
|
27, 6,13,20,28,21,14, 7,
|
||||||
|
56,49,42,35,43,50,57,36,
|
||||||
|
15,22,29,30,23,44,37,58,
|
||||||
|
51,59,38,45,52,31,60,53,
|
||||||
|
46,39,47,54,61,62,55,63,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*This table has been modified from OC_FZIG_ZAG by baking an 8x8 transpose into
|
||||||
|
the destination.*/
|
||||||
|
static const unsigned char OC_FZIG_ZAG_SSE2[128]={
|
||||||
|
0, 8, 1, 2, 9,16,24,17,
|
||||||
|
10, 3, 4,11,18,25,32,40,
|
||||||
|
33,26,19,12, 5, 6,13,20,
|
||||||
|
27,34,41,48,56,49,42,35,
|
||||||
|
28,21,14, 7,15,22,29,36,
|
||||||
|
43,50,57,58,51,44,37,30,
|
||||||
|
23,31,38,45,52,59,60,53,
|
||||||
|
46,39,47,54,61,62,55,63,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64
|
||||||
|
};
|
||||||
|
|
||||||
|
void oc_state_accel_init_x86(oc_theora_state *_state){
|
||||||
|
oc_state_accel_init_c(_state);
|
||||||
|
_state->cpu_flags=oc_cpu_flags_get();
|
||||||
|
# if defined(OC_STATE_USE_VTABLE)
|
||||||
|
if(_state->cpu_flags&OC_CPU_X86_MMX){
|
||||||
|
_state->opt_vtable.frag_copy=oc_frag_copy_mmx;
|
||||||
|
_state->opt_vtable.frag_copy_list=oc_frag_copy_list_mmx;
|
||||||
|
_state->opt_vtable.frag_recon_intra=oc_frag_recon_intra_mmx;
|
||||||
|
_state->opt_vtable.frag_recon_inter=oc_frag_recon_inter_mmx;
|
||||||
|
_state->opt_vtable.frag_recon_inter2=oc_frag_recon_inter2_mmx;
|
||||||
|
_state->opt_vtable.idct8x8=oc_idct8x8_mmx;
|
||||||
|
_state->opt_vtable.state_frag_recon=oc_state_frag_recon_mmx;
|
||||||
|
_state->opt_vtable.loop_filter_init=oc_loop_filter_init_mmx;
|
||||||
|
_state->opt_vtable.state_loop_filter_frag_rows=
|
||||||
|
oc_state_loop_filter_frag_rows_mmx;
|
||||||
|
_state->opt_vtable.restore_fpu=oc_restore_fpu_mmx;
|
||||||
|
_state->opt_data.dct_fzig_zag=OC_FZIG_ZAG_MMX;
|
||||||
|
}
|
||||||
|
if(_state->cpu_flags&OC_CPU_X86_MMXEXT){
|
||||||
|
_state->opt_vtable.loop_filter_init=oc_loop_filter_init_mmxext;
|
||||||
|
_state->opt_vtable.state_loop_filter_frag_rows=
|
||||||
|
oc_state_loop_filter_frag_rows_mmxext;
|
||||||
|
}
|
||||||
|
if(_state->cpu_flags&OC_CPU_X86_SSE2){
|
||||||
|
_state->opt_vtable.idct8x8=oc_idct8x8_sse2;
|
||||||
|
# endif
|
||||||
|
_state->opt_data.dct_fzig_zag=OC_FZIG_ZAG_SSE2;
|
||||||
|
# if defined(OC_STATE_USE_VTABLE)
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,416 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
/*MMX acceleration of fragment reconstruction for motion compensation.
|
||||||
|
Originally written by Rudolf Marek.
|
||||||
|
Additional optimization by Nils Pipenbrinck.
|
||||||
|
Note: Loops are unrolled for best performance.
|
||||||
|
The iteration each instruction belongs to is marked in the comments as #i.*/
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "x86int.h"
|
||||||
|
|
||||||
|
#if defined(OC_X86_ASM)
|
||||||
|
|
||||||
|
/*Copies an 8x8 block of pixels from _src to _dst, assuming _ystride bytes
|
||||||
|
between rows.*/
|
||||||
|
# define OC_FRAG_COPY_MMX(_dst,_src,_ystride) \
|
||||||
|
do{ \
|
||||||
|
const unsigned char *src; \
|
||||||
|
unsigned char *dst; \
|
||||||
|
src=(_src); \
|
||||||
|
dst=(_dst); \
|
||||||
|
__asm mov SRC,src \
|
||||||
|
__asm mov DST,dst \
|
||||||
|
__asm mov YSTRIDE,_ystride \
|
||||||
|
/*src+0*ystride*/ \
|
||||||
|
__asm movq mm0,[SRC] \
|
||||||
|
/*src+1*ystride*/ \
|
||||||
|
__asm movq mm1,[SRC+YSTRIDE] \
|
||||||
|
/*ystride3=ystride*3*/ \
|
||||||
|
__asm lea YSTRIDE3,[YSTRIDE+YSTRIDE*2] \
|
||||||
|
/*src+2*ystride*/ \
|
||||||
|
__asm movq mm2,[SRC+YSTRIDE*2] \
|
||||||
|
/*src+3*ystride*/ \
|
||||||
|
__asm movq mm3,[SRC+YSTRIDE3] \
|
||||||
|
/*dst+0*ystride*/ \
|
||||||
|
__asm movq [DST],mm0 \
|
||||||
|
/*dst+1*ystride*/ \
|
||||||
|
__asm movq [DST+YSTRIDE],mm1 \
|
||||||
|
/*Pointer to next 4.*/ \
|
||||||
|
__asm lea SRC,[SRC+YSTRIDE*4] \
|
||||||
|
/*dst+2*ystride*/ \
|
||||||
|
__asm movq [DST+YSTRIDE*2],mm2 \
|
||||||
|
/*dst+3*ystride*/ \
|
||||||
|
__asm movq [DST+YSTRIDE3],mm3 \
|
||||||
|
/*Pointer to next 4.*/ \
|
||||||
|
__asm lea DST,[DST+YSTRIDE*4] \
|
||||||
|
/*src+0*ystride*/ \
|
||||||
|
__asm movq mm0,[SRC] \
|
||||||
|
/*src+1*ystride*/ \
|
||||||
|
__asm movq mm1,[SRC+YSTRIDE] \
|
||||||
|
/*src+2*ystride*/ \
|
||||||
|
__asm movq mm2,[SRC+YSTRIDE*2] \
|
||||||
|
/*src+3*ystride*/ \
|
||||||
|
__asm movq mm3,[SRC+YSTRIDE3] \
|
||||||
|
/*dst+0*ystride*/ \
|
||||||
|
__asm movq [DST],mm0 \
|
||||||
|
/*dst+1*ystride*/ \
|
||||||
|
__asm movq [DST+YSTRIDE],mm1 \
|
||||||
|
/*dst+2*ystride*/ \
|
||||||
|
__asm movq [DST+YSTRIDE*2],mm2 \
|
||||||
|
/*dst+3*ystride*/ \
|
||||||
|
__asm movq [DST+YSTRIDE3],mm3 \
|
||||||
|
} \
|
||||||
|
while(0)
|
||||||
|
|
||||||
|
/*Copies an 8x8 block of pixels from _src to _dst, assuming _ystride bytes
|
||||||
|
between rows.*/
|
||||||
|
void oc_frag_copy_mmx(unsigned char *_dst,
|
||||||
|
const unsigned char *_src,int _ystride){
|
||||||
|
#define SRC edx
|
||||||
|
#define DST eax
|
||||||
|
#define YSTRIDE ecx
|
||||||
|
#define YSTRIDE3 esi
|
||||||
|
OC_FRAG_COPY_MMX(_dst,_src,_ystride);
|
||||||
|
#undef SRC
|
||||||
|
#undef DST
|
||||||
|
#undef YSTRIDE
|
||||||
|
#undef YSTRIDE3
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Copies the fragments specified by the lists of fragment indices from one
|
||||||
|
frame to another.
|
||||||
|
_dst_frame: The reference frame to copy to.
|
||||||
|
_src_frame: The reference frame to copy from.
|
||||||
|
_ystride: The row stride of the reference frames.
|
||||||
|
_fragis: A pointer to a list of fragment indices.
|
||||||
|
_nfragis: The number of fragment indices to copy.
|
||||||
|
_frag_buf_offs: The offsets of fragments in the reference frames.*/
|
||||||
|
void oc_frag_copy_list_mmx(unsigned char *_dst_frame,
|
||||||
|
const unsigned char *_src_frame,int _ystride,
|
||||||
|
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs){
|
||||||
|
ptrdiff_t fragii;
|
||||||
|
for(fragii=0;fragii<_nfragis;fragii++){
|
||||||
|
ptrdiff_t frag_buf_off;
|
||||||
|
frag_buf_off=_frag_buf_offs[_fragis[fragii]];
|
||||||
|
#define SRC edx
|
||||||
|
#define DST eax
|
||||||
|
#define YSTRIDE ecx
|
||||||
|
#define YSTRIDE3 edi
|
||||||
|
OC_FRAG_COPY_MMX(_dst_frame+frag_buf_off,
|
||||||
|
_src_frame+frag_buf_off,_ystride);
|
||||||
|
#undef SRC
|
||||||
|
#undef DST
|
||||||
|
#undef YSTRIDE
|
||||||
|
#undef YSTRIDE3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_frag_recon_intra_mmx(unsigned char *_dst,int _ystride,
|
||||||
|
const ogg_int16_t *_residue){
|
||||||
|
__asm{
|
||||||
|
#define DST edx
|
||||||
|
#define DST4 esi
|
||||||
|
#define YSTRIDE eax
|
||||||
|
#define YSTRIDE3 edi
|
||||||
|
#define RESIDUE ecx
|
||||||
|
mov DST,_dst
|
||||||
|
mov YSTRIDE,_ystride
|
||||||
|
mov RESIDUE,_residue
|
||||||
|
lea DST4,[DST+YSTRIDE*4]
|
||||||
|
lea YSTRIDE3,[YSTRIDE+YSTRIDE*2]
|
||||||
|
/*Set mm0 to 0xFFFFFFFFFFFFFFFF.*/
|
||||||
|
pcmpeqw mm0,mm0
|
||||||
|
/*#0 Load low residue.*/
|
||||||
|
movq mm1,[0*8+RESIDUE]
|
||||||
|
/*#0 Load high residue.*/
|
||||||
|
movq mm2,[1*8+RESIDUE]
|
||||||
|
/*Set mm0 to 0x8000800080008000.*/
|
||||||
|
psllw mm0,15
|
||||||
|
/*#1 Load low residue.*/
|
||||||
|
movq mm3,[2*8+RESIDUE]
|
||||||
|
/*#1 Load high residue.*/
|
||||||
|
movq mm4,[3*8+RESIDUE]
|
||||||
|
/*Set mm0 to 0x0080008000800080.*/
|
||||||
|
psrlw mm0,8
|
||||||
|
/*#2 Load low residue.*/
|
||||||
|
movq mm5,[4*8+RESIDUE]
|
||||||
|
/*#2 Load high residue.*/
|
||||||
|
movq mm6,[5*8+RESIDUE]
|
||||||
|
/*#0 Bias low residue.*/
|
||||||
|
paddsw mm1,mm0
|
||||||
|
/*#0 Bias high residue.*/
|
||||||
|
paddsw mm2,mm0
|
||||||
|
/*#0 Pack to byte.*/
|
||||||
|
packuswb mm1,mm2
|
||||||
|
/*#1 Bias low residue.*/
|
||||||
|
paddsw mm3,mm0
|
||||||
|
/*#1 Bias high residue.*/
|
||||||
|
paddsw mm4,mm0
|
||||||
|
/*#1 Pack to byte.*/
|
||||||
|
packuswb mm3,mm4
|
||||||
|
/*#2 Bias low residue.*/
|
||||||
|
paddsw mm5,mm0
|
||||||
|
/*#2 Bias high residue.*/
|
||||||
|
paddsw mm6,mm0
|
||||||
|
/*#2 Pack to byte.*/
|
||||||
|
packuswb mm5,mm6
|
||||||
|
/*#0 Write row.*/
|
||||||
|
movq [DST],mm1
|
||||||
|
/*#1 Write row.*/
|
||||||
|
movq [DST+YSTRIDE],mm3
|
||||||
|
/*#2 Write row.*/
|
||||||
|
movq [DST+YSTRIDE*2],mm5
|
||||||
|
/*#3 Load low residue.*/
|
||||||
|
movq mm1,[6*8+RESIDUE]
|
||||||
|
/*#3 Load high residue.*/
|
||||||
|
movq mm2,[7*8+RESIDUE]
|
||||||
|
/*#4 Load high residue.*/
|
||||||
|
movq mm3,[8*8+RESIDUE]
|
||||||
|
/*#4 Load high residue.*/
|
||||||
|
movq mm4,[9*8+RESIDUE]
|
||||||
|
/*#5 Load high residue.*/
|
||||||
|
movq mm5,[10*8+RESIDUE]
|
||||||
|
/*#5 Load high residue.*/
|
||||||
|
movq mm6,[11*8+RESIDUE]
|
||||||
|
/*#3 Bias low residue.*/
|
||||||
|
paddsw mm1,mm0
|
||||||
|
/*#3 Bias high residue.*/
|
||||||
|
paddsw mm2,mm0
|
||||||
|
/*#3 Pack to byte.*/
|
||||||
|
packuswb mm1,mm2
|
||||||
|
/*#4 Bias low residue.*/
|
||||||
|
paddsw mm3,mm0
|
||||||
|
/*#4 Bias high residue.*/
|
||||||
|
paddsw mm4,mm0
|
||||||
|
/*#4 Pack to byte.*/
|
||||||
|
packuswb mm3,mm4
|
||||||
|
/*#5 Bias low residue.*/
|
||||||
|
paddsw mm5,mm0
|
||||||
|
/*#5 Bias high residue.*/
|
||||||
|
paddsw mm6,mm0
|
||||||
|
/*#5 Pack to byte.*/
|
||||||
|
packuswb mm5,mm6
|
||||||
|
/*#3 Write row.*/
|
||||||
|
movq [DST+YSTRIDE3],mm1
|
||||||
|
/*#4 Write row.*/
|
||||||
|
movq [DST4],mm3
|
||||||
|
/*#5 Write row.*/
|
||||||
|
movq [DST4+YSTRIDE],mm5
|
||||||
|
/*#6 Load low residue.*/
|
||||||
|
movq mm1,[12*8+RESIDUE]
|
||||||
|
/*#6 Load high residue.*/
|
||||||
|
movq mm2,[13*8+RESIDUE]
|
||||||
|
/*#7 Load low residue.*/
|
||||||
|
movq mm3,[14*8+RESIDUE]
|
||||||
|
/*#7 Load high residue.*/
|
||||||
|
movq mm4,[15*8+RESIDUE]
|
||||||
|
/*#6 Bias low residue.*/
|
||||||
|
paddsw mm1,mm0
|
||||||
|
/*#6 Bias high residue.*/
|
||||||
|
paddsw mm2,mm0
|
||||||
|
/*#6 Pack to byte.*/
|
||||||
|
packuswb mm1,mm2
|
||||||
|
/*#7 Bias low residue.*/
|
||||||
|
paddsw mm3,mm0
|
||||||
|
/*#7 Bias high residue.*/
|
||||||
|
paddsw mm4,mm0
|
||||||
|
/*#7 Pack to byte.*/
|
||||||
|
packuswb mm3,mm4
|
||||||
|
/*#6 Write row.*/
|
||||||
|
movq [DST4+YSTRIDE*2],mm1
|
||||||
|
/*#7 Write row.*/
|
||||||
|
movq [DST4+YSTRIDE3],mm3
|
||||||
|
#undef DST
|
||||||
|
#undef DST4
|
||||||
|
#undef YSTRIDE
|
||||||
|
#undef YSTRIDE3
|
||||||
|
#undef RESIDUE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_frag_recon_inter_mmx(unsigned char *_dst,const unsigned char *_src,
|
||||||
|
int _ystride,const ogg_int16_t *_residue){
|
||||||
|
int i;
|
||||||
|
/*Zero mm0.*/
|
||||||
|
__asm pxor mm0,mm0;
|
||||||
|
for(i=4;i-->0;){
|
||||||
|
__asm{
|
||||||
|
#define DST edx
|
||||||
|
#define SRC ecx
|
||||||
|
#define YSTRIDE edi
|
||||||
|
#define RESIDUE eax
|
||||||
|
mov DST,_dst
|
||||||
|
mov SRC,_src
|
||||||
|
mov YSTRIDE,_ystride
|
||||||
|
mov RESIDUE,_residue
|
||||||
|
/*#0 Load source.*/
|
||||||
|
movq mm3,[SRC]
|
||||||
|
/*#1 Load source.*/
|
||||||
|
movq mm7,[SRC+YSTRIDE]
|
||||||
|
/*#0 Get copy of src.*/
|
||||||
|
movq mm4,mm3
|
||||||
|
/*#0 Expand high source.*/
|
||||||
|
punpckhbw mm4,mm0
|
||||||
|
/*#0 Expand low source.*/
|
||||||
|
punpcklbw mm3,mm0
|
||||||
|
/*#0 Add residue high.*/
|
||||||
|
paddsw mm4,[8+RESIDUE]
|
||||||
|
/*#1 Get copy of src.*/
|
||||||
|
movq mm2,mm7
|
||||||
|
/*#0 Add residue low.*/
|
||||||
|
paddsw mm3,[RESIDUE]
|
||||||
|
/*#1 Expand high source.*/
|
||||||
|
punpckhbw mm2,mm0
|
||||||
|
/*#0 Pack final row pixels.*/
|
||||||
|
packuswb mm3,mm4
|
||||||
|
/*#1 Expand low source.*/
|
||||||
|
punpcklbw mm7,mm0
|
||||||
|
/*#1 Add residue low.*/
|
||||||
|
paddsw mm7,[16+RESIDUE]
|
||||||
|
/*#1 Add residue high.*/
|
||||||
|
paddsw mm2,[24+RESIDUE]
|
||||||
|
/*Advance residue.*/
|
||||||
|
lea RESIDUE,[32+RESIDUE]
|
||||||
|
/*#1 Pack final row pixels.*/
|
||||||
|
packuswb mm7,mm2
|
||||||
|
/*Advance src.*/
|
||||||
|
lea SRC,[SRC+YSTRIDE*2]
|
||||||
|
/*#0 Write row.*/
|
||||||
|
movq [DST],mm3
|
||||||
|
/*#1 Write row.*/
|
||||||
|
movq [DST+YSTRIDE],mm7
|
||||||
|
/*Advance dst.*/
|
||||||
|
lea DST,[DST+YSTRIDE*2]
|
||||||
|
mov _residue,RESIDUE
|
||||||
|
mov _dst,DST
|
||||||
|
mov _src,SRC
|
||||||
|
#undef DST
|
||||||
|
#undef SRC
|
||||||
|
#undef YSTRIDE
|
||||||
|
#undef RESIDUE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_frag_recon_inter2_mmx(unsigned char *_dst,const unsigned char *_src1,
|
||||||
|
const unsigned char *_src2,int _ystride,const ogg_int16_t *_residue){
|
||||||
|
int i;
|
||||||
|
/*Zero mm7.*/
|
||||||
|
__asm pxor mm7,mm7;
|
||||||
|
for(i=4;i-->0;){
|
||||||
|
__asm{
|
||||||
|
#define SRC1 ecx
|
||||||
|
#define SRC2 edi
|
||||||
|
#define YSTRIDE esi
|
||||||
|
#define RESIDUE edx
|
||||||
|
#define DST eax
|
||||||
|
mov YSTRIDE,_ystride
|
||||||
|
mov DST,_dst
|
||||||
|
mov RESIDUE,_residue
|
||||||
|
mov SRC1,_src1
|
||||||
|
mov SRC2,_src2
|
||||||
|
/*#0 Load src1.*/
|
||||||
|
movq mm0,[SRC1]
|
||||||
|
/*#0 Load src2.*/
|
||||||
|
movq mm2,[SRC2]
|
||||||
|
/*#0 Copy src1.*/
|
||||||
|
movq mm1,mm0
|
||||||
|
/*#0 Copy src2.*/
|
||||||
|
movq mm3,mm2
|
||||||
|
/*#1 Load src1.*/
|
||||||
|
movq mm4,[SRC1+YSTRIDE]
|
||||||
|
/*#0 Unpack lower src1.*/
|
||||||
|
punpcklbw mm0,mm7
|
||||||
|
/*#1 Load src2.*/
|
||||||
|
movq mm5,[SRC2+YSTRIDE]
|
||||||
|
/*#0 Unpack higher src1.*/
|
||||||
|
punpckhbw mm1,mm7
|
||||||
|
/*#0 Unpack lower src2.*/
|
||||||
|
punpcklbw mm2,mm7
|
||||||
|
/*#0 Unpack higher src2.*/
|
||||||
|
punpckhbw mm3,mm7
|
||||||
|
/*Advance src1 ptr.*/
|
||||||
|
lea SRC1,[SRC1+YSTRIDE*2]
|
||||||
|
/*Advance src2 ptr.*/
|
||||||
|
lea SRC2,[SRC2+YSTRIDE*2]
|
||||||
|
/*#0 Lower src1+src2.*/
|
||||||
|
paddsw mm0,mm2
|
||||||
|
/*#0 Higher src1+src2.*/
|
||||||
|
paddsw mm1,mm3
|
||||||
|
/*#1 Copy src1.*/
|
||||||
|
movq mm2,mm4
|
||||||
|
/*#0 Build lo average.*/
|
||||||
|
psraw mm0,1
|
||||||
|
/*#1 Copy src2.*/
|
||||||
|
movq mm3,mm5
|
||||||
|
/*#1 Unpack lower src1.*/
|
||||||
|
punpcklbw mm4,mm7
|
||||||
|
/*#0 Build hi average.*/
|
||||||
|
psraw mm1,1
|
||||||
|
/*#1 Unpack higher src1.*/
|
||||||
|
punpckhbw mm2,mm7
|
||||||
|
/*#0 low+=residue.*/
|
||||||
|
paddsw mm0,[RESIDUE]
|
||||||
|
/*#1 Unpack lower src2.*/
|
||||||
|
punpcklbw mm5,mm7
|
||||||
|
/*#0 high+=residue.*/
|
||||||
|
paddsw mm1,[8+RESIDUE]
|
||||||
|
/*#1 Unpack higher src2.*/
|
||||||
|
punpckhbw mm3,mm7
|
||||||
|
/*#1 Lower src1+src2.*/
|
||||||
|
paddsw mm5,mm4
|
||||||
|
/*#0 Pack and saturate.*/
|
||||||
|
packuswb mm0,mm1
|
||||||
|
/*#1 Higher src1+src2.*/
|
||||||
|
paddsw mm3,mm2
|
||||||
|
/*#0 Write row.*/
|
||||||
|
movq [DST],mm0
|
||||||
|
/*#1 Build lo average.*/
|
||||||
|
psraw mm5,1
|
||||||
|
/*#1 Build hi average.*/
|
||||||
|
psraw mm3,1
|
||||||
|
/*#1 low+=residue.*/
|
||||||
|
paddsw mm5,[16+RESIDUE]
|
||||||
|
/*#1 high+=residue.*/
|
||||||
|
paddsw mm3,[24+RESIDUE]
|
||||||
|
/*#1 Pack and saturate.*/
|
||||||
|
packuswb mm5,mm3
|
||||||
|
/*#1 Write row ptr.*/
|
||||||
|
movq [DST+YSTRIDE],mm5
|
||||||
|
/*Advance residue ptr.*/
|
||||||
|
add RESIDUE,32
|
||||||
|
/*Advance dest ptr.*/
|
||||||
|
lea DST,[DST+YSTRIDE*2]
|
||||||
|
mov _dst,DST
|
||||||
|
mov _residue,RESIDUE
|
||||||
|
mov _src1,SRC1
|
||||||
|
mov _src2,SRC2
|
||||||
|
#undef SRC1
|
||||||
|
#undef SRC2
|
||||||
|
#undef YSTRIDE
|
||||||
|
#undef RESIDUE
|
||||||
|
#undef DST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oc_restore_fpu_mmx(void){
|
||||||
|
__asm emms;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,592 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
/*MMX acceleration of Theora's iDCT.
|
||||||
|
Originally written by Rudolf Marek, based on code from On2's VP3.*/
|
||||||
|
#include "x86int.h"
|
||||||
|
#include "../dct.h"
|
||||||
|
|
||||||
|
#if defined(OC_X86_ASM)
|
||||||
|
|
||||||
|
/*These are offsets into the table of constants below.*/
|
||||||
|
/*7 rows of cosines, in order: pi/16 * (1 ... 7).*/
|
||||||
|
#define OC_COSINE_OFFSET (8)
|
||||||
|
/*A row of 8's.*/
|
||||||
|
#define OC_EIGHT_OFFSET (0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*A table of constants used by the MMX routines.*/
|
||||||
|
static const OC_ALIGN16(ogg_uint16_t) OC_IDCT_CONSTS[(1+7)*4]={
|
||||||
|
8, 8, 8, 8,
|
||||||
|
(ogg_uint16_t)OC_C1S7,(ogg_uint16_t)OC_C1S7,
|
||||||
|
(ogg_uint16_t)OC_C1S7,(ogg_uint16_t)OC_C1S7,
|
||||||
|
(ogg_uint16_t)OC_C2S6,(ogg_uint16_t)OC_C2S6,
|
||||||
|
(ogg_uint16_t)OC_C2S6,(ogg_uint16_t)OC_C2S6,
|
||||||
|
(ogg_uint16_t)OC_C3S5,(ogg_uint16_t)OC_C3S5,
|
||||||
|
(ogg_uint16_t)OC_C3S5,(ogg_uint16_t)OC_C3S5,
|
||||||
|
(ogg_uint16_t)OC_C4S4,(ogg_uint16_t)OC_C4S4,
|
||||||
|
(ogg_uint16_t)OC_C4S4,(ogg_uint16_t)OC_C4S4,
|
||||||
|
(ogg_uint16_t)OC_C5S3,(ogg_uint16_t)OC_C5S3,
|
||||||
|
(ogg_uint16_t)OC_C5S3,(ogg_uint16_t)OC_C5S3,
|
||||||
|
(ogg_uint16_t)OC_C6S2,(ogg_uint16_t)OC_C6S2,
|
||||||
|
(ogg_uint16_t)OC_C6S2,(ogg_uint16_t)OC_C6S2,
|
||||||
|
(ogg_uint16_t)OC_C7S1,(ogg_uint16_t)OC_C7S1,
|
||||||
|
(ogg_uint16_t)OC_C7S1,(ogg_uint16_t)OC_C7S1
|
||||||
|
};
|
||||||
|
|
||||||
|
/*38 cycles*/
|
||||||
|
#define OC_IDCT_BEGIN(_y,_x) __asm{ \
|
||||||
|
__asm movq mm2,OC_I(3,_x) \
|
||||||
|
__asm movq mm6,OC_C(3) \
|
||||||
|
__asm movq mm4,mm2 \
|
||||||
|
__asm movq mm7,OC_J(5,_x) \
|
||||||
|
__asm pmulhw mm4,mm6 \
|
||||||
|
__asm movq mm1,OC_C(5) \
|
||||||
|
__asm pmulhw mm6,mm7 \
|
||||||
|
__asm movq mm5,mm1 \
|
||||||
|
__asm pmulhw mm1,mm2 \
|
||||||
|
__asm movq mm3,OC_I(1,_x) \
|
||||||
|
__asm pmulhw mm5,mm7 \
|
||||||
|
__asm movq mm0,OC_C(1) \
|
||||||
|
__asm paddw mm4,mm2 \
|
||||||
|
__asm paddw mm6,mm7 \
|
||||||
|
__asm paddw mm2,mm1 \
|
||||||
|
__asm movq mm1,OC_J(7,_x) \
|
||||||
|
__asm paddw mm7,mm5 \
|
||||||
|
__asm movq mm5,mm0 \
|
||||||
|
__asm pmulhw mm0,mm3 \
|
||||||
|
__asm paddw mm4,mm7 \
|
||||||
|
__asm pmulhw mm5,mm1 \
|
||||||
|
__asm movq mm7,OC_C(7) \
|
||||||
|
__asm psubw mm6,mm2 \
|
||||||
|
__asm paddw mm0,mm3 \
|
||||||
|
__asm pmulhw mm3,mm7 \
|
||||||
|
__asm movq mm2,OC_I(2,_x) \
|
||||||
|
__asm pmulhw mm7,mm1 \
|
||||||
|
__asm paddw mm5,mm1 \
|
||||||
|
__asm movq mm1,mm2 \
|
||||||
|
__asm pmulhw mm2,OC_C(2) \
|
||||||
|
__asm psubw mm3,mm5 \
|
||||||
|
__asm movq mm5,OC_J(6,_x) \
|
||||||
|
__asm paddw mm0,mm7 \
|
||||||
|
__asm movq mm7,mm5 \
|
||||||
|
__asm psubw mm0,mm4 \
|
||||||
|
__asm pmulhw mm5,OC_C(2) \
|
||||||
|
__asm paddw mm2,mm1 \
|
||||||
|
__asm pmulhw mm1,OC_C(6) \
|
||||||
|
__asm paddw mm4,mm4 \
|
||||||
|
__asm paddw mm4,mm0 \
|
||||||
|
__asm psubw mm3,mm6 \
|
||||||
|
__asm paddw mm5,mm7 \
|
||||||
|
__asm paddw mm6,mm6 \
|
||||||
|
__asm pmulhw mm7,OC_C(6) \
|
||||||
|
__asm paddw mm6,mm3 \
|
||||||
|
__asm movq OC_I(1,_y),mm4 \
|
||||||
|
__asm psubw mm1,mm5 \
|
||||||
|
__asm movq mm4,OC_C(4) \
|
||||||
|
__asm movq mm5,mm3 \
|
||||||
|
__asm pmulhw mm3,mm4 \
|
||||||
|
__asm paddw mm7,mm2 \
|
||||||
|
__asm movq OC_I(2,_y),mm6 \
|
||||||
|
__asm movq mm2,mm0 \
|
||||||
|
__asm movq mm6,OC_I(0,_x) \
|
||||||
|
__asm pmulhw mm0,mm4 \
|
||||||
|
__asm paddw mm5,mm3 \
|
||||||
|
__asm movq mm3,OC_J(4,_x) \
|
||||||
|
__asm psubw mm5,mm1 \
|
||||||
|
__asm paddw mm2,mm0 \
|
||||||
|
__asm psubw mm6,mm3 \
|
||||||
|
__asm movq mm0,mm6 \
|
||||||
|
__asm pmulhw mm6,mm4 \
|
||||||
|
__asm paddw mm3,mm3 \
|
||||||
|
__asm paddw mm1,mm1 \
|
||||||
|
__asm paddw mm3,mm0 \
|
||||||
|
__asm paddw mm1,mm5 \
|
||||||
|
__asm pmulhw mm4,mm3 \
|
||||||
|
__asm paddw mm6,mm0 \
|
||||||
|
__asm psubw mm6,mm2 \
|
||||||
|
__asm paddw mm2,mm2 \
|
||||||
|
__asm movq mm0,OC_I(1,_y) \
|
||||||
|
__asm paddw mm2,mm6 \
|
||||||
|
__asm paddw mm4,mm3 \
|
||||||
|
__asm psubw mm2,mm1 \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*38+8=46 cycles.*/
|
||||||
|
#define OC_ROW_IDCT(_y,_x) __asm{ \
|
||||||
|
OC_IDCT_BEGIN(_y,_x) \
|
||||||
|
/*r3=D'*/ \
|
||||||
|
__asm movq mm3,OC_I(2,_y) \
|
||||||
|
/*r4=E'=E-G*/ \
|
||||||
|
__asm psubw mm4,mm7 \
|
||||||
|
/*r1=H'+H'*/ \
|
||||||
|
__asm paddw mm1,mm1 \
|
||||||
|
/*r7=G+G*/ \
|
||||||
|
__asm paddw mm7,mm7 \
|
||||||
|
/*r1=R1=A''+H'*/ \
|
||||||
|
__asm paddw mm1,mm2 \
|
||||||
|
/*r7=G'=E+G*/ \
|
||||||
|
__asm paddw mm7,mm4 \
|
||||||
|
/*r4=R4=E'-D'*/ \
|
||||||
|
__asm psubw mm4,mm3 \
|
||||||
|
__asm paddw mm3,mm3 \
|
||||||
|
/*r6=R6=F'-B''*/ \
|
||||||
|
__asm psubw mm6,mm5 \
|
||||||
|
__asm paddw mm5,mm5 \
|
||||||
|
/*r3=R3=E'+D'*/ \
|
||||||
|
__asm paddw mm3,mm4 \
|
||||||
|
/*r5=R5=F'+B''*/ \
|
||||||
|
__asm paddw mm5,mm6 \
|
||||||
|
/*r7=R7=G'-C'*/ \
|
||||||
|
__asm psubw mm7,mm0 \
|
||||||
|
__asm paddw mm0,mm0 \
|
||||||
|
/*Save R1.*/ \
|
||||||
|
__asm movq OC_I(1,_y),mm1 \
|
||||||
|
/*r0=R0=G.+C.*/ \
|
||||||
|
__asm paddw mm0,mm7 \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*The following macro does two 4x4 transposes in place.
|
||||||
|
At entry, we assume:
|
||||||
|
r0 = a3 a2 a1 a0
|
||||||
|
I(1) = b3 b2 b1 b0
|
||||||
|
r2 = c3 c2 c1 c0
|
||||||
|
r3 = d3 d2 d1 d0
|
||||||
|
|
||||||
|
r4 = e3 e2 e1 e0
|
||||||
|
r5 = f3 f2 f1 f0
|
||||||
|
r6 = g3 g2 g1 g0
|
||||||
|
r7 = h3 h2 h1 h0
|
||||||
|
|
||||||
|
At exit, we have:
|
||||||
|
I(0) = d0 c0 b0 a0
|
||||||
|
I(1) = d1 c1 b1 a1
|
||||||
|
I(2) = d2 c2 b2 a2
|
||||||
|
I(3) = d3 c3 b3 a3
|
||||||
|
|
||||||
|
J(4) = h0 g0 f0 e0
|
||||||
|
J(5) = h1 g1 f1 e1
|
||||||
|
J(6) = h2 g2 f2 e2
|
||||||
|
J(7) = h3 g3 f3 e3
|
||||||
|
|
||||||
|
I(0) I(1) I(2) I(3) is the transpose of r0 I(1) r2 r3.
|
||||||
|
J(4) J(5) J(6) J(7) is the transpose of r4 r5 r6 r7.
|
||||||
|
|
||||||
|
Since r1 is free at entry, we calculate the Js first.*/
|
||||||
|
/*19 cycles.*/
|
||||||
|
#define OC_TRANSPOSE(_y) __asm{ \
|
||||||
|
__asm movq mm1,mm4 \
|
||||||
|
__asm punpcklwd mm4,mm5 \
|
||||||
|
__asm movq OC_I(0,_y),mm0 \
|
||||||
|
__asm punpckhwd mm1,mm5 \
|
||||||
|
__asm movq mm0,mm6 \
|
||||||
|
__asm punpcklwd mm6,mm7 \
|
||||||
|
__asm movq mm5,mm4 \
|
||||||
|
__asm punpckldq mm4,mm6 \
|
||||||
|
__asm punpckhdq mm5,mm6 \
|
||||||
|
__asm movq mm6,mm1 \
|
||||||
|
__asm movq OC_J(4,_y),mm4 \
|
||||||
|
__asm punpckhwd mm0,mm7 \
|
||||||
|
__asm movq OC_J(5,_y),mm5 \
|
||||||
|
__asm punpckhdq mm6,mm0 \
|
||||||
|
__asm movq mm4,OC_I(0,_y) \
|
||||||
|
__asm punpckldq mm1,mm0 \
|
||||||
|
__asm movq mm5,OC_I(1,_y) \
|
||||||
|
__asm movq mm0,mm4 \
|
||||||
|
__asm movq OC_J(7,_y),mm6 \
|
||||||
|
__asm punpcklwd mm0,mm5 \
|
||||||
|
__asm movq OC_J(6,_y),mm1 \
|
||||||
|
__asm punpckhwd mm4,mm5 \
|
||||||
|
__asm movq mm5,mm2 \
|
||||||
|
__asm punpcklwd mm2,mm3 \
|
||||||
|
__asm movq mm1,mm0 \
|
||||||
|
__asm punpckldq mm0,mm2 \
|
||||||
|
__asm punpckhdq mm1,mm2 \
|
||||||
|
__asm movq mm2,mm4 \
|
||||||
|
__asm movq OC_I(0,_y),mm0 \
|
||||||
|
__asm punpckhwd mm5,mm3 \
|
||||||
|
__asm movq OC_I(1,_y),mm1 \
|
||||||
|
__asm punpckhdq mm4,mm5 \
|
||||||
|
__asm punpckldq mm2,mm5 \
|
||||||
|
__asm movq OC_I(3,_y),mm4 \
|
||||||
|
__asm movq OC_I(2,_y),mm2 \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*38+19=57 cycles.*/
|
||||||
|
#define OC_COLUMN_IDCT(_y) __asm{ \
|
||||||
|
OC_IDCT_BEGIN(_y,_y) \
|
||||||
|
__asm paddw mm2,OC_8 \
|
||||||
|
/*r1=H'+H'*/ \
|
||||||
|
__asm paddw mm1,mm1 \
|
||||||
|
/*r1=R1=A''+H'*/ \
|
||||||
|
__asm paddw mm1,mm2 \
|
||||||
|
/*r2=NR2*/ \
|
||||||
|
__asm psraw mm2,4 \
|
||||||
|
/*r4=E'=E-G*/ \
|
||||||
|
__asm psubw mm4,mm7 \
|
||||||
|
/*r1=NR1*/ \
|
||||||
|
__asm psraw mm1,4 \
|
||||||
|
/*r3=D'*/ \
|
||||||
|
__asm movq mm3,OC_I(2,_y) \
|
||||||
|
/*r7=G+G*/ \
|
||||||
|
__asm paddw mm7,mm7 \
|
||||||
|
/*Store NR2 at I(2).*/ \
|
||||||
|
__asm movq OC_I(2,_y),mm2 \
|
||||||
|
/*r7=G'=E+G*/ \
|
||||||
|
__asm paddw mm7,mm4 \
|
||||||
|
/*Store NR1 at I(1).*/ \
|
||||||
|
__asm movq OC_I(1,_y),mm1 \
|
||||||
|
/*r4=R4=E'-D'*/ \
|
||||||
|
__asm psubw mm4,mm3 \
|
||||||
|
__asm paddw mm4,OC_8 \
|
||||||
|
/*r3=D'+D'*/ \
|
||||||
|
__asm paddw mm3,mm3 \
|
||||||
|
/*r3=R3=E'+D'*/ \
|
||||||
|
__asm paddw mm3,mm4 \
|
||||||
|
/*r4=NR4*/ \
|
||||||
|
__asm psraw mm4,4 \
|
||||||
|
/*r6=R6=F'-B''*/ \
|
||||||
|
__asm psubw mm6,mm5 \
|
||||||
|
/*r3=NR3*/ \
|
||||||
|
__asm psraw mm3,4 \
|
||||||
|
__asm paddw mm6,OC_8 \
|
||||||
|
/*r5=B''+B''*/ \
|
||||||
|
__asm paddw mm5,mm5 \
|
||||||
|
/*r5=R5=F'+B''*/ \
|
||||||
|
__asm paddw mm5,mm6 \
|
||||||
|
/*r6=NR6*/ \
|
||||||
|
__asm psraw mm6,4 \
|
||||||
|
/*Store NR4 at J(4).*/ \
|
||||||
|
__asm movq OC_J(4,_y),mm4 \
|
||||||
|
/*r5=NR5*/ \
|
||||||
|
__asm psraw mm5,4 \
|
||||||
|
/*Store NR3 at I(3).*/ \
|
||||||
|
__asm movq OC_I(3,_y),mm3 \
|
||||||
|
/*r7=R7=G'-C'*/ \
|
||||||
|
__asm psubw mm7,mm0 \
|
||||||
|
__asm paddw mm7,OC_8 \
|
||||||
|
/*r0=C'+C'*/ \
|
||||||
|
__asm paddw mm0,mm0 \
|
||||||
|
/*r0=R0=G'+C'*/ \
|
||||||
|
__asm paddw mm0,mm7 \
|
||||||
|
/*r7=NR7*/ \
|
||||||
|
__asm psraw mm7,4 \
|
||||||
|
/*Store NR6 at J(6).*/ \
|
||||||
|
__asm movq OC_J(6,_y),mm6 \
|
||||||
|
/*r0=NR0*/ \
|
||||||
|
__asm psraw mm0,4 \
|
||||||
|
/*Store NR5 at J(5).*/ \
|
||||||
|
__asm movq OC_J(5,_y),mm5 \
|
||||||
|
/*Store NR7 at J(7).*/ \
|
||||||
|
__asm movq OC_J(7,_y),mm7 \
|
||||||
|
/*Store NR0 at I(0).*/ \
|
||||||
|
__asm movq OC_I(0,_y),mm0 \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OC_MID(_m,_i) [CONSTS+_m+(_i)*8]
|
||||||
|
#define OC_C(_i) OC_MID(OC_COSINE_OFFSET,_i-1)
|
||||||
|
#define OC_8 OC_MID(OC_EIGHT_OFFSET,0)
|
||||||
|
|
||||||
|
static void oc_idct8x8_slow(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||||
|
int i;
|
||||||
|
/*This routine accepts an 8x8 matrix, but in partially transposed form.
|
||||||
|
Every 4x4 block is transposed.*/
|
||||||
|
__asm{
|
||||||
|
#define CONSTS eax
|
||||||
|
#define Y edx
|
||||||
|
#define X ecx
|
||||||
|
mov CONSTS,offset OC_IDCT_CONSTS
|
||||||
|
mov Y,_y
|
||||||
|
mov X,_x
|
||||||
|
#define OC_I(_k,_y) [(_y)+(_k)*16]
|
||||||
|
#define OC_J(_k,_y) [(_y)+((_k)-4)*16+8]
|
||||||
|
OC_ROW_IDCT(Y,X)
|
||||||
|
OC_TRANSPOSE(Y)
|
||||||
|
#undef OC_I
|
||||||
|
#undef OC_J
|
||||||
|
#define OC_I(_k,_y) [(_y)+(_k)*16+64]
|
||||||
|
#define OC_J(_k,_y) [(_y)+((_k)-4)*16+72]
|
||||||
|
OC_ROW_IDCT(Y,X)
|
||||||
|
OC_TRANSPOSE(Y)
|
||||||
|
#undef OC_I
|
||||||
|
#undef OC_J
|
||||||
|
#define OC_I(_k,_y) [(_y)+(_k)*16]
|
||||||
|
#define OC_J(_k,_y) OC_I(_k,_y)
|
||||||
|
OC_COLUMN_IDCT(Y)
|
||||||
|
#undef OC_I
|
||||||
|
#undef OC_J
|
||||||
|
#define OC_I(_k,_y) [(_y)+(_k)*16+8]
|
||||||
|
#define OC_J(_k,_y) OC_I(_k,_y)
|
||||||
|
OC_COLUMN_IDCT(Y)
|
||||||
|
#undef OC_I
|
||||||
|
#undef OC_J
|
||||||
|
#undef CONSTS
|
||||||
|
#undef Y
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
__asm pxor mm0,mm0;
|
||||||
|
for(i=0;i<4;i++){
|
||||||
|
ogg_int16_t *x;
|
||||||
|
x=_x+16*i;
|
||||||
|
#define X ecx
|
||||||
|
__asm{
|
||||||
|
mov X,x
|
||||||
|
movq [X+0x00],mm0
|
||||||
|
movq [X+0x08],mm0
|
||||||
|
movq [X+0x10],mm0
|
||||||
|
movq [X+0x18],mm0
|
||||||
|
}
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*25 cycles.*/
|
||||||
|
#define OC_IDCT_BEGIN_10(_y,_x) __asm{ \
|
||||||
|
__asm movq mm2,OC_I(3,_x) \
|
||||||
|
__asm nop \
|
||||||
|
__asm movq mm6,OC_C(3) \
|
||||||
|
__asm movq mm4,mm2 \
|
||||||
|
__asm movq mm1,OC_C(5) \
|
||||||
|
__asm pmulhw mm4,mm6 \
|
||||||
|
__asm movq mm3,OC_I(1,_x) \
|
||||||
|
__asm pmulhw mm1,mm2 \
|
||||||
|
__asm movq mm0,OC_C(1) \
|
||||||
|
__asm paddw mm4,mm2 \
|
||||||
|
__asm pxor mm6,mm6 \
|
||||||
|
__asm paddw mm2,mm1 \
|
||||||
|
__asm movq mm5,OC_I(2,_x) \
|
||||||
|
__asm pmulhw mm0,mm3 \
|
||||||
|
__asm movq mm1,mm5 \
|
||||||
|
__asm paddw mm0,mm3 \
|
||||||
|
__asm pmulhw mm3,OC_C(7) \
|
||||||
|
__asm psubw mm6,mm2 \
|
||||||
|
__asm pmulhw mm5,OC_C(2) \
|
||||||
|
__asm psubw mm0,mm4 \
|
||||||
|
__asm movq mm7,OC_I(2,_x) \
|
||||||
|
__asm paddw mm4,mm4 \
|
||||||
|
__asm paddw mm7,mm5 \
|
||||||
|
__asm paddw mm4,mm0 \
|
||||||
|
__asm pmulhw mm1,OC_C(6) \
|
||||||
|
__asm psubw mm3,mm6 \
|
||||||
|
__asm movq OC_I(1,_y),mm4 \
|
||||||
|
__asm paddw mm6,mm6 \
|
||||||
|
__asm movq mm4,OC_C(4) \
|
||||||
|
__asm paddw mm6,mm3 \
|
||||||
|
__asm movq mm5,mm3 \
|
||||||
|
__asm pmulhw mm3,mm4 \
|
||||||
|
__asm movq OC_I(2,_y),mm6 \
|
||||||
|
__asm movq mm2,mm0 \
|
||||||
|
__asm movq mm6,OC_I(0,_x) \
|
||||||
|
__asm pmulhw mm0,mm4 \
|
||||||
|
__asm paddw mm5,mm3 \
|
||||||
|
__asm paddw mm2,mm0 \
|
||||||
|
__asm psubw mm5,mm1 \
|
||||||
|
__asm pmulhw mm6,mm4 \
|
||||||
|
__asm paddw mm6,OC_I(0,_x) \
|
||||||
|
__asm paddw mm1,mm1 \
|
||||||
|
__asm movq mm4,mm6 \
|
||||||
|
__asm paddw mm1,mm5 \
|
||||||
|
__asm psubw mm6,mm2 \
|
||||||
|
__asm paddw mm2,mm2 \
|
||||||
|
__asm movq mm0,OC_I(1,_y) \
|
||||||
|
__asm paddw mm2,mm6 \
|
||||||
|
__asm psubw mm2,mm1 \
|
||||||
|
__asm nop \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*25+8=33 cycles.*/
|
||||||
|
#define OC_ROW_IDCT_10(_y,_x) __asm{ \
|
||||||
|
OC_IDCT_BEGIN_10(_y,_x) \
|
||||||
|
/*r3=D'*/ \
|
||||||
|
__asm movq mm3,OC_I(2,_y) \
|
||||||
|
/*r4=E'=E-G*/ \
|
||||||
|
__asm psubw mm4,mm7 \
|
||||||
|
/*r1=H'+H'*/ \
|
||||||
|
__asm paddw mm1,mm1 \
|
||||||
|
/*r7=G+G*/ \
|
||||||
|
__asm paddw mm7,mm7 \
|
||||||
|
/*r1=R1=A''+H'*/ \
|
||||||
|
__asm paddw mm1,mm2 \
|
||||||
|
/*r7=G'=E+G*/ \
|
||||||
|
__asm paddw mm7,mm4 \
|
||||||
|
/*r4=R4=E'-D'*/ \
|
||||||
|
__asm psubw mm4,mm3 \
|
||||||
|
__asm paddw mm3,mm3 \
|
||||||
|
/*r6=R6=F'-B''*/ \
|
||||||
|
__asm psubw mm6,mm5 \
|
||||||
|
__asm paddw mm5,mm5 \
|
||||||
|
/*r3=R3=E'+D'*/ \
|
||||||
|
__asm paddw mm3,mm4 \
|
||||||
|
/*r5=R5=F'+B''*/ \
|
||||||
|
__asm paddw mm5,mm6 \
|
||||||
|
/*r7=R7=G'-C'*/ \
|
||||||
|
__asm psubw mm7,mm0 \
|
||||||
|
__asm paddw mm0,mm0 \
|
||||||
|
/*Save R1.*/ \
|
||||||
|
__asm movq OC_I(1,_y),mm1 \
|
||||||
|
/*r0=R0=G'+C'*/ \
|
||||||
|
__asm paddw mm0,mm7 \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*25+19=44 cycles'*/
|
||||||
|
#define OC_COLUMN_IDCT_10(_y) __asm{ \
|
||||||
|
OC_IDCT_BEGIN_10(_y,_y) \
|
||||||
|
__asm paddw mm2,OC_8 \
|
||||||
|
/*r1=H'+H'*/ \
|
||||||
|
__asm paddw mm1,mm1 \
|
||||||
|
/*r1=R1=A''+H'*/ \
|
||||||
|
__asm paddw mm1,mm2 \
|
||||||
|
/*r2=NR2*/ \
|
||||||
|
__asm psraw mm2,4 \
|
||||||
|
/*r4=E'=E-G*/ \
|
||||||
|
__asm psubw mm4,mm7 \
|
||||||
|
/*r1=NR1*/ \
|
||||||
|
__asm psraw mm1,4 \
|
||||||
|
/*r3=D'*/ \
|
||||||
|
__asm movq mm3,OC_I(2,_y) \
|
||||||
|
/*r7=G+G*/ \
|
||||||
|
__asm paddw mm7,mm7 \
|
||||||
|
/*Store NR2 at I(2).*/ \
|
||||||
|
__asm movq OC_I(2,_y),mm2 \
|
||||||
|
/*r7=G'=E+G*/ \
|
||||||
|
__asm paddw mm7,mm4 \
|
||||||
|
/*Store NR1 at I(1).*/ \
|
||||||
|
__asm movq OC_I(1,_y),mm1 \
|
||||||
|
/*r4=R4=E'-D'*/ \
|
||||||
|
__asm psubw mm4,mm3 \
|
||||||
|
__asm paddw mm4,OC_8 \
|
||||||
|
/*r3=D'+D'*/ \
|
||||||
|
__asm paddw mm3,mm3 \
|
||||||
|
/*r3=R3=E'+D'*/ \
|
||||||
|
__asm paddw mm3,mm4 \
|
||||||
|
/*r4=NR4*/ \
|
||||||
|
__asm psraw mm4,4 \
|
||||||
|
/*r6=R6=F'-B''*/ \
|
||||||
|
__asm psubw mm6,mm5 \
|
||||||
|
/*r3=NR3*/ \
|
||||||
|
__asm psraw mm3,4 \
|
||||||
|
__asm paddw mm6,OC_8 \
|
||||||
|
/*r5=B''+B''*/ \
|
||||||
|
__asm paddw mm5,mm5 \
|
||||||
|
/*r5=R5=F'+B''*/ \
|
||||||
|
__asm paddw mm5,mm6 \
|
||||||
|
/*r6=NR6*/ \
|
||||||
|
__asm psraw mm6,4 \
|
||||||
|
/*Store NR4 at J(4).*/ \
|
||||||
|
__asm movq OC_J(4,_y),mm4 \
|
||||||
|
/*r5=NR5*/ \
|
||||||
|
__asm psraw mm5,4 \
|
||||||
|
/*Store NR3 at I(3).*/ \
|
||||||
|
__asm movq OC_I(3,_y),mm3 \
|
||||||
|
/*r7=R7=G'-C'*/ \
|
||||||
|
__asm psubw mm7,mm0 \
|
||||||
|
__asm paddw mm7,OC_8 \
|
||||||
|
/*r0=C'+C'*/ \
|
||||||
|
__asm paddw mm0,mm0 \
|
||||||
|
/*r0=R0=G'+C'*/ \
|
||||||
|
__asm paddw mm0,mm7 \
|
||||||
|
/*r7=NR7*/ \
|
||||||
|
__asm psraw mm7,4 \
|
||||||
|
/*Store NR6 at J(6).*/ \
|
||||||
|
__asm movq OC_J(6,_y),mm6 \
|
||||||
|
/*r0=NR0*/ \
|
||||||
|
__asm psraw mm0,4 \
|
||||||
|
/*Store NR5 at J(5).*/ \
|
||||||
|
__asm movq OC_J(5,_y),mm5 \
|
||||||
|
/*Store NR7 at J(7).*/ \
|
||||||
|
__asm movq OC_J(7,_y),mm7 \
|
||||||
|
/*Store NR0 at I(0).*/ \
|
||||||
|
__asm movq OC_I(0,_y),mm0 \
|
||||||
|
}
|
||||||
|
|
||||||
|
static void oc_idct8x8_10(ogg_int16_t _y[64],ogg_int16_t _x[64]){
|
||||||
|
__asm{
|
||||||
|
#define CONSTS eax
|
||||||
|
#define Y edx
|
||||||
|
#define X ecx
|
||||||
|
mov CONSTS,offset OC_IDCT_CONSTS
|
||||||
|
mov Y,_y
|
||||||
|
mov X,_x
|
||||||
|
#define OC_I(_k,_y) [(_y)+(_k)*16]
|
||||||
|
#define OC_J(_k,_y) [(_y)+((_k)-4)*16+8]
|
||||||
|
/*Done with dequant, descramble, and partial transpose.
|
||||||
|
Now do the iDCT itself.*/
|
||||||
|
OC_ROW_IDCT_10(Y,X)
|
||||||
|
OC_TRANSPOSE(Y)
|
||||||
|
#undef OC_I
|
||||||
|
#undef OC_J
|
||||||
|
#define OC_I(_k,_y) [(_y)+(_k)*16]
|
||||||
|
#define OC_J(_k,_y) OC_I(_k,_y)
|
||||||
|
OC_COLUMN_IDCT_10(Y)
|
||||||
|
#undef OC_I
|
||||||
|
#undef OC_J
|
||||||
|
#define OC_I(_k,_y) [(_y)+(_k)*16+8]
|
||||||
|
#define OC_J(_k,_y) OC_I(_k,_y)
|
||||||
|
OC_COLUMN_IDCT_10(Y)
|
||||||
|
#undef OC_I
|
||||||
|
#undef OC_J
|
||||||
|
#undef CONSTS
|
||||||
|
#undef Y
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
#define X ecx
|
||||||
|
__asm{
|
||||||
|
pxor mm0,mm0;
|
||||||
|
mov X,_x
|
||||||
|
movq [X+0x00],mm0
|
||||||
|
movq [X+0x10],mm0
|
||||||
|
movq [X+0x20],mm0
|
||||||
|
movq [X+0x30],mm0
|
||||||
|
}
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Performs an inverse 8x8 Type-II DCT transform.
|
||||||
|
The input is assumed to be scaled by a factor of 4 relative to orthonormal
|
||||||
|
version of the transform.*/
|
||||||
|
void oc_idct8x8_mmx(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi){
|
||||||
|
/*_last_zzi is subtly different from an actual count of the number of
|
||||||
|
coefficients we decoded for this block.
|
||||||
|
It contains the value of zzi BEFORE the final token in the block was
|
||||||
|
decoded.
|
||||||
|
In most cases this is an EOB token (the continuation of an EOB run from a
|
||||||
|
previous block counts), and so this is the same as the coefficient count.
|
||||||
|
However, in the case that the last token was NOT an EOB token, but filled
|
||||||
|
the block up with exactly 64 coefficients, _last_zzi will be less than 64.
|
||||||
|
Provided the last token was not a pure zero run, the minimum value it can
|
||||||
|
be is 46, and so that doesn't affect any of the cases in this routine.
|
||||||
|
However, if the last token WAS a pure zero run of length 63, then _last_zzi
|
||||||
|
will be 1 while the number of coefficients decoded is 64.
|
||||||
|
Thus, we will trigger the following special case, where the real
|
||||||
|
coefficient count would not.
|
||||||
|
Note also that a zero run of length 64 will give _last_zzi a value of 0,
|
||||||
|
but we still process the DC coefficient, which might have a non-zero value
|
||||||
|
due to DC prediction.
|
||||||
|
Although convoluted, this is arguably the correct behavior: it allows us to
|
||||||
|
use a smaller transform when the block ends with a long zero run instead
|
||||||
|
of a normal EOB token.
|
||||||
|
It could be smarter... multiple separate zero runs at the end of a block
|
||||||
|
will fool it, but an encoder that generates these really deserves what it
|
||||||
|
gets.
|
||||||
|
Needless to say we inherited this approach from VP3.*/
|
||||||
|
/*Perform the iDCT.*/
|
||||||
|
if(_last_zzi<=10)oc_idct8x8_10(_y,_x);
|
||||||
|
else oc_idct8x8_slow(_y,_x);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,219 @@
|
||||||
|
#if !defined(_x86_vc_mmxloop_H)
|
||||||
|
# define _x86_vc_mmxloop_H (1)
|
||||||
|
# include <stddef.h>
|
||||||
|
# include "x86int.h"
|
||||||
|
|
||||||
|
#if defined(OC_X86_ASM)
|
||||||
|
|
||||||
|
/*On entry, mm0={a0,...,a7}, mm1={b0,...,b7}, mm2={c0,...,c7}, mm3={d0,...d7}.
|
||||||
|
On exit, mm1={b0+lflim(R_0,L),...,b7+lflim(R_7,L)} and
|
||||||
|
mm2={c0-lflim(R_0,L),...,c7-lflim(R_7,L)}; mm0 and mm3 are clobbered.*/
|
||||||
|
#define OC_LOOP_FILTER8_MMX __asm{ \
|
||||||
|
/*mm7=0*/ \
|
||||||
|
__asm pxor mm7,mm7 \
|
||||||
|
/*mm6:mm0={a0,...,a7}*/ \
|
||||||
|
__asm movq mm6,mm0 \
|
||||||
|
__asm punpcklbw mm0,mm7 \
|
||||||
|
__asm punpckhbw mm6,mm7 \
|
||||||
|
/*mm3:mm5={d0,...,d7}*/ \
|
||||||
|
__asm movq mm5,mm3 \
|
||||||
|
__asm punpcklbw mm3,mm7 \
|
||||||
|
__asm punpckhbw mm5,mm7 \
|
||||||
|
/*mm6:mm0={a0-d0,...,a7-d7}*/ \
|
||||||
|
__asm psubw mm0,mm3 \
|
||||||
|
__asm psubw mm6,mm5 \
|
||||||
|
/*mm3:mm1={b0,...,b7}*/ \
|
||||||
|
__asm movq mm3,mm1 \
|
||||||
|
__asm punpcklbw mm1,mm7 \
|
||||||
|
__asm movq mm4,mm2 \
|
||||||
|
__asm punpckhbw mm3,mm7 \
|
||||||
|
/*mm5:mm4={c0,...,c7}*/ \
|
||||||
|
__asm movq mm5,mm2 \
|
||||||
|
__asm punpcklbw mm4,mm7 \
|
||||||
|
__asm punpckhbw mm5,mm7 \
|
||||||
|
/*mm7={3}x4 \
|
||||||
|
mm5:mm4={c0-b0,...,c7-b7}*/ \
|
||||||
|
__asm pcmpeqw mm7,mm7 \
|
||||||
|
__asm psubw mm4,mm1 \
|
||||||
|
__asm psrlw mm7,14 \
|
||||||
|
__asm psubw mm5,mm3 \
|
||||||
|
/*Scale by 3.*/ \
|
||||||
|
__asm pmullw mm4,mm7 \
|
||||||
|
__asm pmullw mm5,mm7 \
|
||||||
|
/*mm7={4}x4 \
|
||||||
|
mm5:mm4=f={a0-d0+3*(c0-b0),...,a7-d7+3*(c7-b7)}*/ \
|
||||||
|
__asm psrlw mm7,1 \
|
||||||
|
__asm paddw mm4,mm0 \
|
||||||
|
__asm psllw mm7,2 \
|
||||||
|
__asm movq mm0,[LL] \
|
||||||
|
__asm paddw mm5,mm6 \
|
||||||
|
/*R_i has the range [-127,128], so we compute -R_i instead. \
|
||||||
|
mm4=-R_i=-(f+4>>3)=0xFF^(f-4>>3)*/ \
|
||||||
|
__asm psubw mm4,mm7 \
|
||||||
|
__asm psubw mm5,mm7 \
|
||||||
|
__asm psraw mm4,3 \
|
||||||
|
__asm psraw mm5,3 \
|
||||||
|
__asm pcmpeqb mm7,mm7 \
|
||||||
|
__asm packsswb mm4,mm5 \
|
||||||
|
__asm pxor mm6,mm6 \
|
||||||
|
__asm pxor mm4,mm7 \
|
||||||
|
__asm packuswb mm1,mm3 \
|
||||||
|
/*Now compute lflim of -mm4 cf. Section 7.10 of the sepc.*/ \
|
||||||
|
/*There's no unsigned byte+signed byte with unsigned saturation op code, so \
|
||||||
|
we have to split things by sign (the other option is to work in 16 bits, \
|
||||||
|
but working in 8 bits gives much better parallelism). \
|
||||||
|
We compute abs(R_i), but save a mask of which terms were negative in mm6. \
|
||||||
|
Then we compute mm4=abs(lflim(R_i,L))=min(abs(R_i),max(2*L-abs(R_i),0)). \
|
||||||
|
Finally, we split mm4 into positive and negative pieces using the mask in \
|
||||||
|
mm6, and add and subtract them as appropriate.*/ \
|
||||||
|
/*mm4=abs(-R_i)*/ \
|
||||||
|
/*mm7=255-2*L*/ \
|
||||||
|
__asm pcmpgtb mm6,mm4 \
|
||||||
|
__asm psubb mm7,mm0 \
|
||||||
|
__asm pxor mm4,mm6 \
|
||||||
|
__asm psubb mm7,mm0 \
|
||||||
|
__asm psubb mm4,mm6 \
|
||||||
|
/*mm7=255-max(2*L-abs(R_i),0)*/ \
|
||||||
|
__asm paddusb mm7,mm4 \
|
||||||
|
/*mm4=min(abs(R_i),max(2*L-abs(R_i),0))*/ \
|
||||||
|
__asm paddusb mm4,mm7 \
|
||||||
|
__asm psubusb mm4,mm7 \
|
||||||
|
/*Now split mm4 by the original sign of -R_i.*/ \
|
||||||
|
__asm movq mm5,mm4 \
|
||||||
|
__asm pand mm4,mm6 \
|
||||||
|
__asm pandn mm6,mm5 \
|
||||||
|
/*mm1={b0+lflim(R_0,L),...,b7+lflim(R_7,L)}*/ \
|
||||||
|
/*mm2={c0-lflim(R_0,L),...,c7-lflim(R_7,L)}*/ \
|
||||||
|
__asm paddusb mm1,mm4 \
|
||||||
|
__asm psubusb mm2,mm4 \
|
||||||
|
__asm psubusb mm1,mm6 \
|
||||||
|
__asm paddusb mm2,mm6 \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OC_LOOP_FILTER_V_MMX(_pix,_ystride,_ll) \
|
||||||
|
do{ \
|
||||||
|
/*Used local variable pix__ in order to fix compilation errors like: \
|
||||||
|
"error C2425: 'SHL' : non-constant expression in 'second operand'".*/ \
|
||||||
|
unsigned char *pix__; \
|
||||||
|
unsigned char *ll__; \
|
||||||
|
ll__=(_ll); \
|
||||||
|
pix__=(_pix); \
|
||||||
|
__asm mov YSTRIDE,_ystride \
|
||||||
|
__asm mov LL,ll__ \
|
||||||
|
__asm mov PIX,pix__ \
|
||||||
|
__asm sub PIX,YSTRIDE \
|
||||||
|
__asm sub PIX,YSTRIDE \
|
||||||
|
/*mm0={a0,...,a7}*/ \
|
||||||
|
__asm movq mm0,[PIX] \
|
||||||
|
/*ystride3=_ystride*3*/ \
|
||||||
|
__asm lea YSTRIDE3,[YSTRIDE+YSTRIDE*2] \
|
||||||
|
/*mm3={d0,...,d7}*/ \
|
||||||
|
__asm movq mm3,[PIX+YSTRIDE3] \
|
||||||
|
/*mm1={b0,...,b7}*/ \
|
||||||
|
__asm movq mm1,[PIX+YSTRIDE] \
|
||||||
|
/*mm2={c0,...,c7}*/ \
|
||||||
|
__asm movq mm2,[PIX+YSTRIDE*2] \
|
||||||
|
OC_LOOP_FILTER8_MMX \
|
||||||
|
/*Write it back out.*/ \
|
||||||
|
__asm movq [PIX+YSTRIDE],mm1 \
|
||||||
|
__asm movq [PIX+YSTRIDE*2],mm2 \
|
||||||
|
} \
|
||||||
|
while(0)
|
||||||
|
|
||||||
|
#define OC_LOOP_FILTER_H_MMX(_pix,_ystride,_ll) \
|
||||||
|
do{ \
|
||||||
|
/*Used local variable ll__ in order to fix compilation errors like: \
|
||||||
|
"error C2443: operand size conflict".*/ \
|
||||||
|
unsigned char *ll__; \
|
||||||
|
unsigned char *pix__; \
|
||||||
|
ll__=(_ll); \
|
||||||
|
pix__=(_pix)-2; \
|
||||||
|
__asm mov PIX,pix__ \
|
||||||
|
__asm mov YSTRIDE,_ystride \
|
||||||
|
__asm mov LL,ll__ \
|
||||||
|
/*x x x x d0 c0 b0 a0*/ \
|
||||||
|
__asm movd mm0,[PIX] \
|
||||||
|
/*x x x x d1 c1 b1 a1*/ \
|
||||||
|
__asm movd mm1,[PIX+YSTRIDE] \
|
||||||
|
/*ystride3=_ystride*3*/ \
|
||||||
|
__asm lea YSTRIDE3,[YSTRIDE+YSTRIDE*2] \
|
||||||
|
/*x x x x d2 c2 b2 a2*/ \
|
||||||
|
__asm movd mm2,[PIX+YSTRIDE*2] \
|
||||||
|
/*x x x x d3 c3 b3 a3*/ \
|
||||||
|
__asm lea D,[PIX+YSTRIDE*4] \
|
||||||
|
__asm movd mm3,[PIX+YSTRIDE3] \
|
||||||
|
/*x x x x d4 c4 b4 a4*/ \
|
||||||
|
__asm movd mm4,[D] \
|
||||||
|
/*x x x x d5 c5 b5 a5*/ \
|
||||||
|
__asm movd mm5,[D+YSTRIDE] \
|
||||||
|
/*x x x x d6 c6 b6 a6*/ \
|
||||||
|
__asm movd mm6,[D+YSTRIDE*2] \
|
||||||
|
/*x x x x d7 c7 b7 a7*/ \
|
||||||
|
__asm movd mm7,[D+YSTRIDE3] \
|
||||||
|
/*mm0=d1 d0 c1 c0 b1 b0 a1 a0*/ \
|
||||||
|
__asm punpcklbw mm0,mm1 \
|
||||||
|
/*mm2=d3 d2 c3 c2 b3 b2 a3 a2*/ \
|
||||||
|
__asm punpcklbw mm2,mm3 \
|
||||||
|
/*mm3=d1 d0 c1 c0 b1 b0 a1 a0*/ \
|
||||||
|
__asm movq mm3,mm0 \
|
||||||
|
/*mm0=b3 b2 b1 b0 a3 a2 a1 a0*/ \
|
||||||
|
__asm punpcklwd mm0,mm2 \
|
||||||
|
/*mm3=d3 d2 d1 d0 c3 c2 c1 c0*/ \
|
||||||
|
__asm punpckhwd mm3,mm2 \
|
||||||
|
/*mm1=b3 b2 b1 b0 a3 a2 a1 a0*/ \
|
||||||
|
__asm movq mm1,mm0 \
|
||||||
|
/*mm4=d5 d4 c5 c4 b5 b4 a5 a4*/ \
|
||||||
|
__asm punpcklbw mm4,mm5 \
|
||||||
|
/*mm6=d7 d6 c7 c6 b7 b6 a7 a6*/ \
|
||||||
|
__asm punpcklbw mm6,mm7 \
|
||||||
|
/*mm5=d5 d4 c5 c4 b5 b4 a5 a4*/ \
|
||||||
|
__asm movq mm5,mm4 \
|
||||||
|
/*mm4=b7 b6 b5 b4 a7 a6 a5 a4*/ \
|
||||||
|
__asm punpcklwd mm4,mm6 \
|
||||||
|
/*mm5=d7 d6 d5 d4 c7 c6 c5 c4*/ \
|
||||||
|
__asm punpckhwd mm5,mm6 \
|
||||||
|
/*mm2=d3 d2 d1 d0 c3 c2 c1 c0*/ \
|
||||||
|
__asm movq mm2,mm3 \
|
||||||
|
/*mm0=a7 a6 a5 a4 a3 a2 a1 a0*/ \
|
||||||
|
__asm punpckldq mm0,mm4 \
|
||||||
|
/*mm1=b7 b6 b5 b4 b3 b2 b1 b0*/ \
|
||||||
|
__asm punpckhdq mm1,mm4 \
|
||||||
|
/*mm2=c7 c6 c5 c4 c3 c2 c1 c0*/ \
|
||||||
|
__asm punpckldq mm2,mm5 \
|
||||||
|
/*mm3=d7 d6 d5 d4 d3 d2 d1 d0*/ \
|
||||||
|
__asm punpckhdq mm3,mm5 \
|
||||||
|
OC_LOOP_FILTER8_MMX \
|
||||||
|
/*mm2={b0+R_0'',...,b7+R_7''}*/ \
|
||||||
|
__asm movq mm0,mm1 \
|
||||||
|
/*mm1={b0+R_0'',c0-R_0'',...,b3+R_3'',c3-R_3''}*/ \
|
||||||
|
__asm punpcklbw mm1,mm2 \
|
||||||
|
/*mm2={b4+R_4'',c4-R_4'',...,b7+R_7'',c7-R_7''}*/ \
|
||||||
|
__asm punpckhbw mm0,mm2 \
|
||||||
|
/*[d]=c1 b1 c0 b0*/ \
|
||||||
|
__asm movd D,mm1 \
|
||||||
|
__asm mov [PIX+1],D_WORD \
|
||||||
|
__asm psrlq mm1,32 \
|
||||||
|
__asm shr D,16 \
|
||||||
|
__asm mov [PIX+YSTRIDE+1],D_WORD \
|
||||||
|
/*[d]=c3 b3 c2 b2*/ \
|
||||||
|
__asm movd D,mm1 \
|
||||||
|
__asm mov [PIX+YSTRIDE*2+1],D_WORD \
|
||||||
|
__asm shr D,16 \
|
||||||
|
__asm mov [PIX+YSTRIDE3+1],D_WORD \
|
||||||
|
__asm lea PIX,[PIX+YSTRIDE*4] \
|
||||||
|
/*[d]=c5 b5 c4 b4*/ \
|
||||||
|
__asm movd D,mm0 \
|
||||||
|
__asm mov [PIX+1],D_WORD \
|
||||||
|
__asm psrlq mm0,32 \
|
||||||
|
__asm shr D,16 \
|
||||||
|
__asm mov [PIX+YSTRIDE+1],D_WORD \
|
||||||
|
/*[d]=c7 b7 c6 b6*/ \
|
||||||
|
__asm movd D,mm0 \
|
||||||
|
__asm mov [PIX+YSTRIDE*2+1],D_WORD \
|
||||||
|
__asm shr D,16 \
|
||||||
|
__asm mov [PIX+YSTRIDE3+1],D_WORD \
|
||||||
|
} \
|
||||||
|
while(0)
|
||||||
|
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,176 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
/*MMX acceleration of complete fragment reconstruction algorithm.
|
||||||
|
Originally written by Rudolf Marek.*/
|
||||||
|
#include <string.h>
|
||||||
|
#include "x86int.h"
|
||||||
|
#include "mmxloop.h"
|
||||||
|
|
||||||
|
#if defined(OC_X86_ASM)
|
||||||
|
|
||||||
|
void oc_state_frag_recon_mmx(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||||
|
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant){
|
||||||
|
unsigned char *dst;
|
||||||
|
ptrdiff_t frag_buf_off;
|
||||||
|
int ystride;
|
||||||
|
int refi;
|
||||||
|
/*Apply the inverse transform.*/
|
||||||
|
/*Special case only having a DC component.*/
|
||||||
|
if(_last_zzi<2){
|
||||||
|
/*Note that this value must be unsigned, to keep the __asm__ block from
|
||||||
|
sign-extending it when it puts it in a register.*/
|
||||||
|
ogg_uint16_t p;
|
||||||
|
/*We round this dequant product (and not any of the others) because there's
|
||||||
|
no iDCT rounding.*/
|
||||||
|
p=(ogg_int16_t)(_dct_coeffs[0]*(ogg_int32_t)_dc_quant+15>>5);
|
||||||
|
/*Fill _dct_coeffs with p.*/
|
||||||
|
__asm{
|
||||||
|
#define Y eax
|
||||||
|
#define P ecx
|
||||||
|
mov Y,_dct_coeffs
|
||||||
|
movzx P,p
|
||||||
|
lea Y,[Y+128]
|
||||||
|
/*mm0=0000 0000 0000 AAAA*/
|
||||||
|
movd mm0,P
|
||||||
|
/*mm0=0000 0000 AAAA AAAA*/
|
||||||
|
punpcklwd mm0,mm0
|
||||||
|
/*mm0=AAAA AAAA AAAA AAAA*/
|
||||||
|
punpckldq mm0,mm0
|
||||||
|
movq [Y],mm0
|
||||||
|
movq [8+Y],mm0
|
||||||
|
movq [16+Y],mm0
|
||||||
|
movq [24+Y],mm0
|
||||||
|
movq [32+Y],mm0
|
||||||
|
movq [40+Y],mm0
|
||||||
|
movq [48+Y],mm0
|
||||||
|
movq [56+Y],mm0
|
||||||
|
movq [64+Y],mm0
|
||||||
|
movq [72+Y],mm0
|
||||||
|
movq [80+Y],mm0
|
||||||
|
movq [88+Y],mm0
|
||||||
|
movq [96+Y],mm0
|
||||||
|
movq [104+Y],mm0
|
||||||
|
movq [112+Y],mm0
|
||||||
|
movq [120+Y],mm0
|
||||||
|
#undef Y
|
||||||
|
#undef P
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
/*Dequantize the DC coefficient.*/
|
||||||
|
_dct_coeffs[0]=(ogg_int16_t)(_dct_coeffs[0]*(int)_dc_quant);
|
||||||
|
oc_idct8x8_mmx(_dct_coeffs+64,_dct_coeffs,_last_zzi);
|
||||||
|
}
|
||||||
|
/*Fill in the target buffer.*/
|
||||||
|
frag_buf_off=_state->frag_buf_offs[_fragi];
|
||||||
|
refi=_state->frags[_fragi].refi;
|
||||||
|
ystride=_state->ref_ystride[_pli];
|
||||||
|
dst=_state->ref_frame_data[OC_FRAME_SELF]+frag_buf_off;
|
||||||
|
if(refi==OC_FRAME_SELF)oc_frag_recon_intra_mmx(dst,ystride,_dct_coeffs+64);
|
||||||
|
else{
|
||||||
|
const unsigned char *ref;
|
||||||
|
int mvoffsets[2];
|
||||||
|
ref=_state->ref_frame_data[refi]+frag_buf_off;
|
||||||
|
if(oc_state_get_mv_offsets(_state,mvoffsets,_pli,
|
||||||
|
_state->frag_mvs[_fragi])>1){
|
||||||
|
oc_frag_recon_inter2_mmx(dst,ref+mvoffsets[0],ref+mvoffsets[1],ystride,
|
||||||
|
_dct_coeffs+64);
|
||||||
|
}
|
||||||
|
else oc_frag_recon_inter_mmx(dst,ref+mvoffsets[0],ystride,_dct_coeffs+64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*We copy these entire function to inline the actual MMX routines so that we
|
||||||
|
use only a single indirect call.*/
|
||||||
|
|
||||||
|
void oc_loop_filter_init_mmx(signed char _bv[256],int _flimit){
|
||||||
|
memset(_bv,~(_flimit<<1),8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Apply the loop filter to a given set of fragment rows in the given plane.
|
||||||
|
The filter may be run on the bottom edge, affecting pixels in the next row of
|
||||||
|
fragments, so this row also needs to be available.
|
||||||
|
_bv: The bounding values array.
|
||||||
|
_refi: The index of the frame buffer to filter.
|
||||||
|
_pli: The color plane to filter.
|
||||||
|
_fragy0: The Y coordinate of the first fragment row to filter.
|
||||||
|
_fragy_end: The Y coordinate of the fragment row to stop filtering at.*/
|
||||||
|
void oc_state_loop_filter_frag_rows_mmx(const oc_theora_state *_state,
|
||||||
|
signed char _bv[256],int _refi,int _pli,int _fragy0,int _fragy_end){
|
||||||
|
const oc_fragment_plane *fplane;
|
||||||
|
const oc_fragment *frags;
|
||||||
|
const ptrdiff_t *frag_buf_offs;
|
||||||
|
unsigned char *ref_frame_data;
|
||||||
|
ptrdiff_t fragi_top;
|
||||||
|
ptrdiff_t fragi_bot;
|
||||||
|
ptrdiff_t fragi0;
|
||||||
|
ptrdiff_t fragi0_end;
|
||||||
|
int ystride;
|
||||||
|
int nhfrags;
|
||||||
|
fplane=_state->fplanes+_pli;
|
||||||
|
nhfrags=fplane->nhfrags;
|
||||||
|
fragi_top=fplane->froffset;
|
||||||
|
fragi_bot=fragi_top+fplane->nfrags;
|
||||||
|
fragi0=fragi_top+_fragy0*(ptrdiff_t)nhfrags;
|
||||||
|
fragi0_end=fragi_top+_fragy_end*(ptrdiff_t)nhfrags;
|
||||||
|
ystride=_state->ref_ystride[_pli];
|
||||||
|
frags=_state->frags;
|
||||||
|
frag_buf_offs=_state->frag_buf_offs;
|
||||||
|
ref_frame_data=_state->ref_frame_data[_refi];
|
||||||
|
/*The following loops are constructed somewhat non-intuitively on purpose.
|
||||||
|
The main idea is: if a block boundary has at least one coded fragment on
|
||||||
|
it, the filter is applied to it.
|
||||||
|
However, the order that the filters are applied in matters, and VP3 chose
|
||||||
|
the somewhat strange ordering used below.*/
|
||||||
|
while(fragi0<fragi0_end){
|
||||||
|
ptrdiff_t fragi;
|
||||||
|
ptrdiff_t fragi_end;
|
||||||
|
fragi=fragi0;
|
||||||
|
fragi_end=fragi+nhfrags;
|
||||||
|
while(fragi<fragi_end){
|
||||||
|
if(frags[fragi].coded){
|
||||||
|
unsigned char *ref;
|
||||||
|
ref=ref_frame_data+frag_buf_offs[fragi];
|
||||||
|
#define PIX eax
|
||||||
|
#define YSTRIDE3 edi
|
||||||
|
#define YSTRIDE ecx
|
||||||
|
#define LL edx
|
||||||
|
#define D esi
|
||||||
|
#define D_WORD si
|
||||||
|
if(fragi>fragi0)OC_LOOP_FILTER_H_MMX(ref,ystride,_bv);
|
||||||
|
if(fragi0>fragi_top)OC_LOOP_FILTER_V_MMX(ref,ystride,_bv);
|
||||||
|
if(fragi+1<fragi_end&&!frags[fragi+1].coded){
|
||||||
|
OC_LOOP_FILTER_H_MMX(ref+8,ystride,_bv);
|
||||||
|
}
|
||||||
|
if(fragi+nhfrags<fragi_bot&&!frags[fragi+nhfrags].coded){
|
||||||
|
OC_LOOP_FILTER_V_MMX(ref+(ystride<<3),ystride,_bv);
|
||||||
|
}
|
||||||
|
#undef PIX
|
||||||
|
#undef YSTRIDE3
|
||||||
|
#undef YSTRIDE
|
||||||
|
#undef LL
|
||||||
|
#undef D
|
||||||
|
#undef D_WORD
|
||||||
|
}
|
||||||
|
fragi++;
|
||||||
|
}
|
||||||
|
fragi0+=nhfrags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,192 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
CPU capability detection for x86 processors.
|
||||||
|
Originally written by Rudolf Marek.
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include "x86cpu.h"
|
||||||
|
|
||||||
|
#if !defined(OC_X86_ASM)
|
||||||
|
ogg_uint32_t oc_cpu_flags_get(void){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/*Why does MSVC need this complicated rigamarole?
|
||||||
|
At this point I honestly do not care.*/
|
||||||
|
|
||||||
|
/*Visual C cpuid helper function.
|
||||||
|
For VS2005 we could as well use the _cpuid builtin, but that wouldn't work
|
||||||
|
for VS2003 users, so we do it in inline assembler.*/
|
||||||
|
static void oc_cpuid_helper(ogg_uint32_t _cpu_info[4],ogg_uint32_t _op){
|
||||||
|
_asm{
|
||||||
|
mov eax,[_op]
|
||||||
|
mov esi,_cpu_info
|
||||||
|
cpuid
|
||||||
|
mov [esi+0],eax
|
||||||
|
mov [esi+4],ebx
|
||||||
|
mov [esi+8],ecx
|
||||||
|
mov [esi+12],edx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# define cpuid(_op,_eax,_ebx,_ecx,_edx) \
|
||||||
|
do{ \
|
||||||
|
ogg_uint32_t cpu_info[4]; \
|
||||||
|
oc_cpuid_helper(cpu_info,_op); \
|
||||||
|
(_eax)=cpu_info[0]; \
|
||||||
|
(_ebx)=cpu_info[1]; \
|
||||||
|
(_ecx)=cpu_info[2]; \
|
||||||
|
(_edx)=cpu_info[3]; \
|
||||||
|
}while(0)
|
||||||
|
|
||||||
|
static void oc_detect_cpuid_helper(ogg_uint32_t *_eax,ogg_uint32_t *_ebx){
|
||||||
|
_asm{
|
||||||
|
pushfd
|
||||||
|
pushfd
|
||||||
|
pop eax
|
||||||
|
mov ebx,eax
|
||||||
|
xor eax,200000h
|
||||||
|
push eax
|
||||||
|
popfd
|
||||||
|
pushfd
|
||||||
|
pop eax
|
||||||
|
popfd
|
||||||
|
mov ecx,_eax
|
||||||
|
mov [ecx],eax
|
||||||
|
mov ecx,_ebx
|
||||||
|
mov [ecx],ebx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ogg_uint32_t oc_parse_intel_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){
|
||||||
|
ogg_uint32_t flags;
|
||||||
|
/*If there isn't even MMX, give up.*/
|
||||||
|
if(!(_edx&0x00800000))return 0;
|
||||||
|
flags=OC_CPU_X86_MMX;
|
||||||
|
if(_edx&0x02000000)flags|=OC_CPU_X86_MMXEXT|OC_CPU_X86_SSE;
|
||||||
|
if(_edx&0x04000000)flags|=OC_CPU_X86_SSE2;
|
||||||
|
if(_ecx&0x00000001)flags|=OC_CPU_X86_PNI;
|
||||||
|
if(_ecx&0x00000100)flags|=OC_CPU_X86_SSSE3;
|
||||||
|
if(_ecx&0x00080000)flags|=OC_CPU_X86_SSE4_1;
|
||||||
|
if(_ecx&0x00100000)flags|=OC_CPU_X86_SSE4_2;
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ogg_uint32_t oc_parse_amd_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){
|
||||||
|
ogg_uint32_t flags;
|
||||||
|
/*If there isn't even MMX, give up.*/
|
||||||
|
if(!(_edx&0x00800000))return 0;
|
||||||
|
flags=OC_CPU_X86_MMX;
|
||||||
|
if(_edx&0x00400000)flags|=OC_CPU_X86_MMXEXT;
|
||||||
|
if(_edx&0x80000000)flags|=OC_CPU_X86_3DNOW;
|
||||||
|
if(_edx&0x40000000)flags|=OC_CPU_X86_3DNOWEXT;
|
||||||
|
if(_ecx&0x00000040)flags|=OC_CPU_X86_SSE4A;
|
||||||
|
if(_ecx&0x00000800)flags|=OC_CPU_X86_SSE5;
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
ogg_uint32_t oc_cpu_flags_get(void){
|
||||||
|
ogg_uint32_t flags;
|
||||||
|
ogg_uint32_t eax;
|
||||||
|
ogg_uint32_t ebx;
|
||||||
|
ogg_uint32_t ecx;
|
||||||
|
ogg_uint32_t edx;
|
||||||
|
# if !defined(__amd64__)&&!defined(__x86_64__)
|
||||||
|
/*Not all x86-32 chips support cpuid, so we have to check.*/
|
||||||
|
oc_detect_cpuid_helper(&eax,&ebx);
|
||||||
|
/*No cpuid.*/
|
||||||
|
if(eax==ebx)return 0;
|
||||||
|
# endif
|
||||||
|
cpuid(0,eax,ebx,ecx,edx);
|
||||||
|
/* l e t n I e n i u n e G*/
|
||||||
|
if(ecx==0x6C65746E&&edx==0x49656E69&&ebx==0x756E6547||
|
||||||
|
/* 6 8 x M T e n i u n e G*/
|
||||||
|
ecx==0x3638784D&&edx==0x54656E69&&ebx==0x756E6547){
|
||||||
|
int family;
|
||||||
|
int model;
|
||||||
|
/*Intel, Transmeta (tested with Crusoe TM5800):*/
|
||||||
|
cpuid(1,eax,ebx,ecx,edx);
|
||||||
|
flags=oc_parse_intel_flags(edx,ecx);
|
||||||
|
family=(eax>>8)&0xF;
|
||||||
|
model=(eax>>4)&0xF;
|
||||||
|
/*The SSE unit on the Pentium M and Core Duo is much slower than the MMX
|
||||||
|
unit, so don't use it.*/
|
||||||
|
if(family==6&&(model==9||model==13||model==14)){
|
||||||
|
flags&=~(OC_CPU_X86_SSE2|OC_CPU_X86_PNI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* D M A c i t n e h t u A*/
|
||||||
|
else if(ecx==0x444D4163&&edx==0x69746E65&&ebx==0x68747541||
|
||||||
|
/* C S N y b e d o e G*/
|
||||||
|
ecx==0x43534e20&&edx==0x79622065&&ebx==0x646f6547){
|
||||||
|
/*AMD, Geode:*/
|
||||||
|
cpuid(0x80000000,eax,ebx,ecx,edx);
|
||||||
|
if(eax<0x80000001)flags=0;
|
||||||
|
else{
|
||||||
|
cpuid(0x80000001,eax,ebx,ecx,edx);
|
||||||
|
flags=oc_parse_amd_flags(edx,ecx);
|
||||||
|
}
|
||||||
|
/*Also check for SSE.*/
|
||||||
|
cpuid(1,eax,ebx,ecx,edx);
|
||||||
|
flags|=oc_parse_intel_flags(edx,ecx);
|
||||||
|
}
|
||||||
|
/*Technically some VIA chips can be configured in the BIOS to return any
|
||||||
|
string here the user wants.
|
||||||
|
There is a special detection method that can be used to identify such
|
||||||
|
processors, but in my opinion, if the user really wants to change it, they
|
||||||
|
deserve what they get.*/
|
||||||
|
/* s l u a H r u a t n e C*/
|
||||||
|
else if(ecx==0x736C7561&&edx==0x48727561&&ebx==0x746E6543){
|
||||||
|
/*VIA:*/
|
||||||
|
/*I only have documentation for the C7 (Esther) and Isaiah (forthcoming)
|
||||||
|
chips (thanks to the engineers from Centaur Technology who provided it).
|
||||||
|
These chips support Intel-like cpuid info.
|
||||||
|
The C3-2 (Nehemiah) cores appear to, as well.*/
|
||||||
|
cpuid(1,eax,ebx,ecx,edx);
|
||||||
|
flags=oc_parse_intel_flags(edx,ecx);
|
||||||
|
if(eax>=0x80000001){
|
||||||
|
/*The (non-Nehemiah) C3 processors support AMD-like cpuid info.
|
||||||
|
We need to check this even if the Intel test succeeds to pick up 3DNow!
|
||||||
|
support on these processors.
|
||||||
|
Unlike actual AMD processors, we cannot _rely_ on this info, since
|
||||||
|
some cores (e.g., the 693 stepping of the Nehemiah) claim to support
|
||||||
|
this function, yet return edx=0, despite the Intel test indicating
|
||||||
|
MMX support.
|
||||||
|
Therefore the features detected here are strictly added to those
|
||||||
|
detected by the Intel test.*/
|
||||||
|
/*TODO: How about earlier chips?*/
|
||||||
|
cpuid(0x80000001,eax,ebx,ecx,edx);
|
||||||
|
/*Note: As of the C7, this function returns Intel-style extended feature
|
||||||
|
flags, not AMD-style.
|
||||||
|
Currently, this only defines bits 11, 20, and 29 (0x20100800), which
|
||||||
|
do not conflict with any of the AMD flags we inspect.
|
||||||
|
For the remaining bits, Intel tells us, "Do not count on their value",
|
||||||
|
but VIA assures us that they will all be zero (at least on the C7 and
|
||||||
|
Isaiah chips).
|
||||||
|
In the (unlikely) event a future processor uses bits 18, 19, 30, or 31
|
||||||
|
(0xC0C00000) for something else, we will have to add code to detect
|
||||||
|
the model to decide when it is appropriate to inspect them.*/
|
||||||
|
flags|=oc_parse_amd_flags(edx,ecx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
/*Implement me.*/
|
||||||
|
flags=0;
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#if !defined(_x86_vc_x86cpu_H)
|
||||||
|
# define _x86_vc_x86cpu_H (1)
|
||||||
|
#include "../internal.h"
|
||||||
|
|
||||||
|
#define OC_CPU_X86_MMX (1<<0)
|
||||||
|
#define OC_CPU_X86_3DNOW (1<<1)
|
||||||
|
#define OC_CPU_X86_3DNOWEXT (1<<2)
|
||||||
|
#define OC_CPU_X86_MMXEXT (1<<3)
|
||||||
|
#define OC_CPU_X86_SSE (1<<4)
|
||||||
|
#define OC_CPU_X86_SSE2 (1<<5)
|
||||||
|
#define OC_CPU_X86_PNI (1<<6)
|
||||||
|
#define OC_CPU_X86_SSSE3 (1<<7)
|
||||||
|
#define OC_CPU_X86_SSE4_1 (1<<8)
|
||||||
|
#define OC_CPU_X86_SSE4_2 (1<<9)
|
||||||
|
#define OC_CPU_X86_SSE4A (1<<10)
|
||||||
|
#define OC_CPU_X86_SSE5 (1<<11)
|
||||||
|
|
||||||
|
ogg_uint32_t oc_cpu_flags_get(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#if !defined(_x86_vc_x86int_H)
|
||||||
|
# define _x86_vc_x86int_H (1)
|
||||||
|
# include "../internal.h"
|
||||||
|
# if defined(OC_X86_ASM)
|
||||||
|
# define oc_state_accel_init oc_state_accel_init_x86
|
||||||
|
# define OC_STATE_USE_VTABLE (1)
|
||||||
|
# endif
|
||||||
|
# include "../state.h"
|
||||||
|
# include "x86cpu.h"
|
||||||
|
|
||||||
|
void oc_state_accel_init_x86(oc_theora_state *_state);
|
||||||
|
|
||||||
|
void oc_frag_copy_mmx(unsigned char *_dst,
|
||||||
|
const unsigned char *_src,int _ystride);
|
||||||
|
void oc_frag_copy_list_mmx(unsigned char *_dst_frame,
|
||||||
|
const unsigned char *_src_frame,int _ystride,
|
||||||
|
const ptrdiff_t *_fragis,ptrdiff_t _nfragis,const ptrdiff_t *_frag_buf_offs);
|
||||||
|
void oc_frag_recon_intra_mmx(unsigned char *_dst,int _ystride,
|
||||||
|
const ogg_int16_t *_residue);
|
||||||
|
void oc_frag_recon_inter_mmx(unsigned char *_dst,
|
||||||
|
const unsigned char *_src,int _ystride,const ogg_int16_t *_residue);
|
||||||
|
void oc_frag_recon_inter2_mmx(unsigned char *_dst,const unsigned char *_src1,
|
||||||
|
const unsigned char *_src2,int _ystride,const ogg_int16_t *_residue);
|
||||||
|
void oc_idct8x8_mmx(ogg_int16_t _y[64],ogg_int16_t _x[64],int _last_zzi);
|
||||||
|
void oc_state_frag_recon_mmx(const oc_theora_state *_state,ptrdiff_t _fragi,
|
||||||
|
int _pli,ogg_int16_t _dct_coeffs[128],int _last_zzi,ogg_uint16_t _dc_quant);
|
||||||
|
void oc_loop_filter_init_mmx(signed char _bv[256],int _flimit);
|
||||||
|
void oc_state_loop_filter_frag_rows_mmx(const oc_theora_state *_state,
|
||||||
|
signed char _bv[256],int _refi,int _pli,int _fragy0,int _fragy_end);
|
||||||
|
void oc_restore_fpu_mmx(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
|
||||||
|
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function:
|
||||||
|
last mod: $Id$
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include "x86int.h"
|
||||||
|
|
||||||
|
#if defined(OC_X86_ASM)
|
||||||
|
|
||||||
|
/*This table has been modified from OC_FZIG_ZAG by baking a 4x4 transpose into
|
||||||
|
each quadrant of the destination.*/
|
||||||
|
static const unsigned char OC_FZIG_ZAG_MMX[128]={
|
||||||
|
0, 8, 1, 2, 9,16,24,17,
|
||||||
|
10, 3,32,11,18,25, 4,12,
|
||||||
|
5,26,19,40,33,34,41,48,
|
||||||
|
27, 6,13,20,28,21,14, 7,
|
||||||
|
56,49,42,35,43,50,57,36,
|
||||||
|
15,22,29,30,23,44,37,58,
|
||||||
|
51,59,38,45,52,31,60,53,
|
||||||
|
46,39,47,54,61,62,55,63,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
64,64,64,64,64,64,64,64,
|
||||||
|
};
|
||||||
|
|
||||||
|
void oc_state_accel_init_x86(oc_theora_state *_state){
|
||||||
|
_state->cpu_flags=oc_cpu_flags_get();
|
||||||
|
if(_state->cpu_flags&OC_CPU_X86_MMX){
|
||||||
|
_state->opt_vtable.frag_copy=oc_frag_copy_mmx;
|
||||||
|
_state->opt_vtable.frag_copy_list=oc_frag_copy_list_mmx;
|
||||||
|
_state->opt_vtable.frag_recon_intra=oc_frag_recon_intra_mmx;
|
||||||
|
_state->opt_vtable.frag_recon_inter=oc_frag_recon_inter_mmx;
|
||||||
|
_state->opt_vtable.frag_recon_inter2=oc_frag_recon_inter2_mmx;
|
||||||
|
_state->opt_vtable.idct8x8=oc_idct8x8_mmx;
|
||||||
|
_state->opt_vtable.state_frag_recon=oc_state_frag_recon_mmx;
|
||||||
|
_state->opt_vtable.loop_filter_init=oc_loop_filter_init_mmx;
|
||||||
|
_state->opt_vtable.state_loop_filter_frag_rows=
|
||||||
|
oc_state_loop_filter_frag_rows_mmx;
|
||||||
|
_state->opt_vtable.restore_fpu=oc_restore_fpu_mmx;
|
||||||
|
_state->opt_data.dct_fzig_zag=OC_FZIG_ZAG_MMX;
|
||||||
|
}
|
||||||
|
else oc_state_accel_init_c(_state);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: single-block PCM analysis mode dispatch
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
#include "vorbis/codec.h"
|
||||||
|
#include "codec_internal.h"
|
||||||
|
#include "registry.h"
|
||||||
|
#include "scales.h"
|
||||||
|
#include "os.h"
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
|
/* decides between modes, dispatches to the appropriate mapping. */
|
||||||
|
int vorbis_analysis(vorbis_block *vb, ogg_packet *op){
|
||||||
|
int ret,i;
|
||||||
|
vorbis_block_internal *vbi=vb->internal;
|
||||||
|
|
||||||
|
vb->glue_bits=0;
|
||||||
|
vb->time_bits=0;
|
||||||
|
vb->floor_bits=0;
|
||||||
|
vb->res_bits=0;
|
||||||
|
|
||||||
|
/* first things first. Make sure encode is ready */
|
||||||
|
for(i=0;i<PACKETBLOBS;i++)
|
||||||
|
oggpack_reset(vbi->packetblob[i]);
|
||||||
|
|
||||||
|
/* we only have one mapping type (0), and we let the mapping code
|
||||||
|
itself figure out what soft mode to use. This allows easier
|
||||||
|
bitrate management */
|
||||||
|
|
||||||
|
if((ret=_mapping_P[0]->forward(vb)))
|
||||||
|
return(ret);
|
||||||
|
|
||||||
|
if(op){
|
||||||
|
if(vorbis_bitrate_managed(vb))
|
||||||
|
/* The app is using a bitmanaged mode... but not using the
|
||||||
|
bitrate management interface. */
|
||||||
|
return(OV_EINVAL);
|
||||||
|
|
||||||
|
op->packet=oggpack_get_buffer(&vb->opb);
|
||||||
|
op->bytes=oggpack_bytes(&vb->opb);
|
||||||
|
op->b_o_s=0;
|
||||||
|
op->e_o_s=vb->eofflag;
|
||||||
|
op->granulepos=vb->granulepos;
|
||||||
|
op->packetno=vb->sequence; /* for sake of completeness */
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ANALYSIS
|
||||||
|
int analysis_noisy=1;
|
||||||
|
|
||||||
|
/* there was no great place to put this.... */
|
||||||
|
void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB,ogg_int64_t off){
|
||||||
|
int j;
|
||||||
|
FILE *of;
|
||||||
|
char buffer[80];
|
||||||
|
|
||||||
|
sprintf(buffer,"%s_%d.m",base,i);
|
||||||
|
of=fopen(buffer,"w");
|
||||||
|
|
||||||
|
if(!of)perror("failed to open data dump file");
|
||||||
|
|
||||||
|
for(j=0;j<n;j++){
|
||||||
|
if(bark){
|
||||||
|
float b=toBARK((4000.f*j/n)+.25);
|
||||||
|
fprintf(of,"%f ",b);
|
||||||
|
}else
|
||||||
|
if(off!=0)
|
||||||
|
fprintf(of,"%f ",(double)(j+off)/8000.);
|
||||||
|
else
|
||||||
|
fprintf(of,"%f ",(double)j);
|
||||||
|
|
||||||
|
if(dB){
|
||||||
|
float val;
|
||||||
|
if(v[j]==0.)
|
||||||
|
val=-140.;
|
||||||
|
else
|
||||||
|
val=todB(v+j);
|
||||||
|
fprintf(of,"%f\n",val);
|
||||||
|
}else{
|
||||||
|
fprintf(of,"%f\n",v[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(of);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _analysis_output(char *base,int i,float *v,int n,int bark,int dB,
|
||||||
|
ogg_int64_t off){
|
||||||
|
if(analysis_noisy)_analysis_output_always(base,i,v,n,bark,dB,off);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: libvorbis backend and mapping structures; needed for
|
||||||
|
static mode headers
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
/* this is exposed up here because we need it for static modes.
|
||||||
|
Lookups for each backend aren't exposed because there's no reason
|
||||||
|
to do so */
|
||||||
|
|
||||||
|
#ifndef _vorbis_backend_h_
|
||||||
|
#define _vorbis_backend_h_
|
||||||
|
|
||||||
|
#include "codec_internal.h"
|
||||||
|
|
||||||
|
/* this would all be simpler/shorter with templates, but.... */
|
||||||
|
/* Floor backend generic *****************************************/
|
||||||
|
typedef struct{
|
||||||
|
void (*pack) (vorbis_info_floor *,oggpack_buffer *);
|
||||||
|
vorbis_info_floor *(*unpack)(vorbis_info *,oggpack_buffer *);
|
||||||
|
vorbis_look_floor *(*look) (vorbis_dsp_state *,vorbis_info_floor *);
|
||||||
|
void (*free_info) (vorbis_info_floor *);
|
||||||
|
void (*free_look) (vorbis_look_floor *);
|
||||||
|
void *(*inverse1) (struct vorbis_block *,vorbis_look_floor *);
|
||||||
|
int (*inverse2) (struct vorbis_block *,vorbis_look_floor *,
|
||||||
|
void *buffer,float *);
|
||||||
|
} vorbis_func_floor;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
int order;
|
||||||
|
long rate;
|
||||||
|
long barkmap;
|
||||||
|
|
||||||
|
int ampbits;
|
||||||
|
int ampdB;
|
||||||
|
|
||||||
|
int numbooks; /* <= 16 */
|
||||||
|
int books[16];
|
||||||
|
|
||||||
|
float lessthan; /* encode-only config setting hacks for libvorbis */
|
||||||
|
float greaterthan; /* encode-only config setting hacks for libvorbis */
|
||||||
|
|
||||||
|
} vorbis_info_floor0;
|
||||||
|
|
||||||
|
|
||||||
|
#define VIF_POSIT 63
|
||||||
|
#define VIF_CLASS 16
|
||||||
|
#define VIF_PARTS 31
|
||||||
|
typedef struct{
|
||||||
|
int partitions; /* 0 to 31 */
|
||||||
|
int partitionclass[VIF_PARTS]; /* 0 to 15 */
|
||||||
|
|
||||||
|
int class_dim[VIF_CLASS]; /* 1 to 8 */
|
||||||
|
int class_subs[VIF_CLASS]; /* 0,1,2,3 (bits: 1<<n poss) */
|
||||||
|
int class_book[VIF_CLASS]; /* subs ^ dim entries */
|
||||||
|
int class_subbook[VIF_CLASS][8]; /* [VIF_CLASS][subs] */
|
||||||
|
|
||||||
|
|
||||||
|
int mult; /* 1 2 3 or 4 */
|
||||||
|
int postlist[VIF_POSIT+2]; /* first two implicit */
|
||||||
|
|
||||||
|
|
||||||
|
/* encode side analysis parameters */
|
||||||
|
float maxover;
|
||||||
|
float maxunder;
|
||||||
|
float maxerr;
|
||||||
|
|
||||||
|
float twofitweight;
|
||||||
|
float twofitatten;
|
||||||
|
|
||||||
|
int n;
|
||||||
|
|
||||||
|
} vorbis_info_floor1;
|
||||||
|
|
||||||
|
/* Residue backend generic *****************************************/
|
||||||
|
typedef struct{
|
||||||
|
void (*pack) (vorbis_info_residue *,oggpack_buffer *);
|
||||||
|
vorbis_info_residue *(*unpack)(vorbis_info *,oggpack_buffer *);
|
||||||
|
vorbis_look_residue *(*look) (vorbis_dsp_state *,
|
||||||
|
vorbis_info_residue *);
|
||||||
|
void (*free_info) (vorbis_info_residue *);
|
||||||
|
void (*free_look) (vorbis_look_residue *);
|
||||||
|
long **(*class) (struct vorbis_block *,vorbis_look_residue *,
|
||||||
|
int **,int *,int);
|
||||||
|
int (*forward) (oggpack_buffer *,struct vorbis_block *,
|
||||||
|
vorbis_look_residue *,
|
||||||
|
int **,int *,int,long **,int);
|
||||||
|
int (*inverse) (struct vorbis_block *,vorbis_look_residue *,
|
||||||
|
float **,int *,int);
|
||||||
|
} vorbis_func_residue;
|
||||||
|
|
||||||
|
typedef struct vorbis_info_residue0{
|
||||||
|
/* block-partitioned VQ coded straight residue */
|
||||||
|
long begin;
|
||||||
|
long end;
|
||||||
|
|
||||||
|
/* first stage (lossless partitioning) */
|
||||||
|
int grouping; /* group n vectors per partition */
|
||||||
|
int partitions; /* possible codebooks for a partition */
|
||||||
|
int partvals; /* partitions ^ groupbook dim */
|
||||||
|
int groupbook; /* huffbook for partitioning */
|
||||||
|
int secondstages[64]; /* expanded out to pointers in lookup */
|
||||||
|
int booklist[512]; /* list of second stage books */
|
||||||
|
|
||||||
|
const int classmetric1[64];
|
||||||
|
const int classmetric2[64];
|
||||||
|
} vorbis_info_residue0;
|
||||||
|
|
||||||
|
/* Mapping backend generic *****************************************/
|
||||||
|
typedef struct{
|
||||||
|
void (*pack) (vorbis_info *,vorbis_info_mapping *,
|
||||||
|
oggpack_buffer *);
|
||||||
|
vorbis_info_mapping *(*unpack)(vorbis_info *,oggpack_buffer *);
|
||||||
|
void (*free_info) (vorbis_info_mapping *);
|
||||||
|
int (*forward) (struct vorbis_block *vb);
|
||||||
|
int (*inverse) (struct vorbis_block *vb,vorbis_info_mapping *);
|
||||||
|
} vorbis_func_mapping;
|
||||||
|
|
||||||
|
typedef struct vorbis_info_mapping0{
|
||||||
|
int submaps; /* <= 16 */
|
||||||
|
int chmuxlist[256]; /* up to 256 channels in a Vorbis stream */
|
||||||
|
|
||||||
|
int floorsubmap[16]; /* [mux] submap to floors */
|
||||||
|
int residuesubmap[16]; /* [mux] submap to residue */
|
||||||
|
|
||||||
|
int coupling_steps;
|
||||||
|
int coupling_mag[256];
|
||||||
|
int coupling_ang[256];
|
||||||
|
|
||||||
|
} vorbis_info_mapping0;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,252 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: bitrate tracking and management
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
#include "vorbis/codec.h"
|
||||||
|
#include "codec_internal.h"
|
||||||
|
#include "os.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "bitrate.h"
|
||||||
|
|
||||||
|
/* compute bitrate tracking setup */
|
||||||
|
void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bm){
|
||||||
|
codec_setup_info *ci=vi->codec_setup;
|
||||||
|
bitrate_manager_info *bi=&ci->bi;
|
||||||
|
|
||||||
|
memset(bm,0,sizeof(*bm));
|
||||||
|
|
||||||
|
if(bi && (bi->reservoir_bits>0)){
|
||||||
|
long ratesamples=vi->rate;
|
||||||
|
int halfsamples=ci->blocksizes[0]>>1;
|
||||||
|
|
||||||
|
bm->short_per_long=ci->blocksizes[1]/ci->blocksizes[0];
|
||||||
|
bm->managed=1;
|
||||||
|
|
||||||
|
bm->avg_bitsper= rint(1.*bi->avg_rate*halfsamples/ratesamples);
|
||||||
|
bm->min_bitsper= rint(1.*bi->min_rate*halfsamples/ratesamples);
|
||||||
|
bm->max_bitsper= rint(1.*bi->max_rate*halfsamples/ratesamples);
|
||||||
|
|
||||||
|
bm->avgfloat=PACKETBLOBS/2;
|
||||||
|
|
||||||
|
/* not a necessary fix, but one that leads to a more balanced
|
||||||
|
typical initialization */
|
||||||
|
{
|
||||||
|
long desired_fill=bi->reservoir_bits*bi->reservoir_bias;
|
||||||
|
bm->minmax_reservoir=desired_fill;
|
||||||
|
bm->avg_reservoir=desired_fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vorbis_bitrate_clear(bitrate_manager_state *bm){
|
||||||
|
memset(bm,0,sizeof(*bm));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vorbis_bitrate_managed(vorbis_block *vb){
|
||||||
|
vorbis_dsp_state *vd=vb->vd;
|
||||||
|
private_state *b=vd->backend_state;
|
||||||
|
bitrate_manager_state *bm=&b->bms;
|
||||||
|
|
||||||
|
if(bm && bm->managed)return(1);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finish taking in the block we just processed */
|
||||||
|
int vorbis_bitrate_addblock(vorbis_block *vb){
|
||||||
|
vorbis_block_internal *vbi=vb->internal;
|
||||||
|
vorbis_dsp_state *vd=vb->vd;
|
||||||
|
private_state *b=vd->backend_state;
|
||||||
|
bitrate_manager_state *bm=&b->bms;
|
||||||
|
vorbis_info *vi=vd->vi;
|
||||||
|
codec_setup_info *ci=vi->codec_setup;
|
||||||
|
bitrate_manager_info *bi=&ci->bi;
|
||||||
|
|
||||||
|
int choice=rint(bm->avgfloat);
|
||||||
|
long this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
|
||||||
|
long min_target_bits=(vb->W?bm->min_bitsper*bm->short_per_long:bm->min_bitsper);
|
||||||
|
long max_target_bits=(vb->W?bm->max_bitsper*bm->short_per_long:bm->max_bitsper);
|
||||||
|
int samples=ci->blocksizes[vb->W]>>1;
|
||||||
|
long desired_fill=bi->reservoir_bits*bi->reservoir_bias;
|
||||||
|
if(!bm->managed){
|
||||||
|
/* not a bitrate managed stream, but for API simplicity, we'll
|
||||||
|
buffer the packet to keep the code path clean */
|
||||||
|
|
||||||
|
if(bm->vb)return(-1); /* one has been submitted without
|
||||||
|
being claimed */
|
||||||
|
bm->vb=vb;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bm->vb=vb;
|
||||||
|
|
||||||
|
/* look ahead for avg floater */
|
||||||
|
if(bm->avg_bitsper>0){
|
||||||
|
double slew=0.;
|
||||||
|
long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper);
|
||||||
|
double slewlimit= 15./bi->slew_damp;
|
||||||
|
|
||||||
|
/* choosing a new floater:
|
||||||
|
if we're over target, we slew down
|
||||||
|
if we're under target, we slew up
|
||||||
|
|
||||||
|
choose slew as follows: look through packetblobs of this frame
|
||||||
|
and set slew as the first in the appropriate direction that
|
||||||
|
gives us the slew we want. This may mean no slew if delta is
|
||||||
|
already favorable.
|
||||||
|
|
||||||
|
Then limit slew to slew max */
|
||||||
|
|
||||||
|
if(bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){
|
||||||
|
while(choice>0 && this_bits>avg_target_bits &&
|
||||||
|
bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){
|
||||||
|
choice--;
|
||||||
|
this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
|
||||||
|
}
|
||||||
|
}else if(bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){
|
||||||
|
while(choice+1<PACKETBLOBS && this_bits<avg_target_bits &&
|
||||||
|
bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){
|
||||||
|
choice++;
|
||||||
|
this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slew=rint(choice-bm->avgfloat)/samples*vi->rate;
|
||||||
|
if(slew<-slewlimit)slew=-slewlimit;
|
||||||
|
if(slew>slewlimit)slew=slewlimit;
|
||||||
|
choice=rint(bm->avgfloat+= slew/vi->rate*samples);
|
||||||
|
this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* enforce min(if used) on the current floater (if used) */
|
||||||
|
if(bm->min_bitsper>0){
|
||||||
|
/* do we need to force the bitrate up? */
|
||||||
|
if(this_bits<min_target_bits){
|
||||||
|
while(bm->minmax_reservoir-(min_target_bits-this_bits)<0){
|
||||||
|
choice++;
|
||||||
|
if(choice>=PACKETBLOBS)break;
|
||||||
|
this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enforce max (if used) on the current floater (if used) */
|
||||||
|
if(bm->max_bitsper>0){
|
||||||
|
/* do we need to force the bitrate down? */
|
||||||
|
if(this_bits>max_target_bits){
|
||||||
|
while(bm->minmax_reservoir+(this_bits-max_target_bits)>bi->reservoir_bits){
|
||||||
|
choice--;
|
||||||
|
if(choice<0)break;
|
||||||
|
this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Choice of packetblobs now made based on floater, and min/max
|
||||||
|
requirements. Now boundary check extreme choices */
|
||||||
|
|
||||||
|
if(choice<0){
|
||||||
|
/* choosing a smaller packetblob is insufficient to trim bitrate.
|
||||||
|
frame will need to be truncated */
|
||||||
|
long maxsize=(max_target_bits+(bi->reservoir_bits-bm->minmax_reservoir))/8;
|
||||||
|
bm->choice=choice=0;
|
||||||
|
|
||||||
|
if(oggpack_bytes(vbi->packetblob[choice])>maxsize){
|
||||||
|
|
||||||
|
oggpack_writetrunc(vbi->packetblob[choice],maxsize*8);
|
||||||
|
this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
long minsize=(min_target_bits-bm->minmax_reservoir+7)/8;
|
||||||
|
if(choice>=PACKETBLOBS)
|
||||||
|
choice=PACKETBLOBS-1;
|
||||||
|
|
||||||
|
bm->choice=choice;
|
||||||
|
|
||||||
|
/* prop up bitrate according to demand. pad this frame out with zeroes */
|
||||||
|
minsize-=oggpack_bytes(vbi->packetblob[choice]);
|
||||||
|
while(minsize-->0)oggpack_write(vbi->packetblob[choice],0,8);
|
||||||
|
this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now we have the final packet and the final packet size. Update statistics */
|
||||||
|
/* min and max reservoir */
|
||||||
|
if(bm->min_bitsper>0 || bm->max_bitsper>0){
|
||||||
|
|
||||||
|
if(max_target_bits>0 && this_bits>max_target_bits){
|
||||||
|
bm->minmax_reservoir+=(this_bits-max_target_bits);
|
||||||
|
}else if(min_target_bits>0 && this_bits<min_target_bits){
|
||||||
|
bm->minmax_reservoir+=(this_bits-min_target_bits);
|
||||||
|
}else{
|
||||||
|
/* inbetween; we want to take reservoir toward but not past desired_fill */
|
||||||
|
if(bm->minmax_reservoir>desired_fill){
|
||||||
|
if(max_target_bits>0){ /* logical bulletproofing against initialization state */
|
||||||
|
bm->minmax_reservoir+=(this_bits-max_target_bits);
|
||||||
|
if(bm->minmax_reservoir<desired_fill)bm->minmax_reservoir=desired_fill;
|
||||||
|
}else{
|
||||||
|
bm->minmax_reservoir=desired_fill;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(min_target_bits>0){ /* logical bulletproofing against initialization state */
|
||||||
|
bm->minmax_reservoir+=(this_bits-min_target_bits);
|
||||||
|
if(bm->minmax_reservoir>desired_fill)bm->minmax_reservoir=desired_fill;
|
||||||
|
}else{
|
||||||
|
bm->minmax_reservoir=desired_fill;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* avg reservoir */
|
||||||
|
if(bm->avg_bitsper>0){
|
||||||
|
long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper);
|
||||||
|
bm->avg_reservoir+=this_bits-avg_target_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,ogg_packet *op){
|
||||||
|
private_state *b=vd->backend_state;
|
||||||
|
bitrate_manager_state *bm=&b->bms;
|
||||||
|
vorbis_block *vb=bm->vb;
|
||||||
|
int choice=PACKETBLOBS/2;
|
||||||
|
if(!vb)return 0;
|
||||||
|
|
||||||
|
if(op){
|
||||||
|
vorbis_block_internal *vbi=vb->internal;
|
||||||
|
|
||||||
|
if(vorbis_bitrate_managed(vb))
|
||||||
|
choice=bm->choice;
|
||||||
|
|
||||||
|
op->packet=oggpack_get_buffer(vbi->packetblob[choice]);
|
||||||
|
op->bytes=oggpack_bytes(vbi->packetblob[choice]);
|
||||||
|
op->b_o_s=0;
|
||||||
|
op->e_o_s=vb->eofflag;
|
||||||
|
op->granulepos=vb->granulepos;
|
||||||
|
op->packetno=vb->sequence; /* for sake of completeness */
|
||||||
|
}
|
||||||
|
|
||||||
|
bm->vb=0;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: bitrate tracking and management
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _V_BITRATE_H_
|
||||||
|
#define _V_BITRATE_H_
|
||||||
|
|
||||||
|
#include "vorbis/codec.h"
|
||||||
|
#include "codec_internal.h"
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
/* encode side bitrate tracking */
|
||||||
|
typedef struct bitrate_manager_state {
|
||||||
|
int managed;
|
||||||
|
|
||||||
|
long avg_reservoir;
|
||||||
|
long minmax_reservoir;
|
||||||
|
long avg_bitsper;
|
||||||
|
long min_bitsper;
|
||||||
|
long max_bitsper;
|
||||||
|
|
||||||
|
long short_per_long;
|
||||||
|
double avgfloat;
|
||||||
|
|
||||||
|
vorbis_block *vb;
|
||||||
|
int choice;
|
||||||
|
} bitrate_manager_state;
|
||||||
|
|
||||||
|
typedef struct bitrate_manager_info{
|
||||||
|
long avg_rate;
|
||||||
|
long min_rate;
|
||||||
|
long max_rate;
|
||||||
|
long reservoir_bits;
|
||||||
|
double reservoir_bias;
|
||||||
|
|
||||||
|
double slew_damp;
|
||||||
|
|
||||||
|
} bitrate_manager_info;
|
||||||
|
|
||||||
|
extern void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bs);
|
||||||
|
extern void vorbis_bitrate_clear(bitrate_manager_state *bs);
|
||||||
|
extern int vorbis_bitrate_managed(vorbis_block *vb);
|
||||||
|
extern int vorbis_bitrate_addblock(vorbis_block *vb);
|
||||||
|
extern int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd, ogg_packet *op);
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,461 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: basic codebook pack/unpack/code/decode operations
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
#include "vorbis/codec.h"
|
||||||
|
#include "codebook.h"
|
||||||
|
#include "scales.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
/* packs the given codebook into the bitstream **************************/
|
||||||
|
|
||||||
|
int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *opb){
|
||||||
|
long i,j;
|
||||||
|
int ordered=0;
|
||||||
|
|
||||||
|
/* first the basic parameters */
|
||||||
|
oggpack_write(opb,0x564342,24);
|
||||||
|
oggpack_write(opb,c->dim,16);
|
||||||
|
oggpack_write(opb,c->entries,24);
|
||||||
|
|
||||||
|
/* pack the codewords. There are two packings; length ordered and
|
||||||
|
length random. Decide between the two now. */
|
||||||
|
|
||||||
|
for(i=1;i<c->entries;i++)
|
||||||
|
if(c->lengthlist[i-1]==0 || c->lengthlist[i]<c->lengthlist[i-1])break;
|
||||||
|
if(i==c->entries)ordered=1;
|
||||||
|
|
||||||
|
if(ordered){
|
||||||
|
/* length ordered. We only need to say how many codewords of
|
||||||
|
each length. The actual codewords are generated
|
||||||
|
deterministically */
|
||||||
|
|
||||||
|
long count=0;
|
||||||
|
oggpack_write(opb,1,1); /* ordered */
|
||||||
|
oggpack_write(opb,c->lengthlist[0]-1,5); /* 1 to 32 */
|
||||||
|
|
||||||
|
for(i=1;i<c->entries;i++){
|
||||||
|
char this=c->lengthlist[i];
|
||||||
|
char last=c->lengthlist[i-1];
|
||||||
|
if(this>last){
|
||||||
|
for(j=last;j<this;j++){
|
||||||
|
oggpack_write(opb,i-count,ov_ilog(c->entries-count));
|
||||||
|
count=i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oggpack_write(opb,i-count,ov_ilog(c->entries-count));
|
||||||
|
|
||||||
|
}else{
|
||||||
|
/* length random. Again, we don't code the codeword itself, just
|
||||||
|
the length. This time, though, we have to encode each length */
|
||||||
|
oggpack_write(opb,0,1); /* unordered */
|
||||||
|
|
||||||
|
/* algortihmic mapping has use for 'unused entries', which we tag
|
||||||
|
here. The algorithmic mapping happens as usual, but the unused
|
||||||
|
entry has no codeword. */
|
||||||
|
for(i=0;i<c->entries;i++)
|
||||||
|
if(c->lengthlist[i]==0)break;
|
||||||
|
|
||||||
|
if(i==c->entries){
|
||||||
|
oggpack_write(opb,0,1); /* no unused entries */
|
||||||
|
for(i=0;i<c->entries;i++)
|
||||||
|
oggpack_write(opb,c->lengthlist[i]-1,5);
|
||||||
|
}else{
|
||||||
|
oggpack_write(opb,1,1); /* we have unused entries; thus we tag */
|
||||||
|
for(i=0;i<c->entries;i++){
|
||||||
|
if(c->lengthlist[i]==0){
|
||||||
|
oggpack_write(opb,0,1);
|
||||||
|
}else{
|
||||||
|
oggpack_write(opb,1,1);
|
||||||
|
oggpack_write(opb,c->lengthlist[i]-1,5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* is the entry number the desired return value, or do we have a
|
||||||
|
mapping? If we have a mapping, what type? */
|
||||||
|
oggpack_write(opb,c->maptype,4);
|
||||||
|
switch(c->maptype){
|
||||||
|
case 0:
|
||||||
|
/* no mapping */
|
||||||
|
break;
|
||||||
|
case 1:case 2:
|
||||||
|
/* implicitly populated value mapping */
|
||||||
|
/* explicitly populated value mapping */
|
||||||
|
|
||||||
|
if(!c->quantlist){
|
||||||
|
/* no quantlist? error */
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* values that define the dequantization */
|
||||||
|
oggpack_write(opb,c->q_min,32);
|
||||||
|
oggpack_write(opb,c->q_delta,32);
|
||||||
|
oggpack_write(opb,c->q_quant-1,4);
|
||||||
|
oggpack_write(opb,c->q_sequencep,1);
|
||||||
|
|
||||||
|
{
|
||||||
|
int quantvals;
|
||||||
|
switch(c->maptype){
|
||||||
|
case 1:
|
||||||
|
/* a single column of (c->entries/c->dim) quantized values for
|
||||||
|
building a full value list algorithmically (square lattice) */
|
||||||
|
quantvals=_book_maptype1_quantvals(c);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
/* every value (c->entries*c->dim total) specified explicitly */
|
||||||
|
quantvals=c->entries*c->dim;
|
||||||
|
break;
|
||||||
|
default: /* NOT_REACHABLE */
|
||||||
|
quantvals=-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* quantized values */
|
||||||
|
for(i=0;i<quantvals;i++)
|
||||||
|
oggpack_write(opb,labs(c->quantlist[i]),c->q_quant);
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* error case; we don't have any other map types now */
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unpacks a codebook from the packet buffer into the codebook struct,
|
||||||
|
readies the codebook auxiliary structures for decode *************/
|
||||||
|
static_codebook *vorbis_staticbook_unpack(oggpack_buffer *opb){
|
||||||
|
long i,j;
|
||||||
|
static_codebook *s=_ogg_calloc(1,sizeof(*s));
|
||||||
|
s->allocedp=1;
|
||||||
|
|
||||||
|
/* make sure alignment is correct */
|
||||||
|
if(oggpack_read(opb,24)!=0x564342)goto _eofout;
|
||||||
|
|
||||||
|
/* first the basic parameters */
|
||||||
|
s->dim=oggpack_read(opb,16);
|
||||||
|
s->entries=oggpack_read(opb,24);
|
||||||
|
if(s->entries==-1)goto _eofout;
|
||||||
|
|
||||||
|
if(ov_ilog(s->dim)+ov_ilog(s->entries)>24)goto _eofout;
|
||||||
|
|
||||||
|
/* codeword ordering.... length ordered or unordered? */
|
||||||
|
switch((int)oggpack_read(opb,1)){
|
||||||
|
case 0:{
|
||||||
|
long unused;
|
||||||
|
/* allocated but unused entries? */
|
||||||
|
unused=oggpack_read(opb,1);
|
||||||
|
if((s->entries*(unused?1:5)+7)>>3>opb->storage-oggpack_bytes(opb))
|
||||||
|
goto _eofout;
|
||||||
|
/* unordered */
|
||||||
|
s->lengthlist=_ogg_malloc(sizeof(*s->lengthlist)*s->entries);
|
||||||
|
|
||||||
|
/* allocated but unused entries? */
|
||||||
|
if(unused){
|
||||||
|
/* yes, unused entries */
|
||||||
|
|
||||||
|
for(i=0;i<s->entries;i++){
|
||||||
|
if(oggpack_read(opb,1)){
|
||||||
|
long num=oggpack_read(opb,5);
|
||||||
|
if(num==-1)goto _eofout;
|
||||||
|
s->lengthlist[i]=num+1;
|
||||||
|
}else
|
||||||
|
s->lengthlist[i]=0;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
/* all entries used; no tagging */
|
||||||
|
for(i=0;i<s->entries;i++){
|
||||||
|
long num=oggpack_read(opb,5);
|
||||||
|
if(num==-1)goto _eofout;
|
||||||
|
s->lengthlist[i]=num+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
/* ordered */
|
||||||
|
{
|
||||||
|
long length=oggpack_read(opb,5)+1;
|
||||||
|
if(length==0)goto _eofout;
|
||||||
|
s->lengthlist=_ogg_malloc(sizeof(*s->lengthlist)*s->entries);
|
||||||
|
|
||||||
|
for(i=0;i<s->entries;){
|
||||||
|
long num=oggpack_read(opb,ov_ilog(s->entries-i));
|
||||||
|
if(num==-1)goto _eofout;
|
||||||
|
if(length>32 || num>s->entries-i ||
|
||||||
|
(num>0 && (num-1)>>(length-1)>1)){
|
||||||
|
goto _errout;
|
||||||
|
}
|
||||||
|
if(length>32)goto _errout;
|
||||||
|
for(j=0;j<num;j++,i++)
|
||||||
|
s->lengthlist[i]=length;
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* EOF */
|
||||||
|
goto _eofout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do we have a mapping to unpack? */
|
||||||
|
switch((s->maptype=oggpack_read(opb,4))){
|
||||||
|
case 0:
|
||||||
|
/* no mapping */
|
||||||
|
break;
|
||||||
|
case 1: case 2:
|
||||||
|
/* implicitly populated value mapping */
|
||||||
|
/* explicitly populated value mapping */
|
||||||
|
|
||||||
|
s->q_min=oggpack_read(opb,32);
|
||||||
|
s->q_delta=oggpack_read(opb,32);
|
||||||
|
s->q_quant=oggpack_read(opb,4)+1;
|
||||||
|
s->q_sequencep=oggpack_read(opb,1);
|
||||||
|
if(s->q_sequencep==-1)goto _eofout;
|
||||||
|
|
||||||
|
{
|
||||||
|
int quantvals=0;
|
||||||
|
switch(s->maptype){
|
||||||
|
case 1:
|
||||||
|
quantvals=(s->dim==0?0:_book_maptype1_quantvals(s));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
quantvals=s->entries*s->dim;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* quantized values */
|
||||||
|
if(((quantvals*s->q_quant+7)>>3)>opb->storage-oggpack_bytes(opb))
|
||||||
|
goto _eofout;
|
||||||
|
s->quantlist=_ogg_malloc(sizeof(*s->quantlist)*quantvals);
|
||||||
|
for(i=0;i<quantvals;i++)
|
||||||
|
s->quantlist[i]=oggpack_read(opb,s->q_quant);
|
||||||
|
|
||||||
|
if(quantvals&&s->quantlist[quantvals-1]==-1)goto _eofout;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto _errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* all set */
|
||||||
|
return(s);
|
||||||
|
|
||||||
|
_errout:
|
||||||
|
_eofout:
|
||||||
|
vorbis_staticbook_destroy(s);
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns the number of bits ************************************************/
|
||||||
|
int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b){
|
||||||
|
if(a<0 || a>=book->c->entries)return(0);
|
||||||
|
oggpack_write(b,book->codelist[a],book->c->lengthlist[a]);
|
||||||
|
return(book->c->lengthlist[a]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the 'eliminate the decode tree' optimization actually requires the
|
||||||
|
codewords to be MSb first, not LSb. This is an annoying inelegancy
|
||||||
|
(and one of the first places where carefully thought out design
|
||||||
|
turned out to be wrong; Vorbis II and future Ogg codecs should go
|
||||||
|
to an MSb bitpacker), but not actually the huge hit it appears to
|
||||||
|
be. The first-stage decode table catches most words so that
|
||||||
|
bitreverse is not in the main execution path. */
|
||||||
|
|
||||||
|
static ogg_uint32_t bitreverse(ogg_uint32_t x){
|
||||||
|
x= ((x>>16)&0x0000ffff) | ((x<<16)&0xffff0000);
|
||||||
|
x= ((x>> 8)&0x00ff00ff) | ((x<< 8)&0xff00ff00);
|
||||||
|
x= ((x>> 4)&0x0f0f0f0f) | ((x<< 4)&0xf0f0f0f0);
|
||||||
|
x= ((x>> 2)&0x33333333) | ((x<< 2)&0xcccccccc);
|
||||||
|
return((x>> 1)&0x55555555) | ((x<< 1)&0xaaaaaaaa);
|
||||||
|
}
|
||||||
|
|
||||||
|
STIN long decode_packed_entry_number(codebook *book, oggpack_buffer *b){
|
||||||
|
int read=book->dec_maxlength;
|
||||||
|
long lo,hi;
|
||||||
|
long lok = oggpack_look(b,book->dec_firsttablen);
|
||||||
|
|
||||||
|
if (lok >= 0) {
|
||||||
|
long entry = book->dec_firsttable[lok];
|
||||||
|
if(entry&0x80000000UL){
|
||||||
|
lo=(entry>>15)&0x7fff;
|
||||||
|
hi=book->used_entries-(entry&0x7fff);
|
||||||
|
}else{
|
||||||
|
oggpack_adv(b, book->dec_codelengths[entry-1]);
|
||||||
|
return(entry-1);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
lo=0;
|
||||||
|
hi=book->used_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Single entry codebooks use a firsttablen of 1 and a
|
||||||
|
dec_maxlength of 1. If a single-entry codebook gets here (due to
|
||||||
|
failure to read one bit above), the next look attempt will also
|
||||||
|
fail and we'll correctly kick out instead of trying to walk the
|
||||||
|
underformed tree */
|
||||||
|
|
||||||
|
lok = oggpack_look(b, read);
|
||||||
|
|
||||||
|
while(lok<0 && read>1)
|
||||||
|
lok = oggpack_look(b, --read);
|
||||||
|
if(lok<0)return -1;
|
||||||
|
|
||||||
|
/* bisect search for the codeword in the ordered list */
|
||||||
|
{
|
||||||
|
ogg_uint32_t testword=bitreverse((ogg_uint32_t)lok);
|
||||||
|
|
||||||
|
while(hi-lo>1){
|
||||||
|
long p=(hi-lo)>>1;
|
||||||
|
long test=book->codelist[lo+p]>testword;
|
||||||
|
lo+=p&(test-1);
|
||||||
|
hi-=p&(-test);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(book->dec_codelengths[lo]<=read){
|
||||||
|
oggpack_adv(b, book->dec_codelengths[lo]);
|
||||||
|
return(lo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
oggpack_adv(b, read);
|
||||||
|
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode side is specced and easier, because we don't need to find
|
||||||
|
matches using different criteria; we simply read and map. There are
|
||||||
|
two things we need to do 'depending':
|
||||||
|
|
||||||
|
We may need to support interleave. We don't really, but it's
|
||||||
|
convenient to do it here rather than rebuild the vector later.
|
||||||
|
|
||||||
|
Cascades may be additive or multiplicitive; this is not inherent in
|
||||||
|
the codebook, but set in the code using the codebook. Like
|
||||||
|
interleaving, it's easiest to do it here.
|
||||||
|
addmul==0 -> declarative (set the value)
|
||||||
|
addmul==1 -> additive
|
||||||
|
addmul==2 -> multiplicitive */
|
||||||
|
|
||||||
|
/* returns the [original, not compacted] entry number or -1 on eof *********/
|
||||||
|
long vorbis_book_decode(codebook *book, oggpack_buffer *b){
|
||||||
|
if(book->used_entries>0){
|
||||||
|
long packed_entry=decode_packed_entry_number(book,b);
|
||||||
|
if(packed_entry>=0)
|
||||||
|
return(book->dec_index[packed_entry]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if there's no dec_index, the codebook unpacking isn't collapsed */
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns 0 on OK or -1 on eof *************************************/
|
||||||
|
/* decode vector / dim granularity gaurding is done in the upper layer */
|
||||||
|
long vorbis_book_decodevs_add(codebook *book,float *a,oggpack_buffer *b,int n){
|
||||||
|
if(book->used_entries>0){
|
||||||
|
int step=n/book->dim;
|
||||||
|
long *entry = alloca(sizeof(*entry)*step);
|
||||||
|
float **t = alloca(sizeof(*t)*step);
|
||||||
|
int i,j,o;
|
||||||
|
|
||||||
|
for (i = 0; i < step; i++) {
|
||||||
|
entry[i]=decode_packed_entry_number(book,b);
|
||||||
|
if(entry[i]==-1)return(-1);
|
||||||
|
t[i] = book->valuelist+entry[i]*book->dim;
|
||||||
|
}
|
||||||
|
for(i=0,o=0;i<book->dim;i++,o+=step)
|
||||||
|
for (j=0;o+j<n && j<step;j++)
|
||||||
|
a[o+j]+=t[j][i];
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decode vector / dim granularity gaurding is done in the upper layer */
|
||||||
|
long vorbis_book_decodev_add(codebook *book,float *a,oggpack_buffer *b,int n){
|
||||||
|
if(book->used_entries>0){
|
||||||
|
int i,j,entry;
|
||||||
|
float *t;
|
||||||
|
|
||||||
|
for(i=0;i<n;){
|
||||||
|
entry = decode_packed_entry_number(book,b);
|
||||||
|
if(entry==-1)return(-1);
|
||||||
|
t = book->valuelist+entry*book->dim;
|
||||||
|
for(j=0;i<n && j<book->dim;)
|
||||||
|
a[i++]+=t[j++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unlike the others, we guard against n not being an integer number
|
||||||
|
of <dim> internally rather than in the upper layer (called only by
|
||||||
|
floor0) */
|
||||||
|
long vorbis_book_decodev_set(codebook *book,float *a,oggpack_buffer *b,int n){
|
||||||
|
if(book->used_entries>0){
|
||||||
|
int i,j,entry;
|
||||||
|
float *t;
|
||||||
|
|
||||||
|
for(i=0;i<n;){
|
||||||
|
entry = decode_packed_entry_number(book,b);
|
||||||
|
if(entry==-1)return(-1);
|
||||||
|
t = book->valuelist+entry*book->dim;
|
||||||
|
for (j=0;i<n && j<book->dim;){
|
||||||
|
a[i++]=t[j++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0;i<n;){
|
||||||
|
a[i++]=0.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
long vorbis_book_decodevv_add(codebook *book,float **a,long offset,int ch,
|
||||||
|
oggpack_buffer *b,int n){
|
||||||
|
|
||||||
|
long i,j,entry;
|
||||||
|
int chptr=0;
|
||||||
|
if(book->used_entries>0){
|
||||||
|
int m=(offset+n)/ch;
|
||||||
|
for(i=offset/ch;i<m;){
|
||||||
|
entry = decode_packed_entry_number(book,b);
|
||||||
|
if(entry==-1)return(-1);
|
||||||
|
{
|
||||||
|
const float *t = book->valuelist+entry*book->dim;
|
||||||
|
for (j=0;i<m && j<book->dim;j++){
|
||||||
|
a[chptr++][i]+=t[j];
|
||||||
|
if(chptr==ch){
|
||||||
|
chptr=0;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: basic shared codebook operations
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _V_CODEBOOK_H_
|
||||||
|
#define _V_CODEBOOK_H_
|
||||||
|
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
|
||||||
|
/* This structure encapsulates huffman and VQ style encoding books; it
|
||||||
|
doesn't do anything specific to either.
|
||||||
|
|
||||||
|
valuelist/quantlist are nonNULL (and q_* significant) only if
|
||||||
|
there's entry->value mapping to be done.
|
||||||
|
|
||||||
|
If encode-side mapping must be done (and thus the entry needs to be
|
||||||
|
hunted), the auxiliary encode pointer will point to a decision
|
||||||
|
tree. This is true of both VQ and huffman, but is mostly useful
|
||||||
|
with VQ.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct static_codebook{
|
||||||
|
long dim; /* codebook dimensions (elements per vector) */
|
||||||
|
long entries; /* codebook entries */
|
||||||
|
char *lengthlist; /* codeword lengths in bits */
|
||||||
|
|
||||||
|
/* mapping ***************************************************************/
|
||||||
|
int maptype; /* 0=none
|
||||||
|
1=implicitly populated values from map column
|
||||||
|
2=listed arbitrary values */
|
||||||
|
|
||||||
|
/* The below does a linear, single monotonic sequence mapping. */
|
||||||
|
long q_min; /* packed 32 bit float; quant value 0 maps to minval */
|
||||||
|
long q_delta; /* packed 32 bit float; val 1 - val 0 == delta */
|
||||||
|
int q_quant; /* bits: 0 < quant <= 16 */
|
||||||
|
int q_sequencep; /* bitflag */
|
||||||
|
|
||||||
|
long *quantlist; /* map == 1: (int)(entries^(1/dim)) element column map
|
||||||
|
map == 2: list of dim*entries quantized entry vals
|
||||||
|
*/
|
||||||
|
int allocedp;
|
||||||
|
} static_codebook;
|
||||||
|
|
||||||
|
typedef struct codebook{
|
||||||
|
long dim; /* codebook dimensions (elements per vector) */
|
||||||
|
long entries; /* codebook entries */
|
||||||
|
long used_entries; /* populated codebook entries */
|
||||||
|
const static_codebook *c;
|
||||||
|
|
||||||
|
/* for encode, the below are entry-ordered, fully populated */
|
||||||
|
/* for decode, the below are ordered by bitreversed codeword and only
|
||||||
|
used entries are populated */
|
||||||
|
float *valuelist; /* list of dim*entries actual entry values */
|
||||||
|
ogg_uint32_t *codelist; /* list of bitstream codewords for each entry */
|
||||||
|
|
||||||
|
int *dec_index; /* only used if sparseness collapsed */
|
||||||
|
char *dec_codelengths;
|
||||||
|
ogg_uint32_t *dec_firsttable;
|
||||||
|
int dec_firsttablen;
|
||||||
|
int dec_maxlength;
|
||||||
|
|
||||||
|
/* The current encoder uses only centered, integer-only lattice books. */
|
||||||
|
int quantvals;
|
||||||
|
int minval;
|
||||||
|
int delta;
|
||||||
|
} codebook;
|
||||||
|
|
||||||
|
extern void vorbis_staticbook_destroy(static_codebook *b);
|
||||||
|
extern int vorbis_book_init_encode(codebook *dest,const static_codebook *source);
|
||||||
|
extern int vorbis_book_init_decode(codebook *dest,const static_codebook *source);
|
||||||
|
extern void vorbis_book_clear(codebook *b);
|
||||||
|
|
||||||
|
extern float *_book_unquantize(const static_codebook *b,int n,int *map);
|
||||||
|
extern float *_book_logdist(const static_codebook *b,float *vals);
|
||||||
|
extern float _float32_unpack(long val);
|
||||||
|
extern long _float32_pack(float val);
|
||||||
|
extern int _best(codebook *book, float *a, int step);
|
||||||
|
extern long _book_maptype1_quantvals(const static_codebook *b);
|
||||||
|
|
||||||
|
extern int vorbis_book_besterror(codebook *book,float *a,int step,int addmul);
|
||||||
|
extern long vorbis_book_codeword(codebook *book,int entry);
|
||||||
|
extern long vorbis_book_codelen(codebook *book,int entry);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *b);
|
||||||
|
extern static_codebook *vorbis_staticbook_unpack(oggpack_buffer *b);
|
||||||
|
|
||||||
|
extern int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b);
|
||||||
|
|
||||||
|
extern long vorbis_book_decode(codebook *book, oggpack_buffer *b);
|
||||||
|
extern long vorbis_book_decodevs_add(codebook *book, float *a,
|
||||||
|
oggpack_buffer *b,int n);
|
||||||
|
extern long vorbis_book_decodev_set(codebook *book, float *a,
|
||||||
|
oggpack_buffer *b,int n);
|
||||||
|
extern long vorbis_book_decodev_add(codebook *book, float *a,
|
||||||
|
oggpack_buffer *b,int n);
|
||||||
|
extern long vorbis_book_decodevv_add(codebook *book, float **a,
|
||||||
|
long off,int ch,
|
||||||
|
oggpack_buffer *b,int n);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,242 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: libvorbis codec headers
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _vorbis_codec_h_
|
||||||
|
#define _vorbis_codec_h_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
|
||||||
|
typedef struct vorbis_info{
|
||||||
|
int version;
|
||||||
|
int channels;
|
||||||
|
long rate;
|
||||||
|
|
||||||
|
/* The below bitrate declarations are *hints*.
|
||||||
|
Combinations of the three values carry the following implications:
|
||||||
|
|
||||||
|
all three set to the same value:
|
||||||
|
implies a fixed rate bitstream
|
||||||
|
only nominal set:
|
||||||
|
implies a VBR stream that averages the nominal bitrate. No hard
|
||||||
|
upper/lower limit
|
||||||
|
upper and or lower set:
|
||||||
|
implies a VBR bitstream that obeys the bitrate limits. nominal
|
||||||
|
may also be set to give a nominal rate.
|
||||||
|
none set:
|
||||||
|
the coder does not care to speculate.
|
||||||
|
*/
|
||||||
|
|
||||||
|
long bitrate_upper;
|
||||||
|
long bitrate_nominal;
|
||||||
|
long bitrate_lower;
|
||||||
|
long bitrate_window;
|
||||||
|
|
||||||
|
void *codec_setup;
|
||||||
|
} vorbis_info;
|
||||||
|
|
||||||
|
/* vorbis_dsp_state buffers the current vorbis audio
|
||||||
|
analysis/synthesis state. The DSP state belongs to a specific
|
||||||
|
logical bitstream ****************************************************/
|
||||||
|
typedef struct vorbis_dsp_state{
|
||||||
|
int analysisp;
|
||||||
|
vorbis_info *vi;
|
||||||
|
|
||||||
|
float **pcm;
|
||||||
|
float **pcmret;
|
||||||
|
int pcm_storage;
|
||||||
|
int pcm_current;
|
||||||
|
int pcm_returned;
|
||||||
|
|
||||||
|
int preextrapolate;
|
||||||
|
int eofflag;
|
||||||
|
|
||||||
|
long lW;
|
||||||
|
long W;
|
||||||
|
long nW;
|
||||||
|
long centerW;
|
||||||
|
|
||||||
|
ogg_int64_t granulepos;
|
||||||
|
ogg_int64_t sequence;
|
||||||
|
|
||||||
|
ogg_int64_t glue_bits;
|
||||||
|
ogg_int64_t time_bits;
|
||||||
|
ogg_int64_t floor_bits;
|
||||||
|
ogg_int64_t res_bits;
|
||||||
|
|
||||||
|
void *backend_state;
|
||||||
|
} vorbis_dsp_state;
|
||||||
|
|
||||||
|
typedef struct vorbis_block{
|
||||||
|
/* necessary stream state for linking to the framing abstraction */
|
||||||
|
float **pcm; /* this is a pointer into local storage */
|
||||||
|
oggpack_buffer opb;
|
||||||
|
|
||||||
|
long lW;
|
||||||
|
long W;
|
||||||
|
long nW;
|
||||||
|
int pcmend;
|
||||||
|
int mode;
|
||||||
|
|
||||||
|
int eofflag;
|
||||||
|
ogg_int64_t granulepos;
|
||||||
|
ogg_int64_t sequence;
|
||||||
|
vorbis_dsp_state *vd; /* For read-only access of configuration */
|
||||||
|
|
||||||
|
/* local storage to avoid remallocing; it's up to the mapping to
|
||||||
|
structure it */
|
||||||
|
void *localstore;
|
||||||
|
long localtop;
|
||||||
|
long localalloc;
|
||||||
|
long totaluse;
|
||||||
|
struct alloc_chain *reap;
|
||||||
|
|
||||||
|
/* bitmetrics for the frame */
|
||||||
|
long glue_bits;
|
||||||
|
long time_bits;
|
||||||
|
long floor_bits;
|
||||||
|
long res_bits;
|
||||||
|
|
||||||
|
void *internal;
|
||||||
|
|
||||||
|
} vorbis_block;
|
||||||
|
|
||||||
|
/* vorbis_block is a single block of data to be processed as part of
|
||||||
|
the analysis/synthesis stream; it belongs to a specific logical
|
||||||
|
bitstream, but is independent from other vorbis_blocks belonging to
|
||||||
|
that logical bitstream. *************************************************/
|
||||||
|
|
||||||
|
struct alloc_chain{
|
||||||
|
void *ptr;
|
||||||
|
struct alloc_chain *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* vorbis_info contains all the setup information specific to the
|
||||||
|
specific compression/decompression mode in progress (eg,
|
||||||
|
psychoacoustic settings, channel setup, options, codebook
|
||||||
|
etc). vorbis_info and substructures are in backends.h.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
/* the comments are not part of vorbis_info so that vorbis_info can be
|
||||||
|
static storage */
|
||||||
|
typedef struct vorbis_comment{
|
||||||
|
/* unlimited user comment fields. libvorbis writes 'libvorbis'
|
||||||
|
whatever vendor is set to in encode */
|
||||||
|
char **user_comments;
|
||||||
|
int *comment_lengths;
|
||||||
|
int comments;
|
||||||
|
char *vendor;
|
||||||
|
|
||||||
|
} vorbis_comment;
|
||||||
|
|
||||||
|
|
||||||
|
/* libvorbis encodes in two abstraction layers; first we perform DSP
|
||||||
|
and produce a packet (see docs/analysis.txt). The packet is then
|
||||||
|
coded into a framed OggSquish bitstream by the second layer (see
|
||||||
|
docs/framing.txt). Decode is the reverse process; we sync/frame
|
||||||
|
the bitstream and extract individual packets, then decode the
|
||||||
|
packet back into PCM audio.
|
||||||
|
|
||||||
|
The extra framing/packetizing is used in streaming formats, such as
|
||||||
|
files. Over the net (such as with UDP), the framing and
|
||||||
|
packetization aren't necessary as they're provided by the transport
|
||||||
|
and the streaming layer is not used */
|
||||||
|
|
||||||
|
/* Vorbis PRIMITIVES: general ***************************************/
|
||||||
|
|
||||||
|
extern void vorbis_info_init(vorbis_info *vi);
|
||||||
|
extern void vorbis_info_clear(vorbis_info *vi);
|
||||||
|
extern int vorbis_info_blocksize(vorbis_info *vi,int zo);
|
||||||
|
extern void vorbis_comment_init(vorbis_comment *vc);
|
||||||
|
extern void vorbis_comment_add(vorbis_comment *vc, const char *comment);
|
||||||
|
extern void vorbis_comment_add_tag(vorbis_comment *vc,
|
||||||
|
const char *tag, const char *contents);
|
||||||
|
extern char *vorbis_comment_query(vorbis_comment *vc, const char *tag, int count);
|
||||||
|
extern int vorbis_comment_query_count(vorbis_comment *vc, const char *tag);
|
||||||
|
extern void vorbis_comment_clear(vorbis_comment *vc);
|
||||||
|
|
||||||
|
extern int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb);
|
||||||
|
extern int vorbis_block_clear(vorbis_block *vb);
|
||||||
|
extern void vorbis_dsp_clear(vorbis_dsp_state *v);
|
||||||
|
extern double vorbis_granule_time(vorbis_dsp_state *v,
|
||||||
|
ogg_int64_t granulepos);
|
||||||
|
|
||||||
|
extern const char *vorbis_version_string(void);
|
||||||
|
|
||||||
|
/* Vorbis PRIMITIVES: analysis/DSP layer ****************************/
|
||||||
|
|
||||||
|
extern int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi);
|
||||||
|
extern int vorbis_commentheader_out(vorbis_comment *vc, ogg_packet *op);
|
||||||
|
extern int vorbis_analysis_headerout(vorbis_dsp_state *v,
|
||||||
|
vorbis_comment *vc,
|
||||||
|
ogg_packet *op,
|
||||||
|
ogg_packet *op_comm,
|
||||||
|
ogg_packet *op_code);
|
||||||
|
extern float **vorbis_analysis_buffer(vorbis_dsp_state *v,int vals);
|
||||||
|
extern int vorbis_analysis_wrote(vorbis_dsp_state *v,int vals);
|
||||||
|
extern int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb);
|
||||||
|
extern int vorbis_analysis(vorbis_block *vb,ogg_packet *op);
|
||||||
|
|
||||||
|
extern int vorbis_bitrate_addblock(vorbis_block *vb);
|
||||||
|
extern int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,
|
||||||
|
ogg_packet *op);
|
||||||
|
|
||||||
|
/* Vorbis PRIMITIVES: synthesis layer *******************************/
|
||||||
|
extern int vorbis_synthesis_idheader(ogg_packet *op);
|
||||||
|
extern int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,
|
||||||
|
ogg_packet *op);
|
||||||
|
|
||||||
|
extern int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi);
|
||||||
|
extern int vorbis_synthesis_restart(vorbis_dsp_state *v);
|
||||||
|
extern int vorbis_synthesis(vorbis_block *vb,ogg_packet *op);
|
||||||
|
extern int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op);
|
||||||
|
extern int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb);
|
||||||
|
extern int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm);
|
||||||
|
extern int vorbis_synthesis_lapout(vorbis_dsp_state *v,float ***pcm);
|
||||||
|
extern int vorbis_synthesis_read(vorbis_dsp_state *v,int samples);
|
||||||
|
extern long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op);
|
||||||
|
|
||||||
|
extern int vorbis_synthesis_halfrate(vorbis_info *v,int flag);
|
||||||
|
extern int vorbis_synthesis_halfrate_p(vorbis_info *v);
|
||||||
|
|
||||||
|
/* Vorbis ERRORS and return codes ***********************************/
|
||||||
|
|
||||||
|
#define OV_FALSE -1
|
||||||
|
#define OV_EOF -2
|
||||||
|
#define OV_HOLE -3
|
||||||
|
|
||||||
|
#define OV_EREAD -128
|
||||||
|
#define OV_EFAULT -129
|
||||||
|
#define OV_EIMPL -130
|
||||||
|
#define OV_EINVAL -131
|
||||||
|
#define OV_ENOTVORBIS -132
|
||||||
|
#define OV_EBADHEADER -133
|
||||||
|
#define OV_EVERSION -134
|
||||||
|
#define OV_ENOTAUDIO -135
|
||||||
|
#define OV_EBADPACKET -136
|
||||||
|
#define OV_EBADLINK -137
|
||||||
|
#define OV_ENOSEEK -138
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,166 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: libvorbis codec headers
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _V_CODECI_H_
|
||||||
|
#define _V_CODECI_H_
|
||||||
|
|
||||||
|
#include "envelope.h"
|
||||||
|
#include "codebook.h"
|
||||||
|
|
||||||
|
#define BLOCKTYPE_IMPULSE 0
|
||||||
|
#define BLOCKTYPE_PADDING 1
|
||||||
|
#define BLOCKTYPE_TRANSITION 0
|
||||||
|
#define BLOCKTYPE_LONG 1
|
||||||
|
|
||||||
|
#define PACKETBLOBS 15
|
||||||
|
|
||||||
|
typedef struct vorbis_block_internal{
|
||||||
|
float **pcmdelay; /* this is a pointer into local storage */
|
||||||
|
float ampmax;
|
||||||
|
int blocktype;
|
||||||
|
|
||||||
|
oggpack_buffer *packetblob[PACKETBLOBS]; /* initialized, must be freed;
|
||||||
|
blob [PACKETBLOBS/2] points to
|
||||||
|
the oggpack_buffer in the
|
||||||
|
main vorbis_block */
|
||||||
|
} vorbis_block_internal;
|
||||||
|
|
||||||
|
typedef void vorbis_look_floor;
|
||||||
|
typedef void vorbis_look_residue;
|
||||||
|
typedef void vorbis_look_transform;
|
||||||
|
|
||||||
|
/* mode ************************************************************/
|
||||||
|
typedef struct {
|
||||||
|
int blockflag;
|
||||||
|
int windowtype;
|
||||||
|
int transformtype;
|
||||||
|
int mapping;
|
||||||
|
} vorbis_info_mode;
|
||||||
|
|
||||||
|
typedef void vorbis_info_floor;
|
||||||
|
typedef void vorbis_info_residue;
|
||||||
|
typedef void vorbis_info_mapping;
|
||||||
|
|
||||||
|
#include "psy.h"
|
||||||
|
#include "bitrate.h"
|
||||||
|
|
||||||
|
typedef struct private_state {
|
||||||
|
/* local lookup storage */
|
||||||
|
envelope_lookup *ve; /* envelope lookup */
|
||||||
|
int window[2];
|
||||||
|
vorbis_look_transform **transform[2]; /* block, type */
|
||||||
|
drft_lookup fft_look[2];
|
||||||
|
|
||||||
|
int modebits;
|
||||||
|
vorbis_look_floor **flr;
|
||||||
|
vorbis_look_residue **residue;
|
||||||
|
vorbis_look_psy *psy;
|
||||||
|
vorbis_look_psy_global *psy_g_look;
|
||||||
|
|
||||||
|
/* local storage, only used on the encoding side. This way the
|
||||||
|
application does not need to worry about freeing some packets'
|
||||||
|
memory and not others'; packet storage is always tracked.
|
||||||
|
Cleared next call to a _dsp_ function */
|
||||||
|
unsigned char *header;
|
||||||
|
unsigned char *header1;
|
||||||
|
unsigned char *header2;
|
||||||
|
|
||||||
|
bitrate_manager_state bms;
|
||||||
|
|
||||||
|
ogg_int64_t sample_count;
|
||||||
|
} private_state;
|
||||||
|
|
||||||
|
/* codec_setup_info contains all the setup information specific to the
|
||||||
|
specific compression/decompression mode in progress (eg,
|
||||||
|
psychoacoustic settings, channel setup, options, codebook
|
||||||
|
etc).
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#include "highlevel.h"
|
||||||
|
typedef struct codec_setup_info {
|
||||||
|
|
||||||
|
/* Vorbis supports only short and long blocks, but allows the
|
||||||
|
encoder to choose the sizes */
|
||||||
|
|
||||||
|
long blocksizes[2];
|
||||||
|
|
||||||
|
/* modes are the primary means of supporting on-the-fly different
|
||||||
|
blocksizes, different channel mappings (LR or M/A),
|
||||||
|
different residue backends, etc. Each mode consists of a
|
||||||
|
blocksize flag and a mapping (along with the mapping setup */
|
||||||
|
|
||||||
|
int modes;
|
||||||
|
int maps;
|
||||||
|
int floors;
|
||||||
|
int residues;
|
||||||
|
int books;
|
||||||
|
int psys; /* encode only */
|
||||||
|
|
||||||
|
vorbis_info_mode *mode_param[64];
|
||||||
|
int map_type[64];
|
||||||
|
vorbis_info_mapping *map_param[64];
|
||||||
|
int floor_type[64];
|
||||||
|
vorbis_info_floor *floor_param[64];
|
||||||
|
int residue_type[64];
|
||||||
|
vorbis_info_residue *residue_param[64];
|
||||||
|
static_codebook *book_param[256];
|
||||||
|
codebook *fullbooks;
|
||||||
|
|
||||||
|
vorbis_info_psy *psy_param[4]; /* encode only */
|
||||||
|
vorbis_info_psy_global psy_g_param;
|
||||||
|
|
||||||
|
bitrate_manager_info bi;
|
||||||
|
highlevel_encode_setup hi; /* used only by vorbisenc.c. It's a
|
||||||
|
highly redundant structure, but
|
||||||
|
improves clarity of program flow. */
|
||||||
|
int halfrate_flag; /* painless downsample for decode */
|
||||||
|
} codec_setup_info;
|
||||||
|
|
||||||
|
extern vorbis_look_psy_global *_vp_global_look(vorbis_info *vi);
|
||||||
|
extern void _vp_global_free(vorbis_look_psy_global *look);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int sorted_index[VIF_POSIT+2];
|
||||||
|
int forward_index[VIF_POSIT+2];
|
||||||
|
int reverse_index[VIF_POSIT+2];
|
||||||
|
|
||||||
|
int hineighbor[VIF_POSIT];
|
||||||
|
int loneighbor[VIF_POSIT];
|
||||||
|
int posts;
|
||||||
|
|
||||||
|
int n;
|
||||||
|
int quant_q;
|
||||||
|
vorbis_info_floor1 *vi;
|
||||||
|
|
||||||
|
long phrasebits;
|
||||||
|
long postbits;
|
||||||
|
long frames;
|
||||||
|
} vorbis_look_floor1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern int *floor1_fit(vorbis_block *vb,vorbis_look_floor1 *look,
|
||||||
|
const float *logmdct, /* in */
|
||||||
|
const float *logmask);
|
||||||
|
extern int *floor1_interpolate_fit(vorbis_block *vb,vorbis_look_floor1 *look,
|
||||||
|
int *A,int *B,
|
||||||
|
int del);
|
||||||
|
extern int floor1_encode(oggpack_buffer *opb,vorbis_block *vb,
|
||||||
|
vorbis_look_floor1 *look,
|
||||||
|
int *post,int *ilogmask);
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,374 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: PCM data envelope analysis
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
#include "vorbis/codec.h"
|
||||||
|
#include "codec_internal.h"
|
||||||
|
|
||||||
|
#include "os.h"
|
||||||
|
#include "scales.h"
|
||||||
|
#include "envelope.h"
|
||||||
|
#include "mdct.h"
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
|
void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){
|
||||||
|
codec_setup_info *ci=vi->codec_setup;
|
||||||
|
vorbis_info_psy_global *gi=&ci->psy_g_param;
|
||||||
|
int ch=vi->channels;
|
||||||
|
int i,j;
|
||||||
|
int n=e->winlength=128;
|
||||||
|
e->searchstep=64; /* not random */
|
||||||
|
|
||||||
|
e->minenergy=gi->preecho_minenergy;
|
||||||
|
e->ch=ch;
|
||||||
|
e->storage=128;
|
||||||
|
e->cursor=ci->blocksizes[1]/2;
|
||||||
|
e->mdct_win=_ogg_calloc(n,sizeof(*e->mdct_win));
|
||||||
|
mdct_init(&e->mdct,n);
|
||||||
|
|
||||||
|
for(i=0;i<n;i++){
|
||||||
|
e->mdct_win[i]=sin(i/(n-1.)*M_PI);
|
||||||
|
e->mdct_win[i]*=e->mdct_win[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* magic follows */
|
||||||
|
e->band[0].begin=2; e->band[0].end=4;
|
||||||
|
e->band[1].begin=4; e->band[1].end=5;
|
||||||
|
e->band[2].begin=6; e->band[2].end=6;
|
||||||
|
e->band[3].begin=9; e->band[3].end=8;
|
||||||
|
e->band[4].begin=13; e->band[4].end=8;
|
||||||
|
e->band[5].begin=17; e->band[5].end=8;
|
||||||
|
e->band[6].begin=22; e->band[6].end=8;
|
||||||
|
|
||||||
|
for(j=0;j<VE_BANDS;j++){
|
||||||
|
n=e->band[j].end;
|
||||||
|
e->band[j].window=_ogg_malloc(n*sizeof(*e->band[0].window));
|
||||||
|
for(i=0;i<n;i++){
|
||||||
|
e->band[j].window[i]=sin((i+.5)/n*M_PI);
|
||||||
|
e->band[j].total+=e->band[j].window[i];
|
||||||
|
}
|
||||||
|
e->band[j].total=1./e->band[j].total;
|
||||||
|
}
|
||||||
|
|
||||||
|
e->filter=_ogg_calloc(VE_BANDS*ch,sizeof(*e->filter));
|
||||||
|
e->mark=_ogg_calloc(e->storage,sizeof(*e->mark));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void _ve_envelope_clear(envelope_lookup *e){
|
||||||
|
int i;
|
||||||
|
mdct_clear(&e->mdct);
|
||||||
|
for(i=0;i<VE_BANDS;i++)
|
||||||
|
_ogg_free(e->band[i].window);
|
||||||
|
_ogg_free(e->mdct_win);
|
||||||
|
_ogg_free(e->filter);
|
||||||
|
_ogg_free(e->mark);
|
||||||
|
memset(e,0,sizeof(*e));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fairly straight threshhold-by-band based until we find something
|
||||||
|
that works better and isn't patented. */
|
||||||
|
|
||||||
|
static int _ve_amp(envelope_lookup *ve,
|
||||||
|
vorbis_info_psy_global *gi,
|
||||||
|
float *data,
|
||||||
|
envelope_band *bands,
|
||||||
|
envelope_filter_state *filters){
|
||||||
|
long n=ve->winlength;
|
||||||
|
int ret=0;
|
||||||
|
long i,j;
|
||||||
|
float decay;
|
||||||
|
|
||||||
|
/* we want to have a 'minimum bar' for energy, else we're just
|
||||||
|
basing blocks on quantization noise that outweighs the signal
|
||||||
|
itself (for low power signals) */
|
||||||
|
|
||||||
|
float minV=ve->minenergy;
|
||||||
|
float *vec=alloca(n*sizeof(*vec));
|
||||||
|
|
||||||
|
/* stretch is used to gradually lengthen the number of windows
|
||||||
|
considered prevoius-to-potential-trigger */
|
||||||
|
int stretch=max(VE_MINSTRETCH,ve->stretch/2);
|
||||||
|
float penalty=gi->stretch_penalty-(ve->stretch/2-VE_MINSTRETCH);
|
||||||
|
if(penalty<0.f)penalty=0.f;
|
||||||
|
if(penalty>gi->stretch_penalty)penalty=gi->stretch_penalty;
|
||||||
|
|
||||||
|
/*_analysis_output_always("lpcm",seq2,data,n,0,0,
|
||||||
|
totalshift+pos*ve->searchstep);*/
|
||||||
|
|
||||||
|
/* window and transform */
|
||||||
|
for(i=0;i<n;i++)
|
||||||
|
vec[i]=data[i]*ve->mdct_win[i];
|
||||||
|
mdct_forward(&ve->mdct,vec,vec);
|
||||||
|
|
||||||
|
/*_analysis_output_always("mdct",seq2,vec,n/2,0,1,0); */
|
||||||
|
|
||||||
|
/* near-DC spreading function; this has nothing to do with
|
||||||
|
psychoacoustics, just sidelobe leakage and window size */
|
||||||
|
{
|
||||||
|
float temp=vec[0]*vec[0]+.7*vec[1]*vec[1]+.2*vec[2]*vec[2];
|
||||||
|
int ptr=filters->nearptr;
|
||||||
|
|
||||||
|
/* the accumulation is regularly refreshed from scratch to avoid
|
||||||
|
floating point creep */
|
||||||
|
if(ptr==0){
|
||||||
|
decay=filters->nearDC_acc=filters->nearDC_partialacc+temp;
|
||||||
|
filters->nearDC_partialacc=temp;
|
||||||
|
}else{
|
||||||
|
decay=filters->nearDC_acc+=temp;
|
||||||
|
filters->nearDC_partialacc+=temp;
|
||||||
|
}
|
||||||
|
filters->nearDC_acc-=filters->nearDC[ptr];
|
||||||
|
filters->nearDC[ptr]=temp;
|
||||||
|
|
||||||
|
decay*=(1./(VE_NEARDC+1));
|
||||||
|
filters->nearptr++;
|
||||||
|
if(filters->nearptr>=VE_NEARDC)filters->nearptr=0;
|
||||||
|
decay=todB(&decay)*.5-15.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* perform spreading and limiting, also smooth the spectrum. yes,
|
||||||
|
the MDCT results in all real coefficients, but it still *behaves*
|
||||||
|
like real/imaginary pairs */
|
||||||
|
for(i=0;i<n/2;i+=2){
|
||||||
|
float val=vec[i]*vec[i]+vec[i+1]*vec[i+1];
|
||||||
|
val=todB(&val)*.5f;
|
||||||
|
if(val<decay)val=decay;
|
||||||
|
if(val<minV)val=minV;
|
||||||
|
vec[i>>1]=val;
|
||||||
|
decay-=8.;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*_analysis_output_always("spread",seq2++,vec,n/4,0,0,0);*/
|
||||||
|
|
||||||
|
/* perform preecho/postecho triggering by band */
|
||||||
|
for(j=0;j<VE_BANDS;j++){
|
||||||
|
float acc=0.;
|
||||||
|
float valmax,valmin;
|
||||||
|
|
||||||
|
/* accumulate amplitude */
|
||||||
|
for(i=0;i<bands[j].end;i++)
|
||||||
|
acc+=vec[i+bands[j].begin]*bands[j].window[i];
|
||||||
|
|
||||||
|
acc*=bands[j].total;
|
||||||
|
|
||||||
|
/* convert amplitude to delta */
|
||||||
|
{
|
||||||
|
int p,this=filters[j].ampptr;
|
||||||
|
float postmax,postmin,premax=-99999.f,premin=99999.f;
|
||||||
|
|
||||||
|
p=this;
|
||||||
|
p--;
|
||||||
|
if(p<0)p+=VE_AMP;
|
||||||
|
postmax=max(acc,filters[j].ampbuf[p]);
|
||||||
|
postmin=min(acc,filters[j].ampbuf[p]);
|
||||||
|
|
||||||
|
for(i=0;i<stretch;i++){
|
||||||
|
p--;
|
||||||
|
if(p<0)p+=VE_AMP;
|
||||||
|
premax=max(premax,filters[j].ampbuf[p]);
|
||||||
|
premin=min(premin,filters[j].ampbuf[p]);
|
||||||
|
}
|
||||||
|
|
||||||
|
valmin=postmin-premin;
|
||||||
|
valmax=postmax-premax;
|
||||||
|
|
||||||
|
/*filters[j].markers[pos]=valmax;*/
|
||||||
|
filters[j].ampbuf[this]=acc;
|
||||||
|
filters[j].ampptr++;
|
||||||
|
if(filters[j].ampptr>=VE_AMP)filters[j].ampptr=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* look at min/max, decide trigger */
|
||||||
|
if(valmax>gi->preecho_thresh[j]+penalty){
|
||||||
|
ret|=1;
|
||||||
|
ret|=4;
|
||||||
|
}
|
||||||
|
if(valmin<gi->postecho_thresh[j]-penalty)ret|=2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static int seq=0;
|
||||||
|
static ogg_int64_t totalshift=-1024;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
long _ve_envelope_search(vorbis_dsp_state *v){
|
||||||
|
vorbis_info *vi=v->vi;
|
||||||
|
codec_setup_info *ci=vi->codec_setup;
|
||||||
|
vorbis_info_psy_global *gi=&ci->psy_g_param;
|
||||||
|
envelope_lookup *ve=((private_state *)(v->backend_state))->ve;
|
||||||
|
long i,j;
|
||||||
|
|
||||||
|
int first=ve->current/ve->searchstep;
|
||||||
|
int last=v->pcm_current/ve->searchstep-VE_WIN;
|
||||||
|
if(first<0)first=0;
|
||||||
|
|
||||||
|
/* make sure we have enough storage to match the PCM */
|
||||||
|
if(last+VE_WIN+VE_POST>ve->storage){
|
||||||
|
ve->storage=last+VE_WIN+VE_POST; /* be sure */
|
||||||
|
ve->mark=_ogg_realloc(ve->mark,ve->storage*sizeof(*ve->mark));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(j=first;j<last;j++){
|
||||||
|
int ret=0;
|
||||||
|
|
||||||
|
ve->stretch++;
|
||||||
|
if(ve->stretch>VE_MAXSTRETCH*2)
|
||||||
|
ve->stretch=VE_MAXSTRETCH*2;
|
||||||
|
|
||||||
|
for(i=0;i<ve->ch;i++){
|
||||||
|
float *pcm=v->pcm[i]+ve->searchstep*(j);
|
||||||
|
ret|=_ve_amp(ve,gi,pcm,ve->band,ve->filter+i*VE_BANDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
ve->mark[j+VE_POST]=0;
|
||||||
|
if(ret&1){
|
||||||
|
ve->mark[j]=1;
|
||||||
|
ve->mark[j+1]=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ret&2){
|
||||||
|
ve->mark[j]=1;
|
||||||
|
if(j>0)ve->mark[j-1]=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ret&4)ve->stretch=-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ve->current=last*ve->searchstep;
|
||||||
|
|
||||||
|
{
|
||||||
|
long centerW=v->centerW;
|
||||||
|
long testW=
|
||||||
|
centerW+
|
||||||
|
ci->blocksizes[v->W]/4+
|
||||||
|
ci->blocksizes[1]/2+
|
||||||
|
ci->blocksizes[0]/4;
|
||||||
|
|
||||||
|
j=ve->cursor;
|
||||||
|
|
||||||
|
while(j<ve->current-(ve->searchstep)){/* account for postecho
|
||||||
|
working back one window */
|
||||||
|
if(j>=testW)return(1);
|
||||||
|
|
||||||
|
ve->cursor=j;
|
||||||
|
|
||||||
|
if(ve->mark[j/ve->searchstep]){
|
||||||
|
if(j>centerW){
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if(j>ve->curmark){
|
||||||
|
float *marker=alloca(v->pcm_current*sizeof(*marker));
|
||||||
|
int l,m;
|
||||||
|
memset(marker,0,sizeof(*marker)*v->pcm_current);
|
||||||
|
fprintf(stderr,"mark! seq=%d, cursor:%fs time:%fs\n",
|
||||||
|
seq,
|
||||||
|
(totalshift+ve->cursor)/44100.,
|
||||||
|
(totalshift+j)/44100.);
|
||||||
|
_analysis_output_always("pcmL",seq,v->pcm[0],v->pcm_current,0,0,totalshift);
|
||||||
|
_analysis_output_always("pcmR",seq,v->pcm[1],v->pcm_current,0,0,totalshift);
|
||||||
|
|
||||||
|
_analysis_output_always("markL",seq,v->pcm[0],j,0,0,totalshift);
|
||||||
|
_analysis_output_always("markR",seq,v->pcm[1],j,0,0,totalshift);
|
||||||
|
|
||||||
|
for(m=0;m<VE_BANDS;m++){
|
||||||
|
char buf[80];
|
||||||
|
sprintf(buf,"delL%d",m);
|
||||||
|
for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[m].markers[l]*.1;
|
||||||
|
_analysis_output_always(buf,seq,marker,v->pcm_current,0,0,totalshift);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(m=0;m<VE_BANDS;m++){
|
||||||
|
char buf[80];
|
||||||
|
sprintf(buf,"delR%d",m);
|
||||||
|
for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[m+VE_BANDS].markers[l]*.1;
|
||||||
|
_analysis_output_always(buf,seq,marker,v->pcm_current,0,0,totalshift);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->mark[l]*.4;
|
||||||
|
_analysis_output_always("mark",seq,marker,v->pcm_current,0,0,totalshift);
|
||||||
|
|
||||||
|
|
||||||
|
seq++;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ve->curmark=j;
|
||||||
|
if(j>=testW)return(1);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j+=ve->searchstep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _ve_envelope_mark(vorbis_dsp_state *v){
|
||||||
|
envelope_lookup *ve=((private_state *)(v->backend_state))->ve;
|
||||||
|
vorbis_info *vi=v->vi;
|
||||||
|
codec_setup_info *ci=vi->codec_setup;
|
||||||
|
long centerW=v->centerW;
|
||||||
|
long beginW=centerW-ci->blocksizes[v->W]/4;
|
||||||
|
long endW=centerW+ci->blocksizes[v->W]/4;
|
||||||
|
if(v->W){
|
||||||
|
beginW-=ci->blocksizes[v->lW]/4;
|
||||||
|
endW+=ci->blocksizes[v->nW]/4;
|
||||||
|
}else{
|
||||||
|
beginW-=ci->blocksizes[0]/4;
|
||||||
|
endW+=ci->blocksizes[0]/4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ve->curmark>=beginW && ve->curmark<endW)return(1);
|
||||||
|
{
|
||||||
|
long first=beginW/ve->searchstep;
|
||||||
|
long last=endW/ve->searchstep;
|
||||||
|
long i;
|
||||||
|
for(i=first;i<last;i++)
|
||||||
|
if(ve->mark[i])return(1);
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _ve_envelope_shift(envelope_lookup *e,long shift){
|
||||||
|
int smallsize=e->current/e->searchstep+VE_POST; /* adjust for placing marks
|
||||||
|
ahead of ve->current */
|
||||||
|
int smallshift=shift/e->searchstep;
|
||||||
|
|
||||||
|
memmove(e->mark,e->mark+smallshift,(smallsize-smallshift)*sizeof(*e->mark));
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
for(i=0;i<VE_BANDS*e->ch;i++)
|
||||||
|
memmove(e->filter[i].markers,
|
||||||
|
e->filter[i].markers+smallshift,
|
||||||
|
(1024-smallshift)*sizeof(*(*e->filter).markers));
|
||||||
|
totalshift+=shift;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
e->current-=shift;
|
||||||
|
if(e->curmark>=0)
|
||||||
|
e->curmark-=shift;
|
||||||
|
e->cursor-=shift;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: PCM data envelope analysis and manipulation
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _V_ENVELOPE_
|
||||||
|
#define _V_ENVELOPE_
|
||||||
|
|
||||||
|
#include "mdct.h"
|
||||||
|
|
||||||
|
#define VE_PRE 16
|
||||||
|
#define VE_WIN 4
|
||||||
|
#define VE_POST 2
|
||||||
|
#define VE_AMP (VE_PRE+VE_POST-1)
|
||||||
|
|
||||||
|
#define VE_BANDS 7
|
||||||
|
#define VE_NEARDC 15
|
||||||
|
|
||||||
|
#define VE_MINSTRETCH 2 /* a bit less than short block */
|
||||||
|
#define VE_MAXSTRETCH 12 /* one-third full block */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float ampbuf[VE_AMP];
|
||||||
|
int ampptr;
|
||||||
|
|
||||||
|
float nearDC[VE_NEARDC];
|
||||||
|
float nearDC_acc;
|
||||||
|
float nearDC_partialacc;
|
||||||
|
int nearptr;
|
||||||
|
|
||||||
|
} envelope_filter_state;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int begin;
|
||||||
|
int end;
|
||||||
|
float *window;
|
||||||
|
float total;
|
||||||
|
} envelope_band;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int ch;
|
||||||
|
int winlength;
|
||||||
|
int searchstep;
|
||||||
|
float minenergy;
|
||||||
|
|
||||||
|
mdct_lookup mdct;
|
||||||
|
float *mdct_win;
|
||||||
|
|
||||||
|
envelope_band band[VE_BANDS];
|
||||||
|
envelope_filter_state *filter;
|
||||||
|
int stretch;
|
||||||
|
|
||||||
|
int *mark;
|
||||||
|
|
||||||
|
long storage;
|
||||||
|
long current;
|
||||||
|
long curmark;
|
||||||
|
long cursor;
|
||||||
|
} envelope_lookup;
|
||||||
|
|
||||||
|
extern void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi);
|
||||||
|
extern void _ve_envelope_clear(envelope_lookup *e);
|
||||||
|
extern long _ve_envelope_search(vorbis_dsp_state *v);
|
||||||
|
extern void _ve_envelope_shift(envelope_lookup *e,long shift);
|
||||||
|
extern int _ve_envelope_mark(vorbis_dsp_state *v);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,223 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: floor backend 0 implementation
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
#include "vorbis/codec.h"
|
||||||
|
#include "codec_internal.h"
|
||||||
|
#include "registry.h"
|
||||||
|
#include "lpc.h"
|
||||||
|
#include "lsp.h"
|
||||||
|
#include "codebook.h"
|
||||||
|
#include "scales.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
#include "misc.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int ln;
|
||||||
|
int m;
|
||||||
|
int **linearmap;
|
||||||
|
int n[2];
|
||||||
|
|
||||||
|
vorbis_info_floor0 *vi;
|
||||||
|
|
||||||
|
long bits;
|
||||||
|
long frames;
|
||||||
|
} vorbis_look_floor0;
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************/
|
||||||
|
|
||||||
|
static void floor0_free_info(vorbis_info_floor *i){
|
||||||
|
vorbis_info_floor0 *info=(vorbis_info_floor0 *)i;
|
||||||
|
if(info){
|
||||||
|
memset(info,0,sizeof(*info));
|
||||||
|
_ogg_free(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void floor0_free_look(vorbis_look_floor *i){
|
||||||
|
vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
|
||||||
|
if(look){
|
||||||
|
|
||||||
|
if(look->linearmap){
|
||||||
|
|
||||||
|
if(look->linearmap[0])_ogg_free(look->linearmap[0]);
|
||||||
|
if(look->linearmap[1])_ogg_free(look->linearmap[1]);
|
||||||
|
|
||||||
|
_ogg_free(look->linearmap);
|
||||||
|
}
|
||||||
|
memset(look,0,sizeof(*look));
|
||||||
|
_ogg_free(look);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static vorbis_info_floor *floor0_unpack (vorbis_info *vi,oggpack_buffer *opb){
|
||||||
|
codec_setup_info *ci=vi->codec_setup;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
vorbis_info_floor0 *info=_ogg_malloc(sizeof(*info));
|
||||||
|
info->order=oggpack_read(opb,8);
|
||||||
|
info->rate=oggpack_read(opb,16);
|
||||||
|
info->barkmap=oggpack_read(opb,16);
|
||||||
|
info->ampbits=oggpack_read(opb,6);
|
||||||
|
info->ampdB=oggpack_read(opb,8);
|
||||||
|
info->numbooks=oggpack_read(opb,4)+1;
|
||||||
|
|
||||||
|
if(info->order<1)goto err_out;
|
||||||
|
if(info->rate<1)goto err_out;
|
||||||
|
if(info->barkmap<1)goto err_out;
|
||||||
|
if(info->numbooks<1)goto err_out;
|
||||||
|
|
||||||
|
for(j=0;j<info->numbooks;j++){
|
||||||
|
info->books[j]=oggpack_read(opb,8);
|
||||||
|
if(info->books[j]<0 || info->books[j]>=ci->books)goto err_out;
|
||||||
|
if(ci->book_param[info->books[j]]->maptype==0)goto err_out;
|
||||||
|
if(ci->book_param[info->books[j]]->dim<1)goto err_out;
|
||||||
|
}
|
||||||
|
return(info);
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
floor0_free_info(info);
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize Bark scale and normalization lookups. We could do this
|
||||||
|
with static tables, but Vorbis allows a number of possible
|
||||||
|
combinations, so it's best to do it computationally.
|
||||||
|
|
||||||
|
The below is authoritative in terms of defining scale mapping.
|
||||||
|
Note that the scale depends on the sampling rate as well as the
|
||||||
|
linear block and mapping sizes */
|
||||||
|
|
||||||
|
static void floor0_map_lazy_init(vorbis_block *vb,
|
||||||
|
vorbis_info_floor *infoX,
|
||||||
|
vorbis_look_floor0 *look){
|
||||||
|
if(!look->linearmap[vb->W]){
|
||||||
|
vorbis_dsp_state *vd=vb->vd;
|
||||||
|
vorbis_info *vi=vd->vi;
|
||||||
|
codec_setup_info *ci=vi->codec_setup;
|
||||||
|
vorbis_info_floor0 *info=(vorbis_info_floor0 *)infoX;
|
||||||
|
int W=vb->W;
|
||||||
|
int n=ci->blocksizes[W]/2,j;
|
||||||
|
|
||||||
|
/* we choose a scaling constant so that:
|
||||||
|
floor(bark(rate/2-1)*C)=mapped-1
|
||||||
|
floor(bark(rate/2)*C)=mapped */
|
||||||
|
float scale=look->ln/toBARK(info->rate/2.f);
|
||||||
|
|
||||||
|
/* the mapping from a linear scale to a smaller bark scale is
|
||||||
|
straightforward. We do *not* make sure that the linear mapping
|
||||||
|
does not skip bark-scale bins; the decoder simply skips them and
|
||||||
|
the encoder may do what it wishes in filling them. They're
|
||||||
|
necessary in some mapping combinations to keep the scale spacing
|
||||||
|
accurate */
|
||||||
|
look->linearmap[W]=_ogg_malloc((n+1)*sizeof(**look->linearmap));
|
||||||
|
for(j=0;j<n;j++){
|
||||||
|
int val=floor( toBARK((info->rate/2.f)/n*j)
|
||||||
|
*scale); /* bark numbers represent band edges */
|
||||||
|
if(val>=look->ln)val=look->ln-1; /* guard against the approximation */
|
||||||
|
look->linearmap[W][j]=val;
|
||||||
|
}
|
||||||
|
look->linearmap[W][j]=-1;
|
||||||
|
look->n[W]=n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static vorbis_look_floor *floor0_look(vorbis_dsp_state *vd,
|
||||||
|
vorbis_info_floor *i){
|
||||||
|
vorbis_info_floor0 *info=(vorbis_info_floor0 *)i;
|
||||||
|
vorbis_look_floor0 *look=_ogg_calloc(1,sizeof(*look));
|
||||||
|
|
||||||
|
(void)vd;
|
||||||
|
|
||||||
|
look->m=info->order;
|
||||||
|
look->ln=info->barkmap;
|
||||||
|
look->vi=info;
|
||||||
|
|
||||||
|
look->linearmap=_ogg_calloc(2,sizeof(*look->linearmap));
|
||||||
|
|
||||||
|
return look;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *floor0_inverse1(vorbis_block *vb,vorbis_look_floor *i){
|
||||||
|
vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
|
||||||
|
vorbis_info_floor0 *info=look->vi;
|
||||||
|
int j,k;
|
||||||
|
|
||||||
|
int ampraw=oggpack_read(&vb->opb,info->ampbits);
|
||||||
|
if(ampraw>0){ /* also handles the -1 out of data case */
|
||||||
|
long maxval=(1<<info->ampbits)-1;
|
||||||
|
float amp=(float)ampraw/maxval*info->ampdB;
|
||||||
|
int booknum=oggpack_read(&vb->opb,ov_ilog(info->numbooks));
|
||||||
|
|
||||||
|
if(booknum!=-1 && booknum<info->numbooks){ /* be paranoid */
|
||||||
|
codec_setup_info *ci=vb->vd->vi->codec_setup;
|
||||||
|
codebook *b=ci->fullbooks+info->books[booknum];
|
||||||
|
float last=0.f;
|
||||||
|
|
||||||
|
/* the additional b->dim is a guard against any possible stack
|
||||||
|
smash; b->dim is provably more than we can overflow the
|
||||||
|
vector */
|
||||||
|
float *lsp=_vorbis_block_alloc(vb,sizeof(*lsp)*(look->m+b->dim+1));
|
||||||
|
|
||||||
|
if(vorbis_book_decodev_set(b,lsp,&vb->opb,look->m)==-1)goto eop;
|
||||||
|
for(j=0;j<look->m;){
|
||||||
|
for(k=0;j<look->m && k<b->dim;k++,j++)lsp[j]+=last;
|
||||||
|
last=lsp[j-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
lsp[look->m]=amp;
|
||||||
|
return(lsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eop:
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int floor0_inverse2(vorbis_block *vb,vorbis_look_floor *i,
|
||||||
|
void *memo,float *out){
|
||||||
|
vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
|
||||||
|
vorbis_info_floor0 *info=look->vi;
|
||||||
|
|
||||||
|
floor0_map_lazy_init(vb,info,look);
|
||||||
|
|
||||||
|
if(memo){
|
||||||
|
float *lsp=(float *)memo;
|
||||||
|
float amp=lsp[look->m];
|
||||||
|
|
||||||
|
/* take the coefficients back to a spectral envelope curve */
|
||||||
|
vorbis_lsp_to_curve(out,
|
||||||
|
look->linearmap[vb->W],
|
||||||
|
look->n[vb->W],
|
||||||
|
look->ln,
|
||||||
|
lsp,look->m,amp,(float)info->ampdB);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
memset(out,0,sizeof(*out)*look->n[vb->W]);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* export hooks */
|
||||||
|
const vorbis_func_floor floor0_exportbundle={
|
||||||
|
NULL,&floor0_unpack,&floor0_look,&floor0_free_info,
|
||||||
|
&floor0_free_look,&floor0_inverse1,&floor0_inverse2
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,57 @@
|
||||||
|
/********************************************************************
|
||||||
|
* *
|
||||||
|
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
|
||||||
|
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||||
|
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||||
|
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||||
|
* *
|
||||||
|
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
|
||||||
|
* by the Xiph.Org Foundation http://www.xiph.org/ *
|
||||||
|
* *
|
||||||
|
********************************************************************
|
||||||
|
|
||||||
|
function: highlevel encoder setup struct separated out for vorbisenc clarity
|
||||||
|
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
typedef struct highlevel_byblocktype {
|
||||||
|
double tone_mask_setting;
|
||||||
|
double tone_peaklimit_setting;
|
||||||
|
double noise_bias_setting;
|
||||||
|
double noise_compand_setting;
|
||||||
|
} highlevel_byblocktype;
|
||||||
|
|
||||||
|
typedef struct highlevel_encode_setup {
|
||||||
|
int set_in_stone;
|
||||||
|
const void *setup;
|
||||||
|
double base_setting;
|
||||||
|
|
||||||
|
double impulse_noisetune;
|
||||||
|
|
||||||
|
/* bitrate management below all settable */
|
||||||
|
float req;
|
||||||
|
int managed;
|
||||||
|
long bitrate_min;
|
||||||
|
long bitrate_av;
|
||||||
|
double bitrate_av_damp;
|
||||||
|
long bitrate_max;
|
||||||
|
long bitrate_reservoir;
|
||||||
|
double bitrate_reservoir_bias;
|
||||||
|
|
||||||
|
int impulse_block_p;
|
||||||
|
int noise_normalize_p;
|
||||||
|
int coupling_p;
|
||||||
|
|
||||||
|
double stereo_point_setting;
|
||||||
|
double lowpass_kHz;
|
||||||
|
int lowpass_altered;
|
||||||
|
|
||||||
|
double ath_floating_dB;
|
||||||
|
double ath_absolute_dB;
|
||||||
|
|
||||||
|
double amplitude_track_dBpersec;
|
||||||
|
double trigger_setting;
|
||||||
|
|
||||||
|
highlevel_byblocktype block[4]; /* padding, impulse, transition, long */
|
||||||
|
|
||||||
|
} highlevel_encode_setup;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue