// must not be called in the ctor, can throw exceptions void MemoryDataSource::_loadFile() { if (this->data == NULL) { VideoClip::Format format; FILE* file = openSupportedFormatFile(filename, format, this->fullFilename); if (file == NULL) { std::string message = "Can't open or find video file: " + filename; log(message); throw TheoraplayerException(message); } this->formatName = format.name; #ifdef _WIN32 struct _stat64 s; _fstati64(_fileno(file), &s); #else struct stat s; fstat(fileno(file), &s); #endif this->size = (int64_t)s.st_size; if (this->size > 0xFFFFFFFF) { fclose(file); throw TheoraplayerException("MemoryDataSource doesn't support files larger than 4GB!"); } if (this->size < UINT_MAX) { this->data = new unsigned char[(unsigned int)this->size]; fread(this->data, 1, (size_t)this->size, file); } else { fclose(file); throw TheoraplayerException("Unable to preload file to memory, file is too large."); } fclose(file); } }
void FileDataSource::_openFile() { if (this->filePtr == NULL) { VideoClip::Format format; this->filePtr = openSupportedFormatFile(this->filename, format, this->fullFilename); if (this->filePtr == NULL) { std::string message = "Can't open or find video file: " + filename; log(message); throw TheoraplayerException(message); } this->formatName = format.name; #ifdef _WIN32 struct _stat64 s; _fstati64(_fileno(this->filePtr), &s); #else struct stat s; fstat(fileno(this->filePtr), &s); #endif this->length = (int64_t)s.st_size; } }
void VideoClip_Theora::_readTheoraVorbisHeaders() { ogg_packet tempOggPacket; //init Vorbis/Theora Layer //Ensure all structures get cleared out. memset(&this->info.OggSyncState, 0, sizeof(ogg_sync_state)); memset(&this->info.OggPage, 0, sizeof(ogg_page)); memset(&this->info.VorbisStreamState, 0, sizeof(ogg_stream_state)); memset(&this->info.TheoraStreamState, 0, sizeof(ogg_stream_state)); memset(&this->info.TheoraInfo, 0, sizeof(th_info)); memset(&this->info.TheoraComment, 0, sizeof(th_comment)); memset(&this->info.VorbisInfo, 0, sizeof(vorbis_info)); memset(&this->info.VorbisDSPState, 0, sizeof(vorbis_dsp_state)); memset(&this->info.VorbisBlock, 0, sizeof(vorbis_block)); memset(&this->info.VorbisComment, 0, sizeof(vorbis_comment)); // init all structures ogg_sync_init(&this->info.OggSyncState); th_comment_init(&this->info.TheoraComment); th_info_init(&this->info.TheoraInfo); vorbis_info_init(&this->info.VorbisInfo); vorbis_comment_init(&this->info.VorbisComment); // start ogg_stream_state oggStateTest; bool decodeAudio = (theoraplayer::manager->getAudioInterfaceFactory() != NULL); char* buffer = NULL; int bytesRead = 0; bool done = false; while (!done) { buffer = ogg_sync_buffer(&this->info.OggSyncState, BUFFER_SIZE); bytesRead = this->stream->read(buffer, BUFFER_SIZE); ogg_sync_wrote(&this->info.OggSyncState, bytesRead); if (bytesRead == 0) { break; } while (ogg_sync_pageout(&this->info.OggSyncState, &this->info.OggPage) > 0) { memset(&oggStateTest, 0, sizeof(oggStateTest)); //is this an initial header? If not, stop if (ogg_page_bos(&this->info.OggPage) == 0) { //This is done blindly, because stream only accept themselves if (this->theoraStreams > 0) { ogg_stream_pagein(&this->info.TheoraStreamState, &this->info.OggPage); } if (this->vorbisStreams > 0) { ogg_stream_pagein(&this->info.VorbisStreamState, &this->info.OggPage); } done = true; break; } ogg_stream_init(&oggStateTest, ogg_page_serialno(&this->info.OggPage)); ogg_stream_pagein(&oggStateTest, &this->info.OggPage); ogg_stream_packetout(&oggStateTest, &tempOggPacket); // identify the codec if (this->theoraStreams == 0 && th_decode_headerin(&this->info.TheoraInfo, &this->info.TheoraComment, &this->info.TheoraSetup, &tempOggPacket) > 0) { // This is the Theora Header memcpy(&this->info.TheoraStreamState, &oggStateTest, sizeof(oggStateTest)); this->theoraStreams = 1; } else if (decodeAudio && this->vorbisStreams == 0 && vorbis_synthesis_headerin(&this->info.VorbisInfo, &this->info.VorbisComment, &tempOggPacket) >= 0) { // This is vorbis header memcpy(&this->info.VorbisStreamState, &oggStateTest, sizeof(oggStateTest)); this->vorbisStreams = 1; } else // Hm, guess it's not a header we support, so erase it { ogg_stream_clear(&oggStateTest); } } } int result = 0; while ((this->theoraStreams > 0 && this->theoraStreams < 3) || (this->vorbisStreams && this->vorbisStreams < 3)) { // Check 2nd'dary headers... Theora First while (this->theoraStreams > 0 && this->theoraStreams < 3 && (result = ogg_stream_packetout(&this->info.TheoraStreamState, &tempOggPacket))) { if (result < 0) { throw TheoraplayerException("Error parsing Theora stream headers!"); } if (th_decode_headerin(&this->info.TheoraInfo, &this->info.TheoraComment, &this->info.TheoraSetup, &tempOggPacket) == 0) { throw TheoraplayerException("Invalid theora stream!"); } ++this->theoraStreams; } // end while looking for more theora headers // look 2nd vorbis header packets while (this->vorbisStreams < 3 && (result = ogg_stream_packetout(&this->info.VorbisStreamState, &tempOggPacket))) { if (result < 0) { throw TheoraplayerException("Error parsing vorbis stream headers!"); } if (vorbis_synthesis_headerin(&this->info.VorbisInfo, &this->info.VorbisComment, &tempOggPacket) != 0) { throw TheoraplayerException("Invalid stream!"); } ++this->vorbisStreams; } // end while looking for more vorbis headers // Not finished with Headers, get some more file data if (ogg_sync_pageout(&this->info.OggSyncState, &this->info.OggPage) > 0) { if (this->theoraStreams > 0) { ogg_stream_pagein(&this->info.TheoraStreamState, &this->info.OggPage); } if (this->vorbisStreams > 0) { ogg_stream_pagein(&this->info.VorbisStreamState, &this->info.OggPage); } } else { buffer = ogg_sync_buffer(&this->info.OggSyncState, BUFFER_SIZE); bytesRead = this->stream->read(buffer, BUFFER_SIZE); ogg_sync_wrote(&this->info.OggSyncState, bytesRead); if (bytesRead == 0) { throw TheoraplayerException("End of file found prematurely!"); } } } // end while looking for all headers //log("Vorbis Headers: " + str(mVorbisHeaders) + " Theora Headers : " + str(mTheoraHeaders)); }