EVOLUTION-MANAGER
Edit File: oggStreamDecoder.cpp
/* * oggStreamDecoder is a class to extract an ogg packet from an * ogg page stream * * Copyright (C) 2008 Joern Seger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program 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 General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include <iostream> #include <vector> #include <cstring> #include "definition.h" #include "oggHeader.h" #include "oggStreamDecoder.h" OggStreamDecoder::SegmentElement::SegmentElement(uint8* _data, uint32 length) : data(_data), length(length) { } OggStreamDecoder::OggStreamDecoder() { } OggStreamDecoder::~OggStreamDecoder() { clear(); } void OggStreamDecoder::init(OggPage page) { /* if this is not a Begin Of Stream page, do nothing */ if (!page.isBOS()) { std::cerr << "OggStreamDecoder: ogg page is not a begin of stream\n"; return; } packetCount = 0; /* extract and remember the serial number of this stream */ serialNo = page.serialno(); setConfigured(); } void OggStreamDecoder::clear() { delete[] tmpSegment.data; tmpSegment.data = 0; tmpSegment.length = 0; } uint32 OggStreamDecoder::getSerialNo() { return(serialNo); } OggStreamDecoder& OggStreamDecoder::operator<<(OggPage& page) { /* if this stream is not initialized, try to initialize it */ if (!isInitialized()) init(page); /* decode the packets */ if (!isConfigured()) { throw ("OggStreamDecoder::operator<<: This stream is not is not configured yet\n"); } if (page.serialno() != serialNo) { throw ("OggStreamDecoder::operator<<: page does not belong to this stream\n"); } /* extract the header */ uint8* data(page.data()); OggHeader* header = (OggHeader*)(data); data += sizeof(OggHeader); /* extract the relevant data from the header */ unsigned char tableSegments(header->tableSegments); // extract the segment table uint8* segment = (uint8*) data; data += tableSegments; /* will the last packet be continued on in the next page? */ bool willBeContinued; if (segment[header->tableSegments-1] != 255) willBeContinued = false; else willBeContinued = true; std::vector<SegmentElement> segmentDataList; // extract pointers to the packets in this page SegmentElement segData(data,0); for (unsigned int i=0; i<tableSegments; ++i) { data += segment[i]; segData.length += segment[i]; if (segment[i] != 255) { segmentDataList.push_back(segData); segData = SegmentElement(data,0); } } // store the last packet if it does not end in this page if (willBeContinued) segmentDataList.push_back(segData); /* it would be good to know where the granule position belongs to */ uint32 infoPosition(256); /* does the last packet do not end here */ if (!willBeContinued) infoPosition = segmentDataList.size()-1; else if (segmentDataList.size() > 1) infoPosition = segmentDataList.size()-2; // now extract the ogg packets itself // every segment in the list is one packet (maybe there is a // remaining part in tmpSegment from the page before and // there might be a segment, that is not finished on this page) for (unsigned int i(0); i<segmentDataList.size(); ++i) { uint32 overallLength = tmpSegment.length+segmentDataList[i].length; unsigned char* newPacketPtr = new unsigned char[overallLength]; if (tmpSegment.length) memcpy(newPacketPtr,tmpSegment.data, tmpSegment.length); memcpy(newPacketPtr+tmpSegment.length, segmentDataList[i].data, segmentDataList[i].length); // delete the temporary Segment if (tmpSegment.data) { delete[] tmpSegment.data; tmpSegment = SegmentElement(); } if ((i == (segmentDataList.size()-1)) && willBeContinued) { //store last segment as it is does not end here tmpSegment = SegmentElement(newPacketPtr, overallLength); } else { // we found a full packet OggPacketInternal::PacketType packetType(OggPacketInternal::normal); int64 granulePosition(-1); if ((i == 0) && (page.isBOS())) packetType = OggPacketInternal::bos; if ((i == segmentDataList.size()-1) && (page.isEOS())) packetType = OggPacketInternal::eos; if (i == infoPosition) granulePosition = header->position; /* create the packet */ OggPacket packet(new OggPacketInternal(newPacketPtr, overallLength, packetCount++, granulePosition, packetType)); oggPacketList.push_back(packet); } } if (!oggPacketList.empty()) setAvailable(); return(*this); } OggPacket OggStreamDecoder::inspectNextPacket() { OggPacket packet; if (!isAvailable()) { throw("OggStreamDecoder::inspectNextPacket: no packet available\n"); // std::cerr << "OggStreamDecoder::inspectNextPacket: no packet available\n"; // return (packet); } // we will not harm the list in any kind packet = oggPacketList.front(); return (packet); } OggStreamDecoder& OggStreamDecoder::operator>>(OggPacket& packet) { if (!isAvailable()) { throw ("OggStreamDecoder::operator>>: no packet available\n"); // std::cerr << "OggStreamDecoder::operator>>: no packet available\n"; // return(*this); } packet = oggPacketList.front(); oggPacketList.pop_front(); /* is this the last packet within this stream, * then set the stream status */ if (packet.isEOS()) { setEndOfStream(); } else { if (oggPacketList.empty()) { setEmpty(); } } return(*this); }