2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>
\r
4 * This file is part of CasparCG.
\r
6 * CasparCG is free software: you can redistribute it and/or modify
\r
7 * it under the terms of the GNU General Public License as published by
\r
8 * the Free Software Foundation, either version 3 of the License, or
\r
9 * (at your option) any later version.
\r
11 * CasparCG is distributed in the hope that it will be useful,
\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 * GNU General Public License for more details.
\r
16 * You should have received a copy of the GNU General Public License
\r
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
\r
21 #include "..\..\stdafx.h"
\r
23 #include "TargaManager.h"
\r
24 #include "..\..\frame\FrameManager.h"
\r
25 #include "..\..\frame\FrameMediaController.h"
\r
26 #include "..\..\utils\FileInputStream.h"
\r
27 #include "..\..\fileinfo.h"
\r
28 #include "..\..\frame\buffers\StaticFrameBuffer.h"
\r
32 using namespace caspar::utils;
\r
34 ///////////////////////////////
\r
35 // TargaProducer declaration
\r
37 class TargaProducer : public MediaProducer, public FrameMediaController
\r
40 explicit TargaProducer(PixmapDataPtr pImage);
\r
41 virtual ~TargaProducer();
\r
43 virtual IMediaController* QueryController(const tstring& id);
\r
45 virtual bool Initialize(FrameManagerPtr pFrameManager);
\r
46 virtual FrameBuffer& GetFrameBuffer() {
\r
47 return frameBuffer_;
\r
51 StaticFrameBuffer frameBuffer_;
\r
52 caspar::utils::PixmapDataPtr pImage_;
\r
55 //////////////////////////////
\r
56 // TargaManager definition
\r
58 TargaManager::TargaManager()
\r
60 _extensions.push_back(TEXT("tga"));
\r
63 TargaManager::~TargaManager()
\r
66 MediaProducerPtr TargaManager::CreateProducer(const tstring& filename) {
\r
67 MediaProducerPtr result;
\r
68 if(filename.length() > 0) {
\r
69 utils::InputStreamPtr pTgaFile(new utils::FileInputStream(filename));
\r
70 if(pTgaFile->Open()) {
\r
71 PixmapDataPtr pImage;
\r
72 if(TargaManager::Load(pTgaFile, pImage)) {
\r
73 result = MediaProducerPtr(new TargaProducer(pImage));
\r
80 bool TargaManager::getFileInfo(FileInfo* pFileInfo)
\r
82 if(pFileInfo != 0) {
\r
83 pFileInfo->length = 1;
\r
84 pFileInfo->type = TEXT("still");
\r
85 pFileInfo->encoding = TEXT("TGA");
\r
91 PixmapDataPtr TargaManager::CropPadToFrameFormat(PixmapDataPtr pSource, const FrameFormatDescription& fmtDesc)
\r
93 if(pSource->width == fmtDesc.width && pSource->height == fmtDesc.height)
\r
96 unsigned short colsToCopy = pSource->width;
\r
97 unsigned short rowsToCopy = pSource->height;
\r
100 if(pSource->width > fmtDesc.width)
\r
102 offsetX = (pSource->width-fmtDesc.width)/2;
\r
103 colsToCopy = fmtDesc.width;
\r
107 if(pSource->height > fmtDesc.height)
\r
109 offsetY = (pSource->height-fmtDesc.height)/2;
\r
110 rowsToCopy = fmtDesc.height;
\r
113 int bytesPerPixel = pSource->bpp;
\r
115 PixmapDataPtr pNewImage(new caspar::utils::PixmapData(fmtDesc.width, fmtDesc.height, bytesPerPixel));
\r
116 unsigned char* pNewImageData = pNewImage->GetDataPtr();
\r
118 //initialize new buffer with zeroes
\r
119 memset(pNewImageData, 0, fmtDesc.width*fmtDesc.height*bytesPerPixel);
\r
121 for(int i=0;i<rowsToCopy;++i)
\r
122 memcpy(&(pNewImageData[bytesPerPixel*fmtDesc.width*i]), &(pSource->GetDataPtr()[bytesPerPixel*(pSource->width*(i+offsetY)+offsetX)]), bytesPerPixel*colsToCopy);
\r
128 bool TargaManager::Load(utils::InputStreamPtr spTGA, PixmapDataPtr& pResult)
\r
130 utils::InputStream* pTGA = spTGA.get();
\r
131 PixmapDataPtr pImage(new utils::PixmapData());
\r
133 bool returnValue = true;
\r
134 //correct headers to compare to
\r
135 char headerUncompressed[12] = {0,0, 2,0,0,0,0,0,0,0,0,0};
\r
136 char headerCompressed[12] = {0,0,10,0,0,0,0,0,0,0,0,0};
\r
138 unsigned char header[12];
\r
139 unsigned char tgaInfo[6];
\r
140 unsigned int nImageSize = 0, nBytesPerPixel = 0;
\r
142 unsigned char *pColorBuffer = NULL;
\r
145 unsigned int nBytesPerRow;
\r
146 int nCurrentRow = 0;
\r
148 char rowDirection = -1;
\r
150 pTGA->Read(header, 12); //read header to be able to process compressed files in one way and uncompressed files in another
\r
151 pTGA->Read(tgaInfo, 6); //read image-info such as height and width
\r
153 int width = tgaInfo[1] * 256 + tgaInfo[0]; //extract width
\r
154 int height = tgaInfo[3] * 256 + tgaInfo[2]; //extract height
\r
155 int bits = tgaInfo[4]; //extract bits/pixel
\r
157 pImage->Set(width, height, 4);
\r
158 unsigned char* pImageData = pImage->GetDataPtr();
\r
161 if(tgaInfo[5] & 0x20)
\r
164 //calculate usefull numbers
\r
165 nBytesPerPixel = bits / 8;
\r
166 nBytesPerRow = pImage->width * nBytesPerPixel;
\r
168 //internal data always have 4 bytes / pixel
\r
169 nImageSize = pImage->width * pImage->height * 4;
\r
171 if(nBytesPerPixel != 3 && nBytesPerPixel != 4)
\r
173 returnValue = false;
\r
174 goto tgaLoaderExit;
\r
177 memset(pImageData, 0, nImageSize);
\r
179 //Workaround for image identification field problem
\r
181 unsigned char iifSize = header[0];
\r
182 unsigned char temp[256];
\r
184 pTGA->Read(temp, iifSize);
\r
190 //We've got an uncompressed file on our hands, take care of it
\r
191 if(memcmp(headerUncompressed, header, 12) == 0)
\r
193 unsigned char* pRowBuffer = new unsigned char[nBytesPerRow];
\r
196 if(rowDirection == -1)
\r
197 nCurrentRow = height-1;
\r
201 for(; rowIndex < height; nCurrentRow+=rowDirection, ++rowIndex)
\r
203 if(pTGA->Read(pRowBuffer, nBytesPerRow) < nBytesPerRow)
\r
205 delete[] pRowBuffer;
\r
206 returnValue = false;
\r
207 goto tgaLoaderExit;
\r
210 //Swap color-channels
\r
211 for(i=0;i<pImage->width;i++)
\r
213 pImageData[4*(nCurrentRow*width+i)+0] = pRowBuffer[i*nBytesPerPixel+0];
\r
214 pImageData[4*(nCurrentRow*width+i)+1] = pRowBuffer[i*nBytesPerPixel+1];
\r
215 pImageData[4*(nCurrentRow*width+i)+2] = pRowBuffer[i*nBytesPerPixel+2];
\r
216 if(nBytesPerPixel == 4)
\r
217 pImageData[4*(nCurrentRow*width+i)+3] = pRowBuffer[i*nBytesPerPixel+3];
\r
219 pImageData[4*(nCurrentRow*width+i)+3] = 255;
\r
222 delete[] pRowBuffer;
\r
225 //wasn't uncompressed, is it compressed? in that case, take care of it!
\r
226 else if(memcmp(headerCompressed, header, 12) == 0)
\r
229 if(rowDirection == -1)
\r
230 nCurrentRow = pImage->height-1;
\r
234 nBytesPerRow = width * 4;
\r
236 int nPixelCount = height * width;
\r
237 int nCurrentPixel = 0;
\r
238 int nCurrentByte = 0;
\r
240 pColorBuffer = new unsigned char[nBytesPerPixel];
\r
244 unsigned char chunkHeader = 0;
\r
246 //read chunkHeader - exit on error
\r
247 if(pTGA->Read(&chunkHeader, 1) < 0)
\r
249 returnValue = false;
\r
250 goto tgaLoaderExit;
\r
253 if(chunkHeader < 128) //it's a RAW-header
\r
257 for(unsigned short counter=0; counter<chunkHeader; counter++)
\r
259 //read pixeldata - exit on error
\r
260 if(pTGA->Read(pColorBuffer, nBytesPerPixel) < nBytesPerPixel)
\r
262 returnValue = false;
\r
263 goto tgaLoaderExit;
\r
266 unsigned int thisByte = nCurrentRow*nBytesPerRow+nCurrentByte;
\r
269 pImageData[thisByte+0] = pColorBuffer[0];
\r
270 pImageData[thisByte+1] = pColorBuffer[1];
\r
271 pImageData[thisByte+2] = pColorBuffer[2];
\r
272 if(nBytesPerPixel == 4)
\r
273 pImageData[thisByte+3] = pColorBuffer[3];
\r
275 pImageData[thisByte+3] = 255;
\r
279 if(nCurrentByte >= nBytesPerRow)
\r
281 nCurrentRow += rowDirection;
\r
287 else //it's a RLE header
\r
289 chunkHeader -= 127;
\r
291 //read pixeldata - exit on error
\r
292 if(pTGA->Read(pColorBuffer, nBytesPerPixel) < nBytesPerPixel)
\r
294 returnValue = false;
\r
295 goto tgaLoaderExit;
\r
298 //repeat this pixel
\r
299 for(unsigned short counter=0; counter<chunkHeader; counter++)
\r
301 unsigned int thisByte = nCurrentRow*nBytesPerRow+nCurrentByte;
\r
304 pImageData[thisByte+0] = pColorBuffer[0];
\r
305 pImageData[thisByte+1] = pColorBuffer[1];
\r
306 pImageData[thisByte+2] = pColorBuffer[2];
\r
307 if(nBytesPerPixel == 4)
\r
308 pImageData[thisByte+3] = pColorBuffer[3];
\r
310 pImageData[thisByte+3] = 255;
\r
314 if(nCurrentByte >= nBytesPerRow)
\r
316 nCurrentRow += rowDirection;
\r
322 }while(nCurrentPixel<nPixelCount && rowIndex < pImage->height);
\r
325 returnValue = false;
\r
328 if(pColorBuffer != NULL)
\r
329 delete[] pColorBuffer;
\r
334 return returnValue;
\r
338 ///////////////////////////////
\r
339 // TargaProducer definition
\r
341 TargaProducer::TargaProducer(PixmapDataPtr pImage) : pImage_(pImage) {
\r
344 TargaProducer::~TargaProducer() {
\r
347 IMediaController* TargaProducer::QueryController(const tstring& id) {
\r
348 if(id == TEXT("FrameController"))
\r
354 bool TargaProducer::Initialize(FrameManagerPtr pFrameManager) {
\r
355 if(pFrameManager != 0) {
\r
356 FramePtr pFrame = pFrameManager->CreateFrame();
\r
357 if(pFrame != 0 && pFrame->GetDataPtr() != 0) {
\r
358 PixmapDataPtr pResult = TargaManager::CropPadToFrameFormat(pImage_, pFrameManager->GetFrameFormatDescription());
\r
360 unsigned char* pFrameData = pFrame->GetDataPtr();
\r
361 unsigned char* pImageData = pResult->GetDataPtr();
\r
363 memcpy(pFrameData, pImageData, pFrame->GetDataSize());
\r
365 frameBuffer_.push_back(pFrame);
\r