Projects
Essentials
lightspark
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 85
View file
lightspark.spec
Changed
@@ -24,7 +24,7 @@ %bcond_with rtmp %endif Name: lightspark -Version: 0.7.2.99+git20151003.1109 +Version: 0.7.2.99+git20151010.1946 Release: 0 Summary: Modern, free, open-source flash player implementation License: LGPL-3.0+
View file
lightspark.tar.xz/src/backends/netutils.cpp
Changed
@@ -245,7 +245,8 @@ cache(_cache), //CACHING owner(o), //PROGRESS redirected(false),requestStatus(0), //HTTP REDIR, STATUS & HEADERS - length(0) //DOWNLOADED DATA + length(0), //DOWNLOADED DATA + emptyanswer(false) { } @@ -261,7 +262,8 @@ cache(_cache), //CACHING owner(o), //PROGRESS redirected(false),requestStatus(0),requestHeaders(h),data(_data),//HTTP REDIR, STATUS & HEADERS - length(0) //DOWNLOADED DATA + length(0), //DOWNLOADED DATA + emptyanswer(false) { } @@ -391,7 +393,11 @@ setFailed(); } else if(getRequestStatus()/100 == 3) {;} //HTTP redirect - else if(getRequestStatus()/100 == 2) {;} //HTTP OK + else if(getRequestStatus()/100 == 2) //HTTP OK + { + if (getRequestStatus() == 204) + emptyanswer = true; + } } else { @@ -423,7 +429,10 @@ //Only read the length when we're not redirecting if(getRequestStatus()/100 != 3) { - setLength(atoi(headerValue.c_str())); + int len = atoi(headerValue.c_str()); + if (len == 0) + emptyanswer = true; + setLength(len); return; } }
View file
lightspark.tar.xz/src/backends/netutils.h
Changed
@@ -127,6 +127,8 @@ uint32_t length; //Set the length of the downloaded file, can be called multiple times to accomodate a growing file void setLength(uint32_t _length); + + bool emptyanswer; public: //This class can only get destroyed by DownloadManager derivate classes virtual ~Downloader(); @@ -138,6 +140,9 @@ //True if the download has finished //Can be used in conjunction with failed to find out if it finished successfully bool hasFinished() { return cache->hasTerminated(); } + + // true if status header is 204 or content-length header is 0 + bool hasEmptyAnswer() { return emptyanswer; } const tiny_string& getURL() { return url; }
View file
lightspark.tar.xz/src/scripting/flash/display/flashdisplay.cpp
Changed
@@ -330,8 +330,11 @@ // Wait for some data, making sure our check for failure is working sbuf->sgetc(); // peek one byte - if(downloader->getRequestStatus() == 204) // empty answer + if(downloader->hasEmptyAnswer()) + { + LOG(LOG_INFO,"empty answer:"<<url); return; + } if(cache->hasFailed()) //Check to see if the download failed for some reason {
View file
lightspark.tar.xz/src/scripting/flash/net/NetStreamInfo.cpp
Changed
@@ -81,17 +81,17 @@ ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,audioBufferByteLength); ASFUNCTIONBODY_GETTER(NetStreamInfo,audioBufferLength); ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,audioByteCount); -ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,audioBytesPerSecond); +ASFUNCTIONBODY_GETTER(NetStreamInfo,audioBytesPerSecond); ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,audioLossRate); -ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,byteCount); -ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,currentBytesPerSecond); +ASFUNCTIONBODY_GETTER(NetStreamInfo,byteCount); +ASFUNCTIONBODY_GETTER(NetStreamInfo,currentBytesPerSecond); ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,dataBufferByteLength); -ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,dataBufferLength); +ASFUNCTIONBODY_GETTER(NetStreamInfo,dataBufferLength); ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,dataByteCount); -ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,dataBytesPerSecond); +ASFUNCTIONBODY_GETTER(NetStreamInfo,dataBytesPerSecond); ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,droppedFrames); ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,isLive); -ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,maxBytesPerSecond); +ASFUNCTIONBODY_GETTER(NetStreamInfo,maxBytesPerSecond); ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,metaData); ASFUNCTIONBODY_GETTER(NetStreamInfo,playbackBytesPerSecond); ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,resourceName); @@ -100,7 +100,7 @@ ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,videoBufferByteLength); ASFUNCTIONBODY_GETTER(NetStreamInfo,videoBufferLength); ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,videoByteCount); -ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,videoBytesPerSecond); +ASFUNCTIONBODY_GETTER(NetStreamInfo,videoBytesPerSecond); ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,videoLossRate); ASFUNCTIONBODY_GETTER_NOT_IMPLEMENTED(NetStreamInfo,xmpData);
View file
lightspark.tar.xz/src/scripting/flash/net/URLStream.cpp
Changed
@@ -62,6 +62,7 @@ _R<MemoryStreamCache> cache(_MR(new MemoryStreamCache)); if(!createDownloader(cache, loader,this)) return; + data->setLength(0); bool success=false; if(!downloader->hasFailed()) @@ -116,7 +117,6 @@ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED); c->setDeclaredMethodByQName("load","",Class<IFunction>::getFunction(load),NORMAL_METHOD,true); c->setDeclaredMethodByQName("close","",Class<IFunction>::getFunction(close),NORMAL_METHOD,true); - c->setDeclaredMethodByQName("load","",Class<IFunction>::getFunction(load),NORMAL_METHOD,true); c->setDeclaredMethodByQName("bytesAvailable","",Class<IFunction>::getFunction(bytesAvailable),GETTER_METHOD,true); c->setDeclaredMethodByQName("endian","",Class<IFunction>::getFunction(_getEndian),GETTER_METHOD,true); c->setDeclaredMethodByQName("endian","",Class<IFunction>::getFunction(_setEndian),SETTER_METHOD,true);
View file
lightspark.tar.xz/src/scripting/flash/net/flashnet.cpp
Changed
@@ -1032,7 +1032,7 @@ NetStream::NetStream(Class_base* c):EventDispatcher(c),tickStarted(false),paused(false),closed(true), streamTime(0),frameRate(0),connection(),downloader(NULL),videoDecoder(NULL), audioDecoder(NULL),audioStream(NULL),datagenerationfile(NULL),datagenerationthreadstarted(false),client(NullRef), - oldVolume(-1.0),checkPolicyFile(false),rawAccessAllowed(false),framesdecoded(0),playbackBytesPerSecond(0), + oldVolume(-1.0),checkPolicyFile(false),rawAccessAllowed(false),framesdecoded(0),playbackBytesPerSecond(0),maxBytesPerSecond(0),datagenerationexpecttype(DATAGENERATION_HEADER),datagenerationbuffer(Class<ByteArray>::getInstanceS()), backBufferLength(0),backBufferTime(30),bufferLength(0),bufferTime(0.1),bufferTimeMax(0), maxPauseBufferTime(0) { @@ -1104,6 +1104,41 @@ { NetStream* th=Class<NetStream>::cast(obj); NetStreamInfo* res = Class<NetStreamInfo>::getInstanceS(); + if(th->isReady()) + { + res->byteCount = th->getReceivedLength(); + res->dataBufferLength = th->getReceivedLength(); + } + if (th->datagenerationfile) + { + int curbps = 0; + uint64_t cur=compat_msectiming(); + th->countermutex.lock(); + while (th->currentBytesPerSecond.size() > 0 && (cur - th->currentBytesPerSecond.front().timestamp > 1000)) + { + th->currentBytesPerSecond.pop_front(); + } + auto it = th->currentBytesPerSecond.cbegin(); + while (it != th->currentBytesPerSecond.cend()) + { + curbps += it->bytesread; + it++; + } + if (th->maxBytesPerSecond < curbps) + th->maxBytesPerSecond = curbps; + + res->currentBytesPerSecond = curbps; + res->dataBytesPerSecond = curbps; + res->maxBytesPerSecond = th->maxBytesPerSecond; + + //TODO compute video/audio BytesPerSecond correctly + res->videoBytesPerSecond = curbps*3/4; + res->audioBytesPerSecond = curbps/4; + + th->countermutex.unlock(); + } + else + LOG(LOG_NOT_IMPLEMENTED,"NetStreamInfo.currentBytesPerSecond/maxBytesPerSecond/dataBytesPerSecond is only implemented for data generation mode"); res->playbackBytesPerSecond = th->playbackBytesPerSecond; res->audioBufferLength = th->bufferLength; res->videoBufferLength = th->bufferLength; @@ -1332,8 +1367,9 @@ ASFUNCTIONBODY(NetStream,seek) { //NetStream* th=Class<NetStream>::cast(obj); - LOG(LOG_NOT_IMPLEMENTED,"NetStream.seek is not implemented yet"); - assert_and_throw(argslen == 1); + int pos; + ARG_UNPACK(pos); + LOG(LOG_NOT_IMPLEMENTED,"NetStream.seek is not implemented yet:"<<pos); return NULL; } @@ -1357,7 +1393,138 @@ { if (th->datagenerationfile) { - th->datagenerationfile->append(bytearray->getBuffer(bytearray->getLength(),false),bytearray->getLength()); + //th->datagenerationfile->append(bytearray->getBuffer(bytearray->getLength(),false),bytearray->getLength()); + th->datagenerationbuffer->setPosition(th->datagenerationbuffer->getLength()); + th->datagenerationbuffer->writeBytes(bytearray->getBuffer(bytearray->getLength(),false),bytearray->getLength()); + th->datagenerationbuffer->setPosition(0); + uint8_t tmp_byte = 0; + uint32_t processedlength = th->datagenerationbuffer->getPosition(); + bool done = false; + while (!done) + { + switch (th->datagenerationexpecttype) + { + case DATAGENERATION_HEADER: + { + // TODO check for correct header? + // skip flv header + th->datagenerationbuffer->setPosition(5); + uint32_t headerlen = 0; + // header length is always in big endian + if (!th->datagenerationbuffer->readByte(tmp_byte)) + { + done = true; + break; + } + headerlen |= tmp_byte<<24; + if (!th->datagenerationbuffer->readByte(tmp_byte)) + { + done = true; + break; + } + headerlen |= tmp_byte<<16; + if (!th->datagenerationbuffer->readByte(tmp_byte)) + { + done = true; + break; + } + headerlen |= tmp_byte<<8; + if (!th->datagenerationbuffer->readByte(tmp_byte)) + { + done = true; + break; + } + headerlen |= tmp_byte; + if (headerlen > 0) + { + th->datagenerationbuffer->setPosition(headerlen); + th->datagenerationexpecttype = DATAGENERATION_PREVTAG; + processedlength+= headerlen; + } + else + done = true; + break; + } + case DATAGENERATION_PREVTAG: + { + uint32_t tmp_uint32; + if (!th->datagenerationbuffer->readUnsignedInt(tmp_uint32)) // prevtag (value may be wrong as we don't check for big endian) + { + done = true; + break; + } + processedlength += 4; + th->datagenerationexpecttype = DATAGENERATION_FLVTAG; + break; + } + case DATAGENERATION_FLVTAG: + { + if (!th->datagenerationbuffer->readByte(tmp_byte)) // tag type + { + done = true; + break; + } + uint32_t datalen = 0; + if (!th->datagenerationbuffer->readByte(tmp_byte)) // data len 1 + { + done = true; + break; + } + datalen |= tmp_byte<<16; + if (!th->datagenerationbuffer->readByte(tmp_byte)) // data len 2 + { + done = true; + break; + } + datalen |= tmp_byte<<8; + if (!th->datagenerationbuffer->readByte(tmp_byte)) // data len 3 + { + done = true; + break; + } + datalen |= tmp_byte; + datalen += 1 + 3 + 3 + 1 + 3; + if (datalen + processedlength< th->datagenerationbuffer->getLength()) + { + processedlength += datalen; + th->datagenerationbuffer->setPosition(processedlength); + th->datagenerationexpecttype = DATAGENERATION_PREVTAG; + } + break; + } + default: + LOG(LOG_ERROR,"invalid DATAGENERATION_EXPECT_TYPE:"<<th->datagenerationexpecttype); + done = true; + break; + } + } + if (processedlength > 0) + { + th->datagenerationfile->append(th->datagenerationbuffer->getBuffer(processedlength,false),processedlength); + if (processedlength!=th->datagenerationbuffer->getLength()) + th->datagenerationbuffer->removeFrontBytes(processedlength); + else + th->datagenerationbuffer->setLength(0); + uint64_t cur=compat_msectiming(); + struct bytespertime b; + b.timestamp = cur; + b.bytesread = processedlength; + th->countermutex.lock(); + th->currentBytesPerSecond.push_back(b); + while (cur - th->currentBytesPerSecond.front().timestamp > 60000) + th->currentBytesPerSecond.pop_front(); + uint32_t curbps = 0; + auto it = th->currentBytesPerSecond.cbegin(); + while (it != th->currentBytesPerSecond.cend()) + { + curbps += it->bytesread; + it++; + } + if (th->maxBytesPerSecond < curbps) + th->maxBytesPerSecond = curbps; + + th->countermutex.unlock(); + } if (!th->datagenerationthreadstarted && th->datagenerationfile->getReceivedLength() >= 8192) { th->datagenerationthreadstarted = true; @@ -1377,13 +1544,17 @@ if (val == "resetBegin") { - LOG(LOG_INFO,"NetStream.appendBytesAction:"<<val<<" "<<th->url); if (th->datagenerationfile) delete th->datagenerationfile; th->datagenerationfile = new FileStreamCache; th->datagenerationfile->openForWriting(); + th->datagenerationbuffer->setLength(0); + } + else if (val == "resetSeek") + { + LOG(LOG_INFO,"resetSeek:"<<th->datagenerationbuffer->getLength()); + th->datagenerationbuffer->setLength(0); } - else LOG(LOG_NOT_IMPLEMENTED,"NetStream.appendBytesAction is not implemented yet:"<<val); return NULL; @@ -1435,7 +1606,7 @@ //Must have videoDecoder, but audioDecoder is optional (in //case the video doesn't have audio) return videoDecoder && videoDecoder->isValid() && - (!audioDecoder || audioDecoder->isValid()); + (!audioDecoder || audioDecoder->isValid()); } bool NetStream::lockIfReady() @@ -1513,6 +1684,7 @@ this->bufferLength = 0; countermutex.unlock(); bool done=false; + bool bufferfull = true; while(!done) { //Check if threadAbort has been called, if so, stop this loop @@ -1521,9 +1693,14 @@ done = true; continue; } - bool decodingSuccess=streamDecoder->decodeNextFrame(); - if(decodingSuccess==false) - done = true; + bool decodingSuccess= bufferfull && streamDecoder->decodeNextFrame(); + if(!decodingSuccess && bufferfull) + { + bufferfull = false; + this->incRef(); + getVm()->addEvent(_MR(this), + _MR(Class<NetStatusEvent>::getInstanceS("status", "NetStream.Buffer.Empty"))); + } else { if (streamDecoder->videoDecoder) @@ -1567,7 +1744,8 @@ if(audioStream==NULL && audioDecoder && audioDecoder->isValid() && getSys()->audioManager->pluginLoaded()) audioStream=getSys()->audioManager->createStreamPlugin(audioDecoder); - sendClientNotification("onMetaData", createMetaDataObject(streamDecoder)); + if(!datagenerationfile && bufferfull) + sendClientNotification("onMetaData", createMetaDataObject(streamDecoder)); tickStarted=true; this->incRef(); @@ -1578,6 +1756,13 @@ float localRenderRate=dmin(frameRate,24); getSys()->setRenderRate(localRenderRate); } + if (!bufferfull && ((framesdecoded / frameRate) >= this->bufferTime)) + { + bufferfull = true; + this->incRef(); + getVm()->addEvent(_MR(this), + _MR(Class<NetStatusEvent>::getInstanceS("status", "NetStream.Buffer.Full"))); + } profile->accountTime(chronometer.checkpoint()); if(threadAborting) throw JobTerminationException();
View file
lightspark.tar.xz/src/scripting/flash/net/flashnet.h
Changed
@@ -29,6 +29,7 @@ #include "backends/decoder.h" #include "backends/interfaces/audio/IAudioPlugin.h" #include "NetStreamInfo.h" +#include "scripting/flash/utils/ByteArray.h" namespace lightspark { @@ -276,7 +277,16 @@ uint32_t framesdecoded; uint32_t prevstreamtime; number_t playbackBytesPerSecond; - + number_t maxBytesPerSecond; + + struct bytespertime { + uint64_t timestamp; + uint32_t bytesread; + }; + std::deque<bytespertime> currentBytesPerSecond; + enum DATAGENERATION_EXPECT_TYPE { DATAGENERATION_HEADER=0,DATAGENERATION_PREVTAG,DATAGENERATION_FLVTAG }; + DATAGENERATION_EXPECT_TYPE datagenerationexpecttype; + _NR<ByteArray> datagenerationbuffer; ASObject *createMetaDataObject(StreamDecoder* streamDecoder); ASObject *createPlayStatusObject(const tiny_string& code);
View file
lightspark.tar.xz/src/scripting/flash/utils/ByteArray.cpp
Changed
@@ -633,6 +633,13 @@ bytes[position++] = b; } +void ByteArray::writeBytes(uint8_t *data, int length) +{ + getBuffer(position+length,true); + memcpy(bytes+position,data,length); + position+=length; +} + ASFUNCTIONBODY(ByteArray,writeByte) { ByteArray* th=static_cast<ByteArray*>(obj); @@ -1224,6 +1231,13 @@ s.read((char*)bytes+oldlen,length); unlock(); } +void ByteArray::removeFrontBytes(int count) +{ + memmove(bytes,bytes+count,count); + position -= count; + len -= count; +} + void ByteArray::compress_zlib()
View file
lightspark.tar.xz/src/scripting/flash/utils/ByteArray.h
Changed
@@ -57,6 +57,7 @@ bool readU29(uint32_t& ret); bool readUTF(tiny_string& ret); void writeByte(uint8_t b); + void writeBytes(uint8_t* data, int length); void writeShort(uint16_t val); void writeUnsignedInt(uint32_t val); void writeUTF(const tiny_string& str); @@ -73,6 +74,11 @@ void setPosition(uint32_t p); void append(std::streambuf* data, int length); + /** + * @brief remove bytes from front of buffer + * @param count number of bytes to remove + */ + void removeFrontBytes(int count); uint8_t getObjectEncoding() const { return objectEncoding; } uint8_t getCurrentObjectEncoding() const { return currentObjectEncoding; }
View file
lightspark.tar.xz/src/scripting/toplevel/Date.cpp
Changed
@@ -181,7 +181,7 @@ } if (argslen == 0) { GDateTime* tmp = g_date_time_new_now_utc(); - int64_t ms = g_date_time_to_unix(tmp)*1000; + int64_t ms = g_date_time_to_unix(tmp)*1000 + g_date_time_get_microsecond (tmp)/1000; g_date_time_unref(tmp); th->MakeDateFromMilliseconds(ms); } else @@ -275,7 +275,7 @@ { Date* th=Class<Date>::getInstanceS(); GDateTime* tmp = g_date_time_new_now_utc(); - th->MakeDateFromMilliseconds(g_date_time_to_unix(tmp)*1000); + th->MakeDateFromMilliseconds(g_date_time_to_unix(tmp)*1000 + g_date_time_get_microsecond (tmp)/1000); g_date_time_unref(tmp); return Class<ASString>::getInstanceS(th->toString());
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.