EVOLUTION-MANAGER
Edit File: theoraDecoder.cpp
/* * TheoraDecoder wrapper * * 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 "theoraDecoder.h" #ifdef HAVE_LIBTHEORADEC #include "theoraStreamParameter.h" #include <iostream> #include <sstream> #include <string> #include <theora/codec.h> #include <theora/theoradec.h> TheoraDecoder::TheoraDecoder(int8 _streamID) : MediaOutputDecoder(_streamID), setupInfo(NULL), theoraDecState(NULL), initCount(0) { } TheoraDecoder::~TheoraDecoder() { th_setup_free(setupInfo); th_decode_free(theoraDecState); th_info_clear(&theoraInfo); } void TheoraDecoder::initDecoder(StreamConfig& config, std::vector<OggComment>& oggComments) { if (isConfigured()) { std::cerr << "Theora Decoder: Decoder is still configured\n"; return; } /* initialize the info and comment handler structs */ th_info_init(&theoraInfo); th_comment_init(&theoraComment); /* initialize the packet counter */ packetCount = 0; /* Konfiguration des Decoders */ for (uint8 i(0); i<config.headerList.size(); ++i) { /* Einfügen der Header * Fehlermeldung, wenn die Daten nicht zum aktuellen Codec passen */ int retVal = th_decode_headerin(&theoraInfo, &theoraComment, &setupInfo, config.headerList[i].obj()); if (retVal <= 0) throw "TheoraDecoder::initDecoder: packet is not a header\n"; } /* extract the comments */ for (uint8 i(0); i<theoraComment.comments; ++i) { /* We have to extract the tags by ourself */ std::string commentStr(theoraComment.user_comments[i], theoraComment.comment_lengths[i]); std::size_t commentSeparatorPos; if ((commentSeparatorPos = commentStr.find_first_of("=")) != std::string::npos) { OggComment comment; comment.tag = commentStr.substr(0, commentSeparatorPos); comment.value = commentStr.substr(commentSeparatorPos+1, std::string::npos); oggComments.push_back(comment); } } /* finish initialization */ theoraDecState = th_decode_alloc(&theoraInfo, setupInfo); th_comment_clear(&theoraComment); /* config.type = ogg_theora; TheoraStreamParameter* theoraParam = new TheoraStreamParameter; theoraParam->aspectRatioNum = theoraInfo.aspect_numerator; theoraParam->aspectRatioDenom = theoraInfo.aspect_denominator; theoraParam->framerateNum = theoraInfo.fps_numerator; theoraParam->framerateDenom = theoraInfo.fps_denominator; theoraParam->keyframeShift = theoraInfo.keyframe_granule_shift; theoraParam->frameX = theoraInfo.frame_width; theoraParam->frameY = theoraInfo.frame_height; theoraParam->frameXOffset = theoraInfo.pic_x; theoraParam->frameYOffset = theoraInfo.pic_y; theoraParam->pictureX = theoraInfo.pic_width; theoraParam->pictureY = theoraInfo.pic_height; theoraParam->videoBitrate = theoraInfo.target_bitrate; theoraParam->videoQuality = theoraInfo.quality; if (config.parameter) delete config.parameter; config.parameter = theoraParam; */ /* set the state machine */ setConfigured(); } MediaOutputDecoder& TheoraDecoder::operator<<(OggPacket packet) { /* if the stream is not initialized, initialize the first structs */ if (!isConfigured()) throw "TheoraDecoder::operator<<: Cannot handle packet, decoder not initialized\n"; /* while inserting data into the stream, we do not * decode. We just store the packets and will decode them * on demand */ packetList.push_back(packet); /* has there not been a packet in the queue before */ if (isEmpty()) { /* set the internal state */ setAvailable(); } /* count the video packets, to have a gimps of the actual position */ packetCount++; return(*this); } bool TheoraDecoder::isNextPacketKeyframe() { return ((th_packet_iskeyframe(packetList.front().obj()) == 1)); } bool TheoraDecoder::isPacketKeyframe(OggPacket packet) { return ((th_packet_iskeyframe(packet.obj()) == 1)); } uint32 TheoraDecoder::getPositionOfNextPacket() { if (isEmpty()) return (0xFFFFFFFF); return (packetCount - packetList.size()); } TheoraDecoder& TheoraDecoder::operator>>(th_ycbcr_buffer& picture) { if (!isConfigured()) throw "TheoraDecoder::operator>>: Theora Stream is not initialized\n"; if (isEmpty()) throw "TheoraDecoder::operator>>: no packet available to create new picture\n"; /* get the first packet from the packet list */ OggPacket packet = packetList.front(); packetList.pop_front(); /* insert the packet into the theora decoder */ ogg_int64_t dummy; th_decode_packetin(theoraDecState, packet.obj(), &dummy); /* finally decode the picture */ th_decode_ycbcr_out(theoraDecState, picture); if (packetList.empty()) { setEmpty(); } return(*this); } std::string TheoraDecoder::getInfoString() { std::stringstream stream; if (!isConfigured()) { std::cerr << "TheoraDecoder::operator>>: Theora Stream is not initialized\n"; return (stream.str()); } stream << std::endl; stream << "Size : " << theoraInfo.pic_width << ":" << theoraInfo.pic_height << " (Frame Size : " << theoraInfo.frame_width << ":" << theoraInfo.frame_height << " ; Offset: "<<theoraInfo.pic_x<<":"<<theoraInfo.pic_y<<" \n"; stream << "Aspect Ratio : " << theoraInfo.aspect_numerator << ":" << theoraInfo.aspect_denominator << std::endl; stream << "Framerate : " << theoraInfo.fps_numerator /theoraInfo.fps_denominator << "\n"; stream << "Colorspace : "; switch (theoraInfo.colorspace) { case TH_CS_ITU_REC_470M: stream << "NTSC\n"; break; case TH_CS_ITU_REC_470BG: stream << "PAL\n"; break; default: stream << "unspecified\n"; } stream << "Quality : " << theoraInfo.quality << " / 61" << std::endl; stream << "Data rate : " << theoraInfo.target_bitrate << " kBit/s" << std::endl; stream << std::endl; stream << "Comments:\n"; for (int i=0; i<theoraComment.comments; ++i) stream << theoraComment.user_comments[i] << std::endl; return (stream.str()); } th_info& TheoraDecoder::getInfo() { return (theoraInfo); } th_comment& TheoraDecoder::getComment() { return (theoraComment); } uint32 TheoraDecoder::getWidth() { return(theoraInfo.pic_width); } uint32 TheoraDecoder::getHeight() { return(theoraInfo.pic_height); } #endif