1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: camera.cpp
4
5 Copyright (C)2009-2012 Nintendo Co., Ltd. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Rev: 46365 $
14 *---------------------------------------------------------------------------*/
15
16 #include <nn/os.h>
17 #include <nn/camera.h>
18 #include <nn/y2r.h>
19 #include "camera.h"
20 #include <string.h>
21
22 // The buffer to receive the camera capture data must be 4-byte aligned.
23 // However, when it is aligned to less than 64-bytes, the transfer speed may drop.
24 u8 s_YuvBuffer[2][CAMERA_IMG_WIDTH * CAMERA_IMG_HEIGHT * Y2R_YUV_BYTES] NN_ATTRIBUTE_ALIGN(64);
25 // Buffer to save camera data
26 // Allocated from device memory
27 u8* s_RgbBuffer;
28
29
TransferThreadFunc(CameraDemo * pCameraDemo)30 void TransferThreadFunc(CameraDemo* pCameraDemo)
31 {
32 pCameraDemo->TransferThreadFuncImpl();
33 }
34
TransferThreadFuncImpl(void)35 void CameraDemo::TransferThreadFuncImpl(void)
36 {
37 nn::os::Event *events[EVENT_CAMERA_NUM] = {&m_TransferEvent, &m_ErrorEvent, &m_EndEvent};
38
39 // Configure the transfer
40 nn::camera::CTR::SetReceiving(events[EVENT_CAMERA_TRANSFER], reinterpret_cast<void*>(s_YuvBuffer[0]), nn::camera::PORT_CAM1, m_CameraOutputSize, m_TransferUnit);
41
42 u32 yuvWp = 0;
43
44 while(1)
45 {
46 s32 num = nn::os::WaitObject::WaitAny(reinterpret_cast<nn::os::WaitObject**>(events), EVENT_CAMERA_NUM);
47
48 if(num == EVENT_CAMERA_ERROR)
49 {
50 // Error occurred
51 NN_LOG("camera: An error or reboot occurred\n");
52 // Restart capture
53 nn::camera::CTR::SetReceiving(events[EVENT_CAMERA_TRANSFER], reinterpret_cast<void*>(s_YuvBuffer[yuvWp]), nn::camera::PORT_CAM1, m_CameraOutputSize, m_TransferUnit);
54
55 nn::camera::CTR::StartCapture(nn::camera::PORT_CAM1);
56 }
57 else if(num == EVENT_CAMERA_TRANSFER)
58 {
59 // Transfer completed
60 yuvWp ^= 1;
61 nn::camera::CTR::SetReceiving(events[EVENT_CAMERA_TRANSFER], reinterpret_cast<void*>(s_YuvBuffer[yuvWp]), nn::camera::PORT_CAM1, m_CameraOutputSize, m_TransferUnit);
62
63 // This demo does not support stopping Y2R before sleep, but since it only displays the previous results regardless of the success or failure of the conversion, there is no problem that would cause stopping
64 nn::y2r::CTR::StopConversion();
65 while(nn::y2r::CTR::IsBusyConversion()) // Wait because configuration cannot be done during Enable
66 {
67 }
68
69 // Convert received YUV data with YUVtoRGB.
70 u32 preYuvWp = yuvWp ^ 1;
71 nn::y2r::CTR::SetSendingYuv(reinterpret_cast<void*>(s_YuvBuffer[preYuvWp]), m_CameraOutputSize, CAMERA_IMG_WIDTH*Y2R_YUV_BYTES);
72 nn::y2r::CTR::SetReceiving(reinterpret_cast<void*>(s_RgbBuffer), m_Y2rOutputSize, CAMERA_IMG_WIDTH*8*Y2R_RGB_BYTES);
73
74 // An error is returned during sleep, but since this demo only outputs a converted image, there is no need to handle it
75 nn::y2r::CTR::StartConversion();
76 }
77 else if(num == EVENT_CAMERA_END)
78 {
79 // Exit camera
80 break;
81 }
82 }
83
84 // Transfer ends
85 }
86
CheckCameraResult(nn::Result result)87 bool CameraDemo::CheckCameraResult( nn::Result result )
88 {
89 if(result == nn::camera::CTR::ResultIsSleeping())
90 {
91 // If the system is closed, retry is required
92 return false;
93 }
94 if(result == nn::camera::CTR::ResultFatalError())
95 {
96 // Each application handles fatal errors as necessary
97 NN_LOG("The camera is broken.\n");
98 }
99 return true;
100 }
101
CameraInitialize()102 void CameraDemo::CameraInitialize()
103 {
104 // Initialize CAMERA
105 nn::Result result = nn::camera::Initialize();
106 if(!CheckCameraResult(result))
107 {
108 return;
109 }
110 if ( result == nn::camera::CTR::ResultUsingOtherProcess() )
111 {
112 // This error usually should not occur
113 // Bug where an applet in the background transitions to the application without exiting the camera
114 NN_UTIL_PANIC_IF_FAILED(result);
115 }
116
117 // Puts into a state where the camera library initialization completes
118 m_InitializeState = CAMERA_STATE_INITIALIZED;
119 }
120
CameraSetting()121 void CameraDemo::CameraSetting()
122 {
123 // Camera configuration
124
125 // Specify the number of lines to be accumulated in the buffer
126 s16 transferLine = nn::camera::GetMaxLines( CAMERA_IMG_WIDTH, CAMERA_IMG_HEIGHT );
127 if(CAMERA_IMG_WIDTH < 16) // Because the GetMaxLines function gets the maximum number of lines, the original number of lines may be less than that.
128 {
129 transferLine = CAMERA_IMG_HEIGHT;
130 }
131 nn::camera::SetTransferLines( nn::camera::PORT_CAM1, transferLine, CAMERA_IMG_WIDTH, CAMERA_IMG_HEIGHT );
132
133 // Change the frame rate
134 nn::Result result = nn::camera::SetFrameRate(CAMERA_SELECT, CAMERA_FRAME_RATE);
135 if(!CheckCameraResult(result))
136 {
137 return;
138 }
139
140 // Change image size
141 result = nn::camera::SetSize(CAMERA_SELECT, CAMERA_SIZE, nn::camera::CONTEXT_A);
142 if(!CheckCameraResult(result))
143 {
144 return;
145 }
146
147 // Put camera in startup state
148 result = nn::camera::Activate(CAMERA_SELECT);
149 if(!CheckCameraResult(result))
150 {
151 return;
152 }
153
154 // Set trimming
155 nn::camera::SetTrimming(nn::camera::PORT_CAM1, true);
156 nn::camera::SetTrimmingParamsCenter(nn::camera::PORT_CAM1, CAMERA_IMG_WIDTH, CAMERA_IMG_HEIGHT, CAMERA_WIDTH, CAMERA_HEIGHT);
157
158 // Set the conversion coefficients
159 nn::y2r::CTR::StandardCoefficient no;
160 result = nn::camera::CTR::GetSuitableY2rStandardCoefficient(&no);
161 if(!CheckCameraResult(result))
162 {
163 return;
164 }
165 nn::y2r::CTR::SetStandardCoefficient( no );
166
167 // Calculate number of loops from the size of the image to transfer
168 m_TransferUnit = nn::camera::GetTransferBytes(nn::camera::PORT_CAM1);
169
170 m_CameraOutputSize = nn::camera::GetFrameBytes(CAMERA_IMG_WIDTH, CAMERA_IMG_HEIGHT);
171 m_Y2rOutputSize = nn::y2r::GetOutputImageSize(CAMERA_IMG_WIDTH, CAMERA_IMG_HEIGHT, Y2R_OUTPUT_FORMAT);
172
173 // Get camera interrupt handle
174 nn::camera::GetBufferErrorInterruptEvent(&m_ErrorEvent, nn::camera::PORT_CAM1);
175
176 m_InitializeState = CAMERA_STATE_SET;
177
178 // Create thread for camera error/data transfer processing
179 m_TransferThread.StartUsingAutoStack(
180 TransferThreadFunc,
181 this,
182 4096,
183 nn::os::DEFAULT_THREAD_PRIORITY - 1); // It has a higher priority than the main thread
184 }
185
Initialize(demo::RenderSystemDrawing * p_RenderSystem,nn::fnd::ExpHeap * p_AppHeap)186 void CameraDemo::Initialize(demo::RenderSystemDrawing* p_RenderSystem, nn::fnd::ExpHeap* p_AppHeap)
187 {
188 Device::Initialize(p_RenderSystem);
189
190 mp_AppHeap = p_AppHeap;
191 s_RgbBuffer = reinterpret_cast<u8*>(mp_AppHeap->Allocate(CAMERA_IMG_WIDTH * CAMERA_IMG_HEIGHT * Y2R_RGB_BYTES, 64));
192
193 // Initialize CAMERA
194 CameraInitialize();
195
196 // Initialize Y2R
197 nn::y2r::Initialize();
198
199 // Set Y2R
200
201 // Forcibly stop any conversion that is in progress
202 nn::y2r::StopConversion();
203 while(nn::y2r::IsBusyConversion()) // Wait because configuration cannot be done during Enable
204 {
205 }
206 // Change input format
207 nn::y2r::SetInputFormat(Y2R_INPUT_FORMAT);
208
209 // Change output format
210 nn::y2r::SetOutputFormat(Y2R_OUTPUT_FORMAT);
211
212 // Change angle of rotation for output data
213 nn::y2r::SetRotation(Y2R_ROTATION);
214
215 // Change order of output data
216 nn::y2r::SetBlockAlignment(Y2R_BLOCK_ALIGNMENT);
217
218 // Specify input data size
219 nn::y2r::SetInputLineWidth(CAMERA_IMG_WIDTH);
220 nn::y2r::SetInputLines(CAMERA_IMG_HEIGHT);
221
222 // Set alpha value (not used for this demo)
223 nn::y2r::SetAlpha(0xFF);
224
225 // Set CAMERA if already initialized
226 if ( m_InitializeState == CAMERA_STATE_INITIALIZED )
227 {
228 CameraSetting();
229 }
230 }
231
Finalize()232 void CameraDemo::Finalize()
233 {
234 // End transfer processing thread
235 m_EndEvent.Signal();
236 m_TransferThread.Join();
237 m_TransferThread.Finalize();
238
239 nn::y2r::Finalize();
240 nn::camera::Finalize();
241
242 // Free RGB buffer
243 mp_AppHeap->Free(s_RgbBuffer);
244
245 Device::Finalize();
246 }
247
CameraInitialSequence()248 void CameraDemo::CameraInitialSequence()
249 {
250 if ( m_InitializeState == CAMERA_STATE_NONE )
251 {
252 CameraInitialize();
253 }
254 if ( m_InitializeState == CAMERA_STATE_INITIALIZED )
255 {
256 CameraSetting();
257 }
258 if ( m_InitializeState == CAMERA_STATE_SET )
259 {
260 // Start camera capture
261 nn::camera::ClearBuffer(nn::camera::PORT_CAM1);
262 nn::camera::StartCapture(nn::camera::PORT_CAM1);
263 m_InitializeState = CAMERA_STATE_STARTED;
264 }
265 }
266
Start()267 void CameraDemo::Start()
268 {
269 Device::Start();
270
271 // Try again if Initialize failed because the system was closed
272 CameraInitialSequence();
273 }
274
End()275 void CameraDemo::End()
276 {
277 Device::End();
278 }
279
DrawFrame(void)280 void CameraDemo::DrawFrame(void)
281 {
282 // Try again if Initialize failed because the system was closed
283 CameraInitialSequence();
284
285 static GLuint textureId = 0;
286
287 if( textureId != 0 )
288 {
289 mp_RenderSystem->DeleteTexture(textureId);
290 }
291
292 GLenum target = GL_TEXTURE_2D | NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP;
293 GLenum internalFormat = GL_IMG_FORMAT;
294 GLenum format = GL_IMG_FORMAT;
295 GLenum type = GL_IMG_TYPE;
296 u32 textureWidth = CAMERA_IMG_WIDTH;
297 u32 textureHeight = CAMERA_IMG_HEIGHT;
298 mp_RenderSystem->GenerateTexture(target,
299 internalFormat,
300 textureWidth, textureHeight,
301 format, type, s_RgbBuffer,
302 textureId);
303
304 mp_RenderSystem->SetColor(0.0f, 0.0f, 1.0f, 0.0f);
305
306 f32 windowPositionX = 0.0f;
307 f32 windowPositionY = 0.0f;
308 f32 rectangleWidth = CAMERA_IMG_WIDTH;
309 f32 rectangleHeight = CAMERA_IMG_HEIGHT;
310 mp_RenderSystem->FillTexturedRectangle(textureId,
311 windowPositionX, windowPositionY,
312 rectangleWidth, rectangleHeight,
313 CAMERA_IMG_WIDTH, CAMERA_IMG_HEIGHT,
314 textureWidth, textureHeight);
315 }
316
317 /*---------------------------------------------------------------------------*
318 End of file
319 *---------------------------------------------------------------------------*/
320