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