1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
|
/*******************************************************************************
* moov.cpp
*
* ---------------------------------------------------------------------------
* Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
* Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
*
* POV-Ray is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* POV-Ray is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ---------------------------------------------------------------------------
* POV-Ray is based on the popular DKB raytracer version 2.12.
* DKBTrace was originally written by David K. Buck.
* DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
* ---------------------------------------------------------------------------
* $File: //depot/public/povray/3.x/source/base/animation/moov.cpp $
* $Revision: #1 $
* $Change: 6069 $
* $DateTime: 2013/11/06 11:59:40 $
* $Author: chrisc $
*******************************************************************************/
#include <limits.h>
// configbase.h must always be the first POV file included within base *.cpp files
#include "base/configbase.h"
#include "base/pov_err.h"
#include "base/types.h"
#include "base/animation/animation.h"
#include "base/animation/moov.h"
// this must be the last file included
#include "base/povdebug.h"
namespace pov_base
{
typedef POVMSType Type;
struct PrivateData
{
unsigned int width;
unsigned int height;
Type componenttype;
bool alphachannel;
int timescale;
int frameduration;
POV_LONG mdatsize;
vector<int> imagesizes;
};
namespace Moov
{
void WriteAtomHeader(OStream *file, Type type, POV_LONG size);
void WriteType(OStream *file, Type data);
void WriteInt2(OStream *file, POVMSInt data);
void WriteInt4(OStream *file, POVMSInt data);
void WriteInt8(OStream *file, POV_LONG data);
void WriteN(OStream *file, size_t cnt, POVMSInt data);
void *ReadFileHeader(IStream *file, float& lengthinseconds, unsigned int& lengthinframes, Animation::CodecType& codec, unsigned int& w, unsigned int& h, const Animation::ReadOptions& options, vector<string>& warnings)
{
throw POV_EXCEPTION(kCannotHandleDataErr, "Reading QuickTime movie files is not supported (yet)!");
return NULL;
}
void PreReadFrame(IStream *file, unsigned int frame, POV_LONG& bytes, Animation::CodecType& codec, const Animation::ReadOptions& options, vector<string>& warnings, void *state)
{
}
void PostReadFrame(IStream *file, unsigned int frame, POV_LONG bytes, Animation::CodecType& codec, const Animation::ReadOptions& options, vector<string>& warnings, void *state)
{
}
void FinishReadFile(IStream *file, vector<string>& warnings, void *state)
{
}
void *WriteFileHeader(OStream *file, Animation::CodecType& codec, unsigned int w, unsigned int h, const Animation::WriteOptions& options, vector<string>& warnings)
{
PrivateData pd;
pd.width = w;
pd.height = h;
// determine codec equivalent
switch(codec)
{
case Animation::LosslessCodec:
case Animation::PNGCodec:
codec = Animation::PNGCodec;
pd.componenttype = 'png ';
pd.alphachannel = options.alphachannel;
break;
case Animation::LossyCodec:
case Animation::JPEGCodec:
codec = Animation::JPEGCodec;
pd.componenttype = 'jpeg';
pd.alphachannel = false;
break;
case Animation::BMPCodec:
codec = Animation::BMPCodec;
pd.componenttype = 'WRLE';
pd.alphachannel = false;
break;
default:
return NULL; // error - cannot handle format
}
if(pd.alphachannel != options.alphachannel)
warnings.push_back("Alpha channel output not supported for this animation codec. Alpha channel output will be disabled.");
// compute time scale
double ts = double(options.framespersecond);
int m = 1;
for(m = 1; m <= 1000; m *= 10)
{
if((fabs((ts * double(m)) - double(int((ts * double(m))))) < 1.0e-5) && ((ts * double(m)) >= 1.0))
break;
}
pd.timescale = max(int(double(options.framespersecond) * double(m)), 1);
// frame duration according to time scale
pd.frameduration = m;
// movie data atom header
WriteAtomHeader(file, 'mdat', -1);
pd.mdatsize = 16;
// NOTE: This allocation occurs at the end such that there cannot be a memory leak
// should any of the previous operations fail. If and only if this function returns
// a state other than NULL shall it be assumed to have been successful!
return reinterpret_cast<void *>(new PrivateData(pd));
}
void PreWriteFrame(OStream *, const Animation::WriteOptions&, vector<string>&, void *state)
{
PrivateData *pd = reinterpret_cast<PrivateData *>(state);
if(pd == NULL)
throw POV_EXCEPTION_CODE(kNullPointerErr);
// there really is nothing to do here [trf]
}
void PostWriteFrame(OStream *file, POV_LONG bytes, const Animation::WriteOptions&, vector<string>&, void *state)
{
PrivateData *pd = reinterpret_cast<PrivateData *>(state);
if(pd == NULL)
throw POV_EXCEPTION_CODE(kNullPointerErr);
// update mdat size
file->seekg(0, SEEK_END);
pd->mdatsize = file->tellg() + 16;
file->seekg(8, SEEK_SET);
WriteInt8(file, pd->mdatsize);
file->seekg(0, SEEK_END);
if(bytes > 2147483647) // 2^31 - 1
throw POV_EXCEPTION(kInvalidDataSizeErr, "Cannot handle frame data larger than 2^31 bytes!");
pd->imagesizes.push_back(int(bytes));
}
void FinishWriteFile(OStream *file, const Animation::WriteOptions& options, vector<string>& warnings, void *state)
{
PrivateData *pd = reinterpret_cast<PrivateData *>(state);
if(pd == NULL)
throw POV_EXCEPTION_CODE(kNullPointerErr);
POV_LONG stsz_size = 20 + (pd->imagesizes.size() * 4);
POV_LONG stsc_size = 28;
POV_LONG stts_size = 32;
POV_LONG stsd_size = 102;
POV_LONG stbl_size = 8 + stsd_size + stts_size + stsc_size + stsz_size;
POV_LONG vmhd_size = 20;
POV_LONG minf_size = 8 + vmhd_size + stbl_size;
POV_LONG hdlr_size = 32;
POV_LONG mdhd_size = 32;
POV_LONG mdia_size = 8 + mdhd_size + hdlr_size + minf_size;
POV_LONG tkhd_size = 112;
POV_LONG trak_size = 8 + tkhd_size + mdia_size;
POV_LONG mvhd_size = 108;
POV_LONG moov_size = 8 + mvhd_size + trak_size;
int duration = pd->frameduration * pd->imagesizes.size();
// write movie atom
WriteAtomHeader(file, 'moov', moov_size);
// write movie header atom
WriteAtomHeader(file, 'mvhd', mvhd_size);
WriteInt4(file, 0); // version and flags
WriteInt4(file, 0); // creation time
WriteInt4(file, 0); // modification time
WriteInt4(file, pd->timescale); // time scale
WriteInt4(file, duration); // duration
WriteInt4(file, 1 << 16); // preferred playback rate
WriteInt2(file, 1 << 8); // preferred sound volume
WriteN(file, 10, 0); // ten reserved bytes
WriteInt4(file, 1 << 16); // matrix a
WriteInt4(file, 0); // matrix b
WriteInt4(file, 0); // matrix u
WriteInt4(file, 0); // matrix c
WriteInt4(file, 1 << 16); // matrix d
WriteInt4(file, 0); // matrix v
WriteInt4(file, 0); // matrix tx
WriteInt4(file, 0); // matrix ty
WriteInt4(file, 1 << 30); // matrix w
WriteInt4(file, 0); // preview time
WriteInt4(file, 0); // preview duration
WriteInt4(file, 0); // poster time
WriteInt4(file, 0); // selection time
WriteInt4(file, 0); // selection duration
WriteInt4(file, 0); // current time
WriteInt4(file, 2); // next track id (this code uses track 1)
// write track atom
WriteAtomHeader(file, 'trak', trak_size);
// write track header atom
WriteAtomHeader(file, 'tkhd', tkhd_size);
WriteInt4(file, 0); // version and flags
WriteInt4(file, 0); // creation time
WriteInt4(file, 0); // modification time
WriteInt4(file, 1); // track id
WriteN(file, 4, 0); // four reserved bytes
WriteInt4(file, duration); // duration
WriteN(file, 8, 0); // eight reserved bytes
WriteInt2(file, 1); // layer
WriteInt2(file, 0); // alternate group
WriteInt2(file, 1 << 8); // sound volume
WriteN(file, 2, 0); // two reserved bytes
WriteInt4(file, 1 << 16); // matrix a
WriteInt4(file, 0); // matrix b
WriteInt4(file, 0); // matrix u
WriteInt4(file, 0); // matrix c
WriteInt4(file, 1 << 16); // matrix d
WriteInt4(file, 0); // matrix v
WriteInt4(file, 0); // matrix tx
WriteInt4(file, 0); // matrix ty
WriteInt4(file, 1 << 30); // matrix w
WriteInt4(file, pd->width << 16); // track width
WriteInt4(file, pd->height << 16); // track height
// write media atom
WriteAtomHeader(file, 'mdia', mdia_size);
// write header media atom
WriteAtomHeader(file, 'mdhd', mdhd_size);
WriteInt4(file, 0); // version and flags
WriteInt4(file, 0); // creation time
WriteInt4(file, 0); // modification time
WriteInt4(file, pd->timescale); // time scale
WriteInt4(file, duration); // duration
WriteInt2(file, 0); // language
WriteInt2(file, 0); // quality
// write handler atom
WriteAtomHeader(file, 'hdlr', hdlr_size);
WriteInt4(file, 0); // version and flags
WriteType(file, pd->componenttype); // component type
WriteType(file, 'vide'); // component subtype (this media is video)
WriteInt4(file, 0); // reserved
WriteInt4(file, 0); // reserved
WriteInt4(file, 0); // reserved
// write media information atom
WriteAtomHeader(file, 'minf', minf_size);
// write video media information header atom
WriteAtomHeader(file, 'vmhd', vmhd_size);
WriteInt4(file, 0); // version and flags
WriteInt2(file, 0); // graphics mode
WriteInt2(file, 0); // opcolor red
WriteInt2(file, 0); // opcolor green
WriteInt2(file, 0); // opcolor blue
// write sample table atom
WriteAtomHeader(file, 'stbl', stbl_size);
// write sample description atom
WriteAtomHeader(file, 'stsd', stsd_size);
WriteInt4(file, 0); // version and flags
WriteInt4(file, 1); // number of entries (this code only needs one entry)
WriteInt4(file, 86); // description size
WriteType(file, pd->componenttype); // data format
WriteInt4(file, 0); // reserved
WriteInt2(file, 0); // reserved
WriteInt2(file, 0); // data reference index
WriteInt2(file, 0); // version
WriteInt2(file, 0); // revision level
WriteType(file, 'appl'); // vendor
WriteInt4(file, 0); // temporal quality
WriteInt4(file, 512); // spacial quality
WriteInt2(file, pd->width); // width
WriteInt2(file, pd->height); // height
WriteInt4(file, 72 << 16); // horizontal resolution
WriteInt4(file, 72 << 16); // vertical resolution
WriteInt4(file, 0); // data size (required to be zero according to Apple documentation)
WriteInt4(file, 1); // frame count
WriteN(file, 1, 4); // name (32-byte Pascal string, so first byte is length!)
WriteType(file, pd->componenttype); // name (continued, uses codec type for simplicity)
WriteN(file, 27, 0); // name (continued, unused)
WriteInt2(file, options.bpcc * (3 + (pd->alphachannel ? 1 : 0))); // depth
WriteInt2(file, -1); // color table id
// write time-to-sample atom
WriteAtomHeader(file, 'stts', stts_size);
WriteInt4(file, 0); // version and flags
WriteInt4(file, 1); // number of entries (this code only needs one entry)
WriteInt4(file, pd->imagesizes.size()); // sample count
WriteInt4(file, pd->frameduration); // sample duration
// write sample-to-chunk atom
WriteAtomHeader(file, 'stsc', stsc_size);
WriteInt4(file, 0); // version and flags
WriteInt4(file, 1); // number of entries (this code only needs one entry)
WriteInt4(file, 1); // first chunk
WriteInt4(file, pd->imagesizes.size()); // samples per chunk
WriteInt4(file, 1); // sample description id
// write sample size atom
WriteAtomHeader(file, 'stsz', stsz_size);
WriteInt4(file, 0); // version and flags
WriteInt4(file, 0); // sample size (all samples have different sizes, so this needs to be zero)
WriteInt4(file, pd->imagesizes.size()); // number of entries
for(vector<int>::const_iterator i = pd->imagesizes.begin(); i != pd->imagesizes.end(); i++)
WriteInt4(file, *i); // sample size entry
delete pd;
}
/*
void ReadAtomHeader(IStream *file, Type& type, POV_LONG& size)
{
ReadInt4(file, size);
if(size == 0) // atom goes up to end of file
{
ReadType(file, type);
POV_LONG t = file->tellg();
file->seekg(0, IOBase::SEEK_END);
size = file->tellg() - t + 8;
file->seekg(t, IOBase::SEEK_SET);
}
else if(size == 1) // atom sizes is outside 32-bit range
{
ReadType(file, type);
ReadInt8(file, size);
}
else
ReadType(file, type);
}
*/
void WriteAtomHeader(OStream *file, Type type, POV_LONG size)
{
if(size < 0) // temporary size - always assume 64-bit size
{
WriteInt4(file, 1);
WriteType(file, type);
WriteInt8(file, 0);
}
else if(size > UINT_MAX) // size outside 32-bit range
{
WriteInt4(file, 1);
WriteType(file, type);
WriteInt8(file, size);
}
else // size within 32-bit range
{
WriteType(file, type);
WriteInt4(file, size);
}
}
void WriteType(OStream *file, Type data)
{
file->Write_Byte((data >> 24) & 255);
file->Write_Byte((data >> 16) & 255);
file->Write_Byte((data >> 8) & 255);
file->Write_Byte(data & 255);
}
void WriteInt2(OStream *file, POVMSInt data)
{
file->Write_Byte((data >> 8) & 255);
file->Write_Byte(data & 255);
}
void WriteInt4(OStream *file, POVMSInt data)
{
file->Write_Byte((data >> 24) & 255);
file->Write_Byte((data >> 16) & 255);
file->Write_Byte((data >> 8) & 255);
file->Write_Byte(data & 255);
}
void WriteInt8(OStream *file, POV_LONG data)
{
file->Write_Byte((data >> 56) & 255);
file->Write_Byte((data >> 48) & 255);
file->Write_Byte((data >> 40) & 255);
file->Write_Byte((data >> 32) & 255);
file->Write_Byte((data >> 24) & 255);
file->Write_Byte((data >> 16) & 255);
file->Write_Byte((data >> 8) & 255);
file->Write_Byte(data & 255);
}
void WriteN(OStream *file, size_t cnt, POVMSInt data)
{
for(size_t i = 0; i < cnt; i++)
file->Write_Byte(data & 255);
}
}
}
|