diff options
author | Ben Murdoch <benm@google.com> | 2013-08-07 11:04:47 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2013-08-07 11:04:47 +0100 |
commit | 3240926e260ce088908e02ac07a6cf7b0c0cbf44 (patch) | |
tree | 5ff5fa16b2fb9278c6d731b3d19123731f3f8626 /media | |
parent | 3b21a50ee4fe6f71bb117cbee9998a4f465eea9d (diff) | |
download | chromium_org-3240926e260ce088908e02ac07a6cf7b0c0cbf44.tar.gz |
Merge from Chromium at DEPS revision r216133
This commit was generated by merge_to_master.py.
Change-Id: I541d5d1d8520b6b3829fbc1fa18552bf9ad4a5c7
Diffstat (limited to 'media')
-rw-r--r-- | media/DEPS | 1 | ||||
-rw-r--r-- | media/base/android/media_source_player.cc | 34 | ||||
-rw-r--r-- | media/base/android/media_source_player.h | 6 | ||||
-rw-r--r-- | media/base/android/media_source_player_unittest.cc | 35 | ||||
-rw-r--r-- | media/base/media_log.cc | 30 | ||||
-rw-r--r-- | media/base/media_log.h | 6 | ||||
-rw-r--r-- | media/base/media_log_event.h | 3 | ||||
-rw-r--r-- | media/base/sample_format.cc | 23 | ||||
-rw-r--r-- | media/base/sample_format.h | 3 | ||||
-rw-r--r-- | media/base/video_frame.cc | 28 | ||||
-rw-r--r-- | media/base/video_frame.h | 3 | ||||
-rw-r--r-- | media/filters/ffmpeg_demuxer.cc | 77 |
12 files changed, 227 insertions, 22 deletions
diff --git a/media/DEPS b/media/DEPS index 7bb03fcbd8..9c27abac17 100644 --- a/media/DEPS +++ b/media/DEPS @@ -3,7 +3,6 @@ include_rules = [ "+jni", "+third_party/ffmpeg", "+third_party/libvpx", - "+third_party/openmax", "+third_party/opus", "+third_party/skia", "+ui/gfx", diff --git a/media/base/android/media_source_player.cc b/media/base/android/media_source_player.cc index 5d4aa98b66..979d1ccff4 100644 --- a/media/base/android/media_source_player.cc +++ b/media/base/android/media_source_player.cc @@ -67,6 +67,7 @@ MediaDecoderJob::MediaDecoderJob( media_codec_bridge_(media_codec_bridge), needs_flush_(false), is_audio_(is_audio), + input_eos_encountered_(false), weak_this_(this), is_decoding_(false) { } @@ -130,7 +131,9 @@ MediaDecoderJob::DecodeStatus MediaDecoderJob::QueueInputBuffer( 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()) { + return DECODE_INPUT_END_OF_STREAM; + } + if (unit.key_id.empty()) { media_codec_bridge_->QueueInputBuffer( input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp); } else { @@ -157,14 +160,21 @@ void MediaDecoderJob::DecodeInternal( const MediaDecoderJob::DecoderCallback& callback) { if (needs_flush) { DVLOG(1) << "DecodeInternal needs flush."; + input_eos_encountered_ = false; media_codec_bridge_->Reset(); } - 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; + DecodeStatus decode_status = DECODE_INPUT_END_OF_STREAM; + if (!input_eos_encountered_) { + decode_status = QueueInputBuffer(unit); + if (decode_status == DECODE_INPUT_END_OF_STREAM) { + input_eos_encountered_ = true; + } else if (decode_status != DECODE_SUCCEEDED) { + ui_loop_->PostTask(FROM_HERE, + base::Bind(callback, decode_status, + start_presentation_timestamp, 0)); + return; + } } size_t offset = 0; @@ -178,12 +188,14 @@ void MediaDecoderJob::DecodeInternal( timeout, &offset, &size, &presentation_timestamp, &end_of_stream); if (end_of_stream) - decode_status = DECODE_END_OF_STREAM; + decode_status = DECODE_OUTPUT_END_OF_STREAM; switch (outputBufferIndex) { case MediaCodecBridge::INFO_OUTPUT_BUFFERS_CHANGED: + DCHECK(decode_status != DECODE_INPUT_END_OF_STREAM); media_codec_bridge_->GetOutputBuffers(); break; case MediaCodecBridge::INFO_OUTPUT_FORMAT_CHANGED: + DCHECK(decode_status != DECODE_INPUT_END_OF_STREAM); // TODO(qinmin): figure out what we should do if format changes. decode_status = DECODE_FORMAT_CHANGED; break; @@ -232,7 +244,7 @@ void MediaDecoderJob::ReleaseOutputBuffer( static_cast<AudioCodecBridge*>(media_codec_bridge_.get())->PlayOutputBuffer( outputBufferIndex, size); } - if (status != DECODE_END_OF_STREAM || size != 0u) + if (status != DECODE_OUTPUT_END_OF_STREAM || size != 0u) media_codec_bridge_->ReleaseOutputBuffer(outputBufferIndex, !is_audio_); ui_loop_->PostTask(FROM_HERE, base::Bind( callback, status, presentation_timestamp, is_audio_ ? size : 0)); @@ -639,7 +651,9 @@ void MediaSourcePlayer::MediaDecoderCallback( return; } - if (decode_status != MediaDecoderJob::DECODE_TRY_ENQUEUE_INPUT_AGAIN_LATER) { + // If the input reaches input EOS, there is no need to request new data. + if (decode_status != MediaDecoderJob::DECODE_TRY_ENQUEUE_INPUT_AGAIN_LATER && + decode_status != MediaDecoderJob::DECODE_INPUT_END_OF_STREAM) { if (is_audio) audio_access_unit_index_++; else @@ -656,7 +670,7 @@ void MediaSourcePlayer::MediaDecoderCallback( UpdateTimestamps(presentation_timestamp, audio_output_bytes); } - if (decode_status == MediaDecoderJob::DECODE_END_OF_STREAM) { + if (decode_status == MediaDecoderJob::DECODE_OUTPUT_END_OF_STREAM) { PlaybackCompleted(is_audio); return; } diff --git a/media/base/android/media_source_player.h b/media/base/android/media_source_player.h index 7253d565e3..05fd224e04 100644 --- a/media/base/android/media_source_player.h +++ b/media/base/android/media_source_player.h @@ -43,7 +43,8 @@ class MediaDecoderJob { DECODE_TRY_ENQUEUE_INPUT_AGAIN_LATER, DECODE_TRY_DEQUEUE_OUTPUT_AGAIN_LATER, DECODE_FORMAT_CHANGED, - DECODE_END_OF_STREAM, + DECODE_INPUT_END_OF_STREAM, + DECODE_OUTPUT_END_OF_STREAM, DECODE_FAILED, }; @@ -111,6 +112,9 @@ class MediaDecoderJob { // Whether this is an audio decoder. bool is_audio_; + // Whether input EOS is encountered. + bool input_eos_encountered_; + // Weak pointer passed to media decoder jobs for callbacks. It is bounded to // the decoder thread. base::WeakPtrFactory<MediaDecoderJob> weak_this_; diff --git a/media/base/android/media_source_player_unittest.cc b/media/base/android/media_source_player_unittest.cc index cc99cf7cde..40d28e43f5 100644 --- a/media/base/android/media_source_player_unittest.cc +++ b/media/base/android/media_source_player_unittest.cc @@ -35,7 +35,10 @@ class MockMediaPlayerManager : public MediaPlayerManager { virtual void OnMediaMetadataChanged( int player_id, base::TimeDelta duration, int width, int height, bool success) OVERRIDE {} - virtual void OnPlaybackComplete(int player_id) OVERRIDE {} + virtual void OnPlaybackComplete(int player_id) OVERRIDE { + if (message_loop_.is_running()) + message_loop_.Quit(); + } virtual void OnMediaInterrupted(int player_id) OVERRIDE {} virtual void OnBufferingUpdate(int player_id, int percentage) OVERRIDE {} virtual void OnSeekComplete(int player_id, @@ -426,4 +429,34 @@ TEST_F(MediaSourcePlayerTest, EXPECT_LE(100.0, (current - previous).InMillisecondsF()); } +TEST_F(MediaSourcePlayerTest, NoRequestForDataAfterInputEOS) { + if (!MediaCodecBridge::IsAvailable()) + return; + + // Test MediaSourcePlayer will not request for new data after input EOS is + // reached. + scoped_refptr<gfx::SurfaceTextureBridge> surface_texture( + new gfx::SurfaceTextureBridge(0)); + gfx::ScopedJavaSurface surface(surface_texture.get()); + player_->SetVideoSurface(surface.Pass()); + StartVideoDecoderJob(); + player_->OnSeekRequestAck(manager_->last_seek_request_id()); + EXPECT_EQ(1, manager_->num_requests()); + // Send the first input chunk. + player_->ReadFromDemuxerAck(CreateReadFromDemuxerAckForVideo()); + manager_->message_loop()->Run(); + EXPECT_EQ(2, manager_->num_requests()); + + // Send EOS. + MediaPlayerHostMsg_ReadFromDemuxerAck_Params ack_params; + ack_params.type = DemuxerStream::VIDEO; + ack_params.access_units.resize(1); + ack_params.access_units[0].status = DemuxerStream::kOk; + ack_params.access_units[0].end_of_stream = true; + player_->ReadFromDemuxerAck(ack_params); + manager_->message_loop()->Run(); + // No more request for data should be made. + EXPECT_EQ(2, manager_->num_requests()); +} + } // namespace media diff --git a/media/base/media_log.cc b/media/base/media_log.cc index 0f2e182284..8a07b020c7 100644 --- a/media/base/media_log.cc +++ b/media/base/media_log.cc @@ -56,6 +56,8 @@ const char* MediaLog::EventTypeToString(MediaLogEvent::Type type) { return "BUFFERED_EXTENTS_CHANGED"; case MediaLogEvent::MEDIA_SOURCE_ERROR: return "MEDIA_SOURCE_ERROR"; + case MediaLogEvent::PROPERTY_CHANGE: + return "PROPERTY_CHANGE"; } NOTREACHED(); return NULL; @@ -198,4 +200,32 @@ scoped_ptr<MediaLogEvent> MediaLog::CreateMediaSourceErrorEvent( return event.Pass(); } +void MediaLog::SetStringProperty( + const char* key, const std::string& value) { + scoped_ptr<MediaLogEvent> event(CreateEvent(MediaLogEvent::PROPERTY_CHANGE)); + event->params.SetString(key, value); + AddEvent(event.Pass()); +} + +void MediaLog::SetIntegerProperty( + const char* key, int value) { + scoped_ptr<MediaLogEvent> event(CreateEvent(MediaLogEvent::PROPERTY_CHANGE)); + event->params.SetInteger(key, value); + AddEvent(event.Pass()); +} + +void MediaLog::SetDoubleProperty( + const char* key, double value) { + scoped_ptr<MediaLogEvent> event(CreateEvent(MediaLogEvent::PROPERTY_CHANGE)); + event->params.SetDouble(key, value); + AddEvent(event.Pass()); +} + +void MediaLog::SetBooleanProperty( + const char* key, bool value) { + scoped_ptr<MediaLogEvent> event(CreateEvent(MediaLogEvent::PROPERTY_CHANGE)); + event->params.SetBoolean(key, value); + AddEvent(event.Pass()); +} + } //namespace media diff --git a/media/base/media_log.h b/media/base/media_log.h index 191de33b56..1d25c0973a 100644 --- a/media/base/media_log.h +++ b/media/base/media_log.h @@ -68,6 +68,12 @@ class MEDIA_EXPORT MediaLog : public base::RefCountedThreadSafe<MediaLog> { scoped_ptr<MediaLogEvent> CreateMediaSourceErrorEvent( const std::string& error); + // Report a property change without an accompanying event. + void SetStringProperty(const char* key, const std::string& value); + void SetIntegerProperty(const char* key, int value); + void SetDoubleProperty(const char* key, double value); + void SetBooleanProperty(const char* key, bool value); + protected: friend class base::RefCountedThreadSafe<MediaLog>; virtual ~MediaLog(); diff --git a/media/base/media_log_event.h b/media/base/media_log_event.h index 142626b1d7..811d1131a7 100644 --- a/media/base/media_log_event.h +++ b/media/base/media_log_event.h @@ -87,6 +87,9 @@ struct MediaLogEvent { // Errors reported by Media Source Extensions code. MEDIA_SOURCE_ERROR, // params: "error": Error string describing the error detected. + + // A property has changed without any special event occurring. + PROPERTY_CHANGE, }; int32 id; diff --git a/media/base/sample_format.cc b/media/base/sample_format.cc index 3fdcf1018e..a4791cd686 100644 --- a/media/base/sample_format.cc +++ b/media/base/sample_format.cc @@ -29,4 +29,27 @@ int SampleFormatToBytesPerChannel(SampleFormat sample_format) { return 0; } +const char* SampleFormatToString(SampleFormat sample_format) { + switch(sample_format) { + case kUnknownSampleFormat: + return "Unknown sample format"; + case kSampleFormatU8: + return "Unsigned 8-bit with bias of 128"; + case kSampleFormatS16: + return "Signed 16-bit"; + case kSampleFormatS32: + return "Signed 32-bit"; + case kSampleFormatF32: + return "Float 32-bit"; + case kSampleFormatPlanarS16: + return "Signed 16-bit planar"; + case kSampleFormatPlanarF32: + return "Float 32-bit planar"; + case kSampleFormatMax: + break; + } + NOTREACHED() << "Invalid sample format provided: " << sample_format; + return ""; +} + } // namespace media diff --git a/media/base/sample_format.h b/media/base/sample_format.h index bcaa5b2785..3d2799fa12 100644 --- a/media/base/sample_format.h +++ b/media/base/sample_format.h @@ -29,6 +29,9 @@ enum SampleFormat { // |sample_format|. MEDIA_EXPORT int SampleFormatToBytesPerChannel(SampleFormat sample_format); +// Returns the name of the sample format as a string +MEDIA_EXPORT const char* SampleFormatToString(SampleFormat sample_format); + } // namespace media #endif // MEDIA_BASE_SAMPLE_FORMAT_H diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc index de7440ae20..10ad0511ff 100644 --- a/media/base/video_frame.cc +++ b/media/base/video_frame.cc @@ -43,6 +43,34 @@ scoped_refptr<VideoFrame> VideoFrame::CreateFrame( } // static +std::string VideoFrame::FormatToString(VideoFrame::Format format) { + switch (format) { + case VideoFrame::INVALID: + return "INVALID"; + case VideoFrame::RGB32: + return "RGB32"; + case VideoFrame::YV12: + return "YV12"; + case VideoFrame::YV16: + return "YV16"; + case VideoFrame::EMPTY: + return "EMPTY"; + case VideoFrame::I420: + return "I420"; + case VideoFrame::NATIVE_TEXTURE: + return "NATIVE_TEXTURE"; +#if defined(GOOGLE_TV) + case VideoFrame::HOLE: + return "HOLE"; +#endif + case VideoFrame::YV12A: + return "YV12A"; + } + NOTREACHED() << "Invalid videoframe format provided: " << format; + return ""; +} + +// static bool VideoFrame::IsValidConfig(VideoFrame::Format format, const gfx::Size& coded_size, const gfx::Rect& visible_rect, diff --git a/media/base/video_frame.h b/media/base/video_frame.h index 128143c4df..8207d9be1d 100644 --- a/media/base/video_frame.h +++ b/media/base/video_frame.h @@ -53,6 +53,9 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { YV12A = 14, // 20bpp YUVA planar 1x1 Y, 2x2 VU, 1x1 A samples. }; + // Returns the name of a Format as a string. + static std::string FormatToString(Format format); + // This class calls the TextureNoLongerNeededCallback when the last reference // on the class is destroyed. The VideoFrame holds a reference to the mailbox // but anyone else who queries the mailbox should also hold a reference while diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc index 70c55963f1..14b1fff99c 100644 --- a/media/filters/ffmpeg_demuxer.cc +++ b/media/filters/ffmpeg_demuxer.cc @@ -17,6 +17,7 @@ #include "base/metrics/sparse_histogram.h" #include "base/stl_util.h" #include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" #include "base/task_runner_util.h" #include "base/time/time.h" #include "media/base/audio_decoder_config.h" @@ -491,8 +492,12 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, // partial playback. At least one audio or video stream must be playable. AVFormatContext* format_context = glue_->format_context(); streams_.resize(format_context->nb_streams); - bool found_audio_stream = false; - bool found_video_stream = false; + + AVStream* audio_stream = NULL; + AudioDecoderConfig audio_config; + + AVStream* video_stream = NULL; + VideoDecoderConfig video_config; base::TimeDelta max_duration; for (size_t i = 0; i < format_context->nb_streams; ++i) { @@ -501,31 +506,32 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, AVMediaType codec_type = codec_context->codec_type; if (codec_type == AVMEDIA_TYPE_AUDIO) { - if (found_audio_stream) + if (audio_stream) continue; + // Log the codec detected, whether it is supported or not. UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedAudioCodec", codec_context->codec_id); // Ensure the codec is supported. IsValidConfig() also checks that the // channel layout and sample format are valid. - AudioDecoderConfig audio_config; AVStreamToAudioDecoderConfig(stream, &audio_config, false); if (!audio_config.IsValidConfig()) continue; - found_audio_stream = true; + audio_stream = stream; } else if (codec_type == AVMEDIA_TYPE_VIDEO) { - if (found_video_stream) + if (video_stream) continue; + // Log the codec detected, whether it is supported or not. UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedVideoCodec", codec_context->codec_id); // Ensure the codec is supported. IsValidConfig() also checks that the // frame size and visible size are valid. - VideoDecoderConfig video_config; AVStreamToVideoDecoderConfig(stream, &video_config, false); + if (!video_config.IsValidConfig()) continue; - found_video_stream = true; + video_stream = stream; } else { continue; } @@ -541,7 +547,7 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, } } - if (!found_audio_stream && !found_video_stream) { + if (!audio_stream && !video_stream) { status_cb.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); return; } @@ -579,6 +585,59 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, if (bitrate_ > 0) data_source_->SetBitrate(bitrate_); + // Audio logging + if (audio_stream) { + AVCodecContext* audio_codec = audio_stream->codec; + media_log_->SetBooleanProperty("found_audio_stream", true); + + SampleFormat sample_format = audio_config.sample_format(); + std::string sample_name = SampleFormatToString(sample_format); + + media_log_->SetStringProperty("audio_sample_format", sample_name); + + media_log_->SetStringProperty("audio_codec_name", + audio_codec->codec_name); + media_log_->SetIntegerProperty("audio_sample_rate", + audio_codec->sample_rate); + media_log_->SetIntegerProperty("audio_channels_count", + audio_codec->channels); + media_log_->SetIntegerProperty("audio_samples_per_second", + audio_config.samples_per_second()); + } else { + media_log_->SetBooleanProperty("found_audio_stream", false); + } + + // Video logging + if (video_stream) { + AVCodecContext* video_codec = video_stream->codec; + media_log_->SetBooleanProperty("found_video_stream", true); + media_log_->SetStringProperty("video_codec_name", video_codec->codec_name); + media_log_->SetIntegerProperty("width", video_codec->width); + media_log_->SetIntegerProperty("height", video_codec->height); + media_log_->SetIntegerProperty("coded_width", + video_codec->coded_width); + media_log_->SetIntegerProperty("coded_height", + video_codec->coded_height); + media_log_->SetStringProperty( + "time_base", + base::StringPrintf("%d/%d", + video_codec->time_base.num, + video_codec->time_base.den)); + media_log_->SetStringProperty( + "video_format", VideoFrame::FormatToString(video_config.format())); + media_log_->SetBooleanProperty("video_is_encrypted", + video_config.is_encrypted()); + } else { + media_log_->SetBooleanProperty("found_video_stream", false); + } + + + media_log_->SetDoubleProperty("max_duration", max_duration.InSecondsF()); + media_log_->SetDoubleProperty("start_time", start_time_.InSecondsF()); + media_log_->SetDoubleProperty("filesize_in_bytes", + static_cast<double>(filesize_in_bytes)); + media_log_->SetIntegerProperty("bitrate", bitrate_); + status_cb.Run(PIPELINE_OK); } |