I want to create an AUGraph that has the following AudioUnits:
1 * 440HZ sine wave generator
1 * 880HZ sine wave generator
1 * Mixer
1 * Output
If I connect my sine wave generators to my mixer, then the mixer to the output I get no sound.
If I connect a sine wave generator directly to the output I do get sound, probably because the Output unit connects to the sine wave generator callback.
Is there something I'm missing with how this should be connected?
Full code sample, Connect 1 * Joins 1 is not working, comment these out and run Connect 2 and Joins 2 to hear the sine wave working
//
// main.c
// TestAudioUnit
//
// Created by Chris Davis on 25/08/2013.
// Copyright (c) 2013 Chris Davis. All rights reserved.
//
#include <CoreFoundation/CoreFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
typedef struct MyAUGraphPlayer
{
AudioStreamBasicDescription streamFormat;
AUGraph graph;
AUNode output;
AUNode mixer;
AUNode sine;
AudioUnit audioUnits[3];
AudioBufferList *inputBuffer;
Float64 firstInputSampleTime;
Float64 firstOutputSampleTime;
Float64 inToOutSampleTimeOffset;
} MyAUGraphPlayer;
OSStatus SineWaveRenderCallback(void * inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
// inRefCon is the context pointer we passed in earlier when setting the render callback
double currentPhase = *((double *)inRefCon);
// ioData is where we're supposed to put the audio samples we've created
Float32 * outputBuffer = (Float32 *)ioData->mBuffers[0].mData;
const double frequency = 880.0;
const double phaseStep = (frequency / 44100.) * (M_PI * 2.);
for(int i = 0; i < inNumberFrames; i++) {
outputBuffer[i] = sin(currentPhase);
currentPhase += phaseStep;
}
// If we were doing stereo (or more), this would copy our sine wave samples
// to all of the remaining channels
for(int i = 1; i < ioData->mNumberBuffers; i++) {
memcpy(ioData->mBuffers[i].mData, outputBuffer, ioData->mBuffers[i].mDataByteSize);
}
// writing the current phase back to inRefCon so we can use it on the next call
*((double *)inRefCon) = currentPhase;
return noErr;
}
int main(int argc, const char * argv[])
{
MyAUGraphPlayer *player = {0};
MyAUGraphPlayer p = {0};
player=&p;
NewAUGraph(&player->graph);
//Output
{
AudioComponentDescription description = {
.componentType = kAudioUnitType_Output,
.componentSubType = kAudioUnitSubType_DefaultOutput,
.componentManufacturer = kAudioUnitManufacturer_Apple
};
AUGraphAddNode(player->graph, &description, &player->output);
AudioComponent comp = AudioComponentFindNext(NULL, &description);
AudioComponentInstanceNew(comp, &player->audioUnits[0]);
AudioUnitInitialize(player->audioUnits[0]);
AudioStreamBasicDescription ASBD = {
.mSampleRate = 44100,
.mFormatID = kAudioFormatLinearPCM,
.mFormatFlags = kAudioFormatFlagsNativeFloatPacked,
.mChannelsPerFrame = 1,
.mFramesPerPacket = 1,
.mBitsPerChannel = sizeof(Float32) * 8,
.mBytesPerPacket = sizeof(Float32),
.mBytesPerFrame = sizeof(Float32)
};
AudioUnitSetProperty(player->audioUnits[0],
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Global,
0,
&ASBD,
sizeof(ASBD));
}
//Mixer
{
AudioComponentDescription description = {
.componentType = kAudioUnitType_Mixer,
.componentSubType = kAudioUnitSubType_StereoMixer,
.componentManufacturer = kAudioUnitManufacturer_Apple
};
AUGraphAddNode(player->graph, &description, &player->mixer);
AudioComponent comp = AudioComponentFindNext(NULL, &description);
AudioComponentInstanceNew(comp, &player->audioUnits[1]);
AudioUnitInitialize(player->audioUnits[1]);
}
//Sine
{
AudioComponentDescription description = {
.componentType = kAudioUnitType_Generator,
.componentSubType = kAudioUnitSubType_ScheduledSoundPlayer,
.componentManufacturer = kAudioUnitManufacturer_Apple
};
AUGraphAddNode(player->graph, &description, &player->sine);
AudioComponent comp = AudioComponentFindNext(NULL, &description);
AudioComponentInstanceNew(comp, &player->audioUnits[2]);
AudioUnitInitialize(player->audioUnits[2]);
}
//Connect 1
{
AURenderCallbackStruct callbackInfo = {
.inputProc = SineWaveRenderCallback,
.inputProcRefCon = player
};
AudioUnitSetProperty(player->audioUnits[1],
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global,
0,
&callbackInfo,
sizeof(callbackInfo));
}
//Joins 1 - sine to mixer to outout
{
AUGraphConnectNodeInput(player->graph,
player->sine,
0,
player->mixer,
0);
AUGraphConnectNodeInput(player->graph,
player->mixer,
0,
player->output,
0);
}
//connect 2
/*{
AURenderCallbackStruct callbackInfo = {
.inputProc = SineWaveRenderCallback,
.inputProcRefCon = player
};
AudioUnitSetProperty(player->audioUnits[0],
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global,
0,
&callbackInfo,
sizeof(callbackInfo));
}
//Joins 2 - sine direct to output
{
AUGraphConnectNodeInput(player->graph,
player->sine,
0,
player->output,
0);
}*/
AUGraphInitialize(player->graph);
player->firstOutputSampleTime = -1;
AudioOutputUnitStart(player->audioUnits[0]);
AUGraphStart(player->graph);
printf("enter key to stop\n");
getchar();
return 0;
}
This code correctly plays the sine wave, however, I get lots of errors from CoreAudio during setup:
//
// main.c
// TestAudioUnit
//
// Created by Chris Davis on 25/08/2013.
// Copyright (c) 2013 Chris Davis. All rights reserved.
//
#include <CoreFoundation/CoreFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
typedef struct MyAUGraphPlayer
{
AudioStreamBasicDescription streamFormat;
AUGraph graph;
AUNode output;
AUNode mixer;
AUNode sine;
AudioUnit audioUnits[3];
AudioBufferList *inputBuffer;
Float64 firstInputSampleTime;
Float64 firstOutputSampleTime;
Float64 inToOutSampleTimeOffset;
} MyAUGraphPlayer;
OSStatus SineWaveRenderCallback(void * inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
// inRefCon is the context pointer we passed in earlier when setting the render callback
double currentPhase = *((double *)inRefCon);
// ioData is where we're supposed to put the audio samples we've created
Float32 * outputBuffer = (Float32 *)ioData->mBuffers[0].mData;
const double frequency = 880.0;
const double phaseStep = (frequency / 44100.) * (M_PI * 2.);
for(int i = 0; i < inNumberFrames; i++) {
outputBuffer[i] = sin(currentPhase);
currentPhase += phaseStep;
}
// If we were doing stereo (or more), this would copy our sine wave samples
// to all of the remaining channels
for(int i = 1; i < ioData->mNumberBuffers; i++) {
memcpy(ioData->mBuffers[i].mData, outputBuffer, ioData->mBuffers[i].mDataByteSize);
}
// writing the current phase back to inRefCon so we can use it on the next call
*((double *)inRefCon) = currentPhase;
return noErr;
}
int main(int argc, const char * argv[])
{
MyAUGraphPlayer *player = {0};
MyAUGraphPlayer p = {0};
player=&p;
NewAUGraph(&player->graph);
OSStatus result = 0;
AudioStreamBasicDescription ASBD = {
.mSampleRate = 44100,
.mFormatID = kAudioFormatLinearPCM,
.mFormatFlags = kAudioFormatFlagsNativeFloatPacked,
.mChannelsPerFrame = 2,
.mFramesPerPacket = 1,
.mBitsPerChannel = sizeof(Float32) * 8,
.mBytesPerPacket = sizeof(Float32),
.mBytesPerFrame = sizeof(Float32)
};
//Output
{
AudioComponentDescription description = {
.componentType = kAudioUnitType_Output,
.componentSubType = kAudioUnitSubType_DefaultOutput,
.componentManufacturer = kAudioUnitManufacturer_Apple
};
result = AUGraphAddNode(player->graph, &description, &player->output);
printf("err: %d\n", result);
AudioComponent comp = AudioComponentFindNext(NULL, &description);
result = AudioComponentInstanceNew(comp, &player->audioUnits[0]);
printf("err: %d\n", result);
result = AudioUnitInitialize(player->audioUnits[0]);
printf("err: %d\n", result);
}
//Mixer
{
AudioComponentDescription description = {
.componentType = kAudioUnitType_Mixer,
.componentSubType = kAudioUnitSubType_StereoMixer,
.componentManufacturer = kAudioUnitManufacturer_Apple
};
result = AUGraphAddNode(player->graph, &description, &player->mixer);
printf("err: %d\n", result);
AudioComponent comp = AudioComponentFindNext(NULL, &description);
result = AudioComponentInstanceNew(comp, &player->audioUnits[1]);
printf("err: %d\n", result);
}
//Sine
{
AudioComponentDescription description = {
.componentType = kAudioUnitType_Generator,
.componentSubType = kAudioUnitSubType_ScheduledSoundPlayer,
.componentManufacturer = kAudioUnitManufacturer_Apple
};
result = AUGraphAddNode(player->graph, &description, &player->sine);
printf("err: %d\n", result);
AudioComponent comp = AudioComponentFindNext(NULL, &description);
result = AudioComponentInstanceNew(comp, &player->audioUnits[2]);
printf("err: %d\n", result);
result = AudioUnitInitialize(player->audioUnits[2]);
printf("err: %d\n", result);
}
result = AUGraphConnectNodeInput(player->graph,
player->sine,
0,
player->mixer,
0);
printf("err: %d\n", result);
result = AUGraphConnectNodeInput(player->graph,
player->mixer,
0,
player->output,
0);
printf("err: %d\n", result);
result = AUGraphOpen(player->graph);
printf("err: %d\n", result);
UInt32 numbuses = 1;
result = AudioUnitSetProperty(player->audioUnits[1], kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &numbuses, sizeof(numbuses));
printf("err: %d\n", result);
for (UInt32 i = 0; i <= numbuses; ++i) {
// setup render callback struct
AURenderCallbackStruct rcbs;
rcbs.inputProc = &SineWaveRenderCallback;
rcbs.inputProcRefCon = &player;
printf("set AUGraphSetNodeInputCallback\n");
// set a callback for the specified node's specified input
result = AUGraphSetNodeInputCallback(player->graph, player->mixer, i, &rcbs);
printf("AUGraphSetNodeInputCallback err: %d\n", result);
printf("set input bus %d, client kAudioUnitProperty_StreamFormat\n", (unsigned int)i);
// set the input stream format, this is the format of the audio for mixer input
result = AudioUnitSetProperty(player->audioUnits[1], kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, i, &ASBD, sizeof(ASBD));
printf("err: %d\n", result);
}
result = AudioUnitSetProperty(player->audioUnits[1], kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &ASBD, sizeof(ASBD));
printf("err: %d\n", result);
OSStatus status = AUGraphInitialize(player->graph);
printf("err: %d\n", status);
player->firstOutputSampleTime = -1;
AudioOutputUnitStart(player->audioUnits[0]);
AUGraphStart(player->graph);
printf("enter key to stop\n");
getchar();
return 0;
}
Related
I am trying to convert an CVPixelBuffer format from YUV('2vuy') to ARGB using Accelerate framework with the below code.
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
void* baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer);
size_t srcBufferWidth = CVPixelBufferGetWidth(pixelBuffer);
size_t srcBufferHeight = CVPixelBufferGetHeight(pixelBuffer);
size_t srcBufferBytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
vImage_Error err = kvImageNoError;
static vImage_YpCbCrToARGB outInfo;
static bool infoGenerated = false;
if (!infoGenerated) {
vImage_YpCbCrPixelRange pixelRange;
pixelRange.Yp_bias = 16;
pixelRange.CbCr_bias = 128;
pixelRange.YpRangeMax = 235;
pixelRange.CbCrRangeMax = 240;
pixelRange.YpMax = 255;
pixelRange.YpMin = 0;
pixelRange.CbCrMax = 255;
pixelRange.CbCrMin = 1;
const vImage_YpCbCrToARGBMatrix *matrixYpCbCrToARGB = kvImage_YpCbCrToARGBMatrix_ITU_R_709_2;
err = vImageConvert_YpCbCrToARGB_GenerateConversion(matrixYpCbCrToARGB, &pixelRange, &outInfo, kvImage422CbYpCrYp8, kvImageARGB8888, kvImageNoFlags);
if (err ==kvImageNoError) {
infoGenerated = true;
}
}
if (infoGenerated) {
const uint8_t permuteMap[4] = {0, 1, 2, 3};
vImage_Buffer srcBuffer = { (void *)baseAddress, srcBufferHeight, srcBufferWidth, srcBufferBytesPerRow};
void *destData = malloc(srcBufferWidth * srcBufferHeight * 4);
vImage_Buffer destBuffer = {
.data = destData,
.width = srcBufferWidth,
.height = srcBufferHeight,
.rowBytes = srcBufferWidth * 4
};
err = vImageConvert_422CbYpCrYp8ToARGB8888(&srcBuffer, &destBuffer, &outInfo, permuteMap, 0, kvImageNoFlags);
if (err!=kvImageNoError) {
NSLog(#"vImage_Error converting vImageConvert_422CbYpCrYp8ToARGB8888 errorcode:%ld",err);
}
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
}
The conversion is successful but the resulting destination buffer has a blue shade. I want it in the original colour. What Am I missing or doing wrong here?
Source buffer:
Destination Buffer:
I met some problem while learning Vulkan. I followed Vulkan Coockbook but I failed on executing vkGetPhysicalDeviceSurfaceCapabilitiesKHR(), it returned VK_ERROR_SURFACE_LOST_KHR. I have no idea what the wrong is with my code.
CyApplication::CyApplication(void) {
#ifdef _WIN32
VulkanLibrary = LoadLibrary(L"vulkan-1.dll");
#elif defined __linux
VulkanLibrary = dlopen("libvulkan.so.1", RTLD_NOW);
#endif
if (VulkanLibrary == nullptr) {
throw std::runtime_error("");
}
#ifdef _WIN32
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)GetProcAddress(VulkanLibrary, "vkGetInstanceProcAddr");
#elif defined __linux
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(VulkanLibrary, "vkGetInstanceProcAddr");
#endif
// Load global functions
vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceExtensionProperties");
vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceLayerProperties");
vkCreateInstance = (PFN_vkCreateInstance)vkGetInstanceProcAddr(nullptr, "vkCreateInstance");
// Create instance
desiredInstanceExtensions.emplace_back(VK_KHR_SURFACE_EXTENSION_NAME);
desiredInstanceExtensions.emplace_back(
#ifdef VK_USE_PLATFORM_WIN32_KHR
VK_KHR_WIN32_SURFACE_EXTENSION_NAME
#elif defined VK_USE_PLATFORM_XLIB_KHR
VK_KHR_XLIB_SURFACE_EXTENSION_NAME
#elif defined VK_USE_PLATFORM_XCB_KHR
VK_KHR_XCB_SURFACE_EXTENSION_NAME
#endif
);
applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
applicationInfo.pNext = nullptr;
applicationInfo.pApplicationName = "Cygine";
applicationInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
applicationInfo.pEngineName = "Cygine";
applicationInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
applicationInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0);
instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instanceCreateInfo.pNext = nullptr;
instanceCreateInfo.flags = 0;
instanceCreateInfo.pApplicationInfo = &applicationInfo;
instanceCreateInfo.enabledLayerCount = 0;
instanceCreateInfo.ppEnabledLayerNames = nullptr;
instanceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(desiredInstanceExtensions.size());
instanceCreateInfo.ppEnabledExtensionNames = desiredInstanceExtensions.data();
if (vkCreateInstance(&instanceCreateInfo, nullptr, &instance)) {
throw std::runtime_error("Failed to create the Vulkan instance.");
}
loadInstanceLevelFunctions();
// Create presentation surface
#ifdef VK_USE_PLATFORM_WIN32_KHR
wndParams.HInstance = GetModuleHandle(nullptr);
WNDCLASSEX window_class = {
sizeof(WNDCLASSEX), // UINT cbSize
// Win 3.x
CS_HREDRAW | CS_VREDRAW, // UINT style
WindowProcedure, // WNDPROC lpfnWndProc
0, // int cbClsExtra
0, // int cbWndExtra
wndParams.HInstance, // HINSTANCE hInstance
nullptr, // HICON hIcon
LoadCursor(nullptr, IDC_ARROW), // HCURSOR hCursor
(HBRUSH)(COLOR_WINDOW + 1), // HBRUSH hbrBackground
nullptr, // LPCSTR lpszMenuName
L"CygineWindow", // LPCSTR lpszClassName
// Win 4.0
nullptr // HICON hIconSm
};
if (!RegisterClassEx(&window_class)) {
throw std::runtime_error("WSL");
}
wndParams.Hwnd = CreateWindow(L"CyApplicationWindow",
L"CyApplication",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
(HWND)nullptr,
(HMENU)nullptr,
wndParams.HInstance,
(LPVOID)nullptr);
if (wndParams.Hwnd = nullptr) {
throw std::runtime_error("");
}
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
surfaceCreateInfo.pNext = nullptr;
surfaceCreateInfo.flags = 0;
surfaceCreateInfo.hinstance = wndParams.HInstance;
surfaceCreateInfo.hwnd = wndParams.Hwnd;
ShowWindow(wndParams.Hwnd, SW_SHOW);
VkResult result = vkCreateWin32SurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
if (result != VK_SUCCESS) {
exit(EXIT_FAILURE);
}
#elif defined VK_USE_PLATFORM_XLIB_KHR
wndParams.dpy = XOpenDisplay();
wndParams.window = XCreateWindow(nullptr);
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
surfaceCreateInfo.pNext = nullptr;
surfaceCreateInfo.flags = 0;
surfaceCreateInfo.hinstance = wndParams.dpy;
surfaceCreateInfo.hwnd = wndParams.window;
VkResult result = vkCreateXlibSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
if (result != VK_SUCCESS || surface == VK_NULL_HANDLE) {
exit(EXIT_FAILURE);
}
#elif defined VK_USE_PLATFORM_XCB_KHR
wndParams.connect = xcb_connect();
wndParams.window = xcb_generate_id(nullptr);
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
surfaceCreateInfo.pNext = nullptr;
surfaceCreateInfo.flags = 0;
surfaceCreateInfo.hinstance = wndParams.dpy;
surfaceCreateInfo.hwnd = wndParams.window;
VkResult result = vkCreateXcbSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
if (result != VK_SUCCESS || surface == VK_NULL_HANDLE) {
exit(EXIT_FAILURE);
}
#endif
// Select physical device
desiredPhysicalDeviceExtensions.emplace_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
getAvailablePhysicalDevices();
do {
fmt::print("Select a physical device that Cygine will run on: ");
std::cin >> selectedPhysicalDeviceID;
} while (selectedPhysicalDeviceID >= availablePhysicalDevicesCount);
physicalDevice = availablePhysicalDevices[selectedPhysicalDeviceID];
getAvailablePhysicalDeviceExtensions(physicalDevice);
// Create logical device
getPhysicalDeviceQueueFamilyProperties(availablePhysicalDevices[selectedPhysicalDeviceID]);
selectQueueFamily(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.pNext = nullptr;
queueCreateInfo.flags = 0;
queueCreateInfo.queueFamilyIndex = queueFamilyIndex;
queueCreateInfo.queueCount = 1;
float queuePriority = 1.0f;
queueCreateInfo.pQueuePriorities = &queuePriority;
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceCreateInfo.pNext = nullptr;
deviceCreateInfo.flags = 0;
deviceCreateInfo.queueCreateInfoCount = /*static_cast<uint32_t>(queueCreateInfos.size())*/ 1;
deviceCreateInfo.pQueueCreateInfos = /*queueCreateInfos.data()*/ &queueCreateInfo;
deviceCreateInfo.enabledLayerCount = 0;
deviceCreateInfo.ppEnabledLayerNames = nullptr;
deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(desiredPhysicalDeviceExtensions.size());
deviceCreateInfo.ppEnabledExtensionNames = desiredPhysicalDeviceExtensions.data();
deviceCreateInfo.pEnabledFeatures = &desiredDeviceFeatures;
if (vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device) != VK_SUCCESS) {
throw std::runtime_error("failed to create logical device!");
}
loadDeviceLevelFunctions();
// Create presentation surface
/*
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(640, 480, "Window Title", NULL, NULL);
if (glfwCreateWindowSurface(instance, window, nullptr, &surface))
throw std::runtime_error("failed to create");
*/
getSurfaceCapabilities();
fmt::print("Min Image Count: {}\n", surfaceCapabilities.minImageCount);
}
} // CygineApplicationAbstractions
Above is a part of my code. Have to say cooking Vulkan is really trivial ðŸ˜... Does any one have an idea? Hope you can solve my problem. Thanks!
if (wndParams.Hwnd = nullptr) {
You assign nullptr to Hwnd, so the surface is invalid when you query it.
I am working on an android project, which use vudroid, which in turn use mupdf version 0.5.
Vudroid remove the original openjpeg support of mupdf, I have ported the mupdf version 1.5's openjpeg support.
But I encounter a new problem, color information in jpx image gone, the desired effect:
my effect:
the ported load-jpx code:
#include "fitz.h"
#include "mupdf.h"
/* Without the definition of OPJ_STATIC, compilation fails on windows
* due to the use of __stdcall. We believe it is required on some
* linux toolchains too. */
#define OPJ_STATIC
#ifndef _MSC_VER
#define OPJ_HAVE_STDINT_H
#endif
#include <openjpeg.h>
static void fz_opj_error_callback(const char *msg, void *client_data)
{
//fz_context *ctx = (fz_context *)client_data;
//fz_warn(ctx, "openjpeg error: %s", msg);
}
static void fz_opj_warning_callback(const char *msg, void *client_data)
{
//fz_context *ctx = (fz_context *)client_data;
//fz_warn(ctx, "openjpeg warning: %s", msg);
}
static void fz_opj_info_callback(const char *msg, void *client_data)
{
/* fz_warn("openjpeg info: %s", msg); */
}
typedef struct stream_block_s
{
unsigned char *data;
int size;
int pos;
} stream_block;
static OPJ_SIZE_T fz_opj_stream_read(void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data)
{
stream_block *sb = (stream_block *)p_user_data;
int len;
len = sb->size - sb->pos;
if (len < 0)
len = 0;
if (len == 0)
return (OPJ_SIZE_T)-1; /* End of file! */
if ((OPJ_SIZE_T)len > p_nb_bytes)
len = p_nb_bytes;
memcpy(p_buffer, sb->data + sb->pos, len);
sb->pos += len;
return len;
}
static OPJ_OFF_T fz_opj_stream_skip(OPJ_OFF_T skip, void * p_user_data)
{
stream_block *sb = (stream_block *)p_user_data;
if (skip > sb->size - sb->pos)
skip = sb->size - sb->pos;
sb->pos += skip;
return sb->pos;
}
static OPJ_BOOL fz_opj_stream_seek(OPJ_OFF_T seek_pos, void * p_user_data)
{
stream_block *sb = (stream_block *)p_user_data;
if (seek_pos > sb->size)
return OPJ_FALSE;
sb->pos = seek_pos;
return OPJ_TRUE;
}
fz_error
fz_load_jpx(pdf_image* img, unsigned char *data, int size, fz_colorspace *defcs, int indexed)
{
//fz_pixmap *img;
opj_dparameters_t params;
opj_codec_t *codec;
opj_image_t *jpx;
opj_stream_t *stream;
fz_colorspace *colorspace;
unsigned char *p;
OPJ_CODEC_FORMAT format;
int a, n, w, h, depth, sgnd;
int x, y, k, v;
stream_block sb;
if (size < 2)
fz_throw("not enough data to determine image format");
/* Check for SOC marker -- if found we have a bare J2K stream */
if (data[0] == 0xFF && data[1] == 0x4F)
format = OPJ_CODEC_J2K;
else
format = OPJ_CODEC_JP2;
opj_set_default_decoder_parameters(¶ms);
if (indexed)
params.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG;
codec = opj_create_decompress(format);
opj_set_info_handler(codec, fz_opj_info_callback, 0);
opj_set_warning_handler(codec, fz_opj_warning_callback, 0);
opj_set_error_handler(codec, fz_opj_error_callback, 0);
if (!opj_setup_decoder(codec, ¶ms))
{
fz_throw("j2k decode failed");
}
stream = opj_stream_default_create(OPJ_TRUE);
sb.data = data;
sb.pos = 0;
sb.size = size;
opj_stream_set_read_function(stream, fz_opj_stream_read);
opj_stream_set_skip_function(stream, fz_opj_stream_skip);
opj_stream_set_seek_function(stream, fz_opj_stream_seek);
opj_stream_set_user_data(stream, &sb);
/* Set the length to avoid an assert */
opj_stream_set_user_data_length(stream, size);
if (!opj_read_header(stream, codec, &jpx))
{
opj_stream_destroy(stream);
opj_destroy_codec(codec);
fz_throw("Failed to read JPX header");
}
if (!opj_decode(codec, stream, jpx))
{
opj_stream_destroy(stream);
opj_destroy_codec(codec);
opj_image_destroy(jpx);
fz_throw("Failed to decode JPX image");
}
opj_stream_destroy(stream);
opj_destroy_codec(codec);
/* jpx should never be NULL here, but check anyway */
if (!jpx)
fz_throw("opj_decode failed");
pdf_logimage("opj_decode succeeded");
for (k = 1; k < (int)jpx->numcomps; k++)
{
if (!jpx->comps[k].data)
{
opj_image_destroy(jpx);
fz_throw("image components are missing data");
}
if (jpx->comps[k].w != jpx->comps[0].w)
{
opj_image_destroy(jpx);
fz_throw("image components have different width");
}
if (jpx->comps[k].h != jpx->comps[0].h)
{
opj_image_destroy(jpx);
fz_throw("image components have different height");
}
if (jpx->comps[k].prec != jpx->comps[0].prec)
{
opj_image_destroy(jpx);
fz_throw("image components have different precision");
}
}
n = jpx->numcomps;
w = jpx->comps[0].w;
h = jpx->comps[0].h;
depth = jpx->comps[0].prec;
sgnd = jpx->comps[0].sgnd;
if (jpx->color_space == OPJ_CLRSPC_SRGB && n == 4) { n = 3; a = 1; }
else if (jpx->color_space == OPJ_CLRSPC_SYCC && n == 4) { n = 3; a = 1; }
else if (n == 2) { n = 1; a = 1; }
else if (n > 4) { n = 4; a = 1; }
else { a = 0; }
if (defcs)
{
if (defcs->n == n)
{
colorspace = defcs;
}
else
{
fz_warn("jpx file and dict colorspaces do not match");
defcs = NULL;
}
}
if (!defcs)
{
switch (n)
{
case 1: colorspace = pdf_devicegray; break;
case 3: colorspace = pdf_devicergb; break;
case 4: colorspace = pdf_devicecmyk; break;
}
}
//error = fz_new_pixmap(&img, colorspace, w, h);
//if (error)
// return error;
pdf_logimage("colorspace handled\n");
int bpc = 1;
if (colorspace) {
bpc = 1 + colorspace->n;
};
pdf_logimage("w = %d, bpc = %d, h = %d\n", w, bpc, h);
img->samples = fz_newbuffer(w * bpc * h);
//opj_image_destroy(jpx);
//fz_throw("out of memory loading jpx");
p = (char*)img->samples->bp;
pdf_logimage("start to deal with samples");
for (y = 0; y < h; y++)
{
for (x = 0; x < w; x++)
{
for (k = 0; k < n + a; k++)
{
v = jpx->comps[k].data[y * w + x];
if (sgnd)
v = v + (1 << (depth - 1));
if (depth > 8)
v = v >> (depth - 8);
*p++ = v;
}
if (!a)
*p++ = 255;
}
}
img->samples->wp = p;
pdf_logimage("start to deal with samples succeeded");
opj_image_destroy(jpx);
// if (a)
// {
// if (n == 4)
// {
// fz_pixmap *tmp = fz_new_pixmap(ctx, fz_device_rgb(ctx), w, h);
// fz_convert_pixmap(ctx, tmp, img);
// fz_drop_pixmap(ctx, img);
// img = tmp;
// }
// fz_premultiply_pixmap(ctx, img);
// }
return fz_okay;
}
The render code:
JNIEXPORT jbyteArray JNICALL Java_org_vudroid_pdfdroid_codec_PdfPage_drawPage
(JNIEnv *env, jclass clazz, jlong dochandle, jlong pagehandle)
{
renderdocument_t *doc = (renderdocument_t*) dochandle;
renderpage_t *page = (renderpage_t*) pagehandle;
//DEBUG("PdfView(%p).drawpage(%p, %p)", this, doc, page);
fz_error error;
fz_matrix ctm;
fz_irect viewbox;
fz_pixmap *pixmap;
jfloat *matrix;
jint *viewboxarr;
jint *dimen;
jint *buffer;
int length, val;
pixmap = nil;
/* initialize parameter arrays for MuPDF */
ctm.a = 1;
ctm.b = 0;
ctm.c = 0;
ctm.d = 1;
ctm.e = 0;
ctm.f = 0;
// matrix = (*env)->GetPrimitiveArrayCritical(env, matrixarray, 0);
// ctm.a = matrix[0];
// ctm.b = matrix[1];
// ctm.c = matrix[2];
// ctm.d = matrix[3];
// ctm.e = matrix[4];
// ctm.f = matrix[5];
// (*env)->ReleasePrimitiveArrayCritical(env, matrixarray, matrix, 0);
// DEBUG("Matrix: %f %f %f %f %f %f",
// ctm.a, ctm.b, ctm.c, ctm.d, ctm.e, ctm.f);
// viewboxarr = (*env)->GetPrimitiveArrayCritical(env, viewboxarray, 0);
// viewbox.x0 = viewboxarr[0];
// viewbox.y0 = viewboxarr[1];
// viewbox.x1 = viewboxarr[2];
// viewbox.y1 = viewboxarr[3];
// (*env)->ReleasePrimitiveArrayCritical(env, viewboxarray, viewboxarr, 0);
// DEBUG("Viewbox: %d %d %d %d",
// viewbox.x0, viewbox.y0, viewbox.x1, viewbox.y1);
viewbox.x0 = 0;
viewbox.y0 = 0;
viewbox.x1 = 595;
viewbox.y1 = 841;
/* do the rendering */
DEBUG("doing the rendering...");
//buffer = (*env)->GetPrimitiveArrayCritical(env, bufferarray, 0);
// do the actual rendering:
error = fz_rendertree(&pixmap, doc->rast, page->page->tree,
ctm, viewbox, 1);
/* evil magic: we transform the rendered image's byte order
*/
int x, y;
if (bmpdata)
fz_free(bmpdata);
bmpstride = ((pixmap->w * 3 + 3) / 4) * 4;
bmpdata = fz_malloc(pixmap->h * bmpstride);
DEBUG("inside drawpage, bmpstride = %d, pixmap->w = %d, pixmap->h = %d\n", bmpstride, pixmap->w, pixmap->h);
if (!bmpdata)
return;
for (y = 0; y < pixmap->h; y++)
{
unsigned char *p = bmpdata + y * bmpstride;
unsigned char *s = pixmap->samples + y * pixmap->w * 4;
for (x = 0; x < pixmap->w; x++)
{
p[x * 3 + 0] = s[x * 4 + 3];
p[x * 3 + 1] = s[x * 4 + 2];
p[x * 3 + 2] = s[x * 4 + 1];
}
}
FILE* fp = fopen("/sdcard/drawpage", "wb");
fwrite(bmpdata, pixmap->h * bmpstride, 1, fp);
fclose(fp);
jbyteArray array = (*env)->NewByteArray(env, pixmap->h * bmpstride);
(*env)->SetByteArrayRegion(env, array, 0, pixmap->h * bmpstride, bmpdata);
// if(!error) {
// DEBUG("Converting image buffer pixel order");
// length = pixmap->w * pixmap->h;
// unsigned int *col = pixmap->samples;
// int c = 0;
// for(val = 0; val < length; val++) {
// col[val] = ((col[val] & 0xFF000000) >> 24) |
// ((col[val] & 0x00FF0000) >> 8) |
// ((col[val] & 0x0000FF00) << 8);
// }
// winconvert(pixmap);
// }
// (*env)->ReleasePrimitiveArrayCritical(env, bufferarray, buffer, 0);
fz_free(pixmap);
if (error) {
DEBUG("error!");
throw_exception(env, "error rendering page");
}
DEBUG("PdfView.drawPage() done");
return array;
}
I have compare the jpx output samples to the mupdf-1.5 windows, it is the same, but the colorspace of original jpx have gone.
Could help me to get the colorspace back?
It seems you are trying to use an old version of MuPDF with some bits pulled in from a more recent version. TO be honest that's hardly likely to work. I would also guess that its not the OpenJPEG library causing your problem, since the image appears, but converted to grayscale.
Have you tried opening the file in the current version of MuPDF ? Does it work ?
If so then it seems to me your correct approach should be to use the current code, not try and bolt pieces onto an older version.
I get a triangle demo from internet. It works on my ubuntu13.04 virtual machine,but it doesn't work on my ubuntu12.04 virtual machine.All of my two vritual machines installed libgles2-mesa-dev(apt-get).The only diffrenet is:the ubuntu12.04 glesv2 is based on mesa-8.0 and the ubuntu13.04 glesv2 is based on mesa-9.
My code:
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <unistd.h>
#include <X11/Xlib.h>
#define VERTEX_ARRAY 0
EGLDisplay eglDisplay = 0;
EGLConfig eglConfig = 0;
EGLSurface eglSurface = 0;
EGLContext eglContext = 0;
EGLNativeWindowType eglWindow = 0;
bool TestEGLError()
{
EGLint iErr = eglGetError();
if (iErr != EGL_SUCCESS)
{
return false;
}
return true;
}
bool CreateEGLContext()
{
eglDisplay = eglGetDisplay((EGLNativeDisplayType) EGL_DEFAULT_DISPLAY);
EGLint iMajorVersion, iMinorVersion;
if (!eglInitialize(eglDisplay, &iMajorVersion, &iMinorVersion))
{
return false;
}
const EGLint pi32ConfigAttribs[] =
{
EGL_LEVEL, 0,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NATIVE_RENDERABLE, EGL_FALSE,
EGL_DEPTH_SIZE, EGL_DONT_CARE,
EGL_NONE
};
EGLint config16bpp[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 16,
EGL_STENCIL_SIZE, 0,
EGL_NONE
};
int iConfigs;
if (!eglChooseConfig(eglDisplay,config16bpp, &eglConfig, 1, &iConfigs) || (iConfigs != 1))
{
return false;
}
eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, eglWindow, NULL);
if(eglSurface == EGL_NO_SURFACE)
{
eglGetError(); // Clear error
eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, NULL, NULL);
}
if (!TestEGLError())
{
return false;
}
eglBindAPI(EGL_OPENGL_ES_API);
EGLint ai32ContextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, ai32ContextAttribs);
if (!TestEGLError())
{
return false;
}
eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
if (!TestEGLError())
{
return false;
}
return true;
}
bool Render()
{
bool bRet = false;
float pfIdentity[] =
{
1.0f,0.0f,0.0f,0.0f,
0.0f,1.0f,0.0f,0.0f,
0.0f,0.0f,1.0f,0.0f,
0.0f,0.0f,0.0f,1.0f
};
char szFragShaderSrc[] = {"\
void main (void)\
{\
gl_FragColor = vec4(1.0, 1.0, 0.66 ,1.0);\
}"};
char szVertShaderSrc[] = {"\
attribute highp vec4 myVertex;\
uniform mediump mat4 myPMVMatrix;\
void main(void)\
{\
gl_Position = myPMVMatrix * myVertex;\
}"};
char * pszFragShader = (char *)szFragShaderSrc;
char * pszVertShader = (char *)szVertShaderSrc;
GLuint uiFragShader = 0;
GLuint uiVertShader = 0;
GLuint uiProgramObject = 0;
GLint bShaderCompiled;
GLint bLinked;
GLuint ui32Vbo = 0;
GLfloat afVertices[] = { -0.4f,-0.4f,0.0f, // Position
0.4f ,-0.4f,0.0f,
0.0f ,0.4f ,0.0f};
int i32InfoLogLength, i32CharsWritten;
char* pszInfoLog = NULL;
int i32Location = 0;
unsigned int uiSize = 0;
uiFragShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(uiFragShader, 1, (const char**)&pszFragShader, NULL);
glCompileShader(uiFragShader);
glGetShaderiv(uiFragShader, GL_COMPILE_STATUS, &bShaderCompiled);
if (!bShaderCompiled)
{
glGetShaderiv(uiFragShader, GL_INFO_LOG_LENGTH, &i32InfoLogLength);
pszInfoLog = new char[i32InfoLogLength];
glGetShaderInfoLog(uiFragShader, i32InfoLogLength, &i32CharsWritten, pszInfoLog);
delete[] pszInfoLog;
goto cleanup;
}
uiVertShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(uiVertShader, 1, (const char**)&pszVertShader, NULL);
glCompileShader(uiVertShader);
glGetShaderiv(uiVertShader, GL_COMPILE_STATUS, &bShaderCompiled);
if (!bShaderCompiled)
{
glGetShaderiv(uiVertShader, GL_INFO_LOG_LENGTH, &i32InfoLogLength);
pszInfoLog = new char[i32InfoLogLength];
glGetShaderInfoLog(uiVertShader, i32InfoLogLength, &i32CharsWritten, pszInfoLog);
delete[] pszInfoLog;
goto cleanup;
}
uiProgramObject = glCreateProgram();
glAttachShader(uiProgramObject, uiFragShader);
glAttachShader(uiProgramObject, uiVertShader);
glBindAttribLocation(uiProgramObject, VERTEX_ARRAY, "myVertex");
glLinkProgram(uiProgramObject);
glGetProgramiv(uiProgramObject, GL_LINK_STATUS, &bLinked);
if (!bLinked)
{
glGetProgramiv(uiProgramObject, GL_INFO_LOG_LENGTH, &i32InfoLogLength);
pszInfoLog = new char[i32InfoLogLength];
glGetProgramInfoLog(uiProgramObject, i32InfoLogLength, &i32CharsWritten, pszInfoLog);
delete[] pszInfoLog;
goto cleanup;
}
glUseProgram(uiProgramObject);
glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
glGenBuffers(1, &ui32Vbo);
glBindBuffer(GL_ARRAY_BUFFER, ui32Vbo);
uiSize = 3 * (sizeof(GLfloat) * 3); // Calc afVertices size (3 vertices * stride (3 GLfloats per vertex))
glBufferData(GL_ARRAY_BUFFER, uiSize, afVertices, GL_STATIC_DRAW);
{
glClear(GL_COLOR_BUFFER_BIT);
i32Location = glGetUniformLocation(uiProgramObject, "myPMVMatrix");
glUniformMatrix4fv( i32Location, 1, GL_FALSE, pfIdentity);
glEnableVertexAttribArray(VERTEX_ARRAY);
glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
eglSwapBuffers(eglDisplay, eglSurface);
}
bRet = true;
cleanup:
if (uiProgramObject)
glDeleteProgram(uiProgramObject);
if (uiFragShader)
glDeleteShader(uiFragShader);
if (uiVertShader)
glDeleteShader(uiVertShader);
// Delete the VBO as it is no longer needed
if (ui32Vbo)
glDeleteBuffers(1, &ui32Vbo);
return bRet;
}
int main(int argc ,char* argv[])
{
unsigned int uiHeight = 800;
unsigned int uiWidth = 480;
int screen;
Display *x_display;
Window root_window;
x_display = XOpenDisplay ( NULL ); // open the standard display (the primary screen)
if ( x_display == NULL ) {
printf ("cannot connect to X server");
return false;
}
screen = DefaultScreen(x_display);
root_window = RootWindow(x_display,screen);
static int Hnd = XCreateSimpleWindow(x_display, root_window,0,0,800,480,0,0,0);
eglWindow = (EGLNativeWindowType)Hnd;
if (!eglWindow)
{
printf("Failed to create X window.\n");
return false;
}
XUndefineCursor(x_display, eglWindow);
XMapRaised(x_display, eglWindow);
XFlush(x_display);
CreateEGLContext();
while(1)
{
Render();
usleep(100000);
}
return 0;
}
I am recording sound from mic input using Audio queue service.
-(void)startRecording{
[self setupAudioFormat:&recordState.dataFormat];
recordState.currentPacket = 0;
OSStatus status;
status = AudioQueueNewInput(&recordState.dataFormat,
AudioInputCallback,
&recordState,
CFRunLoopGetCurrent(),
kCFRunLoopCommonModes,
0,
&recordState.queue);
if (status == 0)
{
// Prime recording buffers with empty data
for (int i = 0; i < NUM_BUFFERS; i++)
{
NSLog(#"buf in");
AudioQueueAllocateBuffer(recordState.queue, 16000, &recordState.buffers[i]);
AudioQueueEnqueueBuffer (recordState.queue, recordState.buffers[i], 0, NULL);
}
status = AudioFileCreateWithURL(fileURL,
kAudioFileAIFFType,
&recordState.dataFormat,
kAudioFileFlags_EraseFile,
&recordState.audioFile);
if (status == 0)
{
recordState.recording = true;
status = AudioQueueStart(recordState.queue, NULL);
if (status == 0)
{
NSLog(#"Recording");
}
}
}
if (status != 0)
{
//[self stopRecording];
NSLog(#"recording failed");
}
}
on callback:
void AudioInputCallback(void * inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp * inStartTime,
UInt32 inNumberPacketDescriptions,
const AudioStreamPacketDescription * inPacketDescs)
{
RecordState * recordState = (RecordState*)inUserData;
if (!recordState->recording)
{
printf("Not recording, returning\n");
}
// if (inNumberPacketDescriptions == 0 && recordState->dataFormat.mBytesPerPacket != 0)
// {
// inNumberPacketDescriptions = inBuffer->mAudioDataByteSize / recordState->dataFormat.mBytesPerPacket;
// }
/*
int sampleCount = recordState->buffers[0]->mAudioDataBytesCapacity / sizeof (AUDIO_DATA_TYPE_FORMAT);
NSLog(#"sample count = %i",sampleCount);
AUDIO_DATA_TYPE_FORMAT *p = (AUDIO_DATA_TYPE_FORMAT*)recordState->buffers[0]->mAudioData;
for (int i = 0; i < sampleCount; i++) {
if (p[i] > 1000) {
NSLog(#"%hd",p[i]);
}
}*/
printf("Writing buffer %lld\n", recordState->currentPacket);
OSStatus status = AudioFileWritePackets(recordState->audioFile,
false,
inBuffer->mAudioDataByteSize,
inPacketDescs,
recordState->currentPacket,
&inNumberPacketDescriptions,
inBuffer->mAudioData);
if (status == 0)
{
recordState->buffers[0] = nil;
recordState->currentPacket += inNumberPacketDescriptions;
}
AudioQueueEnqueueBuffer(recordState->queue, inBuffer, 0, NULL);
}
Here i want to read recorded buffer. is it possible to get something like this:
short[] buffer = ?;//here should an audio buffer converted to some structure (short[] just for example)
then i would like to read every element of this structure:
for (int i = 0; i < sizeOfBuffer; i++) {
bufferVal = buffer[i];
}
In short how to handle buffer when recording ?
Thanks.