player: initial implementation
This commit is contained in:
		
							parent
							
								
									beca2400dd
								
							
						
					
					
						commit
						21f6a1fe9d
					
				
					 3 changed files with 152 additions and 1 deletions
				
			
		|  | @ -8,7 +8,7 @@ EXTRA_DIST=server.html server.html.h embed.js.h | |||
| AM_CPPFLAGS = $(MIST_CFLAGS) | ||||
| LDADD = $(MIST_LIBS) | ||||
| SUBDIRS=converters analysers | ||||
| bin_PROGRAMS=MistBuffer MistController MistConnRAW MistConnRTMP MistConnHTTP MistConnHTTPProgressive MistConnHTTPDynamic | ||||
| bin_PROGRAMS=MistBuffer MistController MistConnRAW MistConnRTMP MistConnHTTP MistConnHTTPProgressive MistConnHTTPDynamic MistPlayer | ||||
| MistBuffer_SOURCES=buffer.cpp buffer_user.h buffer_user.cpp buffer_stream.h buffer_stream.cpp tinythread.cpp tinythread.h ../VERSION | ||||
| MistBuffer_LDADD=$(MIST_LIBS) -lpthread | ||||
| MistController_SOURCES=controller.cpp ../VERSION ./server.html.h | ||||
|  | @ -18,6 +18,8 @@ MistConnHTTP_SOURCES=conn_http.cpp tinythread.cpp tinythread.h ../VERSION ./embe | |||
| MistConnHTTP_LDADD=$(MIST_LIBS) -lpthread | ||||
| MistConnHTTPProgressive_SOURCES=conn_http_progressive.cpp ../VERSION | ||||
| MistConnHTTPDynamic_SOURCES=conn_http_dynamic.cpp ../VERSION | ||||
| MistPlayer_SOURCES=player.h player.cpp | ||||
| MistPlayer_LDADD=$(MIST_LIBS) | ||||
| 
 | ||||
| lspSOURCES=$(lspdir)/jquery.js $(lspdir)/placeholder.js $(lspdir)/md5.js $(lspdir)/main.js $(lspdir)/functions.js | ||||
| lspDATA=$(lspdir)/header.html $(lspdir)/style.css $(lspdir)/footer.html | ||||
|  |  | |||
							
								
								
									
										124
									
								
								src/player.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								src/player.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,124 @@ | |||
| 
 | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| #include <algorithm> | ||||
| 
 | ||||
| #include <sys/time.h> | ||||
| #include <mist/dtsc.h> | ||||
| #include "player.h" | ||||
| 
 | ||||
| namespace Player{ | ||||
|   ///\todo Make getNowMS available in a library
 | ||||
|   /// Gets the current system time in milliseconds.
 | ||||
|   long long int getNowMS(){ | ||||
|     timeval t; | ||||
|     gettimeofday(&t, 0); | ||||
|     return t.tv_sec * 1000 + t.tv_usec/1000; | ||||
|   }//getNowMS
 | ||||
| 
 | ||||
|   File::File(std::string filename){ | ||||
|     stream = new DTSC::Stream(5); | ||||
|     ring = NULL;// ring will be initialized when necessary
 | ||||
|     fileSrc.open(filename.c_str(), std::ifstream::in | std::ifstream::binary); | ||||
|     std::cout.setf(std::ios::unitbuf);//do not choke
 | ||||
|     nextPacket();// initial read always returns nothing
 | ||||
|     if (!nextPacket()){//parse metadata
 | ||||
|       std::cout << stream->outHeader(); | ||||
|     } else { | ||||
|       std::cerr << "Error: Expected metadata!" << std::endl; | ||||
|     } | ||||
|   }; | ||||
|   File::~File() { | ||||
|     if (ring) { | ||||
|       stream->dropRing(ring); | ||||
|       ring = NULL; | ||||
|     } | ||||
|     delete stream; | ||||
|   } | ||||
|   // \returns True if there is a packet available for pull.
 | ||||
|   bool File::nextPacket(){ | ||||
|     if (fileSrc.good()){ | ||||
|       if (stream->parsePacket(inBuffer)){ | ||||
|         return true; | ||||
|       } else { | ||||
|         char buffer[1024 * 10]; | ||||
|         fileSrc.read(buffer, sizeof(buffer)); | ||||
|         inBuffer.append(buffer, fileSrc.gcount()); | ||||
|       } | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
|   void File::seek(int position){ | ||||
|     // XXX: implement seek.
 | ||||
|   }; | ||||
|   std::string * File::getPacket(){ | ||||
|     if (ring->waiting){ | ||||
|       return NULL; | ||||
|     }//still waiting for next buffer?
 | ||||
|     if (ring->starved){ | ||||
|       //if corrupt data, warn and get new DTSC::Ring
 | ||||
|       std::cerr << "Warning: User was send corrupt video data and send to the next keyframe!" << std::endl; | ||||
|       stream->dropRing(ring); | ||||
|       ring = stream->getRing(); | ||||
|       return NULL; | ||||
|     } | ||||
|     //switch to next buffer
 | ||||
|     if (ring->b < 0){ | ||||
|       ring->waiting = true; | ||||
|       return NULL; | ||||
|     }//no next buffer? go in waiting mode.
 | ||||
|     // get current packet
 | ||||
|     std::string * packet = &stream->outPacket(ring->b); | ||||
|     // make next request take a different packet
 | ||||
|     ring->b--; | ||||
|     return packet; | ||||
|   } | ||||
| 
 | ||||
|   /// Reads a command from stdin. Returns true if a command was read.
 | ||||
|   bool File::readCommand() { | ||||
|     // XXX: implement seek.
 | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   void File::Play() { | ||||
|     long long now, timeDiff = 0, lastTime = 0; | ||||
|     while (fileSrc.good()) { | ||||
|       if (readCommand()) { | ||||
|         continue; | ||||
|       } | ||||
|       now = getNowMS(); | ||||
|       if (now - timeDiff >= lastTime || lastTime - (now - timeDiff) > 5000) { | ||||
|         if (nextPacket()) { | ||||
|           std::string * packet; | ||||
|           if (!ring){ring = stream->getRing();}//get ring after reading first non-metadata
 | ||||
|           packet = getPacket(); | ||||
|           if (!packet){ | ||||
|             continue; | ||||
|           } | ||||
|           lastTime = stream->getTime(); | ||||
|           if (std::abs(now - timeDiff - lastTime) > 5000) { | ||||
|             timeDiff = now - lastTime; | ||||
|           } | ||||
|           std::cout.write(packet->c_str(), packet->length()); | ||||
|         } | ||||
|       } else { | ||||
|         usleep(std::min(999LL, lastTime - (now - timeDiff)) * 1000); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| int main(int argc, char** argv){ | ||||
|   if (argc < 2){ | ||||
|     std::cerr << "Usage: " << argv[0] << " filename.dtsc" << std::endl; | ||||
|     return 1; | ||||
|   } | ||||
|   std::string filename = argv[1]; | ||||
|   #if DEBUG >= 3 | ||||
|   std::cerr << "VoD " << filename << std::endl; | ||||
|   #endif | ||||
|   Player::File file(filename); | ||||
|   file.Play(); | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										25
									
								
								src/player.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/player.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | |||
| /// \file player.h
 | ||||
| /// Provides functionality for playing files for Video on Demand
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "buffer_stream.h" | ||||
| 
 | ||||
| namespace Player{ | ||||
|   class File{ | ||||
|   private: | ||||
|     std::ifstream fileSrc; ///<File handle of the input file.
 | ||||
|     std::string inBuffer; ///<Buffer of unprocessed bytes read from input.
 | ||||
|     DTSC::Stream * stream; | ||||
|     DTSC::Ring * ring; | ||||
|     bool nextPacket(); ///<Pulls the next packet into the queue.
 | ||||
|     bool getPacketFromInput(); ///<Attempts to retrieve a packet from input.
 | ||||
|     bool readCommand(); | ||||
|   public: | ||||
|     File(std::string filename); ///<Attempts to open a DTSC file
 | ||||
|     void Play(); | ||||
|     ~File(); | ||||
|     void seek(int position); | ||||
|     std::string * getPacket(); | ||||
|   }; | ||||
| }; | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Peter Wu
						Peter Wu