| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/filters/ffmpeg_demuxer.h" | 5 #include "media/filters/ffmpeg_demuxer.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/base64.h" | 10 #include "base/base64.h" |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 template <class T> // T has int width() & height() methods. | 107 template <class T> // T has int width() & height() methods. |
| 108 static void UmaHistogramAspectRatio(const char* name, const T& size) { | 108 static void UmaHistogramAspectRatio(const char* name, const T& size) { |
| 109 UMA_HISTOGRAM_CUSTOM_ENUMERATION( | 109 UMA_HISTOGRAM_CUSTOM_ENUMERATION( |
| 110 name, | 110 name, |
| 111 // Intentionally use integer division to truncate the result. | 111 // Intentionally use integer division to truncate the result. |
| 112 size.height() ? (size.width() * 100) / size.height() : kInfiniteRatio, | 112 size.height() ? (size.width() * 100) / size.height() : kInfiniteRatio, |
| 113 base::CustomHistogram::ArrayToCustomRanges( | 113 base::CustomHistogram::ArrayToCustomRanges( |
| 114 kCommonAspectRatios100, arraysize(kCommonAspectRatios100))); | 114 kCommonAspectRatios100, arraysize(kCommonAspectRatios100))); |
| 115 } | 115 } |
| 116 | 116 |
| 117 // Record detected track counts by type corresponding to a src= playback. |
| 118 // Counts are split into 50 buckets, capped into [0,100] range. |
| 119 static void RecordDetectedTrackTypeStats(int audio_count, |
| 120 int video_count, |
| 121 int text_count) { |
| 122 UMA_HISTOGRAM_COUNTS_100("Media.DetectedTrackCount.Audio", audio_count); |
| 123 UMA_HISTOGRAM_COUNTS_100("Media.DetectedTrackCount.Video", video_count); |
| 124 UMA_HISTOGRAM_COUNTS_100("Media.DetectedTrackCount.Text", text_count); |
| 125 } |
| 126 |
| 117 // Record audio decoder config UMA stats corresponding to a src= playback. | 127 // Record audio decoder config UMA stats corresponding to a src= playback. |
| 118 static void RecordAudioCodecStats(const AudioDecoderConfig& audio_config) { | 128 static void RecordAudioCodecStats(const AudioDecoderConfig& audio_config) { |
| 119 UMA_HISTOGRAM_ENUMERATION("Media.AudioCodec", audio_config.codec(), | 129 UMA_HISTOGRAM_ENUMERATION("Media.AudioCodec", audio_config.codec(), |
| 120 kAudioCodecMax + 1); | 130 kAudioCodecMax + 1); |
| 121 UMA_HISTOGRAM_ENUMERATION("Media.AudioSampleFormat", | 131 UMA_HISTOGRAM_ENUMERATION("Media.AudioSampleFormat", |
| 122 audio_config.sample_format(), kSampleFormatMax + 1); | 132 audio_config.sample_format(), kSampleFormatMax + 1); |
| 123 UMA_HISTOGRAM_ENUMERATION("Media.AudioChannelLayout", | 133 UMA_HISTOGRAM_ENUMERATION("Media.AudioChannelLayout", |
| 124 audio_config.channel_layout(), | 134 audio_config.channel_layout(), |
| 125 CHANNEL_LAYOUT_MAX + 1); | 135 CHANNEL_LAYOUT_MAX + 1); |
| 126 AudioSampleRate asr; | 136 AudioSampleRate asr; |
| (...skipping 966 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1093 scoped_ptr<MediaTracks> media_tracks(new MediaTracks()); | 1103 scoped_ptr<MediaTracks> media_tracks(new MediaTracks()); |
| 1094 AVStream* audio_stream = NULL; | 1104 AVStream* audio_stream = NULL; |
| 1095 AudioDecoderConfig audio_config; | 1105 AudioDecoderConfig audio_config; |
| 1096 AVStream* video_stream = NULL; | 1106 AVStream* video_stream = NULL; |
| 1097 VideoDecoderConfig video_config; | 1107 VideoDecoderConfig video_config; |
| 1098 | 1108 |
| 1099 // If available, |start_time_| will be set to the lowest stream start time. | 1109 // If available, |start_time_| will be set to the lowest stream start time. |
| 1100 start_time_ = kInfiniteDuration(); | 1110 start_time_ = kInfiniteDuration(); |
| 1101 | 1111 |
| 1102 base::TimeDelta max_duration; | 1112 base::TimeDelta max_duration; |
| 1113 int detected_audio_track_count = 0; |
| 1114 int detected_video_track_count = 0; |
| 1115 int detected_text_track_count = 0; |
| 1103 for (size_t i = 0; i < format_context->nb_streams; ++i) { | 1116 for (size_t i = 0; i < format_context->nb_streams; ++i) { |
| 1104 AVStream* stream = format_context->streams[i]; | 1117 AVStream* stream = format_context->streams[i]; |
| 1105 const AVCodecContext* codec_context = stream->codec; | 1118 const AVCodecContext* codec_context = stream->codec; |
| 1106 const AVMediaType codec_type = codec_context->codec_type; | 1119 const AVMediaType codec_type = codec_context->codec_type; |
| 1107 | 1120 |
| 1108 if (codec_type == AVMEDIA_TYPE_AUDIO) { | 1121 if (codec_type == AVMEDIA_TYPE_AUDIO) { |
| 1122 // Log the codec detected, whether it is supported or not, and whether or |
| 1123 // not we have already detected a supported codec in another stream. |
| 1124 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedAudioCodecHash", |
| 1125 HashCodecName(GetCodecName(codec_context))); |
| 1126 detected_audio_track_count++; |
| 1127 |
| 1109 if (audio_stream) | 1128 if (audio_stream) |
| 1110 continue; | 1129 continue; |
| 1130 } else if (codec_type == AVMEDIA_TYPE_VIDEO) { |
| 1131 // Log the codec detected, whether it is supported or not, and whether or |
| 1132 // not we have already detected a supported codec in another stream. |
| 1133 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedVideoCodecHash", |
| 1134 HashCodecName(GetCodecName(codec_context))); |
| 1135 detected_video_track_count++; |
| 1111 | 1136 |
| 1112 // Log the codec detected, whether it is supported or not. | |
| 1113 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedAudioCodecHash", | |
| 1114 HashCodecName(GetCodecName(codec_context))); | |
| 1115 } else if (codec_type == AVMEDIA_TYPE_VIDEO) { | |
| 1116 if (video_stream) | 1137 if (video_stream) |
| 1117 continue; | 1138 continue; |
| 1118 | 1139 |
| 1119 #if BUILDFLAG(ENABLE_HEVC_DEMUXING) | 1140 #if BUILDFLAG(ENABLE_HEVC_DEMUXING) |
| 1120 if (stream->codec->codec_id == AV_CODEC_ID_HEVC) { | 1141 if (stream->codec->codec_id == AV_CODEC_ID_HEVC) { |
| 1121 // If ffmpeg is built without HEVC parser/decoder support, it will be | 1142 // If ffmpeg is built without HEVC parser/decoder support, it will be |
| 1122 // able to demux HEVC based solely on container-provided information, | 1143 // able to demux HEVC based solely on container-provided information, |
| 1123 // but unable to get some of the parameters without parsing the stream | 1144 // but unable to get some of the parameters without parsing the stream |
| 1124 // (e.g. coded size needs to be read from SPS, pixel format is typically | 1145 // (e.g. coded size needs to be read from SPS, pixel format is typically |
| 1125 // deduced from decoder config in hvcC box). These are not really needed | 1146 // deduced from decoder config in hvcC box). These are not really needed |
| 1126 // when using external decoder (e.g. hardware decoder), so override them | 1147 // when using external decoder (e.g. hardware decoder), so override them |
| 1127 // here, to make sure this translates into a valid VideoDecoderConfig. | 1148 // here, to make sure this translates into a valid VideoDecoderConfig. |
| 1128 if (stream->codec->coded_width == 0 && | 1149 if (stream->codec->coded_width == 0 && |
| 1129 stream->codec->coded_height == 0) { | 1150 stream->codec->coded_height == 0) { |
| 1130 DCHECK(stream->codec->width > 0); | 1151 DCHECK(stream->codec->width > 0); |
| 1131 DCHECK(stream->codec->height > 0); | 1152 DCHECK(stream->codec->height > 0); |
| 1132 stream->codec->coded_width = stream->codec->width; | 1153 stream->codec->coded_width = stream->codec->width; |
| 1133 stream->codec->coded_height = stream->codec->height; | 1154 stream->codec->coded_height = stream->codec->height; |
| 1134 } | 1155 } |
| 1135 if (stream->codec->pix_fmt == AV_PIX_FMT_NONE) { | 1156 if (stream->codec->pix_fmt == AV_PIX_FMT_NONE) { |
| 1136 stream->codec->pix_fmt = AV_PIX_FMT_YUV420P; | 1157 stream->codec->pix_fmt = AV_PIX_FMT_YUV420P; |
| 1137 } | 1158 } |
| 1138 } | 1159 } |
| 1139 #endif | 1160 #endif |
| 1140 // Log the codec detected, whether it is supported or not. | |
| 1141 UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedVideoCodecHash", | |
| 1142 HashCodecName(GetCodecName(codec_context))); | |
| 1143 } else if (codec_type == AVMEDIA_TYPE_SUBTITLE) { | 1161 } else if (codec_type == AVMEDIA_TYPE_SUBTITLE) { |
| 1162 detected_text_track_count++; |
| 1144 if (codec_context->codec_id != AV_CODEC_ID_WEBVTT || !text_enabled_) { | 1163 if (codec_context->codec_id != AV_CODEC_ID_WEBVTT || !text_enabled_) { |
| 1145 continue; | 1164 continue; |
| 1146 } | 1165 } |
| 1147 } else { | 1166 } else { |
| 1148 continue; | 1167 continue; |
| 1149 } | 1168 } |
| 1150 | 1169 |
| 1151 // Attempt to create a FFmpegDemuxerStream from the AVStream. This will | 1170 // Attempt to create a FFmpegDemuxerStream from the AVStream. This will |
| 1152 // return nullptr if the AVStream is invalid. Validity checks will verify | 1171 // return nullptr if the AVStream is invalid. Validity checks will verify |
| 1153 // things like: codec, channel layout, sample/pixel format, etc... | 1172 // things like: codec, channel layout, sample/pixel format, etc... |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1211 | 1230 |
| 1212 if (start_time < start_time_) { | 1231 if (start_time < start_time_) { |
| 1213 start_time_ = start_time; | 1232 start_time_ = start_time; |
| 1214 | 1233 |
| 1215 // Choose the stream with the lowest starting time as the fallback stream | 1234 // Choose the stream with the lowest starting time as the fallback stream |
| 1216 // for seeking. Video should always be preferred. | 1235 // for seeking. Video should always be preferred. |
| 1217 fallback_stream_for_seeking_ = StreamSeekInfo(i, start_time); | 1236 fallback_stream_for_seeking_ = StreamSeekInfo(i, start_time); |
| 1218 } | 1237 } |
| 1219 } | 1238 } |
| 1220 | 1239 |
| 1240 RecordDetectedTrackTypeStats(detected_audio_track_count, |
| 1241 detected_video_track_count, |
| 1242 detected_text_track_count); |
| 1243 |
| 1221 if (!audio_stream && !video_stream) { | 1244 if (!audio_stream && !video_stream) { |
| 1222 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() | 1245 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() |
| 1223 << ": no supported streams"; | 1246 << ": no supported streams"; |
| 1224 status_cb.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); | 1247 status_cb.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); |
| 1225 return; | 1248 return; |
| 1226 } | 1249 } |
| 1227 | 1250 |
| 1228 if (text_enabled_) | 1251 if (text_enabled_) |
| 1229 AddTextStreams(); | 1252 AddTextStreams(); |
| 1230 | 1253 |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1538 | 1561 |
| 1539 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { | 1562 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { |
| 1540 DCHECK(task_runner_->BelongsToCurrentThread()); | 1563 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1541 for (const auto& stream : streams_) { // |stream| is a ref to a pointer. | 1564 for (const auto& stream : streams_) { // |stream| is a ref to a pointer. |
| 1542 if (stream) | 1565 if (stream) |
| 1543 stream->SetLiveness(liveness); | 1566 stream->SetLiveness(liveness); |
| 1544 } | 1567 } |
| 1545 } | 1568 } |
| 1546 | 1569 |
| 1547 } // namespace media | 1570 } // namespace media |
| OLD | NEW |