From e2de64d6f1beb9e492daf5b886e19933c1fa41dd Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdemultimedia@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- mpeglib/lib/mpgplayer/mpegStreamPlayer.cpp | 431 +++++++++++++++++++++++++++++ 1 file changed, 431 insertions(+) create mode 100644 mpeglib/lib/mpgplayer/mpegStreamPlayer.cpp (limited to 'mpeglib/lib/mpgplayer/mpegStreamPlayer.cpp') diff --git a/mpeglib/lib/mpgplayer/mpegStreamPlayer.cpp b/mpeglib/lib/mpgplayer/mpegStreamPlayer.cpp new file mode 100644 index 00000000..133e6319 --- /dev/null +++ b/mpeglib/lib/mpgplayer/mpegStreamPlayer.cpp @@ -0,0 +1,431 @@ +/* + feeds audio/video streams to the decoders + Copyright (C) 2000 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#include "mpegStreamPlayer.h" +#include "../mpegplay/mpegSystemHeader.h" +#include "../util/syncClockMPEG.h" + +#define _NUKE_BUFFER_SIZE 1024 + +#define _BUFFER_HIGH_WATER 0.8 +#define _BUFFER_LOW_WATER 0.2 + +#define _BUFFER_CHUNK_SIZE 1500 + +#include + +using namespace std; + + +MpegStreamPlayer::MpegStreamPlayer(InputStream* input, + OutputStream* output, + DecoderPlugin* audioDecoder, + DecoderPlugin* videoDecoder) { + this->input=input; + this->output=output; + this->audioDecoder=audioDecoder; + this->videoDecoder=videoDecoder; + + /** + here we set the plugins in autoPlay mode. + because we handle all commands over the loopback buffer. + This is necessary, because on start we send play() + but this does not mean that we already have + build this class (divxplugin for example) + See this switch as an implicit play command + */ + + audioDecoder->config("-y","on",NULL); + videoDecoder->config("-y","on",NULL); + + + audioInput=new BufferInputStream(1024*_BUFFER_CHUNK_SIZE, + 1024*200,"audioInput"); + videoInput=new BufferInputStream(1024*_BUFFER_CHUNK_SIZE, + 1024*200,"videoInput"); + audioInput->open("audio loopback"); + videoInput->open("video loopback"); + + audioDecoder->setOutputPlugin(output); + audioDecoder->setInputPlugin(audioInput); + + videoDecoder->setOutputPlugin(output); + videoDecoder->setInputPlugin(videoInput); + + timeStampVideo=new TimeStamp(); + timeStampAudio=new TimeStamp(); + + packetCnt=0; + audioPacketCnt=0; + videoPacketCnt=0; + seekPos=-1; + nukeBuffer=new char[_NUKE_BUFFER_SIZE]; + + syncClock=new SyncClockMPEG(); + syncClock->setSyncMode(__SYNC_AUDIO); + writeToDisk=false; +} + + +MpegStreamPlayer::~MpegStreamPlayer() { + audioInput->close(); + videoInput->close(); + + // everything is prepared for future shutdown + // restart any waiting decoders + // (they exit immediately) + audioDecoder->close(); + videoDecoder->close(); + audioDecoder->waitForStreamState(_STREAM_STATE_EOF); + videoDecoder->waitForStreamState(_STREAM_STATE_EOF); + + delete videoInput; + delete audioInput; + delete nukeBuffer; + delete timeStampVideo; + delete timeStampAudio; + delete syncClock; +} + +int MpegStreamPlayer::getByteDirect() { + unsigned char byte; + if (input->read((char*)&byte,1) != 1) { + return -1; + } + return (int)byte; +} + +int MpegStreamPlayer::processResyncRequest() { + // here is our protocol for resync over the loopback stream + // if out clients are in sync and we set the resync method on the + // stream he sometimes set a "commit" in the stream + // we check if both stream are committed (== clients are in sync and paused) + // if both are in _STREAM_STATE_RESYNC_COMMIT + // we can safley do a seek + // and restart them + + if (seekPos != -1) { + int audioDecoderState=audioDecoder->getStreamState(); + int videoDecoderState=videoDecoder->getStreamState(); + if (audioDecoderState == _STREAM_STATE_RESYNC_COMMIT) { + if (videoDecoderState == _STREAM_STATE_RESYNC_COMMIT) { + Command restart(_COMMAND_RESYNC_END); + input->seek(seekPos); + seekPos=-1; + audioDecoder->insertSyncCommand(&restart); + videoDecoder->insertSyncCommand(&restart); + Command play(_COMMAND_PLAY); + audioDecoder->insertAsyncCommand(&play); + videoDecoder->insertAsyncCommand(&play); + return true; + } + } + } + return false; +} + +/** + according to the header info we read the packets +*/ +int MpegStreamPlayer::processSystemHeader(MpegSystemHeader* mpegSystemHeader) { + int layer=mpegSystemHeader->getLayer(); + + + if (processResyncRequest() == true) { + return false; + } + + if (layer==_PACKET_NO_SYSLAYER) { + syncClock->setSyncMode(__SYNC_NONE); + return insertVideoData(mpegSystemHeader,8192); + } + if (layer==_PACKET_SYSLAYER) { + int packetID=mpegSystemHeader->getPacketID(); + int packetLength=mpegSystemHeader->getPacketLen(); + int subStreamID=mpegSystemHeader->getSubStreamID(); + + switch(packetID>>4) { + case _PAKET_ID_VIDEO>>4: + if((packetID - _PAKET_ID_VIDEO) != + mpegSystemHeader->getVideoLayerSelect()) { + break; + } + + insertVideoData(mpegSystemHeader,packetLength); + //dumpData(mpegSystemHeader); + return true; + //break; + case _PAKET_ID_AUDIO_1>>4: + case _PAKET_ID_AUDIO_2>>4: + if((packetID - _PAKET_ID_AUDIO_1) != + mpegSystemHeader->getAudioLayerSelect()) { + break; + } + insertAudioData(mpegSystemHeader,packetLength); + return true; + } + switch(packetID) { + case _PRIVATE_STREAM_1_ID: + switch(subStreamID) { + case _SUBSTREAM_AC3_ID: + insertAudioData(mpegSystemHeader,packetLength); + //dumpData(mpegSystemHeader); + return true; + default: + printf("unknown private stream id:%8x\n",subStreamID); + } + } + + // if we got here the packet is not useful + // nuke it + nuke(packetLength); + return true; + + + } + cout << "unknown layer"< 0) { + nukeSize=packetLength; + if (nukeSize > _NUKE_BUFFER_SIZE) { + nukeSize=_NUKE_BUFFER_SIZE; + } + input->read(nukeBuffer,nukeSize); + packetLength-=nukeSize; + } +} + + + +int MpegStreamPlayer::isInit() { + int audioDecoderState=audioDecoder->getStreamState(); + int videoDecoderState=videoDecoder->getStreamState(); + if ( (audioDecoderState != _STREAM_STATE_FIRST_INIT) && + (videoDecoderState != _STREAM_STATE_FIRST_INIT) ) { + return true; + } + return false; +} + +/** + here we make sure that our plugins make + a clean shutdown for a seek request. +*/ +void MpegStreamPlayer::processThreadCommand(Command* command) { + + int id=command->getID(); + + switch(id) { + case _COMMAND_NONE: + break; + case _COMMAND_PAUSE: + case _COMMAND_PLAY: + audioDecoder->insertAsyncCommand(command); + videoDecoder->insertAsyncCommand(command); + break; + case _COMMAND_CLOSE: + audioDecoder->close(); + videoDecoder->close(); + break; + case _COMMAND_SEEK: { + Command cmd1(_COMMAND_PAUSE); + audioDecoder->insertAsyncCommand(&cmd1); + videoDecoder->insertAsyncCommand(&cmd1); + + Command cmd2(_COMMAND_RESYNC_START); + audioDecoder->insertAsyncCommand(&cmd2); + videoDecoder->insertAsyncCommand(&cmd2); + + seekPos=command->getIntArg(); + break; + } + default: + cout << "unknown command id in Command::print"<writeToDisk=lwriteToDisk; +} + + +int MpegStreamPlayer::getWriteToDisk() { + return writeToDisk; +} + + +int MpegStreamPlayer::hasEnd() { + audioInput->close(); + videoInput->close(); + TimeWrapper::usleep(100000); + if (audioInput->getFillgrade()>0) { + return false; + } + if (videoInput->getFillgrade()>0) { + return false; + } + return true; +} + + + +int MpegStreamPlayer::insertAudioData(MpegSystemHeader* header,int len) { + + audioPacketCnt++; + packetCnt++; + timeStampAudio->setVideoFrameCounter(0); + + timeStampAudio->setPTSFlag(false); + if (header->getPTSFlag()==true) { + + timeStampAudio->setPTSFlag(true); + + double pts=header->getPTSTimeStamp(); + double scr=header->getSCRTimeStamp(); + + if (pts==timeStampAudio->getPTSTimeStamp()) { + cout << "(audio) old PTS == NEW PTS"<setSCRTimeStamp(scr); + timeStampAudio->setPTSTimeStamp(pts); + } + + timeStampAudio->setSyncClock(syncClock); + + + finishAudio(len); + + return true; +} + + +int MpegStreamPlayer::insertVideoData(MpegSystemHeader* header,int len) { + + videoPacketCnt++; + packetCnt++; + timeStampVideo->setVideoFrameCounter(0); + timeStampVideo->setPTSFlag(false); + if (header->getPTSFlag()==true) { + timeStampVideo->setPTSFlag(true); + + double pts=header->getPTSTimeStamp(); + double scr=header->getSCRTimeStamp(); + double dts=header->getDTSTimeStamp(); + + if (pts==timeStampVideo->getPTSTimeStamp()) { + cout << "(video) old PTS == NEW PTS"<setSCRTimeStamp(scr); + timeStampVideo->setPTSTimeStamp(pts); + timeStampVideo->setDTSTimeStamp(dts); + } + + + timeStampVideo->setSyncClock(syncClock); + + finishVideo(len); + + return true; +} + +int MpegStreamPlayer::insertAudioDataRaw(unsigned char* input, + int len,TimeStamp* stamp) { + audioInput->write((char*)input,len,stamp); + if (writeToDisk==true) { + FILE* audio=fopen("audio.mpg","a+"); + fwrite(input,1,len,audio); + fclose(audio); + } + return true; +} + + +int MpegStreamPlayer::insertVideoDataRaw(unsigned char* input, + int len,TimeStamp* stamp) { + + videoInput->write((char*)input,len,stamp); + if (writeToDisk==true) { + FILE* video=fopen("video.mpg","a+"); + fwrite(input,1,len,video); + fclose(video); + } + + return true; +} + + +void MpegStreamPlayer::dumpData(MpegSystemHeader* mpegSystemHeader) { + + int packetLength=mpegSystemHeader->getPacketLen(); + + unsigned char* packetBuffer= new unsigned char[packetLength]; + input->read((char*)packetBuffer,packetLength); + int cnt; + for(cnt=0;cnt < packetLength;cnt++) { + printf(" %2x ",packetBuffer[cnt]); + if ((cnt+1)%16 == 0) { + printf("\n"); + } + } + + printf("\n"); + cout << "**************************************** packt Dump"<getStreamState(); + if (resyncState != _STREAM_STATE_RESYNC_COMMIT) { + if (writeToDisk==true) { + char* buf=new char[len]; + len=input->read(buf,len); + insertAudioDataRaw((unsigned char*) buf,len,timeStampAudio); + delete buf; + } else { + audioInput->write(input,len,timeStampAudio); + } + + } else { + //cout << "throw away audio"<getStreamState(); + if (resyncState != _STREAM_STATE_RESYNC_COMMIT) { + if (writeToDisk==true) { + char* buf=new char[len]; + len=input->read(buf,len); + insertVideoDataRaw((unsigned char*)buf,len,timeStampVideo); + delete buf; + } else { + videoInput->write(input,len,timeStampVideo); + } + + } else { + //cout <<"throw away video"<