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 <memory> | 8 #include <memory> |
9 #include <set> | 9 #include <set> |
10 #include <utility> | 10 #include <utility> |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 | 51 |
52 namespace { | 52 namespace { |
53 | 53 |
54 void SetAVStreamDiscard(AVStream* stream, AVDiscard discard) { | 54 void SetAVStreamDiscard(AVStream* stream, AVDiscard discard) { |
55 DCHECK(stream); | 55 DCHECK(stream); |
56 stream->discard = discard; | 56 stream->discard = discard; |
57 } | 57 } |
58 | 58 |
59 } // namespace | 59 } // namespace |
60 | 60 |
61 static base::Time ExtractTimelineOffset(AVFormatContext* format_context) { | 61 static base::Time ExtractTimelineOffset( |
62 if (strstr(format_context->iformat->name, "webm") || | 62 container_names::MediaContainerName container, |
63 strstr(format_context->iformat->name, "matroska")) { | 63 const AVFormatContext* format_context) { |
| 64 if (container == container_names::CONTAINER_WEBM) { |
64 const AVDictionaryEntry* entry = | 65 const AVDictionaryEntry* entry = |
65 av_dict_get(format_context->metadata, "creation_time", NULL, 0); | 66 av_dict_get(format_context->metadata, "creation_time", NULL, 0); |
66 | 67 |
67 base::Time timeline_offset; | 68 base::Time timeline_offset; |
68 | 69 |
69 // FFmpegDemuxerTests assume base::Time::FromUTCString() is used here. | 70 // FFmpegDemuxerTests assume base::Time::FromUTCString() is used here. |
70 if (entry != NULL && entry->value != NULL && | 71 if (entry != NULL && entry->value != NULL && |
71 base::Time::FromUTCString(entry->value, &timeline_offset)) { | 72 base::Time::FromUTCString(entry->value, &timeline_offset)) { |
72 return timeline_offset; | 73 return timeline_offset; |
73 } | 74 } |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 if (ToAudioSampleRate(audio_config.samples_per_second(), &asr)) { | 154 if (ToAudioSampleRate(audio_config.samples_per_second(), &asr)) { |
154 UMA_HISTOGRAM_ENUMERATION("Media.AudioSamplesPerSecond", asr, | 155 UMA_HISTOGRAM_ENUMERATION("Media.AudioSamplesPerSecond", asr, |
155 kAudioSampleRateMax + 1); | 156 kAudioSampleRateMax + 1); |
156 } else { | 157 } else { |
157 UMA_HISTOGRAM_COUNTS("Media.AudioSamplesPerSecondUnexpected", | 158 UMA_HISTOGRAM_COUNTS("Media.AudioSamplesPerSecondUnexpected", |
158 audio_config.samples_per_second()); | 159 audio_config.samples_per_second()); |
159 } | 160 } |
160 } | 161 } |
161 | 162 |
162 // Record video decoder config UMA stats corresponding to a src= playback. | 163 // Record video decoder config UMA stats corresponding to a src= playback. |
163 static void RecordVideoCodecStats(const VideoDecoderConfig& video_config, | 164 static void RecordVideoCodecStats(container_names::MediaContainerName container, |
| 165 const VideoDecoderConfig& video_config, |
164 AVColorRange color_range, | 166 AVColorRange color_range, |
165 MediaLog* media_log) { | 167 MediaLog* media_log) { |
166 media_log->RecordRapporWithSecurityOrigin("Media.OriginUrl.SRC.VideoCodec." + | 168 media_log->RecordRapporWithSecurityOrigin("Media.OriginUrl.SRC.VideoCodec." + |
167 GetCodecName(video_config.codec())); | 169 GetCodecName(video_config.codec())); |
168 | 170 |
| 171 // TODO(xhwang): Fix these misleading metric names. They should be something |
| 172 // like "Media.SRC.Xxxx". See http://crbug.com/716183. |
169 UMA_HISTOGRAM_ENUMERATION("Media.VideoCodec", video_config.codec(), | 173 UMA_HISTOGRAM_ENUMERATION("Media.VideoCodec", video_config.codec(), |
170 kVideoCodecMax + 1); | 174 kVideoCodecMax + 1); |
| 175 if (container == container_names::CONTAINER_MOV) { |
| 176 UMA_HISTOGRAM_ENUMERATION("Media.SRC.VideoCodec.MP4", video_config.codec(), |
| 177 kVideoCodecMax + 1); |
| 178 } else if (container == container_names::CONTAINER_WEBM) { |
| 179 UMA_HISTOGRAM_ENUMERATION("Media.SRC.VideoCodec.WebM", video_config.codec(), |
| 180 kVideoCodecMax + 1); |
| 181 } |
171 | 182 |
172 // Drop UNKNOWN because U_H_E() uses one bucket for all values less than 1. | 183 // Drop UNKNOWN because U_H_E() uses one bucket for all values less than 1. |
173 if (video_config.profile() >= 0) { | 184 if (video_config.profile() >= 0) { |
174 UMA_HISTOGRAM_ENUMERATION("Media.VideoCodecProfile", video_config.profile(), | 185 UMA_HISTOGRAM_ENUMERATION("Media.VideoCodecProfile", video_config.profile(), |
175 VIDEO_CODEC_PROFILE_MAX + 1); | 186 VIDEO_CODEC_PROFILE_MAX + 1); |
176 } | 187 } |
177 UMA_HISTOGRAM_COUNTS_10000("Media.VideoVisibleWidth", | 188 UMA_HISTOGRAM_COUNTS_10000("Media.VideoVisibleWidth", |
178 video_config.visible_rect().width()); | 189 video_config.visible_rect().width()); |
179 UmaHistogramAspectRatio("Media.VideoVisibleAspectRatio", | 190 UmaHistogramAspectRatio("Media.VideoVisibleAspectRatio", |
180 video_config.visible_rect()); | 191 video_config.visible_rect()); |
(...skipping 1154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1335 | 1346 |
1336 // This AVStream does not successfully convert. | 1347 // This AVStream does not successfully convert. |
1337 continue; | 1348 continue; |
1338 } | 1349 } |
1339 | 1350 |
1340 StreamParser::TrackId track_id = stream->id; | 1351 StreamParser::TrackId track_id = stream->id; |
1341 std::string track_label = streams_[i]->GetMetadata("handler_name"); | 1352 std::string track_label = streams_[i]->GetMetadata("handler_name"); |
1342 std::string track_language = streams_[i]->GetMetadata("language"); | 1353 std::string track_language = streams_[i]->GetMetadata("language"); |
1343 | 1354 |
1344 // Some metadata is named differently in FFmpeg for webm files. | 1355 // Some metadata is named differently in FFmpeg for webm files. |
1345 if (strstr(format_context->iformat->name, "webm") || | 1356 if (glue_->container() == container_names::CONTAINER_WEBM) { |
1346 strstr(format_context->iformat->name, "matroska")) { | |
1347 // TODO(servolk): FFmpeg doesn't set stream->id correctly for webm files. | 1357 // TODO(servolk): FFmpeg doesn't set stream->id correctly for webm files. |
1348 // Need to fix that and use it as track id. crbug.com/323183 | 1358 // Need to fix that and use it as track id. crbug.com/323183 |
1349 track_id = | 1359 track_id = |
1350 static_cast<StreamParser::TrackId>(media_tracks->tracks().size() + 1); | 1360 static_cast<StreamParser::TrackId>(media_tracks->tracks().size() + 1); |
1351 track_label = streams_[i]->GetMetadata("title"); | 1361 track_label = streams_[i]->GetMetadata("title"); |
1352 } | 1362 } |
1353 | 1363 |
1354 if (codec_type == AVMEDIA_TYPE_AUDIO) { | 1364 if (codec_type == AVMEDIA_TYPE_AUDIO) { |
1355 streams_[i]->SetEnabled(detected_audio_track_count == 1, | 1365 streams_[i]->SetEnabled(detected_audio_track_count == 1, |
1356 base::TimeDelta()); | 1366 base::TimeDelta()); |
(...skipping 21 matching lines...) Expand all Loading... |
1378 | 1388 |
1379 media_track = media_tracks->AddAudioTrack(audio_config, track_id, "main", | 1389 media_track = media_tracks->AddAudioTrack(audio_config, track_id, "main", |
1380 track_label, track_language); | 1390 track_label, track_language); |
1381 media_track->set_id(base::UintToString(track_id)); | 1391 media_track->set_id(base::UintToString(track_id)); |
1382 DCHECK(track_id_to_demux_stream_map_.find(media_track->id()) == | 1392 DCHECK(track_id_to_demux_stream_map_.find(media_track->id()) == |
1383 track_id_to_demux_stream_map_.end()); | 1393 track_id_to_demux_stream_map_.end()); |
1384 track_id_to_demux_stream_map_[media_track->id()] = streams_[i].get(); | 1394 track_id_to_demux_stream_map_[media_track->id()] = streams_[i].get(); |
1385 } else if (codec_type == AVMEDIA_TYPE_VIDEO) { | 1395 } else if (codec_type == AVMEDIA_TYPE_VIDEO) { |
1386 VideoDecoderConfig video_config = streams_[i]->video_decoder_config(); | 1396 VideoDecoderConfig video_config = streams_[i]->video_decoder_config(); |
1387 | 1397 |
1388 RecordVideoCodecStats(video_config, stream->codecpar->color_range, | 1398 RecordVideoCodecStats(glue_->container(), video_config, |
1389 media_log_); | 1399 stream->codecpar->color_range, media_log_); |
1390 | 1400 |
1391 media_track = media_tracks->AddVideoTrack(video_config, track_id, "main", | 1401 media_track = media_tracks->AddVideoTrack(video_config, track_id, "main", |
1392 track_label, track_language); | 1402 track_label, track_language); |
1393 media_track->set_id(base::UintToString(track_id)); | 1403 media_track->set_id(base::UintToString(track_id)); |
1394 DCHECK(track_id_to_demux_stream_map_.find(media_track->id()) == | 1404 DCHECK(track_id_to_demux_stream_map_.find(media_track->id()) == |
1395 track_id_to_demux_stream_map_.end()); | 1405 track_id_to_demux_stream_map_.end()); |
1396 track_id_to_demux_stream_map_[media_track->id()] = streams_[i].get(); | 1406 track_id_to_demux_stream_map_[media_track->id()] = streams_[i].get(); |
1397 } | 1407 } |
1398 | 1408 |
1399 max_duration = std::max(max_duration, streams_[i]->duration()); | 1409 max_duration = std::max(max_duration, streams_[i]->duration()); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1447 // | 1457 // |
1448 // FFmpeg's use of negative timestamps for opus pre-skip is nonstandard, but | 1458 // FFmpeg's use of negative timestamps for opus pre-skip is nonstandard, but |
1449 // for more information on pre-skip see section 4.2 of the Ogg Opus spec: | 1459 // for more information on pre-skip see section 4.2 of the Ogg Opus spec: |
1450 // https://tools.ietf.org/html/draft-ietf-codec-oggopus-08#section-4.2 | 1460 // https://tools.ietf.org/html/draft-ietf-codec-oggopus-08#section-4.2 |
1451 for (const auto& stream : streams_) { | 1461 for (const auto& stream : streams_) { |
1452 if (!stream || stream->type() != DemuxerStream::AUDIO) | 1462 if (!stream || stream->type() != DemuxerStream::AUDIO) |
1453 continue; | 1463 continue; |
1454 const AVStream* audio_stream = stream->av_stream(); | 1464 const AVStream* audio_stream = stream->av_stream(); |
1455 DCHECK(audio_stream); | 1465 DCHECK(audio_stream); |
1456 if (audio_stream->codecpar->codec_id == AV_CODEC_ID_OPUS || | 1466 if (audio_stream->codecpar->codec_id == AV_CODEC_ID_OPUS || |
1457 (strcmp(format_context->iformat->name, "ogg") == 0 && | 1467 (glue_->container() == container_names::CONTAINER_OGG && |
1458 audio_stream->codecpar->codec_id == AV_CODEC_ID_VORBIS)) { | 1468 audio_stream->codecpar->codec_id == AV_CODEC_ID_VORBIS)) { |
1459 for (size_t i = 0; i < streams_.size(); ++i) { | 1469 for (size_t i = 0; i < streams_.size(); ++i) { |
1460 if (!streams_[i]) | 1470 if (!streams_[i]) |
1461 continue; | 1471 continue; |
1462 streams_[i]->enable_negative_timestamp_fixups(); | 1472 streams_[i]->enable_negative_timestamp_fixups(); |
1463 | 1473 |
1464 // Fixup the seeking information to avoid selecting the audio stream | 1474 // Fixup the seeking information to avoid selecting the audio stream |
1465 // simply because it has a lower starting time. | 1475 // simply because it has a lower starting time. |
1466 if (streams_[i]->av_stream() == audio_stream && | 1476 if (streams_[i]->av_stream() == audio_stream && |
1467 streams_[i]->start_time() < base::TimeDelta()) { | 1477 streams_[i]->start_time() < base::TimeDelta()) { |
1468 streams_[i]->set_start_time(base::TimeDelta()); | 1478 streams_[i]->set_start_time(base::TimeDelta()); |
1469 } | 1479 } |
1470 } | 1480 } |
1471 } | 1481 } |
1472 } | 1482 } |
1473 | 1483 |
1474 // If no start time could be determined, default to zero. | 1484 // If no start time could be determined, default to zero. |
1475 if (start_time_ == kInfiniteDuration) { | 1485 if (start_time_ == kInfiniteDuration) { |
1476 start_time_ = base::TimeDelta(); | 1486 start_time_ = base::TimeDelta(); |
1477 } | 1487 } |
1478 | 1488 |
1479 // MPEG-4 B-frames cause grief for a simple container like AVI. Enable PTS | 1489 // MPEG-4 B-frames cause grief for a simple container like AVI. Enable PTS |
1480 // generation so we always get timestamps, see http://crbug.com/169570 | 1490 // generation so we always get timestamps, see http://crbug.com/169570 |
1481 if (strcmp(format_context->iformat->name, "avi") == 0) | 1491 if (glue_->container() == container_names::CONTAINER_AVI) |
1482 format_context->flags |= AVFMT_FLAG_GENPTS; | 1492 format_context->flags |= AVFMT_FLAG_GENPTS; |
1483 | 1493 |
1484 // For testing purposes, don't overwrite the timeline offset if set already. | 1494 // For testing purposes, don't overwrite the timeline offset if set already. |
1485 if (timeline_offset_.is_null()) | 1495 if (timeline_offset_.is_null()) { |
1486 timeline_offset_ = ExtractTimelineOffset(format_context); | 1496 timeline_offset_ = |
| 1497 ExtractTimelineOffset(glue_->container(), format_context); |
| 1498 } |
1487 | 1499 |
1488 // Since we're shifting the externally visible start time to zero, we need to | 1500 // Since we're shifting the externally visible start time to zero, we need to |
1489 // adjust the timeline offset to compensate. | 1501 // adjust the timeline offset to compensate. |
1490 if (!timeline_offset_.is_null() && start_time_ < base::TimeDelta()) | 1502 if (!timeline_offset_.is_null() && start_time_ < base::TimeDelta()) |
1491 timeline_offset_ += start_time_; | 1503 timeline_offset_ += start_time_; |
1492 | 1504 |
1493 if (max_duration == kInfiniteDuration && !timeline_offset_.is_null()) { | 1505 if (max_duration == kInfiniteDuration && !timeline_offset_.is_null()) { |
1494 SetLiveness(DemuxerStream::LIVENESS_LIVE); | 1506 SetLiveness(DemuxerStream::LIVENESS_LIVE); |
1495 } else if (max_duration != kInfiniteDuration) { | 1507 } else if (max_duration != kInfiniteDuration) { |
1496 SetLiveness(DemuxerStream::LIVENESS_RECORDED); | 1508 SetLiveness(DemuxerStream::LIVENESS_RECORDED); |
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1881 | 1893 |
1882 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { | 1894 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { |
1883 DCHECK(task_runner_->BelongsToCurrentThread()); | 1895 DCHECK(task_runner_->BelongsToCurrentThread()); |
1884 for (const auto& stream : streams_) { | 1896 for (const auto& stream : streams_) { |
1885 if (stream) | 1897 if (stream) |
1886 stream->SetLiveness(liveness); | 1898 stream->SetLiveness(liveness); |
1887 } | 1899 } |
1888 } | 1900 } |
1889 | 1901 |
1890 } // namespace media | 1902 } // namespace media |
OLD | NEW |