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) | AM_CPPFLAGS = $(MIST_CFLAGS) | ||||||
| LDADD = $(MIST_LIBS) | LDADD = $(MIST_LIBS) | ||||||
| SUBDIRS=converters analysers | 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_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 | MistBuffer_LDADD=$(MIST_LIBS) -lpthread | ||||||
| MistController_SOURCES=controller.cpp ../VERSION ./server.html.h | 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 | MistConnHTTP_LDADD=$(MIST_LIBS) -lpthread | ||||||
| MistConnHTTPProgressive_SOURCES=conn_http_progressive.cpp ../VERSION | MistConnHTTPProgressive_SOURCES=conn_http_progressive.cpp ../VERSION | ||||||
| MistConnHTTPDynamic_SOURCES=conn_http_dynamic.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 | 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 | 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