зеркало из https://github.com/mozilla/gecko-dev.git
Bug 895730 - AudioTrackEncoder should handle the case where audio chunk is null. r=roc
This commit is contained in:
Родитель
32d3b06b96
Коммит
546e3d0f33
|
@ -16,7 +16,8 @@
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
#define MAX_FRAMES_TO_DROP 48000
|
static const int DEFAULT_CHANNELS = 1;
|
||||||
|
static const int DEFAULT_SAMPLING_RATE = 16000;
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
|
AudioTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
|
||||||
|
@ -34,16 +35,25 @@ AudioTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
|
||||||
AudioSegment::ChunkIterator iter(*audio);
|
AudioSegment::ChunkIterator iter(*audio);
|
||||||
while (!iter.IsEnded()) {
|
while (!iter.IsEnded()) {
|
||||||
AudioChunk chunk = *iter;
|
AudioChunk chunk = *iter;
|
||||||
if (chunk.mBuffer) {
|
|
||||||
Init(chunk.mChannelData.Length(), aTrackRate);
|
// The number of channels is determined by the first non-null chunk, and
|
||||||
|
// thus the audio encoder is initialized at this time.
|
||||||
|
if (!chunk.IsNull()) {
|
||||||
|
nsresult rv = Init(chunk.mChannelData.Length(), aTrackRate);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
mSilentDuration += chunk.mDuration;
|
||||||
|
}
|
||||||
iter.Next();
|
iter.Next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append and consume this raw segment.
|
// Append and consume this raw segment.
|
||||||
|
if (mInitialized) {
|
||||||
AppendAudioSegment(audio);
|
AppendAudioSegment(audio);
|
||||||
|
}
|
||||||
|
|
||||||
// The stream has stopped and reached the end of track.
|
// The stream has stopped and reached the end of track.
|
||||||
if (aTrackEvents == MediaStreamListener::TRACK_EVENT_ENDED) {
|
if (aTrackEvents == MediaStreamListener::TRACK_EVENT_ENDED) {
|
||||||
|
@ -57,35 +67,42 @@ AudioTrackEncoder::NotifyRemoved(MediaStreamGraph* aGraph)
|
||||||
{
|
{
|
||||||
// In case that MediaEncoder does not receive a TRACK_EVENT_ENDED event.
|
// In case that MediaEncoder does not receive a TRACK_EVENT_ENDED event.
|
||||||
LOG("[AudioTrackEncoder]: NotifyRemoved.");
|
LOG("[AudioTrackEncoder]: NotifyRemoved.");
|
||||||
|
|
||||||
|
// If source audio chunks are completely silent till the end of encoding,
|
||||||
|
// initialize the encoder with default channel counts and sampling rate, and
|
||||||
|
// append this many null data to the segment of track encoder.
|
||||||
|
if (!mInitialized && mSilentDuration > 0) {
|
||||||
|
Init(DEFAULT_CHANNELS, DEFAULT_SAMPLING_RATE);
|
||||||
|
mRawSegment->AppendNullData(mSilentDuration);
|
||||||
|
mSilentDuration = 0;
|
||||||
|
}
|
||||||
NotifyEndOfStream();
|
NotifyEndOfStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
AudioTrackEncoder::AppendAudioSegment(MediaSegment* aSegment)
|
AudioTrackEncoder::AppendAudioSegment(MediaSegment* aSegment)
|
||||||
{
|
{
|
||||||
// Drop the in-coming segment if buffer(mRawSegment) is overflow.
|
|
||||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||||
|
|
||||||
AudioSegment* audio = static_cast<AudioSegment*>(aSegment);
|
AudioSegment* audio = static_cast<AudioSegment*>(aSegment);
|
||||||
AudioSegment::ChunkIterator iter(*audio);
|
AudioSegment::ChunkIterator iter(*audio);
|
||||||
|
|
||||||
if (mRawSegment->GetDuration() < MAX_FRAMES_TO_DROP) {
|
// Append this many null data to our queued segment if there is a complete
|
||||||
|
// silence before the audio track encoder has initialized.
|
||||||
|
if (mSilentDuration > 0) {
|
||||||
|
mRawSegment->AppendNullData(mSilentDuration);
|
||||||
|
mSilentDuration = 0;
|
||||||
|
}
|
||||||
|
|
||||||
while (!iter.IsEnded()) {
|
while (!iter.IsEnded()) {
|
||||||
AudioChunk chunk = *iter;
|
AudioChunk chunk = *iter;
|
||||||
if (chunk.mBuffer) {
|
// Append and consume both non-null and null chunks.
|
||||||
mRawSegment->AppendAndConsumeChunk(&chunk);
|
mRawSegment->AppendAndConsumeChunk(&chunk);
|
||||||
}
|
|
||||||
iter.Next();
|
iter.Next();
|
||||||
}
|
}
|
||||||
if (mRawSegment->GetDuration() >= GetPacketDuration()) {
|
if (mRawSegment->GetDuration() >= GetPacketDuration()) {
|
||||||
mReentrantMonitor.NotifyAll();
|
mReentrantMonitor.NotifyAll();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#ifdef DEBUG
|
|
||||||
else {
|
|
||||||
LOG("[AudioTrackEncoder]: A segment has dropped!");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,7 @@ public:
|
||||||
, mRawSegment(new AudioSegment())
|
, mRawSegment(new AudioSegment())
|
||||||
, mEndOfStream(false)
|
, mEndOfStream(false)
|
||||||
, mCanceled(false)
|
, mCanceled(false)
|
||||||
|
, mSilentDuration(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
|
void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
|
||||||
|
@ -176,6 +177,12 @@ protected:
|
||||||
* mReentrantMonitor.
|
* mReentrantMonitor.
|
||||||
*/
|
*/
|
||||||
bool mCanceled;
|
bool mCanceled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The total duration of null chunks we have received from MediaStreamGraph
|
||||||
|
* before initializing the audio track encoder.
|
||||||
|
*/
|
||||||
|
TrackTicks mSilentDuration;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VideoTrackEncoder : public TrackEncoder
|
class VideoTrackEncoder : public TrackEncoder
|
||||||
|
|
Загрузка…
Ссылка в новой задаче