summaryrefslogtreecommitdiff
path: root/media/base
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2013-08-05 13:57:33 +0100
committerTorne (Richard Coles) <torne@google.com>2013-08-05 13:57:33 +0100
commita36e5920737c6adbddd3e43b760e5de8431db6e0 (patch)
tree347d048bb8c8828d50113bf94ace40bf0613f2cd /media/base
parent34378da0e9429d394aafdaa771301aff58447cb1 (diff)
downloadchromium_org-a36e5920737c6adbddd3e43b760e5de8431db6e0.tar.gz
Merge from Chromium at DEPS revision r215573
This commit was generated by merge_to_master.py. Change-Id: Ib95814f98e5765b459dd32425f9bf9138edf2bca
Diffstat (limited to 'media/base')
-rw-r--r--media/base/android/demuxer_stream_player_params.cc9
-rw-r--r--media/base/android/demuxer_stream_player_params.h28
-rw-r--r--media/base/android/java/src/org/chromium/media/MediaCodecBridge.java7
-rw-r--r--media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java4
-rw-r--r--media/base/android/java/src/org/chromium/media/VideoCapture.java55
-rw-r--r--media/base/android/media_codec_bridge.cc5
-rw-r--r--media/base/android/media_codec_bridge.h8
-rw-r--r--media/base/android/media_player_android.h2
-rw-r--r--media/base/android/media_player_bridge.cc4
-rw-r--r--media/base/android/media_player_bridge.h2
-rw-r--r--media/base/android/media_source_player.cc120
-rw-r--r--media/base/android/media_source_player.h44
-rw-r--r--media/base/android/media_source_player_unittest.cc14
-rw-r--r--media/base/audio_buffer.cc83
-rw-r--r--media/base/audio_buffer.h22
-rw-r--r--media/base/audio_buffer_unittest.cc28
-rw-r--r--media/base/container_names.cc4
-rw-r--r--media/base/container_names_unittest.cc8
-rw-r--r--media/base/simd/filter_yuv_mmx.cc3
19 files changed, 324 insertions, 126 deletions
diff --git a/media/base/android/demuxer_stream_player_params.cc b/media/base/android/demuxer_stream_player_params.cc
index 3ed1a8c446..827be11956 100644
--- a/media/base/android/demuxer_stream_player_params.cc
+++ b/media/base/android/demuxer_stream_player_params.cc
@@ -19,6 +19,10 @@ MediaPlayerHostMsg_DemuxerReady_Params::
MediaPlayerHostMsg_DemuxerReady_Params::
~MediaPlayerHostMsg_DemuxerReady_Params() {}
+AccessUnit::AccessUnit() : end_of_stream(false) {}
+
+AccessUnit::~AccessUnit() {}
+
MediaPlayerHostMsg_ReadFromDemuxerAck_Params::
MediaPlayerHostMsg_ReadFromDemuxerAck_Params()
: type(DemuxerStream::UNKNOWN) {}
@@ -26,9 +30,4 @@ MediaPlayerHostMsg_ReadFromDemuxerAck_Params::
MediaPlayerHostMsg_ReadFromDemuxerAck_Params::
~MediaPlayerHostMsg_ReadFromDemuxerAck_Params() {}
-MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit::AccessUnit()
- : end_of_stream(false) {}
-
-MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit::~AccessUnit() {}
-
} // namespace media
diff --git a/media/base/android/demuxer_stream_player_params.h b/media/base/android/demuxer_stream_player_params.h
index 585af2b4c7..a9fb0520ae 100644
--- a/media/base/android/demuxer_stream_player_params.h
+++ b/media/base/android/demuxer_stream_player_params.h
@@ -36,21 +36,21 @@ struct MEDIA_EXPORT MediaPlayerHostMsg_DemuxerReady_Params {
std::string key_system;
};
-struct MEDIA_EXPORT MediaPlayerHostMsg_ReadFromDemuxerAck_Params {
- struct MEDIA_EXPORT AccessUnit {
- AccessUnit();
- ~AccessUnit();
-
- DemuxerStream::Status status;
- bool end_of_stream;
- // TODO(ycheo): Use the shared memory to transfer the block data.
- std::vector<uint8> data;
- base::TimeDelta timestamp;
- std::vector<char> key_id;
- std::vector<char> iv;
- std::vector<media::SubsampleEntry> subsamples;
- };
+struct MEDIA_EXPORT AccessUnit {
+ AccessUnit();
+ ~AccessUnit();
+
+ DemuxerStream::Status status;
+ bool end_of_stream;
+ // TODO(ycheo): Use the shared memory to transfer the block data.
+ std::vector<uint8> data;
+ base::TimeDelta timestamp;
+ std::vector<char> key_id;
+ std::vector<char> iv;
+ std::vector<media::SubsampleEntry> subsamples;
+};
+struct MEDIA_EXPORT MediaPlayerHostMsg_ReadFromDemuxerAck_Params {
MediaPlayerHostMsg_ReadFromDemuxerAck_Params();
~MediaPlayerHostMsg_ReadFromDemuxerAck_Params();
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
index 26c0731ce2..ed5d9478c5 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
@@ -285,6 +285,13 @@ class MediaCodecBridge {
}
}
+ @CalledByNative
+ private void setVolume(double volume) {
+ if (mAudioTrack != null) {
+ mAudioTrack.setStereoVolume((float) volume, (float) volume);
+ }
+ }
+
private void resetLastPresentationTimeIfNeeded(long presentationTimeUs) {
if (mFlushed) {
mLastPresentationTimeUs =
diff --git a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
index e1b0e09475..4b0a1aa6d1 100644
--- a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
@@ -85,8 +85,8 @@ public class MediaPlayerBridge {
}
@CalledByNative
- protected void setVolume(float leftVolume, float rightVolume) {
- getLocalPlayer().setVolume(leftVolume, rightVolume);
+ protected void setVolume(double volume) {
+ getLocalPlayer().setVolume((float) volume, (float) volume);
}
@CalledByNative
diff --git a/media/base/android/java/src/org/chromium/media/VideoCapture.java b/media/base/android/java/src/org/chromium/media/VideoCapture.java
index 8d67f5ed9f..f055f35ed6 100644
--- a/media/base/android/java/src/org/chromium/media/VideoCapture.java
+++ b/media/base/android/java/src/org/chromium/media/VideoCapture.java
@@ -31,9 +31,35 @@ public class VideoCapture implements PreviewCallback, OnFrameAvailableListener {
public int mDesiredFps = 0;
}
+ // Some devices with OS older than JELLY_BEAN don't support YV12 format correctly.
+ // Some devices don't support YV12 format correctly even with JELLY_BEAN or newer OS.
+ // To work around the issues on those devices, we'd have to request NV21.
+ // This is a temporary hack till device manufacturers fix the problem or
+ // we don't need to support those devices any more.
+ private static class DeviceImageFormatHack {
+ private static final String[] sBUGGY_DEVICE_LIST = {
+ "SAMSUNG-SGH-I747",
+ };
+
+ static int getImageFormat() {
+ if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
+ return ImageFormat.NV21;
+ }
+
+ for (String buggyDevice : sBUGGY_DEVICE_LIST) {
+ if (buggyDevice.contentEquals(android.os.Build.MODEL)) {
+ return ImageFormat.NV21;
+ }
+ }
+
+ return ImageFormat.YV12;
+ }
+ }
+
private Camera mCamera;
public ReentrantLock mPreviewBufferLock = new ReentrantLock();
- private int mPixelFormat = ImageFormat.YV12;
+ private int mImageFormat = ImageFormat.YV12;
+ private byte[] mColorPlane = null;
private Context mContext = null;
// True when native code has started capture.
private boolean mIsRunning = false;
@@ -147,8 +173,10 @@ public class VideoCapture implements PreviewCallback, OnFrameAvailableListener {
Log.d(TAG, "allocate: matched width=" + matchedWidth +
", height=" + matchedHeight);
+ calculateImageFormat(matchedWidth, matchedHeight);
+
parameters.setPreviewSize(matchedWidth, matchedHeight);
- parameters.setPreviewFormat(mPixelFormat);
+ parameters.setPreviewFormat(mImageFormat);
parameters.setPreviewFpsRange(fpsMin, fpsMax);
mCamera.setParameters(parameters);
@@ -174,7 +202,7 @@ public class VideoCapture implements PreviewCallback, OnFrameAvailableListener {
mCamera.setPreviewTexture(mSurfaceTexture);
int bufSize = matchedWidth * matchedHeight *
- ImageFormat.getBitsPerPixel(mPixelFormat) / 8;
+ ImageFormat.getBitsPerPixel(mImageFormat) / 8;
for (int i = 0; i < NUM_CAPTURE_BUFFERS; i++) {
byte[] buffer = new byte[bufSize];
mCamera.addCallbackBuffer(buffer);
@@ -291,6 +319,9 @@ public class VideoCapture implements PreviewCallback, OnFrameAvailableListener {
} else {
rotation = (mCameraOrientation - rotation + 360) % 360;
}
+ if (mImageFormat == ImageFormat.NV21) {
+ convertNV21ToYV12(data);
+ }
nativeOnFrameAvailable(mNativeVideoCaptureDeviceAndroid,
data, mExpectedFrameSize,
rotation, flipVertical, flipHorizontal);
@@ -377,4 +408,22 @@ public class VideoCapture implements PreviewCallback, OnFrameAvailableListener {
}
return orientation;
}
+
+ private void calculateImageFormat(int width, int height) {
+ mImageFormat = DeviceImageFormatHack.getImageFormat();
+ if (mImageFormat == ImageFormat.NV21) {
+ mColorPlane = new byte[width * height / 4];
+ }
+ }
+
+ private void convertNV21ToYV12(byte[] data) {
+ final int ySize = mCurrentCapability.mWidth * mCurrentCapability.mHeight;
+ final int uvSize = ySize / 4;
+ for (int i = 0; i < uvSize; i++) {
+ final int index = ySize + i * 2;
+ data[ySize + i] = data[index];
+ mColorPlane[i] = data[index + 1];
+ }
+ System.arraycopy(mColorPlane, 0, data, ySize + uvSize, uvSize);
+ }
}
diff --git a/media/base/android/media_codec_bridge.cc b/media/base/android/media_codec_bridge.cc
index a3c15c0b89..ab54936780 100644
--- a/media/base/android/media_codec_bridge.cc
+++ b/media/base/android/media_codec_bridge.cc
@@ -373,6 +373,11 @@ void AudioCodecBridge::PlayOutputBuffer(int index, size_t size) {
env, media_codec(), byte_array.obj());
}
+void AudioCodecBridge::SetVolume(double volume) {
+ JNIEnv* env = AttachCurrentThread();
+ Java_MediaCodecBridge_setVolume(env, media_codec(), volume);
+}
+
VideoCodecBridge::VideoCodecBridge(const char* mime)
: MediaCodecBridge(mime) {
}
diff --git a/media/base/android/media_codec_bridge.h b/media/base/android/media_codec_bridge.h
index d28d39df12..3469b1804e 100644
--- a/media/base/android/media_codec_bridge.h
+++ b/media/base/android/media_codec_bridge.h
@@ -75,8 +75,9 @@ class MEDIA_EXPORT MediaCodecBridge {
// Submits an empty buffer with a EOS (END OF STREAM) flag.
void QueueEOS(int input_buffer_index);
- // Returns the index of an input buffer to be filled with valid data or
- // INFO_TRY_AGAIN_LATER if no such buffer is currently available.
+ // Returns an index (>=0) of an input buffer to be filled with valid data,
+ // INFO_TRY_AGAIN_LATER if no such buffer is currently available, or
+ // INFO_MEDIA_CODEC_ERROR if unexpected error happens.
// Use kTimeOutInfinity for infinite timeout.
int DequeueInputBuffer(base::TimeDelta timeout);
@@ -132,6 +133,9 @@ class AudioCodecBridge : public MediaCodecBridge {
// DequeueOutputBuffer() and before ReleaseOutputBuffer.
void PlayOutputBuffer(int index, size_t size);
+ // Set the volume of the audio output.
+ void SetVolume(double volume);
+
private:
explicit AudioCodecBridge(const char* mime);
diff --git a/media/base/android/media_player_android.h b/media/base/android/media_player_android.h
index 18831b668d..f1c9c37ee0 100644
--- a/media/base/android/media_player_android.h
+++ b/media/base/android/media_player_android.h
@@ -71,7 +71,7 @@ class MEDIA_EXPORT MediaPlayerAndroid {
virtual void Release() = 0;
// Set the player volume.
- virtual void SetVolume(float leftVolume, float rightVolume) = 0;
+ virtual void SetVolume(double volume) = 0;
// Get the media information from the player.
virtual int GetVideoWidth() = 0;
diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc
index 15a26ece3f..e0d9868827 100644
--- a/media/base/android/media_player_bridge.cc
+++ b/media/base/android/media_player_bridge.cc
@@ -300,14 +300,14 @@ void MediaPlayerBridge::Release() {
listener_.ReleaseMediaPlayerListenerResources();
}
-void MediaPlayerBridge::SetVolume(float left_volume, float right_volume) {
+void MediaPlayerBridge::SetVolume(double volume) {
if (j_media_player_bridge_.is_null())
return;
JNIEnv* env = base::android::AttachCurrentThread();
CHECK(env);
Java_MediaPlayerBridge_setVolume(
- env, j_media_player_bridge_.obj(), left_volume, right_volume);
+ env, j_media_player_bridge_.obj(), volume);
}
void MediaPlayerBridge::OnVideoSizeChanged(int width, int height) {
diff --git a/media/base/android/media_player_bridge.h b/media/base/android/media_player_bridge.h
index 421bcb3e01..85a2960405 100644
--- a/media/base/android/media_player_bridge.h
+++ b/media/base/android/media_player_bridge.h
@@ -58,7 +58,7 @@ class MEDIA_EXPORT MediaPlayerBridge : public MediaPlayerAndroid {
virtual void Pause() OVERRIDE;
virtual void SeekTo(base::TimeDelta time) OVERRIDE;
virtual void Release() OVERRIDE;
- virtual void SetVolume(float leftVolume, float rightVolume) OVERRIDE;
+ virtual void SetVolume(double volume) OVERRIDE;
virtual int GetVideoWidth() OVERRIDE;
virtual int GetVideoHeight() OVERRIDE;
virtual base::TimeDelta GetCurrentTime() OVERRIDE;
diff --git a/media/base/android/media_source_player.cc b/media/base/android/media_source_player.cc
index 5673b926a0..5d4aa98b66 100644
--- a/media/base/android/media_source_player.cc
+++ b/media/base/android/media_source_player.cc
@@ -22,7 +22,7 @@ namespace {
// Timeout value for media codec operations. Because the first
// DequeInputBuffer() can take about 150 milliseconds, use 250 milliseconds
// here. See b/9357571.
-const int kMediaCodecTimeoutInMicroseconds = 250000;
+const int kMediaCodecTimeoutInMilliseconds = 250;
// Use 16bit PCM for audio output. Keep this value in sync with the output
// format we passed to AudioTrack in MediaCodecBridge.
@@ -82,6 +82,8 @@ class AudioDecoderJob : public MediaDecoderJob {
const AudioCodec audio_codec, int sample_rate, int channel_count,
const uint8* extra_data, size_t extra_data_size, jobject media_crypto);
+ void SetVolume(double volume);
+
private:
AudioDecoderJob(MediaCodecBridge* media_codec_bridge);
};
@@ -100,7 +102,7 @@ class VideoDecoderJob : public MediaDecoderJob {
};
void MediaDecoderJob::Decode(
- const MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit& unit,
+ const AccessUnit& unit,
const base::TimeTicks& start_time_ticks,
const base::TimeDelta& start_presentation_timestamp,
const MediaDecoderJob::DecoderCallback& callback) {
@@ -114,43 +116,55 @@ void MediaDecoderJob::Decode(
needs_flush_ = false;
}
+MediaDecoderJob::DecodeStatus MediaDecoderJob::QueueInputBuffer(
+ const AccessUnit& unit) {
+ base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(
+ kMediaCodecTimeoutInMilliseconds);
+ int input_buf_index = media_codec_bridge_->DequeueInputBuffer(timeout);
+ if (input_buf_index == MediaCodecBridge::INFO_MEDIA_CODEC_ERROR)
+ return DECODE_FAILED;
+ if (input_buf_index == MediaCodecBridge::INFO_TRY_AGAIN_LATER)
+ return DECODE_TRY_ENQUEUE_INPUT_AGAIN_LATER;
+
+ // TODO(qinmin): skip frames if video is falling far behind.
+ DCHECK(input_buf_index >= 0);
+ if (unit.end_of_stream || unit.data.empty()) {
+ media_codec_bridge_->QueueEOS(input_buf_index);
+ } else if (unit.key_id.empty()) {
+ media_codec_bridge_->QueueInputBuffer(
+ input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp);
+ } else {
+ if (unit.iv.empty() || unit.subsamples.empty()) {
+ LOG(ERROR) << "The access unit doesn't have iv or subsamples while it "
+ << "has key IDs!";
+ return DECODE_FAILED;
+ }
+ media_codec_bridge_->QueueSecureInputBuffer(
+ input_buf_index, &unit.data[0], unit.data.size(),
+ reinterpret_cast<const uint8*>(&unit.key_id[0]), unit.key_id.size(),
+ reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(),
+ &unit.subsamples[0], unit.subsamples.size(), unit.timestamp);
+ }
+
+ return DECODE_SUCCEEDED;
+}
+
void MediaDecoderJob::DecodeInternal(
- const MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit& unit,
+ const AccessUnit& unit,
const base::TimeTicks& start_time_ticks,
const base::TimeDelta& start_presentation_timestamp,
bool needs_flush,
const MediaDecoderJob::DecoderCallback& callback) {
- if (needs_flush)
+ if (needs_flush) {
+ DVLOG(1) << "DecodeInternal needs flush.";
media_codec_bridge_->Reset();
- base::TimeDelta timeout = base::TimeDelta::FromMicroseconds(
- kMediaCodecTimeoutInMicroseconds);
- int input_buf_index = media_codec_bridge_->DequeueInputBuffer(timeout);
- if (input_buf_index == MediaCodecBridge::INFO_MEDIA_CODEC_ERROR) {
- ui_loop_->PostTask(FROM_HERE, base::Bind(
- callback, DECODE_FAILED, start_presentation_timestamp, 0));
- return;
}
- // TODO(qinmin): skip frames if video is falling far behind.
- if (input_buf_index >= 0) {
- if (unit.end_of_stream || unit.data.empty()) {
- media_codec_bridge_->QueueEOS(input_buf_index);
- } else if (unit.key_id.empty()){
- media_codec_bridge_->QueueInputBuffer(
- input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp);
- } else {
- if (unit.iv.empty() || unit.subsamples.empty()) {
- LOG(ERROR) << "The access unit doesn't have iv or subsamples while it "
- << "has key IDs!";
- ui_loop_->PostTask(FROM_HERE, base::Bind(
- callback, DECODE_FAILED, start_presentation_timestamp, 0));
- return;
- }
- media_codec_bridge_->QueueSecureInputBuffer(
- input_buf_index, &unit.data[0], unit.data.size(),
- reinterpret_cast<const uint8*>(&unit.key_id[0]), unit.key_id.size(),
- reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(),
- &unit.subsamples[0], unit.subsamples.size(), unit.timestamp);
- }
+
+ DecodeStatus decode_status = QueueInputBuffer(unit);
+ if (decode_status != DECODE_SUCCEEDED) {
+ ui_loop_->PostTask(FROM_HERE,
+ base::Bind(callback, decode_status, start_presentation_timestamp, 0));
+ return;
}
size_t offset = 0;
@@ -158,9 +172,11 @@ void MediaDecoderJob::DecodeInternal(
base::TimeDelta presentation_timestamp;
bool end_of_stream = false;
+ base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(
+ kMediaCodecTimeoutInMilliseconds);
int outputBufferIndex = media_codec_bridge_->DequeueOutputBuffer(
timeout, &offset, &size, &presentation_timestamp, &end_of_stream);
- DecodeStatus decode_status = DECODE_SUCCEEDED;
+
if (end_of_stream)
decode_status = DECODE_END_OF_STREAM;
switch (outputBufferIndex) {
@@ -172,7 +188,7 @@ void MediaDecoderJob::DecodeInternal(
decode_status = DECODE_FORMAT_CHANGED;
break;
case MediaCodecBridge::INFO_TRY_AGAIN_LATER:
- decode_status = DECODE_TRY_AGAIN_LATER;
+ decode_status = DECODE_TRY_DEQUEUE_OUTPUT_AGAIN_LATER;
break;
case MediaCodecBridge::INFO_MEDIA_CODEC_ERROR:
decode_status = DECODE_FAILED;
@@ -257,7 +273,7 @@ VideoDecoderJob* VideoDecoderJob::Create(
const VideoCodec video_codec, const gfx::Size& size, jobject surface,
jobject media_crypto) {
scoped_ptr<VideoCodecBridge> codec(VideoCodecBridge::Create(video_codec));
- if (codec->Start(video_codec, size, surface, media_crypto))
+ if (codec && codec->Start(video_codec, size, surface, media_crypto))
return new VideoDecoderJob(codec.release());
return NULL;
}
@@ -275,8 +291,8 @@ AudioDecoderJob* AudioDecoderJob::Create(
size_t extra_data_size,
jobject media_crypto) {
scoped_ptr<AudioCodecBridge> codec(AudioCodecBridge::Create(audio_codec));
- if (codec->Start(audio_codec, sample_rate, channel_count, extra_data,
- extra_data_size, true, media_crypto)) {
+ if (codec && codec->Start(audio_codec, sample_rate, channel_count, extra_data,
+ extra_data_size, true, media_crypto)) {
return new AudioDecoderJob(codec.release());
}
return NULL;
@@ -287,6 +303,10 @@ AudioDecoderJob::AudioDecoderJob(MediaCodecBridge* media_codec_bridge)
media_codec_bridge,
true) {}
+void AudioDecoderJob::SetVolume(double volume) {
+ static_cast<AudioCodecBridge*>(media_codec_bridge_.get())->SetVolume(volume);
+}
+
MediaSourcePlayer::MediaSourcePlayer(
int player_id,
MediaPlayerManager* manager)
@@ -304,6 +324,7 @@ MediaSourcePlayer::MediaSourcePlayer(
playing_(false),
is_audio_encrypted_(false),
is_video_encrypted_(false),
+ volume_(-1.0),
clock_(&default_tick_clock_),
reconfig_audio_decoder_(false),
reconfig_video_decoder_(false),
@@ -407,7 +428,9 @@ void MediaSourcePlayer::Release() {
ReleaseMediaResourcesFromManager();
}
-void MediaSourcePlayer::SetVolume(float leftVolume, float rightVolume) {
+void MediaSourcePlayer::SetVolume(double volume) {
+ volume_ = volume;
+ SetVolumeInternal();
}
bool MediaSourcePlayer::CanPause() {
@@ -546,6 +569,7 @@ void MediaSourcePlayer::SetDrmBridge(MediaDrmBridge* drm_bridge) {
}
void MediaSourcePlayer::OnSeekRequestAck(unsigned seek_request_id) {
+ DVLOG(1) << "OnSeekRequestAck(" << seek_request_id << ")";
// Do nothing until the most recent seek request is processed.
if (seek_request_id_ != seek_request_id)
return;
@@ -613,7 +637,9 @@ void MediaSourcePlayer::MediaDecoderCallback(
Release();
OnMediaError(MEDIA_ERROR_DECODE);
return;
- } else if (decode_status == MediaDecoderJob::DECODE_SUCCEEDED) {
+ }
+
+ if (decode_status != MediaDecoderJob::DECODE_TRY_ENQUEUE_INPUT_AGAIN_LATER) {
if (is_audio)
audio_access_unit_index_++;
else
@@ -698,6 +724,7 @@ void MediaSourcePlayer::DecodeMoreAudio() {
}
void MediaSourcePlayer::DecodeMoreVideo() {
+ DVLOG(1) << "DecodeMoreVideo()";
DCHECK(!video_decoder_job_->is_decoding());
DCHECK(HasVideoData());
@@ -712,6 +739,9 @@ void MediaSourcePlayer::DecodeMoreVideo() {
return;
}
+ DVLOG(3) << "VideoDecoderJob::Decode(" << video_access_unit_index_ << ", "
+ << start_time_ticks_.ToInternalValue() << ", "
+ << start_presentation_timestamp_.InMilliseconds() << ")";
video_decoder_job_->Decode(
received_video_.access_units[video_access_unit_index_],
start_time_ticks_, start_presentation_timestamp_,
@@ -734,6 +764,7 @@ void MediaSourcePlayer::PlaybackCompleted(bool is_audio) {
}
void MediaSourcePlayer::ClearDecodingData() {
+ DVLOG(1) << "ClearDecodingData()";
if (audio_decoder_job_)
audio_decoder_job_->Flush();
if (video_decoder_job_)
@@ -786,8 +817,10 @@ void MediaSourcePlayer::ConfigureAudioDecoderJob() {
audio_codec_, sampling_rate_, num_channels_, &audio_extra_data_[0],
audio_extra_data_.size(), media_codec.obj()));
- if (audio_decoder_job_)
+ if (audio_decoder_job_) {
+ SetVolumeInternal();
reconfig_audio_decoder_ = false;
+ }
}
void MediaSourcePlayer::ConfigureVideoDecoderJob() {
@@ -866,6 +899,7 @@ void MediaSourcePlayer::SyncAndStartDecoderJobs() {
}
void MediaSourcePlayer::RequestAudioData() {
+ DVLOG(2) << "RequestAudioData()";
DCHECK(HasAudio());
if (waiting_for_audio_data_)
@@ -878,6 +912,7 @@ void MediaSourcePlayer::RequestAudioData() {
}
void MediaSourcePlayer::RequestVideoData() {
+ DVLOG(2) << "RequestVideoData()";
DCHECK(HasVideo());
if (waiting_for_video_data_)
return;
@@ -896,4 +931,9 @@ bool MediaSourcePlayer::HasVideoData() const {
return video_access_unit_index_ < received_video_.access_units.size();
}
+void MediaSourcePlayer::SetVolumeInternal() {
+ if (audio_decoder_job_ && volume_ >= 0)
+ audio_decoder_job_.get()->SetVolume(volume_);
+}
+
} // namespace media
diff --git a/media/base/android/media_source_player.h b/media/base/android/media_source_player.h
index efab0a2f6c..7253d565e3 100644
--- a/media/base/android/media_source_player.h
+++ b/media/base/android/media_source_player.h
@@ -40,7 +40,8 @@ class MediaDecoderJob {
public:
enum DecodeStatus {
DECODE_SUCCEEDED,
- DECODE_TRY_AGAIN_LATER,
+ DECODE_TRY_ENQUEUE_INPUT_AGAIN_LATER,
+ DECODE_TRY_DEQUEUE_OUTPUT_AGAIN_LATER,
DECODE_FORMAT_CHANGED,
DECODE_END_OF_STREAM,
DECODE_FAILED,
@@ -54,19 +55,14 @@ class MediaDecoderJob {
size_t)> DecoderCallback;
// Called by MediaSourcePlayer to decode some data.
- void Decode(
- const MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit& unit,
- const base::TimeTicks& start_time_ticks,
- const base::TimeDelta& start_presentation_timestamp,
- const MediaDecoderJob::DecoderCallback& callback);
+ void Decode(const AccessUnit& unit,
+ const base::TimeTicks& start_time_ticks,
+ const base::TimeDelta& start_presentation_timestamp,
+ const MediaDecoderJob::DecoderCallback& callback);
// Flush the decoder.
void Flush();
- struct Deleter {
- inline void operator()(MediaDecoderJob* ptr) const { ptr->Release(); }
- };
-
// Causes this instance to be deleted on the thread it is bound to.
void Release();
@@ -86,18 +82,19 @@ class MediaDecoderJob {
const base::TimeDelta& presentation_timestamp,
const MediaDecoderJob::DecoderCallback& callback, DecodeStatus status);
+ DecodeStatus QueueInputBuffer(const AccessUnit& unit);
+
// Helper function to decoder data on |thread_|. |unit| contains all the data
// to be decoded. |start_time_ticks| and |start_presentation_timestamp|
// represent the system time and the presentation timestamp when the first
// frame is rendered. We use these information to estimate when the current
// frame should be rendered. If |needs_flush| is true, codec needs to be
// flushed at the beginning of this call.
- void DecodeInternal(
- const MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit& unit,
- const base::TimeTicks& start_time_ticks,
- const base::TimeDelta& start_presentation_timestamp,
- bool needs_flush,
- const MediaDecoderJob::DecoderCallback& callback);
+ void DecodeInternal(const AccessUnit& unit,
+ const base::TimeTicks& start_time_ticks,
+ const base::TimeDelta& start_presentation_timestamp,
+ bool needs_flush,
+ const MediaDecoderJob::DecoderCallback& callback);
// The UI message loop where callbacks should be dispatched.
scoped_refptr<base::MessageLoopProxy> ui_loop_;
@@ -122,8 +119,9 @@ class MediaDecoderJob {
bool is_decoding_;
};
-typedef scoped_ptr<MediaDecoderJob, MediaDecoderJob::Deleter>
- ScopedMediaDecoderJob;
+struct DecoderJobDeleter {
+ inline void operator()(MediaDecoderJob* ptr) const { ptr->Release(); }
+};
// This class handles media source extensions on Android. It uses Android
// MediaCodec to decode audio and video streams in two separate threads.
@@ -142,7 +140,7 @@ class MEDIA_EXPORT MediaSourcePlayer : public MediaPlayerAndroid {
virtual void Pause() OVERRIDE;
virtual void SeekTo(base::TimeDelta timestamp) OVERRIDE;
virtual void Release() OVERRIDE;
- virtual void SetVolume(float leftVolume, float rightVolume) OVERRIDE;
+ virtual void SetVolume(double volume) OVERRIDE;
virtual int GetVideoWidth() OVERRIDE;
virtual int GetVideoHeight() OVERRIDE;
virtual base::TimeDelta GetCurrentTime() OVERRIDE;
@@ -219,6 +217,9 @@ class MEDIA_EXPORT MediaSourcePlayer : public MediaPlayerAndroid {
bool HasAudioData() const;
bool HasVideoData() const;
+ // Helper function to set the volume.
+ void SetVolumeInternal();
+
enum PendingEventFlags {
NO_EVENT_PENDING = 0,
SEEK_EVENT_PENDING = 1 << 0,
@@ -246,6 +247,7 @@ class MEDIA_EXPORT MediaSourcePlayer : public MediaPlayerAndroid {
bool playing_;
bool is_audio_encrypted_;
bool is_video_encrypted_;
+ double volume_;
// base::TickClock used by |clock_|.
base::DefaultTickClock default_tick_clock_;
@@ -266,8 +268,8 @@ class MEDIA_EXPORT MediaSourcePlayer : public MediaPlayerAndroid {
gfx::ScopedJavaSurface surface_;
// Decoder jobs
- ScopedMediaDecoderJob audio_decoder_job_;
- ScopedMediaDecoderJob video_decoder_job_;
+ scoped_ptr<AudioDecoderJob, DecoderJobDeleter> audio_decoder_job_;
+ scoped_ptr<VideoDecoderJob, DecoderJobDeleter> video_decoder_job_;
bool reconfig_audio_decoder_;
bool reconfig_video_decoder_;
diff --git a/media/base/android/media_source_player_unittest.cc b/media/base/android/media_source_player_unittest.cc
index 31466400c9..cc99cf7cde 100644
--- a/media/base/android/media_source_player_unittest.cc
+++ b/media/base/android/media_source_player_unittest.cc
@@ -94,9 +94,12 @@ class MediaSourcePlayerTest : public testing::Test {
protected:
// Get the decoder job from the MediaSourcePlayer.
MediaDecoderJob* GetMediaDecoderJob(bool is_audio) {
- if (is_audio)
- return player_->audio_decoder_job_.get();
- return player_->video_decoder_job_.get();
+ if (is_audio) {
+ return reinterpret_cast<MediaDecoderJob*>(
+ player_->audio_decoder_job_.get());
+ }
+ return reinterpret_cast<MediaDecoderJob*>(
+ player_->video_decoder_job_.get());
}
// Starts an audio decoder job.
@@ -393,7 +396,10 @@ TEST_F(MediaSourcePlayerTest, DecoderJobsCannotStartWithoutAudio) {
EXPECT_TRUE(video_decoder_job->is_decoding());
}
-TEST_F(MediaSourcePlayerTest, StartTimeTicksResetAfterDecoderUnderruns) {
+// Disabled due to http://crbug.com/266041.
+// TODO(xhwang/qinmin): Fix this test and reenable it.
+TEST_F(MediaSourcePlayerTest,
+ DISABLED_StartTimeTicksResetAfterDecoderUnderruns) {
if (!MediaCodecBridge::IsAvailable())
return;
diff --git a/media/base/audio_buffer.cc b/media/base/audio_buffer.cc
index 61296dad87..b2cdd8c41a 100644
--- a/media/base/audio_buffer.cc
+++ b/media/base/audio_buffer.cc
@@ -11,22 +11,23 @@
namespace media {
-// Alignment of each channel's data; use 8-byte alignment as that is bigger
-// than maximum size of a sample, and the minimum alignment.
-enum { kChannelAlignment = 8 };
+// Alignment of each channel's data; this must match what ffmpeg expects
+// (which may be 0, 16, or 32, depending on the processor). Selecting 32 in
+// order to work on all processors.
+enum { kChannelAlignment = 32 };
AudioBuffer::AudioBuffer(SampleFormat sample_format,
int channel_count,
int frame_count,
+ bool create_buffer,
const uint8* const* data,
const base::TimeDelta timestamp,
const base::TimeDelta duration)
: sample_format_(sample_format),
channel_count_(channel_count),
- frame_count_(frame_count),
adjusted_frame_count_(frame_count),
trim_start_(0),
- end_of_stream_(data == NULL && frame_count_ == 0),
+ end_of_stream_(!create_buffer && data == NULL && frame_count == 0),
timestamp_(timestamp),
duration_(duration) {
CHECK_GE(channel_count, 0);
@@ -37,7 +38,7 @@ AudioBuffer::AudioBuffer(SampleFormat sample_format,
int data_size = frame_count * bytes_per_channel;
// Empty buffer?
- if (!data)
+ if (!create_buffer)
return;
if (sample_format == kSampleFormatPlanarF32 ||
@@ -56,7 +57,8 @@ AudioBuffer::AudioBuffer(SampleFormat sample_format,
// Copy each channel's data into the appropriate spot.
for (int i = 0; i < channel_count; ++i) {
channel_data_.push_back(data_.get() + i * block_size_per_channel);
- memcpy(channel_data_[i], data[i], data_size);
+ if (data)
+ memcpy(channel_data_[i], data[i], data_size);
}
return;
}
@@ -71,7 +73,8 @@ AudioBuffer::AudioBuffer(SampleFormat sample_format,
data_size *= channel_count;
data_.reset(
static_cast<uint8*>(base::AlignedAlloc(data_size, kChannelAlignment)));
- memcpy(data_.get(), data[0], data_size);
+ if (data)
+ memcpy(data_.get(), data[0], data_size);
}
AudioBuffer::~AudioBuffer() {}
@@ -85,9 +88,29 @@ scoped_refptr<AudioBuffer> AudioBuffer::CopyFrom(
const base::TimeDelta timestamp,
const base::TimeDelta duration) {
// If you hit this CHECK you likely have a bug in a demuxer. Go fix it.
+ CHECK_GT(frame_count, 0); // Otherwise looks like an EOF buffer.
CHECK(data[0]);
- return make_scoped_refptr(new AudioBuffer(
- sample_format, channel_count, frame_count, data, timestamp, duration));
+ return make_scoped_refptr(new AudioBuffer(sample_format,
+ channel_count,
+ frame_count,
+ true,
+ data,
+ timestamp,
+ duration));
+}
+
+// static
+scoped_refptr<AudioBuffer> AudioBuffer::CreateBuffer(SampleFormat sample_format,
+ int channel_count,
+ int frame_count) {
+ CHECK_GT(frame_count, 0); // Otherwise looks like an EOF buffer.
+ return make_scoped_refptr(new AudioBuffer(sample_format,
+ channel_count,
+ frame_count,
+ true,
+ NULL,
+ kNoTimestamp(),
+ kNoTimestamp()));
}
// static
@@ -98,14 +121,19 @@ scoped_refptr<AudioBuffer> AudioBuffer::CreateEmptyBuffer(
const base::TimeDelta duration) {
CHECK_GT(frame_count, 0); // Otherwise looks like an EOF buffer.
// Since data == NULL, format doesn't matter.
- return make_scoped_refptr(new AudioBuffer(
- kSampleFormatF32, channel_count, frame_count, NULL, timestamp, duration));
+ return make_scoped_refptr(new AudioBuffer(kSampleFormatF32,
+ channel_count,
+ frame_count,
+ false,
+ NULL,
+ timestamp,
+ duration));
}
// static
scoped_refptr<AudioBuffer> AudioBuffer::CreateEOSBuffer() {
return make_scoped_refptr(new AudioBuffer(
- kUnknownSampleFormat, 1, 0, NULL, kNoTimestamp(), kNoTimestamp()));
+ kUnknownSampleFormat, 1, 0, false, NULL, kNoTimestamp(), kNoTimestamp()));
}
// Convert int16 values in the range [kint16min, kint16max] to [-1.0, 1.0].
@@ -124,10 +152,12 @@ void AudioBuffer::ReadFrames(int frames_to_copy,
// specified must be in range.
DCHECK(!end_of_stream());
DCHECK_EQ(dest->channels(), channel_count_);
- source_frame_offset += trim_start_;
- DCHECK_LE(source_frame_offset + frames_to_copy, frame_count_);
+ DCHECK_LE(source_frame_offset + frames_to_copy, adjusted_frame_count_);
DCHECK_LE(dest_frame_offset + frames_to_copy, dest->frames());
+ // Move the start past any frames that have been trimmed.
+ source_frame_offset += trim_start_;
+
if (!data_) {
// Special case for an empty buffer.
dest->ZeroFramesPartial(dest_frame_offset, frames_to_copy);
@@ -189,8 +219,8 @@ void AudioBuffer::ReadFrames(int frames_to_copy,
}
void AudioBuffer::TrimStart(int frames_to_trim) {
- CHECK_LT(frames_to_trim, adjusted_frame_count_);
- trim_start_ += frames_to_trim;
+ CHECK_GE(frames_to_trim, 0);
+ CHECK_LE(frames_to_trim, adjusted_frame_count_);
// Adjust timestamp_ and duration_ to reflect the smaller number of frames.
double offset = static_cast<double>(duration_.InMicroseconds()) *
@@ -200,8 +230,25 @@ void AudioBuffer::TrimStart(int frames_to_trim) {
timestamp_ += offset_as_time;
duration_ -= offset_as_time;
+ // Finally adjust the number of frames in this buffer and where the start
+ // really is.
+ adjusted_frame_count_ -= frames_to_trim;
+ trim_start_ += frames_to_trim;
+}
+
+void AudioBuffer::TrimEnd(int frames_to_trim) {
+ CHECK_GE(frames_to_trim, 0);
+ CHECK_LE(frames_to_trim, adjusted_frame_count_);
+
+ // Adjust duration_ only to reflect the smaller number of frames.
+ double offset = static_cast<double>(duration_.InMicroseconds()) *
+ frames_to_trim / adjusted_frame_count_;
+ base::TimeDelta offset_as_time =
+ base::TimeDelta::FromMicroseconds(static_cast<int64>(offset));
+ duration_ -= offset_as_time;
+
// Finally adjust the number of frames in this buffer.
- adjusted_frame_count_ = frame_count_ - trim_start_;
+ adjusted_frame_count_ -= frames_to_trim;
}
} // namespace media
diff --git a/media/base/audio_buffer.h b/media/base/audio_buffer.h
index 9200666cb5..e52355ac4c 100644
--- a/media/base/audio_buffer.h
+++ b/media/base/audio_buffer.h
@@ -37,6 +37,12 @@ class MEDIA_EXPORT AudioBuffer
const base::TimeDelta timestamp,
const base::TimeDelta duration);
+ // Create an AudioBuffer with |frame_count| frames. Buffer is allocated, but
+ // not initialized. Timestamp and duration are set to kNoTimestamp().
+ static scoped_refptr<AudioBuffer> CreateBuffer(SampleFormat sample_format,
+ int channel_count,
+ int frame_count);
+
// Create an empty AudioBuffer with |frame_count| frames.
static scoped_refptr<AudioBuffer> CreateEmptyBuffer(
int channel_count,
@@ -60,10 +66,15 @@ class MEDIA_EXPORT AudioBuffer
AudioBus* dest);
// Trim an AudioBuffer by removing |frames_to_trim| frames from the start.
+ // Timestamp and duration are adjusted to reflect the fewer frames.
// Note that repeated calls to TrimStart() may result in timestamp() and
// duration() being off by a few microseconds due to rounding issues.
void TrimStart(int frames_to_trim);
+ // Trim an AudioBuffer by removing |frames_to_trim| frames from the end.
+ // Duration is adjusted to reflect the fewer frames.
+ void TrimEnd(int frames_to_trim);
+
// Return the number of channels.
int channel_count() const { return channel_count_; }
@@ -83,16 +94,22 @@ class MEDIA_EXPORT AudioBuffer
// If there's no data in this buffer, it represents end of stream.
bool end_of_stream() const { return end_of_stream_; }
+ // Access to the raw buffer for ffmpeg to write directly to. Data for planar
+ // data is grouped by channel.
+ uint8* writable_data() { return data_.get(); }
+
private:
friend class base::RefCountedThreadSafe<AudioBuffer>;
// Allocates aligned contiguous buffer to hold all channel data (1 block for
// interleaved data, |channel_count| blocks for planar data), copies
- // [data,data+data_size) to the allocated buffer(s). If |data| is null an end
- // of stream buffer is created.
+ // [data,data+data_size) to the allocated buffer(s). If |data| is null, no
+ // data is copied. If |create_buffer| is false, no data buffer is created (or
+ // copied to).
AudioBuffer(SampleFormat sample_format,
int channel_count,
int frame_count,
+ bool create_buffer,
const uint8* const* data,
const base::TimeDelta timestamp,
const base::TimeDelta duration);
@@ -101,7 +118,6 @@ class MEDIA_EXPORT AudioBuffer
const SampleFormat sample_format_;
const int channel_count_;
- const int frame_count_;
int adjusted_frame_count_;
int trim_start_;
const bool end_of_stream_;
diff --git a/media/base/audio_buffer_unittest.cc b/media/base/audio_buffer_unittest.cc
index f6384e880f..473778a6b5 100644
--- a/media/base/audio_buffer_unittest.cc
+++ b/media/base/audio_buffer_unittest.cc
@@ -256,7 +256,7 @@ TEST(AudioBufferTest, Trim) {
buffer->ReadFrames(20, 0, 0, bus.get());
VerifyResult(bus->channel(0), 20, 1.0f, 1.0f);
- // Trim off 10 frames.
+ // Trim off 10 frames from the start.
buffer->TrimStart(10);
EXPECT_EQ(buffer->frame_count(), frames - 10);
EXPECT_EQ(buffer->timestamp(), start_time + base::TimeDelta::FromSeconds(10));
@@ -264,13 +264,27 @@ TEST(AudioBufferTest, Trim) {
buffer->ReadFrames(20, 0, 0, bus.get());
VerifyResult(bus->channel(0), 20, 11.0f, 1.0f);
- // Trim off 80 more.
- buffer->TrimStart(80);
- EXPECT_EQ(buffer->frame_count(), frames - 90);
- EXPECT_EQ(buffer->timestamp(), start_time + base::TimeDelta::FromSeconds(90));
- EXPECT_EQ(buffer->duration(), base::TimeDelta::FromSeconds(10));
+ // Trim off 10 frames from the end.
+ buffer->TrimEnd(10);
+ EXPECT_EQ(buffer->frame_count(), frames - 20);
+ EXPECT_EQ(buffer->timestamp(), start_time + base::TimeDelta::FromSeconds(10));
+ EXPECT_EQ(buffer->duration(), base::TimeDelta::FromSeconds(80));
+ buffer->ReadFrames(20, 0, 0, bus.get());
+ VerifyResult(bus->channel(0), 20, 11.0f, 1.0f);
+
+ // Trim off 50 more from the start.
+ buffer->TrimStart(50);
+ EXPECT_EQ(buffer->frame_count(), frames - 70);
+ EXPECT_EQ(buffer->timestamp(), start_time + base::TimeDelta::FromSeconds(60));
+ EXPECT_EQ(buffer->duration(), base::TimeDelta::FromSeconds(30));
buffer->ReadFrames(10, 0, 0, bus.get());
- VerifyResult(bus->channel(0), 10, 91.0f, 1.0f);
+ VerifyResult(bus->channel(0), 10, 61.0f, 1.0f);
+
+ // Trim off the last 30 frames.
+ buffer->TrimEnd(30);
+ EXPECT_EQ(buffer->frame_count(), 0);
+ EXPECT_EQ(buffer->timestamp(), start_time + base::TimeDelta::FromSeconds(60));
+ EXPECT_EQ(buffer->duration(), base::TimeDelta::FromSeconds(0));
}
} // namespace media
diff --git a/media/base/container_names.cc b/media/base/container_names.cc
index 8b68e31e24..f062929d54 100644
--- a/media/base/container_names.cc
+++ b/media/base/container_names.cc
@@ -975,8 +975,6 @@ static bool CheckMov(const uint8* buffer, int buffer_size) {
default:
return false;
}
- if (atomsize <= 0)
- break; // Indicates the last atom or length too big.
if (atomsize == 1) {
// Indicates that the length is the next 64bits.
if (offset + 16 > buffer_size)
@@ -985,6 +983,8 @@ static bool CheckMov(const uint8* buffer, int buffer_size) {
break; // Offset is way past buffer size.
atomsize = Read32(buffer + offset + 12);
}
+ if (atomsize <= 0)
+ break; // Indicates the last atom or length too big.
offset += atomsize;
}
return true;
diff --git a/media/base/container_names_unittest.cc b/media/base/container_names_unittest.cc
index 4aa20638ba..21f80af6d9 100644
--- a/media/base/container_names_unittest.cc
+++ b/media/base/container_names_unittest.cc
@@ -74,6 +74,13 @@ const char kRm1Buffer[12] = ".RMF\0\0";
const char kRm2Buffer[12] = ".ra\xfd";
uint8 kWtvBuffer[] = { 0xb7, 0xd8, 0x00, 0x20, 0x37, 0x49, 0xda, 0x11, 0xa6,
0x4e, 0x00, 0x07, 0xe9, 0x5e, 0xad, 0x8d };
+uint8 kBug263073Buffer[] = {
+ 0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32,
+ 0x00, 0x00, 0x00, 0x00, 0x69, 0x73, 0x6f, 0x6d, 0x6d, 0x70, 0x34, 0x32,
+ 0x00, 0x00, 0x00, 0x01, 0x6d, 0x64, 0x61, 0x74, 0x00, 0x00, 0x00, 0x00,
+ 0xaa, 0x2e, 0x22, 0xcf, 0x00, 0x00, 0x00, 0x37, 0x67, 0x64, 0x00, 0x28,
+ 0xac, 0x2c, 0xa4, 0x01, 0xe0, 0x08, 0x9f, 0x97, 0x01, 0x52, 0x02, 0x02,
+ 0x02, 0x80, 0x00, 0x01};
// Test that containers that start with fixed strings are handled correctly.
// This is to verify that the TAG matches the first 4 characters of the string.
@@ -91,6 +98,7 @@ TEST(ContainerNamesTest, CheckFixedStrings) {
VERIFY(kRm1Buffer, CONTAINER_RM);
VERIFY(kRm2Buffer, CONTAINER_RM);
VERIFY(kWtvBuffer, CONTAINER_WTV);
+ VERIFY(kBug263073Buffer, CONTAINER_MOV);
}
// Determine the container type of a specified file.
diff --git a/media/base/simd/filter_yuv_mmx.cc b/media/base/simd/filter_yuv_mmx.cc
index c69d9de651..3991fe72fe 100644
--- a/media/base/simd/filter_yuv_mmx.cc
+++ b/media/base/simd/filter_yuv_mmx.cc
@@ -16,6 +16,7 @@ namespace media {
#if defined(COMPILER_MSVC)
// Warning 4799 is about calling emms before the function exits.
// We calls emms in a frame level so suppress this warning.
+#pragma warning(push)
#pragma warning(disable: 4799)
#endif
@@ -72,7 +73,7 @@ void FilterYUVRows_MMX(uint8* dest,
}
#if defined(COMPILER_MSVC)
-#pragma warning(default: 4799)
+#pragma warning(pop)
#endif
} // namespace media