Bug 856562 - Fix decode race in gstreamer backend r=alessandro.d

This commit is contained in:
Edwin Flores 2013-05-16 14:35:16 +12:00
parent 99768370bd
commit 57bdc4503a
2 changed files with 55 additions and 59 deletions

View File

@ -423,34 +423,28 @@ void GStreamerReader::NotifyBytesConsumed()
mLastReportedByteOffset = mByteOffset; mLastReportedByteOffset = mByteOffset;
} }
bool GStreamerReader::WaitForDecodedData(int* aCounter)
{
ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
/* Report consumed bytes from here as we can't do it from gst threads */
NotifyBytesConsumed();
while(*aCounter == 0) {
if (mReachedEos) {
return false;
}
mon.Wait();
NotifyBytesConsumed();
}
(*aCounter)--;
return true;
}
bool GStreamerReader::DecodeAudioData() bool GStreamerReader::DecodeAudioData()
{ {
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
if (!WaitForDecodedData(&mAudioSinkBufferCount)) { GstBuffer *buffer = nullptr;
mAudioQueue.Finish();
return false; {
ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
if (mReachedEos) {
mAudioQueue.Finish();
return false;
}
if (!mAudioSinkBufferCount) {
return true;
}
buffer = gst_app_sink_pull_buffer(mAudioAppSink);
mAudioSinkBufferCount--;
} }
GstBuffer* buffer = gst_app_sink_pull_buffer(mAudioAppSink);
int64_t timestamp = GST_BUFFER_TIMESTAMP(buffer); int64_t timestamp = GST_BUFFER_TIMESTAMP(buffer);
timestamp = gst_segment_to_stream_time(&mAudioSegment, timestamp = gst_segment_to_stream_time(&mAudioSegment,
GST_FORMAT_TIME, timestamp); GST_FORMAT_TIME, timestamp);
@ -479,49 +473,53 @@ bool GStreamerReader::DecodeVideoFrame(bool &aKeyFrameSkip,
{ {
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
GstBuffer* buffer = nullptr; GstBuffer *buffer = nullptr;
int64_t timestamp, nextTimestamp;
while (true)
{ {
if (!WaitForDecodedData(&mVideoSinkBufferCount)) { ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
if (mReachedEos) {
mVideoQueue.Finish(); mVideoQueue.Finish();
break; return false;
} }
if (!mVideoSinkBufferCount) {
return true;
}
mDecoder->NotifyDecodedFrames(0, 1); mDecoder->NotifyDecodedFrames(0, 1);
buffer = gst_app_sink_pull_buffer(mVideoAppSink); buffer = gst_app_sink_pull_buffer(mVideoAppSink);
bool isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT); mVideoSinkBufferCount--;
if ((aKeyFrameSkip && !isKeyframe)) { }
gst_buffer_unref(buffer);
buffer = nullptr;
continue;
}
timestamp = GST_BUFFER_TIMESTAMP(buffer); bool isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT);
{ if ((aKeyFrameSkip && !isKeyframe)) {
ReentrantMonitorAutoEnter mon(mGstThreadsMonitor); gst_buffer_unref(buffer);
timestamp = gst_segment_to_stream_time(&mVideoSegment, return true;
GST_FORMAT_TIME, timestamp); }
}
NS_ASSERTION(GST_CLOCK_TIME_IS_VALID(timestamp),
"frame has invalid timestamp");
timestamp = nextTimestamp = GST_TIME_AS_USECONDS(timestamp);
if (GST_CLOCK_TIME_IS_VALID(GST_BUFFER_DURATION(buffer)))
nextTimestamp += GST_TIME_AS_USECONDS(GST_BUFFER_DURATION(buffer));
else if (fpsNum && fpsDen)
/* add 1-frame duration */
nextTimestamp += gst_util_uint64_scale(GST_USECOND, fpsNum, fpsDen);
if (timestamp < aTimeThreshold) { int64_t timestamp = GST_BUFFER_TIMESTAMP(buffer);
LOG(PR_LOG_DEBUG, ("skipping frame %" GST_TIME_FORMAT {
" threshold %" GST_TIME_FORMAT, ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
GST_TIME_ARGS(timestamp), GST_TIME_ARGS(aTimeThreshold))); timestamp = gst_segment_to_stream_time(&mVideoSegment,
gst_buffer_unref(buffer); GST_FORMAT_TIME, timestamp);
buffer = nullptr; }
continue; NS_ASSERTION(GST_CLOCK_TIME_IS_VALID(timestamp),
} "frame has invalid timestamp");
int64_t nextTimestamp = timestamp = GST_TIME_AS_USECONDS(timestamp);
if (GST_CLOCK_TIME_IS_VALID(GST_BUFFER_DURATION(buffer)))
nextTimestamp += GST_TIME_AS_USECONDS(GST_BUFFER_DURATION(buffer));
else if (fpsNum && fpsDen)
/* add 1-frame duration */
nextTimestamp += gst_util_uint64_scale(GST_USECOND, fpsNum, fpsDen);
break; if (timestamp < aTimeThreshold) {
LOG(PR_LOG_DEBUG, ("skipping frame %" GST_TIME_FORMAT
" threshold %" GST_TIME_FORMAT,
GST_TIME_ARGS(timestamp), GST_TIME_ARGS(aTimeThreshold)));
gst_buffer_unref(buffer);
return true;
} }
if (!buffer) if (!buffer)
@ -570,8 +568,7 @@ bool GStreamerReader::DecodeVideoFrame(bool &aKeyFrameSkip,
b.mPlanes[i].mSkip = 0; b.mPlanes[i].mSkip = 0;
} }
bool isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT);
GST_BUFFER_FLAG_DELTA_UNIT);
/* XXX ? */ /* XXX ? */
int64_t offset = 0; int64_t offset = 0;
VideoData* video = VideoData::Create(mInfo, image, offset, VideoData* video = VideoData::Create(mInfo, image, offset,

View File

@ -50,7 +50,6 @@ public:
private: private:
void ReadAndPushData(guint aLength); void ReadAndPushData(guint aLength);
bool WaitForDecodedData(int* counter);
void NotifyBytesConsumed(); void NotifyBytesConsumed();
int64_t QueryDuration(); int64_t QueryDuration();