Bug 924678: Stop MP3 parser if decoder got cleared, r=doublec

If the decoder has been cleaned up, there is no point in further
parsing the MP3 file. This patch makes the I/O logic stop in that
case.

The patch also fixes a bug where the beginning of an MP3 chunk was
parsed multiple times if the chunk is larger than 4 GiB.

--HG--
extra : rebase_source : d247ed3995991d362c51a0666274e9de3b90b7d2
This commit is contained in:
Thomas Zimmermann 2013-10-14 10:38:48 +02:00
parent 568572011d
commit ba40fab0c9
2 changed files with 37 additions and 24 deletions

View File

@ -62,8 +62,8 @@ private:
};
// When loading an MP3 stream from a file, we need to parse the file's
// content to find its duration. Reading files of 100 Mib or more can
// delay the player app noticably, so the file os read and decoded in
// content to find its duration. Reading files of 100 MiB or more can
// delay the player app noticably, so the file is read and decoded in
// smaller chunks.
//
// We first read on the decode thread, but parsing must be done on the
@ -79,7 +79,9 @@ private:
class OmxDecoderNotifyDataArrivedRunnable : public nsRunnable
{
public:
OmxDecoderNotifyDataArrivedRunnable(android::OmxDecoder* aOmxDecoder, const char* aBuffer, uint64_t aLength, int64_t aOffset, uint64_t aFullLength)
OmxDecoderNotifyDataArrivedRunnable(android::OmxDecoder* aOmxDecoder,
const char* aBuffer, uint64_t aLength,
int64_t aOffset, uint64_t aFullLength)
: mOmxDecoder(aOmxDecoder),
mBuffer(aBuffer),
mLength(aLength),
@ -96,24 +98,7 @@ public:
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
const char* buffer = mBuffer.get();
while (mLength) {
uint32_t length = std::min<uint64_t>(mLength, UINT32_MAX);
mOmxDecoder->NotifyDataArrived(mBuffer.get(), mLength, mOffset);
buffer += length;
mLength -= length;
mOffset += length;
}
if (mOffset < mFullLength) {
// We cannot read data in the main thread because it
// might block for too long. Instead we post an IO task
// to the IO thread if there is more data available.
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new OmxDecoderProcessCachedDataTask(mOmxDecoder.get(), mOffset));
}
NotifyDataArrived();
Completed();
return NS_OK;
@ -130,6 +115,32 @@ public:
}
private:
void NotifyDataArrived()
{
const char* buffer = mBuffer.get();
while (mLength) {
uint32_t length = std::min<uint64_t>(mLength, UINT32_MAX);
bool success = mOmxDecoder->NotifyDataArrived(buffer, mLength,
mOffset);
if (!success) {
return;
}
buffer += length;
mLength -= length;
mOffset += length;
}
if (mOffset < mFullLength) {
// We cannot read data in the main thread because it
// might block for too long. Instead we post an IO task
// to the IO thread if there is more data available.
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
new OmxDecoderProcessCachedDataTask(mOmxDecoder.get(), mOffset));
}
}
// Call this function at the end of Run() to notify waiting
// threads.
void Completed()
@ -633,10 +644,10 @@ void OmxDecoder::ReleaseDecoder()
mDecoder = nullptr;
}
void OmxDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
bool OmxDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
{
if (!mAudioTrack.get() || !mIsMp3 || !mMP3FrameParser.IsMP3() || !mDecoder) {
return;
return false;
}
mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
@ -650,6 +661,8 @@ void OmxDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mDecoder->UpdateEstimatedMediaDuration(mDurationUs);
}
return true;
}
void OmxDecoder::ReleaseVideoBuffer() {

View File

@ -183,7 +183,7 @@ public:
void ReleaseDecoder();
void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
bool NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
void GetDuration(int64_t *durationUs) {
*durationUs = mDurationUs;