00001 /* 00002 * Copyright (C) 2009, Edmundo Albuquerque de Souza e Silva. 00003 * 00004 * This file may be distributed under the terms of the Q Public License 00005 * as defined by Trolltech AS of Norway and appearing in the file 00006 * LICENSE.QPL included in the packaging of this file. 00007 * 00008 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING 00009 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00010 * PURPOSE. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, 00011 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING 00012 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 00013 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 00014 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00015 * 00016 */ 00017 00018 #ifndef __RIOMMVIDEO_H_ 00019 #define __RIOMMVIDEO_H_ 00020 00021 #include <qstring.h> 00022 #include <qstringlist.h> 00023 #include <qptrstack.h> 00024 00025 #include "RioMMExplorer.h" 00026 #include "RioTimer.h" 00027 #include "common.h" 00028 #include "ConfigData.h" 00029 00030 #define READFROM_BUFFER 0x0 00031 #define READFROM_SERVER 0x1 00032 00033 #define RIOXINE_PLAYER "RIOxine" 00034 #define MPLAYER_PLAYER "MPlayer" 00035 00036 const int MaxPipeDataSize = 1024; 00037 const unsigned int maxBlockTime = 1000000; 00038 const unsigned int minBlockTime = 500000; 00039 00040 typedef enum 00041 { 00042 EVENT_PAUSE, 00043 EVENT_GOTO 00044 } PlayThreadEventType; 00045 00046 00047 class PlayThreadEvent 00048 { 00049 public: 00050 PlayThreadEventType event; //evento a ser processado 00051 int source; //bloco que estava sendo tocado no momento 00052 //da requisição 00053 int target; //bloco destino da requisição 00054 }; 00055 00056 00057 00058 class RioMMInterface; 00059 00060 class CRioMMVideo : public CRioMMObject 00061 { 00062 private: 00063 bool readSettings( void ); 00064 void writeDefaultSettings( void ); 00065 RioMMInterface *riomminterface; // gui - interface 00066 bool makeLog; 00067 QString logData; 00068 QString logAppend; 00069 QString logAction; 00070 pthread_mutex_t log_mutex;//mutex usado para controlar o acesso 00071 //paralelos às variáveis logData, logAppend e 00072 //logAction 00073 00074 QPtrStack<PlayThreadEvent> PTEventStack; //pilha de eventos da PlayThread 00075 bool DealPendentEvents();//Evento que trata os eventos da pilha PTEventStack 00076 00077 protected: 00078 int pipe_player[ 2 ];//pipe used to send data to 00079 //player 00080 char pipe_buffer[ MaxPipeDataSize ]; 00081 pid_t playerPID; // player Process id 00082 unsigned int PlayBuffer; // Current block being played 00083 RioBlock NextRequestBlock;// next block to be fetched 00084 int target;// bloco do grupo no momento da entrada no 00085 //grupo. Com ele cliente pode saber se já 00086 //alcançou o grupo. 00087 pthread_t PlayThreadID; 00088 bool Paused; 00089 unsigned int req_block; 00090 bool patching; ///Informa se cliente está em patching 00091 QStringList *playerCmdLine; 00092 bool connectPI; 00093 int PID; 00094 int ReadFrom; //Informa se o cliente está 00095 //obtendo blocos do servidor 00096 //(READFROM_SERVER) ou da 00097 //cache(READFROM_BUFFER) 00098 QString piHost; 00099 bool WaitingPrefetch; 00100 pthread_mutex_t PlayPauseMutex; 00101 pthread_mutex_t PrefetchMutex; 00102 bool HasSubTitle; 00103 bool useCache; 00104 QString User; 00105 #ifdef RIO_EMUL 00106 QString logPath; 00107 #endif 00108 QString player; 00109 RioFile *subTitle; 00110 CRioTimer timer; 00111 CommunicationStream *CommMultiStream; 00112 RioCallBackTransport callback_transport; 00113 RioMMExplorer *rioMMExplorer; 00114 00115 #ifdef RIO_EMUL 00116 char LOGARRIVAL[100]; 00117 unsigned int calculeted_time; 00118 unsigned int play_time; 00119 int delayed_blocks; 00120 int lost_blocks; 00121 ofstream m_log; 00122 bool Stopped; 00123 int multicast; 00124 struct timeval final_block_time; 00125 struct timeval timer_before; 00126 struct timeval timer_after; 00127 struct timeval diff_timer; 00128 #endif 00129 // Variavel booleana que indica o status (sucesso ou erro de conexao) 00130 // ao pedirmos um bloco a partir da funcao ReadBlock 00131 bool ReadBlockStatus; 00132 00133 void StartPlayer( void ); 00134 00135 /***************************************************************************/ 00136 /* Request next block to the server. The block returned by the server will */ 00137 /* placed in slot index of Request buffer. This function returns true if */ 00138 /* the requested block exists in server, i. e., if it is lesser than the */ 00139 /* total blocks stored on server, otherwise it returns false. */ 00140 /***************************************************************************/ 00141 bool ReadNextBlock( unsigned int ); 00142 00143 /** 00144 * PlayThread controla a execução do vídeo e a recuperação dos blocos a serem 00145 * tocados no momento da sua execução invocando, quando necessário, os métodos 00146 * que manipulam requisições e recuperações de blocos no servidor e/ou em disco. 00147 * @param videoObject é um ponteiro para esta instância da RioMMVideo pois uma 00148 * thread precisa disto para acessar os membros e demais métodos desta classe. 00149 */ 00150 static void *PlayThread( void * ); 00151 00152 static void PlayThreadCleanup( void * ); 00153 00154 /** 00155 * WaitFullBuffer requisita o número de blocos suficiente para encher o buffer 00156 * e espera até que os mesmos cheguem para, então, liberar o mutex da 00157 * playthread, mas se os blocos demorarem muito (na WaitPrefetch), então a 00158 * FreeBlock é chamada para os fragmentos recebidos e o cliente toca tais 00159 * fragmentos dando continuidade à execução do vídeo. 00160 * Este método só é chamado na GoTo. O cliente esvazia o buffer e fica 00161 * aguardando os blocos iniciais. 00162 * @return retorna false caso WaitPrefetch() ou Move_Prefetch() retornem false 00163 * e retorna true caso contrário. 00164 */ 00165 bool WaitFullBuffer(); 00166 00167 /** 00168 * WaitMulticastBlocks verifica se os blocos esperados se encontram na cache. 00169 * Caso positivo ela retorna imediatamente. Caso negativo ela aguarda os blocos 00170 * chegarem por um determinado período. 00171 * Este método só é chamado na WaitBlocks. 00172 * Este método é executado por um membro de um grupo que pode virar líder. 00173 * Esperando encher buffer... 00174 */ 00175 bool WaitMulticastBlocks(); 00176 00177 /** 00178 * Leader_WaitMulticastBlocks é a função de espera de blocos executada por um 00179 * líder (apenas o líder pode executar este método). Este método verifica se tem 00180 * blocos necessários para encher o PlayOutBuffer. Caso não tenha, verifica se 00181 * tem fragmentos (chamando a CallFreeBlock). Caso ainda assim não tenha nada, 00182 * então solicita o(s) bloco(s) que não tenha ao servidor (pela ReadBlock). 00183 * No caso de este método não conseguir recuperar nenhum bloco ou nenhum 00184 * fragento na CallFreeBlock, então esperará pelos blocos solicitados na 00185 * (terceira situação descrita acima) até um limite de tempo. Se este limite for 00186 * ultrapassado então CallFreeBlock será chamado para estes blocos. 00187 * Nota: Este método só é chamado na WaitBlocks. 00188 * @return true caso algum bloco esteja disponível para ser tocado e false caso 00189 * contrário. 00190 */ 00191 bool Leader_WaitMulticastBlocks(); 00192 00193 /** 00194 * WaitBlocks aguarda a chegada dos blocos solicitados de acordo com o contexto 00195 * do cliente. Se for um cliente conectado à PL e for líder, WaitBlocks chama 00196 * Leader_WaitMulticastBlocks; caso seja um cliente conectado à PL mas não líder 00197 * e não estiver em patching, WaitBlocks chama WaitMulticastBlocks. 00198 * Se cliente estiver conectado à PL mas estiver em patching, CallFreeBlock é 00199 * chamada se o bloco não estiver em disco. O mesmo acontece para o cliente que 00200 * não estiver conectado à PL. 00201 * Nota: WaitBlocks só é chamada na PlayThread(). 00202 * @return retorna true se Leader_WaitMulticastBlocks ou WaitMulticastBlocks 00203 * falharem ou false caso contrário. 00204 */ 00205 bool WaitBlocks(); 00206 00207 /** 00208 * CallFreeBlock chama a FreeBlock para liberar os fragmentos do bloco referente 00209 * à posição PlayBuffer do buffer (Request[ PlayBuffer].Block) que já tiverem 00210 * chegado. 00211 * @param PlayBuffer indica o bloco cujos fragmentos se quer liberar para 00212 * exibição imediata. 00213 * @return retorna true caso consiga liberar os fragmentos ou false caso os 00214 * mesmos não esteja disponíveis. 00215 */ 00216 bool CallFreeBlock( int ); 00217 00218 bool ReadBlock( int, RioBlock, RioStreamType, int, int ); 00219 00220 public: 00221 #ifdef RIO_EMUL 00222 struct print_log 00223 { 00224 struct timeval arrival_time; 00225 struct timeval call_time; 00226 int block; 00227 }; 00228 00229 struct print_log *timers; 00230 struct timeval initial_time; 00231 struct timeval final_time; 00232 #endif 00233 00234 bool waitingMSGCODE_IP; 00235 bool first; 00236 bool signal; 00237 int my_address; 00238 int my_port; 00239 int wId; 00240 bool syncOn; 00241 CRioStream Stream; 00242 pthread_mutex_t multicastMutex; 00243 pthread_cond_t multicastCondition; 00244 00245 /** 00246 * CRioMMVideo é o construtor da classe CRioMMVideo. 00247 * @param block Informa em qual bloco deve ser iniciada a exibição do vídeo. 00248 * @param videoname Informa o nome do vídeo no servidor que o cliente quer 00249 * assistir. 00250 * @param numBuffers Informa o tamanho do PlayOutBuffer do cliente. 00251 * @param rio é um ponteiro para a RioMMInterface e serve para o cliente ter 00252 * acesso aos métodos e membros da mesma. 00253 * @param config Informa as opções passadas como parâmetro na chamada do 00254 * cliente pelo shell. 00255 * @param rioMMExplorer é um ponteiro para a classe rioMMExplorer que 00256 * possibilita manipulação de arquivos no servidor bem como transferência de 00257 * arquivos entre o servidor e o sistema local. 00258 */ 00259 CRioMMVideo( char *, unsigned int, RioBlock, 00260 struct timeval RTT_average,RioMMInterface*, int block, 00261 ConfigData*, RioMMExplorer* ); 00262 ~CRioMMVideo(); 00263 00264 /** 00265 * Prefetch só é chamada quando o cliente esta no inicio (play). Neste caso ela 00266 * faz tantas requisições de blocos quantas forem necessárias para encher o 00267 * PlayOutBuffer do cliente. 00268 */ 00269 virtual void Prefetch( void ); 00270 00271 /** 00272 * Move_Prefetch faz o mesmo que o metodo Prefetch com a diferenca de que nao 00273 * precisa se conectar na PI pois isto ja esta feito. 00274 * Nota: Move_Prefetch() só é chamada pela WaitFullBuffer(). 00275 * @return retorna true se a chamada a ReadNextBlock retornar 00276 * true (ou se ReadNextBlock não for chamada) e false caso contrário. 00277 */ 00278 bool Move_Prefetch( void ); 00279 00280 /** 00281 * PlayBlock escreve o bloco buf, de tamanho size, no buffer do mplayer para ser 00282 * tocado imediatamente. 00283 * @param buf são os dados a serem gravados no pipe do mplayer. 00284 * @param size é a quantidade de dados em bytes a ser escrita no buffer do 00285 * mplayer. 00286 */ 00287 void PlayBlock( int, int ); 00288 00289 void FastForward( void ); 00290 void FastRewind( void ); 00291 00292 /** 00293 * GoTo coloca o evento EVENT_GOTO na pilha de eventos tratada pela PlayThread. 00294 * Assim que a PlayThread ler este evento ela fará o salto para o bloco indicado 00295 * pelo parâmetro block e tomará as medidas cabíveis para encher o 00296 * PlayOutBuffer. 00297 * @param block informa para qual bloco a aplicação deve ser direcionada, isto 00298 * é, dada a interação do usuário, qual o próximo bloco deve ser tocado (caso o 00299 * cliente já o tenha em disco) ou solicitado ao servidor (se o cliente não 00300 * tiver o bloco em disco). Neste último caso, Move_Prefetch é chamada para que 00301 * o cliente encha o PlayOutBuffer antes de prosseguir com a execução do vídeo. 00302 */ 00303 void GoTo( RioBlock ); 00304 00305 /** 00306 * Play() inicia a execução do vídeo criando uma PlayThread, caso cliente ainda 00307 * não tenha inicializado, ou dá prosseguimento à execução da mesma caso o 00308 * cliente esteja em estado de pausa. 00309 */ 00310 void Play( void ); 00311 00312 /** 00313 * Pause coloca o evento EVENT_PAUSE na pilha de eventos tratada pela PlayThread. 00314 * Assim que a PlayThread ler este evento ela suspenderá temporariamente a execução 00315 * do vídeo no cliente mas não matará a PlayThread. 00316 */ 00317 void Pause( void ); 00318 00319 /** 00320 * Stop finaliza a execução do vídeo e mata a PlayThread em execução. 00321 */ 00322 void Stop( void ); 00323 00324 #ifdef RIO_EMUL 00325 void Quit( void ); 00326 #endif 00327 00328 /** 00329 * init faz inicializações da conexão com a PL (se o cliente estiver com 00330 * connectPI == true) e inicializa os membros first, my_address e my_port. 00331 * @return retorna 1 caso não consiga criar a startReceiveThread da 00332 * CommMultiStream ou não consiga abrir o socket com a CommMultiStream e retorna 00333 * 0 caso contrário. 00334 */ 00335 int init( void ); 00336 00337 /** 00338 * WaitPrefetch apenas aguarda os blocos solicitados pela Prefetch. 00339 * Nesta funcao, quando ocorre um timeout, ele simplesmente ignora o que 00340 * não chegou e inicia a exibição, mesmo sem o buffer completo. Isto não é um 00341 * erro, mas decidiu-se que nao valia a pena aumentar o startup delay do 00342 * cliente para encher completamente o buffer. 00343 * Nota: WaitPrefetch() só é chamada na WaitFullBuffer e no início da 00344 * PlayThread() como fruto de chamada a Prefetch() ou Move_Prefetch(). 00345 * @return true se há algum bloco, ainda que fragmentado, disponível para ser 00346 * tocado e false caso contrário. 00347 */ 00348 bool WaitPrefetch(); 00349 00350 /** 00351 * WaitEndOfVideo aguarda que o mplayer seja finalizado por detecção de EOF 00352 * (término do arquivo de vídeo). Este método deve ser utilizado no momento de 00353 * se mandar tocar o último bloco a fim de que a PlayThread aguarde o mplayer 00354 * terminar a exibição do último bloco de vídeo antes de ser finalizada. 00355 */ 00356 void WaitEndOfVideo( void ); 00357 00358 int GetSubTitles( RioAccess, CRioStream * ); 00359 00360 //Mutex's handlers 00361 /** 00362 * PrefetchMutexLock trava o mutex PrefetchMutex. 00363 * @param msg é usado apenas no modo RIO_DEBUG2 para facilitar depurações de 00364 * clientes travados em mutex's. 00365 */ 00366 void PrefetchMutexLock( string msg = "" ); 00367 00368 /** 00369 * PrefetchMutexUnlock destrava o mutex PrefetchMutex. 00370 * @param msg é usado apenas no modo RIO_DEBUG2 para facilitar depurações de 00371 * clientes travados em mutex's. 00372 */ 00373 void PrefetchMutexUnlock( string msg = "" ); 00374 00375 /** 00376 * MulticastMutexLock trava o mutex multicastMutex. 00377 * @param msg é usado apenas no modo RIO_DEBUG2 para facilitar depurações de 00378 * clientes travados em mutex's. 00379 */ 00380 void MulticastMutexLock( string msg = "" ); 00381 00382 /** 00383 * MulticastMutexUnlock destrava o mutex multicastMutex. 00384 * @param msg é usado apenas no modo RIO_DEBUG2 para facilitar depurações de 00385 * clientes travados em mutex's. 00386 */ 00387 void MulticastMutexUnlock( string msg = "" ); 00388 00389 /** 00390 * MulticastWaitCondition trava o cliente aguardando a execução da 00391 * MulticastReleaseCondition. 00392 * @param msg é usado apenas no modo RIO_DEBUG2 para facilitar depurações de 00393 * clientes travados em mutex's. 00394 */ 00395 void MulticastWaitCondition( string msg = "" ); 00396 00397 /** 00398 * MulticastReleaseCondition libera a execução do cliente travado pela execução 00399 * da MulticastWaitCondition. 00400 * @param msg é usado apenas no modo RIO_DEBUG2 para facilitar depurações de 00401 * clientes travados em mutex's. 00402 */ 00403 void MulticastReleaseCondition( string msg = "" ); 00404 00405 /** 00406 * PlayPauseMutexLock trava o mutex PlayPauseMutex. 00407 * @param msg é usado apenas no modo RIO_DEBUG2 para facilitar depurações de 00408 * clientes travados em mutex's. 00409 */ 00410 void PlayPauseMutexLock( string msg = "" ); 00411 00412 /** 00413 * PlayPauseMutexUnlock destrava o mutex PlayPauseMutex. 00414 * @param msg é usado apenas no modo RIO_DEBUG2 para facilitar depurações de 00415 * clientes travados em mutex's. 00416 */ 00417 void PlayPauseMutexUnlock( string msg = "" ); 00418 00419 /** 00420 * GetCurrentPosition retorna o número do bloco que está sendo tocado neste 00421 * momento. 00422 * @return retorna o valor do membro CurrentBlock. 00423 */ 00424 RioBlock GetCurrentPosition( void ); //Returns the current block 00425 //being played 00426 /** 00427 * GetTotalPositions retorna o tamanho total do vídeo em número de blocos. 00428 * @return retorna o valor do membro TotalBlocks. 00429 */ 00430 RioBlock GetTotalPositions( void ); // Returns the total of blocks 00431 00432 #ifdef RIO_DEBUG2 00433 /** 00434 * getMode retorna o atual papel do cliente no sistema: PASSIVE, LEADER, 00435 * SUBLEADER, INACTIVE ou UNAVAILABLE. Esta informação é obtida da tabela da 00436 * CommMultiStream, que armazena esta e outras informações a respeito do 00437 * cliente. 00438 * @return retorna o papel atual do cliente no sistema. 00439 */ 00440 ClientMode getMode( void ); 00441 #endif 00442 00443 /** 00444 * isFirst verifica se o cliente detém algum tipo de liderança (se é líder ou 00445 * sublíder) e retorna true, caso positivo ou false, caso negativo. 00446 * @return true se cliente for líder ou sublíder e false caso contrário. 00447 */ 00448 bool isFirst( void); 00449 static void MulticastCallBack( void *parm, int result ); 00450 00451 /** 00452 * CallBack é chamada toda vez que um bloco unicast chegou e está pronto pra 00453 * ser tocado (seja por ter chegado intacto ou via FreeBlock). Este método 00454 * grava os dados recebidos na memória cache (disco) pois já tem os dados 00455 * gravados no PlayOutBuffer (a RioNeti o faz). 00456 * @param request ponteiro para a requisição de bloco que acabou de ser 00457 * atendida (bloco pronto pra ser tocado). 00458 */ 00459 static void CallBack( struct RioRequest *request ); 00460 00461 void SetTarget( int target ); 00462 void SetNextRequestBlock( int block ); 00463 00464 /** 00465 * GetNextRequestBlock retorna o próximo bloco a ser requisitado para o 00466 * PlayOutBuffer. 00467 * @return retorna o valor do membro NextRequestBlock. 00468 */ 00469 RioBlock GetNextRequestBlock(); 00470 00471 void ClearBuffer(); 00472 void Stream_Control( string msg = "" ); 00473 bool isPatching(); 00474 00475 /** 00476 * Este metodo chama a FreeBlock da RioNetI que por sua vez verifica se chegaram 00477 * fragmentos do bloco apontado pela posicao PlayBuffer (parametro) do vetor 00478 * Request. Caso verdadeiro, os fragmentos sao gravados no buffer do cliente e 00479 * o bloco é liberado para ser tocado. 00480 * @param PlayBuffer é a posicao do vetor Request que aponta para o bloco cujos 00481 * fragmentos, caso existam, devem ser liberados. 00482 * @return retorna o tamanho em bytes do bloco recuperado. 00483 */ 00484 int FreeBlock( int PlayBuffer ); 00485 00486 int FreePendentBlocks( bool useCache, int nBuffers ); 00487 00488 /** 00489 * thereAreFragments verifica se existem fragmentos para o bloco fornecido no 00490 * parametro block. 00491 * @param block Bloco a ser pesquisado se já existem fragmentos para ele. 00492 * @return true caso encontre fragmentos para o bloco e false caso contrário. 00493 */ 00494 bool thereAreFragments( RioBlock block ); 00495 00496 void SetWID( int ); 00497 int ProcessSignal( int, void * ); 00498 void appendLog( QString ); 00499 void inputLog( QString ); 00500 void inputLog( int, unsigned int = 0, unsigned int = 0 ); 00501 unsigned int getCurrentPlayingBlock(); 00502 const bool getmakeLog(); 00503 }; 00504 #endif